diff --git a/.github/workflows/deploy_release.yml b/.github/workflows/deploy_release.yml index 0c5729c553..ce493533e7 100644 --- a/.github/workflows/deploy_release.yml +++ b/.github/workflows/deploy_release.yml @@ -36,11 +36,11 @@ jobs: scripts/buildSdist.sh - name: Publish a Python distribution to PyPI - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.pypi_password }} - packages_dir: python/sdist/dist + packages-dir: python/sdist/dist bioSimulatorsUpdateCliAndDockerImage: name: Release to BioSimulators diff --git a/.github/workflows/test_python_cplusplus.yml b/.github/workflows/test_python_cplusplus.yml index 3bc7f8c920..8a4eaa3bb8 100644 --- a/.github/workflows/test_python_cplusplus.yml +++ b/.github/workflows/test_python_cplusplus.yml @@ -36,7 +36,7 @@ jobs: - run: echo "BNGPATH=${GITHUB_WORKSPACE}/ThirdParty/BioNetGen-2.7.0" >> $GITHUB_ENV # sonar cloud - - run: echo "SONAR_SCANNER_VERSION=4.6.2.2472" >> $GITHUB_ENV + - run: echo "SONAR_SCANNER_VERSION=4.7.0.2747" >> $GITHUB_ENV - run: echo "SONAR_SCANNER_HOME=${HOME}/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux" >> $GITHUB_ENV - run: echo "SONAR_SCANNER_OPTS=-server" >> $GITHUB_ENV - run: echo "${SONAR_SCANNER_HOME}/bin" >> $GITHUB_PATH diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a3e07b657..0ab17965d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,27 @@ ## v0.X Series +### v0.18.1 (2023-06-26) + +Fixes: +* Fixed pysb pattern matching during PEtab import + by @FFroehlich in https://github.com/AMICI-dev/AMICI/pull/2118 +* Fixed `sp.Matrix` errors with `numpy==1.25` + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2124 +* Readme: added info containers + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2125 +* Fixed deprecation warnings + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2122 + https://github.com/AMICI-dev/AMICI/pull/2131 +* Fixed logging typo in SBML import + by @dilpath in https://github.com/AMICI-dev/AMICI/pull/2126 +* Added minimum version for `pandas` + by @dilpath in https://github.com/AMICI-dev/AMICI/pull/2129 + +**Full Changelog**: https://github.com/AMICI-dev/AMICI/compare/v0.18.0...v0.18.1 + ### v0.18.0 (2023-05-26) + Features: * More efficient handling of splines in SBML models by @paulstapor, @lcontento, @dweindl @@ -10,7 +30,7 @@ Features: * Partial support of current PEtab2.0 draft, including support for PySB models by @dweindl, @FFroehlich in https://github.com/AMICI-dev/AMICI/pull/1800 -Fixes +Fixes: * **Fixed incorrect forward sensitivities for models with events with** **state-dependent trigger functions** by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2084 diff --git a/README.md b/README.md index 006ae200dc..7b45537dc3 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ To install AMICI, first read the installation instructions for [Python](https://amici.readthedocs.io/en/latest/python_installation.html), [C++](https://amici.readthedocs.io/en/develop/cpp_installation.html) or [Matlab](https://amici.readthedocs.io/en/develop/matlab_installation.html). +There are also instructions for using AMICI inside +[containers](https://github.com/AMICI-dev/AMICI/tree/master/container). To get you started with Python-AMICI, the best way might be checking out this [Jupyter notebook](https://github.com/AMICI-dev/AMICI/blob/master/documentation/GettingStarted.ipynb) diff --git a/pytest.ini b/pytest.ini index 4bdaa3c9a1..cebd4ab2c2 100644 --- a/pytest.ini +++ b/pytest.ini @@ -3,11 +3,19 @@ addopts = -vv --strict-markers filterwarnings = + error + # amici + ignore:Conservation laws for non-constant species in models with RateRules are currently not supported and will be turned off.:UserWarning + ignore:Conservation laws for non-constant species in models with Species-AssignmentRules are currently not supported and will be turned off.:UserWarning + ignore:Conservation laws for non-constant species in combination with parameterized stoichiometric coefficients are not currently supported and will be turned off.:UserWarning + ignore:Support for PEtab2.0 is experimental!:UserWarning # hundreds of SBML <=5.17 warnings ignore:.*inspect.getargspec\(\) is deprecated.*:DeprecationWarning # pysb warnings ignore:the imp module is deprecated in favour of importlib.*:DeprecationWarning:pysb\.core ignore:Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working.*:DeprecationWarning:pysb\.core ignore:Model.initial_conditions will be removed in a future version. Instead, you can get a list of Initial objects with Model.initials.:DeprecationWarning:pysb\.core + # https://github.com/pytest-dev/pytest-xdist/issues/825#issuecomment-1292283870 + ignore:The --rsyncdir command line argument and rsyncdirs config variable are deprecated.:DeprecationWarning norecursedirs = .git amici_models build doc documentation matlab models ThirdParty amici sdist examples diff --git a/python/sdist/amici/petab_util.py b/python/sdist/amici/petab_util.py index 31f1ae1313..9108b108bc 100644 --- a/python/sdist/amici/petab_util.py +++ b/python/sdist/amici/petab_util.py @@ -58,6 +58,11 @@ def get_states_in_condition_table( return states import pysb.pattern + if not petab_problem.model.model.species: + import pysb.bng + + pysb.bng.generate_equations(petab_problem.model.model) + try: spm = pysb.pattern.SpeciesPatternMatcher( model=petab_problem.model.model diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index 365e3441a6..7abd0450a9 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -18,6 +18,7 @@ import libsbml as sbml import numpy as np import sympy as sp +from sympy.logic.boolalg import BooleanFalse, BooleanTrue from . import has_clibs from .constants import SymbolId @@ -214,7 +215,7 @@ def _process_document(self) -> None: conversion_properties.addOption("performValidation", False) conversion_properties.addOption("abortIfUnflattenable", "none") if ( - log_execution_time("converting SBML local parameters", logger)( + log_execution_time("flattening hierarchical SBML", logger)( self.sbml_doc.convert )(conversion_properties) != sbml.LIBSBML_OPERATION_SUCCESS @@ -1047,7 +1048,12 @@ def _process_reactions(self): reaction.getKineticLaw() or sp.Float(0) ) - self.flux_vector[reaction_index] = sym_math + self.flux_vector[reaction_index] = sym_math.subs( + { + BooleanTrue(): sp.Float(1.0), + BooleanFalse(): sp.Float(0.0), + } + ) if any( str(symbol) in reaction_ids for symbol in self.flux_vector[reaction_index].free_symbols diff --git a/python/sdist/setup.cfg b/python/sdist/setup.cfg index 733a2a4938..ecf0a74c0a 100644 --- a/python/sdist/setup.cfg +++ b/python/sdist/setup.cfg @@ -35,7 +35,7 @@ install_requires = numpy; python_version>='3.12' python-libsbml h5py - pandas + pandas>=2.0.2 wurlitzer toposort setuptools>=48 diff --git a/python/tests/splines_utils.py b/python/tests/splines_utils.py index 0e1ebf27b4..e1c0c4352c 100644 --- a/python/tests/splines_utils.py +++ b/python/tests/splines_utils.py @@ -47,7 +47,6 @@ def integrate_spline( params: Union[Dict, None], tt: Sequence[float], initial_value: float = 0, - **kwargs, ): """ Integrate the `AbstractSpline` `spline` at timepoints `tt` @@ -56,7 +55,7 @@ def integrate_spline( ispline = [initial_value + spline.integrate(0, t) for t in tt] if params is not None: ispline = [x.subs(params) for x in ispline] - return np.asarray(ispline, **kwargs) + return ispline def create_condition_table() -> pd.DataFrame: @@ -213,10 +212,13 @@ def create_petab_problem( dt /= measure_upsample n_obs = math.ceil(T / dt) + 1 tt_obs = np.linspace(0, float(T), n_obs) - zz_true = [ - integrate_spline(spline, params_true, tt_obs, iv, dtype=float) - for (spline, iv) in zip(splines, initial_values) - ] + zz_true = np.array( + [ + integrate_spline(spline, params_true, tt_obs, iv) + for (spline, iv) in zip(splines, initial_values) + ], + dtype=float, + ) zz_obs = [zz + sigma * np.random.randn(len(zz)) for zz in zz_true] # Create PEtab tables @@ -263,7 +265,7 @@ def create_petab_problem( folder = os.path.abspath(folder) os.makedirs(folder, exist_ok=True) problem.to_files( - sbml_file=os.path.join(folder, f"{model_name}_model.xml"), + model_file=os.path.join(folder, f"{model_name}_model.xml"), condition_file=os.path.join(folder, f"{model_name}_conditions.tsv"), measurement_file=os.path.join(folder, f"{model_name}_measurements.tsv"), parameter_file=os.path.join(folder, f"{model_name}_parameters.tsv"), diff --git a/python/tests/test_events.py b/python/tests/test_events.py index b69c271734..c562f3c4fc 100644 --- a/python/tests/test_events.py +++ b/python/tests/test_events.py @@ -164,7 +164,7 @@ def get_early_x(t): tmp_x = expm(event_1_time * A) x1 = np.matmul(tmp_x, x0) # apply bolus - delta_x = np.array([[float(-x1[2, :] / 2)], [0], [0]]) + delta_x = np.array([[float(-x1[2, 0] / 2)], [0], [0]]) x1 += delta_x # "simulate" on tmp_x = expm((t - event_1_time) * A) @@ -425,7 +425,11 @@ def model_definition_event_state_dep_ddeltax_dtpx(): timepoints = np.linspace(0.0, 5.0, 100) events = { # state-dependent ddeltaxdt - "event_1": {"trigger": "time > alpha", "target": "x_1", "assignment": "x_1 * time"}, + "event_1": { + "trigger": "time > alpha", + "target": "x_1", + "assignment": "x_1 * time", + }, # state-dependent ddeltaxdp "event_2": { "trigger": "time > beta", @@ -453,7 +457,9 @@ def x_expected(t, x_1_0, alpha, beta, gamma, delta): x = ((x_1_0 + alpha) * alpha + (beta - alpha)) * delta + (t - beta) else: # after third event triggered - x = (((x_1_0 + alpha) * alpha + (beta - alpha)) * delta + (gamma - beta)) ** 2 * 2 + (t - gamma) + x = ( + ((x_1_0 + alpha) * alpha + (beta - alpha)) * delta + (gamma - beta) + ) ** 2 * 2 + (t - gamma) return np.array((x,)) diff --git a/python/tests/test_pysb.py b/python/tests/test_pysb.py index 334fca208d..5673667e3f 100644 --- a/python/tests/test_pysb.py +++ b/python/tests/test_pysb.py @@ -341,6 +341,7 @@ def test_heavyside_and_special_symbols(): @skip_on_valgrind def test_energy(): + pysb.SelfExporter.cleanup() model_pysb = pysb.Model("energy") pysb.Monomer("A", ["a", "b"]) pysb.Monomer("B", ["a"]) diff --git a/python/tests/valgrind-python.supp b/python/tests/valgrind-python.supp index dde0c74cf7..26a9f0e7d1 100644 --- a/python/tests/valgrind-python.supp +++ b/python/tests/valgrind-python.supp @@ -761,3 +761,17 @@ Memcheck:Value8 fun:dictkeys_get_index } + +{ + Python os_stat / PyFloat_FromDouble + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:PyFloat_FromDouble + fun:fill_time + fun:_pystat_fromstructstat + fun:posix_do_stat.constprop.0 + fun:os_stat_impl + fun:os_stat + ... +} diff --git a/scripts/run-valgrind-py.sh b/scripts/run-valgrind-py.sh index 45e565c756..510e27868a 100755 --- a/scripts/run-valgrind-py.sh +++ b/scripts/run-valgrind-py.sh @@ -24,4 +24,8 @@ PYTHONMALLOC=malloc valgrind \ --leak-check=full \ --gen-suppressions=all \ -v \ - python -m pytest -vv --ignore-glob=*petab* + python -m pytest -vv --ignore-glob=*petab* -W "ignore:Signature " +# ^ ignores the following warning that occurs only under valgrind, +# e.g. `valgrind python -c "import h5py"`: +# UserWarning: Signature b'\x00\xd0\xcc\xcc\xcc\xcc\xcc\xcc\xfb\xbf\x00\x00\x00\x00\x00\x00' +# for does not match any known type: falling back to type probe function. diff --git a/tests/benchmark-models/benchmark_models.yaml b/tests/benchmark-models/benchmark_models.yaml index 4e196e5261..8550c9ca38 100644 --- a/tests/benchmark-models/benchmark_models.yaml +++ b/tests/benchmark-models/benchmark_models.yaml @@ -23,7 +23,7 @@ Borghans_BiophysChem1997: llh: 83.3237191357272 t_sim: 0.005 t_fwd: 0.5 - t_adj: 0.1 + t_adj: 0.2 note: benchmark collection reference value matches up to sign when applying log10-correction +sum(log(meas*log(10)) / 2 Brannmark_JBC2010: diff --git a/tests/benchmark-models/test_petab_benchmark.py b/tests/benchmark-models/test_petab_benchmark.py index 40071b5ecb..91bd117a81 100755 --- a/tests/benchmark-models/test_petab_benchmark.py +++ b/tests/benchmark-models/test_petab_benchmark.py @@ -50,6 +50,7 @@ debug_path.mkdir(exist_ok=True, parents=True) +@pytest.mark.filterwarnings("ignore:divide by zero encountered in log10") @pytest.mark.parametrize("scale", (True, False)) @pytest.mark.parametrize("model", models) def test_benchmark_gradient(model, scale): diff --git a/tests/benchmark-models/test_petab_model.py b/tests/benchmark-models/test_petab_model.py index c31255f9da..5742d668c6 100755 --- a/tests/benchmark-models/test_petab_model.py +++ b/tests/benchmark-models/test_petab_model.py @@ -148,7 +148,7 @@ def main(): ] res = res_repeats[0] - times[label] = np.mean( + times[label] = np.min( [ sum(r.cpu_time + r.cpu_timeB for r in res[RDATAS]) / 1000 # only forwards/backwards simulation diff --git a/version.txt b/version.txt index 66333910a4..249afd517d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.18.0 +0.18.1