PEtab-dev / PEtab

PEtab - an SBML and TSV based data format for parameter estimation problems in systems biology
https://petab.readthedocs.io
MIT License
56 stars 12 forks source link

Can we take the nominalValue in the parameters table from SBML? #508

Closed thomassligon closed 3 years ago

thomassligon commented 3 years ago

Which problem would you like to address? Please describe. The nominalValue in the parameters table would be nicer if we could take it from SBML. Otherwise, when I change the model, I need to manually change all of these values in the parameters table.

Describe the solution you would like Currently, I have a large parameters table, nominalValue is set to the parameter.value from SBML, and lowerBound and UpperBound are 10^2 lower and higher than nominalValue.

Describe alternatives you have considered Manual update.

Additional context Could we define a relative value for the bounds? For example, setting nominalValue to SBML instead of a number could tell PETab that nominalValue should be read from SBML (the value attribute of the parameter definition) and then upperBound and lowerBound are to be calculated relative to nominalValue.

dweindl commented 3 years ago

Hi Tom, sorry for the late reply. Do I understand you correctly, that you'd like to have a function in the PEtab library to update/create a parameter table to set the bounds relative to the parameters in the SBML model? Not sure hope helpful that is in general, as in most applications one would not have a good guess for most parameters. But for your case, this should be rather easy to implement yourself. If you use petab.parameters.create_parameter_df, this will set the nominal values based on the values from the SBML model. Afterwards it's just using pandas to set the bounds in whatever relative way you like (e.g., parameter_df['lowerBound'] = 0.5 * parameter_df['nominalValue']; parameter_df['upperBound'] = 2 * parameter_df['nominalValue']).

thomassligon commented 3 years ago

Hi Daniel, thanks. That is basically exactly what I was looking for, with the small difference that it is a few lines of code instead of a table. But, I still have a few questions/comments.

First, you write "...in most applications one would not have a good guess for most parameters...", but this is unavoidable! I know that you can just set min = 1e-3 and max = 1e+3 but that implicitly sets the nominal value to 1, and this value is always needed as an initial condition for solving the ODEs. So, since I always need an initial condition, I prefer to apply any biological knowledge I have, however limited. That gives me the best starting point I can find.

Now for the questions, I'll ask them in the context of my current code. I have a file called configuration.yaml that looks like this:

format_version: 1
parameter_file: ..\data\parameters.tsv
petab_version: 0.1.10
problems:
- condition_files:
  - ..\data\conditions.tsv
  measurement_files:
  - ..\data\measurements.tsv
  observable_files:
  - ..\data\observables.tsv
  sbml_files:
  - ..\Models\ASTHMA_V40_M09.xml

and the code includes the following lines:

petab_problem = petab.Problem.from_yaml('configuration.yaml')
importer = pypesto.petab.PetabImporter(petab_problem)
model = importer.create_model(verbose=True)
print(model.getParameterScale()) # only for testing
print("Model parameters:", list(model.getParameterIds()), '\n') # only for testing
...
import libsbml
converter_config = libsbml.SBMLLocalParameterConverter().getDefaultProperties()
petab_problem.sbml_document.convert(converter_config)
obj = importer.create_objective(guess_steadystate=False)
obj.amici_solver.setSensitivityMethod(2) # testing SS calculation
problem = importer.create_problem(obj)
optimizer = optimize.ScipyOptimizer()
engine = engine.SingleCoreEngine()
result = optimize.minimize(problem=problem, optimizer=optimizer, n_starts=10, engine=engine)
result.optimize_result.get_for_key('fval')

Question 1: What do I do with the parameter_file statement in yaml? Do I just leave it out?

Question 2: Where do I add the new statements, including petab.parameters.create_parameter_df, (assuming that they will need libsbml to read the SBML file)?

thomassligon commented 3 years ago

I have added these lines:

parameter_df = petab.parameters.create_parameter_df # take parameters from SBML
parameter_df['lowerBound'] = 1e-2*parameter_df['nominalValue'] # set lowerBound
parameter_df['upperBound'] = 1e+2*parameter_df['nominalValue'] # set upperBound

but I am getting an exception:

Exception has occurred: TypeError       (note: full exception trace is shown but execution is paused at: _run_module_as_main)
'function' object is not subscriptable
  File "C:\data\Tom\Research\Asthma\python\PE.py", line 19, in <module>
    parameter_df['lowerBound'] = 1e-2*parameter_df['nominalValue'] # set lowerBound

Is this telling me that parameter_df is not subscriptable, i.e. parameter_df['lowerBound'] is not valid?

dweindl commented 3 years ago

parameter_df = petab.parameters.create_parameter_df # take parameters from SBML

Because you missed the () here. In your code, parameter_df is not the parameter table, but a pointer to the function to create it.

thomassligon commented 3 years ago

Thanks, the following code is running without error messages, and I assume it is creating the parameter table as required, which answers the original question.

petab_problem = petab.Problem.from_yaml('configuration.yaml')
petab.lint_problem(petab_problem)
parameter_df = petab.parameters.create_parameter_df(petab_problem.sbml_model,
                                                    petab_problem.condition_df,
                                                    petab_problem.observable_df,
                                                    petab_problem.measurement_df) # take parameters from SBML
parameter_df['lowerBound'] = 1e-2*parameter_df['nominalValue'] # set lowerBound
parameter_df['upperBound'] = 1e+2*parameter_df['nominalValue'] # set upperBound