From caa09c230ad17f2a030e17724b2fd04c86a415a5 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Sat, 13 Mar 2021 22:53:15 +0100 Subject: [PATCH 01/21] Cleanup --- .../exampleSteadystateScaledTest.h | 4 +-- include/parpeamici/amiciSimulationRunner.h | 2 +- include/parpeamici/hierarchicalOptimization.h | 34 +++++++++---------- ...lOptimizationAnalyticalParameterProvider.h | 4 +-- include/parpeamici/multiConditionProblem.h | 12 +++---- include/parpeamici/optimizationApplication.h | 2 +- .../parpeoptimization/minibatchOptimization.h | 2 +- src/parpeamici/amiciSimulationRunner.cpp | 2 +- src/parpeamici/optimizationApplication.cpp | 2 +- .../minibatchOptimizationTest.h | 2 +- .../parpeoptimization/quadraticTestProblem.h | 2 +- 11 files changed, 34 insertions(+), 34 deletions(-) diff --git a/examples/parpeamici/steadystate/exampleSteadystateScaledTest.h b/examples/parpeamici/steadystate/exampleSteadystateScaledTest.h index e98eb37ba..73e9f9a0e 100644 --- a/examples/parpeamici/steadystate/exampleSteadystateScaledTest.h +++ b/examples/parpeamici/steadystate/exampleSteadystateScaledTest.h @@ -95,7 +95,7 @@ TEST_F(steadystateProblemTests, testSteadystateMultiCond) { parpe::MultiConditionDataProviderDefault dp(std::move(model), modelNonOwning->getSolver()); - dp.edata_.push_back(amici::ExpData(*modelNonOwning)); + dp.edata_.emplace_back(amici::ExpData(*modelNonOwning)); dp.edata_[0].fixedParameters = modelNonOwning->getFixedParameters(); dp.edata_[0].setObservedData(yExp); dp.edata_[0].setObservedDataStdDev(std::vector(yExp.size(), 1.0)); @@ -126,7 +126,7 @@ TEST_F(steadystateProblemTests, testSteadystateHierarchical) { yScaledExp[offsettedObservableIdx] = offsetExp + yExp[1]; parpe::MultiConditionDataProviderDefault dp(std::move(model), modelNonOwning->getSolver()); // x0? - dp.edata_.push_back(amici::ExpData(*modelNonOwning)); + dp.edata_.emplace_back(amici::ExpData(*modelNonOwning)); dp.edata_[0].fixedParameters = modelNonOwning->getFixedParameters(); dp.edata_[0].setObservedData(yScaledExp); dp.edata_[0].setObservedDataStdDev(std::vector(yExp.size(), 1.0)); diff --git a/include/parpeamici/amiciSimulationRunner.h b/include/parpeamici/amiciSimulationRunner.h index 0c4fa3bf9..270fb49bf 100644 --- a/include/parpeamici/amiciSimulationRunner.h +++ b/include/parpeamici/amiciSimulationRunner.h @@ -127,7 +127,7 @@ class AmiciSimulationRunner int jobIdx, const std::vector& optimizationParameters, amici::SensitivityOrder sensitivityOrder, - const std::vector& conditionIndices); + const std::vector& conditionIndices) const; #endif std::vector const& optimization_parameters_; diff --git a/include/parpeamici/hierarchicalOptimization.h b/include/parpeamici/hierarchicalOptimization.h index 7df863154..19072af19 100644 --- a/include/parpeamici/hierarchicalOptimization.h +++ b/include/parpeamici/hierarchicalOptimization.h @@ -112,15 +112,15 @@ class HierarchicalOptimizationWrapper : public GradientFunction * @brief Get parameters for initial function evaluation * @return */ - std::vector getDefaultScalingFactors() const; + [[nodiscard]] std::vector getDefaultScalingFactors() const; /** * @brief Get parameters for initial function evaluation * @return */ - std::vector getDefaultOffsetParameters() const; + [[nodiscard]] std::vector getDefaultOffsetParameters() const; - std::vector getDefaultSigmaParameters() const; + [[nodiscard]] std::vector getDefaultSigmaParameters() const; /** * @brief Run simulations with scaling parameters set to 1.0 and collect @@ -130,7 +130,7 @@ class HierarchicalOptimizationWrapper : public GradientFunction * @return Vector of double vectors containing AMICI ReturnData::y (nt x ny, * column-major) */ - std::tuple>, + [[nodiscard]] std::tuple>, std::vector>> getUnscaledModelOutputsAndSigmas( const gsl::span reducedParameters, @@ -142,7 +142,7 @@ class HierarchicalOptimizationWrapper : public GradientFunction * @param modelOutputs Model outputs as provided by getModelOutputs * @return the computed scaling factors */ - std::vector computeAnalyticalScalings( + [[nodiscard]] std::vector computeAnalyticalScalings( std::vector> const& measurements, std::vector> const& modelOutputsUnscaled) const; @@ -155,11 +155,11 @@ class HierarchicalOptimizationWrapper : public GradientFunction * @param modelOutputs Model outputs as provided by getModelOutputs * @return the computed offset parameters */ - std::vector computeAnalyticalOffsets( + [[nodiscard]] std::vector computeAnalyticalOffsets( const std::vector>& measurements, std::vector>& modelOutputsUnscaled) const; - std::vector computeAnalyticalSigmas( + [[nodiscard]] std::vector computeAnalyticalSigmas( std::vector> const& measurements, const std::vector>& modelOutputsScaled) const; @@ -207,25 +207,25 @@ class HierarchicalOptimizationWrapper : public GradientFunction * @brief Get number of parameters the function expects * @return That */ - virtual int numParameters() const override; + [[nodiscard]] int numParameters() const override; - int numProportionalityFactors() const; + [[nodiscard]] int numProportionalityFactors() const; - std::vector const& getProportionalityFactorIndices() const; + [[nodiscard]] std::vector const& getProportionalityFactorIndices() const; - int numOffsetParameters() const; + [[nodiscard]] int numOffsetParameters() const; - int numSigmaParameters() const; + [[nodiscard]] int numSigmaParameters() const; - std::vector const& getOffsetParameterIndices() const; + [[nodiscard]] std::vector const& getOffsetParameterIndices() const; - std::vector const& getSigmaParameterIndices() const; + [[nodiscard]] std::vector const& getSigmaParameterIndices() const; - std::vector getAnalyticalParameterIndices() const; + [[nodiscard]] std::vector getAnalyticalParameterIndices() const; - AmiciSummedGradientFunction* getWrappedFunction() const; + [[nodiscard]] AmiciSummedGradientFunction* getWrappedFunction() const; - std::vector getParameterIds() const override; + [[nodiscard]] std::vector getParameterIds() const override; private: void init(); diff --git a/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h b/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h index d99091087..d6e2e4932 100644 --- a/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h +++ b/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h @@ -17,7 +17,7 @@ namespace parpe { class AnalyticalParameterProvider { public: - virtual ~AnalyticalParameterProvider() {} + virtual ~AnalyticalParameterProvider() = default; /** * @brief Get vector of condition indices for which the parameter with the @@ -25,7 +25,7 @@ class AnalyticalParameterProvider * @param parameterIndex referring to the index in the analytical parameter * list in the hdf5 file * (*not* the optimization parameter index). - * @return Vector of condition indice + * @return Vector of condition indices */ virtual std::vector getConditionsForParameter( int parameterIndex) const = 0; diff --git a/include/parpeamici/multiConditionProblem.h b/include/parpeamici/multiConditionProblem.h index 805bafcc4..2af508ca6 100644 --- a/include/parpeamici/multiConditionProblem.h +++ b/include/parpeamici/multiConditionProblem.h @@ -114,7 +114,7 @@ class AmiciSummedGradientFunction : public SummedGradientFunction { virtual ~AmiciSummedGradientFunction() = default; - virtual FunctionEvaluationStatus evaluate( + FunctionEvaluationStatus evaluate( gsl::span parameters, int dataset, double &fval, @@ -122,7 +122,7 @@ class AmiciSummedGradientFunction : public SummedGradientFunction { Logger *logger, double *cpuTime) const override; - virtual FunctionEvaluationStatus evaluate( + FunctionEvaluationStatus evaluate( gsl::span parameters, std::vector datasets, double &fval, @@ -134,9 +134,9 @@ class AmiciSummedGradientFunction : public SummedGradientFunction { * @brief Number of optimization parameters * @return */ - virtual int numParameters() const override; + [[nodiscard]] int numParameters() const override; - std::vector getParameterIds() const override; + [[nodiscard]] std::vector getParameterIds() const override; /** * @brief Run simulations (no gradient) with given parameters and collect @@ -154,7 +154,7 @@ class AmiciSummedGradientFunction : public SummedGradientFunction { Logger *logger, double *cpuTime) const; - virtual std::vector> getAllMeasurements() const; + [[nodiscard]] virtual std::vector> getAllMeasurements() const; /** * @brief Callback function for LoadBalancer @@ -163,7 +163,7 @@ class AmiciSummedGradientFunction : public SummedGradientFunction { */ virtual void messageHandler(std::vector &buffer, int jobId) const; - virtual amici::ParameterScaling getParameterScaling(int parameterIndex) const; + [[nodiscard]] virtual amici::ParameterScaling getParameterScaling(int parameterIndex) const; /** Include model states in result package */ bool sendStates = false; diff --git a/include/parpeamici/optimizationApplication.h b/include/parpeamici/optimizationApplication.h index ba60d16ab..7b4f86781 100644 --- a/include/parpeamici/optimizationApplication.h +++ b/include/parpeamici/optimizationApplication.h @@ -144,7 +144,7 @@ class OptimizationApplication { */ int init(int argc, char **argv); - void runMultiStarts(); + void runMultiStarts() const; protected: // command line option parsing diff --git a/include/parpeoptimization/minibatchOptimization.h b/include/parpeoptimization/minibatchOptimization.h index 3dfc2ce20..be25297c6 100755 --- a/include/parpeoptimization/minibatchOptimization.h +++ b/include/parpeoptimization/minibatchOptimization.h @@ -576,7 +576,7 @@ class MinibatchOptimizer { * @param oldGradient cost function gradient before last step * @param cost new cost function value after interception * @param subsequentFails number of iterations during rescue interceptor - * @param f Function to minize + * @param f Function to minimize * @param data Full data set on which f will be evaluated * @param logger Logger instance for status messages * @param reporter OptimizationReporter instance for tracking progress diff --git a/src/parpeamici/amiciSimulationRunner.cpp b/src/parpeamici/amiciSimulationRunner.cpp index a1de3100c..d7df5eb28 100644 --- a/src/parpeamici/amiciSimulationRunner.cpp +++ b/src/parpeamici/amiciSimulationRunner.cpp @@ -146,7 +146,7 @@ AmiciSimulationRunner::queueSimulation( int jobIdx, std::vector const& optimizationParameters, amici::SensitivityOrder sensitivityOrder, - std::vector const& conditionIndices) + std::vector const& conditionIndices) const { // TODO avoid copy optimizationParameters; reuse;; for const& in work // package need to split into(de)serialize diff --git a/src/parpeamici/optimizationApplication.cpp b/src/parpeamici/optimizationApplication.cpp index 4f7c068da..0e472448b 100644 --- a/src/parpeamici/optimizationApplication.cpp +++ b/src/parpeamici/optimizationApplication.cpp @@ -58,7 +58,7 @@ int OptimizationApplication::init(int argc, char **argv) { return status; } -void OptimizationApplication::runMultiStarts() +void OptimizationApplication::runMultiStarts() const { // TODO: use uniqe_ptr, not ref MultiStartOptimization optimizer(*multiStartOptimizationProblem, true, diff --git a/tests/parpeoptimization/minibatchOptimizationTest.h b/tests/parpeoptimization/minibatchOptimizationTest.h index 955609e9d..94889e7a1 100644 --- a/tests/parpeoptimization/minibatchOptimizationTest.h +++ b/tests/parpeoptimization/minibatchOptimizationTest.h @@ -177,7 +177,7 @@ TEST_F(minibatchOptimizationLinearModel, linearModelCheckCostGradient) { auto p = getOptimizationProblem(); for(int i = 0; i < 10; ++i) - parpe::optimizationProblemGradientCheck(p.get(), 10, 1e-1); + parpe::optimizationProblemGradientCheck(p.get(), 10, 1e-1); // TODO: check results automatically } diff --git a/tests/parpeoptimization/quadraticTestProblem.h b/tests/parpeoptimization/quadraticTestProblem.h index 77830b2df..cccd76438 100644 --- a/tests/parpeoptimization/quadraticTestProblem.h +++ b/tests/parpeoptimization/quadraticTestProblem.h @@ -146,7 +146,7 @@ class QuadraticGradientFunctionMock : public GradientFunction { class QuadraticTestProblem : public OptimizationProblem { public: - QuadraticTestProblem(std::unique_ptr logger = std::make_unique()); + explicit QuadraticTestProblem(std::unique_ptr logger = std::make_unique()); void fillParametersMin(gsl::span buffer) const override; void fillParametersMax(gsl::span buffer) const override; From 86ae9b5f71ca6ab69e878296dc2e5b86153d4cfe Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Mon, 22 Mar 2021 11:21:16 +0100 Subject: [PATCH 02/21] Update dependencies (#328) * petab>=0.1.16 * git subrepo clone (merge) --branch=v0.11.14 --force git@github.com:AMICI-dev/AMICI.git deps/AMICI subrepo: subdir: "deps/AMICI" merged: "09132907" upstream: origin: "git@github.com:AMICI-dev/AMICI.git" branch: "v0.11.14" commit: "09132907" git-subrepo: version: "0.4.1" origin: "https://github.com/ingydotnet/git-subrepo" commit: "a04d8c2" * Check type for numbers.Number, not float * petab>=0.1.17 * PEtab: allow timepoint-specific mappings for scalar sigmas * CI: disable Fujita_SciSignal2010 for now --- benchmark_collection/all.sh | 4 +- .../.github/ISSUE_TEMPLATE/feature_request.md | 14 + deps/AMICI/.github/workflows/test_matlab.yml | 21 + .../test_sbml_semantic_test_suite.yml | 9 +- deps/AMICI/.gitrepo | 6 +- deps/AMICI/CHANGELOG.md | 917 ++++++++++++++++++ deps/AMICI/documentation/CI.md | 7 +- .../ExampleExperimentalConditions.ipynb | 1 + deps/AMICI/documentation/GettingStarted.ipynb | 2 +- deps/AMICI/documentation/about.rst | 8 +- deps/AMICI/documentation/amici_refs.bib | 73 +- deps/AMICI/documentation/changelog.md | 1 + deps/AMICI/documentation/index.rst | 1 + .../documentation/model_presimulation.ipynb | 1 - deps/AMICI/documentation/python_interface.rst | 55 +- deps/AMICI/documentation/references.md | 44 +- deps/AMICI/include/amici/abstract_model.h | 102 +- deps/AMICI/include/amici/edata.h | 51 +- deps/AMICI/include/amici/exception.h | 8 +- deps/AMICI/include/amici/misc.h | 4 +- deps/AMICI/include/amici/newton_solver.h | 4 + deps/AMICI/include/amici/rdata.h | 70 +- deps/AMICI/include/amici/returndata_matlab.h | 2 +- deps/AMICI/include/amici/vector.h | 2 +- deps/AMICI/matlab/@amimodel/amimodel.m | 2 + deps/AMICI/matlab/@amimodel/generateC.m | 6 +- .../AMICI/matlab/@amimodel/generateRebuildM.m | 26 + deps/AMICI/matlab/amiwrap.m | 2 + deps/AMICI/matlab/tests/testModels.m | 37 +- .../models/model_calvetti/model_calvetti.h | 84 +- .../model_calvetti/rebuild_model_calvetti.m | 5 + deps/AMICI/models/model_dirac/model_dirac.h | 82 +- .../models/model_dirac/rebuild_model_dirac.m | 5 + deps/AMICI/models/model_events/model_events.h | 82 +- .../model_events/rebuild_model_events.m | 5 + .../model_jakstat_adjoint.h | 82 +- .../rebuild_model_jakstat_adjoint.m | 5 + .../model_jakstat_adjoint_o2.h | 82 +- .../model_nested_events/model_nested_events.h | 82 +- .../rebuild_model_nested_events.m | 5 + deps/AMICI/models/model_neuron/model_neuron.h | 82 +- .../model_neuron/rebuild_model_neuron.m | 5 + .../models/model_neuron_o2/model_neuron_o2.h | 82 +- .../models/model_robertson/model_robertson.h | 84 +- .../model_robertson/rebuild_model_robertson.m | 5 + .../model_steadystate/model_steadystate.h | 82 +- .../rebuild_model_steadystate.m | 5 + deps/AMICI/python/amici/ode_export.py | 661 +++++++++---- deps/AMICI/python/amici/petab_import_pysb.py | 8 + deps/AMICI/python/amici/pysb_import.py | 13 +- deps/AMICI/python/amici/sbml_import.py | 414 +++++++- .../ExampleExperimentalConditions.ipynb | 462 +++++++++ .../model_presimulation.ipynb | 416 -------- deps/AMICI/python/tests/test_events.py | 351 +++++++ deps/AMICI/python/tests/test_heavisides.py | 147 +-- deps/AMICI/python/tests/test_sbml_import.py | 31 + deps/AMICI/python/tests/util.py | 173 ++++ deps/AMICI/scripts/downloadAndBuildDoxygen.sh | 2 +- deps/AMICI/scripts/run-SBMLTestsuite.sh | 2 +- deps/AMICI/sonar-project.properties | 14 +- deps/AMICI/src/abstract_model.cpp | 4 +- deps/AMICI/src/amici.cpp | 7 + deps/AMICI/src/forwardproblem.cpp | 14 +- deps/AMICI/src/model_header.ODE_template.h | 334 +------ deps/AMICI/src/rdata.cpp | 129 ++- deps/AMICI/src/returndata_matlab.cpp | 69 +- deps/AMICI/src/steadystateproblem.cpp | 11 +- deps/AMICI/src/sundials_matrix_wrapper.cpp | 51 +- .../benchmark-models/benchmark_models.yaml | 2 +- .../test_benchmark_collection.sh | 4 +- deps/AMICI/tests/conftest.py | 18 +- deps/AMICI/tests/cpputest/expectedResults.h5 | Bin 4195960 -> 4198368 bytes deps/AMICI/tests/cpputest/testOptions.h5 | Bin 345976 -> 345728 bytes deps/AMICI/tests/cpputest/testfunctions.cpp | 2 +- .../AMICI/tests/cpputest/unittests/tests1.cpp | 42 +- .../cpputest/unittests/testsSerialization.cpp | 7 +- .../generateTestConfig/example_neuron.py | 2 +- deps/AMICI/tests/testSBMLSuite.py | 37 +- deps/AMICI/version.txt | 2 +- python/parpe/hdf5_pe_input.py | 12 +- python/setup.py | 2 +- .../petab-test-suite/test_petab_test_suite.py | 6 +- 82 files changed, 3934 insertions(+), 1859 deletions(-) create mode 100644 deps/AMICI/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 deps/AMICI/.github/workflows/test_matlab.yml create mode 100644 deps/AMICI/CHANGELOG.md create mode 120000 deps/AMICI/documentation/ExampleExperimentalConditions.ipynb create mode 120000 deps/AMICI/documentation/changelog.md delete mode 120000 deps/AMICI/documentation/model_presimulation.ipynb create mode 100644 deps/AMICI/matlab/@amimodel/generateRebuildM.m create mode 100644 deps/AMICI/models/model_calvetti/rebuild_model_calvetti.m create mode 100644 deps/AMICI/models/model_dirac/rebuild_model_dirac.m create mode 100644 deps/AMICI/models/model_events/rebuild_model_events.m create mode 100644 deps/AMICI/models/model_jakstat_adjoint/rebuild_model_jakstat_adjoint.m create mode 100644 deps/AMICI/models/model_nested_events/rebuild_model_nested_events.m create mode 100644 deps/AMICI/models/model_neuron/rebuild_model_neuron.m create mode 100644 deps/AMICI/models/model_robertson/rebuild_model_robertson.m create mode 100644 deps/AMICI/models/model_steadystate/rebuild_model_steadystate.m create mode 100644 deps/AMICI/python/examples/example_presimulation/ExampleExperimentalConditions.ipynb delete mode 100644 deps/AMICI/python/examples/example_presimulation/model_presimulation.ipynb create mode 100644 deps/AMICI/python/tests/test_events.py create mode 100644 deps/AMICI/python/tests/util.py diff --git a/benchmark_collection/all.sh b/benchmark_collection/all.sh index 5bc854c58..2dff9e286 100755 --- a/benchmark_collection/all.sh +++ b/benchmark_collection/all.sh @@ -11,10 +11,10 @@ expected_to_work=" Boehm_JProteomeRes2014 Borghans_BiophysChem1997 Elowitz_Nature2000 -Fujita_SciSignal2010 Sneyd_PNAS2002 Zheng_PNAS2012" -#Schwen_PONE2014 Chen_MSB2009 +# Fujita_SciSignal2010 "Timepoint-specific parameter overrides currently unsupported." in PEtab parameter mapping +# Schwen_PONE2014 Chen_MSB2009 for MODEL in $expected_to_work; do printf '=%.0s' {1..20} diff --git a/deps/AMICI/.github/ISSUE_TEMPLATE/feature_request.md b/deps/AMICI/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..a5cd274b4 --- /dev/null +++ b/deps/AMICI/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,14 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement, new +assignees: '' + +--- + +**Feature description** +[A clear and concise description of what you would like to have.] + +**Motivation/Application** +[Why is this feature useful?] diff --git a/deps/AMICI/.github/workflows/test_matlab.yml b/deps/AMICI/.github/workflows/test_matlab.yml new file mode 100644 index 000000000..d14c0012b --- /dev/null +++ b/deps/AMICI/.github/workflows/test_matlab.yml @@ -0,0 +1,21 @@ +name: Matlab +on: [push, pull_request, workflow_dispatch] + +jobs: + matlab: + name: Matlab + + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@master + - run: git fetch --prune --unshallow + + - run: echo "AMICI_DIR=$(pwd)" >> $GITHUB_ENV + + - name: Install MATLAB + uses: matlab-actions/setup-matlab@v0 + - name: Run script + uses: matlab-actions/run-command@v0 + with: + command: cd matlab; installAMICI; addpath tests; testModels diff --git a/deps/AMICI/.github/workflows/test_sbml_semantic_test_suite.yml b/deps/AMICI/.github/workflows/test_sbml_semantic_test_suite.yml index 602683e7a..d47a58631 100644 --- a/deps/AMICI/.github/workflows/test_sbml_semantic_test_suite.yml +++ b/deps/AMICI/.github/workflows/test_sbml_semantic_test_suite.yml @@ -19,9 +19,14 @@ on: jobs: build: name: SBML Semantic Test Suite - runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + cases: ["1 - 250", "251 - 500", "501 - 750", "751 - 1000", + "1000-1250", "1251-1780"] + steps: - uses: actions/checkout@v1 with: @@ -31,7 +36,7 @@ jobs: sudo apt-get update \ && sudo apt-get install -y swig4.0 libatlas-base-dev - run: AMICI_PARALLEL_COMPILE=2 ./scripts/installAmiciSource.sh - - run: AMICI_PARALLEL_COMPILE=2 ./scripts/run-SBMLTestsuite.sh + - run: AMICI_PARALLEL_COMPILE=2 ./scripts/run-SBMLTestsuite.sh ${{ matrix.cases }} - name: "Upload artifact: SBML semantic test suite results" uses: actions/upload-artifact@v1 diff --git a/deps/AMICI/.gitrepo b/deps/AMICI/.gitrepo index 886e9bae5..86c1d8b45 100644 --- a/deps/AMICI/.gitrepo +++ b/deps/AMICI/.gitrepo @@ -5,8 +5,8 @@ ; [subrepo] remote = git@github.com:ICB-DCM/AMICI.git - branch = v0.11.13 - commit = b090fbb34ee64e65522cef0a2c0d639e70cfbcfe - parent = 6a39edf26417c415f4c3fc701b33a61be3c08a93 + branch = v0.11.14 + commit = 09132907788a4b443f4d93223b34ee9fc5ad051a + parent = 99cf392ba569889f542eaa7b57145ea659570fe1 cmdver = 0.4.1 method = merge diff --git a/deps/AMICI/CHANGELOG.md b/deps/AMICI/CHANGELOG.md new file mode 100644 index 000000000..875c9603a --- /dev/null +++ b/deps/AMICI/CHANGELOG.md @@ -0,0 +1,917 @@ +# Changelog + +## v0.11.14 (2021-03-16) + +New features: +* **Python import now supports SBML Events** (#1443) +* Implement support for compilation without sensitivities (#1454) + +Fixes: + * Issue #1446: Check whether constant parameters are valid targets (#1450) + * Issue #1422: Fix Steadystate solver failing if preequilibration starts in + steadystate (#1461) + * Issue #1401: Ensure diagnostics variables in ReturnData are always of + expected length (#1438, #1447) + * Fix FIM approximation for parameter dependent sigma (#1441) + * Fix invalid SBML in PEtab/PySB import (#1433) + * Fix: No context for inspect.getouterframes (#1432) + +Documentation: +* Added this CHANGELOG +* Added feature request issue template (#1437) +* Updated reference list (#1430) +* Overhauled experimental conditions notebook (#1460) + +CI: +* Test Matlab interface on GHA (#1451) +* Include componentTags in SBML test suite output (#1462) +* Split SBML semantic test suite into multiple jobs (#1452) +* Fix Crauste ref val, fixes #1458 (#1459) + +Misc: +* Various cleanup (#1465, #1448, #1455) +* Micro-optimize SUNMatrixWrapper::transpose (#1439) +* Remove constant triggers from roots in Heaviside (#1440) + +## v0.11.13 (2021-02-20) + +Breaking changes: +* AMICI requires Python>=3.7 +* Updated package installation (PEP517/518): + Creating source distributions requires https://github.com/pypa/build (#1384) + (but now handles all package building dependencies properly) + +Features: +* More flexible state reinitialization (#1417) + +Updated dependencies: +* Upgrade to sundials 5.7.0 (#1392) + +Fixes: +* Python: account for heaviside functions in expressions (#1382) +* Python: allow loading of existing models in import_petab_problem (#1383) +* Python: Don't override user-provided compiler/linker flags (#1389) +* Python: PEtab import reinitialization fixes (#1417) +* Python: Fix PEtab observables for pysb models (#1390) +* Python: Substitute expressions in event condition expressions (#1404) +* Python: Unspecified initial states in PEtab conditions table default to SBML initial value (#1397) +* C++: Fix timepoint out of bounds access (#1402) +* C++: Fix exported CMake config (#1388) +* Fixed Dockerfile: add python3-venv (#1398, #1408) + +Other: +* Slim exported swig interface (#1425) +* Updated documentation + * Getting started tutorial (#1423) + * List supported SBML test tags (#1428) + * Add AMICI C++/Python/Matlab feature comparison (#1409) + * ... +* Various minor CI improvements +* ... + +## v0.11.12 (2021-01-26) + +Features: +* Add expression IDs and names to generated models (#1374) + +Fixes: +* Raise minimum sympy version to 1.7.1 (Closes #1367) +* Fix species assignment rules in reactions (#1372) +* Fix id vector for DAEs (#1376) + +Docs: +* Update how-to-cite (#1378) + + +## v0.11.11 (2020-12-15) + +### Python +* Restore support for species references (#1358) +* Add support for noise models in pysb (#1360) +* Proper handling of discontinuities in the ODE rhs (#1352) +* Fix directly calling AMICI from snakemake (#1348 ) +* Extend mathml function support, particularly for numerical arguments (#1357) +* Restore support for sympy 1.6 (#1356) + +### C++ +* Fix some compiler related warnings (#1349, #1362 ) +* Fix a rare segfault for adjoint sensitivities (#1351) + +### CI +* Move windows tests to GHA (#1354) +* Pin breathe to 4.24.1 + +### Docker +* Update ubuntu to 20.04 + +## v0.11.10 (2020-11-30) + +Bugfix release that restores compatibility with sympy 1.7 + +## v0.11.9 (2020-11-29) + +### Python +* General improvements to SBML import (#1312, #1316, #1315, #1322 , #1324 #1333, #1329) +* Small bugfixes and improvements (#1321 ) +* Improve derivative computation for instances of `power` (#1320 ) + +### C++ +* Fix FIM and residual computation for models with parameter dependent sigma. (#1338) +* Disable chi2/residual/FIM computation for non-gaussian objective functions. (#1338) +* Bugfix for integration failure during adjoint solve (#1327) + +### Doc +* Update references (#1331, #1336) + +### CI +* Update OpenBLAS for windows (#1334) + +## v0.11.8 (2020-10-21) + +### Python +* Fix pysb-petab support (#1288) +* Fix ExpData constructor overloading (#1299) +* Fix support for positivity enforcement (#1306) +* **Refactor SBML import, adds support for parameter rate rules and initial assignments** (#1284, #1296, #1304) +* Improve model generation for models with many parameters (#1300) +* Add support for PEtab based synthetic data generation (#1283) + +### C++ +* Make HDF5 an optional dependency (#1285) + +### Doc +* General Improvements to Documentation (#1289, #1291, #1292, #1293, #1294, #1286, #1277, #1281) + +### CI +* Add python 3.9 support test (#1282) +* Allow manual triggering of GitHub actions (#1287) +* Remove appveyor config (#1295) +* Update GHA env and path management (#1302) + +## v0.11.7 (2020-09-22) + +### Python +* Improve and extend available objective functions (#1235) +* Fix processing of compartment definitions (#1223) +* Fix replacement of reserved symbols (#1265) +* Use Hierarchical Derivatives for Expressions (#1224, #1246) +* Fix duplicate running of swig (#1216) +* Overload python interface functions for amici.{Model,Solver,ExpData} and amici.{Model,Solver,ExpData}Ptr (#1271) + +### C++ +* Fix and extend use of sparse matrix operations (#1230, #1240, #1244, #1247, #1271) +* **Fix application of maximal number of steps**, MaxNumStep parameter now limit total number of steps, not number of steps between output times. (#1267) + +### Doc +* Move all Documentation to RTD (#1229, #1241) +* General Improvements to Documentation (#1225, #1227, #1219, #1228, #1232, #1233, #1234, #1237, #1238, #1239, #1243, #1253, #1255, #1262) + +### CI +* Better check for doc building (#1226) +* Add more gradient checks (#1213) +* Update GHA to Ubuntu 20.04 (#1268) + +## v0.11.6 (2020-08-20) + +### Python +* Bugfix for piecewise functions (#1199) +* Refactor swigging - generate one single wrapper (#1213) + +### C++ +* Fix warnings: account for zero indexing in nan/inf error (#1112) + +### Doc +* Update Windows build instructions (#1200, #1202) +* Update README: Projects using AMICI (#1209) +* Add CODE_OF_CONDUCT.md (#1210) +* Update documentation for Python interface (#1208) + +### CI +* Create sdist on GHA using swig4.0.1 (#1204) (Fixing broken pypi package) +* Fix links after repository move +* Speed-up swig build: disable all languages except python (#1211) +* Fix doc generation on readthedocs (#1196) + + +## v0.11.5 (2020-08-07) + +### General +* Move repo to new organization (#1193) +* Update Bibliography + +### Python +* Fix bug for energyPySB models (#1191) + +### CI +* Fix release deployment (#1189) + +## v0.11.4 (2020-08-06) + +### Python +* Skip unnecessary expressions in pysb models (#1185) +* MSVC compiler support (this time for real... #1152) + +### CI +* Implement MSVC tests (#1152) +* Rename and group GitHub actions (#1186) +* Fix release deployment (#1186) + +## v0.11.3 (2020-08-06) + +### Python +* Fix simplification for pysb models (#1168) +* Pass verbosity flags to pysb network generation (#1173) +* Enable experimental pysb-petab support (#1175) +* Add installation instructions for Fedora (#1177) +* Implement support for SBML rate-references (#1180) + +### C++ +* Refactoring (#1162, #1163) + +### CI +* Move majority of tests to Github Actions (#1166, #1160) +* Improve reporting of skipped tests in SBML testsuite (#1183) + +## v0.11.2 (2020-07-17) + +### Python +* Speed up model import, compilation (#1123, #1112) +* Improve/Add steady-state solver documentation (#1102) +* Improve extension import (#1141) +* Bugfixes SBML import (#1135, #1134, #1145, #1154) +* Fixed issue that prevented simplification (#1158) + +### C++ +* Bugfixes (#1121, #1125, #1131, #1132, #1136) +* Enable openMP by default (#1118) +* Improve memoy footprint for simulations with replicates (#1153) +* Improve steady-state solver and add option to to adjoint-steadystate hybrid (#1143, #1099, #1129, #1146) + +### CI +* Store build artifacts from github actions (#1138) + +## v0.11.1 (2020-06-05) + +### Python +* Upgrade to sympy 1.6.0, which is now required minimum version (#1098, #1103) +* Speed up model import + * Speed-up computation of sx0, reduce file size (#1109) + * Replace terribly slow sympy.MutableDenseMatrix.is_zero_matrix by custom implementation (#1104) +* speedup dataframe creation in `get*AsDataFrame` (#1088) +* Allow caching edatas for simulate_petab (#1106) +* Fix wrong deprecation warning (Fixes #1093) +* Fix segmentation faults in NewtonSolver under certain conditions (#1089, #1090, #1097) +* fix wrong power function call in `unscale_parameter` (#1094) +* Fix MathML conversion (#1086) +* Fix deepcopy of SymPy objects (#1091) + +### Matlab +* handle empty rdata->{pre|post}eq_numlinsteps (Closes #1113), which previously made the matlab interface unusable +* Fix generation of compileMexFile.m for matlab compilation of python code (#1115) + +### C++ +* Reduce memory requirements and speedup compilation of large models (#1105) +* Place generated code into own namespace (#937) (#1112) +* Fix several msvc compiler warnings (#1116) (Note that MSVC support is still experimental) **breaking change for users of C++ interface** +* Fix swig warning: ensure base class ContextManager is known before use (Fixes #1092) (#1101) + +### CI +* Don't install/run valgrind on travis CI (done with github actions… (#1111) + + +## v0.11.0 (2020-05-10) + +Python: + +- **Implement support for variable compartments (#1036)** +- Better handling of constant species (#1047) +- **Better handling of C++ enums, this makes `amici.SensitivityMethod_forward` available as `amici.SensitivityMethod.forward` (#1042)** +- Improve installation routines (#1055, #1056, #1058, #1076) +- Add option to reduce memory usage (#1044) +- **Fix handling of symbolic expressions in nested rules (#1081, 1069)** + +Library: + +- Update Sundials to 5.2.0 (#1039) +- Update SuiteSparse to 5.4.0 (#1040) +- Refactor use of ReturnData, now completely created post-hoc (#1002) +- **Fix propagation of reinitialization in ExpData constructor (#1041)** +- **Fix issue where InternalSensitivityParameter was sometimes not set (#1075)** +- **Fix or disable certain combinations of equilibraition, presimulation and adjoint sensitivity analysis** + +CI: + +- Move from Codacy to Sonarcloud (#1065) +- Run SBML Testsuite when appropriate (#1058) + +## v0.10.21 (2020-04-04) + +Library: +* Fix: Handle paths with blanks in build scripts +* Feature: Add function to write amici::Solver settings to HDF5 (#1023) +* Fix: typehints (#1018, #1022) +* Refactor: Move creation of parameter mapping for objective<->simulation to classes (#1020) + +CI: +* Refactor: Cleanup and reorganize tests (#1026) +* Fix: benchmark problem test should fail on missing files (Closes #1015) + + +## v0.10.20 (2020-03-18) + +* Fixed (re)initialization of sensitivities if ExpData::fixedParametersPreequilibration is set (#994) +* Fixed sensitivities for parameters in sigma expressions for Python/SBML in case provided expression was not just a single parameter ID +* Enable parallel compilation of model files from Python (#997) based on AMICI_PARALLEL_COMPILE enviroment variable +* Fixed computation of log-likelihood for log10-normal distributed noise +* Added `reinitializeFixedParameterInitialStates` to ExpData (#1000) (**breaking change**: overrides settings in `amici::Model`) +* Python model import now verifies that chosen model name is a valid identifier (Closes #928) +* Made w available in ReturnData (Closes #990) (#992) +* Fixed setting of log level when passing boolean values to verbose (#991) +* Documentation now on ReadTheDocs https://amici.readthedocs.io/en/ +* Use proper state/observable names in plotting functions (#979) +* PEtab support: + * Adapt to most recent PEtab (0.1.5) + * Extended support for import of PEtab models + * Added support for computing cost function based on PEtab problem + * Implemented handling of species in condition table + * petab_import.import_model now provides reproducible parameter list (Closes #976) + * Fix python import error in import_petab_problem: Add absolute paths to python path, invalidate caches and reload (#970) + * Added example notebook +* CI: PEtab test suite integrated in CI workflow +* Added AMICI dockerfile and image deployment to dockerhub (#948) +* Removed mention of 'mex' in warning/error ids (#968) +* More informative errors on SWIG interface import failures (#959) + +## v0.10.19 (2020-02-13) + +Python: +* Fix logo display on pypi +* Fix deadlocks in multithreaded python environments when using openMP parallelization + +Matlab: +* Fix compilation errors due to switch to C++14 + +## v0.10.18 (2020-02-11) + +General: +* AMICI now comes with a logo +* implement getName function for models +* Updated documentation / examples + +Python: +* Enable MSVC compilation of Python extensions (#847) +* Always recompile clibs and extensions (Closes #700) +* Extended PEtab support (Running +* enable multithreading in swig (#938) +* Fixes pysb (#902) (#907) + +C++ +* Build optimized AMICI and sundials by default (Closes #934) + +Matlab: +* Fix(matlab) Compile CalcMD5 on demand (Fixes #914) +* Don't pass empty include strings to mex +* Fix Matlab compilation error if AMICI or model path contains blanks + +CI: +* Running additional test models + +... and various minor fixes/updates + +## v0.10.17 (2020-01-15) + +- **added python 3.8 support, dropped python 3.6 support** (#898) +- Added logging functionality (#900) +- Fixes PySB import (#879, #902) +- Fixes symbolic processing (#899) +- Improved build scripts (#894, +- Improved petab support (#886, #888, #891) +- CI related fixes (#865, #896) + +## v0.10.16 (2019-12-11) + +* **Sparsify dwdp to reduce computation time for adjoints (#858)** +* Fix(matlab) update example name example_dae_events->example_calvetti (Closes #866) +* Fix nullptr deferencing for simulations with events when no measurements are provided (Fixes #866) +* Fix accessing empty vector during adjoint state event update (Closes #866) +* Fix pysb_import (fixes #878) + + +## v0.10.15 (2019-12-03) + +Bugfix release due to incorrect sensitivities w.r.t. sigmas introduced in 0.10.14. + +No other changes. + +## v0.10.14 (2019-12-02) + +**NOTE: For Python-imported SBML-models this release may compute incorrect sensitivities w.r.t. sigma. Bug introduced in 0.10.14, fixed in 0.10.15.** + +Python: + +* Don't require use of ModelPtr.get to call ExpData(Model) +* Fix import in generated model Python package +* Setup AMICI standalone scripts as setuptools entrypoints +* Simplify symbolic sensitivity expressions during Python SBML import + Fixes Infs in the Jacobian when using Hill-functions with states of 0.0. +* Extended Newton solver #848 + The changes that allow performing Newton tests from the paper: + G. T. Lines, Ł. Paszkowski, L. Schmiester, D. Weindl, P. Stapor, and J. Hasenauer. Efficient computation of steady states in large-scale ODE models of biochemical reaction networks. accepted for Proceedings of the 8th IFAC Conference on Foundations of Systems Biology in Engineering (FOSBE), Valencia, Spain, October 2019. +* Use SWIG>=4.0 on travis to include PyDoc in sdist / pypi package (#841) +* **Fix choice of likelihood formula; failed if observable names were not equal to observable IDs** +* Fix(sbml-import) Compartment IDs in right-hand side of Rules are not replaced and lead to undefined identifiers in c++ files +* Fix invalid logging level +* Speed up sympy simplification (#871) + +C++: + +* Performance: Avoid unnecessary repeated function calls for SUNMatrixWrapper dimensions +* Add AmiciApplication class as context for handling so far global settings. + This allows for example setting custom logging functions for concurrent AMICI + runs, e.g. in multi-thread applications (Closes #576). + +Misc: + +* Setup performance test on github actions (#853) +* Update documentation and FAQ for CBLAS requirement and others +* Update reference list + +## v0.10.13 (2019-10-09) + +* BREAKING CHANGE: Renaming {get|set}tNewtonPreequilibration to {get|set}Preequilibration (Closes #720) +* Make wurlitzer non-optional requirement for AMICI python package (Fixes missing AMICI errors when running from jupyter notebooks) +* Compute initial state for Model::getInitialStates if not already set (Fixes #818) +* Make swig generate pydoc comments from doxygen comments #830 (Closes #745) to provide Python docstrings for C++ wrapper functions +* feature(cmake) Add option to disable compiler optimizations for wrapfunctions.cpp (Fixes #828) (#829) +* Change SBML test suite to pytest to allow for parallel test execution… (#824) +* Fix(cmake): -E option is not available in all sed versions. Neither is the equivalent -r. Use --regexp-extended instead (Closes #826) +* Refactor(python) Move PEtab import code from command line script… (#825) +* Fix(core) Fix regular expressions for intel compiler (Closes #754) (#822) +* Update workflow figure to include PySB (Closes #799) +* Fix compiler warnings + +## v0.10.12 (2019-09-28) + +* Fix handling of species specified in PEtab condition table (#813) +* Fix some Visual C++ issues, update cppcheck handling, cleanup (VisualC++ still not fully supported) +* Minor fixups (#801) +* Create SBML test suite result files for upload to http://sbml.org/Facilities/Database/ (#798) + + +## v0.10.11 (2019-08-31) + +* Fixed setting initial conditions for preequilibration (#784) +* Fixed species->parameter conversion during PEtab import (#782) +* Set correct Matlab include directories in CMake (#793) +* Extended and updated documentation (#785, #787) +* Fix various SBML import issues +* Run SBML test suite using github actions instead of travisCI (#789) + +## v0.10.10 (2019-08-07) + +* Simplify/fix AMICI installation + * If available use environment modules to detect dependencies + + * Add SWIG installation script + +* Update list of publication +* Update documentation + * Update doc for SWIG build and custom SWIG location. + * Add AMICI interface overview / workflow figure and show in README + * Document environment variables for model/core compilation (Closes #737) + +* Added handling of abs function, since there seem to be problems with case sensitivity (#713) Closes #770 + +Detaills: + * cmake: Use package_ROOT environment variables + * fix(cmake) Fix finding version.txt + * cmake: Auto-detect loaded MKL environment module + * cmake: Use new FindPython3 modules where possible + * fix(python) Restore python3.6 compatibility + * Inside venv, use pip instead of pip3 which should point to the correct version + * fix(python) Workaround for missing ensurepip during venv creation [ci skip] + * feature(python) Use MKL from environment modules to provide cblas + * fix(python) Fix define_macros not being passed to setuptools for Extension + * fix(python) Fix define_macros not being passed to setuptools for clibs + * Do not always add 'cblas' library since users may want to override that by a cblas-compatible library with a different name (closes #736) + * Update HDF5 path hints; use shared library if static is not available. + * Check for HDF5_BASE from environment module + * Fix system-dependent sundials library directory (Fixes #749) (#750) + * Handle OSTYPE==linux in scripts/buildBNGL.sh (Fixes #751) + * Add SWIG download and build script + * Improve finding swig executable and allow user override via SWIG environment variable + * Provide installation hints if no SWIG found (Closes #724) + * Allow overriding cmake executable with environment variables in build scripts (Closes #738) + + +## v0.10.9 (2019-07-24) + +Fixup for missing version bump in v0.10.8 release. No code changes compared to v0.10.8. + +## v0.10.8 (2019-07-24) + +Changes in this release: + +All: +- Updated / extended documentation +- Fix reuse of `Solver` instances (#541) + +C++: +- Check for correct AMICI version for model in CMake +- Add reporting of computation times (#699) + +Python: +- Fix manifest file (#698) +- Fix initial amounts/concentrations in SBML import + +... and various other minor fixes/improvements + +## v0.10.7 (2019-05-01) + +Python +* fix unset noise distribution when automatically generating observables in case None are passed (#691) + +## v0.10.6 (2019-04-19) + +C++ +- Add SuperLUMT support (#681) +- Sparsified dJydy (#686) +- Enabled support of impulse-free events for DAE models (#687) - thanks to Sebastien Sten for providing a testcase for this + +Python +- Enabled support for piecewise functions in SBML import (#662) +- Fix numeric type when constructing ExpData from Dataframes (#690) +- Fix dynamic override in PETab + + +## v0.10.5 (2019-04-08) + +Bugfix release + +Doc +- Update documentation of Windows installation + +C++ +- Fix missing source files in CMakeLists.txt (#658) +- Set CMake policies to prevent warnings (Closes #676) (#677) +- Start using gsl::span instead of raw pointers (#393) (#678) + +Python +- PySB parsing fix (#669) +- Fix failure to propagate BLAS_LIBS contents (#665) +- Require setuptools at setup (#673) +- Updated PEtab import to allow for different noise models + + +## v0.10.4 (2019-03-21) + +Features / improvements: + +* Implement ReturnData and ExpData wrappers as more efficient views (#657) +* Add list of references using AMICI (#659) +* Custom llh (normal/laplace, lin/log/log10) (#656) + +Bugfixes: + ++ Speedup and fix travis build + +## v0.10.3 (2019-03-13) + +Features / improvements: + +- adds the option for early termination on integration failures for runAmiciSimulations +- improve runtime of `SUNMatrixWrapper::mutliply` +- expose finite difference routines in public API +- enable parallel compilation of clib source files + +Bugfixes: + +- fixed symbolic processing for unreleased pysb features + +## v0.10.2 (2019-03-07) + +Features / improvements: + +- extended `ExpData` interface to allow for condition specific parameters, parameter scales, parameter lists, initial conditions and initial condition sensitivities. + +Bugfixes: + +- fixed output values of `ReturnData::x_ss` and `ReturnData::sx_ss` + +## v0.10.1 (2019-03-04) + +* travis-ci.com migration +* fix problem with has{variable} functions +* allow to import sbml model from string, not only file + +## v0.10.0 (2019-03-01) + +Features / improvements: + +- updated sundials to 4.1.0 +- updated SuiteSparse to 5.4.0 +- added generic implementations for symbolic expressions that were sparse matrix vector products + +Bugfixes: + +- fixed return value of `rz` when no data is provided. + +## v0.9.5 (2019-02-26) + +Features / improvements: + +- allow python installations without compilation of c++ extension +- improvements to ExpData <-> pandas.DataFrame interface +- allow generation of matlab models from python +- implement CLI interface for PEtab +- improve computation time for conservation laws from pysb import + +Bugfixes: + +- Fix sign in undamped Newton step. + +Maintenance: + +- use newer CI images + +## v0.9.4 (2019-02-11) + +Minor fixes only: +- fix(core) Get solver diagnostics for first(last) timepoint (#588) (Closes #586) +- fix(ci) Fix autodeploy (Closes #589) + +## v0.9.3 (2019-02-07) + +**CRITICAL FIXES** +- **fix(python) fix symbolic computations for adjoint (#583)** + +**Features** +- feature(python) Check for matching AMICI versions when importing model (Closes #556). Set exact AMICI version as model package requirement. +- feature(core) Add option to rethrow AMICI exception (Closes #552) +- feature(python) Redirect C/C++ output in stdout is redirected (e.g. in ipython notebooks) (Closes #456) + +**Minor fixes** +- fix(python) Fix doc and rename sys_pipes to something more meaningful +- fix(ci) Fix premature exit of scripts/runNotebook.sh +- fix(deploy) Update pyenv shims to find twine + + + +## v0.9.2 (2019-01-30) + +Bugfixes: + +- fixes a critical bug in the newton solver +- fixes multiple bugs in sbml import for degenerate models, empty stoichiometry assignments and conversion factors +- improved error messages for sbml import +- #560 +- #557 +- #559 + + +## v0.9.1 (2019-01-21) + +Features / improvements: + +- make pure steadystate results available as `rdata['x_ss']` and `rdata['sx_ss'] ` +- add option to specify integration tolerances for the adjoint problem via `atolB` and `rtolB` + +Bugfixes: + +- improved conservation law identification to also account for constant species. +- fixed a bug where simulation results were written into results of the second newton solver attempt +- fixed an openMP related warning + +Maintenance: + +- attempt to fix automatic deploy to pypi via travis + +## v0.9.0 (2019-01-18) + +Features / improvements: + +- Allow computation and application of conservation laws for pysb importet models. This enables use of NewtonSolver for preequilibration for models where it was previously not possible. +- Use `klu_refactor` in the sparse Newton solver instead of always using `klu_factor` and only perform symbolic factorization once (#421) +- Allow more detailed finiteness checks (#514) + +Bugfixes: + - #491 + +Maintenance: +- Several improvements to travis log sizes and folding +- Use default copy constructor for Model by implementing class wrappers for sundials matrix types (#516) +- Reenable run of SBML testsuite + + +## v0.8.2 (2019-01-07) + +Features / improvements: +* Speedup symbolic processing for ODE generation in python + +Bugfixes: +* Fix(python) Add missing deepcopy (introduced in 6847ba675f2088854db583199b8754aaa6e01576) +* Fix(core) Prevent parameter scaling length mismatch (#488) +* Fix(python) Set distutils dependency to current version to fix +* fix(python) add symlink to version.txt to be included in package + +Backwards-compatibility: +* Replace 'newline' by literal to restore Please use v0.7.0 + +## v0.5.0 (2018-03-15) + +Main new features are: + +- Reimplemented support for DAE equations +- Added newton solver for steady state calculation and preequilibration +- Better caching for recompilation of models +- Blas support to allow compilation of large models with many observables +- Improved SBML support +- Added c++ interface +- Added support for second order adjoint computation + +- Rewrote large parts of the code as proper c++11 code to allow easier code maintanance +- Substantially extended testing in continuous integration to assure code quality + +## v0.4.0 (2017-05-15) + +* First citable version of AMICI (via zenodo integration). +* Better support for standalone compilation +* Improved SBML import scripts +* General Code Cleanup + +## v0.3.0 (2016-09-05) + +This update comes with many improvements, bug fixes and several new features. Most notably: + +1) AMICI should now run on older versions of MATLAB (back to R2014a) +2) AMICI now compiles using older versions of Visual Studio +3) AMICI now also supports second order adjoint sensitivities (full (via the o2flag = 1 and as a vector product via o2flag = 2) +4) AMICI now supports more SBML, SBML v2 and rate rules + + +## 0.2.1 (2016-05-09) + +Bugfix release. This release also includes some changes that should improve the performance on the new R2016a release of MATLAB. + + +## v0.2 (2016-03-17) + +This update comes with many improvements to the computation time for both compilation and simulation. Moreover several new features were included: + +1) Hessian Vector products for second order forward sensitivities +2) Correct treatment of parameter/state dependent discontinuities for both forward and adjoint sensitivities + + +## v0.1 (2015-11-05) + +This is the initial release of the toolbox diff --git a/deps/AMICI/documentation/CI.md b/deps/AMICI/documentation/CI.md index de86b0bfb..93fd106dc 100644 --- a/deps/AMICI/documentation/CI.md +++ b/deps/AMICI/documentation/CI.md @@ -1,6 +1,7 @@ # Continuous integration (CI) and tests -AMICI uses a continuous integration pipeline running on https://travis-ci.org/. +AMICI uses a continuous integration pipeline running via +https://github.com/features/actions. This includes the following steps: - Checking existence and format of documentation @@ -67,7 +68,7 @@ This code is to be updated whenever `amici::Model` changes. ### Regenerating C++ code of the test models -Regeneration of the model code must done whenever `amici::Model` or +Regeneration of the model code has to be done whenever `amici::Model` or the Matlab model import routines change. This is done with @@ -89,7 +90,7 @@ replace `tests/cpputest/expectedResults.h5` by Before replacing the test results, confirm that only expected datasets have changed, e.g. using - h5diff -v -r 1e-8 tests/cpputest/expectedResults.h5 tests/cpputest/writeResults.h5.bak | less + h5diff -v --relative 1e-8 tests/cpputest/expectedResults.h5 tests/cpputest/writeResults.h5.bak | less ## Adding/Updating tests diff --git a/deps/AMICI/documentation/ExampleExperimentalConditions.ipynb b/deps/AMICI/documentation/ExampleExperimentalConditions.ipynb new file mode 120000 index 000000000..269610ab4 --- /dev/null +++ b/deps/AMICI/documentation/ExampleExperimentalConditions.ipynb @@ -0,0 +1 @@ +../python/examples/example_presimulation/ExampleExperimentalConditions.ipynb \ No newline at end of file diff --git a/deps/AMICI/documentation/GettingStarted.ipynb b/deps/AMICI/documentation/GettingStarted.ipynb index a4036aba8..c1bc4df6b 100644 --- a/deps/AMICI/documentation/GettingStarted.ipynb +++ b/deps/AMICI/documentation/GettingStarted.ipynb @@ -185,7 +185,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook only explains the basics of AMICI simulations. In general, AMICI simulations are highly customizable and can also be used to simulate sensitivities. The [ExampleSteadystate](https://amici.readthedocs.io/en/latest/ExampleSteadystate.html) notebook in this folder gives more detail about the model employed here and goes into the basics of sensitivity analysis. The [ExampleEquilibrationLogic](https://amici.readthedocs.io/en/latest/ExampleEquilibrationLogic.html) notebook, builds on this by using a modified version of this model to give detailed insights into the methods and options to compute steady states before and after simulations, as well as respective sensitivities. The [Presimulation example](https://amici.readthedocs.io/en/latest/model_presimulation.html) notebook, goes into the details of how even more complex experimental setups, such as addition of drugs at predefined timepoints, can be simulated in AMICI. Finally, the [petab](https://amici.readthedocs.io/en/latest/petab.html) notebook explains how standardized definitions of experimental data and conditions in the [PEtab](https://github.com/PEtab-dev/PEtab) format can be imported in AMICI." + "This notebook only explains the basics of AMICI simulations. In general, AMICI simulations are highly customizable and can also be used to simulate sensitivities. The [ExampleSteadystate](https://amici.readthedocs.io/en/latest/ExampleSteadystate.html) notebook in this folder gives more detail about the model employed here and goes into the basics of sensitivity analysis. The [ExampleEquilibrationLogic](https://amici.readthedocs.io/en/latest/ExampleEquilibrationLogic.html) notebook, builds on this by using a modified version of this model to give detailed insights into the methods and options to compute steady states before and after simulations, as well as respective sensitivities. The [ExampleExperimentalConditions example](https://amici.readthedocs.io/en/latest/ExampleExperimentalConditions.html) notebook, goes into the details of how even more complex experimental setups, such as addition of drugs at predefined timepoints, can be simulated in AMICI. Finally, the [petab](https://amici.readthedocs.io/en/latest/petab.html) notebook explains how standardized definitions of experimental data and conditions in the [PEtab](https://github.com/PEtab-dev/PEtab) format can be imported in AMICI." ] } ], diff --git a/deps/AMICI/documentation/about.rst b/deps/AMICI/documentation/about.rst index 3533b31f7..468c98c8a 100644 --- a/deps/AMICI/documentation/about.rst +++ b/deps/AMICI/documentation/about.rst @@ -42,7 +42,6 @@ Features * Pre-equilibration and pre-simulation conditions * Support for `discrete events and logical operations `_ - (Matlab-only) Interfaces & workflow ====================== @@ -57,7 +56,8 @@ simulation. .. image:: gfx/amici_workflow.png :alt: AMICI workflow -The functionality of the Python, Matlab and C++ interfaces slightly differ, as shown in the following table: +The functionality of the Python, Matlab and C++ interfaces slightly differ, +as shown in the following table: .. list-table:: :header-rows: 1 @@ -96,8 +96,8 @@ The functionality of the Python, Matlab and C++ interfaces slightly differ, as s - no - yes * - Events - - no - - no + - yes + - yes - yes * - :term:`preequilibration` - yes diff --git a/deps/AMICI/documentation/amici_refs.bib b/deps/AMICI/documentation/amici_refs.bib index 8bcdbb634..e73d87ed4 100644 --- a/deps/AMICI/documentation/amici_refs.bib +++ b/deps/AMICI/documentation/amici_refs.bib @@ -594,34 +594,6 @@ @Article{WangSta2019 url = {http://www.sciencedirect.com/science/article/pii/S2405896319321433}, } -@Article{Staedter2020.09.03.268276, - author = {St{\"a}dter, Philipp and Sch{\"a}lte, Yannik and Schmiester, Leonard and Hasenauer, Jan and Stapor, Paul L.}, - journal = {bioRxiv}, - title = {Benchmarking of numerical integration methods for ODE models of biological systems}, - year = {2020}, - abstract = {Ordinary differential equation (ODE) models are a key tool to understand complex mechanisms in systems biology. These models are studied using various approaches, including stability and bifurcation analysis, but most frequently by numerical simulations. The number of required simulations is often large, e.g., when unknown parameters need to be inferred. This renders efficient and reliable numerical integration methods essential. However, these methods depend on various hyperparameters, which strongly impact the ODE solution. Despite this, and although hundreds of published ODE models are freely available in public databases, a thorough study that quantifies the impact of hyperparameters on the ODE solver in terms of accuracy and computation time is still missing. In this manuscript, we investigate which choices of algorithms and hyperparameters are generally favorable when dealing with ODE models arising from biological processes. To ensure a representative evaluation, we considered 167 published models. Our study provides evidence that most ODEs in computational biology are stiff, and we give guidelines for the choice of algorithms and hyperparameters. We anticipate that our results will help researchers in systems biology to choose appropriate numerical methods when dealing with ODE models.Competing Interest StatementThe authors have declared no competing interest.}, - doi = {10.1101/2020.09.03.268276}, - elocation-id = {2020.09.03.268276}, - eprint = {https://www.biorxiv.org/content/early/2020/09/04/2020.09.03.268276.full.pdf}, - publisher = {Cold Spring Harbor Laboratory}, - timestamp = {2020-09-30}, - url = {https://www.biorxiv.org/content/early/2020/09/04/2020.09.03.268276}, -} - -@Article{RaimundezDud2020, - author = {Raim{\'u}ndez, Elba and Dudkin, Erika and Vanhoefer, Jakob and Alamoudi, Emad and Merkt, Simon and Fuhrmann, Lara and Bai, Fan and Hasenauer, Jan}, - journal = {medRxiv}, - title = {COVID-19 outbreak in Wuhan demonstrates the limitations of publicly available case numbers for epidemiological modelling.}, - year = {2020}, - abstract = {Epidemiological models are widely used to analyse the spread of diseases such as the global COVID-19 pandemic caused by SARS-CoV-2. However, all models are based on simplifying assumptions and on sparse data. This limits the reliability of parameter estimates and predictions. In this manuscript, we demonstrate the relevance of these limitations by performing a study of the COVID-19 outbreak in Wuhan, China. We perform parameter estimation, uncertainty analysis and model selection for a range of established epidemiological models. Amongst others, we employ Markov chain Monte Carlo sampling, parameter and prediction profile calculation algorithms. Our results show that parameter estimates and predictions obtained for several established models on the basis of reported case numbers can be subject to substantial uncertainty. More importantly, estimates were often unrealistic and the confidence / credibility intervals did not cover plausible values of critical parameters obtained using different approaches. These findings suggest, amongst others, that several models are over-simplistic and that the reported case numbers provide often insufficient information.Competing Interest StatementThe authors have declared no competing interest.Funding StatementThis work was supported by the European Union{\textquoteright}s Horizon 2020 research and innovation program (CanPathPro; Grant no. 686282; E.D., J.H., S.M.), the Federal Ministry of Education and Research of Germany (Grant no. 031L0159C; E.A. \& Grant no. 01ZX1705; J.H.), the Federal Ministry of Economic Affairs and Energy (Grant no. 16KN074236; J.V.), and the German Research Foundation (Clusters of Excellence EXC 2047 \& EXC 2151; E.R., F.B., J.H.).Author DeclarationsAll relevant ethical guidelines have been followed; any necessary IRB and/or ethics committee approvals have been obtained and details of the IRB/oversight body are included in the manuscript.YesAll necessary patient/participant consent has been obtained and the appropriate institutional forms have been archived.YesI understand that all clinical trials and any other prospective interventional studies must be registered with an ICMJE-approved registry, such as ClinicalTrials.gov. I confirm that any such study reported in the manuscript has been registered and the trial registration ID is provided (note: if posting a prospective study registered retrospectively, please provide a statement in the trial ID field explaining why the study was not registered in advance).Yes I have followed all appropriate research reporting guidelines and uploaded the relevant EQUATOR Network research reporting checklist(s) and other pertinent material as supplementary files, if applicable.YesThe complete implementation (including the respective version of the used toolboxes) and data are available on ZENODO (https://doi.org/10.5281/zenodo.3757227). This includes the MATLAB code as well as the the specification of the parameter estimation problems as PEtab files (with the model in SBML format).https://doi.org/10.5281/zenodo.3757227}, - doi = {10.1101/2020.04.19.20071597}, - elocation-id = {2020.04.19.20071597}, - eprint = {https://www.medrxiv.org/content/early/2020/04/22/2020.04.19.20071597.full.pdf}, - publisher = {Cold Spring Harbor Laboratory Press}, - timestamp = {2020-11-09}, - url = {https://www.medrxiv.org/content/early/2020/04/22/2020.04.19.20071597}, -} - @Article{GerosaChi2020, author = {Luca Gerosa and Christopher Chidley and Fabian Fröhlich and Gabriela Sanchez and Sang Kyun Lim and Jeremy Muhlich and Jia-Yun Chen and Sreeram Vallabhaneni and Gregory J. Baker and Denis Schapiro and Mariya I. Atanasova and Lily A. Chylek and Tujin Shi and Lian Yi and Carrie D. Nicora and Allison Claas and Thomas S.C. Ng and Rainer H. Kohler and Douglas A. Lauffenburger and Ralph Weissleder and Miles A. Miller and Wei-Jun Qian and H. Steven Wiley and Peter K. Sorger}, journal = {Cell Systems}, @@ -794,6 +766,51 @@ @Article{Erdem2020.11.09.373407 url = {https://www.biorxiv.org/content/early/2020/11/10/2020.11.09.373407}, } +@Article{StaedterSch2021, + author = {Städter, Philipp and Schälte, Yannik and Schmiester, Leonard and Hasenauer, Jan and Stapor, Paul L.}, + journal = {Scientific Reports}, + title = {Benchmarking of numerical integration methods for ODE models of biological systems}, + year = {2021}, + issn = {2045-2322}, + number = {1}, + pages = {2696}, + volume = {11}, + abstract = {Ordinary differential equation (ODE) models are a key tool to understand complex mechanisms in systems biology. These models are studied using various approaches, including stability and bifurcation analysis, but most frequently by numerical simulations. The number of required simulations is often large, e.g., when unknown parameters need to be inferred. This renders efficient and reliable numerical integration methods essential. However, these methods depend on various hyperparameters, which strongly impact the ODE solution. Despite this, and although hundreds of published ODE models are freely available in public databases, a thorough study that quantifies the impact of hyperparameters on the ODE solver in terms of accuracy and computation time is still missing. In this manuscript, we investigate which choices of algorithms and hyperparameters are generally favorable when dealing with ODE models arising from biological processes. To ensure a representative evaluation, we considered 142 published models. Our study provides evidence that most ODEs in computational biology are stiff, and we give guidelines for the choice of algorithms and hyperparameters. We anticipate that our results will help researchers in systems biology to choose appropriate numerical methods when dealing with ODE models.}, + doi = {10.1038/s41598-021-82196-2}, + refid = {Städter2021}, + timestamp = {2021-02-19}, + url = {https://doi.org/10.1038/s41598-021-82196-2}, +} + +@Article{Schmiester2021.02.06.430039, + author = {Schmiester, Leonard and Weindl, Daniel and Hasenauer, Jan}, + journal = {bioRxiv}, + title = {Efficient gradient-based parameter estimation for dynamic models using qualitative data}, + year = {2021}, + abstract = {Motivation Unknown parameters of dynamical models are commonly estimated from experimental data. However, while various efficient optimization and uncertainty analysis methods have been proposed for quantitative data, methods for qualitative data are rare and suffer from bad scaling and convergence.Results Here, we propose an efficient and reliable framework for estimating the parameters of ordinary differential equation models from qualitative data. In this framework, we derive a semi-analytical algorithm for gradient calculation of the optimal scaling method developed for qualitative data. This enables the use of efficient gradient-based optimization algorithms. We demonstrate that the use of gradient information improves performance of optimization and uncertainty quantification on several application examples. On average, we achieve a speedup of more than one order of magnitude compared to gradient-free optimization. Additionally, in some examples, the gradient-based approach yields substantially improved objective function values and quality of the fits. Accordingly, the proposed framework substantially improves the parameterization of models from qualitative data.Availability The proposed approach is implemented in the open-source Python Parameter EStimation TOolbox (pyPESTO). All application examples and code to reproduce this study are available at https://doi.org/10.5281/zenodo.4507613.Competing Interest StatementThe authors have declared no competing interest.}, + doi = {10.1101/2021.02.06.430039}, + elocation-id = {2021.02.06.430039}, + eprint = {https://www.biorxiv.org/content/early/2021/02/08/2021.02.06.430039.full.pdf}, + publisher = {Cold Spring Harbor Laboratory}, + timestamp = {2021-02-19}, + url = {https://www.biorxiv.org/content/early/2021/02/08/2021.02.06.430039}, +} + +@Article{RaimundezDud2021, + author = {Elba Raimúndez and Erika Dudkin and Jakob Vanhoefer and Emad Alamoudi and Simon Merkt and Lara Fuhrmann and Fan Bai and Jan Hasenauer}, + journal = {Epidemics}, + title = {COVID-19 outbreak in Wuhan demonstrates the limitations of publicly available case numbers for epidemiological modeling}, + year = {2021}, + issn = {1755-4365}, + pages = {100439}, + volume = {34}, + abstract = {Epidemiological models are widely used to analyze the spread of diseases such as the global COVID-19 pandemic caused by SARS-CoV-2. However, all models are based on simplifying assumptions and often on sparse data. This limits the reliability of parameter estimates and predictions. In this manuscript, we demonstrate the relevance of these limitations and the pitfalls associated with the use of overly simplistic models. We considered the data for the early phase of the COVID-19 outbreak in Wuhan, China, as an example, and perform parameter estimation, uncertainty analysis and model selection for a range of established epidemiological models. Amongst others, we employ Markov chain Monte Carlo sampling, parameter and prediction profile calculation algorithms. Our results show that parameter estimates and predictions obtained for several established models on the basis of reported case numbers can be subject to substantial uncertainty. More importantly, estimates were often unrealistic and the confidence/credibility intervals did not cover plausible values of critical parameters obtained using different approaches. These findings suggest, amongst others, that standard compartmental models can be overly simplistic and that the reported case numbers provide often insufficient information for obtaining reliable and realistic parameter values, and for forecasting the evolution of epidemics.}, + doi = {https://doi.org/10.1016/j.epidem.2021.100439}, + keywords = {Compartment model, SEIRD, Parameter estimation, Model selection, Uncertainty analysis}, + timestamp = {2021-02-19}, + url = {https://www.sciencedirect.com/science/article/pii/S1755436521000037}, +} + @Comment{jabref-meta: databaseType:bibtex;} @Comment{jabref-meta: grouping: diff --git a/deps/AMICI/documentation/changelog.md b/deps/AMICI/documentation/changelog.md new file mode 120000 index 000000000..04c99a55c --- /dev/null +++ b/deps/AMICI/documentation/changelog.md @@ -0,0 +1 @@ +../CHANGELOG.md \ No newline at end of file diff --git a/deps/AMICI/documentation/index.rst b/deps/AMICI/documentation/index.rst index d230451a3..39a6b4b7e 100644 --- a/deps/AMICI/documentation/index.rst +++ b/deps/AMICI/documentation/index.rst @@ -29,6 +29,7 @@ Welcome to AMICI's documentation! how_to_cite references background + changelog glossary contributing diff --git a/deps/AMICI/documentation/model_presimulation.ipynb b/deps/AMICI/documentation/model_presimulation.ipynb deleted file mode 120000 index 7b73d05c7..000000000 --- a/deps/AMICI/documentation/model_presimulation.ipynb +++ /dev/null @@ -1 +0,0 @@ -../python/examples/example_presimulation/model_presimulation.ipynb \ No newline at end of file diff --git a/deps/AMICI/documentation/python_interface.rst b/deps/AMICI/documentation/python_interface.rst index c605c71d6..9db3a06c7 100644 --- a/deps/AMICI/documentation/python_interface.rst +++ b/deps/AMICI/documentation/python_interface.rst @@ -26,15 +26,31 @@ AMICI can import :term:`SBML` models via the Status of SBML support in Python-AMICI ++++++++++++++++++++++++++++++++++++++ -Python-AMICI currently **passes 862 out of the 1780 (~48%) test cases** from +Python-AMICI currently **passes 996 out of the 1780 (~56%) test cases** from the semantic `SBML Test Suite `_ (`current status `_). -The following SBML test tags are supported +The following SBML test suite tags are currently supported (i.e., at least one test case with the respective test passes; `tag descriptions `_): +**Component tags:** + +* AssignmentRule +* Compartment +* CSymbolAvogadro +* CSymbolTime +* EventNoDelay +* FunctionDefinition +* InitialAssignment +* Parameter +* RateRule +* Reaction +* Species + +**Test tags:** + * 0D-Compartment * Amount * AssignedConstantStoichiometry @@ -44,6 +60,7 @@ The following SBML test tags are supported * Concentration * ConstantSpecies * ConversionFactors +* EventT0Firing * HasOnlySubstanceUnits * InitialValueReassigned * L3v2MathML @@ -63,17 +80,15 @@ In addition, we currently plan to add support for the following features (see corresponding `issues `_ for details and progress): -- Events (currently Matlab-only) (`#757 `_) - Algebraic rules (`#760 `_) -contributions are welcome. - However, the following features are unlikely to be supported: - any SBML extensions - `factorial()`, `ceil()`, `floor()`, due to incompatibility with symbolic sensitivity computations - `delay()` due to missing :term:`SUNDIALS` solver support +- events with delays, events with non-persistent triggers Tutorials +++++++++ @@ -105,7 +120,7 @@ Importing plain ODEs The AMICI Python interface does not currently support direct import of ODEs. However, it is straightforward to encode them as RateRules in an SBML model. -The `yaml2sbml `_ package may come in +The `yaml2sbml `_ package may come in handy, as it facilitates generating SBML models from a YAML-based specification of an ODE model. Besides the SBML model it can also create `PEtab `_ files. @@ -125,7 +140,7 @@ Examples GettingStarted.ipynb ExampleSteadystate.ipynb petab.ipynb - model_presimulation.ipynb + ExampleExperimentalConditions.ipynb ExampleEquilibrationLogic.ipynb @@ -140,21 +155,27 @@ OpenMP support for parallelized simulation for multiple experimental conditions AMICI can be built with OpenMP support, which allows to parallelize model simulations for multiple experimental conditions. -On Linux and OSX this is enabled by default. This can be verified using:: +On Linux and OSX this is enabled by default. This can be verified using: - import amici - amici.compiledWithOpenMP() +.. code-block:: python + + import amici + amici.compiledWithOpenMP() If not already enabled by default, you can enable OpenMP support by setting the environment variables ``AMICI_CXXFLAGS`` and ``AMICI_LDFLAGS`` to the correct OpenMP flags of your compiler and linker, respectively. This has to be done for both AMICI package installation *and* model compilation. When using -``gcc`` on Linux, this would be:: +``gcc`` on Linux, this would be: + +.. code-block:: bash + + # on your shell: + AMICI_CXXFLAGS=-fopenmp AMICI_LDFLAGS=-fopenmp pip3 install amici - # on your shell: - AMICI_CXXFLAGS=-fopenmp AMICI_LDFLAGS=-fopenmp pip3 install amici +.. code-block:: python - # in python, before model compilation: - import os - os.environ['AMICI_CXXFLAGS'] = '-fopenmp' - os.environ['AMICI_LDFLAGS'] = '-fopenmp' + # in python, before model compilation: + import os + os.environ['AMICI_CXXFLAGS'] = '-fopenmp' + os.environ['AMICI_LDFLAGS'] = '-fopenmp' diff --git a/deps/AMICI/documentation/references.md b/deps/AMICI/documentation/references.md index 848f63271..efe862292 100644 --- a/deps/AMICI/documentation/references.md +++ b/deps/AMICI/documentation/references.md @@ -1,11 +1,23 @@ # References -List of publications using AMICI. Total number is 50. +List of publications using AMICI. Total number is 51. If you applied AMICI in your work and your publication is missing, please let us know via a new Github issue. -

2020

-
+

2021

+
+
+

Raimúndez, Elba, Erika Dudkin, Jakob Vanhoefer, Emad Alamoudi, Simon Merkt, Lara Fuhrmann, Fan Bai, and Jan Hasenauer. 2021. “COVID-19 Outbreak in Wuhan Demonstrates the Limitations of Publicly Available Case Numbers for Epidemiological Modeling.” Epidemics 34: 100439. https://doi.org/https://doi.org/10.1016/j.epidem.2021.100439.

+
+
+

Schmiester, Leonard, Daniel Weindl, and Jan Hasenauer. 2021. “Efficient Gradient-Based Parameter Estimation for Dynamic Models Using Qualitative Data.” bioRxiv. https://doi.org/10.1101/2021.02.06.430039.

+
+
+

Städter, Philipp, Yannik Schälte, Leonard Schmiester, Jan Hasenauer, and Paul L. Stapor. 2021. “Benchmarking of Numerical Integration Methods for Ode Models of Biological Systems.” Scientific Reports 11 (1): 2696. https://doi.org/10.1038/s41598-021-82196-2.

+
+
+

2020

+

Alabert, Constance, Carolin Loos, Moritz Voelker-Albert, Simona Graziano, Ignasi Forné, Nazaret Reveron-Gomez, Lea Schuh, et al. 2020. “Domain Model Explains Propagation Dynamics and Stability of Histone H3k27 and H3k36 Methylation Landscapes.” Cell Reports 30 (4): 1223–1234.e8. https://doi.org/10.1016/j.celrep.2019.12.060.

@@ -18,9 +30,6 @@ If you applied AMICI in your work and your publication is missing, please let us

Kuritz, Karsten, Alain R Bonny, João Pedro Fonseca, and Frank Allgöwer. 2020. “PDE-Constrained Optimization for Estimating Population Dynamics over Cell Cycle from Static Single Cell Measurements.” bioRxiv. https://doi.org/10.1101/2020.03.30.015909.

-
-

Raimúndez, Elba, Erika Dudkin, Jakob Vanhoefer, Emad Alamoudi, Simon Merkt, Lara Fuhrmann, Fan Bai, and Jan Hasenauer. 2020. “COVID-19 Outbreak in Wuhan Demonstrates the Limitations of Publicly Available Case Numbers for Epidemiological Modelling.” medRxiv. https://doi.org/10.1101/2020.04.19.20071597.

-

Schälte, Yannik, and Jan Hasenauer. 2020. “Efficient Exact Inference for Dynamical Systems with Noisy Measurements Using Sequential Approximate Bayesian Computation.” bioRxiv. https://doi.org/10.1101/2020.01.30.927004.

@@ -33,9 +42,6 @@ If you applied AMICI in your work and your publication is missing, please let us

Schuh, Lea, Carolin Loos, Daniil Pokrovsky, Axel Imhof, Ralph Rupp, and Carsten Marr. 2020. “Computational Modeling Reveals Cell-Cycle Dependent Kinetics of H4k20 Methylation States During Xenopus Embryogenesis.” bioRxiv. https://doi.org/10.1101/2020.05.28.110684.

-
-

Städter, Philipp, Yannik Schälte, Leonard Schmiester, Jan Hasenauer, and Paul L. Stapor. 2020. “Benchmarking of Numerical Integration Methods for Ode Models of Biological Systems.” bioRxiv. https://doi.org/10.1101/2020.09.03.268276.

-

Sten, Sebastian. 2020. “Mathematical Modeling of Neurovascular Coupling.” Linköping University Medical Dissertations. PhD thesis, Linköping UniversityLinköping UniversityLinköping University, Division of Diagnostics; Specialist Medicine, Faculty of Medicine; Health Sciences, Center for Medical Image Science; Visualization (CMIV); Linköping University, Division of Diagnostics; Specialist Medicine. https://doi.org/10.3384/diss.diva-167806.

@@ -46,8 +52,8 @@ If you applied AMICI in your work and your publication is missing, please let us

Tsipa, Argyro, Jake Alan Pitt, Julio R. Banga, and Athanasios Mantalaris. 2020. “A Dual-Parameter Identification Approach for Data-Based Predictive Modeling of Hybrid Gene Regulatory Network-Growth Kinetics in Pseudomonas Putida Mt-2.” Bioprocess and Biosystems Engineering 43 (9): 1671–88. https://doi.org/10.1007/s00449-020-02360-2.

-

2019

-
+

2019

+

Adlung, Lorenz, Paul Stapor, Christian Tönsing, Leonard Schmiester, Luisa E. Schwarzmüller, Dantong Wang, Jens Timmer, Ursula Klingmüller, Jan Hasenauer, and Marcel Schilling. 2019. “Cell-to-Cell Variability in Jak2/Stat5 Pathway Components and Cytoplasmic Volumes Define Survival Threshold in Erythroid Progenitor Cells.” bioRxiv. https://doi.org/10.1101/866871.

@@ -91,8 +97,8 @@ If you applied AMICI in your work and your publication is missing, please let us

Watanabe, Simon Berglund. 2019. “Identifiability of Parameters in Pbpk Models.” Master’s thesis, Chalmers University of Technology / Department of Mathematical Sciences. https://hdl.handle.net/20.500.12380/256855.

-

2018

-
+

2018

+

Ballnus, Benjamin, Steffen Schaper, Fabian J Theis, and Jan Hasenauer. 2018. “Bayesian Parameter Estimation for Biochemical Reaction Networks Using Region-Based Adaptive Parallel Tempering.” Bioinformatics 34 (13): i494–i501. https://doi.org/10.1093/bioinformatics/bty229.

@@ -127,8 +133,8 @@ If you applied AMICI in your work and your publication is missing, please let us

Villaverde, Alejandro F, Fabian Fröhlich, Daniel Weindl, Jan Hasenauer, and Julio R Banga. 2018. “Benchmarking optimization methods for parameter estimation in large kinetic models.” Bioinformatics 35 (5): 830–38. https://doi.org/10.1093/bioinformatics/bty736.

-

2017

-
+

2017

+

Ballnus, B., S. Hug, K. Hatz, L. Görlitz, J. Hasenauer, and F. J. Theis. 2017. “Comprehensive Benchmarking of Markov Chain Monte Carlo Methods for Dynamical Systems.” BMC Syst. Biol. 11 (63). https://doi.org/10.1186/s12918-017-0433-1.

@@ -145,8 +151,8 @@ If you applied AMICI in your work and your publication is missing, please let us

Maier, C., C. Loos, and J. Hasenauer. 2017. “Robust Parameter Estimation for Dynamical Systems from Outlier-Corrupted Data.” Bioinformatics 33 (5): 718–25. https://doi.org/10.1093/bioinformatics/btw703.

-

2016

-
+

2016

+

Boiger, R., J. Hasenauer, S. Hross, and B. Kaltenbacher. 2016. “Integration Based Profile Likelihood Calculation for PDE Constrained Parameter Estimation Problems.” Inverse Prob. 32 (12): 125009. https://doi.org/10.1088/0266-5611/32/12/125009.

@@ -166,8 +172,8 @@ If you applied AMICI in your work and your publication is missing, please let us

Loos, C., A. Fiedler, and J. Hasenauer. 2016. “Parameter Estimation for Reaction Rate Equation Constrained Mixture Models.” In Proc. 13th Int. Conf. Comp. Meth. Syst. Biol., edited by E. Bartocci, P. Lio, and N. Paoletti, 186–200. Lecture Notes in Bioinformatics. Springer International Publishing. https://doi.org/10.1007/978-3-319-45177-0.

-

2015

-
+

2015

+

Loos, C., C. Marr, F. J. Theis, and J. Hasenauer. 2015. “Computational Methods in Systems Biology.” In, edited by O. Roux and J. Bourdon, 9308:52–63. Lecture Notes in Computer Science. Springer International Publishing. https://doi.org/10.1007/978-3-319-23401-4_6.

diff --git a/deps/AMICI/include/amici/abstract_model.h b/deps/AMICI/include/amici/abstract_model.h index c74bc9f95..dc11b13e9 100644 --- a/deps/AMICI/include/amici/abstract_model.h +++ b/deps/AMICI/include/amici/abstract_model.h @@ -171,7 +171,7 @@ class AbstractModel { const AmiVector &x, const AmiVector &dx) = 0; /** - * @brief Model specific sparse implementation of explicit parameter + * @brief Model-specific sparse implementation of explicit parameter * derivative of right hand side * @param t time * @param x state @@ -195,19 +195,19 @@ class AbstractModel { realtype cj) = 0; /** - * @brief Returns the amici version that was used to generate the model - * @return ver amici version string + * @brief Returns the AMICI version that was used to generate the model + * @return AMICI version string */ - virtual const std::string getAmiciVersion() const; + virtual std::string getAmiciVersion() const; /** - * @brief Returns the amici commit that was used to generate the model - * @return ver amici commit string + * @brief Returns the AMICI commit that was used to generate the model + * @return AMICI commit string */ - virtual const std::string getAmiciCommit() const; + virtual std::string getAmiciCommit() const; /** - * @brief Model specific implementation of fx0 + * @brief Model-specific implementation of fx0 * @param x0 initial state * @param t initial time * @param p parameter vector @@ -225,7 +225,7 @@ class AbstractModel { virtual bool isFixedParameterStateReinitializationAllowed() const; /** - * @brief Model specific implementation of fx0_fixedParameters + * @brief Model-specific implementation of fx0_fixedParameters * @param x0 initial state * @param t initial time * @param p parameter vector @@ -238,7 +238,7 @@ class AbstractModel { gsl::span reinitialization_state_idxs); /** - * @brief Model specific implementation of fsx0_fixedParameters + * @brief Model-specific implementation of fsx0_fixedParameters * @param sx0 initial state sensitivities * @param t initial time * @param x0 initial state @@ -254,7 +254,7 @@ class AbstractModel { gsl::span reinitialization_state_idxs); /** - * @brief Model specific implementation of fsx0 + * @brief Model-specific implementation of fsx0 * @param sx0 initial state sensitivities * @param t initial time * @param x0 initial state @@ -275,7 +275,7 @@ class AbstractModel { virtual void fdx0(AmiVector &x0, AmiVector &dx0); /** - * @brief Model specific implementation of fstau + * @brief Model-specific implementation of fstau * @param stau total derivative of event timepoint * @param t current time * @param x current state @@ -291,7 +291,7 @@ class AbstractModel { const realtype *sx, int ip, int ie); /** - * @brief Model specific implementation of fy + * @brief Model-specific implementation of fy * @param y model output at current timepoint * @param t current time * @param x current state @@ -305,7 +305,7 @@ class AbstractModel { const realtype *w); /** - * @brief Model specific implementation of fdydp + * @brief Model-specific implementation of fdydp * @param dydp partial derivative of observables y w.r.t. model parameters p * @param t current time * @param x current state @@ -321,7 +321,7 @@ class AbstractModel { int ip, const realtype *w, const realtype *dwdp); /** - * @brief Model specific implementation of fdydx + * @brief Model-specific implementation of fdydx * @param dydx partial derivative of observables y w.r.t. model states x * @param t current time * @param x current state @@ -336,7 +336,7 @@ class AbstractModel { const realtype *w, const realtype *dwdx); /** - * @brief Model specific implementation of fz + * @brief Model-specific implementation of fz * @param z value of event output * @param ie event index * @param t current time @@ -349,7 +349,7 @@ class AbstractModel { const realtype *p, const realtype *k, const realtype *h); /** - * @brief Model specific implementation of fsz + * @brief Model-specific implementation of fsz * @param sz Sensitivity of rz, total derivative * @param ie event index * @param t current time @@ -365,7 +365,7 @@ class AbstractModel { const realtype *sx, int ip); /** - * @brief Model specific implementation of frz + * @brief Model-specific implementation of frz * @param rz value of root function at current timepoint (non-output events * not included) * @param ie event index @@ -379,7 +379,7 @@ class AbstractModel { const realtype *p, const realtype *k, const realtype *h); /** - * @brief Model specific implementation of fsrz + * @brief Model-specific implementation of fsrz * @param srz Sensitivity of rz, total derivative * @param ie event index * @param t current time @@ -395,7 +395,7 @@ class AbstractModel { const realtype *h, const realtype *sx, int ip); /** - * @brief Model specific implementation of fdzdp + * @brief Model-specific implementation of fdzdp * @param dzdp partial derivative of event-resolved output z w.r.t. model * parameters p * @param ie event index @@ -411,7 +411,7 @@ class AbstractModel { const realtype *h, int ip); /** - * @brief Model specific implementation of fdzdx + * @brief Model-specific implementation of fdzdx * @param dzdx partial derivative of event-resolved output z w.r.t. model * states x * @param ie event index @@ -426,7 +426,7 @@ class AbstractModel { const realtype *h); /** - * @brief Model specific implementation of fdrzdp + * @brief Model-specific implementation of fdrzdp * @param drzdp partial derivative of root output rz w.r.t. model parameters * p * @param ie event index @@ -442,7 +442,7 @@ class AbstractModel { const realtype *h, int ip); /** - * @brief Model specific implementation of fdrzdx + * @brief Model-specific implementation of fdrzdx * @param drzdx partial derivative of root output rz w.r.t. model states x * @param ie event index * @param t current time @@ -456,7 +456,7 @@ class AbstractModel { const realtype *h); /** - * @brief Model specific implementation of fdeltax + * @brief Model-specific implementation of fdeltax * @param deltax state update * @param t current time * @param x current state @@ -473,7 +473,7 @@ class AbstractModel { const realtype *xdot_old); /** - * @brief Model specific implementation of fdeltasx + * @brief Model-specific implementation of fdeltasx * @param deltasx sensitivity update * @param t current time * @param x current state @@ -496,7 +496,7 @@ class AbstractModel { const realtype *sx, const realtype *stau); /** - * @brief Model specific implementation of fdeltaxB + * @brief Model-specific implementation of fdeltaxB * @param deltaxB adjoint state update * @param t current time * @param x current state @@ -515,7 +515,7 @@ class AbstractModel { const realtype *xB); /** - * @brief Model specific implementation of fdeltaqB + * @brief Model-specific implementation of fdeltaqB * @param deltaqB sensitivity update * @param t current time * @param x current state @@ -535,7 +535,7 @@ class AbstractModel { const realtype *xB); /** - * @brief Model specific implementation of fsigmay + * @brief Model-specific implementation of fsigmay * @param sigmay standard deviation of measurements * @param t current time * @param p parameter vector @@ -545,7 +545,7 @@ class AbstractModel { const realtype *k); /** - * @brief Model specific implementation of fsigmay + * @brief Model-specific implementation of fsigmay * @param dsigmaydp partial derivative of standard deviation of measurements * @param t current time * @param p parameter vector @@ -556,7 +556,7 @@ class AbstractModel { const realtype *p, const realtype *k, int ip); /** - * @brief Model specific implementation of fsigmaz + * @brief Model-specific implementation of fsigmaz * @param sigmaz standard deviation of event measurements * @param t current time * @param p parameter vector @@ -566,7 +566,7 @@ class AbstractModel { const realtype *k); /** - * @brief Model specific implementation of fsigmaz + * @brief Model-specific implementation of fsigmaz * @param dsigmazdp partial derivative of standard deviation of event * measurements * @param t current time @@ -578,7 +578,7 @@ class AbstractModel { const realtype *p, const realtype *k, int ip); /** - * @brief Model specific implementation of fJy + * @brief Model-specific implementation of fJy * @param nllh negative log-likelihood for measurements y * @param iy output index * @param p parameter vector @@ -592,7 +592,7 @@ class AbstractModel { const realtype *sigmay, const realtype *my); /** - * @brief Model specific implementation of fJz + * @brief Model-specific implementation of fJz * @param nllh negative log-likelihood for event measurements z * @param iz event output index * @param p parameter vector @@ -606,7 +606,7 @@ class AbstractModel { const realtype *sigmaz, const realtype *mz); /** - * @brief Model specific implementation of fJrz + * @brief Model-specific implementation of fJrz * @param nllh regularization for event measurements z * @param iz event output index * @param p parameter vector @@ -619,7 +619,7 @@ class AbstractModel { const realtype *sigmaz); /** - * @brief Model specific implementation of fdJydy + * @brief Model-specific implementation of fdJydy * @param dJydy partial derivative of time-resolved measurement negative * log-likelihood Jy * @param iy output index @@ -648,7 +648,7 @@ class AbstractModel { virtual void fdJydy_rowvals(SUNMatrixWrapper &dJydy, int index); /** - * @brief Model specific implementation of fdJydsigma + * @brief Model-specific implementation of fdJydsigma * @param dJydsigma Sensitivity of time-resolved measurement negative * log-likelihood Jy w.r.t. standard deviation sigmay * @param iy output index @@ -663,7 +663,7 @@ class AbstractModel { const realtype *sigmay, const realtype *my); /** - * @brief Model specific implementation of fdJzdz + * @brief Model-specific implementation of fdJzdz * @param dJzdz partial derivative of event measurement negative * log-likelihood Jz * @param iz event output index @@ -678,7 +678,7 @@ class AbstractModel { const realtype *sigmaz, const realtype *mz); /** - * @brief Model specific implementation of fdJzdsigma + * @brief Model-specific implementation of fdJzdsigma * @param dJzdsigma Sensitivity of event measurement negative log-likelihood * Jz w.r.t. standard deviation sigmaz * @param iz event output index @@ -693,7 +693,7 @@ class AbstractModel { const realtype *sigmaz, const realtype *mz); /** - * @brief Model specific implementation of fdJrzdz + * @brief Model-specific implementation of fdJrzdz * @param dJrzdz partial derivative of event penalization Jrz * @param iz event output index * @param p parameter vector @@ -706,7 +706,7 @@ class AbstractModel { const realtype *sigmaz); /** - * @brief Model specific implementation of fdJrzdsigma + * @brief Model-specific implementation of fdJrzdsigma * @param dJrzdsigma Sensitivity of event penalization Jrz w.r.t. standard * deviation sigmaz * @param iz event output index @@ -720,7 +720,7 @@ class AbstractModel { const realtype *sigmaz); /** - * @brief Model specific implementation of fw + * @brief Model-specific implementation of fw * @param w Recurring terms in xdot * @param t timepoint * @param x vector with the states @@ -734,7 +734,7 @@ class AbstractModel { const realtype *tcl); /** - * @brief Model specific sparse implementation of dwdp + * @brief Model-specific sparse implementation of dwdp * @param dwdp Recurring terms in xdot, parameter derivative * @param t timepoint * @param x vector with the states @@ -751,19 +751,19 @@ class AbstractModel { const realtype *stcl); /** - * @brief Model specific implementation for dwdp, column pointers + * @brief Model-specific implementation for dwdp, column pointers * @param dwdp sparse matrix to which colptrs will be written */ virtual void fdwdp_colptrs(SUNMatrixWrapper &dwdp); /** - * @brief Model specific implementation for dwdp, row values + * @brief Model-specific implementation for dwdp, row values * @param dwdp sparse matrix to which rowvals will be written */ virtual void fdwdp_rowvals(SUNMatrixWrapper &dwdp); /** - * @brief Model specific sensitivity implementation of dwdp + * @brief Model-specific sensitivity implementation of dwdp * @param dwdp Recurring terms in xdot, parameter derivative * @param t timepoint * @param x vector with the states @@ -781,7 +781,7 @@ class AbstractModel { const realtype *stcl, int ip); /** - * @brief Model specific implementation of dwdx, data part + * @brief Model-specific implementation of dwdx, data part * @param dwdx Recurring terms in xdot, state derivative * @param t timepoint * @param x vector with the states @@ -796,19 +796,19 @@ class AbstractModel { const realtype *w, const realtype *tcl); /** - * @brief Model specific implementation for dwdx, column pointers + * @brief Model-specific implementation for dwdx, column pointers * @param dwdx sparse matrix to which colptrs will be written */ virtual void fdwdx_colptrs(SUNMatrixWrapper &dwdx); /** - * @brief Model specific implementation for dwdx, row values + * @brief Model-specific implementation for dwdx, row values * @param dwdx sparse matrix to which rowvals will be written */ virtual void fdwdx_rowvals(SUNMatrixWrapper &dwdx); /** - * @brief Model specific implementation of fdwdw, no w chainrule (Py) + * @brief Model-specific implementation of fdwdw, no w chainrule (Py) * @param dwdw partial derivative w wrt w * @param t timepoint * @param x Vector with the states @@ -823,13 +823,13 @@ class AbstractModel { const realtype *w, const realtype *tcl); /** - * @brief Model specific implementation of fdwdw, colptrs part + * @brief Model-specific implementation of fdwdw, colptrs part * @param dwdw sparse matrix to which colptrs will be written */ virtual void fdwdw_colptrs(SUNMatrixWrapper &dwdw); /** - * @brief Model specific implementation of fdwdw, rowvals part + * @brief Model-specific implementation of fdwdw, rowvals part * @param dwdw sparse matrix to which rowvals will be written */ virtual void fdwdw_rowvals(SUNMatrixWrapper &dwdw); diff --git a/deps/AMICI/include/amici/edata.h b/deps/AMICI/include/amici/edata.h index d43d0a91e..1ed10896d 100644 --- a/deps/AMICI/include/amici/edata.h +++ b/deps/AMICI/include/amici/edata.h @@ -34,19 +34,19 @@ class ExpData : public SimulationParameters { /** * @brief constructor that only initializes dimensions * - * @param nytrue - * @param nztrue - * @param nmaxevent + * @param nytrue Number of observables + * @param nztrue Number of event outputs + * @param nmaxevent Maximal number of events to track */ ExpData(int nytrue, int nztrue, int nmaxevent); /** * @brief constructor that initializes timepoints from vectors * - * @param nytrue (dimension: scalar) - * @param nztrue (dimension: scalar) - * @param nmaxevent (dimension: scalar) - * @param ts (dimension: nt) + * @param nytrue Number of observables + * @param nztrue Number of event outputs + * @param nmaxevent Maximal number of events to track + * @param ts Timepoints (dimension: nt) */ ExpData(int nytrue, int nztrue, int nmaxevent, std::vector ts); @@ -54,11 +54,11 @@ class ExpData : public SimulationParameters { * @brief constructor that initializes timepoints and fixed parameters from * vectors * - * @param nytrue (dimension: scalar) - * @param nztrue (dimension: scalar) - * @param nmaxevent (dimension: scalar) - * @param ts (dimension: nt) - * @param fixedParameters (dimension: nk) + * @param nytrue Number of observables + * @param nztrue Number of event outputs + * @param nmaxevent Maximal number of events to track + * @param ts Timepoints (dimension: nt) + * @param fixedParameters Model constants (dimension: nk) */ ExpData(int nytrue, int nztrue, int nmaxevent, std::vector ts, std::vector fixedParameters); @@ -66,14 +66,17 @@ class ExpData : public SimulationParameters { /** * @brief constructor that initializes timepoints and data from vectors * - * @param nytrue (dimension: scalar) - * @param nztrue (dimension: scalar) - * @param nmaxevent (dimension: scalar) - * @param ts (dimension: nt) - * @param observedData (dimension: nt x nytrue, row-major) - * @param observedDataStdDev (dimension: nt x nytrue, row-major) - * @param observedEvents (dimension: nmaxevent x nztrue, row-major) - * @param observedEventsStdDev (dimension: nmaxevent x nztrue, row-major) + * @param nytrue Number of observables + * @param nztrue Number of event outputs + * @param nmaxevent Maximal number of events to track + * @param ts Timepoints (dimension: nt) + * @param observedData observed data (dimension: nt x nytrue, row-major) + * @param observedDataStdDev standard deviation of observed data + * (dimension: nt x nytrue, row-major) + * @param observedEvents observed events + * (dimension: nmaxevents x nztrue, row-major) + * @param observedEventsStdDev standard deviation of observed events/roots + * (dimension: nmaxevents x nztrue, row-major) */ ExpData(int nytrue, int nztrue, int nmaxevent, std::vector ts, std::vector const &observedData, @@ -142,7 +145,7 @@ class ExpData : public SimulationParameters { int nt() const; /** - * @brief set function that copies data from input to ExpData::ts + * @brief Set function that copies data from input to ExpData::ts * * @param ts timepoints */ @@ -373,11 +376,11 @@ class ExpData : public SimulationParameters { /** * @brief get function that returns a pointer to standard deviation of - * observed event data at ieth occurrence + * observed event data at ie-th occurrence * * @param ie event occurrence * - * @return pointer to standard deviation of observed event data at ieth + * @return pointer to standard deviation of observed event data at ie-th * occurrence */ const realtype *getObservedEventsStdDevPtr(int ie) const; @@ -429,6 +432,7 @@ class ExpData : public SimulationParameters { /** @brief observed data (dimension: nt x nytrue, row-major) */ std::vector observed_data_; + /** * @brief standard deviation of observed data (dimension: nt x nytrue, * row-major) @@ -439,6 +443,7 @@ class ExpData : public SimulationParameters { * @brief observed events (dimension: nmaxevents x nztrue, row-major) */ std::vector observed_events_; + /** * @brief standard deviation of observed events/roots * (dimension: nmaxevents x nztrue, row-major) diff --git a/deps/AMICI/include/amici/exception.h b/deps/AMICI/include/amici/exception.h index 5b9b2c226..6556e5fcd 100644 --- a/deps/AMICI/include/amici/exception.h +++ b/deps/AMICI/include/amici/exception.h @@ -130,12 +130,8 @@ class IntegrationFailureB : public AmiException { * and an error will be thrown */ class SetupFailure : public AmiException { -public: - /** - * @brief Constructor, simply calls AmiException constructor - * @param msg - */ - explicit SetupFailure(const char *msg) : AmiException(msg) {} + public: + using AmiException::AmiException; }; diff --git a/deps/AMICI/include/amici/misc.h b/deps/AMICI/include/amici/misc.h index dd59b03fc..ee069b522 100644 --- a/deps/AMICI/include/amici/misc.h +++ b/deps/AMICI/include/amici/misc.h @@ -44,8 +44,8 @@ gsl::span slice(std::vector &data, int index, unsigned size) { */ template -const gsl::span slice(const std::vector &data, - int index, unsigned size) { +gsl::span slice(const std::vector &data, + int index, unsigned size) { if ((index + 1) * size > data.size()) throw std::out_of_range("requested slice is out of data range"); if (size > 0) diff --git a/deps/AMICI/include/amici/newton_solver.h b/deps/AMICI/include/amici/newton_solver.h index 73a924a97..01c033aeb 100644 --- a/deps/AMICI/include/amici/newton_solver.h +++ b/deps/AMICI/include/amici/newton_solver.h @@ -154,6 +154,8 @@ class NewtonSolverDense : public NewtonSolver { NewtonSolverDense(const NewtonSolverDense&) = delete; + NewtonSolverDense& operator=(const NewtonSolverDense& other) = delete; + ~NewtonSolverDense() override; /** @@ -212,6 +214,8 @@ class NewtonSolverSparse : public NewtonSolver { NewtonSolverSparse(const NewtonSolverSparse&) = delete; + NewtonSolverSparse& operator=(const NewtonSolverSparse& other) = delete; + ~NewtonSolverSparse() override; /** diff --git a/deps/AMICI/include/amici/rdata.h b/deps/AMICI/include/amici/rdata.h index 819fc1716..1637f67ed 100644 --- a/deps/AMICI/include/amici/rdata.h +++ b/deps/AMICI/include/amici/rdata.h @@ -29,18 +29,17 @@ namespace amici { /** * @brief Stores all data to be returned by amici::runAmiciSimulation. * - * NOTE: multidimensional arrays are stored in row-major order - * (FORTRAN-style) + * NOTE: multi-dimensional arrays are stored in row-major order (C-style) */ class ReturnData: public ModelDimensions { public: /** - * @brief default constructor + * @brief Default constructor */ ReturnData() = default; /** - * @brief ReturnData + * @brief Constructor * @param ts see amici::SimulationParameters::ts * @param model_dimensions Model dimensions * @param nplist see amici::ModelDimensions::nplist @@ -52,8 +51,8 @@ class ReturnData: public ModelDimensions { * @param sensi see amici::Solver::sensi * @param sensi_meth see amici::Solver::sensi_meth * @param rdrm see amici::Solver::rdata_reporting - * @param quadratic_llh whether model defines a quadratic nllh and computing res, sres and - * FIM makes sense + * @param quadratic_llh whether model defines a quadratic nllh and + * computing res, sres and FIM makes sense */ ReturnData(std::vector ts, ModelDimensions const& model_dimensions, @@ -76,10 +75,10 @@ class ReturnData: public ModelDimensions { /** * @brief constructor that uses information from model and solver to * appropriately initialize fields - * @param preeq simulated preequilibration problem, pass nullptr to ignore - * @param fwd simulated forward problem, pass nullptr to ignore - * @param bwd simulated backward problem, pass nullptr to ignore - * @param posteq simulated postequilibration problem, pass nullptr to ignore + * @param preeq simulated preequilibration problem, pass `nullptr` to ignore + * @param fwd simulated forward problem, pass `nullptr` to ignore + * @param bwd simulated backward problem, pass `nullptr` to ignore + * @param posteq simulated postequilibration problem, pass `nullptr` to ignore * @param model matching model instance * @param solver matching solver instance * @param edata matching experimental data @@ -137,7 +136,7 @@ class ReturnData: public ModelDimensions { std::vector srz; /** - * second order parameter derivative of event trigger output (shape + * second-order parameter derivative of event trigger output (shape * `nmaxevent` x `nztrue` x `nplist` x `nplist`, row-major) */ std::vector s2rz; @@ -305,28 +304,30 @@ class ReturnData: public ModelDimensions { std::vector sx0; /** - * preequilibration sensitivities found by Newton solver (shape `nplist` x `nx`, row-major) + * preequilibration sensitivities found by Newton solver + * (shape `nplist` x `nx`, row-major) */ std::vector sx_ss; - /** loglikelihood value */ + /** log-likelihood value */ realtype llh = 0.0; - /** chi2 value */ + /** \f$\chi^2\f$ value */ realtype chi2 = 0.0; - /** parameter derivative of loglikelihood (shape `nplist`) */ + /** parameter derivative of log-likelihood (shape `nplist`) */ std::vector sllh; /** - * second order parameter derivative of loglikelihood (shape `nJ-1` x `nplist`, row-major) + * second-order parameter derivative of log-likelihood + * (shape `nJ-1` x `nplist`, row-major) */ std::vector s2llh; /** status code */ int status = 0; - /** number of states (alias nx_rdata, kept for backward compatibility) */ + /** number of states (alias `nx_rdata`, kept for backward compatibility) */ int nx{0}; /** @@ -347,10 +348,10 @@ class ReturnData: public ModelDimensions { /** maximal number of newton iterations for steady state calculation */ int newton_maxsteps{0}; - /** scaling of parameterization (lin,log,log10) */ + /** scaling of parameterization */ std::vector pscale; - /** flag indicating whether second order sensitivities were requested */ + /** flag indicating whether second-order sensitivities were requested */ SecondOrderMode o2mode{SecondOrderMode::none}; /** sensitivity order */ @@ -425,16 +426,16 @@ class ReturnData: public ModelDimensions { void initializeObjectiveFunction(bool enable_chi2); /** - * @brief extracts data from a preequilibration steadystateproblem - * @param preeq Steadystateproblem for preequilibration + * @brief extracts data from a preequilibration SteadystateProblem + * @param preeq SteadystateProblem for preequilibration * @param model Model instance to compute return values */ void processPreEquilibration(SteadystateProblem const &preeq, Model &model); /** - * @brief extracts data from a preequilibration steadystateproblem - * @param posteq Steadystateproblem for postequilibration + * @brief extracts data from a preequilibration SteadystateProblem + * @param posteq SteadystateProblem for postequilibration * @param model Model instance to compute return values * @param edata ExpData instance containing observable data */ @@ -457,7 +458,7 @@ class ReturnData: public ModelDimensions { * @brief extracts results from backward problem * @param fwd forward problem * @param bwd backward problem - * @param preeq Steadystateproblem for preequilibration + * @param preeq SteadystateProblem for preequilibration * @param model model that was used for forward/backward simulation */ void processBackwardProblem(ForwardProblem const &fwd, @@ -572,8 +573,8 @@ class ReturnData: public ModelDimensions { } /** - * @brief Extracts output information for data-points, expects that x_solver and sx_solver were - * were set appropriately + * @brief Extracts output information for data-points, expects that + * x_solver_ and sx_solver_ were set appropriately * @param it timepoint index * @param model model that was used in forward solve * @param edata ExpData instance carrying experimental data @@ -581,8 +582,8 @@ class ReturnData: public ModelDimensions { void getDataOutput(int it, Model &model, ExpData const *edata); /** - * @brief Extracts data information for forward sensitivity analysis, expects that x_solver and - * sx_solver were were set appropriately + * @brief Extracts data information for forward sensitivity analysis, + * expects that x_solver_ and sx_solver_ were set appropriately * @param it index of current timepoint * @param model model that was used in forward solve * @param edata ExpData instance carrying experimental data @@ -590,10 +591,11 @@ class ReturnData: public ModelDimensions { void getDataSensisFSA(int it, Model &model, ExpData const *edata); /** - * @brief Extracts output information for events, expects that x_solver and sx_solver were - * were set appropriately + * @brief Extracts output information for events, expects that x_solver_ + * and sx_solver_ were set appropriately * @param t event timepoint - * @param rootidx information about which roots fired (1 indicating fired, 0/-1 for not) + * @param rootidx information about which roots fired + * (1 indicating fired, 0/-1 for not) * @param model model that was used in forward solve * @param edata ExpData instance carrying experimental data */ @@ -601,8 +603,8 @@ class ReturnData: public ModelDimensions { Model &model, ExpData const *edata); /** - * @brief Extracts event information for forward sensitivity analysis, expects that x_solver and - * sx_solver were set appropriately + * @brief Extracts event information for forward sensitivity analysis, + * expects that x_solver_ and sx_solver_ were set appropriately * @param ie index of event type * @param t event timepoint * @param model model that was used in forward solve @@ -615,7 +617,7 @@ class ReturnData: public ModelDimensions { * @brief Updates contribution to likelihood from quadratures (xQB), * if preequilibration was run in adjoint mode * @param model model that was used for forward/backward simulation - * @param preeq Steadystateproblem for preequilibration + * @param preeq SteadystateProblem for preequilibration * @param xQB vector with quadratures from adjoint computation */ void handleSx0Backward(const Model &model, SteadystateProblem const &preeq, diff --git a/deps/AMICI/include/amici/returndata_matlab.h b/deps/AMICI/include/amici/returndata_matlab.h index c4944622f..ae9b05885 100644 --- a/deps/AMICI/include/amici/returndata_matlab.h +++ b/deps/AMICI/include/amici/returndata_matlab.h @@ -53,7 +53,7 @@ void writeMatlabField0(mxArray *matlabStruct, const char *fieldName, */ template void writeMatlabField1(mxArray *matlabStruct, const char *fieldName, - std::vector const &fieldData, const int dim0); + gsl::span const &fieldData, const int dim0); /** * @brief initialize matrix, attach to the field and write data diff --git a/deps/AMICI/include/amici/vector.h b/deps/AMICI/include/amici/vector.h index 25462354b..c50499f10 100644 --- a/deps/AMICI/include/amici/vector.h +++ b/deps/AMICI/include/amici/vector.h @@ -14,7 +14,7 @@ namespace amici { /** Since const N_Vector is not what we want */ using const_N_Vector = - std::add_const::type>::type *; + std::add_const_t> *; inline const realtype* N_VGetArrayPointerConst(const_N_Vector x) { return N_VGetArrayPointer(const_cast(x)); diff --git a/deps/AMICI/matlab/@amimodel/amimodel.m b/deps/AMICI/matlab/@amimodel/amimodel.m index 1b77aac6b..cef415bdf 100644 --- a/deps/AMICI/matlab/@amimodel/amimodel.m +++ b/deps/AMICI/matlab/@amimodel/amimodel.m @@ -241,6 +241,8 @@ function updateWrapPath(this,wrap_path) generateC(this) + generateRebuildM(this) + compileC(this) generateM(this,amimodelo2) diff --git a/deps/AMICI/matlab/@amimodel/generateC.m b/deps/AMICI/matlab/@amimodel/generateC.m index 6b5e8264f..d2d0435a3 100644 --- a/deps/AMICI/matlab/@amimodel/generateC.m +++ b/deps/AMICI/matlab/@amimodel/generateC.m @@ -191,12 +191,12 @@ function generateC(this) initstr = num2str(transpose(this.z2event), '%d, '); fprintf(fid,[' std::vector{' initstr(1:end-1) '})\n']); fprintf(fid,[' {};\n\n']); -fprintf(fid,[' virtual amici::Model* clone() const override { return new Model_' this.modelname '(*this); };\n\n']); -fprintf(fid,[' const std::string getAmiciCommit() const override { return "' getCommitHash(fileparts(fileparts(mfilename('fullpath')))) '"; };\n\n']); +fprintf(fid,[' amici::Model* clone() const override { return new Model_' this.modelname '(*this); };\n\n']); +fprintf(fid,[' std::string getAmiciCommit() const override { return "' getCommitHash(fileparts(fileparts(mfilename('fullpath')))) '"; };\n\n']); for ifun = this.funs cppFunctionName = strrep(ifun{1}, 'sigma_', 'sigma'); - fprintf(fid,[' virtual void f' cppFunctionName this.fun.(ifun{1}).argstr ' override {\n']); + fprintf(fid,[' void f' cppFunctionName this.fun.(ifun{1}).argstr ' override {\n']); if(checkIfFunctionBodyIsNonEmpty(this,ifun{1})) fprintf(fid,[' ' cppFunctionName '_' this.modelname '' removeTypes(this.fun.(ifun{1}).argstr) ';\n']); end diff --git a/deps/AMICI/matlab/@amimodel/generateRebuildM.m b/deps/AMICI/matlab/@amimodel/generateRebuildM.m new file mode 100644 index 000000000..56b213af7 --- /dev/null +++ b/deps/AMICI/matlab/@amimodel/generateRebuildM.m @@ -0,0 +1,26 @@ +function generateRebuildM(this) +% generateRebuildM generates a Matlab script for recompilation of this +% model +% +% Return values: +% void + + +filename = fullfile(this.wrap_path,'models',this.modelname,['rebuild_',this.modelname,'.m']); +% would require struct to string conversion, skipping for now +amimodelo2 = '[]'; + +fid = fopen(filename, 'w'); + +fprintf(fid, ['function ' ['rebuild_', this.modelname] '()\n']); +fprintf(fid, ['modelName = ''' this.modelname ''';\n']); +fprintf(fid, 'amimodel.compileAndLinkModel(modelName, '''', [], [], [], []);\n'); +fprintf(fid, ['amimodel.generateMatlabWrapper(' num2str(this.nx) ', ' num2str(this.ny) ... + ', ' num2str(this.np) ', ' num2str(this.nk) ', ' num2str(this.nz) ', ' num2str(this.o2flag) ', ' ... + amimodelo2 ', [''simulate_'' modelName ''.m''], ''' ... + this.modelname ''', ''' this.param ''', ' num2str(this.forward) ', ' num2str(this.adjoint) ');\n']); +fprintf(fid, 'end\n'); + +fclose(fid); +end + diff --git a/deps/AMICI/matlab/amiwrap.m b/deps/AMICI/matlab/amiwrap.m index 842b3a3a5..838d95c10 100644 --- a/deps/AMICI/matlab/amiwrap.m +++ b/deps/AMICI/matlab/amiwrap.m @@ -169,8 +169,10 @@ function amiwrap( varargin ) % generate the matlab wrapper disp('Generating M code ...') if(o2flag) + model.generateRebuildM() model.generateM(modelo2); else + model.generateRebuildM() model.generateM([]); end diff --git a/deps/AMICI/matlab/tests/testModels.m b/deps/AMICI/matlab/tests/testModels.m index a0e3516a9..baf1c57bd 100644 --- a/deps/AMICI/matlab/tests/testModels.m +++ b/deps/AMICI/matlab/tests/testModels.m @@ -4,24 +4,33 @@ function testModels() % disable specific warnings for these tests, some tests are supposed % to produce warnings warningreset = warning; - warning('off','AMICI:mex:simulation') - warning('off','AMICI:mex:CVODES:CVode:TOO_MUCH_WORK') + warning('off','AMICI:simulation') + warning('off','AMICI:CVODES:CVode:TOO_MUCH_WORK') + % second-order currently not supported via rebuild_*.m (GitHub Actions) + % only via wrapTestModels ignoredTests = {'/model_jakstat_adjoint/sensiadjointemptysensind', ... - '/model_jakstat_adjoint/sensiforwardemptysensind'}; + '/model_jakstat_adjoint/sensiforwardemptysensind', ... + '/model_jakstat_adjoint/sensi2adjoint', ... + '/model_jakstat_adjoint/sensi2forward', ... + '/model_jakstat_adjoint/sensi2forwardlogparam', ... + '/model_neuron/sensi2forward'}; + model_dir = [fileparts(mfilename('fullpath')) '/../../models/']; cd(fileparts(mfilename('fullpath'))) addpath(genpath('../../tests/cpputest')); addpath(genpath('../examples')); % wrapTestModels() - cd(fileparts(mfilename('fullpath'))) + cd(fileparts(mfilename('fullpath'))) hdf5file = fullfile(fileparts(mfilename('fullpath')), ... '../../tests/cpputest', 'expectedResults.h5'); - + info = h5info(hdf5file); for imodel = 1:length(info.Groups) - if(~isempty(regexp(info.Groups(imodel).Name(2:end),'^model_neuron'))) + modelname = info.Groups(imodel).Name(2:end); + + if(~isempty(regexp(modelname,'^model_neuron'))) model_atol = 1e-9; model_rtol = 1e-4; else @@ -29,13 +38,25 @@ function testModels() model_rtol = 1e-5; end for itest = 1:length(info.Groups(imodel).Groups) - if(ismember(info.Groups(imodel).Groups(itest).Name, ignoredTests)) + testname = info.Groups(imodel).Groups(itest).Name; + if(ismember(testname, ignoredTests)) continue end + + display(testname); [results,options,data,t,theta,kappa] = readDataFromHDF5(info.Groups(imodel).Groups(itest),hdf5file); - sol = getResults(info.Groups(imodel).Name(2:end),options,data,t,theta,kappa); + + % rebuild model + old_path = addpath([model_dir modelname]); + old_pwd = cd([model_dir modelname]); + rebuild = str2func(['rebuild_' modelname]); + rebuild(); + cd(old_pwd); + + sol = getResults(modelname,options,data,t,theta,kappa); compareResults(sol,results); + path(old_path); end end diff --git a/deps/AMICI/models/model_calvetti/model_calvetti.h b/deps/AMICI/models/model_calvetti/model_calvetti.h index 97ba91b8f..0a326de31 100644 --- a/deps/AMICI/models/model_calvetti/model_calvetti.h +++ b/deps/AMICI/models/model_calvetti/model_calvetti.h @@ -1,6 +1,6 @@ #ifndef _amici_model_calvetti_h #define _amici_model_calvetti_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -65,138 +65,138 @@ class Model_model_calvetti : public amici::Model_DAE { std::vector{}) {}; - virtual amici::Model* clone() const override { return new Model_model_calvetti(*this); }; + amici::Model* clone() const override { return new Model_model_calvetti(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) override { JSparse_model_calvetti(JSparse, t, x, p, k, h, cj, dx, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_calvetti(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fM(realtype *M, const realtype t, const realtype *x, const realtype *p, const realtype *k) override { + void fM(realtype *M, const realtype t, const realtype *x, const realtype *p, const realtype *k) override { M_model_calvetti(M, t, x, p, k); } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_calvetti(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_calvetti(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { dwdx_model_calvetti(dwdx, t, x, p, k, h, w, tcl); } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *dx, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *dx, const realtype *w, const realtype *dwdp) override { } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_calvetti(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx) override { root_model_calvetti(root, t, x, p, k, h, dx); } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_calvetti(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { w_model_calvetti(w, t, x, p, k, h, tcl); } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { x0_model_calvetti(x0, t, p, k); } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx, const realtype *w) override { xdot_model_calvetti(xdot, t, x, p, k, h, dx, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_calvetti(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } }; diff --git a/deps/AMICI/models/model_calvetti/rebuild_model_calvetti.m b/deps/AMICI/models/model_calvetti/rebuild_model_calvetti.m new file mode 100644 index 000000000..ef44a7afc --- /dev/null +++ b/deps/AMICI/models/model_calvetti/rebuild_model_calvetti.m @@ -0,0 +1,5 @@ +function rebuild_model_calvetti() +modelName = 'model_calvetti'; +amimodel.compileAndLinkModel(modelName, '', [], [], [], []); +amimodel.generateMatlabWrapper(6, 6, 0, 6, 0, 0, [], ['simulate_' modelName '.m'], 'model_calvetti', 'lin', 1, 1); +end diff --git a/deps/AMICI/models/model_dirac/model_dirac.h b/deps/AMICI/models/model_dirac/model_dirac.h index 5a22ab5d5..2eb5cdb4b 100644 --- a/deps/AMICI/models/model_dirac/model_dirac.h +++ b/deps/AMICI/models/model_dirac/model_dirac.h @@ -1,6 +1,6 @@ #ifndef _amici_model_dirac_h #define _amici_model_dirac_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -65,135 +65,135 @@ class Model_model_dirac : public amici::Model_ODE { std::vector{}) {}; - virtual amici::Model* clone() const override { return new Model_model_dirac(*this); }; + amici::Model* clone() const override { return new Model_model_dirac(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_dirac(JSparse, t, x, p, k, h, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_dirac(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_dirac(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_dirac(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { deltasx_model_dirac(deltasx, t, x, p, k, h, w, ip, ie, xdot, xdot_old, sx, stau); } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { deltax_model_dirac(deltax, t, x, p, k, h, ie, xdot, xdot_old); } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dxdotdp_model_dirac(dxdotdp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_dirac(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { root_model_dirac(root, t, x, p, k, h); } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_dirac(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { stau_model_dirac(stau, t, x, p, k, h, sx, ip, ie); } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { xdot_model_dirac(xdot, t, x, p, k, h, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_dirac(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } }; diff --git a/deps/AMICI/models/model_dirac/rebuild_model_dirac.m b/deps/AMICI/models/model_dirac/rebuild_model_dirac.m new file mode 100644 index 000000000..66aa6f62d --- /dev/null +++ b/deps/AMICI/models/model_dirac/rebuild_model_dirac.m @@ -0,0 +1,5 @@ +function rebuild_model_dirac() +modelName = 'model_dirac'; +amimodel.compileAndLinkModel(modelName, '', [], [], [], []); +amimodel.generateMatlabWrapper(2, 1, 4, 0, 0, 0, [], ['simulate_' modelName '.m'], 'model_dirac', 'log10', 1, 1); +end diff --git a/deps/AMICI/models/model_events/model_events.h b/deps/AMICI/models/model_events/model_events.h index 77c803e25..2cf13ace8 100644 --- a/deps/AMICI/models/model_events/model_events.h +++ b/deps/AMICI/models/model_events/model_events.h @@ -1,6 +1,6 @@ #ifndef _amici_model_events_h #define _amici_model_events_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -79,148 +79,148 @@ class Model_model_events : public amici::Model_ODE { std::vector{1, 2}) {}; - virtual amici::Model* clone() const override { return new Model_model_events(*this); }; + amici::Model* clone() const override { return new Model_model_events(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_events(JSparse, t, x, p, k, h, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { Jrz_model_events(nllh, iz, p, k, rz, sigmaz); } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_events(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { Jz_model_events(nllh, iz, p, k, z, sigmaz, mz); } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { dJrzdsigma_model_events(dJrzdsigma, iz, p, k, rz, sigmaz); } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { dJrzdz_model_events(dJrzdz, iz, p, k, rz, sigmaz); } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_events(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_events(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { dJzdsigma_model_events(dJzdsigma, iz, p, k, z, sigmaz, mz); } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { dJzdz_model_events(dJzdz, iz, p, k, z, sigmaz, mz); } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { deltasx_model_events(deltasx, t, x, p, k, h, w, ip, ie, xdot, xdot_old, sx, stau); } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { drzdx_model_events(drzdx, ie, t, x, p, k, h); } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dxdotdp_model_events(dxdotdp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dydp_model_events(dydp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_events(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { dzdx_model_events(dzdx, ie, t, x, p, k, h); } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { root_model_events(root, t, x, p, k, h); } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { rz_model_events(rz, ie, t, x, p, k, h); } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_events(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { sigmaz_model_events(sigmaz, t, p, k); } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { srz_model_events(srz, ie, t, x, p, k, h, sx, ip); } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { stau_model_events(stau, t, x, p, k, h, sx, ip, ie); } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { sz_model_events(sz, ie, t, x, p, k, h, sx, ip); } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { x0_model_events(x0, t, p, k); } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { xdot_model_events(xdot, t, x, p, k, h, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_events(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { z_model_events(z, ie, t, x, p, k, h); } diff --git a/deps/AMICI/models/model_events/rebuild_model_events.m b/deps/AMICI/models/model_events/rebuild_model_events.m new file mode 100644 index 000000000..bbb591694 --- /dev/null +++ b/deps/AMICI/models/model_events/rebuild_model_events.m @@ -0,0 +1,5 @@ +function rebuild_model_events() +modelName = 'model_events'; +amimodel.compileAndLinkModel(modelName, '', [], [], [], []); +amimodel.generateMatlabWrapper(3, 1, 4, 4, 2, 0, [], ['simulate_' modelName '.m'], 'model_events', 'log10', 1, 1); +end diff --git a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint.h b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint.h index b4b1d35c8..ce4eb29b7 100644 --- a/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint.h +++ b/deps/AMICI/models/model_jakstat_adjoint/model_jakstat_adjoint.h @@ -1,6 +1,6 @@ #ifndef _amici_model_jakstat_adjoint_h #define _amici_model_jakstat_adjoint_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -68,138 +68,138 @@ class Model_model_jakstat_adjoint : public amici::Model_ODE { std::vector{}) {}; - virtual amici::Model* clone() const override { return new Model_model_jakstat_adjoint(*this); }; + amici::Model* clone() const override { return new Model_model_jakstat_adjoint(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_jakstat_adjoint(JSparse, t, x, p, k, h, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_jakstat_adjoint(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_jakstat_adjoint(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_jakstat_adjoint(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { dsigmaydp_model_jakstat_adjoint(dsigmaydp, t, p, k, ip); } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { dwdp_model_jakstat_adjoint(dwdp, t, x, p, k, h, w, tcl, stcl); } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { dwdx_model_jakstat_adjoint(dwdx, t, x, p, k, h, w, tcl); } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dxdotdp_model_jakstat_adjoint(dxdotdp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dydp_model_jakstat_adjoint(dydp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_jakstat_adjoint(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_jakstat_adjoint(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { sx0_model_jakstat_adjoint(sx0, t, x0, p, k, ip); } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { w_model_jakstat_adjoint(w, t, x, p, k, h, tcl); } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { x0_model_jakstat_adjoint(x0, t, p, k); } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { xdot_model_jakstat_adjoint(xdot, t, x, p, k, h, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_jakstat_adjoint(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } }; diff --git a/deps/AMICI/models/model_jakstat_adjoint/rebuild_model_jakstat_adjoint.m b/deps/AMICI/models/model_jakstat_adjoint/rebuild_model_jakstat_adjoint.m new file mode 100644 index 000000000..443952d4c --- /dev/null +++ b/deps/AMICI/models/model_jakstat_adjoint/rebuild_model_jakstat_adjoint.m @@ -0,0 +1,5 @@ +function rebuild_model_jakstat_adjoint() +modelName = 'model_jakstat_adjoint'; +amimodel.compileAndLinkModel(modelName, '', [], [], [], []); +amimodel.generateMatlabWrapper(9, 3, 17, 2, 0, 0, [], ['simulate_' modelName '.m'], 'model_jakstat_adjoint', 'log10', 1, 1); +end diff --git a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h index f726def6e..273de3a97 100644 --- a/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h +++ b/deps/AMICI/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h @@ -1,6 +1,6 @@ #ifndef _amici_model_jakstat_adjoint_o2_h #define _amici_model_jakstat_adjoint_o2_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -68,138 +68,138 @@ class Model_model_jakstat_adjoint_o2 : public amici::Model_ODE { std::vector{}) {}; - virtual amici::Model* clone() const override { return new Model_model_jakstat_adjoint_o2(*this); }; + amici::Model* clone() const override { return new Model_model_jakstat_adjoint_o2(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_jakstat_adjoint_o2(JSparse, t, x, p, k, h, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_jakstat_adjoint_o2(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_jakstat_adjoint_o2(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_jakstat_adjoint_o2(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { dsigmaydp_model_jakstat_adjoint_o2(dsigmaydp, t, p, k, ip); } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { dwdp_model_jakstat_adjoint_o2(dwdp, t, x, p, k, h, w, tcl, stcl); } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { dwdx_model_jakstat_adjoint_o2(dwdx, t, x, p, k, h, w, tcl); } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dxdotdp_model_jakstat_adjoint_o2(dxdotdp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dydp_model_jakstat_adjoint_o2(dydp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_jakstat_adjoint_o2(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_jakstat_adjoint_o2(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { sx0_model_jakstat_adjoint_o2(sx0, t, x0, p, k, ip); } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { w_model_jakstat_adjoint_o2(w, t, x, p, k, h, tcl); } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { x0_model_jakstat_adjoint_o2(x0, t, p, k); } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { xdot_model_jakstat_adjoint_o2(xdot, t, x, p, k, h, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_jakstat_adjoint_o2(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } }; diff --git a/deps/AMICI/models/model_nested_events/model_nested_events.h b/deps/AMICI/models/model_nested_events/model_nested_events.h index 0f5d29450..ceab6cb1a 100644 --- a/deps/AMICI/models/model_nested_events/model_nested_events.h +++ b/deps/AMICI/models/model_nested_events/model_nested_events.h @@ -1,6 +1,6 @@ #ifndef _amici_model_nested_events_h #define _amici_model_nested_events_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -68,138 +68,138 @@ class Model_model_nested_events : public amici::Model_ODE { std::vector{}) {}; - virtual amici::Model* clone() const override { return new Model_model_nested_events(*this); }; + amici::Model* clone() const override { return new Model_model_nested_events(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_nested_events(JSparse, t, x, p, k, h, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_nested_events(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_nested_events(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_nested_events(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { deltaqB_model_nested_events(deltaqB, t, x, p, k, h, ip, ie, xdot, xdot_old, xB); } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { deltasx_model_nested_events(deltasx, t, x, p, k, h, w, ip, ie, xdot, xdot_old, sx, stau); } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { deltax_model_nested_events(deltax, t, x, p, k, h, ie, xdot, xdot_old); } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dxdotdp_model_nested_events(dxdotdp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_nested_events(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { root_model_nested_events(root, t, x, p, k, h); } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_nested_events(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { stau_model_nested_events(stau, t, x, p, k, h, sx, ip, ie); } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { sx0_model_nested_events(sx0, t, x0, p, k, ip); } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { x0_model_nested_events(x0, t, p, k); } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { xdot_model_nested_events(xdot, t, x, p, k, h, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_nested_events(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } }; diff --git a/deps/AMICI/models/model_nested_events/rebuild_model_nested_events.m b/deps/AMICI/models/model_nested_events/rebuild_model_nested_events.m new file mode 100644 index 000000000..38f3e1b9c --- /dev/null +++ b/deps/AMICI/models/model_nested_events/rebuild_model_nested_events.m @@ -0,0 +1,5 @@ +function rebuild_model_nested_events() +modelName = 'model_nested_events'; +amimodel.compileAndLinkModel(modelName, '', [], [], [], []); +amimodel.generateMatlabWrapper(1, 1, 5, 0, 0, 0, [], ['simulate_' modelName '.m'], 'model_nested_events', 'log10', 1, 1); +end diff --git a/deps/AMICI/models/model_neuron/model_neuron.h b/deps/AMICI/models/model_neuron/model_neuron.h index df2611a59..3aaeb06a4 100644 --- a/deps/AMICI/models/model_neuron/model_neuron.h +++ b/deps/AMICI/models/model_neuron/model_neuron.h @@ -1,6 +1,6 @@ #ifndef _amici_model_neuron_h #define _amici_model_neuron_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -82,151 +82,151 @@ class Model_model_neuron : public amici::Model_ODE { std::vector{1}) {}; - virtual amici::Model* clone() const override { return new Model_model_neuron(*this); }; + amici::Model* clone() const override { return new Model_model_neuron(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_neuron(JSparse, t, x, p, k, h, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { Jrz_model_neuron(nllh, iz, p, k, rz, sigmaz); } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_neuron(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { Jz_model_neuron(nllh, iz, p, k, z, sigmaz, mz); } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { dJrzdsigma_model_neuron(dJrzdsigma, iz, p, k, rz, sigmaz); } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { dJrzdz_model_neuron(dJrzdz, iz, p, k, rz, sigmaz); } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_neuron(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_neuron(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { dJzdsigma_model_neuron(dJzdsigma, iz, p, k, z, sigmaz, mz); } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { dJzdz_model_neuron(dJzdz, iz, p, k, z, sigmaz, mz); } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { deltaqB_model_neuron(deltaqB, t, x, p, k, h, ip, ie, xdot, xdot_old, xB); } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { deltasx_model_neuron(deltasx, t, x, p, k, h, w, ip, ie, xdot, xdot_old, sx, stau); } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { deltax_model_neuron(deltax, t, x, p, k, h, ie, xdot, xdot_old); } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { deltaxB_model_neuron(deltaxB, t, x, p, k, h, ie, xdot, xdot_old, xB); } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { drzdx_model_neuron(drzdx, ie, t, x, p, k, h); } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dxdotdp_model_neuron(dxdotdp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_neuron(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { dzdx_model_neuron(dzdx, ie, t, x, p, k, h); } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { root_model_neuron(root, t, x, p, k, h); } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { rz_model_neuron(rz, ie, t, x, p, k, h); } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_neuron(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { sigmaz_model_neuron(sigmaz, t, p, k); } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { srz_model_neuron(srz, ie, t, x, p, k, h, sx, ip); } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { stau_model_neuron(stau, t, x, p, k, h, sx, ip, ie); } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { sx0_model_neuron(sx0, t, x0, p, k, ip); } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { sz_model_neuron(sz, ie, t, x, p, k, h, sx, ip); } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { x0_model_neuron(x0, t, p, k); } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { xdot_model_neuron(xdot, t, x, p, k, h, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_neuron(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { z_model_neuron(z, ie, t, x, p, k, h); } diff --git a/deps/AMICI/models/model_neuron/rebuild_model_neuron.m b/deps/AMICI/models/model_neuron/rebuild_model_neuron.m new file mode 100644 index 000000000..0c368819d --- /dev/null +++ b/deps/AMICI/models/model_neuron/rebuild_model_neuron.m @@ -0,0 +1,5 @@ +function rebuild_model_neuron() +modelName = 'model_neuron'; +amimodel.compileAndLinkModel(modelName, '', [], [], [], []); +amimodel.generateMatlabWrapper(2, 1, 4, 2, 1, 0, [], ['simulate_' modelName '.m'], 'model_neuron', 'log10', 1, 1); +end diff --git a/deps/AMICI/models/model_neuron_o2/model_neuron_o2.h b/deps/AMICI/models/model_neuron_o2/model_neuron_o2.h index 8ec152b98..79904d771 100644 --- a/deps/AMICI/models/model_neuron_o2/model_neuron_o2.h +++ b/deps/AMICI/models/model_neuron_o2/model_neuron_o2.h @@ -1,6 +1,6 @@ #ifndef _amici_model_neuron_o2_h #define _amici_model_neuron_o2_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -84,153 +84,153 @@ class Model_model_neuron_o2 : public amici::Model_ODE { std::vector{1, 1, 1, 1, 1}) {}; - virtual amici::Model* clone() const override { return new Model_model_neuron_o2(*this); }; + amici::Model* clone() const override { return new Model_model_neuron_o2(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_neuron_o2(JSparse, t, x, p, k, h, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { Jrz_model_neuron_o2(nllh, iz, p, k, rz, sigmaz); } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_neuron_o2(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { Jz_model_neuron_o2(nllh, iz, p, k, z, sigmaz, mz); } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { dJrzdsigma_model_neuron_o2(dJrzdsigma, iz, p, k, rz, sigmaz); } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { dJrzdz_model_neuron_o2(dJrzdz, iz, p, k, rz, sigmaz); } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_neuron_o2(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_neuron_o2(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { dJzdsigma_model_neuron_o2(dJzdsigma, iz, p, k, z, sigmaz, mz); } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { dJzdz_model_neuron_o2(dJzdz, iz, p, k, z, sigmaz, mz); } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { deltaqB_model_neuron_o2(deltaqB, t, x, p, k, h, ip, ie, xdot, xdot_old, xB); } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { deltasx_model_neuron_o2(deltasx, t, x, p, k, h, w, ip, ie, xdot, xdot_old, sx, stau); } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { deltax_model_neuron_o2(deltax, t, x, p, k, h, ie, xdot, xdot_old); } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { deltaxB_model_neuron_o2(deltaxB, t, x, p, k, h, ie, xdot, xdot_old, xB); } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { drzdx_model_neuron_o2(drzdx, ie, t, x, p, k, h); } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { dwdx_model_neuron_o2(dwdx, t, x, p, k, h, w, tcl); } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dxdotdp_model_neuron_o2(dxdotdp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_neuron_o2(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { dzdx_model_neuron_o2(dzdx, ie, t, x, p, k, h); } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { root_model_neuron_o2(root, t, x, p, k, h); } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { rz_model_neuron_o2(rz, ie, t, x, p, k, h); } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_neuron_o2(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { sigmaz_model_neuron_o2(sigmaz, t, p, k); } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { srz_model_neuron_o2(srz, ie, t, x, p, k, h, sx, ip); } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { stau_model_neuron_o2(stau, t, x, p, k, h, sx, ip, ie); } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { sx0_model_neuron_o2(sx0, t, x0, p, k, ip); } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { sz_model_neuron_o2(sz, ie, t, x, p, k, h, sx, ip); } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { w_model_neuron_o2(w, t, x, p, k, h, tcl); } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { x0_model_neuron_o2(x0, t, p, k); } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { xdot_model_neuron_o2(xdot, t, x, p, k, h, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_neuron_o2(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { z_model_neuron_o2(z, ie, t, x, p, k, h); } diff --git a/deps/AMICI/models/model_robertson/model_robertson.h b/deps/AMICI/models/model_robertson/model_robertson.h index bedd9e642..9e3c40f29 100644 --- a/deps/AMICI/models/model_robertson/model_robertson.h +++ b/deps/AMICI/models/model_robertson/model_robertson.h @@ -1,6 +1,6 @@ #ifndef _amici_model_robertson_h #define _amici_model_robertson_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -66,139 +66,139 @@ class Model_model_robertson : public amici::Model_DAE { std::vector{}) {}; - virtual amici::Model* clone() const override { return new Model_model_robertson(*this); }; + amici::Model* clone() const override { return new Model_model_robertson(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) override { JSparse_model_robertson(JSparse, t, x, p, k, h, cj, dx, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_robertson(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fM(realtype *M, const realtype t, const realtype *x, const realtype *p, const realtype *k) override { + void fM(realtype *M, const realtype t, const realtype *x, const realtype *p, const realtype *k) override { M_model_robertson(M, t, x, p, k); } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_robertson(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_robertson(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { dwdp_model_robertson(dwdp, t, x, p, k, h, w, tcl, stcl); } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { dwdx_model_robertson(dwdx, t, x, p, k, h, w, tcl); } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *dx, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *dx, const realtype *w, const realtype *dwdp) override { dxdotdp_model_robertson(dxdotdp, t, x, p, k, h, ip, dx, w, dwdp); } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_robertson(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx) override { } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_robertson(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { w_model_robertson(w, t, x, p, k, h, tcl); } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { x0_model_robertson(x0, t, p, k); } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx, const realtype *w) override { xdot_model_robertson(xdot, t, x, p, k, h, dx, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_robertson(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } }; diff --git a/deps/AMICI/models/model_robertson/rebuild_model_robertson.m b/deps/AMICI/models/model_robertson/rebuild_model_robertson.m new file mode 100644 index 000000000..3fcf9fe46 --- /dev/null +++ b/deps/AMICI/models/model_robertson/rebuild_model_robertson.m @@ -0,0 +1,5 @@ +function rebuild_model_robertson() +modelName = 'model_robertson'; +amimodel.compileAndLinkModel(modelName, '', [], [], [], []); +amimodel.generateMatlabWrapper(3, 3, 3, 1, 0, 0, [], ['simulate_' modelName '.m'], 'model_robertson', 'log10', 1, 1); +end diff --git a/deps/AMICI/models/model_steadystate/model_steadystate.h b/deps/AMICI/models/model_steadystate/model_steadystate.h index 2637d681b..c009c86ca 100644 --- a/deps/AMICI/models/model_steadystate/model_steadystate.h +++ b/deps/AMICI/models/model_steadystate/model_steadystate.h @@ -1,6 +1,6 @@ #ifndef _amici_model_steadystate_h #define _amici_model_steadystate_h -/* Generated by amiwrap (R2017b) 0a85246ec55554a1db269634c806f27f071f487f */ +/* Generated by amiwrap (R2017b) 2bd39716102b9842354964196889d40d2eb2731c */ #include #include #include "amici/defines.h" @@ -65,135 +65,135 @@ class Model_model_steadystate : public amici::Model_ODE { std::vector{}) {}; - virtual amici::Model* clone() const override { return new Model_model_steadystate(*this); }; + amici::Model* clone() const override { return new Model_model_steadystate(*this); }; - const std::string getAmiciCommit() const override { return "0a85246ec55554a1db269634c806f27f071f487f"; }; + std::string getAmiciCommit() const override { return "2bd39716102b9842354964196889d40d2eb2731c"; }; - virtual void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_steadystate(JSparse, t, x, p, k, h, w, dwdx); } - virtual void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fJrz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fJy(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { Jy_model_steadystate(nllh, iy, p, k, y, sigmay, my); } - virtual void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fJz(double *nllh, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdsigma(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { + void fdJrzdz(double *dJrzdz, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz) override { } - virtual void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydsigma(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydsigma_model_steadystate(dJydsigma, iy, p, k, y, sigmay, my); } - virtual void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { + void fdJydy(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my) override { dJydy_model_steadystate(dJydy, iy, p, k, y, sigmay, my); } - virtual void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdsigma(double *dJzdsigma, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { + void fdJzdz(double *dJzdz, const int iz, const realtype *p, const realtype *k, const double *z, const double *sigmaz, const double *mz) override { } - virtual void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaqB(double *deltaqB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { + void fdeltasx(double *deltasx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const int ip, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *sx, const realtype *stau) override { } - virtual void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { + void fdeltax(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old) override { } - virtual void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { + void fdeltaxB(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB) override { } - virtual void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdrzdp(double *drzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdrzdx(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmaydp(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { + void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - virtual void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl) override { dwdp_model_steadystate(dwdp, t, x, p, k, h, w, tcl, stcl); } - virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl) override { dwdx_model_steadystate(dwdx, t, x, p, k, h, w, tcl); } - virtual void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { dxdotdp_model_steadystate(dxdotdp, t, x, p, k, h, ip, w, dwdp); } - virtual void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { + void fdydp(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { } - virtual void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { + void fdydx(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { dydx_model_steadystate(dydx, t, x, p, k, h, w, dwdx); } - virtual void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { + void fdzdp(double *dzdp, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip) override { } - virtual void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fdzdx(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void froot(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void frz(double *rz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } - virtual void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { + void fsigmay(double *sigmay, const realtype t, const realtype *p, const realtype *k) override { sigmay_model_steadystate(sigmay, t, p, k); } - virtual void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { + void fsigmaz(double *sigmaz, const realtype t, const realtype *p, const realtype *k) override { } - virtual void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsrz(double *srz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { + void fstau(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip, const int ie) override { } - virtual void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { + void fsx0(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip) override { } - virtual void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { + void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - virtual void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl) override { w_model_steadystate(w, t, x, p, k, h, tcl); } - virtual void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { + void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { x0_model_steadystate(x0, t, p, k); } - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fxdot(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { xdot_model_steadystate(xdot, t, x, p, k, h, w); } - virtual void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { + void fy(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w) override { y_model_steadystate(y, t, x, p, k, h, w); } - virtual void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { + void fz(double *z, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h) override { } }; diff --git a/deps/AMICI/models/model_steadystate/rebuild_model_steadystate.m b/deps/AMICI/models/model_steadystate/rebuild_model_steadystate.m new file mode 100644 index 000000000..f7a6f63e5 --- /dev/null +++ b/deps/AMICI/models/model_steadystate/rebuild_model_steadystate.m @@ -0,0 +1,5 @@ +function rebuild_model_steadystate() +modelName = 'model_steadystate'; +amimodel.compileAndLinkModel(modelName, '', [], [], [], []); +amimodel.generateMatlabWrapper(3, 3, 5, 4, 0, 0, [], ['simulate_' modelName '.m'], 'model_steadystate', 'log10', 1, 1); +end diff --git a/deps/AMICI/python/amici/ode_export.py b/deps/AMICI/python/amici/ode_export.py index b6391f880..713ecf468 100644 --- a/deps/AMICI/python/amici/ode_export.py +++ b/deps/AMICI/python/amici/ode_export.py @@ -45,7 +45,7 @@ ) from .logging import get_logger, log_execution_time, set_log_level from .constants import SymbolId -from .import_utils import smart_subs_dict +from .import_utils import smart_subs_dict, toposort_symbols # Template for model simulation main.cpp file CXX_MAIN_TEMPLATE_FILE = os.path.join(amiciSrcPath, 'main.template.cpp') @@ -78,9 +78,9 @@ 'const realtype *k, const realtype *y, const realtype *sigmay, ' 'const realtype *my)', }, - 'dJydsigmay': { + 'dJydsigma': { 'signature': - '(realtype *dJydsigmay, const int iy, const realtype *p, ' + '(realtype *dJydsigma, const int iy, const realtype *p, ' 'const realtype *k, const realtype *y, const realtype *sigmay, ' 'const realtype *my)', }, @@ -189,12 +189,31 @@ 'const realtype *p, const realtype *k, const realtype *h, ' 'const realtype *sx, const int ip, const int ie)' }, + 'deltax': { + 'signature': + '(double *deltax, const realtype t, const realtype *x, ' + 'const realtype *p, const realtype *k, const realtype *h, ' + 'const int ie, const realtype *xdot, const realtype *xdot_old)' + }, + 'ddeltaxdx': { + 'signature': '()', + 'flags': ['dont_generate_body'] + }, + 'ddeltaxdt': { + 'signature': '()', + 'flags': ['dont_generate_body'] + }, + 'ddeltaxdp': { + 'signature': '()', + 'flags': ['dont_generate_body'] + }, 'deltasx': { 'signature': '(realtype *deltasx, const realtype t, const realtype *x, ' 'const realtype *p, const realtype *k, const realtype *h, ' - 'const realtype *w, const int ip, const int ie, const realtype *xdot, ' - 'const realtype *xdot_old, const realtype *sx, const realtype *stau)' + 'const realtype *w, const int ip, const int ie, ' + 'const realtype *xdot, const realtype *xdot_old, ' + 'const realtype *sx, const realtype *stau)' }, 'w': { 'signature': @@ -270,12 +289,23 @@ sensi_functions = [ function for function in functions if 'const int ip' in functions[function]['signature'] - and function != 'sxdot' +] +# list of sensitivity functions +sparse_sensi_functions = [ + function for function in functions + if 'const int ip' not in functions[function]['signature'] + and function.endswith('dp') or function.endswith('dp_explicit') ] # list of event functions event_functions = [ function for function in functions - if 'const int ie' in functions[function]['signature'] + if 'const int ie' in functions[function]['signature'] and + 'const int ip' not in functions[function]['signature'] +] +event_sensi_functions = [ + function for function in functions + if 'const int ie' in functions[function]['signature'] and + 'const int ip' in functions[function]['signature'] ] # list of multiobs functions multiobs_functions = [ @@ -353,6 +383,7 @@ def __init__(self, if not isinstance(name, str): raise TypeError(f'name must be str, was {type(name)}') + self._name: str = name self._value: sp.Expr = cast_to_sym(value, 'value') @@ -687,6 +718,7 @@ def __init__(self, """ super(LogLikelihood, self).__init__(identifier, name, value) + class Event(ModelQuantity): """ An Event defines either a SBML event or a root of the argument of a @@ -727,6 +759,13 @@ def __init__(self, self._state_update = state_update self._observable = event_observable + def __eq__(self, other): + """ + Check equality of events at the level of trigger/root functions, as we + need to collect unique root functions for roots.cpp + """ + return self.get_val() == other.get_val() + # defines the type of some attributes in ODEModel symbol_to_type = { @@ -1021,14 +1060,14 @@ def import_from_sbml_importer(self, dxdotdw_updates = [] - def transform_dxdt_to_concentration(specie_id, dxdt): + def transform_dxdt_to_concentration(species_id, dxdt): """ Produces the appropriate expression for the first derivative of a species with respect to time, for species that reside in compartments with a constant volume, or a volume that is defined by an assignment or rate rule. - :param specie_id: + :param species_id: The identifier of the species (generated in "sbml_import.py"). :param dxdt: @@ -1045,13 +1084,13 @@ def transform_dxdt_to_concentration(specie_id, dxdt): # species in (i) compartments with a rate rule, (ii) compartments # with an assignment rule, and (iii) compartments with a constant # volume, respectively. - specie = si.symbols[SymbolId.SPECIES][specie_id] + species = si.symbols[SymbolId.SPECIES][species_id] - comp = specie['compartment'] - x_index = specie['index'] + comp = species['compartment'] + x_index = species['index'] if comp in si.symbols[SymbolId.SPECIES]: dv_dt = si.symbols[SymbolId.SPECIES][comp]['dt'] - xdot = (dxdt - dv_dt * specie_id) / comp + xdot = (dxdt - dv_dt * species_id) / comp dxdotdw_updates.extend( (x_index, w_index, xdot.diff(r_flux)) for w_index, r_flux in enumerate(fluxes) @@ -1072,8 +1111,8 @@ def transform_dxdt_to_concentration(specie_id, dxdt): for var in comp_rate_vars: dv_dt += \ v.diff(var) * si.symbols[SymbolId.SPECIES][var]['dt'] - dv_dx = v.diff(specie_id) - xdot = (dxdt - dv_dt * specie_id) / (dv_dx * specie_id + v) + dv_dx = v.diff(species_id) + xdot = (dxdt - dv_dt * species_id) / (dv_dx * species_id + v) dxdotdw_updates.extend( (x_index, w_index, xdot.diff(r_flux)) for w_index, r_flux in enumerate(fluxes) @@ -1097,19 +1136,19 @@ def transform_dxdt_to_concentration(specie_id, dxdt): # create dynamics without respecting conservation laws first dxdt = smart_multiply(si.stoichiometric_matrix, MutableDenseMatrix(fluxes)) - for ix, ((specie_id, specie), formula) in enumerate(zip( + for ix, ((species_id, species), formula) in enumerate(zip( symbols[SymbolId.SPECIES].items(), dxdt )): - assert ix == specie['index'] # check that no reordering occurred + assert ix == species['index'] # check that no reordering occurred # rate rules and amount species don't need to be updated - if 'dt' in specie: + if 'dt' in species: continue - if specie['amount']: - specie['dt'] = formula + if species['amount']: + species['dt'] = formula else: - specie['dt'] = transform_dxdt_to_concentration(specie_id, - formula) + species['dt'] = transform_dxdt_to_concentration(species_id, + formula) # create all basic components of the ODE model and add them. for symbol_name in symbols: @@ -1120,6 +1159,8 @@ def transform_dxdt_to_concentration(specie_id, dxdt): args += ['dt', 'init'] else: args += ['value'] + if symbol_name == SymbolId.EVENT: + args += ['state_update', 'event_observable'] protos = [ { @@ -1176,11 +1217,12 @@ def transform_dxdt_to_concentration(specie_id, dxdt): self.generate_basic_variables(from_sbml=True) # substitute 'w' expressions into event expressions now, to avoid # rewriting '{model_name}_root.cpp' headers to include 'w.h' + w_sorted = toposort_symbols(dict(zip(self._syms['w'], self._eqs['w']))) for index, event in enumerate(self._events): self._events[index] = Event( identifier=event.get_id(), name=event.get_name(), - value=event.get_val().subs(zip(self._syms['w'], self.eq('w'))), + value=event.get_val().subs(w_sorted), state_update=event._state_update, event_observable=event._observable, ) @@ -1377,7 +1419,7 @@ def sym(self, else: return self._syms[name] - def sparsesym(self, name: str) -> List[str]: + def sparsesym(self, name: str, force_generate: bool = True) -> List[str]: """ Returns (and constructs if necessary) the sparsified identifiers for a sparsified symbolic variable. @@ -1385,15 +1427,18 @@ def sparsesym(self, name: str) -> List[str]: :param name: name of the symbolic variable + :param force_generate: + whether the symbols should be generated if not available + :return: linearized Matrix containing the symbolic identifiers """ if name not in sparse_functions: raise ValueError(f'{name} is not marked as sparse') - if name not in self._sparsesyms: + if name not in self._sparsesyms and force_generate: self._generate_sparse_symbol(name) - return self._sparsesyms[name] + return self._sparsesyms.get(name, []) def eq(self, name: str) -> sp.Matrix: """ @@ -1578,7 +1623,6 @@ def _generate_symbol(self, name: str, *, from_sbml: bool = False) -> None: length = self.eq(name).shape[0] else: length = len(self.eq(name)) - self._syms[name] = sp.Matrix([ sp.Symbol(f'{name}{i}', real=True) for i in range(length) ]) @@ -1588,12 +1632,20 @@ def generate_basic_variables(self, *, from_sbml: bool = False) -> None: Generates the symbolic identifiers for all variables in ODEModel.variable_prototype """ + # Workaround to generate `'w'` before events, such that `'w'` can be + # replaced in events, to avoid adding `w` to the header of + # "{model_name}_stau.cpp". + if 'w' not in self._syms: + self._generate_symbol('w', from_sbml=from_sbml) # We need to process events and Heaviside functions in the ODE Model, # before adding it to ODEExporter self.parse_events() for var in self._variable_prototype: + # Part of the workaround described earlier in this method. + if var == 'w': + continue if var not in self._syms: self._generate_symbol(var, from_sbml=from_sbml) @@ -1608,15 +1660,19 @@ def parse_events(self) -> None: """ # Track all roots functions in the right hand side - roots = [] + roots = copy.deepcopy(self._events) for state in self._states: - state.set_dt(_process_heavisides(state.get_dt(), roots)) + state.set_dt(self._process_heavisides(state.get_dt(), roots)) for expr in self._expressions: - expr.set_val(_process_heavisides(expr.get_val(), roots)) + expr.set_val(self._process_heavisides(expr.get_val(), roots)) # Now add the found roots to the model components for root in roots: + # skip roots of SBML events, as these have already been added + if root in self._events: + continue + # add roots of heaviside functions self.add_component(root) def get_appearance_counts(self, idxs: List[int]) -> List[int]: @@ -1710,7 +1766,10 @@ def _compute_equation(self, name: str) -> None: name of the symbolic variable """ - match_deriv = re.match(r'd([\w_]+)d([a-z_]+)', name) + # replacement ensures that we don't have to adapt name in abstract + # model and keep backwards compatibility with matlab + match_deriv = re.match(r'd([\w_]+)d([a-z_]+)', + name.replace('dJydsigma', 'dJydsigmay')) time_symbol = sp.Matrix([symbol_with_assumptions('t')]) if name in self._equation_prototype: @@ -1794,7 +1853,8 @@ def _compute_equation(self, name: str) -> None: elif name == 'dtcldx': # this is always zero - self._eqs[name] = sp.zeros(self.num_cons_law(), self.num_states_solver()) + self._eqs[name] = \ + sp.zeros(self.num_cons_law(), self.num_states_solver()) elif name == 'dtcldp': # force symbols @@ -1815,31 +1875,86 @@ def _compute_equation(self, name: str) -> None: # backsubstitution of optimized right hand side terms into RHS # calling subs() is costly. Due to looping over events though, the # following lines are only evaluated if a model has events - tmp_xdot = self._eqs['xdot'].subs(zip(self._syms['w'], - self._eqs['w'])) - self._eqs[name] = smart_multiply(self.eq('drootdx'), tmp_xdot) + \ - self.eq('drootdt') + w_sorted = \ + toposort_symbols(dict(zip(self._syms['w'], self._eqs['w']))) + tmp_xdot = self._eqs['xdot'].subs(w_sorted) + self._eqs[name] = ( + smart_multiply(self.eq('drootdx'), tmp_xdot) + + self.eq('drootdt') + ) - elif name == 'stau': + elif name == 'deltax': + # fill boluses for Heaviside functions, as empty state updates + # would cause problems when writing the function file later + event_eqs = [] + for event in self._events: + if event._state_update is None: + event_eqs.append(sp.zeros(self.num_states_solver(), 1)) + else: + event_eqs.append(event._state_update) + + self._eqs[name] = event_eqs + + elif name == 'ddeltaxdx': self._eqs[name] = [ - -self.eq('sroot')[ie, :] / self.eq('drootdt_total')[ie] + smart_jacobian(self.eq('deltax')[ie], self.sym('x')) for ie in range(self.num_events()) ] - elif name == 'deltasx': + elif name == 'ddeltaxdt': + self._eqs[name] = [ + smart_jacobian(self.eq('deltax')[ie], time_symbol) + for ie in range(self.num_events()) + ] + + elif name == 'ddeltaxdp': self._eqs[name] = [ - smart_multiply((self.eq('xdot_old') - self.eq('xdot')), - self.eq('stau')[ie]) + smart_jacobian(self.eq('deltax')[ie], self.sym('p')) for ie in range(self.num_events()) ] + elif name == 'stau': + self._eqs[name] = [ + -self.eq('sroot')[ie, :] / self.eq('drootdt_total')[ie] + for ie in range(self.num_events()) + ] + + elif name == 'deltasx': + event_eqs = [] + for ie, event in enumerate(self._events): + if event._state_update is not None: + # ====== chain rule for the state variables =============== + # get xdot with expressions back-substituted + tmp_eq = smart_multiply( + (self.sym('xdot_old') - self.sym('xdot')), + self.eq('stau')[ie]) + # construct an enhanced state sensitivity, which accounts + # for the time point sensitivity as well + tmp_dxdp = self.sym('sx') * sp.ones(1, self.num_par()) + tmp_dxdp += smart_multiply(self.sym('xdot'), + self.eq('stau')[ie]) + tmp_eq += smart_multiply(self.eq('ddeltaxdx')[ie], + tmp_dxdp) + # ====== chain rule for the time point ==================== + tmp_eq += smart_multiply(self.eq('ddeltaxdt')[ie], + self.eq('stau')[ie]) + # ====== partial derivative for the parameters ============ + tmp_eq += self.eq('ddeltaxdp')[ie] + else: + tmp_eq = smart_multiply( + (self.eq('xdot_old') - self.eq('xdot')), + self.eq('stau')[ie]) + + event_eqs.append(tmp_eq) + + self._eqs[name] = event_eqs + elif name == 'xdot_old': # force symbols self._eqs[name] = self.sym(name) - elif match_deriv: - self._derivative(match_deriv.group(1), match_deriv.group(2)) + self._derivative(match_deriv.group(1), match_deriv.group(2), name) else: raise ValueError(f'Unknown equation {name}') @@ -1861,7 +1976,8 @@ def _compute_equation(self, name: str) -> None: self._eqs[name] = [dec(sub_eq.applyfunc)(self._simplify) for sub_eq in self._eqs[name]] else: - self._eqs[name] = dec(self._eqs[name].applyfunc)(self._simplify) + self._eqs[name] = \ + dec(self._eqs[name].applyfunc)(self._simplify) def sym_names(self) -> List[str]: """ @@ -2230,6 +2346,146 @@ def conservation_law_has_multispecies(self, n_species = len(state_set.intersection(tcl.get_val().free_symbols)) return n_species > 1 + def _expr_is_time_dependent(self, expr: sp.Expr) -> bool: + """Determine whether an expression is time-dependent. + + :param expr: + The expression. + + :returns: + Whether the expression is time-dependent. + """ + # `expr.free_symbols` will be different to `self._states.keys()`, so + # it's easier to compare as `str`. + expr_syms = {str(sym) for sym in expr.free_symbols} + + # Check if the time variable is in the expression. + if 't' in expr_syms: + return True + + # Check if any time-dependent states are in the expression. + state_syms = [str(sym) for sym in self._states] + for state in expr_syms.intersection(state_syms): + if not self.state_is_constant(state_syms.index(state)): + return True + + return False + + def _get_unique_root( + self, + root_found: sp.Expr, + roots: List[Event], + ) -> sp.Symbol: + """ + Collects roots of Heaviside functions and events and stores them in + the roots list. It checks for redundancy to not store symbolically + equivalent root functions more than once. + + :param root_found: + equation of the root function + :param roots: + list of already known root functions with identifier + + :returns: + unique identifier for root, or `None` if the root is not + time-dependent + """ + + if not self._expr_is_time_dependent(root_found): + return None + + for root in roots: + if sp.simplify(root_found - root.get_val()) == 0: + return root.get_id() + + # create an event for a new root function + root_symstr = f'Heaviside_{len(roots)}' + roots.append(Event( + identifier=sp.Symbol(root_symstr), + name=root_symstr, + value=root_found, + state_update=None, + event_observable=None + )) + return roots[-1].get_id() + + def _collect_heaviside_roots( + self, + args: Sequence[sp.Expr] + ) -> List[sp.Expr]: + """ + Recursively checks an expression for the occurrence of Heaviside + functions and return all roots found + + :param args: + args attribute of the expanded expression + + :returns: + root functions that were extracted from Heaviside function + arguments + """ + root_funs = [] + for arg in args: + if arg.func == sp.Heaviside: + root_funs.append(arg.args[0]) + elif arg.has(sp.Heaviside): + root_funs.extend(self._collect_heaviside_roots(arg.args)) + + # substitute 'w' expressions into root expressions now, to avoid + # rewriting '{model_name}_stau.cpp' headers to include 'w.h' + w_sorted = toposort_symbols(dict(zip(self._syms['w'], self.eq('w')))) + root_funs = [ + r.subs(w_sorted) + for r in root_funs + ] + + return root_funs + + def _process_heavisides( + self, + dxdt: sp.Expr, + roots: List[Event], + ) -> sp.Expr: + """ + Parses the RHS of a state variable, checks for Heaviside functions, + collects unique roots functions that can be tracked by SUNDIALS and + replaces Heaviside Functions by amici helper variables that will be + updated based on SUNDIALS root tracking. + + :param dxdt: + right hand side of state variable + :param roots: + list of known root functions with identifier + + :returns: + dxdt with Heaviside functions replaced by amici helper variables + """ + + # expanding the rhs will in general help to collect the same + # heaviside function + dt_expanded = dxdt.expand() + # track all the old Heaviside expressions in tmp_roots_old + # replace them later by the new expressions + heavisides = [] + # run through the expression tree and get the roots + tmp_roots_old = self._collect_heaviside_roots(dt_expanded.args) + for tmp_old in tmp_roots_old: + # we want unique identifiers for the roots + tmp_new = self._get_unique_root(tmp_old, roots) + # `tmp_new` is None if the root is not time-dependent. + if tmp_new is None: + continue + # For Heavisides, we need to add the negative function as well + self._get_unique_root(sp.sympify(- tmp_old), roots) + heavisides.append((sp.Heaviside(tmp_old), tmp_new)) + + if heavisides: + # only apply subs if necessary + for heaviside_sympy, heaviside_amici in heavisides: + dxdt = dxdt.subs(heaviside_sympy, heaviside_amici) + + return dxdt + def _print_with_exception(math: sp.Expr) -> str: """ @@ -2361,6 +2617,9 @@ class ODEExporter: :ivar _build_hints: If the given model uses special functions, this set contains hints for model building. + + :ivar generate_sensitivity_code: + Specifies whether code for sensitivity computation is to be generated """ def __init__( @@ -2370,7 +2629,8 @@ def __init__( verbose: Optional[Union[bool, int]] = False, assume_pow_positivity: Optional[bool] = False, compiler: Optional[str] = None, - allow_reinit_fixpar_initcond: Optional[bool] = True + allow_reinit_fixpar_initcond: Optional[bool] = True, + generate_sensitivity_code: Optional[bool] = True ): """ Generate AMICI C++ files for the ODE provided to the constructor. @@ -2395,6 +2655,9 @@ def __init__( :param allow_reinit_fixpar_initcond: see :class:`amici.ode_export.ODEExporter` + + :param generate_sensitivity_code specifies whether code required for + sensitivity computation will be generated """ set_log_level(logger, verbose) @@ -2419,6 +2682,7 @@ def __init__( self.allow_reinit_fixpar_initcond: bool = allow_reinit_fixpar_initcond self._build_hints = set() + self.generate_sensitivity_code: bool = generate_sensitivity_code @log_execution_time('generating cpp code', logger) def generate_model_code(self) -> None: @@ -2459,15 +2723,29 @@ def _generate_c_code(self) -> None: Create C++ code files for the model based on ODEExporter.model """ for function in self.functions.keys(): + if function in sensi_functions + sparse_sensi_functions and \ + not self.generate_sensitivity_code: + continue + if 'dont_generate_body' not in \ self.functions[function].get('flags', []): dec = log_execution_time(f'writing {function}.cpp', logger) dec(self._write_function_file)(function) - if function in sparse_functions: + if function in sparse_functions \ + and 'body' in self.functions[function]: self._write_function_index(function, 'colptrs') self._write_function_index(function, 'rowvals') for name in self.model.sym_names(): + # only generate for those that have nontrivial implementation, + # check for both basic variables (not in functions) and function + # computed values + if (name in self.functions and + 'body' not in self.functions[name] and + name not in nobody_functions) or \ + (name not in self.functions and + len(self.model.sym(name)) == 0): + continue self._write_index_files(name) self._write_wrapfunctions_cpp() @@ -2560,8 +2838,8 @@ def _generate_m_code(self) -> None: lines.append("amimodel.compileAndLinkModel" "(modelName, '', [], [], [], []);") lines.append(f"amimodel.generateMatlabWrapper({nxtrue_rdata}, " - f"{nytrue}, {self.model.num_par()}, {self.model.num_const()}, " - f"{nz}, {o2flag}, ...\n [], " + f"{nytrue}, {self.model.num_par()}, " + f"{self.model.num_const()}, {nz}, {o2flag}, ...\n [], " "['simulate_' modelName '.m'], modelName, ...\n" " 'lin', 1, 1);") @@ -2595,11 +2873,14 @@ def _write_index_files(self, name: str) -> None: symbol_name = strip_pysb(symbol) if str(symbol) == '0': continue + if str(symbol_name) == '': + raise ValueError(f'{name} contains a symbol called ""') lines.append( f'#define {symbol_name} {name}[{index}]' ) - with open(os.path.join(self.model_path, f'{name}.h'), 'w') as fileout: + filename = os.path.join(self.model_path, f'{self.model_name}_{name}.h') + with open(filename, 'w') as fileout: fileout.write('\n'.join(lines)) def _write_function_file(self, function: str) -> None: @@ -2637,13 +2918,33 @@ def _write_function_file(self, function: str) -> None: lines.append('') - for sym in self.model.sym_names(): - # added |double for data - # added '[0]*' for initial conditions - if re.search( - fr'const (realtype|double) \*{sym}[0]*[,)]+', signature - ) or (function == sym and function not in non_unique_id_symbols): - lines.append(f'#include "{sym}.h"') + # extract symbols that need definitions from signature + # don't add includes for files that won't be generated. + # Unfortunately we cannot check for `self.functions[sym]['body']` + # here since it may not have been generated yet. + for match in re.findall( + fr'const (realtype|double) \*([\w]+)[0]*[,\)]+', signature + ): + sym = match[1] + if sym not in self.model.sym_names(): + continue + + if sym in sparse_functions: + iszero = smart_is_zero_matrix(self.model.sparseeq(sym)) + elif sym in self.functions: + iszero = smart_is_zero_matrix(self.model.eq(sym)) + else: + iszero = len(self.model.sym(sym)) == 0 + + if iszero: + continue + + lines.append(f'#include "{self.model_name}_{sym}.h"') + + # include return symbols + if function in self.model.sym_names() and \ + function not in non_unique_id_symbols: + lines.append(f'#include "{self.model_name}_{function}.h"') lines.extend([ '', @@ -2664,7 +2965,11 @@ def _write_function_file(self, function: str) -> None: # starting (^|\W) for the following match body = [re.sub(r'(^|\W)std::pow\(', r'\1amici::pos_pow(', line) for line in body] - self.functions[function]['body'] = body + + if body: + self.functions[function]['body'] = body + else: + return lines += body lines.extend([ '}', @@ -2732,9 +3037,11 @@ def _write_function_index(self, function: str, indextype: str) -> None: static_array_name = f"{function}_{indextype}_{self.model_name}_" if function in multiobs_functions: # list of index vectors - lines.append("static constexpr std::array, {len(values)}> " - f"{static_array_name} = {{{{") + lines.append( + "static constexpr std::array, {len(values)}> " + f"{static_array_name} = {{{{" + ) lines.extend([' {' + ', '.join(map(str, index_vector)) + '}, ' for index_vector in values]) @@ -2753,9 +3060,15 @@ def _write_function_index(self, function: str, indextype: str) -> None: if len(values): if function in multiobs_functions: - lines.append(f" {function}.set_{setter}(gsl::make_span({static_array_name}[index]));") + lines.append( + f" {function}.set_{setter}" + f"(gsl::make_span({static_array_name}[index]));" + ) else: - lines.append(f" {function}.set_{setter}(gsl::make_span({static_array_name}));") + lines.append( + f" {function}.set_{setter}" + f"(gsl::make_span({static_array_name}));" + ) lines.extend([ '}' @@ -2789,9 +3102,13 @@ def _get_function_body(self, lines = [] - if len(equations) == 0 or (isinstance(equations, (sp.Matrix, - sp.ImmutableDenseMatrix)) - and min(equations.shape) == 0): + if ( + len(equations) == 0 + or ( + isinstance(equations, (sp.Matrix, sp.ImmutableDenseMatrix)) + and min(equations.shape) == 0 + ) + ): # dJydy is a list return lines @@ -2856,6 +3173,12 @@ def _get_function_body(self, f'{_print_with_exception(formula)};') elif function in event_functions: + cases = {ie: _get_sym_lines_array(equations[ie], function, 0) + for ie in range(self.model.num_events()) + if not smart_is_zero_matrix(equations[ie])} + lines.extend(get_switch_statement('ie', cases, 1)) + + elif function in event_sensi_functions: outer_cases = {} for ie, inner_equations in enumerate(equations): inner_lines = [] @@ -2883,10 +3206,11 @@ def _get_function_body(self, for iobs in range(self.model.num_obs()) if not smart_is_zero_matrix(equations[iobs])} else: - cases = {iobs: _get_sym_lines_array(equations[:, iobs], function, - 0) - for iobs in range(self.model.num_obs()) - if not smart_is_zero_matrix(equations[:, iobs])} + cases = { + iobs: _get_sym_lines_array(equations[:, iobs], function, 0) + for iobs in range(self.model.num_obs()) + if not smart_is_zero_matrix(equations[:, iobs]) + } lines.extend(get_switch_statement('iy', cases, 1)) elif function in self.model.sym_names() \ @@ -2943,12 +3267,16 @@ def _write_model_header_cpp(self) -> None: 'NEVENT': str(self.model.num_events()), 'NOBJECTIVE': '1', 'NW': str(len(self.model.sym('w'))), - 'NDWDP': str(len(self.model.sparsesym('dwdp'))), + 'NDWDP': str(len(self.model.sparsesym( + 'dwdp', force_generate=self.generate_sensitivity_code + ))), 'NDWDX': str(len(self.model.sparsesym('dwdx'))), 'NDWDW': str(len(self.model.sparsesym('dwdw'))), 'NDXDOTDW': str(len(self.model.sparsesym('dxdotdw'))), 'NDXDOTDP_EXPLICIT': str(len(self.model.sparsesym( - 'dxdotdp_explicit'))), + 'dxdotdp_explicit', + force_generate=self.generate_sensitivity_code + ))), 'NDXDOTDX_EXPLICIT': str(len(self.model.sparsesym( 'dxdotdx_explicit'))), 'NDJYDY': 'std::vector{%s}' @@ -2993,11 +3321,39 @@ def _write_model_header_cpp(self) -> None: if self.model._has_quadratic_nllh else 'false', } - for fun in [ - 'w', 'dwdp', 'dwdx', 'dwdw', 'x_rdata', 'x_solver', 'total_cl', - 'dxdotdw', 'dxdotdp_explicit', 'dxdotdx_explicit', - 'dJydy' - ]: + for fun, fundef in self.functions.items(): + if fun in nobody_functions: + continue + + if 'body' not in fundef: + tpl_data[f'{fun.upper()}_DEF'] = '' + + if fun in sensi_functions + sparse_sensi_functions and \ + not self.generate_sensitivity_code: + impl = '' + else: + impl = get_model_override_implementation( + fun, self.model_name, nobody=True + ) + + tpl_data[f'{fun.upper()}_IMPL'] = impl + + if fun in sparse_functions: + for indexfield in ['colptrs', 'rowvals']: + if fun in sparse_sensi_functions and \ + not self.generate_sensitivity_code: + impl = '' + else: + impl = get_sunindex_override_implementation( + fun, self.model_name, indexfield, nobody=True + ) + tpl_data[f'{fun.upper()}_{indexfield.upper()}_DEF'] \ + = '' + tpl_data[f'{fun.upper()}_{indexfield.upper()}_IMPL'] \ + = impl + + continue + tpl_data[f'{fun.upper()}_DEF'] = \ get_function_extern_declaration(fun, self.model_name) tpl_data[f'{fun.upper()}_IMPL'] = \ @@ -3045,8 +3401,8 @@ def _get_symbol_name_initializer_list(self, name: str) -> str: """ return '\n'.join( [ - f'"{symbol}",' - for symbol in self.model.name(name) + f'"{symbol}", // {name}[{idx}]' + for idx, symbol in enumerate(self.model.name(name)) ] ) @@ -3063,8 +3419,8 @@ def _get_symbol_id_initializer_list(self, name: str) -> str: """ return '\n'.join( [ - f'"{strip_pysb(symbol)}",' - for symbol in self.model.sym(name) + f'"{strip_pysb(symbol)}", // {name}[{idx}]' + for idx, symbol in enumerate(self.model.sym(name)) ] ) @@ -3073,18 +3429,10 @@ def _write_c_make_file(self): Write CMake CMakeLists.txt file for this model. """ - sources = [self.model_name + '_' + function + '.cpp ' - for function in self.functions.keys() - if self.functions[function].get('body', None) is not None] - - # add extra source files for sparse matrices - for function in sparse_functions: - sources.append(self.model_name + '_' + function - + '_colptrs.cpp') - sources.append(self.model_name + '_' + function - + '_rowvals.cpp ') - - sources.append(f'{self.model_name}.cpp') + sources = [ + f + ' ' for f in os.listdir(self.model_path) + if f.endswith('.cpp') and f != 'main.cpp' + ] template_data = {'MODELNAME': self.model_name, 'SOURCES': '\n'.join(sources), @@ -3266,7 +3614,8 @@ def get_sunindex_extern_declaration(fun: str, name: str, f'(SUNMatrixWrapper &{indextype}{index_arg});' -def get_model_override_implementation(fun: str, name: str) -> str: +def get_model_override_implementation(fun: str, name: str, + nobody: bool = False) -> str: """ Constructs amici::Model::* override implementation for a given function @@ -3276,14 +3625,21 @@ def get_model_override_implementation(fun: str, name: str) -> str: :param name: model name + :param nobody: + whether the function has a nontrivial implementation + :return: c++ function implementation string """ - return \ - 'virtual void f{fun}{signature} override {{\n' \ - '{ind8}{fun}_{name}{eval_signature};\n' \ - '{ind4}}}\n'.format( + impl = 'virtual void f{fun}{signature} override {{' + + if nobody: + impl += '}}\n' + else: + impl += '\n{ind8}{fun}_{name}{eval_signature};\n{ind4}}}\n' + + return impl.format( ind4=' '*4, ind8=' '*8, fun=fun, @@ -3294,7 +3650,8 @@ def get_model_override_implementation(fun: str, name: str) -> str: def get_sunindex_override_implementation(fun: str, name: str, - indextype: str) -> str: + indextype: str, + nobody: bool = False) -> str: """ Constructs the amici::Model:: function implementation for an index function of a given function @@ -3308,6 +3665,9 @@ def get_sunindex_override_implementation(fun: str, name: str, :param indextype: index function {'colptrs', 'rowvals'} + :param nobody: + whether the corresponding function has a nontrivial implementation + :return: c++ function implementation string @@ -3315,10 +3675,14 @@ def get_sunindex_override_implementation(fun: str, name: str, index_arg = ', int index' if fun in multiobs_functions else '' index_arg_eval = ', index' if fun in multiobs_functions else '' - return \ - 'virtual void f{fun}_{indextype}{signature} override {{\n' \ - '{ind8}{fun}_{indextype}_{name}{eval_signature};\n' \ - '{ind4}}}\n'.format( + impl = 'virtual void f{fun}_{indextype}{signature} override {{' + + if nobody: + impl += '}}\n' + else: + impl += '{ind8}{fun}_{indextype}_{name}{eval_signature};\n{ind4}}}\n' + + return impl.format( ind4=' '*4, ind8=' '*8, fun=fun, @@ -3354,10 +3718,11 @@ def remove_typedefs(signature: str) -> str: 'const int ', 'int ', 'SUNMatrixContent_Sparse ', + 'gsl::span' ] for typedef in typedefs: - signature = signature.replace(typedef, ' ') + signature = signature.replace(typedef, '') return signature @@ -3641,93 +4006,3 @@ def _custom_print_min(self, expr): return self._print(expr.args[0]) return "%smin(%s, %s)" % (self._ns, self._print(expr.args[0]), self._print(Min(*expr.args[1:]))) - - -def _collect_heaviside_roots(args: Sequence[sp.Expr]) -> List[sp.Expr]: - """ - Recursively checks an expression for the occurrence of Heaviside - functions and return all roots found - - :param args: - args attribute of the expanded expression - - :returns: - root functions that were extracted from Heaviside function arguments - """ - root_funs = [] - for arg in args: - if arg.func == sp.Heaviside: - root_funs.append(arg.args[0]) - elif arg.has(sp.Heaviside): - root_funs.extend(_collect_heaviside_roots(arg.args)) - - return root_funs - - -def _get_unique_root(root_found: sp.Expr, roots: List[Event]) -> sp.Symbol: - """ - Collects roots of Heaviside functions and events and stores them in - the roots list. It checks for redundancy to not store symbolically - equivalent root functions more than once. - - :param root_found: - equation of the root function - :param roots: - list of already known root functions with identifier - - :returns: - unique identifier for root - """ - for root in roots: - if sp.simplify(root_found - root.get_val()) == 0: - return root.get_id() - - # create an event for a new root function - root_symstr = f'Heaviside_{len(roots)}' - roots.append(Event( - identifier=sp.Symbol(root_symstr), - name=root_symstr, - value=root_found, - state_update=None, - event_observable=None - )) - return roots[-1].get_id() - - -def _process_heavisides(dxdt: sp.Expr, roots: List[Event]) -> sp.Expr: - """ - Parses the RHS of a state variable, checks for Heaviside functions, - collects unique roots functions that can be tracked by SUNDIALS and - replaces Heaviside Functions by amici helper variables that will be - updated based on SUNDIALS root tracking. - - :param dxdt: - right hand side of state variable - :param roots: - list of known root functions with identifier - - :returns: - dxdt with Heaviside functions replaced by amici helper variables - """ - - # expanding the rhs will in general help to collect the same - # heaviside function - dt_expanded = dxdt.expand() - # track all the old Heaviside expressions in tmp_roots_old - # replace them later by the new expressions - heavisides = [] - # run through the expression tree and get the roots - tmp_roots_old = _collect_heaviside_roots(dt_expanded.args) - for tmp_old in tmp_roots_old: - # we want unique identifiers for the roots - tmp_new = _get_unique_root(tmp_old, roots) - # For Heavisides, we need to add the negative function as well - _get_unique_root(sp.sympify(- tmp_old), roots) - heavisides.append((sp.Heaviside(tmp_old), tmp_new)) - - if heavisides: - # only apply subs if necessary - for heaviside_sympy, heaviside_amici in heavisides: - dxdt = dxdt.subs(heaviside_sympy, heaviside_amici) - - return dxdt diff --git a/deps/AMICI/python/amici/petab_import_pysb.py b/deps/AMICI/python/amici/petab_import_pysb.py index 4f0abd212..f5aa22dd5 100644 --- a/deps/AMICI/python/amici/petab_import_pysb.py +++ b/deps/AMICI/python/amici/petab_import_pysb.py @@ -236,6 +236,11 @@ def create_dummy_sbml( dummy_sbml_model.setExtentUnits("mole") dummy_sbml_model.setSubstanceUnits('mole') + # mandatory if there are species + c = dummy_sbml_model.createCompartment() + c.setId('dummy_compartment') + c.setConstant(False) + # parameters are required for parameter mapping for parameter in pysb_model.parameters: p = dummy_sbml_model.createParameter() @@ -261,6 +266,9 @@ def create_dummy_sbml( s.setId(component.name) s.setInitialAmount(0.0) s.setHasOnlySubstanceUnits(False) + s.setBoundaryCondition(False) + s.setCompartment('dummy_compartment') + s.setConstant(False) return document, dummy_sbml_model diff --git a/deps/AMICI/python/amici/pysb_import.py b/deps/AMICI/python/amici/pysb_import.py index 878222fcf..ce1e1ef0b 100644 --- a/deps/AMICI/python/amici/pysb_import.py +++ b/deps/AMICI/python/amici/pysb_import.py @@ -49,6 +49,7 @@ def pysb2amici( compute_conservation_laws: bool = True, compile: bool = True, simplify: Callable = lambda x: sp.powsimp(x, deep=True), + generate_sensitivity_code: bool = True, ): """ Generate AMICI C++ files for the provided model. @@ -93,7 +94,7 @@ def pysb2amici( :attr:`logging.DEBUG`/:attr:`logging.ERROR` :param assume_pow_positivity: - if set to ``true``, a special pow function is used to avoid problems + if set to ``True``, a special pow function is used to avoid problems with state variables that may become negative due to numerical errors @@ -102,17 +103,21 @@ def pysb2amici( extension :param compute_conservation_laws: - if set to ``true``, conservation laws are automatically computed and + if set to ``True``, conservation laws are automatically computed and applied such that the state-jacobian of the ODE right-hand-side has - full rank. This option should be set to ``true`` when using the Newton + full rank. This option should be set to ``True`` when using the Newton algorithm to compute steadystates :param compile: - If ``true``, build the python module for the generated model. If false, + If ``True``, build the python module for the generated model. If false, just generate the source code. :param simplify: see :attr:`amici.ODEModel._simplify` + + :param generate_sensitivity_code: + if set to ``False``, code for sensitivity computation will not be + generated """ if observables is None: observables = [] diff --git a/deps/AMICI/python/amici/sbml_import.py b/deps/AMICI/python/amici/sbml_import.py index 73ae6aa2f..ab9cfd9ba 100644 --- a/deps/AMICI/python/amici/sbml_import.py +++ b/deps/AMICI/python/amici/sbml_import.py @@ -217,6 +217,7 @@ def sbml2amici(self, compute_conservation_laws: bool = True, simplify: Callable = lambda x: sp.powsimp(x, deep=True), log_as_log10: bool = True, + generate_sensitivity_code: bool = True, **kwargs) -> None: """ Generate and compile AMICI C++ files for the model provided to the @@ -256,11 +257,11 @@ def sbml2amici(self, callable generating a custom noise string. :param verbose: - verbosity level for logging, True/False default to - logging.Error/logging.DEBUG + verbosity level for logging, ``True``/``False`` default to + ``logging.Error``/``logging.DEBUG`` :param assume_pow_positivity: - if set to True, a special pow function is + if set to ``True``, a special pow function is used to avoid problems with state variables that may become negative due to numerical errors @@ -272,21 +273,28 @@ def sbml2amici(self, see :class:`amici.ode_export.ODEExporter` :param compile: - If True, compile the generated Python package, - if False, just generate code. + If ``True``, compile the generated Python package, + if ``False``, just generate code. :param compute_conservation_laws: - if set to true, conservation laws are automatically computed and - applied such that the state-jacobian of the ODE right-hand-side has - full rank. This option should be set to True when using the newton - algorithm to compute steadystate sensitivities. + if set to ``True``, conservation laws are automatically computed + and applied such that the state-jacobian of the ODE + right-hand-side has full rank. This option should be set to + ``True`` when using the newton algorithm to compute steadystate + sensitivities. :param simplify: see :attr:`ODEModel._simplify` :param log_as_log10: - If True, log in the SBML model will be parsed as `log10` (default), - if False, log will be parsed as natural logarithm `ln` + If ``True``, log in the SBML model will be parsed as ``log10`` + (default), if ``False``, log will be parsed as natural logarithm + ``ln`` + + :param generate_sensitivity_code: + If ``False``, the code required for sensitivity computation will + not be generated + """ set_log_level(logger, verbose) @@ -337,6 +345,14 @@ def sbml2amici(self, sbml.L3P_PARSE_LOG_AS_LN ) self._process_sbml(constant_parameters) + if self.symbols.get(SymbolId.EVENT, False): + if compute_conservation_laws: + logger.warning( + 'Conservation laws are currently not supported for models ' + 'with events, and will be turned off.' + ) + compute_conservation_laws = False + self._process_observables(observables, sigmas, noise_distributions) self._replace_compartments_with_volumes() @@ -352,7 +368,8 @@ def sbml2amici(self, verbose=verbose, assume_pow_positivity=assume_pow_positivity, compiler=compiler, - allow_reinit_fixpar_initcond=allow_reinit_fixpar_initcond + allow_reinit_fixpar_initcond=allow_reinit_fixpar_initcond, + generate_sensitivity_code=generate_sensitivity_code ) exporter.set_name(model_name) exporter.set_paths(output_dir) @@ -372,10 +389,6 @@ def _process_sbml(self, constant_parameters: List[str] = None) -> None: :param constant_parameters: SBML Ids identifying constant parameters """ - - if constant_parameters is None: - constant_parameters = [] - self.check_support() self._gather_locals() self._process_parameters(constant_parameters) @@ -385,6 +398,7 @@ def _process_sbml(self, constant_parameters: List[str] = None) -> None: self._process_rules() self._process_initial_assignments() self._process_species_references() + self._process_events() def check_support(self) -> None: """ @@ -396,9 +410,6 @@ def check_support(self) -> None: and self.sbml.all_elements_from_plugins.getSize(): raise SBMLException('SBML extensions are currently not supported!') - if self.sbml.getNumEvents(): - raise SBMLException('Events are currently not supported!') - if any([not rule.isAssignment() and not isinstance( self.sbml.getElementBySId(rule.getVariable()), (sbml.Compartment, sbml.Species, sbml.Parameter) @@ -414,12 +425,69 @@ def check_support(self) -> None: ) for rule in self.sbml.getListOfRules()]): raise SBMLException('Only assignment and rate rules are ' 'currently supported for compartments, ' - 'species, and parameters! Error ' - f'occurred with rule: {rule.getVariable()}') + 'species, and parameters!') if any([r.getFast() for r in self.sbml.getListOfReactions()]): raise SBMLException('Fast reactions are currently not supported!') + # Check events for unsupported functionality + self.check_event_support() + + def check_event_support(self) -> None: + """ + Check possible events in the model, as AMICI does currently not support + + * delays in events + * priorities of events + * events fired at initial time + + Furthermore, event triggers are optional (e.g., if an event is fired at + initial time, no trigger function is necessary). + In this case, warn that this event will have no effect. + """ + for event in self.sbml.getListOfEvents(): + event_id = event.getId() + # Check for delays in events + delay = event.getDelay() + if delay is not None: + try: + delay_time = float(self._sympy_from_sbml_math(delay)) + if delay_time != 0: + raise ValueError + # `TypeError` would be raised in the above `float(...)` + # if the delay is not a fixed time + except (TypeError, ValueError): + raise SBMLException('Events with execution delays are ' + 'currently not supported in AMICI.') + # Check for priorities + if event.getPriority() is not None: + raise SBMLException(f'Event {event_id} has a priority ' + 'specified. This is currently not ' + 'supported in AMICI.') + + # check trigger + trigger_sbml = event.getTrigger() + if trigger_sbml is None: + logger.warning(f'Event {event_id} trigger has no trigger, ' + 'so will be skipped.') + continue + if trigger_sbml.getMath() is None: + logger.warning(f'Event {event_id} trigger has no trigger ' + 'expression, so a dummy trigger will be set.') + if not trigger_sbml.getInitialValue(): + # True: event not executed if triggered at time == 0 + # (corresponding to AMICI default). Raise if set to False. + raise SBMLException( + f'Event {event_id} has a trigger that has an initial ' + 'value of False. This is currently not supported in AMICI.' + ) + + if not trigger_sbml.getPersistent(): + raise SBMLException( + f'Event {event_id} has a non-persistent trigger.' + 'This is currently not supported in AMICI.' + ) + @log_execution_time('gathering local SBML symbols', logger) def _gather_locals(self) -> None: """ @@ -573,6 +641,7 @@ def _process_species(self) -> None: 'index': len(self.symbols[SymbolId.SPECIES]), } + self._convert_event_assignment_parameter_targets_to_species() self._process_species_initial() self._process_rate_rules() @@ -615,11 +684,10 @@ def _process_species_initial(self): @log_execution_time('processing SBML rate rules', logger) def _process_rate_rules(self): """ - Process assignment and rate rules for species, compartments and - parameters. Compartments and parameters with rate rules are - implemented as species. Note that, in the case of species, - rate rules may describe the change in amount, not concentration, - of a species. + Process rate rules for species, compartments and parameters. + Compartments and parameters with rate rules are implemented as species. + Note that, in the case of species, rate rules may describe the change + in amount, not concentration, of a species. """ rules = self.sbml.getListOfRules() # compartments with rules are replaced with constants in the relevant @@ -735,6 +803,16 @@ def _process_parameters(self, for parameter in self.sbml.getListOfParameters() if parameter.getId() in constant_parameters ] + for parameter in fixed_parameters: + if self._get_element_initial_assignment(parameter.getId()) is not \ + None or self.is_assignment_rule_target(parameter) or \ + self.is_rate_rule_target(parameter): + raise SBMLException( + f'Cannot turn parameter {parameter.getId()} into a ' + 'constant/fixed parameter since it either has an ' + 'initial assignment or is the target of an assignment or ' + 'rate rule.' + ) parameters = [ parameter for parameter @@ -869,6 +947,179 @@ def _process_time(self) -> None: self._replace_in_all_expressions(sbml_time_symbol, amici_time_symbol) + def _convert_event_assignment_parameter_targets_to_species(self): + """ + Convert parameters that are targets of event assignments to species. + + This is for the convenience of only implementing event assignments for + "species". + """ + parameter_targets = \ + _collect_event_assignment_parameter_targets(self.sbml) + for parameter_target in parameter_targets: + # Parameter rate rules already exist as species. + if parameter_target in self.symbols[SymbolId.SPECIES]: + continue + if parameter_target in self.parameter_assignment_rules: + raise SBMLException( + 'AMICI does not currently support models with SBML events ' + 'that affect parameters that are also the target of ' + 'assignment rules.' + ) + parameter_def = None + for symbol_id in {SymbolId.PARAMETER, SymbolId.FIXED_PARAMETER}: + if parameter_target in self.symbols[symbol_id]: + # `parameter_target` should only exist in one of the + # `symbol_id` dictionaries. + if parameter_def is not None: + raise AssertionError( + 'Unexpected error. The parameter target of an ' + 'event assignment was processed twice.' + ) + parameter_def = \ + self.symbols[symbol_id].pop(parameter_target) + if parameter_def is None: + raise AssertionError( + 'Unexpected error. The parameter target of an event ' + 'assignment could not be found.' + ) + # Fixed parameters are added as species such that they can be + # targets of events. + self.symbols[SymbolId.SPECIES][parameter_target] = { + 'name': parameter_def['name'], + 'init': sp.Float(parameter_def['value']), + # 'compartment': None, # can ignore for amounts + 'constant': False, + 'amount': True, + # 'conversion_factor': 1.0, # can be ignored + 'index': len(self.symbols[SymbolId.SPECIES]), + 'dt': sp.Float(0), + } + + @log_execution_time('processing SBML events', logger) + def _process_events(self) -> None: + """Process SBML events.""" + events = self.sbml.getListOfEvents() + + def get_empty_bolus_value() -> sp.Float: + """ + Used in the event update vector for species that are not affected + by the event. + """ + return sp.Symbol('AMICI_EMTPY_BOLUS') + + # Used to update species concentrations when an event affects a + # compartment. + concentration_species_by_compartment = { + symbol_with_assumptions(c.getId()): [] + for c in self.sbml.getListOfCompartments() + } + for species, species_def in self.symbols[SymbolId.SPECIES].items(): + if ( + # Species is a concentration + not species_def.get('amount', True) and + # Species has a compartment + 'compartment' in species_def + ): + concentration_species_by_compartment[ + species_def['compartment'] + ].append(species) + + for ievent, event in enumerate(events): + # get the event id (which is optional unfortunately) + event_id = event.getId() + if event_id is None or event_id == '': + event_id = f'event_{ievent}' + event_sym = sp.Symbol(event_id) + + # get and parse the trigger function + trigger_sbml = event.getTrigger() + trigger_sym = self._sympy_from_sbml_math(trigger_sbml) + trigger = _parse_event_trigger(trigger_sym) + + # Currently, all event assignment targets must exist in + # self.symbols[SymbolId.SPECIES] + state_vector = list(self.symbols[SymbolId.SPECIES].keys()) + + # parse the boluses / event assignments + bolus = [get_empty_bolus_value() for _ in state_vector] + event_assignments = event.getListOfEventAssignments() + compartment_event_assignments = set() + for event_assignment in event_assignments: + variable_sym = \ + symbol_with_assumptions(event_assignment.getVariable()) + if event_assignment.getMath() is None: + # Ignore event assignments with no change in value. + continue + formula = self._sympy_from_sbml_math(event_assignment) + try: + # Try to find the species in the state vector. + index = state_vector.index(variable_sym) + bolus[index] = formula + except ValueError: + raise SBMLException( + 'Could not process event assignment for ' + f'{str(variable_sym)}. AMICI currently only allows ' + 'event assignments to species; parameters; or, ' + 'compartments with rate rules, at the moment.' + ) + try: + # Try working with the formula now to detect errors + # here instead of at multiple points downstream. + _ = formula - variable_sym + except TypeError: + raise SBMLException( + 'Could not process event assignment for ' + f'{str(variable_sym)}. AMICI only allows symbolic ' + 'expressions as event assignments.' + ) + if variable_sym in concentration_species_by_compartment: + compartment_event_assignments.add(variable_sym) + + for comp, assignment in \ + self.compartment_assignment_rules.items(): + if variable_sym not in assignment.free_symbols: + continue + compartment_event_assignments.add(comp) + + # Update the concentration of species with concentration units + # in compartments that were affected by the event assignments. + for compartment_sym in compartment_event_assignments: + for species_sym in concentration_species_by_compartment[ + compartment_sym + ]: + # If the species was not affected by an event assignment + # then the old value should be updated. + if ( + bolus[state_vector.index(species_sym)] + == get_empty_bolus_value() + ): + species_value = species_sym + # else the species was affected by an event assignment, + # hence the updated value should be updated further. + else: + species_value = bolus[state_vector.index(species_sym)] + # New species value is old amount / new volume. + bolus[state_vector.index(species_sym)] = ( + species_value * compartment_sym / formula + ) + + # Subtract the current species value from each species with an + # update, as the bolus will be added on to the current species + # value during simulation. + for index in range(len(bolus)): + if bolus[index] != get_empty_bolus_value(): + bolus[index] -= state_vector[index] + bolus[index] = bolus[index].subs(get_empty_bolus_value(), + sp.Float(0.0)) + + self.symbols[SymbolId.EVENT][event_sym] = { + 'name': event_id, + 'value': trigger, + 'state_update': sp.MutableDenseMatrix(bolus), + 'event_observable': None, + } + @log_execution_time('processing SBML observables', logger) def _process_observables( self, @@ -1229,7 +1480,8 @@ def _replace_in_all_expressions(self, for k, v in self.symbols[symbol].items() } - for symbol in [SymbolId.OBSERVABLE, SymbolId.LLHY, SymbolId.SIGMAY]: + for symbol in [SymbolId.OBSERVABLE, SymbolId.LLHY, + SymbolId.SIGMAY]: if old not in self.symbols[symbol]: continue self.symbols[symbol][new] = self.symbols[symbol][old] @@ -1237,12 +1489,19 @@ def _replace_in_all_expressions(self, # replace in values for symbol in [SymbolId.OBSERVABLE, SymbolId.LLHY, SymbolId.SIGMAY, - SymbolId.EXPRESSION]: + SymbolId.EXPRESSION, SymbolId.EVENT]: if not self.symbols.get(symbol, None): continue for element in self.symbols[symbol].values(): element['value'] = smart_subs(element['value'], old, new) + # replace in event state updates (boluses) + if self.symbols.get(SymbolId.EVENT, False): + for event in self.symbols[SymbolId.EVENT].values(): + for index in range(len(event['state_update'])): + event['state_update'][index] = \ + smart_subs(event['state_update'][index], old, new) + if SymbolId.SPECIES in self.symbols: for species in self.symbols[SymbolId.SPECIES].values(): species['init'] = smart_subs(species['init'], @@ -1268,7 +1527,8 @@ def _clean_reserved_symbols(self) -> None: """ Remove all reserved symbols from self.symbols """ - reserved_symbols = ['x', 'k', 'p', 'y', 'w', 'h', 't'] + reserved_symbols = ['x', 'k', 'p', 'y', 'w', 'h', 't', + 'AMICI_EMPTY_BOLUS'] for sym in reserved_symbols: old_symbol = symbol_with_assumptions(sym) new_symbol = symbol_with_assumptions(f'amici_{sym}') @@ -1372,8 +1632,7 @@ def _get_element_stoichiometry(self, return sp.Float(1.0) - def is_assignment_rule_target(self, - element: sbml.SBase) -> bool: + def is_assignment_rule_target(self, element: sbml.SBase) -> bool: """ Checks if an element has a valid assignment rule in the specified model. @@ -1390,6 +1649,23 @@ def is_assignment_rule_target(self, return True + def is_rate_rule_target(self, element: sbml.SBase) -> bool: + """ + Checks if an element has a valid assignment rule in the specified + model. + + :param element: + SBML variable + + :return: + boolean indicating truth of function name + """ + a = self.sbml.getRateRuleByVariable(element.getId()) + if a is None or self._sympy_from_sbml_math(a) is None: + return False + + return True + def _check_lib_sbml_errors(sbml_doc: sbml.SBMLDocument, show_warnings: bool = False) -> None: @@ -1525,7 +1801,7 @@ def _parse_special_functions(sym: sp.Expr, toplevel: bool = True) -> sp.Expr: if isinstance(sym, (sp.Function, sp.Mul, sp.Add)): sym._args = args - + elif toplevel and isinstance(sym, BooleanAtom): # Replace boolean constants by numbers so they can be differentiated # must not replace in Piecewise function. Therefore, we only replace @@ -1537,7 +1813,7 @@ def _parse_special_functions(sym: sp.Expr, toplevel: bool = True) -> sp.Expr: def _denest_piecewise( args: Sequence[Union[sp.Expr, sp.logic.boolalg.Boolean, bool]] - ) -> Tuple[Union[sp.Expr, sp.logic.boolalg.Boolean, bool]]: +) -> Tuple[Union[sp.Expr, sp.logic.boolalg.Boolean, bool]]: """ Denest piecewise functions that contain piecewise as condition @@ -1582,8 +1858,8 @@ def _denest_piecewise( def _parse_piecewise_to_heaviside(args: Iterable[sp.Expr]) -> sp.Expr: """ - Piecewise functions cannot be transformed into C++ right away, but AMICI has - a special interface for Heaviside function, so we transform them + Piecewise functions cannot be transformed into C++ right away, but AMICI + has a special interface for Heaviside functions, so we transform them. :param args: symbolic expressions for arguments of the piecewise function @@ -1602,14 +1878,14 @@ def _parse_piecewise_to_heaviside(args: Iterable[sp.Expr]) -> sp.Expr: if trigger == sp.false: continue - tmp = _parse_trigger(trigger) + tmp = _parse_heaviside_trigger(trigger) formula += coeff * sp.simplify(not_condition * tmp) not_condition *= (1-tmp) return formula -def _parse_trigger(trigger: sp.Expr) -> sp.Expr: +def _parse_heaviside_trigger(trigger: sp.Expr) -> sp.Expr: """ Recursively translates a boolean trigger function into a real valued root function @@ -1619,6 +1895,7 @@ def _parse_trigger(trigger: sp.Expr) -> sp.Expr: """ if trigger.is_Relational: root = trigger.args[0] - trigger.args[1] + _check_unsupported_functions(root, 'sympy.Expression') # normalize such that we always implement <, # this ensures that we can correctly evaluate the condition if @@ -1640,15 +1917,56 @@ def _parse_trigger(trigger: sp.Expr) -> sp.Expr: # or(x,y) = not(and(not(x),not(y)) if isinstance(trigger, sp.Or): - return 1-sp.Mul(*[1-_parse_trigger(arg) + return 1-sp.Mul(*[1-_parse_heaviside_trigger(arg) for arg in trigger.args]) if isinstance(trigger, sp.And): - return sp.Mul(*[_parse_trigger(arg) + return sp.Mul(*[_parse_heaviside_trigger(arg) for arg in trigger.args]) - raise SBMLException('AMICI can not parse piecewise functions ' - f'with argument {trigger}.') + raise SBMLException( + 'AMICI can not parse piecewise/event trigger functions with argument ' + f'{trigger}.' + ) + + +def _parse_event_trigger(trigger: sp.Expr) -> sp.Expr: + """ + Recursively translates a boolean trigger function into a real valued + root function + + :param trigger: + :return: real valued root function expression + """ + # Events can be defined without trigger, i.e., the event will never fire. + # In this case, set a dummy trigger: + if trigger is None: + return sp.Float(1.0) + if trigger.is_Relational: + root = trigger.args[0] - trigger.args[1] + _check_unsupported_functions(root, 'sympy.Expression') + + # convert relational expressions into trigger functions + if isinstance(trigger, sp.core.relational.LessThan) or \ + isinstance(trigger, sp.core.relational.StrictLessThan): + # y < x or y <= x + return -root + if isinstance(trigger, sp.core.relational.GreaterThan) or \ + isinstance(trigger, sp.core.relational.StrictGreaterThan): + # y >= x or y > x + return root + + # or(x,y): any of {x,y} is > 0: sp.Max(x, y) + if isinstance(trigger, sp.Or): + return sp.Max(*[_parse_event_trigger(arg) for arg in trigger.args]) + # and(x,y): all out of {x,y} are > 0: sp.Min(x, y) + if isinstance(trigger, sp.And): + return sp.Min(*[_parse_event_trigger(arg) for arg in trigger.args]) + + raise SBMLException( + 'AMICI can not parse piecewise/event trigger functions with argument ' + f'{trigger}.' + ) def _parse_logical_operators(math_str: Union[str, float, None] @@ -1864,3 +2182,17 @@ def replace_logx(math_str: Union[str, float, None]) -> Union[str, float, None]: return re.sub( r'(^|\W)log(\d+)\(', r'\g<1>1/ln(\2)*ln(', math_str ) + + +def _collect_event_assignment_parameter_targets(sbml_model: sbml.Model): + targets = set() + sbml_parameters = sbml_model.getListOfParameters() + sbml_parameter_ids = [p.getId() for p in sbml_parameters] + for event in sbml_model.getListOfEvents(): + for event_assignment in event.getListOfEventAssignments(): + target_id = event_assignment.getVariable() + if target_id in sbml_parameter_ids: + targets.add(_get_identifier_symbol( + sbml_parameters[sbml_parameter_ids.index(target_id)] + )) + return targets diff --git a/deps/AMICI/python/examples/example_presimulation/ExampleExperimentalConditions.ipynb b/deps/AMICI/python/examples/example_presimulation/ExampleExperimentalConditions.ipynb new file mode 100644 index 000000000..07da70c02 --- /dev/null +++ b/deps/AMICI/python/examples/example_presimulation/ExampleExperimentalConditions.ipynb @@ -0,0 +1,462 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# AMICI Python example \"Experimental Conditions\"\n", + "In this example we will explore some more options for the initialization of experimental conditions, including how to reset initial conditions based on changing values for `fixedParameters` as well as an additional presimulation phase on top of preequilibration. This notebook is expected to run from the `python/example_presimulation` directory." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# SBML model we want to import\n", + "sbml_file = 'model_presimulation.xml'\n", + "# Name of the model that will also be the name of the python module\n", + "model_name = 'model_presimulation'\n", + "# Directory to which the generated model code is written\n", + "model_output_dir = model_name\n", + "\n", + "import libsbml\n", + "import amici\n", + "import amici.plotting\n", + "import os\n", + "import sys\n", + "import importlib\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "from pprint import pprint" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model Loading\n", + "Here we load a simple model of protein phosphorylation that can be inhibited by a drug. This model was created using PySB (see `createModel.py`)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Species:\n", + "[('__s0', \"PROT(kin=None, drug=None, phospho='u')\"),\n", + " ('__s1', 'DRUG(bound=None)'),\n", + " ('__s2', 'KIN(bound=None)'),\n", + " ('__s3', \"DRUG(bound=1) ._br_PROT(kin=None, drug=1, phospho='u')\"),\n", + " ('__s4', \"KIN(bound=1) ._br_PROT(kin=1, drug=None, phospho='u')\"),\n", + " ('__s5', \"PROT(kin=None, drug=None, phospho='p')\")]\n", + "\n", + "Reactions:\n", + "PROT_DRUG_bind: __s0 + __s1 <-> __s3\t\t[-(koff_prot_drug * __s3) + kon_prot_drug * __s0 * __s1]\n", + "PROT_KIN_bind: __s0 + __s2 -> __s4\t\t[kon_prot_kin * __s0 * __s2]\n", + "PROT_KIN_phospho: __s4 -> __s2 + __s5\t\t[kphospho_prot_kin * __s4]\n", + "PROT_dephospho: __s5 -> __s0\t\t[kdephospho_prot * __s5]\n", + "Parameters:\n", + "[('initProt', 'initProt'),\n", + " ('initDrug', 'initDrug'),\n", + " ('initKin', 'initKin'),\n", + " ('pPROT_obs', 'pPROT_obs'),\n", + " ('PROT_0', 'PROT_0'),\n", + " ('DRUG_0', 'DRUG_0'),\n", + " ('KIN_0', 'KIN_0'),\n", + " ('kon_prot_drug', 'kon_prot_drug'),\n", + " ('koff_prot_drug', 'koff_prot_drug'),\n", + " ('kon_prot_kin', 'kon_prot_kin'),\n", + " ('kphospho_prot_kin', 'kphospho_prot_kin'),\n", + " ('kdephospho_prot', 'kdephospho_prot'),\n", + " ('__obs0', 'pPROT'),\n", + " ('__obs1', 'tPROT')]\n" + ] + } + ], + "source": [ + "sbml_reader = libsbml.SBMLReader()\n", + "sbml_doc = sbml_reader.readSBML(sbml_file)\n", + "sbml_model = sbml_doc.getModel()\n", + "\n", + "print('Species:')\n", + "pprint([(s.getId(),s.getName()) for s in sbml_model.getListOfSpecies()])\n", + "\n", + "print('\\nReactions:')\n", + "for reaction in sbml_model.getListOfReactions():\n", + " reactants = ' + '.join(['%s %s'%(int(r.getStoichiometry()) if r.getStoichiometry() > 1 else '', r.getSpecies()) for r in reaction.getListOfReactants()])\n", + " products = ' + '.join(['%s %s'%(int(r.getStoichiometry()) if r.getStoichiometry() > 1 else '', r.getSpecies()) for r in reaction.getListOfProducts()])\n", + " reversible = '<' if reaction.getReversible() else ''\n", + " print('%3s: %10s %1s->%10s\\t\\t[%s]' % (reaction.getName(), \n", + " reactants,\n", + " reversible,\n", + " products,\n", + " libsbml.formulaToL3String(reaction.getKineticLaw().getMath())))\n", + " \n", + "print('Parameters:')\n", + "pprint([(p.getId(),p.getName()) for p in sbml_model.getListOfParameters()])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "# Create an SbmlImporter instance for our SBML model\n", + "sbml_importer = amici.SbmlImporter(sbml_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this example we want specify the initial drug and kinase concentrations as experimental conditions. Accordingly we specify them as `fixedParameters`. The meaning of `fixedParameters` is defined in the [Glossary](https://amici.readthedocs.io/en/latest/glossary.html#term-fixed-parameters), which we display here for convenience." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import IFrame\n", + "IFrame('https://amici.readthedocs.io/en/latest/glossary.html#term-fixed-parameters', width=600, height=175)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "fixedParameters = ['DRUG_0','KIN_0']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The SBML model specifies a single observable named `pPROT` which describes the fraction of phosphorylated Protein. We load this observable using [amici.assignmentRules2observables](https://amici.readthedocs.io/en/latest/generated/amici.sbml_import.html#amici.sbml_import.assignmentRules2observables)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Observables:\n", + "{'__obs0': {'formula': '__s5', 'name': 'pPROT'}}\n" + ] + } + ], + "source": [ + "# Retrieve model output names and formulae from AssignmentRules and remove the respective rules\n", + "observables = amici.assignmentRules2observables(\n", + " sbml_importer.sbml, # the libsbml model object\n", + " filter_function=lambda variable: variable.getName() == 'pPROT' \n", + " )\n", + "print('Observables:')\n", + "pprint(observables)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now the model is ready for compilation using [sbml2amici](https://amici.readthedocs.io/en/latest/generated/amici.sbml_import.SbmlImporter.html#amici.sbml_import.SbmlImporter.sbml2amici). Note that we here pass `fixedParameters` as arguments to `constant_parameters`, which ensures that amici is aware that we want to have them as `fixedParameters`:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "sbml_importer.sbml2amici(model_name, \n", + " model_output_dir, \n", + " verbose=False,\n", + " observables=observables,\n", + " constant_parameters=fixedParameters)\n", + "# load the generated module\n", + "model_module = amici.import_model_module(model_name, model_output_dir)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To simulate the model we need to create an instance via the `getModel()` method in the generated model module." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# Create Model instance\n", + "model = model_module.getModel()\n", + "\n", + "# Create solver instance\n", + "solver = model.getSolver()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The only thing we need to simulate the model is a timepoint vector, which can be specified using the [setTimepoints](https://amici.readthedocs.io/en/latest/generated/amici.amici.Model.html#amici.amici.Model.setTimepoints) method. If we do not specify any additional options, the default values for `fixedParameters` and `parameters` that were specified in the SBML file will be used." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYYAAAEZCAYAAACTsIJzAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAArdElEQVR4nO3deZxU1Z338c+vd/al6WZrdhBEWZQGjTFRVBxUAtGYRJI4KjGMM5onZpvok4mJTiZPTGaS+JrxyRMmMToag0tQiaKYYUxMjCLNvssi2N3Q0NDs9FJd9Xv+qItWt93Q3XRXdVV9369Xvaruuadu/Y4W/at7zr3nmLsjIiJySkaiAxARkc5FiUFERBpQYhARkQaUGEREpAElBhERaUCJQUREGlBikLRiZt8zsycSHcfpnClGM9tlZlfFMyZJL0oMknLM7FYzW29mJ82swsx+bma9Ex2XSLJQYpCUYmZfBx4Evgn0Ai4GhgF/MLOcOMWQFY/PEekoSgySMsysJ3A/8GV3f8XdQ+6+C/gMMBz4QlA1z8yeMrNjZrbKzCbFHONbZlYe7NtqZlcG5Rlmdo+Z7TCzg2b2tJn1DfYNNzM3sy+a2XvA/5jZy2Z2V6P41prZDcHrh8ys1MyOmtlKM/tYo+Y0G2OjY54urjwzeyIoP2xmK8ys/9n9V5Z0oMQgqeQSIA9YFFvo7seBJcCMoGgO8AzQF3gSeN7Mss1sLHAXMNXdewB/A+wK3vNl4JPAZcAg4BDwcKPPvww4N3jfb4G5p3aY2XiiZy4vBUUrgMkxMTxjZnkxx2oyxibafLq4biF61jQEyAfuAKqbOIZIA0oMkkr6AQfcvb6JfXuD/QAr3f1Zdw8BPyGaTC4GwkAuMN7Mst19l7vvCN5zB/Btdy9z91rge8CNjbqNvufuJ9y9GngOmGxmw4J9nwcWBe/F3Z9w94PuXu/u/xZ87tiYYzUXY2OniytENCGMdvewu69096Nn/s8o6U6JQVLJAaBfM338A4P9AKWnCt09ApQBg9x9O3A30T+u+81soZkNCqoOA54LumQOA5uJJpLYrpnY4x4jenZwU1A0F/jNqf1m9g0z22xmR4Lj9eKDxNVsjE2063RxPQ4sBRaa2R4z+1EzZx0iDSgxSCp5E6gFbogtNLPuwDXAsqBoSMy+DKAI2APg7k+6+6VE/+A60YFsiP6hvsbde8c88ty9POajGk9V/Ftgrpl9hOgv/teCz/wY8I9Exz76uHtv4AhgMe9tNsZGmo0rGGO5393HE+1mmwX8bZP/5URiKDFIynD3I0QHn//dzGYG4wbDgaeJ/uJ+PKg6xcxuCM4s7iaaTN4ys7FmdoWZ5QI1RPvjI8F7/h/wL6e6hsyswMzmnCGkJUQTzAPAU8Evf4AeQD1QCWSZ2X1Az0bvbTLGJj6j2bjMbLqZTTCzTOAo0a6lSBPHEGlAiUFSirv/CPjfwL8S/WO4nOiv6itP9e8DLwCfJTpQezNwQ9CXnwv8kGiXUwVQCNwbvOchYDHwqpkdI/pH+qIzxFJLdCD8KqIDyKcsBV4B3gF2E01CpY3e3lyMjZ0urgHAs8F/h83An/ggOYo0y7RQj4iIxNIZg4iINKDEICIiDSgxiIhIA0oMIiLSQNJP9tWvXz8fPnx4osMQEUkqK1euPODuBU3tS/rEMHz4cEpKShIdhohIUjGz3c3tU1eSiIg0oMQgIiINKDGIiEgDST/G0JRQKERZWRk1NTWJDqVd5OXlUVRURHa2JsYUkY4X18RgZjOJzu2SCfzS3X/YaP9PgenBZlegMJh5slXKysro0aMHw4cPx8zO/IZOzN05ePAgZWVljBgxItHhiEgaiFtiCGZ4fJjoKlplwAozW+zum07VcfevxtT/MnBBWz6rpqYmJZICgJmRn59PZWVlokMRkTQRzzGGacB2d9/p7nXAQqLLFzZnLtH57NskFZLCKanUFhHp/OLZlTSYhlMLl9HMtMXB3PIjgP9pZv98YD7A0KFD2zdKEZFAOOLURyLUh536iFMfjgRlHpR9sB0OHrGvwxEn7E4kZl/Eo68/eCa6P9j22HI/VS/62j2mPOJceW5/Jg3p3e7t7qyDzzcBz7p7uKmd7r4AWABQXFysecNFUkQ44tSEwlSHwlTXhakJhakJRaipD1MbilATClNbH6G2Pvp8arsuKIs+R7fr6iPUhSOEwtHXobC/vx0KRwjVO6HIB6/rI9F6p/7ohyIROvuqBIU985I+MZQTs1wh0aUKy5upexNwZ4dH1Ak89thjfP/73wfgn/7pn7jlllsSHJFIy9WEwhyrqedoTYjjNfUcrw0eMa9P1tVzojbMidp6TtaFOV5bT3VdmJOh6PbJ2iARhKJ/2NsqM8PIycwgNzuDnMwMcrI+eM4OnrMyjO65WeRkRsuyszLIzjCyMzPIygyeM4yszAyyM42sjGh5VoaRGVMvup3xfvn7z5lGhkXflxmUZWZAhlnMtpFpRkbwnJlhmPF+udkHdSyDaF0zMoLjRB8d28Ucz8SwAhhjZiOIJoSbgM81rmRm44A+RNfvTWlVVVXcf//9lJSUYGZMmTKF2bNn06dPn0SHJmnE3TlaU8+hE3UcOlnH4ZMhDp2s49DJEIdP1nGkOsThkyGOVEcfR6tDHK0JcbSmvkV/yDMzjG45mXTPzaJrbhbdcjLpkpNJYY88uuRk0jU7uh19nUWXnAy6ZGeSm51JXnYmeVkZ0efsTPKyo69zszLIzYo+52RlkJuVQVambstqL3FLDO5eb2Z3EV3WMBN4xN03mtkDQIm7Lw6q3gQs9HZaWu7+329k056j7XGo940f1JPvfuK8Zvffd9999O3bl7vvvhuAb3/72xQWFvKVr3ylQb2lS5cyY8YM+vbtC8CMGTN45ZVXmDt3brvGK+nH3TlaXc++YzXsP1pL5fEaKo/VcuB4XfAcfV11opaqE3WEwk3/c8sw6Nklm14xj6I+XejZJZseeVn0zMumZ14WPfKi291zs+iel0WP3Gy65WbSPS/661wXUCSXuI4xuPsSogukx5bd12j7e/GMqSPMmzePG264gbvvvptIJMLChQt5++23P1SvvLycIUM+6F0rKiqivLy53jWRKHfn8MkQ5Yer2XO4mr1HathzuJo9R2rYd6SGfcdq2He0hprQh3/N52ZlUNAjl/zuuQzqlceEwT3p2y2X/G459O2WQ59u2fTumkOfrjn06ZpNz7xsMjL0Rz3ddNbB53Zzul/2HWX48OHk5+ezevVq9u3bxwUXXEB+fn7c45DkVVcfofTQSXYdOMGugycprTpJ2aGTlB2qprTqJCfqGl6XkZOZwYBeeQzolcekot7075lL/5559O+ZR2GPXAqCR/fcLP16lzNK+cSQKLfffjuPPvooFRUVzJs3r8k6gwcP5o9//OP722VlZVx++eXxCVASzt2pPFbL9srj7Nh/nB2VJ9hReZxdB09QfqiaSEzvTtecTIb06cqQvl24eGQ+Q/p2ZXDvPAb17sLAXl3I75ajX/bSbqyduvITpri42Buvx7B582bOPffcBEUUVVdXx4QJEwiFQmzbto3MzMwP1amqqmLKlCmsWrUKgAsvvJCVK1e+P+YQqzO0SdruSHWIrRXH2FJxlC0Vx9hacYx39h3jWE39+3W652YxsqAbw/O7MbxfN4bnd2VYfvS5b7cc/dKXdmVmK929uKl9OmPoIDk5OUyfPp3evXs3mRQA+vbty3e+8x2mTp0KfDBoLclt/7EaNpYfZUP5ETbsOcKG8qOUH65+f3/PvCzGDejJnMmDGF3QndGFPRhd2J3+PXP1x186BSWGDhKJRHjrrbd45plnTltv3rx5zXY1SedXEwqzvvwIq987xOr3DrP6vcNUHP1gVt+R/boxZVgfbv7IMMYO6MG4AT0Y0DNPCUA6NSWGDrBp0yZmzZrF9ddfz5gxYxIdjrSjQyfqWLGrirffreLtXVVs2nOU+mAwYGjfrlw0si8Ti3ozYXAvzh3Ygx55mipdko8SQwcYP348O3fufH97/fr13HzzzQ3q5Obmsnz58niHJq10rCbEmzsO8sb2Ayx/t4otFccAyMnKYPKQ3vzdZSO5YEgfJg/tTb/uuQmOVqR9pGxicPdOc7o+YcIE1qxZ0+b3J/sFAskkHHHWlB7mz9sq+cu2A6wuPUw44nTJzqR4eB9mTRzItBH5TCzqRV5202NHIskuJRNDXl4eBw8eJD8/v9Mkh7Y6tVBPXl5eokNJWcdr63n9nUr+e/M+Xtuyn0MnQ5jBxMG9uOOykVw6uoALh/UmN0uJQNJDSiaGoqIiysrKUmZxm1NLe0r7OXi8llc2VvDKhgre2nmQUNjp1SWb6WMLuPLc/lw6uh99uuUkOkyRhEjJxJCdna1lMOVDqk7UsXRjBS+t28ubOw8Sjjgj+nXj1kuGc9W5/ZkyrI8mYhMhRRODyCk1oTDLNu/n2ZWlvL7tAOGIMzy/K39/2SiumziQcQN6JH13o0h7U2KQlOPurCs7wrMry1i8dg9HqkMM7JXHlz42klkTB3LeoJ5KBiKnocQgKeN4bT3PrS7niTd3s3XfMXKzMph5/gBunFLEJaP6kam5hERaRIlBkt62fcd4/K3dLFpVzvHaes4f3JP/c8MErps4kJ66wUyk1ZQYJCm5O396p5IFr+/krzsOkpOVwayJA7n54mFMHtJbXUUiZ0GJQZJKfTjCi+v28v/+tIMtFccY2CuPb80cx2enDqGvLi8VaRdKDJIUakJhnlpRyoLXd1J+uJoxhd35109PYvakQeRk6RJTkfakxCCdWl19hGdWlvLvy7ZTcbSG4mF9uH/2eVwxrlAL04h0ECUG6ZTCEee51eU8tOwdSququXBob37ymUlcMrpfokMTSXlxTQxmNhN4CMgEfunuP2yizmeA7wEOrHX3z8UzRkksd2fZ5v38n5c3s6PyBOcN6smvbz2fy8cWaEBZJE7ilhjMLBN4GJgBlAErzGyxu2+KqTMGuBf4qLsfMrPCeMUniffOvmP884ub+PO2A4ws6MbPP38hM88foIQgEmfxPGOYBmx3950AZrYQmANsiqnzJeBhdz8E4O774xifJMjhk3X89A/v8MTy9+iWk8l9s8Zz80eGka15i0QSIp6JYTBQGrNdBlzUqM45AGb2BtHupu+5+yuND2Rm84H5AEOHDu2QYKXjRSLOwhWlPPjKFo7VhPj8RcP46oxzdNmpSIJ1tsHnLGAMcDlQBLxuZhPc/XBsJXdfACwAKC4u1io2SWhn5XHuXbSe5e9WcdGIvtw/5zzGDeiZ6LBEhPgmhnJgSMx2UVAWqwxY7u4h4F0ze4doolgRnxClo4XCERa8vpOHlm0jLyuDBz81gc8UD9E4gkgnEs/EsAIYY2YjiCaEm4DGVxw9D8wFfm1m/Yh2Le1EUsL6siN889m1bKk4xrUTBvC9T5xHYU+tTCfS2cQtMbh7vZndBSwlOn7wiLtvNLMHgBJ3Xxzsu9rMNgFh4JvufjBeMUrHCEecBa/v5N9e3Up+9xx+cfMU/ua8AYkOS0SaYcm+0HxxcbGXlJQkOgxpxt4j1Xz1qTW8tbOKaycM4AfXT6B3Vw0uiySama109+Km9nW2wWdJIS+v38s9i9YTCkf40Y0T+fSUIo0liCQBJQZpdzWhMPf/fiO/fbuUSUW9+NlNFzCiX7dEhyUiLaTEIO1qz+Fq/v6JlawtO8Idl43i61efoxvVRJKMEoO0m7d2HuTO36yitj6iAWaRJKbEIGfN3Xn0r7v4/kubGZbflQU3FzO6sHuiwxKRNlJikLNSWx/m3kXrWbSqnKvH9+ffPjOJHlpnWSSpKTFImx2pDnHH4yt5c+dBvjbjHO6aPlqL54ikACUGaZM9h6u57dcr2HngOD/77GQ+ecHgRIckIu1EiUFabfPeo9z26xWcqK3nsdumaVU1kRSjxCCt8sb2A9zx+Eq65Wbx9B0f4dyBmhFVJNUoMUiLvbqxgjufXMXIft15dN5UBvbqkuiQRKQDKDFIi7yyYS93Pbma8wf34rF50+jVRVceiaQqJQY5o5fW7eV/LVzN5CG9efS2qbocVSTFKTHIab2wppyvPb2WC4f25te3TaN7rr4yIqlOk9hIs55bXcZXn1pD8bA+PKqkIJI29C9dmvTiuj187em1fGRkPr+8pZiuOfqqiKQL/WuXD/nLtgN89ak1TB3Wl1/dMpUuOZmJDklE4khdSdLA2tLDzH+8hFEF3fnPW4qVFETSkBKDvG9H5XFue3QF+d1z+C9dkiqStuKaGMxsppltNbPtZnZPE/tvNbNKM1sTPG6PZ3zprOJIDX/7q7fJMPiveRdR2DMv0SGJSILEbYzBzDKBh4EZQBmwwswWu/umRlWfcve74hWXwJGTIf72keUcqQ6xcP7FWoZTJM3F84xhGrDd3Xe6ex2wEJgTx8+XJtSHI/zDkyvZdeAkC/52CucP7pXokEQkweKZGAYDpTHbZUFZY58ys3Vm9qyZDWnqQGY238xKzKyksrKyI2JNG99/aTNvbD/ID26YwCWjNEuqiHS+weffA8PdfSLwB+Cxpiq5+wJ3L3b34oKCgrgGmEoWvv0ej/51F7dfOoIbpxQlOhwR6STimRjKgdgzgKKg7H3uftDda4PNXwJT4hRb2lmxq4rvvLCBj59TwD3XjEt0OCLSicQzMawAxpjZCDPLAW4CFsdWMLOBMZuzgc1xjC9tlB+u5o7HVzKkT1f+fe4FZGV2thNHEUmkuF2V5O71ZnYXsBTIBB5x941m9gBQ4u6Lgf9lZrOBeqAKuDVe8aWLk3X1fOmxEurCEf7zlmLdqyAiHxLXKTHcfQmwpFHZfTGv7wXujWdM6cTduXfRerZUHOVXt05lVEH3RIckIp2Q+hDSyDMry3hhzR7uvuocpo8tTHQ4ItJJKTGkie37j/HdFzZyyah87pw+OtHhiEgnpsSQBmpCYe78zWq65mTys89OJjPDEh2SiHRimnY7DTzw4ia27jvGo7dN1RxIInJGOmNIcS+t28uTy9/j7y4byeUaVxCRFlBiSGGlVSe553frmDykN9+4emyiwxGRJKHEkKLCEefup9aAwb/PvYBs3cQmIi2kMYYU9es33mXl7kP89LOTGNK3a6LDEZEkop+RKejdAyf48dKtXHVufz45uakJbEVEmqfEkGLCEeebz6wlNyuDH1x/Pma6NFVEWkeJIcU89tddlOw+xHc/cZ4uTRWRNlFiSCG7DpzgR0u3cMW4Qm64UF1IItI2SgwpIhJx/vF368jOzOAH109QF5KItJkSQ4p4/K3dvP1uFd+ZNZ4BvdSFJCJtp8SQAiqO1PCjV7bw8XMK+LSW6BSRs6TEkAJ+sGQzoYjz/Tm6CklEzl6rE4OZdTOzzI4IRlrvzR0HWbx2D3dcNoqh+bqRTUTO3hkTg5llmNnnzOwlM9sPbAH2mtkmM/uxmWly/wQJhSN8d/EGivp04R8uH5XocEQkRbTkjOE1YBTRJTcHuPsQdy8ELgXeAh40sy90YIzSjP96czfv7DvOd2aNJy9bJ3Ei0j5akhiucvd/dvd17h45VejuVe7+O3f/FPBUSz7MzGaa2VYz225m95ym3qfMzM2suCXHTUf7j9Xwsz+8w2XnFHD1+P6JDkdEUkhLJtH7cqMBTQcOAH9x93cB3D10poME4xIPAzOAMmCFmS12902N6vUAvgIsb1EL0tQPX95CbX2E780+TwPOItKuWnLG0KPRoydQDLxsZje14rOmAdvdfae71wELgTlN1Ptn4EGgphXHTislu6pYtKqcL318BCP6dUt0OCKSYs54xuDu9zdVbmZ9gf8m+ge+JQYDpTHbZcBFjY55ITDE3V8ys282dyAzmw/MBxg6dGgLPz41hCPOfS9sZFCvPO6crnF/EWl/bb6Pwd2rgHbrwzCzDOAnwNdb8NkL3L3Y3YsLCgraK4Sk8NzqcjbtPcq9155L1xwtpyEi7a/NicHMpgOHWvGWcmBIzHZRUHZKD+B84I9mtgu4GFisAegP1ITC/OTVrUws6sWsiQMTHY6IpKgz/uQ0s/VEB5xj9QX2ALe04rNWAGPMbATRhHAT8LlTO939CNAv5nP/CHzD3Uta8Rkp7Ym3drPnSA3/+ulJGnAWkQ7Tkr6IWY22HTjo7ida80HuXm9mdwFLgUzgEXffaGYPACXuvrg1x0s3R2tC/Mdr2/nYmH5cMrrfmd8gItJGLRl83t1UuZldCsx19ztb+mHuvgRY0qjsvmbqXt7S46aDX/xpB4dPhvjWzHGJDkVEUlyrRi/N7AKi3T+fBt4FFnVEUNLQvqM1/Oov7zJ70iDOH9wr0eGISIpryRjDOcDc4HGA6F3O5u7TOzg2CTy0bBvhiPONq8cmOhQRSQMtOWPYAvwZmOXu2wHM7KsdGpW8b0flcZ5aUcoXLhqq2VNFJC5acrnqDcBe4DUz+08zu5J2vH9BTu/fXt1KXlYGX75yTKJDEZE0ccbE4O7Pu/tNwDiiM63eDRSa2c/N7OoOji+trS87wpL1Fdz+sZH0656b6HBEJE20+AY3dz/h7k+6+yeI3py2GvhWh0Um/Mdr2+iZl8XtHxuR6FBEJI20ZKGeD3UbufuhYFqKK5urI2dna8Uxlm7cx60fHUGPvOxEhyMiaaRFC/WY2ZfNrMFsdWaWY2ZXmNljtO4OaGmBh1/bTrecTG67ZHiiQxGRNNOSq5JmAvOA3wbTWRwG8ojevfwq8DN3X91hEaahnZXHeXHdHr708ZH06ZaT6HBEJM205M7nGuD/Av/XzLKJzmdU7e6HOzi2tPXzP+4gOzOD2y8dmehQRCQNterO52Cltr0dFIsApVUneW51OV+4eBgFPXQlkojEX5un3ZaO8YvXd2AGf3eZzhZEJDGUGDqRfUdreHpFGTdOGcLAXl0SHY6IpKlWJwYz62ZmmR0RTLpb8PpOwu78/WWjEh2KiKSxltzHkGFmnzOzl8xsP9G5k/aa2SYz+7GZaeHhdnDweC2/Wb6bOZMHaU4kEUmoFt3HAIwC7gUGuPsQdy8ELgXeAh40sy90YIxp4bE3d1MTivAPlyvPikhiteSqpKvcPWRmw909cqrQ3auA3wG/Cy5jlTaqCYX5zVu7uXJcIaMLuyc6HBFJcy2ZRC8UvPzQojxmdnGjOtIGi9fu4eCJOuZdqjmRRCTxWjLG8Bkz+yHQw8zONbPY9yzouNDSg7vzyF/eZdyAHlwyKj/R4YiItGiM4Q1gE9AH+Amw3cxWmdmLQHVHBpcO3tx5kC0Vx5j30RFoLkIR6QxaMiVGOfBfZrbD3d8AMLN8YDjRK5RazMxmAg8RnWfpl+7+w0b77wDuBMLAcWC+u29qzWckm0f+sou+3XKYPXlQokMREQFaMe32qaQQvD7o7ivd/URsnTMcJxN4GLgGGA/MNbPxjao96e4T3H0y8COiZygpa9eBEyzbso8vXDSUvGzdGiIinUM8p92eBmx3953uXgcsBObEVnD3ozGb3QBvwXGT1qN/3UVWhvGFi4clOhQRkfe1ddrtLkSTSmum3R4MlMZslwEXNa5kZncCXwNygCuaOpCZzQfmAwwdOrSpKp3ekeoQT5eU8omJgyjsmZfocERE3tfppt1294eBh83sc8A/0cTZiLsvILgiqri4OCnPKp4pKeVkXViXqIpIp9PqabfN7O+BLDNbA6xx93da+PZyYEjMdlFQ1pyFwM9bE1+yqA9H+PUbu5g2oi/nD+6V6HBERBpo9SR67n4f0SuLjgDXm9l/tvCtK4AxZjbCzHKAm4DFsRXMbEzM5nXAttbGlwz+e/M+yg9XM++jOlsQkc6nxWcMZvYH4Bvuvtbd9wFLg0eLuHu9md0VvCcTeMTdN5rZA0CJuy8G7jKzq4AQcIgUXUv6ibfeY3DvLswY3z/RoYiIfEhrupK+BfzMzHYB/9vdW72Sm7svAZY0Krsv5vVXWnvMZLP74An+sv0AX59xDpkZuqFNRDqfFnclufsqd58OvAi8YmbfNTOtJtNKC1eUkplhfLp4yJkri4gkQKvGGIIb2bYSHRT+MrDNzG7uiMBSUV19hGdKSrliXCEDeukSVRHpnFqcGMzsDaJXEf2U6D0JtwKXA9PMTJPptcCyzfs4cLyOudN0tiAinVdrxhjmA5vcvfF9A182s83tGFPKevLt9xjYK4/LzilMdCgiIs1qzRjDxiaSwinXtVM8Kau06iR/3naAz04dokFnEenUWn0fQ1PcfWd7HCeVLVzxHhkGn9Ggs4h0cu2SGOT0QuEIT5eUMX1sIYN660IuEenclBjiYNnm/VQeq2XutOSc8E9E0osSQxz89u33GNAzj8vHFiQ6FBGRM1Ji6GClVSd5fVsln5k6hKxM/ecWkc5Pf6k62NMl0SUoPjtVg84ikhyUGDpQJOIsWlXOx8YUMFiDziKSJJQYOtDyd6soP1zNpy4cnOhQRERaTImhAy1aVUb33CyuHj8g0aGIiLSYEkMHqa4L8/KGCq45fwBdcjITHY6ISIspMXSQVzdVcLy2nhsuLEp0KCIiraLE0EGeW13O4N5duGhE30SHIiLSKkoMHWD/sRpef6eST14wiAxNmCciSUaJoQMsXrOHiMP1F6gbSUSST1wTg5nNNLOtZrbdzO5pYv/XzGyTma0zs2VmNiye8bWXRavKmVTUi9GF3RMdiohIq8UtMZhZJvAwcA0wHphrZuMbVVsNFLv7ROBZ4Efxiq+9bKk4yqa9R7n+At27ICLJKZ5nDNOA7e6+093rgIXAnNgK7v6au58MNt8Ckq4v5rlV5WRlGJ+YNCjRoYiItEk8E8NgoDRmuywoa84XgZeb2mFm882sxMxKKisr2zHEsxOOOM+vKefysQXkd89NdDgiIm3SKQefzewLQDHw46b2u/sCdy929+KCgs4zlfVfdxxg39Fa3bsgIkktK46fVQ7ETjFaFJQ1YGZXAd8GLnP32jjF1i4WrSqnZ14WV4wrTHQoIiJtFs8zhhXAGDMbYWY5wE3A4tgKZnYB8Atgtrvvj2NsZ626LszSjRVcO2EgedmaAkNEklfcEoO71wN3AUuBzcDT7r7RzB4ws9lBtR8D3YFnzGyNmS1u5nCdzmtb93OyLsxsDTqLSJKLZ1cS7r4EWNKo7L6Y11fFM5729OK6PfTrnstFI/MTHYqIyFnplIPPyeZ4bT3LNu/n2gkDyNQUGCKS5JQY2sGyzfuorY/o3gURSQlKDO3g92v3MKBnHlOG9kl0KCIiZ02J4SwdqQ7xp3cquW7iQM2kKiIpQYnhLL26sYJQ2NWNJCIpQ4nhLP1+3V6G9O3CpKJeiQ5FRKRdKDGchaoTdbyx/QDXTRiEmbqRRCQ1KDGchVc2VBCOOJ+YNDDRoYiItBslhrPw+7V7GNmvG+MH9kx0KCIi7UaJoY32H6th+bsHmTVxoLqRRCSlKDG00cvrK4g4uhpJRFKOEkMb/X7tHsb278GY/j0SHYqISLtSYmiDvUeqKdl9iFkTNegsIqlHiaENXtlQAcC1SgwikoKUGNpgyfq9jBvQg1EF3RMdiohIu1NiaKV9R2so2X2Ia87X2YKIpCYlhlZ6ZUMF7nDdxAGJDkVEpEMoMbTSkvV7GVPYndGFuhpJRFKTEkMr7D9Ww9u7qrh2grqRRCR1xTUxmNlMM9tqZtvN7J4m9n/czFaZWb2Z3RjP2Fpi6cZ9uKPEICIpLW6JwcwygYeBa4DxwFwzG9+o2nvArcCT8YqrNZas28uogm6c019XI4lI6ornGcM0YLu773T3OmAhMCe2grvvcvd1QCSOcbXIgeO1LH/3INdO0NxIIpLa4pkYBgOlMdtlQVlSWLoxOjeSupFEJNUl5eCzmc03sxIzK6msrIzLZ768voKR/boxboCuRhKR1BbPxFAODInZLgrKWs3dF7h7sbsXFxQUtEtwp1N1oo43dx7kmgkD1I0kIikvnolhBTDGzEaYWQ5wE7A4jp/fZq9ujK7Upm4kEUkHcUsM7l4P3AUsBTYDT7v7RjN7wMxmA5jZVDMrAz4N/MLMNsYrvtN5af1ehuV31UptIpIWsuL5Ye6+BFjSqOy+mNcriHYxdRqHTtTx5o6DfOnjI9WNJCJpISkHn+Pp5Q0V1Eec69SNJCJpQonhDJ5fU87owu6cN0jdSCKSHpQYTmPP4WrefreKOZMGqRtJRNKGEsNp/H7tHgBmTx6U4EhEROJHieE0Xlizh8lDejMsv1uiQxERiRslhmZs23eMTXuPMkdnCyKSZpQYmvHCmj1kGFw3UVcjiUh6UWJogrvzwtpyPjq6H4U98hIdjohIXCkxNGF16WFKq6qZMzlpJn8VEWk3SgxNWLxmDzlZGfzNef0THYqISNwpMTRSH47w4ro9XHVuIT3yshMdjohI3CkxNPLGjoMcOF7H7EnqRhKR9KTE0MgLa8rpkZfF5WM7fp0HEZHOSIkhRk0ozNINFVxz/gDysjMTHY6ISEIoMcR4pqSUE3VhXY0kImlNiSFQeayWHy3dyiWj8rlkVH6iwxERSRglhsC/vLSJ2lCEf/7k+ZpJVUTSmhID8Mb2Azy/Zg93XDaSUQXdEx2OiEhCpX1iqK0P853nNzC0b1f+YfroRIcjIpJwcV3zuTP6xZ92svPACR69baquRBIRIc5nDGY208y2mtl2M7unif25ZvZUsH+5mQ3vyHh2HTjBf7y2nesmDuTysYUd+VEiIkkjbonBzDKBh4FrgPHAXDMb36jaF4FD7j4a+CnwYEfF4+5854UN5GRmcN+sxmGIiKSveJ4xTAO2u/tOd68DFgJzGtWZAzwWvH4WuNI66BKhl9bv5c/bDvD1q8+hf09NrS0icko8E8NgoDRmuywoa7KOu9cDR4AP3VRgZvPNrMTMSiorK9sUTPfcLGaM78/NFw9r0/tFRFJVUg4+u/sCYAFAcXGxt+UYl48t1LiCiEgT4nnGUA4MidkuCsqarGNmWUAv4GBcohMRESC+iWEFMMbMRphZDnATsLhRncXALcHrG4H/cfc2nRGIiEjbxK0ryd3rzewuYCmQCTzi7hvN7AGgxN0XA78CHjez7UAV0eQhIiJxFNcxBndfAixpVHZfzOsa4NPxjElERBpK+ykxRESkISUGERFpQIlBREQaUGIQEZEGLNmvBjWzSmB3G9/eDzjQjuEkktrS+aRKO0Bt6azOpi3D3L2gqR1JnxjOhpmVuHtxouNoD2pL55Mq7QC1pbPqqLaoK0lERBpQYhARkQbSPTEsSHQA7Uht6XxSpR2gtnRWHdKWtB5jEBGRD0v3MwYREWlEiUFERBpI28RgZjPNbKuZbTezexIdT2uY2SNmtt/MNsSU9TWzP5jZtuC5TyJjbAkzG2Jmr5nZJjPbaGZfCcqTsS15Zva2ma0N2nJ/UD7CzJYH37OnginnOz0zyzSz1Wb2YrCdrO3YZWbrzWyNmZUEZUn3/QIws95m9qyZbTGzzWb2kY5qS1omBjPLBB4GrgHGA3PNbHxio2qVR4GZjcruAZa5+xhgWbDd2dUDX3f38cDFwJ3B/4dkbEstcIW7TwImAzPN7GLgQeCn7j4aOAR8MXEhtspXgM0x28naDoDp7j455nr/ZPx+ATwEvOLu44BJRP//dExb3D3tHsBHgKUx2/cC9yY6rla2YTiwIWZ7KzAweD0Q2JroGNvQpheAGcneFqArsAq4iOhdqVlBeYPvXWd9EF1dcRlwBfAiYMnYjiDWXUC/RmVJ9/0iuprluwQXDHV0W9LyjAEYDJTGbJcFZcmsv7vvDV5XAP0TGUxrmdlw4AJgOUnalqD7ZQ2wH/gDsAM47O71QZVk+Z79DPhHIBJs55Oc7QBw4FUzW2lm84OyZPx+jQAqgV8HXXy/NLNudFBb0jUxpDSP/nxImuuQzaw78Dvgbnc/Grsvmdri7mF3n0z0F/c0YFxiI2o9M5sF7Hf3lYmOpZ1c6u4XEu02vtPMPh67M4m+X1nAhcDP3f0C4ASNuo3asy3pmhjKgSEx20VBWTLbZ2YDAYLn/QmOp0XMLJtoUviNuy8KipOyLae4+2HgNaJdLr3N7NRKicnwPfsoMNvMdgELiXYnPUTytQMAdy8PnvcDzxFN2Mn4/SoDytx9ebD9LNFE0SFtSdfEsAIYE1xpkUN0benFCY7pbC0Gbgle30K0v75TMzMjus73Znf/ScyuZGxLgZn1Dl53ITpWsplogrgxqNbp2+Lu97p7kbsPJ/rv4n/c/fMkWTsAzKybmfU49Rq4GthAEn6/3L0CKDWzsUHRlcAmOqotiR5USeBgzrXAO0T7gb+d6HhaGftvgb1AiOgviS8S7QdeBmwD/hvom+g4W9COS4me+q4D1gSPa5O0LROB1UFbNgD3BeUjgbeB7cAzQG6iY21Fmy4HXkzWdgQxrw0eG0/9O0/G71cQ92SgJPiOPQ/06ai2aEoMERFpIF27kkREpBlKDCIi0oASg4iINKDEICIiDSgxiIhIA0oMIiLSgBKDiIg0oMQg0kZmVmRmn21mXxcz+1MwxXtT+3PM7PWYaSZEOg0lBpG2u5LofDVNmQcscvdwUzvdvY7oHatNJhaRRFJiEGkDM7sU+AlwY7A62MhGVT5PMG9NMGfPS8HqbhtizjKeD+qJdCo6jRVpA3f/i5mtAL7h7hti9wUTM450911B0Uxgj7tfF+zvFZRvAKbGKWSRFtMZg0jbjQW2NFHeDzgcs70emGFmD5rZx9z9CETXbwDqTs0AKtJZKDGItIGZ9QOO+AermsWqBvJObbj7O0THItYD3zez+2Lq5gI1HRmrSGupK0mkbYYDe5ra4e6HgmU+89y9xswGAVXu/oSZHQZuBzCzfOCAu4fiFbRIS+iMQaRttgD9gsHkS5rY/yrR9SYAJgBvB+tBfxf4flA+HXipowMVaS2txyDSAczsQuCr7n7zaeosAu4JuppEOg2dMYh0AHdfBbx2uhvcgOeVFKQz0hmDiIg0oDMGERFpQIlBREQaUGIQEZEGlBhERKQBJQYREWlAiUFERBr4/9Iby3HKlUbPAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Run simulation using default model parameters and solver options\n", + "model.setTimepoints(np.linspace(0, 60, 60)) \n", + "rdata = amici.runAmiciSimulation(model, solver)\n", + "amici.plotting.plotObservableTrajectories(rdata)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Simulation options can be specified either in the [Model](https://amici.readthedocs.io/en/latest/generated/amici.amici.Model.html) or in an [ExpData](https://amici.readthedocs.io/en/latest/generated/amici.amici.ExpData.html) instance. The `ExpData` instance can also carry experimental data. To initialize an `ExpData` instance from simulation results, amici offers some [convenient constructors](https://amici.readthedocs.io/en/latest/generated/amici.amici.ExpData.html#amici.amici.ExpData). In the following we will initialize an `ExpData` object from simulation results, but add noise with standard deviation `0.1` and specify the standard deviation accordingly. Moreover, we will specify custom values for `DRUG_0=0` and `KIN_0=2`. If `fixedParameter` is specified in an `ExpData` instance, [runAmiciSimulation](https://amici.readthedocs.io/en/latest/generated/amici.html#amici.runAmiciSimulation) will use those parameters instead of the ones specified in the `Model` instance." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "edata = amici.ExpData(rdata, 0.1, 0.0)\n", + "edata.fixedParameters = [0,2]\n", + "rdata = amici.runAmiciSimulation(model, solver, edata)\n", + "amici.plotting.plotObservableTrajectories(rdata)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For many biological systems, it is reasonable to assume that they start in a\n", + " steady state. In this example we want to specify an experiment where a pretreatment with a drug is performed _before_ the kinase is added. We assume that the pretreatment is sufficiently long such that the system reaches steadystate before the kinase is added. To implement this in amici, we can specify `fixedParametersPreequilibration` in the `ExpData` object. This automatically adds a preequilibration phase where the model is run to steadystate, before regular simulation starts. Here we set `DRUG_0=3` and `KIN_0=0` for the preequilibration. This means that there is no kinase available in the preequilibration phase. " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "edata.fixedParametersPreequilibration = [3,0]\n", + "rdata = amici.runAmiciSimulation(model, solver, edata)\n", + "amici.plotting.plotObservableTrajectories(rdata)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The resulting trajectory is definitely not what one may expect. The problem is that the `DRUG_0` and `KIN_0` set initial conditions for species in the model. By default these initial conditions are only applied at the very beginning of the simulation, i.e., before the preequilibration. Accordingly, the `fixedParameters` that we specified do not have any effect. To fix this, we need to set the `reinitializeFixedParameterInitialStates` attribue to `True`, to spefify that AMICI reinitializes all states that have `fixedParameter`-dependent initial states." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "edata.reinitializeFixedParameterInitialStates = True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this option activated, the kinase concentration will be reinitialized after the preequilibration and we will see the expected change in fractional phosphorylation:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "rdata = amici.runAmiciSimulation(model, solver, edata)\n", + "amici.plotting.plotObservableTrajectories(rdata)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On top of preequilibration, we can also specify presimulation. This option can be used to specify pretreatments where the system is not assumed to reach steadystate. Presimulation can be activated by specifying `t_presim` and `edata.fixedParametersPresimulation`. If both `fixedParametersPresimulation` and `fixedParametersPreequilibration` are specified, preequilibration will be performed first, followed by presimulation, followed by regular simulation. For this example we specify `DRUG_0=10` and `KIN_0=0` for the presimulation and `DRUG_0=10` and `KIN_0=2` for the regular simulation. We do not overwrite the `DRUG_0=3` and `KIN_0=0` that was previously specified for preequilibration." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(3.0, 0.0)\n", + "(10.0, 0.0)\n", + "(10.0, 2.0)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "edata.t_presim = 10\n", + "edata.fixedParametersPresimulation = [10.0, 0.0]\n", + "edata.fixedParameters = [10.0, 2.0]\n", + "print(edata.fixedParametersPreequilibration)\n", + "print(edata.fixedParametersPresimulation)\n", + "print(edata.fixedParameters)\n", + "rdata = amici.runAmiciSimulation(model, solver, edata)\n", + "amici.plotting.plotObservableTrajectories(rdata)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python3", + "language": "python", + "name": "python" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "pycharm": { + "stem_cell": { + "cell_type": "raw", + "metadata": { + "collapsed": false + }, + "source": [] + } + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/deps/AMICI/python/examples/example_presimulation/model_presimulation.ipynb b/deps/AMICI/python/examples/example_presimulation/model_presimulation.ipynb deleted file mode 100644 index 882bbaaec..000000000 --- a/deps/AMICI/python/examples/example_presimulation/model_presimulation.ipynb +++ /dev/null @@ -1,416 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# AMICI Python example \"presimulation\"\n", - "In this example we will explore some more options for the initialization of experimental conditions, including how to reset initial conditions based on changing values for fixedParameters as well as an additional presimulation phase on top of preequilibration" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# SBML model we want to import\n", - "sbml_file = 'model_presimulation.xml'\n", - "# Name of the model that will also be the name of the python module\n", - "model_name = 'model_presimulation'\n", - "# Directory to which the generated model code is written\n", - "model_output_dir = model_name\n", - "\n", - "import libsbml\n", - "import amici\n", - "import amici.plotting\n", - "import os\n", - "import sys\n", - "import importlib\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Model Loading\n", - "Here we load a simple model of protein phosphorylation that can be inhibited by a drug. This model was created using PySB (see `createModel.py`)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Species: [('__s0', \"PROT(kin=None, drug=None, phospho='u')\"), ('__s1', 'DRUG(bound=None)'), ('__s2', 'KIN(bound=None)'), ('__s3', \"DRUG(bound=1) ._br_PROT(kin=None, drug=1, phospho='u')\"), ('__s4', \"KIN(bound=1) ._br_PROT(kin=1, drug=None, phospho='u')\"), ('__s5', \"PROT(kin=None, drug=None, phospho='p')\")]\n", - "\n", - "Reactions:\n", - "PROT_DRUG_bind: __s0 + __s1 <-> __s3\t\t[__s0 * __s1 * kon_prot_drug - __s3 * koff_prot_drug]\n", - "PROT_KIN_bind: __s0 + __s2 -> __s4\t\t[__s0 * __s2 * kon_prot_kin]\n", - "PROT_KIN_phospho: __s4 -> __s2 + __s5\t\t[__s4 * kphospho_prot_kin]\n", - "PROT_dephospho: __s5 -> __s0\t\t[__s5 * kdephospho_prot]\n", - "Parameters: [('initProt', 'initProt'), ('initDrug', 'initDrug'), ('initKin', 'initKin'), ('pPROT_obs', 'pPROT_obs'), ('PROT_0', 'PROT_0'), ('DRUG_0', 'DRUG_0'), ('KIN_0', 'KIN_0'), ('kon_prot_drug', 'kon_prot_drug'), ('koff_prot_drug', 'koff_prot_drug'), ('kon_prot_kin', 'kon_prot_kin'), ('kphospho_prot_kin', 'kphospho_prot_kin'), ('kdephospho_prot', 'kdephospho_prot'), ('__obs0', 'pPROT'), ('__obs1', 'tPROT')]\n" - ] - } - ], - "source": [ - "sbml_reader = libsbml.SBMLReader()\n", - "sbml_doc = sbml_reader.readSBML(sbml_file)\n", - "sbml_model = sbml_doc.getModel()\n", - "dir(sbml_doc)\n", - "\n", - "print('Species: ', [(s.getId(),s.getName()) for s in sbml_model.getListOfSpecies()])\n", - "\n", - "print('\\nReactions:')\n", - "for reaction in sbml_model.getListOfReactions():\n", - " reactants = ' + '.join(['%s %s'%(int(r.getStoichiometry()) if r.getStoichiometry() > 1 else '', r.getSpecies()) for r in reaction.getListOfReactants()])\n", - " products = ' + '.join(['%s %s'%(int(r.getStoichiometry()) if r.getStoichiometry() > 1 else '', r.getSpecies()) for r in reaction.getListOfProducts()])\n", - " reversible = '<' if reaction.getReversible() else ''\n", - " print('%3s: %10s %1s->%10s\\t\\t[%s]' % (reaction.getName(), \n", - " reactants,\n", - " reversible,\n", - " products,\n", - " libsbml.formulaToL3String(reaction.getKineticLaw().getMath())))\n", - " \n", - "print('Parameters: ', [(p.getId(),p.getName()) for p in sbml_model.getListOfParameters()])" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "# Create an SbmlImporter instance for our SBML model\n", - "sbml_importer = amici.SbmlImporter(sbml_file)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For this example we want specify the initial drug and kinase concentrations as experimental conditions. Accordingly we specify them as fixedParameters." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "fixedParameters = ['DRUG_0','KIN_0']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The SBML model specifies a single observable named `pPROT` which describes the fraction of phosphorylated Protein. We load this observable using `amici.assignmentRules2observables`." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Observables: {'__obs0': {'name': 'pPROT', 'formula': '__s5'}}\n" - ] - } - ], - "source": [ - "# Retrieve model output names and formulae from AssignmentRules and remove the respective rules\n", - "observables = amici.assignmentRules2observables(\n", - " sbml_importer.sbml, # the libsbml model object\n", - " filter_function=lambda variable: variable.getName() == 'pPROT' \n", - " )\n", - "print('Observables:', observables)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now the model is ready for compilation:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "sbml_importer.sbml2amici(model_name, \n", - " model_output_dir, \n", - " verbose=False,\n", - " observables=observables,\n", - " constant_parameters=fixedParameters)\n", - "sys.path.insert(0, os.path.abspath(model_output_dir))\n", - "# load the compiled module\n", - "model_module = importlib.import_module(model_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To simulate the model we need to create an instance via the `getModel()` method in the generated model module." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Model instance\n", - "model = model_module.getModel()\n", - "# set timepoints for which we want to simulate the model\n", - "\n", - "\n", - "# Create solver instance\n", - "solver = model.getSolver()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The only thing we need to simulate the model is a timepoint vector, which can be specified using the `setTimepoints()` method. If we do not specify any additional options, the default values for fixedParameters and Parameters that were specified in the SBML file will be used." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Run simulation using default model parameters and solver options\n", - "model.setTimepoints(np.linspace(0, 60, 60)) \n", - "rdata = amici.runAmiciSimulation(model, solver)\n", - "amici.plotting.plotObservableTrajectories(rdata)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Simulation options can be specified either in the Model or in an ExpData object. The ExpData object can also carry experimental data. To initialize an ExpData object from simulation routines, amici offers some convenient constructors. In the following we will initialize an ExpData object from simulation results, but add noise with standard deviation `0.1` and specify the standard deviation accordingly. Moreover, we will specify custom values for `DRUG_0=0` and `KIN_0=2`. If fixedParameter is specfied in an ExpData object, runAmiciSimulation will use those parameters instead of the ones specified in the Model object." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "edata = amici.ExpData(rdata, 0.1, 0.0)\n", - "edata.fixedParameters = [0,2]\n", - "rdata = amici.runAmiciSimulation(model, solver, edata)\n", - "amici.plotting.plotObservableTrajectories(rdata)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For many biological systems, it is reasonable to assume that they start in a\n", - " steady state. In this example we want to specify an experiment where a pretreatment with a drug is performed _before_ the kinase is added. We assume that the pretreatment is sufficiently long such that the system reaches steadystate before the kinase is added. To implement this in amici, we can specify `fixedParametersPreequilibration` in the ExpData object. Here we set `DRUG_0=3` and `KIN_0=0` for the preequilibration." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "edata.fixedParametersPreequilibration = [3,0]\n", - "rdata = amici.runAmiciSimulation(model, solver, edata)\n", - "amici.plotting.plotObservableTrajectories(rdata)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The resulting trajectory is definitely not what one may expect. The problem is that the `DRUG_0` and `KIN_0` set initial condtions for species in the model. By default these initial conditions are only applied at the very beginning of the simulation, i.e., before the preequilibration. Accordingly, the fixedParameters that we specified do not have any effect. To fix this, we need to activate reinitialization of states that depend on fixedParameters via `ExpData.reinitializeFixedParameterInitialStates`" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "edata.reinitializeFixedParameterInitialStates = True" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With this option activated, the kinase concentration will be reinitialized after the preequilibration and we will see the expected change in fractional phosphorylation:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "rdata = amici.runAmiciSimulation(model, solver, edata)\n", - "amici.plotting.plotObservableTrajectories(rdata)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "On top of preequilibration, we can also specify presimulation. This option can be used to specify pretreatments where the system is not assumed to reach steadystate. Presimulation can be activated by specifying `t_presim` and `edata.fixedParametersPresimulation`. If both `fixedParametersPresimulation` and `fixedParametersPreequilibration` are specified, preequilibration will be performed first, followed by presimulation, followed by regular simulation. For this example we specify `DRUG_0=10` and `KIN_0=0` for the presimulation and `DRUG_0=10` and `KIN_0=2` for the regular simulation. We do not overwrite the `DRUG_0=3` and `KIN_0=0` that was previously specified for preequilibration." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(3.0, 0.0)\n", - "(10.0, 0.0)\n", - "(10.0, 2.0)\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "edata.t_presim = 10\n", - "edata.fixedParametersPresimulation = [10.0,0.0]\n", - "edata.fixedParameters = [10.0,2.0]\n", - "print(edata.fixedParametersPreequilibration)\n", - "print(edata.fixedParametersPresimulation)\n", - "print(edata.fixedParameters)\n", - "rdata = amici.runAmiciSimulation(model, solver, edata)\n", - "amici.plotting.plotObservableTrajectories(rdata)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.7" - }, - "pycharm": { - "stem_cell": { - "cell_type": "raw", - "source": [], - "metadata": { - "collapsed": false - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} \ No newline at end of file diff --git a/deps/AMICI/python/tests/test_events.py b/deps/AMICI/python/tests/test_events.py new file mode 100644 index 000000000..8bb34ecf8 --- /dev/null +++ b/deps/AMICI/python/tests/test_events.py @@ -0,0 +1,351 @@ +"""Tests for SBML events, including piecewise expressions.""" +import numpy as np +import pytest +import os +from scipy.linalg import expm +from copy import deepcopy + +from util import ( + create_sbml_model, + create_amici_model, + check_trajectories_without_sensitivities, + check_trajectories_with_forward_sensitivities, +) + +@pytest.fixture(params=[ + 'events_plus_heavisides', + 'nested_events', +]) +def model(request): + """Returns the requested AMICI model and analytical expressions.""" + ( + initial_assignments, + parameters, + rate_rules, + species, + events, + timepoints, + x_pected, + sx_pected + ) = get_model_definition(request.param) + + # SBML model + sbml_document, sbml_model = create_sbml_model( + initial_assignments=initial_assignments, + parameters=parameters, + rate_rules=rate_rules, + species=species, + events=events, + # uncomment `to_file` to save SBML model to file for inspection + # to_file=sbml_test_models / (model_name + '.sbml'), + ) + + # AMICI model + amici_model = create_amici_model( + sbml_model=sbml_model, + model_name=request.param, + ) + amici_model.setTimepoints(timepoints) + + return amici_model, parameters, timepoints, x_pected, sx_pected + + +def get_model_definition(model_name): + if model_name == 'events_plus_heavisides': + return model_definition_events_plus_heavisides() + if model_name == 'nested_events': + return model_definition_nested_events() + else: + raise NotImplementedError( + f'Model with name {model_name} is not implemented.' + ) + + +def model_definition_events_plus_heavisides(): + """Test model for state- and parameter-dependent heavisides. + + ODEs + ---- + d/dt x_1: + - { 0, t < delta + - { -alpha * x_1, t >= delta + d/dt x_2: + - beta * x_1 - gamma * x_2 + d/dt x_3: + - { -eta * x_3, t < zeta + - { -eta * x_3 + 1, t >= zeta + + Events: + ------- + event_1: + trigger: k1 - x_3 + bolus: [[ -x_3 / 2], + [ 0], + [ 0]] + event_2: + trigger: t - zeta + bolus: [[ 0], + [ 0], + [ zeta / 3]] + """ + # Model components + species = ['x_1', 'x_2', 'x_3'] + initial_assignments = { + 'x_1': 'k1', + 'x_2': 'k2', + 'x_3': 'k3', + } + rate_rules = { + 'x_1': 'piecewise( -alpha * x_1, time >= delta, 0)', + 'x_2': 'beta * x_1 - gamma * x_2', + 'x_3': '-eta * x_3 + piecewise( 1, time >= zeta, 0)', + } + parameters = { + 'k1': 2, + 'k2': 0.01, + 'k3': 5, + 'alpha': 2, + 'beta': 3, + 'gamma': 2, + 'delta': 3, + 'eta': 1, + 'zeta': 5, + } + events = { + 'event_1': { + 'trigger': 'x_3 < k1', + 'target': 'x_1', + 'assignment': 'x_1 - x_3 / 2' + }, + 'event_2': { + 'trigger': 'time >= zeta', + 'target': 'x_3', + 'assignment': 'x_3 + zeta / 3' + } + } + timepoints = np.linspace(0, 8, 400) + + # Analytical solution + def x_pected(t, k1, k2, k3, alpha, beta, gamma, delta, eta, zeta): + # The system reads dx/dt = Ax + b + # x0 = (k1, k2, k3) + x0 = np.array([[k1], [k2], [k3]]) + + # gather event time points + event_1_time = (np.log(k3) - np.log(k1)) / eta # k1 > x3 + event_2_time = delta + event_3_time = zeta + + def get_early_x(t): + # compute dynamics + if t < event_1_time: + # Define A + A = np.array([[0, 0, 0], + [beta, -gamma, 0], + [0, 0, -eta]]) + tmp_x = expm(t * A) + return np.matmul(tmp_x, x0) + + elif t <= event_2_time: + # "simulate" until first event + A = np.array([[0, 0, 0], + [beta, -gamma, 0], + [0, 0, -eta]]) + tmp_x = expm(event_1_time * A) + x1 = np.matmul(tmp_x, x0) + # apply bolus + delta_x = np.array([[float(-x1[2, :] / 2)], [0], [0]]) + x1 += delta_x + # "simulate" on + tmp_x = expm((t - event_1_time) * A) + return np.matmul(tmp_x, x1) + + if t < event_2_time: + x = get_early_x(t).flatten() + elif t < event_3_time: + x2 = get_early_x(event_2_time) + + A = np.array([[-alpha, 0, 0], + [beta, -gamma, 0], + [0, 0, -eta]]) + tmp_x = expm((t - event_2_time) * A) + x = np.matmul(tmp_x, x2).flatten() + else: + x2 = get_early_x(event_2_time) + + A = np.array([[-alpha, 0, 0], + [beta, -gamma, 0], + [0, 0, -eta]]) + tmp_x = expm((event_3_time - event_2_time) * A) + x3 = np.matmul(tmp_x, x2) + # apply bolus + x3 += np.array([[0], [0], [zeta / 3]]) + + hom_x = np.matmul(expm((t - event_3_time) * A), x3) + inhom_x = [[0], [0], + [-np.exp(-eta * (t - event_3_time)) / (eta) + + 1 / (eta)]] + + x = (hom_x + inhom_x).flatten() + + return np.array(x) + + def sx_pected(t, parameters): + # get sx, w.r.t. parameters, via finite differences + sx = [] + + for ip in parameters: + eps = 1e-6 + perturbed_params = deepcopy(parameters) + perturbed_params[ip] += eps + sx_p = x_pected(t, **perturbed_params) + perturbed_params[ip] -= 2*eps + sx_m = x_pected(t, **perturbed_params) + sx.append((sx_p - sx_m) / (2 * eps)) + + return np.array(sx) + + return ( + initial_assignments, + parameters, + rate_rules, + species, + events, + timepoints, + x_pected, + sx_pected + ) + + + +def model_definition_nested_events(): + """Test model for state- and parameter-dependent heavisides. + + ODEs + ---- + d/dt x_1: + inflow_1 - decay_1 * x1 + d/dt x_2: + - decay_2 * x_2 + + Events: + ------- + event_1: + trigger: x_1 > inflow_1 / decay_2 + bolus: [[ 0], + [ -1 / time]] + event_2: + trigger: x_2 > 0.5 + bolus: [[ bolus], + [ bolus]] + """ + # Model components + species = ['x_1', 'x_2'] + initial_assignments = { + 'x_1': 'k1', + 'x_2': 'k2', + } + rate_rules = { + 'x_1': 'inflow_1 - decay_1 * x_1', + 'x_2': '- decay_2 * x_2', + } + parameters = { + 'k1': 0, + 'k2': 0, + 'inflow_1': 4, + 'decay_1': 2, + 'decay_2': 5, + 'bolus': 0, # for bolus != 0, nested event sensitivities are off! + } + events = { + 'event_1': { + 'trigger': 'x_1 > inflow_1 / decay_2', + 'target': 'x_2', + 'assignment': 'x_2 - 1 / time' + }, + 'event_2': { + 'trigger': 'x_2 < - 0.5', + 'target': ['x_1', 'x_2'], + 'assignment': ['x_1 + bolus', 'x_2 + bolus'], + } + } + timepoints = np.linspace(0, 1, 101) + + # Analytical solution + def x_pected(t, k1, k2, inflow_1, decay_1, decay_2, bolus): + # gather temporary variables + # event_time = x_1 > inflow_1 / decay_2 + equil = inflow_1 / decay_1 + tmp1 = inflow_1 / decay_2 - inflow_1 / decay_1 + tmp2 = k1 - inflow_1 / decay_1 + event_time = (- 1 / decay_1) * np.log( tmp1 / tmp2) + + def get_early_x(t): + # compute dynamics before event + x_1 = equil * (1 - np.exp(-decay_1 * t)) + k1*np.exp(-decay_1 * t) + x_2 = k2 * np.exp(-decay_2 * t) + return np.array([[x_1], [x_2]]) + + if t < event_time: + x = get_early_x(t).flatten() + else: + # compute state after event + x_tau = get_early_x(event_time) + tau_x1 = x_tau[0] + bolus + tau_x2 = x_tau[1] - 1 / event_time + bolus + + # compute dynamics after event + inhom = np.exp(decay_1 * event_time) * tau_x1 + x_1 = equil * (1 - np.exp(decay_1 * (event_time - t))) + \ + inhom * np.exp(- decay_1 * t) + x_2 = tau_x2 * np.exp(decay_2 * event_time) * np.exp(-decay_2 * t) + + x = np.array([[x_1], [x_2]]) + + return x.flatten() + + def sx_pected(t, parameters): + # get sx, w.r.t. parameters, via finite differences + sx = [] + + for ip in parameters: + eps = 1e-6 + perturbed_params = deepcopy(parameters) + perturbed_params[ip] += eps + sx_p = x_pected(t, **perturbed_params) + perturbed_params[ip] -= 2*eps + sx_m = x_pected(t, **perturbed_params) + sx.append((sx_p - sx_m) / (2 * eps)) + + return np.array(sx) + + return ( + initial_assignments, + parameters, + rate_rules, + species, + events, + timepoints, + x_pected, + sx_pected + ) + + +def test_models(model): + amici_model, parameters, timepoints, x_pected, sx_pected = model + + result_expected_x = np.array([ + x_pected(t, **parameters) + for t in timepoints + ]) + result_expected_sx = np.array([ + sx_pected(t, parameters) + for t in timepoints + ]) + + # assert correctness of trajectories + check_trajectories_without_sensitivities(amici_model, + result_expected_x) + check_trajectories_with_forward_sensitivities(amici_model, + result_expected_x, + result_expected_sx) diff --git a/deps/AMICI/python/tests/test_heavisides.py b/deps/AMICI/python/tests/test_heavisides.py index 557b539d7..1c84ae0ac 100644 --- a/deps/AMICI/python/tests/test_heavisides.py +++ b/deps/AMICI/python/tests/test_heavisides.py @@ -1,23 +1,14 @@ """Tests for SBML events, including piecewise expressions.""" -import importlib -import libsbml import numpy as np -from pathlib import Path import pytest -import sys - -from amici import ( - AmiciModel, - runAmiciSimulation, - SbmlImporter, - SensitivityMethod, - SensitivityOrder -) -sbml_test_models = Path('sbml_test_models') -sbml_test_models_output_dir = sbml_test_models / 'amici_models' -sbml_test_models_output_dir.mkdir(parents=True, exist_ok=True) +from util import ( + create_sbml_model, + create_amici_model, + check_trajectories_without_sensitivities, + check_trajectories_with_forward_sensitivities, +) @pytest.fixture(params=[ 'state_and_parameter_dependent_heavisides', @@ -31,6 +22,7 @@ def model(request): parameters, rate_rules, species, + events, timepoints, x_pected, sx_pected @@ -42,6 +34,7 @@ def model(request): parameters=parameters, rate_rules=rate_rules, species=species, + events=events, # uncomment `to_file` to save SBML model to file for inspection # to_file=sbml_test_models / (model_name + '.sbml'), ) @@ -68,120 +61,12 @@ def test_models(model): for t in timepoints ]) - # --- Test the state trajectories without sensitivities ------------------- - # Does the AMICI simulation match the analytical solution? - solver = amici_model.getSolver() - rdata = runAmiciSimulation(amici_model, solver=solver) - solver.setAbsoluteTolerance(1e-15) - np.testing.assert_almost_equal(rdata['x'], result_expected_x, decimal=5) - - # Show that we can do arbitrary precision here (test 8 digits) - solver = amici_model.getSolver() - solver.setAbsoluteTolerance(1e-15) - solver.setRelativeTolerance(1e-12) - rdata = runAmiciSimulation(amici_model, solver=solver) - np.testing.assert_almost_equal(rdata['x'], result_expected_x, decimal=8) - - # --- Test the state trajectories with sensitivities ---------------------- - # Does the AMICI simulation match the analytical solution? - solver = amici_model.getSolver() - solver.setSensitivityOrder(SensitivityOrder.first) - solver.setSensitivityMethod(SensitivityMethod.forward) - solver.setAbsoluteTolerance(1e-15) - rdata = runAmiciSimulation(amici_model, solver=solver) - - np.testing.assert_almost_equal(rdata['x'], result_expected_x, decimal=5) - np.testing.assert_almost_equal(rdata['sx'], result_expected_sx, decimal=5) - - # Show that we can do arbitrary precision here (test 8 digits) - solver = amici_model.getSolver() - solver.setSensitivityOrder(SensitivityOrder.first) - solver.setSensitivityMethod(SensitivityMethod.forward) - solver.setAbsoluteTolerance(1e-15) - solver.setRelativeTolerance(1e-13) - solver.setAbsoluteToleranceFSA(1e-15) - solver.setRelativeToleranceFSA(1e-13) - rdata = runAmiciSimulation(amici_model, solver=solver) - np.testing.assert_almost_equal(rdata['x'], result_expected_x, decimal=8) - np.testing.assert_almost_equal(rdata['sx'], result_expected_sx, decimal=8) - - -def create_amici_model(sbml_model, model_name) -> AmiciModel: - sbml_importer = SbmlImporter(sbml_model) - output_dir = sbml_test_models_output_dir / model_name - sbml_importer.sbml2amici( - model_name=model_name, - output_dir=str(output_dir) - ) - - sys.path.insert(0, str(output_dir.resolve())) - model_module = importlib.import_module(model_name) - - model = model_module.getModel() - return model - - -def create_sbml_model( - initial_assignments, - parameters, - rate_rules, - species, - to_file: str = None, -): - """Create an SBML model from simple definitions. - - See the model definitions and usage in :py:func:`model` for example input. - - The default initial concentration of species is `1.0`. This can currently - be changed by specifying an initial assignment. - """ - document = libsbml.SBMLDocument(3, 1) - model = document.createModel() - - compartment = model.createCompartment() - compartment.setId('compartment') - compartment.setConstant(True) - compartment.setSize(1) - compartment.setSpatialDimensions(3) - compartment.setUnits('dimensionless') - - for species_id in species: - species = model.createSpecies() - species.setId(species_id) - species.setCompartment('compartment') - species.setConstant(False) - species.setSubstanceUnits('dimensionless') - species.setBoundaryCondition(False) - species.setHasOnlySubstanceUnits(False) - species.setInitialConcentration(1.0) - - for target, formula in initial_assignments.items(): - initial_assignment = model.createInitialAssignment() - initial_assignment.setSymbol(target) - initial_assignment.setMath(libsbml.parseL3Formula(formula)) - - for target, formula in rate_rules.items(): - rate_rule = model.createRateRule() - rate_rule.setVariable(target) - rate_rule.setMath(libsbml.parseL3Formula(formula)) - - for parameter_id, parameter_value in parameters.items(): - parameter = model.createParameter() - parameter.setId(parameter_id) - parameter.setConstant(True) - parameter.setValue(parameter_value) - parameter.setUnits('dimensionless') - - if to_file: - libsbml.writeSBMLToFile( - document, - str(to_file), - ) - - # Need to return document, else AMICI throws an error. - # (possibly due to garbage collection?) - return document, model + check_trajectories_without_sensitivities(amici_model, + result_expected_x) + check_trajectories_with_forward_sensitivities(amici_model, + result_expected_x, + result_expected_sx) def get_model_definition(model_name): @@ -227,6 +112,7 @@ def model_definition_state_and_parameter_dependent_heavisides(): 'zeta': 0.25, } timepoints = np.linspace(0, 10, 100) + events = {} # Analytical solution def x_pected(t, alpha, beta, gamma, delta, eta, zeta): @@ -313,6 +199,7 @@ def sx_pected(t, alpha, beta, gamma, delta, eta, zeta): parameters, rate_rules, species, + events, timepoints, x_pected, sx_pected @@ -349,6 +236,7 @@ def model_definition_piecewise_with_boolean_operations(): 'x_1_0': 1, } timepoints = np.linspace(0, 5, 100) + events = {} # Analytical solution def x_pected(t, x_1_0, alpha, beta, gamma, delta): @@ -389,6 +277,7 @@ def sx_pected(t, x_1_0, alpha, beta, gamma, delta): parameters, rate_rules, species, + events, timepoints, x_pected, sx_pected @@ -424,6 +313,7 @@ def model_definition_piecewise_many_conditions(): 'x_1_0': 1, } timepoints = np.linspace(0, t_final, 100) + events = {} # Analytical solution def x_pected(t, x_1_0): @@ -440,6 +330,7 @@ def sx_pected(t, x_1_0): parameters, rate_rules, species, + events, timepoints, x_pected, sx_pected diff --git a/deps/AMICI/python/tests/test_sbml_import.py b/deps/AMICI/python/tests/test_sbml_import.py index 5540b5c92..a9b84c267 100644 --- a/deps/AMICI/python/tests/test_sbml_import.py +++ b/deps/AMICI/python/tests/test_sbml_import.py @@ -1,6 +1,7 @@ """Tests related to amici.sbml_import""" import os +import sys import re from urllib.request import urlopen import shutil @@ -29,6 +30,10 @@ def simple_sbml_model(): s1.setId('S1') s1.setCompartment('C1') model.addSpecies(s1) + p1 = model.createParameter() + p1.setId('p1') + p1.setValue(0.0) + model.addParameter(p1) return document, model @@ -46,6 +51,32 @@ def test_sbml2amici_no_observables(simple_sbml_model): compute_conservation_laws=False) +@pytest.mark.skipif(sys.platform in ['win32', 'cygwin'], + reason="windows stinks") +def test_nosensi(simple_sbml_model): + sbml_doc, sbml_model = simple_sbml_model + sbml_importer = SbmlImporter(sbml_source=sbml_model, + from_file=False) + + with TemporaryDirectory() as tmpdir: + sbml_importer.sbml2amici(model_name="test", + output_dir=tmpdir, + observables=None, + compute_conservation_laws=False, + generate_sensitivity_code=False) + + model_module = amici.import_model_module(module_name='test', + module_path=tmpdir) + + model = model_module.getModel() + model.setTimepoints(np.linspace(0, 60, 61)) + solver = model.getSolver() + solver.setSensitivityOrder(amici.SensitivityOrder.first) + solver.setSensitivityMethod(amici.SensitivityMethod.forward) + rdata = amici.runAmiciSimulation(model, solver) + assert rdata.status == amici.AMICI_ERROR + + def assert_fun(x): assert x diff --git a/deps/AMICI/python/tests/util.py b/deps/AMICI/python/tests/util.py new file mode 100644 index 000000000..cac811b11 --- /dev/null +++ b/deps/AMICI/python/tests/util.py @@ -0,0 +1,173 @@ +"""Tests for SBML events, including piecewise expressions.""" +import libsbml +import numpy as np +from pathlib import Path + +from amici import ( + AmiciModel, + import_model_module, + runAmiciSimulation, + SbmlImporter, + SensitivityMethod, + SensitivityOrder +) + + +def create_amici_model(sbml_model, model_name) -> AmiciModel: + """ + Import an sbml file and create an AMICI model from it + """ + sbml_test_models = Path('sbml_test_models') + sbml_test_models_output_dir = sbml_test_models / 'amici_models' + sbml_test_models_output_dir.mkdir(parents=True, exist_ok=True) + + sbml_importer = SbmlImporter(sbml_model) + output_dir = sbml_test_models_output_dir / model_name + sbml_importer.sbml2amici( + model_name=model_name, + output_dir=str(output_dir) + ) + + model_module = import_model_module(model_name, str(output_dir.resolve())) + model = model_module.getModel() + return model + + +def create_sbml_model( + initial_assignments, + parameters, + rate_rules, + species, + events, + to_file: str = None, +): + """Create an SBML model from simple definitions. + + See the model definitions and usage in :py:func:`model` for example input. + + The default initial concentration of species is `1.0`. This can currently + be changed by specifying an initial assignment. + """ + document = libsbml.SBMLDocument(3, 1) + model = document.createModel() + + compartment = model.createCompartment() + compartment.setId('compartment') + compartment.setConstant(True) + compartment.setSize(1) + compartment.setSpatialDimensions(3) + compartment.setUnits('dimensionless') + + for species_id in species: + species = model.createSpecies() + species.setId(species_id) + species.setCompartment('compartment') + species.setConstant(False) + species.setSubstanceUnits('dimensionless') + species.setBoundaryCondition(False) + species.setHasOnlySubstanceUnits(False) + species.setInitialConcentration(1.0) + + for target, formula in initial_assignments.items(): + initial_assignment = model.createInitialAssignment() + initial_assignment.setSymbol(target) + initial_assignment.setMath(libsbml.parseL3Formula(formula)) + + for target, formula in rate_rules.items(): + rate_rule = model.createRateRule() + rate_rule.setVariable(target) + rate_rule.setMath(libsbml.parseL3Formula(formula)) + + for parameter_id, parameter_value in parameters.items(): + parameter = model.createParameter() + parameter.setId(parameter_id) + parameter.setConstant(True) + parameter.setValue(parameter_value) + parameter.setUnits('dimensionless') + + for event_id, event_def in events.items(): + event = model.createEvent() + event.setId(event_id) + event.setName(event_id) + event.setUseValuesFromTriggerTime(True) + trigger = event.createTrigger() + trigger.setMath(libsbml.parseL3Formula(event_def['trigger'])) + trigger.setPersistent(True) + trigger.setInitialValue(True) + if isinstance(event_def['target'], list): + assignments = [] + for ia, event_target in enumerate(event_def['target']): + event_assignment = event_def['assignment'][ia] + assignments.append(event.createEventAssignment()) + assignments[ia].setVariable(event_target) + assignments[ia].setMath( + libsbml.parseL3Formula(event_assignment)) + else: + assignment = event.createEventAssignment() + assignment.setVariable(event_def['target']) + assignment.setMath(libsbml.parseL3Formula(event_def['assignment'])) + + if to_file: + libsbml.writeSBMLToFile( + document, + str(to_file), + ) + + # Need to return document, else AMICI throws an error. + # (possibly due to garbage collection?) + return document, model + + +def check_trajectories_without_sensitivities( + amici_model: AmiciModel, + result_expected_x: np.ndarray, +): + """ + Check whether the AMICI simulation matches a known solution + (ideally an analytically calculated one). + """ + + # Does the AMICI simulation match the analytical solution? + solver = amici_model.getSolver() + solver.setAbsoluteTolerance(1e-15) + rdata = runAmiciSimulation(amici_model, solver=solver) + np.testing.assert_almost_equal(rdata['x'], result_expected_x, decimal=5) + + # Show that we can do arbitrary precision here (test 8 digits) + solver = amici_model.getSolver() + solver.setAbsoluteTolerance(1e-15) + solver.setRelativeTolerance(1e-12) + rdata = runAmiciSimulation(amici_model, solver=solver) + np.testing.assert_almost_equal(rdata['x'], result_expected_x, decimal=8) + + +def check_trajectories_with_forward_sensitivities( + amici_model: AmiciModel, + result_expected_x: np.ndarray, + result_expected_sx: np.ndarray, +): + """ + Check whether the forward sensitivities of the AMICI simulation match + a known solution (ideally an analytically calculated one). + """ + + # Show that we can do arbitrary precision here (test 8 digits) + solver = amici_model.getSolver() + solver.setAbsoluteTolerance(1e-15) + solver.setSensitivityOrder(SensitivityOrder.first) + solver.setSensitivityMethod(SensitivityMethod.forward) + rdata = runAmiciSimulation(amici_model, solver=solver) + np.testing.assert_almost_equal(rdata['x'], result_expected_x, decimal=5) + np.testing.assert_almost_equal(rdata['sx'], result_expected_sx, decimal=5) + + # Show that we can do arbitrary precision here (test 8 digits) + solver = amici_model.getSolver() + solver.setSensitivityOrder(SensitivityOrder.first) + solver.setSensitivityMethod(SensitivityMethod.forward) + solver.setAbsoluteTolerance(1e-15) + solver.setRelativeTolerance(1e-13) + solver.setAbsoluteToleranceFSA(1e-15) + solver.setRelativeToleranceFSA(1e-13) + rdata = runAmiciSimulation(amici_model, solver=solver) + np.testing.assert_almost_equal(rdata['x'], result_expected_x, decimal=8) + np.testing.assert_almost_equal(rdata['sx'], result_expected_sx, decimal=8) diff --git a/deps/AMICI/scripts/downloadAndBuildDoxygen.sh b/deps/AMICI/scripts/downloadAndBuildDoxygen.sh index 9e6bab2ca..8cae173e6 100755 --- a/deps/AMICI/scripts/downloadAndBuildDoxygen.sh +++ b/deps/AMICI/scripts/downloadAndBuildDoxygen.sh @@ -9,7 +9,7 @@ DOXYGEN_DIR="${AMICI_PATH}"/ThirdParty/doxygen cd "${AMICI_PATH}"/ThirdParty if [[ ! -d ${DOXYGEN_DIR} ]]; then # git clone --depth 1 https://github.com/doxygen/doxygen.git "${DOXYGEN_DIR}" - git clone --single-branch --branch master --depth 1 https://github.com/doxygen/doxygen.git "${DOXYGEN_DIR}" + git clone --single-branch --branch Release_1_9_1 --depth 1 https://github.com/doxygen/doxygen.git "${DOXYGEN_DIR}" fi cd "${DOXYGEN_DIR}" diff --git a/deps/AMICI/scripts/run-SBMLTestsuite.sh b/deps/AMICI/scripts/run-SBMLTestsuite.sh index 9906442b5..1767a16df 100755 --- a/deps/AMICI/scripts/run-SBMLTestsuite.sh +++ b/deps/AMICI/scripts/run-SBMLTestsuite.sh @@ -26,5 +26,5 @@ if [[ -d "${RESULT_DIR}" ]]; then fi mkdir "${RESULT_DIR}" -pytest ./tests/testSBMLSuite.py --cases="${args}" -rfsE -s -n auto \ +pytest ./tests/testSBMLSuite.py --cases="${args}" -rfsE -n auto \ --cov=amici --cov-report=xml:"coverage_SBMLSuite.xml" --cov-append diff --git a/deps/AMICI/sonar-project.properties b/deps/AMICI/sonar-project.properties index 3dda19a12..f376ff3bd 100644 --- a/deps/AMICI/sonar-project.properties +++ b/deps/AMICI/sonar-project.properties @@ -9,7 +9,19 @@ sonar.organization=icb-dcm sonar.projectKey=ICB-DCM_AMICI sonar.sources=. -sonar.exclusions=build/**,ThirdParty/**,doc/**,models/**,python/sdist/amici/**,**/*.html,**/*.m,model_*/**,**/sbml_test_models/** +sonar.exclusions=\ + build/**,\ + ThirdParty/**,\ + doc/**,\ + models/**,\ + model_*/**,\ + **/amici_models/**,\ + python/sdist/amici/**,\ + **/*.html,\ + **/*.m,\ + **/sbml_test_models/**,\ + documentation/model_dir/**,\ + matlab/mtoc/** sonar.sourceEncoding=UTF-8 diff --git a/deps/AMICI/src/abstract_model.cpp b/deps/AMICI/src/abstract_model.cpp index e9469125c..f866eb7db 100644 --- a/deps/AMICI/src/abstract_model.cpp +++ b/deps/AMICI/src/abstract_model.cpp @@ -2,13 +2,13 @@ namespace amici { -const std::string +std::string AbstractModel::getAmiciVersion() const { throw AmiException("Version not set during code generation"); } -const std::string +std::string AbstractModel::getAmiciCommit() const { throw AmiException("Commit not set during code generation"); diff --git a/deps/AMICI/src/amici.cpp b/deps/AMICI/src/amici.cpp index 72da4c2a4..841fdb98a 100644 --- a/deps/AMICI/src/amici.cpp +++ b/deps/AMICI/src/amici.cpp @@ -193,6 +193,13 @@ AmiciApplication::runAmiciSimulation(Solver& solver, "AMICI simulation failed:\n%s\nError occurred in:\n%s", ex.what(), ex.getBacktrace()); + } catch (std::exception const& ex) { + rdata->status = AMICI_ERROR; + if (rethrow) + throw; + warningF("AMICI:simulation", + "AMICI simulation failed:\n%s\n", + ex.what()); } rdata->processSimulationObjects( diff --git a/deps/AMICI/src/forwardproblem.cpp b/deps/AMICI/src/forwardproblem.cpp index a0f4de08c..8147edce0 100644 --- a/deps/AMICI/src/forwardproblem.cpp +++ b/deps/AMICI/src/forwardproblem.cpp @@ -157,9 +157,10 @@ void ForwardProblem::handleEvent(realtype *tlastroot, const bool seflag) { /* only check this in the first event fired, otherwise this will always * be true */ if (t_ == *tlastroot) { - throw AmiException("AMICI is stuck in an event, as the initial" - "step-size after the event is too small. To fix " - "this, increase absolute and relative tolerances!"); + throw AmiException("AMICI is stuck in an event, as the initial " + "step-size after the event is too small. " + "To fix this, increase absolute and relative " + "tolerances!"); } *tlastroot = t_; } @@ -231,6 +232,13 @@ void ForwardProblem::handleEvent(realtype *tlastroot, const bool seflag) { } /* fire the secondary event */ if (secondevent > 0) { + /* Secondary events may result in wrong forward sensitivities, + * if the secondary event has a bolus... */ + if (solver->computingFSA()) + solver->app->warning("AMICI:simulation", + "Secondary event was triggered. Depending on " + "the bolus of the secondary event, forward " + "sensitivities can be incorrect."); handleEvent(tlastroot, true); } diff --git a/deps/AMICI/src/model_header.ODE_template.h b/deps/AMICI/src/model_header.ODE_template.h index 99e5257a7..79eec1d51 100644 --- a/deps/AMICI/src/model_header.ODE_template.h +++ b/deps/AMICI/src/model_header.ODE_template.h @@ -26,21 +26,12 @@ extern std::array stateIds; extern std::array observableIds; extern std::array expressionIds; -extern void Jy_TPL_MODELNAME(realtype *nllh, const int iy, const realtype *p, - const realtype *k, const realtype *y, - const realtype *sigmay, const realtype *my); -extern void dJydsigmay_TPL_MODELNAME(realtype *dJydsigmay, const int iy, - const realtype *p, const realtype *k, - const realtype *y, const realtype *sigmay, - const realtype *my); +TPL_JY_DEF +TPL_DJYDSIGMA_DEF TPL_DJYDY_DEF TPL_DJYDY_COLPTRS_DEF TPL_DJYDY_ROWVALS_DEF - -extern void root_TPL_MODELNAME(realtype *root, const realtype t, - const realtype *x, const realtype *p, - const realtype *k, const realtype *h); - +TPL_ROOT_DEF TPL_DWDP_DEF TPL_DWDP_COLPTRS_DEF TPL_DWDP_ROWVALS_DEF @@ -59,54 +50,20 @@ TPL_DXDOTDP_EXPLICIT_ROWVALS_DEF TPL_DXDOTDX_EXPLICIT_DEF TPL_DXDOTDX_EXPLICIT_COLPTRS_DEF TPL_DXDOTDX_EXPLICIT_ROWVALS_DEF - -extern void dydx_TPL_MODELNAME(realtype *dydx, const realtype t, - const realtype *x, const realtype *p, - const realtype *k, const realtype *h, - const realtype *w, const realtype *dwdx); -extern void dydp_TPL_MODELNAME(realtype *dydp, const realtype t, - const realtype *x, const realtype *p, - const realtype *k, const realtype *h, - const int ip, const realtype *w, - const realtype *dwp); -extern void dsigmaydp_TPL_MODELNAME(realtype *dsigmaydp, const realtype t, - const realtype *p, const realtype *k, - const int ip); -extern void sigmay_TPL_MODELNAME(realtype *sigmay, const realtype t, - const realtype *p, const realtype *k); +TPL_DYDX_DEF +TPL_DYDP_DEF +TPL_SIGMAY_DEF +TPL_DSIGMAYDP_DEF TPL_W_DEF -extern void x0_TPL_MODELNAME(realtype *x0, const realtype t, const realtype *p, - const realtype *k); -extern void x0_fixedParameters_TPL_MODELNAME(realtype *x0, const realtype t, - const realtype *p, - const realtype *k, - gsl::span reinitialization_state_idxs); -extern void sx0_TPL_MODELNAME(realtype *sx0, const realtype t, - const realtype *x0, const realtype *p, - const realtype *k, const int ip); -extern void sx0_fixedParameters_TPL_MODELNAME(realtype *sx0, const realtype t, - const realtype *x0, - const realtype *p, - const realtype *k, const int ip, - gsl::span reinitialization_state_idxs); -extern void xdot_TPL_MODELNAME(realtype *xdot, const realtype t, - const realtype *x, const realtype *p, - const realtype *k, const realtype *h, - const realtype *w); -extern void y_TPL_MODELNAME(realtype *y, const realtype t, const realtype *x, - const realtype *p, const realtype *k, - const realtype *h, const realtype *w); -extern void stau_TPL_MODELNAME(realtype *stau, const realtype t, - const realtype *x, const realtype *p, - const realtype *k, const realtype *h, - const realtype *sx, const int ip, const int ie); -extern void deltasx_TPL_MODELNAME(realtype *deltasx, const realtype t, - const realtype *x, const realtype *p, - const realtype *k, const realtype *h, - const realtype *w, const int ip, - const int ie, const realtype *xdot, - const realtype *xdot_old, const realtype *sx, - const realtype *stau); +TPL_X0_DEF +TPL_X0_FIXEDPARAMETERS_DEF +TPL_SX0_DEF +TPL_SX0_FIXEDPARAMETERS_DEF +TPL_XDOT_DEF +TPL_Y_DEF +TPL_STAU_DEF +TPL_DELTAX_DEF +TPL_DELTASX_DEF TPL_X_RDATA_DEF TPL_X_SOLVER_DEF TPL_TOTAL_CL_DEF @@ -178,20 +135,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { const realtype *k, const realtype *rz, const realtype *sigmaz) override {} - /** model specific implementation of fJy - * @param nllh negative log-likelihood for measurements y - * @param iy output index - * @param p parameter vector - * @param k constant vector - * @param y model output at timepoint - * @param sigmay measurement standard deviation at timepoint - * @param my measurements at timepoint - **/ - virtual void fJy(realtype *nllh, const int iy, const realtype *p, - const realtype *k, const realtype *y, - const realtype *sigmay, const realtype *my) override { - Jy_TPL_MODELNAME(nllh, iy, p, k, y, sigmay, my); - } + TPL_JY_IMPL /** model specific implementation of fJz * @param nllh negative log-likelihood for event measurements z @@ -232,23 +176,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { const realtype *k, const realtype *rz, const realtype *sigmaz) override {} - /** model specific implementation of fdJydsigma - * @param dJydsigma Sensitivity of time-resolved measurement - * negative log-likelihood Jy w.r.t. standard deviation sigmay - * @param iy output index - * @param p parameter vector - * @param k constant vector - * @param y model output at timepoint - * @param sigmay measurement standard deviation at timepoint - * @param my measurement at timepoint - **/ - virtual void fdJydsigma(realtype *dJydsigma, const int iy, - const realtype *p, const realtype *k, - const realtype *y, const realtype *sigmay, - const realtype *my) override { - dJydsigmay_TPL_MODELNAME(dJydsigma, iy, p, k, y, sigmay, my); - } - + TPL_DJYDSIGMA_IMPL /** model specific implementation of fdJzdsigma * @param dJzdsigma Sensitivity of event measurement @@ -299,46 +227,9 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { const realtype *xdot_old, const realtype *xB) override {} - /** model specific implementation of fdeltasx - * @param deltasx sensitivity update - * @param t current time - * @param x current state - * @param p parameter vector - * @param k constant vector - * @param h heaviside vector - * @param w repeating elements vector - * @param ip sensitivity index - * @param ie event index - * @param xdot new model right hand side - * @param xdot_old previous model right hand side - * @param sx state sensitivity - * @param stau event-time sensitivity - **/ - virtual void fdeltasx(realtype *deltasx, const realtype t, - const realtype *x, const realtype *p, - const realtype *k, const realtype *h, - const realtype *w, const int ip, const int ie, - const realtype *xdot, const realtype *xdot_old, - const realtype *sx, const realtype *stau) override { - deltasx_TPL_MODELNAME(deltasx, t, x, p, k, h, w, ip, ie, xdot, - xdot_old, sx, stau); - } + TPL_DELTASX_IMPL - /** model specific implementation of fdeltax - * @param deltax state update - * @param t current time - * @param x current state - * @param p parameter vector - * @param k constant vector - * @param h heaviside vector - * @param ie event index - * @param xdot new model right hand side - * @param xdot_old previous model right hand side - **/ - virtual void fdeltax(realtype *deltax, const realtype t, const realtype *x, - const realtype *p, const realtype *k, - const realtype *h, const int ie, const realtype *xdot, - const realtype *xdot_old) override {} + TPL_DELTAX_IMPL /** model specific implementation of fdeltaxB * @param deltaxB adjoint state update @@ -386,18 +277,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { const realtype *x, const realtype *p, const realtype *k, const realtype *h) override {} - /** model specific implementation of fsigmay - * @param dsigmaydp partial derivative of standard deviation of measurements - * @param t current time - * @param p parameter vector - * @param k constant vector - * @param ip sensitivity index - **/ - virtual void fdsigmaydp(realtype *dsigmaydp, const realtype t, - const realtype *p, const realtype *k, - const int ip) override { - dsigmaydp_TPL_MODELNAME(dsigmaydp, t, p, k, ip); - } + TPL_DSIGMAYDP_IMPL /** model specific implementation of fsigmaz * @param dsigmazdp partial derivative of standard deviation of event @@ -439,35 +319,9 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { TPL_DXDOTDX_EXPLICIT_COLPTRS_IMPL TPL_DXDOTDX_EXPLICIT_ROWVALS_IMPL - /** model specific implementation of fdydx - * @param dydx partial derivative of observables y w.r.t. model states x - * @param t current time - * @param x current state - * @param p parameter vector - * @param k constant vector - * @param h heaviside vector - **/ - virtual void fdydx(realtype *dydx, const realtype t, const realtype *x, - const realtype *p, const realtype *k, const realtype *h, - const realtype *w, const realtype *dwdx) override { - dydx_TPL_MODELNAME(dydx, t, x, p, k, h, w, dwdx); - } + TPL_DYDX_IMPL - /** model specific implementation of fdydp - * @param dydp partial derivative of observables y w.r.t. model parameters p - * @param t current time - * @param x current state - * @param p parameter vector - * @param k constant vector - * @param h heaviside vector - * @param ip parameter index w.r.t. which the derivative is requested - **/ - virtual void fdydp(realtype *dydp, const realtype t, const realtype *x, - const realtype *p, const realtype *k, const realtype *h, - const int ip, const realtype *w, - const realtype *dwdp) override { - dydp_TPL_MODELNAME(dydp, t, x, p, k, h, ip, w, dwdp); - } + TPL_DYDP_IMPL /** model specific implementation of fdzdp * @param dzdp partial derivative of event-resolved output z w.r.t. model @@ -498,19 +352,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { const realtype *x, const realtype *p, const realtype *k, const realtype *h) override {} - /** model specific implementation for froot - * @param root values of the trigger function - * @param t timepoint - * @param x Vector with the states - * @param p parameter vector - * @param k constants vector - * @param h heaviside vector - **/ - virtual void froot(realtype *root, const realtype t, const realtype *x, - const realtype *p, const realtype *k, - const realtype *h) override { - root_TPL_MODELNAME(root, t, x, p, k, h); - } + TPL_ROOT_IMPL /** model specific implementation of frz * @param rz value of root function at current timepoint (non-output events @@ -526,16 +368,7 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { const realtype *x, const realtype *p, const realtype *k, const realtype *h) override {} - /** model specific implementation of fsigmay - * @param sigmay standard deviation of measurements - * @param t current time - * @param p parameter vector - * @param k constant vector - **/ - virtual void fsigmay(realtype *sigmay, const realtype t, const realtype *p, - const realtype *k) override { - sigmay_TPL_MODELNAME(sigmay, t, p, k); - } + TPL_SIGMAY_IMPL /** model specific implementation of fsigmaz * @param sigmaz standard deviation of event measurements @@ -562,54 +395,9 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { const realtype *h, const realtype *sx, const int ip) override {} - /** model specific implementation of fstau - * @param stau total derivative of event timepoint - * @param t current time - * @param x current state - * @param p parameter vector - * @param k constant vector - * @param h heaviside vector - * @param sx current state sensitivity - * @param ip sensitivity index - * @param ie event index - **/ - virtual void fstau(realtype *stau, const realtype t, const realtype *x, - const realtype *p, const realtype *k, const realtype *h, - const realtype *sx, const int ip, - const int ie) override { - stau_TPL_MODELNAME(stau, t, x, p, k, h, sx, ip, ie); - } - - /** model specific implementation of fsx0 - * @param sx0 initial state sensitivities - * @param t initial time - * @param x0 initial state - * @param p parameter vector - * @param k constant vector - * @param ip sensitivity index - **/ - virtual void fsx0(realtype *sx0, const realtype t, const realtype *x0, - const realtype *p, const realtype *k, - const int ip) override { - sx0_TPL_MODELNAME(sx0, t, x0, p, k, ip); - } - - /** model specific implementation of fsx0_fixedParameters - * @param sx0 initial state sensitivities - * @param t initial time - * @param x0 initial state - * @param p parameter vector - * @param k constant vector - * @param ip sensitivity index - **/ - virtual void fsx0_fixedParameters(realtype *sx0, const realtype t, - const realtype *x0, const realtype *p, - const realtype *k, - const int ip, - gsl::span reinitialization_state_idxs - ) override { - sx0_fixedParameters_TPL_MODELNAME(sx0, t, x0, p, k, ip, reinitialization_state_idxs); - } + TPL_STAU_IMPL + TPL_SX0_IMPL + TPL_SX0_FIXEDPARAMETERS_IMPL /** model specific implementation of fsz * @param sz Sensitivity of rz, total derivative @@ -629,59 +417,13 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { TPL_W_IMPL - /** model specific implementation of fx0 - * @param x0 initial state - * @param t initial time - * @param p parameter vector - * @param k constant vector - **/ - virtual void fx0(realtype *x0, const realtype t, const realtype *p, - const realtype *k) override { - x0_TPL_MODELNAME(x0, t, p, k); - } + TPL_X0_IMPL - /** model specific implementation of fx0_fixedParameters - * @param x0 initial state - * @param t initial time - * @param p parameter vector - * @param k constant vector - **/ - virtual void fx0_fixedParameters(realtype *x0, const realtype t, - const realtype *p, - const realtype *k, - gsl::span reinitialization_state_idxs - ) override { - x0_fixedParameters_TPL_MODELNAME(x0, t, p, k, reinitialization_state_idxs); - } + TPL_X0_FIXEDPARAMETERS_IMPL - /** model specific implementation for fxdot - * @param xdot residual function - * @param t timepoint - * @param x Vector with the states - * @param p parameter vector - * @param k constants vector - * @param h heaviside vector - * @param w vector with helper variables - **/ - virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, - const realtype *p, const realtype *k, const realtype *h, - const realtype *w) override { - xdot_TPL_MODELNAME(xdot, t, x, p, k, h, w); - } + TPL_XDOT_IMPL - /** model specific implementation of fy - * @param y model output at current timepoint - * @param t current time - * @param x current state - * @param p parameter vector - * @param k constant vector - * @param h heaviside vector - **/ - virtual void fy(realtype *y, const realtype t, const realtype *x, - const realtype *p, const realtype *k, const realtype *h, - const realtype *w) override { - y_TPL_MODELNAME(y, t, x, p, k, h, w); - } + TPL_Y_IMPL /** model specific implementation of fz * @param z value of event output @@ -805,18 +547,18 @@ class Model_TPL_MODELNAME : public amici::Model_ODE { } /** - * @brief returns the amici version that was used to generate the model - * @return ver amici version string + * @brief returns the AMICI version that was used to generate the model + * @return AMICI version string */ - virtual const std::string getAmiciVersion() const override { + virtual std::string getAmiciVersion() const override { return "TPL_AMICI_VERSION_STRING"; } /** - & @brief returns the amici version that was used to generate the model - * @return commit amici git commit hash + * @brief returns the amici version that was used to generate the model + * @return AMICI git commit hash */ - virtual const std::string getAmiciCommit() const override { + virtual std::string getAmiciCommit() const override { return "TPL_AMICI_COMMIT_STRING"; } diff --git a/deps/AMICI/src/rdata.cpp b/deps/AMICI/src/rdata.cpp index d369ec7db..9b7f94461 100644 --- a/deps/AMICI/src/rdata.cpp +++ b/deps/AMICI/src/rdata.cpp @@ -477,26 +477,58 @@ void ReturnData::handleSx0Forward(const Model &model, void ReturnData::processSolver(Solver const &solver) { cpu_time = solver.getCpuTime(); - if (!numsteps.empty()) - numsteps = solver.getNumSteps(); - if (!numrhsevals.empty()) - numrhsevals = solver.getNumRhsEvals(); - if (!numerrtestfails.empty()) - numerrtestfails = solver.getNumErrTestFails(); - if (!numnonlinsolvconvfails.empty()) - numnonlinsolvconvfails = solver.getNumNonlinSolvConvFails(); - if (!order.empty()) - order = solver.getLastOrder(); + + const std::vector *tmp; + + if (!numsteps.empty()) { + tmp = &solver.getNumSteps(); + // copy_n instead of assignment to ensure length `nt` + // (vector from solver may be shorter in case of integration errors) + std::copy_n(tmp->cbegin(), tmp->size(), numsteps.begin()); + } + + if (!numsteps.empty()) { + tmp = &solver.getNumRhsEvals(); + std::copy_n(tmp->cbegin(), tmp->size(), numrhsevals.begin()); + } + + if (!numerrtestfails.empty()) { + tmp = &solver.getNumErrTestFails(); + std::copy_n(tmp->cbegin(), tmp->size(), numerrtestfails.begin()); + } + + if (!numnonlinsolvconvfails.empty()) { + tmp = &solver.getNumNonlinSolvConvFails(); + std::copy_n(tmp->cbegin(), tmp->size(), numnonlinsolvconvfails.begin()); + } + + if (!order.empty()) { + tmp = &solver.getLastOrder(); + std::copy_n(tmp->cbegin(), tmp->size(), order.begin()); + } cpu_timeB = solver.getCpuTimeB(); - if (!numstepsB.empty()) - numstepsB = solver.getNumStepsB(); - if (!numrhsevalsB.empty()) - numrhsevalsB = solver.getNumRhsEvalsB(); - if (!numerrtestfailsB.empty()) - numerrtestfailsB = solver.getNumErrTestFailsB(); - if (!numnonlinsolvconvfailsB.empty()) - numnonlinsolvconvfailsB = solver.getNumNonlinSolvConvFailsB(); + + if (!numstepsB.empty()) { + tmp = &solver.getNumStepsB(); + std::copy_n(tmp->cbegin(), tmp->size(), numstepsB.begin()); + } + + if (!numrhsevalsB.empty()) { + tmp = &solver.getNumRhsEvalsB(); + std::copy_n(tmp->cbegin(), tmp->size(), numrhsevalsB.begin()); + } + + if (!numerrtestfailsB.empty()) { + tmp = &solver.getNumErrTestFailsB(); + std::copy_n(tmp->cbegin(), tmp->size(), numerrtestfailsB.begin()); + } + + if (!numnonlinsolvconvfailsB.empty()) { + tmp = &solver.getNumNonlinSolvConvFailsB(); + std::copy_n(tmp->cbegin(), tmp->size(), + numnonlinsolvconvfailsB.begin()); + } } void ReturnData::readSimulationState(SimulationState const &state, @@ -805,17 +837,19 @@ void ReturnData::fFIM(int it, Model &model, const ExpData &edata) { model.getObservableSigmaSensitivity(ssigmay_it, it, &edata); /* - * https://www.wolframalpha.com/input/?i=d%2Fdu+d%2Fdv+0.5*log%282+*+pi+*+s%28u%2Cv%29%5E2%29+%2B+0.5+*+%28%28y%28u%2Cv%29+-+m%29%2Fs%28u%2Cv%29%29%5E2 - * r = (m - y) - * d/du(d/(dv)(0.5 log(2 π s^2) + 0.5 ((y - m)/s)^2)) = - * (-s_du*y_dv*r + 2*s_dv*y_du*r - s_du_dv*r^2 - - * 222222222222 2222222222222 *********** + * https://www.wolframalpha.com/input/?i=d%2Fdu+d%2Fdv+log%28s%28u%2Cv%29%29+%2B+0.5+*+%28r%28u%2Cv%29%2Fs%28u%2Cv%29%29%5E2 + * r = (y - m) + * r_du = y_du + * d/du(d/(dv)(log(s) + 0.5 (r/s)^2)) = + * -(2*y_du*s_dv)*r/s^3 - (2*y_dv*s_du)*r/s^3 + y_du_dv*r/s^2 + * 22222222222222222222 2222222222222222222 ############# + * + * + (y_dv*y_du)/s^2 + (3*s_dv*s_du)*r^2/s^4 - s_du_dv*r^2/s^3 + * 111111111111111 333333333333333333333 *************** * - * s*y_du_dv*r + s_du_dv*s^2 + 2*s_dv*s_du*s + s*y_dv*y_du)/s^3 - - * ########### +++++++++++ ------------- 11111111111 + * - (s_dv*s_du)/s^2 + (s_du_dv)/s + * +++++++++++ * - * (3*s_du*(-s_dv*r^2 - s*y_dv*r + s_dv*s^2))/s^4 - * 333333333 22222222 -------- * * we compute this using fsres: * sres_u * sres_v = (y_du*s - s_du * r) * (y_dv*s - s_dv * r) / s^4 @@ -824,15 +858,35 @@ void ReturnData::fFIM(int it, Model &model, const ExpData &edata) { * * r should be on the same order as s. We keep 1/s^2 and drop 1/s terms. * drop: - * ********: r^2/s^3 term - * ########: r/s^2 term + * ********: r^2/s^3 term, typically zero anyways + * ########: r/s^2 term, requires second order sensitivities * ++++++++: 1/s term, typically zero anyways * * keep: - * ---------: accounts for .5(2*pi*sigma^2) - * 123123123: accounted for by sres*sres, but - * -3*(s_dv*y_du + s_du*y_dv)*r/s^3 is missing from 2222 and - * -2*s_du*s_dv*r^2/s^4 is missing from 3333 + * 123123123: accounted for by sres*sres, + * but + * - (s_dv*s_du)/s^2 is unaccounted for and + * - (s_dv*y_du + s_du*y_dv)*r/s^3 is missing from 2222 and + * + 2*(s_du*s_dv)*r^2/s^4 is missing from 3333 + * + * s_dv*y_du and s_du*y_dv are usually zero since we do not have parameters + * that affect both observables and sigmas. Accordingly, it is hard to know + * emprically whether these terms are important or not. + * + * This leaves us with + * + (s_du*s_dv)(2*r^2-s^2)/s^4 + * which may be problematic, since this expression does not factorise and + * may thus introduce directions of negative curvature. + * + * For the least squares trick, where error residuals + * er = sqrt(log(s) + c), with sensitivity er_du = s_du/(2*s*er). This + * would yield terms (s_du*s_dv)*(s^2/(4*er^2))/s^4. + * These terms are guaranteed to yield positive curvature, but go to zero + * in the limit c -> Infty. + * + * Empirically, simply taking this limit and dropping all missing terms, + * works substantially better. This was evaluated using the fides optimizer + * on the Boehm2014 Benchmark example. */ auto observedData = edata.getObservedDataPtr(it); @@ -843,16 +897,17 @@ void ReturnData::fFIM(int it, Model &model, const ExpData &edata) { auto y = y_it.at(iy); auto m = observedData[iy]; auto s = sigmay_it.at(iy); + // auto r = amici::fres(y, m, s); for (int ip = 0; ip < nplist; ++ip) { auto dy_i = sy_it.at(iy + ny * ip); auto ds_i = ssigmay_it.at(iy + ny * ip); + auto sr_i = amici::fsres(y, dy_i, m, s, ds_i); for (int jp = 0; jp < nplist; ++jp) { auto dy_j = sy_it.at(iy + ny * jp); auto ds_j = ssigmay_it.at(iy + ny * jp); - FIM.at(ip + nplist * jp) += - amici::fsres(y, dy_i, m, s, ds_i) * - amici::fsres(y, dy_j, m, s, ds_j) - - ds_i * ds_j / pow(s, 2.0); + auto sr_j = amici::fsres(y, dy_j, m, s, ds_j); + FIM.at(ip + nplist * jp) += sr_i*sr_j; + /*+ ds_i*ds_j*(2*pow(r/pow(s,2.0), 2.0) - 1/pow(s,2.0));*/ } } } diff --git a/deps/AMICI/src/returndata_matlab.cpp b/deps/AMICI/src/returndata_matlab.cpp index 58fe9cf68..0a1d79961 100644 --- a/deps/AMICI/src/returndata_matlab.cpp +++ b/deps/AMICI/src/returndata_matlab.cpp @@ -46,7 +46,7 @@ mxArray *initMatlabReturnFields(ReturnData const *rdata) { writeMatlabField0(matlabSolutionStruct, "status", rdata->status); - writeMatlabField1(matlabSolutionStruct, "t", rdata->ts, rdata->nt); + writeMatlabField1(matlabSolutionStruct, "t", gsl::make_span(rdata->ts), rdata->nt); writeMatlabField0(matlabSolutionStruct, "llh", rdata->llh); writeMatlabField0(matlabSolutionStruct, "chi2", rdata->chi2); @@ -64,7 +64,7 @@ mxArray *initMatlabReturnFields(ReturnData const *rdata) { writeMatlabField2(matlabSolutionStruct, "sigmay", rdata->sigmay, rdata->nt, rdata->ny, perm1); } if (rdata->sensi >= SensitivityOrder::first) { - writeMatlabField1(matlabSolutionStruct, "sllh", rdata->sllh, rdata->nplist); + writeMatlabField1(matlabSolutionStruct, "sllh", gsl::make_span(rdata->sllh), rdata->nplist); writeMatlabField2(matlabSolutionStruct, "sx0", rdata->sx0, rdata->nplist, rdata->nx, perm0); if (rdata->sensi_meth == SensitivityMethod::forward) { @@ -141,18 +141,33 @@ mxArray *initMatlabDiagnosisFields(ReturnData const *rdata) { if (!std::isinf(rdata->ts[it])) finite_nt++; - writeMatlabField1(matlabDiagnosisStruct, "numsteps", rdata->numsteps, finite_nt); - writeMatlabField1(matlabDiagnosisStruct, "numrhsevals", rdata->numrhsevals, finite_nt); - writeMatlabField1(matlabDiagnosisStruct, "numerrtestfails", rdata->numerrtestfails, finite_nt); - writeMatlabField1(matlabDiagnosisStruct, "numnonlinsolvconvfails", rdata->numnonlinsolvconvfails, finite_nt); - writeMatlabField1(matlabDiagnosisStruct, "order", rdata->order, finite_nt); + writeMatlabField1( + matlabDiagnosisStruct, "numsteps", + gsl::make_span(rdata->numsteps).subspan(0, finite_nt), + finite_nt); + writeMatlabField1( + matlabDiagnosisStruct, "numrhsevals", + gsl::make_span(rdata->numrhsevals).subspan(0, finite_nt), + finite_nt); + writeMatlabField1( + matlabDiagnosisStruct, "numerrtestfails", + gsl::make_span(rdata->numerrtestfails).subspan(0, finite_nt), + finite_nt); + writeMatlabField1( + matlabDiagnosisStruct, "numnonlinsolvconvfails", + gsl::make_span(rdata->numnonlinsolvconvfails).subspan(0, finite_nt), + finite_nt); + writeMatlabField1( + matlabDiagnosisStruct, "order", + gsl::make_span(rdata->order).subspan(0, finite_nt), + finite_nt); if (rdata->nx > 0) { - writeMatlabField1(matlabDiagnosisStruct, "xdot", rdata->xdot, rdata->nx_solver); + writeMatlabField1(matlabDiagnosisStruct, "xdot", gsl::make_span(rdata->xdot), rdata->nx_solver); writeMatlabField2(matlabDiagnosisStruct, "J", rdata->J, rdata->nx_solver, rdata->nx_solver, perm1); - writeMatlabField1(matlabDiagnosisStruct, "preeq_status", rdata->preeq_status, 3); - writeMatlabField1(matlabDiagnosisStruct, "preeq_numsteps", rdata->preeq_numsteps, 3); + writeMatlabField1(matlabDiagnosisStruct, "preeq_status", gsl::make_span(rdata->preeq_status), 3); + writeMatlabField1(matlabDiagnosisStruct, "preeq_numsteps", gsl::make_span(rdata->preeq_numsteps), 3); writeMatlabField2(matlabDiagnosisStruct, "preeq_numlinsteps", rdata->preeq_numlinsteps, rdata->preeq_numlinsteps.size() > 0 @@ -163,8 +178,8 @@ mxArray *initMatlabDiagnosisFields(ReturnData const *rdata) { writeMatlabField0(matlabDiagnosisStruct, "preeq_t", rdata->preeq_t); writeMatlabField0(matlabDiagnosisStruct, "preeq_wrms", rdata->preeq_wrms); - writeMatlabField1(matlabDiagnosisStruct, "posteq_status", rdata->posteq_status, 3); - writeMatlabField1(matlabDiagnosisStruct, "posteq_numsteps", rdata->posteq_numsteps, 3); + writeMatlabField1(matlabDiagnosisStruct, "posteq_status", gsl::make_span(rdata->posteq_status), 3); + writeMatlabField1(matlabDiagnosisStruct, "posteq_numsteps", gsl::make_span(rdata->posteq_numsteps), 3); writeMatlabField2(matlabDiagnosisStruct, "posteq_numlinsteps", rdata->posteq_numlinsteps, rdata->posteq_numlinsteps.size() > 0 @@ -177,10 +192,23 @@ mxArray *initMatlabDiagnosisFields(ReturnData const *rdata) { } if (rdata->sensi >= SensitivityOrder::first) { if (rdata->sensi_meth == SensitivityMethod::adjoint) { - writeMatlabField1(matlabDiagnosisStruct, "numstepsB", rdata->numstepsB, finite_nt); - writeMatlabField1(matlabDiagnosisStruct, "numrhsevalsB", rdata->numrhsevalsB, finite_nt); - writeMatlabField1(matlabDiagnosisStruct, "numerrtestfailsB", rdata->numerrtestfailsB, finite_nt); - writeMatlabField1(matlabDiagnosisStruct, "numnonlinsolvconvfailsB", rdata->numnonlinsolvconvfailsB, finite_nt); + writeMatlabField1( + matlabDiagnosisStruct, "numstepsB", + gsl::make_span(rdata->numstepsB).subspan(0, finite_nt), + finite_nt); + writeMatlabField1( + matlabDiagnosisStruct, "numrhsevalsB", + gsl::make_span(rdata->numrhsevalsB).subspan(0, finite_nt), + finite_nt); + writeMatlabField1( + matlabDiagnosisStruct, "numerrtestfailsB", + gsl::make_span(rdata->numerrtestfailsB).subspan(0, finite_nt), + finite_nt); + writeMatlabField1( + matlabDiagnosisStruct, "numnonlinsolvconvfailsB", + gsl::make_span(rdata->numnonlinsolvconvfailsB + ).subspan(0, finite_nt), + finite_nt); } } @@ -201,16 +229,19 @@ void writeMatlabField0(mxArray *matlabStruct, const char *fieldName, template void writeMatlabField1(mxArray *matlabStruct, const char *fieldName, - std::vector const& fieldData, int dim0) { + gsl::span const& fieldData, int dim0) { if(fieldData.size() != dim0) - throw AmiException("Dimension mismatch when writing rdata->%s to matlab results",fieldName); + throw AmiException("Dimension mismatch when writing rdata->%s to " + "matlab results (expected %d, got %d)", + fieldName, dim0, static_cast(fieldData.size())); std::vector dim = {(mwSize)(dim0), (mwSize)(1)}; double *array = initAndAttachArray(matlabStruct, fieldName, dim); + auto data_ptr = fieldData.data(); for(int i = 0; i < dim0; i++) - array[i] = static_cast(fieldData[i]); + array[i] = static_cast(data_ptr[i]); } template diff --git a/deps/AMICI/src/steadystateproblem.cpp b/deps/AMICI/src/steadystateproblem.cpp index f2f4c91a9..6d75c469f 100644 --- a/deps/AMICI/src/steadystateproblem.cpp +++ b/deps/AMICI/src/steadystateproblem.cpp @@ -374,6 +374,10 @@ bool SteadystateProblem::getSensitivityFlag(const Model *model, steady_state_status_[1] == SteadyStateStatus::success && model->getSteadyStateSensitivityMode() == SteadyStateSensitivityMode::simulationFSA; + bool simulationStartedInSteadystate = + steady_state_status_[0] == SteadyStateStatus::success && + numsteps_[0] == 0; + /* Do we need forward sensis for postequilibration? */ bool needForwardSensisPosteq = !preequilibration && !forwardSensisAlreadyComputed && @@ -388,7 +392,8 @@ bool SteadystateProblem::getSensitivityFlag(const Model *model, /* Do we need to do the linear system solve to get forward sensitivities? */ bool needForwardSensisNewton = - needForwardSensisPreeq || needForwardSensisPosteq; + (needForwardSensisPreeq || needForwardSensisPosteq) && + !simulationStartedInSteadystate; /* When we're creating a new solver object */ bool needForwardSensiAtCreation = needForwardSensisPreeq && @@ -400,7 +405,9 @@ bool SteadystateProblem::getSensitivityFlag(const Model *model, return needForwardSensisNewton; case SteadyStateContext::sensiStorage: - return needForwardSensisNewton || forwardSensisAlreadyComputed; + return needForwardSensisNewton || + forwardSensisAlreadyComputed || + simulationStartedInSteadystate; case SteadyStateContext::solverCreation: return needForwardSensiAtCreation; diff --git a/deps/AMICI/src/sundials_matrix_wrapper.cpp b/deps/AMICI/src/sundials_matrix_wrapper.cpp index 21d690e73..4e080958c 100644 --- a/deps/AMICI/src/sundials_matrix_wrapper.cpp +++ b/deps/AMICI/src/sundials_matrix_wrapper.cpp @@ -629,14 +629,15 @@ void SUNMatrixWrapper::transpose(SUNMatrixWrapper &C, const realtype alpha, if (!matrix_ || !C.matrix_) return; - if (!((C.matrix_id() == SUNMATRIX_SPARSE && C.sparsetype() == CSC_MAT) - || C.matrix_id() == SUNMATRIX_DENSE)) + auto C_matrix_id = C.matrix_id(); + if (!((C_matrix_id == SUNMATRIX_SPARSE && C.sparsetype() == CSC_MAT) + || C_matrix_id == SUNMATRIX_DENSE)) throw std::domain_error("Not Implemented."); check_csc(this); assert(rows() == C.rows()); assert(columns() == C.columns()); - if (C.matrix_id() == SUNMATRIX_SPARSE) { + if (C_matrix_id == SUNMATRIX_SPARSE) { if (!C.capacity() && num_nonzeros()) C.reallocate(num_nonzeros()); assert(C.capacity() >= num_nonzeros()); @@ -651,40 +652,38 @@ void SUNMatrixWrapper::transpose(SUNMatrixWrapper &C, const realtype alpha, // see https://github.com/DrTimothyAldenDavis/SuiteSparse/blob/master/CSparse/Source/cs_transpose.c - sunindextype aidx; - sunindextype cidx; - sunindextype acol; - std::vector w; - - sunindextype ccol; - sunindextype crow; - sunindextype widx; - - if (C.matrix_id()== SUNMATRIX_SPARSE) { + auto nrows = rows(); + if (C_matrix_id == SUNMATRIX_SPARSE) { w = std::vector(columns()); - for (acol = 0; acol < rows(); acol++) /* row counts */ - for (aidx = get_indexptr(acol); - aidx < get_indexptr(acol+1); aidx++) { - widx = (acol/blocksize)*blocksize + get_indexval(aidx) % blocksize; - w.at(widx)++; - assert(w[widx] <= rows()); + for (sunindextype acol = 0; acol < nrows; acol++) { /* row counts */ + auto next_indexptr = get_indexptr(acol+1); + for (sunindextype aidx = get_indexptr(acol); + aidx < next_indexptr; aidx++) { + sunindextype widx = (acol/blocksize)*blocksize + get_indexval(aidx) % blocksize; + assert(widx >= 0 && widx < (sunindextype)w.size()); + w[widx]++; + assert(w[widx] <= nrows); } + } /* row pointers */ cumsum(gsl::make_span(C.indexptrs_, C.columns()+1), w); } - for (acol = 0; acol < rows(); acol++) + for (sunindextype acol = 0; acol < nrows; acol++) { - for (aidx = get_indexptr(acol); aidx < get_indexptr(acol+1); aidx++) + auto next_indexptr = get_indexptr(acol+1); + + for (sunindextype aidx = get_indexptr(acol); aidx < next_indexptr; aidx++) { - ccol = (acol/blocksize)*blocksize + get_indexval(aidx) % blocksize; - crow = (get_indexval(aidx)/blocksize)*blocksize + acol % blocksize; - assert(crow < rows()); + sunindextype ccol = (acol/blocksize)*blocksize + get_indexval(aidx) % blocksize; + sunindextype crow = (get_indexval(aidx)/blocksize)*blocksize + acol % blocksize; + assert(crow < nrows); assert(ccol < columns()); - if (C.matrix_id() == SUNMATRIX_SPARSE) { + if (C_matrix_id == SUNMATRIX_SPARSE) { assert(aidx < capacity()); - cidx = w.at(ccol)++; + assert(ccol >= 0 && ccol < (sunindextype)w.size()); + sunindextype cidx = w[ccol]++; C.set_indexval(cidx, crow); /* place A(i,j) as entry C(j,i) */ C.set_data(cidx, alpha * get_data(aidx)); } else { diff --git a/deps/AMICI/tests/benchmark-models/benchmark_models.yaml b/deps/AMICI/tests/benchmark-models/benchmark_models.yaml index ed89cb252..a84afe34f 100644 --- a/deps/AMICI/tests/benchmark-models/benchmark_models.yaml +++ b/deps/AMICI/tests/benchmark-models/benchmark_models.yaml @@ -26,7 +26,7 @@ Chen_MSB2009: note: benchmark collection reference ignores factor 1/2 Crauste_CellSystems2017: - llh: 190.96398465243203 + llh: -190.96521897435176 note: benchmark collection only reports chi2 value, but llh value can be derived Elowitz_Nature2000: diff --git a/deps/AMICI/tests/benchmark-models/test_benchmark_collection.sh b/deps/AMICI/tests/benchmark-models/test_benchmark_collection.sh index 6f14a8dd6..ea3dbbfbe 100755 --- a/deps/AMICI/tests/benchmark-models/test_benchmark_collection.sh +++ b/deps/AMICI/tests/benchmark-models/test_benchmark_collection.sh @@ -14,7 +14,8 @@ Schwen_PONE2014 Fujita_SciSignal2010 Sneyd_PNAS2002 Zheng_PNAS2012 -Weber_BMC2015" +Weber_BMC2015 +Crauste_CellSystems2017" # # Not matching reference for unclear reasons @@ -30,7 +31,6 @@ Weber_BMC2015" # Alkan_SciSignal2018 # Beer_MolBioSystems2014 # Blasi_CellSystems2016 -# Crauste_CellSystems2017 # Hass_PONE2017 # Korkut_eLIFE2015 # Perelson_Science1996 diff --git a/deps/AMICI/tests/conftest.py b/deps/AMICI/tests/conftest.py index e6e186535..89eb1342d 100644 --- a/deps/AMICI/tests/conftest.py +++ b/deps/AMICI/tests/conftest.py @@ -75,13 +75,21 @@ def pytest_sessionfinish(session, exitstatus): def write_passed_tags(passed_ids, out=sys.stdout): """Write tags of passed SBML semantic test cases""" - passed_tags = set() + passed_component_tags = set() + passed_test_tags = set() + from testSBMLSuite import get_tags_for_test for test_id in passed_ids: - passed_tags |= get_tags_for_test(test_id) - - out.write("At least one test with the following tags has passed:\n") - out.write(' ' + '\n '.join(passed_tags)) + cur_component_tags, cur_test_tags = get_tags_for_test(test_id) + passed_component_tags |= cur_component_tags + passed_test_tags |= cur_test_tags + + out.write("\nAt least one test with the following component tags has " + "passed:\n") + out.write(' ' + '\n '.join(sorted(passed_component_tags))) + out.write("\n\nAt least one test with the following test tags has " + "passed:\n") + out.write(' ' + '\n '.join(sorted(passed_test_tags))) def pytest_runtest_logreport(report: "TestReport") -> None: diff --git a/deps/AMICI/tests/cpputest/expectedResults.h5 b/deps/AMICI/tests/cpputest/expectedResults.h5 index 8d993ab2c8fb1c2af47ccc80b8213315cadd9e6a..3525c1b4b1f29ba0c7eef5de599bb5e865918c73 100644 GIT binary patch delta 40073 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 tx@%o6?vk9mSwBo&Khi7ivQPRkJ!{p1ro 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 diff --git a/deps/AMICI/tests/cpputest/testfunctions.cpp b/deps/AMICI/tests/cpputest/testfunctions.cpp index 3a997392e..b24fdd1be 100644 --- a/deps/AMICI/tests/cpputest/testfunctions.cpp +++ b/deps/AMICI/tests/cpputest/testfunctions.cpp @@ -38,7 +38,7 @@ void simulateVerifyWrite(const std::string& path) void simulateVerifyWrite(const std::string &path, double atol, double rtol) { - simulateVerifyWrite(NEW_OPTION_FILE, HDFFILE, HDFFILEWRITE, std::move(path), atol, rtol); + simulateVerifyWrite(NEW_OPTION_FILE, HDFFILE, HDFFILEWRITE, path, atol, rtol); } void simulateWithDefaultOptions() { diff --git a/deps/AMICI/tests/cpputest/unittests/tests1.cpp b/deps/AMICI/tests/cpputest/unittests/tests1.cpp index a0b487c17..869c6dc9f 100644 --- a/deps/AMICI/tests/cpputest/unittests/tests1.cpp +++ b/deps/AMICI/tests/cpputest/unittests/tests1.cpp @@ -20,7 +20,7 @@ namespace generic_model { std::unique_ptr getModel() { - return std::unique_ptr(new amici::Model_Test()); + return std::make_unique(); } } // namespace generic_model @@ -82,10 +82,6 @@ TEST_GROUP(model) z2event); std::vector unscaled{ NAN }; - - void setup() {} - - void teardown() {} }; TEST(model, testScalingLin) @@ -178,13 +174,7 @@ TEST(model, reinitializeFixedParameterInitialStates) AmiVectorArray sx(model.np(), nx); } -TEST_GROUP(symbolicFunctions){ void setup(){ - -} - - void teardown(){ - - } }; +TEST_GROUP(symbolicFunctions){}; TEST(symbolicFunctions, testSign) { @@ -240,13 +230,7 @@ TEST(symbolicFunctions, testpos_pow) CHECK_EQUAL(pow(0.1, 3), amici::pos_pow(0.1, 3)); } -TEST_GROUP(amiciSolver){ void setup(){ - -} - - void teardown(){ - - } }; +TEST_GROUP(amiciSolver){ }; TEST(amiciSolver, testEquality) { @@ -270,13 +254,7 @@ TEST(amiciSolver, testClone) CHECK_FALSE(*i2 == *c2); } -TEST_GROUP(amiciSolverIdas){ void setup(){ - -} - - void teardown(){ - - } }; +TEST_GROUP(amiciSolverIdas){}; TEST(amiciSolverIdas, testConstructionDestruction) { @@ -323,7 +301,7 @@ TEST_GROUP(edata) SecondOrderMode::none, std::vector(), std::vector()); - void setup() + void setup() override { model->setTimepoints(timepoints); model->setNMaxEvent(nmaxevent); @@ -331,7 +309,7 @@ TEST_GROUP(edata) testModel.setNMaxEvent(nmaxevent); } - void teardown() {} + void teardown() override {} }; TEST(edata, testConstructors1) @@ -792,10 +770,6 @@ TEST_GROUP(amivector) std::vector vec1{ 1, 2, 4, 3 }; std::vector vec2{ 4, 1, 2, 3 }; std::vector vec3{ 4, 4, 2, 1 }; - - void setup() {} - - void teardown() {} }; TEST(amivector, vector) @@ -836,7 +810,7 @@ TEST_GROUP(sunmatrixwrapper) // result std::vector d{1.3753, 1.5084, 1.1655}; - void setup() { + void setup() override { A.set_data(0, 0, 0.69); A.set_data(1, 0, 0.32); A.set_data(2, 0, 0.95); @@ -865,8 +839,6 @@ TEST_GROUP(sunmatrixwrapper) B.set_indexval(6, 3); } - - void teardown() {} }; TEST(sunmatrixwrapper, sparse_multiply) diff --git a/deps/AMICI/tests/cpputest/unittests/testsSerialization.cpp b/deps/AMICI/tests/cpputest/unittests/testsSerialization.cpp index 2c7623880..520f3b34e 100644 --- a/deps/AMICI/tests/cpputest/unittests/testsSerialization.cpp +++ b/deps/AMICI/tests/cpputest/unittests/testsSerialization.cpp @@ -96,7 +96,7 @@ checkReturnDataEqual(amici::ReturnData const& r, amici::ReturnData const& s) // clang-format off TEST_GROUP(dataSerialization){ amici::CVodeSolver solver; - void setup() { + void setup() override { // set non-default values for all members solver.setAbsoluteTolerance(1e-4); solver.setRelativeTolerance(1e-5); @@ -113,16 +113,13 @@ TEST_GROUP(dataSerialization){ solver.setPreequilibration(true); solver.setStateOrdering(static_cast(amici::SUNLinSolKLU::StateOrdering::COLAMD)); solver.setInterpolationType(amici::InterpolationType::polynomial); - solver.setStabilityLimitFlag(0); + solver.setStabilityLimitFlag(false); solver.setLinearSolver(amici::LinearSolver::dense); solver.setLinearMultistepMethod(amici::LinearMultistepMethod::adams); solver.setNonlinearSolverIteration(amici::NonlinearSolverIteration::newton); solver.setInternalSensitivityMethod(amici::InternalSensitivityMethod::staggered); solver.setReturnDataReportingMode(amici::RDataReporting::likelihood); } - - void teardown() { - } }; // clang-format on diff --git a/deps/AMICI/tests/generateTestConfig/example_neuron.py b/deps/AMICI/tests/generateTestConfig/example_neuron.py index 8c730ff56..97cc6c698 100755 --- a/deps/AMICI/tests/generateTestConfig/example_neuron.py +++ b/deps/AMICI/tests/generateTestConfig/example_neuron.py @@ -21,7 +21,7 @@ def __init__(self): self.modelOptions['pscale'] = 2 self.solverOptions['atol'] = 1e-16 - self.solverOptions['maxsteps'] = 1e45 + self.solverOptions['maxsteps'] = 1e5 self.solverOptions['nmaxevent'] = 22 self.solverOptions['rtol'] = 1e-12 self.solverOptions['sens_ind'] = [] diff --git a/deps/AMICI/tests/testSBMLSuite.py b/deps/AMICI/tests/testSBMLSuite.py index d0c72b19f..9a4c9f648 100755 --- a/deps/AMICI/tests/testSBMLSuite.py +++ b/deps/AMICI/tests/testSBMLSuite.py @@ -19,6 +19,7 @@ import re import shutil import sys +from typing import Tuple, Set import amici import libsbml as sbml @@ -79,6 +80,10 @@ def test_sbml_testsuite_case(test_number, result_path): # simulate model rdata = amici.runAmiciSimulation(model, solver) + if rdata['status'] != amici.AMICI_SUCCESS and test_id in [ + '00748', '00374', '00369' + ]: + raise amici.sbml_import.SBMLException('Simulation Failed') # verify simulated = verify_results(settings, rdata, results, wrapper, @@ -259,11 +264,11 @@ def compile_model(path, test_id, model_dir): os.makedirs(model_dir) model_name = 'SBMLTest' + test_id - wrapper.sbml2amici(model_name, output_dir=model_dir) + wrapper.sbml2amici(model_name, output_dir=model_dir, + generate_sensitivity_code=False) # settings - sys.path.insert(0, model_dir) - model_module = importlib.import_module(model_name) + model_module = amici.import_model_module(model_name, model_dir) model = model_module.getModel() solver = model.getSolver() @@ -306,16 +311,28 @@ def format_test_id(test_id) -> str: return test_str -def get_tags_for_test(test_id): - """Get sbml test suite tags for the given test ID""" +def get_tags_for_test(test_id) -> Tuple[Set[str], Set[str]]: + """Get sbml test suite tags for the given test ID + + Returns: + Tuple of set of strings for componentTags and testTags + """ current_test_path = os.path.join(TEST_PATH, test_id) info_file = os.path.join(current_test_path, f'{test_id}-model.m') with open(info_file) as f: + component_tags = set() + test_tags = set() for line in f: if line.startswith('testTags:'): - res = set(re.split(r'[ ,:]', line[len('testTags:'):].strip())) - res.discard('') - return res - print(f"No testTags found for test case {test_id}.") - return set() + test_tags = set( + re.split(r'[ ,:]', line[len('testTags:'):].strip())) + test_tags.discard('') + if line.startswith('componentTags:'): + component_tags = set( + re.split(r'[ ,:]', line[len('componentTags:'):].strip())) + component_tags.discard('') + if test_tags and component_tags: + return component_tags, test_tags + print(f"No componentTags or testTags found for test case {test_id}.") + return component_tags, test_tags diff --git a/deps/AMICI/version.txt b/deps/AMICI/version.txt index 44ab23e43..a95c45d4f 100644 --- a/deps/AMICI/version.txt +++ b/deps/AMICI/version.txt @@ -1 +1 @@ -0.11.13 +0.11.14 diff --git a/python/parpe/hdf5_pe_input.py b/python/parpe/hdf5_pe_input.py index e85c85910..7ee7975cb 100644 --- a/python/parpe/hdf5_pe_input.py +++ b/python/parpe/hdf5_pe_input.py @@ -2,6 +2,7 @@ import argparse import logging import sys +from numbers import Number from typing import Any, Collection, Optional, Dict, Tuple import amici @@ -353,7 +354,7 @@ def _set_initial_concentration(condition_id, species_id, self.petab_problem.condition_df.loc[ condition_id, species_id]) - if isinstance(value, float): + if isinstance(value, Number): # numeric initial state par_map[init_par_id] = value scale_map[init_par_id] = ptc.LIN @@ -398,7 +399,7 @@ def _set_initial_concentration(condition_id, species_id, self.petab_problem.condition_df.loc[ preeq_cond_id, species_id]) - if isinstance(value, float): + if isinstance(value, Number): condition_map_sim[init_par_id] = value _set_initial_concentration( preeq_cond_id, species_id, init_par_id, @@ -409,7 +410,7 @@ def _set_initial_concentration(condition_id, species_id, self.petab_problem.condition_df.loc[ sim_cond_id, species_id]) - if not isinstance(value_sim, float) \ + if not isinstance(value_sim, Number) \ or not np.isnan(value_sim): # mark for reinitialization, # unless the value is nan @@ -630,7 +631,8 @@ def _generate_measurement_matrices(self): """ if petab.measurement_table_has_timepoint_specific_mappings( - self.petab_problem.measurement_df): + self.petab_problem.measurement_df, + allow_scalar_numeric_noise_parameters=True): raise RuntimeError("Timepoint-specific overrides are not yet " "supported.") @@ -688,7 +690,7 @@ def write_measurements(self): f' time {row[ptc.TIME]}\n' + str(cur_mes_df)) mes[time_idx, observable_idx] = float(row[ptc.MEASUREMENT]) sigma = to_float_if_float(row[ptc.NOISE_PARAMETERS]) - if isinstance(sigma, float): + if isinstance(sigma, Number): sd[time_idx, observable_idx] = sigma # write to file diff --git a/python/setup.py b/python/setup.py index c0fb03841..256f0173c 100644 --- a/python/setup.py +++ b/python/setup.py @@ -17,7 +17,7 @@ install_requires=['numpy>=1.18.1', 'termcolor>=1.1.0', 'colorama>=0.4.3', - 'petab>=0.1.14', + 'petab>=0.1.17', 'amici>=0.11.12', 'h5py>=3.0.0', 'python-libsbml>=5.17.0', diff --git a/tests/petab-test-suite/test_petab_test_suite.py b/tests/petab-test-suite/test_petab_test_suite.py index 453dfe48b..996ac04bf 100755 --- a/tests/petab-test-suite/test_petab_test_suite.py +++ b/tests/petab-test-suite/test_petab_test_suite.py @@ -75,6 +75,7 @@ def _test_case(case: Union[int, str]) -> None: # create amici model from PEtab cmd = ['amici_import_petab', '-y', yaml_file, '-o', amici_model_dir, '-n', model_name] + print(" ".join(cmd)) check_run(cmd) # must not exist when calling setup_amici_model.sh @@ -84,20 +85,23 @@ def _test_case(case: Union[int, str]) -> None: # set up for parPE cmd = [os.path.join(parpe_dir, 'misc', 'setup_amici_model.sh'), amici_model_dir, parpe_model_dir] + print(" ".join(cmd)) check_run(cmd) # create input hdf5 file cmd = ['parpe_petab_to_hdf5', '-y', yaml_file, '-d', amici_model_dir, '-n', model_name, '-o', hdf5_input] + print(" ".join(cmd)) check_run(cmd) # simulate model using nominal parameters cmd = [os.path.join(parpe_model_dir, 'build', f'simulateNominal_{model_name}'), hdf5_input, hdf5_output] + print(" ".join(cmd)) ret = check_run(cmd) - print(' '.join(cmd)) + # check output g = re.search(r'Likelihood: (\d+\.\d+)', ret.stdout).group(0) llh_actual = - float(g.split(' ')[1]) From 9d19c08c90db18973a5b1525d6a2f4dec98875d5 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 25 Mar 2021 10:40:17 +0100 Subject: [PATCH 03/21] CI: Update benchmark models tests / add new models (#332) * Cleanup benchmark model scripts * Additional models * require petab>=0.1.18 --- benchmark_collection/all.sh | 50 +++++++++-- benchmark_collection/import_and_run.sh | 111 +++++++++++++------------ misc/setup_amici_model.sh | 3 +- python/parpe/hdf5_pe_input.py | 3 +- python/setup.py | 2 +- 5 files changed, 104 insertions(+), 65 deletions(-) diff --git a/benchmark_collection/all.sh b/benchmark_collection/all.sh index 2dff9e286..d0737d046 100755 --- a/benchmark_collection/all.sh +++ b/benchmark_collection/all.sh @@ -1,28 +1,60 @@ #!/usr/bin/env bash # Import, build, and run benchmark models -set -e +set -eou pipefail +# Path to benchmark collection model directory [[ -n "${BENCHMARK_COLLECTION}" ]] && model_dir="${BENCHMARK_COLLECTION}" # all_models=$(ls -1d ${model_dir}/*/) - expected_to_work=" Boehm_JProteomeRes2014 Borghans_BiophysChem1997 +Crauste_CellSystems2017 Elowitz_Nature2000 +Fujita_SciSignal2010 +Schwen_PONE2014 Sneyd_PNAS2002 -Zheng_PNAS2012" -# Fujita_SciSignal2010 "Timepoint-specific parameter overrides currently unsupported." in PEtab parameter mapping -# Schwen_PONE2014 Chen_MSB2009 +Weber_BMC2015 +Zheng_PNAS2012 +" +# Timepoint-specific parameter overrides currently unsupported.: +# +# Chen_MSB2009 +# +# missing ref: +# +# Alkan_SciSignal2018 +# Blasi_CellSystems2016 +# Bruno_JExpBio2016 +# Giordano_Nature2020 +# Okuonghae_ChaosSolitonsFractals2020 +# Perelson_Science1996 +# Rahman_MBS2016 +# Raimundez_PCB2020 +# SalazarCavazos_MBoC2020 +# Zhao_QuantBiol2020 +# +# integration trouble: +# +# Beer_MolBioSystems2014 +# Bertozzi_PNAS2020 +# Borghans_BiophysChem1997 +# Isensee_JCB2018 +# +# Mismatch: +# Bachmann_MSB2011: Expected llh -478.459689232875, got nllh -418.409381 +# Brannmark_JBC2010 FAILED: Expected llh 283.778227541074, got nllh 141.889034 +# Lucarelli_CellSystems2018 +# Fiedler_BMC2016 FAILED: Expected llh -117.16780323362, got nllh 109391.496205 -for MODEL in $expected_to_work; do +for model_name in $expected_to_work; do printf '=%.0s' {1..20} - printf %s "${MODEL}" + printf %s "${model_name}" printf '=%.0s' {1..20} echo - echo ./import_and_run.sh "${model_dir}"/"${MODEL}" - ./import_and_run.sh "${model_dir}"/"${MODEL}" + echo ./import_and_run.sh "${model_dir}"/"${model_name}" + ./import_and_run.sh "${model_dir}"/"${model_name}" printf '=%.0s' {1..100} echo done diff --git a/benchmark_collection/import_and_run.sh b/benchmark_collection/import_and_run.sh index 6a8b13d08..fecc2fcfd 100755 --- a/benchmark_collection/import_and_run.sh +++ b/benchmark_collection/import_and_run.sh @@ -1,89 +1,94 @@ #!/usr/bin/env bash # Import, build, and run model from the benchmark collection -set -e +set -eou pipefail get_abs_filename() { # $1 : relative filename echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" } +check_output() { + # Check output + local nllh=$(grep Likelihood "${output_file}" | tr -cd '[:print:]' | sed -r 's/.*Likelihood: (.*)\[.*/\1/') + rm "${output_file}" + local reference_file="${amici_root}/tests/benchmark-models/benchmark_models.yaml" + local ref=$(shyaml get-value "${model_name}".llh <"$reference_file") + local abs="define abs(i) {\\nif (i < 0) return (-i) \nreturn (i)\n}\n" + + # Do we match within tolerance? + # LLH VS nllh! + if (($(echo -e "${abs}\nabs($nllh + $ref) < 0.001 * abs($ref)" | bc))); then + echo "OKAY: Expected llh $ref, got nllh $nllh" + else + echo "FAILED: Expected llh $ref, got nllh $nllh" + exit 1 + fi +} + if [[ $# -lt 1 ]] || [[ $# -gt 1 ]]; then - echo "Import, build, and run model from the benchmark collection" - echo "USAGE: $(basename "$0") /path/to/model/dir" - exit 1; + echo "Import, build, and run model from the benchmark collection" + echo "USAGE: $(basename "$0") /path/to/model/dir" + exit 1 fi -PETAB_MODEL_DIR=$1 -SCRIPT_PATH=$(get_abs_filename "$(dirname "$BASH_SOURCE")") -PARPE_DIR=${SCRIPT_PATH}/.. -MODEL_NAME=$(basename "${PETAB_MODEL_DIR}") -AMICI_MODEL_DIR=${SCRIPT_PATH}/${MODEL_NAME} -petab_yaml=${MODEL_NAME}.yaml -if [[ -z "${AMICI_ROOT}" ]] - then AMICI_ROOT=${PARPE_DIR}/deps/AMICI/ -fi +petab_model_dir=$1 +script_path=$(get_abs_filename "$(dirname "$BASH_SOURCE")") +parpe_dir=${script_path}/.. +model_name=$(basename "${petab_model_dir}") +amici_model_dir=${script_path}/${model_name} +petab_yaml=${model_name}.yaml +output_file=tmp.out +hdf5_infile="parpe_${model_name}/${model_name}.h5" +estimate_exe="parpe_${model_name}/build/estimate_${model_name}" +amici_root="${AMICI_ROOT:-${parpe_dir}/deps/AMICI/}" -cd "${PETAB_MODEL_DIR}" +cd "${petab_model_dir}" echo "Running petablint on ${petab_yaml}..." -petablint -v -y "${MODEL_NAME}".yaml +petablint -v -y "${model_name}".yaml # import AMICI model -if [[ ! -d ${AMICI_MODEL_DIR} ]]; then - echo "Importing model..." - CMD="amici_import_petab.py --verbose -y ${MODEL_NAME}.yaml -o ${AMICI_MODEL_DIR}" - echo "${CMD}" - ${CMD} +if [[ ! -d ${amici_model_dir} ]]; then + echo "Importing model..." + cmd="amici_import_petab.py --verbose -y ${model_name}.yaml -n ${model_name} -o ${amici_model_dir}" + echo "${cmd}" + ${cmd} fi -cd "${SCRIPT_PATH}" +cd "${script_path}" # parPE build -if [[ ! -d parpe_${MODEL_NAME} ]]; then - echo "Setting up parPE..." - "${PARPE_DIR}"/misc/setup_amici_model.sh "${AMICI_MODEL_DIR}" parpe_"${MODEL_NAME}" +if [[ ! -d parpe_${model_name} ]]; then + echo "Setting up parPE..." + "${parpe_dir}"/misc/setup_amici_model.sh "${amici_model_dir}" parpe_"${model_name}" else - (cd parpe_"${MODEL_NAME}"/build && cmake -DAmici_DIR="${AMICI_ROOT}"/build .. && make) + (cd parpe_"${model_name}"/build && cmake -DAmici_DIR="${amici_root}"/build .. && make) fi # generate data file echo "Importing data..." -CMD="parpe_petab_to_hdf5 \ - -o parpe_${MODEL_NAME}/${MODEL_NAME}.h5 \ - -d ${AMICI_MODEL_DIR} \ - -y ${PETAB_MODEL_DIR}/${MODEL_NAME}.yaml \ - -n ${MODEL_NAME}" -echo "$CMD" -$CMD +cmd="parpe_petab_to_hdf5 \ + -o ${hdf5_infile} \ + -d ${amici_model_dir} \ + -y ${petab_model_dir}/${model_name}.yaml \ + -n ${model_name}" +echo "$cmd" +$cmd echo "" echo "Start parameter estimation by:" -echo "parpe_${MODEL_NAME}/build/estimate_${MODEL_NAME} -o parpe_${MODEL_NAME}_results/ parpe_${MODEL_NAME}/${MODEL_NAME}.h5" +echo "${estimate_exe} -o parpe_${model_name}_results/ ${hdf5_infile}" echo "" echo "Running simulation with nominal parameters..." -cmd="parpe_${MODEL_NAME}/build/simulateNominal_${MODEL_NAME} parpe_${MODEL_NAME}/${MODEL_NAME}.h5" +cmd="parpe_${model_name}/build/simulateNominal_${model_name} ${hdf5_infile}" echo "$cmd" -$cmd |& tee tmp.out - -# Check output -NLLH=$(grep Likelihood tmp.out | tr -cd '[:print:]' | sed -r 's/.*Likelihood: (.*)\[.*/\1/') -rm tmp.out -REFERENCE_FILE="${AMICI_ROOT}/tests/benchmark-models/benchmark_models.yaml" -REF=$(shyaml get-value "${MODEL_NAME}".llh < "$REFERENCE_FILE") -ABS="define abs(i) {\\nif (i < 0) return (-i) \nreturn (i)\n}\n" - -# Do we match within tolerance? -# LLH VS NLLH! -if (( $(echo -e "${ABS}\nabs($NLLH + $REF) < 0.001 * abs($REF)" | bc) )); then - echo "OKAY: Expected llh $REF, got nllh $NLLH" -else - echo "FAILED: Expected llh $REF, got nllh $NLLH" - exit 1 -fi +$cmd |& tee "${output_file}" + +check_output echo "Checking gradient..." -echo PARPE_NO_DEBUG=1 "parpe_${MODEL_NAME}/build/estimate_${MODEL_NAME}" -t gradient_check -o "parpe_${MODEL_NAME}_results/gradient_check" "parpe_${MODEL_NAME}/${MODEL_NAME}.h5" -PARPE_NO_DEBUG=1 "parpe_${MODEL_NAME}/build/estimate_${MODEL_NAME}" -t gradient_check -o "parpe_${MODEL_NAME}_results/gradient_check" "parpe_${MODEL_NAME}/${MODEL_NAME}.h5" +echo PARPE_NO_DEBUG=1 "${estimate_exe}" -t gradient_check -o "parpe_${model_name}_results/gradient_check" "${hdf5_infile}" +PARPE_NO_DEBUG=1 "${estimate_exe}" -t gradient_check -o "parpe_${model_name}_results/gradient_check" "${hdf5_infile}" diff --git a/misc/setup_amici_model.sh b/misc/setup_amici_model.sh index 1051db6bb..11301d68e 100755 --- a/misc/setup_amici_model.sh +++ b/misc/setup_amici_model.sh @@ -15,6 +15,7 @@ model_dir="$1" output_dir="$2" template_dir="${script_path}/../templates" model_name=$(basename "${model_dir}") +make_opts="${MAKE_OPTS:-}" if [[ ! -d "${model_dir}" ]]; then echo "ERROR: Model directory ${model_dir} does not exist." @@ -47,4 +48,4 @@ cmake -S "${output_dir}" \ -DParPE_DIR="${script_path}/../build" echo "Building ..." -cmake --build "${output_dir}/build" -- VERBOSE=1 +cmake --build "${output_dir}/build" ${make_opts} -- VERBOSE=1 diff --git a/python/parpe/hdf5_pe_input.py b/python/parpe/hdf5_pe_input.py index 7ee7975cb..c24e57bb9 100644 --- a/python/parpe/hdf5_pe_input.py +++ b/python/parpe/hdf5_pe_input.py @@ -258,7 +258,8 @@ def _generate_simulation_to_optimization_parameter_mapping(self) -> None: # get list of tuple of parameters dicts for all conditions self.parameter_mapping = self.petab_problem \ .get_optimization_to_simulation_parameter_mapping( - warn_unmapped=False, scaled_parameters=False) + warn_unmapped=False, scaled_parameters=False, + allow_timepoint_specific_numeric_noise_parameters=True) variable_par_ids = self.amici_model.getParameterIds() fixed_par_ids = self.amici_model.getFixedParameterIds() diff --git a/python/setup.py b/python/setup.py index 256f0173c..ed299e53b 100644 --- a/python/setup.py +++ b/python/setup.py @@ -17,7 +17,7 @@ install_requires=['numpy>=1.18.1', 'termcolor>=1.1.0', 'colorama>=0.4.3', - 'petab>=0.1.17', + 'petab>=0.1.18', 'amici>=0.11.12', 'h5py>=3.0.0', 'python-libsbml>=5.17.0', From 95015df695a7837e98fa6667448aebc31fedf3ea Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Tue, 30 Mar 2021 16:14:45 +0200 Subject: [PATCH 04/21] Fix/update IpOpt download script for better handling of libcoinhsl (#333) --- ThirdParty/installIpopt.sh | 70 +++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/ThirdParty/installIpopt.sh b/ThirdParty/installIpopt.sh index 1c8792114..4f0e741e4 100755 --- a/ThirdParty/installIpopt.sh +++ b/ThirdParty/installIpopt.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# build Ipopt +# Download and build Ipopt and HSL set -euo pipefail script_dir=$(dirname "$0") @@ -16,6 +16,7 @@ hsl_install_dir="${ipopt_dir}/ThirdParty-HSL/install" if [[ ! -d "${ipopt_dir}" ]]; then if [[ ! -f "${ipopt_archive}" ]]; then + echo "Downloading IpOpt source archive ..." wget -O "${ipopt_archive}" "${ipopt_url}" else echo "Skipping download step." @@ -26,51 +27,64 @@ if [[ ! -d "${ipopt_dir}" ]]; then # Handle HSL solvers cd "${ipopt_dir}" if [[ ! -d "ThirdParty-HSL" ]]; then + echo "Cloning ThirdParty-HSL ..." git clone https://github.com/coin-or-tools/ThirdParty-HSL.git fi cd ThirdParty-HSL + # Need some coinhsl library. if [[ ! -d "coinhsl" ]]; then - # Need some coinhsl library. Check for common ones: - if [[ -f "${script_dir}/coinhsl-2015.06.23.tar.gz" ]]; then - tar -xzf "${script_dir}/coinhsl-2015.06.23.tar.gz" - mv coinhsl-2015.06.23 coinhsl - elif [[ -f "${script_dir}/coinhsl-2014.01.10.tar.gz" ]]; then - tar -xzf "${script_dir}/coinhsl-2014.01.10.tar.gz" - mv coinhsl-2014.01.10 coinhsl - elif [[ -f "${script_dir}/coinhsl-2019.05.21.tar.gz" ]]; then - tar -xzf "${script_dir}/coinhsl-2019.05.21.tar.gz" - mv coinhsl-2019.05.21 coinhsl + # ThirdParty/coinhsl ? + if [[ -d "${script_dir}/coinhsl" ]]; then + echo "Using coinhsl from ${script_dir}/coinhsl" + cp -aR "${script_dir}/coinhsl" coinhsl else - echo "Did not find coinhsl/ or a known coinhsl archive." - echo "Name your coinhsl version." - read version - if [[ -f "${script_dir}/coinhsl-${version}.tar.gz" ]]; then - tar -xzf "${script_dir}/coinhsl-${version}.tar.gz" - mv coinhsl-${version} coinhsl - else - echo "Press any key to continue" - read -n 1 -s -r - fi + # Check for common ones: + coinhsl_archive_names=" + coinhsl-2014.01.10 + coinhsl-2015.06.23 + coinhsl-2019.05.21 + " + for coinhsl_archive in $coinhsl_archive_names; do + if [[ -f "${script_dir}/${coinhsl_archive}.tar.gz" ]]; then + echo "Unpacking ${script_dir}/${coinhsl_archive}.tar.gz ..." + tar -xzf "${script_dir}/${coinhsl_archive}.tar.gz" + mv "${coinhsl_archive}" coinhsl + fi + done + fi + + if [[ ! -d "coinhsl" ]]; then + echo "Did not find coinhsl/ or a known coinhsl archive." \ + "IpOpt will probably not work." fi fi - ./configure --prefix="${hsl_install_dir}" + # Use Intel MKL for lapack? + lapack_lflags="" + if [[ -v MKL_SHLIB ]]; then + lapack_lflags="--with-lapack-lflags=${MKL_SHLIB}" + fi + + ./configure --prefix="${hsl_install_dir}" --with-lapack "${lapack_lflags}" # --enable-static --disable-shared make make install - (cd ${hsl_install_dir}/lib && test ! -e libhsl.so && ln -s libcoinhsl.so libhsl.so || true) + # For some versions of HSL, the library may have the wrong name + # (cd "${hsl_install_dir}/lib" && test ! -e libhsl.so && ln -s libcoinhsl.so libhsl.so || true) cd "${ipopt_dir}" - ./configure --prefix="${ipopt_install_dir}" \ + + PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${hsl_install_dir}/lib/pkgconfig/ ./configure --prefix="${ipopt_install_dir}" \ --enable-static \ --disable-shared \ --with-pic \ --with-hsl \ - --with-hsl-cflags=-I${hsl_install_dir}/include/coin-or/hsl \ - --with-hsl-lflags="-L${hsl_install_dir}/lib/ -lcoinhsl" \ - --disable-linear-solver-loader - make $make_opts + --disable-linear-solver-loader \ + --with-lapack "${lapack_lflags}" +# --with-hsl-cflags=-I${hsl_install_dir}/include/coin-or/hsl \ +# --with-hsl-lflags="-L${hsl_install_dir}/lib/ -lcoinhsl" \ + make $make_opts make $make_opts install else echo "Skipping building Ipopt. Directory already exists." From c47ebade1b78b80c4b433c2cb3e0fc7b9417ae74 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Tue, 30 Mar 2021 16:15:09 +0200 Subject: [PATCH 05/21] Fix: ICC does not support (#334) --- src/parpecommon/hdf5Misc.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/parpecommon/hdf5Misc.cpp b/src/parpecommon/hdf5Misc.cpp index b0797804d..d2de9408c 100644 --- a/src/parpecommon/hdf5Misc.cpp +++ b/src/parpecommon/hdf5Misc.cpp @@ -9,7 +9,16 @@ #include #include #include + +#ifndef __INTEL_COMPILER #include +using std::filesystem::path; +using std::filesystem::create_directories; +#else +#include +using std::experimental::filesystem::path; +using std::experimental::filesystem::create_directories; +#endif #include @@ -508,10 +517,10 @@ H5::H5File hdf5CreateFile(const std::string &filename, bool overwrite) { // Create parent folders - std::filesystem::path dirname(filename); + path dirname(filename); dirname.remove_filename(); if(!dirname.empty()) - std::filesystem::create_directories(dirname); + create_directories(dirname); std::lock_guard lock(mutexHdf); From c06f2c92cc22c527895e4c86e0c30e84f4c1b547 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Wed, 31 Mar 2021 12:22:48 +0200 Subject: [PATCH 06/21] Update supermuc build script (#335) Custom boost, stdc++fs, MKL, ipopt, pkg-config ... --- ThirdParty/installIpopt.sh | 20 ++-- buildAll.sh | 4 +- buildSuperMUC.sh | 173 +++++++++++++++++++++------------ misc/rebuild_amici.sh | 2 +- src/parpecommon/CMakeLists.txt | 1 + src/parpecommon/hdf5Misc.cpp | 73 ++++++++------ 6 files changed, 172 insertions(+), 101 deletions(-) diff --git a/ThirdParty/installIpopt.sh b/ThirdParty/installIpopt.sh index 4f0e741e4..09054775f 100755 --- a/ThirdParty/installIpopt.sh +++ b/ThirdParty/installIpopt.sh @@ -64,27 +64,27 @@ if [[ ! -d "${ipopt_dir}" ]]; then # Use Intel MKL for lapack? lapack_lflags="" if [[ -v MKL_SHLIB ]]; then + # Will require F77=ifort when using intel compilers. lapack_lflags="--with-lapack-lflags=${MKL_SHLIB}" fi - ./configure --prefix="${hsl_install_dir}" --with-lapack "${lapack_lflags}" # --enable-static --disable-shared - make + ./configure --prefix="${hsl_install_dir}" \ + --with-lapack "${lapack_lflags}" \ + --disable-static --enable-shared + make $make_opts make install - # For some versions of HSL, the library may have the wrong name - # (cd "${hsl_install_dir}/lib" && test ! -e libhsl.so && ln -s libcoinhsl.so libhsl.so || true) cd "${ipopt_dir}" - PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${hsl_install_dir}/lib/pkgconfig/ ./configure --prefix="${ipopt_install_dir}" \ - --enable-static \ - --disable-shared \ + PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${hsl_install_dir}/lib/pkgconfig/ \ + ./configure --prefix="${ipopt_install_dir}" \ + --disable-static \ + --enable-shared \ --with-pic \ --with-hsl \ --disable-linear-solver-loader \ --with-lapack "${lapack_lflags}" -# --with-hsl-cflags=-I${hsl_install_dir}/include/coin-or/hsl \ -# --with-hsl-lflags="-L${hsl_install_dir}/lib/ -lcoinhsl" \ - make $make_opts + make $make_opts make $make_opts install else echo "Skipping building Ipopt. Directory already exists." diff --git a/buildAll.sh b/buildAll.sh index 171f58944..a75e81961 100755 --- a/buildAll.sh +++ b/buildAll.sh @@ -5,6 +5,8 @@ set -euo pipefail parpe_root=$(dirname "$0") parpe_root=$(cd "${parpe_root}" && pwd) +make_opts=${MAKEOPTS--j12} + # Build amici amici_dir="${parpe_root}/deps/AMICI/" cd "${amici_dir}" @@ -21,7 +23,7 @@ parpe_build_dir="${parpe_root}/build" mkdir -p "${parpe_build_dir}" cd "${parpe_build_dir}" cmake "${parpe_root}" -make -j12 +make ${make_opts} # run tests make test diff --git a/buildSuperMUC.sh b/buildSuperMUC.sh index cd4119311..18d777ef5 100755 --- a/buildSuperMUC.sh +++ b/buildSuperMUC.sh @@ -1,61 +1,114 @@ #!/bin/bash -set -e -PARPE_ROOT="`dirname \"$BASH_SOURCE\"`" -PARPE_ROOT="`( cd \"${PARPE_ROOT}\" && pwd )`" - -MAKE_OPTS=-j12 -# load modules - -# build AMICI -AMICI_PATH=${PARPE_ROOT}/deps/AMICI - -#cpputest -#CPPUTEST_PATH=${AMICI_PATH}/ThirdParty/cpputest-master -#cd ${CPPUTEST_PATH} -# -DC++11=ON breaks compilation of some `_override` for no obvious reason -#cmake -DC++11=OFF -DCMAKE_INSTALL_PREFIX=`pwd` -#make ${MAKE_OPTS} -#make install - -deps/AMICI/scripts/buildSuiteSparse.sh -deps/AMICI/scripts/buildSundials.sh - -export PYTHON_EXECUTABLE=$(which python3) -mkdir -p ${AMICI_PATH}/build -cd ${AMICI_PATH}/build -cmake -DCMAKE_BUILD_TYPE=Release \ - -DBLAS=MKL \ - -DBLAS_LIBRARIES="${MKL_LIB}" \ - -DBLAS_INCLUDE_DIRS="${MKL_INCDIR}" \ - -DBUILD_TESTING=OFF \ - .. -make ${MAKE_OPTS} amici - -# build dependencies -cd ${PARPE_ROOT}/ThirdParty -#./installCeres.sh -#./installCpputest.sh -# requires download of additional packages ./installIpopt.sh - -CERES_BASE=${PARPE_ROOT}/ThirdParty/ceres-solver-1.13.0/ -CERES_INSTALL_DIR=${CERES_BASE}/build/install/ -if [[ -d ${CERES_BASE} ]]; then - echo "Found CERES. Building..." - mkdir -p ${CERES_BASE}/build - cd ${CERES_BASE}/build - make ${MAKE_OPTS} -else - echo "CERES sources not found. Skipping..." -fi - -echo -echo "Building parPE..." -cd $PARPE_ROOT -mkdir -p build && cd build -CC=mpicc CXX=mpiCC HDF5_ROOT=${HDF5_BASE} BOOST_ROOT=${BOOST_BASE} MPI_HOME=${MPI_BASE} cmake \ - -DBoost_USE_STATIC_LIBS=TRUE \ - -DIPOPT_DIR=`pwd`/../ThirdParty/Ipopt-3.12.9/install \ - -DCERES_LIBRARIES="${CERES_INSTALL_DIR}/lib64/libceres.a;${MKL_LIB}" \ - -DCERES_INCLUDE_DIRS="${CERES_INSTALL_DIR}/include/;${CERES_INSTALL_DIR}/include/ceres/internal/miniglog/;`pwd`/../ThirdParty/eigen-eigen-67e894c6cd8f/build/install/include/eigen3/" \ - .. -make ${MAKE_OPTS} +# Build parPE on SuperMUC +# +# Assumes all relevant modules are loaded with compatible versions. +# Assumes there is Python>=3.7 available on $PATH. +# +# Known issues: +# * With CMake<3.16, linking IpOpt compiled with MKL via pkg-config info may +# result in "ld: cannot find -lpkgcfg_lib_IPOPT_iomp5-NOTFOUND" +# -> use newer CMake + +build_cpputest() { + #cpputest + #CPPUTEST_PATH=${amici_path}/ThirdParty/cpputest-master + #cd ${CPPUTEST_PATH} + # -DC++11=ON breaks compilation of some `_override` for no obvious reason + #cmake -DC++11=OFF -DCMAKE_INSTALL_PREFIX=`pwd` + #make ${make_opts} + #make install + : +} + +build_amici() { + amici_path=${parpe_root}/deps/AMICI + + "${amici_path}/scripts/buildSuiteSparse.sh" + "${amici_path}/scripts/buildSundials.sh" + + python_exec=$(which python3) + export PYTHON_EXECUTABLE=${python_exec} + mkdir -p "${amici_path}/build" + cd "${amici_path}/build" + cmake -S .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DBLAS=MKL \ + -DBLAS_LIBRARIES="${MKL_LIB}" \ + -DBLAS_INCLUDE_DIRS="${MKL_INCDIR}" \ + -DBUILD_TESTS=OFF + make ${make_opts} amici +} + +build_boost() { + # Build custom boost (with CXX11 ABI!) + cd "${parpe_root}/ThirdParty" + # NOTE 1.70.0 has broken CMake config + local archive_name=boost_1_71_0.tar.gz + local boost_dir=${parpe_root}/ThirdParty/boost_1_71_0 + local url="https://dl.bintray.com/boostorg/release/1.71.0/source/${archive_name}" + boost_install_dir=${boost_dir}/install + + if [[ ! -d ${boost_dir} ]]; then + if [[ ! -f ${archive_name} ]]; + then wget $url -O "${archive_name}" + fi + + tar -xzf $archive_name + cd "${boost_dir}" + ./bootstrap.sh \ + --prefix="${boost_install_dir}" \ + --with-libraries=filesystem,program_options,regex,serialization,system + ./b2 install -j 20 + else + echo "Skipping boost - ${boost_dir} already exists" + fi +} + +build_3rd_party_deps() { + # build dependencies + build_boost + "${parpe_root}/ThirdParty/installIpopt.sh" + #./installCeres.sh + #./installCpputest.sh + # ceres_base=${parpe_root}/ThirdParty/ceres-solver-1.13.0/ + # ceres_install_dir=${ceres_base}/build/install/ + # if [[ -d ${ceres_base} ]]; then + # echo "Found CERES. Building..." + # mkdir -p "${ceres_base}/build" + # cd "${ceres_base}/build" + # make ${make_opts} + # else + # echo "CERES sources not found. Skipping..." + # fi +} + +build_parpe() { + echo + echo "Building parPE..." + cd "${parpe_root}" + mkdir -p build && cd build + ipopt_root=${parpe_root}/ThirdParty/Ipopt-releases-3.13.3/ + + HDF5_ROOT=${HDF5_BASE} \ + BOOST_ROOT=${boost_install_dir} \ + MPI_HOME=${MPI_BASE} \ + PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:${ipopt_root}/install/lib/pkgconfig/:${ipopt_root}/ThirdParty-HSL/install/lib/pkgconfig/ \ + cmake -S .. \ + -DPARPE_ENABLE_CERES=OFF \ + -DBoost_USE_STATIC_LIBS=TRUE \ + -DBUILD_TESTING=OFF + make ${make_opts} +} + +set -eou pipefail + +# absolute path to parpe repository base directory +parpe_root=$(dirname "$BASH_SOURCE") +parpe_root=$(cd "${parpe_root}" && pwd) + +make_opts=${MAKEOPTS--j12} + +build_cpputest +build_3rd_party_deps +build_amici +build_parpe diff --git a/misc/rebuild_amici.sh b/misc/rebuild_amici.sh index d01a93e5a..0c987128d 100755 --- a/misc/rebuild_amici.sh +++ b/misc/rebuild_amici.sh @@ -27,7 +27,7 @@ rm -f "${amici_dir}/python/sdist/amici/amici.py" rm -f "${amici_dir}/python/sdist/amici/amici_wrap_without_hdf5.cxx" rm -f "${amici_dir}/python/sdist/amici/amici_wrap.cxx" rm -f "${amici_dir}"/python/sdist/amici/_amici.*.so -ls -l ${amici_dir}/python/sdist/amici +ls -l "${amici_dir}/python/sdist/amici" # rebuild "${amici_dir}/scripts/buildAmici.sh" diff --git a/src/parpecommon/CMakeLists.txt b/src/parpecommon/CMakeLists.txt index f45ca2056..b2860b850 100644 --- a/src/parpecommon/CMakeLists.txt +++ b/src/parpecommon/CMakeLists.txt @@ -28,6 +28,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PUBLIC ${HDF5_LIBRARIES} + PRIVATE stdc++fs ) if(${PARPE_ENABLE_MPI}) diff --git a/src/parpecommon/hdf5Misc.cpp b/src/parpecommon/hdf5Misc.cpp index d2de9408c..65173246b 100644 --- a/src/parpecommon/hdf5Misc.cpp +++ b/src/parpecommon/hdf5Misc.cpp @@ -1,3 +1,12 @@ +/** + * Functions for HDF5 I/O + * + * NOTE: Use only `const char*` versions of any HDF5 functions, not the + * `std::string` version. On many systems, HDF5 libraries are still not compiled + * with C++11 support, but use the old C++03 ABI, which will lead to linking + * issues. + */ + #include #include #include @@ -10,14 +19,20 @@ #include #include -#ifndef __INTEL_COMPILER -#include +#ifdef __has_include +# if __has_include() +# include using std::filesystem::path; using std::filesystem::create_directories; -#else -#include +# elif __has_include() +# include using std::experimental::filesystem::path; using std::experimental::filesystem::create_directories; +# else +# error "Missing " +# endif +#else +#error "Missing " #endif #include @@ -91,7 +106,7 @@ void hdf5CreateGroup(const H5::H5File &file, const std::string &groupPath, bool H5::LinkCreatPropList groupCreationPropertyList(groupCreationPropertyListTmp); try { - auto group = file.createGroup(groupPath, groupCreationPropertyList); + auto group = file.createGroup(groupPath.c_str(), groupCreationPropertyList); } catch (H5::Exception const&) { throw(HDF5Exception("Failed to create group in hdf5CreateGroup:" + groupPath)); @@ -115,7 +130,7 @@ void hdf5CreateExtendableDouble2DArray(const H5::H5File &file, H5::DSetCreatPropList dSetCreatPropList; dSetCreatPropList.setChunk(rank, chunkDimensions); - auto dataset = file.createDataSet(datasetPath, H5::PredType::NATIVE_DOUBLE, + auto dataset = file.createDataSet(datasetPath.c_str(), H5::PredType::NATIVE_DOUBLE, dataspace, dSetCreatPropList); } @@ -123,7 +138,7 @@ void hdf5Extend2ndDimensionAndWriteToDouble2DArray(const H5::H5File &file, const { std::lock_guard lock(mutexHdf); - auto dataset = file.openDataSet(datasetPath); + auto dataset = file.openDataSet(datasetPath.c_str()); // check rank auto filespace = dataset.getSpace(); @@ -161,7 +176,7 @@ void hdf5Extend3rdDimensionAndWriteToDouble3DArray(const H5::H5File &file, { std::lock_guard lock(mutexHdf); - auto dataset = file.openDataSet(datasetPath); + auto dataset = file.openDataSet(datasetPath.c_str()); // extend auto filespace = dataset.getSpace(); @@ -196,7 +211,7 @@ void hdf5CreateOrExtendAndWriteToDouble2DArray(const H5::H5File &file, std::string fullDatasetPath = std::string(parentPath) + "/" + datasetName; - if (!file.nameExists(fullDatasetPath)) { + if (!file.nameExists(fullDatasetPath.c_str())) { hdf5CreateExtendableDouble2DArray( file, fullDatasetPath, buffer.size()); } @@ -215,7 +230,7 @@ void hdf5CreateOrExtendAndWriteToDouble3DArray(const H5::H5File &file, std::string fullDatasetPath = std::string(parentPath) + "/" + datasetName; - if (!file.nameExists(fullDatasetPath)) { + if (!file.nameExists(fullDatasetPath.c_str())) { hdf5CreateExtendableDouble3DArray( file, fullDatasetPath, stride1, stride2); } @@ -237,7 +252,7 @@ void hdf5CreateOrExtendAndWriteToInt2DArray(const H5::H5File &file, auto fullDatasetPath = std::string(parentPath) + "/" + datasetName; - if (!file.nameExists(fullDatasetPath)) { + if (!file.nameExists(fullDatasetPath.c_str())) { hdf5CreateExtendableInt2DArray( file, fullDatasetPath, buffer.size()); } @@ -252,7 +267,7 @@ void hdf5Extend2ndDimensionAndWriteToInt2DArray(const H5::H5File &file, { std::lock_guard lock(mutexHdf); - auto dataset = file.openDataSet(datasetPath); + auto dataset = file.openDataSet(datasetPath.c_str()); // extend auto filespace = dataset.getSpace(); @@ -296,7 +311,7 @@ void hdf5CreateExtendableInt2DArray(const H5::H5File &file, datasetCreationProperty.setChunk(rank, chunkDimensions); Expects(H5Tget_size(H5T_NATIVE_INT) == sizeof(int)); - auto dataset = file.createDataSet(datasetPath, H5::PredType::NATIVE_INT, + auto dataset = file.createDataSet(datasetPath.c_str(), H5::PredType::NATIVE_INT, dataspace, datasetCreationProperty); } @@ -320,7 +335,7 @@ void hdf5CreateExtendableDouble3DArray(const H5::H5File &file, H5::DSetCreatPropList datasetCreationProperty; datasetCreationProperty.setChunk(rank, chunkDimensions); - auto dataset = file.createDataSet(datasetPath, H5::PredType::NATIVE_DOUBLE, + auto dataset = file.createDataSet(datasetPath.c_str(), H5::PredType::NATIVE_DOUBLE, dataspace, datasetCreationProperty); } @@ -336,7 +351,7 @@ void hdf5Read2DDoubleHyperslab(const H5::H5File &file, std::lock_guard lock(mutexHdf); - auto dataset = file.openDataSet(path); + auto dataset = file.openDataSet(path.c_str()); auto dataspace = dataset.getSpace(); hsize_t offset[] = {offset0, offset1}; hsize_t count[] = {size0, size1}; @@ -366,7 +381,7 @@ std::vector hdf5Read1DIntegerHyperslab(H5::H5File const& file, { std::lock_guard lock(mutexHdf); - H5::DataSet dataset = file.openDataSet(path); + H5::DataSet dataset = file.openDataSet(path.c_str()); H5::DataSpace filespace = dataset.getSpace(); const int ndims = filespace.getSimpleExtentNdims(); @@ -396,7 +411,7 @@ std::vector hdf5Read2DIntegerHyperslab(const H5::H5File &file, { std::lock_guard lock(mutexHdf); - H5::DataSet dataset = file.openDataSet(path); + H5::DataSet dataset = file.openDataSet(path.c_str()); H5::DataSpace filespace = dataset.getSpace(); const int ndims = filespace.getSimpleExtentNdims(); @@ -441,7 +456,7 @@ void hdf5Read3DDoubleHyperslab(H5::H5File const& file, std::lock_guard lock(mutexHdf); const int rank = 3; - auto dataset = file.openDataSet(path); + auto dataset = file.openDataSet(path.c_str()); auto dataspace = dataset.getSpace(); hsize_t offset[] = {offset0, offset1, offset2}; hsize_t count[] = {size0, size1, size2}; @@ -533,7 +548,7 @@ H5::H5File hdf5CreateFile(const std::string &filename, } try { - return H5::H5File(filename, H5F_ACC_TRUNC); + return H5::H5File(filename.c_str(), H5F_ACC_TRUNC); } catch (H5::Exception const& e) { printBacktrace(); throw HDF5Exception("hdf5CreateFile: Failed to create file %s. " @@ -554,7 +569,7 @@ void hdf5GetDatasetDimensions(const H5::H5File &file, std::lock_guard lock(mutexHdf); H5_SAVE_ERROR_HANDLER; - auto dataset = file.openDataSet(path); + auto dataset = file.openDataSet(path.c_str()); auto dataspace = dataset.getSpace(); const int nDimsActual = dataspace.getSimpleExtentNdims(); @@ -620,7 +635,7 @@ void hdf5CreateExtendableString1DArray(const H5::H5File &file, const std::string Expects(H5T_STRING == H5Tget_class(strType.getId()) && H5Tis_variable_str(strType.getId())); - file.createDataSet(datasetPath, strType, + file.createDataSet(datasetPath.c_str(), strType, dataspace, datasetCreationProperty); } @@ -629,7 +644,7 @@ void hdf5ExtendAndWriteToString1DArray(const H5::H5File &file, const std::string { std::lock_guard lock(mutexHdf); - auto dataset = file.openDataSet(datasetPath); + auto dataset = file.openDataSet(datasetPath.c_str()); // extend auto filespace = dataset.getSpace(); @@ -662,7 +677,7 @@ void hdf5CreateOrExtendAndWriteToString1DArray(const H5::H5File &file, std::string fullDatasetPath = std::string(parentPath) + "/" + datasetName; - if (!file.nameExists(fullDatasetPath)) { + if (!file.nameExists(fullDatasetPath.c_str())) { hdf5CreateExtendableString1DArray(file, fullDatasetPath); } @@ -675,7 +690,7 @@ H5::H5File hdf5OpenForReading(const std::string &hdf5Filename) H5_SAVE_ERROR_HANDLER; try { - auto file = H5::H5File(hdf5Filename, H5F_ACC_RDONLY); + auto file = H5::H5File(hdf5Filename.c_str(), H5F_ACC_RDONLY); H5_RESTORE_ERROR_HANDLER; return file; } catch (...) { @@ -699,12 +714,12 @@ H5::H5File hdf5OpenForAppending(const std::string &hdf5Filename) // Open for append or create try { - file = H5::H5File(hdf5Filename, H5F_ACC_RDWR); + file = H5::H5File(hdf5Filename.c_str(), H5F_ACC_RDWR); H5_RESTORE_ERROR_HANDLER; } catch (H5::FileIException const&) { H5_RESTORE_ERROR_HANDLER; // create if doesn't exist - file = H5::H5File(hdf5Filename, H5F_ACC_EXCL); + file = H5::H5File(hdf5Filename.c_str(), H5F_ACC_EXCL); } return file; @@ -714,7 +729,7 @@ std::vector hdf5Read1dStringDataset( H5::H5File const& file, const std::string &datasetPath) { [[maybe_unused]] auto lock = hdf5MutexGetLock(); - auto dataset = file.openDataSet(datasetPath); + auto dataset = file.openDataSet(datasetPath.c_str()); auto filespace = dataset.getSpace(); const int ndims = filespace.getSimpleExtentNdims(); @@ -753,8 +768,8 @@ void hdf5Write1dStringDataset( || !H5Tis_variable_str(tid1.getId()), "String type failure."); hdf5EnsureGroupExists(file, parentPath); - auto dataset = file.createDataSet(parentPath + "/" + datasetPath, - tid1, sid1); + std::string fullpath(parentPath + "/" + datasetPath); + auto dataset = file.createDataSet(fullpath.c_str(), tid1, sid1); // we need character pointers std::vector charPtrBuffer(buffer.size()); From 8fc9f2566640924a91a5f63dc6573625b1275482 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Wed, 31 Mar 2021 23:21:36 +0200 Subject: [PATCH 07/21] Update AMICI to v0.11.15 (#336) * git subrepo clone (merge) --branch=v0.11.15 --force git@github.com:AMICI-dev/AMICI.git deps/AMICI subrepo: subdir: "deps/AMICI" merged: "4e671a5b" upstream: origin: "git@github.com:AMICI-dev/AMICI.git" branch: "v0.11.15" commit: "4e671a5b" git-subrepo: version: "0.4.1" origin: "https://github.com/ingydotnet/git-subrepo" commit: "a04d8c2" * Adapt to AMICI changes * amici>=0.11.15 --- .../workflows/release_biosimulators.yml | 32 +++ .../.github/workflows/test_performance.yml | 66 ++++-- .../test_sbml_semantic_test_suite.yml | 1 + deps/AMICI/.gitignore | 1 + deps/AMICI/.gitrepo | 6 +- deps/AMICI/CHANGELOG.md | 217 ++++++++++-------- deps/AMICI/docker/README.md | 2 +- deps/AMICI/documentation/gfx/banner.png | Bin 138875 -> 133029 bytes deps/AMICI/documentation/gfx/logo.png | Bin 85197 -> 82428 bytes deps/AMICI/documentation/gfx/logo_text.png | Bin 97163 -> 92837 bytes deps/AMICI/documentation/rtd_requirements.txt | 2 +- deps/AMICI/include/amici/rdata.h | 4 +- deps/AMICI/include/amici/serialization.h | 76 +++--- deps/AMICI/include/amici/steadystateproblem.h | 9 +- deps/AMICI/python/amici/petab_import.py | 43 +++- deps/AMICI/python/amici/petab_import_pysb.py | 56 +++-- deps/AMICI/python/amici/petab_objective.py | 7 +- deps/AMICI/python/sdist/setup.cfg | 2 +- deps/AMICI/src/hdf5.cpp | 39 ++-- deps/AMICI/src/rdata.cpp | 21 +- deps/AMICI/src/steadystateproblem.cpp | 6 +- .../benchmark-models/benchmark_models.yaml | 10 +- .../test_benchmark_collection.sh | 21 +- .../benchmark-models/test_petab_model.py | 1 + deps/AMICI/tests/cpputest/testfunctions.cpp | 4 +- deps/AMICI/tests/performance/reference.yml | 5 +- deps/AMICI/tests/performance/test.py | 145 ++++++++---- .../petab_test_suite/test_petab_suite.py | 9 +- deps/AMICI/version.txt | 2 +- python/setup.py | 2 +- .../petab-test-suite/test_petab_test_suite.py | 2 +- 31 files changed, 507 insertions(+), 284 deletions(-) create mode 100644 deps/AMICI/.github/workflows/release_biosimulators.yml diff --git a/deps/AMICI/.github/workflows/release_biosimulators.yml b/deps/AMICI/.github/workflows/release_biosimulators.yml new file mode 100644 index 000000000..2f0479e3c --- /dev/null +++ b/deps/AMICI/.github/workflows/release_biosimulators.yml @@ -0,0 +1,32 @@ +name: Release to BioSimulators + +on: + release: + types: + - published + +jobs: + updateCliAndDockerImage: + name: Build and release downstream command-line interface and Docker image + runs-on: ubuntu-latest + env: + # Owner/repository-id for the GitHub repository for the downstream command-line interface and Docker image + DOWNSTREAM_REPOSITORY: biosimulators/Biosimulators_AMICI + + # Username/token to use the GitHub API to trigger an action on the GitHub repository for the downstream + # command-line interface and Docker image. Tokens can be generated at https://github.com/settings/tokens. + # The token should have the scope `repo` + GH_ISSUE_USERNAME: ${{ secrets.BIOSIMULATORS_USERNAME }} + GH_ISSUE_TOKEN: ${{ secrets.BIOSIMULATORS_TOKEN }} + steps: + - name: Trigger GitHub action that will build and release the downstream command-line interface and Docker image + run: | + PACKAGE_VERSION="${GITHUB_REF/refs\/tags\/v/}" + WORKFLOW_FILE=ci.yml + + curl \ + -X POST \ + -u ${GH_ISSUE_USERNAME}:${GH_ISSUE_TOKEN} \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/${DOWNSTREAM_REPOSITORY}/actions/workflows/${WORKFLOW_FILE}/dispatches \ + -d "{\"inputs\": {\"simulatorVersion\": \"${PACKAGE_VERSION}\", \"simulatorVersionLatest\": \"true\"}}" diff --git a/deps/AMICI/.github/workflows/test_performance.yml b/deps/AMICI/.github/workflows/test_performance.yml index 4e78e6ede..a2f463b2f 100644 --- a/deps/AMICI/.github/workflows/test_performance.yml +++ b/deps/AMICI/.github/workflows/test_performance.yml @@ -4,7 +4,7 @@ on: branches: - develop - master - - speedup_reaction_ids + - compile_without_optimization pull_request: branches: @@ -50,12 +50,7 @@ jobs: # import test model - name: Import test model run: | - cd CS_Signalling_ERBB_RAS_AKT \ - && check_time.sh \ - petab_import amici_import_petab -v \ - -n 'CS_Signalling_ERBB_RAS_AKT_petab' \ - -y 'FroehlichKes2018/PEtab/FroehlichKes2018.yaml' \ - --no-compile + check_time.sh petab_import python tests/performance/test.py import - name: "Upload artifact: CS_Signalling_ERBB_RAS_AKT_petab" uses: actions/upload-artifact@v1 @@ -65,29 +60,60 @@ jobs: # install model package - name: Install test model - run: | - check_time.sh install_model \ - python3 CS_Signalling_ERBB_RAS_AKT/CS_Signalling_ERBB_RAS_AKT_petab/setup.py install --user + run: > + check_time.sh install_model tests/performance/test.py compile; + for opt in O0 O1 O2; + do + check_time.sh install_model_${opt} tests/performance/test.py compile_${opt}; + done # run simulations - name: forward_simulation - run: | - check_time.sh forward_simulation tests/performance/test.py forward_simulation + run: > + check_time.sh forward_simulation tests/performance/test.py forward_simulation; + for opt in O0 O1 O2; + do + check_time.sh forward_simulation tests/performance/test.py forward_simulation_${opt}; + done - name: forward_sensitivities - run: | - check_time.sh forward_sensitivities tests/performance/test.py forward_sensitivities + run: > + check_time.sh forward_sensitivities tests/performance/test.py forward_sensitivities; + for opt in O0 O1 O2; + do + check_time.sh forward_sensitivities tests/performance/test.py forward_sensitivities_${opt}; + done - name: adjoint_sensitivities - run: | - check_time.sh adjoint_sensitivities tests/performance/test.py adjoint_sensitivities + run: > + check_time.sh adjoint_sensitivities tests/performance/test.py adjoint_sensitivities; + for opt in O0 O1 O2; + do + check_time.sh adjoint_sensitivities tests/performance/test.py adjoint_sensitivities_${opt}; + done - name: forward_simulation_non_optimal_parameters run: | - check_time.sh forward_simulation_non_optimal_parameters tests/performance/test.py forward_simulation_non_optimal_parameters + check_time.sh forward_simulation_non_optimal_parameters tests/performance/test.py forward_simulation_non_optimal_parameters; + for opt in O0 O1 O2; + do + check_time.sh forward_simulation_non_optimal_parameters tests/performance/test.py forward_simulation_non_optimal_parameters_${opt}; + done - name: adjoint_sensitivities_non_optimal_parameters run: | - check_time.sh adjoint_sensitivities_non_optimal_parameters tests/performance/test.py adjoint_sensitivities_non_optimal_parameters + check_time.sh adjoint_sensitivities_non_optimal_parameters tests/performance/test.py adjoint_sensitivities_non_optimal_parameters; + for opt in O0 O1 O2; + do + check_time.sh adjoint_sensitivities_non_optimal_parameters tests/performance/test.py adjoint_sensitivities_non_optimal_parameters_${opt}; + done - name: forward_steadystate_sensitivities_non_optimal_parameters run: | - check_time.sh forward_steadystate_sensitivities_non_optimal_parameters tests/performance/test.py forward_steadystate_sensitivities_non_optimal_parameters + check_time.sh forward_steadystate_sensitivities_non_optimal_parameters tests/performance/test.py forward_steadystate_sensitivities_non_optimal_parameters; + for opt in O0 O1 O2; + do + check_time.sh forward_steadystate_sensitivities_non_optimal_parameters tests/performance/test.py forward_steadystate_sensitivities_non_optimal_parameters_${opt}; + done - name: adjoint_steadystate_sensitivities_non_optimal_parameters run: | - check_time.sh adjoint_steadystate_sensitivities_non_optimal_parameters tests/performance/test.py adjoint_steadystate_sensitivities_non_optimal_parameters + check_time.sh adjoint_steadystate_sensitivities_non_optimal_parameters tests/performance/test.py adjoint_steadystate_sensitivities_non_optimal_parameters; + for opt in O0 O1 O2; + do + check_time.sh adjoint_steadystate_sensitivities_non_optimal_parameters tests/performance/test.py adjoint_steadystate_sensitivities_non_optimal_parameters_${opt}; + done diff --git a/deps/AMICI/.github/workflows/test_sbml_semantic_test_suite.yml b/deps/AMICI/.github/workflows/test_sbml_semantic_test_suite.yml index d47a58631..7dad35396 100644 --- a/deps/AMICI/.github/workflows/test_sbml_semantic_test_suite.yml +++ b/deps/AMICI/.github/workflows/test_sbml_semantic_test_suite.yml @@ -4,6 +4,7 @@ on: branches: - develop - master + - release** pull_request: paths: - .github/workflows/test_sbml_semantic_test_suite.yml diff --git a/deps/AMICI/.gitignore b/deps/AMICI/.gitignore index 6871f4448..44053581e 100644 --- a/deps/AMICI/.gitignore +++ b/deps/AMICI/.gitignore @@ -193,3 +193,4 @@ coverage_SBMLSuite.xml Benchmark-Models-PEtab/ +CS_Signalling_ERBB_RAS_AKT/ diff --git a/deps/AMICI/.gitrepo b/deps/AMICI/.gitrepo index 86c1d8b45..187fb9131 100644 --- a/deps/AMICI/.gitrepo +++ b/deps/AMICI/.gitrepo @@ -5,8 +5,8 @@ ; [subrepo] remote = git@github.com:ICB-DCM/AMICI.git - branch = v0.11.14 - commit = 09132907788a4b443f4d93223b34ee9fc5ad051a - parent = 99cf392ba569889f542eaa7b57145ea659570fe1 + branch = v0.11.15 + commit = 4e671a5be75e19da81b0946a3e16a913b7fe725b + parent = c06f2c92cc22c527895e4c86e0c30e84f4c1b547 cmdver = 0.4.1 method = merge diff --git a/deps/AMICI/CHANGELOG.md b/deps/AMICI/CHANGELOG.md index 875c9603a..f3e981e42 100644 --- a/deps/AMICI/CHANGELOG.md +++ b/deps/AMICI/CHANGELOG.md @@ -1,6 +1,19 @@ # Changelog -## v0.11.14 (2021-03-16) +## v0.X Series + +### v0.11.15 (2021-03-31) + +Fixes: +* Fixed initial state sensitivities in adjoint preequilibration (#1468) +* Fixed various model import / parameter mapping issues (#1469, #1473, #1475) + +New: +* New AMICI releases will automatically trigger releases at + https://biosimulators.org/simulators/amici/latest +* Transparent logo + +### v0.11.14 (2021-03-16) New features: * **Python import now supports SBML Events** (#1443) @@ -33,7 +46,7 @@ Misc: * Micro-optimize SUNMatrixWrapper::transpose (#1439) * Remove constant triggers from roots in Heaviside (#1440) -## v0.11.13 (2021-02-20) +### v0.11.13 (2021-02-20) Breaking changes: * AMICI requires Python>=3.7 @@ -69,7 +82,7 @@ Other: * Various minor CI improvements * ... -## v0.11.12 (2021-01-26) +### v0.11.12 (2021-01-26) Features: * Add expression IDs and names to generated models (#1374) @@ -83,9 +96,9 @@ Docs: * Update how-to-cite (#1378) -## v0.11.11 (2020-12-15) +### v0.11.11 (2020-12-15) -### Python +#### Python * Restore support for species references (#1358) * Add support for noise models in pysb (#1360) * Proper handling of discontinuities in the ODE rhs (#1352) @@ -93,42 +106,42 @@ Docs: * Extend mathml function support, particularly for numerical arguments (#1357) * Restore support for sympy 1.6 (#1356) -### C++ +#### C++ * Fix some compiler related warnings (#1349, #1362 ) * Fix a rare segfault for adjoint sensitivities (#1351) -### CI +#### CI * Move windows tests to GHA (#1354) * Pin breathe to 4.24.1 -### Docker +#### Docker * Update ubuntu to 20.04 -## v0.11.10 (2020-11-30) +### v0.11.10 (2020-11-30) Bugfix release that restores compatibility with sympy 1.7 -## v0.11.9 (2020-11-29) +### v0.11.9 (2020-11-29) -### Python +#### Python * General improvements to SBML import (#1312, #1316, #1315, #1322 , #1324 #1333, #1329) * Small bugfixes and improvements (#1321 ) * Improve derivative computation for instances of `power` (#1320 ) -### C++ +#### C++ * Fix FIM and residual computation for models with parameter dependent sigma. (#1338) * Disable chi2/residual/FIM computation for non-gaussian objective functions. (#1338) * Bugfix for integration failure during adjoint solve (#1327) -### Doc +#### Doc * Update references (#1331, #1336) -### CI +#### CI * Update OpenBLAS for windows (#1334) -## v0.11.8 (2020-10-21) +### v0.11.8 (2020-10-21) -### Python +#### Python * Fix pysb-petab support (#1288) * Fix ExpData constructor overloading (#1299) * Fix support for positivity enforcement (#1306) @@ -136,21 +149,21 @@ Bugfix release that restores compatibility with sympy 1.7 * Improve model generation for models with many parameters (#1300) * Add support for PEtab based synthetic data generation (#1283) -### C++ +#### C++ * Make HDF5 an optional dependency (#1285) -### Doc +#### Doc * General Improvements to Documentation (#1289, #1291, #1292, #1293, #1294, #1286, #1277, #1281) -### CI +#### CI * Add python 3.9 support test (#1282) * Allow manual triggering of GitHub actions (#1287) * Remove appveyor config (#1295) * Update GHA env and path management (#1302) -## v0.11.7 (2020-09-22) +### v0.11.7 (2020-09-22) -### Python +#### Python * Improve and extend available objective functions (#1235) * Fix processing of compartment definitions (#1223) * Fix replacement of reserved symbols (#1265) @@ -158,101 +171,101 @@ Bugfix release that restores compatibility with sympy 1.7 * Fix duplicate running of swig (#1216) * Overload python interface functions for amici.{Model,Solver,ExpData} and amici.{Model,Solver,ExpData}Ptr (#1271) -### C++ +#### C++ * Fix and extend use of sparse matrix operations (#1230, #1240, #1244, #1247, #1271) * **Fix application of maximal number of steps**, MaxNumStep parameter now limit total number of steps, not number of steps between output times. (#1267) -### Doc +#### Doc * Move all Documentation to RTD (#1229, #1241) * General Improvements to Documentation (#1225, #1227, #1219, #1228, #1232, #1233, #1234, #1237, #1238, #1239, #1243, #1253, #1255, #1262) -### CI +#### CI * Better check for doc building (#1226) * Add more gradient checks (#1213) * Update GHA to Ubuntu 20.04 (#1268) -## v0.11.6 (2020-08-20) +### v0.11.6 (2020-08-20) -### Python +#### Python * Bugfix for piecewise functions (#1199) * Refactor swigging - generate one single wrapper (#1213) -### C++ +#### C++ * Fix warnings: account for zero indexing in nan/inf error (#1112) -### Doc +#### Doc * Update Windows build instructions (#1200, #1202) * Update README: Projects using AMICI (#1209) * Add CODE_OF_CONDUCT.md (#1210) * Update documentation for Python interface (#1208) -### CI +#### CI * Create sdist on GHA using swig4.0.1 (#1204) (Fixing broken pypi package) * Fix links after repository move * Speed-up swig build: disable all languages except python (#1211) * Fix doc generation on readthedocs (#1196) -## v0.11.5 (2020-08-07) +### v0.11.5 (2020-08-07) -### General +#### General * Move repo to new organization (#1193) * Update Bibliography -### Python +#### Python * Fix bug for energyPySB models (#1191) -### CI +#### CI * Fix release deployment (#1189) -## v0.11.4 (2020-08-06) +### v0.11.4 (2020-08-06) -### Python +#### Python * Skip unnecessary expressions in pysb models (#1185) * MSVC compiler support (this time for real... #1152) -### CI +#### CI * Implement MSVC tests (#1152) * Rename and group GitHub actions (#1186) * Fix release deployment (#1186) -## v0.11.3 (2020-08-06) +### v0.11.3 (2020-08-06) -### Python +#### Python * Fix simplification for pysb models (#1168) * Pass verbosity flags to pysb network generation (#1173) * Enable experimental pysb-petab support (#1175) * Add installation instructions for Fedora (#1177) * Implement support for SBML rate-references (#1180) -### C++ +#### C++ * Refactoring (#1162, #1163) -### CI +#### CI * Move majority of tests to Github Actions (#1166, #1160) * Improve reporting of skipped tests in SBML testsuite (#1183) -## v0.11.2 (2020-07-17) +### v0.11.2 (2020-07-17) -### Python +#### Python * Speed up model import, compilation (#1123, #1112) * Improve/Add steady-state solver documentation (#1102) * Improve extension import (#1141) * Bugfixes SBML import (#1135, #1134, #1145, #1154) * Fixed issue that prevented simplification (#1158) -### C++ +#### C++ * Bugfixes (#1121, #1125, #1131, #1132, #1136) * Enable openMP by default (#1118) * Improve memoy footprint for simulations with replicates (#1153) * Improve steady-state solver and add option to to adjoint-steadystate hybrid (#1143, #1099, #1129, #1146) -### CI +#### CI * Store build artifacts from github actions (#1138) -## v0.11.1 (2020-06-05) +### v0.11.1 (2020-06-05) -### Python +#### Python * Upgrade to sympy 1.6.0, which is now required minimum version (#1098, #1103) * Speed up model import * Speed-up computation of sx0, reduce file size (#1109) @@ -265,21 +278,21 @@ Bugfix release that restores compatibility with sympy 1.7 * Fix MathML conversion (#1086) * Fix deepcopy of SymPy objects (#1091) -### Matlab +#### Matlab * handle empty rdata->{pre|post}eq_numlinsteps (Closes #1113), which previously made the matlab interface unusable * Fix generation of compileMexFile.m for matlab compilation of python code (#1115) -### C++ +#### C++ * Reduce memory requirements and speedup compilation of large models (#1105) * Place generated code into own namespace (#937) (#1112) * Fix several msvc compiler warnings (#1116) (Note that MSVC support is still experimental) **breaking change for users of C++ interface** * Fix swig warning: ensure base class ContextManager is known before use (Fixes #1092) (#1101) -### CI +#### CI * Don't install/run valgrind on travis CI (done with github actions… (#1111) -## v0.11.0 (2020-05-10) +### v0.11.0 (2020-05-10) Python: @@ -304,7 +317,7 @@ CI: - Move from Codacy to Sonarcloud (#1065) - Run SBML Testsuite when appropriate (#1058) -## v0.10.21 (2020-04-04) +### v0.10.21 (2020-04-04) Library: * Fix: Handle paths with blanks in build scripts @@ -317,7 +330,7 @@ CI: * Fix: benchmark problem test should fail on missing files (Closes #1015) -## v0.10.20 (2020-03-18) +### v0.10.20 (2020-03-18) * Fixed (re)initialization of sensitivities if ExpData::fixedParametersPreequilibration is set (#994) * Fixed sensitivities for parameters in sigma expressions for Python/SBML in case provided expression was not just a single parameter ID @@ -342,7 +355,7 @@ CI: * Removed mention of 'mex' in warning/error ids (#968) * More informative errors on SWIG interface import failures (#959) -## v0.10.19 (2020-02-13) +### v0.10.19 (2020-02-13) Python: * Fix logo display on pypi @@ -351,7 +364,7 @@ Python: Matlab: * Fix compilation errors due to switch to C++14 -## v0.10.18 (2020-02-11) +### v0.10.18 (2020-02-11) General: * AMICI now comes with a logo @@ -378,7 +391,7 @@ CI: ... and various minor fixes/updates -## v0.10.17 (2020-01-15) +### v0.10.17 (2020-01-15) - **added python 3.8 support, dropped python 3.6 support** (#898) - Added logging functionality (#900) @@ -388,7 +401,7 @@ CI: - Improved petab support (#886, #888, #891) - CI related fixes (#865, #896) -## v0.10.16 (2019-12-11) +### v0.10.16 (2019-12-11) * **Sparsify dwdp to reduce computation time for adjoints (#858)** * Fix(matlab) update example name example_dae_events->example_calvetti (Closes #866) @@ -397,13 +410,13 @@ CI: * Fix pysb_import (fixes #878) -## v0.10.15 (2019-12-03) +### v0.10.15 (2019-12-03) Bugfix release due to incorrect sensitivities w.r.t. sigmas introduced in 0.10.14. No other changes. -## v0.10.14 (2019-12-02) +### v0.10.14 (2019-12-02) **NOTE: For Python-imported SBML-models this release may compute incorrect sensitivities w.r.t. sigma. Bug introduced in 0.10.14, fixed in 0.10.15.** @@ -436,7 +449,7 @@ Misc: * Update documentation and FAQ for CBLAS requirement and others * Update reference list -## v0.10.13 (2019-10-09) +### v0.10.13 (2019-10-09) * BREAKING CHANGE: Renaming {get|set}tNewtonPreequilibration to {get|set}Preequilibration (Closes #720) * Make wurlitzer non-optional requirement for AMICI python package (Fixes missing AMICI errors when running from jupyter notebooks) @@ -450,7 +463,7 @@ Misc: * Update workflow figure to include PySB (Closes #799) * Fix compiler warnings -## v0.10.12 (2019-09-28) +### v0.10.12 (2019-09-28) * Fix handling of species specified in PEtab condition table (#813) * Fix some Visual C++ issues, update cppcheck handling, cleanup (VisualC++ still not fully supported) @@ -458,7 +471,7 @@ Misc: * Create SBML test suite result files for upload to http://sbml.org/Facilities/Database/ (#798) -## v0.10.11 (2019-08-31) +### v0.10.11 (2019-08-31) * Fixed setting initial conditions for preequilibration (#784) * Fixed species->parameter conversion during PEtab import (#782) @@ -467,7 +480,7 @@ Misc: * Fix various SBML import issues * Run SBML test suite using github actions instead of travisCI (#789) -## v0.10.10 (2019-08-07) +### v0.10.10 (2019-08-07) * Simplify/fix AMICI installation * If available use environment modules to detect dependencies @@ -504,11 +517,11 @@ Detaills: * Allow overriding cmake executable with environment variables in build scripts (Closes #738) -## v0.10.9 (2019-07-24) +### v0.10.9 (2019-07-24) Fixup for missing version bump in v0.10.8 release. No code changes compared to v0.10.8. -## v0.10.8 (2019-07-24) +### v0.10.8 (2019-07-24) Changes in this release: @@ -526,12 +539,12 @@ Python: ... and various other minor fixes/improvements -## v0.10.7 (2019-05-01) +### v0.10.7 (2019-05-01) Python * fix unset noise distribution when automatically generating observables in case None are passed (#691) -## v0.10.6 (2019-04-19) +### v0.10.6 (2019-04-19) C++ - Add SuperLUMT support (#681) @@ -544,7 +557,7 @@ Python - Fix dynamic override in PETab -## v0.10.5 (2019-04-08) +### v0.10.5 (2019-04-08) Bugfix release @@ -563,7 +576,7 @@ Python - Updated PEtab import to allow for different noise models -## v0.10.4 (2019-03-21) +### v0.10.4 (2019-03-21) Features / improvements: @@ -575,7 +588,7 @@ Bugfixes: + Speedup and fix travis build -## v0.10.3 (2019-03-13) +### v0.10.3 (2019-03-13) Features / improvements: @@ -588,7 +601,7 @@ Bugfixes: - fixed symbolic processing for unreleased pysb features -## v0.10.2 (2019-03-07) +### v0.10.2 (2019-03-07) Features / improvements: @@ -598,13 +611,13 @@ Bugfixes: - fixed output values of `ReturnData::x_ss` and `ReturnData::sx_ss` -## v0.10.1 (2019-03-04) +### v0.10.1 (2019-03-04) * travis-ci.com migration * fix problem with has{variable} functions * allow to import sbml model from string, not only file -## v0.10.0 (2019-03-01) +### v0.10.0 (2019-03-01) Features / improvements: @@ -616,7 +629,7 @@ Bugfixes: - fixed return value of `rz` when no data is provided. -## v0.9.5 (2019-02-26) +### v0.9.5 (2019-02-26) Features / improvements: @@ -634,13 +647,13 @@ Maintenance: - use newer CI images -## v0.9.4 (2019-02-11) +### v0.9.4 (2019-02-11) Minor fixes only: - fix(core) Get solver diagnostics for first(last) timepoint (#588) (Closes #586) - fix(ci) Fix autodeploy (Closes #589) -## v0.9.3 (2019-02-07) +### v0.9.3 (2019-02-07) **CRITICAL FIXES** - **fix(python) fix symbolic computations for adjoint (#583)** @@ -657,7 +670,7 @@ Minor fixes only: -## v0.9.2 (2019-01-30) +### v0.9.2 (2019-01-30) Bugfixes: @@ -669,7 +682,7 @@ Bugfixes: - #559 -## v0.9.1 (2019-01-21) +### v0.9.1 (2019-01-21) Features / improvements: @@ -686,7 +699,7 @@ Maintenance: - attempt to fix automatic deploy to pypi via travis -## v0.9.0 (2019-01-18) +### v0.9.0 (2019-01-18) Features / improvements: @@ -703,7 +716,7 @@ Maintenance: - Reenable run of SBML testsuite -## v0.8.2 (2019-01-07) +### v0.8.2 (2019-01-07) Features / improvements: * Speedup symbolic processing for ODE generation in python @@ -724,7 +737,7 @@ Maintenance: * Update documentation and tests * Add python version check and raise required version to 3.6 to prevent cryptic error messages when encountering f-strings -## v0.8.1 (2018-11-25) +### v0.8.1 (2018-11-25) - [all] **critical** Fix long standing bugs in solving steadystate problems (including preequilibration) (#471) - [all] Fix AmiVector constructor from std::vector (#471) @@ -732,24 +745,24 @@ Maintenance: - Update documentation -## v0.8.0 (2018-11-25) +### v0.8.0 (2018-11-25) - replaced symengine by sympy for symbolic processing in python *which fixes several critical bugs* that were due to bugs in symengine (#467) -## v0.7.13 (2018-11-18) +### v0.7.13 (2018-11-18) - fixes a critical bug in objective function computation for models compiled using `sbml2amici` and `pysb2amici` that was introduced in v0.7.12 - fixes a critical bug in sensitivity computation when`model.reinitializeFixedParameterInitialStates` was set to true - readds the python interface to the ExpData copy constructor that was inadvertently removed in 0.7.12 and streamlines the respective convenience wrapper to provide access to the full range of constructors. -## v0.7.12 (2018-11-17) +### v0.7.12 (2018-11-17) - fixed a critical bug in `amici.constructEdataFromDataFrame` - enabled multithreaded simulation of multiple experiments (requires compilation with openMP) - modularized sbml import and added pysb import -## v0.7.11 (2018-10-15) +### v0.7.11 (2018-10-15) - [python] Added numpy and python wrappers that provide a more user friendly python API - [python] Enable import of SBML models with non-float assignment rules @@ -758,27 +771,27 @@ Maintenance: - [core] Provide an API for more fine-grained control over sensitivity tolerances and steady-state tolerances - [core] Provide an API to specify non-negative state variables (this feature is still preliminary) -## v0.7.10 (2018-08-29) +### v0.7.10 (2018-08-29) - Fixed python SBML import `log()` issues (#412) -## v0.7.9 (2018-08-24) +### v0.7.9 (2018-08-24) - fixes MATLAB compilation of models - adds option to perform steady state sensitivity analysis via FSA - condition dependent intitial conditions are now newly set after preequilibration is done -## v0.7.8 (2018-08-19) +### v0.7.8 (2018-08-19) - bugfixes for the ExpData interface - created build configuration that enables debugging of c++ extensions on os x - fixed python sbml import when stoichiometry is empty -## v0.7.7 (2018-08-17) +### v0.7.7 (2018-08-17) Fixes a couple of bugs just introduced in v0.7.6 -## v0.7.6 (2018-08-13) +### v0.7.6 (2018-08-13) Important: **Use AMICI v0.7.7 due to https://github.com/ICB-DCM/AMICI/pull/403/commits/3a495d3db2fdbba70c2b0d52a3d4655c33c817a2** @@ -791,7 +804,7 @@ Bug fixes: Breaking C++ API changes: - Revised ExpData interface (#388) -## v0.7.5 (2018-07-30) +### v0.7.5 (2018-07-30) Features/enhancements: - Add computation of residuals, residuals sensitivity, Fisher information matrix (#223) @@ -802,7 +815,7 @@ Minor fixes: - Condition parameters in ExpData now only temporarily override Model parameters (#371) - Ensure non-negative states for Newton solver (#378) -## v0.7.4 (2018-07-27) +### v0.7.4 (2018-07-27) Features/enhancements: - Check SBML model validity (#343) @@ -816,7 +829,7 @@ Minor fixes: - Fix compiler warnings (#353) - Plotting, SBML example mode, ... -## v0.7.3 (2018-07-13) +### v0.7.3 (2018-07-13) Features: - Added symbol names to python-wrapped models and make available via Model.getParameterNames(), model.getStateNames(), ... @@ -824,7 +837,7 @@ Features: Python package available via pypi: https://pypi.org/project/amici/0.7.3/ -## v0.7.2 (2018-07-03) +### v0.7.2 (2018-07-03) Features: - Python package: more flexible HDF5 library localization @@ -838,7 +851,7 @@ Minor fixes: - Various fixes for mingw compilation of python source distribution - Cmake compatibility with < 3.8 restored -## v0.7.1 (2018-06-12) +### v0.7.1 (2018-06-12) Features: - Allow specifying sigma-parameters from Python interface @@ -846,7 +859,7 @@ Features: Major bugfixes: - Fix dsigma_y/dp and downstream sensitivity errors -## v0.7.0 (2018-06-09) +### v0.7.0 (2018-06-09) - Major revision of documentation - Improved Python interface @@ -857,7 +870,7 @@ Major bugfixes: WARNING: - For models with sigma-parameters and dsigma_y/dp != 0, dsigma_y/dp was computed incorrectly. This propagates to all dependent sensitivities. This applies also to some older releases and has been fixed in v0.7.1. -## v0.6.0 (2018-05-22) +### v0.6.0 (2018-05-22) Implement experimental support for python via swig. Python interface is now usable, but API will still receive some updates in the future. @@ -867,7 +880,7 @@ WARNING: - Matlab C++ compilation will fail due to undefined M_PI -> Please use v0.7.0 -## v0.5.0 (2018-03-15) +### v0.5.0 (2018-03-15) Main new features are: @@ -882,14 +895,14 @@ Main new features are: - Rewrote large parts of the code as proper c++11 code to allow easier code maintanance - Substantially extended testing in continuous integration to assure code quality -## v0.4.0 (2017-05-15) +### v0.4.0 (2017-05-15) * First citable version of AMICI (via zenodo integration). * Better support for standalone compilation * Improved SBML import scripts * General Code Cleanup -## v0.3.0 (2016-09-05) +### v0.3.0 (2016-09-05) This update comes with many improvements, bug fixes and several new features. Most notably: @@ -899,12 +912,12 @@ This update comes with many improvements, bug fixes and several new features. Mo 4) AMICI now supports more SBML, SBML v2 and rate rules -## 0.2.1 (2016-05-09) +### 0.2.1 (2016-05-09) Bugfix release. This release also includes some changes that should improve the performance on the new R2016a release of MATLAB. -## v0.2 (2016-03-17) +### v0.2 (2016-03-17) This update comes with many improvements to the computation time for both compilation and simulation. Moreover several new features were included: @@ -912,6 +925,6 @@ This update comes with many improvements to the computation time for both compil 2) Correct treatment of parameter/state dependent discontinuities for both forward and adjoint sensitivities -## v0.1 (2015-11-05) +### v0.1 (2015-11-05) This is the initial release of the toolbox diff --git a/deps/AMICI/docker/README.md b/deps/AMICI/docker/README.md index ec7ecc677..97c072254 100644 --- a/deps/AMICI/docker/README.md +++ b/deps/AMICI/docker/README.md @@ -12,4 +12,4 @@ cd docker && docker build -t $USER/amici:latest . ## Published images AMICI docker images are regularly published to -https://hub.docker.com/layers/dweindl/amici/. +https://hub.docker.com/r/dweindl/amici. diff --git a/deps/AMICI/documentation/gfx/banner.png b/deps/AMICI/documentation/gfx/banner.png index a88c2da489bd2c917e65641ca6d514faf97a968b..40016b4da09cc1b470ba1e7d527eec750a7d4f96 100644 GIT binary patch literal 133029 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 z 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 I>NTJL2aa&xdjJ3c literal 138875 zcmZ5|1yq#V_x5k4``KskR#K2WNlHzMKp;*^ONpr<5GRZfh`%R} z{RRILGM6w8|NG~$l$I?5ah)Fj-yx@DQ3nL#GD2GH4$A5M%z*xb{}S;f5nktp`IcVwy8*3dt$LQRK3#U)9GRSoQ?*PA|wP(!JMLQrolC@{suP zc6_DySo4}-)W%MEg}2W4=(P!s-St}0&O1}a4Cq}B|YJMA9 z!X#twK1|CgH;<9?szW)o7+s~}c{RDgiY;jDkE4lh^ENr{!UTuKe^RN9RBq2ku~VdE z@37SIh>qF?{1`1;z(fkJN#E&sep#-|nzYBi;KnJ za1`q!B<12q$6aIhW~|wWyakJoN)s=Nq$z+Q=-Fus;_psN$&seY*orHuCKeTuha5wV zl|;v&%i%wCOS9jq1-hYgvxxY+IrU$YJbfsu<7HI61Xa6C;`s_N1(vAW`79mp<-Giw zCdIf@SMD7m{PqVq_+^rPbt;tPseKCx<;Zznd`G&mzDK}w}xdy*8KBQH4+!TDTCO>TCGE;|29m&-g zNZ0(<(!ViYGm+wti){&w-{8;-=g!1?W3x@SU)6+SU~;=_NVS(-d?-Ow(QiCKv@uje z-ha2}WL6oN>NMuXJeR#H@iby!pim#`R~QM~Hm_9fH0_ik@$uIQI30POa1Wo_7irEB z1HYO&9yEESCu}&{+uJYQFtJrmV`kt}-DEsjuv%AiS&pACMRhi^X54Q389rU$qjVgW zW$+b9z{%-GmvWxJSyknXN4({c@{f8jtCnf(^xVV{ z%J~c-o2B#~4yF6rj$qfzb4xkY2@0uJKAFhLeL7BD)7ctDmnjCO(ZGmH#4oL zaapNG$YX7}@`N=I$dCwf%f}y+joQi8qL6ZLUG+3H3aj28L&cQXt2RwSG%>x9$By@? za8V}|Rw46C3^NL5ItLV^>yHvvP}=yKWI!K%VKN{=S=l?p{N$4Oz0IgzZhWqfPv17o zeWyS8kNB9%opsHSTAx2|Y=)-}M_r_iy0GEO5J`rV;Ssmmr5MPR)V@z?UOZp9nDYa5 z$H@wBByNi4ein%{U%GdV7=rGo>J)IvrIg1u6)HFq9a9_uY9k%lbWjg5Y5A1VS~M!pkR@RWv8hax-7R<+}u-Kl8$BnXz$qdm;N>4V)cNm zX?3vJEdiceQPCG^gKn~fZ}Hvb;>j{gpPEYDY31h0HS!MO>&v!`NpB3WVd!7OC%jM6A8UgQ43l#_jS*HO{&wi;;O8sn#S<2jL z3+}Z*Qm6CBPP0-jDqPYmfI2cnel6&ZEXD=0#{_8?Mm*VZcxAp4+i0z=Tg}v=^d#_r zSxMpSl+3lm<|hcha~ckx{s0bdG-^A^Z16~oenVT3jHZT|JCDh@SePrk19!axTe9_M z;@BzpR~HzA?ikw^V})sWL>+#%snYDa$7@4`SWNs3lMApp$o)4F{ z4Cc5jcl4(*l)ZhVf+#oo*-+PdC0R>JIYgFNR2spDp-_fLipoz4Y0bsnM?Fk~{WD40 z>hIYyuiAY0^|zq_GJNp?(WX&=NevLxGJ?JdgH^AZKej2w>QfpPk*E2rG00U%qKnZyqoVc8S*1 zllMbN^08RLLHvF{7f~0S*1${2i)vZq^+Uul*94U_XmH_HPu?`(YAC`M92Fq_gl5cWo zjN;|PF(8xpPvxsCj3h&ErV?w8G>2eF)!Z2Izm~$I7I9&62vPV?#>qdwS#z0@geG1D z{VdWMvTXsjSEV#G`di8JoPn}O%fAkntm>A(0{h(mqkI)Sa#Sz|hv#`}AfcY0M?UZ!3v^O-dC9yI2m(g?36d&wd8m}Lu2ymyX1t~OCw`7v^p4>A1#;;Ve`fvQgDPh!mom4L_6i^r!295eKC-^IyF zHhDZbjY+f%sdK(f0`RfABRN;+Oyn^c99%4XQ3MyTPAF)Izhst?1XCoAw)L+N;!w1L z5l|Bl+}lJ6K+FHs!*_on?_Z^IEm`v7Y74TK+1v=ae-UYsTV<4wv(q-3ll$aTby$ zEM(y4Ev=l%DET_;y`Y=okJNOKEjo*4H#|G&_8xG4(ux zezy6%_8Ki^7|}DG5cM4<5bb=AG29Jd;}YYK1_q$O>Q!{p*-H*Avx@svd9QtDdc ztCaMs{g3~x=~#6D2FNqP2{!U?m-VN%K5!pa0b(teVtL# z7GfG`+Ke#bQ^120`lm4?I)v9E8t56t8NlMjHaI(m!s`$NLaXG-iQ3$bTgh2aRW57@ ziMWw@ilfmD1#_ak?P2x?geNQO!E;(jzRUJQ_uKnB0m=*uN}!6#4+Z=G#eCk7SZhA8 z!MVtju~qX-Daem^rtVN-Qw7mb3-=E+wBoz7=0=5Jy~ai)!x`@)$fvV`liJ{xow5qG zW5rKnbOg!3n7}Z_29%-moKZuB^mGpB3YO?AVD270PS_7yC_MPE0CkZ@XzBH{fb@iy zERm!-dBTR6lB}%j)L9yAqsG~P8QABWIQOp6Q5=Lon3$Z8{f*e^vi7w*V@Hz+am(2^ z&>jZ7N#U)l2-gof7Yc-hj3&OVhmYo2E|$*Eqrbo759FbwyYFksFDn4Z_zN(G8c#28>0AuBQPzzPZ{;}U}o#sol#aK(t%HaGM!bB zYsuwgNQZhoFdO#(dt@w7N#F>%&u)Z@o<8mQ2};zE$G;41=lX~ch>nRMPfvfVy84_` zw}K_2JPe40adbnV)R8_1`+SE>2ML^Am2&8>oC|j%277jF01F=ypSS&*q$zHEm`-2B z!`Taq5#xSPx7^P3Vj+IeCRB*TusDBd9%AE$qmS2peX1cUPtw-*u-ThVLXo7x#P%ii zsXZJw><7wlJy;cv$og~-%B(i`06e789CKavEsM;3*a~1-tL0*^!%mA0RIiF#>+mv?d@SZjO3vw0EExhU5+G8bkD=K_K${MX=P58 zgRF$Wfa3`rP!)Mtx(VForKrfBD2AlYI=?ejeE$%3-%)k|q7S}9tE=>FWyf&Xc%()1 zE%Qc*)Db`ZqchNi6nVD00;>G_HIbmKBo4d?a>76FBVpIKT&PY#U>)s~e1qj}|az3HjQy%;hT5h8!9V{l?IQTB#8lZ(0GiUk6JfpNE0+mHCtHPvN-45&n7~gw zPi7C&oAu!80-k2)p6ok!j+iQiBB?Me(S)qKjsV-8$vCG2V6U*5K zV&2E(UjS?B^e?J^LF&4za%!BT$d?G+*{<_CCH`_D9DtthaOO-iqj+f;V}N@m_9G!Cm5uzMKwDQ|DiN!M}94u$;Qw-u`C4 zi$RN{UV1kT*pXw!EhmT%1I<2AJ7smuJ{zpRqzgQZ`33Kq%K}g@#|j}Wd;v(_#x?(m z3E(-?YGd5%OCG87OqcS}O*_*A>X{f9o&5d&J~ILGR@hoEimjjjk$P0|o&f5D33BG9 zlWP-q6k%tT)UY#Z<*VrH)D*f7ZugAGzeWEXIf`7pUUNjG+;w+3k6s=y81gJ}0Zrh` zJ+FtL1XWo&Zae-2cZ1-A(!p@HoBz^#Do(#N&iEU;YSyHDQ>bK6fc(cnyeaxicxmGB z;K^InIGzXYme2YEJZ|v6h4Qee?T#Du?J9q}EA(_My18i5;;Fb*MmE69s*s24v%R~- z>Vv$>s8(b(RO&pP{&O<@3*M58hZm;%OUvkON1K`g9KJdrtDvMo=?Lp;3f_;%D~)!N z8$qFDGrqEzsxZrzd$q`u9yT%(XoiHgsy& zz1bFVEatf5h-xublLpcoP$M&jqmiZq~; z-QE!W8denW0IkP!*h)3+R{cNTq`AH0NNhrnhw?eKr}UwxSBmW~3gPC6nnWtvNM)K$ zMoeCxHda(-E}mO*&~m^rm3!`iQPQ5u(9wotd>{gTv0Up?ZP|=594UIj^?psD zjBxz=$pTdU`K|>dyhgr-lO57Yd&p z{i0l!kkj7&zzTzUi(y8`88IY8eZiL)aiUFBj8rUUSDVtoIc@r&oeIiW8=llD5Zx#% zMB08I1dBjF4=rtO%xkEyfB!VDt_p|bXMV{8J!6e0YM&+nO)wJl1#M)Gih^GUxr+;D zvbaVMZIvH7;blUqgR)+l(`*Aso$VomEMXw!xx|X5+z0BQy%+l#J!!GQeIyAwc*6o0UL#?R z=D2cK+?Vb}3C{CAGWn(_nvK8sYGXhfey++k=)Y6jE<*&zjx)j96p%cdR{HJ3v(Xw2 zi)Tul^#*#D(3VekpiK{NiMvFz?zEusqdn{qx`Ia6r)Emr5CbGTob|(LKMB$s1L@}% zsKED@Z;{x`a!jg*#u1c0&%fP&j4pl`(3^7c#1n{~C-a{igo#$ZYNRsuWP19FbDRD^ zOrqoT)Z?c^rRDJpb#uEr^pkG6F)P3mIb5C5fzRUiOS=X1Lm>J96>s*6^zqt;6sZpq z*W7R|drc^%s8B{GXbEy}4eYC?R+b9UG$g)U;FMCD$W5C~?Q#i;M|n~Z{xeRi53W+( zKX&SJQyc;D#TRXQu{zuYVC8**{;=`BhbYq{No0gmcFUaA1aqg z>}*gXT-dR#wY6Q$%+ktuJ3o(^e<_uS`{e@FGhol*mOaB~tUbkBxW{EsmdcxhV`8EI zGm`eWK@DWk(MLhN3?Sfls{b= z+TA#szC4b%=EguFb%ABTEb86D{ka&d1@uQ7<;Q^`5O6CO37dJ)LH46$g3E&y}=OvSkw{9o}_bd{&edH{YxHt3XpDj; zy=ODBprlr%q<}!vwQd`X<-}{Mk(h!E>a(e50HZ)i2c{lMwwCk*7>MAhONyAgibn`> z4~k8@O^Dksy-#bmp<1f(Jm9b*K(1+I9_R!6RHW>Bg?21~|C!dYvSGxKGGYM75NH~c zN(}@lHYIBm8dMJBD|FMWfhQbi~pB55I*2hkaWe~aURna1505T4Kc}C_DQZ3Uq`$g!JXTmE#1RdPukmm)a~i zan9FTs+N$-l>!i6c{cL>F4qP&M%M<@2Jg6lvCoSLuYAz&bZJQuo`X)>F2zRqwifyEjfMMoWv~?Ek8bVVsA|TA z3tuOAOY^*uimZB=w+p@$t!=vGj-_#J*I|!_N&$&U@I-;y0#qLU1#sd-TeM13YiUup zBI+eX;g?^*M_XMh3A(4uokJEG`w|gq#ja;VtcKT-aomuCHZ{f&4ma zv_9+_ueZ#g7a#76;Q(Ql`LddB)_YO6jsDkUWuvLPX$)<%U46G1z|z_JrP1M07be$k zr%7FTgfQxM+t16^6D=7L(%a z5{lOjEoW(zpP~j<3cJa+AD;}9A_Hzw7e zpqT*X@Jp1a>}&tQmc=d{*aA6YTkXQ5Ifr0W5-_pZIFjxPB9ev2>VwQUqD+KY|JmIstB9nN)qZ88CfyW**_(~qn{J$)-0&sV!A%q6 znK49rF*64*sB@a%x;C{?Nl=ove$gBuc2|{C(%U1VyNM&ZZ~OSO{kKI$b$>?B+*|A7H(%A5yU$wz!sgO~6bEJL z>$eHW#Rc|GuS3M4R}S^pB+4=TQ>!hanstI9=`vINqFbWYqeqPzJj|9>{qaj!QXwwE z=$4>w!bI$7*{l42p^NTpK7Wy@N{0AGv?s6$O;~Y_Ye)}lqSqzd4fr~bh4$y|++kM= zNLpi` z<+jiRL=kwKF$YUUiry_MuXKa~7Qh*f)m=$7rZNrVZy=bLUQTL@5XU;q$GNbtSsT8V z<$FsEEXB8M&kum3Esr87WsBO2p-9CHZ~%!#ZxaWZ23}v2E?I#CI%PktRR#~arBi2L z^z=!%j~>9Q5pZB?QR32?|G?5ZKfji(f-SMv@L_CaW6PwHjDHLU^Y zlhTQv);Z$22saS$lKGBN1v~=tTjIGWt%z4=)D`5=S7;1=4Zi+BC;xE@0!3|zRfB=0a0?w-)$);YNy2_LFL7Z@uE*`o1J2$k zOo9D&1`oNgx^CZ|?dL#Hh-;!(V5)bHBj#NQVV|BZ?ap#jkjq5@yS0AXw=K=-`#P4; zTX4GpcPOX)&m_mG0JY3qpFT3Y5GL0mQA|&KU3`?kv@Y1jXl^Ta%+C^19||PDXs@!W zng=q6PXB ztH;_DOYQEe5Lmk>wFWB}7O-1yeMOOU-wP2ipQ*q2)K<+p6BaYcL1+qBshE-CYMyoPG|4jJSFD~|RzW0HLRO7s@YHEvFr(ts#yiS6#)xErb`O7vx4jb(6gAYG%| z@+ux>1$loKbq!f`=arQ@I)ihEcBccZb!oHG)A59`opq1g+ z9w4y_teS#cC~c3It2>tA$}mUG!b)15c#kei7HC;`{c!j2I5%DNoU=ps20w zEiBm#Y-VP^^4RjFYl+j<1h(BjEt&~Rk=}8{bRv)11+d-d?{`c3ub@eSG&ezJ6tfc2 z+%viN7#Fr-LbSAf%iS*=py{Ch4Id$prHYB8H}i2 zwy_05=?>^B&;jehbj5PmxW#kFCbR8aHoZRJk(CzzRS8rvp(?#7K3kM+g6xOTvtNMF=_l(U!?JB?tl0%I}8Xp-_A(pJE zVxpm)-fbSu(4eHkdgafF77y>b-3RERyz%UJpk2yaasxkVjA$+TB;_iE?Mb#3}py%*?+dbRyF&*>ouUurw|MpMuwlX z##IAoZ4PiKQmY@^H|g#C^xu3~SRmkJtRMT5dF=L}4#?J*oEdKDRJ7Jn)LWZ?5Dxf~Jzt{4Cthe!Zat!*uX7(4n7Q#GwtDN<4INX3l7Jptmh$yMr%q zyHNQGt=;W!h&~3qqS^S2k4(MA+XR(w>V?B0gD(Ptm%zV_k=|+N}X@o06d`{zlufpB0r}p7k_2+rw zmYz_Y4-N{{4(fD!U4BX`lbM{N@Y@}CL{1>Iyr5;m-H_O+DnJB$Dv{_DN;ZNbCC^9& zIK|Fv#jd6V+D$kJ=Q-Auhr2zatT~=g;Gw@hS2z5bgAkLRq$(_2EL2$1*5WxOXdCj~ zNfAmK{4lc{TS_sP6*phFd?&*FSMs?a;@BVM|!}@X&Je)AXU7C)!423dAPC)?tZ!)^sUFnX`!3db%!Df7JObTAkb%Ez7?l5E_C|t)^vmf~7ydtS-Fy%9TVj{Q zww;$86cTj~Cp%EoQ zh6btGTg%$(>(9Dvo^G4&U>?!7+~4tN+4Z=wS0qEHyaDBf8mF6i?ucj9O8Cm2DgOSY z>djkGTO*dUyP|$Ba9!D*KSp#bZm4&2wwqXMGQ2A8C%0Un5!&k0XS;!qDVSXu=Z@K+ zyYt*28qznc+sJprumkd!Z;lqxDRCMT=QJq>0#>t2b9ZGes6WwC1i-E= zPUYBotp{`$D5^I*N2kAe0LVV&e3H4)z0-)&yaCA!h{sfLbodkONgX`dVlFs=2+;yj z44N)1yDdn}a1C}OGd-PVpL;3)RJSCeth#cfu}V?E;3XO%8Xdjo`4^9@NjVR}25B~A zq-B7{hum5;14pJB;Z=d-ZFm9A=*rx!&W;Ya0w(Tp(CrwohuZ!gtiPcG)jo59^An6c zjV-2O#3)b2g6Mu1gq`;eSCArUiUi1~xoNyfyiI6<72?7|C5Hz=p@*L1Yp1#f_;vFY z?@6<2d|M8(%ZaMPo+n}G4X`^0w?_g`2u;8ZLr`J1>sStwrBjZ|2wyGmtOXW>^7V7X zf;QMENF_HvUlnL0^ax#R)CkY~)}YC!fT(vO90rx`EG>r{`wuPyXsWULNsCiqLDn)B zlr7k36`o$qC`=MGwy-dPbOXGd1n$u}{TITMm-6K#lb!%v{|tWtmu7suw$E2Mr)Yiy zhQA;39~#xkgOSD(X<1n~yfoaa4KVAbE5hIJGK|$w=w#}8I!cGgsUfJm;HI9>l7`r! zoyDXBL`r|Ov2U4*oh1);4g5maixi$D+k2aXQ@r4Bc z@l^Y`9nl`TL|4=4gs(G96>I9#<@b(PoIs?Wfr0MamMC0Qa~cL7Ip_XV<)EKa%WI5i z$4~NZT4hTRp#u6yd~v9Zn}+HPpwMm8#6r3FXQM%;HAx`u(&`vr!7G1jn~Koj=2luD z;9xAFm_jshje=2?0m>7BaoE*ki?JS=rcV5o2)5nvGim|+h z1CGDz=E@o9Nf1IPLK6TjvmafDQ4sM8P7BSQ&sbgi3c{1L~B>k{PXUAfpCPBlJhIBLN zff2bg#5jC6r9txM|71zMQ5_dHx8tpJCi=*9x%$XCe(O1>@uPEA?*Gyk97g2)4WbZO z9Yo_WGWmnk=4op0cYEsg*9U?7LsOhPriNN=?*fzn>8~fp)CEL5{AFQ-p*4?okh{hb z@hvUBO(s@=FoTC&Sl$ON#n6daKFYr@vS;{IRUe>2c%@#ngNeo%icUk6o|OJ46|ZV-_XyRxdiULmdSX^ETDL4&~pW z>AgzTK5p0?=2NjXCVc=8VUIu|1UitLuNDaW9}q{|wSIQdRfceH0~A9_xD>}64Gaw= zoYb+Tb_h800@T|BiQ^0V6-Il|!Mc0XB8r4}`t-M*)I@(RZjd!}yakyB4=?!X1^jx5 z)@jU|+n(f|h^(d;?D7=uaFOXC;@Q3!8LNN+@mzvEI}CakVBFb1qJfK-ftr;&Hr8EQ zHWEo!3iQ#RSC9(vp$2Xez>XfkH`vCx2-NjY5Z`0tW3;!=WW+U5(Fm1LOJljqXaBEH zC>Vl113UoaVVmy7f*QIjcHq@yEtDJ@?qTpb@fDO#B}lb_f$!6yYTmZPm>$w7ZYtOh zglf-xFzGt{6M88X^fZWLF!laNNNMK<-#Dx5f|lhYzqfDz=wyJxvR<_0SB+|RTXxX0 z8U-B@hHzB>9z|r7z_ip#hPTTs{|8(%f&q-#Ya-s{pgb08MRynCMHlDhcAD_*yah!jtaWg+F(b|B%3g_nY{us# z6gLHKYc~L{@}#2a{XzZvQwb!R@IVON;_H&4xVXYCkXAsX6`xnKmJ80?P%t| zJ$v<|76LJyp!p3ZL2z9=JAVXJ#qzm5e2M;V$@0DFEmk^>!n8}$juO@$z<U>G0*?0?p4^sl>~)?l^lAM8E0cF761vIZk8Bmf^OT#S1?J&_3* zPX1~?Twzms@soIUfzmpj53kzo_KEIYE+`EICK7vVaUAYXl;1_%R>S8#T;0XQ8vg&z zF!;=eWt~v0?c~b7z8VAJip7|WkC`q8jwbijB z4X2hhrI?DLIqdh4^O3QA?H5l8O1E>h#`IeLnLUeMNA(*out+A-UN2zqb-TgTT-Q{< zwqeNzl&t)uY zk8|$SrKJtcRiR@Y?Yo?Z&VM2C5Z)i|RMM76({5+CoX0R;9YePFY<=zBrJW2rRdEI3 ziMCl7efD{6Fayi_NT=}W$f|B2F+=jN+n4MFxZ9;ta;x~!4op`pR7_q5>n5+p?k*zA zdy57e=qfzMhx;rF%T8+%i34VUkCB%2Mx-YD5?Pdj!p(0lL;2XHkv%)()W4d(Pqxrqk zGBLN-9UPu&Fm_QKyiS6_x@Z<@#n92)v6jNIGq7pxDl0*XNTrRu--WTpovM=aoB0$G zw>_USlpUjafe<@Q-C5uQj53u)|j_wU!DJMKw@ z2*2%DEG{=y|Gl!kBT%X+PxyPqNXzbcoS;kGJPj=(RVzO%q}XBi>#&QpL_J~s_5_`; zNfJlgDY0rfomu6gThSiceHC9qgb|+FvNF0tPltci9X_x!FOxDdwEWWqT!kIp+iuj*V4`yst60G~^dT@MkK8N4q?FyUIY^Jn08Jt^QU+*QE{LiqOEn5bH9$9jf>* zxXqXG(-U(NT}@Y=)J!|56W@1Tv1bc}os`b3!EaX)h(dK$X{;|3*?pm>msO7J+vx+N z>!o1iD3gS!0Lt41H{RpwYzQ&(ZvKp~Y8M-Q zrfD(r8yr{OxwPDX<(xJI z*?Y}+S8SxmBten?9{Ivrl4ws<(NJv?Cd>bAzzOwwbq#Ab9MRMG9dSzL2Zt0pEml?s zAH7OEZ(7fsvC4%1O!^!70*95INm-A=U78_oQ!<3X=MDvxsm9NRpp^glZS@2cvZJGe zn2Ntj>+ED}Arl3_Wo!jT?u&S5t*|7>Wm$mtjv6xN5g6@lisDvzw3C5H;|&$E<+=5? z@LdH6a)W=`r4+Fc7m!x|2mVsvFP5ftn-9`{G*6)3o$6tuyQ?SCy{Kt~$IS=N8n3B0>nuI`n`gmZ&aeqa%0zACo zE)uf;wx4Y0CIt86^V~&QetnK=3({k?5{i4jnhth>gzu>#Ds>;0@5SS49n}}Kba&Tx zAaunJqU10a%-C`2E{Y!ZOv%j`T?Iw?s96XVR%ziYygtHfN7naSB?d$pC@;{M-jEDfG$F_B6y&0(> z6SM2p>Ou%_HE}sogy*d(cUN=9F164U{#ycekTeJ25(?j?MR*qVEjJBxM1@d`tm5*Q zm=3}b8MMFX`InLML;bXTV`+;gjt;qejEH-C5KKZwpxZUdo;KsN8lrd^IVD&F(AY!2 z^=E|u{0d9p#YdatxHLJLKgXrTA6F9rDBSyq12ra1eP9QY{U2NaSRV+O%P9ZC<4m}I z@PQP*Nsh=d=yll?+=|U8U;6WdAMnL@M9#ZTE0_4Pl!{IN_TPjXk)A&LHv4OuaCXxa z^fI91-^f2TOUK#V?g>VxtR1PRX>^;@}4i`#(67zqYKQzn|yyyabOJ$>U94-O;mV0-ofh zT?B}^mAFRuA<_qLFyE}Lg&4qD-k7ET>t>^UcO~b*Cca?q^U~%YxS2u>zi9I5myr;$ zB!(EY!dCCbIjExtIQ@nmACqBHj9vM=(}L-f|F&G}(fAMdzxw0fE1Lp&p5LdJ8g-as zoaui{Ha{%gQvAiX1&sGZR3Hg zonWaq$M=&gl9(_f+pwJ{z*G(rM)Nf6cvuhr;P@6@nm_AJ+xb}|cWxpM3=iUCVE9rW zxVk$e{kabFI1`xUJaJc#=k_-p0Cf@w5A5x^?}h)H95}B1_m=^V%odza8@Y)= zFC%3t0s;7E0^JT$cI_?RRa|HHU9I-n?*yHTqmA7Gz6}rJ&wW`hYR=;UeqX~X|GO{3 z4;=)yVl8zFi+;?FL6DqRy!3{c&!3L&zd3P5e~5~247r1bO8q}U!p4g~@-OCNH)smy z(w5Wf0{l*qZL<+AYJlB8l`6#T+K3?Qj>GOwcgaR>>w!ZU;7ikp+pdrhg^&}=BmjTr zr^;!GHpxlae|0`Y-?!0XHpxXuL3@TWqv@iFYS=2 z;X;AjUH-2cmFxda&XH7PI&Y{u>rX+QHdNO(cIYih# z;)f!^j%8y#q;4DA-KnqOSMeWN_!2k5le80#(pTI>vAGN0)BO)Y*x;|ez;<=U{0CXb znf}*&^ZRGCyc40dw-Q59?ByZ4n)PSV+xSI&x(cjp&4+?RKOO(GlUMjC?=V;iGY6z& zuo62kI0Jn38*!WWSXE=qYzguSJvH&hJ=-Dt`_se#;GCyzLqDBAScx)ve!02fU-0gpBCOI6xBhdHB$n9Ufu;Sca z2wAoSTglZJ;nKoi3QjAX6Y7ti@*QNsp`?pfZ&NUjGSx^PY1q0@@woUV@51ZsqsKkg zH_e!*vWygc*#~|A!CIfWM=e;aYFMyszgpAfSEW`d1T1DI-1nmptE{Ra30xGla}rN2fBFt`@MUirm6Hz3E*d8u7Tr~- z_RDQkBHeeMK_FznSMgiN)o>*CH}>qVi0s7uVq1CLj=CkLhLdEtL(<;Sagxqu4G1ag z^tI=lOH6`#T?Y?;hRkNmxA{Bm;_FQ|>XqtNC$^A9y9&DoA3NFC>*Vd2kuAOSPpvM0 zYLH_xS#gX)5}pQpM_*$p@OUvC*SJd)V-8&KHW??PCVvp zvWgONH-5W1+ge0*)8}S;M&q@h8{VUHqS)(P!N=QO|GU>+VnEIrZ;q4-TBC^fk#diqqZJf3PF|8SA~;un(rFG?Y|G{gYH0@6^R_ zr7jEu{o5P9UWUk+-Cw?c8%B_R=_}K|#~3V^e07W?IyNGLWzZp@?cBL!QN5UA=arAy zzSWTn*y*;q$Bcn*T`la7yeSOU~mESINcPJo9z%mkmzP($G=epJ(4T^w%>q+!9ZYj&2x; zuRpwqW;(UPa6Hz3Q)Vouz5AO~(H82~oqQfTVMXY&`;Cxm!^V(!K2GMT$AF~@LyX8g z?SopiwlR00MKnGKA4vnkxrX^`&qq3co{JWzu;TNN^3G^ccxs||>rBVHrcTSNQ@&v$ zwD#s>rR}3*4P))7?b_939RV8}I#x-{Ro}`C+M%^xU=ql&{!8u-j!-WT)RBI6E|w2} zz16?4J^JNdA|0*ve2p?zCH|sclzBtyVp6G{tZb1ys<`OZqSVRb&rNJ~a!PM7PNoX3 zyXm1#u8n`j+W2C}$V57OJJPGk8+(AqR|Zt5vP?iVTY}rW<3ebkCcz+LX?53_7yi0-r6lj?Wte1f)gx*40e35CIyOr*ed#MqCunBKQi zS2ucGokHn!C6p{0q*;*VrS4qYELbed35Hh3rR zSid%x=q&)1(OL=XB5M8^H^r=h)#vGd@1t)74HwI0O7Kko4DE_&_6b^@)HUfaGZ9}2 zhAFchbKQG<(NKPp-$>(XIfkdp^F&Bg=U{~|z~@)<|T_QDq3?($Zk z%|#N!aYcvHOE2>m&Dr)}P+0}t6E4|C0BvHhxBhMTd8tG~7V1)}hN!Ku7WjWi8hL^y zuV>z@E7i_+i8gjrHmGOZMCW>s_H^P0tG5#+c37c!Yp`WrdHZPc@b!Zb`1LQoOZ+%j zcR)(Bp+)RJ3~`F&_m>IHYH`3oSgH9-Bv*0fHPeRnNsbAeUGc|JTJc0tU%Es?RW#v; zfd!k16&A=|ZHmzq%X(pO3XU*xHaG?7mi%#eGIdd|tcTBEhMzx0N83s)kvq}^Nuf27 z{*aDWr)^|p>|1;H{Jij6xjNa;v+o7-=4O7D6>7Z=hXyV`vu}nGBnbGJLE+J~+xIX3 z4`q#4{!M!y&)O%`Or}P{e_{gzyZ@|e@znE_J(VdKdp;K9ZHGy4d}3XFg3%|^+p|5EW!x=!c3rGNwRjyjaKO9gDPXtaJVH5p!2zfI+?^im(gm_LCCPZTH?C|( zP6t-&SbQ_P(Gcb>!TtshAZ2IXr5%5c>{f8?U;2hBPNpwh$n_s&qSmmJq>L}PFX-`W zy}S!))DTd4VgZkpPe!3n}~#c8<#;fiCki>N;o_o=a?^$%O-)$Nw;4CO zbRJlhaOrdOk!u;YhU&-xQHX+s@KzLrQ{gkaXG_e4Bu(Gla=A;?nPIo@L{($ljFa%O zCQ$+ni6DVLby!Zi;oV9`=67PIg4@nARurv1nfl6d^`jliBydAlOy|00E>fAp)?tn! zB_+GxlFR<-g9j`+a*zy=37Nf{?+snsqX@Kse>YmMY^6v|C-$Ik{{$FifCFX}D_H8d z`(*`uZzBK*|Ax(7%dCgnFOgFA^xqAF!H;eo!aBj`CxhEkYG1t$&#MOK7p{BZ zElR2wYFb?k)hb}i`*!ye)jQHK$4-)GOK&SC7Zw`$_pPR#7d|`VX0%aLYeObNsr3wP z3;KX4)UJ^VENB7+Ys&`;YJXG&Ip=X85Fmf^3FUaiz79iDO!>C0+~_)I@3=|NOz|qx zv>|VH_N3M$OG-aa6obxYpevM$=0PR_=QycCJ2A?5XQ;h+NH;2vf!^MEy=UN{IWB~J zcFp%f(}l7%@ifYHwa78a-UzI2;Whc#v%1=tXIeAGo+fthLWX9jWs};%C5!sd_;}We zt%0DiWT+TA`C~yt*&&o2x!n!t`+t_WTSgr9uq&Ee<;h=zbVts3weqKBd9-e%X%X2XhMQi z;}YFS7tSVM3g+_IW9QhpeC)=-a{6F~?Lc5^^oO@V)evl1RX$lg`6_ao_SLksBs=dR zEOmj&Q!LCLAa?~^;@)K378f9t7~|b>P_n*5mv?aD|3}t!$5Z`(e(%LP1X!OfYH(#S3i8XA&n+_|uSyvevmw6ZqgX4Y})NL`2)yQf7SOnzk8+{;qv?aRZ7Tdt@ccphjBd@#L zY_Gx^)=m#7H@{0iEC9q+s(d14YdvHbq$?%E%il>}+#o%oWPgNUa-3rnr<-U}CMss7 z^;j!9#Lc!NR@MOV9=f^~R}MX`bfxe3>omItqmC`#Cr9$H%<0OUGdIuxr6!A{S;gX! z1bgRiFz2=dN#DUYkb&2>Quoa>b-Tw`!BSKafp@BQ66@v~Fz^h4jz-+w9C2(l3n^4i@;7S_z6 zvoqjd$2O5b8v0^J0AK;azS~IzfC82Aa>={gNP?O=GIl@(fNhQf>9>}pRBG!pdM5}i zESx@xzOoJ>E-u{gFWM7%nVNA1$}J+UPS)>6Ry!yRNMh|s4@nCaNi&SWfZM41cz`Rn zx>`g<69=ln#yOZA}2s%0~_A|H=s*&0bAcd}U-{9FBcVP>EVs3uFP;MG(q=9A)LVQ8N{ef8?kd>=oS{%Drtxi zYoi9dTj0id6`c*F>|p46f*x+GT_`+H80oKRpbemVoNsd^tZt5o^f=Z^u>%daTsnyW zCYu({4opM_?d{6YKS=&zPNB!jlLHA%QS;j{=PS+<`no#ggn`*VI700CB&VlzgMF_ zsXhS$Zo}(d?;E5?wd)M* zddibCTnQ(rfvHms41}VPzePToK<;R!?npoIn;=6Mh~#82EsdDHnW1C*VcotOF{pDC zXPoqJgBA<)=qPRU(#9_5C=jt}IK&LZdT@B%;RGsz&zy2#fFam67>`{8uStY264nb8T|0r5b!U4j&KDNO>1YX?w(16A%DS{!0W9< zsl^qmxVA?%5j4~`ewokAe2d0)^~GOrn~jb4Zn^i$Dy3vRg8?>Lx>@WApu?d~`{8qSprsV5TPFe7OaD<~ljr~d!l8Sa zQqcAR+<^Vi)+rjo0>?znuP%zflZd5A3#+@?Gd&ywJT>vBwBfsA z+2)hI=Cw9903z@gNFhQ@{G+ePWzQ({my}XOh5HcQh1L(C+y`cSa^=E+FCwc%yu_@j z@Ob8&F!NNkZz}JE@=UCTn1IXYMUe!mC8(cDVfz+z%hjAtvCDh|&-UKCcv>M3x8L3* z0iB&I5}$ztY%`<7A@%u2(0o_)|7{R71@k_b(g4jKmPs z6ywu=Dj@oaH~}=zO3pkq^10&7~^% z*o}53A~`VJ(F#RkekSL~Q`Y-U@^2oXD#__?4Kg{eu{Xvo~aILNkZvv|; zte)08v#2fi&ag*p-4!;E)l5vd!vjR`78`Wx9QOiHLmOS7iHqCrm^VITFq4?GN28lL z2;(-#i)aZ?t>xbCNb2126ofcV3`gVNnXybr#1{1S4G*t>#yyE3yVf58_MNk)<|V_= zFS=V^;|B~b22=l=U%VLGfZ-jy6=?GRoTeD=w5^UU6Smo&l%U@G(@yPSlZpJ4dn1~o zCCoG0%1R$?D8<$ll3{b|mf84^M_Fk!dD7xS_A|R3$)FTEd+4&o=?zppT#J~bXTL$X zWWhqlKThkuw07*2*yo=VaecH19!{V}TDX`0k6kTusTqE9tMRq7wf%kT7kkHFX=SvE zDLe~jA`s79Tz+pZg^-A|D66!sJfspSbB*^Xedc5Jv{?^q;lJ$}iN5e1FD_Tza9WNN zfD**yAKV%vaSrA1^f_Rg5#3p_nmMmTWj-(#wxDwGXJ35g`yzG|67Bt|jt;f-3Ct+g zWP#$cHOp%J%&IL+LPC)mV#sj-p`>TRBTPJWUTEfst_g-{52khtrM3Tfr7@f{OOqK` zt@l^$1ArcX{WG45igtf!v<4!6%Zd#22#Kjw4gTn+y8k?vyv-M(qrZLYuNlX~vjAOC z^NPx4m%?QpaefGhZ{ex@KIbBNdbJUHw+WPKxYl76j+AWcLg zE{eJARvHw%Cc0NpjA%X%R95xH4g-XsT^&n`MIh2nA$w_X9KM9LOSAwM%8{l1 zVXUrXoM7wrIpHBM0`ji#Y<>(kDmLm<{cnCLsRUPY_g~(dYKJGVC@M9tQ+Xqn(AAGr z*=hq`7~1oe5nEppqTO z&2AM%0`%>FqWkbxe#SuxB+X`^sTrx5s;!Z01-xweA{oPhTZM(Zm{ENfzrXqO3%ium zN`Dac;g=vxVUwzM1CxU#muxw!@4lv9LR?}CneWf4z4_EH2E)dC#fa3~#W(IrsAXhj zHF4OC5J0A@v014ZRa0Ej5*sD16QPL4TROQe4~^1B0yX;DEZOuOyE77TpFO;J=c(I@H6g40o%4 zVhxGz@~i7Z_m2S%>VJH>y8Q(%_T1rRV~&40HWUvAy}GE{&BUd*J^#fU>%JzTSabmV z3?wf>5wUV0!B~=rCi)}E&S-of z(D;xE;2iS|#=lavzvkvJ(AO~p?iIxTh<&So0kcULxYZ!H6+b=aY6E=?x`*1Ts@e-p z1NZJAsr#_qyUe+9A{EwYPu(@{TnG#3ua@3x4q7zRD`eXE=?#gZsEm(%_5yK)V;Nrt z4eUj>o}OB7j#6-Nn`LJwX(Sgd#`7)87X+jL4n(IyZ8Zo=zidzTGUqz1iydo;NS>jT zpBo@G>`oY9f`#}(Vz9Q)glOu`wf<(z5UlD9d^R*&hyuUp354rbIx%e!)mIj5spw{% zx5trF)~7sjqY^}ygE2QX(wCqYZG7v%zPw@pNCn>QZ;`ao4vP#V%S9M-`}jks6$mlA zUn#tNhK%LROgTSOfzkr8S^w(hW<5R$)P>r%&LO7f7(AD%N*vZ?H8SoU5&g}%%KzkI zlHC_V-}eA#+iI!uuy%X&w0QC_@)gL+?rDCP&dfY@Yp=|YbXqYx0rzR=?tlW8xIj;> zT(ou=9o61iu)cp=o%fBx@l?9wb^~>|O*{q!JIpFvYF6yM4%}sjAQTdGzK~3QZiM7l z7$VAG*9a;J-x`OYp5*bHYoCAU`{+|4^kNaX?$^mn&?E-D&Gr}(;tuw*8{rN5Y4HBe zNF1;t>}Hm$gcAhy)_WuJug2;v{i*5Ky}o=VTwa#oQ+Q$$w0Nao4~bgAK~MWPF<{I+ zjkjW&m-#|u%9xayLhZpNp|x@*--__i!CMgB3}xG ztx60XHUn~KI_7r>RMi##irV{NiSg3wrc;NrS1ON z(|@`PpkK1WX<5>Z`19aluU(?--}3iJ|D~YDMg57$=8H^_!TcMxUlK4e;5B!G;u=gs z%K>C&zMj{?&U2p2;I2>qHv;wR68zh{&N5@AdWPU{a_W~avp(3@E-#~Xo`_CsZ7tnPSqk~$xwBIRh04F~CpAJw zgLU*aS}3Mw9d*eh65!>cw=-Q+waJ!AtG25QXd$$ISdYwLe@qZMswht8OA{>mwq=|? zShXJ(*XIH+?{9vKjJww$nV=j2#+DzppLW5^ zs4|rRRDm^ObEpsN_HZ$$G~_%|`~wi>dMgg9|e~Fvd_AtJQUbC$3UlpYB?Obzh!a&1vuT zOtrth$(^{%RA|xfcKXlW`setO-PsL-t^Ssv)C)!RSxI4~hn=&Ma9hxOg>xix60l~~ zU32^Qg!Fb-fv`liT>7Zl0z+jKXglHd@1hd!BcA=}u_TVQx#?_vq+NJrGBe5WVJQ!m z&}vZ0cZE~t2K&^y!FtxGDG~Ks{63#q-SP@aANMTw^Y_`lk54*z+Fk|)*>3&@15UP{ zr`?-UedLq*eP7knt=M+DWbw{Xdsw%WVnCzDH7w3?@f{$Y%sxpZy{TD&ON09%`F4Bf2KpX)>Ofn?4#+DqR*M9!C2Ytb9 zKGR?|Dc0j>vcWTDgdt6`-XC}MLEYc=e)c{mtWtdV2G7u;$HNX_9~zonsx5(c#W+S- zgbo}Z$~(4B*-Ig@L>IZ5bDq_>)W4-Qa5)>zL8Fk{oN|0x7va+=S{{b-dD|DGp zL|Vk4HR!GZDg#k`{XtC~s4(oVlbNZ-91M2Qm&n$s97-vNcAoT&fQ(DrcEb+3EU}+V zXuJ-`Li2WyCoOHCM3$pfRJ2uvIJq$oO)P&)wjVw=7bVpAVDnJY0*{D@#A2Y>YCw15 z16dlA#|qa-?EHxLR|Augg!fi1@4KPD^ zDln-K`%Hxb&PeU`Kx zqt?`n(?$rS?-HSR)o!|VFjSiM2B6QVzuKv$*={z5Z(dBS0m-&}Mx8OFHAT3$Of3=d zD1vi#hXiA2Wl0Q`6U>A`mF71UX^jkIso%u+2NpM>=3Bi82RPu9$OgC5pTGt~cXLNW zGjhx&YT#wFV?+&Q>+$iBd@{@;W2J@Fsuo7et~@Q2#DgKb#JjMS7}ikhJFnJA3GCa1 zg=LaA(e_clj25(DlHeB>5$CxGWUxP0QqR@=zMDQDa+=2^7Oxuy^!Brl9i8k#D1DDI zdZiBg+-@rVX2p?ja*uh~ceW`D`o9UQGoP916?-RF{~j0r^Pru@kB_6X1|*b}#ydlh z$Gk=t=^!$NznUxzr$R0Is5zM}KI-C4br5P+QNP~ zXzqo*^)(j8*!am$bw6F0k+K>R>T=!00DIUVtAS#`m|`7j+CEII=brvmiNGpF|M2yA z%bU(LM@ME88~>I+PXQI&7%ABqfOR$3oQIuh*ba?!1-x6CvtPhMt0e8gx1`$CR9ddG z!pWkRDgkjP4qZBg* ztXLn1g8N6zq=2s7iFY<8W_VnG=QKPE`Ij-ojMp{gv(VLw{U9&jWL>BPo5A|=f&s%l z&9dAZ{Wo|jK^q#U;+O708Gi{-Zq!u8@7kv0mE5yi%oYqQ;N=e5QtS_GG-zw)>;nNmCb+8Px{2J-joe7jm2SYk8WLAQpZ0$OW|Fq#QRwl~uygxcA;g1SBT9pC$>IgPrm|JF}DJnq*1 z7UtyTZJhGUJZp$6o^Emea;clpg+RRG&WZQTZPG3~Lrpl3y~oBPFBpKlUd%-jeXmhS^} zV$NxunkRn7zQx6j^jKw(N3Hk#?{uL1dJSHFCl0SGv2e**HlJe~Z@P^7vb6MB_J@IB z{NHhNqeX#)J@?}!z`ktAujVm!31Fhk`p%4bA+P@u<0D@% zbE6>gGA0j#D@uQ8g*Fel?mIE59!hSeVvxZM-r_-ww!0KWv74ln`T5}vOrHtaPn!Cf zu|xU50M5I&e-YtQP~fX#iZ0)nYp6V4sWl+cI)2~eQuQB^hQOvNlP@UL$yRkwXW^*k zn~Hi^8Qn%?a`M#-R#vYljyf}`9`2RtP58?8QEo*2`_Yi5$j2$dn!J>*!|R@l*(<&+W+&Lon7WhSIWmkW?)98#2z zmu|9}{Yt!ynsSks4G2n48QzC^gyRT)v?V1?uiB{e-Y-r;@|gRUy0*m+5+2(zoD1n@ zW~d!~Ip*INO-N4i^KWH?QXA+fO^m$C+Wj%ca6uoHSMWBP_4B%>po^ zM3-x+KV*4B<|IbW*=`u0JUr>-r9ltL54A7@pUsxdHF83WbZ==yWk;yV;22IfBWpK5 zj40mf@N|J>7O-uzM=63Sro7vY&Vl%LSn~4{TeztgMNZBBAB)<*$_2+#DtY8mGA~A7XSmSk#ADnMv zW+X;7OI>}B%DswS9;(?#uf+ZxJn5I(WjSo;=0Wg4Lk% zF0dRv|0DFp6EBWtn{y+mwe6nrzMIMSz*)P-+WkEyDXFWFdEc z_NiiLsO2AZqIX$VOgtyqLLaLRKb1$7)1mb^exKCINEq(Sl_hPcyS`aiUj_$cu%B!N z#Q@wU(I{bQS+n2E<689R`;?ivtw<6_i9^B~({4dV5;P7L}i+$M)gFqid-LU*i>Vjj8s;BMO7! zkZ+n@vbSXeXfBuFw~GQy`qkBw*x43LCD)8w) zt4)3d@{J>?dn*Pw_tX?lJ_}uDEyhm#2@O5#T7R}VVQ1)bZoXd6g`FV1-{G&4j?%=t z7ebBTl_fc}ybOGT;=^L1)P2g60jng~=`^=0DXzYHO*?hEb?{S+^9?c_dtJtq!t@RGoYBJnxusR@fmC<^vQgqloc zx`E}KjoDEr{YN+iv|eyS%(?v)a-_eI8)5NqkXG{U-*saE>dCl_sR3Jq%!^fr_9C@6 zNhRvI*dH2w41WFa=B}(mb8#FfQx{?&gXl*>lHfER4m+rQt($6kei6c#>G|;#!JTqchrc5ygJmhZi5vmLrI!ZxvC zO_(1Y5|EDIMx2ttzf)6x;W;;s5~t9Or_*;NgiR5d)l6YX8O+wmleydCt~Ol9F#+Cz zVxh@VK^>=dOP1{-fjwCjhe-+qbz+N@PM?I;tl_T0bVo6Q7tZ3L*QZ+72t*{WDfrkNc&if| zS)X!!pzOosk(pH)98*GuNG_6~V7e(etab0&2&<+wy0r0fGpYZtD*{Z{YI2jL88eS$ zJ>rANtCz|pm86O(wFP5j0n}lk9C|{ClRY{3ReGdPYh0i_s%>Zw4pUyG=)29g_72_E zx7KxR&7838->$c|41UsXKz!}h2&T|%RC78A$X72eD9Ga9$;Oow5t6tWLVYP?*Q;P! zVMP0>X%I~r1%XezMEo%+i;0Z7m}GR-al^YLaBELTT)Ow}_$%bbpS)KW%l+f9ZaE}9 zwscow`ySRT#~KF{Vk+<7OI9Gx&X;F}Q&QNER}aLWDKMf&uJjE(zbO~iHF_!nA7Cu7 zz|ZINt^y5GUehA*S|<&v=R$88^U~(-exn^iqi={^W>MqA!t3W+-3Dm*Ja}HVv|?r_ zOe{vJZNB_W$XZcXpoQQ^T9wq(T>9rM{373XOrdVxJ<*;6-!Nv4c24vja7xergb^Vk zP9L@1I7U8ldZz9U@-$}l>7~DjvzY@+pPGtY2n^CiQ~TGREdT5~_0x1ys~UmxF+aYe z14}lA(JI59Sz3Lb#aw=Gs3`-P-V*5w9cv}nrn zJ_8r@c&_nJFM#AC5v&m1P$?~oEi!1HN!=;_ti|Cjn8M41;!GWuhb&yIMsS03vmB@M;HNE`W@+aEm-!E;Z((SQO25WjW7ltl!wy5AYQp?+zet4&qS!g2wS5h8q zXrj;G^7ilUIOcFEsw}v6EfsZ-)dm$BEFsOFx{2n|pvkA_Nzz?7&Pb-SGN%&TwL41e zhGLy)LJqrvbN!^pn*iau`#yFPm`4US-Xzba=KP9GQe}yddj-4NM?B*8`5k596`Z(3 zuz9~M#Wf+oggFgkGRp|z`Z`{Gbi}enMKRO+B4KGc-F^eQo=T4kSSf6&90$MKGy)jZ z+({kU8{WyI56=>wY|qE06c;mF(omaEkuFg zdMe^j@x8d4A2NDwe;u-;I{5w(|8GI*x?tYcFd62mLII42X z%HbKtkqMdcT%J|xu$RkA<0@14`Gc)RqZdPHxpKmI5Dm|tljc@jfOWbUWCh3iu3QYL z8=GWedcWl4V}1`CaQ-;t=cy#zWecMgmK4aHaasQz57$9sKc-NXp64nT6mVS`awjRw z3Il`iy`AL5#^dw_QiF z+~m18(rJhKt40}j%pUw}TIzqx7hxR)+@v!2W|_XQzAh_96b2<4PB3@!xnD~I4@8%j zz|g-7ICy<)o%`*2cct?=H-6~U7UD%)?x9dR-r2-it`*9%aJRfSN(_dQ( z8@b?acaSa-`t<G&fP}a5E-YAm_x!ljf%tpDyTe`P@#@qQ40y`#@yw%3ydGJh74y z|8(83)5A7BwBeKePQQ{IyhdtCn<kDB(EFG>Px z13#6)?C9bc7P3YOlGnlYKu)jcdCO%AK(OsOab;?b%K94q>67DnmaEkqbDe~tL%ffs zAW?cdb@?CWi8V5&LnEssVZ(0b?hF+MPzQdV>pd_5cy#!H`}uX(v z%|TgTgvn;a_RRJoGe4Cr<=8MX9Em)+yn$SedPuY8pM!6Be>SX4tIJtjHi_{BE<^b|=(yI=FGd++~ycn7H`6pOtr0Q=#UxQXI_cEAHFW3GSg2?Tc1 zBmvvFZ#xO$G6%w33N(Ot)dbd!LDap!l`B!^F1GT3P1Trg&6;Hma((HxH^*A<3Tdbr ze(-{>K@7$&7}q~1@+}vd;GWDsF3#1b4q5FG{|QMS7uh>1o{O&Gi`J{dS6Abmi}p3O zU&|jKK;{*?iHeBS8#G~468z`^W>1_QiRt%T(8c;UUio*hc{3sRaRtD_YC`r2TSo~e z5mjTZhA)M#7TKuq^n`NrgXwu0Gck29^HXxp30Wv11jF_D@Lwj*q!O}>z!h^%h{v}Dly)6p`Mw-$l*9Bin zqn;l45BMS$3@Q2o0Vj}}73Dhs72_0Ju;z2W^cNla*gAMFDqWkcxR$?J$CvYH0vF;i z_7n4W6p~OUCc(qbHFuvNf6Yj9x~atz63UCfR9wI4KT5&LC z*K4FXZIX7ljGU#gaF{1|K`Zy*-U%2`Vgq<}CV}R3 zqMsKW1bRl1a$eXOK=y^8%9@D}JRd&GFLhFiqTRtOuKe2q5rBH9rZz229M3bhruHIRT!;=N3 z@B*1^laXhxz#u?tn~=cg(tpKx0VYQW64alY!PGcrrT|#+9SZ5?6Oo;=i|X`3$i=8G zV@U;pBPtRNGmD3`J#b4;hZWdveV~D7u!PW!H`JHT%;D_}M18`?;dAgXq6bprL=$Xf zU=Wi)9M+$+FOSl4dpM>4WUc8K6O19o8Ude&z~oTgf(7|a`xk5xa_4}~^%1U9$gla9 zza=N|(hhWVOh|~z*j31NjMp?KyUpQ76@`%rYhYT@!R-+yV$DOA63>M1wc0Sxen@ER7SCk3t%p* zq;9vx!S|E-$BRCMzfOmovURF*=1Et(*zusT-bA@hTS5WM+Q4m0ar9?x;Pc8v?hezG zJM64DGub9~cCZr!xm{D0m5j6EcDbL*E+}2Yf+_&m`2(|0WCZ~8t*oDC#By`@l>}fp zbr3f6RYOciKoBd^!08&9X4iZ*oE0I=oT|aSg8FiB84T7!vHR$ix-~6UH*X)loL}^7 zLShWnbr4(e!UN6)X|dx_R!>#3Wnu>Z88j0!Q}-Np&^la93R~G^W9xze5TM*R49}i0 z4fB3I?CQ4TlGyBv9GYAJF)T^dbnV{=kOtgy4!kA8KzY%L0oda2Kx;eI8&<�q4vZ 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 NGIBd+xYL5X9WO{lpXv=p9h9Gmh@x2=194Okh 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 Gp$P!M6r4T) diff --git a/deps/AMICI/documentation/gfx/logo.png b/deps/AMICI/documentation/gfx/logo.png index 3f22c92a86dfab8ef38424cd523326b375f196f8..7810c1e7ce87520128e1e68c487edd38d6ce0b9f 100644 GIT binary patch literal 82428 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 RCGa0e>9Lx8xvY8U{{a9e&UXL+ diff --git a/deps/AMICI/documentation/gfx/logo_text.png b/deps/AMICI/documentation/gfx/logo_text.png index 22354e62b19531d2a70857385557b5a431e0336b..c72388e94128944e67d3c05dfbdef8197147698c 100644 GIT binary patch literal 92837 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 YoYZZe{W-f*n-eQxH||`oG`#oZKSMJe8UO$Q literal 97163 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

!{ri9M2OIKZV1LK9KTQ6 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 &llhS0, AmiVector &xQB) const; /** * @brief Updates contribution to likelihood for initial state sensitivities diff --git a/deps/AMICI/include/amici/serialization.h b/deps/AMICI/include/amici/serialization.h index f816d5663..7906a2cc4 100644 --- a/deps/AMICI/include/amici/serialization.h +++ b/deps/AMICI/include/amici/serialization.h @@ -290,16 +290,19 @@ char *serializeToChar(T const& data, int *size) { template T deserializeFromChar(const char *buffer, int size) { + namespace ba = ::boost::archive; + namespace bio = ::boost::iostreams; + + bio::basic_array_source device(buffer, size); + bio::stream> s(device); + + T data; + try { - ::boost::iostreams::basic_array_source device(buffer, size); - ::boost::iostreams::stream<::boost::iostreams::basic_array_source> s( - device); - ::boost::archive::binary_iarchive iar(s); - T data; + ba::binary_iarchive iar(s); iar >> data; - return data; - } catch(::boost::archive::archive_exception const& e) { + } catch(ba::archive_exception const& e) { throw AmiException("Deserialization from char failed: %s", e.what()); } } @@ -314,19 +317,20 @@ T deserializeFromChar(const char *buffer, int size) { template std::string serializeToString(T const& data) { + namespace ba = ::boost::archive; + namespace bio = ::boost::iostreams; + + std::string serialized; + bio::back_insert_device inserter(serialized); + bio::stream> os(inserter); + try { - std::string serialized; - ::boost::iostreams::back_insert_device inserter(serialized); - ::boost::iostreams::stream< - ::boost::iostreams::back_insert_device> - s(inserter); - ::boost::archive::binary_oarchive oar(s); + ba::binary_oarchive oar(os); oar << data; - s.flush(); return serialized; - } catch(::boost::archive::archive_exception const& e) { + } catch(ba::archive_exception const& e) { throw AmiException("Serialization to string failed: %s", e.what()); } } @@ -341,21 +345,22 @@ std::string serializeToString(T const& data) { template std::vector serializeToStdVec(T const& data) { + namespace ba = ::boost::archive; + namespace bio = ::boost::iostreams; + + std::vector buffer; + bio::stream< + bio::back_insert_device< + std::vector>> os(buffer); + try{ - std::string serialized; - ::boost::iostreams::back_insert_device inserter(serialized); - ::boost::iostreams::stream<::boost::iostreams::back_insert_device> - s(inserter); - ::boost::archive::binary_oarchive oar(s); + ba::binary_oarchive oar(os); oar << data; - s.flush(); - - std::vector buf(serialized.begin(), serialized.end()); - return buf; - } catch(::boost::archive::archive_exception const& e) { - throw AmiException("Serialization to StdVec failed: %s", e.what()); + return buffer; + } catch(ba::archive_exception const& e) { + throw AmiException("Serialization to std::vector failed: %s", e.what()); } } @@ -369,19 +374,22 @@ std::vector serializeToStdVec(T const& data) { template T deserializeFromString(std::string const& serialized) { + namespace ba = ::boost::archive; + namespace bio = ::boost::iostreams; + + bio::basic_array_source device(serialized.data(), serialized.size()); + bio::stream> os(device); + T deserialized; + try{ - ::boost::iostreams::basic_array_source device(serialized.data(), - serialized.size()); - ::boost::iostreams::stream<::boost::iostreams::basic_array_source> s( - device); - ::boost::archive::binary_iarchive iar(s); - T deserialized; + ba::binary_iarchive iar(os); iar >> deserialized; return deserialized; - } catch(::boost::archive::archive_exception const& e) { - throw AmiException("Deserialization from StdVec failed: %s", e.what()); + } catch(ba::archive_exception const& e) { + throw AmiException("Deserialization from std::string failed: %s", + e.what()); } } diff --git a/deps/AMICI/include/amici/steadystateproblem.h b/deps/AMICI/include/amici/steadystateproblem.h index 3629a4702..bd7efe47c 100644 --- a/deps/AMICI/include/amici/steadystateproblem.h +++ b/deps/AMICI/include/amici/steadystateproblem.h @@ -248,7 +248,6 @@ class SteadystateProblem { return x_; }; - /** * @brief Returns state sensitivity at steadystate * @return sx @@ -321,6 +320,12 @@ class SteadystateProblem { */ void getAdjointUpdates(Model &model, const ExpData &edata); + /** + * @brief Return the adjoint state + * @return xB adjoint state + */ + AmiVector const& getAdjointState() const { return xB_; } + /** * @brief Accessor for xQB * @return xQB @@ -372,7 +377,7 @@ class SteadystateProblem { AmiVector xQ_; /** quadrature state vector */ AmiVector xQB_; - /** quadrature state vector */ + /** time-derivative of quadrature state vector */ AmiVector xQBdot_; /** maximum number of steps for Newton solver for allocating numlinsteps */ diff --git a/deps/AMICI/python/amici/petab_import.py b/deps/AMICI/python/amici/petab_import.py index 68fb53e3d..bfbbf744a 100644 --- a/deps/AMICI/python/amici/petab_import.py +++ b/deps/AMICI/python/amici/petab_import.py @@ -459,6 +459,21 @@ def import_model_sbml( sbml_importer = amici.SbmlImporter(sbml_model) sbml_model = sbml_importer.sbml + allow_n_noise_pars = \ + not petab.lint.observable_table_has_nontrivial_noise_formula( + observable_df + ) + if measurement_table is not None and \ + petab.lint.measurement_table_has_timepoint_specific_mappings( + measurement_table, + allow_scalar_numeric_noise_parameters=allow_n_noise_pars + ): + raise ValueError( + 'AMICI does not support importing models with timepoint specific ' + 'mappings for noise or observable parameters. Please flatten ' + 'the problem and try again.' + ) + if observable_df is not None: observables, noise_distrs, sigmas = \ get_observation_model(observable_df) @@ -574,10 +589,10 @@ def import_model_sbml( import_model = import_model_sbml -def get_observation_model(observable_df: pd.DataFrame - ) -> Tuple[Dict[str, Dict[str, str]], - Dict[str, str], - Dict[str, Union[str, float]]]: +def get_observation_model( + observable_df: pd.DataFrame, +) -> Tuple[Dict[str, Dict[str, str]], Dict[str, str], + Dict[str, Union[str, float]]]: """ Get observables, sigmas, and noise distributions from PEtab observation table in a format suitable for @@ -596,13 +611,13 @@ def get_observation_model(observable_df: pd.DataFrame observables = {} sigmas = {} + nan_pat = r'^[nN]a[nN]$' for _, observable in observable_df.iterrows(): - oid = observable.name + oid = str(observable.name) # need to sanitize due to https://github.com/PEtab-dev/PEtab/issues/447 - pat = r'^[nN]a[nN]$' - name = re.sub(pat, '', str(observable.get(OBSERVABLE_NAME, ''))) - formula_obs = re.sub(pat, '', str(observable[OBSERVABLE_FORMULA])) - formula_noise = re.sub(pat, '', str(observable[NOISE_FORMULA])) + name = re.sub(nan_pat, '', str(observable.get(OBSERVABLE_NAME, ''))) + formula_obs = re.sub(nan_pat, '', str(observable[OBSERVABLE_FORMULA])) + formula_noise = re.sub(nan_pat, '', str(observable[NOISE_FORMULA])) observables[oid] = {'name': name, 'formula': formula_obs} sigmas[oid] = formula_noise @@ -617,7 +632,8 @@ def get_observation_model(observable_df: pd.DataFrame return observables, noise_distrs, sigmas -def petab_noise_distributions_to_amici(observable_df: pd.DataFrame) -> Dict: +def petab_noise_distributions_to_amici(observable_df: pd.DataFrame + ) -> Dict[str, str]: """ Map from the petab to the amici format of noise distribution identifiers. @@ -689,6 +705,10 @@ def parse_cli_args(): parser.add_argument('--no-compile', action='store_false', dest='compile', help='Only generate model code, do not compile') + parser.add_argument('--flatten', dest='flatten', default=False, + action='store_true', + help='Flatten measurement specific overrides of ' + 'observable and noise parameters') # Call with set of files parser.add_argument('-s', '--sbml', dest='sbml_file_name', @@ -740,6 +760,9 @@ def main(): # First check for valid PEtab petab.lint_problem(pp) + if args.flatten: + petab.flatten_timepoint_specific_output_overrides(pp) + import_model(model_name=args.model_name, sbml_model=pp.sbml_model, condition_table=pp.condition_df, diff --git a/deps/AMICI/python/amici/petab_import_pysb.py b/deps/AMICI/python/amici/petab_import_pysb.py index f5aa22dd5..3d33906e5 100644 --- a/deps/AMICI/python/amici/petab_import_pysb.py +++ b/deps/AMICI/python/amici/petab_import_pysb.py @@ -47,8 +47,10 @@ def __init__(self, pysb_model: 'pysb.Model' = None, *args, **kwargs): :param args: See :meth:`petab.Problem.__init__` :param kwargs: See :meth:`petab.Problem.__init__` """ - + flatten = kwargs.pop('flatten', False) super().__init__(*args, **kwargs) + if flatten: + petab.flatten_timepoint_specific_output_overrides(self) self.pysb_model: 'pysb.Model' = pysb_model self._add_observation_model() @@ -108,17 +110,33 @@ def from_files(condition_file: str = None, visualization_files: Union[str, Iterable[str]] = None, observable_files: Union[str, Iterable[str]] = None, pysb_model_file: str = None, - ) -> 'PysbPetabProblem': + flatten: bool = False) -> 'PysbPetabProblem': """ Factory method to load model and tables from files. - Arguments: - condition_file: PEtab condition table - measurement_file: PEtab measurement table - parameter_file: PEtab parameter table - visualization_files: PEtab visualization tables - observable_files: PEtab observables tables - pysb_model_file: PySB model file + :param condition_file: + PEtab condition table + + :param measurement_file: + PEtab measurement table + + :param parameter_file: + PEtab parameter table + + :param visualization_files: + PEtab visualization tables + + :param observable_files: + PEtab observables tables + + :param pysb_model_file: + PySB model file + + :param flatten: + Flatten the petab problem + + :return: + Petab Problem """ condition_df = measurement_df = parameter_df = visualization_df = None @@ -152,18 +170,27 @@ def from_files(condition_file: str = None, measurement_df=measurement_df, parameter_df=parameter_df, observable_df=observable_df, - visualization_df=visualization_df) + visualization_df=visualization_df, + flatten=flatten + ) @staticmethod - def from_yaml(yaml_config: Union[Dict, str]) -> 'PysbPetabProblem': + def from_yaml(yaml_config: Union[Dict, str], + flatten: bool = False) -> 'PysbPetabProblem': """ Factory method to load model and tables as specified by YAML file. NOTE: The PySB model is currently expected in the YAML file under ``sbml_files``. - Arguments: - yaml_config: PEtab configuration as dictionary or YAML file name + :param yaml_config: + PEtab configuration as dictionary or YAML file name + + :param flatten: + Flatten the petab problem + + :return: + Petab Problem """ from petab.yaml import (load_yaml, is_composite_problem, assert_single_condition_and_sbml_file) @@ -210,7 +237,8 @@ def from_yaml(yaml_config: Union[Dict, str]) -> 'PysbPetabProblem': for f in problem0.get(VISUALIZATION_FILES, [])], observable_files=[ os.path.join(path_prefix, f) - for f in problem0.get(OBSERVABLE_FILES, [])] + for f in problem0.get(OBSERVABLE_FILES, [])], + flatten=flatten ) diff --git a/deps/AMICI/python/amici/petab_objective.py b/deps/AMICI/python/amici/petab_objective.py index 7b4d4fcf6..2039d6803 100644 --- a/deps/AMICI/python/amici/petab_objective.py +++ b/deps/AMICI/python/amici/petab_objective.py @@ -262,7 +262,12 @@ def create_parameter_mapping( prelim_parameter_mapping = \ petab_problem.get_optimization_to_simulation_parameter_mapping( - warn_unmapped=False, scaled_parameters=scaled_parameters) + warn_unmapped=False, scaled_parameters=scaled_parameters, + allow_timepoint_specific_numeric_noise_parameters= + not petab.lint.observable_table_has_nontrivial_noise_formula( + petab_problem.observable_df + ) + ) parameter_mapping = ParameterMapping() for (_, condition), prelim_mapping_for_condition in \ diff --git a/deps/AMICI/python/sdist/setup.cfg b/deps/AMICI/python/sdist/setup.cfg index 735b68e74..8e8fdbaea 100644 --- a/deps/AMICI/python/sdist/setup.cfg +++ b/deps/AMICI/python/sdist/setup.cfg @@ -41,7 +41,7 @@ include_package_data = True zip_safe = False [options.extras_require] -petab = petab>=0.1.11 +petab = petab>=0.1.17 pysb = pysb>=1.11.0 [options.package_data] diff --git a/deps/AMICI/src/hdf5.cpp b/deps/AMICI/src/hdf5.cpp index 12ef25cf7..2dc974bb8 100644 --- a/deps/AMICI/src/hdf5.cpp +++ b/deps/AMICI/src/hdf5.cpp @@ -1,3 +1,12 @@ +/** + * Functions for HDF5 I/O + * + * NOTE: Use only `const char*` versions of any HDF5 functions, not the + * `std::string` version. On many systems, HDF5 libraries are still not compiled + * with C++11 support, but use the old C++03 ABI, which will lead to linking + * issues. + */ + #include "amici/hdf5.h" #include "amici/amici.h" @@ -97,7 +106,7 @@ void createGroup(H5::H5File const& file, std::unique_ptr readSimulationExpData(std::string const& hdf5Filename, std::string const& hdf5Root, Model const& model) { - H5::H5File file(hdf5Filename, H5F_ACC_RDONLY); + H5::H5File file(hdf5Filename.c_str(), H5F_ACC_RDONLY); hsize_t m, n; @@ -495,7 +504,7 @@ void createAndWriteInt1DDataset(H5::H5File const& file, gsl::span buffer) { hsize_t size = buffer.size(); H5::DataSpace dataspace(1, &size); - auto dataset = file.createDataSet(datasetName, H5::PredType::NATIVE_INT, + auto dataset = file.createDataSet(datasetName.c_str(), H5::PredType::NATIVE_INT, dataspace); dataset.write(buffer.data(), H5::PredType::NATIVE_INT); } @@ -505,7 +514,7 @@ void createAndWriteDouble1DDataset(const H5::H5File &file, gsl::span buffer) { hsize_t size = buffer.size(); H5::DataSpace dataspace(1, &size); - auto dataset = file.createDataSet(datasetName, H5::PredType::NATIVE_DOUBLE, + auto dataset = file.createDataSet(datasetName.c_str(), H5::PredType::NATIVE_DOUBLE, dataspace); dataset.write(buffer.data(), H5::PredType::NATIVE_DOUBLE); } @@ -516,7 +525,7 @@ void createAndWriteDouble2DDataset(const H5::H5File &file, hsize_t n) { const hsize_t adims[] {m, n}; H5::DataSpace dataspace(2, adims); - auto dataset = file.createDataSet(datasetName, H5::PredType::NATIVE_DOUBLE, + auto dataset = file.createDataSet(datasetName.c_str(), H5::PredType::NATIVE_DOUBLE, dataspace); dataset.write(buffer.data(), H5::PredType::NATIVE_DOUBLE); } @@ -527,7 +536,7 @@ void createAndWriteInt2DDataset(H5::H5File const& file, hsize_t n) { const hsize_t adims[] {m, n}; H5::DataSpace dataspace(2, adims); - auto dataset = file.createDataSet(datasetName, H5::PredType::NATIVE_INT, + auto dataset = file.createDataSet(datasetName.c_str(), H5::PredType::NATIVE_INT, dataspace); dataset.write(buffer.data(), H5::PredType::NATIVE_INT); } @@ -538,7 +547,7 @@ void createAndWriteDouble3DDataset(H5::H5File const& file, hsize_t n, hsize_t o) { const hsize_t adims[] {m, n, o}; H5::DataSpace dataspace(3, adims); - auto dataset = file.createDataSet(datasetName, H5::PredType::NATIVE_DOUBLE, + auto dataset = file.createDataSet(datasetName.c_str(), H5::PredType::NATIVE_DOUBLE, dataspace); dataset.write(buffer.data(), H5::PredType::NATIVE_DOUBLE); } @@ -871,14 +880,14 @@ void readSolverSettingsFromHDF5(H5::H5File const& file, Solver &solver, void readSolverSettingsFromHDF5(const std::string &hdffile, Solver &solver, const std::string &datasetPath) { - H5::H5File file(hdffile, H5F_ACC_RDONLY, H5P_DEFAULT); + H5::H5File file(hdffile.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); readSolverSettingsFromHDF5(file, solver, datasetPath); } void readModelDataFromHDF5(const std::string &hdffile, Model &model, const std::string &datasetPath) { - H5::H5File file(hdffile, H5F_ACC_RDONLY, H5P_DEFAULT); + H5::H5File file(hdffile.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); readModelDataFromHDF5(file, model, datasetPath); } @@ -958,12 +967,12 @@ H5::H5File createOrOpenForWriting(const std::string &hdf5filename) { AMICI_H5_SAVE_ERROR_HANDLER; try { - H5::H5File file(hdf5filename, H5F_ACC_RDWR); + H5::H5File file(hdf5filename.c_str(), H5F_ACC_RDWR); AMICI_H5_RESTORE_ERROR_HANDLER; return file; } catch(...) { AMICI_H5_RESTORE_ERROR_HANDLER; - return H5::H5File(hdf5filename, H5F_ACC_EXCL); + return H5::H5File(hdf5filename.c_str(), H5F_ACC_EXCL); } } @@ -977,13 +986,13 @@ bool locationExists(const H5::H5File &file, const std::string &location) bool locationExists(const std::string &filename, const std::string &location) { - H5::H5File file(filename, H5F_ACC_RDONLY); + H5::H5File file(filename.c_str(), H5F_ACC_RDONLY); return locationExists(file, location); } std::vector getIntDataset1D(const H5::H5File &file, std::string const& name) { - auto dataset = file.openDataSet(name); + auto dataset = file.openDataSet(name.c_str()); auto dataspace = dataset.getSpace(); int rank = dataspace.getSimpleExtentNdims(); @@ -1002,7 +1011,7 @@ std::vector getIntDataset1D(const H5::H5File &file, std::vector getDoubleDataset1D(const H5::H5File &file, const std::string &name) { - auto dataset = file.openDataSet(name); + auto dataset = file.openDataSet(name.c_str()); auto dataspace = dataset.getSpace(); int rank = dataspace.getSimpleExtentNdims(); @@ -1025,7 +1034,7 @@ std::vector getDoubleDataset2D(const H5::H5File &file, { m = n = 0; - auto dataset = file.openDataSet(name); + auto dataset = file.openDataSet(name.c_str()); auto dataspace = dataset.getSpace(); int rank = dataspace.getSimpleExtentNdims(); @@ -1050,7 +1059,7 @@ std::vector getDoubleDataset3D(const H5::H5File &file, { m = n = o = 0; - auto dataset = file.openDataSet(name); + auto dataset = file.openDataSet(name.c_str()); auto dataspace = dataset.getSpace(); int rank = dataspace.getSimpleExtentNdims(); diff --git a/deps/AMICI/src/rdata.cpp b/deps/AMICI/src/rdata.cpp index 9b7f94461..6e78a4b83 100644 --- a/deps/AMICI/src/rdata.cpp +++ b/deps/AMICI/src/rdata.cpp @@ -414,7 +414,7 @@ void ReturnData::processBackwardProblem(ForwardProblem const &fwd, auto xQB = bwd.getAdjointQuadrature(); if (preeq && preeq->hasQuadrature()) { - handleSx0Backward(model, *preeq, xQB); + handleSx0Backward(model, *preeq, llhS0, xQB); } else { handleSx0Forward(model, llhS0, xB); } @@ -433,6 +433,7 @@ void ReturnData::processBackwardProblem(ForwardProblem const &fwd, void ReturnData::handleSx0Backward(const Model &model, SteadystateProblem const &preeq, + std::vector &llhS0, AmiVector &xQB) const { /* If preequilibration is run in adjoint mode, the scalar product of sx0 with its adjoint counterpart (see handleSx0Forward()) is not necessary: @@ -441,9 +442,23 @@ void ReturnData::handleSx0Backward(const Model &model, and so is the scalar product. Instead of the scalar product, the quadratures xQB from preequilibration contribute to the gradient (see example notebook on equilibration for further documentation). */ - auto xQBpreeq = preeq.getAdjointQuadrature(); + const auto &xQBpreeq = preeq.getAdjointQuadrature(); for (int ip = 0; ip < model.nplist(); ++ip) - xQB[ip] += xQBpreeq[ip]; + xQB[ip] += xQBpreeq.at(ip); + + /* We really need references here, as sx0 can be large... */ + const auto& sx0preeq = preeq.getStateSensitivity(); + const auto& xBpreeq = preeq.getAdjointState(); + + /* Add the contribution for sx0 from preequilibration. If backward + * preequilibration was done by simulation due to a singular Jacobian, + * xB is not necessarily 0 and we may get a non-zero contribution here. */ + for (int ip = 0; ip < model.nplist(); ++ip) { + llhS0[ip] = 0.0; + for (int ix = 0; ix < model.nxtrue_solver; ++ix) { + llhS0[ip] += xBpreeq.at(ix) * sx0preeq.at(ix, ip); + } + } } void ReturnData::handleSx0Forward(const Model &model, diff --git a/deps/AMICI/src/steadystateproblem.cpp b/deps/AMICI/src/steadystateproblem.cpp index 6d75c469f..969c5723f 100644 --- a/deps/AMICI/src/steadystateproblem.cpp +++ b/deps/AMICI/src/steadystateproblem.cpp @@ -101,9 +101,6 @@ void SteadystateProblem::workSteadyStateBackwardProblem(Solver *solver, clock_t starttime = clock(); computeSteadyStateQuadrature(newtonSolver.get(), solver, model); cpu_timeB_ = (double)((clock() - starttime) * 1000) / CLOCKS_PER_SEC; - - /* Finalize by setting adjoint state to zero (its steady state) */ - xB_.zero(); } void SteadystateProblem::findSteadyState(Solver *solver, @@ -285,6 +282,9 @@ void SteadystateProblem::getQuadratureByLinSolve(NewtonSolver *newtonSolver, computeQBfromQ(model, xQ_, xQB_); /* set flag that quadratures is available (for processing in rdata) */ hasQuadrature_ = true; + + /* Finalize by setting adjoint state to zero (its steady state) */ + xB_.zero(); } catch (NewtonFailure const &) { hasQuadrature_ = false; } diff --git a/deps/AMICI/tests/benchmark-models/benchmark_models.yaml b/deps/AMICI/tests/benchmark-models/benchmark_models.yaml index a84afe34f..d290171e8 100644 --- a/deps/AMICI/tests/benchmark-models/benchmark_models.yaml +++ b/deps/AMICI/tests/benchmark-models/benchmark_models.yaml @@ -5,7 +5,9 @@ Bachmann_MSB2011: Becker_Science2010: llh: -364.118614198023 -#Beer_MolBioSystems2014 None +Beer_MolBioSystems2014: + llh: 58622.9145631413 + note: benchmark collection reference parameters do not match petab, but reference llh has been confirmed for parameters reported there up to sign Boehm_JProteomeRes2014: llh: -138.22199693517703 @@ -16,8 +18,7 @@ Borghans_BiophysChem1997: note: benchmark collection reference value matches up to sign when applying log10-correction +sum(log(meas*log(10)) / 2 Brannmark_JBC2010: - llh: 283.778227541074 - note: unchecked + llh: -141.889113770537 #Bruno_JExpBio2016: None @@ -34,8 +35,7 @@ Elowitz_Nature2000: note: benchmark collection reference value matches up to sign when applying log10-correction +sum(log(meas*log(10))) / 2 Fiedler_BMC2016: - llh: -117.16780323362 - note: unchecked + llh: 58.58390161681 Fujita_SciSignal2010: llh: 53.08749124997969 diff --git a/deps/AMICI/tests/benchmark-models/test_benchmark_collection.sh b/deps/AMICI/tests/benchmark-models/test_benchmark_collection.sh index ea3dbbfbe..0422dd3e2 100755 --- a/deps/AMICI/tests/benchmark-models/test_benchmark_collection.sh +++ b/deps/AMICI/tests/benchmark-models/test_benchmark_collection.sh @@ -7,15 +7,18 @@ # Confirmed to be working models=" +Beer_MolBioSystems2014 Boehm_JProteomeRes2014 Borghans_BiophysChem1997 +Brannmark_JBC2010 +Crauste_CellSystems2017 Elowitz_Nature2000 -Schwen_PONE2014 +Fiedler_BMC2016 Fujita_SciSignal2010 +Schwen_PONE2014 Sneyd_PNAS2002 -Zheng_PNAS2012 Weber_BMC2015 -Crauste_CellSystems2017" +Zheng_PNAS2012" # # Not matching reference for unclear reasons @@ -29,19 +32,12 @@ Crauste_CellSystems2017" # # no reference value: # Alkan_SciSignal2018 -# Beer_MolBioSystems2014 # Blasi_CellSystems2016 # Hass_PONE2017 # Korkut_eLIFE2015 # Perelson_Science1996 # Bruno_JExpBio2016 # -# Timepoint-specific parameter overrides -# Fiedler_BMC2016 -# Brannmark_JBC2010 -# Isensee_JCB2018 -# Sobotta_Frontiers2017 -# # yaml missing: # Casaletto_PNAS2019 # @@ -59,6 +55,9 @@ Crauste_CellSystems2017" # # Evaluation is known to be inconsistent: # Chen_MSB2009 +# +# Integration Failure: +# Isensee_JCB2018 set -e @@ -91,7 +90,7 @@ for model in $models; do yaml="${model_dir}"/"${model}"/"${model}".yaml amici_model_dir=test_bmc/"${model}" mkdir -p "$amici_model_dir" - cmd_import="amici_import_petab --verbose -y ${yaml} -o ${amici_model_dir} -n ${model}" + cmd_import="amici_import_petab --verbose -y ${yaml} -o ${amici_model_dir} -n ${model} --flatten" cmd_run="$script_path/test_petab_model.py --verbose -y ${yaml} -d ${amici_model_dir} -m ${model} -c" printf '=%.0s' {1..40} diff --git a/deps/AMICI/tests/benchmark-models/test_petab_model.py b/deps/AMICI/tests/benchmark-models/test_petab_model.py index 370b38df6..692a7aadd 100755 --- a/deps/AMICI/tests/benchmark-models/test_petab_model.py +++ b/deps/AMICI/tests/benchmark-models/test_petab_model.py @@ -75,6 +75,7 @@ def main(): # load PEtab files problem = petab.Problem.from_yaml(args.yaml_file_name) + petab.flatten_timepoint_specific_output_overrides(problem) # load model if args.model_directory: diff --git a/deps/AMICI/tests/cpputest/testfunctions.cpp b/deps/AMICI/tests/cpputest/testfunctions.cpp index b24fdd1be..382e7fa43 100644 --- a/deps/AMICI/tests/cpputest/testfunctions.cpp +++ b/deps/AMICI/tests/cpputest/testfunctions.cpp @@ -73,7 +73,7 @@ void simulateVerifyWrite(const std::string& hdffileOptions, const std::string& h // write // delete destination group - H5::H5File in(hdffileOptions, H5F_ACC_RDONLY); + H5::H5File in(hdffileOptions.c_str(), H5F_ACC_RDONLY); auto out = amici::hdf5::createOrOpenForWriting(hdffilewrite); if(hdf5::locationExists(out, path)) H5Ldelete(out.getId(), path.c_str(), H5P_DEFAULT); @@ -169,7 +169,7 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, } // compare to saved data in hdf file - H5::H5File file(hdffile, H5F_ACC_RDONLY); + H5::H5File file(hdffile.c_str(), H5F_ACC_RDONLY); hsize_t m, n; diff --git a/deps/AMICI/tests/performance/reference.yml b/deps/AMICI/tests/performance/reference.yml index b641ac92a..085363b6a 100644 --- a/deps/AMICI/tests/performance/reference.yml +++ b/deps/AMICI/tests/performance/reference.yml @@ -2,7 +2,10 @@ create_sdist: 5 install_sdist: 150 petab_import: 2100 -install_model: 350 +install_model: 120 +install_model_O0: 40 +install_model_O1: 90 +install_model_O2: 120 forward_simulation: 2 forward_sensitivities: 2 adjoint_sensitivities: 2 diff --git a/deps/AMICI/tests/performance/test.py b/deps/AMICI/tests/performance/test.py index 0f853c4a6..cf58c116b 100755 --- a/deps/AMICI/tests/performance/test.py +++ b/deps/AMICI/tests/performance/test.py @@ -5,47 +5,73 @@ import petab import subprocess import os +import re +import shutil from amici.petab_import import import_model -def main(): +def parse_args(): arg = sys.argv[1] + if '_' in arg and re.match(r'O[0-2]', arg.split("_")[-1]): + optim = arg.split("_")[-1] + os.environ['AMICI_CXXFLAGS'] = f'-{optim}' + suffix = f'_{optim}' + arg = '_'.join(arg.split("_")[:-1]) + else: + suffix = '' - if arg == 'compilation': - git_dir = os.path.join(os.curdir, 'CS_Signalling_ERBB_RAS_AKT') - if not os.path.exists(git_dir): - subprocess.run([ - 'git', 'clone', '--depth', '1', - 'https://github.com/ICB-DCM/CS_Signalling_ERBB_RAS_AKT'] - ) - os.chdir(os.path.join(os.curdir, 'CS_Signalling_ERBB_RAS_AKT')) - - pp = petab.Problem.from_yaml('FroehlichKes2018/PEtab/FroehlichKes2018.yaml') - petab.lint_problem(pp) - os.chdir(os.path.dirname(os.path.abspath(os.curdir))) - import_model(model_name='CS_Signalling_ERBB_RAS_AKT_petab', - sbml_model=pp.sbml_model, - condition_table=pp.condition_df, - observable_table=pp.observable_df, - measurement_table=pp.measurement_df, - compile=False, - verbose=True) - os.chdir(os.path.join(os.curdir, 'CS_Signalling_ERBB_RAS_AKT_petab')) - - subprocess.run(['python', 'setup.py', 'install']) + return arg, suffix - return - else: - import CS_Signalling_ERBB_RAS_AKT_petab as model_module - model = model_module.getModel() - solver = model.getSolver() - # TODO - edata = amici.ExpData(model) - edata.setTimepoints([1e8]) - edata.setObservedData([1.0]) - edata.setObservedDataStdDev([1.0]) +def check_results(rdata): + diagnostics = ['numsteps', 'numstepsB', 'numrhsevals', 'numrhsevalsB', + 'numerrtestfails', 'numerrtestfailsB', + 'numnonlinsolvconvfails', 'numnonlinsolvconvfailsB', + 'preeq_cpu_time', 'preeq_cpu_timeB', + 'cpu_time', 'cpu_timeB', + 'posteq_cpu_time', 'posteq_cpu_timeB'] + for d in diagnostics: + print(d, rdata[d]) + assert rdata['status'] == amici.AMICI_SUCCESS + + +def run_import(model_name): + git_dir = os.path.join(os.curdir, 'CS_Signalling_ERBB_RAS_AKT') + if not os.path.exists(git_dir): + subprocess.run([ + 'git', 'clone', '--depth', '1', + 'https://github.com/ICB-DCM/CS_Signalling_ERBB_RAS_AKT'] + ) + os.chdir(os.path.join(os.curdir, 'CS_Signalling_ERBB_RAS_AKT')) + + pp = petab.Problem.from_yaml( + 'FroehlichKes2018/PEtab/FroehlichKes2018.yaml' + ) + petab.lint_problem(pp) + import_model(model_name=model_name, + sbml_model=pp.sbml_model, + condition_table=pp.condition_df, + observable_table=pp.observable_df, + measurement_table=pp.measurement_df, + compile=False, + verbose=True) + + +def compile_model(model_name, model_dir): + if model_name != os.path.basename(model_dir): + shutil.copytree( + os.path.join(os.curdir, 'CS_Signalling_ERBB_RAS_AKT', + model_name), + model_dir + ) + + subprocess.run(['python', 'setup.py', + 'build_ext', f'--build-lib=.', '--force'], + cwd=model_dir) + + +def prepare_simulation(arg, model, solver, edata): if arg == 'forward_simulation': solver.setSensitivityMethod(amici.SensitivityMethod.none) solver.setSensitivityOrder(amici.SensitivityOrder.none) @@ -57,41 +83,60 @@ def main(): solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) solver.setSensitivityOrder(amici.SensitivityOrder.first) elif arg == 'forward_simulation_non_optimal_parameters': - tmpPar = model.getParameters() - model.setParameters([0.1 for _ in tmpPar]) + tmp_par = model.getParameters() + model.setParameters([0.1 for _ in tmp_par]) solver.setSensitivityMethod(amici.SensitivityMethod.none) solver.setSensitivityOrder(amici.SensitivityOrder.none) elif arg == 'adjoint_sensitivities_non_optimal_parameters': - tmpPar = model.getParameters() - model.setParameters([0.1 for _ in tmpPar]) + tmp_par = model.getParameters() + model.setParameters([0.1 for _ in tmp_par]) solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) solver.setSensitivityOrder(amici.SensitivityOrder.first) elif arg == 'forward_steadystate_sensitivities_non_optimal_parameters': - tmpPar = model.getParameters() - model.setParameters([0.1 for _ in tmpPar]) + tmp_par = model.getParameters() + model.setParameters([0.1 for _ in tmp_par]) solver.setSensitivityMethod(amici.SensitivityMethod.forward) solver.setSensitivityOrder(amici.SensitivityOrder.first) edata.setTimepoints([float('inf')]) elif arg == 'adjoint_steadystate_sensitivities_non_optimal_parameters': - tmpPar = model.getParameters() - model.setParameters([0.1 for _ in tmpPar]) + tmp_par = model.getParameters() + model.setParameters([0.1 for _ in tmp_par]) solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) solver.setSensitivityOrder(amici.SensitivityOrder.first) edata.setTimepoints([float('inf')]) else: print("Unknown argument:", arg) sys.exit(1) + + +def main(): + arg, suffix = parse_args() + + model_dir = os.path.join(os.curdir, 'CS_Signalling_ERBB_RAS_AKT', + 'CS_Signalling_ERBB_RAS_AKT_petab' + suffix) + model_name = 'CS_Signalling_ERBB_RAS_AKT_petab' + + if arg == 'import': + run_import(model_name) + return + elif arg == 'compile': + compile_model(model_name, model_dir) + return + else: + model_module = amici.import_model_module(model_name, model_dir) + model = model_module.getModel() + solver = model.getSolver() + # TODO + edata = amici.ExpData(model) + edata.setTimepoints([1e8]) + edata.setObservedData([1.0]) + edata.setObservedDataStdDev([1.0]) + + prepare_simulation(arg, model, solver, edata) + rdata = amici.runAmiciSimulation(model, solver, edata) - diagnostics = ['numsteps', 'numstepsB', 'numrhsevals', 'numrhsevalsB', - 'numerrtestfails', 'numerrtestfailsB', - 'numnonlinsolvconvfails', 'numnonlinsolvconvfailsB', - 'preeq_cpu_time', 'preeq_cpu_timeB', - 'cpu_time', 'cpu_timeB', - 'posteq_cpu_time', 'posteq_cpu_timeB'] - for d in diagnostics: - print(d, rdata[d]) - assert rdata['status'] == amici.AMICI_SUCCESS + check_results(rdata) if __name__ == '__main__': diff --git a/deps/AMICI/tests/petab_test_suite/test_petab_suite.py b/deps/AMICI/tests/petab_test_suite/test_petab_suite.py index f799c2808..73c7a58db 100755 --- a/deps/AMICI/tests/petab_test_suite/test_petab_suite.py +++ b/deps/AMICI/tests/petab_test_suite/test_petab_suite.py @@ -57,11 +57,14 @@ def _test_case(case, model_type): case_dir = os.path.join(petabtests.PYSB_DIR, case) # import petab problem yaml_file = os.path.join(case_dir, petabtests.problem_yaml_name(case)) - problem = PysbPetabProblem.from_yaml(yaml_file) + problem = PysbPetabProblem.from_yaml(yaml_file, + flatten=case.startswith('0006')) else: raise ValueError(f"Unsupported model_type: {model_type}") # compile amici model + if case.startswith('0006') and model_type != "pysb": + petab.flatten_timepoint_specific_output_overrides(problem) model_output_dir = f'amici_models/model_{case}' model = import_petab_problem( problem, model_output_dir=model_output_dir, @@ -83,6 +86,10 @@ def _test_case(case, model_type): gt_chi2 = solution[petabtests.CHI2] gt_llh = solution[petabtests.LLH] gt_simulation_dfs = solution[petabtests.SIMULATION_DFS] + if case.startswith('0006'): + # account for flattening + gt_simulation_dfs[0].loc[:, petab.OBSERVABLE_ID] = ('obs_a__10__c0', + 'obs_a__15__c0') tol_chi2 = solution[petabtests.TOL_CHI2] tol_llh = solution[petabtests.TOL_LLH] tol_simulations = solution[petabtests.TOL_SIMULATIONS] diff --git a/deps/AMICI/version.txt b/deps/AMICI/version.txt index a95c45d4f..4aa090693 100644 --- a/deps/AMICI/version.txt +++ b/deps/AMICI/version.txt @@ -1 +1 @@ -0.11.14 +0.11.15 diff --git a/python/setup.py b/python/setup.py index ed299e53b..5ada124b1 100644 --- a/python/setup.py +++ b/python/setup.py @@ -18,7 +18,7 @@ 'termcolor>=1.1.0', 'colorama>=0.4.3', 'petab>=0.1.18', - 'amici>=0.11.12', + 'amici>=0.11.15', 'h5py>=3.0.0', 'python-libsbml>=5.17.0', 'snakemake>=5.10.0', diff --git a/tests/petab-test-suite/test_petab_test_suite.py b/tests/petab-test-suite/test_petab_test_suite.py index 996ac04bf..ef16c6352 100755 --- a/tests/petab-test-suite/test_petab_test_suite.py +++ b/tests/petab-test-suite/test_petab_test_suite.py @@ -27,7 +27,7 @@ def test_case(case: Union[int, str]) -> None: _test_case(case) except Exception as e: if isinstance(e, NotImplementedError) \ - or "Timepoint-specific parameter overrides" in str(e): + or "models with timepoint specific mappings" in str(e): logger.info(f"Case {case} expectedly failed. " "Required functionality is not yet " f"implemented: {e}") From d7ebb4cf6f9203d0a2a6bba43fe3ecc82718062c Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 1 Apr 2021 10:54:51 +0200 Subject: [PATCH 08/21] Fetch googletest and change to .cpp for IDE integration (#338) * Rearrange googletests for IDE integration * CMake fetches googletest * Remove obsolete googletest installation script --- .github/workflows/parpe_tests.yml | 3 -- CMakeLists.txt | 19 ----------- ThirdParty/installDeps.sh | 2 -- ThirdParty/installGoogleTest.sh | 28 ---------------- .../charliecloud/parpe_base/install_parpe.sh | 3 -- .../parpeamici/steadystate/CMakeLists.txt | 4 +-- examples/parpeamici/steadystate/main_test.cpp | 12 ------- tests/CMakeLists.txt | 33 +++++++++++++++++++ tests/CMakeLists.txt.in | 15 +++++++++ tests/parpeamici/CMakeLists.txt | 14 ++++---- ...erTest.h => amiciSimulationRunnerTest.cpp} | 0 ...est.h => hierarchicalOptimizationTest.cpp} | 0 tests/parpeamici/main.cpp | 16 --------- ...t.h => multiConditionDataProviderTest.cpp} | 0 ...emTest.h => multiConditionProblemTest.cpp} | 0 ...rTest.h => simulationResultWriterTest.cpp} | 0 tests/parpecommon/CMakeLists.txt | 8 ++--- .../{commonTests.h => commonTests.cpp} | 0 .../{hdf5MiscTests.h => hdf5MiscTests.cpp} | 0 tests/parpecommon/main.cpp | 13 -------- tests/parpeloadbalancer/CMakeLists.txt | 6 ++-- ...asterTest.h => loadBalancerMasterTest.cpp} | 0 tests/parpeloadbalancer/main.cpp | 11 ------- tests/parpeoptimization/CMakeLists.txt | 30 +++++++++++------ ...sTest.h => localOptimizationCeresTest.cpp} | 0 ...tTest.h => localOptimizationIpoptTest.cpp} | 0 ...onTest.h => minibatchOptimizationTest.cpp} | 0 ...nTest.h => multiStartOptimizationTest.cpp} | 0 ...ionsTest.h => optimizationOptionsTest.cpp} | 0 ...blemTest.h => optimizationProblemTest.cpp} | 0 ...est.h => optimizationResultWriterTest.cpp} | 0 31 files changed, 80 insertions(+), 137 deletions(-) delete mode 100755 ThirdParty/installGoogleTest.sh delete mode 100644 examples/parpeamici/steadystate/main_test.cpp create mode 100644 tests/CMakeLists.txt.in rename tests/parpeamici/{amiciSimulationRunnerTest.h => amiciSimulationRunnerTest.cpp} (100%) rename tests/parpeamici/{hierarchicalOptimizationTest.h => hierarchicalOptimizationTest.cpp} (100%) delete mode 100644 tests/parpeamici/main.cpp rename tests/parpeamici/{multiConditionDataProviderTest.h => multiConditionDataProviderTest.cpp} (100%) rename tests/parpeamici/{multiConditionProblemTest.h => multiConditionProblemTest.cpp} (100%) rename tests/parpeamici/{simulationResultWriterTest.h => simulationResultWriterTest.cpp} (100%) rename tests/parpecommon/{commonTests.h => commonTests.cpp} (100%) rename tests/parpecommon/{hdf5MiscTests.h => hdf5MiscTests.cpp} (100%) delete mode 100644 tests/parpecommon/main.cpp rename tests/parpeloadbalancer/{loadBalancerMasterTest.h => loadBalancerMasterTest.cpp} (100%) delete mode 100644 tests/parpeloadbalancer/main.cpp rename tests/parpeoptimization/{localOptimizationCeresTest.h => localOptimizationCeresTest.cpp} (100%) rename tests/parpeoptimization/{localOptimizationIpoptTest.h => localOptimizationIpoptTest.cpp} (100%) rename tests/parpeoptimization/{minibatchOptimizationTest.h => minibatchOptimizationTest.cpp} (100%) rename tests/parpeoptimization/{multiStartOptimizationTest.h => multiStartOptimizationTest.cpp} (100%) rename tests/parpeoptimization/{optimizationOptionsTest.h => optimizationOptionsTest.cpp} (100%) rename tests/parpeoptimization/{optimizationProblemTest.h => optimizationProblemTest.cpp} (100%) rename tests/parpeoptimization/{optimizationResultWriterTest.h => optimizationResultWriterTest.cpp} (100%) diff --git a/.github/workflows/parpe_tests.yml b/.github/workflows/parpe_tests.yml index 855c45d1c..f3a8893cd 100644 --- a/.github/workflows/parpe_tests.yml +++ b/.github/workflows/parpe_tests.yml @@ -53,9 +53,6 @@ jobs: -DBUILD_TESTS=OFF \ && cmake --build "${AMICI_PATH}/build" --parallel -- VERBOSE=1 - - name: Install google test - run: ThirdParty/installGoogleTest.sh - - name: Install parPE Python deps run: | pip install -r ${PARPE_BASE}/python/requirements.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index bcacf6cc4..38058e601 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,25 +101,6 @@ if(${BUILD_TESTING}) set(TESTS_MPIEXEC_COMMAND mpiexec --allow-run-as-root --oversubscribe -n 4 CACHE STRING "") - # googletest - add_definitions(-DGTEST_LANGUAGE_CXX11) - find_package(Threads REQUIRED) - if ($ENV{GOOGLETEST_DIR}) - set(GOOGLETEST_DIR $ENV{GOOGLETEST_DIR}) - else() - set(GOOGLETEST_DIR "${CMAKE_CURRENT_LIST_DIR}/ThirdParty/googletest") - endif() - if (EXISTS ${GOOGLETEST_DIR}) - set(GTestSrc ${GOOGLETEST_DIR}/googletest) - set(GMockSrc ${GOOGLETEST_DIR}/googlemock) - else () - message(FATAL_ERROR "No googletest src dir found - set GOOGLETEST_DIR " - "or run ../ThirdParty/installGoogleTest.sh to enable!" - " (Or disable building tests with BUILD_TESTING=OFF)") - endif () - include_directories(${GTestSrc} "${GTestSrc}/include" - ${GMockSrc} "${GMockSrc}/include") - # # Create test coverage reports? set(GCOV_REPORT FALSE CACHE BOOL "Create GCOV report?") diff --git a/ThirdParty/installDeps.sh b/ThirdParty/installDeps.sh index 3c0b910bb..bc587a86a 100755 --- a/ThirdParty/installDeps.sh +++ b/ThirdParty/installDeps.sh @@ -15,5 +15,3 @@ cd "$script_dir" ./installCeres.sh ./installIpopt.sh - -./installGoogleTest.sh diff --git a/ThirdParty/installGoogleTest.sh b/ThirdParty/installGoogleTest.sh deleted file mode 100755 index 270a99363..000000000 --- a/ThirdParty/installGoogleTest.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# Download and build googletest - -set -euo pipefail - -script_path="$(dirname "$0")" -script_path="$(cd "${script_path}" && pwd)" - -cd "${script_path}" - -if [[ ! -d "googletest" ]]; then - echo "googletest/ does not exist" - if [[ ! -f "googletest.zip" ]]; then - echo "Downloading googletest..." - wget "https://github.com/google/googletest/archive/master.zip" -O "googletest.zip" - fi - - echo "Unpacking and building googletest..." - unzip "googletest" - mv "googletest-master" "googletest" - cd "googletest" - mkdir -p build - cd build - cmake .. - make -j 4 -else - echo "googletest/ exists. nothing to do." -fi diff --git a/container/charliecloud/parpe_base/install_parpe.sh b/container/charliecloud/parpe_base/install_parpe.sh index 8fab7b578..1a46ef8c0 100755 --- a/container/charliecloud/parpe_base/install_parpe.sh +++ b/container/charliecloud/parpe_base/install_parpe.sh @@ -30,9 +30,6 @@ cmake \ #- cd $PARPE_BASE/ThirdParty && ./installCeres.sh -# For google-test for parPE tests -cd "${PARPE_BASE}" && ThirdParty/installGoogleTest.sh - # install parPE python requirements pip install -r "${PARPE_BASE}"/python/requirements.txt diff --git a/examples/parpeamici/steadystate/CMakeLists.txt b/examples/parpeamici/steadystate/CMakeLists.txt index 49b633f1e..1e7b4dbfb 100644 --- a/examples/parpeamici/steadystate/CMakeLists.txt +++ b/examples/parpeamici/steadystate/CMakeLists.txt @@ -133,18 +133,16 @@ if(${BUILD_TESTING}) add_test (NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME} -c) set(SRC_LIST_CPP - main_test.cpp exampleSteadystateScaledTest.h ${CMAKE_SOURCE_DIR}/tests/parpecommon/testingMisc.cpp steadystateProblem.cpp - ${GTestSrc}/src/gtest-all.cc - ${GMockSrc}/src/gmock-all.cc ) add_executable(${PROJECT_NAME} ${SRC_LIST_CPP}) add_dependencies(${PROJECT_NAME} ${MODEL_NAME}) target_link_libraries(${PROJECT_NAME} parpeamici + gmock_main ${MODEL_LIBRARIES} ${GCOV_LIBRARY} ) diff --git a/examples/parpeamici/steadystate/main_test.cpp b/examples/parpeamici/steadystate/main_test.cpp deleted file mode 100644 index 0db5f422c..000000000 --- a/examples/parpeamici/steadystate/main_test.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "exampleSteadystateScaledTest.h" - -#include - -#include -#include - -int main(int argc, char *argv[]) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5578600aa..a505b3a4f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,38 @@ +# ------------------------------------------------------------------------------ +# Set up google test +# ------------------------------------------------------------------------------ + +# Download and unpack googletest at configure time +configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) +execute_process( + COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download) +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() +execute_process( + COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download) +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker settings on Windows +set(gtest_force_shared_crt + ON + CACHE BOOL "" FORCE) + +# Add googletest directly to our build. This defines the gtest and gtest_main +# targets. +add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src + ${CMAKE_CURRENT_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL) + include(GoogleTest) +# ------------------------------------------------------------------------------ + add_subdirectory(parpecommon) if(${PARPE_ENABLE_MPI}) diff --git a/tests/CMakeLists.txt.in b/tests/CMakeLists.txt.in new file mode 100644 index 000000000..6e80530a7 --- /dev/null +++ b/tests/CMakeLists.txt.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/tests/parpeamici/CMakeLists.txt b/tests/parpeamici/CMakeLists.txt index 65505b43d..297a83a17 100644 --- a/tests/parpeamici/CMakeLists.txt +++ b/tests/parpeamici/CMakeLists.txt @@ -1,16 +1,13 @@ project(unittests_amici) set(SRC_LIST_CPP - main.cpp ../parpecommon/testingMisc.cpp ../parpeoptimization/quadraticTestProblem.cpp - amiciSimulationRunnerTest.h - multiConditionDataProviderTest.h - multiConditionProblemTest.h - simulationResultWriterTest.h - hierarchicalOptimizationTest.h - ${GTestSrc}/src/gtest-all.cc - ${GMockSrc}/src/gmock-all.cc + amiciSimulationRunnerTest.cpp + multiConditionDataProviderTest.cpp + multiConditionProblemTest.cpp + simulationResultWriterTest.cpp + hierarchicalOptimizationTest.cpp ) add_executable(${PROJECT_NAME} ${SRC_LIST_CPP}) @@ -27,6 +24,7 @@ add_dependencies(${PROJECT_NAME} prepare_test_hierarchical_optimization) target_link_libraries(${PROJECT_NAME} parpeamici + gmock_main ${GCOV_LIBRARY} ) diff --git a/tests/parpeamici/amiciSimulationRunnerTest.h b/tests/parpeamici/amiciSimulationRunnerTest.cpp similarity index 100% rename from tests/parpeamici/amiciSimulationRunnerTest.h rename to tests/parpeamici/amiciSimulationRunnerTest.cpp diff --git a/tests/parpeamici/hierarchicalOptimizationTest.h b/tests/parpeamici/hierarchicalOptimizationTest.cpp similarity index 100% rename from tests/parpeamici/hierarchicalOptimizationTest.h rename to tests/parpeamici/hierarchicalOptimizationTest.cpp diff --git a/tests/parpeamici/main.cpp b/tests/parpeamici/main.cpp deleted file mode 100644 index 36e8eee07..000000000 --- a/tests/parpeamici/main.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "amiciSimulationRunnerTest.h" -#include "multiConditionDataProviderTest.h" -#include "multiConditionProblemTest.h" -#include "simulationResultWriterTest.h" -#include "hierarchicalOptimizationTest.h" - -#include - -#include -#include - -int main(int argc, char *argv[]) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/parpeamici/multiConditionDataProviderTest.h b/tests/parpeamici/multiConditionDataProviderTest.cpp similarity index 100% rename from tests/parpeamici/multiConditionDataProviderTest.h rename to tests/parpeamici/multiConditionDataProviderTest.cpp diff --git a/tests/parpeamici/multiConditionProblemTest.h b/tests/parpeamici/multiConditionProblemTest.cpp similarity index 100% rename from tests/parpeamici/multiConditionProblemTest.h rename to tests/parpeamici/multiConditionProblemTest.cpp diff --git a/tests/parpeamici/simulationResultWriterTest.h b/tests/parpeamici/simulationResultWriterTest.cpp similarity index 100% rename from tests/parpeamici/simulationResultWriterTest.h rename to tests/parpeamici/simulationResultWriterTest.cpp diff --git a/tests/parpecommon/CMakeLists.txt b/tests/parpecommon/CMakeLists.txt index 1413a2bdf..cef64daa8 100644 --- a/tests/parpecommon/CMakeLists.txt +++ b/tests/parpecommon/CMakeLists.txt @@ -1,12 +1,9 @@ project(unittests_common) set(SRC_LIST - main.cpp - commonTests.h - hdf5MiscTests.h + commonTests.cpp + hdf5MiscTests.cpp ${CMAKE_SOURCE_DIR}/tests/parpecommon/testingMisc.cpp - ${GTestSrc}/src/gtest-all.cc - ${GMockSrc}/src/gmock-all.cc ) add_executable(${PROJECT_NAME} ${SRC_LIST}) @@ -14,6 +11,7 @@ add_executable(${PROJECT_NAME} ${SRC_LIST}) target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT} parpecommon + gtest_main ${GCOV_LIBRARY} ) diff --git a/tests/parpecommon/commonTests.h b/tests/parpecommon/commonTests.cpp similarity index 100% rename from tests/parpecommon/commonTests.h rename to tests/parpecommon/commonTests.cpp diff --git a/tests/parpecommon/hdf5MiscTests.h b/tests/parpecommon/hdf5MiscTests.cpp similarity index 100% rename from tests/parpecommon/hdf5MiscTests.h rename to tests/parpecommon/hdf5MiscTests.cpp diff --git a/tests/parpecommon/main.cpp b/tests/parpecommon/main.cpp deleted file mode 100644 index a11775358..000000000 --- a/tests/parpecommon/main.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "commonTests.h" -#include "hdf5MiscTests.h" - -#include - -#include -#include - -int main(int argc, char *argv[]) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/parpeloadbalancer/CMakeLists.txt b/tests/parpeloadbalancer/CMakeLists.txt index 2c61f7799..461f3ec9e 100644 --- a/tests/parpeloadbalancer/CMakeLists.txt +++ b/tests/parpeloadbalancer/CMakeLists.txt @@ -3,10 +3,7 @@ project(unittests_loadbalancer) add_test (NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME} -c) set(SRC_LIST - main.cpp - loadBalancerMasterTest.h - ${GTestSrc}/src/gtest-all.cc - ${GMockSrc}/src/gmock-all.cc + loadBalancerMasterTest.cpp ) add_executable(${PROJECT_NAME} ${SRC_LIST}) @@ -14,5 +11,6 @@ add_executable(${PROJECT_NAME} ${SRC_LIST}) target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT} parpeloadbalancer + gmock_main ${GCOV_LIBRARY} ) diff --git a/tests/parpeloadbalancer/loadBalancerMasterTest.h b/tests/parpeloadbalancer/loadBalancerMasterTest.cpp similarity index 100% rename from tests/parpeloadbalancer/loadBalancerMasterTest.h rename to tests/parpeloadbalancer/loadBalancerMasterTest.cpp diff --git a/tests/parpeloadbalancer/main.cpp b/tests/parpeloadbalancer/main.cpp deleted file mode 100644 index 752b7ec70..000000000 --- a/tests/parpeloadbalancer/main.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "loadBalancerMasterTest.h" - -#include -#include -#include - -int main(int argc, char *argv[]) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/parpeoptimization/CMakeLists.txt b/tests/parpeoptimization/CMakeLists.txt index 58877fe10..f13955a3b 100644 --- a/tests/parpeoptimization/CMakeLists.txt +++ b/tests/parpeoptimization/CMakeLists.txt @@ -3,18 +3,13 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) project(unittests_optimization) set(SRC_LIST_CPP - main.cpp ../parpecommon/testingMisc.cpp quadraticTestProblem.cpp - multiStartOptimizationTest.h - minibatchOptimizationTest.h - optimizationResultWriterTest.h - optimizationOptionsTest.h - optimizationProblemTest.h - localOptimizationIpoptTest.h - localOptimizationCeresTest.h - ${GTestSrc}/src/gtest-all.cc - ${GMockSrc}/src/gmock-all.cc + multiStartOptimizationTest.cpp + minibatchOptimizationTest.cpp + optimizationResultWriterTest.cpp + optimizationOptionsTest.cpp + optimizationProblemTest.cpp ) add_executable(${PROJECT_NAME} ${SRC_LIST_CPP}) @@ -22,14 +17,29 @@ add_executable(${PROJECT_NAME} ${SRC_LIST_CPP}) target_link_libraries(${PROJECT_NAME} parpeoptimization parpecommon + gmock_main ${GCOV_LIBRARY} ) +if(${PARPE_ENABLE_IPOPT}) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationIpoptTest.cpp) +endif() + +if(${PARPE_ENABLE_CERES}) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationCeresTest.cpp) +endif() + if(${PARPE_ENABLE_TOMS611}) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationToms611Test.cpp) target_link_libraries(${PROJECT_NAME} toms611) endif(${PARPE_ENABLE_TOMS611}) if(${PARPE_ENABLE_FSQP}) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationFsqpTest.cpp) target_link_libraries(${PROJECT_NAME} fsqp) endif(${PARPE_ENABLE_FSQP}) diff --git a/tests/parpeoptimization/localOptimizationCeresTest.h b/tests/parpeoptimization/localOptimizationCeresTest.cpp similarity index 100% rename from tests/parpeoptimization/localOptimizationCeresTest.h rename to tests/parpeoptimization/localOptimizationCeresTest.cpp diff --git a/tests/parpeoptimization/localOptimizationIpoptTest.h b/tests/parpeoptimization/localOptimizationIpoptTest.cpp similarity index 100% rename from tests/parpeoptimization/localOptimizationIpoptTest.h rename to tests/parpeoptimization/localOptimizationIpoptTest.cpp diff --git a/tests/parpeoptimization/minibatchOptimizationTest.h b/tests/parpeoptimization/minibatchOptimizationTest.cpp similarity index 100% rename from tests/parpeoptimization/minibatchOptimizationTest.h rename to tests/parpeoptimization/minibatchOptimizationTest.cpp diff --git a/tests/parpeoptimization/multiStartOptimizationTest.h b/tests/parpeoptimization/multiStartOptimizationTest.cpp similarity index 100% rename from tests/parpeoptimization/multiStartOptimizationTest.h rename to tests/parpeoptimization/multiStartOptimizationTest.cpp diff --git a/tests/parpeoptimization/optimizationOptionsTest.h b/tests/parpeoptimization/optimizationOptionsTest.cpp similarity index 100% rename from tests/parpeoptimization/optimizationOptionsTest.h rename to tests/parpeoptimization/optimizationOptionsTest.cpp diff --git a/tests/parpeoptimization/optimizationProblemTest.h b/tests/parpeoptimization/optimizationProblemTest.cpp similarity index 100% rename from tests/parpeoptimization/optimizationProblemTest.h rename to tests/parpeoptimization/optimizationProblemTest.cpp diff --git a/tests/parpeoptimization/optimizationResultWriterTest.h b/tests/parpeoptimization/optimizationResultWriterTest.cpp similarity index 100% rename from tests/parpeoptimization/optimizationResultWriterTest.h rename to tests/parpeoptimization/optimizationResultWriterTest.cpp From 45a96ff4a2765bb8543497b45ac3c2e398bc3345 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 1 Apr 2021 10:56:43 +0200 Subject: [PATCH 09/21] Rename tests --- .../parpeamici/amiciSimulationRunnerTest.cpp | 2 +- .../hierarchicalOptimizationTest.cpp | 30 +++++++------- .../parpeamici/simulationResultWriterTest.cpp | 4 +- tests/parpecommon/commonTests.cpp | 40 +++++++++---------- tests/parpecommon/hdf5MiscTests.cpp | 33 +++++---------- .../loadBalancerMasterTest.cpp | 8 ++-- .../localOptimizationCeresTest.cpp | 4 +- .../minibatchOptimizationTest.cpp | 18 ++++----- .../multiStartOptimizationTest.cpp | 2 +- .../optimizationOptionsTest.cpp | 14 +++---- .../optimizationProblemTest.cpp | 10 ++--- .../optimizationResultWriterTest.cpp | 2 +- 12 files changed, 77 insertions(+), 90 deletions(-) diff --git a/tests/parpeamici/amiciSimulationRunnerTest.cpp b/tests/parpeamici/amiciSimulationRunnerTest.cpp index 8a43e5b4f..4a7ebff70 100644 --- a/tests/parpeamici/amiciSimulationRunnerTest.cpp +++ b/tests/parpeamici/amiciSimulationRunnerTest.cpp @@ -7,7 +7,7 @@ #include -TEST(simulationWorkerAmici, testSerializeResultPackageMessage) +TEST(SimulationWorkerAmici, SerializeResultPackageMessage) { parpe::AmiciSimulationRunner::AmiciResultPackageSimple results = { 1.1, diff --git a/tests/parpeamici/hierarchicalOptimizationTest.cpp b/tests/parpeamici/hierarchicalOptimizationTest.cpp index d59108f40..f0f2435a9 100644 --- a/tests/parpeamici/hierarchicalOptimizationTest.cpp +++ b/tests/parpeamici/hierarchicalOptimizationTest.cpp @@ -24,7 +24,7 @@ using ::testing::ReturnRefOfCopy; using ::testing::SetArgReferee; using ::testing::DoAll; -TEST(hierarchicalOptimization1, reader) { +TEST(HierarchicalOptimization1, Reader) { // mappingToObservable = np.array([[ 0, 1, 0], [ 0, 2, 0], [ 1, 1, 1], [1, 2, 1], [1, 3, 1]]) parpe::AnalyticalParameterHdf5Reader r(H5::H5File(TESTFILE, H5F_ACC_RDONLY), @@ -90,7 +90,7 @@ class AmiciSummedGradientFunctionMock : public parpe::AmiciSummedGradientFunctio }; -class hierarchicalOptimization : public ::testing::Test { +class HierarchicalOptimization : public ::testing::Test { protected: int numParameters_ = 4; @@ -126,7 +126,7 @@ class hierarchicalOptimization : public ::testing::Test { -TEST_F(hierarchicalOptimization, hierarchicalOptimization) { +TEST_F(HierarchicalOptimization, HierarchicalOptimization) { auto funUnqiue = std::make_unique(); auto fun = funUnqiue.get(); ON_CALL(*fun, numParameters()).WillByDefault(Return(numParameters_)); @@ -229,7 +229,7 @@ TEST_F(hierarchicalOptimization, hierarchicalOptimization) { EXPECT_EQ(2, hierarchicalOptimizationWrapper.numParameters()); } -TEST_F(hierarchicalOptimization, testNoAnalyticalParameters) { +TEST_F(HierarchicalOptimization, NoAnalyticalParameters) { // Should only call fun::evaluate, nothing else // setup @@ -262,7 +262,7 @@ TEST_F(hierarchicalOptimization, testNoAnalyticalParameters) { } -TEST_F(hierarchicalOptimization, testComputeAnalyticalScalings) { +TEST_F(HierarchicalOptimization, ComputeAnalyticalScalings) { /* data * measurement = data * 10 * check scaling = 10 @@ -325,7 +325,7 @@ TEST_F(hierarchicalOptimization, testComputeAnalyticalScalings) { } -TEST_F(hierarchicalOptimization, testComputeAnalyticalOffsets) { +TEST_F(HierarchicalOptimization, ComputeAnalyticalOffsets) { /* data * measurement = data + 10 * check offset = 10 @@ -370,7 +370,7 @@ TEST_F(hierarchicalOptimization, testComputeAnalyticalOffsets) { EXPECT_EQ(1.0, scaledOffset2); } -TEST_F(hierarchicalOptimization, applyOptimalScaling) { +TEST_F(HierarchicalOptimization, ApplyOptimalScaling) { constexpr int numObservables = 2; // constexpr int numTimepoints = 2; constexpr int scalingIdx = 0; @@ -398,7 +398,7 @@ TEST_F(hierarchicalOptimization, applyOptimalScaling) { } -TEST_F(hierarchicalOptimization, applyOptimalOffset) { +TEST_F(HierarchicalOptimization, ApplyOptimalOffset) { constexpr int numObservables = 2; // constexpr int numTimepoints = 2; constexpr int offsetIdx = 0; @@ -425,7 +425,7 @@ TEST_F(hierarchicalOptimization, applyOptimalOffset) { } -TEST_F(hierarchicalOptimization, testScaling) { +TEST_F(HierarchicalOptimization, Scaling) { EXPECT_EQ(42.0, amici::getUnscaledParameter(42.0, amici::ParameterScaling::none)); EXPECT_EQ(42.0, @@ -444,7 +444,7 @@ TEST_F(hierarchicalOptimization, testScaling) { amici::ParameterScaling::ln)); } -TEST(hierarchicalOptimization1, spliceParameters) { +TEST(HierarchicalOptimization1, SpliceParameters) { const std::vector fullParametersExp {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0}; @@ -466,7 +466,7 @@ TEST(hierarchicalOptimization1, spliceParameters) { EXPECT_EQ(fullParametersExp, fullParametersAct); } -TEST(hierarchicalOptimization1, spliceParametersNothingToDo) { +TEST(HierarchicalOptimization1, SpliceParametersNothingToDo) { const std::vector fullParametersExp {0.0, 1.0, 2.0}; const std::vector reducedParameters {0.0, 1.0, 2.0}; @@ -489,7 +489,7 @@ TEST(hierarchicalOptimization1, spliceParametersNothingToDo) { } -TEST(hierarchicalOptimization1, fillFilteredParams) { +TEST(HierarchicalOptimization1, FillFilteredParams) { const std::vector resultExp {1.0, 2.0, 3.0, 4.0, 5.0}; const std::vector valuesToFilter {9.0, 1.0, 2.0, 9.0, 9.0, 3.0, 4.0, 5.0, 9.0}; @@ -504,7 +504,7 @@ TEST(hierarchicalOptimization1, fillFilteredParams) { } -TEST_F(hierarchicalOptimization, testWrappedFunIsCalledWithGradient) { +TEST_F(HierarchicalOptimization, WrappedFunIsCalledWithGradient) { // setup auto fun = std::make_unique(); auto funNonOwning = fun.get(); @@ -577,7 +577,7 @@ TEST_F(hierarchicalOptimization, testWrappedFunIsCalledWithGradient) { hierarchicalWrapper.evaluate(parameters, fval, gsl::span(), nullptr, nullptr); } -TEST(hierarchicalOptimization1, likelihoodOfMatchingData) { +TEST(HierarchicalOptimization1, LikelihoodOfMatchingData) { const std::vector data {1.0, 2.0, 3.0}; const std::vector sigmas {1.0, 1.0, 1.0}; @@ -590,7 +590,7 @@ TEST(hierarchicalOptimization1, likelihoodOfMatchingData) { } -TEST_F(hierarchicalOptimization, problemWrapper) { +TEST_F(HierarchicalOptimization, ProblemWrapper) { //std::unique_ptr problem(new parpe::QuadraticTestProblem()); //auto hCost = std::make_unique(); //auto wrappedFun = dynamic_cast*>(wrappedProblem->costFun.get()); diff --git a/tests/parpeamici/simulationResultWriterTest.cpp b/tests/parpeamici/simulationResultWriterTest.cpp index 3ab82d990..b86318d87 100644 --- a/tests/parpeamici/simulationResultWriterTest.cpp +++ b/tests/parpeamici/simulationResultWriterTest.cpp @@ -14,7 +14,7 @@ #include -TEST(simulationResultWriter, testResultWriter) { +TEST(SimulationResultWriter, ResultWriter) { // setup ResultWriter const char* tmpName = "parpeTest_testResultWriter.h5"; auto _ = gsl::finally([tmpName] { remove(tmpName); }); @@ -74,7 +74,7 @@ TEST(simulationResultWriter, testResultWriter) { parpe::checkEqualArray(measurements.data(), yMesAct.data(), yMesAct.size(), 1e-16, 1e-16); } -TEST(simulationResultWriter, testResultWriterNewExistingFile) { +TEST(SimulationResultWriter, ResultWriterNewExistingFile) { const char* tmpName = "parpeTest_testResultWriterNewExistingFile.h5"; auto _ = gsl::finally([tmpName] { remove(tmpName); }); diff --git a/tests/parpecommon/commonTests.cpp b/tests/parpecommon/commonTests.cpp index ce6a22ee3..daaef6e24 100644 --- a/tests/parpecommon/commonTests.cpp +++ b/tests/parpecommon/commonTests.cpp @@ -18,11 +18,11 @@ using namespace parpe; -TEST(testingMisc, testTenToMinusInf) { +TEST(Testing, TenToMinusInf) { ASSERT_EQ(0.0, pow(10, -INFINITY)); } -TEST(testingMisc, testWithinTolerance) { +TEST(Testing, WithinTolerance) { captureStreamToString([](){ double atol = 0.1; double rtol = 0.1; @@ -43,7 +43,7 @@ TEST(testingMisc, testWithinTolerance) { }, stderr, STDERR_FILENO); } -TEST(testingMisc, testCheckEqualArray) { +TEST(Testing, CheckEqualArray) { const double expected[] = {1.0, 2.0, 3.0}; const double actual[] = {1.0, 2.0, 3.0}; @@ -51,7 +51,7 @@ TEST(testingMisc, testCheckEqualArray) { checkEqualArray(nullptr, nullptr, 3, 1e-16, 1e-16); } -TEST(testingMisc, testRandInt) { +TEST(Testing, RandInt) { const int numTests = 100; const int min = -1; const int max = 1; @@ -62,14 +62,14 @@ TEST(testingMisc, testRandInt) { } } -TEST(commonMisc, testBacktrace) { +TEST(Common, Backtrace) { std::string output = captureStreamToString([]() { parpe::printBacktrace(5); }, stderr, STDERR_FILENO); EXPECT_TRUE(100 < output.size()); } -TEST(commonMisc, testRandDouble) { +TEST(Common, RandDouble) { const int numTests = 100; const double min = -1.0; const double max = 1.0; @@ -80,7 +80,7 @@ TEST(commonMisc, testRandDouble) { } } -TEST(commonMisc, testFillArrayRandomDoubleSameInterval) { +TEST(Common, FillArrayRandomDoubleSameInterval) { const int numTests = 100; const double min = -1.0; const double max = 1.0; @@ -93,7 +93,7 @@ TEST(commonMisc, testFillArrayRandomDoubleSameInterval) { } } -TEST(commonMisc, testFillArrayRandomDoubleIndividualInterval) { +TEST(Common, FillArrayRandomDoubleIndividualInterval) { const int numTests = 100; const double min[numTests] = {-1.0, 0.0, 1.0}; const double max[numTests] = {-0.5, 0.5, 1.5}; @@ -108,7 +108,7 @@ TEST(commonMisc, testFillArrayRandomDoubleIndividualInterval) { #ifdef PARPE_ENABLE_MPI -TEST(commonMisc, testMpi) { +TEST(Common, Mpi) { // Before MPI initialized EXPECT_EQ(-1, parpe::getMpiRank()); EXPECT_EQ(-1, parpe::getMpiCommSize()); @@ -126,7 +126,7 @@ TEST(commonMisc, testMpi) { #endif -TEST(commonMisc, runInParallelAndWaitForFinish) { +TEST(Common, RunInParallelAndWaitForFinish) { captureStreamToString([](){ const int numThreads = 15; void* args[numThreads]; @@ -136,7 +136,7 @@ TEST(commonMisc, runInParallelAndWaitForFinish) { }, stdout); } -TEST(commonMisc, strFormatCurrentLocaltime) { +TEST(Common, StrFormatCurrentLocaltime) { int buflen = 10; char buf[buflen]; parpe::strFormatCurrentLocaltime(gsl::make_span(buf, buflen), "abc"); @@ -144,13 +144,13 @@ TEST(commonMisc, strFormatCurrentLocaltime) { } -TEST(logging, printDebugInfoAndWait) { +TEST(Logging, PrintDebugInfoAndWait) { captureStreamToString([](){ parpe::printDebugInfoAndWait(0); }, stdout); } -TEST(logging, misc) { +TEST(Logging, MessageIsPrinted) { captureStreamToString([](){ parpe::warning("bla"); parpe::error("bla"); @@ -158,7 +158,7 @@ TEST(logging, misc) { }, stdout); } -TEST(logging, printMPIInfo) { +TEST(Logging, PrintMPIInfo) { std::string s = captureStreamToString([](){ parpe::printMPIInfo(); }, stdout); @@ -166,7 +166,7 @@ TEST(logging, printMPIInfo) { EXPECT_TRUE(s.size() > 20); } -TEST(logging, logProcessStats) { +TEST(Logging, LogProcessStats) { std::string s = captureStreamToString([](){ parpe::logProcessStats(); }, stdout); @@ -178,7 +178,7 @@ TEST(logging, logProcessStats) { #include #include -TEST(costFunction, mseZero) { +TEST(CostFunction, MseZero) { parpe::MeanSquaredError mse; std::vector label = {1.0, 1.0}; std::vector prediction = {1.0, 1.0}; @@ -203,7 +203,7 @@ TEST(costFunction, mseZero) { } -TEST(costFunction, mseNonzero) { +TEST(CostFunction, MseNonzero) { parpe::MeanSquaredError mse; std::vector label = {1.0, 1.0}; std::vector prediction = {1.0, 2.0}; @@ -228,7 +228,7 @@ TEST(costFunction, mseNonzero) { } -TEST(costFunction, linearModel) { +TEST(CostFunction, LinearModel) { std::vector parameters = { 3.0, 2.0 }; // x = 3.0, b = 2.0 std::vector> features = { { 4.0 } }; // y = A x + b = 4.0 * 3.0 + 2.0 = 14.0 @@ -250,7 +250,7 @@ TEST(costFunction, linearModel) { EXPECT_TRUE(gradExp == gradAct); } -TEST(costFunction, linearModel2) { +TEST(CostFunction, LinearModel2) { std::vector parameters = { 3.0, 1.0, 2.0 }; std::vector> features = { { 4.0, 1.0 } }; // y = A x + b = 4.0 * 3.0 + 1.0*1.0 + 2.0 = 15.0 @@ -272,7 +272,7 @@ TEST(costFunction, linearModel2) { EXPECT_TRUE(gradExp == gradAct); } -TEST(costFunction, linearModel3) { +TEST(CostFunction, LinearModel3) { std::vector parameters = { 3.0, 1.0, 2.0 }; std::vector> features = { { 4.0, 1.0 }, { 8.0, 2.0 }}; // y = A x + b = 4.0 * 3.0 + 1.0*1.0 + 2.0 = 15.0 diff --git a/tests/parpecommon/hdf5MiscTests.cpp b/tests/parpecommon/hdf5MiscTests.cpp index 4bd88471d..06e2dfff0 100644 --- a/tests/parpecommon/hdf5MiscTests.cpp +++ b/tests/parpecommon/hdf5MiscTests.cpp @@ -7,7 +7,7 @@ #include #include -class hdf5Misc : public ::testing::Test { +class HDF5 : public ::testing::Test { protected: void SetUp() override { @@ -29,24 +29,24 @@ class hdf5Misc : public ::testing::Test { -TEST_F(hdf5Misc, testOpenExistingFileNoOverwrite) { +TEST_F(HDF5, OpenExistingFileNoOverwrite) { EXPECT_THROW(parpe::hdf5CreateFile(tempFileName, false), parpe::HDF5Exception); } -TEST_F(hdf5Misc, testOpenExistingFileOverwrite) { +TEST_F(HDF5, OpenExistingFileOverwrite) { file.close(); file = parpe::hdf5CreateFile(tempFileName, true); } -TEST_F(hdf5Misc, testMutexGetLock) { +TEST_F(HDF5, MutexGetLock) { parpe::hdf5MutexGetLock(); } -TEST_F(hdf5Misc, testErrorStackWalker) { +TEST_F(HDF5, ErrorStackWalker) { H5_SAVE_ERROR_HANDLER; // provoke error by asking to truncate a file that is already open @@ -65,7 +65,7 @@ TEST_F(hdf5Misc, testErrorStackWalker) { } -TEST_F(hdf5Misc, testCreateGroup) { +TEST_F(HDF5, CreateGroup) { const char *groupName = "/test"; EXPECT_FALSE(parpe::hdf5GroupExists(file, groupName)); @@ -76,7 +76,7 @@ TEST_F(hdf5Misc, testCreateGroup) { } -TEST_F(hdf5Misc, testCreateExistingGroup) { +TEST_F(HDF5, CreateExistingGroup) { parpe::hdf5CreateGroup(file, "/test", false); H5_SAVE_ERROR_HANDLER; @@ -86,7 +86,7 @@ TEST_F(hdf5Misc, testCreateExistingGroup) { } -TEST_F(hdf5Misc, testEnsureGroupExists) { +TEST_F(HDF5, EnsureGroupExists) { const char *groupName = "/test"; EXPECT_FALSE(parpe::hdf5GroupExists(file, groupName)); @@ -98,7 +98,7 @@ TEST_F(hdf5Misc, testEnsureGroupExists) { parpe::hdf5EnsureGroupExists(file, groupName); } -TEST_F(hdf5Misc, testStringAttribute) { +TEST_F(HDF5, StringAttribute) { const char *groupName = "/"; const char *attrName = "testA"; const char *expAttrValue = "adsf"; @@ -121,7 +121,7 @@ TEST_F(hdf5Misc, testStringAttribute) { } -TEST_F(hdf5Misc, testDatasetDimensions) { +TEST_F(HDF5, DatasetDimensions) { const char datasetName[] = "bla"; const int rank = 3; const hsize_t dims[rank] = {1,2,3}; @@ -146,16 +146,3 @@ TEST_F(hdf5Misc, testDatasetDimensions) { EXPECT_EQ((signed)dims[2], d2); EXPECT_EQ(0, d3); } - -// TODO: -// hdf5CreateExtendableDouble2DArray -// hdf5CreateOrExtendAndWriteToDouble2DArray -// hdf5CreateOrExtendAndWriteToDouble3DArray -// hdf5CreateOrExtendAndWriteToInt2DArray -// hdf5CreateExtendableInt2DArray -// hdf5CreateExtendableDouble3DArray -// hdf5Extend2ndDimensionAndWriteToDouble2DArray -// hdf5Extend3rdDimensionAndWriteToDouble3DArray -// hdf5Extend2ndDimensionAndWriteToInt2DArray -// hdf5Read2DDoubleHyperslab -// hdf5Read3DDoubleHyperslab diff --git a/tests/parpeloadbalancer/loadBalancerMasterTest.cpp b/tests/parpeloadbalancer/loadBalancerMasterTest.cpp index 5ef5f8b7d..efbebc3c2 100644 --- a/tests/parpeloadbalancer/loadBalancerMasterTest.cpp +++ b/tests/parpeloadbalancer/loadBalancerMasterTest.cpp @@ -51,7 +51,7 @@ class MockMPI { } }; -class queuemaster : public ::testing::Test { +class LoadBalancer : public ::testing::Test { protected: MockMPI mockMpi; @@ -60,7 +60,7 @@ class queuemaster : public ::testing::Test { #include -TEST_F(queuemaster, test_queueinit) { +TEST_F(LoadBalancer, QueueInited) { EXPECT_CALL(mockMpi, MPI_Comm_size(_, _)).Times(1); // Can happen or not, depending on how quick it's terminated // mock().expectOneCall("MPI_Testany"); @@ -71,7 +71,7 @@ TEST_F(queuemaster, test_queueinit) { lbm.terminate(); } -TEST_F(queuemaster, test_queue) { +TEST_F(LoadBalancer, Queues) { EXPECT_CALL(mockMpi, MPI_Comm_size(_, _)).Times(1); parpe::LoadBalancerMaster lbm; lbm.run(); @@ -89,7 +89,7 @@ TEST_F(queuemaster, test_queue) { lbm.terminate(); } -TEST_F(queuemaster, test_terminateMasterQueue_noInit) { +TEST_F(LoadBalancer, TerminateMasterWithoutInitSucceeds) { // terminate uninitialized masterQueue should not fail parpe::LoadBalancerMaster lbm; lbm.terminate(); diff --git a/tests/parpeoptimization/localOptimizationCeresTest.cpp b/tests/parpeoptimization/localOptimizationCeresTest.cpp index d73bbdad0..07c832db1 100644 --- a/tests/parpeoptimization/localOptimizationCeresTest.cpp +++ b/tests/parpeoptimization/localOptimizationCeresTest.cpp @@ -15,7 +15,7 @@ using ::testing::Ne; using ::testing::AtLeast; -TEST(localOptimizationCeres, testOptimization) { +TEST(LocalOptimizationCeres, Optimization) { parpe::QuadraticTestProblem problem; EXPECT_CALL(*problem.reporter, starting(_)); @@ -47,7 +47,7 @@ TEST(localOptimizationCeres, testOptimization) { #if (CERES_VERSION_MAJOR < 1 && CERES_VERSION_MINOR < 13) IGNORE_TEST(localOptimizationCeres, testReporterCalled) { #else -TEST(localOptimizationCeres, testReporterCalled) { +TEST(LocalOptimizationCeres, IsReporterCalled) { #endif parpe::QuadraticTestProblem problem; auto o = problem.getOptimizationOptions(); diff --git a/tests/parpeoptimization/minibatchOptimizationTest.cpp b/tests/parpeoptimization/minibatchOptimizationTest.cpp index 94889e7a1..fe8b12d99 100644 --- a/tests/parpeoptimization/minibatchOptimizationTest.cpp +++ b/tests/parpeoptimization/minibatchOptimizationTest.cpp @@ -14,7 +14,7 @@ #include -TEST(minibatchOptimization, getBatches) { +TEST(MinibatchOptimization, CreatesBatches) { int numElements = 10; std::vector input(numElements); @@ -41,7 +41,7 @@ TEST(minibatchOptimization, getBatches) { EXPECT_TRUE(std::vector(input.begin() + batchSize, input.end()) == batchesAct[1]); } -TEST(minibatchOptimization, updateParameters) { +TEST(MinibatchOptimization, UpdatesParameters) { // Test whether the most simple parameter updater works reliably std::vector gradient {3.0, 4.0}; std::vector parameters {2.0, 3.0}; @@ -71,7 +71,7 @@ TEST(minibatchOptimization, updateParameters) { -class minibatchOptimizationLinearModel : public ::testing::Test { +class MinibatchOptimizationLinearModel : public ::testing::Test { protected: void SetUp() override { @@ -137,7 +137,7 @@ class minibatchOptimizationLinearModel : public ::testing::Test { }; -TEST_F(minibatchOptimizationLinearModel, testCostWithTrueParametersIsZeroIndivdually) { +TEST_F(MinibatchOptimizationLinearModel, CostWithTrueParametersIsZeroIndivdually) { // verify cost gradient with true parameters is 0 auto lm2 = getLinearModelMSE(); double mse = NAN; @@ -149,7 +149,7 @@ TEST_F(minibatchOptimizationLinearModel, testCostWithTrueParametersIsZeroIndivdu } } -TEST_F(minibatchOptimizationLinearModel, testCostWithTrueParametersIsZeroFull) { +TEST_F(MinibatchOptimizationLinearModel, CostWithTrueParametersIsZeroFull) { // verify cost gradient with true parameters is 0 auto lm2 = getLinearModelMSE(); double mse = NAN; @@ -159,7 +159,7 @@ TEST_F(minibatchOptimizationLinearModel, testCostWithTrueParametersIsZeroFull) { EXPECT_TRUE(std::vector(trueParameters.size(), 0.0) == gradient); } -TEST_F(minibatchOptimizationLinearModel, testMinibatchSucceedFromOptimum) { +TEST_F(MinibatchOptimizationLinearModel, MinibatchSucceedFromOptimum) { // verify optimization succeeds with true parameters auto lm2 = getLinearModelMSE(); parpe::MinibatchOptimizer mb; @@ -172,7 +172,7 @@ TEST_F(minibatchOptimizationLinearModel, testMinibatchSucceedFromOptimum) { EXPECT_TRUE(trueParameters == std::get<2>(result)); } -TEST_F(minibatchOptimizationLinearModel, linearModelCheckCostGradient) { +TEST_F(MinibatchOptimizationLinearModel, LinearModelCheckCostGradient) { // use gradient checker auto p = getOptimizationProblem(); @@ -184,7 +184,7 @@ TEST_F(minibatchOptimizationLinearModel, linearModelCheckCostGradient) { #ifdef PARPE_ENABLE_IPOPT #include -TEST_F(minibatchOptimizationLinearModel, linearModelTestBatchOptimizerSucceeds) { +TEST_F(MinibatchOptimizationLinearModel, linearModelDoesBatchOptimizerSucceed) { // test batch optimizer auto p = getOptimizationProblem(); @@ -201,7 +201,7 @@ TEST_F(minibatchOptimizationLinearModel, linearModelTestBatchOptimizerSucceeds) } #endif -TEST_F(minibatchOptimizationLinearModel, linearModel) { +TEST_F(MinibatchOptimizationLinearModel, LinearModel) { // optimization/tests/unittests_optimization -sg minibatchOptimizationLinearModel -sn linearModel std::cout<<"True parameters "< ignore diff --git a/tests/parpeoptimization/optimizationOptionsTest.cpp b/tests/parpeoptimization/optimizationOptionsTest.cpp index 188cd1acd..a05c65b06 100644 --- a/tests/parpeoptimization/optimizationOptionsTest.cpp +++ b/tests/parpeoptimization/optimizationOptionsTest.cpp @@ -27,7 +27,7 @@ void setCeresOption(const std::pair &pair, #endif -TEST(optimizationOptions, setGetOptionStr) { +TEST(OptimizationOptions, setGetOptionStr) { parpe::OptimizationOptions o; std::string key = "str"; std::string expVal = "testStr"; @@ -37,7 +37,7 @@ TEST(optimizationOptions, setGetOptionStr) { EXPECT_EQ(expVal, actVal); } -TEST(optimizationOptions, setGetOptionInt) { +TEST(OptimizationOptions, setGetOptionInt) { parpe::OptimizationOptions o; std::string key = "str"; double expVal = 1.23; @@ -47,7 +47,7 @@ TEST(optimizationOptions, setGetOptionInt) { EXPECT_NEAR(expVal, actVal, 1e-15); } -TEST(optimizationOptions, setGetOptionDouble) { +TEST(OptimizationOptions, setGetOptionDouble) { parpe::OptimizationOptions o; std::string key = "str"; auto expVal = 123; @@ -58,14 +58,14 @@ TEST(optimizationOptions, setGetOptionDouble) { } -TEST(optimizationOptions, getNonExistingOption) { +TEST(OptimizationOptions, getNonExistingOption) { parpe::OptimizationOptions o; EXPECT_THROW(o.getIntOption("missingKey"), std::invalid_argument); } #ifdef PARPE_ENABLE_IPOPT -TEST(optimizationOptions, setIpOptOptions) { +TEST(OptimizationOptions, setIpOptOptions) { std::string key = "max_iter"; int expVal = 10; @@ -84,7 +84,7 @@ TEST(optimizationOptions, setIpOptOptions) { #endif #ifdef PARPE_ENABLE_CERES -TEST(optimizationOptions, setCeresOptions) { +TEST(OptimizationOptions, setCeresOptions) { std::string key = "max_num_iterations"; int expVal = 10; @@ -103,7 +103,7 @@ TEST(optimizationOptions, setCeresOptions) { } #endif -TEST(optimizationOptions, fromHDF5) { +TEST(OptimizationOptions, fromHDF5) { const char* tmpName = "parpeTest_fromHDF5.h5"; auto _ = gsl::finally([tmpName] { remove(tmpName); }); diff --git a/tests/parpeoptimization/optimizationProblemTest.cpp b/tests/parpeoptimization/optimizationProblemTest.cpp index a00744e35..942373093 100644 --- a/tests/parpeoptimization/optimizationProblemTest.cpp +++ b/tests/parpeoptimization/optimizationProblemTest.cpp @@ -94,7 +94,7 @@ class SummedGradientFunctionLinearModelTest }; -TEST(optimizationProblem, quadraticTestFunction) { +TEST(OptimizationProblem, quadraticTestFunction) { // Test QuadraticGradientFunction for f(-1) = 42 parpe::QuadraticGradientFunction f {}; double parameter = -1; @@ -112,7 +112,7 @@ TEST(optimizationProblem, quadraticTestFunction) { -TEST(optimizationProblem, gradientChecker) { +TEST(OptimizationProblem, gradientChecker) { parpe::QuadraticTestProblem problem {}; constexpr int numParameterIndices {1}; int parameterIndices[numParameterIndices] {0}; @@ -124,7 +124,7 @@ TEST(optimizationProblem, gradientChecker) { } -TEST(optimizationProblem, linearModel) { +TEST(OptimizationProblem, linearModel) { // Test if the linear model produces correct results SummedGradientFunctionLinearModelTest model; @@ -145,7 +145,7 @@ TEST(optimizationProblem, linearModel) { } -TEST(optimizationProblem, linearModelToGradientFun) { +TEST(OptimizationProblem, linearModelToGradientFun) { // Test that the SummedGradientFunction <-> GradientFunction Adapter works // with the linear model std::vector dataset {2.0, 3.0}; @@ -166,7 +166,7 @@ TEST(optimizationProblem, linearModelToGradientFun) { #ifdef PARPE_ENABLE_IPOPT -TEST(optimizationProblem, linearModelToGradientFunOptimization) { +TEST(OptimizationProblem, linearModelToGradientFunOptimization) { // create optimization problem for the linear model // does not do anything meaningful yet std::vector dataset {2.0, 3.0}; diff --git a/tests/parpeoptimization/optimizationResultWriterTest.cpp b/tests/parpeoptimization/optimizationResultWriterTest.cpp index 2f05edbd7..f6f9f6544 100644 --- a/tests/parpeoptimization/optimizationResultWriterTest.cpp +++ b/tests/parpeoptimization/optimizationResultWriterTest.cpp @@ -6,7 +6,7 @@ #include #include -TEST(optimizationResultWriter, testResultWriter) { +TEST(OptimizationResultWriter, ResultWriter) { const char* tmpFilename = "deleteme.h5"; parpe::OptimizationResultWriter w(tmpFilename, true, "/bla/"); From 253dbdbc5b04a7ecbe2c0686b775a0ca3513c299 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 1 Apr 2021 21:44:56 +0200 Subject: [PATCH 10/21] Update DLIB optimizer interface (#337) --- CMakeLists.txt | 4 +- ThirdParty/installDlib.sh | 32 ++-- .../parpeoptimization/localOptimizationDlib.h | 5 +- .../localOptimizationDlib.cpp | 141 ++++++++++-------- 4 files changed, 102 insertions(+), 80 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 38058e601..a72d54881 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,10 +71,10 @@ endif(${PARPE_ENABLE_MPI}) find_package(PkgConfig) pkg_search_module(IPOPT REQUIRED IMPORTED_TARGET GLOBAL ipopt>=3.11.0 ) -if(${ENABLE_DLIB}) +if(${PARPE_ENABLE_DLIB}) set(DLIB_DIR "${CMAKE_CURRENT_LIST_DIR}/ThirdParty/dlib-19.7" CACHE FILEPATH "DLIB base directory") -endif(${ENABLE_DLIB}) +endif(${PARPE_ENABLE_DLIB}) # PThreads set(THREADS_PREFER_PTHREAD_FLAG ON) diff --git a/ThirdParty/installDlib.sh b/ThirdParty/installDlib.sh index f02d822d0..3c8085685 100755 --- a/ThirdParty/installDlib.sh +++ b/ThirdParty/installDlib.sh @@ -1,24 +1,32 @@ #!/usr/bin/env bash -# build DLIB +# Download and build DLIB set -euo pipefail +script_dir=$(dirname "$0") +script_dir=$(cd "${script_dir}" && pwd) +cd "${script_dir}" + +make_opts=${MAKEOPTS-} dlib_archive="dlib-19.7.tar.bz2" -if [ ! -d "dlib-19.7" ]; then +dlib_dir=${script_dir}/dlib-19.7 + +if [ ! -d "${dlib_dir}" ]; then if [ ! -f "${dlib_archive}" ]; then - wget "http://dlib.net/files/${dlib_archive}" -o "${dlib_archive}" + wget "http://dlib.net/files/${dlib_archive}" -O "${dlib_archive}" fi tar -xjf "${dlib_archive}" fi -cd "dlib-19.7/" +cd "${dlib_dir}" mkdir -p build && cd build/ - cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" \ - -DDLIB_NO_GUI_SUPPORT=ON \ - -DDLIB_GIF_SUPPORT=OFF \ - -DDLIB_JPEG_SUPPORT=OFF \ - -DDLIB_PNG_SUPPORT=OFF \ - -DDLIB_LINK_WITH_SQLITE3=OFF \ - .. +cmake -S .. \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/install" \ + -DDLIB_NO_GUI_SUPPORT=ON \ + -DDLIB_GIF_SUPPORT=OFF \ + -DDLIB_JPEG_SUPPORT=OFF \ + -DDLIB_PNG_SUPPORT=OFF \ + -DDLIB_LINK_WITH_SQLITE3=OFF \ + .. -make -j12 && make install +make ${make_opts} && make install diff --git a/include/parpeoptimization/localOptimizationDlib.h b/include/parpeoptimization/localOptimizationDlib.h index 18200212f..4e05e5d61 100644 --- a/include/parpeoptimization/localOptimizationDlib.h +++ b/include/parpeoptimization/localOptimizationDlib.h @@ -14,13 +14,14 @@ class OptimizerDlibLineSearch : public Optimizer { * @brief Minimize an objective function given as OptimizationProblem using * dlib line search algorithm * - * TODO: no options are specifyable for the moment + * TODO: no options are specifiable for the moment * * @param problem * @return Returns 0 on success. */ - int optimize(OptimizationProblem *problem) override; + std::tuple > + optimize(OptimizationProblem *problem) override; }; } // namespace parpe diff --git a/src/parpeoptimization/localOptimizationDlib.cpp b/src/parpeoptimization/localOptimizationDlib.cpp index d2116fe54..66aa04597 100644 --- a/src/parpeoptimization/localOptimizationDlib.cpp +++ b/src/parpeoptimization/localOptimizationDlib.cpp @@ -1,87 +1,100 @@ -#include -#include "logging.h" -#include "optimizationOptions.h" -#include "optimizationProblem.h" +#include + +#include +#include +#include + #include #include -namespace parpe { - typedef dlib::matrix column_vector; typedef dlib::matrix general_matrix; -column_vector dlibColumnVectorFromDoubleArray(double const *src, int len) { - column_vector colVec(len); - std::copy(src, src + len, colVec.begin()); - return colVec; +namespace gsl { + +template < + typename T, + long num_rows, + long num_cols, + typename mem_manager, + typename layout + > +span make_span(dlib::matrix const& matrix) { + return span(matrix.begin(), matrix.size()); } -int parpe::OptimizerDlibLineSearch::optimize(OptimizationProblem *problem) -{ - int status = 0; - - int numParams = problem->getNumOptimizationParameters(); - column_vector startingPoint = dlibColumnVectorFromDoubleArray(problem->getInitialParameters(), numParams); - column_vector min = dlibColumnVectorFromDoubleArray(problem->getParametersMin(), numParams); - column_vector max = dlibColumnVectorFromDoubleArray(problem->getParametersMax(), numParams); - - clock_t timeBegin = clock(); - clock_t timeIterBegin = clock(); - - double finalFVal = dlib::find_min_box_constrained( - dlib::lbfgs_search_strategy(10), - dlib::objective_delta_stop_strategy( - 1e-9, problem->getOptimizationOptions().maxOptimizerIterations), - [&problem](const column_vector& x){ - // objective function - static __thread int numFunctionCalls = 0; - clock_t timeBegin = clock(); - - double fval = NAN; - problem->evaluateObjectiveFunction(x.begin(), &fval, nullptr); +template < + typename T, + long num_rows, + long num_cols, + typename mem_manager, + typename layout + > +span make_span(dlib::matrix &matrix) { + return span(matrix.begin(), matrix.size()); +} - if(problem->getOptimizationOptions().printToStdout) - std::cout<logObjectiveFunctionEvaluation(x.begin(), fval, nullptr, - numFunctionCalls, wallTime); - return fval; +column_vector dlibColumnVectorFromDoubleArray(double const *src, int len) { + column_vector colVec(len); + std::copy(src, src + len, colVec.begin()); + return colVec; +} - }, - [&problem, &timeIterBegin](const column_vector& x){ - // objective function gradient - static __thread int numFunctionCalls = 0; - clock_t timeBegin = clock(); +std::tuple > +parpe::OptimizerDlibLineSearch::optimize(OptimizationProblem *problem) +{ + int numParams = problem->cost_fun_->numParameters(); - double fVal = NAN; - column_vector fGrad(problem->getNumOptimizationParameters()); - problem->evaluateObjectiveFunction(x.begin(), &fVal, fGrad.begin()); + column_vector startingPoint(numParams); + problem->fillInitialParameters(gsl::make_span(startingPoint)); - if(problem->getOptimizationOptions().printToStdout) - std::cout<<" g"<fillParametersMin(gsl::make_span(startingPoint)); - clock_t timeEnd = clock(); - double wallTime = (double)(timeEnd - timeBegin) / CLOCKS_PER_SEC; -// double wallTimeIter = (double)(timeEnd - timeIterBegin) / CLOCKS_PER_SEC; - timeIterBegin = clock(); + column_vector max(numParams); + problem->fillParametersMax(gsl::make_span(startingPoint)); - problem->logObjectiveFunctionEvaluation(x.begin(), fVal, fGrad.begin(), numFunctionCalls, wallTime); - problem->intermediateFunction( - 0, numFunctionCalls, fVal, 0, 0, 0, 0, 0, 0, 0, 0); - return fGrad; - }, - startingPoint, min, max); - clock_t timeEnd = clock(); - double wallTime = (double)(timeEnd - timeBegin) / CLOCKS_PER_SEC; + auto optimizationController = problem->getReporter(); - problem->logOptimizerFinished(finalFVal, startingPoint.begin(), wallTime, 0); + optimizationController->starting(gsl::make_span(startingPoint)); - return status; + double finalFVal = dlib::find_min_box_constrained( + dlib::lbfgs_search_strategy(10), + dlib::objective_delta_stop_strategy( + 1e-9, problem->getOptimizationOptions().maxOptimizerIterations), + [&optimizationController](const column_vector& x){ + // objective function + double fval = NAN; + optimizationController->evaluate( + gsl::make_span(x), + fval, gsl::span(nullptr, 0)); + + return fval; + + }, + [&optimizationController](const column_vector& x){ + // objective function gradient + + double fVal = NAN; + column_vector fGrad(optimizationController->numParameters()); + optimizationController->evaluate( + gsl::make_span(x), fVal, gsl::make_span(fGrad)); + return fGrad; + }, + startingPoint, min, max); + + optimizationController->finished( + finalFVal, gsl::make_span(startingPoint), 0); + + return std::make_tuple( + 0, finalFVal, + std::vector(startingPoint.begin(), startingPoint.end())); } } // namespace parpe From 1fdf07292b1bafb5db738a28376ad886e68c41f4 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Tue, 13 Apr 2021 16:23:15 +0200 Subject: [PATCH 11/21] Fix serialization (https://github.com/AMICI-dev/AMICI/pull/1490) --- deps/AMICI/include/amici/serialization.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/deps/AMICI/include/amici/serialization.h b/deps/AMICI/include/amici/serialization.h index 7906a2cc4..b246cfb89 100644 --- a/deps/AMICI/include/amici/serialization.h +++ b/deps/AMICI/include/amici/serialization.h @@ -326,13 +326,12 @@ std::string serializeToString(T const& data) { try { ba::binary_oarchive oar(os); - oar << data; - - return serialized; } catch(ba::archive_exception const& e) { throw AmiException("Serialization to string failed: %s", e.what()); } + + return serialized; } /** @@ -354,14 +353,14 @@ std::vector serializeToStdVec(T const& data) { std::vector>> os(buffer); try{ + // archive must be destroyed BEFORE returning ba::binary_oarchive oar(os); - oar << data; - - return buffer; } catch(ba::archive_exception const& e) { throw AmiException("Serialization to std::vector failed: %s", e.what()); } + + return buffer; } /** @@ -382,15 +381,16 @@ T deserializeFromString(std::string const& serialized) { T deserialized; try{ + // archive must be destroyed BEFORE returning ba::binary_iarchive iar(os); iar >> deserialized; - - return deserialized; } catch(ba::archive_exception const& e) { throw AmiException("Deserialization from std::string failed: %s", e.what()); } + + return deserialized; } From 8439485c6bdd28bd8ae845ee9157034cd626058f Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Tue, 13 Apr 2021 23:55:47 +0200 Subject: [PATCH 12/21] Update AMICI (v0.11.16) (#339) * git subrepo clone (merge) --branch=v0.11.16 --force git@github.com:AMICI-dev/AMICI.git deps/AMICI subrepo: subdir: "deps/AMICI" merged: "57a7b11c" upstream: origin: "git@github.com:AMICI-dev/AMICI.git" branch: "v0.11.16" commit: "57a7b11c" git-subrepo: version: "0.4.1" origin: "https://github.com/ingydotnet/git-subrepo" commit: "a04d8c2" * Update to changed amici::ReturnData::ReturnData --- deps/AMICI/.gitrepo | 6 +- deps/AMICI/CHANGELOG.md | 9 +++ deps/AMICI/include/amici/model.h | 79 +++++++++++++++---- deps/AMICI/include/amici/rdata.h | 16 +++- deps/AMICI/include/amici/serialization.h | 5 +- deps/AMICI/python/amici/gradient_check.py | 12 ++- deps/AMICI/python/amici/numpy.py | 6 +- deps/AMICI/python/amici/parameter_mapping.py | 9 +++ .../python/tests/test_pregenerated_models.py | 39 +++++++-- deps/AMICI/src/rdata.cpp | 62 ++++++++++++--- deps/AMICI/version.txt | 2 +- .../parpeamici/simulationResultWriterTest.cpp | 2 +- 12 files changed, 197 insertions(+), 50 deletions(-) diff --git a/deps/AMICI/.gitrepo b/deps/AMICI/.gitrepo index 187fb9131..ed378cb2e 100644 --- a/deps/AMICI/.gitrepo +++ b/deps/AMICI/.gitrepo @@ -5,8 +5,8 @@ ; [subrepo] remote = git@github.com:ICB-DCM/AMICI.git - branch = v0.11.15 - commit = 4e671a5be75e19da81b0946a3e16a913b7fe725b - parent = c06f2c92cc22c527895e4c86e0c30e84f4c1b547 + branch = v0.11.16 + commit = 57a7b11cc2fb301cf838daefd966830c522643a8 + parent = 1fdf07292b1bafb5db738a28376ad886e68c41f4 cmdver = 0.4.1 method = merge diff --git a/deps/AMICI/CHANGELOG.md b/deps/AMICI/CHANGELOG.md index f3e981e42..3a0980a33 100644 --- a/deps/AMICI/CHANGELOG.md +++ b/deps/AMICI/CHANGELOG.md @@ -2,6 +2,15 @@ ## v0.X Series +### v0.11.16 (2021-04-13) + +Fixes: +* Fixed serialization bug (#1490) + +New: +* Construction of condition specific plist for parameter mappings (#1487, #1488) +* **Add support for error residuals** (#1489) + ### v0.11.15 (2021-03-31) Fixes: diff --git a/deps/AMICI/include/amici/model.h b/deps/AMICI/include/amici/model.h index 4d998e3c2..1e4780844 100644 --- a/deps/AMICI/include/amici/model.h +++ b/deps/AMICI/include/amici/model.h @@ -642,6 +642,45 @@ class Model : public AbstractModel, public ModelDimensions { throw AmiException("Mismatch in conservation law sensitivity size"); state_ = state; }; + + /** + * @brief Sets the estimated lower boundary for sigma_y. When :meth:`setAddSigmaResiduals` is + * activated, this lower boundary must ensure that log(sigma) + min_sigma > 0. + * @param min_sigma lower boundary + */ + void setMinimumSigmaResiduals(double min_sigma) { + min_sigma_ = min_sigma; + } + + /** + * @brief Gets the specified estimated lower boundary for sigma_y. + * @return lower boundary + */ + realtype getMinimumSigmaResiduals() const { + return min_sigma_; + } + + /** + * @brief Specifies whether residuals should be added to account for parameter dependent sigma. + * + * If set to true, additional residuals of the form \f$ \sqrt{\log(\sigma) + C} \f$ will be added. + * This enables least-squares optimization for variables with Gaussian noise assumption and parameter + * dependent standard deviation sigma. The constant \f$ C \f$ can be set via + * :meth:`setMinimumSigmaResiduals`. + * + * @param sigma_res if true, additional residuals are added + */ + void setAddSigmaResiduals(bool sigma_res) { + sigma_res_ = sigma_res; + } + + /** + * @brief Checks whether residuals should be added to account for parameter dependent sigma. + * @return sigma_res + */ + bool getAddSigmaResiduals() const { + return sigma_res_; + } /** * @brief Get the list of parameters for which sensitivities are computed. @@ -767,7 +806,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Get sensitivity of time-resolved observables. * - * Total derivative \f$sy = dydx * sx + dydp\f$ + * Total derivative \f$ sy = dydx * sx + dydp\f$ * (only for forward sensitivities). * @param sy buffer (shape `ny` x `nplist`, row-major) * @param t Timpoint @@ -801,7 +840,7 @@ class Model : public AbstractModel, public ModelDimensions { const int it, const ExpData *edata); /** - * @brief Add time-resolved measurement negative log-likelihood \f$Jy\f$. + * @brief Add time-resolved measurement negative log-likelihood \f$ Jy \f$. * @param Jy Buffer (shape 1) * @param it Timepoint index * @param x State variables @@ -812,7 +851,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Add sensitivity of time-resolved measurement negative log-likelihood - * \f$Jy\f$. + * \f$ Jy \f$. * * @param sllh First-order buffer (shape `nplist`) * @param s2llh Second-order buffer (shape `nJ - 1` x `nplist`, row-major) @@ -829,7 +868,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Add sensitivity of time-resolved measurement negative - * log-likelihood \f$Jy\f$. + * log-likelihood \f$ Jy \f$. * * Partial derivative (to be used with adjoint sensitivities). * @@ -847,7 +886,7 @@ class Model : public AbstractModel, public ModelDimensions { const ExpData &edata); /** - * @brief Get state sensitivity of the negative loglikelihood \f$Jy\f$, + * @brief Get state sensitivity of the negative loglikelihood \f$ Jy \f$, * partial derivative (to be used with adjoint sensitivities). * * @param dJydx Output buffer (shape `nJ` x `nx_solver`, row-major) @@ -978,7 +1017,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Add sensitivity of time-resolved measurement negative - * log-likelihood \f$Jy\f$. + * log-likelihood \f$ Jy \f$. * * Total derivative (to be used with forward sensitivities). * @@ -1001,7 +1040,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Add sensitivity of time-resolved measurement negative - * log-likelihood \f$Jy\f$. + * log-likelihood \f$ Jy \f$. * * Partial derivative (to be used with adjoint sensitivities). * @@ -1022,7 +1061,7 @@ class Model : public AbstractModel, public ModelDimensions { const ExpData &edata); /** - * @brief State sensitivity of the negative loglikelihood \f$Jz\f$. + * @brief State sensitivity of the negative loglikelihood \f$ Jz \f$. * * Partial derivative (to be used with adjoint sensitivities). * @@ -1305,7 +1344,7 @@ class Model : public AbstractModel, public ModelDimensions { void fy(realtype t, const AmiVector &x); /** - * @brief Compute partial derivative of observables \f$y\f$ w.r.t. model + * @brief Compute partial derivative of observables \f$ y \f$ w.r.t. model * parameters `p`. * @param t Current timepoint * @param x Current state @@ -1313,7 +1352,7 @@ class Model : public AbstractModel, public ModelDimensions { void fdydp(realtype t, const AmiVector &x); /** - * @brief Compute partial derivative of observables \f$y\f$ w.r.t. state + * @brief Compute partial derivative of observables \f$ y \f$ w.r.t. state * variables `x`. * @param t Current timepoint * @param x Current state @@ -1336,7 +1375,7 @@ class Model : public AbstractModel, public ModelDimensions { void fdsigmaydp(int it, const ExpData *edata); /** - * @brief Compute negative log-likelihood of measurements \f$y\f$. + * @brief Compute negative log-likelihood of measurements \f$ y \f$. * * @param Jy Variable to which llh will be added * @param it Timepoint index @@ -1347,7 +1386,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Compute partial derivative of time-resolved measurement negative - * log-likelihood \f$Jy\f$. + * log-likelihood \f$ Jy \f$. * @param it timepoint index * @param x state variables * @param edata Pointer to experimental data @@ -1365,7 +1404,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Compute sensitivity of time-resolved measurement negative - * log-likelihood \f$Jy\f$ w.r.t. parameters for the given timepoint. + * log-likelihood \f$ Jy \f$ w.r.t. parameters for the given timepoint. * @param it timepoint index * @param x state variables * @param edata pointer to experimental data instance @@ -1374,7 +1413,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Sensitivity of time-resolved measurement negative log-likelihood - * \f$Jy\f$ w.r.t. state variables. + * \f$ Jy \f$ w.r.t. state variables. * @param it Timepoint index * @param x State variables * @param edata Pointer to experimental data instance @@ -1428,7 +1467,7 @@ class Model : public AbstractModel, public ModelDimensions { void fdrzdp(int ie, realtype t, const AmiVector &x); /** - * @brief Compute sensitivity of event-resolved measurements \f$rz\f$ w.r.t. + * @brief Compute sensitivity of event-resolved measurements \f$ rz \f$ w.r.t. * model states `x`. * @param ie Event index * @param t Current timepoint @@ -1469,7 +1508,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Compute partial derivative of event measurement negative - * log-likelihood \f$Jz\f$. + * log-likelihood \f$ Jz \f$. * @param ie Event index * @param nroots Event index * @param t Current timepoint @@ -1481,7 +1520,7 @@ class Model : public AbstractModel, public ModelDimensions { /** * @brief Compute sensitivity of event measurement negative log-likelihood - * \f$Jz\f$ w.r.t. standard deviation sigmaz. + * \f$ Jz \f$ w.r.t. standard deviation sigmaz. * @param ie Event index * @param nroots Event index * @param t Current timepoint @@ -1704,6 +1743,12 @@ class Model : public AbstractModel, public ModelDimensions { * checked for finiteness */ bool always_check_finite_ {false}; + + /** indicates whether sigma residuals are to be added for every datapoint */ + bool sigma_res_ {false}; + + /** offset to ensure positivity of sigma residuals, only has an effect when `sigma_res_` is `true` */ + realtype min_sigma_ {50.0}; private: /** Sparse dwdp implicit temporary storage (shape `ndwdp`) */ diff --git a/deps/AMICI/include/amici/rdata.h b/deps/AMICI/include/amici/rdata.h index c0c42b78a..ec8fe146b 100644 --- a/deps/AMICI/include/amici/rdata.h +++ b/deps/AMICI/include/amici/rdata.h @@ -53,6 +53,8 @@ class ReturnData: public ModelDimensions { * @param rdrm see amici::Solver::rdata_reporting * @param quadratic_llh whether model defines a quadratic nllh and * computing res, sres and FIM makes sense + * @param sigma_res indicates whether additional residuals are to be added for each sigma + * @param sigma_offset offset to ensure real-valuedness of sigma residuals */ ReturnData(std::vector ts, ModelDimensions const& model_dimensions, @@ -60,7 +62,8 @@ class ReturnData: public ModelDimensions { int newton_maxsteps, std::vector pscale, SecondOrderMode o2mode, SensitivityOrder sensi, SensitivityMethod sensi_meth, - RDataReporting rdrm, bool quadratic_llh); + RDataReporting rdrm, bool quadratic_llh, bool sigma_res, + realtype sigma_offset); /** * @brief constructor that uses information from model and solver to @@ -372,9 +375,15 @@ class ReturnData: public ModelDimensions { template friend void boost::serialization::serialize(Archive &ar, ReturnData &r, unsigned int version); + + /** boolean indicating whether residuals for standard deviations have been added */ + bool sigma_res; protected: - + + /** offset for sigma_residuals */ + realtype sigma_offset; + /** timepoint for model evaluation*/ realtype t_; @@ -517,8 +526,9 @@ class ReturnData: public ModelDimensions { /** * @brief Chi-squared function * @param it time index + * @param edata ExpData instance containing observable data */ - void fchi2(int it); + void fchi2(int it, const ExpData &edata); /** * @brief Residual sensitivity function diff --git a/deps/AMICI/include/amici/serialization.h b/deps/AMICI/include/amici/serialization.h index b246cfb89..0e2e6e090 100644 --- a/deps/AMICI/include/amici/serialization.h +++ b/deps/AMICI/include/amici/serialization.h @@ -299,12 +299,13 @@ T deserializeFromChar(const char *buffer, int size) { T data; try { + // archive must be destroyed BEFORE returning ba::binary_iarchive iar(s); iar >> data; - return data; } catch(ba::archive_exception const& e) { throw AmiException("Deserialization from char failed: %s", e.what()); } + return data; } /** @@ -325,6 +326,7 @@ std::string serializeToString(T const& data) { bio::stream> os(inserter); try { + // archive must be destroyed BEFORE returning ba::binary_oarchive oar(os); oar << data; } catch(ba::archive_exception const& e) { @@ -383,7 +385,6 @@ T deserializeFromString(std::string const& serialized) { try{ // archive must be destroyed BEFORE returning ba::binary_iarchive iar(os); - iar >> deserialized; } catch(ba::archive_exception const& e) { throw AmiException("Deserialization from std::string failed: %s", diff --git a/deps/AMICI/python/amici/gradient_check.py b/deps/AMICI/python/amici/gradient_check.py index badf98afe..6055e2bdd 100644 --- a/deps/AMICI/python/amici/gradient_check.py +++ b/deps/AMICI/python/amici/gradient_check.py @@ -67,6 +67,8 @@ def check_finite_difference(x0: Sequence[float], og_sensitivity_order = solver.getSensitivityOrder() og_parameters = model.getParameters() og_plist = model.getParameterList() + if edata: + og_eplist = edata.plist # sensitivity p = copy.deepcopy(x0) @@ -74,6 +76,8 @@ def check_finite_difference(x0: Sequence[float], model.setParameters(p) model.setParameterList(plist) + if edata: + edata.plist = plist # simulation with gradient if int(og_sensitivity_order) < int(SensitivityOrder.first): @@ -122,6 +126,8 @@ def check_finite_difference(x0: Sequence[float], solver.setSensitivityOrder(og_sensitivity_order) model.setParameters(og_parameters) model.setParameterList(og_plist) + if edata: + edata.plist = og_eplist def check_derivatives(model: Model, @@ -190,18 +196,18 @@ def check_derivatives(model: Model, if 'ssigmay' in rdata.keys() \ and rdata['ssigmay'] is not None \ - and rdata['ssigmay'].any(): + and rdata['ssigmay'].any() and not model.getAddSigmaResiduals(): leastsquares_applicable = False if check_least_squares and leastsquares_applicable: fields += ['res', 'y'] check_results(rdata, 'FIM', - np.dot(rdata['sres'].transpose(), rdata['sres']), + np.dot(rdata['sres'].T, rdata['sres']), assert_fun, 1e-8, 1e-4) check_results(rdata, 'sllh', - -np.dot(rdata['res'].transpose(), rdata['sres']), + -np.dot(rdata['res'].T, rdata['sres']), assert_fun, 1e-8, 1e-4) for ip, pval in enumerate(p): diff --git a/deps/AMICI/python/amici/numpy.py b/deps/AMICI/python/amici/numpy.py index adace3b18..5d8fd51d0 100644 --- a/deps/AMICI/python/amici/numpy.py +++ b/deps/AMICI/python/amici/numpy.py @@ -195,8 +195,10 @@ def __init__(self, rdata: Union[ReturnDataPtr, ReturnData]): 'sllh': [rdata.nplist], 's2llh': [rdata.np, rdata.nplist], - 'res': [rdata.nt * rdata.nytrue], - 'sres': [rdata.nt * rdata.nytrue, rdata.nplist], + 'res': [rdata.nt * rdata.nytrue * + (2 if rdata.sigma_res else 1)], + 'sres': [rdata.nt * rdata.nytrue * + (2 if rdata.sigma_res else 1), rdata.nplist], 'FIM': [rdata.nplist, rdata.nplist], # diagnosis diff --git a/deps/AMICI/python/amici/parameter_mapping.py b/deps/AMICI/python/amici/parameter_mapping.py index 9f91c6b1a..e7dcc0d2e 100644 --- a/deps/AMICI/python/amici/parameter_mapping.py +++ b/deps/AMICI/python/amici/parameter_mapping.py @@ -236,12 +236,21 @@ def _get_par(model_par, value): scales = [petab_to_amici_scale(scale_map_sim_var[par_id]) for par_id in amici_model.getParameterIds()] + # plist + plist = [ + ip for ip, par_id in enumerate(amici_model.getParameterIds()) + if isinstance(parameter_mapping.map_sim_var[par_id], str) + ] + if parameters: edata.parameters = parameters if scales: edata.pscale = amici.parameterScalingFromIntVector(scales) + if plist: + edata.plist = plist + ########################################################################## # fixed parameters preequilibration if map_preeq_fix: diff --git a/deps/AMICI/python/tests/test_pregenerated_models.py b/deps/AMICI/python/tests/test_pregenerated_models.py index e339e03a5..6bd63768b 100755 --- a/deps/AMICI/python/tests/test_pregenerated_models.py +++ b/deps/AMICI/python/tests/test_pregenerated_models.py @@ -3,19 +3,17 @@ """Run simulations with Matlab-AMICI pre-generated models and verify using saved expectations.""" -import sys import h5py import amici -import unittest -import importlib import os -import copy from amici.gradient_check import check_derivatives, check_results import pytest +import numpy as np + options_file = os.path.join(os.path.dirname(__file__), '..', '..', - 'tests', 'cpputest', 'testOptions.h5') + 'tests', 'cpputest', 'testOptions.h5') expected_results_file = os.path.join(os.path.dirname(__file__), '..', '..', 'tests', 'cpputest', 'expectedResults.h5') expected_results = h5py.File(expected_results_file, 'r') @@ -147,6 +145,8 @@ def test_pregenerated_model(sub_test, case): with pytest.raises(RuntimeError): solver.setSensitivityMethod(amici.SensitivityMethod.adjoint) + chi2_ref = rdata.chi2 + # test likelihood mode solver.setReturnDataReportingMode(amici.RDataReporting.likelihood) rdata = amici.runAmiciSimulation(model, solver, edata) @@ -155,6 +155,35 @@ def test_pregenerated_model(sub_test, case): fields=['t', 'llh', 'sllh', 's2llh', 'FIM'], **verify_simulation_opts ) + # test sigma residuals + + if model_name == 'model_jakstat_adjoint' and \ + solver.getSensitivityMethod() != amici.SensitivityMethod.adjoint: + model.setAddSigmaResiduals(True) + solver.setReturnDataReportingMode(amici.RDataReporting.full) + rdata = amici.runAmiciSimulation(model, solver, edata) + # check whether activation changes chi2 + assert chi2_ref != rdata.chi2 + + if edata and solver.getSensitivityMethod() and \ + solver.getSensitivityOrder() and len(model.getParameterList()): + check_derivatives(model, solver, edata, assert_fun, + **check_derivative_opts) + + chi2_ref = rdata.chi2 + res_ref = rdata.res + + model.setMinimumSigmaResiduals(100) + rdata = amici.runAmiciSimulation(model, solver, edata) + # check whether changing the minimum changes res but not chi2 + assert np.isclose(chi2_ref, rdata.chi2) + assert not np.allclose(res_ref, rdata.res) + + model.setMinimumSigmaResiduals(-10) + rdata = amici.runAmiciSimulation(model, solver, edata) + # check whether having a bad minimum results in nan chi2 + assert np.isnan(rdata.chi2) + with pytest.raises(RuntimeError): model.getParameterByName('thisParameterDoesNotExist') diff --git a/deps/AMICI/src/rdata.cpp b/deps/AMICI/src/rdata.cpp index 6e78a4b83..50400d5af 100644 --- a/deps/AMICI/src/rdata.cpp +++ b/deps/AMICI/src/rdata.cpp @@ -11,6 +11,7 @@ #include "amici/symbolic_functions.h" #include +#include namespace amici { @@ -21,8 +22,9 @@ ReturnData::ReturnData(Solver const &solver, const Model &model) solver.getNewtonMaxSteps(), model.getParameterScale(), model.o2mode, solver.getSensitivityOrder(), solver.getSensitivityMethod(), - solver.getReturnDataReportingMode(), model.hasQuadraticLLH()) { -} + solver.getReturnDataReportingMode(), model.hasQuadraticLLH(), + model.getAddSigmaResiduals(), + model.getMinimumSigmaResiduals()) {} ReturnData::ReturnData(std::vector ts, ModelDimensions const& model_dimensions, @@ -31,12 +33,14 @@ ReturnData::ReturnData(std::vector ts, std::vector pscale, SecondOrderMode o2mode, SensitivityOrder sensi, SensitivityMethod sensi_meth, RDataReporting rdrm, - bool quadratic_llh) + bool quadratic_llh, bool sigma_res, + realtype sigma_offset) : ModelDimensions(model_dimensions), ts(std::move(ts)), nx(nx_rdata), nxtrue(nxtrue_rdata), nplist(nplist), nmaxevent(nmaxevent), nt(nt), newton_maxsteps(newton_maxsteps), pscale(std::move(pscale)), o2mode(o2mode), sensi(sensi), - sensi_meth(sensi_meth), rdata_reporting(rdrm), x_solver_(nx_solver), + sensi_meth(sensi_meth), rdata_reporting(rdrm), sigma_res(sigma_res), + sigma_offset(sigma_offset), x_solver_(nx_solver), sx_solver_(nx_solver, nplist), x_rdata_(nx), sx_rdata_(nx, nplist), nroots_(ne) { switch (rdata_reporting) { @@ -72,7 +76,8 @@ void ReturnData::initializeResidualReporting(bool enable_res) { y.resize(nt * ny, 0.0); sigmay.resize(nt * ny, 0.0); if (enable_res) - res.resize(nt * nytrue, 0.0); + res.resize((sigma_res ? 2 : 1) * nt * nytrue, 0.0); + if ((sensi_meth == SensitivityMethod::forward && sensi >= SensitivityOrder::first) || sensi >= SensitivityOrder::second) { @@ -80,7 +85,7 @@ void ReturnData::initializeResidualReporting(bool enable_res) { sy.resize(nt * ny * nplist, 0.0); ssigmay.resize(nt * ny * nplist, 0.0); if (enable_res) - sres.resize(nt * nytrue * nplist, 0.0); + sres.resize((sigma_res ? 2 : 1) * nt * nytrue * nplist, 0.0); } } @@ -293,7 +298,7 @@ void ReturnData::getDataOutput(int it, Model &model, ExpData const *edata) { if (!isNaN(llh)) model.addObservableObjective(llh, it, x_solver_, *edata); fres(it, model, *edata); - fchi2(it); + fchi2(it, *edata); } if (sensi >= SensitivityOrder::first && nplist > 0) { @@ -664,9 +669,10 @@ void ReturnData::applyChainRuleFactorToSimulationResults(const Model &model) { if (!sres.empty()) - for (int iyt = 0; iyt < nytrue * nt; ++iyt) + for (int ires = 0; ires < static_cast(res.size()); ++ires) for (int ip = 0; ip < nplist; ++ip) - sres.at((iyt * nplist + ip)) *= pcoefficient.at(ip); + sres.at((ires * nplist + ip)) *= pcoefficient.at(ip); + if(!FIM.empty()) for (int ip = 0; ip < nplist; ++ip) @@ -775,9 +781,8 @@ static realtype fres(realtype y, realtype my, realtype sigma_y) { return (y - my) / sigma_y; } -static realtype fsres(realtype y, realtype sy, realtype my, - realtype sigma_y, realtype ssigma_y) { - return (sy - ssigma_y * fres(y, my, sigma_y)) / sigma_y; +static realtype fres_error(realtype sigma_y, realtype sigma_offset) { + return sqrt(2*log(sigma_y) + sigma_offset); } void ReturnData::fres(const int it, Model &model, const ExpData &edata) { @@ -797,19 +802,35 @@ void ReturnData::fres(const int it, Model &model, const ExpData &edata) { continue; res.at(iyt) = amici::fres(y_it.at(iy), observedData[iy], sigmay_it.at(iy)); + if (sigma_res) + res.at(iyt + nt * nytrue) = fres_error(sigmay_it.at(iy), + sigma_offset); } } -void ReturnData::fchi2(const int it) { +void ReturnData::fchi2(const int it, const ExpData &edata) { if (res.empty() || isNaN(chi2)) return; for (int iy = 0; iy < nytrue; ++iy) { int iyt_true = iy + it * nytrue; chi2 += pow(res.at(iyt_true), 2); + if (sigma_res && edata.isSetObservedData(it, iy)) + chi2 += pow(res.at(iyt_true + nt * nytrue), 2) - sigma_offset; } } +static realtype fsres(realtype y, realtype sy, realtype my, + realtype sigma_y, realtype ssigma_y) { + return (sy - ssigma_y * fres(y, my, sigma_y)) / sigma_y; +} + +static realtype fsres_error(realtype sigma_y, realtype ssigma_y, + realtype sigma_offset) { + return ssigma_y / ( fres_error(sigma_y, sigma_offset) * sigma_y); +} + + void ReturnData::fsres(const int it, Model &model, const ExpData &edata) { if (sres.empty()) return; @@ -833,6 +854,14 @@ void ReturnData::fsres(const int it, Model &model, const ExpData &edata) { sres.at(idx) = amici::fsres(y_it.at(iy), sy_it.at(iy + ny * ip), observedData[iy], sigmay_it.at(iy), ssigmay_it.at(iy + ny * ip)); + if (sigma_res) { + int idx_res = + (iy + it * edata.nytrue() + edata.nytrue() * edata.nt()) * + nplist + ip; + sres.at(idx_res) = amici::fsres_error(sigmay_it.at(iy), + ssigmay_it.at(iy + ny * ip), + sigma_offset); + } } } } @@ -917,11 +946,18 @@ void ReturnData::fFIM(int it, Model &model, const ExpData &edata) { auto dy_i = sy_it.at(iy + ny * ip); auto ds_i = ssigmay_it.at(iy + ny * ip); auto sr_i = amici::fsres(y, dy_i, m, s, ds_i); + realtype sre_i; + if (sigma_res) + sre_i = amici::fsres_error(s, ds_i, sigma_offset); for (int jp = 0; jp < nplist; ++jp) { auto dy_j = sy_it.at(iy + ny * jp); auto ds_j = ssigmay_it.at(iy + ny * jp); auto sr_j = amici::fsres(y, dy_j, m, s, ds_j); FIM.at(ip + nplist * jp) += sr_i*sr_j; + if (sigma_res) { + auto sre_j = amici::fsres_error(s, ds_j, sigma_offset); + FIM.at(ip + nplist * jp) += sre_i * sre_j; + } /*+ ds_i*ds_j*(2*pow(r/pow(s,2.0), 2.0) - 1/pow(s,2.0));*/ } } diff --git a/deps/AMICI/version.txt b/deps/AMICI/version.txt index 4aa090693..db07b54af 100644 --- a/deps/AMICI/version.txt +++ b/deps/AMICI/version.txt @@ -1 +1 @@ -0.11.15 +0.11.16 diff --git a/tests/parpeamici/simulationResultWriterTest.cpp b/tests/parpeamici/simulationResultWriterTest.cpp index b86318d87..7ba3f8e4c 100644 --- a/tests/parpeamici/simulationResultWriterTest.cpp +++ b/tests/parpeamici/simulationResultWriterTest.cpp @@ -45,7 +45,7 @@ TEST(SimulationResultWriter, ResultWriter) { std::vector(), amici::SecondOrderMode::none, amici::SensitivityOrder::none, amici::SensitivityMethod::none, amici::RDataReporting::full, - true); + true, true, 50); std::iota(rdata.x.begin(), rdata.x.end(), 0); rdata.llh = 1.2345; rdata.y.resize(measurements.size()); From 086df4c7ae6fdd782c8ba5d33a25850dce1c52e3 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Fri, 16 Apr 2021 15:05:18 +0200 Subject: [PATCH 13/21] Fix AMICI: -Wno-maybe-uninitialized --- deps/AMICI/scripts/buildAmici.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/AMICI/scripts/buildAmici.sh b/deps/AMICI/scripts/buildAmici.sh index 446fe1d8b..b943cf6fd 100755 --- a/deps/AMICI/scripts/buildAmici.sh +++ b/deps/AMICI/scripts/buildAmici.sh @@ -24,7 +24,7 @@ fi CppUTest_DIR=${cpputest_build_dir} \ ${cmake} \ - -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror" \ + -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror -Wno-maybe-uninitialized" \ -DCMAKE_BUILD_TYPE=$build_type \ -DPython3_EXECUTABLE="$(command -v python3)" .. From cde4b7940fd1a3760d05bb598e2885a32dacd4d9 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Wed, 21 Apr 2021 13:05:26 +0200 Subject: [PATCH 14/21] Fix CMake make_minimum_required, which is 3.13 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a72d54881..a3b034295 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 3.10) # for GoogleTest -cmake_policy(VERSION 3.10) +cmake_minimum_required(VERSION 3.13) # pkg_search_module GLOBAL +cmake_policy(VERSION 3.13) if(POLICY CMP0074) # Use package_ROOT environment variables From 91dc12b75d29a7fbac47b65412de97c661f780bc Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 22 Apr 2021 14:49:55 +0200 Subject: [PATCH 15/21] CI: test gradient check with and without hierarchical optimization --- .../parpeamici/steadystate/test_steadystate.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/parpeamici/steadystate/test_steadystate.py b/examples/parpeamici/steadystate/test_steadystate.py index 246cbda8c..d1c8a166b 100644 --- a/examples/parpeamici/steadystate/test_steadystate.py +++ b/examples/parpeamici/steadystate/test_steadystate.py @@ -15,6 +15,7 @@ # General setup script_path = os.path.dirname(os.path.abspath(__name__)) # test executables are expected in working directory +# (i.e. working dir is build/examples/parpeamici/steadystate) cwd = os.getcwd() HDF5_FILE = os.path.join( cwd, 'steadystate_scaled-prefix/src/steadystate_scaled/', @@ -22,7 +23,9 @@ HDF5_FILE_TEST = os.path.join( cwd, 'steadystate_scaled-prefix/src/steadystate_scaled/', 'example_data-testset.h5') - +# build directory is expected to be a direct subdirectory of the parPE root dir +parpe_root = os.path.join(script_path, "../../../..") +OPTIM_OPT = os.path.join(parpe_root, "misc/optimizationOptions.py") MPIEXEC = os.environ.get('PARPE_TESTS_MPIEXEC', "mpiexec -n 5 --oversubscribe").split(" ") optim_exe = './example_steadystate_multi' @@ -32,16 +35,20 @@ result_filename = '_rank00000.h5' -def test_nompi_gradient_check(): +@pytest.mark.parametrize("hierarchical", [False, True]) +def test_nompi_gradient_check(hierarchical): """Test gradient check without MPI""" - outdir = 'example_steadystate_multi-test-gradient' + outdir = f'example_steadystate_multi-test-gradient-{int(hierarchical)}' shutil.rmtree(outdir, ignore_errors=True) + subprocess.run([OPTIM_OPT, HDF5_FILE, '-s', 'hierarchicalOptimization', + str(int(hierarchical))], + capture_output=True, check=True, encoding="utf-8") # Gradient check may fail in certain parameter regimes. Therefore, try # multiple times. max_tries = 4 - for i_try in range(max_tries): + for _ in range(max_tries): ret = subprocess.run(f'{optim_exe} -t gradient_check' f' -o {outdir}/ {HDF5_FILE}'.split(' '), capture_output=True, From 3a691696a081b0f6c92c2fb0e67276272a9746af Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 22 Apr 2021 15:14:30 +0200 Subject: [PATCH 16/21] Fix hierarchicalOptimization.h::removeInnerParameters indexing error --- include/parpeamici/hierarchicalOptimization.h | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/include/parpeamici/hierarchicalOptimization.h b/include/parpeamici/hierarchicalOptimization.h index 19072af19..5f2f3cccc 100644 --- a/include/parpeamici/hierarchicalOptimization.h +++ b/include/parpeamici/hierarchicalOptimization.h @@ -475,26 +475,32 @@ removeInnerParameters(const gsl::span allParameters, allParameters.size() - proportionalityFactorIndices.size() - offsetParameterIndices.size() - sigmaParameterIndices.size()); - int idxOuter = 0; + int nextOuterIdx = 0; for(int idxFull = 0; idxFull < static_cast(allParameters.size()); ++idxFull) { + + // skip if current parameter is scaling/offset/sigma if(std::find(proportionalityFactorIndices.begin(), - proportionalityFactorIndices.end(), idxOuter) + proportionalityFactorIndices.end(), idxFull) != std::end(proportionalityFactorIndices)) continue; + if(std::find(offsetParameterIndices.begin(), - offsetParameterIndices.end(), idxOuter) + offsetParameterIndices.end(), idxFull) != std::end(offsetParameterIndices)) continue; + if(std::find(sigmaParameterIndices.begin(), - sigmaParameterIndices.end(), idxOuter) + sigmaParameterIndices.end(), idxFull) != std::end(sigmaParameterIndices)) continue; - outerParameters[idxOuter] = allParameters[idxFull]; - ++idxOuter; + + // otherwise copy + outerParameters[nextOuterIdx] = allParameters[idxFull]; + ++nextOuterIdx; } - Ensures(idxOuter == static_cast(outerParameters.size())); + Ensures(nextOuterIdx == static_cast(outerParameters.size())); return outerParameters; } From b6235122823d35b87c2cdd8f3e5235a17c978dde Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 22 Apr 2021 15:37:46 +0200 Subject: [PATCH 17/21] Cleanup --- include/parpeamici/hierarchicalOptimization.h | 12 ++++----- ...lOptimizationAnalyticalParameterProvider.h | 12 ++++----- include/parpeamici/simulationResultWriter.h | 3 --- include/parpeamici/standaloneSimulator.h | 2 +- include/parpecommon/functions.h | 4 +-- include/parpecommon/misc.h | 2 +- .../parpeoptimization/optimizationOptions.h | 6 ++--- .../parpeoptimization/optimizationProblem.h | 5 ++-- src/parpeamici/hierarchicalOptimization.cpp | 4 +-- src/parpecommon/logging.cpp | 8 +++--- src/parpecommon/misc.cpp | 25 +++++++++++-------- src/parpeoptimization/optimizationOptions.cpp | 18 ++++++------- tests/parpecommon/commonTests.cpp | 4 +-- .../quadraticTestProblem.cpp | 11 ++++---- 14 files changed, 56 insertions(+), 60 deletions(-) diff --git a/include/parpeamici/hierarchicalOptimization.h b/include/parpeamici/hierarchicalOptimization.h index 5f2f3cccc..dded78e5c 100644 --- a/include/parpeamici/hierarchicalOptimization.h +++ b/include/parpeamici/hierarchicalOptimization.h @@ -17,7 +17,7 @@ namespace parpe { enum class ErrorModel { normal -}; // TODO logNormal, laplace +}; // TODO logNormal, Laplace class AnalyticalParameterProvider; class AnalyticalParameterHdf5Reader; @@ -247,7 +247,7 @@ class HierarchicalOptimizationWrapper : public GradientFunction /** Total number of conditions used in `fun` */ int numConditions; - /** Total number of observables occuring in `fun` */ + /** Total number of observables occurring in `fun` */ int numObservables; /** Error model to use for computing analytical parameters and negative @@ -258,7 +258,7 @@ class HierarchicalOptimizationWrapper : public GradientFunction /** * @brief The HierarchicalOptimizationProblemWrapper class wraps an - * OptimizationProblem and hides the analytically optimizated parameters (from + * OptimizationProblem and hides the analytically optimized parameters (from * starting point, parameter bounds, ...) * */ @@ -354,7 +354,7 @@ class HierarchicalOptimizationReporter : public OptimizationReporter mutable std::vector cached_full_gradient_; // TODO should override other functions as well // TODO: in all functions, we need to check of the provided parameters or - // functio nvalues match To cached ones, if we want to provide all together + // function values match To cached ones, if we want to provide all together // to downstreams }; @@ -506,7 +506,7 @@ removeInnerParameters(const gsl::span allParameters, /** * @brief From the given parameter vector, extract outer optimization - * parameters, as defined in the file HDF5 file parameterFile + * parameters, as defined in the file HDF5 file `parameterFile` * @param fullParameters * @param parameterFile * @param parameterPath @@ -548,7 +548,7 @@ computeNegLogLikelihood(std::vector const& measurements, /** * @brief If sensitivities are computed w.r.t. analytically computed parameters - * (which is unneccessary), this function checks they are below the given + * (which is unnecessary), this function checks they are below the given * threshold. * @param gradient * @param analyticalIndices diff --git a/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h b/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h index d6e2e4932..3a1e53406 100644 --- a/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h +++ b/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h @@ -23,7 +23,7 @@ class AnalyticalParameterProvider * @brief Get vector of condition indices for which the parameter with the * given index is used. * @param parameterIndex referring to the index in the analytical parameter - * list in the hdf5 file + * list in the HDF5 file * (*not* the optimization parameter index). * @return Vector of condition indices */ @@ -65,7 +65,7 @@ class AnalyticalParameterProviderDefault : public AnalyticalParameterProvider // TODO private std::vector> conditionsForParameter; std::vector optimizationParameterIndices; - // x[scalingIdx][conditionIdx] -> std::vector of observableIndicies + // x[scalingIdx][conditionIdx] -> std::vector of observableIndices std::vector>> mapping; }; @@ -87,7 +87,7 @@ class AnalyticalParameterHdf5Reader : public AnalyticalParameterProvider * indices of the analytically determined parameters within the overall * optimization parameters * @param mapPath path of to the dataset with the - * parameter-oberservable-condition mapping + * parameter-observable-condition mapping */ AnalyticalParameterHdf5Reader(const H5::H5File& file, std::string analyticalParameterIndicesPath, @@ -100,9 +100,9 @@ class AnalyticalParameterHdf5Reader : public AnalyticalParameterProvider * @brief Get vector of condition indices for which the parameter with the * given index is used. * @param parameterIndex referring to the index in the analytical parameter - * list in the hdf5 file + * list in the HDF5 file * (*not* the optimization parameter index). - * @return Vector of condition indice + * @return Vector of condition indices */ std::vector getConditionsForParameter( int parameterIndex) const override; @@ -151,7 +151,7 @@ class AnalyticalParameterHdf5Reader : public AnalyticalParameterProvider std::string mapPath; std::string analyticalParameterIndicesPath; - // x[scalingIdx][conditionIdx] -> std::vector of observableIndicies + // x[scalingIdx][conditionIdx] -> std::vector of observableIndices std::vector>> mapping; }; diff --git a/include/parpeamici/simulationResultWriter.h b/include/parpeamici/simulationResultWriter.h index 2d044e8c6..53a18dac9 100644 --- a/include/parpeamici/simulationResultWriter.h +++ b/include/parpeamici/simulationResultWriter.h @@ -55,8 +55,6 @@ class SimulationResultWriter { * @brief Create results datasets. * * Must be called before first call to `save*` - * @param udata - * @param edata * @param numSimulations */ void createDatasets(hsize_t numSimulations); @@ -65,7 +63,6 @@ class SimulationResultWriter { /** * @brief Save results for a single simulation to HDF5 file. - * @param udata * @param edata * @param rdata * @param simulationIdx If >= 0: write results in the selected diff --git a/include/parpeamici/standaloneSimulator.h b/include/parpeamici/standaloneSimulator.h index a01ef5894..aa5092a41 100644 --- a/include/parpeamici/standaloneSimulator.h +++ b/include/parpeamici/standaloneSimulator.h @@ -17,7 +17,7 @@ namespace parpe { * ./simulate --at-optimum : use parameters from last iteration of all * multi-start optimization runs * --parameter-matrix : using arbitrary parameters from some matrix - * in hdf5 file + * in HDF5 file * --along-trajectory : use parameters along the optimization * trajectory of all multi-start optimization * runs diff --git a/include/parpecommon/functions.h b/include/parpecommon/functions.h index 0e858d80e..199035b11 100644 --- a/include/parpecommon/functions.h +++ b/include/parpecommon/functions.h @@ -74,7 +74,7 @@ class SummedGradientFunction * @param gradient Preallocated space for the gradient of size * dim(parameters). Or gsl::span() for evaluation without gradient. * @param logger Optional Logger instance used for output - * @param cputime Optional output argument to reoprt cpuTime consumed by the + * @param cputime Optional output argument to report cpuTime consumed by the * the function * @return Evaluation status */ @@ -94,7 +94,7 @@ class SummedGradientFunction * @param gradient Preallocated space for the gradient of size * dim(parameters). Or gsl::span() for evaluation without gradient. * @param logger Optional Logger instance used for output - * @param cputime Optional output argument to reoprt cpuTime consumed by the + * @param cputime Optional output argument to report cpuTime consumed by the * the function * @return Evaluation status */ diff --git a/include/parpecommon/misc.h b/include/parpecommon/misc.h index 1b7bd531e..92077d76b 100644 --- a/include/parpecommon/misc.h +++ b/include/parpecommon/misc.h @@ -177,7 +177,7 @@ class InverseUniqueLock }; /** - * @brief Check if a and b are equal to machine precission + * @brief Check if a and b are equal to machine precision * @param a * @param b * @return diff --git a/include/parpeoptimization/optimizationOptions.h b/include/parpeoptimization/optimizationOptions.h index d8c169942..c11f5f988 100644 --- a/include/parpeoptimization/optimizationOptions.h +++ b/include/parpeoptimization/optimizationOptions.h @@ -32,7 +32,7 @@ class OptimizationOptions { OptimizationOptions() = default; /** Optimizer factory method depending on OptimizationOptions::optimizer */ - Optimizer *createOptimizer() const; + std::unique_ptr createOptimizer() const; /** Optimizer to use */ optimizerName optimizer = optimizerName::OPTIMIZER_IPOPT; @@ -86,12 +86,12 @@ class OptimizationOptions { std::map options; }; -Optimizer* optimizerFactory(optimizerName optimizer); +std::unique_ptr optimizerFactory(optimizerName optimizer); /** * @brief Print list of supported optimizers */ -void printAvailableOptimizers(std::string prefix = ""); +void printAvailableOptimizers(const std::string &prefix = ""); } // namespace parpe #endif // OPTIMIZATIONOPTIONS_H diff --git a/include/parpeoptimization/optimizationProblem.h b/include/parpeoptimization/optimizationProblem.h index d2b9094a7..4e52dcda5 100644 --- a/include/parpeoptimization/optimizationProblem.h +++ b/include/parpeoptimization/optimizationProblem.h @@ -46,7 +46,6 @@ class OptimizationReporter: public GradientFunction { /** * @brief Is called just before the optimizer starts. Must be called before * other functions. - * @param numParameters * @param initialParameters * @return Quit optimization? */ @@ -54,9 +53,9 @@ class OptimizationReporter: public GradientFunction { /** * @brief Is called after each iteration except for the last one - * @param numParameters * @param parameters - * @param currentIter + * @param objectiveFunctionValue + * @param objectiveFunctionGradient * @return Quit optimization? */ virtual bool iterationFinished(gsl::span parameters, diff --git a/src/parpeamici/hierarchicalOptimization.cpp b/src/parpeamici/hierarchicalOptimization.cpp index f12e66769..dfb569a73 100644 --- a/src/parpeamici/hierarchicalOptimization.cpp +++ b/src/parpeamici/hierarchicalOptimization.cpp @@ -86,7 +86,7 @@ void HierarchicalOptimizationWrapper::init() { if (errorModel != ErrorModel::normal) { - throw ParPEException("Only gaussian noise is supported so far."); + throw ParPEException("Only Gaussian noise is supported so far."); } /* Some functions currently expect these lists to be sorted, therefore @@ -1304,7 +1304,7 @@ HierarchicalOptimizationReporter::iterationFinished( // We don't have the full parameter vector, only the outer // parameters so we can't append them due to different dimension // TODO: save both, outer + combined? can easily save outer + inner - // separetly + // separately std::vector nanParameters(cached_full_parameters_.size(), NAN); diff --git a/src/parpecommon/logging.cpp b/src/parpecommon/logging.cpp index 0d9037998..6a41291b2 100644 --- a/src/parpecommon/logging.cpp +++ b/src/parpecommon/logging.cpp @@ -31,12 +31,10 @@ std::string printfToString(const char *fmt, va_list ap) { ++size; // actual formatting - auto buf = new char[size]; - size = vsnprintf(buf, size, fmt, ap); - std::string str(buf, size); - delete[] buf; + auto buf = std::make_unique(size); + size = vsnprintf(buf.get(), size, fmt, ap); - return str; + return std::string(buf.get(), size); } void logmessage(loglevel lvl, const char *format, ...) diff --git a/src/parpecommon/misc.cpp b/src/parpecommon/misc.cpp index eb1e4989d..32eefa008 100644 --- a/src/parpecommon/misc.cpp +++ b/src/parpecommon/misc.cpp @@ -82,29 +82,32 @@ std::string getBacktrace(int nMaxFrames) void *callstack[nMaxFrames]; int nFrames = backtrace(callstack, nMaxFrames); - char **symbols = backtrace_symbols(callstack, nFrames); - + auto symbols = std::unique_ptr{ + backtrace_symbols(callstack, nFrames), free}; char buf[1024]; + for (int i = 0; i < nFrames; i++) { Dl_info info; if (dladdr(callstack[i], &info) && info.dli_sname) { - char *demangled = nullptr; + auto demangled = + std::unique_ptr{nullptr, free}; int status = -1; if (info.dli_sname[0] == '_') - demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); - snprintf(buf, sizeof(buf), "%-3d %*p %s + %td\n", - i, int(2 + sizeof(void*) * 2), callstack[i], - status == 0 ? demangled : - info.dli_sname == nullptr ? symbols[i] : info.dli_sname, + demangled.reset( + abi::__cxa_demangle(info.dli_sname,nullptr, nullptr, + &status)); + snprintf(buf, sizeof(buf), "%-3d %*p %s + %td\n", i, + int(2 + sizeof(void*) * 2), callstack[i], + status == 0 ? demangled.get() : + info.dli_sname == nullptr ? + symbols.get()[i] : info.dli_sname, (char *)callstack[i] - (char *)info.dli_saddr); - free(demangled); } else { snprintf(buf, sizeof(buf), "%-3d %*p %s\n", - i, int(2 + sizeof(void*) * 2), callstack[i], symbols[i]); + i, int(2 + sizeof(void*) * 2), callstack[i], symbols.get()[i]); } oss << buf; } - free(symbols); if (nFrames == nMaxFrames) oss << "[truncated]\n"; diff --git a/src/parpeoptimization/optimizationOptions.cpp b/src/parpeoptimization/optimizationOptions.cpp index 57cbf34c9..20971272f 100644 --- a/src/parpeoptimization/optimizationOptions.cpp +++ b/src/parpeoptimization/optimizationOptions.cpp @@ -79,7 +79,7 @@ void optimizationOptionsFromAttribute(H5::H5Object& loc, } } -Optimizer *OptimizationOptions::createOptimizer() const { +std::unique_ptr OptimizationOptions::createOptimizer() const { return optimizerFactory(optimizer); } @@ -258,49 +258,49 @@ void OptimizationOptions::setOption(const std::string& key, std::string value) options[key] = std::move(value); } -Optimizer* optimizerFactory(optimizerName optimizer) +std::unique_ptr optimizerFactory(optimizerName optimizer) { switch (optimizer) { case optimizerName::OPTIMIZER_IPOPT: #ifdef PARPE_ENABLE_IPOPT - return new OptimizerIpOpt(); + return std::make_unique(); #else return nullptr; #endif case optimizerName::OPTIMIZER_CERES: #ifdef PARPE_ENABLE_CERES - return new OptimizerCeres(); + return std::make_unique(); #else return nullptr; #endif case optimizerName::OPTIMIZER_DLIB: #ifdef PARPE_ENABLE_DLIB - return new OptimizerDlibLineSearch(); + return std::make_unique(); #else return nullptr; #endif case optimizerName::OPTIMIZER_TOMS611: #ifdef PARPE_ENABLE_TOMS611 - return new OptimizerToms611TrustRegionSumsl(); + return std::make_unique(); #else return nullptr; #endif case optimizerName::OPTIMIZER_FSQP: #ifdef PARPE_ENABLE_FSQP - return new OptimizerFsqp(); + return std::make_unique(); #else return nullptr; #endif case optimizerName::OPTIMIZER_MINIBATCH_1: throw ParPEException("optimizerFactory() cannot be used with " - "minibatch optimizer."); + "mini-batch optimizer."); } return nullptr; } -void printAvailableOptimizers(std::string prefix) +void printAvailableOptimizers(std::string const& prefix) { optimizerName optimizer {optimizerName::OPTIMIZER_IPOPT}; diff --git a/tests/parpecommon/commonTests.cpp b/tests/parpecommon/commonTests.cpp index daaef6e24..64b7fba13 100644 --- a/tests/parpecommon/commonTests.cpp +++ b/tests/parpecommon/commonTests.cpp @@ -114,12 +114,12 @@ TEST(Common, Mpi) { EXPECT_EQ(-1, parpe::getMpiCommSize()); // MPI initialized - MPI_Init(0, nullptr); + MPI_Init(nullptr, nullptr); EXPECT_EQ(0, parpe::getMpiRank()); EXPECT_EQ(1, parpe::getMpiCommSize()); MPI_Finalize(); - // Should not make invalid calls after mpi_finalize + // Should not make invalid calls after MPI_Finalize EXPECT_EQ(-1, parpe::getMpiRank()); EXPECT_EQ(-1, parpe::getMpiCommSize()); } diff --git a/tests/parpeoptimization/quadraticTestProblem.cpp b/tests/parpeoptimization/quadraticTestProblem.cpp index 213c820b7..5b212697a 100644 --- a/tests/parpeoptimization/quadraticTestProblem.cpp +++ b/tests/parpeoptimization/quadraticTestProblem.cpp @@ -14,8 +14,9 @@ namespace parpe { QuadraticTestProblem::QuadraticTestProblem(std::unique_ptr logger) : OptimizationProblem( - std::unique_ptr( - new NiceMock()), std::move(logger)) { + std::make_unique>(), + std::move(logger) + ) { auto options = getOptimizationOptions(); options.maxOptimizerIterations = 12; @@ -30,7 +31,6 @@ QuadraticTestProblem::QuadraticTestProblem(std::unique_ptr logger) void QuadraticTestProblem::fillParametersMin(gsl::span buffer) const { buffer[0] = -1e5; - } void QuadraticTestProblem::fillParametersMax(gsl::span buffer) const @@ -49,9 +49,8 @@ QuadraticOptimizationMultiStartProblem::getLocalProblem( int multiStartIndex) const { auto loggerPrefix = std::string("[start ") + std::to_string(multiStartIndex) + "]"; - auto p = std::unique_ptr( - new QuadraticTestProblem( - std::make_unique(loggerPrefix))); + auto p = std::make_unique( + std::make_unique(loggerPrefix)); p->setOptimizationOptions(options); return p; } From 4039b5c67dec1df664d065986375865733ec6982 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 22 Apr 2021 23:18:04 +0200 Subject: [PATCH 18/21] doc/typos --- include/parpeamici/hierarchicalOptimization.h | 9 +-- ...lOptimizationAnalyticalParameterProvider.h | 2 +- .../parpeamici/multiConditionDataProvider.h | 13 ++-- include/parpeamici/multiConditionProblem.h | 4 +- include/parpeamici/standaloneSimulator.h | 2 +- .../parpeloadbalancer/loadBalancerMaster.h | 4 +- .../parpeloadbalancer/loadBalancerWorker.h | 12 ++-- .../localOptimizationToms611.h | 4 +- .../parpeoptimization/minibatchOptimization.h | 65 ++++++++++--------- src/parpeamici/amiciSimulationRunner.cpp | 4 +- src/parpeamici/multiConditionDataProvider.cpp | 4 +- 11 files changed, 61 insertions(+), 62 deletions(-) diff --git a/include/parpeamici/hierarchicalOptimization.h b/include/parpeamici/hierarchicalOptimization.h index dded78e5c..016cf40cb 100644 --- a/include/parpeamici/hierarchicalOptimization.h +++ b/include/parpeamici/hierarchicalOptimization.h @@ -87,13 +87,6 @@ class HierarchicalOptimizationWrapper : public GradientFunction using GradientFunction::evaluate; - /** - * @brief See base class - * @param parameters - * @param fval - * @param gradient - * @return - */ FunctionEvaluationStatus evaluate(gsl::span parameters, double& fval, gsl::span gradient, @@ -355,7 +348,7 @@ class HierarchicalOptimizationReporter : public OptimizationReporter // TODO should override other functions as well // TODO: in all functions, we need to check of the provided parameters or // function values match To cached ones, if we want to provide all together - // to downstreams + // to downstream }; /** diff --git a/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h b/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h index 3a1e53406..28c495698 100644 --- a/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h +++ b/include/parpeamici/hierarchicalOptimizationAnalyticalParameterProvider.h @@ -83,7 +83,7 @@ class AnalyticalParameterHdf5Reader : public AnalyticalParameterProvider /** * @brief AnalyticalParameterHdf5Reader * @param file - * @param scalingParameterIndicesPath location in hdf5 file of the list of + * @param scalingParameterIndicesPath location in HDF5 file of the list of * indices of the analytically determined parameters within the overall * optimization parameters * @param mapPath path of to the dataset with the diff --git a/include/parpeamici/multiConditionDataProvider.h b/include/parpeamici/multiConditionDataProvider.h index 44c9a9b6e..cedca9259 100644 --- a/include/parpeamici/multiConditionDataProvider.h +++ b/include/parpeamici/multiConditionDataProvider.h @@ -127,7 +127,8 @@ class MultiConditionDataProviderDefault : public MultiConditionDataProvider /** * @brief Provides the number of conditions for which data is available and * simulations need to be run. - * This is determined from the dimensions of the hdf5MeasurementPath + * This is determined from the dimensions of the + * MultiConditionDataProviderDefault::hdf5MeasurementPath * dataset. * @return Number of conditions */ @@ -348,10 +349,12 @@ class MultiConditionDataProviderHDF5 : public MultiConditionDataProvider /** * @brief Based on the array of optimization parameters, set the simulation - * parameters in the given Model object to the ones for condition index. - * @param conditionIndex - * @param optimizationParams - * @param udata + * parameters in the given Model object to the ones for simulation index. + * @param simulationIdx Index of the simulation condition for which to set + * model parameters. + * @param optimizationParams Problem parameters from which to extract + * simulation parameters. + * @param model Model on which to set parameter values and scale */ void updateSimulationParametersAndScale( int simulationIdx, diff --git a/include/parpeamici/multiConditionProblem.h b/include/parpeamici/multiConditionProblem.h index 2af508ca6..4a9d8a07d 100644 --- a/include/parpeamici/multiConditionProblem.h +++ b/include/parpeamici/multiConditionProblem.h @@ -188,7 +188,7 @@ class AmiciSummedGradientFunction : public SummedGradientFunction { double *cpuTime) const; /** - * @brief Aggregates loglikelihood received from workers. + * @brief Aggregates log-likelihood received from workers. * @param data Simulation job result * @param negLogLikelihood output argument to which *negative* * log likelihood is added @@ -206,7 +206,7 @@ class AmiciSummedGradientFunction : public SummedGradientFunction { /** - * @brief Aggregates loglikelihood gradient received from workers. + * @brief Aggregates log-likelihood gradient received from workers. * @param conditionIdx * @param simulationGradient log-likelihood gradient from simulation * @param objectiveFunctionGradient output to which *negative* diff --git a/include/parpeamici/standaloneSimulator.h b/include/parpeamici/standaloneSimulator.h index aa5092a41..dd817f317 100644 --- a/include/parpeamici/standaloneSimulator.h +++ b/include/parpeamici/standaloneSimulator.h @@ -34,7 +34,7 @@ class StandaloneSimulator * @param resultPath HDF5 file root group name * @param optimizationParameters Parameters for simulation (results from * hierarchical or standard optimization - * @param loadBalancer LoadBalander instance for distributed memory + * @param loadBalancer LoadBalancer instance for distributed memory * parallel, or nullptr for shared memory parallel or sequential * @param inputFile File with simulation options and data used for * optimization diff --git a/include/parpeloadbalancer/loadBalancerMaster.h b/include/parpeloadbalancer/loadBalancerMaster.h index fa94f7542..3e5ce9f36 100644 --- a/include/parpeloadbalancer/loadBalancerMaster.h +++ b/include/parpeloadbalancer/loadBalancerMaster.h @@ -94,7 +94,7 @@ class LoadBalancerMaster { void sendTerminationSignalToAllWorkers(); /** - * @brief Retuns whether we are ready to accept jobs (`run` was called, but + * @brief Returns whether we are ready to accept jobs (`run` was called, but * `terminate` was not). * @return true if running, false otherwise */ @@ -204,7 +204,7 @@ class LoadBalancerMaster { std::vector sendRequests; /** Jobs that have been sent to workers. Required for handling replies and - * signalling the client that processing has completed. */ + * signaling the client that processing has completed. */ std::vector sentJobsData; /** Mutex to protect access to `queue`. */ diff --git a/include/parpeloadbalancer/loadBalancerWorker.h b/include/parpeloadbalancer/loadBalancerWorker.h index ee14ba7ac..e60cd972a 100644 --- a/include/parpeloadbalancer/loadBalancerWorker.h +++ b/include/parpeloadbalancer/loadBalancerWorker.h @@ -15,11 +15,11 @@ class LoadBalancerWorker { LoadBalancerWorker() = default; /** - * messageHandler is called by run when a message is received. The - * message is contained in buffer. + * Callback function for when a message is received. + * * @param buffer The message - * @param jobId is a message identifier, unique over the range of MAX_INT - * messages + * @param jobId A message identifier, unique over the range of MAX_INT + * messages. */ using messageHandlerFunc = std::function &buffer, int jobId)>; @@ -27,8 +27,8 @@ class LoadBalancerWorker { private: /** - * @brief waitForAndHandleJobs - * @return true: received termination signal + * @brief Probe for and dispatch the next incoming job + * @return `true` if the termination signal was received, `false` otherwise. */ bool waitForAndHandleJobs(const messageHandlerFunc& messageHandler); }; diff --git a/include/parpeoptimization/localOptimizationToms611.h b/include/parpeoptimization/localOptimizationToms611.h index 339648924..6db73855c 100644 --- a/include/parpeoptimization/localOptimizationToms611.h +++ b/include/parpeoptimization/localOptimizationToms611.h @@ -13,8 +13,10 @@ class OptimizerToms611TrustRegionSumsl : public Optimizer { /** * @brief Minimize an objective function given as OptimizationProblem using * the `sumsl_` trust-region algorithm from TOMS611 + * (ACM TOMS 9 (1983) 503-524, https://doi.org/10.1145/356056.356066, + * code: http://netlib.org/toms/) * - * TODO: no options are specifyable for the moment + * TODO: no options are specifiable for the moment * * @param problem * @return Returns 0 on success. diff --git a/include/parpeoptimization/minibatchOptimization.h b/include/parpeoptimization/minibatchOptimization.h index be25297c6..931d61188 100755 --- a/include/parpeoptimization/minibatchOptimization.h +++ b/include/parpeoptimization/minibatchOptimization.h @@ -19,7 +19,7 @@ namespace parpe { /** - * @brief Return status for minibatch optimizer + * @brief Return status for mini-batch optimizer */ enum class minibatchExitStatus { gradientNormConvergence, maxEpochsExceeded, invalidNumber @@ -72,7 +72,7 @@ class MinibatchOptimizationProblem: public OptimizationProblem { }; /** - * @brief learning rate updaters for minibatch optimizers + * @brief learning rate updaters for mini-batch optimizers * * The LearningRateUpdater provides the possibility to reduce the learning rate per epoch * and makes it possible to adapt the learning rate according to success or failure of @@ -119,7 +119,7 @@ class LearningRateUpdater { /** Learning rate, i.e. step size, at the moment of optimization */ double currentLearningRate = 0.0; - /** If an optimization step is not succesful, the learning rate, i.e., step size, will be reduced by this factor */ + /** If an optimization step is not successful, the learning rate, i.e., step size, will be reduced by this factor */ double reductionFactor = 4.0; /** Learning rate, i.e. step size, at the beginning of optimization */ @@ -133,7 +133,7 @@ class LearningRateUpdater { }; /** - * @brief Interface for parameter updaters for minibatch optimizers + * @brief Interface for parameter updaters for mini-batch optimizers */ class ParameterUpdater { public: @@ -157,7 +157,7 @@ class ParameterUpdater { /** If the ODE is repeatedly non-integrable, a cold restart is performed using this method */ virtual void clearCache() = 0; - /** Intialize the parameter updater */ + /** Initialize the parameter updater */ virtual void initialize(unsigned int numParameters) = 0; virtual ~ParameterUpdater() = default; @@ -165,7 +165,7 @@ class ParameterUpdater { }; /** - * @brief Minibatch optimizer: Vanilla SGD Updater + * @brief Mini-batch optimizer: Vanilla SGD Updater * The simplest mini batch algorithm. */ class ParameterUpdaterVanilla: public ParameterUpdater { @@ -187,7 +187,7 @@ class ParameterUpdaterVanilla: public ParameterUpdater { }; /** - * @brief Minibatch optimizer: RMSProp Updater + * @brief Mini-batch optimizer: RMSProp Updater * A so-called adaptive mini batching algorithm without momentum */ class ParameterUpdaterRmsProp: public ParameterUpdater { @@ -212,7 +212,7 @@ class ParameterUpdaterRmsProp: public ParameterUpdater { /** Rate for memorizing gradient norms (between 0 and 1, high rates mean long memory) */ double decayRate = 0.9; - /** Stabilization factor for gradient normalization (avoid deviding by 0) */ + /** Stabilization factor for gradient normalization (avoid dividing by 0) */ double delta = 1e-7; /** Memorized gradient norms (decaying average) from last steps */ @@ -223,7 +223,7 @@ class ParameterUpdaterRmsProp: public ParameterUpdater { }; /** - * @brief Minibatch optimizer: Momentum Updater + * @brief Mini-batch optimizer: Momentum Updater * A classical gradient based optimizer using a vanilla momentum formula */ class ParameterUpdaterMomentum: public ParameterUpdater { @@ -256,7 +256,7 @@ class ParameterUpdaterMomentum: public ParameterUpdater { }; /** - * @brief Minibatch optimizer: Adam Updater + * @brief Mini-batch optimizer: Adam Updater * A momentum-based and so-called adaptive mini batching algorithm */ class ParameterUpdaterAdam: public ParameterUpdater { @@ -284,7 +284,7 @@ class ParameterUpdaterAdam: public ParameterUpdater { /** Rate for memorizing gradient norms (between 0 and 1, high rates mean long memory) */ double decayRateGradientNorm = 0.9; - /** Stabilization factor for gradient normalization (avoid deviding by 0) */ + /** Stabilization factor for gradient normalization (avoid dividing by 0) */ double delta = 1e-7; /** Memorized gradient norms (decaying average) from last steps */ @@ -301,7 +301,7 @@ class ParameterUpdaterAdam: public ParameterUpdater { }; /** - * @brief Minibatch optimizer: Adam Classic Updater + * @brief Mini-batch optimizer: Adam Classic Updater * A momentum-based and so-called adaptive mini batching algorithm, * using the original settings from the literature */ @@ -405,7 +405,7 @@ class MinibatchOptimizer { /** * @brief Minimize the given function using mini-batch gradient descent. * - * @param f Function to minize + * @param f Function to minimize * @param data Full data set on which f will be evaluated * @param initialParameters Starting point for optimization * @param reporter OptimizationReporter instance for tracking progress @@ -467,7 +467,7 @@ class MinibatchOptimizer { batchLogger->logmessage(LOGLVL_DEBUG, ss.str().c_str()); if (status == functionEvaluationFailure) { - // Check, if the interceptor should be used (should alwayss be the case, except for study purpose... + // Check, if the interceptor should be used (should always be the case, except for study purpose... if (interceptor > interceptType::none) status = rescueInterceptor(parameters, oldParameters, gradient, oldGradient, lowerParameterBounds, upperParameterBounds, cost, subsequentFails, @@ -478,7 +478,7 @@ class MinibatchOptimizer { return finish(cost, parameters, minibatchExitStatus::invalidNumber, reporter, batchLogger.get()); } else { - // Cost function evaluation was succeful, so we can increase the step size + // Cost function evaluation was successful, so we can increase the step size subsequentFails = std::max(subsequentFails - 1, 0); learningRateUpdater->increaseLearningRate(); @@ -493,7 +493,7 @@ class MinibatchOptimizer { } - // epoch finished, write the values in hdf5-file + // epoch finished, write the values in HDF5-file if (reporter) reporter->iterationFinished(parameters, cost, gradient); @@ -551,7 +551,7 @@ class MinibatchOptimizer { if (logger) { switch (status) { case minibatchExitStatus::invalidNumber: - logger->logmessage(LOGLVL_ERROR, "Minibatch cost function evaluation failed."); + logger->logmessage(LOGLVL_ERROR, "Mini-batch cost function evaluation failed."); break; case minibatchExitStatus::gradientNormConvergence: logger->logmessage(LOGLVL_INFO, "Convergence: gradientNormThreshold reached."); @@ -639,7 +639,7 @@ class MinibatchOptimizer { // If nothing helps and no cold restart wanted: cancel optimization if (initialFail or (finalFail and interceptor != interceptType::reduceStepAndRestart)) { - logger->logmessage(LOGLVL_DEBUG, "Failure at intial point of optimization. Stopping."); + logger->logmessage(LOGLVL_DEBUG, "Failure at initial point of optimization. Stopping."); return functionEvaluationFailure; } @@ -658,7 +658,7 @@ class MinibatchOptimizer { } // debug output - ss << ": Interceptor, before new evalaluation: " << std::endl + ss << ": Interceptor, before new evaluation: " << std::endl << " New cost: " << cost << ", new |g|2: " << getVectorNorm(gradient) << ", new LearningRate: " << learningRate @@ -678,7 +678,7 @@ class MinibatchOptimizer { parDifference = getVectorDifference(parameters, oldParameters); // debug output - ss << ": Interceptor, after new evalaluation: " << std::endl + ss << ": Interceptor, after new evaluation: " << std::endl << " New Cost: " << cost << " new |g|2: " << getVectorNorm(gradient) << " new LearningRate: " << learningRate @@ -701,7 +701,7 @@ class MinibatchOptimizer { * @param oldGradient cost function gradient before last step * @param cost new cost function value after interception * @param subsequentFails number of iterations during rescue interceptor - * @param f Function to minize + * @param f Function to minimize * @param data Full data set on which f will be evaluated * @param logger Logger instance for status messages * @param reporter OptimizationReporter instance for tracking progress @@ -740,7 +740,7 @@ class MinibatchOptimizer { parameterUpdater->updateParameters(alpha, iteration, gradient, parameters, lowerParameterBounds, upperParameterBounds); - /* Write new cost funtion value and return */ + /* Write new cost function value and return */ double newCost = NAN; evaluate(f, parameters, datasets, newCost, gsl::span(), logger, reporter); return newCost; @@ -807,9 +807,9 @@ class MinibatchOptimizer { cost1 = evalLineSearch(stepLength); parabola_ss << " Step adaption did not work..." << std::endl; } - parabola_ss << " cost0: " << cost << " (steplength: " << getVectorNorm(parDifference) - << "), cost1: " << cost1 << " (steplength: " << stepLength - << "), cost2: " << cost2 << " (steplength: " << newStepLength + parabola_ss << " cost0: " << cost << " (step length: " << getVectorNorm(parDifference) + << "), cost1: " << cost1 << " (step length: " << stepLength + << "), cost2: " << cost2 << " (step length: " << newStepLength << ") " << std::endl; if (logger) logger->logmessage(LOGLVL_DEBUG, parabola_ss.str().c_str()); @@ -827,9 +827,9 @@ class MinibatchOptimizer { // Debugging output if (logger) { line_ss << " Line-Search: two steps were done, results are: " << std::endl - << " cost0: " << cost << " (steplength: " << getVectorNorm(parDifference) - << "), cost1: " << cost1 << " (steplength: " << stepLength - << "), cost2: " << cost2 << " (steplength: " << newStepLength + << " cost0: " << cost << " (step length: " << getVectorNorm(parDifference) + << "), cost1: " << cost1 << " (step length: " << stepLength + << "), cost2: " << cost2 << " (step length: " << newStepLength << ")" << std::endl; logger->logmessage(LOGLVL_DEBUG, line_ss.str().c_str()); } @@ -861,8 +861,9 @@ class MinibatchOptimizer { } /** - * @brief Perform line search according to interpolation algo by [Dennis and Schnabel, - * Numerical Methods for Unconstrained Optimization and Non-linear Equations, 1993]. + * @brief Perform line search according to interpolation algorithm by + * [Dennis and Schnabel, Numerical Methods for Unconstrained Optimization + * and Non-linear Equations, 1993]. * * @param alpha1 step length of first step * @param alpha2 step length of second step @@ -890,7 +891,7 @@ class MinibatchOptimizer { * * alpha3 = -b + sqrt(b*b - 3*a*dirGradient ) / (3*a) * - * Possibly, we have to iterrate this process. */ + * Possibly, we have to iterate this process. */ /* Declare variables which will be needed outside the loop */ double cost3 = NAN; @@ -960,7 +961,7 @@ void setMinibatchOption(const std::pair &p MinibatchOptimizer* optimizer); /** - * @brief Create and setup a minibatch optimizer according to the given options + * @brief Create and setup a mini-batch optimizer according to the given options * @param options * @return */ diff --git a/src/parpeamici/amiciSimulationRunner.cpp b/src/parpeamici/amiciSimulationRunner.cpp index d7df5eb28..1eb3fce55 100644 --- a/src/parpeamici/amiciSimulationRunner.cpp +++ b/src/parpeamici/amiciSimulationRunner.cpp @@ -78,7 +78,7 @@ AmiciSimulationRunner::runDistributedMemory(LoadBalancerMaster* loadBalancer, pthread_mutex_lock(&simulationsMutex); while (numJobsFinished < numJobsTotal) // TODO don't wait for all to // complete; stop early if errors - // occured + // occurred pthread_cond_wait(&simulationsCond, &simulationsMutex); pthread_mutex_unlock(&simulationsMutex); pthread_mutex_destroy(&simulationsMutex); @@ -112,7 +112,7 @@ AmiciSimulationRunner::runSharedMemory(const messageHandlerFunc& messageHandler, for (int simulationIdx = 0; simulationIdx < (signed)condition_indices_.size(); ++simulationIdx) { - // to reuse the parallel code and for debugging we still serialze the + // to reuse the parallel code and for debugging we still serialize the // job data here auto curConditionIndices = std::vector{ simulationIdx }; AmiciWorkPackageSimple work{ optimization_parameters_, diff --git a/src/parpeamici/multiConditionDataProvider.cpp b/src/parpeamici/multiConditionDataProvider.cpp index 6d5ead756..7075a4a4d 100644 --- a/src/parpeamici/multiConditionDataProvider.cpp +++ b/src/parpeamici/multiConditionDataProvider.cpp @@ -63,7 +63,7 @@ int MultiConditionDataProviderHDF5::getNumberOfSimulationConditions() const { // TODO: add additional layer for selection of condition indices (for - // testing and later for minibatch) + // testing and later for mini-batch) // -> won't need different file for testing/validation splits // TODO: cache @@ -378,7 +378,7 @@ MultiConditionDataProviderHDF5::getOptimizationParametersUpperBounds( auto dataset = file_.openDataSet(hdf5_parameter_max_path_); auto dataspace = dataset.getSpace(); - // hdf5ParameterMaxPath dimensions dont match + // hdf5ParameterMaxPath dimensions don't match Expects(dataspace.getSimpleExtentNdims() == 1); hsize_t dim = 0; dataspace.getSimpleExtentDims(&dim); From b1c0eb9b8fc33d2b63d1c542d9fa9d87e3ae4577 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Tue, 25 May 2021 16:32:13 +0200 Subject: [PATCH 19/21] Fix install scripts --- CMakeModules/ParPEConfig.cmake.in | 3 ++- ThirdParty/installIpopt.sh | 2 +- buildAll.sh | 3 ++- buildSuperMUC.sh | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeModules/ParPEConfig.cmake.in b/CMakeModules/ParPEConfig.cmake.in index ebb66791e..183577e52 100644 --- a/CMakeModules/ParPEConfig.cmake.in +++ b/CMakeModules/ParPEConfig.cmake.in @@ -12,7 +12,8 @@ endif() if(${PARPE_ENABLE_IPOPT}) find_dependency(PkgConfig REQUIRED) -pkg_search_module(IPOPT REQUIRED IMPORTED_TARGET GLOBAL ipopt>=3.11.0) +pkg_search_module(IPOPT REQUIRED IMPORTED_TARGET GLOBAL ipopt=@IPOPT_VERSION@) +message("-- Found Ipopt version: ${IPOPT_VERSION}") endif() if(${PARPE_ENABLE_CERES}) diff --git a/ThirdParty/installIpopt.sh b/ThirdParty/installIpopt.sh index 09054775f..c7369cbe8 100755 --- a/ThirdParty/installIpopt.sh +++ b/ThirdParty/installIpopt.sh @@ -76,7 +76,7 @@ if [[ ! -d "${ipopt_dir}" ]]; then cd "${ipopt_dir}" - PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${hsl_install_dir}/lib/pkgconfig/ \ + PKG_CONFIG_PATH=${PKG_CONFIG_PATH-}:${hsl_install_dir}/lib/pkgconfig/ \ ./configure --prefix="${ipopt_install_dir}" \ --disable-static \ --enable-shared \ diff --git a/buildAll.sh b/buildAll.sh index a75e81961..377770a8f 100755 --- a/buildAll.sh +++ b/buildAll.sh @@ -18,7 +18,8 @@ cd "${amici_dir}" "${parpe_root}/ThirdParty/installIpopt.sh" # build parpe -export PKG_CONFIG_PATH=${parpe_root}/ThirdParty/Ipopt-releases-3.13.3/:${PKG_CONFIG_PATH:-} +ipopt_root=${parpe_root}/ThirdParty/Ipopt-releases-3.13.3/ +export PKG_CONFIG_PATH=${PKG_CONFIG_PATH:-}:${ipopt_root}/install/lib/pkgconfig/:${ipopt_root}/ThirdParty-HSL/install/lib/pkgconfig/ parpe_build_dir="${parpe_root}/build" mkdir -p "${parpe_build_dir}" cd "${parpe_build_dir}" diff --git a/buildSuperMUC.sh b/buildSuperMUC.sh index 18d777ef5..5e683726f 100755 --- a/buildSuperMUC.sh +++ b/buildSuperMUC.sh @@ -92,7 +92,7 @@ build_parpe() { HDF5_ROOT=${HDF5_BASE} \ BOOST_ROOT=${boost_install_dir} \ MPI_HOME=${MPI_BASE} \ - PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:${ipopt_root}/install/lib/pkgconfig/:${ipopt_root}/ThirdParty-HSL/install/lib/pkgconfig/ \ + PKG_CONFIG_PATH=${PKG_CONFIG_PATH:-}:${ipopt_root}/install/lib/pkgconfig/:${ipopt_root}/ThirdParty-HSL/install/lib/pkgconfig/ \ cmake -S .. \ -DPARPE_ENABLE_CERES=OFF \ -DBoost_USE_STATIC_LIBS=TRUE \ From d0bd8c19b9bb5426affdcd8386d893eee7940e80 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 3 Jun 2021 14:33:40 +0200 Subject: [PATCH 20/21] Add optimizer: fides-cpp (#340) Add wrapper and build scripts for https://github.com/dweindl/fides-cpp (C++ rewrite of https://github.com/fides-dev/fides). So far, only BFGS is supported via HDF5 optimizer options. --- .github/workflows/parpe_tests.yml | 7 +- CMakeLists.txt | 5 + CMakeModules/ParPEConfig.cmake.in | 6 + ThirdParty/installFides.sh | 44 +++++ .../localOptimizationFides.h | 28 +++ .../parpeoptimization/optimizationOptions.h | 1 + src/parpecommon/parpeConfig.h.in | 2 + src/parpeoptimization/CMakeLists.txt | 8 + .../localOptimizationFides.cpp | 162 ++++++++++++++++++ src/parpeoptimization/optimizationOptions.cpp | 24 +++ tests/parpeoptimization/CMakeLists.txt | 5 + .../localOptimizationFidesTest.cpp | 61 +++++++ tests/parpeoptimization/main.cpp | 4 + 13 files changed, 356 insertions(+), 1 deletion(-) create mode 100755 ThirdParty/installFides.sh create mode 100644 include/parpeoptimization/localOptimizationFides.h create mode 100644 src/parpeoptimization/localOptimizationFides.cpp create mode 100644 tests/parpeoptimization/localOptimizationFidesTest.cpp diff --git a/.github/workflows/parpe_tests.yml b/.github/workflows/parpe_tests.yml index f3a8893cd..11f66db27 100644 --- a/.github/workflows/parpe_tests.yml +++ b/.github/workflows/parpe_tests.yml @@ -57,6 +57,10 @@ jobs: run: | pip install -r ${PARPE_BASE}/python/requirements.txt + - name: "Install parPE deps: fides" + run: | + sudo apt install libspdlog-dev && ${PARPE_BASE}/ThirdParty/installFides.sh + - name: Configure parPE run: | cmake \ @@ -66,7 +70,8 @@ jobs: -DIPOPT_INCLUDE_DIRS=/usr/include/coin/ \ -DIPOPT_LIBRARIES=/usr/lib/libipopt.so \ -DGCOV_REPORT=TRUE \ - -DBUILD_TESTING=TRUE + -DBUILD_TESTING=TRUE \ + -DPARPE_ENABLE_FIDES=TRUE - name: Build parPE # with sonar build wrapper diff --git a/CMakeLists.txt b/CMakeLists.txt index a3b034295..aea9f82ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ set(BUILD_PYTHON_MODULE FALSE CACHE BOOL "Build Python module?") set(BLAS "CBLAS" CACHE STRING "BLAS library to use") set_property(CACHE BLAS PROPERTY STRINGS "CBLAS" "MKL") set(PARPE_ENABLE_MPI TRUE CACHE BOOL "Use MPI?") +set(PARPE_ENABLE_FIDES FALSE CACHE BOOL "Enable fides optimizer?") set(PARPE_ENABLE_IPOPT TRUE CACHE BOOL "Enable ipopt optimizer?") set(PARPE_ENABLE_CERES TRUE CACHE BOOL "Enable ceres optimizer?") set(PARPE_ENABLE_DLIB FALSE CACHE BOOL "Enable dlib optimizers?") @@ -68,6 +69,10 @@ if(${PARPE_ENABLE_MPI}) endif(${PARPE_ENABLE_MPI}) # +if(${PARPE_ENABLE_FIDES}) + find_package(Fides REQUIRED) +endif(${PARPE_ENABLE_FIDES}) + find_package(PkgConfig) pkg_search_module(IPOPT REQUIRED IMPORTED_TARGET GLOBAL ipopt>=3.11.0 ) diff --git a/CMakeModules/ParPEConfig.cmake.in b/CMakeModules/ParPEConfig.cmake.in index 183577e52..015538f64 100644 --- a/CMakeModules/ParPEConfig.cmake.in +++ b/CMakeModules/ParPEConfig.cmake.in @@ -5,6 +5,7 @@ include(CMakeFindDependencyMacro) set(PARPE_ENABLE_MPI @PARPE_ENABLE_MPI@) set(PARPE_ENABLE_IPOPT @PARPE_ENABLE_IPOPT@) set(PARPE_ENABLE_CERES @PARPE_ENABLE_CERES@) +set(PARPE_ENABLE_FIDES @PARPE_ENABLE_FIDES@) if(${PARPE_ENABLE_MPI}) find_dependency(MPI REQUIRED) @@ -22,6 +23,11 @@ find_dependency(Ceres COMPONENTS find_dependency(Eigen3 REQUIRED) endif() +if(${PARPE_ENABLE_FIDES}) +find_dependency(Fides + HINTS "${CMAKE_SOURCE_DIR}/ThirdParty/fides-cpp/build/") +endif() + find_dependency(Amici REQUIRED) find_dependency(OpenMP) find_dependency(HDF5 COMPONENTS C CXX HL REQUIRED) diff --git a/ThirdParty/installFides.sh b/ThirdParty/installFides.sh new file mode 100755 index 000000000..39bb9e362 --- /dev/null +++ b/ThirdParty/installFides.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Download and build fides-cpp + +build_blaze() { + cd "${script_dir}" + + if [[ ! -d "${blaze_dir}" ]]; then + if [[ ! -f "blaze-3.8.tar.gz" ]]; then + wget https://bitbucket.org/blaze-lib/blaze/downloads/blaze-3.8.tar.gz + fi + tar -xzf blaze-3.8.tar.gz + cd blaze-3.8 + cmake -S . -B build/ -DCMAKE_INSTALL_PREFIX="$(pwd)/build/install" + cd build + make -j2 install + fi +} + +build_fides() { + if [ ! -d "${fides_dir}" ]; then + cd "${script_dir}" + git clone https://github.com/dweindl/fides-cpp.git + cd "${fides_dir}" + git checkout 9906bdac6a1966ddd4b37b96f98ad8f89770c128 + fi + + cd "${fides_dir}" + cmake -S . -B build -DBUILD_TESTING=OFF + cd build + make ${make_opts} +} + +set -euo pipefail +script_dir=$(dirname "$0") +script_dir=$(cd "${script_dir}" && pwd) +cd "${script_dir}" + +make_opts=${MAKEOPTS-} + +fides_dir=${script_dir}/fides-cpp +blaze_dir=${script_dir}/blaze-3.8 + +build_blaze +build_fides diff --git a/include/parpeoptimization/localOptimizationFides.h b/include/parpeoptimization/localOptimizationFides.h new file mode 100644 index 000000000..d78fadb86 --- /dev/null +++ b/include/parpeoptimization/localOptimizationFides.h @@ -0,0 +1,28 @@ +#ifndef LOCAL_OPTIMIZATION_FIDES_H +#define LOCAL_OPTIMIZATION_FIDES_H + +#include +#include + +namespace parpe { + +class OptimizerFides : public Optimizer +{ + public: + OptimizerFides() = default; + + /** + * @brief Minimize an objective function given as OptimizationProblem using + * fides optimizer + * + * @param problem + * @return . + */ + + std::tuple> optimize( + OptimizationProblem* problem) override; +}; + +} // namespace parpe + +#endif diff --git a/include/parpeoptimization/optimizationOptions.h b/include/parpeoptimization/optimizationOptions.h index c11f5f988..e3f9fa85b 100644 --- a/include/parpeoptimization/optimizationOptions.h +++ b/include/parpeoptimization/optimizationOptions.h @@ -20,6 +20,7 @@ enum class optimizerName { OPTIMIZER_DLIB, OPTIMIZER_TOMS611, OPTIMIZER_FSQP, + OPTIMIZER_FIDES, OPTIMIZER_MINIBATCH_1 = 10 }; diff --git a/src/parpecommon/parpeConfig.h.in b/src/parpecommon/parpeConfig.h.in index ffc483176..2fa8b2c31 100644 --- a/src/parpecommon/parpeConfig.h.in +++ b/src/parpecommon/parpeConfig.h.in @@ -2,6 +2,8 @@ #define PARPE_CONFIG_H #cmakedefine PARPE_ENABLE_MPI + +#cmakedefine PARPE_ENABLE_FIDES #cmakedefine PARPE_ENABLE_IPOPT #cmakedefine PARPE_ENABLE_CERES #cmakedefine PARPE_ENABLE_FSQP diff --git a/src/parpeoptimization/CMakeLists.txt b/src/parpeoptimization/CMakeLists.txt index 0316b7dfb..f584d07bc 100644 --- a/src/parpeoptimization/CMakeLists.txt +++ b/src/parpeoptimization/CMakeLists.txt @@ -27,6 +27,14 @@ set(HEADER_LIST add_library(${PROJECT_NAME} ${SRC_LIST}) +if(${PARPE_ENABLE_FIDES}) + target_sources(${PROJECT_NAME} + PRIVATE localOptimizationFides.cpp) + list(APPEND HEADER_LIST + localOptimizationFides.h) + target_link_libraries(${PROJECT_NAME} PUBLIC Fides::fides) +endif(${PARPE_ENABLE_FIDES}) + if(${PARPE_ENABLE_IPOPT}) target_sources(${PROJECT_NAME} PRIVATE localOptimizationIpopt.cpp diff --git a/src/parpeoptimization/localOptimizationFides.cpp b/src/parpeoptimization/localOptimizationFides.cpp new file mode 100644 index 000000000..cba2b17ad --- /dev/null +++ b/src/parpeoptimization/localOptimizationFides.cpp @@ -0,0 +1,162 @@ +#include + +#include "parpecommon/logging.h" +#include "parpeoptimization/optimizationOptions.h" +#include "parpeoptimization/optimizationProblem.h" + +#include +#include + +using blaze::columnVector; +using blaze::CustomVector; +using blaze::DynamicVector; +using blaze::unaligned; +using blaze::unpadded; +using UnalignedUnpadded = CustomVector; + +namespace gsl { + +template +auto +make_span(DynamicVector& dv) +{ + return gsl::span(dv.data(), dv.size()); +} + +template +auto +make_span(DynamicVector const& dv) +{ + return gsl::span(dv.data(), dv.size()); +} + +} // namespace gsl + +namespace parpe { + +fides::Options +get_optimization_options(OptimizationOptions const& parpe_options) +{ + fides::Options fides_options; + fides_options.maxiter = parpe_options.maxOptimizerIterations; + + parpe_options.for_each( + [&fides_options](const std::pair& pair, int) { + const std::string& key = pair.first; + const std::string& val = pair.second; + auto &options = fides_options; + if (key == "maxiter") { + options.maxiter = std::stoi(val); + } else if (key == "maxtime") { + options.maxtime = std::chrono::seconds(std::stoi(val)); + } else if (key == "fatol") { + options.fatol = std::stod(val); + } else if (key == "frtol") { + options.frtol = std::stod(val); + } else if (key == "xtol") { + options.xtol = std::stod(val); + } else if (key == "gatol") { + options.gatol = std::stod(val); + } else if (key == "grtol") { + options.grtol = std::stod(val); + } else if (key == "subspace_solver") { + auto result = std::find_if( + fides::subspace_dim_to_str.cbegin(), + fides::subspace_dim_to_str.cend(), + [key](const auto& kv) { return kv.second == key; }); + if (result != fides::subspace_dim_to_str.cend()) + options.subspace_solver = result->first; + else + logmessage(LOGLVL_WARNING, + "Invalid value %s provided for option " + "'subspace_solver'. Ignoring.", + val.c_str()); + } else if (key == "stepback_strategy") { + auto result = std::find_if( + fides::step_back_strategy_str.cbegin(), + fides::step_back_strategy_str.cend(), + [key](const auto& kv) { return kv.second == key; }); + if (result != fides::step_back_strategy_str.cend()) + options.stepback_strategy = result->first; + else + logmessage(LOGLVL_WARNING, + "Invalid value %s provided for option " + "'stepback_strategy'. Ignoring.", + val.c_str()); + } else if (key == "theta_max") { + options.theta_max = std::stoi(val); + } else if (key == "delta_init") { + options.delta_init = std::stoi(val); + } else if (key == "mu") { + options.mu = std::stoi(val); + } else if (key == "eta") { + options.eta = std::stoi(val); + } else if (key == "gamma1") { + options.gamma1 = std::stoi(val); + } else if (key == "gamma2") { + options.gamma2 = std::stoi(val); + } else if (key == "refine_stepback") { + options.refine_stepback = std::stoi(val); + } else { + logmessage(LOGLVL_WARNING, + "Ignoring unknown optimization option %s.", + key.c_str()); + return; + } + + logmessage(LOGLVL_DEBUG, + "Set optimization option %s to %s.", + key.c_str(), + val.c_str()); + }, + 0); + + return fides_options; +} + +std::tuple> +OptimizerFides::optimize(OptimizationProblem* problem) +{ + auto reporter = problem->getReporter(); + auto numParams = + static_cast(problem->cost_fun_->numParameters()); + + DynamicVector x0(numParams); + problem->fillInitialParameters(x0); + + DynamicVector lb(numParams); + problem->fillParametersMin(lb); + + DynamicVector ub(numParams); + problem->fillParametersMax(ub); + + WallTimer optimization_timer; + + auto fun = [&problem](DynamicVector x) { + static __thread int numFunctionCalls = 0; + ++numFunctionCalls; + DynamicVector g(x.size(), NAN); + double fval = NAN; + problem->cost_fun_->evaluate( + gsl::make_span(x), fval, gsl::make_span(g), nullptr, nullptr); + + return std::make_tuple(fval, g, blaze::DynamicMatrix()); + }; + + auto fides_options = + get_optimization_options(problem->getOptimizationOptions()); + // TODO to config + fides::BFGS hessian_approximation; + fides::Optimizer optimizer( + fun, lb, ub, fides_options, &hessian_approximation); + + reporter->starting(x0); + auto [fval, x, grad, hess] = optimizer.minimize(x0); + reporter->finished(fval, x, static_cast(optimizer.exit_flag_)); + + return std::make_tuple(static_cast(optimizer.exit_flag_) <= 0, + fval, + std::vector(x.begin(), x.end())); +} + +} // namespace parpe diff --git a/src/parpeoptimization/optimizationOptions.cpp b/src/parpeoptimization/optimizationOptions.cpp index 20971272f..455284a2e 100644 --- a/src/parpeoptimization/optimizationOptions.cpp +++ b/src/parpeoptimization/optimizationOptions.cpp @@ -5,6 +5,10 @@ #include #endif +#ifdef PARPE_ENABLE_FIDES +#include +#endif + #ifdef PARPE_ENABLE_IPOPT #include #endif @@ -127,6 +131,9 @@ std::unique_ptr OptimizationOptions::fromHDF5(const H5::H5F std::string optimizerPath; switch(o->optimizer) { + case optimizerName::OPTIMIZER_FIDES: + optimizerPath = std::string(hdf5path) + "/fides"; + break; case optimizerName::OPTIMIZER_CERES: optimizerPath = std::string(hdf5path) + "/ceres"; break; @@ -261,6 +268,12 @@ void OptimizationOptions::setOption(const std::string& key, std::string value) std::unique_ptr optimizerFactory(optimizerName optimizer) { switch (optimizer) { + case optimizerName::OPTIMIZER_FIDES: +#ifdef PARPE_ENABLE_FIDES + return std::make_unique(); +#else + return nullptr; +#endif case optimizerName::OPTIMIZER_IPOPT: #ifdef PARPE_ENABLE_IPOPT return std::make_unique(); @@ -307,6 +320,17 @@ void printAvailableOptimizers(std::string const& prefix) // Note: Keep fall-through switch statement, so compiler will warn us about // any addition to optimizerName switch (optimizer) { + case optimizerName::OPTIMIZER_FIDES: +#ifdef PARPE_ENABLE_FIDES + std::cout<(optimizerName::OPTIMIZER_FIDES) + <<" enabled\n"; +#else + std::cout<(optimizerName::OPTIMIZER_FIDES) + <<" disabled\n"; +#endif + [[fallthrough]]; case optimizerName::OPTIMIZER_IPOPT: #ifdef PARPE_ENABLE_IPOPT std::cout< + +#include +#include + +#include "../parpecommon/testingMisc.h" +#include "quadraticTestProblem.h" + +#include + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Eq; +using ::testing::Ne; + +TEST(LocalOptimizationFides, FindsOptimum) +{ + parpe::QuadraticTestProblem problem; + + // should trigger termination + auto fatol = 1e-12; + + // should not trigger termination + auto xtol = 1e-16; + auto frtol = 0.0; + auto gatol = -1.0; + auto grtol = -1.0; + + + auto optimization_options = problem.getOptimizationOptions(); + optimization_options.setOption("xtol", xtol); + optimization_options.setOption("fatol", fatol); + optimization_options.setOption("frtol", frtol); + optimization_options.setOption("gatol", gatol); + optimization_options.setOption("grtol", grtol); + optimization_options.setOption("maxiter", 25); + problem.setOptimizationOptions(optimization_options); + + EXPECT_CALL(*problem.reporter, starting(_)); + EXPECT_CALL(*problem.reporter, + finished(_, _, static_cast(fides::ExitStatus::ftol))); + + // No calls without gradient + EXPECT_CALL(*dynamic_cast( + problem.cost_fun_.get()), + evaluate_impl(_, _, Eq(gsl::span()), _, _)) + .Times(0); + // At least one gradient evaluation + EXPECT_CALL(*dynamic_cast( + problem.cost_fun_.get()), + evaluate_impl(_, _, Ne(gsl::span()), _, _)) + .Times(AtLeast(1)); + + parpe::OptimizerFides optimizer; + auto [status, fval, parameters]= optimizer.optimize(&problem); + + // check status, cost, parameter + EXPECT_EQ(0, status); + EXPECT_NEAR(42.0, fval, fatol * 10.0); + EXPECT_NEAR(-1.0, parameters.at(0), 1e-6); +} diff --git a/tests/parpeoptimization/main.cpp b/tests/parpeoptimization/main.cpp index aea340cf0..f0b2ee417 100644 --- a/tests/parpeoptimization/main.cpp +++ b/tests/parpeoptimization/main.cpp @@ -10,6 +10,10 @@ #include "localOptimizationIpoptTest.h" #endif +#ifdef PARPE_ENABLE_FIDES +#include "localOptimizationFidesTest.h" +#endif + #ifdef PARPE_ENABLE_CERES #include "localOptimizationCeresTest.h" #endif From e75509e111c232b52058d4cff07f3bc31f23f020 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Thu, 3 Jun 2021 15:11:11 +0200 Subject: [PATCH 21/21] Update AMICI to v0.11.17 git subrepo clone (merge) --branch=v0.11.17 --force git@github.com:AMICI-dev/AMICI.git deps/AMICI (#341) subrepo: subdir: "deps/AMICI" merged: "c0377065" upstream: origin: "git@github.com:AMICI-dev/AMICI.git" branch: "v0.11.17" commit: "c0377065" git-subrepo: version: "0.4.1" origin: "https://github.com/ingydotnet/git-subrepo" commit: "a04d8c2" --- .../workflows/release_biosimulators.yml | 2 +- deps/AMICI/.github/workflows/test_install.yml | 4 +- deps/AMICI/.github/workflows/test_pypi.yml | 45 ++++++++++ deps/AMICI/.gitrepo | 6 +- deps/AMICI/CHANGELOG.md | 18 ++++ deps/AMICI/INSTALL.md | 10 +-- deps/AMICI/README.md | 16 +++- deps/AMICI/documentation/amici_refs.bib | 84 +++++++++++++++++-- deps/AMICI/documentation/how_to_cite.rst | 16 ++-- deps/AMICI/documentation/references.md | 30 +++++-- deps/AMICI/include/amici/serialization.h | 2 + deps/AMICI/python/amici/__main__.py | 25 ++++++ deps/AMICI/python/amici/ode_export.py | 41 ++++----- deps/AMICI/python/amici/petab_objective.py | 47 +---------- deps/AMICI/python/sdist/amici/__main__.py | 1 + deps/AMICI/scripts/buildAmici.sh | 2 +- deps/AMICI/scripts/installAmiciArchive.sh | 4 + deps/AMICI/src/hdf5.cpp | 11 +++ deps/AMICI/src/model.cpp | 4 +- deps/AMICI/src/rdata.cpp | 2 +- deps/AMICI/version.txt | 2 +- 21 files changed, 267 insertions(+), 105 deletions(-) create mode 100644 deps/AMICI/.github/workflows/test_pypi.yml create mode 100644 deps/AMICI/python/amici/__main__.py create mode 120000 deps/AMICI/python/sdist/amici/__main__.py diff --git a/deps/AMICI/.github/workflows/release_biosimulators.yml b/deps/AMICI/.github/workflows/release_biosimulators.yml index 2f0479e3c..53d5a5559 100644 --- a/deps/AMICI/.github/workflows/release_biosimulators.yml +++ b/deps/AMICI/.github/workflows/release_biosimulators.yml @@ -29,4 +29,4 @@ jobs: -u ${GH_ISSUE_USERNAME}:${GH_ISSUE_TOKEN} \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/${DOWNSTREAM_REPOSITORY}/actions/workflows/${WORKFLOW_FILE}/dispatches \ - -d "{\"inputs\": {\"simulatorVersion\": \"${PACKAGE_VERSION}\", \"simulatorVersionLatest\": \"true\"}}" + -d "{\"ref\": \"dev\", \"inputs\": {\"simulatorVersion\": \"${PACKAGE_VERSION}\", \"simulatorVersionLatest\": \"true\"}}" diff --git a/deps/AMICI/.github/workflows/test_install.yml b/deps/AMICI/.github/workflows/test_install.yml index 82ef251f4..b075d8d6f 100644 --- a/deps/AMICI/.github/workflows/test_install.yml +++ b/deps/AMICI/.github/workflows/test_install.yml @@ -75,4 +75,6 @@ jobs: run: | pip3 install -v --user $(ls -t python/sdist/dist/amici-*.tar.gz | head -1) - + - name: Test import + run: | + python -m amici diff --git a/deps/AMICI/.github/workflows/test_pypi.yml b/deps/AMICI/.github/workflows/test_pypi.yml new file mode 100644 index 000000000..138a93395 --- /dev/null +++ b/deps/AMICI/.github/workflows/test_pypi.yml @@ -0,0 +1,45 @@ +name: PyPI installation +on: + workflow_dispatch: + schedule: + - cron: '48 4 * * *' + +jobs: + pypi: + name: PyPI installation + + strategy: + fail-fast: false + matrix: + python-version: [3.7, 3.8, 3.9] + os: [ubuntu-20.04, macos-latest] + + runs-on: ${{ matrix.os }} + + steps: + - name: apt + run: | + if [[ ${{ matrix.os }} == ubuntu* ]] ; then \ + sudo apt-get update \ + && sudo apt-get install -y \ + g++ \ + libatlas-base-dev \ + libhdf5-serial-dev \ + swig + fi + + - name: homebrew + run: | + if [[ ${{ matrix.os }} == macos* ]] ; then \ + brew install hdf5 swig gcc libomp + fi + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - run: pip install --upgrade pip + - run: pip install -v amici + - run: python -c "from amici import _amici; print(_amici)" + - run: python -m amici diff --git a/deps/AMICI/.gitrepo b/deps/AMICI/.gitrepo index ed378cb2e..20b7889ce 100644 --- a/deps/AMICI/.gitrepo +++ b/deps/AMICI/.gitrepo @@ -5,8 +5,8 @@ ; [subrepo] remote = git@github.com:ICB-DCM/AMICI.git - branch = v0.11.16 - commit = 57a7b11cc2fb301cf838daefd966830c522643a8 - parent = 1fdf07292b1bafb5db738a28376ad886e68c41f4 + branch = v0.11.17 + commit = c0377065207b68c881143d203de1f56fd52878b9 + parent = d0bd8c19b9bb5426affdcd8386d893eee7940e80 cmdver = 0.4.1 method = merge diff --git a/deps/AMICI/CHANGELOG.md b/deps/AMICI/CHANGELOG.md index 3a0980a33..e39c780db 100644 --- a/deps/AMICI/CHANGELOG.md +++ b/deps/AMICI/CHANGELOG.md @@ -2,6 +2,24 @@ ## v0.X Series +### v0.11.17 (2021-05-30) + +Fixes: +* Fix "maybe-uninitialized" compiler warning (#1495) +* Fix substitution of expressions in `drootdt_total (#1512) +* C++: Fix serialization and == operator (#1493) +* C++: Avoid `w` in `root` and `stau` headers (refactor) (#1503) + +Documentation: +* Updated OpenBLAS Windows installation instructions (#1496) +* Updated how-to-cite to Bioinformatics paper (#1499) +* Updated list of papers using AMICI (#1509) + +Other: +* Remove sllh computation from `petab_objective.simulate_petab` (#1498) +* Add __main__.py to Python package to provide info on AMICI installation + via `python -m amici` (#1500) + ### v0.11.16 (2021-04-13) Fixes: diff --git a/deps/AMICI/INSTALL.md b/deps/AMICI/INSTALL.md index 2d4153502..61140d2e2 100755 --- a/deps/AMICI/INSTALL.md +++ b/deps/AMICI/INSTALL.md @@ -231,14 +231,14 @@ This will download openBLAS and compile it, creating You will also need to define two environment variables: BLAS_LIBS="/LIBPATH:C:/BLAS/lib openblas.lib" - BLAS_CFLAGS="/IC:/BLAS/OpenBLAS-v0.3.12/OpenBLAS-0.3.12" + BLAS_CFLAGS="/IC:/BLAS/OpenBLAS-0.3.12/OpenBLAS-0.3.12" One way to do that is to run a PowerShell script with the following commands: - [System.Environment]::SetEnvironmentVariable("BLAS_LIBS", "/LIBPATH:C:\BLAS\lib openblas.lib", [System.EnvironmentVariableTarget]::User) - [System.Environment]::SetEnvironmentVariable("BLAS_LIBS", "/LIBPATH:C:\BLAS\lib openblas.lib", [System.EnvironmentVariableTarget]::Process) - [System.Environment]::SetEnvironmentVariable("BLAS_CFLAGS", "-IC:\BLAS\OpenBLAS-v0.3.12\OpenBLAS-0.3.12", [System.EnvironmentVariableTarget]::User) - [System.Environment]::SetEnvironmentVariable("BLAS_CFLAGS", "-IC:\BLAS\OpenBLAS-v0.3.12\OpenBLAS-0.3.12", [System.EnvironmentVariableTarget]::Process) + [System.Environment]::SetEnvironmentVariable("BLAS_LIBS", "/LIBPATH:C:/BLAS/lib openblas.lib", [System.EnvironmentVariableTarget]::User) + [System.Environment]::SetEnvironmentVariable("BLAS_LIBS", "/LIBPATH:C:/BLAS/lib openblas.lib", [System.EnvironmentVariableTarget]::Process) + [System.Environment]::SetEnvironmentVariable("BLAS_CFLAGS", "-IC:/BLAS/OpenBLAS-0.3.12/OpenBLAS-0.3.12", [System.EnvironmentVariableTarget]::User) + [System.Environment]::SetEnvironmentVariable("BLAS_CFLAGS", "-IC:/BLAS/OpenBLAS-0.3.12/OpenBLAS-0.3.12", [System.EnvironmentVariableTarget]::Process) The call ending in `Process` sets the environment variable in the current process, and it is no longer in effect in the next process. The call ending in `User` is permanent, and takes effect the next time the user logs on. diff --git a/deps/AMICI/README.md b/deps/AMICI/README.md index 4f37d0680..1b05c7050 100644 --- a/deps/AMICI/README.md +++ b/deps/AMICI/README.md @@ -33,6 +33,8 @@ constrained optimization problems. PyPI version + + PyPI installation Build Status @@ -127,14 +129,20 @@ If you used AMICI in your work, we are happy to include your project, please let us know via a Github issue. When using AMICI in your project, please cite -* Fröhlich, F., Weindl, D., Schälte, Y., Pathirana, D., Paszkowski, Ł., Lines, G.T., Stapor, P. and Hasenauer, J., 2020. - AMICI: High-Performance Sensitivity Analysis for Large Ordinary Differential Equation Models. arXiv preprint [arXiv:2012.09122](https://arxiv.org/abs/2012.09122). +* Fröhlich, F., Weindl, D., Schälte, Y., Pathirana, D., Paszkowski, Ł., Lines, G.T., Stapor, P. and Hasenauer, J., 2021. + AMICI: High-Performance Sensitivity Analysis for Large Ordinary Differential Equation Models. Bioinformatics, btab227, + [DOI:10.1093/bioinformatics/btab227](https://doi.org/10.1093/bioinformatics/btab227). ``` @article{frohlich2020amici, title={AMICI: High-Performance Sensitivity Analysis for Large Ordinary Differential Equation Models}, author={Fr{\"o}hlich, Fabian and Weindl, Daniel and Sch{\"a}lte, Yannik and Pathirana, Dilan and Paszkowski, {\L}ukasz and Lines, Glenn Terje and Stapor, Paul and Hasenauer, Jan}, - journal={arXiv preprint arXiv:2012.09122}, - year={2020} + journal = {Bioinformatics}, + year = {2021}, + month = {04}, + issn = {1367-4803}, + doi = {10.1093/bioinformatics/btab227}, + note = {btab227}, + eprint = {https://academic.oup.com/bioinformatics/advance-article-pdf/doi/10.1093/bioinformatics/btab227/36866220/btab227.pdf}, } ``` diff --git a/deps/AMICI/documentation/amici_refs.bib b/deps/AMICI/documentation/amici_refs.bib index e73d87ed4..6803ee7e6 100644 --- a/deps/AMICI/documentation/amici_refs.bib +++ b/deps/AMICI/documentation/amici_refs.bib @@ -549,7 +549,7 @@ @Article{LinesPas2019 @Article{VillaverdeRai2019, author = {Alejandro F. Villaverde and Elba Raimúndez and Jan Hasenauer and Julio R. Banga}, journal = {IFAC-PapersOnLine}, - title = {A Comparison of Methods for Quantifying Prediction Uncertainty in Systems Biology⁎⁎This research has received funding from the European Unions Horizon 2020 research and innovation program under grant agreement No 686282 (CanPathPro) and the German Ministry of Education and Research (BMBF) under the grant agreement No 01ZX1310B (SYS-Stomach) and No 01ZX1705A (INCOME).}, + title = {A Comparison of Methods for Quantifying Prediction Uncertainty in Systems Biology}, year = {2019}, issn = {2405-8963}, note = {8th Conference on Foundations of Systems Biology in Engineering FOSBE 2019}, @@ -711,7 +711,7 @@ @Article{Schaelte2020.01.30.927004 url = {https://www.biorxiv.org/content/early/2020/01/31/2020.01.30.927004}, } -@Article{Adlung866871, +@Article{AdlungSta2019, author = {Adlung, Lorenz and Stapor, Paul and T{\"o}nsing, Christian and Schmiester, Leonard and Schwarzm{\"u}ller, Luisa E. and Wang, Dantong and Timmer, Jens and Klingm{\"u}ller, Ursula and Hasenauer, Jan and Schilling, Marcel}, journal = {bioRxiv}, title = {Cell-to-cell variability in JAK2/STAT5 pathway components and cytoplasmic volumes define survival threshold in erythroid progenitor cells}, @@ -725,10 +725,10 @@ @Article{Adlung866871 url = {https://www.biorxiv.org/content/early/2019/12/07/866871}, } -@Article{PITT201872, +@Article{PittGom2018, author = {Jake Alan Pitt and Lucian Gomoescu and Constantinos C. Pantelides and Benoît Chachuat and Julio R. Banga}, journal = {IFAC-PapersOnLine}, - title = {Critical Assessment of Parameter Estimation Methods in Models of Biological Oscillators⁎⁎This project has received funding from the European Unions Horizon 2020 research and innovation program under grant agreement 675585 (Marie Sklodowska-Curie ITN SyMBioSys). The authors JAP and LG are Marie Sklodowska-Curie Early Stage Researchers at IIM-CSIC (Spain) and PSE Ltd (UK) respectively.}, + title = {Critical Assessment of Parameter Estimation Methods in Models of Biological Oscillators}, year = {2018}, issn = {2405-8963}, note = {7th Conference on Foundation of Systems Biology in Engineering FOSBE 2018}, @@ -752,7 +752,7 @@ @MastersThesis{Watanabe2019 url = {https://hdl.handle.net/20.500.12380/256855}, } -@Article{Erdem2020.11.09.373407, +@Article{ErdemBen2020, author = {Erdem, Cemal and Bensman, Ethan M. and Mutsuddy, Arnab and Saint-Antoine, Michael M. and Bouhaddou, Mehdi and Blake, Robert C. and Dodd, Will and Gross, Sean M. and Heiser, Laura M. and Feltus, F. Alex and Birtwistle, Marc R.}, journal = {bioRxiv}, title = {A Simple and Efficient Pipeline for Construction, Merging, Expansion, and Simulation of Large-Scale, Single-Cell Mechanistic Models}, @@ -811,6 +811,80 @@ @Article{RaimundezDud2021 url = {https://www.sciencedirect.com/science/article/pii/S1755436521000037}, } +@Article{vanRosmalenSmi2021, + author = {R.P. {van Rosmalen} and R.W. Smith and V.A.P. {Martins dos Santos} and C. Fleck and M. Suarez-Diez}, + journal = {Metabolic Engineering}, + title = {Model reduction of genome-scale metabolic models as a basis for targeted kinetic models}, + year = {2021}, + issn = {1096-7176}, + pages = {74-84}, + volume = {64}, + abstract = {Constraint-based, genome-scale metabolic models are an essential tool to guide metabolic engineering. However, they lack the detail and time dimension that kinetic models with enzyme dynamics offer. Model reduction can be used to bridge the gap between the two methods and allow for the integration of kinetic models into the Design-Built-Test-Learn cycle. Here we show that these reduced size models can be representative of the dynamics of the original model and demonstrate the automated generation and parameterisation of such models. Using these minimal models of metabolism could allow for further exploration of dynamic responses in metabolic networks.}, + doi = {https://doi.org/10.1016/j.ymben.2021.01.008}, + keywords = {Metabolic engineering, DBTL cycle, Model reduction, Model optimisation, Model-driven design, Synthetic biology}, + url = {https://www.sciencedirect.com/science/article/pii/S1096717621000161}, +} + +@Article{StenPod2021, + author = {Sten, Sebastian and Pod{\'e}us, Henrik and Sundqvist, Nicolas and Elinder, Fredrik and Engstr{\"o}m, Maria and Cedersund, Gunnar}, + journal = {bioRxiv}, + title = {A multi-data based quantitative model for the neurovascular coupling in the brain}, + year = {2021}, + abstract = {The neurovascular coupling (NVC) forms the foundation for functional imaging techniques of the brain, since NVC connects neural activity with observable hemodynamic changes. Many aspects of the NVC have been studied both experimentally and with mathematical models: various combinations of blood volume and flow, electrical activity, oxygen saturation measures, blood oxygenation level-dependent (BOLD) response, and optogenetics have been measured and modeled in rodents, primates, or humans. We now present a first inter-connected mathematical model that describes all such data types simultaneously. The model can predict independent validation data not used for training. Using simulations, we show for example how complex bimodal behaviors appear upon stimulation. These simulations thus demonstrate how our new quantitative model, incorporating most of the core aspects of the NVC, can be used to mechanistically explain each of its constituent datasets.Competing Interest StatementThe authors have declared no competing interest.}, + doi = {10.1101/2021.03.25.437053}, + elocation-id = {2021.03.25.437053}, + eprint = {https://www.biorxiv.org/content/early/2021/03/26/2021.03.25.437053.full.pdf}, + publisher = {Cold Spring Harbor Laboratory}, + url = {https://www.biorxiv.org/content/early/2021/03/26/2021.03.25.437053}, +} + +@PhdThesis{Gaspari2021, + author = {Gaspari, Erika}, + school = {Wageningen University}, + title = {Model-driven design of Mycoplasma as a vaccine chassis}, + year = {2021}, + address = {Wageningen}, + comment = {WU thesis 7758 Includes bibliographical references. - With summaries in English, Italian and Spanish +10.18174/539593}, + doi = {10.18174/539593}, + issn = {9789463956864}, + url = {https://edepot.wur.nl/539593}, +} + +@Article{VanhoeferMat2021, + author = {Jakob Vanhoefer and Marta R. A. Matos and Dilan Pathirana and Yannik Schälte and Jan Hasenauer}, + journal = {Journal of Open Source Software}, + title = {yaml2sbml: Human-readable and -writable specification of ODE models and their conversion to SBML}, + year = {2021}, + number = {61}, + pages = {3215}, + volume = {6}, + doi = {10.21105/joss.03215}, + publisher = {The Open Journal}, + url = {https://doi.org/10.21105/joss.03215}, +} + +@Misc{VillaverdePat2021, + author = {Alejandro F. Villaverde and Dilan Pathirana and Fabian Fröhlich and Jan Hasenauer and Julio R. Banga}, + title = {A protocol for dynamic model calibration}, + year = {2021}, + archiveprefix = {arXiv}, + eprint = {2105.12008}, + primaryclass = {q-bio.QM}, +} +@article {Froehlich2021.05.20.445065, + author = {Fr{\"o}hlich, Fabian and Sorger, Peter K.}, + title = {Fides: Reliable Trust-Region Optimization for Parameter Estimation of Ordinary Differential Equation Models}, + elocation-id = {2021.05.20.445065}, + year = {2021}, + doi = {10.1101/2021.05.20.445065}, + publisher = {Cold Spring Harbor Laboratory}, + abstract = {Motivation Because they effectively represent mass action kinetics, ordinary differential equation models are widely used to describe biochemical processes. Optimization-based calibration of these models on experimental data can be challenging, even for low-dimensional problems. However, reliable model calibration is a prerequisite for many subsequent analysis steps, including uncertainty analysis, model selection and biological interpretation. Although multiple hypothesis have been advanced to explain why optimization based calibration of biochemical models is challenging, there are few comprehensive studies that test these hypothesis and tools for performing such studies are also lacking.Results We implemented an established trust-region method as a modular python framework (fides) to enable structured comparison of different approaches to ODE model calibration involving Hessian approximation schemes and trust-region subproblem solvers. We evaluate fides on a set of benchmark problems that include experimental data. We find a high variability in optimizer performance among different implementations of the same algorithm, with fides performing more reliably that other implementations investigated. Our investigation of possible sources of poor optimizer performance identify shortcomings in the widely used Gauss-Newton approximation. We address these shortcomings by proposing a novel hybrid Hessian approximation scheme that enhances optimizer performance.Availability Fides is published under the permissive BSD-3-Clause license with source code publicly available at https://github.com/fides-dev/fides. Citeable releases are archived on Zenodo.Contact fabian_froehlich{at}hms.harvard.edu and peter_sorger{at}hms.harvard.eduSupplementary information Supplementary data are available at Bioinformatics online and at https://github.com/fides-dev/fides-benchmark.Competing Interest StatementPKS is a member of the SAB or BOD member of Applied Biomath, RareCyte Inc., and Glencoe Software, which distributes a commercial version of the OMERO database; PKS is also a member of the NanoString SAB. In the last five years the Sorger lab has received research funding from Novartis and Merck. Sorger declares that none of these relationships have related to the content of this manuscript.}, + URL = {https://www.biorxiv.org/content/early/2021/05/22/2021.05.20.445065}, + eprint = {https://www.biorxiv.org/content/early/2021/05/22/2021.05.20.445065.full.pdf}, + journal = {bioRxiv} +} + @Comment{jabref-meta: databaseType:bibtex;} @Comment{jabref-meta: grouping: diff --git a/deps/AMICI/documentation/how_to_cite.rst b/deps/AMICI/documentation/how_to_cite.rst index b94673e0b..5439a8e04 100644 --- a/deps/AMICI/documentation/how_to_cite.rst +++ b/deps/AMICI/documentation/how_to_cite.rst @@ -13,17 +13,23 @@ your project, please let us know via a Github issue. When using AMICI in your project, please cite -* Fröhlich, F., Weindl, D., Schälte, Y., Pathirana, D., Paszkowski, Ł., Lines, G.T., Stapor, P. and Hasenauer, J., 2020. - AMICI: High-Performance Sensitivity Analysis for Large Ordinary Differential Equation Models. arXiv preprint `arXiv:2012.09122 `_. +* Fröhlich, F., Weindl, D., Schälte, Y., Pathirana, D., Paszkowski, Ł., Lines, G.T., Stapor, P. and Hasenauer, J., 2021. + AMICI: High-Performance Sensitivity Analysis for Large Ordinary Differential Equation Models. Bioinformatics, btab227, + `DOI:10.1093/bioinformatics/btab227 `_. .. code-block:: bibtex @article{frohlich2020amici, title={AMICI: High-Performance Sensitivity Analysis for Large Ordinary Differential Equation Models}, author={Fr{\"o}hlich, Fabian and Weindl, Daniel and Sch{\"a}lte, Yannik and Pathirana, Dilan and Paszkowski, {\L}ukasz and Lines, Glenn Terje and Stapor, Paul and Hasenauer, Jan}, - journal={arXiv preprint arXiv:2012.09122}, - year={2020} - } + journal = {Bioinformatics}, + year = {2021}, + month = {04}, + issn = {1367-4803}, + doi = {10.1093/bioinformatics/btab227}, + note = {btab227}, + eprint = {https://academic.oup.com/bioinformatics/advance-article-pdf/doi/10.1093/bioinformatics/btab227/36866220/btab227.pdf}, + } When presenting work that employs AMICI, feel free to use one of the icons in `documentation/gfx/ `_, diff --git a/deps/AMICI/documentation/references.md b/deps/AMICI/documentation/references.md index efe862292..3f624bdac 100644 --- a/deps/AMICI/documentation/references.md +++ b/deps/AMICI/documentation/references.md @@ -1,11 +1,17 @@ # References -List of publications using AMICI. Total number is 51. +List of publications using AMICI. Total number is 57. If you applied AMICI in your work and your publication is missing, please let us know via a new Github issue.

2021

+ +
+

Gaspari, Erika. 2021. “Model-Driven Design of Mycoplasma as a Vaccine Chassis.” PhD thesis, Wageningen: Wageningen University. https://doi.org/10.18174/539593.

+

Raimúndez, Elba, Erika Dudkin, Jakob Vanhoefer, Emad Alamoudi, Simon Merkt, Lara Fuhrmann, Fan Bai, and Jan Hasenauer. 2021. “COVID-19 Outbreak in Wuhan Demonstrates the Limitations of Publicly Available Case Numbers for Epidemiological Modeling.” Epidemics 34: 100439. https://doi.org/https://doi.org/10.1016/j.epidem.2021.100439.

@@ -15,13 +21,25 @@ If you applied AMICI in your work and your publication is missing, please let us

Städter, Philipp, Yannik Schälte, Leonard Schmiester, Jan Hasenauer, and Paul L. Stapor. 2021. “Benchmarking of Numerical Integration Methods for Ode Models of Biological Systems.” Scientific Reports 11 (1): 2696. https://doi.org/10.1038/s41598-021-82196-2.

+
+

Sten, Sebastian, Henrik Podéus, Nicolas Sundqvist, Fredrik Elinder, Maria Engström, and Gunnar Cedersund. 2021. “A Multi-Data Based Quantitative Model for the Neurovascular Coupling in the Brain.” bioRxiv. https://doi.org/10.1101/2021.03.25.437053.

+
+
+

Vanhoefer, Jakob, Marta R. a. Matos, Dilan Pathirana, Yannik Schälte, and Jan Hasenauer. 2021. “Yaml2sbml: Human-Readable and -Writable Specification of Ode Models and Their Conversion to Sbml.” Journal of Open Source Software 6 (61): 3215. https://doi.org/10.21105/joss.03215.

+
+
+

van Rosmalen, R. P., R. W. Smith, V. A. P. Martins dos Santos, C. Fleck, and M. Suarez-Diez. 2021. “Model Reduction of Genome-Scale Metabolic Models as a Basis for Targeted Kinetic Models.” Metabolic Engineering 64: 74–84. https://doi.org/https://doi.org/10.1016/j.ymben.2021.01.008.

+
+
+

Villaverde, Alejandro F., Dilan Pathirana, Fabian Fröhlich, Jan Hasenauer, and Julio R. Banga. 2021. “A Protocol for Dynamic Model Calibration.” http://arxiv.org/abs/2105.12008.

+

2020

Alabert, Constance, Carolin Loos, Moritz Voelker-Albert, Simona Graziano, Ignasi Forné, Nazaret Reveron-Gomez, Lea Schuh, et al. 2020. “Domain Model Explains Propagation Dynamics and Stability of Histone H3k27 and H3k36 Methylation Landscapes.” Cell Reports 30 (4): 1223–1234.e8. https://doi.org/10.1016/j.celrep.2019.12.060.

-
+

Erdem, Cemal, Ethan M. Bensman, Arnab Mutsuddy, Michael M. Saint-Antoine, Mehdi Bouhaddou, Robert C. Blake, Will Dodd, et al. 2020. “A Simple and Efficient Pipeline for Construction, Merging, Expansion, and Simulation of Large-Scale, Single-Cell Mechanistic Models.” bioRxiv. https://doi.org/10.1101/2020.11.09.373407.

@@ -54,7 +72,7 @@ If you applied AMICI in your work and your publication is missing, please let us

2019

-
+

Adlung, Lorenz, Paul Stapor, Christian Tönsing, Leonard Schmiester, Luisa E. Schwarzmüller, Dantong Wang, Jens Timmer, Ursula Klingmüller, Jan Hasenauer, and Marcel Schilling. 2019. “Cell-to-Cell Variability in Jak2/Stat5 Pathway Components and Cytoplasmic Volumes Define Survival Threshold in Erythroid Progenitor Cells.” bioRxiv. https://doi.org/10.1101/866871.

@@ -88,7 +106,7 @@ If you applied AMICI in your work and your publication is missing, please let us

Terje Lines, Glenn, Łukasz Paszkowski, Leonard Schmiester, Daniel Weindl, Paul Stapor, and Jan Hasenauer. 2019. “Efficient Computation of Steady States in Large-Scale Ode Models of Biochemical Reaction Networks.” IFAC-PapersOnLine 52 (26): 32–37. https://doi.org/10.1016/j.ifacol.2019.12.232.

-

Villaverde, Alejandro F., Elba Raimúndez, Jan Hasenauer, and Julio R. Banga. 2019. “A Comparison of Methods for Quantifying Prediction Uncertainty in Systems Biology⁎⁎This Research Has Received Funding from the European Unions Horizon 2020 Research and Innovation Program Under Grant Agreement No 686282 (Canpathpro) and the German Ministry of Education and Research (Bmbf) Under the Grant Agreement No 01ZX1310B (Sys-Stomach) and No 01ZX1705A (Income).” IFAC-PapersOnLine 52 (26): 45–51. https://doi.org/10.1016/j.ifacol.2019.12.234.

+

Villaverde, Alejandro F., Elba Raimúndez, Jan Hasenauer, and Julio R. Banga. 2019. “A Comparison of Methods for Quantifying Prediction Uncertainty in Systems Biology.” IFAC-PapersOnLine 52 (26): 45–51. https://doi.org/10.1016/j.ifacol.2019.12.234.

Wang, Dantong, Paul Stapor, and Jan Hasenauer. 2019. “Dirac Mixture Distributions for the Approximation of Mixed Effects Models.” IFAC-PapersOnLine 52 (26): 200–206. https://doi.org/10.1016/j.ifacol.2019.12.258.

@@ -120,8 +138,8 @@ If you applied AMICI in your work and your publication is missing, please let us

Loos, Carolin, Katharina Moeller, Fabian Fröhlich, Tim Hucho, and Jan Hasenauer. 2018. “A Hierarchical, Data-Driven Approach to Modeling Single-Cell Populations Predicts Latent Causes of Cell-to-Cell Variability.” Cell Systems 6 (5): 593–603. https://doi.org/10.1016/j.cels.2018.04.008.

-
-

Pitt, Jake Alan, Lucian Gomoescu, Constantinos C. Pantelides, Benoît Chachuat, and Julio R. Banga. 2018. “Critical Assessment of Parameter Estimation Methods in Models of Biological Oscillators⁎⁎This Project Has Received Funding from the European Unions Horizon 2020 Research and Innovation Program Under Grant Agreement 675585 (Marie Sklodowska-Curie Itn Symbiosys). The Authors Jap and Lg Are Marie Sklodowska-Curie Early Stage Researchers at Iim-Csic (Spain) and Pse Ltd (Uk) Respectively.” IFAC-PapersOnLine 51 (19): 72–75. https://doi.org/https://doi.org/10.1016/j.ifacol.2018.09.040.

+
+

Pitt, Jake Alan, Lucian Gomoescu, Constantinos C. Pantelides, Benoît Chachuat, and Julio R. Banga. 2018. “Critical Assessment of Parameter Estimation Methods in Models of Biological Oscillators.” IFAC-PapersOnLine 51 (19): 72–75. https://doi.org/https://doi.org/10.1016/j.ifacol.2018.09.040.

Schälte, Y., P. Stapor, and J. Hasenauer. 2018. “Evaluation of Derivative-Free Optimizers for Parameter Estimation in Systems Biology.” FAC-PapersOnLine 51 (19): 98–101. https://doi.org/10.1016/j.ifacol.2018.09.025.

diff --git a/deps/AMICI/include/amici/serialization.h b/deps/AMICI/include/amici/serialization.h index 0e2e6e090..ebb2ec87d 100644 --- a/deps/AMICI/include/amici/serialization.h +++ b/deps/AMICI/include/amici/serialization.h @@ -116,6 +116,8 @@ void serialize(Archive &ar, amici::Model &m, const unsigned int /*version*/) { ar &m.nmaxevent_; ar &m.state_is_non_negative_; ar &m.pythonGenerated; + ar &m.min_sigma_; + ar &m.sigma_res_; } diff --git a/deps/AMICI/python/amici/__main__.py b/deps/AMICI/python/amici/__main__.py new file mode 100644 index 000000000..dac523027 --- /dev/null +++ b/deps/AMICI/python/amici/__main__.py @@ -0,0 +1,25 @@ +"""Package-level entrypoint""" + +from . import __version__, compiledWithOpenMP, has_clibs, hdf5_enabled +import os +import sys + +def print_info(): + """Displays information on the current AMICI installation. + + Useful for verifying package installation of submitting bug reports""" + features = [] + + if has_clibs: + features.append("extensions") + + if compiledWithOpenMP(): + features.append("OpenMP") + + if hdf5_enabled: + features.append("HDF5") + + print(f"AMICI ({sys.platform}) version {__version__} ({','.join(features)})") + +if __name__ == '__main__': + print_info() diff --git a/deps/AMICI/python/amici/ode_export.py b/deps/AMICI/python/amici/ode_export.py index 713ecf468..b5ec800af 100644 --- a/deps/AMICI/python/amici/ode_export.py +++ b/deps/AMICI/python/amici/ode_export.py @@ -1215,17 +1215,6 @@ def transform_dxdt_to_concentration(species_id, dxdt): # fill in 'self._sym' based on prototypes and components in ode_model self.generate_basic_variables(from_sbml=True) - # substitute 'w' expressions into event expressions now, to avoid - # rewriting '{model_name}_root.cpp' headers to include 'w.h' - w_sorted = toposort_symbols(dict(zip(self._syms['w'], self._eqs['w']))) - for index, event in enumerate(self._events): - self._events[index] = Event( - identifier=event.get_id(), - name=event.get_name(), - value=event.get_val().subs(w_sorted), - state_update=event._state_update, - event_observable=event._observable, - ) self._has_quadratic_nllh = all( llh['dist'] in ['normal', 'lin-normal'] for llh in si.symbols[SymbolId.LLHY].values() @@ -1631,21 +1620,15 @@ def generate_basic_variables(self, *, from_sbml: bool = False) -> None: """ Generates the symbolic identifiers for all variables in ODEModel.variable_prototype - """ - # Workaround to generate `'w'` before events, such that `'w'` can be - # replaced in events, to avoid adding `w` to the header of - # "{model_name}_stau.cpp". - if 'w' not in self._syms: - self._generate_symbol('w', from_sbml=from_sbml) + :param from_sbml: + whether the model is generated from SBML + """ # We need to process events and Heaviside functions in the ODE Model, # before adding it to ODEExporter self.parse_events() for var in self._variable_prototype: - # Part of the workaround described earlier in this method. - if var == 'w': - continue if var not in self._syms: self._generate_symbol(var, from_sbml=from_sbml) @@ -1658,7 +1641,6 @@ def parse_events(self) -> None: and replaces the formulae of the found roots by identifiers of AMICI's Heaviside function implementation in the right hand side """ - # Track all roots functions in the right hand side roots = copy.deepcopy(self._events) for state in self._states: @@ -1667,6 +1649,11 @@ def parse_events(self) -> None: for expr in self._expressions: expr.set_val(self._process_heavisides(expr.get_val(), roots)) + # remove all possible Heavisides from roots, which may arise from + # the substitution of `'w'` in `_collect_heaviside_roots` + for root in roots: + root.set_val(self._process_heavisides(root.get_val(), roots)) + # Now add the found roots to the model components for root in roots: # skip roots of SBML events, as these have already been added @@ -1877,7 +1864,7 @@ def _compute_equation(self, name: str) -> None: # following lines are only evaluated if a model has events w_sorted = \ toposort_symbols(dict(zip(self._syms['w'], self._eqs['w']))) - tmp_xdot = self._eqs['xdot'].subs(w_sorted) + tmp_xdot = smart_subs_dict(self._eqs['xdot'], w_sorted) self._eqs[name] = ( smart_multiply(self.eq('drootdx'), tmp_xdot) + self.eq('drootdt') @@ -2411,7 +2398,7 @@ def _get_unique_root( def _collect_heaviside_roots( self, - args: Sequence[sp.Expr] + args: Sequence[sp.Expr], ) -> List[sp.Expr]: """ Recursively checks an expression for the occurrence of Heaviside @@ -2432,8 +2419,12 @@ def _collect_heaviside_roots( root_funs.extend(self._collect_heaviside_roots(arg.args)) # substitute 'w' expressions into root expressions now, to avoid - # rewriting '{model_name}_stau.cpp' headers to include 'w.h' - w_sorted = toposort_symbols(dict(zip(self._syms['w'], self.eq('w')))) + # rewriting '{model_name}_root.cpp' and '{model_name}_stau.cpp' headers + # to include 'w.h' + w_sorted = toposort_symbols(dict(zip( + [expr.get_id() for expr in self._expressions], + [expr.get_val() for expr in self._expressions], + ))) root_funs = [ r.subs(w_sorted) for r in root_funs diff --git a/deps/AMICI/python/amici/petab_objective.py b/deps/AMICI/python/amici/petab_objective.py index 2039d6803..6ae8ab0ca 100644 --- a/deps/AMICI/python/amici/petab_objective.py +++ b/deps/AMICI/python/amici/petab_objective.py @@ -139,9 +139,6 @@ def simulate_petab( # Compute total llh llh = sum(rdata['llh'] for rdata in rdatas) - # Compute total sllh - sllh = aggregate_sllh(amici_model=amici_model, rdatas=rdatas, - parameter_mapping=parameter_mapping) # Log results sim_cond = petab_problem.get_simulation_conditions_from_measurement_df() @@ -151,7 +148,6 @@ def simulate_petab( return { LLH: llh, - SLLH: sllh, RDATAS: rdatas } @@ -732,45 +728,4 @@ def rdatas_to_simulation_df( df = rdatas_to_measurement_df(rdatas=rdatas, model=model, measurement_df=measurement_df) - return df.rename(columns={MEASUREMENT: SIMULATION}) - - -def aggregate_sllh( - amici_model: AmiciModel, - rdatas: Sequence[amici.ReturnDataView], - parameter_mapping: Optional[ParameterMapping], -) -> Union[None, Dict[str, float]]: - """ - Aggregate likelihood gradient for all conditions, according to PEtab - parameter mapping. - - :param amici_model: - AMICI model from which ``rdatas`` were obtained. - :param rdatas: - Simulation results. - :param parameter_mapping: - PEtab parameter mapping to condition-specific - simulation parameters - - :return: - aggregated sllh - """ - sllh = {} - model_par_ids = amici_model.getParameterIds() - for condition_par_map, rdata in \ - zip(parameter_mapping, rdatas): - par_map_sim_var = condition_par_map.map_sim_var - if rdata['status'] != amici.AMICI_SUCCESS \ - or 'sllh' not in rdata \ - or rdata['sllh'] is None: - return None - - for model_par_id, problem_par_id in par_map_sim_var.items(): - if isinstance(problem_par_id, str): - model_par_idx = model_par_ids.index(model_par_id) - cur_par_sllh = rdata['sllh'][model_par_idx] - try: - sllh[problem_par_id] += cur_par_sllh - except KeyError: - sllh[problem_par_id] = cur_par_sllh - return sllh + return df.rename(columns={MEASUREMENT: SIMULATION}) \ No newline at end of file diff --git a/deps/AMICI/python/sdist/amici/__main__.py b/deps/AMICI/python/sdist/amici/__main__.py new file mode 120000 index 000000000..cfa13d34d --- /dev/null +++ b/deps/AMICI/python/sdist/amici/__main__.py @@ -0,0 +1 @@ +../../amici/__main__.py \ No newline at end of file diff --git a/deps/AMICI/scripts/buildAmici.sh b/deps/AMICI/scripts/buildAmici.sh index b943cf6fd..446fe1d8b 100755 --- a/deps/AMICI/scripts/buildAmici.sh +++ b/deps/AMICI/scripts/buildAmici.sh @@ -24,7 +24,7 @@ fi CppUTest_DIR=${cpputest_build_dir} \ ${cmake} \ - -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror -Wno-maybe-uninitialized" \ + -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror" \ -DCMAKE_BUILD_TYPE=$build_type \ -DPython3_EXECUTABLE="$(command -v python3)" .. diff --git a/deps/AMICI/scripts/installAmiciArchive.sh b/deps/AMICI/scripts/installAmiciArchive.sh index 20f4251ee..25de4f9f9 100755 --- a/deps/AMICI/scripts/installAmiciArchive.sh +++ b/deps/AMICI/scripts/installAmiciArchive.sh @@ -33,4 +33,8 @@ else fi pip install $(ls -t ${AMICI_PATH}/build/python/amici-*.tar.gz | head -1) + +# verify import succeeds +python -m amici + deactivate diff --git a/deps/AMICI/src/hdf5.cpp b/deps/AMICI/src/hdf5.cpp index 2dc974bb8..b548e4d54 100644 --- a/deps/AMICI/src/hdf5.cpp +++ b/deps/AMICI/src/hdf5.cpp @@ -960,6 +960,17 @@ void readModelDataFromHDF5(const H5::H5File &file, Model &model, model.setUnscaledInitialStateSensitivities(sx0); } } + + if(attributeExists(file, datasetPath, "sigma_res")) { + auto sigma_res = getIntScalarAttribute(file, datasetPath, "sigma_res"); + model.setAddSigmaResiduals(static_cast(sigma_res)); + } + + if(attributeExists(file, datasetPath, "min_sigma")) { + auto min_sigma = getDoubleScalarAttribute(file, datasetPath, + "min_sigma"); + model.setMinimumSigmaResiduals(min_sigma); + } } diff --git a/deps/AMICI/src/model.cpp b/deps/AMICI/src/model.cpp index 1058655bf..2123be742 100644 --- a/deps/AMICI/src/model.cpp +++ b/deps/AMICI/src/model.cpp @@ -185,7 +185,9 @@ bool operator==(const Model &a, const Model &b) { (a.state_.plist == b.state_.plist) && (a.x0data_ == b.x0data_) && (a.sx0data_ == b.sx0data_) && (a.nmaxevent_ == b.nmaxevent_) && - (a.state_is_non_negative_ == b.state_is_non_negative_); + (a.state_is_non_negative_ == b.state_is_non_negative_) && + (a.sigma_res_ == b.sigma_res_) && + (a.min_sigma_ == b.min_sigma_); } bool operator==(const ModelDimensions &a, const ModelDimensions &b) { diff --git a/deps/AMICI/src/rdata.cpp b/deps/AMICI/src/rdata.cpp index 50400d5af..df64d76eb 100644 --- a/deps/AMICI/src/rdata.cpp +++ b/deps/AMICI/src/rdata.cpp @@ -946,7 +946,7 @@ void ReturnData::fFIM(int it, Model &model, const ExpData &edata) { auto dy_i = sy_it.at(iy + ny * ip); auto ds_i = ssigmay_it.at(iy + ny * ip); auto sr_i = amici::fsres(y, dy_i, m, s, ds_i); - realtype sre_i; + realtype sre_i = 0.0; if (sigma_res) sre_i = amici::fsres_error(s, ds_i, sigma_offset); for (int jp = 0; jp < nplist; ++jp) { diff --git a/deps/AMICI/version.txt b/deps/AMICI/version.txt index db07b54af..c12244635 100644 --- a/deps/AMICI/version.txt +++ b/deps/AMICI/version.txt @@ -1 +1 @@ -0.11.16 +0.11.17