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

Allow initial concentrations / sizes in condition table #238

Merged
merged 10 commits into from
Jan 22, 2020
6 changes: 3 additions & 3 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ attr-naming-style=snake_case

# Regular expression matching correct attribute names. Overrides attr-naming-
# style.
attr-rgx=^[a-z][a-z0-9]*((_[a-z0-9]+)*)?$
attr-rgx=^[a-z_][a-z0-9]*((_[a-z0-9]+)*)?$

# Bad variable names which should always be refused, separated by a comma.
bad-names=foo,
Expand Down Expand Up @@ -380,7 +380,7 @@ const-naming-style=UPPER_CASE

# Regular expression matching correct constant names. Overrides const-naming-
# style.
#const-rgx=
const-rgx=^[a-zA-Z][a-zA-Z0-9]*((_[a-zA-Z0-9]+)*)?$
dweindl marked this conversation as resolved.
Show resolved Hide resolved

# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
Expand Down Expand Up @@ -443,7 +443,7 @@ variable-naming-style=snake_case

# Regular expression matching correct variable names. Overrides variable-
# naming-style.
variable-rgx=^[a-z][a-z0-9]*((_[a-z0-9]+)*)?$
variable-rgx=^[a-z_][a-z0-9]*((_[a-z0-9]+)*)?$


[LOGGING]
Expand Down
65 changes: 44 additions & 21 deletions doc/documentation_data_format.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,36 +109,59 @@ Any parameters named `noiseParameter${1..n}` *must* be overwritten in the

## Condition table

The condition table specifies parameters or *constant* species for specific
simulation conditions (generally corresponding to different experimental
conditions).
The condition table specifies parameters, or initial values of species and
compartments for specific simulation conditions (generally corresponding to
different experimental conditions).

This is specified as tab-separated value file with condition-specific
species/parameters in the following way:
This is specified as a tab-separated value file in the following way:

| conditionId | [conditionName] | parameterOrStateId1 | ... | parameterOrStateId${n} |
| conditionId | [conditionName] | parameterOrStateOrCompartmentId1 | ... | parameterOrStateOrCompartmentId${n} |
|---|---|---|---|---|
| conditionId1 | conditionName1 | NUMERIC|parameterId | ...| ...
| conditionId1 | conditionName1 | NUMERIC|parameterId|stateId|compartmentId | ...| ...
| conditionId2 | ... | ... | ...| ...
|... | ... | ... | ... |...| ...

Row names are condition names as referenced in the measurement table below.
Column names are global parameter IDs or IDs of constant species as given in
the SBML model. These parameters will override any parameter values specified
in the model. `parameterOrStateId`s and `conditionId`s must be unique.
Row- and column-ordering are arbitrary, although specifying `conditionId`
first may improve human readability.

Values for condition parameters may be provided either as numeric values, or
as parameter IDs. In case parameter IDs are provided, they need to be defined
in the SBML model, the parameter table or both.
Additional columns are *not* allowed.

### Detailed field description

Row- and column-ordering are arbitrary, although specifying `parameterId`
first may improve human readability. The `conditionName` column is optional.
- `conditionId` [STRING, NOT NULL]

Additional columns are *not* allowed.
Unique identifier for the simulation/experimental condition, to be referenced
by the measurement table described below.

- `conditionName` [STRING, OPTIONAL]

Condition names are arbitrary strings to describe the given condition.
They may be used for reporting or visualization.

- `${parameterOrStateOrCompartmentId1}`

Further columns may be global parameter IDs, IDs of species or compartments
as defined in the SBML model. Only one column is allowed per ID.
Values for these condition parameters may be provided either as numeric
values, or as IDs defined in the SBML model, the parameter table or both.

- `${parameterId}`

The values will override any parameter values specified in the model.

- `${speciesId}`

If a species ID is provided, it is interpreted as the initial
concentration/amount of that species and will override the initial
concentration/amount given in the SBML model or given by a preequilibration
condition. If `NaN` is provided for a condition, the result of the
preequilibration (or initial concentration/amount from the SBML model, if
no preequilibration is defined) is used.

- `${compartmentId}`

*Note 1:* Instead of adding additional columns to the condition table, they
can easily be added to a separate file, since every row of the condition table
has `parameterId` as unique key.
If a compartment ID is provided, it is interpreted as the initial
compartment size.


## Measurement table
Expand Down Expand Up @@ -294,7 +317,7 @@ Additional columns may be added.

### Detailed field description:

- `parameterId` [STRING, NOT NULL, REFERENCES(sbml.parameterId)]
- `parameterId` [STRING, NOT NULL]

The `parameterId` of the parameter described in this row. This has be
identical to the parameter IDs specified in the SBML model or in the
Expand Down
1 change: 1 addition & 0 deletions petab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
from .sbml import * # noqa: F403, F401
from .yaml import * # noqa: F403, F401
from .version import __version__ # noqa: F401
from .format_version import __format_version__ # noqa: F401
10 changes: 6 additions & 4 deletions petab/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,13 @@ def check_condition_df(
if sbml_model is not None:
for column_name in df.columns:
if column_name != CONDITION_NAME \
and sbml_model.getParameter(column_name) is None:
and sbml_model.getParameter(column_name) is None \
and sbml_model.getSpecies(column_name) is None \
and sbml_model.getCompartment(column_name) is None:
raise AssertionError(
"Condition table contains column for unknown parameter"
f" {column_name}. Column names must match parameter Ids "
"defined in the SBML model.")
"Condition table contains column for unknown entity '"
f"{column_name}'. Column names must match parameter, "
"species or compartment IDs specified in the SBML model.")


def check_measurement_df(df: pd.DataFrame) -> None:
Expand Down
5 changes: 3 additions & 2 deletions petab/parameter_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import numpy as np
import pandas as pd

from . import lint, measurements, sbml
from . import lint, measurements, sbml, core
from . import ENV_NUM_THREADS
from .C import * # noqa: F403

Expand Down Expand Up @@ -299,7 +299,8 @@ def _apply_condition_parameters(mapping: ParMappingDict,
if overridee_id == CONDITION_NAME:
continue

mapping[overridee_id] = condition_df.loc[condition_id, overridee_id]
mapping[overridee_id] = core.to_float_if_float(
condition_df.loc[condition_id, overridee_id])


def _apply_parameter_table(mapping: ParMappingDict,
Expand Down
48 changes: 47 additions & 1 deletion tests/test_lint.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import os
import subprocess
from math import nan
from unittest.mock import patch

import libsbml
import pandas as pd
import petab
import pytest

import petab
from petab import (lint, sbml) # noqa: E402
from petab.C import *

# import fixtures
pytest_plugins = [
"tests.test_petab",
]


def test_assert_measured_observables_present_in_model():
Expand Down Expand Up @@ -294,3 +302,41 @@ def test_assert_measurement_conditions_present_in_condition_table():
with pytest.raises(AssertionError):
lint.assert_measurement_conditions_present_in_condition_table(
measurement_df=measurement_df, condition_df=condition_df)


def test_check_condition_df(minimal_sbml_model):
"""Check that we correctly detect errors in condition table"""

_, sbml_model = minimal_sbml_model

condition_df = pd.DataFrame(data={
CONDITION_ID: ['condition1'],
'p1': [nan],
})
condition_df.set_index(CONDITION_ID, inplace=True)

# parameter missing in model
with pytest.raises(AssertionError):
lint.check_condition_df(condition_df, sbml_model)

# fix:
sbml_model.createParameter().setId('p1')
lint.check_condition_df(condition_df, sbml_model)

# species missing in model
condition_df['s1'] = [3.0]
with pytest.raises(AssertionError):
lint.check_condition_df(condition_df, sbml_model)

# fix:
sbml_model.createSpecies().setId('s1')
lint.check_condition_df(condition_df, sbml_model)

# compartment missing in model
condition_df['c1'] = [4.0]
with pytest.raises(AssertionError):
lint.check_condition_df(condition_df, sbml_model)

# fix:
sbml_model.createCompartment().setId('c1')
lint.check_condition_df(condition_df, sbml_model)