diff --git a/.github/workflows/test_conda_install.yml b/.github/workflows/test_conda_install.yml index 4e24ef78ea..9a1db741f5 100644 --- a/.github/workflows/test_conda_install.yml +++ b/.github/workflows/test_conda_install.yml @@ -47,7 +47,7 @@ jobs: - name: Test import shell: bash -l {0} run: | - python -c "from amici import _amici; print(_amici)" + python -c "from amici._installation import _amici; print(_amici)" python -m amici - name: Run SBML import test shell: bash -l {0} diff --git a/.github/workflows/test_python_cplusplus.yml b/.github/workflows/test_python_cplusplus.yml index fe70ddd8bd..799ffbbdc2 100644 --- a/.github/workflows/test_python_cplusplus.yml +++ b/.github/workflows/test_python_cplusplus.yml @@ -56,7 +56,7 @@ jobs: run: scripts/installAmiciSource.sh - name: Check OpenMP support - run: source venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiled_with_openmp())" + run: source venv/bin/activate && python -c "from amici.sim.sundials import compiled_with_openmp; import sys; sys.exit(not compiled_with_openmp())" - name: Python tests (part 1) run: | @@ -278,7 +278,7 @@ jobs: run: scripts/installAmiciSource.sh - name: Check OpenMP support - run: source venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiled_with_openmp())" + run: source venv/bin/activate && python -c "from amici.sim.sundials import compiled_with_openmp; import sys; sys.exit(not compiled_with_openmp())" - name: cppcheck run: scripts/run-cppcheck.sh @@ -340,7 +340,7 @@ jobs: scripts/installAmiciSource.sh - name: Check OpenMP support - run: source venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiled_with_openmp())" + run: source venv/bin/activate && python -c "from amici.sim.sundials import compiled_with_openmp; import sys; sys.exit(not compiled_with_openmp())" - name: Get BioNetGen run: scripts/buildBNGL.sh diff --git a/.gitignore b/.gitignore index 4a3df8cbdd..96bf825460 100644 --- a/.gitignore +++ b/.gitignore @@ -155,13 +155,13 @@ python/tests/piecewise_test/* python/sdist/amici.egg-info/* python/sdist/amici/version.txt -python/sdist/amici/amici.py -python/sdist/amici/amici_wrap.cxx -python/sdist/amici/amici_without_hdf5.py -python/sdist/amici/amici_wrap_without_hdf5.cxx -python/sdist/amici/include/ -python/sdist/amici/lib/ -python/sdist/amici/share/ +python/sdist/amici/_installation/amici.py +python/sdist/amici/_installation/amici_wrap.cxx +python/sdist/amici/_installation/amici_without_hdf5.py +python/sdist/amici/_installation/amici_wrap_without_hdf5.cxx +python/sdist/amici/_installation/include/ +python/sdist/amici/_installation/lib/ +python/sdist/amici/_installation/share/ python/sdist/build/* python/sdist/amici/git_version.txt diff --git a/doc/conf.py b/doc/conf.py index 1d0fa82804..18918ae953 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -93,7 +93,7 @@ def install_doxygen(): # -- Mock out some problematic modules------------------------------------- # Note that for sub-modules, all parent modules must be listed explicitly. -autodoc_mock_imports = ["_amici", "amici._amici"] +autodoc_mock_imports = ["_amici", "amici._installation._amici"] for mod_name in autodoc_mock_imports: sys.modules[mod_name] = mock.MagicMock() @@ -363,7 +363,7 @@ def install_doxygen(): "BoolVector": ":class:`bool`", "DoubleVector": ":class:`float`", "StringVector": ":class:`str`", - "ExpDataPtrVector": ":class:`amici.amici.ExpData`", + "ExpDataPtrVector": ":class:`amici.sim.sundials.ExpData`", } # TODO: alias for forward type definition, remove after release of petab_sciml diff --git a/doc/examples/example_errors.ipynb b/doc/examples/example_errors.ipynb index 170400d7ae..13daedfe4e 100644 --- a/doc/examples/example_errors.ipynb +++ b/doc/examples/example_errors.ipynb @@ -11,27 +11,22 @@ ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, + "id": "b9e6cb8843da8bc3", + "metadata": {}, + "outputs": [], "source": [ "%matplotlib inline\n", "import os\n", "from contextlib import suppress\n", "from pathlib import Path\n", "\n", - "import amici\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "from amici import (\n", " SbmlImporter,\n", - " SensitivityMethod,\n", - " SensitivityOrder,\n", - " SteadyStateSensitivityMode,\n", " import_model_module,\n", - " run_simulation,\n", - " simulation_status_to_str,\n", ")\n", "from amici.importers.petab.v1 import (\n", " EDATAS,\n", @@ -39,7 +34,17 @@ " import_petab_problem,\n", " simulate_petab,\n", ")\n", - "from amici.plotting import plot_jacobian, plot_state_trajectories\n", + "from amici.sim.sundials import (\n", + " AMICI_SUCCESS,\n", + " ExpData,\n", + " SensitivityMethod,\n", + " SensitivityOrder,\n", + " SteadyStateSensitivityMode,\n", + " run_simulation,\n", + " simulation_status_to_str,\n", + " unscale_parameter,\n", + ")\n", + "from amici.sim.sundials.plotting import plot_jacobian, plot_state_trajectories\n", "from petab.v1.sbml import get_sbml_model\n", "\n", "try:\n", @@ -51,8 +56,7 @@ " import benchmark_models_petab\n", " except ModuleNotFoundError:\n", " print(\"** Please restart the kernel. **\")" - ], - "id": "b9e6cb8843da8bc3" + ] }, { "cell_type": "markdown", @@ -131,9 +135,9 @@ "\n", "The number of steps the solver has to take is closely related to the chosen error tolerance. More accurate results, more steps. Therefore, this problem can be solved in two ways:\n", "\n", - "1. Increasing the maximum number of steps via [amici.Solver.set_max_steps](https://amici.readthedocs.io/en/latest/generated/amici.amici.Solver.html#amici.amici.Solver.set_max_steps). Note that this will increase the time required for simulation, and that simulation may still fail eventually. Sometimes it may be preferable to not increase this limit but rather fail fast. Also note that increasing the number of allowed steps increase RAM requirements (even if fewer steps are actually taken), so don't set this to ridiculously large values in order to avoid this error.\n", + "1. Increasing the maximum number of steps via [Solver.set_max_steps](https://amici.readthedocs.io/en/latest/generated/amici.sim.sundials.Solver.html#amici.sim.sundials.Solver.set_max_steps). Note that this will increase the time required for simulation, and that simulation may still fail eventually. Sometimes it may be preferable to not increase this limit but rather fail fast. Also note that increasing the number of allowed steps increase RAM requirements (even if fewer steps are actually taken), so don't set this to ridiculously large values in order to avoid this error.\n", "\n", - "2. Reducing the number of steps CVODES has to take. This is determined by the required error tolerance. There are various solver error tolerances than can be adjusted. The most relevant ones are those controlled via [amici.Solver.set_relative_tolerance()](https://amici.readthedocs.io/en/latest/generated/amici.amici.Solver.html#amici.amici.Solver.set_relative_tolerance) and [amici.Solver.set_absolute_tolerance()](https://amici.readthedocs.io/en/latest/generated/amici.amici.Solver.html#amici.amici.Solver.set_absolute_tolerance).\n", + "2. Reducing the number of steps CVODES has to take. This is determined by the required error tolerance. There are various solver error tolerances than can be adjusted. The most relevant ones are those controlled via [Solver.set_relative_tolerance()](https://amici.readthedocs.io/en/latest/generated/amici.sim.sundials.Solver.html#amici.sim.sundials.Solver.set_relative_tolerance) and [Solver.set_absolute_tolerance()](https://amici.readthedocs.io/en/latest/generated/amici.sim.sundials.Solver.html#amici.sim.sundials.Solver.set_absolute_tolerance).\n", "\n", "So, let's fix that:" ] @@ -162,7 +166,7 @@ " \"Status:\",\n", " [simulation_status_to_str(rdata.status) for rdata in res[RDATAS]],\n", ")\n", - "assert all(rdata.status == amici.AMICI_SUCCESS for rdata in res[RDATAS])\n", + "assert all(rdata.status == AMICI_SUCCESS for rdata in res[RDATAS])\n", "print(\"Simulations finished successfully.\")\n", "print()\n", "\n", @@ -183,7 +187,7 @@ " \"Status:\",\n", " [simulation_status_to_str(rdata.status) for rdata in res[RDATAS]],\n", ")\n", - "assert all(rdata.status == amici.AMICI_SUCCESS for rdata in res[RDATAS])\n", + "assert all(rdata.status == AMICI_SUCCESS for rdata in res[RDATAS])\n", "print(\"Simulations finished successfully.\")" ] }, @@ -253,7 +257,7 @@ "outputs": [], "source": [ "# Create a copy of this simulation condition\n", - "edata = amici.ExpData(res[EDATAS][0])\n", + "edata = ExpData(res[EDATAS][0])\n", "edata.set_timepoints(np.linspace(0, 0.33011, 5000))\n", "amici_solver = amici_model.create_solver()\n", "rdata = run_simulation(amici_model, amici_solver, edata)\n", @@ -403,7 +407,7 @@ " \"Status:\",\n", " [simulation_status_to_str(rdata.status) for rdata in res[RDATAS]],\n", ")\n", - "assert all(rdata.status == amici.AMICI_SUCCESS for rdata in res[RDATAS])\n", + "assert all(rdata.status == AMICI_SUCCESS for rdata in res[RDATAS])\n", "print(\"Simulations finished successfully.\")" ] }, @@ -631,9 +635,7 @@ "unscaled_parameter = dict(\n", " zip(\n", " amici_model.get_free_parameter_ids(),\n", - " starmap(\n", - " amici.unscale_parameter, zip(edata.free_parameters, edata.pscale)\n", - " ),\n", + " starmap(unscale_parameter, zip(edata.free_parameters, edata.pscale)),\n", " )\n", ")\n", "print(dict((p, unscaled_parameter[p]) for p in (\"Kd\", \"Kp\", \"n_par\")))" @@ -796,7 +798,7 @@ " \"Status:\",\n", " [simulation_status_to_str(rdata.status) for rdata in res[RDATAS]],\n", ")\n", - "assert all(rdata.status == amici.AMICI_SUCCESS for rdata in res[RDATAS])" + "assert all(rdata.status == AMICI_SUCCESS for rdata in res[RDATAS])" ] }, { @@ -835,7 +837,7 @@ " \"Status:\",\n", " [simulation_status_to_str(rdata.status) for rdata in res[RDATAS]],\n", ")\n", - "assert all(rdata.status == amici.AMICI_SUCCESS for rdata in res[RDATAS])" + "assert all(rdata.status == AMICI_SUCCESS for rdata in res[RDATAS])" ] }, { @@ -972,7 +974,7 @@ "\n", "# hard to reproduce on GHA\n", "if os.getenv(\"GITHUB_ACTIONS\") is None:\n", - " assert all(rdata.status == amici.AMICI_SUCCESS for rdata in res[RDATAS])" + " assert all(rdata.status == AMICI_SUCCESS for rdata in res[RDATAS])" ] }, { @@ -998,7 +1000,7 @@ " scaled_parameters=True,\n", " solver=amici_solver,\n", " )\n", - " if all(rdata.status == amici.AMICI_SUCCESS for rdata in res[RDATAS]):\n", + " if all(rdata.status == AMICI_SUCCESS for rdata in res[RDATAS]):\n", " print(\n", " f\"-> Succeeded with relative steady state tolerance {amici_solver.get_relative_tolerance_steady_state()}\\n\"\n", " )\n", @@ -1014,7 +1016,7 @@ "rdata = res[RDATAS][0]\n", "print(f\"preeq_status={rdata.preeq_status}\")\n", "print(f\"{rdata.preeq_numsteps=}\")\n", - "assert all(rdata.status == amici.AMICI_SUCCESS for rdata in res[RDATAS])" + "assert all(rdata.status == AMICI_SUCCESS for rdata in res[RDATAS])" ] }, { diff --git a/doc/examples/example_jax/ExampleJax.ipynb b/doc/examples/example_jax/ExampleJax.ipynb index 4f6aa51503..83822638f1 100644 --- a/doc/examples/example_jax/ExampleJax.ipynb +++ b/doc/examples/example_jax/ExampleJax.ipynb @@ -274,16 +274,16 @@ ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, + "id": "4c510f3e65879888", + "metadata": {}, + "outputs": [], "source": [ "from amici.importers.petab.v1 import import_petab_problem\n", "\n", "amici_model = import_petab_problem(petab_problem, compile_=True, verbose=False)" - ], - "id": "4c510f3e65879888" + ] }, { "cell_type": "markdown", @@ -304,16 +304,17 @@ ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, + "id": "beb890bd2f3d0880", + "metadata": {}, + "outputs": [], "source": [ - "import amici\n", "from amici.importers.petab.v1 import simulate_petab\n", + "from amici.sim.sundials import SensitivityOrder\n", "\n", "amici_solver = amici_model.create_solver()\n", - "amici_solver.set_sensitivity_order(amici.SensitivityOrder.first)\n", + "amici_solver.set_sensitivity_order(SensitivityOrder.first)\n", "\n", "\n", "def amici_callback_base(parameters: jnp.array):\n", @@ -328,8 +329,7 @@ " tuple(ret[\"sllh\"][par_id] for par_id in petab_problem.x_free_ids)\n", " )\n", " return llh, sllh" - ], - "id": "beb890bd2f3d0880" + ] }, { "cell_type": "markdown", diff --git a/doc/examples/example_jax_petab/ExampleJaxPEtab.ipynb b/doc/examples/example_jax_petab/ExampleJaxPEtab.ipynb index e8d89a8e1a..3865eb9dbf 100644 --- a/doc/examples/example_jax_petab/ExampleJaxPEtab.ipynb +++ b/doc/examples/example_jax_petab/ExampleJaxPEtab.ipynb @@ -565,8 +565,8 @@ "metadata": {}, "outputs": [], "source": [ - "import amici\n", "from amici.importers.petab.v1 import simulate_petab\n", + "from amici.sim.sundials import SensitivityMethod, SensitivityOrder\n", "\n", "# Import the PEtab problem as a standard AMICI model\n", "amici_model = import_petab_problem(\n", @@ -594,7 +594,7 @@ "outputs": [], "source": [ "# Profile simulation only\n", - "solver.set_sensitivity_order(amici.SensitivityOrder.none)" + "solver.set_sensitivity_order(SensitivityOrder.none)" ] }, { @@ -616,16 +616,16 @@ ] }, { - "metadata": {}, "cell_type": "code", - "source": [ - "# Profile gradient computation using forward sensitivity analysis\n", - "solver.set_sensitivity_order(amici.SensitivityOrder.first)\n", - "solver.set_sensitivity_method(amici.SensitivityMethod.forward)" - ], + "execution_count": null, "id": "81fe95a6e7f613f1", + "metadata": {}, "outputs": [], - "execution_count": null + "source": [ + "# Profile gradient computation using forward sensitivity analysis\n", + "solver.set_sensitivity_order(SensitivityOrder.first)\n", + "solver.set_sensitivity_method(SensitivityMethod.forward)" + ] }, { "cell_type": "code", @@ -653,8 +653,8 @@ "outputs": [], "source": [ "# Profile gradient computation using adjoint sensitivity analysis\n", - "solver.set_sensitivity_order(amici.SensitivityOrder.first)\n", - "solver.set_sensitivity_method(amici.SensitivityMethod.adjoint)" + "solver.set_sensitivity_order(SensitivityOrder.first)\n", + "solver.set_sensitivity_method(SensitivityMethod.adjoint)" ] }, { diff --git a/doc/examples/example_petab/petab.ipynb b/doc/examples/example_petab/petab.ipynb index 092743127a..57f171d63d 100644 --- a/doc/examples/example_petab/petab.ipynb +++ b/doc/examples/example_petab/petab.ipynb @@ -12,19 +12,19 @@ ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "import petab\n", - "from amici import run_simulation\n", "from amici.importers.petab.v1 import (\n", " import_petab_problem,\n", " simulate_petab,\n", ")\n", "from amici.importers.petab.v1.petab_problem import PetabProblem\n", - "from amici.plotting import plot_state_trajectories" + "from amici.sim.sundials import run_simulation\n", + "from amici.sim.sundials.plotting import plot_state_trajectories" ] }, { diff --git a/doc/examples/example_petab/petab_v2.ipynb b/doc/examples/example_petab/petab_v2.ipynb index f77feecfd4..d04f675ce0 100644 --- a/doc/examples/example_petab/petab_v2.ipynb +++ b/doc/examples/example_petab/petab_v2.ipynb @@ -13,19 +13,19 @@ ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, + "id": "419616ae233de558", + "metadata": {}, + "outputs": [], "source": [ "import logging\n", "\n", - "import amici\n", "from amici.importers.petab import *\n", - "from amici.plotting import *\n", + "from amici.sim.sundials import AMICI_SUCCESS\n", + "from amici.sim.sundials.plotting import *\n", "from petab.v2 import Problem" - ], - "id": "419616ae233de558" + ] }, { "cell_type": "markdown", @@ -38,8 +38,10 @@ }, { "cell_type": "code", + "execution_count": null, "id": "bb11cbb310be1e2b", "metadata": {}, + "outputs": [], "source": [ "# Load a PEtab v2 problem\n", "problem_id = \"Boehm_JProteomeRes2014\"\n", @@ -47,9 +49,7 @@ "problem = Problem.from_yaml(petab_yaml)\n", "\n", "print(problem)" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "markdown", @@ -59,14 +59,14 @@ }, { "cell_type": "code", + "execution_count": null, "id": "1bc978a08382cd40", "metadata": {}, + "outputs": [], "source": [ "importer = PetabImporter(problem, verbose=logging.INFO)\n", "simulator = importer.create_simulator()" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "markdown", @@ -76,19 +76,19 @@ }, { "cell_type": "code", + "execution_count": null, "id": "cee93ebff9477aca", "metadata": {}, + "outputs": [], "source": [ "# simulate all conditions encoded in the PEtab problem for which there are measurements\n", "# using the nominal parameter values from the PEtab problem\n", "result = simulator.simulate(problem.get_x_nominal_dict())\n", - "assert all(r.status == amici.AMICI_SUCCESS for r in result[RDATAS]), (\n", + "assert all(r.status == AMICI_SUCCESS for r in result[RDATAS]), (\n", " \"Simulation failed.\"\n", ")\n", "result" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "markdown", @@ -96,7 +96,7 @@ "metadata": {}, "source": [ "The returned dictionary contains the simulation results for all experimental conditions encoded in the PEtab problem in `result['rdatas']`.\n", - "Those are the same objects as for any other AMICI simulation using `amici.run_simulation`.\n", + "Those are the same objects as for any other AMICI simulation using `run_simulation`.\n", "Additionally, the dictionary contains the `ExpData` instances used for the simulations in `result['edatas']`, which we will use below to visualize the PEtab-encoded measurements.\n", "`result['llh']` and `result['sllh']` contain the aggregated log-likelihood value and its gradient, respectively, over all experimental conditions.\n", "These can be used directly for parameter estimation. However, for parameter estimation, it is recommended to use the `pypesto` package that provides a full parameter estimation framework on top of AMICI and PEtab.\n", @@ -106,21 +106,21 @@ }, { "cell_type": "code", + "execution_count": null, "id": "e532cbc3ebb361ef", "metadata": {}, + "outputs": [], "source": [ "rdata = result[\"rdatas\"][0]\n", "edata = result[\"edatas\"][0]\n", "plot_observable_trajectories(rdata, model=simulator.model, edata=edata)" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "markdown", "id": "8e99536dd10b5116", "metadata": {}, - "source": "Simulation settings can be adjusted via the `PetabSimulator.solver` and `PetabSimulator.model` attributes, which are instances of `amici.Solver` and `amici.Solver`, respectively." + "source": "Simulation settings can be adjusted via the `PetabSimulator.solver` and `PetabSimulator.model` attributes, which are instances of `Solver` and `Solver`, respectively." }, { "cell_type": "markdown", @@ -134,15 +134,15 @@ }, { "cell_type": "code", + "execution_count": null, "id": "6b09db0d5fb98d5d", "metadata": {}, + "outputs": [], "source": [ "model = importer.create_model()\n", "# It's important to use the petab problem from the importer, as it was modified to encode the experimental conditions.\n", "em = ExperimentManager(model=model, petab_problem=importer.petab_problem)" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "markdown", @@ -152,13 +152,13 @@ }, { "cell_type": "code", + "execution_count": null, "id": "ee7582b9dc373519", "metadata": {}, + "outputs": [], "source": [ "importer.petab_problem.experiments" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "markdown", @@ -168,47 +168,47 @@ }, { "cell_type": "code", + "execution_count": null, "id": "fbd47a575ad57cd3", "metadata": {}, + "outputs": [], "source": [ "edata = em.create_edata(importer.petab_problem.experiments[-1])\n", "edata" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "code", + "execution_count": null, "id": "9f24d8fdb8753fa1", "metadata": {}, + "outputs": [], "source": [ "rdata = model.simulate(edata=edata)\n", - "assert rdata.status == amici.AMICI_SUCCESS, \"Simulation failed.\"\n", + "assert rdata.status == AMICI_SUCCESS, \"Simulation failed.\"\n", "rdata" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "code", + "execution_count": null, "id": "53688eb0192a4793", "metadata": {}, + "outputs": [], "source": [ "plot_observable_trajectories(rdata, model=model, edata=edata)\n", "plot_state_trajectories(rdata, model=model)" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "code", + "execution_count": null, "id": "631939e37d5b0b71", "metadata": {}, + "outputs": [], "source": [ "rdata.xr.x.to_pandas()" - ], - "outputs": [], - "execution_count": null + ] }, { "cell_type": "markdown", diff --git a/doc/examples/example_presimulation/ExampleExperimentalConditions.ipynb b/doc/examples/example_presimulation/ExampleExperimentalConditions.ipynb index 766e30ee46..62795470c1 100644 --- a/doc/examples/example_presimulation/ExampleExperimentalConditions.ipynb +++ b/doc/examples/example_presimulation/ExampleExperimentalConditions.ipynb @@ -23,9 +23,11 @@ "\n", "from pprint import pprint\n", "\n", - "import amici.plotting\n", + "import amici\n", "import libsbml\n", - "import numpy as np" + "import numpy as np\n", + "from amici.sim.sundials import ExpData, run_simulation\n", + "from amici.sim.sundials.plotting import plot_observable_trajectories" ] }, { @@ -271,8 +273,8 @@ "source": [ "# Run simulation using default model parameters and solver options\n", "model.set_timepoints(np.linspace(0, 60, 60))\n", - "rdata = amici.run_simulation(model, solver)\n", - "amici.plotting.plot_observable_trajectories(rdata)" + "rdata = run_simulation(model, solver)\n", + "plot_observable_trajectories(rdata)" ] }, { @@ -288,10 +290,10 @@ "metadata": {}, "outputs": [], "source": [ - "edata = amici.ExpData(rdata, 0.1, 0.0)\n", + "edata = ExpData(rdata, 0.1, 0.0)\n", "edata.fixed_parameters = [0, 2]\n", - "rdata = amici.run_simulation(model, solver, edata)\n", - "amici.plotting.plot_observable_trajectories(rdata)" + "rdata = run_simulation(model, solver, edata)\n", + "plot_observable_trajectories(rdata)" ] }, { @@ -309,8 +311,8 @@ "outputs": [], "source": [ "edata.fixed_parameters_pre_equilibration = [3, 0]\n", - "rdata = amici.run_simulation(model, solver, edata)\n", - "amici.plotting.plot_observable_trajectories(rdata)" + "rdata = run_simulation(model, solver, edata)\n", + "plot_observable_trajectories(rdata)" ] }, { @@ -342,8 +344,8 @@ "metadata": {}, "outputs": [], "source": [ - "rdata = amici.run_simulation(model, solver, edata)\n", - "amici.plotting.plot_observable_trajectories(rdata)" + "rdata = run_simulation(model, solver, edata)\n", + "plot_observable_trajectories(rdata)" ] }, { @@ -363,8 +365,8 @@ "print(edata.fixed_parameters_pre_equilibration)\n", "print(edata.fixed_parameters_presimulation)\n", "print(edata.fixed_parameters)\n", - "rdata = amici.run_simulation(model, solver, edata)\n", - "amici.plotting.plot_observable_trajectories(rdata)" + "rdata = run_simulation(model, solver, edata)\n", + "plot_observable_trajectories(rdata)" ] } ], diff --git a/doc/examples/example_splines/ExampleSplines.ipynb b/doc/examples/example_splines/ExampleSplines.ipynb index f5aab2534f..78e1ff7957 100644 --- a/doc/examples/example_splines/ExampleSplines.ipynb +++ b/doc/examples/example_splines/ExampleSplines.ipynb @@ -35,6 +35,11 @@ "import matplotlib as mpl\n", "import numpy as np\n", "import sympy as sp\n", + "from amici.sim.sundials import (\n", + " SensitivityMethod,\n", + " SensitivityOrder,\n", + " run_simulation,\n", + ")\n", "from matplotlib import pyplot as plt\n", "\n", "# Choose build directory\n", @@ -97,10 +102,10 @@ " T = np.linspace(0, T, 100)\n", " model.set_timepoints([float(t) for t in T])\n", " solver = model.create_solver()\n", - " solver.set_sensitivity_order(amici.SensitivityOrder.first)\n", - " solver.set_sensitivity_method(amici.SensitivityMethod.forward)\n", + " solver.set_sensitivity_order(SensitivityOrder.first)\n", + " solver.set_sensitivity_method(SensitivityMethod.forward)\n", " # Simulate\n", - " rdata = amici.run_simulation(model, solver)\n", + " rdata = run_simulation(model, solver)\n", " # Plot results\n", " if plot:\n", " fig, ax = plt.subplots()\n", diff --git a/doc/examples/example_steady_states/ExampleEquilibrationLogic.ipynb b/doc/examples/example_steady_states/ExampleEquilibrationLogic.ipynb index 013f3b3447..e84146c6b8 100644 --- a/doc/examples/example_steady_states/ExampleEquilibrationLogic.ipynb +++ b/doc/examples/example_steady_states/ExampleEquilibrationLogic.ipynb @@ -79,10 +79,10 @@ ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# Import necessary libraries and define the model\n", "import os\n", @@ -94,6 +94,13 @@ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "from amici import (\n", + " MeasurementChannel as MC,\n", + ")\n", + "from amici import (\n", + " import_model_module,\n", + ")\n", + "from amici.importers.antimony import antimony2sbml\n", + "from amici.sim.sundials import (\n", " AMICI_ERROR,\n", " AMICI_SUCCESS,\n", " ExpData,\n", @@ -102,15 +109,10 @@ " SteadyStateComputationMode,\n", " SteadyStateSensitivityMode,\n", " SteadyStateStatus,\n", - " import_model_module,\n", " run_simulation,\n", " simulation_status_to_str,\n", ")\n", - "from amici import (\n", - " MeasurementChannel as MC,\n", - ")\n", - "from amici.importers.antimony import antimony2sbml\n", - "from amici.plotting import (\n", + "from amici.sim.sundials.plotting import (\n", " plot_observable_trajectories,\n", " plot_state_trajectories,\n", ")\n", @@ -165,10 +167,10 @@ ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# Import the model\n", "sbml_importer = amici.SbmlImporter(antimony2sbml(ant_model), from_file=False)\n", diff --git a/doc/examples/getting_started_extended/GettingStartedExtended.ipynb b/doc/examples/getting_started_extended/GettingStartedExtended.ipynb index 0538c8cba2..0868900744 100644 --- a/doc/examples/getting_started_extended/GettingStartedExtended.ipynb +++ b/doc/examples/getting_started_extended/GettingStartedExtended.ipynb @@ -30,7 +30,19 @@ "import amici\n", "import libsbml\n", "import matplotlib.pyplot as plt\n", - "import numpy as np" + "import numpy as np\n", + "from amici.sim.sundials import (\n", + " ExpData,\n", + " ParameterScaling,\n", + " SensitivityMethod,\n", + " SensitivityOrder,\n", + " get_data_observables_as_data_frame,\n", + " get_edata_from_data_frame,\n", + " get_residuals_as_data_frame,\n", + " get_simulation_observables_as_data_frame,\n", + " get_simulation_states_as_data_frame,\n", + " run_simulation,\n", + ")" ] }, { @@ -144,7 +156,9 @@ "execution_count": 4, "metadata": {}, "outputs": [], - "source": "fixed_parameters = [\"k0\"]" + "source": [ + "fixed_parameters = [\"k0\"]" + ] }, { "cell_type": "markdown", @@ -403,7 +417,7 @@ "solver = model.create_solver()\n", "\n", "# Run simulation using default model parameters and solver options\n", - "rdata = amici.run_simulation(model, solver)" + "rdata = run_simulation(model, solver)" ] }, { @@ -905,10 +919,10 @@ } ], "source": [ - "import amici.plotting\n", + "from amici.sim.sundials.plotting import *\n", "\n", - "amici.plotting.plot_state_trajectories(rdata, model=None)\n", - "amici.plotting.plot_observable_trajectories(rdata, model=None)" + "plot_state_trajectories(rdata, model=None)\n", + "plot_observable_trajectories(rdata, model=None)" ] }, { @@ -928,9 +942,7 @@ }, "outputs": [], "source": [ - "amici.plotting.plot_expressions(\n", - " \"observable_x1 + observable_x2 + observable_x3\", rdata=rdata\n", - ")" + "plot_expressions(\"observable_x1 + observable_x2 + observable_x3\", rdata=rdata)" ] }, { @@ -939,7 +951,7 @@ "source": [ "### Computing likelihood\n", "\n", - "Often model parameters need to be inferred from experimental data. This is commonly done by maximizing the likelihood of observing the data given to current model parameters. AMICI will compute this likelihood if experimental data is provided to `amici.runAmiciSimulation` as optional third argument. Measurements along with their standard deviations are provided through an `amici.ExpData` instance." + "Often model parameters need to be inferred from experimental data. This is commonly done by maximizing the likelihood of observing the data given to current model parameters. AMICI will compute this likelihood if experimental data is provided to `run_amici_simulations` as optional third argument. Measurements along with their standard deviations are provided through an `ExpData` instance." ] }, { @@ -956,13 +968,13 @@ "solver = model.create_solver()\n", "\n", "# Run simulation without experimental data\n", - "rdata = amici.run_simulation(model, solver)\n", + "rdata = run_simulation(model, solver)\n", "\n", "# Create ExpData instance from simulation results\n", - "edata = amici.ExpData(rdata, 1.0, 0.0)\n", + "edata = ExpData(rdata, 1.0, 0.0)\n", "\n", "# Re-run simulation, this time passing \"experimental data\"\n", - "rdata = amici.run_simulation(model, solver, edata)\n", + "rdata = run_simulation(model, solver, edata)\n", "\n", "print(f\"Log-likelihood {rdata['llh']:f}\")" ] @@ -978,7 +990,7 @@ "metadata": {}, "outputs": [], "source": [ - "amici.plotting.plot_observable_trajectories(rdata, edata=edata)\n", + "plot_observable_trajectories(rdata, edata=edata)\n", "plt.legend(loc=\"center left\", bbox_to_anchor=(1.04, 0.5))" ] }, @@ -998,12 +1010,12 @@ "source": [ "solver.set_relative_tolerance(1e-16)\n", "solver.set_absolute_tolerance(1e-16)\n", - "solver.set_sensitivity_order(amici.SensitivityOrder.none)\n", - "rdata_ref = amici.run_simulation(model, solver, edata)\n", + "solver.set_sensitivity_order(SensitivityOrder.none)\n", + "rdata_ref = run_simulation(model, solver, edata)\n", "\n", "\n", "def get_simulation_error(solver):\n", - " rdata = amici.run_simulation(model, solver, edata)\n", + " rdata = run_simulation(model, solver, edata)\n", " return np.mean(np.abs(rdata[\"x\"] - rdata_ref[\"x\"])), np.mean(\n", " np.abs(rdata[\"llh\"] - rdata_ref[\"llh\"])\n", " )\n", @@ -1077,18 +1089,18 @@ "# model.set_parameter_list([1, 2]) # sensitivities\n", "# w.r.t. the specified parameters\n", "model.set_parameter_scale(\n", - " amici.ParameterScaling.none\n", + " ParameterScaling.none\n", ") # parameters are used as-is (not log-transformed)\n", "\n", "solver = model.create_solver()\n", "solver.set_sensitivity_method(\n", - " amici.SensitivityMethod.forward\n", + " SensitivityMethod.forward\n", ") # forward sensitivity analysis\n", "solver.set_sensitivity_order(\n", - " amici.SensitivityOrder.first\n", + " SensitivityOrder.first\n", ") # first-order sensitivities\n", "\n", - "rdata = amici.run_simulation(model, solver)\n", + "rdata = run_simulation(model, solver)\n", "\n", "# print sensitivity-related results\n", "for key, value in rdata.items():\n", @@ -1116,15 +1128,15 @@ " list(model.get_free_parameter_ids()).index(\"observable_x1withsigma_sigma\")\n", "] = 0.1 # Change default parameter\n", "model.set_free_parameters(p_orig)\n", - "model.set_parameter_scale(amici.ParameterScaling.none)\n", + "model.set_parameter_scale(ParameterScaling.none)\n", "model.set_timepoints(np.linspace(0, 10, 21))\n", "\n", "solver = model.create_solver()\n", "solver.set_max_steps(10**4) # Set maximum number of steps for the solver\n", "\n", "# simulate time-course to get artificial data\n", - "rdata = amici.run_simulation(model, solver)\n", - "edata = amici.ExpData(rdata, 1.0, 0)\n", + "rdata = run_simulation(model, solver)\n", + "edata = ExpData(rdata, 1.0, 0)\n", "edata.fixed_parameters = model.get_fixed_parameters()\n", "# set sigma to 1.0 except for observable 5, so that p[7] is used instead\n", "# (if we have sigma parameterized, the corresponding ExpData entries must NaN, otherwise they will override the parameter)\n", @@ -1134,14 +1146,14 @@ ")\n", "\n", "# enable sensitivities\n", - "solver.set_sensitivity_order(amici.SensitivityOrder.first) # First-order ...\n", + "solver.set_sensitivity_order(SensitivityOrder.first) # First-order ...\n", "solver.set_sensitivity_method(\n", - " amici.SensitivityMethod.adjoint\n", + " SensitivityMethod.adjoint\n", ") # ... adjoint sensitivities\n", "model.require_sensitivities_for_all_parameters() # ... w.r.t. all parameters\n", "\n", "# compute adjoint sensitivities\n", - "rdata = amici.run_simulation(model, solver, edata)\n", + "rdata = run_simulation(model, solver, edata)\n", "# print(rdata['sigmay'])\n", "print(f\"Log-likelihood: {rdata['llh']}\")\n", "print(f\"Gradient: {rdata['sllh']}\")" @@ -1173,9 +1185,9 @@ " verbose and print(f\"f: p={p}\")\n", "\n", " old_parameters = model.get_free_parameters()\n", - " solver.set_sensitivity_order(amici.SensitivityOrder.none)\n", + " solver.set_sensitivity_order(SensitivityOrder.none)\n", " model.set_free_parameters(p)\n", - " rdata = amici.run_simulation(model, solver, edata)\n", + " rdata = run_simulation(model, solver, edata)\n", "\n", " model.set_free_parameters(old_parameters)\n", "\n", @@ -1195,10 +1207,10 @@ " verbose and print(f\"g: p={p}\")\n", "\n", " old_parameters = model.get_free_parameters()\n", - " solver.set_sensitivity_method(amici.SensitivityMethod.forward)\n", - " solver.set_sensitivity_order(amici.SensitivityOrder.first)\n", + " solver.set_sensitivity_method(SensitivityMethod.forward)\n", + " solver.set_sensitivity_order(SensitivityOrder.first)\n", " model.set_free_parameters(p)\n", - " rdata = amici.run_simulation(model, solver, edata)\n", + " rdata = run_simulation(model, solver, edata)\n", "\n", " model.set_free_parameters(old_parameters)\n", "\n", @@ -1259,26 +1271,26 @@ "\n", "\n", "solver.set_sensitivity_method(\n", - " amici.SensitivityMethod.forward\n", + " SensitivityMethod.forward\n", ") # forward sensitivity analysis\n", "solver.set_sensitivity_order(\n", - " amici.SensitivityOrder.first\n", + " SensitivityOrder.first\n", ") # first-order sensitivities\n", "model.require_sensitivities_for_all_parameters()\n", "solver.set_relative_tolerance(1e-12)\n", - "rdata = amici.run_simulation(model, solver, edata)\n", + "rdata = run_simulation(model, solver, edata)\n", "\n", "\n", "def fd(x0, ip, eps, symbol=\"llh\"):\n", " p = list(x0[:])\n", " old_parameters = model.get_free_parameters()\n", - " solver.set_sensitivity_order(amici.SensitivityOrder.none)\n", + " solver.set_sensitivity_order(SensitivityOrder.none)\n", " p[ip] += eps\n", " model.set_free_parameters(p)\n", - " rdata_f = amici.run_simulation(model, solver, edata)\n", + " rdata_f = run_simulation(model, solver, edata)\n", " p[ip] -= 2 * eps\n", " model.set_free_parameters(p)\n", - " rdata_b = amici.run_simulation(model, solver, edata)\n", + " rdata_b = run_simulation(model, solver, edata)\n", "\n", " model.set_free_parameters(old_parameters)\n", " return (rdata_f[symbol] - rdata_b[symbol]) / (2 * eps)\n", @@ -1354,7 +1366,7 @@ "outputs": [], "source": [ "# run the simulation\n", - "rdata = amici.run_simulation(model, solver, edata)" + "rdata = run_simulation(model, solver, edata)" ] }, { @@ -1364,7 +1376,7 @@ "outputs": [], "source": [ "# look at the ExpData as DataFrame\n", - "df = amici.get_data_observables_as_data_frame(model, [edata])\n", + "df = get_data_observables_as_data_frame(model, [edata])\n", "df" ] }, @@ -1375,7 +1387,7 @@ "outputs": [], "source": [ "# from the exported dataframe, we can actually reconstruct a copy of the ExpData instance\n", - "reconstructed_edata = amici.get_edata_from_data_frame(model, df)" + "reconstructed_edata = get_edata_from_data_frame(model, df)" ] }, { @@ -1385,7 +1397,7 @@ "outputs": [], "source": [ "# look at the States in rdata as DataFrame\n", - "amici.get_residuals_as_data_frame(model, [edata], [rdata])" + "get_residuals_as_data_frame(model, [edata], [rdata])" ] }, { @@ -1395,7 +1407,7 @@ "outputs": [], "source": [ "# look at the Observables in rdata as DataFrame\n", - "amici.get_simulation_observables_as_data_frame(model, [edata], [rdata])" + "get_simulation_observables_as_data_frame(model, [edata], [rdata])" ] }, { @@ -1405,7 +1417,7 @@ "outputs": [], "source": [ "# look at the States in rdata as DataFrame\n", - "amici.get_simulation_states_as_data_frame(model, [edata], [rdata])" + "get_simulation_states_as_data_frame(model, [edata], [rdata])" ] } ], diff --git a/doc/python_interface.rst b/doc/python_interface.rst index 44689ccb86..34d1658581 100644 --- a/doc/python_interface.rst +++ b/doc/python_interface.rst @@ -173,10 +173,9 @@ An example using Antimony to specify the Lotka-Volterra equations is shown below ) amici_model = model_module.get_model() amici_model.set_timepoints(np.linspace(0, 100, 200)) - amici_solver = amici_model.create_solver() - rdata = amici.run_simulation(amici_model, amici_solver) + rdata = amici_model.simulate() - from amici.plotting import plot_state_trajectories + from amici.sim.sundials.plotting import plot_state_trajectories plot_state_trajectories(rdata, model=amici_model) diff --git a/doc/python_modules.rst b/doc/python_modules.rst index b750d9adad..63a936825d 100644 --- a/doc/python_modules.rst +++ b/doc/python_modules.rst @@ -7,7 +7,6 @@ AMICI Python API :toctree: generated amici - amici.amici amici.importers.utils amici.importers.sbml amici.importers.sbml.conserved_quantities_demartino @@ -29,9 +28,8 @@ AMICI Python API amici.importers.petab.v1.simulator amici.jax amici.exporters.sundials.de_export - amici.plotting - amici.pandas + amici.sim.sundials + amici.sim.sundials.plotting + amici.sim.sundials.gradient_check amici.logging - amici.gradient_check - amici.numpy amici.adapters.fiddy diff --git a/models/model_calvetti_py/model_calvetti_py.h b/models/model_calvetti_py/model_calvetti_py.h index bf5ea1242f..6b099466d9 100644 --- a/models/model_calvetti_py/model_calvetti_py.h +++ b/models/model_calvetti_py/model_calvetti_py.h @@ -557,7 +557,7 @@ class Model_model_calvetti_py : public amici::Model_DAE { * @return AMICI git commit hash */ std::string get_amici_commit() const override { - return "3fb84cd5df12639f17b179d681e8ba4b5be8a160"; + return "20b07e9a8c19bdb7bf94a562f61b3d08dc0299d0"; } bool has_quadratic_llh() const override { diff --git a/models/model_calvetti_py/setup.py b/models/model_calvetti_py/setup.py index 31bec93508..72facc640a 100644 --- a/models/model_calvetti_py/setup.py +++ b/models/model_calvetti_py/setup.py @@ -6,7 +6,7 @@ from pathlib import Path from amici import _get_amici_path -from amici.custom_commands import AmiciBuildCMakeExtension +from amici._installation.custom_commands import AmiciBuildCMakeExtension from cmake_build_extension import CMakeExtension from setuptools import find_namespace_packages, setup @@ -15,7 +15,7 @@ def get_extension() -> CMakeExtension: """Get setuptools extension object for this AMICI model package""" # Build shared object - prefix_path = Path(_get_amici_path()) + prefix_path = Path(_get_amici_path(), "_installation") AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) # handle parallel building @@ -38,7 +38,9 @@ def get_extension() -> CMakeExtension: amici_distribution = importlib.metadata.distribution("amici") amici_dir = Path(amici_distribution.locate_file("")) # this path is created during the amici build if scipy_openblas64 is used - openblas_cmake_dir = amici_dir / "lib" / "cmake" / "openblas" + openblas_cmake_dir = ( + amici_dir / "_installation" / "lib" / "cmake" / "openblas" + ) if openblas_cmake_dir.exists(): cmake_prefix_path.append(str(openblas_cmake_dir)) diff --git a/models/model_calvetti_py/swig/model_calvetti_py.i b/models/model_calvetti_py/swig/model_calvetti_py.i index 3a33581e7f..eed3ffcff7 100644 --- a/models/model_calvetti_py/swig/model_calvetti_py.i +++ b/models/model_calvetti_py/swig/model_calvetti_py.i @@ -46,7 +46,7 @@ if t_imported < t_modified: # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/models/model_dirac_py/model_dirac_py.h b/models/model_dirac_py/model_dirac_py.h index b4b4bc3034..03813080e4 100644 --- a/models/model_dirac_py/model_dirac_py.h +++ b/models/model_dirac_py/model_dirac_py.h @@ -544,7 +544,7 @@ class Model_model_dirac_py : public amici::Model_ODE { * @return AMICI git commit hash */ std::string get_amici_commit() const override { - return "3fb84cd5df12639f17b179d681e8ba4b5be8a160"; + return "20b07e9a8c19bdb7bf94a562f61b3d08dc0299d0"; } bool has_quadratic_llh() const override { diff --git a/models/model_dirac_py/model_dirac_py/model_dirac_py.py b/models/model_dirac_py/model_dirac_py/model_dirac_py.py index fa04165fdc..704d0df293 100644 --- a/models/model_dirac_py/model_dirac_py/model_dirac_py.py +++ b/models/model_dirac_py/model_dirac_py/model_dirac_py.py @@ -94,7 +94,7 @@ class _SwigNonDynamicMeta(type): # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/models/model_dirac_py/setup.py b/models/model_dirac_py/setup.py index 4e5c9c7ad9..7f198f2a18 100644 --- a/models/model_dirac_py/setup.py +++ b/models/model_dirac_py/setup.py @@ -6,7 +6,7 @@ from pathlib import Path from amici import _get_amici_path -from amici.custom_commands import AmiciBuildCMakeExtension +from amici._installation.custom_commands import AmiciBuildCMakeExtension from cmake_build_extension import CMakeExtension from setuptools import find_namespace_packages, setup @@ -15,7 +15,7 @@ def get_extension() -> CMakeExtension: """Get setuptools extension object for this AMICI model package""" # Build shared object - prefix_path = Path(_get_amici_path()) + prefix_path = Path(_get_amici_path(), "_installation") AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) # handle parallel building @@ -38,7 +38,9 @@ def get_extension() -> CMakeExtension: amici_distribution = importlib.metadata.distribution("amici") amici_dir = Path(amici_distribution.locate_file("")) # this path is created during the amici build if scipy_openblas64 is used - openblas_cmake_dir = amici_dir / "lib" / "cmake" / "openblas" + openblas_cmake_dir = ( + amici_dir / "_installation" / "lib" / "cmake" / "openblas" + ) if openblas_cmake_dir.exists(): cmake_prefix_path.append(str(openblas_cmake_dir)) diff --git a/models/model_dirac_py/swig/model_dirac_py.i b/models/model_dirac_py/swig/model_dirac_py.i index 248e97e644..3832c99751 100644 --- a/models/model_dirac_py/swig/model_dirac_py.i +++ b/models/model_dirac_py/swig/model_dirac_py.i @@ -46,7 +46,7 @@ if t_imported < t_modified: # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/models/model_events_py/model_events_py.h b/models/model_events_py/model_events_py.h index 0bf2ec82f7..f45acb4632 100644 --- a/models/model_events_py/model_events_py.h +++ b/models/model_events_py/model_events_py.h @@ -579,7 +579,7 @@ class Model_model_events_py : public amici::Model_ODE { * @return AMICI git commit hash */ std::string get_amici_commit() const override { - return "3fb84cd5df12639f17b179d681e8ba4b5be8a160"; + return "20b07e9a8c19bdb7bf94a562f61b3d08dc0299d0"; } bool has_quadratic_llh() const override { diff --git a/models/model_events_py/setup.py b/models/model_events_py/setup.py index b8bda5ee65..ce88c2530f 100644 --- a/models/model_events_py/setup.py +++ b/models/model_events_py/setup.py @@ -6,7 +6,7 @@ from pathlib import Path from amici import _get_amici_path -from amici.custom_commands import AmiciBuildCMakeExtension +from amici._installation.custom_commands import AmiciBuildCMakeExtension from cmake_build_extension import CMakeExtension from setuptools import find_namespace_packages, setup @@ -15,7 +15,7 @@ def get_extension() -> CMakeExtension: """Get setuptools extension object for this AMICI model package""" # Build shared object - prefix_path = Path(_get_amici_path()) + prefix_path = Path(_get_amici_path(), "_installation") AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) # handle parallel building @@ -38,7 +38,9 @@ def get_extension() -> CMakeExtension: amici_distribution = importlib.metadata.distribution("amici") amici_dir = Path(amici_distribution.locate_file("")) # this path is created during the amici build if scipy_openblas64 is used - openblas_cmake_dir = amici_dir / "lib" / "cmake" / "openblas" + openblas_cmake_dir = ( + amici_dir / "_installation" / "lib" / "cmake" / "openblas" + ) if openblas_cmake_dir.exists(): cmake_prefix_path.append(str(openblas_cmake_dir)) diff --git a/models/model_events_py/swig/model_events_py.i b/models/model_events_py/swig/model_events_py.i index c14cdef4e2..cc5fa797aa 100644 --- a/models/model_events_py/swig/model_events_py.i +++ b/models/model_events_py/swig/model_events_py.i @@ -46,7 +46,7 @@ if t_imported < t_modified: # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/models/model_jakstat_adjoint_py/model_jakstat_adjoint_py.h b/models/model_jakstat_adjoint_py/model_jakstat_adjoint_py.h index 71c22b1b1c..78e73fdb02 100644 --- a/models/model_jakstat_adjoint_py/model_jakstat_adjoint_py.h +++ b/models/model_jakstat_adjoint_py/model_jakstat_adjoint_py.h @@ -552,7 +552,7 @@ class Model_model_jakstat_adjoint_py : public amici::Model_ODE { * @return AMICI git commit hash */ std::string get_amici_commit() const override { - return "3fb84cd5df12639f17b179d681e8ba4b5be8a160"; + return "20b07e9a8c19bdb7bf94a562f61b3d08dc0299d0"; } bool has_quadratic_llh() const override { diff --git a/models/model_jakstat_adjoint_py/setup.py b/models/model_jakstat_adjoint_py/setup.py index 0c29f341d5..cbc905b5e8 100644 --- a/models/model_jakstat_adjoint_py/setup.py +++ b/models/model_jakstat_adjoint_py/setup.py @@ -6,7 +6,7 @@ from pathlib import Path from amici import _get_amici_path -from amici.custom_commands import AmiciBuildCMakeExtension +from amici._installation.custom_commands import AmiciBuildCMakeExtension from cmake_build_extension import CMakeExtension from setuptools import find_namespace_packages, setup @@ -15,7 +15,7 @@ def get_extension() -> CMakeExtension: """Get setuptools extension object for this AMICI model package""" # Build shared object - prefix_path = Path(_get_amici_path()) + prefix_path = Path(_get_amici_path(), "_installation") AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) # handle parallel building @@ -38,7 +38,9 @@ def get_extension() -> CMakeExtension: amici_distribution = importlib.metadata.distribution("amici") amici_dir = Path(amici_distribution.locate_file("")) # this path is created during the amici build if scipy_openblas64 is used - openblas_cmake_dir = amici_dir / "lib" / "cmake" / "openblas" + openblas_cmake_dir = ( + amici_dir / "_installation" / "lib" / "cmake" / "openblas" + ) if openblas_cmake_dir.exists(): cmake_prefix_path.append(str(openblas_cmake_dir)) diff --git a/models/model_jakstat_adjoint_py/swig/model_jakstat_adjoint_py.i b/models/model_jakstat_adjoint_py/swig/model_jakstat_adjoint_py.i index ab94d3c927..56bbf639ab 100644 --- a/models/model_jakstat_adjoint_py/swig/model_jakstat_adjoint_py.i +++ b/models/model_jakstat_adjoint_py/swig/model_jakstat_adjoint_py.i @@ -46,7 +46,7 @@ if t_imported < t_modified: # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/models/model_nested_events_py/model_nested_events_py.h b/models/model_nested_events_py/model_nested_events_py.h index 53ce2a747f..c5ca495059 100644 --- a/models/model_nested_events_py/model_nested_events_py.h +++ b/models/model_nested_events_py/model_nested_events_py.h @@ -552,7 +552,7 @@ class Model_model_nested_events_py : public amici::Model_ODE { * @return AMICI git commit hash */ std::string get_amici_commit() const override { - return "3fb84cd5df12639f17b179d681e8ba4b5be8a160"; + return "20b07e9a8c19bdb7bf94a562f61b3d08dc0299d0"; } bool has_quadratic_llh() const override { diff --git a/models/model_nested_events_py/setup.py b/models/model_nested_events_py/setup.py index 3f74354694..fbf07f6b34 100644 --- a/models/model_nested_events_py/setup.py +++ b/models/model_nested_events_py/setup.py @@ -6,7 +6,7 @@ from pathlib import Path from amici import _get_amici_path -from amici.custom_commands import AmiciBuildCMakeExtension +from amici._installation.custom_commands import AmiciBuildCMakeExtension from cmake_build_extension import CMakeExtension from setuptools import find_namespace_packages, setup @@ -15,7 +15,7 @@ def get_extension() -> CMakeExtension: """Get setuptools extension object for this AMICI model package""" # Build shared object - prefix_path = Path(_get_amici_path()) + prefix_path = Path(_get_amici_path(), "_installation") AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) # handle parallel building @@ -38,7 +38,9 @@ def get_extension() -> CMakeExtension: amici_distribution = importlib.metadata.distribution("amici") amici_dir = Path(amici_distribution.locate_file("")) # this path is created during the amici build if scipy_openblas64 is used - openblas_cmake_dir = amici_dir / "lib" / "cmake" / "openblas" + openblas_cmake_dir = ( + amici_dir / "_installation" / "lib" / "cmake" / "openblas" + ) if openblas_cmake_dir.exists(): cmake_prefix_path.append(str(openblas_cmake_dir)) diff --git a/models/model_nested_events_py/swig/model_nested_events_py.i b/models/model_nested_events_py/swig/model_nested_events_py.i index 2a6453a644..df63335b7f 100644 --- a/models/model_nested_events_py/swig/model_nested_events_py.i +++ b/models/model_nested_events_py/swig/model_nested_events_py.i @@ -46,7 +46,7 @@ if t_imported < t_modified: # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/models/model_neuron_py/model_neuron_py.h b/models/model_neuron_py/model_neuron_py.h index 57aa2aec2c..be4e45f9e1 100644 --- a/models/model_neuron_py/model_neuron_py.h +++ b/models/model_neuron_py/model_neuron_py.h @@ -574,7 +574,7 @@ class Model_model_neuron_py : public amici::Model_ODE { * @return AMICI git commit hash */ std::string get_amici_commit() const override { - return "3fb84cd5df12639f17b179d681e8ba4b5be8a160"; + return "20b07e9a8c19bdb7bf94a562f61b3d08dc0299d0"; } bool has_quadratic_llh() const override { diff --git a/models/model_neuron_py/setup.py b/models/model_neuron_py/setup.py index 3acfb24b76..abeea7c58d 100644 --- a/models/model_neuron_py/setup.py +++ b/models/model_neuron_py/setup.py @@ -6,7 +6,7 @@ from pathlib import Path from amici import _get_amici_path -from amici.custom_commands import AmiciBuildCMakeExtension +from amici._installation.custom_commands import AmiciBuildCMakeExtension from cmake_build_extension import CMakeExtension from setuptools import find_namespace_packages, setup @@ -15,7 +15,7 @@ def get_extension() -> CMakeExtension: """Get setuptools extension object for this AMICI model package""" # Build shared object - prefix_path = Path(_get_amici_path()) + prefix_path = Path(_get_amici_path(), "_installation") AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) # handle parallel building @@ -38,7 +38,9 @@ def get_extension() -> CMakeExtension: amici_distribution = importlib.metadata.distribution("amici") amici_dir = Path(amici_distribution.locate_file("")) # this path is created during the amici build if scipy_openblas64 is used - openblas_cmake_dir = amici_dir / "lib" / "cmake" / "openblas" + openblas_cmake_dir = ( + amici_dir / "_installation" / "lib" / "cmake" / "openblas" + ) if openblas_cmake_dir.exists(): cmake_prefix_path.append(str(openblas_cmake_dir)) diff --git a/models/model_neuron_py/swig/model_neuron_py.i b/models/model_neuron_py/swig/model_neuron_py.i index 539af3b45b..4c27e7f5f4 100644 --- a/models/model_neuron_py/swig/model_neuron_py.i +++ b/models/model_neuron_py/swig/model_neuron_py.i @@ -46,7 +46,7 @@ if t_imported < t_modified: # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/models/model_robertson_py/model_robertson_py.h b/models/model_robertson_py/model_robertson_py.h index b3aef8f8d1..05b27a6c80 100644 --- a/models/model_robertson_py/model_robertson_py.h +++ b/models/model_robertson_py/model_robertson_py.h @@ -536,7 +536,7 @@ class Model_model_robertson_py : public amici::Model_DAE { * @return AMICI git commit hash */ std::string get_amici_commit() const override { - return "3fb84cd5df12639f17b179d681e8ba4b5be8a160"; + return "20b07e9a8c19bdb7bf94a562f61b3d08dc0299d0"; } bool has_quadratic_llh() const override { diff --git a/models/model_robertson_py/setup.py b/models/model_robertson_py/setup.py index f741256557..d3787d169b 100644 --- a/models/model_robertson_py/setup.py +++ b/models/model_robertson_py/setup.py @@ -6,7 +6,7 @@ from pathlib import Path from amici import _get_amici_path -from amici.custom_commands import AmiciBuildCMakeExtension +from amici._installation.custom_commands import AmiciBuildCMakeExtension from cmake_build_extension import CMakeExtension from setuptools import find_namespace_packages, setup @@ -15,7 +15,7 @@ def get_extension() -> CMakeExtension: """Get setuptools extension object for this AMICI model package""" # Build shared object - prefix_path = Path(_get_amici_path()) + prefix_path = Path(_get_amici_path(), "_installation") AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) # handle parallel building @@ -38,7 +38,9 @@ def get_extension() -> CMakeExtension: amici_distribution = importlib.metadata.distribution("amici") amici_dir = Path(amici_distribution.locate_file("")) # this path is created during the amici build if scipy_openblas64 is used - openblas_cmake_dir = amici_dir / "lib" / "cmake" / "openblas" + openblas_cmake_dir = ( + amici_dir / "_installation" / "lib" / "cmake" / "openblas" + ) if openblas_cmake_dir.exists(): cmake_prefix_path.append(str(openblas_cmake_dir)) diff --git a/models/model_robertson_py/swig/model_robertson_py.i b/models/model_robertson_py/swig/model_robertson_py.i index d62408f6c0..8412ff56c4 100644 --- a/models/model_robertson_py/swig/model_robertson_py.i +++ b/models/model_robertson_py/swig/model_robertson_py.i @@ -46,7 +46,7 @@ if t_imported < t_modified: # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/models/model_steadystate_py/model_steadystate_py.h b/models/model_steadystate_py/model_steadystate_py.h index 4d8238872d..f1ce69e448 100644 --- a/models/model_steadystate_py/model_steadystate_py.h +++ b/models/model_steadystate_py/model_steadystate_py.h @@ -536,7 +536,7 @@ class Model_model_steadystate_py : public amici::Model_ODE { * @return AMICI git commit hash */ std::string get_amici_commit() const override { - return "3fb84cd5df12639f17b179d681e8ba4b5be8a160"; + return "20b07e9a8c19bdb7bf94a562f61b3d08dc0299d0"; } bool has_quadratic_llh() const override { diff --git a/models/model_steadystate_py/setup.py b/models/model_steadystate_py/setup.py index 1da24eeff3..d06c2932d3 100644 --- a/models/model_steadystate_py/setup.py +++ b/models/model_steadystate_py/setup.py @@ -6,7 +6,7 @@ from pathlib import Path from amici import _get_amici_path -from amici.custom_commands import AmiciBuildCMakeExtension +from amici._installation.custom_commands import AmiciBuildCMakeExtension from cmake_build_extension import CMakeExtension from setuptools import find_namespace_packages, setup @@ -15,7 +15,7 @@ def get_extension() -> CMakeExtension: """Get setuptools extension object for this AMICI model package""" # Build shared object - prefix_path = Path(_get_amici_path()) + prefix_path = Path(_get_amici_path(), "_installation") AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) # handle parallel building @@ -38,7 +38,9 @@ def get_extension() -> CMakeExtension: amici_distribution = importlib.metadata.distribution("amici") amici_dir = Path(amici_distribution.locate_file("")) # this path is created during the amici build if scipy_openblas64 is used - openblas_cmake_dir = amici_dir / "lib" / "cmake" / "openblas" + openblas_cmake_dir = ( + amici_dir / "_installation" / "lib" / "cmake" / "openblas" + ) if openblas_cmake_dir.exists(): cmake_prefix_path.append(str(openblas_cmake_dir)) diff --git a/models/model_steadystate_py/swig/model_steadystate_py.i b/models/model_steadystate_py/swig/model_steadystate_py.i index cdd2483406..b58ef67df2 100644 --- a/models/model_steadystate_py/swig/model_steadystate_py.i +++ b/models/model_steadystate_py/swig/model_steadystate_py.i @@ -46,7 +46,7 @@ if t_imported < t_modified: # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index e94a0a2a0b..f038f605ca 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,3 +1,9 @@ +# Build and install the AMICI Python package +# +# This file is not part of the AMICI Python package itself, but is included +# in the main CMakeLists.txt to provide targets for building and installing +# the AMICI Python package. + if(DEFINED ENV{PYTHON_EXECUTABLE}) set(Python3_EXECUTABLE $ENV{PYTHON_EXECUTABLE}) endif() diff --git a/python/sdist/MANIFEST.in b/python/sdist/MANIFEST.in index 183e9cc69b..eb045e083d 100644 --- a/python/sdist/MANIFEST.in +++ b/python/sdist/MANIFEST.in @@ -1,20 +1,20 @@ -recursive-include amici/ThirdParty/SuiteSparse * -recursive-include amici/ThirdParty/sundials * -recursive-include amici/ThirdParty/gsl *.hpp -recursive-include amici/cmake * -recursive-include amici/include/amici *.h -recursive-include amici/src * -recursive-include amici/swig * +recursive-include amici/_installation/ThirdParty/SuiteSparse * +recursive-include amici/_installation/ThirdParty/sundials * +recursive-include amici/_installation/ThirdParty/gsl *.hpp +recursive-include amici/_installation/cmake * +recursive-include amici/_installation/include/amici *.h +recursive-include amici/_installation/src * +recursive-include amici/_installation/swig * recursive-include amici/exporters/sundials/templates * include amici/* include version.txt include LICENSE.md -exclude amici/*.so -exclude amici/*.dll +exclude amici/_installation/*.so +exclude amici/_installation/*.dll prune **/build prune **/install -prune amici/share -prune amici/lib -prune amici/ThirdParty/SuiteSparse/lib -prune amici/ThirdParty/SuiteSparse/include +prune amici/_installation/share +prune amici/_installation/lib +prune amici/_installation/ThirdParty/SuiteSparse/lib +prune amici/_installation/ThirdParty/SuiteSparse/include prune __pycache__ diff --git a/python/sdist/amici/CMakeLists.txt b/python/sdist/amici/CMakeLists.txt deleted file mode 120000 index d8cd15fc62..0000000000 --- a/python/sdist/amici/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -../../../CMakeLists.txt \ No newline at end of file diff --git a/python/sdist/amici/ThirdParty b/python/sdist/amici/ThirdParty deleted file mode 120000 index dbca061d2f..0000000000 --- a/python/sdist/amici/ThirdParty +++ /dev/null @@ -1 +0,0 @@ -../../../ThirdParty/ \ No newline at end of file diff --git a/python/sdist/amici/__init__.py b/python/sdist/amici/__init__.py index 908be46445..d3a92bd816 100644 --- a/python/sdist/amici/__init__.py +++ b/python/sdist/amici/__init__.py @@ -135,49 +135,15 @@ def get_model_dir(model_id: str | None = None, jax: bool = False) -> Path: amiciSrcPath = os.path.join(amici_path, "src") #: absolute root path of the amici module amiciModulePath = os.path.dirname(__file__) -#: boolean indicating if this is the full package with swig interface or -# the raw package without extension -has_clibs: bool = any( - os.path.isfile(os.path.join(amici_path, wrapper)) - for wrapper in ["amici.py", "amici_without_hdf5.py"] -) -#: boolean indicating if amici was compiled with hdf5 support -hdf5_enabled: bool = False + # Get version number from file -with open(os.path.join(amici_path, "version.txt")) as f: +with open(os.path.join(amici_path, "_installation", "version.txt")) as f: __version__ = f.read().strip() __commit__ = _get_commit_hash() -# Import SWIG module and swig-dependent submodules if required and available if not _imported_from_setup(): - if has_clibs: - # prevent segfaults under pytest - # see also: - # https://github.com/swig/swig/issues/2881 - # https://github.com/AMICI-dev/AMICI/issues/2565 - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", - category=DeprecationWarning, - message="builtin type .* has no __module__ attribute", - ) - from . import amici - - from .amici import * - - # has to be done before importing readSolverSettingsFromHDF5 - # from .swig_wrappers - hdf5_enabled = "readSolverSettingsFromHDF5" in dir() - # These modules require the swig interface and other dependencies - from .numpy import ExpDataView, ReturnDataView # noqa: F401 - from .pandas import * - from .swig_wrappers import * - - # These modules don't require the swig interface - from typing import Protocol, runtime_checkable - from .importers.sbml import ( # noqa: F401 SbmlImporter, assignment_rules_to_observables, @@ -189,20 +155,6 @@ def get_model_dir(model_id: str | None = None, jax: bool = False) -> Path: except (ImportError, ModuleNotFoundError): JAXModel = object - @runtime_checkable - class ModelModule(Protocol): # noqa: F811 - """Type of AMICI-generated model modules. - - To enable static type checking.""" - - def get_model(self) -> amici.Model: - """Create a model instance.""" - ... - - AmiciModel = amici.Model | amici.ModelPtr -else: - ModelModule = ModuleType - class add_path: """Context manager for temporarily changing PYTHONPATH. @@ -262,6 +214,9 @@ def _module_from_path(module_name: str, module_path: Path | str) -> ModuleType: return module +ModelModule = ModuleType + + def import_model_module( module_name: str, module_path: Path | str ) -> ModelModule: diff --git a/python/sdist/amici/__main__.py b/python/sdist/amici/__main__.py index 8c5a00ba55..4cc001e30b 100644 --- a/python/sdist/amici/__main__.py +++ b/python/sdist/amici/__main__.py @@ -2,13 +2,17 @@ import sys -from . import ( - CpuTimer, - __version__, - compiled_with_openmp, - has_clibs, - hdf5_enabled, -) +from . import __version__ + +try: + from .sim.sundials import ( + CpuTimer, + compiled_with_openmp, + has_clibs, + hdf5_enabled, + ) +except ImportError: + has_clibs = False def print_info(): @@ -20,14 +24,14 @@ def print_info(): if has_clibs: features.append("extensions") - if compiled_with_openmp(): - features.append("OpenMP") + if compiled_with_openmp(): + features.append("OpenMP") - if hdf5_enabled: - features.append("HDF5") + if hdf5_enabled: + features.append("HDF5") - if CpuTimer.uses_thread_clock: - features.append("thread_clock") + if CpuTimer.uses_thread_clock: + features.append("thread_clock") print( f"AMICI ({sys.platform}) version {__version__} ({','.join(features)})" diff --git a/python/sdist/amici/_installation/CMakeLists.txt b/python/sdist/amici/_installation/CMakeLists.txt new file mode 120000 index 0000000000..75f9ac99e5 --- /dev/null +++ b/python/sdist/amici/_installation/CMakeLists.txt @@ -0,0 +1 @@ +../../../../CMakeLists.txt \ No newline at end of file diff --git a/python/sdist/amici/_installation/ThirdParty b/python/sdist/amici/_installation/ThirdParty new file mode 120000 index 0000000000..eca34fef00 --- /dev/null +++ b/python/sdist/amici/_installation/ThirdParty @@ -0,0 +1 @@ +../../../../ThirdParty/ \ No newline at end of file diff --git a/python/sdist/amici/_installation/cmake b/python/sdist/amici/_installation/cmake new file mode 120000 index 0000000000..c7f85fe217 --- /dev/null +++ b/python/sdist/amici/_installation/cmake @@ -0,0 +1 @@ +../../../../cmake/ \ No newline at end of file diff --git a/python/sdist/amici/_installation/custom_commands.py b/python/sdist/amici/_installation/custom_commands.py index 0616d75db2..53a6905872 100644 --- a/python/sdist/amici/_installation/custom_commands.py +++ b/python/sdist/amici/_installation/custom_commands.py @@ -72,7 +72,9 @@ def run(self): os.environ.get("ENABLE_AMICI_DEBUGGING") == "TRUE" and sys.platform == "darwin" ): - search_dir = os.path.join(os.getcwd(), self.build_dir, "amici") + search_dir = os.path.join( + os.getcwd(), self.build_dir, "amici", "_installation" + ) for file in os.listdir(search_dir): if file.endswith(".so"): subprocess.run( @@ -167,7 +169,9 @@ def run(self): if not self.dry_run: # Fix SWIG-generated typehints build_dir = self.build_lib if self.inplace == 0 else os.getcwd() - swig_py_module_path = Path(build_dir, "amici", "amici.py") + swig_py_module_path = Path( + build_dir, "amici", "_installation", "amici.py" + ) # this is class is used for the amici core extension, and any model # extensions. if amici.py is present, this is the core extension. if swig_py_module_path.is_file(): diff --git a/python/sdist/amici/_installation/include b/python/sdist/amici/_installation/include new file mode 120000 index 0000000000..cc792a376d --- /dev/null +++ b/python/sdist/amici/_installation/include @@ -0,0 +1 @@ +../../../../include/ \ No newline at end of file diff --git a/python/sdist/amici/_installation/src b/python/sdist/amici/_installation/src new file mode 120000 index 0000000000..dd8194593a --- /dev/null +++ b/python/sdist/amici/_installation/src @@ -0,0 +1 @@ +../../../../src/ \ No newline at end of file diff --git a/python/sdist/amici/_installation/swig b/python/sdist/amici/_installation/swig new file mode 120000 index 0000000000..5993cceb83 --- /dev/null +++ b/python/sdist/amici/_installation/swig @@ -0,0 +1 @@ +../../../../swig/ \ No newline at end of file diff --git a/python/sdist/amici/_installation/version.txt b/python/sdist/amici/_installation/version.txt new file mode 120000 index 0000000000..5099f3fef8 --- /dev/null +++ b/python/sdist/amici/_installation/version.txt @@ -0,0 +1 @@ +../../../../version.txt \ No newline at end of file diff --git a/python/sdist/amici/adapters/fiddy.py b/python/sdist/amici/adapters/fiddy.py index 38828387ff..b6e29591e4 100644 --- a/python/sdist/amici/adapters/fiddy.py +++ b/python/sdist/amici/adapters/fiddy.py @@ -22,8 +22,15 @@ from amici.importers.petab import LLH, SLLH from amici.importers.petab.v1.conditions import create_edatas from amici.importers.petab.v1.parameter_mapping import create_parameter_mapping - -from .. import ReturnData, SensitivityOrder +from amici.sim.sundials import ( + AmiciExpData, + AmiciModel, + AmiciSolver, + Model, + ReturnData, + SensitivityOrder, + run_simulation, +) if TYPE_CHECKING: from amici.importers.petab import PetabSimulator @@ -108,15 +115,15 @@ def fiddy_array_transpose(array: np.ndarray, variable: str) -> tuple[int]: def run_simulation_to_cached_functions( - amici_model: amici.AmiciModel, + amici_model: AmiciModel, *, cache: bool = True, free_parameter_ids: list[str] = None, - amici_solver: amici.AmiciSolver = None, - amici_edata: amici.AmiciExpData = None, + amici_solver: AmiciSolver = None, + amici_edata: AmiciExpData = None, derivative_variables: list[str] = None, ): - """Convert `amici.run_simulation` to fiddy functions. + """Convert `run_simulation` to fiddy functions. :param amici_model: The AMICI model to simulate. @@ -155,7 +162,7 @@ def run_amici_simulation( problem_parameters = dict(zip(free_parameter_ids, point, strict=True)) amici_model.set_free_parameter_by_id(problem_parameters) amici_solver.set_sensitivity_order(order) - rdata = amici.run_simulation( + rdata = run_simulation( model=amici_model, solver=amici_solver, edata=amici_edata ) return rdata @@ -281,7 +288,7 @@ def reshape( def simulate_petab_to_cached_functions( petab_problem: petab.Problem, - amici_model: amici.Model, + amici_model: Model, free_parameter_ids: list[str] = None, cache: bool = True, precreate_edatas: bool = True, diff --git a/python/sdist/amici/cmake b/python/sdist/amici/cmake deleted file mode 120000 index 791713971c..0000000000 --- a/python/sdist/amici/cmake +++ /dev/null @@ -1 +0,0 @@ -../../../cmake/ \ No newline at end of file diff --git a/python/sdist/amici/debugging/__init__.py b/python/sdist/amici/debugging/__init__.py index 856c542092..d70e437c6c 100644 --- a/python/sdist/amici/debugging/__init__.py +++ b/python/sdist/amici/debugging/__init__.py @@ -1,11 +1,15 @@ """Functions for debugging AMICI simulation failures.""" +from __future__ import annotations + import numpy as np -import amici +import amici.sim.sundials -def get_model_for_preeq(model: amici.Model, edata: amici.ExpData): +def get_model_for_preeq( + model: amici.sim.sundials.Model, edata: amici.sim.sundials.ExpData +): """Get a model set-up to simulate the preequilibration condition as specified in `edata`. diff --git a/python/sdist/amici/exporters/sundials/templates/modelname.template.i b/python/sdist/amici/exporters/sundials/templates/modelname.template.i index 5a85a27fd3..0dadc2bd24 100644 --- a/python/sdist/amici/exporters/sundials/templates/modelname.template.i +++ b/python/sdist/amici/exporters/sundials/templates/modelname.template.i @@ -46,7 +46,7 @@ if t_imported < t_modified: # SWIG version used to build the model extension as `(major, minor, patch)` _SWIG_VERSION = (SWIG_VERSION_MAJOR, SWIG_VERSION_MINOR, SWIG_VERSION_PATCH) -if (amici_swig := amici.amici._SWIG_VERSION) != (model_swig := _SWIG_VERSION): +if (amici_swig := amici.sim.sundials._SWIG_VERSION) != (model_swig := _SWIG_VERSION): import warnings warnings.warn( f"SWIG version mismatch between amici ({amici_swig}) and model " diff --git a/python/sdist/amici/exporters/sundials/templates/setup.template.py b/python/sdist/amici/exporters/sundials/templates/setup.template.py index 6bff45aeb8..bf15dbb584 100644 --- a/python/sdist/amici/exporters/sundials/templates/setup.template.py +++ b/python/sdist/amici/exporters/sundials/templates/setup.template.py @@ -15,7 +15,7 @@ def get_extension() -> CMakeExtension: """Get setuptools extension object for this AMICI model package""" # Build shared object - prefix_path = Path(_get_amici_path()) + prefix_path = Path(_get_amici_path(), "_installation") AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) # handle parallel building @@ -38,7 +38,9 @@ def get_extension() -> CMakeExtension: amici_distribution = importlib.metadata.distribution("amici") amici_dir = Path(amici_distribution.locate_file("")) # this path is created during the amici build if scipy_openblas64 is used - openblas_cmake_dir = amici_dir / "lib" / "cmake" / "openblas" + openblas_cmake_dir = ( + amici_dir / "_installation" / "lib" / "cmake" / "openblas" + ) if openblas_cmake_dir.exists(): cmake_prefix_path.append(str(openblas_cmake_dir)) diff --git a/python/sdist/amici/importers/petab/_petab_importer.py b/python/sdist/amici/importers/petab/_petab_importer.py index 263f18b0eb..b050a21e47 100644 --- a/python/sdist/amici/importers/petab/_petab_importer.py +++ b/python/sdist/amici/importers/petab/_petab_importer.py @@ -21,10 +21,11 @@ from petab.v2.models import MODEL_TYPE_PYSB, MODEL_TYPE_SBML import amici -from amici import SensitivityOrder, get_model_dir +from amici import get_model_dir from amici._symbolic import DEModel, Event from amici.importers.utils import MeasurementChannel, amici_time_symbol from amici.logging import get_logger +from amici.sim.sundials import SensitivityOrder from .v1.sbml_import import _add_global_parameter from .v1.simulations import EDATAS, LLH, RDATAS, RES, S2LLH, SLLH, SRES @@ -694,6 +695,8 @@ def create_edata( :return: The created `ExpData` object for the given experiment. """ + from amici.sim.sundials import ExpData + if isinstance(experiment, str): experiment = self._petab_problem[experiment] @@ -703,7 +706,7 @@ def create_edata( f"for experiment {experiment.id}." ) - edata = amici.ExpData(self._model) + edata = ExpData(self._model) edata.id = experiment.id self._set_constants(edata, experiment) @@ -769,7 +772,7 @@ def get_k(period: ExperimentPeriod): edata.t_start = main_period.time def _set_timepoints_and_measurements( - self, edata: amici.ExpData, experiment: v2.core.Experiment + self, edata: amici.sim.sundials.ExpData, experiment: v2.core.Experiment ) -> None: """ Set timepoints and measurements for the given experiment. @@ -875,7 +878,9 @@ def _get_measurements_and_sigmas( return y, sigma_y def apply_parameters( - self, edata: amici.ExpData, problem_parameters: dict[str, float] + self, + edata: amici.sim.sundials.ExpData, + problem_parameters: dict[str, float], ) -> None: """Apply problem parameters. @@ -1039,7 +1044,7 @@ def petab_problem(self) -> v2.Problem: return self._petab_problem @property - def model(self) -> amici.Model: + def model(self) -> amici.sim.sundials.Model: """The AMICI model used by this ExperimentManager.""" return self._model @@ -1091,7 +1096,7 @@ class PetabSimulator: def __init__( self, em: ExperimentManager, - solver: amici.Solver | None = None, + solver: amici.sim.sundials.Solver | None = None, num_threads: int = 1, # TODO: allow selecting specific experiments? # TODO: store_edatas: bool @@ -1118,12 +1123,12 @@ def __init__( self.num_threads = num_threads @property - def model(self) -> amici.Model: + def model(self) -> amici.sim.sundials.Model: """The AMICI model used by this simulator.""" return self._model @property - def solver(self) -> amici.Solver: + def solver(self) -> amici.sim.sundials.Solver: """The AMICI solver used by this simulator.""" return self._solver @@ -1142,12 +1147,12 @@ def simulate( Dictionary of * the summed cost function value (``LLH``), - * list of :class:`amici.amici.ReturnData` (``RDATAS``) + * list of :class:`amici.sim.sundials.ReturnData` (``RDATAS``) for each experiment, - * list of :class:`amici.amici.ExpData` (``EDATAS``) + * list of :class:`amici.sim.sundials.ExpData` (``EDATAS``) for each experiment - Note that the returned :class:`amici.amici.ExpData` instances + Note that the returned :class:`amici.amiciamici.sim.sundials.ExpData` instances may be changed by subsequent calls to this function. Create a copy if needed. """ @@ -1168,7 +1173,7 @@ def simulate( edata=edata, problem_parameters=problem_parameters ) - rdatas = amici.run_simulations( + rdatas = amici.sim.sundials.run_simulations( self._model, self._solver, edatas, num_threads=self.num_threads ) @@ -1184,7 +1189,7 @@ def simulate( } def _aggregate_sllh( - self, rdatas: Sequence[amici.ReturnDataView] + self, rdatas: Sequence[amici.sim.sundials.ReturnDataView] ) -> dict[str, float] | None: """Aggregate the sensitivities of the log-likelihoods. @@ -1201,7 +1206,7 @@ def _aggregate_sllh( # Check for issues in all condition simulation results. for rdata in rdatas: # Condition failed during simulation. - if rdata.status != amici.AMICI_SUCCESS: + if rdata.status != amici.sim.sundials.AMICI_SUCCESS: return None # Condition simulation result does not provide SLLH. if rdata.sllh is None: @@ -1234,7 +1239,7 @@ def _aggregate_sllh( def _aggregate_s2llh( self, - rdatas: Sequence[amici.ReturnDataView], + rdatas: Sequence[amici.sim.sundials.ReturnDataView], use_fim: bool = True, ) -> np.ndarray | None: """Aggregate the Hessians from individual experiments. @@ -1266,7 +1271,7 @@ def _aggregate_s2llh( # Check for issues in all condition simulation results. for rdata in rdatas: # Condition failed during simulation. - if rdata.status != amici.AMICI_SUCCESS: + if rdata.status != amici.sim.sundials.AMICI_SUCCESS: return None # Condition simulation result does not provide FIM. if rdata.FIM is None: @@ -1388,8 +1393,8 @@ def _set_default_experiment( def rdatas_to_measurement_df( - rdatas: Sequence[amici.ReturnData], - model: amici.AmiciModel, + rdatas: Sequence[amici.sim.sundials.ReturnData], + model: amici.sim.sundials.AmiciModel, petab_problem: v2.Problem, ) -> pd.DataFrame: """ @@ -1447,8 +1452,8 @@ def rdatas_to_measurement_df( def rdatas_to_simulation_df( - rdatas: Sequence[amici.ReturnData], - model: amici.AmiciModel, + rdatas: Sequence[amici.sim.sundials.ReturnData], + model: amici.sim.sundials.AmiciModel, petab_problem: v2.Problem, ) -> pd.DataFrame: """ diff --git a/python/sdist/amici/importers/petab/v1/conditions.py b/python/sdist/amici/importers/petab/v1/conditions.py index 7087db40b7..efc77e64bb 100644 --- a/python/sdist/amici/importers/petab/v1/conditions.py +++ b/python/sdist/amici/importers/petab/v1/conditions.py @@ -1,5 +1,7 @@ """PEtab conditions to AMICI ExpDatas.""" +from __future__ import annotations + import logging import numbers import warnings @@ -17,8 +19,11 @@ TIME, ) -import amici -from amici import AmiciModel +from amici.sim.sundials import ( + AmiciModel, + ExpData, + parameter_scaling_from_int_vector, +) from .parameter_mapping import ( ParameterMapping, @@ -36,7 +41,7 @@ def fill_in_parameters( - edatas: list[amici.ExpData], + edatas: list[ExpData], problem_parameters: dict[str, numbers.Number], scaled_parameters: bool, parameter_mapping: ParameterMapping, @@ -46,7 +51,7 @@ def fill_in_parameters( """Fill fixed and dynamic parameters into the edatas (in-place). :param edatas: - List of experimental datas :class:`amici.amici.ExpData` with + List of experimental datas :class:`ExpData` with everything except parameters filled. :param problem_parameters: Problem parameters as parameterId=>value dict. Only @@ -90,7 +95,7 @@ def fill_in_parameters( def fill_in_parameters_for_condition( - edata: amici.ExpData, + edata: ExpData, problem_parameters: dict[str, numbers.Number], scaled_parameters: bool, parameter_mapping: ParameterMappingForCondition, @@ -205,7 +210,7 @@ def _get_par(model_par, value, mapping): edata.free_parameters = np.asarray(parameters, dtype=float) if scales: - edata.pscale = amici.parameter_scaling_from_int_vector(scales) + edata.pscale = parameter_scaling_from_int_vector(scales) if plist: edata.plist = plist @@ -237,8 +242,8 @@ def create_parameterized_edatas( parameter_mapping: ParameterMapping = None, simulation_conditions: pd.DataFrame | dict = None, warn_unused: bool = True, -) -> list[amici.ExpData]: - """Create list of :class:amici.ExpData objects with parameters filled in. +) -> list[ExpData]: + """Create list of :class:ExpData objects with parameters filled in. :param amici_model: AMICI Model assumed to be compatible with ``petab_problem``. @@ -265,7 +270,7 @@ def create_parameterized_edatas( mapping. :return: - List with one :class:`amici.amici.ExpData` per simulation condition, + List with one :class:`ExpData` per simulation condition, with filled in timepoints, data and parameters. """ # number of amici simulations will be number of unique @@ -313,8 +318,8 @@ def create_edata_for_condition( amici_model: AmiciModel, petab_problem: petab.Problem, observable_ids: list[str], -) -> amici.ExpData: - """Get :class:`amici.amici.ExpData` for the given PEtab condition. +) -> ExpData: + """Get :class:`ExpData` for the given PEtab condition. Sets timepoints, observed data and sigmas. @@ -340,7 +345,7 @@ def create_edata_for_condition( ) # create an ExpData object - edata = amici.ExpData(amici_model) + edata = ExpData(amici_model) edata.id = condition[SIMULATION_CONDITION_ID] if condition.get(PREEQUILIBRATION_CONDITION_ID): edata.id += "+" + condition.get(PREEQUILIBRATION_CONDITION_ID) @@ -394,8 +399,8 @@ def create_edatas( amici_model: AmiciModel, petab_problem: petab.Problem, simulation_conditions: pd.DataFrame | dict = None, -) -> list[amici.ExpData]: - """Create list of :class:`amici.amici.ExpData` objects for PEtab problem. +) -> list[ExpData]: + """Create list of :class:`ExpData` objects for PEtab problem. :param amici_model: AMICI model. @@ -406,7 +411,7 @@ def create_edatas( save time if this has be obtained before. :return: - List with one :class:`amici.amici.ExpData` per simulation condition, + List with one :class:`ExpData` per simulation condition, with filled in timepoints and data, but without parameter values (see :func:`create_parameterized_edatas` or :func:`fill_in_parameters` for that). @@ -431,7 +436,7 @@ def create_edatas( edatas = [] for _, condition in simulation_conditions.iterrows(): - # Create amici.ExpData for each simulation + # Create ExpData for each simulation if PREEQUILIBRATION_CONDITION_ID in condition: measurement_index = ( condition.get(SIMULATION_CONDITION_ID), diff --git a/python/sdist/amici/importers/petab/v1/import_helpers.py b/python/sdist/amici/importers/petab/v1/import_helpers.py index 398ae49200..b191c61476 100644 --- a/python/sdist/amici/importers/petab/v1/import_helpers.py +++ b/python/sdist/amici/importers/petab/v1/import_helpers.py @@ -3,6 +3,8 @@ Functions for PEtab import that are independent of the model format. """ +from __future__ import annotations + import logging import os import re diff --git a/python/sdist/amici/importers/petab/v1/parameter_mapping.py b/python/sdist/amici/importers/petab/v1/parameter_mapping.py index adbc5cf12f..b2b7837e7b 100644 --- a/python/sdist/amici/importers/petab/v1/parameter_mapping.py +++ b/python/sdist/amici/importers/petab/v1/parameter_mapping.py @@ -39,9 +39,8 @@ from petab.v1.models import MODEL_TYPE_PYSB, MODEL_TYPE_SBML from sympy.abc import _clash -import amici -from amici import AmiciModel from amici.importers.sbml import get_species_initial +from amici.sim.sundials import AmiciModel, ParameterScaling from . import PREEQ_INDICATOR_ID from .util import get_states_in_condition_table @@ -194,21 +193,21 @@ def free_symbols(self) -> set[str]: def petab_to_amici_scale(petab_scale: str) -> int: """Convert petab scale id to amici scale id.""" if petab_scale == LIN: - return amici.ParameterScaling_none + return ParameterScaling.none if petab_scale == LOG10: - return amici.ParameterScaling_log10 + return ParameterScaling.log10 if petab_scale == LOG: - return amici.ParameterScaling_ln + return ParameterScaling.ln raise ValueError(f"PEtab scale not recognized: {petab_scale}") def amici_to_petab_scale(amici_scale: int) -> str: """Convert amici scale id to petab scale id.""" - if amici_scale == amici.ParameterScaling_none: + if amici_scale == ParameterScaling.none: return LIN - if amici_scale == amici.ParameterScaling_log10: + if amici_scale == ParameterScaling.log10: return LOG10 - if amici_scale == amici.ParameterScaling_ln: + if amici_scale == ParameterScaling.ln: return LOG raise ValueError(f"AMICI scale not recognized: {amici_scale}") diff --git a/python/sdist/amici/importers/petab/v1/petab_problem.py b/python/sdist/amici/importers/petab/v1/petab_problem.py index e52a6b4c15..31ba44a36c 100644 --- a/python/sdist/amici/importers/petab/v1/petab_problem.py +++ b/python/sdist/amici/importers/petab/v1/petab_problem.py @@ -1,5 +1,7 @@ """PEtab-problem based simulations.""" +from __future__ import annotations + import copy import pandas as pd diff --git a/python/sdist/amici/importers/petab/v1/simulations.py b/python/sdist/amici/importers/petab/v1/simulations.py index 65e88fbbfc..3d5f31605c 100644 --- a/python/sdist/amici/importers/petab/v1/simulations.py +++ b/python/sdist/amici/importers/petab/v1/simulations.py @@ -4,6 +4,8 @@ function as defined by a PEtab problem. """ +from __future__ import annotations + import copy import logging from collections.abc import Sequence @@ -15,8 +17,16 @@ from petab.v1.C import * # noqa: F403 import amici -from amici import AmiciExpData, AmiciModel from amici.logging import get_logger, log_execution_time +from amici.sim.sundials import ( + AMICI_SUCCESS, + AmiciExpData, + AmiciModel, + ReturnData, + ReturnDataView, + SensitivityOrder, + run_simulations, +) from .conditions import ( create_edatas, @@ -58,7 +68,7 @@ def simulate_petab( petab_problem: petab.Problem, amici_model: AmiciModel, - solver: amici.Solver | None = None, + solver: amici.sim.sundials.Solver | None = None, problem_parameters: dict[str, float] | None = None, simulation_conditions: pd.DataFrame | dict = None, edatas: list[AmiciExpData] = None, @@ -198,7 +208,7 @@ def simulate_petab( ) # Simulate - rdatas = amici.run_simulations( + rdatas = run_simulations( amici_model, solver, edata_list=edatas, @@ -210,7 +220,7 @@ def simulate_petab( llh = sum(rdata["llh"] for rdata in rdatas) # Compute total sllh sllh = None - if solver.get_sensitivity_order() != amici.SensitivityOrder.none: + if solver.get_sensitivity_order() != SensitivityOrder.none: sllh = aggregate_sllh( amici_model=amici_model, rdatas=rdatas, @@ -251,7 +261,7 @@ def simulate_petab( def aggregate_sllh( amici_model: AmiciModel, - rdatas: Sequence[amici.ReturnDataView], + rdatas: Sequence[ReturnDataView], parameter_mapping: ParameterMapping | None, edatas: list[AmiciExpData], petab_scale: bool = True, @@ -289,7 +299,7 @@ def aggregate_sllh( # Check for issues in all condition simulation results. for rdata in rdatas: # Condition failed during simulation. - if rdata.status != amici.AMICI_SUCCESS: + if rdata.status != AMICI_SUCCESS: return None # Condition simulation result does not provide SLLH. if rdata.sllh is None: @@ -397,7 +407,7 @@ def rescale_sensitivity( def rdatas_to_measurement_df( - rdatas: Sequence[amici.ReturnData], + rdatas: Sequence[ReturnData], model: AmiciModel, measurement_df: pd.DataFrame, ) -> pd.DataFrame: @@ -459,12 +469,12 @@ def rdatas_to_measurement_df( def rdatas_to_simulation_df( - rdatas: Sequence[amici.ReturnData], + rdatas: Sequence[ReturnData], model: AmiciModel, measurement_df: pd.DataFrame, ) -> pd.DataFrame: """Create a PEtab simulation dataframe from - :class:`amici.amici.ReturnData` s. + :class:`ReturnData` s. See :func:`rdatas_to_measurement_df` for details, only that model outputs will appear in column ``simulation`` instead of ``measurement``.""" diff --git a/python/sdist/amici/importers/petab/v1/simulator.py b/python/sdist/amici/importers/petab/v1/simulator.py index e64cb30734..c676e2b218 100644 --- a/python/sdist/amici/importers/petab/v1/simulator.py +++ b/python/sdist/amici/importers/petab/v1/simulator.py @@ -9,6 +9,8 @@ - generate synthetic data """ +from __future__ import annotations + import inspect import sys from collections.abc import Callable @@ -16,7 +18,7 @@ import pandas as pd import petab.v1 as petab -from amici import AmiciModel, SensitivityMethod +from amici.sim.sundials import AmiciModel, SensitivityMethod from .petab_import import import_petab_problem from .simulations import RDATAS, rdatas_to_measurement_df, simulate_petab diff --git a/python/sdist/amici/importers/pysb/__init__.py b/python/sdist/amici/importers/pysb/__init__.py index 573a556e2d..12f7757e6b 100644 --- a/python/sdist/amici/importers/pysb/__init__.py +++ b/python/sdist/amici/importers/pysb/__init__.py @@ -5,6 +5,8 @@ in the :class:`pysb.core.Model` format. """ +from __future__ import annotations + import itertools import logging import os diff --git a/python/sdist/amici/importers/sbml/__init__.py b/python/sdist/amici/importers/sbml/__init__.py index 346d3d0bfb..deb0b475d2 100644 --- a/python/sdist/amici/importers/sbml/__init__.py +++ b/python/sdist/amici/importers/sbml/__init__.py @@ -5,6 +5,8 @@ in the `Systems Biology Markup Language (SBML) `_. """ +from __future__ import annotations + import contextlib import copy import itertools as itt @@ -29,7 +31,7 @@ from sympy.matrices.dense import MutableDenseMatrix import amici -from amici import get_model_dir, has_clibs +from amici import get_model_dir from amici._symbolic.de_model import DEModel from amici._symbolic.de_model_components import ( DifferentialState, @@ -432,6 +434,8 @@ def sbml2amici( ) from e if compile: + from amici.sim.sundials import has_clibs + if not has_clibs: warnings.warn( "AMICI C++ extensions have not been built. " diff --git a/python/sdist/amici/include/amici b/python/sdist/amici/include/amici deleted file mode 120000 index 4e5f8a216a..0000000000 --- a/python/sdist/amici/include/amici +++ /dev/null @@ -1 +0,0 @@ -../../../../include/amici/ \ No newline at end of file diff --git a/python/sdist/amici/sim/__init__.py b/python/sdist/amici/sim/__init__.py new file mode 100644 index 0000000000..ac1dee3186 --- /dev/null +++ b/python/sdist/amici/sim/__init__.py @@ -0,0 +1 @@ +"""Functionality for simulating AMICI models.""" diff --git a/python/sdist/amici/sim/jax/__init__.py b/python/sdist/amici/sim/jax/__init__.py new file mode 100644 index 0000000000..07744420df --- /dev/null +++ b/python/sdist/amici/sim/jax/__init__.py @@ -0,0 +1 @@ +"""Functionality for simulating JAX-based AMICI models.""" diff --git a/python/sdist/amici/sim/sundials/__init__.py b/python/sdist/amici/sim/sundials/__init__.py new file mode 100644 index 0000000000..01934ab577 --- /dev/null +++ b/python/sdist/amici/sim/sundials/__init__.py @@ -0,0 +1,71 @@ +""" +Functionality for simulating AMICI models using SUNDIALS solvers. + +This module provides the relevant objects for simulating AMICI models +using :term:`SUNDIALS` solvers such as :term:`CVODES` and :term:`IDAS` and +for analyzing the simulation results. +""" + +import os +import warnings +from types import ModuleType +from typing import Protocol, runtime_checkable + +from ... import amici_path + +#: boolean indicating if this is the full package with swig interface or +# the raw package without extension +has_clibs: bool = any( + os.path.isfile(os.path.join(amici_path, "_installation", wrapper)) + for wrapper in ["amici.py", "amici_without_hdf5.py"] +) +#: boolean indicating if amici was compiled with hdf5 support +hdf5_enabled: bool = False + +if has_clibs: + # Import SWIG module and swig-dependent submodules + # if required and available + + # prevent segfaults under pytest + # see also: + # https://github.com/swig/swig/issues/2881 + # https://github.com/AMICI-dev/AMICI/issues/2565 + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + category=DeprecationWarning, + message="builtin type .* has no __module__ attribute", + ) + # The swig-generated Python module + from amici._installation import amici + + # TODO: selective import to avoid loading unneeded symbols + from amici._installation.amici import * + from amici._installation.amici import _SWIG_VERSION as _SWIG_VERSION + + # has to be done before importing read_solver_settings_from_hdf5 + # from .swig_wrappers + hdf5_enabled = "read_solver_settings_from_hdf5" in dir() + # These modules require the swig interface and other dependencies + from ._numpy import ExpDataView as ExpDataView + from ._numpy import ReturnDataView as ReturnDataView + from ._numpy import evaluate as evaluate + from ._pandas import * + + # Import after import of the swig module as this is supposed to + # shadow some swig symbols + from ._swig_wrappers import * + + @runtime_checkable + class ModelModule(Protocol): # noqa: F811 + """Type of AMICI-generated model modules. + + To enable static type checking.""" + + def get_model(self) -> amici.Model: + """Create a model instance.""" + ... + + AmiciModel = amici.Model | amici.ModelPtr +else: + ModelModule = ModuleType diff --git a/python/sdist/amici/numpy.py b/python/sdist/amici/sim/sundials/_numpy.py similarity index 97% rename from python/sdist/amici/numpy.py rename to python/sdist/amici/sim/sundials/_numpy.py index d6799c7294..3e254db175 100644 --- a/python/sdist/amici/numpy.py +++ b/python/sdist/amici/sim/sundials/_numpy.py @@ -18,8 +18,6 @@ import xarray as xr from sympy.abc import _clash -import amici - from . import ( ExpData, ExpDataPtr, @@ -27,6 +25,7 @@ ReturnData, ReturnDataPtr, SteadyStateStatus, + simulation_status_to_str, ) __all__ = [ @@ -319,7 +318,7 @@ def __dir__(self): class ReturnDataView(SwigPtrView): """ - Interface class for C++ :class:`amici.ReturnData` objects that avoids + Interface class for C++ :class:`ReturnData` objects that avoids possibly costly copies of member data. """ @@ -391,7 +390,7 @@ def __init__(self, rdata: ReturnDataPtr | ReturnData): if not isinstance(rdata, (ReturnDataPtr | ReturnData)): raise TypeError( f"Unsupported pointer {type(rdata)}, must be" - f"amici.ReturnDataPtr or amici.ReturnData!" + f"ReturnDataPtr or ReturnData!" ) self._field_dimensions = { "ts": [rdata.nt], @@ -467,7 +466,7 @@ def __getitem__( return super().__getitem__(item) def __repr__(self): - status = amici.simulation_status_to_str(self._swigptr.status) + status = simulation_status_to_str(self._swigptr.status) return f"<{self.__class__.__name__}(id={self._swigptr.id!r}, status={status})>" def by_id( @@ -482,7 +481,7 @@ def by_id( optional if field would be one of ``{'x', 'y', 'w'}`` :param model: The model from which this ReturnDataView was generated. This is optional if this ReturnData was generated with - ``solver.getReturnDataReportingMode() == amici.RDataReporting.full``. + ``solver.getReturnDataReportingMode() == RDataReporting.full``. """ if field is None: field = _entity_type_from_id(entity_id, self, model) @@ -538,7 +537,7 @@ def __init__(self, edata: ExpDataPtr | ExpData): """ if not isinstance(edata, (ExpDataPtr | ExpData)): raise TypeError( - f"Unsupported pointer {type(edata)}, must be amici.ExpDataPtr!" + f"Unsupported pointer {type(edata)}, must be ExpDataPtr!" ) self._field_dimensions = { "ts": [edata.nt()], @@ -592,8 +591,8 @@ def _field_as_numpy( def _entity_type_from_id( entity_id: str, - rdata: amici.ReturnData | amici.ReturnDataView = None, - model: amici.Model = None, + rdata: ReturnData | ReturnDataView = None, + model: Model = None, ) -> Literal["x", "y", "w", "p", "k"]: """Guess the type of some entity by its ID.""" for entity_type, symbol in ( @@ -608,9 +607,7 @@ def _entity_type_from_id( return symbol else: if entity_id in getattr( - rdata - if isinstance(rdata, amici.ReturnData) - else rdata._swigptr, + rdata if isinstance(rdata, ReturnData) else rdata._swigptr, f"{entity_type.lower()}_ids", ): return symbol diff --git a/python/sdist/amici/pandas.py b/python/sdist/amici/sim/sundials/_pandas.py similarity index 95% rename from python/sdist/amici/pandas.py rename to python/sdist/amici/sim/sundials/_pandas.py index 97497d619c..b2ef8aec4f 100644 --- a/python/sdist/amici/pandas.py +++ b/python/sdist/amici/sim/sundials/_pandas.py @@ -5,6 +5,8 @@ between C++ objects from :mod:`amici.amici` and pandas DataFrames """ +from __future__ import annotations + import copy import math from typing import SupportsFloat @@ -12,9 +14,16 @@ import numpy as np import pandas as pd -import amici - -from .numpy import ExpDataView +from . import ( + ExpData, + ExpDataPtr, + ExpDataView, + Model, + ModelPtr, + ParameterScaling, + ReturnDataView, + parameter_scaling_from_int_vector, +) __all__ = [ "get_expressions_as_dataframe", @@ -25,22 +34,17 @@ "get_residuals_as_data_frame", ] -ExpDatas = ( - list[amici.amici.ExpData] - | list[amici.ExpDataPtr] - | amici.amici.ExpData - | amici.ExpDataPtr -) +ExpDatas = list[ExpData] | list[ExpDataPtr] | ExpData | ExpDataPtr -ReturnDatas = list[amici.ReturnDataView] | amici.ReturnDataView +ReturnDatas = list[ReturnDataView] | ReturnDataView -AmiciModel = amici.ModelPtr | amici.Model +AmiciModel = ModelPtr | Model -def _process_edata_list(edata_list: ExpDatas) -> list[amici.amici.ExpData]: +def _process_edata_list(edata_list: ExpDatas) -> list[ExpData]: """ - Maps single instances of :class:`amici.amici.ExpData` to lists of - :class:`amici.amici.ExpData` + Maps single instances of :class:`ExpData` to lists of + :class:`ExpData` :param edata_list: list of instances or single instance @@ -48,16 +52,16 @@ def _process_edata_list(edata_list: ExpDatas) -> list[amici.amici.ExpData]: :return: list of instance(s) """ - if isinstance(edata_list, (amici.amici.ExpData | amici.ExpDataPtr)): + if isinstance(edata_list, (ExpData | ExpDataPtr)): return [edata_list] else: return edata_list -def _process_rdata_list(rdata_list: ReturnDatas) -> list[amici.ReturnDataView]: +def _process_rdata_list(rdata_list: ReturnDatas) -> list[ReturnDataView]: """ - Maps single instances of :class:`amici.ReturnData` to lists of - :class:`amici.ReturnData` + Maps single instances of :class:`ReturnData` to lists of + :class:`ReturnData` :param rdata_list: list of instances or single instance @@ -65,7 +69,7 @@ def _process_rdata_list(rdata_list: ReturnDatas) -> list[amici.ReturnDataView]: :return: list of instance(s) """ - if isinstance(rdata_list, amici.ReturnDataView): + if isinstance(rdata_list, ReturnDataView): return [rdata_list] else: return rdata_list @@ -122,7 +126,7 @@ def get_data_observables_as_data_frame( def get_simulation_observables_as_data_frame( - model: amici.Model, + model: Model, edata_list: ExpDatas, rdata_list: ReturnDatas, by_id: bool | None = False, @@ -180,7 +184,7 @@ def get_simulation_observables_as_data_frame( def get_simulation_states_as_data_frame( - model: amici.Model, + model: Model, edata_list: ExpDatas, rdata_list: ReturnDatas, by_id: bool | None = False, @@ -236,7 +240,7 @@ def get_simulation_states_as_data_frame( def get_expressions_as_dataframe( - model: amici.Model, + model: Model, edata_list: ExpDatas, rdata_list: ReturnDatas, by_id: bool | None = False, @@ -292,7 +296,7 @@ def get_expressions_as_dataframe( def get_residuals_as_data_frame( - model: amici.Model, + model: Model, edata_list: ExpDatas, rdata_list: ReturnDatas, by_id: bool | None = False, @@ -365,7 +369,7 @@ def get_residuals_as_data_frame( def _fill_conditions_dict( datadict: dict[str, float], model: AmiciModel, - edata: amici.amici.ExpData, + edata: ExpData, by_id: bool, ) -> dict[str, float]: """ @@ -681,7 +685,7 @@ def construct_edata_from_data_frame( model: AmiciModel, condition: pd.Series, by_id: bool | None = False, -) -> amici.amici.ExpData: +) -> ExpData: """ Constructs an ExpData instance according to the provided Model and DataFrame. @@ -709,7 +713,7 @@ def construct_edata_from_data_frame( ExpData instance. """ # initialize edata - edata = amici.ExpData(model.get()) + edata = ExpData(model.get()) # timepoints df = df.sort_values(by="time", ascending=True) @@ -742,9 +746,9 @@ def construct_edata_from_data_frame( .values ) - edata.pscale = amici.parameter_scaling_from_int_vector( + edata.pscale = parameter_scaling_from_int_vector( [ - amici.ParameterScaling(condition[par + "_scale"].astype(int)) + ParameterScaling(condition[par + "_scale"].astype(int)) for par in list( _get_names_or_ids(model, "free_parameter", by_id=by_id) ) @@ -802,7 +806,7 @@ def construct_edata_from_data_frame( def get_edata_from_data_frame( model: AmiciModel, df: pd.DataFrame, by_id: bool | None = False -) -> list[amici.amici.ExpData]: +) -> list[ExpData]: """ Constructs a ExpData instances according to the provided Model and DataFrame. diff --git a/python/sdist/amici/swig_wrappers.py b/python/sdist/amici/sim/sundials/_swig_wrappers.py similarity index 90% rename from python/sdist/amici/swig_wrappers.py rename to python/sdist/amici/sim/sundials/_swig_wrappers.py index 2040c558a5..3fa9511ea4 100644 --- a/python/sdist/amici/swig_wrappers.py +++ b/python/sdist/amici/sim/sundials/_swig_wrappers.py @@ -1,4 +1,9 @@ -"""Convenience wrappers for the swig interface""" +""" +Convenience wrappers for the swig interface. + +While this functionality could be implemented in the swig interface +directly, it is easier to maintain and extend in pure Python. +""" from __future__ import annotations @@ -10,20 +15,21 @@ from typing import Any import amici -import amici.amici as amici_swig -from amici.amici import ( +import amici._installation.amici as amici_swig +from amici._installation.amici import ( AmiciExpData, AmiciExpDataVector, AmiciModel, AmiciSolver, + RDataReporting, SensitivityMethod, SensitivityOrder, Solver, _get_ptr, ) +from amici.logging import get_logger -from . import ReturnDataView, numpy -from .logging import get_logger +from . import ReturnDataView logger = get_logger(__name__, log_level=logging.DEBUG) @@ -44,8 +50,7 @@ def run_simulation( edata: AmiciExpData | None = None, ) -> ReturnDataView: """ - Convenience wrapper around :py:func:`amici.amici.run_simulation` - (generated by swig) + Simulate a model with given solver and experimental data. :param model: Model instance @@ -77,9 +82,9 @@ def run_simulation( _get_ptr(solver), _get_ptr(edata), _get_ptr(model) ) _log_simulation(rdata) - if solver.get_return_data_reporting_mode() == amici.RDataReporting.full: + if solver.get_return_data_reporting_mode() == RDataReporting.full: _ids_and_names_to_rdata(rdata, model) - return numpy.ReturnDataView(rdata) + return ReturnDataView(rdata) def run_simulations( @@ -124,13 +129,10 @@ def run_simulations( ) for rdata in rdata_ptr_list: _log_simulation(rdata) - if ( - solver.get_return_data_reporting_mode() - == amici.RDataReporting.full - ): + if solver.get_return_data_reporting_mode() == RDataReporting.full: _ids_and_names_to_rdata(rdata, model) - return [numpy.ReturnDataView(r) for r in rdata_ptr_list] + return [ReturnDataView(r) for r in rdata_ptr_list] def read_solver_settings_from_hdf5( @@ -199,9 +201,15 @@ def get_model_settings( ) -> dict[str, Any]: """Get model settings that are set independently of the compiled model. + This function is used for serialization of model settings. + It must only be used in combination with :func:`set_model_settings`. + :param model: The AMICI model instance. - :returns: Keys are AMICI model attributes, values are attribute values. + :returns: + Value to be passed to :func:`set_model_settings` to restore the model + settings. + Keys are AMICI model attributes, values are attribute values. """ settings = {} for setting in model_instance_settings: @@ -234,8 +242,12 @@ def set_model_settings( ) -> None: """Set model settings. + This function is used for deserialization of model settings. + It must only be used in combination with :func:`get_model_settings`. + :param model: The AMICI model instance. - :param settings: Keys are callable attributes (setters) of an AMICI model, + :param settings: The return value of :func:`get_model_settings`. + Keys are callable attributes (setters) of an AMICI model, values are provided to the setters. """ for setting, value in settings.items(): @@ -363,7 +375,7 @@ def restore_model( :param checksum: Checksum of the model extension to verify integrity. """ - from . import import_model_module + from amici import import_model_module model_module = import_model_module(module_name, module_path) model = model_module.get_model() @@ -410,7 +422,7 @@ def restore_edata( """ edata = amici_swig.ExpData(*init_args) - edata.pscale = amici.parameter_scaling_from_int_vector( + edata.pscale = amici_swig.parameter_scaling_from_int_vector( simulation_parameter_dict.pop("pscale") ) for key, value in simulation_parameter_dict.items(): @@ -435,10 +447,12 @@ def restore_solver(cls: type, cls_name: str, hdf5_file: str) -> Solver: :param hdf5_file: HDF5 file from which to read the solver settings. """ + from . import CVodeSolver, IDASolver + if cls_name == "CVodeSolver": - solver = amici.CVodeSolver() + solver = CVodeSolver() elif cls_name == "IDASolver": - solver = amici.IDASolver() + solver = IDASolver() else: raise ValueError(f"Unknown solver class name: {cls_name}") diff --git a/python/sdist/amici/gradient_check.py b/python/sdist/amici/sim/sundials/gradient_check.py similarity index 100% rename from python/sdist/amici/gradient_check.py rename to python/sdist/amici/sim/sundials/gradient_check.py diff --git a/python/sdist/amici/plotting.py b/python/sdist/amici/sim/sundials/plotting.py similarity index 94% rename from python/sdist/amici/plotting.py rename to python/sdist/amici/sim/sundials/plotting.py index 987b890890..f38549c974 100644 --- a/python/sdist/amici/plotting.py +++ b/python/sdist/amici/sim/sundials/plotting.py @@ -12,10 +12,8 @@ import seaborn as sns from matplotlib.axes import Axes -import amici - -from . import Model, ReturnDataView -from .numpy import StrOrExpr, evaluate +from . import ExpData, ExpDataView, Model, ReturnDataView +from ._numpy import StrOrExpr, evaluate __all__ = [ "plot_state_trajectories", @@ -38,7 +36,7 @@ def plot_state_trajectories( :param rdata: AMICI simulation results as returned by - :func:`amici.amici.runAmiciSimulation`. + :func:`run_amici_simulation`. :param state_indices: Indices of state variables for which trajectories are to be plotted. :param ax: @@ -94,14 +92,14 @@ def plot_observable_trajectories( model: Model = None, prefer_names: bool = True, marker=None, - edata: amici.ExpData | amici.ExpDataView = None, + edata: ExpData | ExpDataView = None, ) -> None: """ Plot observable trajectories. :param rdata: AMICI simulation results as returned by - :func:`amici.amici.run_simulation`. + :func:`run_simulation`. :param observable_indices: Indices of observables for which trajectories are to be plotted. :param ax: @@ -116,8 +114,8 @@ def plot_observable_trajectories( :param edata: Experimental data to be plotted (no event observables yet). """ - if isinstance(edata, amici.amici.ExpData): - edata = amici.ExpDataView(edata) + if isinstance(edata, ExpData): + edata = ExpDataView(edata) if not ax: fig, ax = plt.subplots() diff --git a/python/sdist/amici/src b/python/sdist/amici/src deleted file mode 120000 index a1d005e304..0000000000 --- a/python/sdist/amici/src +++ /dev/null @@ -1 +0,0 @@ -../../../src/ \ No newline at end of file diff --git a/python/sdist/amici/swig b/python/sdist/amici/swig deleted file mode 120000 index e8211bd47f..0000000000 --- a/python/sdist/amici/swig +++ /dev/null @@ -1 +0,0 @@ -../../../swig/ \ No newline at end of file diff --git a/python/sdist/amici/testing/models.py b/python/sdist/amici/testing/models.py index b52145d628..b17cb76475 100644 --- a/python/sdist/amici/testing/models.py +++ b/python/sdist/amici/testing/models.py @@ -7,12 +7,11 @@ import libsbml import sympy as sp -from amici import AmiciModel, MeasurementChannel, SbmlImporter +from amici import MeasurementChannel, SbmlImporter, import_model_module +from amici.importers.antimony import antimony2amici, antimony2sbml from amici.importers.sbml.splines import CubicHermiteSpline from amici.importers.utils import amici_time_symbol - -from .. import Model, import_model_module -from ..importers.antimony import antimony2amici, antimony2sbml +from amici.sim.sundials import AmiciModel, Model model_dirac_ant = r""" p1 = 1; diff --git a/python/sdist/amici/version.txt b/python/sdist/amici/version.txt deleted file mode 120000 index 8f6d04dc1f..0000000000 --- a/python/sdist/amici/version.txt +++ /dev/null @@ -1 +0,0 @@ -../../../version.txt \ No newline at end of file diff --git a/python/sdist/setup.py b/python/sdist/setup.py index ab5177d2ef..f43df267c5 100755 --- a/python/sdist/setup.py +++ b/python/sdist/setup.py @@ -6,7 +6,7 @@ This file expects to be run from within its directory. Non-python-package requirements: -- swig>=3.0 +- swig>=4.0 - Optional: hdf5 libraries and headers """ @@ -36,7 +36,7 @@ def get_extensions(): """Get required C(++) extensions for build_ext""" # CMake prefix path for finding FindXXX.cmake to find SuiteSparse # components - install_dir = Path(__file__).parent / "amici" + install_dir = Path(__file__).parent / "amici" / "sim" / "sundials" prefix_path = install_dir.absolute() AmiciBuildCMakeExtension.extend_cmake_prefix_path(str(prefix_path)) @@ -55,8 +55,8 @@ def get_extensions(): # SuiteSparse suitesparse = CMakeExtension( name="SuiteSparse", - install_prefix="amici", - source_dir="amici/ThirdParty/SuiteSparse", + install_prefix="amici/_installation", + source_dir="amici/_installation/ThirdParty/SuiteSparse", cmake_build_type=build_type, cmake_configure_options=[ *global_cmake_configure_options, @@ -84,13 +84,13 @@ def get_extensions(): # to use artifacts from other extensions here. `${build_dir}` will # be replaced by the actual path by `AmiciBuildCMakeExtension` # before being passed to CMake. - cmake_prefix_path.append("${build_dir}/amici") + cmake_prefix_path.append("${build_dir}/amici/_installation") # SUNDIALS sundials = CMakeExtension( name="sundials", - install_prefix="amici", - source_dir="amici/ThirdParty/sundials", + install_prefix="amici/_installation", + source_dir="amici/_installation/ThirdParty/sundials", cmake_build_type=build_type, cmake_configure_options=[ *global_cmake_configure_options, @@ -113,20 +113,22 @@ def get_extensions(): try: import scipy_openblas64 # noqa: F401 - cmake_prefix_path.append("${build_dir}/amici/lib/cmake/openblas") + cmake_prefix_path.append( + "${build_dir}/amici/_installation/lib/cmake/openblas" + ) except ImportError: pass # AMICI amici_ext = CMakeExtension( name="amici", - install_prefix="amici", - source_dir="amici", + install_prefix="amici/_installation", + source_dir="amici/_installation", cmake_build_type=build_type, cmake_configure_options=[ *global_cmake_configure_options, "-Werror=dev" - # Turn warnings in to errors on GitHub Actions, + # Turn warnings into errors on GitHub Actions, # match original repo and forks with default name if os.environ.get("GITHUB_REPOSITORY", "").endswith("/AMICI") else "-Wno-error=dev", @@ -152,12 +154,12 @@ def amici_pre_cmake(ext, binary_dir): binary_dir = Path(binary_dir) shutil.copytree( scipy_openblas64.get_lib_dir(), - binary_dir / "amici" / "lib", + binary_dir / "amici" / "_installation" / "lib", dirs_exist_ok=True, ) shutil.copytree( scipy_openblas64.get_include_dir(), - binary_dir / "amici" / "include", + binary_dir / "amici" / "_installation" / "include", dirs_exist_ok=True, ) except ImportError: diff --git a/python/tests/adapters/test_fiddy.py b/python/tests/adapters/test_fiddy.py index 3b7177c018..df8daaaa9f 100644 --- a/python/tests/adapters/test_fiddy.py +++ b/python/tests/adapters/test_fiddy.py @@ -7,11 +7,11 @@ import amici.importers.petab.v1.simulations import numpy as np import pytest -from amici import SensitivityOrder, SteadyStateSensitivityMode from amici.adapters.fiddy import ( run_simulation_to_cached_functions, simulate_petab_to_cached_functions, ) +from amici.sim.sundials import SensitivityOrder, SteadyStateSensitivityMode from fiddy import MethodId, Type, get_derivative from fiddy.derivative_check import NumpyIsCloseDerivativeCheck from fiddy.success import Consistency diff --git a/python/tests/petab_/test_petab_v2.py b/python/tests/petab_/test_petab_v2.py index 31df89cb52..e3b0038d5d 100644 --- a/python/tests/petab_/test_petab_v2.py +++ b/python/tests/petab_/test_petab_v2.py @@ -1,12 +1,12 @@ import copy -import amici from amici.importers.petab import ( PetabImporter, flatten_timepoint_specific_output_overrides, has_timepoint_specific_overrides, unflatten_simulation_df, ) +from amici.sim.sundials import SensitivityOrder from petab.v2 import C, Problem from petab.v2.models.sbml_model import SbmlModel @@ -308,13 +308,13 @@ def test_petab_simulator_deepcopy_and_pickle(): pi = PetabImporter(problem) ps = pi.create_simulator(force_import=False) - ps.solver.set_sensitivity_order(amici.SensitivityOrder.none) + ps.solver.set_sensitivity_order(SensitivityOrder.none) ps_copy = copy.deepcopy(ps) assert ps.simulate({"kk": 2})["llh"] == ps_copy.simulate({"kk": 2})["llh"] - ps.solver.set_sensitivity_order(amici.SensitivityOrder.first) + ps.solver.set_sensitivity_order(SensitivityOrder.first) assert ( ps.solver.get_sensitivity_order() != ps_copy.solver.get_sensitivity_order() diff --git a/python/tests/splines_utils.py b/python/tests/splines_utils.py index b2c753b06e..26c209cdc5 100644 --- a/python/tests/splines_utils.py +++ b/python/tests/splines_utils.py @@ -17,7 +17,6 @@ import pandas as pd import petab.v1 as petab import sympy as sp -from amici.gradient_check import _check_results from amici.importers.petab.v1 import ( EDATAS, LLH, @@ -40,6 +39,8 @@ amici_time_symbol, create_sbml_model, ) +from amici.sim.sundials import run_simulation +from amici.sim.sundials.gradient_check import _check_results from amici.testing import TemporaryDirectoryWinSafe as TemporaryDirectory from petab.v1.models.sbml_model import SbmlModel @@ -304,7 +305,7 @@ def simulate_splines( use_adjoint: bool = False, skip_sensitivity: bool = False, petab_problem=None, - amici_model: amici.Model = None, + amici_model: amici.sim.sundials.Model = None, **kwargs, ): """ @@ -359,6 +360,8 @@ def simulate_splines( :param kwargs: passed to `create_petab_problem` """ + from amici.sim.sundials import SensitivityMethod, SensitivityOrder + # If no working directory is given, create a temporary one if folder is None: if keep_temporary: @@ -421,11 +424,11 @@ def simulate_splines( solver.set_absolute_tolerance(atol) solver.set_max_steps(maxsteps) if not skip_sensitivity: - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) if use_adjoint: - solver.set_sensitivity_method(amici.SensitivityMethod.adjoint) + solver.set_sensitivity_method(SensitivityMethod.adjoint) else: - solver.set_sensitivity_method(amici.SensitivityMethod.forward) + solver.set_sensitivity_method(SensitivityMethod.forward) # Compute and set timepoints # NB not working, will always be equal to the observation times @@ -740,7 +743,7 @@ def param_by_name(id): for plist in parameter_lists: amici_model.set_parameter_list(plist) amici_model.set_timepoints(rdata.t) - rdata_partial = amici.run_simulation(amici_model, amici_solver) + rdata_partial = run_simulation(amici_model, amici_solver) assert rdata.sx[:, plist, :].shape == rdata_partial.sx.shape assert np.allclose(rdata.sx[:, plist, :], rdata_partial.sx) diff --git a/python/tests/test_antimony_import.py b/python/tests/test_antimony_import.py index fbe95f1cb5..0a7356627e 100644 --- a/python/tests/test_antimony_import.py +++ b/python/tests/test_antimony_import.py @@ -1,4 +1,3 @@ -import amici import numpy as np from amici.importers.antimony import antimony2amici from amici.testing import skip_on_valgrind @@ -6,7 +5,11 @@ @skip_on_valgrind def test_antimony_example(tempdir): - """If this example requires changes, please also update documentation/python_interface.rst.""" + """If this example requires changes, + please also update documentation/python_interface.rst.""" + from amici import import_model_module + from amici.sim.sundials import AMICI_SUCCESS, run_simulation + ant_model = """ model lotka_volterra # see https://en.wikipedia.org/wiki/Lotka%E2%80%93Volterra_equations @@ -32,11 +35,11 @@ def test_antimony_example(tempdir): model_name=module_name, output_dir=tempdir, ) - model_module = amici.import_model_module( + model_module = import_model_module( module_name=module_name, module_path=tempdir ) amici_model = model_module.get_model() amici_model.set_timepoints(np.linspace(0, 100, 200)) amici_solver = amici_model.create_solver() - rdata = amici.run_simulation(amici_model, amici_solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(amici_model, amici_solver) + assert rdata.status == AMICI_SUCCESS diff --git a/python/tests/test_bngl.py b/python/tests/test_bngl.py index 0fe78a40f0..2925a47c4b 100644 --- a/python/tests/test_bngl.py +++ b/python/tests/test_bngl.py @@ -7,7 +7,9 @@ from contextlib import suppress +from amici import import_model_module from amici.importers.bngl import bngl2amici +from amici.sim.sundials import run_simulation from amici.testing import TemporaryDirectoryWinSafe, skip_on_valgrind from pysb.importers.bngl import model_from_bngl from pysb.simulator import ScipyOdeSimulator @@ -40,7 +42,6 @@ @skip_on_valgrind @pytest.mark.parametrize("example", tests) def test_compare_to_pysb_simulation(example): - import amici from amici.importers.utils import RESERVED_SYMBOLS, MeasurementChannel # allow "NULL" as model symbol @@ -95,7 +96,7 @@ def test_compare_to_pysb_simulation(example): else: bngl2amici(model_file, outdir, **kwargs) - amici_model_module = amici.import_model_module(pysb_model.name, outdir) + amici_model_module = import_model_module(pysb_model.name, outdir) model_amici = amici_model_module.get_model() @@ -105,7 +106,7 @@ def test_compare_to_pysb_simulation(example): solver.set_max_steps(10**6) solver.set_absolute_tolerance(atol) solver.set_relative_tolerance(rtol) - rdata = amici.run_simulation(model_amici, solver) + rdata = run_simulation(model_amici, solver) # check agreement of species simulation assert np.isclose(rdata.x, pysb_simres.species, 1e-4, 1e-4).all() diff --git a/python/tests/test_compare_conservation_laws_sbml.py b/python/tests/test_compare_conservation_laws_sbml.py index 1e726be60f..b92bfb6314 100644 --- a/python/tests/test_compare_conservation_laws_sbml.py +++ b/python/tests/test_compare_conservation_laws_sbml.py @@ -4,8 +4,19 @@ import amici import numpy as np import pytest -from amici import ExpData, SteadyStateStatus from amici import MeasurementChannel as MC +from amici.sim.sundials import ( + AMICI_ERROR, + AMICI_SUCCESS, + ExpData, + SensitivityMethod, + SteadyStateComputationMode, + SteadyStateSensitivityMode, + SteadyStateStatus, + get_model_settings, + run_simulation, + set_model_settings, +) from amici.testing import skip_on_valgrind from numpy.testing import assert_allclose @@ -124,10 +135,10 @@ def get_results( model, edata=None, sensi_order=0, - sensi_meth=amici.SensitivityMethod.forward, - sensi_meth_preeq=amici.SensitivityMethod.forward, - stst_mode=amici.SteadyStateComputationMode.integrateIfNewtonFails, - stst_sensi_mode=amici.SteadyStateSensitivityMode.newtonOnly, + sensi_meth=SensitivityMethod.forward, + sensi_meth_preeq=SensitivityMethod.forward, + stst_mode=SteadyStateComputationMode.integrateIfNewtonFails, + stst_sensi_mode=SteadyStateSensitivityMode.newtonOnly, reinitialize_states=False, ): # set model and data properties @@ -147,7 +158,7 @@ def get_results( edata.reinitialize_fixed_parameter_initial_states = reinitialize_states # return simulation results - return amici.run_simulation(model, solver, edata) + return run_simulation(model, solver, edata) @skip_on_valgrind @@ -167,9 +178,9 @@ def test_compare_conservation_laws_sbml(models, edata_fixture): # ----- compare simulations wo edata, sensi = 0, states ------------------ # run simulations rdata_cl = get_results(model_with_cl) - assert rdata_cl["status"] == amici.AMICI_SUCCESS + assert rdata_cl["status"] == AMICI_SUCCESS rdata = get_results(model_without_cl) - assert rdata["status"] == amici.AMICI_SUCCESS + assert rdata["status"] == AMICI_SUCCESS # compare state trajectories assert_allclose( @@ -183,9 +194,9 @@ def test_compare_conservation_laws_sbml(models, edata_fixture): # ----- compare simulations wo edata, sensi = 1, states and sensis ------- # run simulations rdata_cl = get_results(model_with_cl, sensi_order=1) - assert rdata_cl["status"] == amici.AMICI_SUCCESS + assert rdata_cl["status"] == AMICI_SUCCESS rdata = get_results(model_without_cl, sensi_order=1) - assert rdata["status"] == amici.AMICI_SUCCESS + assert rdata["status"] == AMICI_SUCCESS # compare state trajectories for field in ["x", "sx"]: @@ -202,9 +213,9 @@ def test_compare_conservation_laws_sbml(models, edata_fixture): # run simulations edata, _, _ = edata_fixture rdata_cl = get_results(model_with_cl, edata=edata) - assert rdata_cl["status"] == amici.AMICI_SUCCESS + assert rdata_cl["status"] == AMICI_SUCCESS rdata = get_results(model_without_cl, edata=edata) - assert rdata["status"] == amici.AMICI_SUCCESS + assert rdata["status"] == AMICI_SUCCESS # compare preequilibrated states for field in ["x", "x_ss", "llh"]: @@ -220,14 +231,14 @@ def test_compare_conservation_laws_sbml(models, edata_fixture): # run simulations rdata_cl = get_results(model_with_cl, edata=edata, sensi_order=1) - assert rdata_cl["status"] == amici.AMICI_SUCCESS + assert rdata_cl["status"] == AMICI_SUCCESS rdata = get_results( model_without_cl, edata=edata, sensi_order=1, - stst_sensi_mode=amici.SteadyStateSensitivityMode.integrateIfNewtonFails, + stst_sensi_mode=SteadyStateSensitivityMode.integrateIfNewtonFails, ) - assert rdata["status"] == amici.AMICI_SUCCESS + assert rdata["status"] == AMICI_SUCCESS # check that steady state computation succeeded only by sim in full model assert rdata["preeq_status"] == [ SteadyStateStatus.failed_factorization, @@ -254,12 +265,12 @@ def test_compare_conservation_laws_sbml(models, edata_fixture): # ----- check failure st.st. sensi computation if run wo CLs ------------- # check failure of steady state sensitivity computation if run wo CLs model_without_cl.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.newtonOnly + SteadyStateSensitivityMode.newtonOnly ) with warnings.catch_warnings(): warnings.filterwarnings("ignore") rdata = get_results(model_without_cl, edata=edata, sensi_order=1) - assert rdata["status"] == amici.AMICI_ERROR + assert rdata["status"] == AMICI_ERROR def test_adjoint_pre_and_post_equilibration(models, edata_fixture): @@ -275,8 +286,8 @@ def test_adjoint_pre_and_post_equilibration(models, edata_fixture): model_cl, edata=edata, sensi_order=1, - sensi_meth=amici.SensitivityMethod.forward, - sensi_meth_preeq=amici.SensitivityMethod.forward, + sensi_meth=SensitivityMethod.forward, + sensi_meth_preeq=SensitivityMethod.forward, reinitialize_states=reinit, ) # forward preequilibration, adjoint simulation @@ -284,8 +295,8 @@ def test_adjoint_pre_and_post_equilibration(models, edata_fixture): model_cl, edata=edata, sensi_order=1, - sensi_meth=amici.SensitivityMethod.adjoint, - sensi_meth_preeq=amici.SensitivityMethod.forward, + sensi_meth=SensitivityMethod.adjoint, + sensi_meth_preeq=SensitivityMethod.forward, reinitialize_states=reinit, ) # adjoint preequilibration, adjoint simulation @@ -293,14 +304,14 @@ def test_adjoint_pre_and_post_equilibration(models, edata_fixture): model_cl, edata=edata, sensi_order=1, - sensi_meth=amici.SensitivityMethod.adjoint, - sensi_meth_preeq=amici.SensitivityMethod.adjoint, + sensi_meth=SensitivityMethod.adjoint, + sensi_meth_preeq=SensitivityMethod.adjoint, reinitialize_states=reinit, ) - assert rff_cl.status == amici.AMICI_SUCCESS - assert rfa_cl.status == amici.AMICI_SUCCESS - assert raa_cl.status == amici.AMICI_SUCCESS + assert rff_cl.status == AMICI_SUCCESS + assert rfa_cl.status == AMICI_SUCCESS + assert raa_cl.status == AMICI_SUCCESS # assert all are close assert_allclose( @@ -319,12 +330,12 @@ def test_adjoint_pre_and_post_equilibration(models, edata_fixture): model, edata=edata, sensi_order=1, - sensi_meth=amici.SensitivityMethod.adjoint, - sensi_meth_preeq=amici.SensitivityMethod.adjoint, - stst_sensi_mode=amici.SteadyStateSensitivityMode.integrateIfNewtonFails, + sensi_meth=SensitivityMethod.adjoint, + sensi_meth_preeq=SensitivityMethod.adjoint, + stst_sensi_mode=SteadyStateSensitivityMode.integrateIfNewtonFails, reinitialize_states=reinit, ) - assert raa.status == amici.AMICI_SUCCESS + assert raa.status == AMICI_SUCCESS # assert gradients are close (quadrature tolerances are laxer) assert_allclose(raa_cl["sllh"], raa["sllh"], 1e-5, 1e-5) @@ -332,8 +343,8 @@ def test_adjoint_pre_and_post_equilibration(models, edata_fixture): @skip_on_valgrind def test_get_set_model_settings(models): - """test amici.(get|set)_model_settings cycles for models with and without + """test amici.sim.sundials.(get|set)_model_settings cycles for models with and without conservation laws""" for model in models: - amici.set_model_settings(model, amici.get_model_settings(model)) + set_model_settings(model, get_model_settings(model)) diff --git a/python/tests/test_edata.py b/python/tests/test_edata.py index e81fd0ebff..689eb6281b 100644 --- a/python/tests/test_edata.py +++ b/python/tests/test_edata.py @@ -1,8 +1,14 @@ """Tests related to amici.ExpData via Python""" -import amici import numpy as np import pytest +from amici.sim.sundials import ( + ExpData, + ParameterScaling, + SensitivityOrder, + parameter_scaling_from_int_vector, + run_simulation, +) from amici.testing import skip_on_valgrind @@ -18,10 +24,8 @@ def test_edata_sensi_unscaling(model_units_module): # noqa: F811 sx0 = (3, 3, 3, 3) - parameter_scales_log10 = [amici.ParameterScaling.log10.value] * len( - parameters0 - ) - amici_parameter_scales_log10 = amici.parameter_scaling_from_int_vector( + parameter_scales_log10 = [ParameterScaling.log10.value] * len(parameters0) + amici_parameter_scales_log10 = parameter_scaling_from_int_vector( parameter_scales_log10 ) @@ -31,20 +35,20 @@ def test_edata_sensi_unscaling(model_units_module): # noqa: F811 model.set_free_parameters(parameters0) solver = model.create_solver() - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) - edata0 = amici.ExpData(model) + edata0 = ExpData(model) edata0.pscale = amici_parameter_scales_log10 edata0.free_parameters = parameters0 edata0.sx0 = sx0 - edata1 = amici.ExpData(model) + edata1 = ExpData(model) edata1.pscale = amici_parameter_scales_log10 edata1.free_parameters = parameters1 edata1.sx0 = sx0 - rdata0 = amici.run_simulation(model, solver, edata0) - rdata1 = amici.run_simulation(model, solver, edata1) + rdata0 = run_simulation(model, solver, edata0) + rdata1 = run_simulation(model, solver, edata1) # The initial state sensitivities are as specified. assert np.isclose(rdata0.sx0.flatten(), sx0).all() diff --git a/python/tests/test_events.py b/python/tests/test_events.py index 655613d4f9..12650968ae 100644 --- a/python/tests/test_events.py +++ b/python/tests/test_events.py @@ -2,19 +2,25 @@ from copy import deepcopy -import amici import numpy as np import pytest from amici import ( MeasurementChannel as MC, ) from amici import ( - SensitivityMethod, - SensitivityOrder, import_model_module, ) -from amici.gradient_check import check_derivatives from amici.importers.antimony import antimony2amici +from amici.sim.sundials import ( + AMICI_SUCCESS, + ExpData, + SensitivityMethod, + SensitivityOrder, + SteadyStateComputationMode, + SteadyStateSensitivityMode, + run_simulation, +) +from amici.sim.sundials.gradient_check import check_derivatives from amici.testing import skip_on_valgrind from amici.testing.models import create_amici_model, create_sbml_model from numpy.testing import assert_allclose @@ -773,8 +779,8 @@ def test_handling_of_fixed_time_point_event_triggers(tempdir): amici_model.set_timepoints(np.linspace(0, 10, 20)) amici_solver = amici_model.create_solver() - rdata = amici.run_simulation(amici_model, amici_solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(amici_model, amici_solver) + assert rdata.status == AMICI_SUCCESS assert (rdata.x[rdata.ts < 1] == 0).all() assert (rdata.x[(rdata.ts >= 1) & (rdata.ts < 2)] == 1).all() assert (rdata.x[(rdata.ts >= 2) & (rdata.ts < 3)] == 2).all() @@ -783,7 +789,7 @@ def test_handling_of_fixed_time_point_event_triggers(tempdir): assert (rdata.x[(rdata.ts >= 5)] == 5).all() assert rdata.x[-1, :] == 5 - edata = amici.ExpData(rdata, 1, 0, 0) + edata = ExpData(rdata, 1, 0, 0) for sens_meth in ( SensitivityMethod.forward, @@ -825,8 +831,8 @@ def test_multiple_event_assignment_with_compartment(tempdir): assert amici_model.nx_rdata == 3 amici_model.set_timepoints(np.linspace(0, 15, 16)) amici_solver = amici_model.create_solver() - rdata = amici.run_simulation(amici_model, amici_solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(amici_model, amici_solver) + assert rdata.status == AMICI_SUCCESS idx_event_target = amici_model.get_state_ids().index("event_target") idx_unrelated = amici_model.get_state_ids().index("unrelated") idx_species_in_event_target = amici_model.get_state_ids().index( @@ -924,14 +930,14 @@ def test_event_priorities(tempdir): solver.set_sensitivity_order(SensitivityOrder.first) solver.set_sensitivity_method(SensitivityMethod.forward) - rdata = amici.run_simulation(model, solver) + rdata = run_simulation(model, solver) assert np.all(rdata.by_id("target1") == [1, 11, 11]) assert np.all(rdata.by_id("target2") == [2, 22, 22]) assert_allclose(rdata.by_id("target3"), [3, 33 + 1e-6, 33 + 1]) # generate synthetic measurements - edata = amici.ExpData(rdata, 1, 0) + edata = ExpData(rdata, 1, 0) # check forward sensitivities against finite differences # FIXME: sensitivities w.r.t. the bolus parameter are not correct @@ -1014,7 +1020,7 @@ def test_random_event_ordering(tempdir): outcomes = [] N = 1000 for i in range(N): - rdata = amici.run_simulation(model, solver) + rdata = run_simulation(model, solver) assert np.all(rdata.by_id("target_first") == [0, 2, 2]) assert np.all(rdata.by_id("target_last") == [0, 1, 1]) traj = rdata.by_id("target_rnd") @@ -1071,12 +1077,12 @@ def test_event_uses_values_from_trigger_time(tempdir): solver.set_sensitivity_order(SensitivityOrder.first) solver.set_sensitivity_method(SensitivityMethod.forward) - rdata = amici.run_simulation(model, solver) + rdata = run_simulation(model, solver) assert np.all(rdata.by_id("target1") == [2, 2, 2]) assert np.all(rdata.by_id("target2") == [0, 3, 3]) # generate synthetic measurements - edata = amici.ExpData(rdata, 1, 0) + edata = ExpData(rdata, 1, 0) # check sensitivities against finite differences @@ -1146,27 +1152,27 @@ def test_posteq_events_are_handled(tempdir): # test without post-equilibration model.set_timepoints([10]) - rdata = amici.run_simulation(model, solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(model, solver) + assert rdata.status == AMICI_SUCCESS assert rdata.by_id("target").squeeze() == 2.0 assert rdata.by_id("obs_target").squeeze() == 2.0 # test with post-equilibration model.set_steady_state_computation_mode( - amici.SteadyStateComputationMode.integrationOnly + SteadyStateComputationMode.integrationOnly ) model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrationOnly + SteadyStateSensitivityMode.integrationOnly ) model.set_timepoints([np.inf]) - rdata = amici.run_simulation(model, solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(model, solver) + assert rdata.status == AMICI_SUCCESS assert rdata.by_id("target").squeeze() == 2.0 assert rdata.by_id("obs_target").squeeze() == 2.0 assert rdata.posteq_t == 10.0 # check sensitivities against finite differences - edata = amici.ExpData(rdata, 1, 0, 0) + edata = ExpData(rdata, 1, 0, 0) for sens_method in ( SensitivityMethod.forward, SensitivityMethod.adjoint, @@ -1222,21 +1228,21 @@ def test_preeq_presim_preserve_heaviside_state(tempdir): model = model_module.get_model() model.set_timepoints(np.linspace(0, 2, 3)) model.set_steady_state_computation_mode( - amici.SteadyStateComputationMode.integrationOnly + SteadyStateComputationMode.integrationOnly ) solver = model.create_solver() # Only main simulation. E1 triggers, E2 does not. - rdata = amici.run_simulation(model, solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(model, solver) + assert rdata.status == AMICI_SUCCESS assert list(rdata.by_id("target1")) == [1.0, 1.0, 1.0] assert list(rdata.by_id("target2")) == [0.0, 0.0, 0.0] # Pre-equilibration + main simulation. Both E1 and E2 trigger. - edata = amici.ExpData(rdata, 1, 0, 0) + edata = ExpData(rdata, 1, 0, 0) edata.fixed_parameters_pre_equilibration = [1] - rdata = amici.run_simulation(model, solver, edata=edata) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(model, solver, edata=edata) + assert rdata.status == AMICI_SUCCESS assert list(rdata.by_id("target1")) == [1.0, 1.0, 1.0] assert list(rdata.by_id("target2")) == [1.0, 1.0, 1.0] @@ -1244,22 +1250,22 @@ def test_preeq_presim_preserve_heaviside_state(tempdir): # FIXME: this is currently not supported # (root-after-reinitialization when switching from pre-simulation# # to main simulation) - # edata = amici.ExpData(rdata, 1, 0, 0) + # edata = ExpData(rdata, 1, 0, 0) # edata.fixedParametersPresimulation = [1] # edata.t_presim = 10 - # rdata = amici.runAmiciSimulation(model, solver, edata=edata) - # assert rdata.status == amici.AMICI_SUCCESS + # rdata = runAmiciSimulation(model, solver, edata=edata) + # assert rdata.status == AMICI_SUCCESS # assert list(rdata.by_id("target1")) == [1.0, 1.0, 1.0] # assert list(rdata.by_id("target2")) == [1.0, 1.0, 1.0] # Pre-equilibration + pre-simulation + main simulation. # Both E1 and E2 trigger. - edata = amici.ExpData(rdata, 1, 0, 0) + edata = ExpData(rdata, 1, 0, 0) edata.fixed_parameters_pre_equilibration = [1] edata.fixed_parameters_presimulation = [1] edata.t_presim = 10 - rdata = amici.run_simulation(model, solver, edata=edata) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(model, solver, edata=edata) + assert rdata.status == AMICI_SUCCESS assert list(rdata.by_id("target1")) == [1.0, 1.0, 1.0] assert list(rdata.by_id("target2")) == [1.0, 1.0, 1.0] @@ -1291,8 +1297,8 @@ def test_gh2926(tempdir): model.set_timepoints([0, 5, 10.1, 11]) solver = model.create_solver() - rdata = amici.run_simulation(model, solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(model, solver) + assert rdata.status == AMICI_SUCCESS assert rdata.by_id("x1").tolist() == [1.0, 1.0, 2.0, 2.0] @@ -1329,11 +1335,11 @@ def test_event_with_w_dependent_trigger(tempdir): solver.set_relative_tolerance(1e-14) # generate synthetic measurements - rdata = amici.run_simulation(model, solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(model, solver) + assert rdata.status == AMICI_SUCCESS # check that event triggered correctly assert np.isclose(rdata.by_id("target")[-1], 11.0) - edata = amici.ExpData(rdata, 1, 0) + edata = ExpData(rdata, 1.0, 0.0, 42) # check sensitivities against finite differences diff --git a/python/tests/test_hdf5.py b/python/tests/test_hdf5.py index d4e860d176..317a3511b5 100644 --- a/python/tests/test_hdf5.py +++ b/python/tests/test_hdf5.py @@ -5,6 +5,7 @@ import amici import pytest +from amici.sim.sundials import RDataReporting def _modify_solver_attrs(solver): @@ -20,7 +21,7 @@ def _modify_solver_attrs(solver): elif attr == "set_stability_limit_flag": cval = 0 elif attr == "set_return_data_reporting_mode": - cval = amici.RDataReporting.likelihood + cval = RDataReporting.likelihood elif attr == "set_max_time": # default value is the maximum, must not add to that cval = random.random() @@ -35,10 +36,15 @@ def _modify_solver_attrs(solver): @pytest.mark.skipif( - not amici.hdf5_enabled, reason="AMICI was compiled without HDF5" + not amici.sim.sundials.hdf5_enabled, + reason="AMICI was compiled without HDF5", ) def test_solver_hdf5_roundtrip(sbml_example_presimulation_module): """TestCase class for AMICI HDF5 I/O""" + from amici.sim.sundials import ( + read_solver_settings_from_hdf5, + write_solver_settings_to_hdf5, + ) model = sbml_example_presimulation_module.get_model() solver = model.create_solver() @@ -46,7 +52,7 @@ def test_solver_hdf5_roundtrip(sbml_example_presimulation_module): hdf5file = "solverSettings.hdf5" - amici.write_solver_settings_to_hdf5(solver, hdf5file, "ssettings") + write_solver_settings_to_hdf5(solver, hdf5file, "ssettings") new_solver = model.create_solver() @@ -60,7 +66,7 @@ def test_solver_hdf5_roundtrip(sbml_example_presimulation_module): != getattr(new_solver, attr.replace("set", "get"))() ), attr - amici.read_solver_settings_from_hdf5(hdf5file, new_solver, "ssettings") + read_solver_settings_from_hdf5(hdf5file, new_solver, "ssettings") # check that reading in settings worked for attr in dir(solver): diff --git a/python/tests/test_jax.py b/python/tests/test_jax.py index 3f7a517e35..a74a3c0865 100644 --- a/python/tests/test_jax.py +++ b/python/tests/test_jax.py @@ -12,9 +12,15 @@ import numpy as np import optimistix from amici import MeasurementChannel as MC +from amici import import_model_module from amici.importers.petab.v1 import import_petab_problem from amici.importers.pysb import pysb2amici, pysb2jax from amici.jax import JAXProblem, ReturnValue, run_simulations +from amici.sim.sundials import ( + ExpData, + SensitivityMethod, + SensitivityOrder, +) from amici.testing import TemporaryDirectoryWinSafe, skip_on_valgrind from beartype import beartype from numpy.testing import assert_allclose @@ -45,10 +51,10 @@ def test_conversion(): pysb2amici(model, outdir, verbose=True, observation_model=[MC("ab")]) pysb2jax(model, outdir, verbose=True, observation_model=[MC("ab")]) - amici_module = amici.import_model_module( + amici_module = import_model_module( module_name=model.name, module_path=outdir ) - jax_module = amici.import_model_module( + jax_module = import_model_module( module_name=Path(outdir).stem, module_path=Path(outdir).parent ) @@ -106,10 +112,10 @@ def test_dimerization(): observation_model=[MC("a_obs"), MC("b_obs")], ) - amici_module = amici.import_model_module( + amici_module = import_model_module( module_name=model.name, module_path=outdir ) - jax_module = amici.import_model_module( + jax_module = import_model_module( module_name=Path(outdir).stem, module_path=Path(outdir).parent ) @@ -123,24 +129,22 @@ def _test_model(amici_module, jax_module, ts, p, k): amici_model = amici_module.get_model() amici_model.set_timepoints(np.asarray(ts, dtype=np.float64)) - sol_amici_ref = amici.run_simulation( - amici_model, amici_model.create_solver() - ) + sol_amici_ref = amici_model.simulate() jax_model = jax_module.Model() amici_model.set_free_parameters(np.asarray(p, dtype=np.float64)) amici_model.set_fixed_parameters(np.asarray(k, dtype=np.float64)) - edata = amici.ExpData(sol_amici_ref, 1.0, 1.0) + edata = ExpData(sol_amici_ref, 1.0, 1.0) edata.free_parameters = amici_model.get_free_parameters() edata.fixed_parameters = amici_model.get_fixed_parameters() edata.pscale = amici_model.get_parameter_scale() amici_solver = amici_model.create_solver() - amici_solver.set_sensitivity_method(amici.SensitivityMethod.forward) - amici_solver.set_sensitivity_order(amici.SensitivityOrder.first) + amici_solver.set_sensitivity_method(SensitivityMethod.forward) + amici_solver.set_sensitivity_order(SensitivityOrder.first) amici_solver.set_absolute_tolerance(ATOL_SIM) amici_solver.set_relative_tolerance(RTOL_SIM) - rs_amici = amici.run_simulations(amici_model, amici_solver, [edata]) + rs_amici = amici_model.simulate(solver=amici_solver, edata=[edata]) check_fields_jax( rs_amici, @@ -158,7 +162,7 @@ def _test_model(amici_module, jax_module, ts, p, k): amici_model.get_fixed_parameter_ids(), edata, ["sllh", "sx0", "sx", "sres", "sy"], - sensi_order=amici.SensitivityOrder.first, + sensi_order=SensitivityOrder.first, ) @@ -169,7 +173,7 @@ def check_fields_jax( fixed_parameter_ids, edata, fields, - sensi_order=amici.SensitivityOrder.none, + sensi_order=SensitivityOrder.none, ): r_jax = dict() ts = np.array(edata.get_timepoints()) @@ -216,9 +220,9 @@ def check_fields_jax( "max_steps": 2**8, "ret": ReturnValue[output], } - if sensi_order == amici.SensitivityOrder.none: + if sensi_order == SensitivityOrder.none: r_jax[output] = fun(p, **okwargs)[0] - if sensi_order == amici.SensitivityOrder.first: + if sensi_order == SensitivityOrder.first: if output == "llh": r_jax[f"s{output}"] = jax.grad(fun, has_aux=True)(p, **kwargs)[ 0 diff --git a/python/tests/test_misc.py b/python/tests/test_misc.py index 83aa6a5d4b..31ab6df61b 100644 --- a/python/tests/test_misc.py +++ b/python/tests/test_misc.py @@ -8,23 +8,27 @@ import pytest import sympy as sp from amici.importers.utils import smart_subs_dict +from amici.sim.sundials import ( + ParameterScaling, + parameter_scaling_from_int_vector, +) from amici.testing import skip_on_valgrind def test_parameter_scaling_from_int_vector(): """Ensure we can generate a ParameterScaling vector from Python""" - scale_vector = amici.parameter_scaling_from_int_vector( + scale_vector = parameter_scaling_from_int_vector( [ - amici.ParameterScaling.log10, - amici.ParameterScaling.ln, - amici.ParameterScaling.none, + ParameterScaling.log10, + ParameterScaling.ln, + ParameterScaling.none, ] ) - assert scale_vector[0] == amici.ParameterScaling.log10 - assert scale_vector[1] == amici.ParameterScaling.ln - assert scale_vector[2] == amici.ParameterScaling.none + assert scale_vector[0] == ParameterScaling.log10 + assert scale_vector[1] == ParameterScaling.ln + assert scale_vector[2] == ParameterScaling.none @skip_on_valgrind diff --git a/python/tests/test_pandas.py b/python/tests/test_pandas.py index a727dc0706..7cc9d2667c 100644 --- a/python/tests/test_pandas.py +++ b/python/tests/test_pandas.py @@ -2,9 +2,14 @@ import itertools -import amici import numpy as np import pytest +from amici.sim.sundials import ( + ExpData, + get_data_observables_as_data_frame, + get_edata_from_data_frame, + run_simulation, +) from amici.testing import skip_on_valgrind # test parameters for test_pandas_import_export @@ -28,17 +33,17 @@ def test_pandas_import_export(sbml_example_presimulation_module, case): model = sbml_example_presimulation_module.get_model() model.set_timepoints(np.linspace(0, 60, 61)) solver = model.create_solver() - rdata = amici.run_simulation(model, solver) - edata = [amici.ExpData(rdata, 0.01, 0)] + rdata = run_simulation(model, solver) + edata = [ExpData(rdata, 0.01, 0)] # test copy constructor - _ = amici.ExpData(edata[0]) + _ = ExpData(edata[0]) for fp in case: setattr(edata[0], fp, case[fp]) - df_edata = amici.get_data_observables_as_data_frame(model, edata) - edata_reconstructed = amici.get_edata_from_data_frame(model, df_edata) + df_edata = get_data_observables_as_data_frame(model, edata) + edata_reconstructed = get_edata_from_data_frame(model, df_edata) for fp in [ "fixed_parameters", diff --git a/python/tests/test_petab_objective.py b/python/tests/test_petab_objective.py index b41d741975..58299e7897 100755 --- a/python/tests/test_petab_objective.py +++ b/python/tests/test_petab_objective.py @@ -3,12 +3,12 @@ from functools import partial from pathlib import Path -import amici import numpy as np import pandas as pd import petab.v1 as petab import pytest from amici.importers.petab.v1 import SLLH, import_petab_problem, simulate_petab +from amici.sim.sundials import SensitivityOrder from amici.testing import skip_on_valgrind # Absolute and relative tolerances for finite difference gradient checks. @@ -35,7 +35,7 @@ def test_simulate_petab_sensitivities(lotka_volterra): amici_model = import_petab_problem(petab_problem) amici_solver = amici_model.create_solver() - amici_solver.set_sensitivity_order(amici.SensitivityOrder.first) + amici_solver.set_sensitivity_order(SensitivityOrder.first) amici_solver.set_max_steps(int(1e5)) problem_parameters = dict( diff --git a/python/tests/test_preequilibration.py b/python/tests/test_preequilibration.py index a8ae783365..71b1ba35d3 100644 --- a/python/tests/test_preequilibration.py +++ b/python/tests/test_preequilibration.py @@ -5,9 +5,23 @@ import amici import numpy as np import pytest -from amici import SensitivityMethod, SensitivityOrder, SteadyStateStatus from amici.debugging import get_model_for_preeq -from amici.gradient_check import check_derivatives +from amici.sim.sundials import ( + AMICI_ERROR, + AMICI_SUCCESS, + ExpData, + LogSeverity, + LogSeverity_debug, + ParameterScaling, + SensitivityMethod, + SensitivityOrder, + SteadyStateComputationMode, + SteadyStateSensitivityMode, + SteadyStateStatus, + parameter_scaling_from_int_vector, + run_simulation, +) +from amici.sim.sundials.gradient_check import check_derivatives from amici.testing import ( TemporaryDirectoryWinSafe as TemporaryDirectory, ) @@ -29,14 +43,14 @@ def preeq_fixture(pysb_example_presimulation_module): model = pysb_example_presimulation_module.get_model() model.set_reinitialize_fixed_parameter_initial_states(True) model.set_steady_state_computation_mode( - amici.SteadyStateComputationMode.integrateIfNewtonFails + SteadyStateComputationMode.integrateIfNewtonFails ) model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrateIfNewtonFails + SteadyStateSensitivityMode.integrateIfNewtonFails ) solver = model.create_solver() - solver.set_sensitivity_order(amici.SensitivityOrder.first) - solver.set_sensitivity_method(amici.SensitivityMethod.forward) + solver.set_sensitivity_order(SensitivityOrder.first) + solver.set_sensitivity_method(SensitivityMethod.forward) edata = get_data(model) edata.t_presim = 2 @@ -45,21 +59,21 @@ def preeq_fixture(pysb_example_presimulation_module): edata.fixed_parameters_pre_equilibration = [3, 0] edata.set_timepoints([1, 5]) - edata_preeq = amici.ExpData(edata) + edata_preeq = ExpData(edata) edata_preeq.t_presim = 0 edata_preeq.set_timepoints([np.inf]) edata_preeq.fixed_parameters = edata.fixed_parameters_pre_equilibration edata_preeq.fixed_parameters_presimulation = () edata_preeq.fixed_parameters_pre_equilibration = () - edata_presim = amici.ExpData(edata) + edata_presim = ExpData(edata) edata_presim.t_presim = 0 edata_presim.set_timepoints([edata.t_presim]) edata_presim.fixed_parameters = edata.fixed_parameters_presimulation edata_presim.fixed_parameters_presimulation = () edata_presim.fixed_parameters_pre_equilibration = () - edata_sim = amici.ExpData(edata) + edata_sim = ExpData(edata) edata_sim.t_presim = 0 edata_sim.set_timepoints(edata.get_timepoints()) edata_sim.fixed_parameters = edata.fixed_parameters @@ -67,17 +81,17 @@ def preeq_fixture(pysb_example_presimulation_module): edata_sim.fixed_parameters_pre_equilibration = () pscales = [ - amici.ParameterScaling.log10, - amici.ParameterScaling.ln, - amici.ParameterScaling.none, - amici.parameter_scaling_from_int_vector( + ParameterScaling.log10, + ParameterScaling.ln, + ParameterScaling.none, + parameter_scaling_from_int_vector( [ - amici.ParameterScaling.log10, - amici.ParameterScaling.ln, - amici.ParameterScaling.none, - amici.ParameterScaling.log10, - amici.ParameterScaling.ln, - amici.ParameterScaling.none, + ParameterScaling.log10, + ParameterScaling.ln, + ParameterScaling.none, + ParameterScaling.log10, + ParameterScaling.ln, + ParameterScaling.none, ] ), ] @@ -125,12 +139,12 @@ def test_manual_preequilibration(preeq_fixture): model.set_parameter_scale(pscale) # combined - rdata_auto = amici.run_simulation(model, solver, edata) - assert rdata_auto.status == amici.AMICI_SUCCESS + rdata_auto = run_simulation(model, solver, edata) + assert rdata_auto.status == AMICI_SUCCESS # manual preequilibration - rdata_preeq = amici.run_simulation(model, solver, edata_preeq) - assert rdata_preeq.status == amici.AMICI_SUCCESS + rdata_preeq = run_simulation(model, solver, edata_preeq) + assert rdata_preeq.status == AMICI_SUCCESS # manual reinitialization + presimulation x0 = rdata_preeq["x"][0, :] @@ -141,8 +155,8 @@ def test_manual_preequilibration(preeq_fixture): sx0[:, 2] = 0 model.set_initial_state(x0) model.set_initial_state_sensitivities(sx0.flatten()) - rdata_presim = amici.run_simulation(model, solver, edata_presim) - assert rdata_presim.status == amici.AMICI_SUCCESS + rdata_presim = run_simulation(model, solver, edata_presim) + assert rdata_presim.status == AMICI_SUCCESS # manual reinitialization + simulation x0 = rdata_presim["x"][0, :] @@ -153,8 +167,8 @@ def test_manual_preequilibration(preeq_fixture): sx0[:, 2] = 0 model.set_initial_state(x0) model.set_initial_state_sensitivities(sx0.flatten()) - rdata_sim = amici.run_simulation(model, solver, edata_sim) - assert rdata_sim.status == amici.AMICI_SUCCESS + rdata_sim = run_simulation(model, solver, edata_sim) + assert rdata_sim.status == AMICI_SUCCESS for variable in ["x", "sx"]: assert_allclose( @@ -182,11 +196,11 @@ def test_parameter_reordering(preeq_fixture): plists, ) = preeq_fixture - rdata_ordered = amici.run_simulation(model, solver, edata) + rdata_ordered = run_simulation(model, solver, edata) for plist in plists: model.set_parameter_list(plist) - rdata_reordered = amici.run_simulation(model, solver, edata) + rdata_reordered = run_simulation(model, solver, edata) for ip, p_index in enumerate(plist): assert_allclose( @@ -212,7 +226,7 @@ def test_data_replicates(preeq_fixture): plists, ) = preeq_fixture - sensi_meth = amici.SensitivityMethod.forward + sensi_meth = SensitivityMethod.forward solver.set_sensitivity_method(sensi_meth) # add infty timepoint @@ -222,7 +236,7 @@ def test_data_replicates(preeq_fixture): edata.set_timepoints(sorted(ts)) edata.set_observed_data(np.hstack([y, y[0]])) edata.set_observed_data_std_dev(np.hstack([stdy, stdy[0]])) - rdata_single = amici.run_simulation(model, solver, edata) + rdata_single = run_simulation(model, solver, edata) # duplicate data and timepoints y = edata.get_observed_data() @@ -233,7 +247,7 @@ def test_data_replicates(preeq_fixture): edata.set_observed_data(np.hstack([y, y])[idx]) edata.set_observed_data_std_dev(np.hstack([stdy, stdy])[idx]) - rdata_double = amici.run_simulation(model, solver, edata) + rdata_double = run_simulation(model, solver, edata) for variable in ["llh", "sllh"]: assert_allclose( @@ -259,7 +273,7 @@ def test_parameter_in_expdata(preeq_fixture): plists, ) = preeq_fixture - rdata = amici.run_simulation(model, solver, edata) + rdata = run_simulation(model, solver, edata) # get initial states will compute initial states if nothing is set, # this needs go first as we need unmodified model. Also set to @@ -290,17 +304,17 @@ def test_parameter_in_expdata(preeq_fixture): # perturb model pscale, needs to be done after getting parameters, # otherwise we will mess up parameter value model.set_parameter_scale( - amici.parameter_scaling_from_int_vector( + parameter_scaling_from_int_vector( [ - amici.ParameterScaling.log10 - if scaling == amici.ParameterScaling.none - else amici.ParameterScaling.none + ParameterScaling.log10 + if scaling == ParameterScaling.none + else ParameterScaling.none for scaling in model.get_parameter_scale() ] ) ) - rdata_edata = amici.run_simulation(model, solver, edata) + rdata_edata = run_simulation(model, solver, edata) for variable in ["x", "sx"]: assert_allclose( rdata[variable][0, :], @@ -340,13 +354,13 @@ def test_equilibration_methods_with_adjoints(preeq_fixture): rdatas = {} equil_meths = [ - amici.SteadyStateSensitivityMode.newtonOnly, - amici.SteadyStateSensitivityMode.integrationOnly, - amici.SteadyStateSensitivityMode.integrateIfNewtonFails, + SteadyStateSensitivityMode.newtonOnly, + SteadyStateSensitivityMode.integrationOnly, + SteadyStateSensitivityMode.integrateIfNewtonFails, ] sensi_meths = [ - amici.SensitivityMethod.forward, - amici.SensitivityMethod.adjoint, + SensitivityMethod.forward, + SensitivityMethod.adjoint, ] settings = itertools.product(equil_meths, sensi_meths) @@ -358,10 +372,10 @@ def test_equilibration_methods_with_adjoints(preeq_fixture): solver.set_newton_max_steps(0) # add rdatas - rdatas[setting] = amici.run_simulation(model, solver, edata) + rdatas[setting] = run_simulation(model, solver, edata) # assert successful simulation - assert rdatas[setting]["status"] == amici.AMICI_SUCCESS + assert rdatas[setting]["status"] == AMICI_SUCCESS for setting1, setting2 in itertools.product(settings, settings): # assert correctness of result @@ -407,8 +421,8 @@ def test_newton_solver_equilibration(preeq_fixture): rdatas = {} settings = [ - amici.SteadyStateSensitivityMode.integrationOnly, - amici.SteadyStateSensitivityMode.newtonOnly, + SteadyStateSensitivityMode.integrationOnly, + SteadyStateSensitivityMode.newtonOnly, ] solver.set_newton_step_steady_state_check(True) @@ -416,17 +430,17 @@ def test_newton_solver_equilibration(preeq_fixture): for equil_meth in settings: # set sensi method - sensi_meth = amici.SensitivityMethod.forward + sensi_meth = SensitivityMethod.forward solver.set_sensitivity_method(sensi_meth) model.set_steady_state_sensitivity_mode(equil_meth) - if equil_meth == amici.SteadyStateSensitivityMode.newtonOnly: + if equil_meth == SteadyStateSensitivityMode.newtonOnly: solver.set_newton_max_steps(10) # add rdatas - rdatas[equil_meth] = amici.run_simulation(model, solver, edata) + rdatas[equil_meth] = run_simulation(model, solver, edata) # assert successful simulation - assert rdatas[equil_meth]["status"] == amici.AMICI_SUCCESS + assert rdatas[equil_meth]["status"] == AMICI_SUCCESS # assert correct results for variable in ["llh", "sllh", "sx0", "sx_ss", "x_ss"]: @@ -466,7 +480,7 @@ def test_newton_steadystate_check(preeq_fixture): edata.set_observed_data_std_dev(np.hstack([stdy, stdy[0]])) # set sensi method - sensi_meth = amici.SensitivityMethod.forward + sensi_meth = SensitivityMethod.forward solver.set_sensitivity_method(sensi_meth) solver.set_newton_max_steps(100) @@ -476,10 +490,10 @@ def test_newton_steadystate_check(preeq_fixture): solver.set_newton_step_steady_state_check(newton_check) # add rdatas - rdatas[newton_check] = amici.run_simulation(model, solver, edata) + rdatas[newton_check] = run_simulation(model, solver, edata) # assert successful simulation - assert rdatas[newton_check]["status"] == amici.AMICI_SUCCESS + assert rdatas[newton_check]["status"] == AMICI_SUCCESS # assert correct results for variable in ["x_ss", "llh", "sx0", "sx_ss", "sllh"]: @@ -505,23 +519,23 @@ def test_steadystate_computation_mode(preeq_fixture): plists, ) = preeq_fixture - sensi_meth = amici.SensitivityMethod.forward - solver.set_sensitivity_order(amici.SensitivityOrder.first) + sensi_meth = SensitivityMethod.forward + solver.set_sensitivity_order(SensitivityOrder.first) solver.set_sensitivity_method_pre_equilibration(sensi_meth) solver.set_newton_max_steps(10) rdatas = {} stst_computation_modes = [ - amici.SteadyStateComputationMode.integrationOnly, - amici.SteadyStateComputationMode.newtonOnly, + SteadyStateComputationMode.integrationOnly, + SteadyStateComputationMode.newtonOnly, ] for mode in stst_computation_modes: model.set_steady_state_computation_mode(mode) - rdatas[mode] = amici.run_simulation(model, solver, edata) + rdatas[mode] = run_simulation(model, solver, edata) # assert successful simulation - assert rdatas[mode]["status"] == amici.AMICI_SUCCESS - assert rdatas[amici.SteadyStateComputationMode.integrationOnly][ + assert rdatas[mode]["status"] == AMICI_SUCCESS + assert rdatas[SteadyStateComputationMode.integrationOnly][ "preeq_status" ] == [ SteadyStateStatus.not_run, @@ -530,24 +544,17 @@ def test_steadystate_computation_mode(preeq_fixture): ] assert ( - rdatas[amici.SteadyStateComputationMode.integrationOnly][ - "preeq_numsteps" - ][0] + rdatas[SteadyStateComputationMode.integrationOnly]["preeq_numsteps"][0] == 0 ) - assert rdatas[amici.SteadyStateComputationMode.newtonOnly][ - "preeq_status" - ] == [ + assert rdatas[SteadyStateComputationMode.newtonOnly]["preeq_status"] == [ SteadyStateStatus.success, SteadyStateStatus.not_run, SteadyStateStatus.not_run, ] assert ( - rdatas[amici.SteadyStateComputationMode.newtonOnly]["preeq_numsteps"][ - 0 - ] - > 0 + rdatas[SteadyStateComputationMode.newtonOnly]["preeq_numsteps"][0] > 0 ) # assert correct results @@ -573,27 +580,25 @@ def test_simulation_errors(preeq_fixture): plists, ) = preeq_fixture - solver.set_sensitivity_order(amici.SensitivityOrder.first) - solver.set_sensitivity_method_pre_equilibration( - amici.SensitivityMethod.forward - ) + solver.set_sensitivity_order(SensitivityOrder.first) + solver.set_sensitivity_method_pre_equilibration(SensitivityMethod.forward) model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrationOnly + SteadyStateSensitivityMode.integrationOnly ) solver.set_max_steps(1) # exceeded maxsteps # preeq & posteq for e in [edata, edata_preeq]: - rdata = amici.run_simulation(model, solver, e) - assert rdata["status"] != amici.AMICI_SUCCESS - assert rdata._swigptr.messages[0].severity == amici.LogSeverity_debug + rdata = run_simulation(model, solver, e) + assert rdata["status"] != AMICI_SUCCESS + assert rdata._swigptr.messages[0].severity == LogSeverity_debug assert rdata._swigptr.messages[0].identifier == "EQUILIBRATION_FAILURE" assert ( "exceeded maximum number of integration steps" in rdata._swigptr.messages[0].message ) - assert rdata._swigptr.messages[1].severity == amici.LogSeverity_error + assert rdata._swigptr.messages[1].severity == LogSeverity.error assert rdata._swigptr.messages[1].identifier == "OTHER" # too long simulations @@ -602,19 +607,19 @@ def test_simulation_errors(preeq_fixture): solver.set_absolute_tolerance_steady_state(0.0) # preeq & posteq for e in [edata_preeq, edata]: - rdata = amici.run_simulation(model, solver, e) - assert rdata["status"] != amici.AMICI_SUCCESS + rdata = run_simulation(model, solver, e) + assert rdata["status"] != AMICI_SUCCESS messages = [] # remove repeated RHSFUNC_FAIL messages for message in rdata._swigptr.messages: if not messages or message.message != messages[-1].message: messages.append(message) - assert messages[0].severity == amici.LogSeverity.debug + assert messages[0].severity == LogSeverity.debug assert messages[0].identifier.endswith(":RHSFUNC_FAIL") - assert messages[1].severity == amici.LogSeverity.debug + assert messages[1].severity == LogSeverity.debug assert messages[1].identifier == "EQUILIBRATION_FAILURE" assert "exceedingly long simulation time" in messages[1].message - assert messages[2].severity == amici.LogSeverity_error + assert messages[2].severity == LogSeverity.error assert messages[2].identifier == "OTHER" @@ -630,12 +635,12 @@ def test_get_model_for_preeq(preeq_fixture): plists, ) = preeq_fixture model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrationOnly + SteadyStateSensitivityMode.integrationOnly ) model_preeq = get_model_for_preeq(model, edata) # the exactly same settings are used, so results should match exactly - rdata1 = amici.run_simulation(model_preeq, solver) - rdata2 = amici.run_simulation(model, solver, edata_preeq) + rdata1 = run_simulation(model_preeq, solver) + rdata2 = run_simulation(model, solver, edata_preeq) assert_equal( rdata1.x, rdata2.x, @@ -677,8 +682,8 @@ def test_partial_eq(): amici_solver.set_relative_tolerance_steady_state(1e-12) # equilibration of `explodes` will fail - rdata = amici.run_simulation(amici_model, amici_solver) - assert rdata.status == amici.AMICI_ERROR + rdata = run_simulation(amici_model, amici_solver) + assert rdata.status == AMICI_ERROR assert rdata.messages[0].identifier == "EQUILIBRATION_FAILURE" # excluding `explodes` should enable equilibration @@ -688,8 +693,8 @@ def test_partial_eq(): for state_id in amici_model.get_state_ids_solver() ] ) - rdata = amici.run_simulation(amici_model, amici_solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(amici_model, amici_solver) + assert rdata.status == AMICI_SUCCESS assert_allclose( rdata.by_id("A"), 0.5, @@ -731,7 +736,7 @@ def test_preequilibration_t0(tempdir): module_name=module_name, module_path=tempdir ) amici_model = model_module.get_model() - edata = amici.ExpData(amici_model) + edata = ExpData(amici_model) edata.set_timepoints([0.0, 10_000.0]) edata.fixed_parameters_pre_equilibration = [1.0] edata.fixed_parameters = [0.0] @@ -740,11 +745,11 @@ def test_preequilibration_t0(tempdir): amici_solver = amici_model.create_solver() amici_solver.set_relative_tolerance_steady_state(1e-5) amici_model.set_steady_state_computation_mode( - amici.SteadyStateComputationMode.integrationOnly + SteadyStateComputationMode.integrationOnly ) - rdata = amici.run_simulation(amici_model, amici_solver, edata) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(amici_model, amici_solver, edata) + assert rdata.status == AMICI_SUCCESS assert set(rdata.by_id("t0_preeq")) == {-10_000.0} idx_time_integral = amici_model.get_state_ids().index("T") assert np.isclose( @@ -803,7 +808,7 @@ def test_preequilibration_events(tempdir): amici_solver = amici_model.create_solver() amici_solver.set_newton_max_steps(10**5) - edata = amici.ExpData(amici_model) + edata = ExpData(amici_model) edata.set_timepoints([0, 11]) edata.fixed_parameters_pre_equilibration = [1.0] edata.fixed_parameters = [0.0] @@ -811,13 +816,13 @@ def test_preequilibration_events(tempdir): # Integration-only preequilibration should handle all events amici_model = model_module.get_model() amici_model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrationOnly + SteadyStateSensitivityMode.integrationOnly ) amici_model.set_steady_state_computation_mode( - amici.SteadyStateSensitivityMode.integrationOnly + SteadyStateSensitivityMode.integrationOnly ) - rdata = amici.run_simulation(amici_model, amici_solver, edata) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(amici_model, amici_solver, edata) + assert rdata.status == AMICI_SUCCESS assert rdata.preeq_t > 1e-3 # verifies that integration was done assert rdata.x_ss[target1_idx] == 1 assert rdata.x_ss[target2_idx] == 1 @@ -828,7 +833,7 @@ def test_preequilibration_events(tempdir): assert np.all(rdata.x[:, target3_idx] == [1, 1]) assert np.all(rdata.x[:, target4_idx] == [1, 2]) - edata = amici.ExpData(rdata, 1.0, 1.0, 1) + edata = ExpData(rdata, 1.0, 1.0, 1) edata.fixed_parameters_pre_equilibration = [1.0] edata.fixed_parameters = [0.0] @@ -852,8 +857,8 @@ def test_preequilibration_events(tempdir): if p != "trigger_time2" ] ) - rdata = amici.run_simulation(amici_model, amici_solver, edata) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(amici_model, amici_solver, edata) + assert rdata.status == AMICI_SUCCESS check_derivatives( amici_model, diff --git a/python/tests/test_pregenerated_models.py b/python/tests/test_pregenerated_models.py index 95ac8a1724..a050881eda 100755 --- a/python/tests/test_pregenerated_models.py +++ b/python/tests/test_pregenerated_models.py @@ -10,7 +10,16 @@ import h5py import numpy as np import pytest -from amici.gradient_check import _check_results, check_derivatives +from amici.sim.sundials import ( + ExpData, + RDataReporting, + SensitivityMethod, + SteadyStateComputationMode, + SteadyStateSensitivityMode, + run_simulation, + run_simulations, +) +from amici.sim.sundials.gradient_check import _check_results, check_derivatives from amici.testing import skip_on_valgrind cpp_test_dir = Path(__file__).parents[2] / "tests" / "cpp" @@ -38,6 +47,12 @@ def test_pregenerated_model_py(sub_test, case): NOTE: requires having run `make python-tests` in /build/ before to build the python modules for the test models. """ + from amici.sim.sundials import ( + read_exp_data_from_hdf5, + read_model_data_from_hdf5, + read_solver_settings_from_hdf5, + ) + expected_results = expected_results_py if case.startswith("sensi2"): model_name = sub_test + "_o2" @@ -63,28 +78,28 @@ def test_pregenerated_model_py(sub_test, case): ) model = test_model_module.get_model() solver = model.create_solver() - amici.read_model_data_from_hdf5( + read_model_data_from_hdf5( options_file, model.get(), f"/{sub_test}/{case}/options" ) if model_name == "model_steadystate": model.set_steady_state_computation_mode( - amici.SteadyStateComputationMode.integrateIfNewtonFails + SteadyStateComputationMode.integrateIfNewtonFails ) model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrateIfNewtonFails + SteadyStateSensitivityMode.integrateIfNewtonFails ) - amici.read_solver_settings_from_hdf5( + read_solver_settings_from_hdf5( options_file, solver.get(), f"/{sub_test}/{case}/options" ) edata = None if "data" in expected_results[sub_test][case].keys(): - edata = amici.read_exp_data_from_hdf5( + edata = read_exp_data_from_hdf5( str(expected_results_file_py), f"/{sub_test}/{case}/data", model.get(), ) - rdata = amici.run_simulation(model, solver, edata) + rdata = run_simulation(model, solver, edata) check_derivative_opts = dict() @@ -128,7 +143,7 @@ def test_pregenerated_model_py(sub_test, case): ) if model_name == "model_steadystate" and case == "sensiforwarderrorint": - edata = amici.amici.ExpData(model.get()) + edata = amici._installation.amici.ExpData(model.get()) # Test run_simulations: ensure running twice # with same ExpData yields same results @@ -139,12 +154,12 @@ def test_pregenerated_model_py(sub_test, case): model_name == "model_robertson" and case == "sensiforwardSPBCG" ) ): - if isinstance(edata, amici.amici.ExpData): + if isinstance(edata, ExpData): edatas = [edata, edata] else: edatas = [edata.get(), edata.get()] - rdatas = amici.run_simulations( + rdatas = run_simulations( model, solver, edatas, num_threads=2, failfast=False ) verify_simulation_results( @@ -159,14 +174,12 @@ def test_pregenerated_model_py(sub_test, case): ) # test residuals mode - if solver.get_sensitivity_method() == amici.SensitivityMethod.adjoint: + if solver.get_sensitivity_method() == SensitivityMethod.adjoint: with pytest.raises(RuntimeError): - solver.set_return_data_reporting_mode( - amici.RDataReporting.residuals - ) + solver.set_return_data_reporting_mode(RDataReporting.residuals) else: - solver.set_return_data_reporting_mode(amici.RDataReporting.residuals) - rdata = amici.run_simulation(model, solver, edata) + solver.set_return_data_reporting_mode(RDataReporting.residuals) + rdata = run_simulation(model, solver, edata) verify_simulation_results( rdata, expected_results[sub_test][case]["results"], @@ -174,13 +187,13 @@ def test_pregenerated_model_py(sub_test, case): **verify_simulation_opts, ) with pytest.raises(RuntimeError): - solver.set_sensitivity_method(amici.SensitivityMethod.adjoint) + solver.set_sensitivity_method(SensitivityMethod.adjoint) chi2_ref = rdata.chi2 # test likelihood mode - solver.set_return_data_reporting_mode(amici.RDataReporting.likelihood) - rdata = amici.run_simulation(model, solver, edata) + solver.set_return_data_reporting_mode(RDataReporting.likelihood) + rdata = run_simulation(model, solver, edata) verify_simulation_results( rdata, expected_results[sub_test][case]["results"], @@ -192,11 +205,11 @@ def test_pregenerated_model_py(sub_test, case): if ( model_name == "model_jakstat_adjoint" - and solver.get_sensitivity_method() != amici.SensitivityMethod.adjoint + and solver.get_sensitivity_method() != SensitivityMethod.adjoint ): model.set_add_sigma_residuals(True) - solver.set_return_data_reporting_mode(amici.RDataReporting.full) - rdata = amici.run_simulation(model, solver, edata) + solver.set_return_data_reporting_mode(RDataReporting.full) + rdata = run_simulation(model, solver, edata) # check whether activation changes chi2 assert chi2_ref != rdata.chi2 @@ -212,13 +225,13 @@ def test_pregenerated_model_py(sub_test, case): res_ref = rdata.res model.set_minimum_sigma_residuals(100) - rdata = amici.run_simulation(model, solver, edata) + rdata = run_simulation(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.set_minimum_sigma_residuals(-10) - rdata = amici.run_simulation(model, solver, edata) + rdata = run_simulation(model, solver, edata) # check whether having a bad minimum results in nan chi2 assert np.isnan(rdata.chi2) @@ -233,7 +246,7 @@ def verify_simulation_results( compares all fields of the simulation results in rdata against the expectedResults using the provided tolerances - :param rdata: simulation results as returned by amici.runAmiciSimulation + :param rdata: simulation results :param expected_results: stored test results :param fields: subsetting of expected results to check :param atol: absolute tolerance diff --git a/python/tests/test_pysb.py b/python/tests/test_pysb.py index de946f5bd6..1ca7a4a83e 100644 --- a/python/tests/test_pysb.py +++ b/python/tests/test_pysb.py @@ -16,11 +16,19 @@ import pysb.examples # noqa: F811 import pytest import sympy as sp -from amici import ParameterScaling, parameter_scaling_from_int_vector +from amici import MeasurementChannel, import_model_module from amici._symbolic.de_model_components import Event -from amici.gradient_check import check_derivatives from amici.importers.pysb import pysb2amici from amici.importers.utils import amici_time_symbol +from amici.sim.sundials import ( + ExpData, + ParameterScaling, + SensitivityOrder, + SteadyStateSensitivityMode, + parameter_scaling_from_int_vector, + run_simulation, +) +from amici.sim.sundials.gradient_check import check_derivatives from amici.testing import TemporaryDirectoryWinSafe, skip_on_valgrind from numpy.testing import assert_allclose from pysb.simulator import ScipyOdeSimulator @@ -189,13 +197,13 @@ def test_compare_to_pysb_simulation(example): compute_conservation_laws=compute_conservation_laws, observation_model=list( map( - amici.MeasurementChannel, + MeasurementChannel, pysb_model.observables.keys(), ) ), ) - amici_model_module = amici.import_model_module( + amici_model_module = import_model_module( pysb_model.name, outdir ) model_pysb = amici_model_module.get_model() @@ -205,7 +213,7 @@ def test_compare_to_pysb_simulation(example): solver.set_max_steps(int(1e6)) solver.set_absolute_tolerance(atol) solver.set_relative_tolerance(rtol) - rdata = amici.run_simulation(model_pysb, solver) + rdata = run_simulation(model_pysb, solver) # check agreement of species simulations assert np.isclose( @@ -257,11 +265,11 @@ def get_data(model): solver = model.create_solver() model.set_timepoints(np.linspace(0, 60, 61)) model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrateIfNewtonFails + SteadyStateSensitivityMode.integrateIfNewtonFails ) - rdata = amici.run_simulation(model, solver) - edata = amici.ExpData(rdata, 0.1, 0.0) + rdata = run_simulation(model, solver) + edata = ExpData(rdata, 0.1, 0.0) edata.t_presim = 2 edata.fixed_parameters = [10, 2] edata.fixed_parameters_presimulation = [3, 2] @@ -272,13 +280,13 @@ def get_data(model): def get_results(model, edata): solver = model.create_solver() - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) edata.reinitialize_fixed_parameter_initial_states = True model.set_timepoints(np.linspace(0, 60, 61)) model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrateIfNewtonFails + SteadyStateSensitivityMode.integrateIfNewtonFails ) - return amici.run_simulation(model, solver, edata) + return run_simulation(model, solver, edata) @skip_on_valgrind @@ -349,7 +357,7 @@ def test_heaviside_and_special_symbols(): model, outdir, verbose=True, - observation_model=[amici.MeasurementChannel("a")], + observation_model=[MeasurementChannel("a")], ) assert amici_model.ne @@ -381,7 +389,7 @@ def test_energy(): with TemporaryDirectoryWinSafe(prefix=model_pysb.name) as outdir: pysb2amici(model_pysb, output_dir=outdir) - model_module = amici.import_model_module( + model_module = import_model_module( module_name=model_pysb.name, module_path=outdir ) amici_model = model_module.get_model() @@ -422,12 +430,12 @@ def test_pysb_event(tempdir): model, outdir, verbose=True, - observation_model=[amici.MeasurementChannel("a")], + observation_model=[MeasurementChannel("a")], compute_conservation_laws=False, _events=events, ) - model_module = amici.import_model_module( + model_module = import_model_module( module_name=model.name, module_path=outdir ) amici_model = model_module.get_model() diff --git a/python/tests/test_rdata.py b/python/tests/test_rdata.py index d57605d479..b9b80844e0 100644 --- a/python/tests/test_rdata.py +++ b/python/tests/test_rdata.py @@ -1,9 +1,14 @@ """Test amici.ReturnData(View)-related functionality""" -import amici import numpy as np import pytest -from amici.numpy import evaluate +from amici.sim.sundials import ( + AMICI_SUCCESS, + SensitivityMethod, + SensitivityOrder, + evaluate, + run_simulation, +) from amici.testing import skip_on_valgrind from numpy.testing import assert_almost_equal, assert_array_equal @@ -14,10 +19,10 @@ def rdata_by_id_fixture(sbml_example_presimulation_module): model = model_module.get_model() model.set_timepoints(np.linspace(0, 60, 61)) solver = model.create_solver() - solver.set_sensitivity_method(amici.SensitivityMethod.forward) - solver.set_sensitivity_order(amici.SensitivityOrder.first) - rdata = amici.run_simulation(model, solver) - assert rdata.status == amici.AMICI_SUCCESS + solver.set_sensitivity_method(SensitivityMethod.forward) + solver.set_sensitivity_order(SensitivityOrder.first) + rdata = run_simulation(model, solver) + assert rdata.status == AMICI_SUCCESS return model, rdata diff --git a/python/tests/test_sbml_import.py b/python/tests/test_sbml_import.py index 268f4029aa..3ee0c869e3 100644 --- a/python/tests/test_sbml_import.py +++ b/python/tests/test_sbml_import.py @@ -12,7 +12,6 @@ import pytest import sympy as sp from amici import import_model_module -from amici.gradient_check import check_derivatives from amici.importers.antimony import antimony2sbml from amici.importers.sbml import SbmlImporter, SymbolId from amici.importers.utils import ( @@ -21,6 +20,29 @@ from amici.importers.utils import ( symbol_with_assumptions, ) +from amici.sim.sundials import ( + AMICI_ERROR, + AMICI_SUCCESS, + Constraint, + ExpData, + ExpDataView, + ModelModule, + ParameterScaling, + ReturnDataView, + SensitivityMethod, + SensitivityOrder, + SteadyStateSensitivityMode, + get_data_observables_as_data_frame, + get_edata_from_data_frame, + get_expressions_as_dataframe, + get_residuals_as_data_frame, + get_simulation_observables_as_data_frame, + get_simulation_states_as_data_frame, + parameter_scaling_from_int_vector, + run_simulation, + run_simulations, +) +from amici.sim.sundials.gradient_check import check_derivatives from amici.testing import TemporaryDirectoryWinSafe as TemporaryDirectory from amici.testing import skip_on_valgrind from conftest import MODEL_STEADYSTATE_SCALED_XML @@ -114,6 +136,7 @@ def test_nosensi(tempdir): observation_model=None, compute_conservation_laws=False, generate_sensitivity_code=False, + verbose=True, ) model_module = amici.import_model_module( @@ -123,7 +146,7 @@ def test_nosensi(tempdir): model = model_module.get_model() model.set_timepoints(np.linspace(0, 60, 61)) rdata = model.simulate(sensi_order="first", sensi_method="forward") - assert rdata.status == amici.AMICI_ERROR + assert rdata.status == AMICI_ERROR @pytest.fixture(scope="session") @@ -175,7 +198,7 @@ def test_sbml2amici_observable_dependent_error( solver = model.create_solver() # generate artificial data - rdata = amici.run_simulation(model, solver) + rdata = run_simulation(model, solver) assert_allclose( rdata.sigmay[:, 0], 0.1 + 0.05 * rdata.y[:, 0], @@ -185,18 +208,18 @@ def test_sbml2amici_observable_dependent_error( assert_allclose( rdata.sigmay[:, 1], 0.02 * rdata.y[:, 1], rtol=1.0e-5, atol=1.0e-8 ) - edata = amici.ExpData(rdata, 1.0, 0.0) + edata = ExpData(rdata, 1.0, 0.0) edata.set_observed_data_std_dev(np.nan) # check sensitivities - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) # FSA - solver.set_sensitivity_method(amici.SensitivityMethod.forward) - rdata = amici.run_simulation(model, solver, edata) + solver.set_sensitivity_method(SensitivityMethod.forward) + rdata = run_simulation(model, solver, edata) assert np.any(rdata.ssigmay != 0.0) check_derivatives(model, solver, edata) # ASA - solver.set_sensitivity_method(amici.SensitivityMethod.adjoint) + solver.set_sensitivity_method(SensitivityMethod.adjoint) check_derivatives(model, solver, edata) @@ -211,8 +234,8 @@ def test_logging_works(observable_dependent_error_model, caplog): # this will prematurely stop the simulation solver.set_max_steps(1) - rdata = amici.run_simulation(model, solver) - assert rdata.status != amici.AMICI_SUCCESS + rdata = run_simulation(model, solver) + assert rdata.status != AMICI_SUCCESS assert "mxstep steps taken" in caplog.text @@ -220,7 +243,7 @@ def test_logging_works(observable_dependent_error_model, caplog): def test_model_module_is_set(observable_dependent_error_model): model_module = observable_dependent_error_model assert model_module.get_model().module is model_module - assert isinstance(model_module.get_model().module, amici.ModelModule) + assert isinstance(model_module.get_model().module, ModelModule) @pytest.fixture(scope="session") @@ -260,19 +283,17 @@ def test_presimulation(sbml_example_presimulation_module): solver = model.create_solver() model.set_timepoints(np.linspace(0, 60, 61)) model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrationOnly + SteadyStateSensitivityMode.integrationOnly ) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) model.set_reinitialize_fixed_parameter_initial_states(True) - rdata = amici.run_simulation(model, solver) - edata = amici.ExpData(rdata, 0.1, 0.0) + rdata = run_simulation(model, solver) + edata = ExpData(rdata, 0.1, 0.0) edata.fixed_parameters = [10, 2] edata.fixed_parameters_presimulation = [10, 2] edata.fixed_parameters_pre_equilibration = [3, 0] - assert isinstance( - amici.run_simulation(model, solver, edata), amici.ReturnDataView - ) + assert isinstance(run_simulation(model, solver, edata), ReturnDataView) solver.set_relative_tolerance(1e-12) solver.set_absolute_tolerance(1e-12) @@ -313,15 +334,15 @@ def test_presimulation_events(tempdir): model = model_module.get_model() model.set_timepoints([0, 1, 2]) - edata = amici.ExpData(model) + edata = ExpData(model) edata.t_presim = 2 edata.fixed_parameters_presimulation = [1] edata.fixed_parameters = [0] solver = model.create_solver() # generate artificial data - rdata = amici.run_simulation(model, solver, edata) - edata_tmp = amici.ExpData(rdata, 1, 0) + rdata = run_simulation(model, solver, edata) + edata_tmp = ExpData(rdata, 1, 0) edata.set_timepoints(np.array(edata_tmp.get_timepoints()) + 0.1) edata.set_observed_data(edata_tmp.get_observed_data()) edata.set_observed_data_std_dev(edata_tmp.get_observed_data_std_dev()) @@ -333,18 +354,18 @@ def test_presimulation_events(tempdir): for ip, p in enumerate(model.get_free_parameter_ids()) if p != "t_initial_presim" ] - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) for sensi_method in ( - amici.SensitivityMethod.forward, + SensitivityMethod.forward, # FIXME: test with adjoints. currently there is some CVodeF issue # that fails forward simulation with adjoint sensitivities - # amici.SensitivityMethod.adjoint, + # SensitivityMethod.adjoint, ): solver.set_sensitivity_method(sensi_method) - rdata = amici.run_simulation(model, solver, edata) + rdata = run_simulation(model, solver, edata) - assert rdata.status == amici.AMICI_SUCCESS + assert rdata.status == AMICI_SUCCESS assert_allclose( rdata.by_id("some_time"), np.array([0, 1, 2]) + 0.1, atol=1e-14 ) @@ -396,27 +417,27 @@ def test_presimulation_events_and_sensitivities(tempdir): ) model.set_timepoints([0, 1, 2]) - edata = amici.ExpData(model) + edata = ExpData(model) edata.t_presim = 2 solver = model.create_solver() # generate artificial data - rdata = amici.run_simulation(model, solver, edata) - edata_tmp = amici.ExpData(rdata, 1, 0) + rdata = run_simulation(model, solver, edata) + edata_tmp = ExpData(rdata, 1, 0) edata.set_timepoints(np.array(edata_tmp.get_timepoints()) + 0.1) edata.set_observed_data(edata_tmp.get_observed_data()) edata.set_observed_data_std_dev(edata_tmp.get_observed_data_std_dev()) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) for sensi_method in ( - amici.SensitivityMethod.forward, - amici.SensitivityMethod.adjoint, + SensitivityMethod.forward, + SensitivityMethod.adjoint, ): solver.set_sensitivity_method(sensi_method) - rdata = amici.run_simulation(model, solver, edata) + rdata = run_simulation(model, solver, edata) - assert rdata.status == amici.AMICI_SUCCESS + assert rdata.status == AMICI_SUCCESS assert_allclose( rdata.by_id("some_time"), np.array([0, 1, 2]) + 1.1, atol=1e-14 ) @@ -436,29 +457,29 @@ def test_steadystate_simulation(model_steadystate_module): model = model_steadystate_module.get_model() model.set_timepoints(np.linspace(0, 60, 60)) solver = model.create_solver() - solver.set_sensitivity_order(amici.SensitivityOrder.first) - rdata = amici.run_simulation(model, solver) - edata = [amici.ExpData(rdata, 1, 0)] + solver.set_sensitivity_order(SensitivityOrder.first) + rdata = run_simulation(model, solver) + edata = [ExpData(rdata, 1, 0)] edata[0].id = "some condition ID" - rdata = amici.run_simulations(model, solver, edata) + rdata = run_simulations(model, solver, edata) - assert rdata[0].status == amici.AMICI_SUCCESS + assert rdata[0].status == AMICI_SUCCESS assert rdata[0].id == edata[0].id # check roundtripping of DataFrame conversion - df_edata = amici.get_data_observables_as_data_frame(model, edata) - edata_reconstructed = amici.get_edata_from_data_frame(model, df_edata) + df_edata = get_data_observables_as_data_frame(model, edata) + edata_reconstructed = get_edata_from_data_frame(model, df_edata) assert_allclose( - amici.ExpDataView(edata[0])["observed_data"], - amici.ExpDataView(edata_reconstructed[0])["observed_data"], + ExpDataView(edata[0])["observed_data"], + ExpDataView(edata_reconstructed[0])["observed_data"], rtol=1.0e-5, atol=1.0e-8, ) assert_allclose( - amici.ExpDataView(edata[0])["observed_data_std_dev"], - amici.ExpDataView(edata_reconstructed[0])["observed_data_std_dev"], + ExpDataView(edata[0])["observed_data_std_dev"], + ExpDataView(edata_reconstructed[0])["observed_data_std_dev"], rtol=1.0e-5, atol=1.0e-8, ) @@ -477,7 +498,7 @@ def test_steadystate_simulation(model_steadystate_module): edata_reconstructed[0].fixed_parameters_pre_equilibration ) - df_state = amici.get_simulation_states_as_data_frame(model, edata, rdata) + df_state = get_simulation_states_as_data_frame(model, edata, rdata) assert_allclose( rdata[0]["x"], df_state[list(model.get_state_ids())].values, @@ -485,18 +506,16 @@ def test_steadystate_simulation(model_steadystate_module): atol=1.0e-8, ) - df_obs = amici.get_simulation_observables_as_data_frame( - model, edata, rdata - ) + df_obs = get_simulation_observables_as_data_frame(model, edata, rdata) assert_allclose( rdata[0]["y"], df_obs[list(model.get_observable_ids())].values, rtol=1.0e-5, atol=1.0e-8, ) - amici.get_residuals_as_data_frame(model, edata, rdata) + get_residuals_as_data_frame(model, edata, rdata) - df_expr = amici.pandas.get_expressions_as_dataframe(model, edata, rdata) + df_expr = get_expressions_as_dataframe(model, edata, rdata) assert_allclose( rdata[0]["w"], df_expr[list(model.get_expression_ids())].values, @@ -519,19 +538,19 @@ def test_solver_reuse(model_steadystate_module): model = model_steadystate_module.get_model() model.set_timepoints(np.linspace(0, 60, 60)) solver = model.create_solver() - solver.set_sensitivity_order(amici.SensitivityOrder.first) - rdata = amici.run_simulation(model, solver) - edata = amici.ExpData(rdata, 1, 0) + solver.set_sensitivity_order(SensitivityOrder.first) + rdata = run_simulation(model, solver) + edata = ExpData(rdata, 1, 0) for sensi_method in ( - amici.SensitivityMethod.forward, - amici.SensitivityMethod.adjoint, + SensitivityMethod.forward, + SensitivityMethod.adjoint, ): solver.set_sensitivity_method(sensi_method) - rdata1 = amici.run_simulation(model, solver, edata) - rdata2 = amici.run_simulation(model, solver, edata) + rdata1 = run_simulation(model, solver, edata) + rdata2 = run_simulation(model, solver, edata) - assert rdata1.status == amici.AMICI_SUCCESS + assert rdata1.status == AMICI_SUCCESS for attr in rdata1: if "time" in attr or attr == "messages": @@ -592,16 +611,16 @@ def test_likelihoods(model_test_likelihoods): model = model_test_likelihoods.get_model() model.set_timepoints(np.linspace(0, 60, 60)) solver = model.create_solver() - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) # run model once to create an edata rdata = model.simulate(solver=solver) sigmas = rdata["y"].max(axis=0) * 0.05 - edata = amici.ExpData(rdata, sigmas, []) + edata = ExpData(rdata, sigmas, []) # just make all observables positive since some are logarithmic while min(edata.get_observed_data()) < 0: - edata = amici.ExpData(rdata, sigmas, []) + edata = ExpData(rdata, sigmas, []) # and now run for real and also compute likelihood values rdata = model.simulate(solver=solver, edata=[edata])[0] @@ -611,12 +630,10 @@ def test_likelihoods(model_test_likelihoods): assert np.all(np.isfinite(rdata["sllh"])) assert np.any(rdata["sllh"]) - rdata_df = amici.get_simulation_observables_as_data_frame( + rdata_df = get_simulation_observables_as_data_frame( model, edata, rdata, by_id=True ) - edata_df = amici.get_data_observables_as_data_frame( - model, edata, by_id=True - ) + edata_df = get_data_observables_as_data_frame(model, edata, by_id=True) # check correct likelihood value llh_exp = -sum( @@ -634,12 +651,12 @@ def test_likelihoods(model_test_likelihoods): # check gradient for sensi_method in [ - amici.SensitivityMethod.forward, - amici.SensitivityMethod.adjoint, + SensitivityMethod.forward, + SensitivityMethod.adjoint, ]: solver = model.create_solver() solver.set_sensitivity_method(sensi_method) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) solver.set_relative_tolerance(1e-12) solver.set_absolute_tolerance(1e-12) check_derivatives( @@ -682,8 +699,8 @@ def test_units(model_units_module): model.set_timepoints(np.linspace(0, 1, 101)) solver = model.create_solver() - rdata = amici.run_simulation(model, solver) - assert rdata["status"] == amici.AMICI_SUCCESS + rdata = run_simulation(model, solver) + assert rdata["status"] == AMICI_SUCCESS @skip_on_valgrind @@ -715,24 +732,24 @@ def test_sympy_exp_monkeypatch(tempdir): model.require_sensitivities_for_all_parameters() model.set_always_check_finite(True) model.set_parameter_scale( - amici.parameter_scaling_from_int_vector( + parameter_scaling_from_int_vector( [ - amici.ParameterScaling.none + ParameterScaling.none if re.match(r"n[0-9]+$", par_id) - else amici.ParameterScaling.log10 + else ParameterScaling.log10 for par_id in model.get_free_parameter_ids() ] ) ) solver = model.create_solver() - solver.set_sensitivity_method(amici.SensitivityMethod.forward) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_method(SensitivityMethod.forward) + solver.set_sensitivity_order(SensitivityOrder.first) - rdata = amici.run_simulation(model, solver) + rdata = run_simulation(model, solver) # print sensitivity-related results - assert rdata.status == amici.AMICI_SUCCESS + assert rdata.status == AMICI_SUCCESS check_derivatives(model, solver, None, atol=1e-2, rtol=1e-2, epsilon=1e-3) @@ -875,7 +892,6 @@ def test_hardcode_parameters(): def test_constraints(tempdir): """Test non-negativity constraint handling.""" - from amici import Constraint from amici.importers.antimony import antimony2amici ant_model = """ @@ -900,8 +916,8 @@ def test_constraints(tempdir): amici_model = model_module.get_model() amici_model.set_timepoints(np.linspace(0, 100, 200)) amici_solver = amici_model.create_solver() - rdata = amici.run_simulation(amici_model, amici_solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(amici_model, amici_solver) + assert rdata.status == AMICI_SUCCESS # should be non-negative in theory, but is expected to become negative # in practice assert np.any(rdata.x < 0) @@ -910,8 +926,8 @@ def test_constraints(tempdir): amici_solver.set_constraints( [Constraint.non_negative, Constraint.non_negative] ) - rdata = amici.run_simulation(amici_model, amici_solver) - assert rdata.status == amici.AMICI_SUCCESS + rdata = run_simulation(amici_model, amici_solver) + assert rdata.status == AMICI_SUCCESS assert np.all(rdata.x >= 0) assert np.all( np.sum(rdata.x, axis=1) - np.sum(rdata.x[0]) @@ -1027,7 +1043,7 @@ def test_regression_2642(tempdir): model = module.get_model() solver = model.create_solver() model.set_timepoints(np.linspace(0, 1, 3)) - r = amici.run_simulation(model, solver) + r = run_simulation(model, solver) assert ( len(np.unique(r.w[:, model.get_expression_ids().index("binding")])) == 1 @@ -1124,7 +1140,7 @@ def test_t0(tempdir): model.set_t0(2) solver = model.create_solver() - rdata = amici.run_simulation(model, solver) + rdata = run_simulation(model, solver) assert rdata.x == [[2.0]], rdata.x diff --git a/python/tests/test_sbml_import_special_functions.py b/python/tests/test_sbml_import_special_functions.py index 4b961151f5..6f83be38a8 100644 --- a/python/tests/test_sbml_import_special_functions.py +++ b/python/tests/test_sbml_import_special_functions.py @@ -9,8 +9,17 @@ import pytest from amici import MeasurementChannel as MC from amici import SbmlImporter -from amici.gradient_check import check_derivatives from amici.importers.antimony import antimony2amici +from amici.sim.sundials import ( + ExpData, + SensitivityMethod, + SensitivityOrder, + get_data_observables_as_data_frame, + get_simulation_observables_as_data_frame, + run_simulation, + run_simulations, +) +from amici.sim.sundials.gradient_check import check_derivatives from amici.testing import TemporaryDirectoryWinSafe, skip_on_valgrind from conftest import MODEL_STEADYSTATE_SCALED_XML from numpy.testing import ( @@ -54,13 +63,13 @@ def test_special_likelihoods(model_special_likelihoods): model = model_special_likelihoods.get_model() model.set_timepoints(np.linspace(0, 60, 10)) solver = model.create_solver() - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) # Test in region with positive density # run model once to create an edata - rdata = amici.run_simulation(model, solver) - edata = amici.ExpData(rdata, 0.001, 0) + rdata = run_simulation(model, solver) + edata = ExpData(rdata, 0.001, 0) # make sure measurements are smaller for non-degenerate probability y = edata.get_observed_data() @@ -73,19 +82,17 @@ def test_special_likelihoods(model_special_likelihoods): edata.set_observed_data_std_dev(sigmas) # and now run for real and also compute likelihood values - rdata = amici.run_simulations(model, solver, [edata])[0] + rdata = run_simulations(model, solver, [edata])[0] # check if the values make overall sense assert np.isfinite(rdata["llh"]) assert np.all(np.isfinite(rdata["sllh"])) assert np.any(rdata["sllh"]) - rdata_df = amici.get_simulation_observables_as_data_frame( + rdata_df = get_simulation_observables_as_data_frame( model, edata, rdata, by_id=True ) - edata_df = amici.get_data_observables_as_data_frame( - model, edata, by_id=True - ) + edata_df = get_data_observables_as_data_frame(model, edata, by_id=True) # check correct likelihood value llh_exp = -sum( @@ -98,12 +105,12 @@ def test_special_likelihoods(model_special_likelihoods): # check gradient for sensi_method in [ - amici.SensitivityMethod.forward, - amici.SensitivityMethod.adjoint, + SensitivityMethod.forward, + SensitivityMethod.adjoint, ]: solver = model.create_solver() solver.set_sensitivity_method(sensi_method) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) check_derivatives( model, solver, @@ -115,8 +122,8 @@ def test_special_likelihoods(model_special_likelihoods): # Test for m > y, i.e. in region with 0 density - rdata = amici.run_simulation(model, solver) - edata = amici.ExpData(rdata, 0.001, 0) + rdata = run_simulation(model, solver) + edata = ExpData(rdata, 0.001, 0) # make sure measurements are smaller for non-degenerate probability y = edata.get_observed_data() @@ -125,7 +132,7 @@ def test_special_likelihoods(model_special_likelihoods): edata.set_observed_data_std_dev(sigmas) # and now run for real and also compute likelihood values - rdata = amici.run_simulations(model, solver, [edata])[0] + rdata = run_simulations(model, solver, [edata])[0] # m > y -> outside binomial domain -> 0 density assert rdata["llh"] == -np.inf @@ -191,7 +198,7 @@ def test_rateof(tempdir): t = np.linspace(0, 10, 11) amici_model.set_timepoints(t) amici_solver = amici_model.create_solver() - rdata = amici.run_simulation(amici_model, amici_solver) + rdata = run_simulation(amici_model, amici_solver) state_ids_solver = amici_model.get_state_ids_solver() i_S1 = state_ids_solver.index("S1") @@ -244,7 +251,7 @@ def test_rateof_with_expression_dependent_rate(tempdir): t = np.linspace(0, 10, 11) amici_model.set_timepoints(t) amici_solver = amici_model.create_solver() - rdata = amici.run_simulation(amici_model, amici_solver) + rdata = run_simulation(amici_model, amici_solver) state_ids_solver = amici_model.get_state_ids_solver() diff --git a/python/tests/test_swig_interface.py b/python/tests/test_swig_interface.py index 272ef31bac..c2823228ab 100644 --- a/python/tests/test_swig_interface.py +++ b/python/tests/test_swig_interface.py @@ -12,7 +12,28 @@ import numpy as np import pytest import xarray -from amici import SteadyStateSensitivityMode +from amici.sim.sundials import ( + AMICI_FIRST_RHSFUNC_ERR, + CVodeSolver, + ExpData, + ExpDataPtr, + ExpDataView, + IDASolver, + ModelPtr, + ParameterScaling, + RDataReporting, + ReturnDataView, + SensitivityMethod, + SensitivityOrder, + SolverPtr, + SteadyStateComputationMode, + SteadyStateSensitivityMode, + get_model_settings, + parameter_scaling_from_int_vector, + run_simulation, + run_simulations, + set_model_settings, +) from amici.testing import skip_on_valgrind @@ -112,12 +133,12 @@ def test_copy_constructors(pysb_example_presimulation_module): # `pysb_example_presimulation_module.getModel()`. "state_is_non_negative": None, "steady_state_computation_mode": [ - amici.SteadyStateComputationMode.integrationOnly, - amici.SteadyStateComputationMode.integrateIfNewtonFails, + SteadyStateComputationMode.integrationOnly, + SteadyStateComputationMode.integrateIfNewtonFails, ], "steady_state_sensitivity_mode": [ - amici.SteadyStateSensitivityMode.integrationOnly, - amici.SteadyStateSensitivityMode.integrateIfNewtonFails, + SteadyStateSensitivityMode.integrationOnly, + SteadyStateSensitivityMode.integrateIfNewtonFails, ], ("t0", "set_t0"): [ 0.0, @@ -158,7 +179,7 @@ def test_model_instance_settings(pysb_example_presimulation_module): # All settings are tested. assert set(model_instance_settings0) == set( - amici.swig_wrappers.model_instance_settings + amici.sim.sundials._swig_wrappers.model_instance_settings ) # Skip settings with interdependencies. @@ -184,7 +205,7 @@ def test_model_instance_settings(pysb_example_presimulation_module): assert getattr(model0, getter)() == custom # The grouped getter method works. - custom_settings = amici.get_model_settings(model0) + custom_settings = get_model_settings(model0) for name in model_instance_settings: assert custom_settings[name] == model_instance_settings[name][i_custom] @@ -192,7 +213,7 @@ def test_model_instance_settings(pysb_example_presimulation_module): model = pysb_example_presimulation_module.get_model() # The new model has the default settings. - model_default_settings = amici.get_model_settings(model) + model_default_settings = get_model_settings(model) for name in model_instance_settings: if ( name == "initial_state" and not model.has_custom_initial_state() @@ -218,10 +239,10 @@ def test_model_instance_settings(pysb_example_presimulation_module): for name, value in custom_settings.items() if model_instance_settings0[name] is not None } - amici.set_model_settings(model, custom_settings_not_none) + set_model_settings(model, custom_settings_not_none) assert all( same_or_nan(value, custom_settings_not_none[name]) - for name, value in amici.get_model_settings(model).items() + for name, value in get_model_settings(model).items() if name in custom_settings_not_none ) @@ -266,7 +287,7 @@ def test_interdependent_settings(pysb_example_presimulation_module): } ) - default_settings = amici.get_model_settings(model) + default_settings = get_model_settings(model) for original_setting, original_setting_value in original_settings.items(): test_value = getter_transformers[original_setting]( default_settings[original_setting], @@ -278,15 +299,15 @@ def test_interdependent_settings(pysb_example_presimulation_module): for setting, expected_value in expected_settings.items(): input_settings = {setting: copy.deepcopy(expected_value)} - amici.set_model_settings(model, input_settings) - output_settings = amici.get_model_settings(model) + set_model_settings(model, input_settings) + output_settings = get_model_settings(model) test_value = getter_transformers[setting](output_settings[setting]) # The setter works. assert test_value == expected_value input_settings = {setting: output_settings[setting]} - amici.set_model_settings(model, input_settings) - output_settings = amici.get_model_settings(model) + set_model_settings(model, input_settings) + output_settings = get_model_settings(model) test_value = getter_transformers[setting](output_settings[setting]) # (round-trip) The output of the getter can be used as input to the # setter, and does not change the value. @@ -347,7 +368,7 @@ def test_unhandled_settings(pysb_example_presimulation_module): "get_trigger_timepoints", "get_any_state_nonnegative", ] - from amici.swig_wrappers import model_instance_settings + from amici.sim.sundials._swig_wrappers import model_instance_settings handled = [ name @@ -387,7 +408,7 @@ def get_val(obj, attr): def get_mod_val(val, attr, obj): if attr == "get_return_data_reporting_mode": - return amici.RDataReporting.likelihood + return RDataReporting.likelihood elif attr == "get_parameter_list": return tuple(get_mod_val(val[0], "", obj) for _ in val) elif attr == "get_state_is_non_negative": @@ -426,37 +447,37 @@ def assert_same(a: dict, b: dict): # ensure no-custom-(s)x0 is restored assert not model.has_custom_initial_state() assert not model.has_custom_initial_state_sensitivities() - settings = amici.get_model_settings(model) + settings = get_model_settings(model) model.set_initial_state(model.get_initial_state()) model.set_unscaled_initial_state_sensitivities( model.get_initial_state_sensitivities() ) - amici.set_model_settings(model, settings) + set_model_settings(model, settings) assert not model.has_custom_initial_state() assert not model.has_custom_initial_state_sensitivities() # ensure everything was set correctly, and there wasn't any problem # due to, e.g., interactions of different setters - assert_same(settings, amici.get_model_settings(model)) + assert_same(settings, get_model_settings(model)) # ensure custom (s)x0 is restored model.set_initial_state(model.get_initial_state()) - model.set_parameter_scale(amici.ParameterScaling.log10) + model.set_parameter_scale(ParameterScaling.log10) sx0 = model.get_initial_state_sensitivities() model.set_unscaled_initial_state_sensitivities(sx0) assert model.has_custom_initial_state() assert model.has_custom_initial_state_sensitivities() - settings = amici.get_model_settings(model) + settings = get_model_settings(model) model2 = pysb_example_presimulation_module.get_model() - amici.set_model_settings(model2, settings) + set_model_settings(model2, settings) assert model2.has_custom_initial_state() assert model2.has_custom_initial_state_sensitivities() assert model2.get_initial_state_sensitivities() == sx0 - assert_same(settings, amici.get_model_settings(model2)) + assert_same(settings, get_model_settings(model2)) def test_solver_repr(): - for solver in (amici.CVodeSolver(), amici.IDASolver()): - solver_ptr = amici.SolverPtr(solver.this) + for solver in (CVodeSolver(), IDASolver()): + solver_ptr = SolverPtr(solver.this) for s in (solver, solver_ptr): assert "maxsteps" in str(s) assert "maxsteps" in repr(s) @@ -467,8 +488,8 @@ def test_edata_repr(): nz = 2 ne = 3 nt = 4 - edata = amici.ExpData(ny, nz, ne, range(nt)) - edata_ptr = amici.ExpDataPtr(edata.this) + edata = ExpData(ny, nz, ne, range(nt)) + edata_ptr = ExpDataPtr(edata.this) expected_strs = ( f"{nt}x{ny} time-resolved datapoints", f"{ne}x{nz} event-resolved datapoints", @@ -482,8 +503,8 @@ def test_edata_repr(): def test_edata_equality_operator(): - e1 = amici.ExpData(1, 2, 3, [3]) - e2 = amici.ExpData(1, 2, 3, [3]) + e1 = ExpData(1, 2, 3, [3]) + e2 = ExpData(1, 2, 3, [3]) assert e1 == e2 # check that comparison with other types works # this is not implemented by swig by default @@ -491,7 +512,7 @@ def test_edata_equality_operator(): def test_expdata_and_expdataview_are_deepcopyable(): - edata1 = amici.ExpData(3, 2, 3, range(4)) + edata1 = ExpData(3, 2, 3, range(4)) edata1.set_observed_data(np.zeros((3, 4)).flatten()) # ExpData @@ -502,15 +523,15 @@ def test_expdata_and_expdataview_are_deepcopyable(): assert edata1 != edata2 # ExpDataView - ev1 = amici.ExpDataView(edata1) + ev1 = ExpDataView(edata1) ev2 = copy.deepcopy(ev1) assert ev2._swigptr.this != ev1._swigptr.this assert ev1 == ev2 def test_solvers_are_deepcopyable(): - for solver_type in (amici.CVodeSolver, amici.IDASolver): - for solver1 in (solver_type(), amici.SolverPtr(solver_type())): + for solver_type in (CVodeSolver, IDASolver): + for solver1 in (solver_type(), SolverPtr(solver_type())): solver2 = copy.deepcopy(solver1) assert solver1.this != solver2.this assert ( @@ -530,7 +551,7 @@ def test_model_is_deepcopyable(pysb_example_presimulation_module): model_module = pysb_example_presimulation_module for model1 in ( model_module.get_model(), - amici.ModelPtr(model_module.get_model()), + ModelPtr(model_module.get_model()), ): model2 = copy.deepcopy(model1) assert model1.this != model2.this @@ -544,8 +565,8 @@ def test_rdataview(sbml_example_presimulation_module): model_module = sbml_example_presimulation_module model = model_module.get_model() model.set_timepoints([1, 2, 3]) - rdata = amici.run_simulation(model, model.create_solver()) - assert isinstance(rdata, amici.ReturnDataView) + rdata = run_simulation(model, model.create_solver()) + assert isinstance(rdata, ReturnDataView) # check that non-array attributes are looked up in the wrapped object assert rdata.ptr.ny == rdata.ny @@ -576,9 +597,10 @@ def test_rdataview(sbml_example_presimulation_module): def test_python_exceptions(sbml_example_presimulation_module): """Test that C++ exceptions are correctly caught and re-raised in Python.""" + from amici.sim.sundials import run_simulation # amici-base extension throws and its swig-wrapper catches - solver = amici.CVodeSolver() + solver = CVodeSolver() with pytest.raises( RuntimeError, match="maxsteps must be a positive number" ): @@ -590,7 +612,7 @@ def test_python_exceptions(sbml_example_presimulation_module): model.set_steadystate_mask([1] * model.nx_solver * 2) # amici-base extension throws and its swig-wrapper catches - edata = amici.ExpData(1, 1, 1, [1]) + edata = ExpData(1, 1, 1, [1]) # too short sx0 edata.sx0 = (1, 2) with pytest.raises( @@ -598,32 +620,32 @@ def test_python_exceptions(sbml_example_presimulation_module): match=r"Number of initial conditions sensitivities \(36\) " r"in model does not match ExpData \(2\).", ): - amici.run_simulation(model, solver, edata) + run_simulation(model, solver, edata) - amici.run_simulations( + run_simulations( model, solver, [edata, edata], failfast=True, num_threads=1 ) # model throws, base catches, swig-exception handling is not involved model.set_free_parameters([nan] * model.np()) model.set_timepoints([1]) - rdata = amici.run_simulation(model, solver) - assert rdata.status == amici.AMICI_FIRST_RHSFUNC_ERR + rdata = run_simulation(model, solver) + assert rdata.status == AMICI_FIRST_RHSFUNC_ERR - edata = amici.ExpData(1, 1, 1, [1]) - rdatas = amici.run_simulations( + edata = ExpData(1, 1, 1, [1]) + rdatas = run_simulations( model, solver, [edata, edata], failfast=True, num_threads=1 ) - assert rdatas[0].status == amici.AMICI_FIRST_RHSFUNC_ERR + assert rdatas[0].status == AMICI_FIRST_RHSFUNC_ERR # model throws, base catches, swig-exception handling is involved - from amici._amici import run_simulation - with pytest.raises( RuntimeError, match="AMICI failed to integrate the forward problem" ): # rethrow=True - run_simulation(solver, None, model.get(), True) + amici._installation._amici.run_simulation( + solver, None, model.get(), True + ) def test_reporting_mode_obs_llh(sbml_example_presimulation_module): @@ -632,37 +654,32 @@ def test_reporting_mode_obs_llh(sbml_example_presimulation_module): solver = model.create_solver() solver.set_return_data_reporting_mode( - amici.RDataReporting.observables_likelihood + RDataReporting.observables_likelihood ) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) for sens_method in ( - amici.SensitivityMethod.none, - amici.SensitivityMethod.forward, - amici.SensitivityMethod.adjoint, + SensitivityMethod.none, + SensitivityMethod.forward, + SensitivityMethod.adjoint, ): solver.set_sensitivity_method(sens_method) - rdata = amici.run_simulation( - model, solver, amici.ExpData(1, 1, 1, [1]) - ) - assert ( - rdata.rdata_reporting - == amici.RDataReporting.observables_likelihood - ) + rdata = run_simulation(model, solver, ExpData(1, 1, 1, [1])) + assert rdata.rdata_reporting == RDataReporting.observables_likelihood assert rdata.y.size > 0 assert rdata.sigmay.size > 0 assert rdata.J is None match solver.get_sensitivity_method(): - case amici.SensitivityMethod.none: + case SensitivityMethod.none: assert rdata.sllh is None - case amici.SensitivityMethod.forward: + case SensitivityMethod.forward: assert rdata.sy.size > 0 assert rdata.ssigmay.size > 0 assert rdata.sllh.size > 0 assert not np.isnan(rdata.sllh).any() - case amici.SensitivityMethod.adjoint: + case SensitivityMethod.adjoint: assert rdata.sy is None assert rdata.ssigmay is None assert rdata.sllh.size > 0 @@ -708,10 +725,10 @@ def test_pickle_edata(): nz = 3 ne = 4 nt = 5 - edata = amici.ExpData(ny, nz, ne, range(nt)) + edata = ExpData(ny, nz, ne, range(nt)) edata.set_observed_data(list(np.arange(ny * nt, dtype=float))) - edata.pscale = amici.parameter_scaling_from_int_vector( - [amici.ParameterScaling.log10] * 5 + edata.pscale = parameter_scaling_from_int_vector( + [ParameterScaling.log10] * 5 ) edata_pickled = pickle.loads(pickle.dumps(edata)) @@ -719,18 +736,18 @@ def test_pickle_edata(): @pytest.mark.skipif( - not amici.hdf5_enabled, + not amici.sim.sundials.hdf5_enabled, reason="AMICI build without HDF5 support", ) def test_pickle_solver(): for solver in ( - amici.CVodeSolver(), - amici.IDASolver(), - amici.SolverPtr(amici.CVodeSolver()), - amici.SolverPtr(amici.IDASolver()), + CVodeSolver(), + IDASolver(), + SolverPtr(CVodeSolver()), + SolverPtr(IDASolver()), ): solver.set_max_steps(1234) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_order(SensitivityOrder.first) solver_pickled = pickle.loads(pickle.dumps(solver)) assert type(solver) is type(solver_pickled) assert solver.get_max_steps() == solver_pickled.get_max_steps() diff --git a/python/tests/util.py b/python/tests/util.py index 4a126a7211..d0c0bb8137 100644 --- a/python/tests/util.py +++ b/python/tests/util.py @@ -4,19 +4,19 @@ import tempfile from pathlib import Path -import amici import numpy as np import pandas as pd -from amici import ( +from amici import import_model_module +from amici.importers.sbml import SbmlImporter +from amici.sim.sundials import ( + AMICI_SUCCESS, AmiciModel, ExpData, - SbmlImporter, SensitivityMethod, SensitivityOrder, - import_model_module, run_simulation, ) -from amici.gradient_check import _check_close +from amici.sim.sundials.gradient_check import _check_close from numpy.testing import assert_allclose @@ -99,7 +99,7 @@ def check_trajectories_with_adjoint_sensitivities( # First compute dummy experimental data to use adjoints solver = amici_model.create_solver() rdata = run_simulation(amici_model, solver=solver) - assert rdata.status == amici.AMICI_SUCCESS + assert rdata.status == AMICI_SUCCESS rng_seed = 42 edata = ExpData(rdata, 1.0, 1.0, rng_seed) @@ -109,7 +109,7 @@ def check_trajectories_with_adjoint_sensitivities( solver.set_absolute_tolerance(1e-15) solver.set_relative_tolerance(1e-13) rdata_fsa = run_simulation(amici_model, solver=solver, edata=edata) - assert rdata_fsa.status == amici.AMICI_SUCCESS + assert rdata_fsa.status == AMICI_SUCCESS # ASA solver.set_sensitivity_method(SensitivityMethod.adjoint) @@ -120,7 +120,7 @@ def check_trajectories_with_adjoint_sensitivities( solver.set_absolute_tolerance_quadratures(1e-14) solver.set_relative_tolerance_quadratures(1e-8) rdata_asa = run_simulation(amici_model, solver=solver, edata=edata) - assert rdata_asa.status == amici.AMICI_SUCCESS + assert rdata_asa.status == AMICI_SUCCESS assert_allclose(rdata_fsa.x, rdata_asa.x, atol=1e-14, rtol=1e-10) assert_allclose(rdata_fsa.llh, rdata_asa.llh, atol=1e-14, rtol=1e-10) diff --git a/swig/edata.i b/swig/edata.i index a760b14838..78cf2913bc 100644 --- a/swig/edata.i +++ b/swig/edata.i @@ -19,7 +19,7 @@ using namespace amici; :returns: ExpData Instance """ if args: - from amici.numpy import ReturnDataView + from amici.sim.sundials._numpy import ReturnDataView # Get the raw pointer if necessary if isinstance(args[0], (ExpData, ExpDataPtr, Model, ModelPtr)): @@ -103,7 +103,7 @@ def __deepcopy__(self, memo): return type(self)(self) def __reduce__(self): - from amici.swig_wrappers import restore_edata + from amici.sim.sundials._swig_wrappers import restore_edata return ( restore_edata, diff --git a/swig/model.i b/swig/model.i index 174586e3c9..e37cf5968d 100644 --- a/swig/model.i +++ b/swig/model.i @@ -127,7 +127,7 @@ def __deepcopy__(self, memo): return self.clone() def __reduce__(self): - from amici.swig_wrappers import restore_model, get_model_settings, file_checksum + from amici.sim.sundials._swig_wrappers import restore_model, get_model_settings, file_checksum return ( restore_model, @@ -202,7 +202,7 @@ def simulate( If `edata` is a sequence of :class:`ExpData` instances, a list of :class:`ReturnDataView` instances is returned. """ - from .swig_wrappers import _Model__simulate + from amici.sim.sundials._swig_wrappers import _Model__simulate return _Model__simulate( self, @@ -233,7 +233,7 @@ def __deepcopy__(self, memo): return self.clone() def __reduce__(self): - from amici.swig_wrappers import restore_model, get_model_settings, file_checksum + from amici.sim.sundials._swig_wrappers import restore_model, get_model_settings, file_checksum return ( restore_model, @@ -309,7 +309,7 @@ def simulate( If `edata` is a sequence of :class:`ExpData` instances, a list of :class:`ReturnDataView` instances is returned. """ - from .swig_wrappers import _Model__simulate + from amici.sim.sundials._swig_wrappers import _Model__simulate return _Model__simulate( self, diff --git a/swig/solver.i b/swig/solver.i index 1d7672f7fd..7956eef32f 100644 --- a/swig/solver.i +++ b/swig/solver.i @@ -109,9 +109,8 @@ def _solver_reduce(self: "Solver"): reboots and will not work in distributed (MPI) settings. This requires that amici was compiled with HDF5 support. """ - from amici.swig_wrappers import restore_solver + from amici.sim.sundials._swig_wrappers import restore_solver, write_solver_settings_to_hdf5 from tempfile import NamedTemporaryFile - from amici import write_solver_settings_to_hdf5 import os with NamedTemporaryFile(suffix=".h5", delete=False) as tmpfile: tmpfilename = tmpfile.name diff --git a/tests/benchmark_models/test_petab_benchmark.py b/tests/benchmark_models/test_petab_benchmark.py index 81411d7369..d92b92ebdc 100644 --- a/tests/benchmark_models/test_petab_benchmark.py +++ b/tests/benchmark_models/test_petab_benchmark.py @@ -12,7 +12,6 @@ from dataclasses import dataclass, field from pathlib import Path -import amici import benchmark_models_petab import fiddy import numpy as np @@ -20,13 +19,7 @@ import petab.v1 as petab import pytest import yaml -from amici import ( - SensitivityMethod, - SensitivityOrder, - SteadyStateComputationMode, - SteadyStateSensitivityMode, - get_model_root_dir, -) +from amici import get_model_root_dir from amici.adapters.fiddy import ( simulate_petab_to_cached_functions, simulate_petab_v2_to_cached_functions, @@ -40,6 +33,13 @@ simulate_petab, ) from amici.logging import get_logger +from amici.sim.sundials import ( + AMICI_SUCCESS, + SensitivityMethod, + SensitivityOrder, + SteadyStateComputationMode, + SteadyStateSensitivityMode, +) from fiddy import MethodId, get_derivative from fiddy.derivative_check import NumpyIsCloseDerivativeCheck from fiddy.success import Consistency @@ -281,7 +281,7 @@ def test_nominal_parameters_llh(benchmark_problem): amici_solver.set_max_steps(10_000) if problem_id in ("Brannmark_JBC2010", "Isensee_JCB2018"): amici_model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.integrationOnly + SteadyStateSensitivityMode.integrationOnly ) times = dict() @@ -324,7 +324,7 @@ def test_nominal_parameters_llh(benchmark_problem): pd.Series(times).to_csv(script_dir / f"{problem_id}_benchmark.csv") for rdata in rdatas: - assert rdata.status == amici.AMICI_SUCCESS, ( + assert rdata.status == AMICI_SUCCESS, ( f"Simulation failed for {rdata.id}" ) diff --git a/tests/benchmark_models/test_petab_benchmark_jax.py b/tests/benchmark_models/test_petab_benchmark_jax.py index 856726b05a..c077f7fe37 100644 --- a/tests/benchmark_models/test_petab_benchmark_jax.py +++ b/tests/benchmark_models/test_petab_benchmark_jax.py @@ -1,7 +1,6 @@ import logging from functools import partial -import amici import equinox as eqx import jax import jax.numpy as jnp @@ -14,6 +13,7 @@ simulate_petab, ) from amici.jax.petab import run_simulations +from amici.sim.sundials import SensitivityMethod, SensitivityOrder from beartype import beartype from test_petab_benchmark import ( benchmark_outdir, @@ -60,10 +60,8 @@ def test_jax_llh(benchmark_problem): if problem_id in problems_for_gradient_check: point = flat_petab_problem.x_nominal_free_scaled for _ in range(20): - amici_solver.set_sensitivity_method( - amici.SensitivityMethod.forward - ) - amici_solver.set_sensitivity_order(amici.SensitivityOrder.first) + amici_solver.set_sensitivity_method(SensitivityMethod.forward) + amici_solver.set_sensitivity_order(SensitivityOrder.first) amici_model.set_steady_state_sensitivity_mode( cur_settings.ss_sensitivity_mode ) diff --git a/tests/performance/test.py b/tests/performance/test.py index 3e95c5c8dc..370a9f1788 100755 --- a/tests/performance/test.py +++ b/tests/performance/test.py @@ -12,6 +12,14 @@ import amici.importers.sbml import petab.v1 as petab from amici.importers.petab.v1.petab_import import import_model_sbml +from amici.sim.sundials import ( + AMICI_SUCCESS, + ExpData, + SensitivityMethod, + SensitivityOrder, + SteadyStateSensitivityMode, + run_simulation, +) def parse_args(): @@ -54,7 +62,7 @@ def check_results(rdata): ] for d in diagnostics: print(d, rdata[d]) - assert rdata["status"] == amici.AMICI_SUCCESS + assert rdata["status"] == AMICI_SUCCESS def run_import(model_name, model_dir: Path): @@ -96,39 +104,39 @@ def compile_model(model_dir_source: Path, model_dir_compiled: Path): def prepare_simulation(arg, model, solver, edata): if arg == "forward_simulation": - solver.set_sensitivity_method(amici.SensitivityMethod.none) - solver.set_sensitivity_order(amici.SensitivityOrder.none) + solver.set_sensitivity_method(SensitivityMethod.none) + solver.set_sensitivity_order(SensitivityOrder.none) elif arg == "forward_sensitivities": model.set_parameter_list(list(range(100))) - solver.set_sensitivity_method(amici.SensitivityMethod.forward) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_method(SensitivityMethod.forward) + solver.set_sensitivity_order(SensitivityOrder.first) elif arg == "adjoint_sensitivities": - solver.set_sensitivity_method(amici.SensitivityMethod.adjoint) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_method(SensitivityMethod.adjoint) + solver.set_sensitivity_order(SensitivityOrder.first) elif arg == "forward_simulation_non_optimal_parameters": tmp_par = model.get_free_parameters() model.set_free_parameters([0.1 for _ in tmp_par]) - solver.set_sensitivity_method(amici.SensitivityMethod.none) - solver.set_sensitivity_order(amici.SensitivityOrder.none) + solver.set_sensitivity_method(SensitivityMethod.none) + solver.set_sensitivity_order(SensitivityOrder.none) elif arg == "adjoint_sensitivities_non_optimal_parameters": tmp_par = model.get_free_parameters() model.set_free_parameters([0.1 for _ in tmp_par]) - solver.set_sensitivity_method(amici.SensitivityMethod.adjoint) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_method(SensitivityMethod.adjoint) + solver.set_sensitivity_order(SensitivityOrder.first) elif arg == "forward_steadystate_sensitivities_non_optimal_parameters": tmp_par = model.get_free_parameters() model.set_free_parameters([0.1 for _ in tmp_par]) - solver.set_sensitivity_method(amici.SensitivityMethod.forward) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_method(SensitivityMethod.forward) + solver.set_sensitivity_order(SensitivityOrder.first) model.set_steady_state_sensitivity_mode( - amici.SteadyStateSensitivityMode.newtonOnly + SteadyStateSensitivityMode.newtonOnly ) edata.set_timepoints([float("inf")]) elif arg == "adjoint_steadystate_sensitivities_non_optimal_parameters": tmp_par = model.get_free_parameters() model.set_free_parameters([0.1 for _ in tmp_par]) - solver.set_sensitivity_method(amici.SensitivityMethod.adjoint) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_method(SensitivityMethod.adjoint) + solver.set_sensitivity_order(SensitivityOrder.first) edata.set_timepoints([float("inf")]) else: print("Unknown argument:", arg) @@ -158,14 +166,14 @@ def main(): model = model_module.get_model() solver = model.create_solver() # TODO - edata = amici.ExpData(model) + edata = ExpData(model) edata.set_timepoints([1e8]) edata.set_observed_data([1.0]) edata.set_observed_data_std_dev([1.0]) prepare_simulation(arg, model, solver, edata) - rdata = amici.run_simulation(model, solver, edata) + rdata = run_simulation(model, solver, edata) check_results(rdata) diff --git a/tests/petab_test_suite/test_petab_suite.py b/tests/petab_test_suite/test_petab_suite.py index d2f39cffaa..8d866b6c09 100755 --- a/tests/petab_test_suite/test_petab_suite.py +++ b/tests/petab_test_suite/test_petab_suite.py @@ -4,15 +4,12 @@ import logging import sys -import amici import diffrax import pandas as pd import petab.v1 as petab import petabtests import pytest from _pytest.outcomes import Skipped -from amici import SteadyStateSensitivityMode -from amici.gradient_check import check_derivatives as amici_check_derivatives from amici.importers.petab.v1 import ( import_petab_problem, rdatas_to_measurement_df, @@ -20,6 +17,16 @@ ) from amici.importers.petab.v1.conditions import create_parameterized_edatas from amici.logging import get_logger, set_log_level +from amici.sim.sundials import ( + Model, + SensitivityMethod, + SensitivityOrder, + Solver, + SteadyStateSensitivityMode, +) +from amici.sim.sundials.gradient_check import ( + check_derivatives as amici_check_derivatives, +) logger = get_logger(__name__, logging.DEBUG) set_log_level(get_logger("amici.petab_import"), logging.DEBUG) @@ -187,8 +194,8 @@ def _test_case(case, model_type, version, jax): def check_derivatives( problem: petab.Problem, - model: amici.Model, - solver: amici.Solver, + model: Model, + solver: Solver, problem_parameters: dict[str, float], ) -> None: """Check derivatives using finite differences for all experimental @@ -200,8 +207,8 @@ def check_derivatives( solver: AMICI solver problem_parameters: Dictionary of problem parameters """ - solver.set_sensitivity_method(amici.SensitivityMethod.forward) - solver.set_sensitivity_order(amici.SensitivityOrder.first) + solver.set_sensitivity_method(SensitivityMethod.forward) + solver.set_sensitivity_order(SensitivityOrder.first) # Required for case 9 to not fail in # amici::NewtonSolver::computeNewtonSensis model.set_steady_state_sensitivity_mode( diff --git a/tests/petab_test_suite/test_petab_v2_suite.py b/tests/petab_test_suite/test_petab_v2_suite.py index b783595fd6..e30c56de38 100755 --- a/tests/petab_test_suite/test_petab_v2_suite.py +++ b/tests/petab_test_suite/test_petab_v2_suite.py @@ -8,14 +8,16 @@ import petabtests import pytest from _pytest.outcomes import Skipped -from amici import ( +from amici.importers.petab import * +from amici.logging import get_logger, set_log_level +from amici.sim.sundials import ( AMICI_SUCCESS, SensitivityMethod, SensitivityOrder, ) -from amici.gradient_check import check_derivatives as amici_check_derivatives -from amici.importers.petab import * -from amici.logging import get_logger, set_log_level +from amici.sim.sundials.gradient_check import ( + check_derivatives as amici_check_derivatives, +) from petab import v2 logger = get_logger(__name__, logging.DEBUG) diff --git a/tests/sbml/testSBMLSuite.py b/tests/sbml/testSBMLSuite.py index f794dcfdd3..d6f6b17eb0 100755 --- a/tests/sbml/testSBMLSuite.py +++ b/tests/sbml/testSBMLSuite.py @@ -23,11 +23,19 @@ import optimistix import pandas as pd import pytest -from amici.gradient_check import check_derivatives from amici.jax.petab import ( DEFAULT_CONTROLLER_SETTINGS, DEFAULT_ROOT_FINDER_SETTINGS, ) +from amici.sim.sundials import ( + AMICI_SUCCESS, + Model, + SensitivityMethod, + SensitivityOrder, + Solver, + run_simulation, +) +from amici.sim.sundials.gradient_check import check_derivatives from utils import ( apply_settings, find_model_file, @@ -77,8 +85,8 @@ def test_sbml_testsuite_case(test_id, result_path, sbml_semantic_cases_dir): atol, rtol = apply_settings(settings, solver, model, test_id) - solver.set_sensitivity_order(amici.SensitivityOrder.first) - solver.set_sensitivity_method(amici.SensitivityMethod.forward) + solver.set_sensitivity_order(SensitivityOrder.first) + solver.set_sensitivity_method(SensitivityMethod.forward) if test_id == "00885": # 00885: root-after-reinitialization with FSA with default settings @@ -86,8 +94,8 @@ def test_sbml_testsuite_case(test_id, result_path, sbml_semantic_cases_dir): solver.set_relative_tolerance(1e-15) # simulate model - rdata = amici.run_simulation(model, solver) - if rdata["status"] != amici.AMICI_SUCCESS: + rdata = run_simulation(model, solver) + if rdata["status"] != AMICI_SUCCESS: if test_id in ("00748", "00374", "00369"): pytest.skip("Simulation Failed expectedly") else: @@ -125,7 +133,7 @@ def compile_model( test_id: str, model_dir: Path, generate_sensitivity_code: bool = False, -) -> tuple[amici.Model, amici.Solver, amici.SbmlImporter]: +) -> tuple[Model, Solver, amici.SbmlImporter]: """Import the given test model to AMICI""" model_dir.mkdir(parents=True, exist_ok=True) @@ -163,7 +171,7 @@ def compile_model_jax(sbml_dir: Path, test_id: str, model_dir: Path): def jax_sensitivity_check( sbml_dir: Path, test_id: str, - amici_model: amici.Model, + amici_model: Model, rdata: dict, atol: float, rtol: float, @@ -246,11 +254,9 @@ def simulate(pars): if rdata["sx"] is None: solver_amici = amici_model.create_solver() - solver_amici.set_sensitivity_order(amici.SensitivityOrder.first) - solver_amici.set_sensitivity_method( - amici.SensitivityMethod.forward - ) - rdata = amici.run_simulation(amici_model, solver_amici) + solver_amici.set_sensitivity_order(SensitivityOrder.first) + solver_amici.set_sensitivity_method(SensitivityMethod.forward) + rdata = run_simulation(amici_model, solver_amici) np.testing.assert_allclose(x, rdata["x"], rtol=rtol, atol=atol) np.testing.assert_allclose(sx, rdata["sx"], rtol=rtol, atol=atol) diff --git a/tests/sbml/testSBMLSuiteJax.py b/tests/sbml/testSBMLSuiteJax.py index c6930aabb8..2ddb36820e 100644 --- a/tests/sbml/testSBMLSuiteJax.py +++ b/tests/sbml/testSBMLSuiteJax.py @@ -13,6 +13,7 @@ import pandas as pd import pytest from amici.jax.petab import DEFAULT_CONTROLLER_SETTINGS +from amici.sim.sundials import AMICI_SUCCESS from utils import ( find_model_file, read_settings_file, @@ -111,7 +112,7 @@ class RData(dict): ts=np.asarray(ts_jnp).copy(), y=np.asarray(y).copy(), w=np.asarray(w).copy(), - status=amici.AMICI_SUCCESS, + status=AMICI_SUCCESS, )