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

Add support for sbml qual models #328

Merged
merged 44 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
6df2afb
Initial implementation of sbml qual processor
nanglo123 Feb 16, 2024
ebec102
Change location of qual processing and add sample transition processing
nanglo123 Feb 20, 2024
b0d003b
Remove old sbml_qual directory
nanglo123 Feb 20, 2024
f1d7ae4
Add rate law extraction and natural conversion templates
nanglo123 Feb 21, 2024
11ad4e3
Add initials
nanglo123 Feb 21, 2024
a111c34
Add template processing
nanglo123 Feb 22, 2024
1b7b444
Add comments to template processing
nanglo123 Feb 22, 2024
23f8853
Clean up comments and remove testing code
nanglo123 Apr 9, 2024
d073ea0
Add api for sbml qual models
nanglo123 Apr 9, 2024
6bf00b9
Add qual api to sources documentation
nanglo123 Apr 9, 2024
798d5fd
Clean comments and add unit processing
nanglo123 Apr 9, 2024
58ebf2d
Add resources and Converter class
nanglo123 Apr 10, 2024
fdd45d0
Add grounding for concepts
nanglo123 Apr 12, 2024
96784cf
Assign identifiers and deterministically select identifier by alphabe…
nanglo123 Apr 12, 2024
3838a52
Add preprocessing for CURIEs, update variable names to be more inform…
nanglo123 Apr 16, 2024
9567a1f
Update comments about species naming and id
nanglo123 Apr 16, 2024
bc804c7
Add smoke tests for ingesting series of sbml qual models
nanglo123 Apr 16, 2024
65ad5cf
Add smoke test for ingesting qual models from the biomodels website a…
nanglo123 Apr 17, 2024
57827a3
Extract annotations and model id
nanglo123 Apr 17, 2024
502b63b
Add updated comments
nanglo123 Apr 18, 2024
b54aecb
Default to positive input if no sign is given
nanglo123 Apr 19, 2024
2083a4f
Update tests for sbml qual module for models from example repo
nanglo123 Apr 19, 2024
0b2f8ab
Create util file for shared code between sbml and sbml qual processors
nanglo123 Apr 19, 2024
3989e08
Change name of qual processor file
nanglo123 Apr 19, 2024
b300c7f
Change name of import for qual processing api
nanglo123 Apr 19, 2024
865b23c
Capitalize Qual in docs
nanglo123 Apr 19, 2024
7bf0398
Add qual api to be exposed in init. Add converter and grounding map t…
nanglo123 Apr 19, 2024
6db4b40
Add docstrings
nanglo123 Apr 19, 2024
fd188ca
Update docstring for shared model_id and model_annotation methods
nanglo123 Apr 19, 2024
ae94904
Revert testing code for sbml qual
nanglo123 Apr 19, 2024
e9fcf06
Add notebook
nanglo123 Apr 19, 2024
d4e7d4a
Update sorting method based on prefix and identifier
nanglo123 Apr 22, 2024
8455864
Rerun notebook with updated concept names
nanglo123 Apr 22, 2024
7f122b5
Add script for processing sbml qual models from covid-19 disease map
nanglo123 Apr 23, 2024
47a6575
Delete stockflow amrs, add regnet amr for BIOMD0000000562.json
nanglo123 Apr 24, 2024
69ca4d9
Revert format changes to regnet file
nanglo123 Apr 24, 2024
9314a41
Add support for GroupedControlledDegradation templates when exporting…
nanglo123 Apr 24, 2024
946dda6
Loop through each controller individually and create a transition dic…
nanglo123 Apr 24, 2024
7ebffad
Update script to save BIOMD0000000562 to sbml qual examples
nanglo123 Apr 24, 2024
6ebf100
Add more comments to modeling regnet file and fix minor bug, rerun sc…
nanglo123 Apr 25, 2024
5d475d1
Rerun hackathon and evaluation notebooks to regenerate regnet amrs wi…
nanglo123 Apr 25, 2024
645816a
Set duplicate rates from the same transition to 0, regenerate affecte…
nanglo123 Apr 26, 2024
ef0898b
Revert json import in notebook
nanglo123 Apr 26, 2024
d2fcbd9
Use fewer models from web for testing
bgyori Apr 26, 2024
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
7 changes: 7 additions & 0 deletions docs/source/sources.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ SBML extraction (:py:mod:`mira.sources.sbml`)
:members:
:show-inheritance:

SBML Qual extraction (:py:mod:`mira.sources.sbml.qual_api`)
-----------------------------------------------------------
.. automodule:: mira.sources.sbml.qual_api
:members:
:show-inheritance:


BioModels client (:py:mod:`mira.sources.biomodels`)
---------------------------------------------------
.. automodule:: mira.sources.biomodels
Expand Down
150 changes: 110 additions & 40 deletions mira/modeling/amr/regnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
__all__ = ["AMRRegNetModel", "ModelSpecification",
"template_model_to_regnet_json"]


import json
import logging
from copy import deepcopy
Expand Down Expand Up @@ -47,7 +46,7 @@ def __init__(self, model: Model):
model.template_model.annotations.name else "Model"
self.model_description = model.template_model.annotations.description \
if model.template_model.annotations and \
model.template_model.annotations.description else self.model_name
model.template_model.annotations.description else self.model_name

self.rates = []
self.observables = []
Expand Down Expand Up @@ -84,7 +83,7 @@ def __init__(self, model: Model):
self.states.append(state_data)
self._states_by_id[name] = state_data

idx = 0
edge_id = 1
# It's possible that something is naturally degraded/replicated
# by multiple transitions so we need to collect and aggregate rates
intrinsic_by_var = defaultdict(list)
Expand Down Expand Up @@ -132,47 +131,70 @@ def __init__(self, model: Model):
# a regular transition in the regnet framework
# Possibilities are:
# - ControlledReplication / GroupedControlledProduction
# - ControlledDegradation
# - ControlledDegradation / GroupedControlledDegradation
# - ControlledProduction if the control and produced concept are not the same
else:
tid = f"t{idx + 1}"
transition_dict = {'id': tid}
# If we have multiple controls then the thing that replicates
# is both a control and a produced variable.
if len(transition.control) > 1:
indep_ctrl = {c.key for c in transition.control} - \
{transition.produced[0].key}
# There is one corner case where both controllers are also
# the same as the produced variable, in which case.
if not indep_ctrl:
indep_ctrl = {transition.produced[0].key}
transition_dict['source'] = vmap[sorted(indep_ctrl)[0]]
# GroupedControlledProduction
if is_production(transition.template) or is_replication(
transition.template
):
indep_ctrl = {c.key for c in transition.control} - {
transition.produced[0].key
}
# There is one corner case where both controllers are also
# the same as the produced variable, in which case.
if not indep_ctrl:
indep_ctrl = {transition.produced[0].key}

for index, controller in enumerate(indep_ctrl):
self.create_edge(
transition,
vmap[controller],
vmap[transition.produced[0].key],
edge_id,
False if index == 0 else True
)

edge_id += 1
else:
# GroupedControlledDegradation
indep_ctrl = {c.key for c in transition.control} - {
transition.consumed[0].key
}
# There is one corner case where both controllers are also
# the same as the consumed variable, in which case.
if not indep_ctrl:
indep_ctrl = {transition.consumed[0].key}

for index, controller in enumerate(indep_ctrl):
self.create_edge(
transition,
vmap[controller],
vmap[transition.consumed[0].key],
edge_id,
False if index == 0 else True
)

edge_id += 1
else:
transition_dict['source'] = vmap[transition.control[0].key]
transition_dict['target'] = \
vmap[transition.consumed[0].key if
transition.consumed else transition.produced[0].key]
transition_dict['sign'] = (is_production(transition.template) or
is_replication(transition.template))

# Include rate law
if transition.template.rate_law:
rate_law = transition.template.rate_law.args[0]
pnames = transition.template.get_parameter_names()
# We just choose an arbitrary one deterministically
rate_const = sorted(pnames)[0] if pnames else None

transition_dict['properties'] = {
'name': tid,
'rate_constant': rate_const,
}
self.rates.append({
'target': tid,
'expression': str(rate_law),
'expression_mathml': expression_to_mathml(rate_law)
})

self.transitions.append(transition_dict)
idx += 1
# ControlledProduction if produced and controller are not the same
# ControlledDegradation
target = vmap[
transition.consumed[0].key
if transition.consumed
else transition.produced[0].key
]
self.create_edge(
transition,
vmap[transition.control[0].key],
target,
edge_id,
False
)
edge_id += 1

for var, rates in intrinsic_by_var.items():
rate_law = sum(rates)
Expand Down Expand Up @@ -224,6 +246,55 @@ def __init__(self, model: Model):
self.time = None
add_metadata_annotations(self.metadata, model)

def create_edge(self, transition, source, target, edge_id, duplicate):
"""Create and append a transition dictionary to the list of transitions

Parameters
----------
transition : Transition
The Transition object
source : str
The name of the source of the transition
target : str
The name of the target of the transition
edge_id : int
The id to assign to the transition
duplicate : bool
A boolean that tells us whether the transition we are processing has already been
processed at least once. This is for the purpose of not adding duplicate rate laws
to the output amr.
"""
tid = f"t{edge_id}"
transition_dict = {"id": tid}
transition_dict["source"] = source
transition_dict["target"] = target
transition_dict["sign"] = is_production(
transition.template
) or is_replication(transition.template)

#
if transition.template.rate_law:
# If we are processing a duplicate rate, set the rate to 0
rate_law = transition.template.rate_law.args[0] if not duplicate \
else safe_parse_expr('0')
pnames = transition.template.get_parameter_names()
# We just choose an arbitrary one deterministically
rate_const = sorted(pnames)[0] if pnames else None

transition_dict["properties"] = {
"name": tid,
"rate_constant": rate_const,
}
self.rates.append(
{
"target": tid,
"expression": str(rate_law),
"expression_mathml": expression_to_mathml(rate_law),
}
)

self.transitions.append(transition_dict)

def to_json(
self,
name: str = None,
Expand Down Expand Up @@ -461,4 +532,3 @@ class ModelSpecification(BaseModel):
model: RegNetModel
semantics: Optional[Ode]
metadata: Optional[Dict]

1 change: 1 addition & 0 deletions mira/sources/sbml/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .api import *
from .qual_api import *
Loading
Loading