Skip to content

Commit 85611cb

Browse files
committed
Improve temperature conversion and measurement handling
Refactored temperature conversion to Kelvin in measurements to handle cases where temperature unit is None and preserve unit properties. Updated measurement annotation to set default values for time_unit and ph, and improved handling of missing time_unit in species data.
1 parent 7f03e3b commit 85611cb

2 files changed

Lines changed: 40 additions & 49 deletions

File tree

pyenzyme/sbml/serializer.py

Lines changed: 37 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
from copy import deepcopy
4-
import xml.etree.ElementTree as ET
54
from pathlib import Path
65
from typing import Callable, List
76

@@ -74,6 +73,9 @@ def to_sbml(
7473
sbmldoc.setNamespaces(ns)
7574
sbmldoc.setPackageRequired("enzymeml", True)
7675

76+
for measurement in doc.measurements:
77+
_convert_temperature_to_kelvin(measurement)
78+
7779
model = sbmldoc.createModel()
7880
model.setName(doc.name)
7981
units = _assign_ids_to_units(tools.find_unique(doc, pe.UnitDefinition))
@@ -456,10 +458,6 @@ def _add_measurements(measurements: list[pe.Measurement]):
456458

457459
for measurement in measurements:
458460
measurement = deepcopy(measurement)
459-
460-
time_unit = _get_unit_id(measurement.species_data[0].time_unit)
461-
_convert_temperature_to_kelvin(measurement)
462-
463461
conditions = v2.ConditionsAnnot(
464462
ph=v2.PHAnnot(
465463
value=measurement.ph,
@@ -470,6 +468,11 @@ def _add_measurements(measurements: list[pe.Measurement]):
470468
),
471469
)
472470

471+
if len(measurement.species_data) > 0:
472+
time_unit = _get_unit_id(measurement.species_data[0].time_unit)
473+
else:
474+
time_unit = None
475+
473476
meas_annot = v2.MeasurementAnnot(
474477
id=measurement.id,
475478
time_unit=time_unit,
@@ -506,55 +509,43 @@ def _convert_temperature_to_kelvin(measurement: pe.Measurement) -> None:
506509
measurement (pe.Measurement): The measurement object to potentially convert.
507510
Modified in place if conversion is needed.
508511
"""
512+
if measurement.temperature_unit is None:
513+
return
514+
509515
temp_unit = measurement.temperature_unit
510516

511-
if temp_unit and any(
512-
unit.kind == pe.UnitType.CELSIUS for unit in temp_unit.base_units
513-
):
514-
# Find the base unit that is celsius and convert to kelvin
515-
temp_unit = next(
516-
unit for unit in temp_unit.base_units if unit.kind == pe.UnitType.CELSIUS
517+
# Extract the base unit with Celsius
518+
celsius_unit = next(
519+
(unit for unit in temp_unit.base_units if unit.kind == pe.UnitType.CELSIUS),
520+
None,
521+
)
522+
523+
if celsius_unit and measurement.temperature is not None:
524+
# Store the properties of the Celsius unit before replacing
525+
celsius_exponent = celsius_unit.exponent
526+
celsius_scale = celsius_unit.scale
527+
celsius_multiplier = celsius_unit.multiplier
528+
529+
# Remove the Celsius unit from base_units
530+
measurement.temperature_unit.base_units.remove(celsius_unit)
531+
measurement.temperature_unit.name = "Kelvin"
532+
533+
# Add a new Kelvin unit with the same properties
534+
measurement.temperature_unit.add_to_base_units(
535+
kind=pe.UnitType.KELVIN,
536+
exponent=celsius_exponent,
537+
scale=celsius_scale,
538+
multiplier=celsius_multiplier,
517539
)
518-
convert_to_kelvin = True
519-
else:
520-
convert_to_kelvin = False
521540

522-
if convert_to_kelvin and measurement.temperature:
523541
logger.warning(
524542
f"Converting measurement ({measurement.id}) temperature from Celsius to Kelvin. This is not supported by SBML."
525543
)
526-
measurement.temperature = measurement.temperature + CELSIUS_CONVERSION_FACTOR
527544

528-
529-
def _create_condition_element(
530-
ph: float | None,
531-
temperature: float | None,
532-
temperature_unit: UnitDefinition | None,
533-
):
534-
"""
535-
Set the conditions of the reaction in the SBML model.
536-
537-
Args:
538-
ph (float | None): The pH value.
539-
temperature (float | None): The temperature value.
540-
temperature_unit (UnitDefinition | None): The unit of the temperature.
541-
542-
Returns:
543-
ET.Element: The XML element representing the conditions.
544-
"""
545-
element = ET.Element(f"{{{NSMAP['enzymeml']}}}conditions")
546-
mappings = {
547-
"ph": {"@value": ph},
548-
"temperature": {"@value": temperature, "@unit": temperature_unit},
549-
}
550-
551-
_xml.map_to_xml(
552-
root=element,
553-
mappings=mappings,
554-
namespace=NSMAP["enzymeml"],
555-
)
556-
557-
return element
545+
if measurement.temperature is not None:
546+
measurement.temperature = (
547+
measurement.temperature + CELSIUS_CONVERSION_FACTOR
548+
)
558549

559550

560551
def _get_sbml_kind(unit_type):

pyenzyme/sbml/versions/v2.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ class MeasurementAnnot(
266266

267267
id: str = attr(name="id")
268268
name: str | None = attr(name="name", default=None)
269-
time_unit: str | None = attr(name="timeUnit")
269+
time_unit: str | None = attr(name="timeUnit", default=None)
270270
conditions: ConditionsAnnot | None = element(tag="conditions", default=None)
271271
species_data: list[SpeciesDataAnnot] = element(
272272
tag="speciesData",
@@ -374,7 +374,7 @@ def _map_species_data(
374374
time=time,
375375
species_id=species.species_id,
376376
data_unit=_get_unit(species.unit, units), # type: ignore
377-
time_unit=_get_unit(self.time_unit, units), # type: ignore
377+
time_unit=_get_unit(self.time_unit, units) if self.time_unit else None, # type: ignore
378378
initial=species.initial,
379379
data_type=self._map_data_type(species.type), # type: ignore
380380
)
@@ -441,7 +441,7 @@ class ConditionsAnnot(
441441
temperature (TemperatureAnnot | None): The temperature conditions.
442442
"""
443443

444-
ph: PHAnnot | None = element(tag="ph")
444+
ph: PHAnnot | None = element(tag="ph", default=None)
445445
temperature: TemperatureAnnot | None = element(tag="temperature", default=None)
446446

447447
@field_validator("ph")

0 commit comments

Comments
 (0)