Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ See also our [versioning policy](https://amici.readthedocs.io/en/latest/versioni
* The import function `sbml2amici`, `pysb2amici`, and `antimony2amici` now
return an instance of the generated model class if called with `compile=True`
(default).
* The default directory for model import changed, and a base directory
can now be specified via the `AMICI_MODELS_ROOT` environment variable.
See `amici.get_model_dir` for details.

## v0.X Series

Expand Down
47 changes: 47 additions & 0 deletions python/sdist/amici/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,53 @@ def _imported_from_setup() -> bool:
return False


def get_model_root_dir() -> Path:
"""Get the default root directory for AMICI models.

:return:
The model root directory.
This defaults to `{base_dir}/{amici_version}`.
If the environment variable `AMICI_MODELS_ROOT` is set,
it is used as `base_dir`, otherwise `amici_models` in the current
working directory.
"""
try:
base_dir = Path(os.environ["AMICI_MODELS_ROOT"])
except KeyError:
base_dir = Path("amici_models")

return base_dir / __version__


def get_model_dir(model_id: str | None = None, jax: bool = False) -> Path:
"""Get the default directory for the model with the given ID.

:param model_id:
The model ID.
:param jax:
Whether to get the model directory for a JAX model.
If `True`, a suffix `_jax` is appended to the `model_id`.
:return:
The model directory.
This defaults to `{root_dir}/{model_id}`, where `root_dir` is
determined via :func:`get_model_root_dir`.
If `model_id` is `None`, a temporary directory is created in
`{base_dir}/{amici_version}` and returned.
"""
base_dir = get_model_root_dir()

suffix = "_jax" if jax else ""

if model_id is None:
import tempfile

return Path(
tempfile.mkdtemp(dir=base_dir / __version__), suffix=suffix
)

return base_dir / __version__ / (model_id + suffix)


# Initialize AMICI paths
#: absolute root path of the amici repository or Python package
amici_path = _get_amici_path()
Expand Down
3 changes: 2 additions & 1 deletion python/sdist/amici/de_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
amiciModulePath,
amiciSrcPath,
amiciSwigPath,
get_model_dir,
splines,
)
from ._codegen.cxx_functions import (
Expand Down Expand Up @@ -1311,7 +1312,7 @@ def set_paths(self, output_dir: str | Path | None = None) -> None:

"""
if output_dir is None:
output_dir = os.path.join(os.getcwd(), f"amici-{self.model_name}")
output_dir = get_model_dir(self.model_name)

self.model_path = os.path.abspath(output_dir)
self.model_swig_path = os.path.join(self.model_path, "swig")
Expand Down
17 changes: 4 additions & 13 deletions python/sdist/amici/petab/petab_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def import_petab_problem(

:param model_output_dir:
Directory to write the model code to. It will be created if it doesn't
exist. Defaults to current directory.
exist. Defaults to :func:`amici.get_model_dir`.

:param model_name:
Name of the generated model module. Defaults to the ID of the model
Expand Down Expand Up @@ -99,20 +99,11 @@ def import_petab_problem(

# generate folder and model name if necessary
if model_output_dir is None:
if petab_problem.model.type_id == MODEL_TYPE_PYSB:
raise ValueError("Parameter `model_output_dir` is required.")

from .sbml_import import _create_model_output_dir_name

model_output_dir = _create_model_output_dir_name(
petab_problem.sbml_model, model_name, jax=jax
)
model_output_dir = amici.get_model_dir(model_name, jax=jax).absolute()
else:
model_output_dir = os.path.abspath(model_output_dir)
model_output_dir = Path(model_output_dir).absolute()

# create folder
if not os.path.exists(model_output_dir):
os.makedirs(model_output_dir)
model_output_dir.mkdir(parents=True, exist_ok=True)

# check if compilation necessary
if compile_ or (
Expand Down
27 changes: 0 additions & 27 deletions python/sdist/amici/petab/sbml_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import math
import os
import re
import tempfile
from _collections import OrderedDict
from itertools import chain
from pathlib import Path
Expand Down Expand Up @@ -604,29 +603,3 @@ def _get_fixed_parameters_sbml(
continue

return list(sorted(fixed_parameters))


def _create_model_output_dir_name(
sbml_model: "libsbml.Model",
model_name: str | None = None,
jax: bool = False,
) -> Path:
"""
Find a folder for storing the compiled amici model.
If possible, use the sbml model id, otherwise create a random folder.
The folder will be located in the `amici_models` subfolder of the current
folder.
"""
BASE_DIR = Path("amici_models").absolute()
BASE_DIR.mkdir(exist_ok=True)
# try model_name
suffix = "_jax" if jax else ""
if model_name:
return BASE_DIR / (model_name + suffix)

# try sbml model id
if sbml_model_id := sbml_model.getId():
return BASE_DIR / (sbml_model_id + suffix)

# create random folder name
return Path(tempfile.mkdtemp(dir=BASE_DIR))
2 changes: 1 addition & 1 deletion python/sdist/amici/pysb_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ def pysb2amici(
constant_parameters = []

model_name = model_name or model.name

output_dir = output_dir or amici.get_model_dir(model_name)
set_log_level(logger, verbose)
ode_model = ode_model_from_pysb_importer(
model,
Expand Down
5 changes: 4 additions & 1 deletion python/sdist/amici/sbml_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import amici

from . import has_clibs
from . import get_model_dir, has_clibs
from .constants import SymbolId
from .de_export import (
DEExporter,
Expand Down Expand Up @@ -317,6 +317,7 @@ def sbml2amici(

:param output_dir:
Directory where the generated model package will be stored.
Defaults to :func:`amici.get_model_dir`.

:param constant_parameters:
list of SBML Ids identifying constant parameters
Expand Down Expand Up @@ -398,6 +399,8 @@ def sbml2amici(
hardcode_symbols=hardcode_symbols,
)

output_dir = output_dir or get_model_dir(model_name)

exporter = DEExporter(
ode_model,
model_name=model_name,
Expand Down
6 changes: 5 additions & 1 deletion python/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import copy
import importlib
import os
import sys
from pathlib import Path

Expand All @@ -12,7 +13,8 @@

pytest_plugins = ["amici.testing.fixtures"]

EXAMPLES_DIR = Path(__file__).parents[2] / "doc" / "examples"
REPO_ROOT = Path(__file__).parents[2]
EXAMPLES_DIR = REPO_ROOT / "doc" / "examples"
TEST_DIR = Path(__file__).parent
MODEL_STEADYSTATE_SCALED_XML = (
EXAMPLES_DIR / "getting_started" / "model_steadystate_scaled.xml"
Expand All @@ -21,6 +23,8 @@
EXAMPLES_DIR / "example_presimulation" / "model_presimulation.xml"
)

os.environ.setdefault("AMICI_MODELS_ROOT", str(REPO_ROOT.absolute()))


@pytest.fixture(scope="session")
def sbml_example_presimulation_module():
Expand Down
4 changes: 2 additions & 2 deletions tests/benchmark_models/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import benchmark_models_petab
import petab.v1 as petab
import pytest
from amici import get_model_root_dir
from amici.petab.petab_import import import_petab_problem
from petab.v1.lint import measurement_table_has_timepoint_specific_mappings

Expand All @@ -14,8 +15,7 @@

from test_petab_benchmark import problems

repo_root = script_dir.parent.parent
benchmark_outdir = repo_root / "test_bmc"
benchmark_outdir = get_model_root_dir() / "test_bmc"


@pytest.fixture(scope="session", params=problems, ids=problems)
Expand Down
5 changes: 2 additions & 3 deletions tests/benchmark_models/test_petab_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import petab.v1 as petab
import pytest
import yaml
from amici import SensitivityMethod
from amici import SensitivityMethod, get_model_root_dir
from amici.adapters.fiddy import simulate_petab_to_cached_functions
from amici.logging import get_logger
from amici.petab.petab_import import import_petab_problem
Expand All @@ -44,8 +44,7 @@
)

script_dir = Path(__file__).parent.absolute()
repo_root = script_dir.parent.parent
benchmark_outdir = repo_root / "test_bmc"
benchmark_outdir = get_model_root_dir() / "test_bmc"
debug_path = script_dir / "debug"
if debug:
debug_path.mkdir(exist_ok=True, parents=True)
Expand Down
2 changes: 0 additions & 2 deletions tests/petab_test_suite/test_petab_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,8 @@ def _test_case(case, model_type, version, jax):
model_name = (
f"petab_{model_type}_test_case_{case}_{version.replace('.', '_')}"
)
model_output_dir = f"amici_models/{model_name}" + ("_jax" if jax else "")
imported = import_petab_problem(
petab_problem=problem,
model_output_dir=model_output_dir,
model_name=model_name,
compile_=True,
jax=jax,
Expand Down
Loading