PEtab Select FAMOS

In this notebook we’ll run the model selection example from PEtab Select: specification standard and supporting software for automated model selection by Pathirana et. al with basico. This assumes you installed basico with optional PEtab support using

pip install copasi-basico[petab]

We begin by downloading the model:

[1]:
import os

if not os.path.exists('famos'):
    !wget -q https://github.com/copasi/basico/raw/a4ebfa0575b3a0c569ea7274bed71657207c883e/tests/famos.zip
    !unzip -qq -o famos.zip
    !rm -f famos.zip

now import basico and petab_select to evaluate the problem. The evaluate_problem function will calibrate all models suggested by petab_select returning the best overall found model.

[2]:
from petab_select import Problem
from basico.petab import evaluate_problem
import basico

the main parameter to tweak is the evaluation function, that one defines what optimization methods should be run on each suggested model. The default evaluation will run a couple of steps of a global optimization method, followed by some steps of a local optimizer. That is of coure rather arbitrary and will not yield the best results in many cases. So lets define an evaluation function here just to see how it is done:

[3]:
def eval_fun():
    """Evaluation function for currently loaded model

    This function does take the currently loaded model `get_current_model()` and
    perform parameter estimation on it.

    It is supposed to return the solution as returned by `run_parameter_estimation`.

    :return: Solution of parameter estimation
    :rtype: pandas.DataFrame
    """

    # run genetic algorithm, important that update_model=True to ensure
    # that the following parameter estimation is based on the result of the genetic algorithm
    basico.run_parameter_estimation(method=basico.PE.GENETIC_ALGORITHM_SR, update_model=True,
                                    settings={'method': {
                                        'Number of Generations': 50,
                                        'Population Size': 10,
                                        'Stop after # Stalled Generations': 30
                                        }})
    # refine the result with a local optimization method
    sol = basico.run_parameter_estimation(method=basico.PE.NL2SOL, update_model=True,
                                            settings={'method': {
                                                'Iteration Limit': 2000,
                                            }}
                                          )

    return sol

that being done, lets load the petab select problem and evaluate it, depending on the function chosen above, this might take a while. A parallel version is in the works for later

[ ]:
problem = Problem.from_yaml('./famos/petab_select_problem.yaml')
best = evaluate_problem(problem, evaluation=eval_fun, temp_dir='./tmp_selection', delete_temp_files=False)

so lets see what we got, for this we define a print function:

[5]:
def print_model(model) -> None:
    """Helper method to view model attributes."""
    print(
        f"""\
Model subspace ID: {model.model_subspace_id}
PEtab YAML location: {model.model_subspace_petab_yaml}
Custom model parameters: {model.parameters}
Model hash: {model.hash}
Model ID: {model.model_id}
{problem.criterion}: {model.get_criterion(problem.criterion, compute=False)}
Model was calibrated in iteration: {model.iteration}
"""
    )

print_model(best)
Model subspace ID: M
PEtab YAML location: famos\petab\petab_problem.yaml
Custom model parameters: {'a_0ac_k05': 1, 'a_0ac_k08': 'estimate', 'a_0ac_k12': 1, 'a_0ac_k16': 1, 'a_k05_k05k08': 1, 'a_k05_k05k12': 'estimate', 'a_k05_k05k16': 1, 'a_k08_k05k08': 1, 'a_k08_k08k12': 1, 'a_k08_k08k16': 1, 'a_k12_k05k12': 'estimate', 'a_k12_k08k12': 1, 'a_k12_k12k16': 1, 'a_k16_k05k16': 1, 'a_k16_k08k16': 1, 'a_k16_k12k16': 'estimate', 'a_k05k08_k05k08k12': 1, 'a_k05k08_k05k08k16': 1, 'a_k05k12_k05k08k12': 'estimate', 'a_k05k12_k05k12k16': 1, 'a_k05k16_k05k08k16': 1, 'a_k05k16_k05k12k16': 1, 'a_k08k12_k05k08k12': 1, 'a_k08k12_k08k12k16': 1, 'a_k08k16_k05k08k16': 1, 'a_k08k16_k08k12k16': 1, 'a_k12k16_k05k12k16': 1, 'a_k12k16_k08k12k16': 'estimate', 'a_k05k08k12_4ac': 1, 'a_k05k08k16_4ac': 1, 'a_k05k12k16_4ac': 1, 'a_k08k12k16_4ac': 'estimate'}
Model hash: M-01000100001000010010000000010001
Model ID: M-01000100001000010010000000010001
Criterion.AICC: -1708.110992474285
Model was calibrated in iteration: 11

finally lets look at the path that we took:

[6]:
import pandas as pd

# Read the TSV file
summary_df = pd.read_csv('output/summary.tsv', sep='\t')
summary_df
[6]:
method # candidates predecessor change current model criterion current model candidate changes
0 forward 17 [] inf ['a_0ac_k08', 'a_b', 'a_k05k12_k05k08k12', 'a_... [['a_0ac_k05'], ['a_0ac_k12'], ['a_0ac_k16'], ...
1 forward 16 ['a_k05_k05k12'] -1688.480722 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k05'], ['a_0ac_k12'], ['a_0ac_k16'], ...
2 backward 16 [] -1688.480722 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
3 backward 15 ['a_k12_k08k12'] -1690.781213 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
4 backward 14 ['a_k08k16_k08k12k16'] -1693.062200 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
5 backward 13 ['a_k05k16_k05k12k16'] -1695.323944 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
6 backward 12 ['a_k05k12_k05k12k16'] -1697.564277 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
7 backward 11 ['a_k08_k08k12'] -1699.774524 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
8 backward 10 ['a_k08_k05k08'] -1701.947835 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
9 backward 9 ['a_k08_k08k16'] -1704.098940 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
10 backward 8 ['a_k08k16_k05k08k16'] -1706.240108 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
11 backward 7 ['a_k12_k12k16'] -1708.110992 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
12 forward 23 [] -1708.110992 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k05'], ['a_0ac_k12'], ['a_0ac_k16'], ...
13 lateral 168 [] -1708.110992 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k05', 'a_k05_k05k12'], ['a_0ac_k05', ...
14 lateral 0 [] -1708.110992 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... []

and the expected summary:

[7]:
summary_df = pd.read_csv('famos/expected_summary.tsv', sep='\t')
summary_df
[7]:
method # candidates predecessor change current model criterion current model candidate changes
0 forward 17 [] inf ['a_0ac_k08', 'a_b', 'a_k05k12_k05k08k12', 'a_... [['a_0ac_k05'], ['a_0ac_k12'], ['a_0ac_k16'], ...
1 forward 16 ['a_k05_k05k12'] -1688.480660 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k05'], ['a_0ac_k12'], ['a_0ac_k16'], ...
2 backward 16 [] -1688.480660 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
3 backward 15 ['a_k08_k08k16'] -1690.781203 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
4 backward 14 ['a_k05k16_k05k12k16'] -1693.062190 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
5 backward 13 ['a_k08_k08k12'] -1695.323742 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
6 backward 12 ['a_k05k12_k05k12k16'] -1697.562387 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
7 backward 11 ['a_k12_k08k12'] -1699.774480 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
8 backward 10 ['a_k08k16_k08k12k16'] -1701.947757 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
9 backward 9 ['a_k08_k05k08'] -1704.098938 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
10 backward 8 ['a_k08k16_k05k08k16'] -1706.240108 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
11 backward 7 ['a_k12_k12k16'] -1708.110992 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k08'], ['a_k05_k05k12'], ['a_k05k12_k...
12 forward 23 [] -1708.110992 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k05'], ['a_0ac_k12'], ['a_0ac_k16'], ...
13 lateral 168 [] -1708.110992 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... [['a_0ac_k05', 'a_0ac_k08'], ['a_0ac_k05', 'a_...
14 lateral 0 [] -1708.110992 ['a_0ac_k08', 'a_b', 'a_k05_k05k12', 'a_k05k12... []
[ ]: