Skip to content

Commit 0203826

Browse files
committed
moved vcml/sbml/antimony I/O to vcml.utils, rebuild vcml before solving
1 parent 1755df6 commit 0203826

File tree

4 files changed

+197
-166
lines changed

4 files changed

+197
-166
lines changed

pyvcell/vcml/__init__.py

Lines changed: 30 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
import logging
2-
import tempfile
3-
from os import PathLike
4-
from pathlib import Path
5-
61
from pyvcell.vcml.models import (
72
Application,
83
Biomodel,
@@ -26,6 +21,22 @@
2621
SurfaceClass,
2722
VCMLDocument,
2823
)
24+
from pyvcell.vcml.utils import (
25+
field_data_refs,
26+
load_antimony_file,
27+
load_antimony_str,
28+
load_sbml_file,
29+
load_sbml_str,
30+
load_vcml_file,
31+
load_vcml_str,
32+
to_antimony_str,
33+
to_sbml_str,
34+
to_vcml_str,
35+
update_biomodel,
36+
write_antimony_file,
37+
write_sbml_file,
38+
write_vcml_file,
39+
)
2940
from pyvcell.vcml.vcml_reader import VcmlReader
3041
from pyvcell.vcml.vcml_writer import VcmlWriter
3142

@@ -54,139 +65,18 @@
5465
"BoundaryType",
5566
"Application",
5667
"Simulation",
68+
"update_biomodel",
69+
"field_data_refs",
70+
"to_vcml_str",
71+
"to_sbml_str",
72+
"to_antimony_str",
73+
"load_vcml_str",
74+
"load_sbml_str",
75+
"load_antimony_str",
76+
"write_vcml_file",
77+
"write_sbml_file",
78+
"write_antimony_file",
79+
"load_vcml_file",
80+
"load_sbml_file",
81+
"load_antimony_file",
5782
]
58-
59-
60-
def load_antimony_str(antimony_str: str) -> Biomodel:
61-
import antimony # type: ignore[import-untyped]
62-
63-
antimony_success = antimony.loadAntimonyString(antimony_str)
64-
if antimony_success != -1:
65-
sbml_str = antimony.getSBMLString()
66-
sbml_str = sbml_str.replace("sboTerm", "metaid")
67-
logging.info(f"Hack - introduced a metaid in place of sboTerm to SBML string:\n{sbml_str}")
68-
return load_sbml_str(sbml_str)
69-
else:
70-
raise ValueError("Error loading model:", antimony.getLastError())
71-
72-
73-
def load_antimony_file(antimony_file: PathLike[str] | str) -> Biomodel:
74-
import antimony # ignore
75-
76-
antimony_success = antimony.loadAntimonyFile(antimony_file)
77-
if antimony_success != -1:
78-
sbml_str = antimony.getSBMLString()
79-
return load_sbml_str(sbml_str)
80-
else:
81-
raise ValueError("Error loading model:", antimony.getLastError())
82-
83-
84-
def to_antimony_str(
85-
bio_model: Biomodel, application_name: str | None = None, round_trip_validation: bool = True
86-
) -> str:
87-
sbml_str = to_sbml_str(bio_model, application_name, round_trip_validation=round_trip_validation)
88-
import antimony
89-
90-
antimony_success = antimony.loadSBMLString(sbml_str)
91-
if antimony_success != -1:
92-
antimony_str = str(antimony.getAntimonyString())
93-
return antimony_str
94-
else:
95-
raise ValueError("Error converting SBML to Antimony:", antimony.getLastError())
96-
97-
98-
def write_antimony_file(bio_model: Biomodel, antimony_file: PathLike[str] | str) -> None:
99-
antimony_str = to_antimony_str(bio_model)
100-
with open(antimony_file, "w") as f:
101-
f.write(antimony_str)
102-
103-
104-
def load_vcml_str(vcml_str: str) -> Biomodel:
105-
return VcmlReader.biomodel_from_str(vcml_str)
106-
107-
108-
def load_vcml_file(vcml_file: PathLike[str] | str) -> Biomodel:
109-
return VcmlReader.biomodel_from_file(vcml_file)
110-
111-
112-
def to_vcml_str(bio_model: Biomodel) -> str:
113-
vcml_document = VCMLDocument(biomodel=bio_model)
114-
vcml_str: str = VcmlWriter().write_vcml(document=vcml_document)
115-
return vcml_str
116-
117-
118-
def write_vcml_file(bio_model: Biomodel, vcml_file: PathLike[str] | str) -> None:
119-
vcml_document = VCMLDocument(biomodel=bio_model)
120-
VcmlWriter.write_to_file(vcml_document=vcml_document, file_path=vcml_file)
121-
122-
123-
def load_sbml_str(sbml_str: str) -> Biomodel:
124-
import libvcell
125-
126-
with tempfile.TemporaryDirectory() as tempdir:
127-
vcml_path = Path(tempdir) / "model.vcml"
128-
vc_success, vc_errmsg = libvcell.sbml_to_vcml(sbml_content=sbml_str, vcml_file_path=vcml_path)
129-
if vc_success:
130-
return VcmlReader.biomodel_from_file(vcml_path=vcml_path)
131-
else:
132-
raise ValueError("Error loading model:", vc_errmsg)
133-
134-
135-
def load_sbml_file(sbml_file: PathLike[str] | str) -> Biomodel:
136-
import libvcell
137-
138-
with tempfile.TemporaryDirectory() as tempdir:
139-
with open(sbml_file) as f:
140-
sbml_str = f.read()
141-
vcml_path = Path(tempdir) / "model.vcml"
142-
vc_success, vc_errmsg = libvcell.sbml_to_vcml(sbml_content=sbml_str, vcml_file_path=vcml_path)
143-
if vc_success:
144-
return VcmlReader.biomodel_from_file(vcml_path=vcml_path)
145-
else:
146-
raise ValueError("Error loading model:", vc_errmsg)
147-
148-
149-
def to_sbml_str(bio_model: Biomodel, application_name: str | None = None, round_trip_validation: bool = True) -> str:
150-
import libvcell
151-
152-
if application_name is None:
153-
if len(bio_model.applications) == 0:
154-
raise ValueError("sbml export from biomodel needs a biomodel application")
155-
if len(bio_model.applications) > 1:
156-
raise ValueError("Application must have exactly one application")
157-
application_name = bio_model.applications[0].name
158-
elif application_name not in [app.name for app in bio_model.applications]:
159-
raise ValueError(f"Application '{application_name}' not found in biomodel")
160-
vcml_document = VCMLDocument(biomodel=bio_model)
161-
vcml_str: str = VcmlWriter().write_vcml(document=vcml_document)
162-
with tempfile.TemporaryDirectory() as tempdir:
163-
sbml_path = Path(tempdir) / "model.sbml"
164-
success, msg = libvcell.vcml_to_sbml(
165-
vcml_content=vcml_str,
166-
application_name=application_name,
167-
sbml_file_path=sbml_path,
168-
round_trip_validation=round_trip_validation,
169-
)
170-
if not success:
171-
raise ValueError("Error converting VCML to SBML:", msg)
172-
with open(sbml_path) as f:
173-
sbml_str = f.read()
174-
return sbml_str
175-
176-
177-
def write_sbml_file(
178-
bio_model: Biomodel,
179-
sbml_file: PathLike[str] | str,
180-
application_name: str | None = None,
181-
round_trip_validation: bool = True,
182-
) -> None:
183-
sbml_str = to_sbml_str(bio_model, application_name, round_trip_validation)
184-
with open(sbml_file, "w") as f:
185-
f.write(sbml_str)
186-
187-
188-
def refresh_biomodel(bio_model: Biomodel) -> Biomodel:
189-
with tempfile.TemporaryDirectory() as tempdir:
190-
vcml_path = Path(tempdir) / "model.vcml"
191-
write_vcml_file(bio_model=bio_model, vcml_file=vcml_path)
192-
return VcmlReader.biomodel_from_file(vcml_path=vcml_path)

pyvcell/vcml/utils.py

Lines changed: 159 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
import logging
12
import tempfile
3+
from os import PathLike
24
from pathlib import Path
35

46
import sympy # type: ignore[import-untyped]
5-
from libvcell import sbml_to_vcml, vcml_to_sbml, vcml_to_vcml
7+
from libvcell import sbml_to_vcml, vcml_to_sbml
68
from sympy.parsing.sympy_parser import parse_expr # type: ignore[import-untyped]
79

810
from pyvcell._internal.simdata.simdata_models import VariableType
911
from pyvcell.sbml.sbml_spatial_model import SbmlSpatialModel
10-
from pyvcell.vcml import Application, VCMLDocument, VcmlReader, VcmlWriter
11-
from pyvcell.vcml.models import Biomodel
12+
from pyvcell.vcml.models import Application, Biomodel, VCMLDocument
13+
from pyvcell.vcml.vcml_reader import VcmlReader
14+
from pyvcell.vcml.vcml_writer import VcmlWriter
1215

1316

1417
def update_biomodel(bio_model: Biomodel) -> Biomodel:
@@ -21,21 +24,10 @@ def update_biomodel(bio_model: Biomodel) -> Biomodel:
2124
Returns:
2225
BioModel: The updated BioModel object.
2326
"""
24-
vcml_writer = VcmlWriter()
25-
vcml_content: str = vcml_writer.write_vcml(document=VCMLDocument(biomodel=bio_model))
26-
27-
with tempfile.TemporaryDirectory() as tmp_dir_name:
28-
tmp_dir_path = Path(tmp_dir_name)
29-
tmp_dir_path.mkdir(parents=True, exist_ok=True)
30-
vcml_file_path = tmp_dir_path / "model.vcml"
31-
success, error_message = vcml_to_vcml(vcml_content=vcml_content, vcml_file_path=vcml_file_path)
32-
if not success:
33-
raise ValueError(f"Failed to regenerate VCML: {error_message}")
34-
new_bio_model = VcmlReader.biomodel_from_file(vcml_file_path)
35-
return new_bio_model
27+
return load_vcml_str(to_vcml_str(bio_model=bio_model))
3628

3729

38-
def from_sbml(sbml_spatial_model: SbmlSpatialModel) -> Biomodel:
30+
def _from_sbml_object(sbml_spatial_model: SbmlSpatialModel) -> Biomodel:
3931
"""
4032
Import an SBML Spatial model and return a VCell Biomodel.
4133
@@ -63,7 +55,7 @@ def from_sbml(sbml_spatial_model: SbmlSpatialModel) -> Biomodel:
6355
return new_bio_model
6456

6557

66-
def to_sbml(bio_model: Biomodel, application_name: str, round_trip_validation: bool) -> SbmlSpatialModel:
58+
def _to_sbml_object(bio_model: Biomodel, application_name: str, round_trip_validation: bool) -> SbmlSpatialModel:
6759
"""
6860
Export an SBML Spatial model from an application within a VCell Biomodel.
6961
@@ -146,3 +138,153 @@ def field_data_refs(bio_model: Biomodel, simulation_name: str) -> set[tuple[str,
146138
field_data_refs.add((data_name.name, varname.name, VariableType.VOLUME, float(time)))
147139

148140
return field_data_refs
141+
142+
143+
def load_antimony_str(antimony_str: str) -> Biomodel:
144+
import antimony # type: ignore[import-untyped]
145+
146+
antimony_success = antimony.loadAntimonyString(antimony_str)
147+
if antimony_success != -1:
148+
sbml_str = antimony.getSBMLString()
149+
sbml_str = sbml_str.replace("sboTerm", "metaid")
150+
logging.info(f"Hack - introduced a metaid in place of sboTerm to SBML string:\n{sbml_str}")
151+
return load_sbml_str(sbml_str)
152+
else:
153+
raise ValueError("Error loading model:", antimony.getLastError())
154+
155+
156+
def load_antimony_file(antimony_file: PathLike[str] | str) -> Biomodel:
157+
import antimony # ignore
158+
159+
antimony_success = antimony.loadAntimonyFile(antimony_file)
160+
if antimony_success != -1:
161+
sbml_str = antimony.getSBMLString()
162+
return load_sbml_str(sbml_str)
163+
else:
164+
raise ValueError("Error loading model:", antimony.getLastError())
165+
166+
167+
def to_antimony_str(
168+
bio_model: Biomodel, application_name: str | None = None, round_trip_validation: bool = True
169+
) -> str:
170+
sbml_str = to_sbml_str(bio_model, application_name, round_trip_validation=round_trip_validation)
171+
import antimony
172+
173+
antimony_success = antimony.loadSBMLString(sbml_str)
174+
if antimony_success != -1:
175+
antimony_str = str(antimony.getAntimonyString())
176+
return antimony_str
177+
else:
178+
raise ValueError("Error converting SBML to Antimony:", antimony.getLastError())
179+
180+
181+
def write_antimony_file(bio_model: Biomodel, antimony_file: PathLike[str] | str) -> None:
182+
antimony_str = to_antimony_str(bio_model)
183+
with open(antimony_file, "w") as f:
184+
f.write(antimony_str)
185+
186+
187+
def load_vcml_str(vcml_str: str) -> Biomodel:
188+
return VcmlReader.biomodel_from_str(vcml_str)
189+
190+
191+
def load_vcml_file(vcml_file: PathLike[str] | str) -> Biomodel:
192+
return VcmlReader.biomodel_from_file(vcml_file)
193+
194+
195+
def to_vcml_str(bio_model: Biomodel, regenerate: bool = True) -> str:
196+
"""
197+
Convert a Biomodel object to a VCML string, after refreshing its content with a round trip to libvcell
198+
"""
199+
vcml_document = VCMLDocument(biomodel=bio_model)
200+
vcml_str: str = VcmlWriter().write_vcml(document=vcml_document)
201+
if not regenerate:
202+
return vcml_str
203+
204+
import libvcell
205+
206+
with tempfile.TemporaryDirectory() as tempdir:
207+
vcml_path = Path(tempdir) / "model.vcml"
208+
vc_success, vc_errmsg = libvcell.vcml_to_vcml(vcml_content=vcml_str, vcml_file_path=vcml_path)
209+
if not vc_success:
210+
raise ValueError("Error converting VCML to VCML:", vc_errmsg)
211+
with open(vcml_path) as f:
212+
vcml_str = f.read()
213+
return vcml_str
214+
215+
216+
def write_vcml_file(bio_model: Biomodel, vcml_file: PathLike[str] | str, regenerate: bool = True) -> None:
217+
with open(vcml_file, "w") as f:
218+
f.write(to_vcml_str(bio_model=bio_model, regenerate=regenerate))
219+
220+
221+
def load_sbml_str(sbml_str: str) -> Biomodel:
222+
import libvcell
223+
224+
with tempfile.TemporaryDirectory() as tempdir:
225+
vcml_path = Path(tempdir) / "model.vcml"
226+
vc_success, vc_errmsg = libvcell.sbml_to_vcml(sbml_content=sbml_str, vcml_file_path=vcml_path)
227+
if vc_success:
228+
return VcmlReader.biomodel_from_file(vcml_path=vcml_path)
229+
else:
230+
raise ValueError("Error loading model:", vc_errmsg)
231+
232+
233+
def load_sbml_file(sbml_file: PathLike[str] | str) -> Biomodel:
234+
import libvcell
235+
236+
with tempfile.TemporaryDirectory() as tempdir:
237+
with open(sbml_file) as f:
238+
sbml_str = f.read()
239+
vcml_path = Path(tempdir) / "model.vcml"
240+
vc_success, vc_errmsg = libvcell.sbml_to_vcml(sbml_content=sbml_str, vcml_file_path=vcml_path)
241+
if vc_success:
242+
return VcmlReader.biomodel_from_file(vcml_path=vcml_path)
243+
else:
244+
raise ValueError("Error loading model:", vc_errmsg)
245+
246+
247+
def to_sbml_str(bio_model: Biomodel, application_name: str | None = None, round_trip_validation: bool = True) -> str:
248+
import libvcell
249+
250+
if application_name is None:
251+
if len(bio_model.applications) == 0:
252+
raise ValueError("sbml export from biomodel needs a biomodel application")
253+
if len(bio_model.applications) > 1:
254+
raise ValueError("Application must have exactly one application")
255+
application_name = bio_model.applications[0].name
256+
elif application_name not in [app.name for app in bio_model.applications]:
257+
raise ValueError(f"Application '{application_name}' not found in biomodel")
258+
vcml_document = VCMLDocument(biomodel=bio_model)
259+
vcml_str: str = VcmlWriter().write_vcml(document=vcml_document)
260+
with tempfile.TemporaryDirectory() as tempdir:
261+
sbml_path = Path(tempdir) / "model.sbml"
262+
success, msg = libvcell.vcml_to_sbml(
263+
vcml_content=vcml_str,
264+
application_name=application_name,
265+
sbml_file_path=sbml_path,
266+
round_trip_validation=round_trip_validation,
267+
)
268+
if not success:
269+
raise ValueError("Error converting VCML to SBML:", msg)
270+
with open(sbml_path) as f:
271+
sbml_str = f.read()
272+
return sbml_str
273+
274+
275+
def write_sbml_file(
276+
bio_model: Biomodel,
277+
sbml_file: PathLike[str] | str,
278+
application_name: str | None = None,
279+
round_trip_validation: bool = True,
280+
) -> None:
281+
sbml_str = to_sbml_str(bio_model, application_name, round_trip_validation)
282+
with open(sbml_file, "w") as f:
283+
f.write(sbml_str)
284+
285+
286+
def refresh_biomodel(bio_model: Biomodel) -> Biomodel:
287+
with tempfile.TemporaryDirectory() as tempdir:
288+
vcml_path = Path(tempdir) / "model.vcml"
289+
write_vcml_file(bio_model=bio_model, vcml_file=vcml_path)
290+
return VcmlReader.biomodel_from_file(vcml_path=vcml_path)

0 commit comments

Comments
 (0)