Skip to content

Commit c2aba84

Browse files
authored
Merge pull request #398 from CovertLab/metabolism-redux-classic-bump
Small changes to metabolism_redux_classic
2 parents c13eeac + 6654704 commit c2aba84

2 files changed

Lines changed: 110 additions & 22 deletions

File tree

configs/metabolism_redux_classic.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
{
22
"experiment_id" : "metabolism_redux",
33
"max_duration" : 10,
4+
"fail_at_max_duration": false,
5+
"progress_bar": true,
6+
"n_init_sims": 1,
7+
"emitter": "parquet",
8+
"emitter_arg": {"out_dir": "out/"},
9+
"fixed_media": "minimal",
10+
"condition": "basal",
11+
412
"swap_processes" : {
513
"ecoli-metabolism" : "ecoli-metabolism-redux-classic"
614
},

ecoli/processes/metabolism_redux_classic.py

Lines changed: 102 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import numpy as np
66
import numpy.typing as npt
77
import time
8+
import pytest
89
from unum import Unum
910
import warnings
1011
from scipy.sparse import csr_matrix
@@ -47,7 +48,7 @@
4748
"R15-RXN-MET/CPD-479//CPD-479/MET.25.",
4849
"TRANS-RXN-218",
4950
"TRANS-RXN0-601-PROTON//PROTON.15. (reverse)",
50-
"DISULFOXRED-RXN[CCO-PERI-BAC]-MONOMER0-4152/MONOMER0-4438//MONOMER0-4438/MONOMER0-4152.71."
51+
"DISULFOXRED-RXN[CCO-PERI-BAC]-MONOMER0-4152/MONOMER0-4438//MONOMER0-4438/MONOMER0-4152.71." # Commented on Heena's branch?
5152
"DEPHOSICITDEHASE-RXN",
5253
"PHOSICITDEHASE-RXN",
5354
"GLYCOLALD-DEHYDROG-RXN",
@@ -63,6 +64,12 @@
6364
"RXN-22461",
6465
"RXN-22462",
6566
"RXN-22463",
67+
"PYRROLINECARBDEHYDROG-RXN",
68+
"RXN0-7008-PRO/UBIQUINONE-8//L-DELTA1-PYRROLINE_5-CARBOXYLATE/CPD-9956/PROTON.67.",
69+
"GLUCOKIN-RXN-GLC/ATP//ALPHA-GLC-6-P/ADP/PROTON.34.", # gets confused with PTS
70+
"PRPPSYN-RXN-CPD-15318/ATP//PRPP/AMP/PROTON.31.", # duplicate
71+
"TRANS-RXN0-574-GLC//GLC.9.", # duplicate
72+
"GLUCOKIN-RXN-GLC/ATP//D-glucopyranose-6-phosphate/ADP/PROTON.48.", # duplicate
6673
]
6774

6875
# not key central carbon met
@@ -134,6 +141,12 @@ class MetabolismReduxClassic(Step):
134141
"cell_density": 1100 * units.g / units.L,
135142
"concentration_updates": None,
136143
"maintenance_reaction": {},
144+
"objective_weights": {
145+
"secretion": 0.01,
146+
"efficiency": 0.000001,
147+
"kinetics": 0.0000001,
148+
"homeostatic": 1,
149+
},
137150
}
138151

139152
def __init__(self, parameters):
@@ -293,7 +306,6 @@ def ports_schema(self):
293306
"estimated_exchange_dmdt": {},
294307
"estimated_intermediate_dmdt": [],
295308
"target_kinetic_fluxes": [],
296-
"target_kinetic_bounds": [],
297309
"reaction_catalyst_counts": [],
298310
"maintenance_target": 0,
299311
}
@@ -454,14 +466,11 @@ def next_update(self, timestep, states):
454466
target_kinetic_values = enzyme_kinetic_boundaries[:, 1]
455467
target_kinetic_bounds = enzyme_kinetic_boundaries[:, [0, 2]]
456468

457-
# TODO (Cyrus) solve network flow problem to get fluxes
458-
objective_weights = {
459-
"secretion": 0.01,
460-
"efficiency": 0.000001,
461-
"kinetics": 0.0000001,
462-
}
469+
objective_weights = self.parameters["objective_weights"]
470+
463471
solution: FlowResult = self.network_flow_model.solve(
464-
homeostatic_targets=target_homeostatic_dmdt,
472+
homeostatic_concs=homeostatic_metabolite_concentrations,
473+
homeostatic_dm_targets=target_homeostatic_dmdt,
465474
maintenance_target=maintenance_target,
466475
kinetic_targets=target_kinetic_values,
467476
binary_kinetic_idx=binary_kinetic_idx,
@@ -507,7 +516,6 @@ def next_update(self, timestep, states):
507516
"estimated_homeostatic_dmdt": estimated_homeostatic_dmdt,
508517
"target_homeostatic_dmdt": target_homeostatic_dmdt,
509518
"target_kinetic_fluxes": target_kinetic_flux,
510-
"target_kinetic_bounds": target_kinetic_bounds,
511519
"estimated_exchange_dmdt": estimated_exchange_dmdt,
512520
"estimated_intermediate_dmdt": estimated_intermediate_dmdt,
513521
"maintenance_target": target_maintenance_flux,
@@ -634,7 +642,8 @@ def set_up_exchanges(self, exchanges: set[str], uptakes: set[str]):
634642

635643
def solve(
636644
self,
637-
homeostatic_targets: Optional[Iterable[float]] = None,
645+
homeostatic_concs: Iterable[float],
646+
homeostatic_dm_targets: Iterable[float],
638647
maintenance_target: float = 0,
639648
kinetic_targets: Optional[Iterable[float]] = None,
640649
binary_kinetic_idx: Optional[Iterable[int]] = None,
@@ -658,29 +667,36 @@ def solve(
658667
if self.maintenance_idx is not None:
659668
constr.append(v[self.maintenance_idx] == maintenance_target)
660669
# If enzymes not present, constrain rxn flux to 0
661-
if binary_kinetic_idx:
670+
if binary_kinetic_idx is not None:
662671
constr.append(v[binary_kinetic_idx] == 0)
663672

664673
constr.extend([v >= 0, v <= upper_flux_bound, e >= 0, e <= upper_flux_bound])
665674

666675
loss = 0
667-
loss += cp.norm1(dm[self.homeostatic_idx] - homeostatic_targets)
676+
# Must normalize by metabolite concentrations to prevent negative counts.
677+
homeostatic_term = cp.norm1(
678+
(dm[self.homeostatic_idx] - homeostatic_dm_targets) / homeostatic_concs
679+
)
680+
loss += (
681+
objective_weights["homeostatic"] * homeostatic_term
682+
if "homeostatic" in objective_weights
683+
else 0
684+
)
668685
loss += (
669686
objective_weights["secretion"] * (cp.sum(e[self.secretion_idx]))
670687
if "secretion" in objective_weights
671-
else loss
688+
else 0
672689
)
673690
loss += (
674691
objective_weights["efficiency"] * (cp.sum(v))
675692
if "efficiency" in objective_weights
676-
else loss
693+
else 0
677694
)
678-
loss = (
679-
loss
680-
+ objective_weights["kinetics"]
695+
loss += (
696+
objective_weights["kinetics"]
681697
* cp.norm1(v[self.kinetic_rxn_idx] - kinetic_targets)
682698
if "kinetics" in objective_weights
683-
else loss
699+
else 0
684700
)
685701

686702
p = cp.Problem(cp.Minimize(loss), constr)
@@ -726,8 +742,9 @@ def test_network_flow_model():
726742
model.set_up_exchanges(exchanges=exchanges, uptakes=uptakes)
727743

728744
solution: FlowResult = model.solve(
729-
homeostatic_targets=list(homeostatic_metabolites.values()),
730-
objective_weights={"secretion": 0.01, "efficiency": 0.0001},
745+
homeostatic_concs=[0.1],
746+
homeostatic_dm_targets=list(homeostatic_metabolites.values()),
747+
objective_weights={"homeostatic": 1, "secretion": 0.01, "efficiency": 0.0001},
731748
upper_flux_bound=100,
732749
solver=cp.GLOP,
733750
)
@@ -737,7 +754,70 @@ def test_network_flow_model():
737754
)
738755

739756

740-
# TODO (Cyrus) Add test for entire process
757+
@pytest.fixture
758+
def temp_config_dir(tmp_path):
759+
"""Create a temporary directory for test configs."""
760+
return tmp_path
761+
762+
763+
def test_redux_classic(temp_config_dir):
764+
import json
765+
from ecoli.experiments.ecoli_master_sim import EcoliSim
766+
767+
config = {
768+
"experiment_id": "metabolism_redux",
769+
"fail_at_max_duration": False,
770+
"max_duration": 10,
771+
"progress_bar": True,
772+
"emitter": "timeseries",
773+
"fixed_media": "minimal",
774+
"condition": "basal",
775+
"swap_processes": {"ecoli-metabolism": "ecoli-metabolism-redux-classic"},
776+
"exclude_processes": ["exchange_data"],
777+
"flow": {
778+
"ecoli-metabolism-redux-classic": [["ecoli-chromosome-structure"]],
779+
"ecoli-mass-listener": [["ecoli-metabolism-redux-classic"]],
780+
"RNA_counts_listener": [["ecoli-metabolism-redux-classic"]],
781+
"rna_synth_prob_listener": [["ecoli-metabolism-redux-classic"]],
782+
"monomer_counts_listener": [["ecoli-metabolism-redux-classic"]],
783+
"dna_supercoiling_listener": [["ecoli-metabolism-redux-classic"]],
784+
"replication_data_listener": [["ecoli-metabolism-redux-classic"]],
785+
"rnap_data_listener": [["ecoli-metabolism-redux-classic"]],
786+
"unique_molecule_counts": [["ecoli-metabolism-redux-classic"]],
787+
"ribosome_data_listener": [["ecoli-metabolism-redux-classic"]],
788+
},
789+
"raw_output": False,
790+
"operons": True,
791+
"trna_charging": False,
792+
"ppgpp_regulation": False,
793+
"initial_state_gaussian": True,
794+
"trna_attenuation": False,
795+
"variable_elongation_transcription": True,
796+
"variable_elongation_translation": False,
797+
"mechanistic_translation_supply": False,
798+
"mechanistic_aa_transport": False,
799+
"translation_supply": False,
800+
"aa_supply_in_charging": False,
801+
"adjust_timestep_for_charging": False,
802+
"disable_ppgpp_elongation_inhibition": True,
803+
}
804+
805+
config_path = temp_config_dir / "test_metabolism_redux_classic.json"
806+
with open(config_path, "w") as f:
807+
json.dump(config, f)
808+
809+
sim = EcoliSim.from_file(config_path)
810+
sim.build_ecoli()
811+
sim.run()
812+
813+
data = sim.query()
814+
assert data is not None
815+
741816

742817
if __name__ == "__main__":
818+
from tempfile import TemporaryDirectory
819+
from pathlib import Path
820+
743821
test_network_flow_model()
822+
with TemporaryDirectory() as tmp_path:
823+
test_redux_classic(Path(tmp_path))

0 commit comments

Comments
 (0)