Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timecourse export #9

Open
wants to merge 7 commits into
base: oop_periods
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/examples/amici_periods_vs_events/simulate_as_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
# Setup timecourse, add it to the PEtab problem
timecourse_df = petab_timecourse.get_timecourse_df(petab_path / 'timecourse.tsv')
petab_problem.timecourse_df = timecourse_df
timecourse = petab_timecourse.Timecourse.from_df(timecourse_df, timecourse_id)
timecourse = petab_timecourse.Timecourse.from_df(timecourse_df, timecourse_id, petab_problem.condition_df)

# Setup AMICI
solver_settings = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
# Setup timecourse, add it to the PEtab problem
timecourse_df = petab_timecourse.get_timecourse_df(petab_path / 'timecourse.tsv')
petab_problem.timecourse_df = timecourse_df
timecourse = petab_timecourse.Timecourse.from_df(timecourse_df, timecourse_id)
timecourse = petab_timecourse.Timecourse.from_df(timecourse_df, timecourse_id, petab_problem.condition_df)

# Setup AMICI
solver_settings = {
Expand Down
12 changes: 9 additions & 3 deletions petab_timecourse/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, TextIO, Tuple, Union

#import amici
# import amici
import numpy as np
import pandas as pd
import petab
Expand Down Expand Up @@ -41,7 +41,7 @@ class Problem(petab.Problem):
def from_yaml(*args, **kwargs):
problem = petab.Problem.from_yaml(*args, **kwargs)

timecourse_files = problem.extensions_config['timecourse']['timecourse_files']
timecourse_files = problem.extensions_config["timecourse"]["timecourse_files"]
if len(timecourse_files) > 1:
raise ValueError("multiple timecourse files are not yet supported.")
if len(timecourse_files) < 1:
Expand All @@ -54,6 +54,7 @@ def from_yaml(*args, **kwargs):

# TODO remove when integrated into main PEtab library
from functools import partial

problem.get_timecourse = partial(get_timecourse, self=problem)
return problem

Expand All @@ -62,8 +63,10 @@ def get_timecourse(self, timecourse_id: str) -> Timecourse:
return Timecourse.from_df(
timecourse_df=self.timecourse_df,
timecourse_id=timecourse_id,
condition_df=self.condition_df,
)


def to_single_petab_with_events(problem: Problem):
# create an SBML that encodes all timecourses
# as events.
Expand All @@ -72,17 +75,20 @@ def to_single_petab_with_events(problem: Problem):
# timecourse when simulating the single SBML
pass


def to_multiple_petab(problem: Problem):
# one PEtab per unique period, and the order in which to
# simulate each PEtab, for each timecourse
# each PEtab already contains the fixed parameters
# of that period
pass


def to_single_petab(problem: Problem):
#
#
pass


def get_models(problem: petab.Problem):
models = {}
for timecourse_id in problem.timecourse_df.index:
Expand Down
1 change: 1 addition & 0 deletions petab_timecourse/sbml.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def add_timecourse_as_events(
timecourse = Timecourse.from_df(
timecourse_df=petab_problem.timecourse_df,
timecourse_id=timecourse_id,
condition_df=petab_problem.condition_df,
)
#timecourse = parse_timecourse_string(
# petab_problem.timecourse_df.loc[timecourse_id][TIMECOURSE],
Expand Down
1 change: 1 addition & 0 deletions petab_timecourse/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def __init__(
self.timecourse = Timecourse.from_df(
timecourse_df=petab_problem.timecourse_df,
timecourse_id=timecourse_id,
condition_df=petab_problem.condition_df,
)

# FIXME t0 should not be 0 for preeq/presim
Expand Down
66 changes: 38 additions & 28 deletions petab_timecourse/timecourse.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class Period:
The PEtab problem for this time period.
e.g.: only contains measurements within the period start and end.
"""

def __init__(
self,
duration: TYPE_TIME,
Expand Down Expand Up @@ -84,14 +85,15 @@ def get_condition(self, petab_problem: petab.Problem) -> pd.Series:
def get_measurements(
self,
petab_problem: petab.Problem,
t0: float,
t0: Union[int, float],
t_end: Union[int, float],
include_end: bool = False,
) -> pd.Series:
after_start = petab_problem.measurement_df[TIME] >= t0
before_end = (
petab_problem.measurement_df[TIME] <= t0
if include_end else
petab_problem.measurement_df[TIME] < t0
petab_problem.measurement_df[TIME] <= t_end
if include_end
else petab_problem.measurement_df[TIME] < t_end
)
return petab_problem.measurement_df.loc[after_start & before_end]

Expand All @@ -113,6 +115,7 @@ class Timecourse:
periods:
The periods of the timecourse.
"""

def __init__(
self,
timecourse_id: str,
Expand All @@ -138,11 +141,11 @@ def condition_ids(self):

@staticmethod
def from_timecourses(
timecourses: Sequence['Timecourse'],
timecourses: Sequence["Timecourse"],
durations: Sequence[float],
*args,
**kwargs,
) -> 'Timecourse':
) -> "Timecourse":
"""Create a timecourse from a sequence of timecourses.

Args:
Expand All @@ -157,8 +160,8 @@ def from_timecourses(
"""
if len(durations) != len(timecourses) - 1:
raise ValueError(
'Please specify one fewer durations than timecourses. The '
'duration of the final timecourse will be unlimited.'
"Please specify one fewer durations than timecourses. The "
"duration of the final timecourse will be unlimited."
)

periods = []
Expand Down Expand Up @@ -217,19 +220,18 @@ def to_df(self):
)
data[TIMECOURSE] = timecourse_str

return get_timecourse_df(
pd.DataFrame(data=data)
)
return get_timecourse_df(pd.DataFrame(data=data))

@staticmethod
def from_df_row(row: pd.Series) -> 'Timecourse':
def from_df_row(row: pd.Series, condition_df: pd.DataFrame) -> "Timecourse":
periods = []
period_sequence = [
time__condition_id.split(TIME_CONDITION_DELIMITER)
for time__condition_id in row.get(TIMECOURSE).split(PERIOD_DELIMITER)
]
t0 = None
for period_index, (start, condition_id) in enumerate(period_sequence):
# calculate duration
if t0 is None:
try:
t0 = float(start)
Expand All @@ -240,20 +242,21 @@ def from_df_row(row: pd.Series) -> 'Timecourse':
# End the period early if another period comes afterwards
if period_index < len(period_sequence) - 1:
end = period_sequence[period_index + 1][0]

try:
start = float(start)
end = float(end)
except ValueError:
raise ValueError(
'Parameterized timepoints are not yet supported. '
'Please request.'
"Parameterized timepoints are not yet supported. " "Please request."
)
# get parameters
parameters = condition_df.loc[condition_id].to_dict()

periods.append(
Period(
duration=end-start,
duration=end - start,
condition_id=condition_id,
parameters=parameters,
)
)

Expand All @@ -268,29 +271,37 @@ def from_df_row(row: pd.Series) -> 'Timecourse':
def from_df(
timecourse_df: pd.DataFrame,
timecourse_id: str,
) -> 'Timecourse':
return Timecourse.from_df_row(timecourse_df.loc[timecourse_id])
condition_df: pd.DataFrame,
) -> "Timecourse":
return Timecourse.from_df_row(timecourse_df.loc[timecourse_id], condition_df)

def __len__(self):
return len(self.periods)

def export_to_amici(self) -> Tuple[Tuple[float, Dict[str, float]]]:
"""
Returns:
One tuple per period, with period duration and condition parameters.
"""
durations = [p.duration for p in self.periods]
parameters = [p.parameters for p in self.periods]
return tuple(zip(durations, parameters))


def get_timecourse_df(
timecourse_file: Union[str, pd.DataFrame, None]
) -> pd.DataFrame:
"""Read the provided condition file into a ``pandas.Dataframe``
Conditions are rows, parameters are columns, conditionId is index.
def get_timecourse_df(timecourse_file: Union[str, pd.DataFrame, None]) -> pd.DataFrame:
"""Read the provided timecourse file into a ``pandas.Dataframe``
Timecourses are rows, periods are columns, timecourseId is index.
Arguments:
condition_file: File name of PEtab condition file or pandas.Dataframe
timecourse_file: File name of PEtab timecourse file or pandas.Dataframe
"""
if timecourse_file is None:
return timecourse_file

if isinstance(timecourse_file, (str, Path)):
timecourse_file = pd.read_csv(
timecourse_file,
sep='\t',
float_precision='round_trip',
sep="\t",
float_precision="round_trip",
)

petab.lint.assert_no_leading_trailing_whitespace(
Expand All @@ -303,7 +314,6 @@ def get_timecourse_df(
try:
timecourse_file.set_index([TIMECOURSE_ID], inplace=True)
except KeyError:
raise KeyError(
f'Timecourse table missing mandatory field {TIMECOURSE_ID}.')
raise KeyError(f"Timecourse table missing mandatory field {TIMECOURSE_ID}.")

return timecourse_file