Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Process SIF models and export to regnets #283

Merged
merged 6 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading