Skip to content

Commit 51b3fe3

Browse files
committed
add FluxStep support and test with Tutorial_MultiApp_PDE.vcml
1 parent 0dae024 commit 51b3fe3

File tree

7 files changed

+1117
-5
lines changed

7 files changed

+1117
-5
lines changed

examples/models/Tutorial_MultiApp_PDE.vcml

Lines changed: 510 additions & 0 deletions
Large diffs are not rendered by default.

pyvcell/vcml/vcml_reader.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ def visit_SimpleReaction(self, element: _Element, node: vc.Model) -> None:
8888
node.reactions.append(reaction)
8989
self.generic_visit(element, reaction)
9090

91+
def visit_FluxStep(self, element: _Element, node: vc.Model) -> None:
92+
name: str = element.get("Name", default="unnamed")
93+
compartment_name: str = element.get("Structure", default="unknown")
94+
reaction = vc.Reaction(name=name, is_flux=True, compartment_name=compartment_name)
95+
node.reactions.append(reaction)
96+
self.generic_visit(element, reaction)
97+
9198
def visit_Reactant(self, element: _Element, node: vc.Reaction) -> None:
9299
compound_ref: str = element.get("LocalizedCompoundRef", default="unknown")
93100
stoichiometry: int = int(element.get("Stoichiometry", default="1"))

pyvcell/vcml/vcml_writer.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ def write_model(self, model: vc.Model, parent: _Element) -> None:
7373
)
7474
parent.append(species_element)
7575
for reaction in model.reactions:
76-
reaction_element = Element("SimpleReaction", Structure=reaction.compartment_name, Name=reaction.name)
76+
if not reaction.is_flux:
77+
reaction_element = Element("SimpleReaction", Structure=reaction.compartment_name, Name=reaction.name)
78+
else:
79+
reaction_element = Element("FluxStep", Structure=reaction.compartment_name, Name=reaction.name)
7780
parent.append(reaction_element)
7881
self.write_reaction(reaction, reaction_element)
7982

tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@
1818
vcml_spatial_bunny_3d_path,
1919
vcml_spatial_model_1d_path,
2020
vcml_spatial_small_3d_path,
21+
vcml_tutorial_multiapp_pde_path,
2122
)

tests/fixtures/data/Tutorial_MultiApp_PDE.vcml

Lines changed: 509 additions & 0 deletions
Large diffs are not rendered by default.

tests/fixtures/vcell_model_fixtures.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,8 @@ def vcml_field_data_demo_arrays(vcml_field_data_demo_biomodel: tuple[Biomodel, S
4646
@pytest.fixture
4747
def vcml_field_data_tgz_archive_path() -> Path:
4848
return FIXTURE_DATA_DIR / "test2_lsm_DEMO.tgz"
49+
50+
51+
@pytest.fixture
52+
def vcml_tutorial_multiapp_pde_path() -> Path:
53+
return FIXTURE_DATA_DIR / "Tutorial_MultiApp_PDE.vcml"

tests/vcml/test_vcml_reader.py

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,6 @@ def test_vcml_reader_bunny_3D(vcml_spatial_bunny_3d_path: Path) -> None:
212212
("background", 0, "image", None),
213213
("roi_1", 1, "image", None),
214214
]
215-
assert [(sv.name, sv.handle, sv.subvolume_type.name, sv.analytic_expr) for sv in geom.subvolumes] == [
216-
("background", 0, "image", None),
217-
("roi_1", 1, "image", None),
218-
]
219215
assert [(sc.name, sc.subvolume_ref_1, sc.subvolume_ref_2) for sc in geom.surface_classes] == [
220216
("background_roi_1_membrane", "background", "roi_1")
221217
]
@@ -241,6 +237,87 @@ def test_vcml_reader_bunny_3D(vcml_spatial_bunny_3d_path: Path) -> None:
241237
]
242238

243239

240+
def test_vcml_tutorial_multiapp_pde(vcml_tutorial_multiapp_pde_path: Path) -> None:
241+
with open(vcml_tutorial_multiapp_pde_path) as f:
242+
xml_string = f.read()
243+
244+
biomodel = vc.VcmlReader.biomodel_from_str(xml_string)
245+
assert biomodel is not None and biomodel.name == "Tutorial_MultiApp"
246+
model = biomodel.model
247+
assert model is not None and model.name == "unnamed"
248+
249+
assert [p.name for p in model.model_parameters] == []
250+
assert [r.name for r in model.reactions] == ["r0", "flux0"]
251+
assert [(c.name, c.dim) for c in model.compartments] == [("cyt", 3), ("nuc", 3), ("EC", 3), ("pm", 2), ("nm", 2)]
252+
assert [(s.name, s.compartment_name) for s in model.species] == [
253+
("Ran_cyt", "cyt"),
254+
("C_cyt", "cyt"),
255+
("RanC_nuc", "nuc"),
256+
("RanC_cyt", "cyt"),
257+
]
258+
259+
r0: vc.Reaction = model.reactions[0]
260+
assert [(r.name, r.stoichiometry) for r in r0.reactants] == [("RanC_cyt", 1)]
261+
assert [(p.name, p.stoichiometry) for p in r0.products] == [("Ran_cyt", 1), ("C_cyt", 1)]
262+
assert r0.kinetics is not None and r0.kinetics.kinetics_type == "MassAction"
263+
assert r0.compartment_name == "cyt"
264+
assert {p.name: p.value for p in r0.kinetics.kinetics_parameters} == {
265+
"J": "((Kf * RanC_cyt) - ((Kr * Ran_cyt) * C_cyt))",
266+
"Kf": 1.0,
267+
"Kr": 1000.0,
268+
}
269+
270+
r1: vc.Reaction = model.reactions[1]
271+
assert [(r.name, r.stoichiometry) for r in r1.reactants] == [("RanC_cyt", 1)]
272+
assert [(p.name, p.stoichiometry) for p in r1.products] == [("RanC_nuc", 1)]
273+
assert r1.kinetics is not None and r1.kinetics.kinetics_type == "GeneralKinetics"
274+
assert r1.compartment_name == "nm"
275+
assert {p.name: p.value for p in r1.kinetics.kinetics_parameters} == {
276+
"I": 0.0,
277+
"J": "(kfl * (RanC_cyt - RanC_nuc))",
278+
"kfl": 2.0,
279+
"netValence": 1.0,
280+
}
281+
282+
assert [a.name for a in biomodel.applications] == ["3D pde"]
283+
app0 = biomodel.applications[0]
284+
assert app0.stochastic is False
285+
286+
geom = app0.geometry
287+
assert (geom.name, geom.dim) == ("Site visit _Application0_20111127_1900085476", 3)
288+
assert geom.extent == (74.24, 74.24, 26.0)
289+
assert geom.origin == (0.0, 0.0, 0.0)
290+
assert [(sv.name, sv.handle, sv.subvolume_type.name, sv.image_pixel_value) for sv in geom.subvolumes] == [
291+
("ec", 0, "image", 1),
292+
("cytosol", 1, "image", 2),
293+
("Nucleus", 2, "image", 3),
294+
]
295+
assert [(sc.name, sc.subvolume_ref_1, sc.subvolume_ref_2) for sc in geom.surface_classes] == [
296+
("cytosol_ec_membrane", "cytosol", "ec"),
297+
("Nucleus_cytosol_membrane", "Nucleus", "cytosol"),
298+
]
299+
300+
assert [
301+
(cm.compartment_name, cm.geometry_class_name, cm.unit_size_0, cm.boundary_types)
302+
for cm in app0.compartment_mappings
303+
] == [
304+
("cyt", "cytosol", 1.0, ["flux", "flux", "flux", "flux", "flux", "flux"]),
305+
("nuc", "Nucleus", 1.0, ["flux", "flux", "flux", "flux", "flux", "flux"]),
306+
("EC", "ec", 1.0, ["flux", "flux", "flux", "flux", "flux", "flux"]),
307+
("pm", "cytosol_ec_membrane", 1.0, ["flux", "flux", "flux", "flux", "flux", "flux"]),
308+
("nm", "Nucleus_cytosol_membrane", 1.0, ["flux", "flux", "flux", "flux", "flux", "flux"]),
309+
]
310+
311+
assert [(sm.species_name, sm.diff_coef, sm.init_conc, sm.boundary_values) for sm in app0.species_mappings] == [
312+
("Ran_cyt", 10.0, 0.0, []),
313+
("C_cyt", 10.0, 0.0, []),
314+
("RanC_cyt", 10.0, 0.0, []),
315+
("RanC_nuc", 10.0, 0.00045, []),
316+
]
317+
318+
assert [[(rm.reaction_name, rm.included) for rm in app0.reaction_mappings]] == [[("r0", True), ("flux0", True)]]
319+
320+
244321
def test_xml_print_visitor(vcml_spatial_model_1d_path: Path) -> None:
245322
with open(vcml_spatial_model_1d_path) as f:
246323
xml_string = f.read()

0 commit comments

Comments
 (0)