Skip to content

Commit e6db0d1

Browse files
committed
no conditionName, no operationType
1 parent e5e1097 commit e6db0d1

File tree

7 files changed

+59
-98
lines changed

7 files changed

+59
-98
lines changed

petab/v2/C.py

-14
Original file line numberDiff line numberDiff line change
@@ -125,28 +125,14 @@
125125

126126
#: Condition ID column in the condition table
127127
CONDITION_ID = "conditionId"
128-
# TODO: removed?
129-
#: Condition name column in the condition table
130-
CONDITION_NAME = "conditionName"
131128
#: Column in the condition table with the ID of an entity that is changed
132129
TARGET_ID = "targetId"
133-
#: Column in the condition table with the operation type
134-
OPERATION_TYPE = "operationType"
135130
#: Column in the condition table with the new value of the target entity
136131
TARGET_VALUE = "targetValue"
137-
# operation types:
138-
OT_CUR_VAL = "setCurrentValue"
139-
OT_NO_CHANGE = "noChange"
140-
141-
OPERATION_TYPES = [
142-
OT_CUR_VAL,
143-
OT_NO_CHANGE,
144-
]
145132

146133
CONDITION_DF_COLS = [
147134
CONDITION_ID,
148135
TARGET_ID,
149-
OPERATION_TYPE,
150136
TARGET_VALUE,
151137
]
152138

petab/v2/core.py

+13-27
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
"Change",
3030
"Condition",
3131
"ConditionsTable",
32-
"OperationType",
3332
"ExperimentPeriod",
3433
"Experiment",
3534
"ExperimentsTable",
@@ -248,16 +247,6 @@ def __iadd__(self, other: Observable) -> ObservablesTable:
248247
return self
249248

250249

251-
# TODO remove?!
252-
class OperationType(str, Enum):
253-
"""Operation types for model changes in the PEtab conditions table."""
254-
255-
# TODO update names
256-
SET_CURRENT_VALUE = "setCurrentValue"
257-
NO_CHANGE = "noChange"
258-
...
259-
260-
261250
class Change(BaseModel):
262251
"""A change to the model or model state.
263252
@@ -266,17 +255,13 @@ class Change(BaseModel):
266255
267256
>>> Change(
268257
... target_id="k1",
269-
... operation_type=OperationType.SET_CURRENT_VALUE,
270258
... target_value="10",
271259
... ) # doctest: +NORMALIZE_WHITESPACE
272-
Change(target_id='k1', operation_type='setCurrentValue',
273-
target_value=10.0000000000000)
260+
Change(target_id='k1', target_value=10.0000000000000)
274261
"""
275262

276263
#: The ID of the target entity to change.
277264
target_id: str | None = Field(alias=C.TARGET_ID, default=None)
278-
# TODO: remove?!
279-
operation_type: OperationType = Field(alias=C.OPERATION_TYPE)
280265
#: The value to set the target entity to.
281266
target_value: sp.Basic | None = Field(alias=C.TARGET_VALUE, default=None)
282267

@@ -290,14 +275,11 @@ class Change(BaseModel):
290275
@model_validator(mode="before")
291276
@classmethod
292277
def _validate_id(cls, data: dict):
293-
if (
294-
data.get("operation_type", data.get(C.OPERATION_TYPE))
295-
!= C.OT_NO_CHANGE
296-
):
297-
target_id = data.get("target_id", data.get(C.TARGET_ID))
298-
299-
if not is_valid_identifier(target_id):
300-
raise ValueError(f"Invalid ID: {target_id}")
278+
target_id = data.get("target_id", data.get(C.TARGET_ID))
279+
280+
if not is_valid_identifier(target_id):
281+
raise ValueError(f"Invalid ID: {target_id}")
282+
301283
return data
302284

303285
@field_validator("target_value", mode="before")
@@ -323,13 +305,12 @@ class Condition(BaseModel):
323305
... changes=[
324306
... Change(
325307
... target_id="k1",
326-
... operation_type=OperationType.SET_CURRENT_VALUE,
327308
... target_value="10",
328309
... )
329310
... ],
330311
... ) # doctest: +NORMALIZE_WHITESPACE
331-
Condition(id='condition1', changes=[Change(target_id='k1',
332-
operation_type='setCurrentValue', target_value=10.0000000000000)])
312+
Condition(id='condition1',
313+
changes=[Change(target_id='k1', target_value=10.0000000000000)])
333314
"""
334315

335316
#: The condition ID.
@@ -633,12 +614,17 @@ def _validate_id(cls, v, info: ValidationInfo):
633614
)
634615
@classmethod
635616
def _sympify_list(cls, v):
617+
if v is None:
618+
return []
619+
636620
if isinstance(v, float) and np.isnan(v):
637621
return []
622+
638623
if isinstance(v, str):
639624
v = v.split(C.PARAMETER_SEPARATOR)
640625
else:
641626
v = [v]
627+
642628
return [sympify_petab(x) for x in v]
643629

644630

petab/v2/lint.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ def get_valid_parameters_for_parameter_table(
672672
blackset |= placeholders
673673

674674
if condition_df is not None:
675-
blackset |= set(condition_df.columns.values) - {CONDITION_NAME}
675+
blackset |= set(condition_df.columns.values)
676676

677677
# don't use sets here, to have deterministic ordering,
678678
# e.g. for creating parameter tables

petab/v2/petab1to2.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,9 @@ def create_experiment_id(sim_cond_id: str, preeq_cond_id: str) -> str:
226226
validation_issues = v2.lint_problem(new_yaml_file)
227227

228228
if validation_issues:
229+
validation_issues = "\n".join(map(str, validation_issues))
229230
raise ValueError(
230-
"Generated PEtab v2 problem did not pass linting: "
231+
"The generated PEtab v2 problem did not pass linting: "
231232
f"{validation_issues}"
232233
)
233234

@@ -287,7 +288,7 @@ def v1v2_condition_df(
287288
condition_df = condition_df.copy().reset_index()
288289
with suppress(KeyError):
289290
# conditionName was dropped in PEtab v2
290-
condition_df.drop(columns=[v2.C.CONDITION_NAME], inplace=True)
291+
condition_df.drop(columns=[v1.C.CONDITION_NAME], inplace=True)
291292

292293
condition_df = condition_df.melt(
293294
id_vars=[v1.C.CONDITION_ID],
@@ -301,7 +302,6 @@ def v1v2_condition_df(
301302
columns=[
302303
v2.C.CONDITION_ID,
303304
v2.C.TARGET_ID,
304-
v2.C.OPERATION_TYPE,
305305
v2.C.TARGET_VALUE,
306306
]
307307
)
@@ -320,5 +320,4 @@ def v1v2_condition_df(
320320
f"Unable to determine value type {target} in the condition "
321321
"table."
322322
)
323-
condition_df[v2.C.OPERATION_TYPE] = v2.C.OT_CUR_VAL
324323
return condition_df

petab/v2/problem.py

+34-42
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from typing import TYPE_CHECKING
1414

1515
import pandas as pd
16+
import sympy as sp
1617
from pydantic import AnyUrl, BaseModel, Field
1718

1819
from ..v1 import (
@@ -883,7 +884,7 @@ def validate(
883884
return validation_results
884885

885886
def add_condition(
886-
self, id_: str, name: str = None, **kwargs: tuple[str, Number | str]
887+
self, id_: str, name: str = None, **kwargs: Number | str | sp.Expr
887888
):
888889
"""Add a simulation condition to the problem.
889890
@@ -895,27 +896,20 @@ def add_condition(
895896
"""
896897
if not kwargs:
897898
return
898-
records = [
899-
{
900-
CONDITION_ID: id_,
901-
TARGET_ID: target_id,
902-
OPERATION_TYPE: "setCurrentValue",
903-
TARGET_VALUE: target_value
904-
if not isinstance(target_value, tuple)
905-
else target_value[1],
906-
}
899+
changes = [
900+
core.Change(target_id=target_id, target_value=target_value)
907901
for target_id, target_value in kwargs.items()
908902
]
909-
# TODO: is the condition name supported in v2?
910-
if name is not None:
911-
for record in records:
912-
record[CONDITION_NAME] = [name]
913-
tmp_df = pd.DataFrame(records)
914-
self.condition_df = (
915-
pd.concat([self.condition_df, tmp_df], ignore_index=True)
916-
if self.condition_df is not None
917-
else tmp_df
903+
self.conditions_table.conditions.append(
904+
core.Condition(id=id_, changes=changes)
918905
)
906+
if name is not None:
907+
self.mapping_table.mappings.append(
908+
core.Mapping(
909+
petab_id=id_,
910+
model_id=name,
911+
)
912+
)
919913

920914
def add_observable(
921915
self,
@@ -1023,8 +1017,8 @@ def add_measurement(
10231017
experiment_id: str,
10241018
time: float,
10251019
measurement: float,
1026-
observable_parameters: Sequence[str | float] = None,
1027-
noise_parameters: Sequence[str | float] = None,
1020+
observable_parameters: Sequence[str | float] | str | float = None,
1021+
noise_parameters: Sequence[str | float] | str | float = None,
10281022
):
10291023
"""Add a measurement to the problem.
10301024
@@ -1036,27 +1030,25 @@ def add_measurement(
10361030
observable_parameters: The observable parameters
10371031
noise_parameters: The noise parameters
10381032
"""
1039-
record = {
1040-
OBSERVABLE_ID: [obs_id],
1041-
EXPERIMENT_ID: [experiment_id],
1042-
TIME: [time],
1043-
MEASUREMENT: [measurement],
1044-
}
1045-
if observable_parameters is not None:
1046-
record[OBSERVABLE_PARAMETERS] = [
1047-
PARAMETER_SEPARATOR.join(map(str, observable_parameters))
1048-
]
1049-
if noise_parameters is not None:
1050-
record[NOISE_PARAMETERS] = [
1051-
PARAMETER_SEPARATOR.join(map(str, noise_parameters))
1052-
]
1053-
1054-
tmp_df = pd.DataFrame(record)
1055-
self.measurement_df = (
1056-
pd.concat([self.measurement_df, tmp_df])
1057-
if self.measurement_df is not None
1058-
else tmp_df
1059-
).reset_index(drop=True)
1033+
if observable_parameters is not None and not isinstance(
1034+
observable_parameters, Sequence
1035+
):
1036+
observable_parameters = [observable_parameters]
1037+
if noise_parameters is not None and not isinstance(
1038+
noise_parameters, Sequence
1039+
):
1040+
noise_parameters = [noise_parameters]
1041+
1042+
self.measurement_table.measurements.append(
1043+
core.Measurement(
1044+
observable_id=obs_id,
1045+
experiment_id=experiment_id,
1046+
time=time,
1047+
measurement=measurement,
1048+
observable_parameters=observable_parameters,
1049+
noise_parameters=noise_parameters,
1050+
)
1051+
)
10601052

10611053
def add_mapping(self, petab_id: str, model_id: str):
10621054
"""Add a mapping table entry to the problem.

tests/v2/test_core.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import tempfile
22
from pathlib import Path
33

4+
import sympy as sp
5+
46
from petab.v2.core import (
57
Change,
68
Condition,
79
ConditionsTable,
810
Experiment,
911
ExperimentPeriod,
1012
ObservablesTable,
11-
OperationType,
1213
)
1314
from petab.v2.petab1to2 import petab1to2
1415

@@ -55,17 +56,17 @@ def test_experiment_add_periods():
5556
assert exp.periods == [p1, p2]
5657

5758

58-
def test_conditions_table_add_changeset():
59+
def test_conditions_table_add_changes():
5960
conditions_table = ConditionsTable()
6061
assert conditions_table.conditions == []
6162

6263
c1 = Condition(
6364
id="condition1",
64-
changes=[Change(operation_type=OperationType.NO_CHANGE)],
65+
changes=[Change(target_id="k1", target_value=1)],
6566
)
6667
c2 = Condition(
6768
id="condition2",
68-
changes=[Change(operation_type=OperationType.NO_CHANGE)],
69+
changes=[Change(target_id="k2", target_value=sp.sympify("2 * x"))],
6970
)
7071

7172
conditions_table += c1

tests/v2/test_problem.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
NOMINAL_VALUE,
1717
OBSERVABLE_FORMULA,
1818
OBSERVABLE_ID,
19-
OPERATION_TYPE,
20-
OT_CUR_VAL,
2119
PARAMETER_ID,
2220
PETAB_ENTITY_ID,
2321
TARGET_ID,
@@ -73,7 +71,7 @@ def test_problem_from_yaml_multiple_files():
7371

7472
for i in (1, 2):
7573
problem = Problem()
76-
problem.add_condition(f"condition{i}", parameter1=(OT_CUR_VAL, i))
74+
problem.add_condition(f"condition{i}", parameter1=i)
7775
petab.write_condition_df(
7876
problem.condition_df, Path(tmpdir, f"conditions{i}.tsv")
7977
)
@@ -109,14 +107,13 @@ def test_problem_from_yaml_multiple_files():
109107
def test_modify_problem():
110108
"""Test modifying a problem via the API."""
111109
problem = Problem()
112-
problem.add_condition("condition1", parameter1=(OT_CUR_VAL, 1))
113-
problem.add_condition("condition2", parameter2=(OT_CUR_VAL, 2))
110+
problem.add_condition("condition1", parameter1=1)
111+
problem.add_condition("condition2", parameter2=2)
114112

115113
exp_condition_df = pd.DataFrame(
116114
data={
117115
CONDITION_ID: ["condition1", "condition2"],
118116
TARGET_ID: ["parameter1", "parameter2"],
119-
OPERATION_TYPE: [OT_CUR_VAL, OT_CUR_VAL],
120117
TARGET_VALUE: [1.0, 2.0],
121118
}
122119
)

0 commit comments

Comments
 (0)