@@ -481,7 +481,7 @@ def free_symbols(self) -> set[sp.Symbol]:
481481
482482class ExperimentPeriod (BaseModel ):
483483 """A period of a timecourse or experiment defined by a start time
484- and a condition ID .
484+ and a list of condition IDs .
485485
486486 This corresponds to a row of the PEtab experiments table.
487487 """
@@ -490,20 +490,19 @@ class ExperimentPeriod(BaseModel):
490490 time : Annotated [float , AfterValidator (_is_finite_or_neg_inf )] = Field (
491491 alias = C .TIME
492492 )
493- #: The ID of the condition to be applied at the start time.
494- condition_id : str | None = Field (alias = C . CONDITION_ID , default = None )
493+ #: The IDs of the conditions to be applied at the start time.
494+ condition_ids : list [ str ] = Field (default_factory = list )
495495
496496 #: :meta private:
497497 model_config = ConfigDict (populate_by_name = True , extra = "allow" )
498498
499- @field_validator ("condition_id " , mode = "before" )
499+ @field_validator ("condition_ids " , mode = "before" )
500500 @classmethod
501- def _validate_id (cls , condition_id ):
502- if pd .isna (condition_id ) or not condition_id :
503- return None
504- if not is_valid_identifier (condition_id ):
505- raise ValueError (f"Invalid ID: { condition_id } " )
506- return condition_id
501+ def _validate_ids (cls , condition_ids ):
502+ for condition_id in condition_ids :
503+ if not is_valid_identifier (condition_id ):
504+ raise ValueError (f"Invalid ID: { condition_id } " )
505+ return condition_ids
507506
508507
509508class Experiment (BaseModel ):
@@ -554,12 +553,20 @@ def from_df(cls, df: pd.DataFrame) -> ExperimentTable:
554553
555554 experiments = []
556555 for experiment_id , cur_exp_df in df .groupby (C .EXPERIMENT_ID ):
557- periods = [
558- ExperimentPeriod (
559- time = row [C .TIME ], condition_id = row [C .CONDITION_ID ]
556+ periods = []
557+ for timepoint in cur_exp_df [C .TIME ].unique ():
558+ condition_ids = [
559+ cid
560+ for cid in cur_exp_df .loc [
561+ cur_exp_df [C .TIME ] == timepoint , C .CONDITION_ID
562+ ]
563+ if not pd .isna (cid )
564+ ]
565+ periods .append (
566+ ExperimentPeriod (
567+ time = timepoint , condition_ids = condition_ids
568+ )
560569 )
561- for _ , row in cur_exp_df .iterrows ()
562- ]
563570 experiments .append (Experiment (id = experiment_id , periods = periods ))
564571
565572 return cls (experiments = experiments )
@@ -569,10 +576,12 @@ def to_df(self) -> pd.DataFrame:
569576 records = [
570577 {
571578 C .EXPERIMENT_ID : experiment .id ,
572- ** period .model_dump (by_alias = True ),
579+ C .TIME : period .time ,
580+ C .CONDITION_ID : condition_id ,
573581 }
574582 for experiment in self .experiments
575583 for period in experiment .periods
584+ for condition_id in period .condition_ids or ["" ]
576585 ]
577586 return (
578587 pd .DataFrame (records )
0 commit comments