|
| 1 | +from inspect import cleandoc |
| 2 | + |
| 3 | +from petab.v2.C import * |
| 4 | +from petab.v2 import Problem |
| 5 | +from petabtests import ( |
| 6 | + PetabTestCase, |
| 7 | + analytical_a, |
| 8 | + antimony_to_sbml_str, |
| 9 | + analytical_b, |
| 10 | +) |
| 11 | +from pathlib import Path |
| 12 | + |
| 13 | +DESCRIPTION = cleandoc(""" |
| 14 | +## Objective |
| 15 | +
|
| 16 | +This case tests simultaneous re-initialization of compartment size and |
| 17 | +contained species. |
| 18 | +
|
| 19 | +## Model |
| 20 | +
|
| 21 | +Two simple conversion reactions `A <=> B`, `a <=> b` in a single compartment, |
| 22 | +following mass action kinetics. |
| 23 | +
|
| 24 | +`A` and `B` are species defined in terms of concentrations, `a` and `b` are |
| 25 | +`hasOnlySubstanceUnits=True` species defined in terms of amounts. |
| 26 | +
|
| 27 | +The compartment size and the species amounts/concentrations are re-initialized |
| 28 | +at time 10. The assigned values are independent of the model state. |
| 29 | +
|
| 30 | +At time 10, the conditions table changes: |
| 31 | +* The compartment size from 2 to 4. |
| 32 | +* The concentration of `A` to `5`. This implies that the amount of |
| 33 | + `A` is changed to `5 * 2 = 10` (concentration * compartment size). |
| 34 | +* The amount of `a` to `10`. |
| 35 | +
|
| 36 | +This leads to the following model state at time 10: |
| 37 | +* The concentration of `A` is `10 / 4 = 2.5` |
| 38 | + (new amount divided by new volume). |
| 39 | +* The amount of `a` is `10`, unaffected by the compartment size change. |
| 40 | +* The concentration of `B` is `(2 * 2) / 4 = 1` |
| 41 | + (previous amount / new volume |
| 42 | + = previous concentration * previous volume / new volume). |
| 43 | +* The amount of `b` remains at `4`, unaffected by the compartment size change. |
| 44 | +""") |
| 45 | + |
| 46 | +# problem -------------------------------------------------------------------- |
| 47 | + |
| 48 | + |
| 49 | +sbml_file = Path(__file__).parent / "model.xml" |
| 50 | +a_c0 = 2 |
| 51 | +b_c0 = 1 |
| 52 | +a_c10 = 2.5 |
| 53 | +b_c10 = 1 |
| 54 | +vol0 = 2 |
| 55 | +vol_new = 10 |
| 56 | +k1 = 2 |
| 57 | +k2 = 1 |
| 58 | + |
| 59 | +ant_model = f""" |
| 60 | +model petab_test_0022 |
| 61 | + compartment default_compartment = {vol0} |
| 62 | + initial_conc_A = {a_c0} |
| 63 | + initial_conc_B = {b_c0} |
| 64 | +
|
| 65 | + species A in default_compartment = initial_conc_A |
| 66 | + substanceOnly species a in default_compartment = initial_conc_A * default_compartment |
| 67 | +
|
| 68 | + species B in default_compartment = initial_conc_B |
| 69 | + substanceOnly species b in default_compartment = initial_conc_B * default_compartment |
| 70 | +
|
| 71 | + k1 = {k1} |
| 72 | + k2 = {k2} |
| 73 | +
|
| 74 | + A' = k2 * B - k1 * A |
| 75 | + B' = - k2 * B + k1 * A |
| 76 | + a' = k2 * b - k1 * a |
| 77 | + b' = - k2 * b + k1 * a |
| 78 | +
|
| 79 | + # the result of the PEtab reinitialization should be the same as with |
| 80 | + # the following event and no reinitialization: |
| 81 | + # |
| 82 | + # at time >= 10: A = 5, a = 5 * default_compartment, default_compartment = 4 |
| 83 | +end |
| 84 | +""" |
| 85 | +sbml_file.write_text(antimony_to_sbml_str(ant_model)) |
| 86 | + |
| 87 | + |
| 88 | +problem = Problem() |
| 89 | +problem.add_observable("obs_a", "a", noise_formula="1") |
| 90 | +problem.add_observable("obs_A", "A", noise_formula="1") |
| 91 | +problem.add_observable("obs_b", "b", noise_formula="1") |
| 92 | +problem.add_observable("obs_B", "B", noise_formula="1") |
| 93 | + |
| 94 | +problem.add_parameter("k1", lb=0, ub=10, nominal_value=k1, scale=LIN) |
| 95 | +problem.add_experiment("experiment1", 0, "", 10, "condition2") |
| 96 | +problem.add_condition( |
| 97 | + "condition2", "condition2", a=5 * vol0, A=5, default_compartment=vol_new |
| 98 | +) |
| 99 | + |
| 100 | + |
| 101 | +ts = [0, 5, 10, 15] |
| 102 | +for t in ts: |
| 103 | + problem.add_measurement("obs_a", "", t, 2) |
| 104 | + problem.add_measurement("obs_A", "", t, 2) |
| 105 | + problem.add_measurement("obs_b", "", t, 1) |
| 106 | + problem.add_measurement("obs_B", "", t, 1) |
| 107 | + |
| 108 | +# solutions ------------------------------------------------------------------ |
| 109 | + |
| 110 | +simulation_df = problem.measurement_df.copy(deep=True).rename( |
| 111 | + columns={MEASUREMENT: SIMULATION} |
| 112 | +) |
| 113 | +simulation_df[SIMULATION] = [ |
| 114 | + # a, A, b, B |
| 115 | + # t=0 |
| 116 | + a_c0 * vol0, |
| 117 | + a_c0, |
| 118 | + b_c0 * vol0, |
| 119 | + b_c0, |
| 120 | + # t=5 |
| 121 | + analytical_a(5, a_c0, b_c0, k1, k2) * vol0, |
| 122 | + analytical_a(5, a_c0, b_c0, k1, k2), |
| 123 | + analytical_b(5, a_c0, b_c0, k1, k2) * vol0, |
| 124 | + analytical_b(5, a_c0, b_c0, k1, k2), |
| 125 | + # t=10, re-initialize compartment size and contained species |
| 126 | + a_c10 * vol_new, |
| 127 | + a_c10, |
| 128 | + b_c10 * vol_new, |
| 129 | + b_c10, |
| 130 | + # t=15 |
| 131 | + analytical_a(5, a_c10, b_c10, k1, k2) * vol_new, |
| 132 | + analytical_a(5, a_c10, b_c10, k1, k2), |
| 133 | + analytical_b(5, a_c10, b_c10, k1, k2) * vol_new, |
| 134 | + analytical_b(5, a_c10, b_c10, k1, k2), |
| 135 | +] |
| 136 | + |
| 137 | +case = PetabTestCase( |
| 138 | + id=22, |
| 139 | + brief="Simultaneous re-initialization of compartment size and contained species.", |
| 140 | + description=DESCRIPTION, |
| 141 | + model=sbml_file, |
| 142 | + experiment_dfs=[problem.experiment_df], |
| 143 | + condition_dfs=[problem.condition_df], |
| 144 | + observable_dfs=[problem.observable_df], |
| 145 | + measurement_dfs=[problem.measurement_df], |
| 146 | + simulation_dfs=[simulation_df], |
| 147 | + parameter_df=problem.parameter_df, |
| 148 | +) |
0 commit comments