Skip to content

Commit

Permalink
Merge pull request #283 from gyorilab/sif
Browse files Browse the repository at this point in the history
Process SIF models and export to regnets
  • Loading branch information
bgyori authored Feb 21, 2024
2 parents 766cab2 + 14219bc commit ef82a63
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 26 deletions.
32 changes: 19 additions & 13 deletions docs/source/sources.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,26 +78,32 @@ ACSets DecaExpr extraction (:py:mod:`mira.sources.acsets.decapodes.deca_expr`)
:members:
:show-inheritance:

Utility Methods (:py:mod:`mira.sources.util`)
---------------------------------------------
.. automodule:: mira.sources.util
:members:
:show-inheritance:

Vensim (:py:mod:`mira.sources.system_dynamics.vensim`)
------------------------------------------------------
Vensim models (:py:mod:`mira.sources.system_dynamics.vensim`)
-------------------------------------------------------------
.. automodule:: mira.sources.system_dynamics.vensim
:members:
:show-inheritance:

Stella (:py:mod:`mira.sources.system_dynamics.stella`)
------------------------------------------------------
Stella models (:py:mod:`mira.sources.system_dynamics.stella`)
-------------------------------------------------------------
.. automodule:: mira.sources.system_dynamics.stella
:members:
:show-inheritance:

PYSD Model Parsing (:py:mod:`mira.sources.system_dynamics.pysd`)
----------------------------------------------------------------
PySD models (:py:mod:`mira.sources.system_dynamics.pysd`)
---------------------------------------------------------
.. automodule:: mira.sources.system_dynamics.pysd
:members:
:show-inheritance:
:show-inheritance:

SIF networks (:py:mod:`mira.sources.sif`)
-----------------------------------------
.. automodule:: mira.sources.sif
:members:
:show-inheritance:

Utility Methods (:py:mod:`mira.sources.util`)
---------------------------------------------
.. automodule:: mira.sources.util
:members:
:show-inheritance:
29 changes: 16 additions & 13 deletions mira/modeling/amr/regnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,13 @@ def __init__(self, model: Model):
self.transitions = []
self.parameters = []
self.model_name = model.template_model.annotations.name if \
model.template_model.annotations and \
model.template_model.annotations.name else "Model"
self.model_description = model.template_model.annotations.description \
if model.template_model.annotations.description else self.model_name
if model.template_model.annotations and \
model.template_model.annotations.description else self.model_name
self.metadata = {}
self._states_by_id = {}
vmap = {}
for key, var in model.variables.items():
# Use the variable's concept name if possible but fall back
Expand All @@ -67,6 +70,7 @@ def __init__(self, model: Model):
initial = safe_parse_expr(str(initial))
state_data['initial'] = str(initial)
self.states.append(state_data)
self._states_by_id[name] = state_data

for idx, transition in enumerate(model.transitions.values()):
# Regnets cannot represent conversions (only
Expand All @@ -77,35 +81,34 @@ def __init__(self, model: Model):
# sign on the state so we have special handling for it
elif isinstance(transition.template, NaturalDegradation):
var = vmap[transition.consumed[0].key]
state_for_var = self._states_by_id.get(var)
if transition.template.rate_law:
pnames = transition.template.get_parameter_names()
if len(pnames) == 1:
rate_const = list(pnames)[0]
else:
rate_const = float(list(pnames)[0])
for state in self.states:
if state['id'] == var:
state['rate_constant'] = rate_const
state['sign'] = False
else:
state['sign'] = False
if state_for_var:
state_for_var['rate_constant'] = rate_const
if state_for_var:
state_for_var['sign'] = False
continue
# Controlled production corresponds to an inherent positive
# sign on the state so we have special handling for it
elif isinstance(transition.template, ControlledProduction):
var = vmap[transition.produced[0].key]
state_for_var = self._states_by_id.get(var)
if transition.template.rate_law:
pnames = transition.template.get_parameter_names()
if len(pnames) == 1:
rate_const = list(pnames)[0]
else:
rate_const = float(list(pnames)[0])
for state in self.states:
if state['id'] == var:
state['rate_constant'] = rate_const
state['sign'] = True
else:
state['sign'] = True
state_for_var = self._states_by_id.get(var)
if state_for_var:
state_for_var['rate_constant'] = rate_const
if state_for_var:
state_for_var['sign'] = True
continue
# Beyond these, we can assume that the transition is a
# form of production or degradation corresponding to
Expand Down
96 changes: 96 additions & 0 deletions mira/sources/sif.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""This module provides functions to create a MIRA TemplateModel from a
Simple Interaction Format (SIF) file. The SIF format is a simple
space-delimited format where each line represents a relationship
between two entities. The first column is the source node, the second
column is the relation, and the third column is the target node. The
relation is a string that represents the type of interaction between
the source and target nodes. SIF files are useful as a minimal representation
of regulatory networks with positive/negative regulation."""

__all__ = ['template_model_from_sif_edges',
'template_model_from_sif_file',
'template_model_from_sif_url']

import requests
from mira.metamodel import *


def template_model_from_sif_edges(edges):
"""Return TemplateModel from a list of SIF edges.
Parameters
----------
edges : list
A list of tuples of the form (source, rel, target) where source and
target are strings representing the source and target nodes and rel
is a string representing the relation between them.
Returns
-------
TemplateModel
A MIRA TemplateModel.
"""
templates = []
for source, rel, target in edges:
source_concept = Concept(name=source)
target_concept = Concept(name=target)
if rel == 'POSITIVE':
if source == target:
t = ControlledProduction(
controller=source_concept,
outcome=target_concept)
else:
t = GroupedControlledProduction(
controllers=[source_concept, target_concept],
outcome=target_concept)
elif rel == 'NEGATIVE':
if source == target:
t = NaturalDegradation(subject=source_concept)
else:
t = ControlledDegradation(
controller=source_concept,
subject=target_concept)
templates.append(t)
tm = TemplateModel(templates=templates)
return tm


def template_model_from_sif_file(fname):
"""Return TemplateModel from a SIF file.
Parameters
----------
fname : str
The path to the SIF file.
Returns
-------
TemplateModel
A MIRA TemplateModel.
"""
with open(fname, 'r') as fh:
edges = [line.strip().split()
for line in fh.readlines()
if line and not line.startswith('#')]
return template_model_from_sif_edges(edges)


def template_model_from_sif_url(url):
"""Return TemplateModel from a SIF URL.
Parameters
----------
url : str
The URL to the SIF file.
Returns
-------
TemplateModel
A MIRA TemplateModel.
"""
res = requests.get(url)
res.raise_for_status()
edges = [line.strip().split()
for line in res.text.split('\n')
if line and not line.startswith('#')]
return template_model_from_sif_edges(edges)
25 changes: 25 additions & 0 deletions scripts/covid19_diseasemaps/process_covid19_diseasemaps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import json
import tqdm
from mira.modeling.amr.regnet import template_model_to_regnet_json
from mira.sources.sif import template_model_from_sif_url


models = ['Apoptosis', 'Coagulation-pathway', 'ER_Stress', 'ETC', 'E_protein',
'HMOX1_Pathway', 'IFN-lambda', 'Interferon1', 'JNK_pathway',
'Kynurenine_pathway', 'NLRP3_Activation', 'Nsp14', 'Nsp4_Nsp6',
'Nsp9_protein', 'Orf10_Cul2_pathway', 'Orf3a', 'PAMP_signaling',
'Pyrimidine_deprivation', 'RTC-and-transcription',
'Renin_angiotensin', 'TGFB_pathway', 'Virus_replication_cycle']


SIF_URL_BASE = ('https://git-r3lab.uni.lu/covid/models/-/raw/master/'
'Executable%20Modules/SBML_qual_build/sif')


if __name__ == "__main__":
for model in tqdm.tqdm(models):
url = f'{SIF_URL_BASE}/{model}_stable.sif'
tm = template_model_from_sif_url(url)
regnet = template_model_to_regnet_json(tm)
with open(f'{model}.json', 'w') as fh:
json.dump(regnet, fh, indent=1)
16 changes: 16 additions & 0 deletions tests/test_sif.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from mira.sources.sif import template_model_from_sif_edges
from mira.modeling.amr.regnet import template_model_to_regnet_json


def test_sif_processing():
# Lotka volterra example
edges = [
('prey', 'POSITIVE', 'predator'),
('predator', 'NEGATIVE', 'prey'),
('prey', 'POSITIVE', 'prey'),
('predator', 'NEGATIVE', 'predator')
]
tm = template_model_from_sif_edges(edges)
assert len(tm.templates) == 4
regnet = template_model_to_regnet_json(tm)
assert len(regnet['model']['edges']) == 2

0 comments on commit ef82a63

Please sign in to comment.