├── .coveragerc ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── ci_tests.yml │ └── deploy.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .pylintrc ├── .readthedocs.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── doc ├── CHANGELOG.md ├── Makefile ├── _static │ ├── custom.css │ └── petab_schema.yaml ├── conf.py ├── development.rst ├── example.rst ├── example │ ├── example_Fujita │ │ ├── Fujita.yaml │ │ ├── Fujita_experimentalCondition.tsv │ │ ├── Fujita_measurementData.tsv │ │ ├── Fujita_measurementData_minimal.tsv │ │ ├── Fujita_measurementData_nanData.tsv │ │ ├── Fujita_measurementData_t_inf.tsv │ │ ├── Fujita_measurementData_wrongNoise.tsv │ │ ├── Fujita_model.xml │ │ ├── Fujita_observables.tsv │ │ ├── Fujita_parameters.tsv │ │ ├── Fujita_parameters_scaling.tsv │ │ ├── Fujita_simulatedData.tsv │ │ ├── Fujita_simulatedData_t_inf.tsv │ │ ├── Fujita_visuSpec_small.tsv │ │ └── visuSpecs │ │ │ ├── Fujita_visuSpec_1.tsv │ │ │ ├── Fujita_visuSpec_2.tsv │ │ │ ├── Fujita_visuSpec_3.tsv │ │ │ ├── Fujita_visuSpec_datasetIds.tsv │ │ │ ├── Fujita_visuSpec_empty.tsv │ │ │ ├── Fujita_visuSpec_individual_datasets.tsv │ │ │ ├── Fujita_visuSpec_mandatory.tsv │ │ │ └── Fujita_visuSpec_replicates.tsv │ ├── example_Isensee │ │ ├── Isensee.yaml │ │ ├── Isensee_experimentalCondition.tsv │ │ ├── Isensee_measurementData.tsv │ │ ├── Isensee_no_vis.yaml │ │ ├── Isensee_simulationData.tsv │ │ ├── Isensee_visualizationSpecification.tsv │ │ ├── Isensee_visualizationSpecification_replicates.tsv │ │ └── Isensee_visualizationSpecification_scatterplot.tsv │ ├── example_petablint.ipynb │ └── example_visualization.ipynb ├── gfx │ ├── copasi_simulation.png │ ├── petab_files.pdf │ ├── petab_files.png │ ├── petab_files.svg │ ├── petab_files_inkscape.svg │ ├── petab_scope_and_files.pdf │ ├── petab_scope_and_files.png │ ├── petab_scope_and_files.svg │ ├── tutorial_data.png │ └── tutorial_model.png ├── how_to_cite.rst ├── index.rst ├── license.rst ├── logo │ ├── LICENSE.md │ ├── PEtab.pdf │ ├── PEtab.png │ ├── PEtab.svg │ ├── PEtab_github.png │ ├── PEtab_github.svg │ └── PEtab_raw.svg ├── make.bat ├── md2rst.py ├── modules.rst └── tutorial │ ├── Boehm_JProteomeRes2014.yaml │ ├── experimental_conditions.tsv │ ├── measurement_data.tsv │ ├── model_Boehm_JProteomeRes2014.xml │ ├── observables.tsv │ ├── parameters.tsv │ └── visualization_specification.tsv ├── petab ├── __init__.py ├── petablint.py ├── schemas │ ├── petab_schema.v1.0.0.yaml │ └── petab_schema.v2.0.0.yaml ├── v1 │ ├── C.py │ ├── __init__.py │ ├── calculate.py │ ├── composite_problem.py │ ├── conditions.py │ ├── core.py │ ├── format_version.py │ ├── lint.py │ ├── mapping.py │ ├── math │ │ ├── PetabMathExprLexer.g4 │ │ ├── PetabMathExprParser.g4 │ │ ├── SympyVisitor.py │ │ ├── __init__.py │ │ ├── _generated │ │ │ ├── PetabMathExprLexer.interp │ │ │ ├── PetabMathExprLexer.py │ │ │ ├── PetabMathExprLexer.tokens │ │ │ ├── PetabMathExprParser.interp │ │ │ ├── PetabMathExprParser.py │ │ │ ├── PetabMathExprParser.tokens │ │ │ ├── PetabMathExprParserVisitor.py │ │ │ └── __init__.py │ │ ├── regenerate.sh │ │ └── sympify.py │ ├── measurements.py │ ├── models │ │ ├── __init__.py │ │ ├── model.py │ │ ├── pysb_model.py │ │ └── sbml_model.py │ ├── observables.py │ ├── parameter_mapping.py │ ├── parameters.py │ ├── priors.py │ ├── problem.py │ ├── sampling.py │ ├── sbml.py │ ├── simplify.py │ ├── simulate.py │ ├── visualize │ │ ├── __init__.py │ │ ├── cli.py │ │ ├── data_overview.py │ │ ├── helper_functions.py │ │ ├── lint.py │ │ ├── plot_data_and_simulation.py │ │ ├── plot_residuals.py │ │ ├── plotter.py │ │ ├── plotting.py │ │ └── templates │ │ │ ├── mystyle.css │ │ │ └── report.html │ └── yaml.py ├── v2 │ ├── C.py │ ├── __init__.py │ ├── lint.py │ ├── models │ │ ├── __init__.py │ │ ├── model.py │ │ ├── pysb_model.py │ │ └── sbml_model.py │ ├── petab1to2.py │ └── problem.py ├── version.py └── versions.py ├── pyproject.toml ├── pytest.ini ├── requirements-dev.txt ├── setup.py ├── tests ├── __init__.py ├── test_deprecation_warnings.py ├── v1 │ ├── __init__.py │ ├── math │ │ ├── __init__.py │ │ └── test_math.py │ ├── test_calculate.py │ ├── test_combine.py │ ├── test_conditions.py │ ├── test_deprecated.py │ ├── test_lint.py │ ├── test_mapping.py │ ├── test_measurements.py │ ├── test_model_pysb.py │ ├── test_observables.py │ ├── test_parameter_mapping.py │ ├── test_parameters.py │ ├── test_petab.py │ ├── test_priors.py │ ├── test_sbml.py │ ├── test_simplify.py │ ├── test_simulate.py │ ├── test_visualization.py │ ├── test_visualization_data_overview.py │ └── test_yaml.py └── v2 │ ├── __init__.py │ ├── test_conversion.py │ └── test_problem.py └── tox.ini /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | source = petab 4 | 5 | [report] 6 | exclude_lines = 7 | if self.debug: 8 | pragma: no cover 9 | raise NotImplementedError 10 | if __name__ == .__main__.: 11 | ignore_errors = True 12 | omit = 13 | tests/* 14 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # see https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 2 | 3 | # default owners 4 | * @PEtab-dev/libpetab-python-maintainers 5 | 6 | /petab/visualize/ @m-philipps 7 | /tests/test_vis* @m-philipps 8 | /petab/simulate.py @dilpath 9 | /tests/test_simulate.py @dilpath 10 | /doc/ @dweindl 11 | /doc/example @m-philipps 12 | /doc/example/example_petablint.ipynb @dweindl 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | ignore: 9 | - dependency-name: "*" 10 | update-types: ["version-update:semver-patch", "version-update:semver-minor"] 11 | -------------------------------------------------------------------------------- /.github/workflows/ci_tests.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | schedule: 8 | - cron: '48 4 * * *' 9 | 10 | jobs: 11 | build: 12 | strategy: 13 | matrix: 14 | platform: [windows-latest, macos-latest, ubuntu-latest] 15 | python-version: ["3.10", "3.12"] 16 | runs-on: ${{ matrix.platform }} 17 | 18 | steps: 19 | - name: Check out repository 20 | uses: actions/checkout@v4 21 | 22 | - name: Prepare python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | 27 | - name: Get pip cache directory 28 | id: pip_cache_dir 29 | run: | 30 | echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT 31 | shell: bash 32 | 33 | - name: Cache 34 | uses: actions/cache@v4 35 | with: 36 | path: ${{ steps.pip_cache_dir.outputs.dir }} 37 | key: ${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/.ci_pip_reqs.txt') }}-${{ hashFiles('**/setup.py') }} 38 | restore-keys: | 39 | ${{ runner.os }}-${{ matrix.python-version }}- 40 | 41 | - name: Install dependencies 42 | run: | 43 | python -m pip install --upgrade pip wheel 44 | pip install -r requirements-dev.txt 45 | 46 | - name: Quality tests 47 | run: tox -e quality 48 | if: matrix.platform == 'ubuntu-latest' 49 | 50 | - name: Unit tests 51 | run: tox -e unit 52 | 53 | - name: Coverage 54 | uses: codecov/codecov-action@v4 55 | with: 56 | token: ${{ secrets.CODECOV_TOKEN }} 57 | file: ./coverage.xml 58 | if: matrix.platform == 'ubuntu-latest' 59 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | environment: 11 | name: pypi 12 | url: https://pypi.org/p/sbmlmath 13 | permissions: 14 | id-token: write 15 | 16 | steps: 17 | - name: Check out repository 18 | uses: actions/checkout@v4 19 | - name: Set up python 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: 3.11 23 | 24 | - name: Install dependencies / build sdist 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install setuptools wheel build 28 | python -m build -s 29 | 30 | - name: Publish a Python distribution to PyPI 31 | uses: pypa/gh-action-pypi-publish@release/v1 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | # Pycharm 107 | .idea 108 | 109 | # macOS files 110 | *.DS_Store 111 | 112 | # vim 113 | *.swp 114 | 115 | _untracked 116 | doc/_static/README.rst 117 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.4.0 6 | hooks: 7 | - id: check-added-large-files 8 | - id: check-merge-conflict 9 | - id: check-yaml 10 | args: [--allow-multiple-documents] 11 | - id: end-of-file-fixer 12 | - id: trailing-whitespace 13 | - repo: https://github.com/astral-sh/ruff-pre-commit 14 | # Ruff version. 15 | rev: v0.1.11 16 | hooks: 17 | # Run the linter. 18 | - id: ruff 19 | args: 20 | - --fix 21 | - --config 22 | - pyproject.toml 23 | 24 | # Run the formatter. 25 | - id: ruff-format 26 | args: 27 | - --config 28 | - pyproject.toml 29 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | version: 2 5 | 6 | sphinx: 7 | configuration: doc/conf.py 8 | fail_on_warning: false 9 | 10 | build: 11 | os: "ubuntu-22.04" 12 | tools: 13 | python: "3.10" 14 | 15 | python: 16 | install: 17 | - method: pip 18 | path: . 19 | extra_requirements: 20 | - doc 21 | - vis 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # petab contribution guide 2 | 3 | We are happy about contributions to PEtab of any form. 4 | 5 | ## Contributions to this repository 6 | 7 | General: 8 | 9 | * For code contributions, please adhere to the 10 | [PEP8 style guide](https://www.python.org/dev/peps/pep-0008/) 11 | * All new functionality should be covered by unit tests 12 | * Please use Python type hints 13 | * Please document all modules, functions, classes, attributes, arguments, 14 | return values, ... in a style consistent with the rest of the library 15 | * Use descriptive commit messages 16 | 17 | To contribute to this repository: 18 | 19 | * Create a pull request 20 | 21 | *By creating a pull request you agree with your contribution being made 22 | available under the license terms specified in 23 | [https://github.com/PEtab-dev/libpetab-python/blob/master/LICENSE](https://github.com/PEtab-dev/libpetab-python/blob/master/LICENSE).* 24 | 25 | * Assign a reviewer, or let us know otherwise, that your pull request is ready 26 | for review. 27 | 28 | * Wait for feedback (and feel free so send a gentle reminder if you did not 29 | get any feedback within a week) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 petab package developers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include petab/schemas *.yaml 2 | recursive-include petab/v1/visualize/templates * 3 | recursive-exclude tests * 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI](https://github.com/PEtab-dev/libpetab-python/actions/workflows/ci_tests.yml/badge.svg?branch=main)](https://github.com/PEtab-dev/libpetab-python/actions/workflows/ci_tests.yml) 2 | [![codecov](https://codecov.io/gh/PEtab-dev/libpetab-python/branch/main/graph/badge.svg)](https://codecov.io/gh/PEtab-dev/libpetab-python) 3 | [![PyPI version](https://badge.fury.io/py/petab.svg)](https://badge.fury.io/py/petab) 4 | 5 | # petab - a Python package for handling PEtab files 6 | 7 | [PEtab](https://petab.readthedocs.io/) is a data format for specifying 8 | parameter estimation problems in systems biology. This repository provides 9 | the `petab` Python package for reading, writing and validating PEtab files. 10 | 11 | ## Documentation 12 | 13 | Documentation of the `petab` Python package is available at 14 | [https://libpetab-python.readthedocs.io/en/latest/](https://libpetab-python.readthedocs.io/en/latest/). 15 | Documentation of the PEtab format in general is available at 16 | [https://petab.readthedocs.io/en/latest/](https://petab.readthedocs.io/en/latest/). 17 | 18 | ## Installation 19 | 20 | The PEtab library is available on [pypi](https://pypi.org/project/petab/) 21 | and the easiest way to install it is running 22 | 23 | pip3 install petab 24 | 25 | It will require Python>=3.10 to run. (We are following the 26 | [numpy Python support policy](https://numpy.org/neps/nep-0029-deprecation_policy.html)). 27 | 28 | Development versions of the PEtab library can be installed using 29 | 30 | pip3 install https://github.com/PEtab-dev/libpetab-python/archive/develop.zip 31 | 32 | (replace `develop` by the branch or commit you would like to install). 33 | 34 | When setting up a new parameter estimation problem, the most useful tools will 35 | be: 36 | 37 | - The [PEtab validator](https://petab.readthedocs.io/projects/libpetab-python/en/latest/example/example_petablint.html), 38 | which is automatically installed using Python 39 | entrypoints to be available as a shell command from anywhere, called 40 | `petablint` 41 | 42 | - [petab.create_parameter_df](https://petab.readthedocs.io/projects/libpetab-python/en/latest/build/_autosummary/petab.parameters.html#petab.parameters.create_parameter_df) 43 | to create the parameter table, once you have set up the model, 44 | condition table, observable table and measurement table 45 | 46 | - [petab.create_combine_archive](https://petab.readthedocs.io/projects/libpetab-python/en/latest/build/_autosummary/petab.core.html#petab.core.create_combine_archive) 47 | to create a [COMBINE Archive](https://combinearchive.org/index/) from PEtab 48 | files 49 | 50 | ## Examples 51 | 52 | Examples for PEtab Python library usage: 53 | 54 | * [Validation](https://github.com/PEtab-dev/libpetab-python/blob/main/doc/example/example_petablint.ipynb) 55 | * [Visualization](https://github.com/PEtab-dev/libpetab-python/blob/main/doc/example/example_visualization.ipynb) 56 | 57 | 58 | ## Getting help 59 | 60 | If you have any questions or problems with this package, feel free to post them 61 | at our GitHub [issue tracker](https://github.com/PEtab-dev/libpetab-python/issues/). 62 | 63 | ## Contributing 64 | 65 | Contributions and feedback to this package are very welcome, see our 66 | [contribution guide](CONTRIBUTING.md). 67 | -------------------------------------------------------------------------------- /doc/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ../CHANGELOG.md -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /doc/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* Enlarge to max-width 900px (default: 800px) */ 2 | .wy-nav-content { 3 | max-width: 900px !important; 4 | } 5 | -------------------------------------------------------------------------------- /doc/_static/petab_schema.yaml: -------------------------------------------------------------------------------- 1 | ../../petab/petab_schema.yaml -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | import os 8 | import subprocess 9 | import sys 10 | import warnings 11 | 12 | # -- Path setup -------------------------------------------------------------- 13 | 14 | # If extensions (or modules to document with autodoc) are in another directory, 15 | # add these directories to sys.path here. If the directory is relative to the 16 | # documentation root, use os.path.abspath to make it absolute, like shown here. 17 | # 18 | sys.path.insert(0, os.path.abspath("..")) 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = "libpetab-python" 23 | copyright = "2018-2024, the PEtab developers" 24 | author = "PEtab developers" 25 | 26 | # The full version, including alpha/beta/rc tags 27 | release = "latest" 28 | 29 | # -- Custom pre-build -------------------------------------------------------- 30 | 31 | 32 | subprocess.run([sys.executable, "md2rst.py"]) # noqa: S603 33 | 34 | # -- General configuration --------------------------------------------------- 35 | 36 | # Add any Sphinx extension module names here, as strings. They can be 37 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 38 | # ones. 39 | extensions = [ 40 | "sphinx.ext.napoleon", 41 | "sphinx.ext.autodoc", 42 | "sphinx.ext.autosummary", 43 | "sphinx.ext.intersphinx", 44 | "sphinx.ext.viewcode", 45 | "sphinx_markdown_tables", 46 | "myst_nb", 47 | ] 48 | 49 | intersphinx_mapping = { 50 | "pandas": ("https://pandas.pydata.org/docs/", None), 51 | "numpy": ("https://numpy.org/devdocs/", None), 52 | "sympy": ("https://docs.sympy.org/latest/", None), 53 | "python": ("https://docs.python.org/3", None), 54 | } 55 | 56 | # Add any paths that contain templates here, relative to this directory. 57 | templates_path = ["_templates"] 58 | 59 | # List of patterns, relative to source directory, that match files and 60 | # directories to ignore when looking for source files. 61 | # This pattern also affects html_static_path and html_extra_path. 62 | exclude_patterns = [ 63 | "build/doctrees", 64 | "build/html", 65 | "**.ipynb_checkpoints", 66 | "logo/LICENSE.md", 67 | ] 68 | 69 | master_doc = "index" 70 | 71 | autosummary_generate = True 72 | 73 | autodoc_default_options = { 74 | "members": None, 75 | "imported-members": ["petab"], 76 | "inherited-members": None, 77 | "show-inheritance": None, 78 | } 79 | 80 | # For some reason causes sphinx import errors otherwise 81 | autodoc_mock_imports = ["yaml"] 82 | 83 | # myst_nb options 84 | # https://myst-nb.readthedocs.io/en/latest/configuration.html 85 | nb_execution_mode = "force" 86 | nb_execution_raise_on_error = True 87 | nb_execution_show_tb = True 88 | 89 | source_suffix = { 90 | ".rst": "restructuredtext", 91 | ".txt": "restructuredtext", 92 | } 93 | 94 | # ignore numpy warnings 95 | warnings.filterwarnings("ignore", message="numpy.dtype size changed") 96 | warnings.filterwarnings("ignore", message="numpy.ufunc size changed") 97 | 98 | # -- Options for HTML output ------------------------------------------------- 99 | 100 | # The theme to use for HTML and HTML Help pages. See the documentation for 101 | # a list of builtin themes. 102 | # 103 | html_theme = "sphinx_rtd_theme" 104 | 105 | # Add any paths that contain custom static files (such as style sheets) here, 106 | # relative to this directory. They are copied after the builtin static files, 107 | # so a file named "default.css" will overwrite the builtin "default.css". 108 | html_static_path = ["_static"] 109 | 110 | html_context = { 111 | "display_github": True, 112 | "github_user": "petab-dev", 113 | "github_repo": "libpetab-python", 114 | "github_version": "develop", 115 | "conf_py_path": "/doc", 116 | } 117 | 118 | html_logo = "logo/PEtab.png" 119 | 120 | 121 | def skip_some_objects(app, what, name, obj, skip, options): 122 | """Exclude some objects from the documentation""" 123 | if getattr(obj, "__module__", None) == "collections": 124 | return True 125 | 126 | 127 | def setup(app): 128 | """Sphinx setup""" 129 | app.connect("autodoc-skip-member", skip_some_objects) 130 | -------------------------------------------------------------------------------- /doc/development.rst: -------------------------------------------------------------------------------- 1 | Development 2 | =========== 3 | 4 | Versioning 5 | ---------- 6 | 7 | We use `Semantic Versioning `_ with the modifications 8 | described under :ref:`deprecation_policy`. 9 | 10 | .. _deprecation_policy: 11 | 12 | Deprecation policy 13 | ------------------ 14 | 15 | petab aims to provide a stable API for users. However, not all features can be 16 | maintained indefinitely. We will deprecate features in minor releases and 17 | where possible, issue a warning when they are used. We will keep deprecated 18 | features for at least six months after the release that includes the 19 | respective deprecation warning and then remove them earliest in the next minor 20 | or major release. If a deprecated feature is the source of a major bug, we may 21 | remove it earlier. 22 | 23 | Python compatibility 24 | -------------------- 25 | 26 | We follow `numpy's Python support policy `_. 27 | -------------------------------------------------------------------------------- /doc/example.rst: -------------------------------------------------------------------------------- 1 | .. _example: 2 | 3 | Examples 4 | ======== 5 | 6 | The following examples should help to get a better idea of how to use the PEtab library. 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | example/example_petablint.ipynb 12 | example/example_visualization.ipynb 13 | 14 | Examples of systems biology parameter estimation problems specified in PEtab 15 | can be found in the `systems biology benchmark model collection `_. 16 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita.yaml: -------------------------------------------------------------------------------- 1 | parameter_file: Fujita_parameters.tsv 2 | format_version: 1 3 | problems: 4 | - condition_files: 5 | - Fujita_experimentalCondition.tsv 6 | measurement_files: 7 | - Fujita_measurementData.tsv 8 | sbml_files: 9 | - Fujita_model.xml 10 | observable_files: 11 | - Fujita_observables.tsv 12 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_experimentalCondition.tsv: -------------------------------------------------------------------------------- 1 | conditionId conditionName EGF 2 | model1_data1 EGF 0.1 ng/ml 0.1 3 | model1_data2 EGF 0.3 ng/ml 0.3 4 | model1_data3 EGF 1 ng/ml 1 5 | model1_data4 EGF 3 ng/ml 3 6 | model1_data5 EGF 10 ng/ml 10 7 | model1_data6 EGF 30 ng/ml 30 8 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_measurementData_minimal.tsv: -------------------------------------------------------------------------------- 1 | observableId simulationConditionId measurement time 2 | pEGFR_tot model1_data1 0 0 3 | pEGFR_tot model1_data1 0.004955 60 4 | pEGFR_tot model1_data1 0.004034 120 5 | pEGFR_tot model1_data1 0.0063674 300 6 | pEGFR_tot model1_data1 0.010859 600 7 | pEGFR_tot model1_data1 0.0071353 900 8 | pEGFR_tot model1_data1 0.0037103 1800 9 | pEGFR_tot model1_data1 0.0067693 3600 10 | pAkt_tot model1_data1 0 0 11 | pAkt_tot model1_data1 0.031232 60 12 | pAkt_tot model1_data1 0.093444 120 13 | pAkt_tot model1_data1 0.23689 300 14 | pAkt_tot model1_data1 0.14973 600 15 | pAkt_tot model1_data1 0.093097 900 16 | pAkt_tot model1_data1 0.065764 1800 17 | pAkt_tot model1_data1 0.045765 3600 18 | pS6_tot model1_data1 0 0 19 | pS6_tot model1_data1 0.0018563 60 20 | pS6_tot model1_data1 0.0033416 120 21 | pS6_tot model1_data1 0.012632 300 22 | pS6_tot model1_data1 0.078914 600 23 | pS6_tot model1_data1 0.25521 900 24 | pS6_tot model1_data1 0.44745 1800 25 | pS6_tot model1_data1 0.29547 3600 26 | pEGFR_tot model1_data2 0 0 27 | pEGFR_tot model1_data2 0.0249 60 28 | pEGFR_tot model1_data2 0.022994 120 29 | pEGFR_tot model1_data2 0.028904 300 30 | pEGFR_tot model1_data2 0.027942 600 31 | pEGFR_tot model1_data2 0.035465 900 32 | pEGFR_tot model1_data2 0.021229 1800 33 | pEGFR_tot model1_data2 0.02063 3600 34 | pAkt_tot model1_data2 0 0 35 | pAkt_tot model1_data2 0.062207 60 36 | pAkt_tot model1_data2 0.40715 120 37 | pAkt_tot model1_data2 0.319 300 38 | pAkt_tot model1_data2 0.20592 600 39 | pAkt_tot model1_data2 0.14706 900 40 | pAkt_tot model1_data2 0.12542 1800 41 | pAkt_tot model1_data2 0.067827 3600 42 | pS6_tot model1_data2 0 0 43 | pS6_tot model1_data2 0.0019654 60 44 | pS6_tot model1_data2 0.0021975 120 45 | pS6_tot model1_data2 0.020119 300 46 | pS6_tot model1_data2 0.22158 600 47 | pS6_tot model1_data2 0.52331 900 48 | pS6_tot model1_data2 0.85846 1800 49 | pS6_tot model1_data2 0.6598 3600 50 | pEGFR_tot model1_data3 0 0 51 | pEGFR_tot model1_data3 0.12816 60 52 | pEGFR_tot model1_data3 0.13179 120 53 | pEGFR_tot model1_data3 0.12123 300 54 | pEGFR_tot model1_data3 0.09165 600 55 | pEGFR_tot model1_data3 0.11645 900 56 | pEGFR_tot model1_data3 0.049997 1800 57 | pEGFR_tot model1_data3 0.017926 3600 58 | pAkt_tot model1_data3 0 0 59 | pAkt_tot model1_data3 0.38989 60 60 | pAkt_tot model1_data3 0.82306 120 61 | pAkt_tot model1_data3 0.49708 300 62 | pAkt_tot model1_data3 0.2549 600 63 | pAkt_tot model1_data3 0.19377 900 64 | pAkt_tot model1_data3 0.12942 1800 65 | pAkt_tot model1_data3 0.061242 3600 66 | pS6_tot model1_data3 0 0 67 | pS6_tot model1_data3 0.0020839 60 68 | pS6_tot model1_data3 0.0047955 120 69 | pS6_tot model1_data3 0.047495 300 70 | pS6_tot model1_data3 0.39197 600 71 | pS6_tot model1_data3 0.68142 900 72 | pS6_tot model1_data3 1.0001 1800 73 | pS6_tot model1_data3 0.75108 3600 74 | pEGFR_tot model1_data4 0 0 75 | pEGFR_tot model1_data4 0.48781 60 76 | pEGFR_tot model1_data4 0.28974 120 77 | pEGFR_tot model1_data4 0.24074 300 78 | pEGFR_tot model1_data4 0.13851 600 79 | pEGFR_tot model1_data4 0.11025 900 80 | pEGFR_tot model1_data4 0.047644 1800 81 | pEGFR_tot model1_data4 0.017833 3600 82 | pAkt_tot model1_data4 0 0 83 | pAkt_tot model1_data4 0.71187 60 84 | pAkt_tot model1_data4 0.89633 120 85 | pAkt_tot model1_data4 0.49719 300 86 | pAkt_tot model1_data4 0.2397 600 87 | pAkt_tot model1_data4 0.18333 900 88 | pAkt_tot model1_data4 0.089574 1800 89 | pAkt_tot model1_data4 0.037055 3600 90 | pS6_tot model1_data4 0 0 91 | pS6_tot model1_data4 0.0057189 60 92 | pS6_tot model1_data4 0.013126 120 93 | pS6_tot model1_data4 0.062408 300 94 | pS6_tot model1_data4 0.41154 600 95 | pS6_tot model1_data4 0.71428 900 96 | pS6_tot model1_data4 0.92784 1800 97 | pS6_tot model1_data4 0.55064 3600 98 | pEGFR_tot model1_data5 0 0 99 | pEGFR_tot model1_data5 0.90952 60 100 | pEGFR_tot model1_data5 0.3891 120 101 | pEGFR_tot model1_data5 0.30117 300 102 | pEGFR_tot model1_data5 0.10321 600 103 | pEGFR_tot model1_data5 0.10615 900 104 | pEGFR_tot model1_data5 0.039496 1800 105 | pEGFR_tot model1_data5 0.011403 3600 106 | pAkt_tot model1_data5 0 0 107 | pAkt_tot model1_data5 0.87147 60 108 | pAkt_tot model1_data5 0.96118 120 109 | pAkt_tot model1_data5 0.37349 300 110 | pAkt_tot model1_data5 0.15548 600 111 | pAkt_tot model1_data5 0.11922 900 112 | pAkt_tot model1_data5 0.062311 1800 113 | pAkt_tot model1_data5 0.03678 3600 114 | pS6_tot model1_data5 0 0 115 | pS6_tot model1_data5 0.0073292 60 116 | pS6_tot model1_data5 0.014418 120 117 | pS6_tot model1_data5 0.079732 300 118 | pS6_tot model1_data5 0.4562 600 119 | pS6_tot model1_data5 0.65294 900 120 | pS6_tot model1_data5 0.75189 1800 121 | pS6_tot model1_data5 0.37446 3600 122 | pEGFR_tot model1_data6 0 0 123 | pEGFR_tot model1_data6 0.95674 60 124 | pEGFR_tot model1_data6 0.26888 120 125 | pEGFR_tot model1_data6 0.34087 300 126 | pEGFR_tot model1_data6 0.10018 600 127 | pEGFR_tot model1_data6 0.097799 900 128 | pEGFR_tot model1_data6 0.025369 1800 129 | pEGFR_tot model1_data6 0.0081957 3600 130 | pAkt_tot model1_data6 0 0 131 | pAkt_tot model1_data6 0.99726 60 132 | pAkt_tot model1_data6 0.8819 120 133 | pAkt_tot model1_data6 0.27373 300 134 | pAkt_tot model1_data6 0.11182 600 135 | pAkt_tot model1_data6 0.073731 900 136 | pAkt_tot model1_data6 0.053436 1800 137 | pAkt_tot model1_data6 0.038275 3600 138 | pS6_tot model1_data6 0 0 139 | pS6_tot model1_data6 0.0086144 60 140 | pS6_tot model1_data6 0.013062 120 141 | pS6_tot model1_data6 0.07993 300 142 | pS6_tot model1_data6 0.42868 600 143 | pS6_tot model1_data6 0.60508 900 144 | pS6_tot model1_data6 0.62088 1800 145 | pS6_tot model1_data6 0.32084 3600 146 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_measurementData_nanData.tsv: -------------------------------------------------------------------------------- 1 | observableId preequilibrationConditionId simulationConditionId measurement time observableParameters noiseParameters 2 | pEGFR_tot model1_data1 0 0 scaling_pEGFR_tot 0.01 3 | pEGFR_tot model1_data1 0.004955 60 scaling_pEGFR_tot 0.01 4 | pEGFR_tot model1_data1 0.004034 120 scaling_pEGFR_tot 0.01 5 | pEGFR_tot model1_data1 0.0063674 300 scaling_pEGFR_tot 0.01 6 | pEGFR_tot model1_data1 0.010859 600 scaling_pEGFR_tot 0.01 7 | pEGFR_tot model1_data1 0.0071353 900 scaling_pEGFR_tot 0.01 8 | pEGFR_tot model1_data1 0.0037103 1800 scaling_pEGFR_tot 0.01 9 | pEGFR_tot model1_data1 0.0067693 3600 scaling_pEGFR_tot 0.01 10 | pAkt_tot model1_data1 nan 0 scaling_pAkt_tot 0.01 11 | pAkt_tot model1_data1 nan 60 scaling_pAkt_tot 0.01 12 | pAkt_tot model1_data1 nan 120 scaling_pAkt_tot 0.01 13 | pAkt_tot model1_data1 nan 300 scaling_pAkt_tot 0.01 14 | pAkt_tot model1_data1 nan 600 scaling_pAkt_tot 0.01 15 | pAkt_tot model1_data1 nan 900 scaling_pAkt_tot 0.01 16 | pAkt_tot model1_data1 nan 1800 scaling_pAkt_tot 0.01 17 | pAkt_tot model1_data1 nan 3600 scaling_pAkt_tot 0.01 18 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_measurementData_t_inf.tsv: -------------------------------------------------------------------------------- 1 | observableId preequilibrationConditionId simulationConditionId measurement time observableParameters noiseParameters datasetId 2 | pS6_tot model1_data1 0 0 scaling_pS6_tot 0.01 model1_data1_pS6_tot 3 | pS6_tot model1_data1 0.0018563 60 scaling_pS6_tot 0.01 model1_data1_pS6_tot 4 | pS6_tot model1_data1 0.0033416 120 scaling_pS6_tot 0.01 model1_data1_pS6_tot 5 | pS6_tot model1_data1 0.012632 300 scaling_pS6_tot 0.01 model1_data1_pS6_tot 6 | pS6_tot model1_data1 0.078914 600 scaling_pS6_tot 0.02 model1_data1_pS6_tot 7 | pS6_tot model1_data1 0.25521 900 scaling_pS6_tot 0.02 model1_data1_pS6_tot 8 | pS6_tot model1_data1 0.44745 1800 scaling_pS6_tot 0.035 model1_data1_pS6_tot 9 | pS6_tot model1_data1 0.29547 inf scaling_pS6_tot 0.035 model1_data1_pS6_tot 10 | pS6_tot model1_data2 0 0 scaling_pS6_tot 0.01 model1_data2_pS6_tot 11 | pS6_tot model1_data2 0.0019654 60 scaling_pS6_tot 0.01 model1_data2_pS6_tot 12 | pS6_tot model1_data2 0.0021975 120 scaling_pS6_tot 0.01 model1_data2_pS6_tot 13 | pS6_tot model1_data2 0.020119 300 scaling_pS6_tot 0.01 model1_data2_pS6_tot 14 | pS6_tot model1_data2 0.22158 600 scaling_pS6_tot 0.02 model1_data2_pS6_tot 15 | pS6_tot model1_data2 0.52331 900 scaling_pS6_tot 0.03 model1_data2_pS6_tot 16 | pS6_tot model1_data2 0.85846 1800 scaling_pS6_tot 0.1 model1_data2_pS6_tot 17 | pS6_tot model1_data2 0.6598 inf scaling_pS6_tot 0.025 model1_data2_pS6_tot 18 | pS6_tot model1_data3 0 0 scaling_pS6_tot 0.01 model1_data3_pS6_tot 19 | pS6_tot model1_data3 0.0020839 60 scaling_pS6_tot 0.01 model1_data3_pS6_tot 20 | pS6_tot model1_data3 0.0047955 120 scaling_pS6_tot 0.01 model1_data3_pS6_tot 21 | pS6_tot model1_data3 0.047495 300 scaling_pS6_tot 0.01 model1_data3_pS6_tot 22 | pS6_tot model1_data3 0.39197 600 scaling_pS6_tot 0.01 model1_data3_pS6_tot 23 | pS6_tot model1_data3 0.68142 900 scaling_pS6_tot 0.025 model1_data3_pS6_tot 24 | pS6_tot model1_data3 1.0001 1800 scaling_pS6_tot 0.07 model1_data3_pS6_tot 25 | pS6_tot model1_data3 0.75108 inf scaling_pS6_tot 0.075 model1_data3_pS6_tot 26 | pS6_tot model1_data4 0 0 scaling_pS6_tot 0.01 model1_data4_pS6_tot 27 | pS6_tot model1_data4 0.0057189 60 scaling_pS6_tot 0.01 model1_data4_pS6_tot 28 | pS6_tot model1_data4 0.013126 120 scaling_pS6_tot 0.01 model1_data4_pS6_tot 29 | pS6_tot model1_data4 0.062408 300 scaling_pS6_tot 0.01 model1_data4_pS6_tot 30 | pS6_tot model1_data4 0.41154 600 scaling_pS6_tot 0.01 model1_data4_pS6_tot 31 | pS6_tot model1_data4 0.71428 900 scaling_pS6_tot 0.035 model1_data4_pS6_tot 32 | pS6_tot model1_data4 0.92784 1800 scaling_pS6_tot 0.08 model1_data4_pS6_tot 33 | pS6_tot model1_data4 0.55064 inf scaling_pS6_tot 0.08 model1_data4_pS6_tot 34 | pS6_tot model1_data5 0 0 scaling_pS6_tot 0.01 model1_data5_pS6_tot 35 | pS6_tot model1_data5 0.0073292 60 scaling_pS6_tot 0.01 model1_data5_pS6_tot 36 | pS6_tot model1_data5 0.014418 120 scaling_pS6_tot 0.01 model1_data5_pS6_tot 37 | pS6_tot model1_data5 0.079732 300 scaling_pS6_tot 0.01 model1_data5_pS6_tot 38 | pS6_tot model1_data5 0.4562 600 scaling_pS6_tot 0.01 model1_data5_pS6_tot 39 | pS6_tot model1_data5 0.65294 900 scaling_pS6_tot 0.02 model1_data5_pS6_tot 40 | pS6_tot model1_data5 0.75189 1800 scaling_pS6_tot 0.04 model1_data5_pS6_tot 41 | pS6_tot model1_data5 0.37446 inf scaling_pS6_tot 0.08 model1_data5_pS6_tot 42 | pS6_tot model1_data6 0 0 scaling_pS6_tot 0.01 model1_data6_pS6_tot 43 | pS6_tot model1_data6 0.0086144 60 scaling_pS6_tot 0.01 model1_data6_pS6_tot 44 | pS6_tot model1_data6 0.013062 120 scaling_pS6_tot 0.01 model1_data6_pS6_tot 45 | pS6_tot model1_data6 0.07993 300 scaling_pS6_tot 0.01 model1_data6_pS6_tot 46 | pS6_tot model1_data6 0.42868 600 scaling_pS6_tot 0.02 model1_data6_pS6_tot 47 | pS6_tot model1_data6 0.60508 900 scaling_pS6_tot 0.03 model1_data6_pS6_tot 48 | pS6_tot model1_data6 0.62088 1800 scaling_pS6_tot 0.035 model1_data6_pS6_tot 49 | pS6_tot model1_data6 0.32084 inf scaling_pS6_tot 0.07 model1_data6_pS6_tot 50 | pS6_tot model1_data6 0 0 scaling_pS6_tot 0.01 model1_data6_pS6_tot 51 | pS6_tot model1_data6 0.009 60 scaling_pS6_tot 0.01 model1_data6_pS6_tot 52 | pS6_tot model1_data6 0.01 120 scaling_pS6_tot 0.01 model1_data6_pS6_tot 53 | pS6_tot model1_data6 0.05 300 scaling_pS6_tot 0.01 model1_data6_pS6_tot 54 | pS6_tot model1_data6 0.6 600 scaling_pS6_tot 0.02 model1_data6_pS6_tot 55 | pS6_tot model1_data6 0.4 900 scaling_pS6_tot 0.03 model1_data6_pS6_tot 56 | pS6_tot model1_data6 0.83 1800 scaling_pS6_tot 0.035 model1_data6_pS6_tot 57 | pS6_tot model1_data6 0.2 inf scaling_pS6_tot 0.07 model1_data6_pS6_tot 58 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_measurementData_wrongNoise.tsv: -------------------------------------------------------------------------------- 1 | observableId preequilibrationConditionId simulationConditionId measurement time observableParameters noiseParameters 2 | pEGFR_tot model1_data1 0 0 scaling_pEGFR_tot 0.01 3 | pEGFR_tot model1_data1 0.004955 60 scaling_pEGFR_tot 0.01 4 | pEGFR_tot model1_data1 0.004034 120 scaling_pEGFR_tot 0.01 5 | pEGFR_tot model1_data1 0.0063674 300 scaling_pEGFR_tot 0.01 6 | pEGFR_tot model1_data1 0.010859 600 scaling_pEGFR_tot 0.01 7 | pEGFR_tot model1_data1 0.0071353 900 scaling_pEGFR_tot 0.01 8 | pEGFR_tot model1_data1 0.0037103 1800 scaling_pEGFR_tot 0.01 9 | pEGFR_tot model1_data1 0.0067693 3600 scaling_pEGFR_tot 0.01 10 | pAkt_tot model1_data1 0 0 scaling_pAkt_tot noiseParam 11 | pAkt_tot model1_data1 0.004955 60 scaling_pAkt_tot noiseParam 12 | pAkt_tot model1_data1 0.004034 120 scaling_pAkt_tot noiseParam 13 | pAkt_tot model1_data1 0.0063674 300 scaling_pAkt_tot noiseParam 14 | pAkt_tot model1_data1 0.010859 600 scaling_pAkt_tot noiseParam 15 | pAkt_tot model1_data1 0.0071353 900 scaling_pAkt_tot noiseParam 16 | pAkt_tot model1_data1 0.0037103 1800 scaling_pAkt_tot noiseParam 17 | pAkt_tot model1_data1 0.0067693 3600 scaling_pAkt_tot noiseParam 18 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_observables.tsv: -------------------------------------------------------------------------------- 1 | observableId observableName observableFormula noiseFormula observableTransformation noiseDistribution 2 | pAkt_tot observableParameter1_pAkt_tot * (pAkt + pAkt_S6) noiseParameter1_pAkt_tot lin normal 3 | pEGFR_tot observableParameter1_pEGFR_tot * (pEGFR + pEGFR_Akt) noiseParameter1_pEGFR_tot lin normal 4 | pS6_tot pS6 * observableParameter1_pS6_tot noiseParameter1_pS6_tot lin normal 5 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_parameters.tsv: -------------------------------------------------------------------------------- 1 | parameterId parameterName parameterScale lowerBound upperBound nominalValue estimate 2 | EGFR_turnover EGFR_{turnover} log10 1E-08 100000000 0.001479614562719 1 3 | init_AKT init_{AKT} log10 1E-08 100000000 0.026930923029049 1 4 | init_EGFR init_{EGFR} log10 1E-08 100000000 37536153.8059105 1 5 | init_S6 init_{S6} log10 1E-08 100000000 188.063148677911 1 6 | reaction_1_k1 reaction_{1,k1} log10 1E-08 100000000 0.003690766129111 1 7 | reaction_1_k2 reaction_{1,k2} log10 1E-08 100000000 0.002301175486005 1 8 | reaction_2_k1 reaction_{2,k1} log10 1E-08 100000000 0.000936500808211 1 9 | reaction_2_k2 reaction_{2,k2} log10 1E-08 100000000 60965.2066642586 1 10 | reaction_3_k1 reaction_{3,k1} log10 1E-08 100000000 0.433225051651771 1 11 | reaction_4_k1 reaction_{4,k1} log10 1E-08 100000000 0.030155177423024 1 12 | reaction_5_k1 reaction_{5,k1} log10 1E-08 100000000 3.27310803801897E-06 1 13 | reaction_5_k2 reaction_{5,k2} log10 1E-08 100000000 0.000398546299782 1 14 | reaction_6_k1 reaction_{6,k1} log10 1E-08 100000000 5.46319692934546E-06 1 15 | reaction_7_k1 reaction_{7,k1} log10 1E-08 100000000 0.011803208311735 1 16 | reaction_8_k1 reaction_{8,k1} log10 1E-08 100000000 0.000944761775113 1 17 | reaction_9_k1 reaction_{9,k1} log10 1E-08 100000000 0.028510798479438 1 18 | scaling_pAkt_tot scaling_{pAkt}_tot log10 1E-08 100000000 41.377103160384 1 19 | scaling_pEGFR_tot scaling_{pEGFR}_tot log10 1E-08 100000000 5.64785460492811E-08 1 20 | scaling_pS6_tot scaling_{pS6}_tot log10 1E-08 100000000 78521.9513232784 1 21 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_parameters_scaling.tsv: -------------------------------------------------------------------------------- 1 | parameterId parameterName parameterScale lowerBound upperBound nominalValue estimate initializationPriorType initializationPriorParameters objectivePriorType objectivePriorParameters 2 | EGFR_turnover EGFR_{turnover} log10 1E-08 100000000 0.001479614562719 1 uniform 31.62;316.23 uniform 10;1000 3 | init_AKT init_{AKT} log10 1E-08 100000000 0.026930923029049 1 parameterScaleUniform -3;3 parameterScaleUniform -3;3 4 | init_EGFR init_{EGFR} log10 1E-08 100000000 37536153.8059105 1 normal 1000;50 normal 1000:50 5 | init_S6 init_{S6} log10 1E-08 100000000 188.063148677911 1 logNormal 3;2 logNormal 3;2 6 | reaction_1_k1 reaction_{1,k1} log10 1E-08 100000000 0.003690766129111 1 parameterScaleNormal 1;2 parameterScaleNormal 1;2 7 | reaction_1_k2 reaction_{1,k2} log10 1E-08 100000000 0.002301175486005 1 laplace 1000;20 laplace 1000;20 8 | reaction_2_k1 reaction_{2,k1} log10 1E-08 100000000 0.000936500808211 1 logLaplace 2;1 logLaplace 2;1 9 | reaction_2_k2 reaction_{2,k2} log10 1E-08 100000000 60965.2066642586 1 parameterScaleLaplace 2;1 parameterScaleLaplace 2;1 10 | reaction_3_k1 reaction_{3,k1} log10 1E-08 100000000 0.433225051651771 1 11 | reaction_4_k1 reaction_{4,k1} log10 1E-08 100000000 0.030155177423024 1 12 | reaction_5_k1 reaction_{5,k1} log10 1E-08 100000000 3.27310803801897E-06 1 13 | reaction_5_k2 reaction_{5,k2} log10 1E-08 100000000 0.000398546299782 1 14 | reaction_6_k1 reaction_{6,k1} log10 1E-08 100000000 5.46319692934546E-06 1 15 | reaction_7_k1 reaction_{7,k1} log10 1E-08 100000000 0.011803208311735 1 16 | reaction_8_k1 reaction_{8,k1} log10 1E-08 100000000 0.000944761775113 1 17 | reaction_9_k1 reaction_{9,k1} log10 1E-08 100000000 0.028510798479438 1 18 | scaling_pAkt_tot scaling_{pAkt}_tot log10 1E-08 100000000 41.377103160384 1 19 | scaling_pEGFR_tot scaling_{pEGFR}_tot log10 1E-08 100000000 5.64785460492811E-08 1 20 | scaling_pS6_tot scaling_{pS6}_tot log10 1E-08 100000000 78521.9513232784 1 21 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_simulatedData_t_inf.tsv: -------------------------------------------------------------------------------- 1 | observableId preequilibrationConditionId simulationConditionId simulation time observableParameters noiseParameters 2 | pS6_tot model1_data1 0 0 scaling_pS6_tot 0.01 3 | pS6_tot model1_data1 5.78895984805857E-05 60 scaling_pS6_tot 0.01 4 | pS6_tot model1_data1 0.0009531255 120 scaling_pS6_tot 0.01 5 | pS6_tot model1_data1 0.0185497283 300 scaling_pS6_tot 0.01 6 | pS6_tot model1_data1 0.0927501675 600 scaling_pS6_tot 0.02 7 | pS6_tot model1_data1 0.1859892615 900 scaling_pS6_tot 0.02 8 | pS6_tot model1_data1 0.3842285889 1800 scaling_pS6_tot 0.035 9 | pS6_tot model1_data1 0.3671651134 inf scaling_pS6_tot 0.035 10 | pS6_tot model1_data2 0 0 scaling_pS6_tot 0.01 11 | pS6_tot model1_data2 0.0001694707 60 scaling_pS6_tot 0.01 12 | pS6_tot model1_data2 0.0026563935 120 scaling_pS6_tot 0.01 13 | pS6_tot model1_data2 0.045833771 300 scaling_pS6_tot 0.01 14 | pS6_tot model1_data2 0.209607514 600 scaling_pS6_tot 0.02 15 | pS6_tot model1_data2 0.4007484657 900 scaling_pS6_tot 0.03 16 | pS6_tot model1_data2 0.7556316274 1800 scaling_pS6_tot 0.1 17 | pS6_tot model1_data2 0.6612775029 inf scaling_pS6_tot 0.025 18 | pS6_tot model1_data3 0 0 scaling_pS6_tot 0.01 19 | pS6_tot model1_data3 0.0005211244 60 scaling_pS6_tot 0.01 20 | pS6_tot model1_data3 0.007106942 120 scaling_pS6_tot 0.01 21 | pS6_tot model1_data3 0.0945320284 300 scaling_pS6_tot 0.01 22 | pS6_tot model1_data3 0.366852041 600 scaling_pS6_tot 0.01 23 | pS6_tot model1_data3 0.6350909024 900 scaling_pS6_tot 0.025 24 | pS6_tot model1_data3 0.9989387811 1800 scaling_pS6_tot 0.07 25 | pS6_tot model1_data3 0.7818807584 inf scaling_pS6_tot 0.075 26 | pS6_tot model1_data4 0 0 scaling_pS6_tot 0.01 27 | pS6_tot model1_data4 0.001284326 60 scaling_pS6_tot 0.01 28 | pS6_tot model1_data4 0.0137701475 120 scaling_pS6_tot 0.01 29 | pS6_tot model1_data4 0.1357831768 300 scaling_pS6_tot 0.01 30 | pS6_tot model1_data4 0.4317319675 600 scaling_pS6_tot 0.01 31 | pS6_tot model1_data4 0.6581119566 900 scaling_pS6_tot 0.035 32 | pS6_tot model1_data4 0.8936164338 1800 scaling_pS6_tot 0.08 33 | pS6_tot model1_data4 0.6665565723 inf scaling_pS6_tot 0.08 34 | pS6_tot model1_data5 0 0 scaling_pS6_tot 0.01 35 | pS6_tot model1_data5 0.0026774961 60 scaling_pS6_tot 0.01 36 | pS6_tot model1_data5 0.0210783997 120 scaling_pS6_tot 0.01 37 | pS6_tot model1_data5 0.1570157565 300 scaling_pS6_tot 0.01 38 | pS6_tot model1_data5 0.4117751573 600 scaling_pS6_tot 0.01 39 | pS6_tot model1_data5 0.5823970015 900 scaling_pS6_tot 0.02 40 | pS6_tot model1_data5 0.7468131737 1800 scaling_pS6_tot 0.04 41 | pS6_tot model1_data5 0.5504628923 inf scaling_pS6_tot 0.08 42 | pS6_tot model1_data6 0 0 scaling_pS6_tot 0.01 43 | pS6_tot model1_data6 0.0039799398 60 scaling_pS6_tot 0.01 44 | pS6_tot model1_data6 0.0254606658 120 scaling_pS6_tot 0.01 45 | pS6_tot model1_data6 0.1631478226 300 scaling_pS6_tot 0.01 46 | pS6_tot model1_data6 0.4009703836 600 scaling_pS6_tot 0.02 47 | pS6_tot model1_data6 0.5574326493 900 scaling_pS6_tot 0.03 48 | pS6_tot model1_data6 0.7058108511 1800 scaling_pS6_tot 0.035 49 | pS6_tot model1_data6 0.5194180219 inf scaling_pS6_tot 0.07 50 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/Fujita_visuSpec_small.tsv: -------------------------------------------------------------------------------- 1 | plotId plotTypeSimulation plotTypeData datasetId xValues 2 | plot1 LinePlot provided model1_data1_pEGFR_tot time 3 | plot1 LinePlot provided model1_data2_pEGFR_tot time 4 | plot1 LinePlot provided model1_data3_pEGFR_tot time 5 | plot1 LinePlot provided model1_data4_pEGFR_tot time 6 | plot1 LinePlot provided model1_data5_pEGFR_tot time 7 | plot1 LinePlot provided model1_data6_pEGFR_tot time 8 | plot2 LinePlot provided model1_data1_pAkt_tot time 9 | plot2 LinePlot provided model1_data2_pAkt_tot time 10 | plot2 LinePlot provided model1_data3_pAkt_tot time 11 | plot2 LinePlot provided model1_data4_pAkt_tot time 12 | plot2 LinePlot provided model1_data5_pAkt_tot time 13 | plot2 LinePlot provided model1_data6_pAkt_tot time 14 | plot3 LinePlot provided model1_data1_pS6_tot time 15 | plot3 LinePlot provided model1_data2_pS6_tot time 16 | plot3 LinePlot provided model1_data3_pS6_tot time 17 | plot3 LinePlot provided model1_data4_pS6_tot time 18 | plot3 LinePlot provided model1_data5_pS6_tot time 19 | plot3 LinePlot provided model1_data6_pS6_tot time 20 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/visuSpecs/Fujita_visuSpec_1.tsv: -------------------------------------------------------------------------------- 1 | plotId xOffset yScale 2 | plot1 100 log 3 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/visuSpecs/Fujita_visuSpec_2.tsv: -------------------------------------------------------------------------------- 1 | plotId yValues yOffset yScale plotName 2 | plot1 pEGFR_tot 0 log pEGFR total 3 | plot2 pAkt_tot 300 lin pAkt total and pS6 total 4 | plot2 pS6_tot 305 lin pAkt total and pS6 total 5 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/visuSpecs/Fujita_visuSpec_3.tsv: -------------------------------------------------------------------------------- 1 | plotId xOffset yScale 2 | figure_b 100 log 3 | figure_a 500 lin 4 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/visuSpecs/Fujita_visuSpec_datasetIds.tsv: -------------------------------------------------------------------------------- 1 | plotId plotTypeData datasetId xValues legendEntry 2 | plot1 provided model1_data1_pEGFR_tot time Data 1, pEGFR total 3 | plot1 provided model1_data2_pEGFR_tot time Data 2, pEGFR total 4 | plot1 provided model1_data3_pEGFR_tot time Data 3, pEGFR total 5 | plot1 provided model1_data4_pEGFR_tot time Data 4, pEGFR total 6 | plot1 provided model1_data5_pEGFR_tot time Data 5, pEGFR total 7 | plot1 provided model1_data6_pEGFR_tot time Data 6, pEGFR total 8 | plot2 provided model1_data1_pAkt_tot time Data 1, pAkt total 9 | plot2 provided model1_data2_pAkt_tot time Data 2, pAkt total 10 | plot2 provided model1_data3_pAkt_tot time Data 3, pAkt total 11 | plot2 provided model1_data4_pAkt_tot time Data 4, pAkt total 12 | plot2 provided model1_data5_pAkt_tot time Data 5, pAkt total 13 | plot2 provided model1_data6_pAkt_tot time Data 6, pAkt total 14 | plot3 provided model1_data1_pS6_tot time Data 1, pS6 total 15 | plot3 provided model1_data2_pS6_tot time Data 2, pS6 total 16 | plot3 provided model1_data3_pS6_tot time Data 3, pS6 total 17 | plot3 provided model1_data4_pS6_tot time Data 4, pS6 total 18 | plot3 provided model1_data5_pS6_tot time Data 5, pS6 total 19 | plot3 provided model1_data6_pS6_tot time Data 6, pS6 total 20 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/visuSpecs/Fujita_visuSpec_empty.tsv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/example/example_Fujita/visuSpecs/Fujita_visuSpec_empty.tsv -------------------------------------------------------------------------------- /doc/example/example_Fujita/visuSpecs/Fujita_visuSpec_individual_datasets.tsv: -------------------------------------------------------------------------------- 1 | plotId plotTypeData datasetId xValues 2 | plot1 provided model1_data1_pEGFR_tot time 3 | plot2 provided model1_data2_pEGFR_tot time 4 | plot2 provided model1_data3_pEGFR_tot time 5 | plot3 provided model1_data4_pEGFR_tot time 6 | plot3 provided model1_data5_pEGFR_tot time 7 | plot3 provided model1_data6_pEGFR_tot time 8 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/visuSpecs/Fujita_visuSpec_mandatory.tsv: -------------------------------------------------------------------------------- 1 | plotId 2 | plot1 3 | -------------------------------------------------------------------------------- /doc/example/example_Fujita/visuSpecs/Fujita_visuSpec_replicates.tsv: -------------------------------------------------------------------------------- 1 | plotId xValues yValues yOffset yScale plotName plotTypeSimulation plotTypeData 2 | plot1 time pS6_tot 0 lin pS6 total LinePlot replicate 3 | -------------------------------------------------------------------------------- /doc/example/example_Isensee/Isensee.yaml: -------------------------------------------------------------------------------- 1 | format_version: 1 2 | parameter_file: 3 | problems: 4 | - condition_files: 5 | - Isensee_experimentalCondition.tsv 6 | measurement_files: 7 | - Isensee_measurementData.tsv 8 | observable_files: [] 9 | sbml_files: [] 10 | visualization_files: 11 | - Isensee_visualizationSpecification.tsv 12 | -------------------------------------------------------------------------------- /doc/example/example_Isensee/Isensee_no_vis.yaml: -------------------------------------------------------------------------------- 1 | format_version: 1 2 | parameter_file: 3 | problems: 4 | - condition_files: 5 | - Isensee_experimentalCondition.tsv 6 | measurement_files: 7 | - Isensee_measurementData.tsv 8 | observable_files: [] 9 | sbml_files: [] 10 | -------------------------------------------------------------------------------- /doc/example/example_Isensee/Isensee_visualizationSpecification.tsv: -------------------------------------------------------------------------------- 1 | plotId plotName plotTypeSimulation plotTypeData datasetId xValues xOffset xLabel yValues yOffset yLabel legendEntry xScale yScale 2 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__4_ABnOH_and_ctrl fourABnOH_incubation_time 0 Incubation Time [min] pRII_Microscopy 0 pRII_Microscopy 4-ABnOH/Ctrl lin lin 3 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__4_ABnOH_and_Fsk fourABnOH_incubation_time 0 Incubation Time [min] pRII_Microscopy 0 pRII_Microscopy 4-ABnOH/Fsk(10) lin lin 4 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__Rp_cAMPS_pAB_and_ctrl Rp_cAMPS_pAB_incubation_time 0 Incubation Time [min] pRII_Microscopy 0 pRII_Microscopy Rp-cAMPS-pAB/Ctrl lin lin 5 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__Rp_cAMPS_pAB_and_ctrl Rp_cAMPS_pAB_incubation_time 0 Incubation Time [min] pRII_Microscopy 0 pRII_Microscopy Rp-cAMPS-pAB/Fsk(10) lin lin 6 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__Rp8_Br_cAMPS_pAB_and_ctrl Rp8_Br_cAMPS_pAB_incubation_time 0 Incubation Time [min] pRII_Microscopy 0 pRII_Microscopy Rp8-Br-cAMPS-pAB/Ctrl lin lin 7 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__Rp8_Br_cAMPS_pAB_and_Fsk Rp8_Br_cAMPS_pAB_incubation_time 0 Incubation Time [min] pRII_Microscopy 0 pRII_Microscopy Rp8-Br-cAMPS-pAB/Fsk(10) lin lin 8 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__Rp8_pCPT_cAMPS_pAB_and_ctrl Rp8_pCPT_cAMPS_pAB_incubation_time 0 Incubation Time [min] pRII_Microscopy 0 pRII_Microscopy Rp8-pCPT-cAMPS-pAB/Ctrl lin lin 9 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__Rp8_pCPT_cAMPS_pAB_and_Fsk Rp8_pCPT_cAMPS_pAB_incubation_time 0 Incubation Time [min] pRII_Microscopy 0 pRII_Microscopy Rp8-pCPT-cAMPS-pAB/Fsk(10) lin lin 10 | plot2 JI09_150330_Drg350_348_CycNuc LinePlot MeanAndSD JI09_150330_Drg350_348_CycNuc__ctrl time 0 Time [min] pRII_Microscopy 0 pRII_Microscopy Ctrl lin lin 11 | plot2 JI09_150330_Drg350_348_CycNuc LinePlot MeanAndSD JI09_150330_Drg350_348_CycNuc__Fsk10 time 0 Time [min] pRII_Microscopy 0 pRII_Microscopy Fsk(10) lin lin 12 | plot2 JI09_150330_Drg350_348_CycNuc LinePlot MeanAndSD JI09_150330_Drg350_348_CycNuc__IBMX100_and_Fsk10 time 0 Time [min] pRII_Microscopy 0 pRII_Microscopy IBMX(100)/Fsk(10) lin lin 13 | plot2 JI09_150330_Drg350_348_CycNuc LinePlot MeanAndSD JI09_150330_Drg350_348_CycNuc__Sp8_Br_cAMPS_AM10 time 0 Time [min] pRII_Microscopy 0 pRII_Microscopy Sp8-Br-cAMPS-AM(10) lin lin 14 | plot3 JI09_150330_Drg353_351_CycNuc LinePlot MeanAndSD JI09_150330_Drg353_351_CycNuc__4_ABnOH_and_ctrl fourABnOH_level 0 Concentration [$\mu$M] pRII_Microscopy 0 pRII_Microscopy 4-ABnOH/Ctrl log10 lin 15 | plot3 JI09_150330_Drg353_351_CycNuc LinePlot MeanAndSD JI09_150330_Drg353_351_CycNuc__4-ABnOH_and_Fsk fourABnOH_level 0 Concentration [$\mu$M] pRII_Microscopy 0 pRII_Microscopy 4-ABnOH/Fsk(10) log10 lin 16 | plot3 JI09_150330_Drg353_351_CycNuc LinePlot MeanAndSD JI09_150330_Drg353_351_CycNuc__Rp_cAMPS_pAB_and_ctrl Rp_cAMPS_pAB_level 0 Concentration [$\mu$M] pRII_Microscopy 0 pRII_Microscopy Rp-cAMPS-pAB/Ctrl log10 lin 17 | plot3 JI09_150330_Drg353_351_CycNuc LinePlot MeanAndSD JI09_150330_Drg353_351_CycNuc__Rp_cAMPS_pAB_and_Fsk Rp_cAMPS_pAB_level 0 Concentration [$\mu$M] pRII_Microscopy 0 pRII_Microscopy Rp-cAMPS-pAB/Fsk(10) log10 lin 18 | plot3 JI09_150330_Drg353_351_CycNuc LinePlot MeanAndSD JI09_150330_Drg353_351_CycNuc__Rp8_Br_cAMPS_pAB_and_ctrl Rp8_Br_cAMPS_pAB_level 0 Concentration [$\mu$M] pRII_Microscopy 0 pRII_Microscopy Rp8-Br-cAMPS-pAB/Ctrl log10 lin 19 | plot3 JI09_150330_Drg353_351_CycNuc LinePlot MeanAndSD JI09_150330_Drg353_351_CycNuc__Rp8_Br_cAMPS_pAB_and_Fsk Rp8_Br_cAMPS_pAB_level 0 Concentration [$\mu$M] pRII_Microscopy 0 pRII_Microscopy Rp8-Br-cAMPS-pAB/Fsk(10) log10 lin 20 | plot3 JI09_150330_Drg353_351_CycNuc LinePlot MeanAndSD JI09_150330_Drg353_351_CycNuc__Rp8_pCPT_cAMPS_pAB_and_ctrl Rp8_pCPT_cAMPS_pAB_level 0 Concentration [$\mu$M] pRII_Microscopy 0 pRII_Microscopy Rp8-pCPT-cAMPS-pAB/Ctrl log10 lin 21 | plot3 JI09_150330_Drg353_351_CycNuc LinePlot MeanAndSD JI09_150330_Drg353_351_CycNuc__Rp8_pCPT_cAMPS_pAB_and_Fsk Rp8_pCPT_cAMPS_pAB_level 0 Concentration [$\mu$M] pRII_Microscopy 0 pRII_Microscopy Rp8-pCPT-cAMPS-pAB/Fsk(10) log10 lin 22 | plot4 JI09_151102_Drg421_418_Age LinePlot MeanAndSD JI09_151102_Drg421_418_Age__ctrl_and_ctrl time -60 Time [min] pRII_Microscopy 0 pRII_Microscopy Ctrl/Ctrl lin lin 23 | plot4 JI09_151102_Drg421_418_Age LinePlot MeanAndSD JI09_151102_Drg421_418_Age__ctrl_and_Fsk1 time -60 Time [min] pRII_Microscopy 0 pRII_Microscopy Ctrl/Fsk(1) lin lin 24 | plot4 JI09_151102_Drg421_418_Age LinePlot MeanAndSD JI09_151102_Drg421_418_Age__ctrl_and_Fsk3 time -60 Time [min] pRII_Microscopy 0 pRII_Microscopy Ctrl/Fsk(3) lin lin 25 | plot4 JI09_151102_Drg421_418_Age LinePlot MeanAndSD JI09_151102_Drg421_418_Age__ctrl_and_Fsk10 time -60 Time [min] pRII_Microscopy 0 pRII_Microscopy Ctrl/Fsk(10) lin lin 26 | plot4 JI09_151102_Drg421_418_Age LinePlot MeanAndSD JI09_151102_Drg421_418_Age__H894_and_Fsk3 time -60 Time [min] pRII_Microscopy 0 pRII_Microscopy H89(4)/Fsk(3) lin lin 27 | plot4 JI09_151102_Drg421_418_Age LinePlot MeanAndSD JI09_151102_Drg421_418_Age__H8910_and_Fsk3 time -60 Time [min] pRII_Microscopy 0 pRII_Microscopy H89(10)/Fsk(3) lin lin 28 | plot4 JI09_151102_Drg421_418_Age LinePlot MeanAndSD JI09_151102_Drg421_418_Age__H8925_and_Fsk3 time -60 Time [min] pRII_Microscopy 0 pRII_Microscopy H89(25)/Fsk(3) lin lin 29 | plot4 JI09_151102_Drg421_418_Age LinePlot MeanAndSD JI09_151102_Drg421_418_Age__H8925_and_ctrl time -60 Time [min] pRII_Microscopy 0 pRII_Microscopy H89(25)/Ctrl lin lin 30 | plot5 JI09_160126_Drg449_444_CycNuc BarPlot MeanAndSD JI09_160126_Drg449_444_CycNuc__ctrl condition 0 Condition pRII_Western 0 pRII_Western Ctrl lin lin 31 | plot5 JI09_160126_Drg449_444_CycNuc BarPlot MeanAndSD JI09_160126_Drg449_444_CycNuc__Fsk10_and_IBMX100 condition 0 Condition pRII_Western 0 pRII_Western IBMX(100)/Fsk(10) lin lin 32 | plot5 JI09_160126_Drg449_444_CycNuc BarPlot MeanAndSD JI09_160126_Drg449_444_CycNuc__Sp8_Br_cAMPS_AM10 condition 0 Condition pRII_Western 0 pRII_Western Sp8-Br-cAMPS-AM(10) lin lin 33 | plot6 JI09_160201_Drg453-452_CycNuc LinePlot MeanAndSD JI09_160201_Drg453-452_CycNuc__ctrl time 0 Time [min] Calpha_Microscopy 0 Calpha_Microscopy Ctrl lin lin 34 | plot6 JI09_160201_Drg453-452_CycNuc LinePlot MeanAndSD JI09_160201_Drg453-452_CycNuc__Fsk time 0 Time [min] Calpha_Microscopy 0 Calpha_Microscopy Fsk(10) lin lin 35 | plot6 JI09_160201_Drg453-452_CycNuc LinePlot MeanAndSD JI09_160201_Drg453-452_CycNuc__Sp8_Br_cAMPS_AM time 0 Time [min] Calpha_Microscopy 0 Calpha_Microscopy Sp8-Br-cAMPS-AM(10) lin lin 36 | -------------------------------------------------------------------------------- /doc/example/example_Isensee/Isensee_visualizationSpecification_replicates.tsv: -------------------------------------------------------------------------------- 1 | plotId plotName plotTypeSimulation plotTypeData datasetId xValues xOffset yValues yOffset yLabel legendEntry xScale yScale 2 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__4_ABnOH_and_ctrl fourABnOH_incubation_time 0 pRII_Microscopy 0 pRII_Microscopy 4-ABnOH/Ctrl lin lin 3 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__4_ABnOH_and_Fsk fourABnOH_incubation_time 0 pRII_Microscopy 0 pRII_Microscopy 4-ABnOH/Fsk(10) lin lin 4 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__Rp_cAMPS_pAB_and_ctrl Rp_cAMPS_pAB_incubation_time 0 pRII_Microscopy 0 pRII_Microscopy Rp-cAMPS-pAB/Ctrl lin lin 5 | plot1 JI09_150302_Drg345_343_CycNuc LinePlot MeanAndSD JI09_150302_Drg345_343_CycNuc__Rp_cAMPS_pAB_and_ctrl Rp_cAMPS_pAB_incubation_time 0 pRII_Microscopy 0 pRII_Microscopy Rp-cAMPS-pAB/Fsk(10) lin lin 6 | plot2 JI09_150302_Drg345_343_CycNuc LinePlot replicate JI09_150302_Drg345_343_CycNuc__4_ABnOH_and_ctrl fourABnOH_incubation_time 0 pRII_Microscopy 0 pRII_Microscopy 4-ABnOH/Ctrl lin lin 7 | plot2 JI09_150302_Drg345_343_CycNuc LinePlot replicate JI09_150302_Drg345_343_CycNuc__4_ABnOH_and_Fsk fourABnOH_incubation_time 0 pRII_Microscopy 0 pRII_Microscopy 4-ABnOH/Fsk(10) lin lin 8 | plot2 JI09_150302_Drg345_343_CycNuc LinePlot replicate JI09_150302_Drg345_343_CycNuc__Rp_cAMPS_pAB_and_ctrl Rp_cAMPS_pAB_incubation_time 0 pRII_Microscopy 0 pRII_Microscopy Rp-cAMPS-pAB/Ctrl lin lin 9 | plot2 JI09_150302_Drg345_343_CycNuc LinePlot replicate JI09_150302_Drg345_343_CycNuc__Rp_cAMPS_pAB_and_ctrl Rp_cAMPS_pAB_incubation_time 0 pRII_Microscopy 0 pRII_Microscopy Rp-cAMPS-pAB/Fsk(10) lin lin 10 | plot3 JI09_160201_Drg453-452_CycNuc LinePlot MeanAndSD JI09_160201_Drg453-452_CycNuc__ctrl time 0 Calpha_Microscopy 0 Calpha_Microscopy Ctrl lin lin 11 | plot3 JI09_160201_Drg453-452_CycNuc LinePlot MeanAndSD JI09_160201_Drg453-452_CycNuc__Fsk time 0 Calpha_Microscopy 0 Calpha_Microscopy Fsk(10) lin lin 12 | plot3 JI09_160201_Drg453-452_CycNuc LinePlot MeanAndSD JI09_160201_Drg453-452_CycNuc__Sp8_Br_cAMPS_AM time 0 Calpha_Microscopy 0 Calpha_Microscopy Sp8-Br-cAMPS-AM(10) lin lin 13 | plot4 JI09_160201_Drg453-452_CycNuc LinePlot replicate JI09_160201_Drg453-452_CycNuc__ctrl time 0 Calpha_Microscopy 0 Calpha_Microscopy Ctrl lin lin 14 | plot4 JI09_160201_Drg453-452_CycNuc LinePlot replicate JI09_160201_Drg453-452_CycNuc__Fsk time 0 Calpha_Microscopy 0 Calpha_Microscopy Fsk(10) lin lin 15 | plot4 JI09_160201_Drg453-452_CycNuc LinePlot replicate JI09_160201_Drg453-452_CycNuc__Sp8_Br_cAMPS_AM time 0 Calpha_Microscopy 0 Calpha_Microscopy Sp8-Br-cAMPS-AM(10) lin lin 16 | -------------------------------------------------------------------------------- /doc/example/example_Isensee/Isensee_visualizationSpecification_scatterplot.tsv: -------------------------------------------------------------------------------- 1 | plotId plotName plotTypeSimulation plotTypeData datasetId xValues xOffset xLabel yValues yOffset yLabel legendEntry xScale yScale 2 | plot5 JI09_160126_Drg449_444_CycNuc ScatterPlot MeanAndSD JI09_160126_Drg449_444_CycNuc__ctrl condition 0 Condition pRII_Western 0 pRII_Western Ctrl lin lin 3 | plot5 JI09_160126_Drg449_444_CycNuc ScatterPlot MeanAndSD JI09_160126_Drg449_444_CycNuc__Fsk10_and_IBMX100 condition 0 Condition pRII_Western 0 pRII_Western IBMX(100)/Fsk(10) lin lin 4 | plot5 JI09_160126_Drg449_444_CycNuc ScatterPlot MeanAndSD JI09_160126_Drg449_444_CycNuc__Sp8_Br_cAMPS_AM10 condition 0 Condition pRII_Western 0 pRII_Western Sp8-Br-cAMPS-AM(10) lin lin 5 | plot6 JI09_160201_Drg453-452_CycNuc ScatterPlot MeanAndSD JI09_160201_Drg453-452_CycNuc__ctrl time 0 Time [min] Calpha_Microscopy 0 Calpha_Microscopy Ctrl lin lin 6 | plot6 JI09_160201_Drg453-452_CycNuc ScatterPlot MeanAndSD JI09_160201_Drg453-452_CycNuc__Fsk time 0 Time [min] Calpha_Microscopy 0 Calpha_Microscopy Fsk(10) lin lin 7 | plot6 JI09_160201_Drg453-452_CycNuc ScatterPlot MeanAndSD JI09_160201_Drg453-452_CycNuc__Sp8_Br_cAMPS_AM time 0 Time [min] Calpha_Microscopy 0 Calpha_Microscopy Sp8-Br-cAMPS-AM(10) lin lin 8 | -------------------------------------------------------------------------------- /doc/example/example_petablint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Using petablint" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "`petablint` is a tool to validate a model against the PEtab standard. When you have installed PEtab, you can simply call it from the command line. It takes the following arguments:" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 1, 20 | "metadata": {}, 21 | "outputs": [ 22 | { 23 | "name": "stdout", 24 | "output_type": "stream", 25 | "text": [ 26 | "usage: petablint [-h] [-v] [-s SBML_FILE_NAME] [-m MEASUREMENT_FILE_NAME]\r\n", 27 | " [-c CONDITION_FILE_NAME] [-p PARAMETER_FILE_NAME]\r\n", 28 | " [-y YAML_FILE_NAME | -n MODEL_NAME] [-d DIRECTORY]\r\n", 29 | "\r\n", 30 | "Check if a set of files adheres to the PEtab format.\r\n", 31 | "\r\n", 32 | "optional arguments:\r\n", 33 | " -h, --help show this help message and exit\r\n", 34 | " -v, --verbose More verbose output\r\n", 35 | " -s SBML_FILE_NAME, --sbml SBML_FILE_NAME\r\n", 36 | " SBML model filename\r\n", 37 | " -m MEASUREMENT_FILE_NAME, --measurements MEASUREMENT_FILE_NAME\r\n", 38 | " Measurement table\r\n", 39 | " -c CONDITION_FILE_NAME, --conditions CONDITION_FILE_NAME\r\n", 40 | " Conditions table\r\n", 41 | " -p PARAMETER_FILE_NAME, --parameters PARAMETER_FILE_NAME\r\n", 42 | " Parameter table\r\n", 43 | " -y YAML_FILE_NAME, --yaml YAML_FILE_NAME\r\n", 44 | " PEtab YAML problem filename\r\n", 45 | " -n MODEL_NAME, --model-name MODEL_NAME\r\n", 46 | " Model name where all files are in the working\r\n", 47 | " directory and follow PEtab naming convention.\r\n", 48 | " Specifying -[smcp] will override defaults\r\n", 49 | " -d DIRECTORY, --directory DIRECTORY\r\n" 50 | ] 51 | } 52 | ], 53 | "source": [ 54 | "!petablint -h" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "Let's look at an example: In the example_Fujita folder, we have a PEtab configuration file `Fujita.yaml` telling which files belong to the Fujita model:" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 2, 67 | "metadata": {}, 68 | "outputs": [ 69 | { 70 | "name": "stdout", 71 | "output_type": "stream", 72 | "text": [ 73 | "parameter_file: Fujita_parameters.tsv\r\n", 74 | "petab_version: 0.0.0a17\r\n", 75 | "problems:\r\n", 76 | "- condition_files:\r\n", 77 | " - Fujita_experimentalCondition.tsv\r\n", 78 | " measurement_files:\r\n", 79 | " - Fujita_measurementData.tsv\r\n", 80 | " sbml_files:\r\n", 81 | " - Fujita_model.xml\r\n" 82 | ] 83 | } 84 | ], 85 | "source": [ 86 | "!cat example_Fujita/Fujita.yaml" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "To verify everything is ok, we can just call:" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 3, 99 | "metadata": {}, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "\u001b[0m" 106 | ] 107 | } 108 | ], 109 | "source": [ 110 | "!petablint -y example_Fujita/Fujita.yaml" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "If there were some inconsistency or error, we would see that here. `petablint` can be called in different ways. You can e.g. also pass SBML, measurement, condition, and parameter file directly, or, if the files follow PEtab naming conventions, you can just pass the model name." 118 | ] 119 | } 120 | ], 121 | "metadata": { 122 | "kernelspec": { 123 | "display_name": "Python 3", 124 | "language": "python", 125 | "name": "python3" 126 | }, 127 | "language_info": { 128 | "codemirror_mode": { 129 | "name": "ipython", 130 | "version": 3 131 | }, 132 | "file_extension": ".py", 133 | "mimetype": "text/x-python", 134 | "name": "python", 135 | "nbconvert_exporter": "python", 136 | "pygments_lexer": "ipython3", 137 | "version": "3.7.3" 138 | } 139 | }, 140 | "nbformat": 4, 141 | "nbformat_minor": 2 142 | } 143 | -------------------------------------------------------------------------------- /doc/gfx/copasi_simulation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/gfx/copasi_simulation.png -------------------------------------------------------------------------------- /doc/gfx/petab_files.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/gfx/petab_files.pdf -------------------------------------------------------------------------------- /doc/gfx/petab_files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/gfx/petab_files.png -------------------------------------------------------------------------------- /doc/gfx/petab_scope_and_files.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/gfx/petab_scope_and_files.pdf -------------------------------------------------------------------------------- /doc/gfx/petab_scope_and_files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/gfx/petab_scope_and_files.png -------------------------------------------------------------------------------- /doc/gfx/tutorial_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/gfx/tutorial_data.png -------------------------------------------------------------------------------- /doc/gfx/tutorial_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/gfx/tutorial_model.png -------------------------------------------------------------------------------- /doc/how_to_cite.rst: -------------------------------------------------------------------------------- 1 | .. _how_to_cite: 2 | 3 | How to cite 4 | =========== 5 | 6 | Help us to promote PEtab: When using PEtab, please cite our `PEtab article `_: 7 | 8 | .. code-block:: bibtex 9 | 10 | @Article{SchmiesterSch2021, 11 | author = {Schmiester, Leonard AND Schälte, Yannik AND Bergmann, Frank T. AND Camba, Tacio AND Dudkin, Erika AND Egert, Janine AND Fröhlich, Fabian AND Fuhrmann, Lara AND Hauber, Adrian L. AND Kemmer, Svenja AND Lakrisenko, Polina AND Loos, Carolin AND Merkt, Simon AND Müller, Wolfgang AND Pathirana, Dilan AND Raimúndez, Elba AND Refisch, Lukas AND Rosenblatt, Marcus AND Stapor, Paul L. AND Städter, Philipp AND Wang, Dantong AND Wieland, Franz-Georg AND Banga, Julio R. AND Timmer, Jens AND Villaverde, Alejandro F. AND Sahle, Sven AND Kreutz, Clemens AND Hasenauer, Jan AND Weindl, Daniel}, 12 | journal = {PLOS Computational Biology}, 13 | title = {PEtab—Interoperable specification of parameter estimation problems in systems biology}, 14 | year = {2021}, 15 | month = {01}, 16 | number = {1}, 17 | pages = {1-10}, 18 | volume = {17}, 19 | doi = {10.1371/journal.pcbi.1008646}, 20 | publisher = {Public Library of Science}, 21 | url = {https://doi.org/10.1371/journal.pcbi.1008646}, 22 | } 23 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: 2 | _static/README.rst 3 | 4 | .. toctree:: 5 | :maxdepth: 3 6 | :caption: Python package 7 | 8 | modules 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | :caption: About 13 | 14 | Changelog 15 | how_to_cite 16 | license 17 | development 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | :caption: Examples 22 | 23 | example 24 | 25 | 26 | Indices and tables 27 | ================== 28 | 29 | * :ref:`genindex` 30 | * :ref:`modindex` 31 | * :ref:`search` 32 | -------------------------------------------------------------------------------- /doc/license.rst: -------------------------------------------------------------------------------- 1 | License 2 | ======= 3 | 4 | .. literalinclude:: ../LICENSE 5 | -------------------------------------------------------------------------------- /doc/logo/LICENSE.md: -------------------------------------------------------------------------------- 1 | # PEtab logo license 2 | 3 | The PEtab logo is free for use under the 4 | [CC0](https://creativecommons.org/share-your-work/public-domain/cc0) license. 5 | 6 | ![Logo](PEtab.png) 7 | -------------------------------------------------------------------------------- /doc/logo/PEtab.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/logo/PEtab.pdf -------------------------------------------------------------------------------- /doc/logo/PEtab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/logo/PEtab.png -------------------------------------------------------------------------------- /doc/logo/PEtab_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/doc/logo/PEtab_github.png -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /doc/md2rst.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import m2r2 4 | 5 | 6 | def read(fname): 7 | """Read a file.""" 8 | return open(fname).read() 9 | 10 | 11 | def absolute_links(txt): 12 | """Replace relative petab github links by absolute links.""" 13 | repo = "petab-dev/libpetab-python" 14 | raw_base = f"(https://raw.githubusercontent.com/{repo}/master/" 15 | embedded_base = f"(https://github.com/{repo}/tree/master/" 16 | # iterate over links 17 | for var in re.findall(r"\[.*?\]\((?!http).*?\)", txt): 18 | if re.match(r".*?.(png|svg)\)", var): 19 | # link to raw file 20 | rep = var.replace("(", raw_base) 21 | else: 22 | # link to github embedded file 23 | rep = var.replace("(", embedded_base) 24 | txt = txt.replace(var, rep) 25 | return txt 26 | 27 | 28 | def md2rst(source: str, target: str): 29 | txt = absolute_links(read(source)) 30 | txt = m2r2.convert(txt) 31 | with open(target, "w") as f: 32 | f.write(txt) 33 | 34 | 35 | if __name__ == "__main__": 36 | # parse readme 37 | md2rst("../README.md", "_static/README.rst") 38 | -------------------------------------------------------------------------------- /doc/modules.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | .. rubric:: Modules 5 | 6 | .. autosummary:: 7 | :toctree: build/_autosummary 8 | :recursive: 9 | 10 | petab 11 | petab.v1 12 | petab.v1.C 13 | petab.v1.calculate 14 | petab.v1.composite_problem 15 | petab.v1.conditions 16 | petab.v1.core 17 | petab.v1.lint 18 | petab.v1.measurements 19 | petab.v1.models 20 | petab.v1.observables 21 | petab.v1.parameter_mapping 22 | petab.v1.parameters 23 | petab.v1.priors 24 | petab.v1.problem 25 | petab.v1.sampling 26 | petab.v1.sbml 27 | petab.v1.simulate 28 | petab.v1.simplify 29 | petab.v1.visualize 30 | petab.v1.yaml 31 | petab.v2 32 | petab.v2.C 33 | petab.v2.lint 34 | petab.v2.problem 35 | -------------------------------------------------------------------------------- /doc/tutorial/Boehm_JProteomeRes2014.yaml: -------------------------------------------------------------------------------- 1 | format_version: 1 2 | parameter_file: parameters.tsv 3 | problems: 4 | - condition_files: 5 | - experimental_conditions.tsv 6 | measurement_files: 7 | - measurement_data.tsv 8 | observable_files: 9 | - observables.tsv 10 | sbml_files: 11 | - model_Boehm_JProteomeRes2014.xml 12 | visualization_files: 13 | - visualization_specification.tsv 14 | -------------------------------------------------------------------------------- /doc/tutorial/experimental_conditions.tsv: -------------------------------------------------------------------------------- 1 | conditionId conditionName Epo_concentration 2 | epo_stimulation condition1 1.25E-07 3 | -------------------------------------------------------------------------------- /doc/tutorial/measurement_data.tsv: -------------------------------------------------------------------------------- 1 | observableId simulationConditionId measurement time noiseParameters 2 | pSTAT5A_rel epo_stimulation 7.901072999 0 sd_pSTAT5A_rel 3 | pSTAT5A_rel epo_stimulation 66.36349397 2.5 sd_pSTAT5A_rel 4 | pSTAT5A_rel epo_stimulation 81.17132392 5 sd_pSTAT5A_rel 5 | pSTAT5A_rel epo_stimulation 94.73030806 10 sd_pSTAT5A_rel 6 | pSTAT5A_rel epo_stimulation 95.11648305 15 sd_pSTAT5A_rel 7 | pSTAT5A_rel epo_stimulation 91.44171655 20 sd_pSTAT5A_rel 8 | pSTAT5A_rel epo_stimulation 91.25709923 30 sd_pSTAT5A_rel 9 | pSTAT5A_rel epo_stimulation 93.67229784 40 sd_pSTAT5A_rel 10 | pSTAT5A_rel epo_stimulation 88.75423282 50 sd_pSTAT5A_rel 11 | pSTAT5A_rel epo_stimulation 85.26970322 60 sd_pSTAT5A_rel 12 | pSTAT5A_rel epo_stimulation 81.13239534 80 sd_pSTAT5A_rel 13 | pSTAT5A_rel epo_stimulation 76.13592848 100 sd_pSTAT5A_rel 14 | pSTAT5A_rel epo_stimulation 65.24805913 120 sd_pSTAT5A_rel 15 | pSTAT5A_rel epo_stimulation 42.59965871 160 sd_pSTAT5A_rel 16 | pSTAT5A_rel epo_stimulation 25.15779754 200 sd_pSTAT5A_rel 17 | pSTAT5A_rel epo_stimulation 15.4301824 240 sd_pSTAT5A_rel 18 | pSTAT5B_rel epo_stimulation 4.596533343 0 sd_pSTAT5B_rel 19 | pSTAT5B_rel epo_stimulation 29.63454599 2.5 sd_pSTAT5B_rel 20 | pSTAT5B_rel epo_stimulation 46.04380647 5 sd_pSTAT5B_rel 21 | pSTAT5B_rel epo_stimulation 81.97473362 10 sd_pSTAT5B_rel 22 | pSTAT5B_rel epo_stimulation 80.5716093 15 sd_pSTAT5B_rel 23 | pSTAT5B_rel epo_stimulation 79.03571964 20 sd_pSTAT5B_rel 24 | pSTAT5B_rel epo_stimulation 75.67238037 30 sd_pSTAT5B_rel 25 | pSTAT5B_rel epo_stimulation 71.62471986 40 sd_pSTAT5B_rel 26 | pSTAT5B_rel epo_stimulation 69.06286328 50 sd_pSTAT5B_rel 27 | pSTAT5B_rel epo_stimulation 67.14738432 60 sd_pSTAT5B_rel 28 | pSTAT5B_rel epo_stimulation 60.89947629 80 sd_pSTAT5B_rel 29 | pSTAT5B_rel epo_stimulation 54.80925777 100 sd_pSTAT5B_rel 30 | pSTAT5B_rel epo_stimulation 43.98128998 120 sd_pSTAT5B_rel 31 | pSTAT5B_rel epo_stimulation 29.77145816 160 sd_pSTAT5B_rel 32 | pSTAT5B_rel epo_stimulation 20.08901656 200 sd_pSTAT5B_rel 33 | pSTAT5B_rel epo_stimulation 10.96184517 240 sd_pSTAT5B_rel 34 | rSTAT5A_rel epo_stimulation 14.72316822 0 sd_rSTAT5A_rel 35 | rSTAT5A_rel epo_stimulation 33.76234229 2.5 sd_rSTAT5A_rel 36 | rSTAT5A_rel epo_stimulation 36.79985129 5 sd_rSTAT5A_rel 37 | rSTAT5A_rel epo_stimulation 49.71760229 10 sd_rSTAT5A_rel 38 | rSTAT5A_rel epo_stimulation 46.9281201 15 sd_rSTAT5A_rel 39 | rSTAT5A_rel epo_stimulation 47.83657456 20 sd_rSTAT5A_rel 40 | rSTAT5A_rel epo_stimulation 46.92872725 30 sd_rSTAT5A_rel 41 | rSTAT5A_rel epo_stimulation 40.59775294 40 sd_rSTAT5A_rel 42 | rSTAT5A_rel epo_stimulation 43.78366389 50 sd_rSTAT5A_rel 43 | rSTAT5A_rel epo_stimulation 44.45738765 60 sd_rSTAT5A_rel 44 | rSTAT5A_rel epo_stimulation 41.32715926 80 sd_rSTAT5A_rel 45 | rSTAT5A_rel epo_stimulation 41.06273321 100 sd_rSTAT5A_rel 46 | rSTAT5A_rel epo_stimulation 39.23583003 120 sd_rSTAT5A_rel 47 | rSTAT5A_rel epo_stimulation 36.61946054 160 sd_rSTAT5A_rel 48 | rSTAT5A_rel epo_stimulation 34.8937144 200 sd_rSTAT5A_rel 49 | rSTAT5A_rel epo_stimulation 32.21107716 240 sd_rSTAT5A_rel 50 | -------------------------------------------------------------------------------- /doc/tutorial/observables.tsv: -------------------------------------------------------------------------------- 1 | observableId observableFormula noiseFormula observableTransformation noiseDistribution 2 | pSTAT5A_rel (100 * pApB + 200 * pApA * specC17) / (pApB + STAT5A * specC17 + 2 * pApA * specC17) noiseParameter1_pSTAT5A_rel lin normal 3 | pSTAT5B_rel -(100 * pApB - 200 * pBpB * (specC17 - 1)) / ((STAT5B * (specC17 - 1) - pApB) + 2 * pBpB * (specC17 - 1)) noiseParameter1_pSTAT5B_rel lin normal 4 | rSTAT5A_rel (100 * pApB + 100 * STAT5A * specC17 + 200 * pApA * specC17) / (2 * pApB + STAT5A * specC17 + 2 * pApA * specC17 - STAT5B * (specC17 - 1) - 2 * pBpB * (specC17 - 1)) noiseParameter1_rSTAT5A_rel lin normal 5 | -------------------------------------------------------------------------------- /doc/tutorial/parameters.tsv: -------------------------------------------------------------------------------- 1 | parameterId parameterName parameterScale lowerBound upperBound nominalValue estimate 2 | Epo_degradation_BaF3 EPO_{degradation,BaF3} log10 1E-05 100000 1 3 | k_exp_hetero k_{exp,hetero} log10 1E-05 100000 1 4 | k_exp_homo k_{exp,homo} log10 1E-05 100000 1 5 | k_imp_hetero k_{imp,hetero} log10 1E-05 100000 1 6 | k_imp_homo k_{imp,homo} log10 1E-05 100000 1 7 | k_phos k_{phos} log10 1E-05 100000 1 8 | ratio ratio lin 0.693 0 9 | sd_pSTAT5A_rel \sigma_{pSTAT5A,rel} log10 1E-05 100000 1 10 | sd_pSTAT5B_rel \sigma_{pSTAT5B,rel} log10 1E-05 100000 1 11 | sd_rSTAT5A_rel \sigma_{rSTAT5A,rel} log10 1E-05 100000 1 12 | specC17 specC17 lin 0.107 0 13 | -------------------------------------------------------------------------------- /doc/tutorial/visualization_specification.tsv: -------------------------------------------------------------------------------- 1 | plotId plotName plotTypeData xLabel yValues yLabel 2 | plot1 pSTAT5A_rel MeanAndSD Time [min] pSTAT5A_rel Rel. STAT5A phosphorylation [%] 3 | plot2 pSTAT5B_rel MeanAndSD Time [min] pSTAT5B_rel Rel. STAT5B phosphorylation [%] 4 | plot3 rSTAT5A_rel MeanAndSD Time [min] rSTAT5A_rel Rel. STAT5A abundance [%] 5 | -------------------------------------------------------------------------------- /petab/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | PEtab global 3 | ============ 4 | 5 | Attributes: 6 | ENV_NUM_THREADS: 7 | Name of environment variable to set number of threads or processes 8 | PEtab should use for operations that can be performed in parallel. 9 | By default, all operations are performed sequentially. 10 | """ 11 | import importlib 12 | import sys 13 | from functools import partial 14 | from pathlib import Path 15 | from warnings import warn 16 | 17 | ENV_NUM_THREADS = "PETAB_NUM_THREADS" 18 | __all__ = ["ENV_NUM_THREADS"] 19 | 20 | 21 | def __getattr__(name): 22 | if attr := globals().get(name): 23 | return attr 24 | if name == "v1": 25 | return importlib.import_module("petab.v1") 26 | if name != "__path__": 27 | warn( 28 | f"Accessing `petab.{name}` is deprecated and will be removed in " 29 | f"the next major release. Please use `petab.v1.{name}` instead.", 30 | DeprecationWarning, 31 | stacklevel=3, 32 | ) 33 | return getattr(importlib.import_module("petab.v1"), name) 34 | 35 | 36 | def v1getattr(name, module): 37 | if name != "__path__": 38 | warn( 39 | f"Accessing `petab.{name}` is deprecated and will be removed in " 40 | f"the next major release. Please use `petab.v1.{name}` instead.", 41 | DeprecationWarning, 42 | stacklevel=3, 43 | ) 44 | try: 45 | return module.__dict__[name] 46 | except KeyError: 47 | raise AttributeError(name) from None 48 | 49 | 50 | # Create dummy modules for all old modules 51 | v1_root = Path(__file__).resolve().parent / "v1" 52 | v1_objects = [f.relative_to(v1_root) for f in v1_root.rglob("*")] 53 | for v1_object in v1_objects: 54 | if "__pycache__" in str(v1_object): 55 | continue 56 | if v1_object.suffix not in ["", ".py"]: 57 | continue 58 | if not (v1_root / v1_object).exists(): 59 | raise ValueError(v1_root / v1_object) 60 | v1_object_parts = [*v1_object.parts[:-1], v1_object.stem] 61 | module_name = ".".join(["petab", *v1_object_parts]) 62 | 63 | try: 64 | real_module = importlib.import_module( 65 | f"petab.v1.{'.'.join(v1_object_parts)}" 66 | ) 67 | real_module.__getattr__ = partial(v1getattr, module=real_module) 68 | sys.modules[module_name] = real_module 69 | except ModuleNotFoundError: 70 | pass 71 | -------------------------------------------------------------------------------- /petab/schemas/petab_schema.v1.0.0.yaml: -------------------------------------------------------------------------------- 1 | # For syntax see: https://json-schema.org/understanding-json-schema 2 | #$schema: "https://json-schema.org/draft/2019-09/meta/core" 3 | $schema: "http://json-schema.org/draft-06/schema" 4 | description: PEtab parameter estimation problem config file schema 5 | 6 | definitions: 7 | list_of_files: 8 | type: array 9 | description: List of files. 10 | items: 11 | type: string 12 | description: File name or URL. 13 | version_number: 14 | type: string 15 | pattern: ^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?$ 16 | description: Version number (corresponding to PEP 440). 17 | 18 | properties: 19 | 20 | format_version: 21 | anyof: 22 | - $ref: "#/definitions/version_number" 23 | - type: integer 24 | description: Version of the PEtab format (e.g. 1). 25 | 26 | parameter_file: 27 | oneOf: 28 | - type: string 29 | - type: array 30 | description: | 31 | File name (absolute or relative) or URL to PEtab parameter table 32 | containing parameters of all models listed in `problems`. A single 33 | table may be split into multiple files and described as an array here. 34 | 35 | problems: 36 | type: array 37 | description: | 38 | One or multiple PEtab problems (sets of model, condition, observable 39 | and measurement files). If different model and data files are 40 | independent, they can be specified as separate PEtab problems, which 41 | may allow more efficient handling. Files in one problem cannot refer 42 | to models entities or data specified inside another problem. 43 | items: 44 | 45 | type: object 46 | description: | 47 | A set of PEtab model, condition, observable and measurement 48 | files and optional visualization files. 49 | properties: 50 | 51 | sbml_files: 52 | $ref: "#/definitions/list_of_files" 53 | description: List of SBML model files. 54 | 55 | measurement_files: 56 | $ref: "#/definitions/list_of_files" 57 | description: List of PEtab measurement files. 58 | 59 | condition_files: 60 | $ref: "#/definitions/list_of_files" 61 | description: List of PEtab condition files. 62 | 63 | observable_files: 64 | $ref: "#/definitions/list_of_files" 65 | description: List of PEtab observable files. 66 | 67 | visualization_files: 68 | $ref: "#/definitions/list_of_files" 69 | description: List of PEtab visualization files. 70 | 71 | required: 72 | - sbml_files 73 | - observable_files 74 | - measurement_files 75 | - condition_files 76 | 77 | required: 78 | - format_version 79 | - parameter_file 80 | - problems 81 | -------------------------------------------------------------------------------- /petab/schemas/petab_schema.v2.0.0.yaml: -------------------------------------------------------------------------------- 1 | # For syntax see: https://json-schema.org/understanding-json-schema 2 | #$schema: "https://json-schema.org/draft/2019-09/meta/core" 3 | $schema: "http://json-schema.org/draft-06/schema" 4 | description: PEtab parameter estimation problem config file schema 5 | 6 | definitions: 7 | list_of_files: 8 | type: array 9 | description: List of files. 10 | items: 11 | type: string 12 | description: File name or URL. 13 | version_number: 14 | type: string 15 | pattern: ^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?$ 16 | description: Version number (corresponding to PEP 440). 17 | 18 | properties: 19 | 20 | format_version: 21 | anyof: 22 | - $ref: "#/definitions/version_number" 23 | - type: integer 24 | description: Version of the PEtab format 25 | 26 | parameter_file: 27 | oneOf: 28 | - type: string 29 | - type: array 30 | description: | 31 | File name (absolute or relative) or URL to PEtab parameter table 32 | containing parameters of all models listed in `problems`. A single 33 | table may be split into multiple files and described as an array here. 34 | problems: 35 | type: array 36 | description: | 37 | One or multiple PEtab problems (sets of model, condition, observable 38 | and measurement files). If different model and data files are 39 | independent, they can be specified as separate PEtab problems, which 40 | may allow more efficient handling. Files in one problem cannot refer 41 | to models entities or data specified inside another problem. 42 | items: 43 | 44 | type: object 45 | description: | 46 | A set of PEtab model, condition, observable and measurement 47 | files and optional visualization files. 48 | properties: 49 | 50 | model_files: 51 | type: object 52 | description: One or multiple models 53 | 54 | # the model ID 55 | patternProperties: 56 | "^[a-zA-Z_]\\w*$": 57 | type: object 58 | properties: 59 | location: 60 | type: string 61 | description: Model file name or URL 62 | language: 63 | type: string 64 | description: | 65 | Model language, e.g., 'sbml', 'cellml', 'bngl', 'pysb' 66 | required: 67 | - location 68 | - language 69 | additionalProperties: false 70 | 71 | measurement_files: 72 | description: List of PEtab measurement files. 73 | $ref: "#/definitions/list_of_files" 74 | 75 | condition_files: 76 | description: List of PEtab condition files. 77 | $ref: "#/definitions/list_of_files" 78 | 79 | observable_files: 80 | description: List of PEtab observable files. 81 | $ref: "#/definitions/list_of_files" 82 | 83 | visualization_files: 84 | description: List of PEtab visualization files. 85 | $ref: "#/definitions/list_of_files" 86 | 87 | mapping_file: 88 | type: string 89 | description: Optional PEtab mapping file name or URL. 90 | 91 | required: 92 | - model_files 93 | - observable_files 94 | - measurement_files 95 | - condition_files 96 | 97 | extensions: 98 | type: object 99 | description: | 100 | PEtab extensions being used. 101 | patternProperties: 102 | "^[a-zA-Z][\\-\\w]*$": 103 | 104 | type: object 105 | description: | 106 | Information on a specific extension 107 | properties: 108 | version: 109 | $ref: "#/definitions/version_number" 110 | 111 | required: 112 | - version 113 | additionalProperties: true 114 | 115 | additionalProperties: false 116 | 117 | required: 118 | - format_version 119 | - parameter_file 120 | - problems 121 | -------------------------------------------------------------------------------- /petab/v1/__init__.py: -------------------------------------------------------------------------------- 1 | """The PEtab 1.0 subpackage. 2 | 3 | Contains all functionality related to handling PEtab 1.0 problems. 4 | """ 5 | 6 | from ..version import __version__ # noqa: F401, E402 7 | from .C import * # noqa: F403, F401, E402 8 | from .calculate import * # noqa: F403, F401, E402 9 | from .composite_problem import * # noqa: F403, F401, E402 10 | from .conditions import * # noqa: F403, F401, E402 11 | from .core import * # noqa: F403, F401, E402 12 | from .format_version import __format_version__ # noqa: F401, E402 13 | from .lint import * # noqa: F403, F401, E402 14 | from .mapping import * # noqa: F403, F401, E402 15 | from .measurements import * # noqa: F403, F401, E402 16 | from .observables import * # noqa: F403, F401, E402 17 | from .parameter_mapping import * # noqa: F403, F401, E402 18 | from .parameters import * # noqa: F403, F401, E402 19 | from .problem import * # noqa: F403, F401, E402 20 | from .sampling import * # noqa: F403, F401, E402 21 | from .sbml import * # noqa: F403, F401, E402 22 | from .simulate import * # noqa: F403, F401, E402 23 | from .yaml import * # noqa: F403, F401, E402 24 | -------------------------------------------------------------------------------- /petab/v1/composite_problem.py: -------------------------------------------------------------------------------- 1 | """PEtab problems consisting of multiple models""" 2 | import os 3 | 4 | import pandas as pd 5 | 6 | from . import parameters, problem, yaml 7 | from .C import * # noqa: F403 8 | 9 | __all__ = ["CompositeProblem"] 10 | 11 | 12 | class CompositeProblem: 13 | """Representation of a PEtab problem consisting of multiple models 14 | 15 | Attributes: 16 | problems: 17 | List of :py:class:`petab.Problem` s 18 | parameter_df: 19 | PEtab parameter DataFrame 20 | """ 21 | 22 | def __init__( 23 | self, 24 | parameter_df: pd.DataFrame = None, 25 | problems: list[problem.Problem] = None, 26 | ): 27 | """Constructor 28 | 29 | Arguments: 30 | parameter_df: 31 | see CompositeProblem.parameter_df 32 | problems: 33 | see CompositeProblem.problems 34 | """ 35 | self.problems: list[problem.Problem] = problems 36 | self.parameter_df: pd.DataFrame = parameter_df 37 | 38 | @staticmethod 39 | def from_yaml(yaml_config: dict | str) -> "CompositeProblem": 40 | """Create from YAML file 41 | 42 | Factory method to create a CompositeProblem instance from a PEtab 43 | YAML config file 44 | 45 | Arguments: 46 | yaml_config: PEtab configuration as dictionary or YAML file name 47 | """ 48 | if isinstance(yaml_config, str): 49 | path_prefix = os.path.dirname(yaml_config) 50 | yaml_config = yaml.load_yaml(yaml_config) 51 | else: 52 | path_prefix = "" 53 | 54 | parameter_df = parameters.get_parameter_df( 55 | os.path.join(path_prefix, yaml_config[PARAMETER_FILE]) 56 | ) 57 | 58 | problems = [] 59 | for problem_config in yaml_config[PROBLEMS]: 60 | yaml.assert_single_condition_and_sbml_file(problem_config) 61 | 62 | # don't set parameter file if we have multiple models 63 | cur_problem = problem.Problem.from_files( 64 | sbml_file=os.path.join( 65 | path_prefix, problem_config[SBML_FILES][0] 66 | ), 67 | measurement_file=[ 68 | os.path.join(path_prefix, f) 69 | for f in problem_config[MEASUREMENT_FILES] 70 | ], 71 | condition_file=os.path.join( 72 | path_prefix, problem_config[CONDITION_FILES][0] 73 | ), 74 | visualization_files=[ 75 | os.path.join(path_prefix, f) 76 | for f in problem_config[VISUALIZATION_FILES] 77 | ], 78 | observable_files=[ 79 | os.path.join(path_prefix, f) 80 | for f in problem_config[OBSERVABLE_FILES] 81 | ], 82 | ) 83 | problems.append(cur_problem) 84 | 85 | return CompositeProblem(parameter_df=parameter_df, problems=problems) 86 | -------------------------------------------------------------------------------- /petab/v1/conditions.py: -------------------------------------------------------------------------------- 1 | """Functions operating on the PEtab condition table""" 2 | 3 | from collections.abc import Iterable 4 | from pathlib import Path 5 | 6 | import numpy as np 7 | import pandas as pd 8 | 9 | from . import core, lint 10 | from .C import * 11 | 12 | __all__ = [ 13 | "get_condition_df", 14 | "write_condition_df", 15 | "create_condition_df", 16 | "get_parametric_overrides", 17 | ] 18 | 19 | 20 | def get_condition_df( 21 | condition_file: str | pd.DataFrame | Path | None, 22 | ) -> pd.DataFrame: 23 | """Read the provided condition file into a ``pandas.Dataframe`` 24 | 25 | Conditions are rows, parameters are columns, conditionId is index. 26 | 27 | Arguments: 28 | condition_file: File name of PEtab condition file or pandas.Dataframe 29 | """ 30 | if condition_file is None: 31 | return condition_file 32 | 33 | if isinstance(condition_file, str | Path): 34 | condition_file = pd.read_csv( 35 | condition_file, sep="\t", float_precision="round_trip" 36 | ) 37 | 38 | lint.assert_no_leading_trailing_whitespace( 39 | condition_file.columns.values, "condition" 40 | ) 41 | 42 | if not isinstance(condition_file.index, pd.RangeIndex): 43 | condition_file.reset_index( 44 | drop=condition_file.index.name != CONDITION_ID, 45 | inplace=True, 46 | ) 47 | 48 | try: 49 | condition_file.set_index([CONDITION_ID], inplace=True) 50 | except KeyError: 51 | raise KeyError( 52 | f"Condition table missing mandatory field {CONDITION_ID}." 53 | ) from None 54 | 55 | return condition_file 56 | 57 | 58 | def write_condition_df(df: pd.DataFrame, filename: str | Path) -> None: 59 | """Write PEtab condition table 60 | 61 | Arguments: 62 | df: PEtab condition table 63 | filename: Destination file name 64 | """ 65 | df = get_condition_df(df) 66 | df.to_csv(filename, sep="\t", index=True) 67 | 68 | 69 | def create_condition_df( 70 | parameter_ids: Iterable[str], condition_ids: Iterable[str] | None = None 71 | ) -> pd.DataFrame: 72 | """Create empty condition DataFrame 73 | 74 | Arguments: 75 | parameter_ids: the columns 76 | condition_ids: the rows 77 | Returns: 78 | A :py:class:`pandas.DataFrame` with empty given rows and columns and 79 | all nan values 80 | """ 81 | condition_ids = [] if condition_ids is None else list(condition_ids) 82 | 83 | data = {CONDITION_ID: condition_ids} 84 | df = pd.DataFrame(data) 85 | 86 | for p in parameter_ids: 87 | if not lint.is_valid_identifier(p): 88 | raise ValueError("Invalid parameter ID: " + p) 89 | df[p] = np.nan 90 | 91 | df.set_index(CONDITION_ID, inplace=True) 92 | 93 | return df 94 | 95 | 96 | def get_parametric_overrides(condition_df: pd.DataFrame) -> list[str]: 97 | """Get parametric overrides from condition table 98 | 99 | Arguments: 100 | condition_df: PEtab condition table 101 | 102 | Returns: 103 | List of parameter IDs that are mapped in a condition-specific way 104 | """ 105 | constant_parameters = set(condition_df.columns.values.tolist()) - { 106 | CONDITION_ID, 107 | CONDITION_NAME, 108 | } 109 | result = [] 110 | 111 | for column in constant_parameters: 112 | if np.issubdtype(condition_df[column].dtype, np.number): 113 | continue 114 | 115 | floatified = condition_df.loc[:, column].apply(core.to_float_if_float) 116 | 117 | result.extend(x for x in floatified if not isinstance(x, float)) 118 | return result 119 | -------------------------------------------------------------------------------- /petab/v1/format_version.py: -------------------------------------------------------------------------------- 1 | """PEtab file format version""" 2 | __format_version__ = 1 3 | -------------------------------------------------------------------------------- /petab/v1/mapping.py: -------------------------------------------------------------------------------- 1 | """Functionality related to the PEtab entity mapping table""" 2 | from pathlib import Path 3 | 4 | import pandas as pd 5 | 6 | from . import lint 7 | from .C import * # noqa: F403 8 | from .models import Model 9 | 10 | __all__ = [ 11 | "get_mapping_df", 12 | "write_mapping_df", 13 | "check_mapping_df", 14 | "resolve_mapping", 15 | ] 16 | 17 | 18 | def get_mapping_df( 19 | mapping_file: None | str | Path | pd.DataFrame, 20 | ) -> pd.DataFrame: 21 | """ 22 | Read the provided mapping file into a ``pandas.Dataframe``. 23 | 24 | Arguments: 25 | mapping_file: Name of file to read from or pandas.Dataframe 26 | 27 | Returns: 28 | Mapping DataFrame 29 | """ 30 | if mapping_file is None: 31 | return mapping_file 32 | 33 | if isinstance(mapping_file, str | Path): 34 | mapping_file = pd.read_csv( 35 | mapping_file, sep="\t", float_precision="round_trip" 36 | ) 37 | 38 | if not isinstance(mapping_file.index, pd.RangeIndex): 39 | mapping_file.reset_index( 40 | drop=mapping_file.index.name != PETAB_ENTITY_ID, 41 | inplace=True, 42 | ) 43 | 44 | for col in MAPPING_DF_REQUIRED_COLS: 45 | if col not in mapping_file.columns: 46 | raise KeyError( 47 | f"Mapping table missing mandatory field {PETAB_ENTITY_ID}." 48 | ) 49 | 50 | lint.assert_no_leading_trailing_whitespace( 51 | mapping_file.reset_index()[col].values, col 52 | ) 53 | 54 | mapping_file.set_index([PETAB_ENTITY_ID], inplace=True) 55 | 56 | return mapping_file 57 | 58 | 59 | def write_mapping_df(df: pd.DataFrame, filename: str | Path) -> None: 60 | """Write PEtab mapping table 61 | 62 | Arguments: 63 | df: PEtab mapping table 64 | filename: Destination file name 65 | """ 66 | df = get_mapping_df(df) 67 | df.to_csv(filename, sep="\t", index=True) 68 | 69 | 70 | def check_mapping_df( 71 | df: pd.DataFrame, 72 | model: Model | None = None, 73 | ) -> None: 74 | """Run sanity checks on PEtab mapping table 75 | 76 | Arguments: 77 | df: PEtab mapping DataFrame 78 | model: Model for additional checking of parameter IDs 79 | 80 | Raises: 81 | AssertionError: in case of problems 82 | """ 83 | lint._check_df(df, MAPPING_DF_REQUIRED_COLS[1:], "mapping") 84 | 85 | if df.index.name != PETAB_ENTITY_ID: 86 | raise AssertionError( 87 | f"Mapping table has wrong index {df.index.name}. " 88 | f"Expected {PETAB_ENTITY_ID}." 89 | ) 90 | 91 | lint.check_ids(df.index.values, kind=PETAB_ENTITY_ID) 92 | 93 | if model: 94 | for model_entity_id in df[MODEL_ENTITY_ID]: 95 | if not model.has_entity_with_id(model_entity_id): 96 | raise AssertionError( 97 | "Mapping table maps to unknown " 98 | f"model entity ID {model_entity_id}." 99 | ) 100 | 101 | 102 | def resolve_mapping(mapping_df: pd.DataFrame | None, element: str) -> str: 103 | """Resolve mapping for a given element. 104 | 105 | :param element: 106 | Element to resolve. 107 | 108 | :param mapping_df: 109 | Mapping table. 110 | 111 | :return: 112 | Resolved element. 113 | """ 114 | if mapping_df is None: 115 | return element 116 | if element in mapping_df.index: 117 | return mapping_df.loc[element, MODEL_ENTITY_ID] 118 | return element 119 | -------------------------------------------------------------------------------- /petab/v1/math/PetabMathExprLexer.g4: -------------------------------------------------------------------------------- 1 | // Lexer grammar for PEtab math expressions 2 | // run `regenerate.sh` to regenerate the lexer 3 | lexer grammar PetabMathExprLexer; 4 | 5 | 6 | NUMBER : EXPONENT_FLOAT | INTEGER | POINT_FLOAT | INF; 7 | INTEGER : DIGITS ; 8 | EXPONENT_FLOAT : (INTEGER | POINT_FLOAT) EXPONENT ; 9 | POINT_FLOAT : DIGITS '.' DIGITS ; 10 | fragment EXPONENT: ('e' | 'E') ('+' | '-')? DIGITS ; 11 | FLOAT_NUMBER: POINT_FLOAT | EXPONENT_FLOAT; 12 | fragment DIGITS : [0-9]+ ; 13 | 14 | WS : [ \t\r\n]+ -> skip ; 15 | TRUE : 'true' ; 16 | FALSE : 'false' ; 17 | INF : 'inf' ; 18 | NAME : [a-zA-Z_][a-zA-Z0-9_]* ; 19 | OPEN_PAREN : '(' ; 20 | CLOSE_PAREN : ')' ; 21 | BOOLEAN_OR : '||' ; 22 | BOOLEAN_AND : '&&' ; 23 | GT : '>' ; 24 | LT : '<' ; 25 | GTE : '>=' ; 26 | LTE : '<=' ; 27 | EQ : '==' ; 28 | NEQ : '!=' ; 29 | PLUS : '+' ; 30 | MINUS : '-' ; 31 | ASTERISK : '*' ; 32 | SLASH : '/' ; 33 | CARET: '^'; 34 | EXCLAMATION_MARK: '!'; 35 | COMMA: ','; 36 | -------------------------------------------------------------------------------- /petab/v1/math/PetabMathExprParser.g4: -------------------------------------------------------------------------------- 1 | // Parser grammar for PEtab math expressions 2 | // run `regenerate.sh` to regenerate the parser 3 | parser grammar PetabMathExprParser; 4 | 5 | options { tokenVocab=PetabMathExprLexer; } 6 | 7 | petabExpression: 8 | expr EOF ; 9 | 10 | expr: 11 | expr '^' expr # PowerExpr 12 | | ('+'|'-') expr # UnaryExpr 13 | | '!' expr # BooleanNotExpr 14 | | expr ('*'|'/') expr # MultExpr 15 | | expr ('+'|'-') expr # AddExpr 16 | | '(' expr ')' # ParenExpr 17 | | expr comp_op expr # ComparisonExpr 18 | | expr (BOOLEAN_AND | BOOLEAN_OR) expr # BooleanAndOrExpr 19 | | number # Number_ 20 | | booleanLiteral # BooleanLiteral_ 21 | | functionCall # functionCall_ 22 | | var # VarExpr_ 23 | ; 24 | 25 | comp_op: 26 | GT 27 | | LT 28 | | GTE 29 | | LTE 30 | | EQ 31 | | NEQ 32 | ; 33 | 34 | argumentList: expr (',' expr)* ; 35 | functionCall: NAME OPEN_PAREN argumentList CLOSE_PAREN ; 36 | 37 | booleanLiteral: 38 | TRUE 39 | | FALSE 40 | ; 41 | number: NUMBER ; 42 | var: NAME ; 43 | -------------------------------------------------------------------------------- /petab/v1/math/__init__.py: -------------------------------------------------------------------------------- 1 | """Functions for parsing and evaluating mathematical expressions.""" 2 | from .sympify import sympify_petab # noqa: F401 3 | -------------------------------------------------------------------------------- /petab/v1/math/_generated/PetabMathExprLexer.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | null 4 | null 5 | null 6 | null 7 | null 8 | null 9 | 'true' 10 | 'false' 11 | 'inf' 12 | null 13 | '(' 14 | ')' 15 | '||' 16 | '&&' 17 | '>' 18 | '<' 19 | '>=' 20 | '<=' 21 | '==' 22 | '!=' 23 | '+' 24 | '-' 25 | '*' 26 | '/' 27 | '^' 28 | '!' 29 | ',' 30 | 31 | token symbolic names: 32 | null 33 | NUMBER 34 | INTEGER 35 | EXPONENT_FLOAT 36 | POINT_FLOAT 37 | FLOAT_NUMBER 38 | WS 39 | TRUE 40 | FALSE 41 | INF 42 | NAME 43 | OPEN_PAREN 44 | CLOSE_PAREN 45 | BOOLEAN_OR 46 | BOOLEAN_AND 47 | GT 48 | LT 49 | GTE 50 | LTE 51 | EQ 52 | NEQ 53 | PLUS 54 | MINUS 55 | ASTERISK 56 | SLASH 57 | CARET 58 | EXCLAMATION_MARK 59 | COMMA 60 | 61 | rule names: 62 | NUMBER 63 | INTEGER 64 | EXPONENT_FLOAT 65 | POINT_FLOAT 66 | EXPONENT 67 | FLOAT_NUMBER 68 | DIGITS 69 | WS 70 | TRUE 71 | FALSE 72 | INF 73 | NAME 74 | OPEN_PAREN 75 | CLOSE_PAREN 76 | BOOLEAN_OR 77 | BOOLEAN_AND 78 | GT 79 | LT 80 | GTE 81 | LTE 82 | EQ 83 | NEQ 84 | PLUS 85 | MINUS 86 | ASTERISK 87 | SLASH 88 | CARET 89 | EXCLAMATION_MARK 90 | COMMA 91 | 92 | channel names: 93 | DEFAULT_TOKEN_CHANNEL 94 | HIDDEN 95 | 96 | mode names: 97 | DEFAULT_MODE 98 | 99 | atn: 100 | [4, 0, 27, 161, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 64, 8, 0, 1, 1, 1, 1, 1, 2, 1, 2, 3, 2, 70, 8, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 80, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 3, 5, 86, 8, 5, 1, 6, 4, 6, 89, 8, 6, 11, 6, 12, 6, 90, 1, 7, 4, 7, 94, 8, 7, 11, 7, 12, 7, 95, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 5, 11, 117, 8, 11, 10, 11, 12, 11, 120, 9, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 0, 0, 29, 1, 1, 3, 2, 5, 3, 7, 4, 9, 0, 11, 5, 13, 0, 15, 6, 17, 7, 19, 8, 21, 9, 23, 10, 25, 11, 27, 12, 29, 13, 31, 14, 33, 15, 35, 16, 37, 17, 39, 18, 41, 19, 43, 20, 45, 21, 47, 22, 49, 23, 51, 24, 53, 25, 55, 26, 57, 27, 1, 0, 6, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 1, 0, 48, 57, 3, 0, 9, 10, 13, 13, 32, 32, 3, 0, 65, 90, 95, 95, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 167, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 1, 63, 1, 0, 0, 0, 3, 65, 1, 0, 0, 0, 5, 69, 1, 0, 0, 0, 7, 73, 1, 0, 0, 0, 9, 77, 1, 0, 0, 0, 11, 85, 1, 0, 0, 0, 13, 88, 1, 0, 0, 0, 15, 93, 1, 0, 0, 0, 17, 99, 1, 0, 0, 0, 19, 104, 1, 0, 0, 0, 21, 110, 1, 0, 0, 0, 23, 114, 1, 0, 0, 0, 25, 121, 1, 0, 0, 0, 27, 123, 1, 0, 0, 0, 29, 125, 1, 0, 0, 0, 31, 128, 1, 0, 0, 0, 33, 131, 1, 0, 0, 0, 35, 133, 1, 0, 0, 0, 37, 135, 1, 0, 0, 0, 39, 138, 1, 0, 0, 0, 41, 141, 1, 0, 0, 0, 43, 144, 1, 0, 0, 0, 45, 147, 1, 0, 0, 0, 47, 149, 1, 0, 0, 0, 49, 151, 1, 0, 0, 0, 51, 153, 1, 0, 0, 0, 53, 155, 1, 0, 0, 0, 55, 157, 1, 0, 0, 0, 57, 159, 1, 0, 0, 0, 59, 64, 3, 5, 2, 0, 60, 64, 3, 3, 1, 0, 61, 64, 3, 7, 3, 0, 62, 64, 3, 21, 10, 0, 63, 59, 1, 0, 0, 0, 63, 60, 1, 0, 0, 0, 63, 61, 1, 0, 0, 0, 63, 62, 1, 0, 0, 0, 64, 2, 1, 0, 0, 0, 65, 66, 3, 13, 6, 0, 66, 4, 1, 0, 0, 0, 67, 70, 3, 3, 1, 0, 68, 70, 3, 7, 3, 0, 69, 67, 1, 0, 0, 0, 69, 68, 1, 0, 0, 0, 70, 71, 1, 0, 0, 0, 71, 72, 3, 9, 4, 0, 72, 6, 1, 0, 0, 0, 73, 74, 3, 13, 6, 0, 74, 75, 5, 46, 0, 0, 75, 76, 3, 13, 6, 0, 76, 8, 1, 0, 0, 0, 77, 79, 7, 0, 0, 0, 78, 80, 7, 1, 0, 0, 79, 78, 1, 0, 0, 0, 79, 80, 1, 0, 0, 0, 80, 81, 1, 0, 0, 0, 81, 82, 3, 13, 6, 0, 82, 10, 1, 0, 0, 0, 83, 86, 3, 7, 3, 0, 84, 86, 3, 5, 2, 0, 85, 83, 1, 0, 0, 0, 85, 84, 1, 0, 0, 0, 86, 12, 1, 0, 0, 0, 87, 89, 7, 2, 0, 0, 88, 87, 1, 0, 0, 0, 89, 90, 1, 0, 0, 0, 90, 88, 1, 0, 0, 0, 90, 91, 1, 0, 0, 0, 91, 14, 1, 0, 0, 0, 92, 94, 7, 3, 0, 0, 93, 92, 1, 0, 0, 0, 94, 95, 1, 0, 0, 0, 95, 93, 1, 0, 0, 0, 95, 96, 1, 0, 0, 0, 96, 97, 1, 0, 0, 0, 97, 98, 6, 7, 0, 0, 98, 16, 1, 0, 0, 0, 99, 100, 5, 116, 0, 0, 100, 101, 5, 114, 0, 0, 101, 102, 5, 117, 0, 0, 102, 103, 5, 101, 0, 0, 103, 18, 1, 0, 0, 0, 104, 105, 5, 102, 0, 0, 105, 106, 5, 97, 0, 0, 106, 107, 5, 108, 0, 0, 107, 108, 5, 115, 0, 0, 108, 109, 5, 101, 0, 0, 109, 20, 1, 0, 0, 0, 110, 111, 5, 105, 0, 0, 111, 112, 5, 110, 0, 0, 112, 113, 5, 102, 0, 0, 113, 22, 1, 0, 0, 0, 114, 118, 7, 4, 0, 0, 115, 117, 7, 5, 0, 0, 116, 115, 1, 0, 0, 0, 117, 120, 1, 0, 0, 0, 118, 116, 1, 0, 0, 0, 118, 119, 1, 0, 0, 0, 119, 24, 1, 0, 0, 0, 120, 118, 1, 0, 0, 0, 121, 122, 5, 40, 0, 0, 122, 26, 1, 0, 0, 0, 123, 124, 5, 41, 0, 0, 124, 28, 1, 0, 0, 0, 125, 126, 5, 124, 0, 0, 126, 127, 5, 124, 0, 0, 127, 30, 1, 0, 0, 0, 128, 129, 5, 38, 0, 0, 129, 130, 5, 38, 0, 0, 130, 32, 1, 0, 0, 0, 131, 132, 5, 62, 0, 0, 132, 34, 1, 0, 0, 0, 133, 134, 5, 60, 0, 0, 134, 36, 1, 0, 0, 0, 135, 136, 5, 62, 0, 0, 136, 137, 5, 61, 0, 0, 137, 38, 1, 0, 0, 0, 138, 139, 5, 60, 0, 0, 139, 140, 5, 61, 0, 0, 140, 40, 1, 0, 0, 0, 141, 142, 5, 61, 0, 0, 142, 143, 5, 61, 0, 0, 143, 42, 1, 0, 0, 0, 144, 145, 5, 33, 0, 0, 145, 146, 5, 61, 0, 0, 146, 44, 1, 0, 0, 0, 147, 148, 5, 43, 0, 0, 148, 46, 1, 0, 0, 0, 149, 150, 5, 45, 0, 0, 150, 48, 1, 0, 0, 0, 151, 152, 5, 42, 0, 0, 152, 50, 1, 0, 0, 0, 153, 154, 5, 47, 0, 0, 154, 52, 1, 0, 0, 0, 155, 156, 5, 94, 0, 0, 156, 54, 1, 0, 0, 0, 157, 158, 5, 33, 0, 0, 158, 56, 1, 0, 0, 0, 159, 160, 5, 44, 0, 0, 160, 58, 1, 0, 0, 0, 8, 0, 63, 69, 79, 85, 90, 95, 118, 1, 6, 0, 0] 101 | -------------------------------------------------------------------------------- /petab/v1/math/_generated/PetabMathExprLexer.tokens: -------------------------------------------------------------------------------- 1 | NUMBER=1 2 | INTEGER=2 3 | EXPONENT_FLOAT=3 4 | POINT_FLOAT=4 5 | FLOAT_NUMBER=5 6 | WS=6 7 | TRUE=7 8 | FALSE=8 9 | INF=9 10 | NAME=10 11 | OPEN_PAREN=11 12 | CLOSE_PAREN=12 13 | BOOLEAN_OR=13 14 | BOOLEAN_AND=14 15 | GT=15 16 | LT=16 17 | GTE=17 18 | LTE=18 19 | EQ=19 20 | NEQ=20 21 | PLUS=21 22 | MINUS=22 23 | ASTERISK=23 24 | SLASH=24 25 | CARET=25 26 | EXCLAMATION_MARK=26 27 | COMMA=27 28 | 'true'=7 29 | 'false'=8 30 | 'inf'=9 31 | '('=11 32 | ')'=12 33 | '||'=13 34 | '&&'=14 35 | '>'=15 36 | '<'=16 37 | '>='=17 38 | '<='=18 39 | '=='=19 40 | '!='=20 41 | '+'=21 42 | '-'=22 43 | '*'=23 44 | '/'=24 45 | '^'=25 46 | '!'=26 47 | ','=27 48 | -------------------------------------------------------------------------------- /petab/v1/math/_generated/PetabMathExprParser.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | null 4 | null 5 | null 6 | null 7 | null 8 | null 9 | 'true' 10 | 'false' 11 | 'inf' 12 | null 13 | '(' 14 | ')' 15 | '||' 16 | '&&' 17 | '>' 18 | '<' 19 | '>=' 20 | '<=' 21 | '==' 22 | '!=' 23 | '+' 24 | '-' 25 | '*' 26 | '/' 27 | '^' 28 | '!' 29 | ',' 30 | 31 | token symbolic names: 32 | null 33 | NUMBER 34 | INTEGER 35 | EXPONENT_FLOAT 36 | POINT_FLOAT 37 | FLOAT_NUMBER 38 | WS 39 | TRUE 40 | FALSE 41 | INF 42 | NAME 43 | OPEN_PAREN 44 | CLOSE_PAREN 45 | BOOLEAN_OR 46 | BOOLEAN_AND 47 | GT 48 | LT 49 | GTE 50 | LTE 51 | EQ 52 | NEQ 53 | PLUS 54 | MINUS 55 | ASTERISK 56 | SLASH 57 | CARET 58 | EXCLAMATION_MARK 59 | COMMA 60 | 61 | rule names: 62 | petabExpression 63 | expr 64 | comp_op 65 | argumentList 66 | functionCall 67 | booleanLiteral 68 | number 69 | var 70 | 71 | 72 | atn: 73 | [4, 1, 27, 77, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 33, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 51, 8, 1, 10, 1, 12, 1, 54, 9, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 5, 3, 61, 8, 3, 10, 3, 12, 3, 64, 9, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 0, 1, 2, 8, 0, 2, 4, 6, 8, 10, 12, 14, 0, 5, 1, 0, 21, 22, 1, 0, 23, 24, 1, 0, 13, 14, 1, 0, 15, 20, 1, 0, 7, 8, 80, 0, 16, 1, 0, 0, 0, 2, 32, 1, 0, 0, 0, 4, 55, 1, 0, 0, 0, 6, 57, 1, 0, 0, 0, 8, 65, 1, 0, 0, 0, 10, 70, 1, 0, 0, 0, 12, 72, 1, 0, 0, 0, 14, 74, 1, 0, 0, 0, 16, 17, 3, 2, 1, 0, 17, 18, 5, 0, 0, 1, 18, 1, 1, 0, 0, 0, 19, 20, 6, 1, -1, 0, 20, 21, 7, 0, 0, 0, 21, 33, 3, 2, 1, 11, 22, 23, 5, 26, 0, 0, 23, 33, 3, 2, 1, 10, 24, 25, 5, 11, 0, 0, 25, 26, 3, 2, 1, 0, 26, 27, 5, 12, 0, 0, 27, 33, 1, 0, 0, 0, 28, 33, 3, 12, 6, 0, 29, 33, 3, 10, 5, 0, 30, 33, 3, 8, 4, 0, 31, 33, 3, 14, 7, 0, 32, 19, 1, 0, 0, 0, 32, 22, 1, 0, 0, 0, 32, 24, 1, 0, 0, 0, 32, 28, 1, 0, 0, 0, 32, 29, 1, 0, 0, 0, 32, 30, 1, 0, 0, 0, 32, 31, 1, 0, 0, 0, 33, 52, 1, 0, 0, 0, 34, 35, 10, 12, 0, 0, 35, 36, 5, 25, 0, 0, 36, 51, 3, 2, 1, 12, 37, 38, 10, 9, 0, 0, 38, 39, 7, 1, 0, 0, 39, 51, 3, 2, 1, 10, 40, 41, 10, 8, 0, 0, 41, 42, 7, 0, 0, 0, 42, 51, 3, 2, 1, 9, 43, 44, 10, 6, 0, 0, 44, 45, 3, 4, 2, 0, 45, 46, 3, 2, 1, 7, 46, 51, 1, 0, 0, 0, 47, 48, 10, 5, 0, 0, 48, 49, 7, 2, 0, 0, 49, 51, 3, 2, 1, 6, 50, 34, 1, 0, 0, 0, 50, 37, 1, 0, 0, 0, 50, 40, 1, 0, 0, 0, 50, 43, 1, 0, 0, 0, 50, 47, 1, 0, 0, 0, 51, 54, 1, 0, 0, 0, 52, 50, 1, 0, 0, 0, 52, 53, 1, 0, 0, 0, 53, 3, 1, 0, 0, 0, 54, 52, 1, 0, 0, 0, 55, 56, 7, 3, 0, 0, 56, 5, 1, 0, 0, 0, 57, 62, 3, 2, 1, 0, 58, 59, 5, 27, 0, 0, 59, 61, 3, 2, 1, 0, 60, 58, 1, 0, 0, 0, 61, 64, 1, 0, 0, 0, 62, 60, 1, 0, 0, 0, 62, 63, 1, 0, 0, 0, 63, 7, 1, 0, 0, 0, 64, 62, 1, 0, 0, 0, 65, 66, 5, 10, 0, 0, 66, 67, 5, 11, 0, 0, 67, 68, 3, 6, 3, 0, 68, 69, 5, 12, 0, 0, 69, 9, 1, 0, 0, 0, 70, 71, 7, 4, 0, 0, 71, 11, 1, 0, 0, 0, 72, 73, 5, 1, 0, 0, 73, 13, 1, 0, 0, 0, 74, 75, 5, 10, 0, 0, 75, 15, 1, 0, 0, 0, 4, 32, 50, 52, 62] 74 | -------------------------------------------------------------------------------- /petab/v1/math/_generated/PetabMathExprParser.tokens: -------------------------------------------------------------------------------- 1 | NUMBER=1 2 | INTEGER=2 3 | EXPONENT_FLOAT=3 4 | POINT_FLOAT=4 5 | FLOAT_NUMBER=5 6 | WS=6 7 | TRUE=7 8 | FALSE=8 9 | INF=9 10 | NAME=10 11 | OPEN_PAREN=11 12 | CLOSE_PAREN=12 13 | BOOLEAN_OR=13 14 | BOOLEAN_AND=14 15 | GT=15 16 | LT=16 17 | GTE=17 18 | LTE=18 19 | EQ=19 20 | NEQ=20 21 | PLUS=21 22 | MINUS=22 23 | ASTERISK=23 24 | SLASH=24 25 | CARET=25 26 | EXCLAMATION_MARK=26 27 | COMMA=27 28 | 'true'=7 29 | 'false'=8 30 | 'inf'=9 31 | '('=11 32 | ')'=12 33 | '||'=13 34 | '&&'=14 35 | '>'=15 36 | '<'=16 37 | '>='=17 38 | '<='=18 39 | '=='=19 40 | '!='=20 41 | '+'=21 42 | '-'=22 43 | '*'=23 44 | '/'=24 45 | '^'=25 46 | '!'=26 47 | ','=27 48 | -------------------------------------------------------------------------------- /petab/v1/math/_generated/PetabMathExprParserVisitor.py: -------------------------------------------------------------------------------- 1 | # Generated from PetabMathExprParser.g4 by ANTLR 4.13.1 2 | from antlr4 import * 3 | 4 | if "." in __name__: 5 | from .PetabMathExprParser import PetabMathExprParser 6 | else: 7 | from PetabMathExprParser import PetabMathExprParser 8 | 9 | # This class defines a complete generic visitor for a parse tree produced by PetabMathExprParser. 10 | 11 | 12 | class PetabMathExprParserVisitor(ParseTreeVisitor): 13 | # Visit a parse tree produced by PetabMathExprParser#petabExpression. 14 | def visitPetabExpression( 15 | self, ctx: PetabMathExprParser.PetabExpressionContext 16 | ): 17 | return self.visitChildren(ctx) 18 | 19 | # Visit a parse tree produced by PetabMathExprParser#PowerExpr. 20 | def visitPowerExpr(self, ctx: PetabMathExprParser.PowerExprContext): 21 | return self.visitChildren(ctx) 22 | 23 | # Visit a parse tree produced by PetabMathExprParser#BooleanAndOrExpr. 24 | def visitBooleanAndOrExpr( 25 | self, ctx: PetabMathExprParser.BooleanAndOrExprContext 26 | ): 27 | return self.visitChildren(ctx) 28 | 29 | # Visit a parse tree produced by PetabMathExprParser#ComparisonExpr. 30 | def visitComparisonExpr( 31 | self, ctx: PetabMathExprParser.ComparisonExprContext 32 | ): 33 | return self.visitChildren(ctx) 34 | 35 | # Visit a parse tree produced by PetabMathExprParser#MultExpr. 36 | def visitMultExpr(self, ctx: PetabMathExprParser.MultExprContext): 37 | return self.visitChildren(ctx) 38 | 39 | # Visit a parse tree produced by PetabMathExprParser#BooleanLiteral_. 40 | def visitBooleanLiteral_( 41 | self, ctx: PetabMathExprParser.BooleanLiteral_Context 42 | ): 43 | return self.visitChildren(ctx) 44 | 45 | # Visit a parse tree produced by PetabMathExprParser#AddExpr. 46 | def visitAddExpr(self, ctx: PetabMathExprParser.AddExprContext): 47 | return self.visitChildren(ctx) 48 | 49 | # Visit a parse tree produced by PetabMathExprParser#BooleanNotExpr. 50 | def visitBooleanNotExpr( 51 | self, ctx: PetabMathExprParser.BooleanNotExprContext 52 | ): 53 | return self.visitChildren(ctx) 54 | 55 | # Visit a parse tree produced by PetabMathExprParser#ParenExpr. 56 | def visitParenExpr(self, ctx: PetabMathExprParser.ParenExprContext): 57 | return self.visitChildren(ctx) 58 | 59 | # Visit a parse tree produced by PetabMathExprParser#functionCall_. 60 | def visitFunctionCall_( 61 | self, ctx: PetabMathExprParser.FunctionCall_Context 62 | ): 63 | return self.visitChildren(ctx) 64 | 65 | # Visit a parse tree produced by PetabMathExprParser#UnaryExpr. 66 | def visitUnaryExpr(self, ctx: PetabMathExprParser.UnaryExprContext): 67 | return self.visitChildren(ctx) 68 | 69 | # Visit a parse tree produced by PetabMathExprParser#Number_. 70 | def visitNumber_(self, ctx: PetabMathExprParser.Number_Context): 71 | return self.visitChildren(ctx) 72 | 73 | # Visit a parse tree produced by PetabMathExprParser#VarExpr_. 74 | def visitVarExpr_(self, ctx: PetabMathExprParser.VarExpr_Context): 75 | return self.visitChildren(ctx) 76 | 77 | # Visit a parse tree produced by PetabMathExprParser#comp_op. 78 | def visitComp_op(self, ctx: PetabMathExprParser.Comp_opContext): 79 | return self.visitChildren(ctx) 80 | 81 | # Visit a parse tree produced by PetabMathExprParser#argumentList. 82 | def visitArgumentList(self, ctx: PetabMathExprParser.ArgumentListContext): 83 | return self.visitChildren(ctx) 84 | 85 | # Visit a parse tree produced by PetabMathExprParser#functionCall. 86 | def visitFunctionCall(self, ctx: PetabMathExprParser.FunctionCallContext): 87 | return self.visitChildren(ctx) 88 | 89 | # Visit a parse tree produced by PetabMathExprParser#booleanLiteral. 90 | def visitBooleanLiteral( 91 | self, ctx: PetabMathExprParser.BooleanLiteralContext 92 | ): 93 | return self.visitChildren(ctx) 94 | 95 | # Visit a parse tree produced by PetabMathExprParser#number. 96 | def visitNumber(self, ctx: PetabMathExprParser.NumberContext): 97 | return self.visitChildren(ctx) 98 | 99 | # Visit a parse tree produced by PetabMathExprParser#var. 100 | def visitVar(self, ctx: PetabMathExprParser.VarContext): 101 | return self.visitChildren(ctx) 102 | 103 | 104 | del PetabMathExprParser 105 | -------------------------------------------------------------------------------- /petab/v1/math/_generated/__init__.py: -------------------------------------------------------------------------------- 1 | # auto-generated 2 | -------------------------------------------------------------------------------- /petab/v1/math/regenerate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # This script regenerates the ANTLR parser and lexer for PEtab math expressions 3 | set -eou > /dev/null 4 | 5 | # ANTLR version 6 | # IMPORTANT: when updating this, also update the version for 7 | # `antlr4-python3-runtime` in `pyproject.toml` 8 | antlr_version="4.13.1" 9 | 10 | pip show antlr4-tools > /dev/null || pip3 install antlr4-tools 11 | 12 | cd "$(dirname "$0")" 13 | 14 | antlr4 -v $antlr_version \ 15 | -Dlanguage=Python3 \ 16 | -visitor \ 17 | -no-listener \ 18 | -o _generated \ 19 | PetabMathExprParser.g4 \ 20 | PetabMathExprLexer.g4 21 | 22 | echo "# auto-generated" > _generated/__init__.py 23 | -------------------------------------------------------------------------------- /petab/v1/math/sympify.py: -------------------------------------------------------------------------------- 1 | """PEtab math to sympy conversion.""" 2 | 3 | import numpy as np 4 | import sympy as sp 5 | from antlr4 import CommonTokenStream, InputStream 6 | from antlr4.error.ErrorListener import ErrorListener 7 | 8 | from ._generated.PetabMathExprLexer import PetabMathExprLexer 9 | from ._generated.PetabMathExprParser import PetabMathExprParser 10 | from .SympyVisitor import MathVisitorSympy, bool2num 11 | 12 | __all__ = ["sympify_petab"] 13 | 14 | 15 | def sympify_petab(expr: str | int | float) -> sp.Expr | sp.Basic: 16 | """Convert PEtab math expression to sympy expression. 17 | 18 | Args: 19 | expr: PEtab math expression. 20 | 21 | Raises: 22 | ValueError: Upon lexer/parser errors or if the expression is 23 | otherwise invalid. 24 | 25 | Returns: 26 | The sympy expression corresponding to `expr`. 27 | Boolean values are converted to numeric values. 28 | """ 29 | if isinstance(expr, int) or isinstance(expr, np.integer): 30 | return sp.Integer(expr) 31 | if isinstance(expr, float) or isinstance(expr, np.floating): 32 | return sp.Float(expr) 33 | 34 | # Set error listeners 35 | input_stream = InputStream(expr) 36 | lexer = PetabMathExprLexer(input_stream) 37 | lexer.removeErrorListeners() 38 | lexer.addErrorListener(MathErrorListener()) 39 | 40 | stream = CommonTokenStream(lexer) 41 | parser = PetabMathExprParser(stream) 42 | parser.removeErrorListeners() 43 | parser.addErrorListener(MathErrorListener()) 44 | 45 | # Parse expression 46 | try: 47 | tree = parser.petabExpression() 48 | except ValueError as e: 49 | raise ValueError(f"Error parsing {expr!r}: {e.args[0]}") from None 50 | 51 | # Convert to sympy expression 52 | visitor = MathVisitorSympy() 53 | expr = visitor.visit(tree) 54 | expr = bool2num(expr) 55 | # check for `False`, we'll accept both `True` and `None` 56 | if expr.is_extended_real is False: 57 | raise ValueError(f"Expression {expr} is not real-valued.") 58 | 59 | return expr 60 | 61 | 62 | class MathErrorListener(ErrorListener): 63 | """Error listener for math expression parser/lexer.""" 64 | 65 | def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): # noqa N803 66 | raise ValueError(f"Syntax error at {line}:{column}: {msg}") 67 | -------------------------------------------------------------------------------- /petab/v1/models/__init__.py: -------------------------------------------------------------------------------- 1 | """Handling of different model types supported by PEtab.""" 2 | #: SBML model type as used in a PEtab v2 yaml file as `language`. 3 | MODEL_TYPE_SBML = "sbml" 4 | #: PySB model type as used in a PEtab v2 yaml file as `language`. 5 | MODEL_TYPE_PYSB = "pysb" 6 | 7 | known_model_types = { 8 | MODEL_TYPE_SBML, 9 | MODEL_TYPE_PYSB, 10 | } 11 | 12 | from .model import Model # noqa F401 13 | 14 | __all__ = ["MODEL_TYPE_SBML", "MODEL_TYPE_PYSB", "known_model_types", "Model"] 15 | -------------------------------------------------------------------------------- /petab/v1/models/model.py: -------------------------------------------------------------------------------- 1 | """PEtab model abstraction""" 2 | from __future__ import annotations 3 | 4 | import abc 5 | from collections.abc import Iterable 6 | from pathlib import Path 7 | from typing import Any 8 | 9 | __all__ = ["Model", "model_factory"] 10 | 11 | 12 | class Model(abc.ABC): 13 | """Base class for wrappers for any PEtab-supported model type""" 14 | 15 | @abc.abstractmethod 16 | def __init__(self): 17 | ... 18 | 19 | def __repr__(self): 20 | return f"<{self.__class__.__name__} {self.model_id!r}>" 21 | 22 | @staticmethod 23 | @abc.abstractmethod 24 | def from_file(filepath_or_buffer: Any, model_id: str) -> Model: 25 | """Load the model from the given path/URL 26 | 27 | :param filepath_or_buffer: URL or path of the model 28 | :param model_id: Model ID 29 | :returns: A ``Model`` instance holding the given model 30 | """ 31 | ... 32 | 33 | @abc.abstractmethod 34 | def to_file(self, filename: [str, Path]): 35 | """Save the model to the given file 36 | 37 | :param filename: Destination filename 38 | """ 39 | ... 40 | 41 | @classmethod 42 | @property 43 | @abc.abstractmethod 44 | def type_id(cls): 45 | ... 46 | 47 | @property 48 | @abc.abstractmethod 49 | def model_id(self): 50 | ... 51 | 52 | @abc.abstractmethod 53 | def get_parameter_value(self, id_: str) -> float: 54 | """Get a parameter value 55 | 56 | :param id_: ID of the parameter whose value is to be returned 57 | :raises ValueError: If no parameter with the given ID exists 58 | :returns: The value of the given parameter as specified in the model 59 | """ 60 | ... 61 | 62 | @abc.abstractmethod 63 | def get_free_parameter_ids_with_values( 64 | self, 65 | ) -> Iterable[tuple[str, float]]: 66 | """Get free model parameters along with their values 67 | 68 | Returns: 69 | Iterator over tuples of (parameter_id, parameter_value) 70 | """ 71 | ... 72 | 73 | @abc.abstractmethod 74 | def get_parameter_ids(self) -> Iterable[str]: 75 | """Get all parameter IDs from this model 76 | 77 | :returns: Iterator over model parameter IDs 78 | """ 79 | ... 80 | 81 | @abc.abstractmethod 82 | def has_entity_with_id(self, entity_id) -> bool: 83 | """Check if there is a model entity with the given ID 84 | 85 | :param entity_id: ID to check for 86 | :returns: 87 | ``True``, if there is an entity with the given ID, 88 | ``False`` otherwise 89 | """ 90 | ... 91 | 92 | @abc.abstractmethod 93 | def get_valid_parameters_for_parameter_table(self) -> Iterable[str]: 94 | """Get IDs of all parameters that are allowed to occur in the PEtab 95 | parameters table 96 | 97 | :returns: Iterator over parameter IDs 98 | """ 99 | ... 100 | 101 | @abc.abstractmethod 102 | def get_valid_ids_for_condition_table(self) -> Iterable[str]: 103 | """Get IDs of all model entities that are allowed to occur as columns 104 | in the PEtab conditions table. 105 | 106 | :returns: Iterator over model entity IDs 107 | """ 108 | ... 109 | 110 | @abc.abstractmethod 111 | def symbol_allowed_in_observable_formula(self, id_: str) -> bool: 112 | """Check if the given ID is allowed to be used in observable and noise 113 | formulas 114 | 115 | :returns: ``True``, if allowed, ``False`` otherwise 116 | """ 117 | ... 118 | 119 | @abc.abstractmethod 120 | def is_valid(self) -> bool: 121 | """Validate this model 122 | 123 | :returns: 124 | `True` if the model is valid, `False` if there are errors in 125 | this model 126 | """ 127 | ... 128 | 129 | @abc.abstractmethod 130 | def is_state_variable(self, id_: str) -> bool: 131 | """Check whether the given ID corresponds to a model state variable""" 132 | ... 133 | 134 | 135 | def model_factory( 136 | filepath_or_buffer: Any, model_language: str, model_id: str = None 137 | ) -> Model: 138 | """Create a PEtab model instance from the given model 139 | 140 | :param filepath_or_buffer: Path/URL of the model 141 | :param model_language: PEtab model language ID for the given model 142 | :param model_id: PEtab model ID for the given model 143 | :returns: A :py:class:`Model` instance representing the given model 144 | """ 145 | from . import MODEL_TYPE_PYSB, MODEL_TYPE_SBML, known_model_types 146 | 147 | if model_language == MODEL_TYPE_SBML: 148 | from .sbml_model import SbmlModel 149 | 150 | return SbmlModel.from_file(filepath_or_buffer, model_id=model_id) 151 | 152 | if model_language == MODEL_TYPE_PYSB: 153 | from .pysb_model import PySBModel 154 | 155 | return PySBModel.from_file(filepath_or_buffer, model_id=model_id) 156 | 157 | if model_language in known_model_types: 158 | raise NotImplementedError( 159 | f"Unsupported model format: {model_language}" 160 | ) 161 | 162 | raise ValueError(f"Unknown model format: {model_language}") 163 | -------------------------------------------------------------------------------- /petab/v1/sampling.py: -------------------------------------------------------------------------------- 1 | """Functions related to parameter sampling""" 2 | 3 | from collections.abc import Sequence 4 | 5 | import numpy as np 6 | import pandas as pd 7 | 8 | from . import parameters 9 | from .C import * # noqa: F403 10 | 11 | __all__ = ["sample_from_prior", "sample_parameter_startpoints"] 12 | 13 | 14 | def sample_from_prior( 15 | prior: tuple[str, list, str, list], n_starts: int 16 | ) -> np.array: 17 | """Creates samples for one parameter based on prior 18 | 19 | Arguments: 20 | prior: A tuple as obtained from 21 | :func:`petab.parameter.get_priors_from_df` 22 | n_starts: Number of samples 23 | 24 | Returns: 25 | Array with sampled values 26 | """ 27 | # unpack info 28 | p_type, p_params, scaling, bounds = prior 29 | 30 | # define a function to rescale the sampled points to parameter scale 31 | def scale(x): 32 | if scaling == LIN: 33 | return x 34 | if scaling == LOG: 35 | return np.log(x) 36 | if scaling == LOG10: 37 | return np.log10(x) 38 | raise NotImplementedError( 39 | f"Parameter priors on the parameter scale {scaling} are " 40 | "currently not implemented." 41 | ) 42 | 43 | def clip_to_bounds(x: np.array): 44 | """Clip values in array x to bounds""" 45 | return np.maximum(np.minimum(scale(bounds[1]), x), scale(bounds[0])) 46 | 47 | # define lambda functions for each parameter 48 | if p_type == UNIFORM: 49 | sp = scale( 50 | (p_params[1] - p_params[0]) * np.random.random((n_starts,)) 51 | + p_params[0] 52 | ) 53 | 54 | elif p_type == PARAMETER_SCALE_UNIFORM: 55 | sp = (p_params[1] - p_params[0]) * np.random.random( 56 | (n_starts,) 57 | ) + p_params[0] 58 | 59 | elif p_type == NORMAL: 60 | sp = scale( 61 | np.random.normal( 62 | loc=p_params[0], scale=p_params[1], size=(n_starts,) 63 | ) 64 | ) 65 | 66 | elif p_type == LOG_NORMAL: 67 | sp = scale( 68 | np.exp( 69 | np.random.normal( 70 | loc=p_params[0], scale=p_params[1], size=(n_starts,) 71 | ) 72 | ) 73 | ) 74 | 75 | elif p_type == PARAMETER_SCALE_NORMAL: 76 | sp = np.random.normal( 77 | loc=p_params[0], scale=p_params[1], size=(n_starts,) 78 | ) 79 | 80 | elif p_type == LAPLACE: 81 | sp = scale( 82 | np.random.laplace( 83 | loc=p_params[0], scale=p_params[1], size=(n_starts,) 84 | ) 85 | ) 86 | 87 | elif p_type == LOG_LAPLACE: 88 | sp = scale( 89 | np.exp( 90 | np.random.laplace( 91 | loc=p_params[0], scale=p_params[1], size=(n_starts,) 92 | ) 93 | ) 94 | ) 95 | 96 | elif p_type == PARAMETER_SCALE_LAPLACE: 97 | sp = np.random.laplace( 98 | loc=p_params[0], scale=p_params[1], size=(n_starts,) 99 | ) 100 | 101 | else: 102 | raise NotImplementedError( 103 | f"Parameter priors of type {prior[0]} are not implemented." 104 | ) 105 | 106 | return clip_to_bounds(sp) 107 | 108 | 109 | def sample_parameter_startpoints( 110 | parameter_df: pd.DataFrame, 111 | n_starts: int = 100, 112 | seed: int = None, 113 | parameter_ids: Sequence[str] = None, 114 | ) -> np.array: 115 | """Create :class:`numpy.array` with starting points for an optimization 116 | 117 | Arguments: 118 | parameter_df: PEtab parameter DataFrame 119 | n_starts: Number of points to be sampled 120 | seed: Random number generator seed (see :func:`numpy.random.seed`) 121 | parameter_ids: A sequence of parameter IDs for which to sample starting 122 | points. 123 | For subsetting or reordering the parameters. 124 | Defaults to all estimated parameters. 125 | 126 | Returns: 127 | Array of sampled starting points with dimensions 128 | `n_startpoints` x `n_optimization_parameters` 129 | """ 130 | if seed is not None: 131 | np.random.seed(seed) 132 | 133 | # get types and parameters of priors from dataframe 134 | prior_list = parameters.get_priors_from_df( 135 | parameter_df, mode=INITIALIZATION, parameter_ids=parameter_ids 136 | ) 137 | 138 | startpoints = [sample_from_prior(prior, n_starts) for prior in prior_list] 139 | 140 | return np.array(startpoints).T 141 | -------------------------------------------------------------------------------- /petab/v1/simplify.py: -------------------------------------------------------------------------------- 1 | """Functionality for simplifying PEtab problems""" 2 | from math import nan 3 | 4 | import pandas as pd 5 | 6 | import petab.v1 as petab 7 | 8 | from . import Problem 9 | from .C import * # noqa: F403 10 | from .lint import lint_problem 11 | 12 | __all__ = [ 13 | "remove_nan_measurements", 14 | "remove_unused_observables", 15 | "remove_unused_conditions", 16 | "simplify_problem", 17 | "condition_parameters_to_parameter_table", 18 | ] 19 | 20 | 21 | def remove_nan_measurements(problem: Problem): 22 | """Drop any measurements that are NaN""" 23 | problem.measurement_df = problem.measurement_df[ 24 | ~problem.measurement_df[MEASUREMENT].isna() 25 | ] 26 | problem.measurement_df.reset_index(inplace=True, drop=True) 27 | 28 | 29 | def remove_unused_observables(problem: Problem): 30 | """Remove observables that have no measurements""" 31 | measured_observables = set(problem.measurement_df[OBSERVABLE_ID].unique()) 32 | problem.observable_df = problem.observable_df[ 33 | problem.observable_df.index.isin(measured_observables) 34 | ] 35 | 36 | 37 | def remove_unused_conditions(problem: Problem): 38 | """Remove conditions that have no measurements""" 39 | measured_conditions = set( 40 | problem.measurement_df[SIMULATION_CONDITION_ID].unique() 41 | ) 42 | if PREEQUILIBRATION_CONDITION_ID in problem.measurement_df: 43 | measured_conditions |= set( 44 | problem.measurement_df[PREEQUILIBRATION_CONDITION_ID].unique() 45 | ) 46 | 47 | problem.condition_df = problem.condition_df[ 48 | problem.condition_df.index.isin(measured_conditions) 49 | ] 50 | 51 | 52 | def simplify_problem(problem: Problem): 53 | if lint_problem(problem): 54 | raise ValueError("Invalid PEtab problem supplied.") 55 | 56 | remove_unused_observables(problem) 57 | remove_unused_conditions(problem) 58 | condition_parameters_to_parameter_table(problem) 59 | 60 | if lint_problem(problem): 61 | raise AssertionError("Invalid PEtab problem generated.") 62 | 63 | 64 | def condition_parameters_to_parameter_table(problem: Problem): 65 | """Move parameters from the condition table to the parameters table, if 66 | the same parameter value is used for all conditions. 67 | """ 68 | if ( 69 | problem.condition_df is None 70 | or problem.condition_df.empty 71 | or problem.model is None 72 | ): 73 | return 74 | 75 | replacements = {} 76 | for parameter_id in problem.condition_df: 77 | if parameter_id == CONDITION_NAME: 78 | continue 79 | 80 | if problem.model.is_state_variable(parameter_id): 81 | # initial states can't go the parameters table 82 | continue 83 | 84 | series = problem.condition_df[parameter_id] 85 | value = petab.to_float_if_float(series.iloc[0]) 86 | 87 | # same value for all conditions and no parametric overrides (str)? 88 | if isinstance(value, float) and len(series.unique()) == 1: 89 | replacements[parameter_id] = series.iloc[0] 90 | 91 | if not replacements: 92 | return 93 | 94 | rows = [ 95 | { 96 | PARAMETER_ID: parameter_id, 97 | PARAMETER_SCALE: LIN, 98 | LOWER_BOUND: nan, 99 | UPPER_BOUND: nan, 100 | NOMINAL_VALUE: value, 101 | ESTIMATE: 0, 102 | } 103 | for parameter_id, value in replacements.items() 104 | ] 105 | rows = pd.DataFrame(rows) 106 | rows.set_index(PARAMETER_ID, inplace=True) 107 | 108 | if problem.parameter_df is None: 109 | problem.parameter_df = rows 110 | else: 111 | problem.parameter_df = pd.concat([problem.parameter_df, rows]) 112 | 113 | problem.condition_df = problem.condition_df.drop( 114 | columns=replacements.keys() 115 | ) 116 | -------------------------------------------------------------------------------- /petab/v1/visualize/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Visualize 3 | ========= 4 | 5 | PEtab comes with visualization functionality. Those need to be imported via 6 | ``import petab.visualize``. 7 | 8 | """ 9 | # ruff: noqa: F401 10 | import importlib.util 11 | 12 | from .plotting import DataProvider, Figure 13 | 14 | __all__ = ["DataProvider", "Figure"] 15 | 16 | if importlib.util.find_spec("matplotlib") is not None: 17 | from .plot_data_and_simulation import ( 18 | plot_problem, 19 | plot_with_vis_spec, 20 | plot_without_vis_spec, 21 | ) 22 | from .plot_residuals import ( 23 | plot_goodness_of_fit, 24 | plot_residuals_vs_simulation, 25 | ) 26 | from .plotter import MPLPlotter 27 | 28 | __all__.extend( 29 | [ 30 | "plot_without_vis_spec", 31 | "plot_with_vis_spec", 32 | "plot_problem", 33 | "plot_goodness_of_fit", 34 | "plot_residuals_vs_simulation", 35 | "MPLPlotter", 36 | ] 37 | ) 38 | -------------------------------------------------------------------------------- /petab/v1/visualize/cli.py: -------------------------------------------------------------------------------- 1 | """Command-line interface for visualization.""" 2 | import argparse 3 | from pathlib import Path 4 | 5 | import matplotlib.pyplot as plt 6 | 7 | from .. import Problem, get_simulation_df, get_visualization_df 8 | from .plot_data_and_simulation import plot_problem 9 | 10 | __all__ = [] 11 | 12 | 13 | def _parse_cli_args(): 14 | """Parse command-line arguments.""" 15 | parser = argparse.ArgumentParser( 16 | description="Create PEtab visualizations." 17 | ) 18 | 19 | parser.add_argument( 20 | "-y", 21 | "--yaml", 22 | dest="yaml_file_name", 23 | required=True, 24 | help="PEtab problem YAML filename", 25 | ) 26 | parser.add_argument( 27 | "-s", 28 | "--simulations", 29 | dest="simulation_file_name", 30 | required=False, 31 | help="PEtab simulation filename", 32 | ) 33 | parser.add_argument( 34 | "-o", 35 | "--output-directory", 36 | dest="output_directory", 37 | required=True, 38 | help="Output directory", 39 | ) 40 | parser.add_argument( 41 | "-v", 42 | "--visualizations", 43 | required=False, 44 | dest="visualization_file_name", 45 | help="PEtab visualization specification filename", 46 | ) 47 | parser.add_argument( 48 | "--style", 49 | required=False, 50 | dest="style_file_name", 51 | help="Matplotlib style file", 52 | ) 53 | return parser.parse_args() 54 | 55 | 56 | def _petab_visualize_main(): 57 | """Entrypoint for visualization command-line interface.""" 58 | args = _parse_cli_args() 59 | 60 | petab_problem = Problem.from_yaml(args.yaml_file_name) 61 | simulations_df = None 62 | if args.simulation_file_name: 63 | simulations_df = get_simulation_df(args.simulation_file_name) 64 | 65 | if args.visualization_file_name: 66 | petab_problem.visualization_df = get_visualization_df( 67 | args.visualization_file_name 68 | ) 69 | 70 | if args.style_file_name: 71 | plt.style.use(args.style_file_name) 72 | 73 | # Avoid errors when plotting without X server 74 | plt.switch_backend("agg") 75 | 76 | Path(args.output_directory).mkdir(exist_ok=True, parents=True) 77 | 78 | plot_problem( 79 | petab_problem=petab_problem, 80 | simulations_df=simulations_df, 81 | subplot_dir=args.output_directory, 82 | ) 83 | -------------------------------------------------------------------------------- /petab/v1/visualize/data_overview.py: -------------------------------------------------------------------------------- 1 | """ 2 | Functions for creating an overview report of a PEtab problem 3 | """ 4 | 5 | from pathlib import Path 6 | from shutil import copyfile 7 | 8 | import pandas as pd 9 | 10 | import petab.v1 as petab 11 | from petab.v1.C import ( 12 | MEASUREMENT, 13 | OBSERVABLE_ID, 14 | PREEQUILIBRATION_CONDITION_ID, 15 | SIMULATION_CONDITION_ID, 16 | ) 17 | 18 | __all__ = ["create_report"] 19 | 20 | 21 | def create_report( 22 | problem: petab.Problem, model_name: str, output_path: str | Path = "" 23 | ) -> None: 24 | """Create an HTML overview data / model overview report 25 | 26 | Arguments: 27 | problem: PEtab problem 28 | model_name: Name of the model, used for file name for report 29 | output_path: Output directory 30 | """ 31 | template_dir = Path(__file__).absolute().parent / "templates" 32 | output_path = Path(output_path) 33 | template_file = "report.html" 34 | 35 | data_per_observable = get_data_per_observable(problem.measurement_df) 36 | num_conditions = len(problem.condition_df.index) 37 | 38 | # Setup template engine 39 | import jinja2 40 | 41 | template_loader = jinja2.FileSystemLoader(searchpath=template_dir) 42 | template_env = jinja2.Environment(loader=template_loader, autoescape=True) 43 | template = template_env.get_template(template_file) 44 | 45 | # Render and save 46 | output_text = template.render( 47 | problem=problem, 48 | model_name=model_name, 49 | data_per_observable=data_per_observable, 50 | num_conditions=num_conditions, 51 | ) 52 | with open(output_path / f"{model_name}.html", "w") as html_file: 53 | html_file.write(output_text) 54 | copyfile(template_dir / "mystyle.css", output_path / "mystyle.css") 55 | 56 | 57 | def get_data_per_observable(measurement_df: pd.DataFrame) -> pd.DataFrame: 58 | """Get table with number of data points per observable and condition 59 | 60 | Arguments: 61 | measurement_df: PEtab measurement data frame 62 | Returns: 63 | Pivot table with number of data points per observable and condition 64 | """ 65 | my_measurements = measurement_df.copy() 66 | 67 | index = [SIMULATION_CONDITION_ID] 68 | if PREEQUILIBRATION_CONDITION_ID in my_measurements: 69 | my_measurements[PREEQUILIBRATION_CONDITION_ID] = ( 70 | my_measurements[PREEQUILIBRATION_CONDITION_ID] 71 | .astype("object") 72 | .fillna("", inplace=True) 73 | ) 74 | index.append(PREEQUILIBRATION_CONDITION_ID) 75 | 76 | data_per_observable = pd.pivot_table( 77 | my_measurements, 78 | values=MEASUREMENT, 79 | aggfunc="count", 80 | index=index, 81 | columns=[OBSERVABLE_ID], 82 | fill_value=0, 83 | ) 84 | 85 | # Add row and column sums 86 | data_per_observable.loc["SUM", :] = data_per_observable.sum(axis=0).values 87 | data_per_observable["SUM"] = data_per_observable.sum(axis=1).values 88 | 89 | data_per_observable = data_per_observable.astype(int) 90 | 91 | return data_per_observable 92 | -------------------------------------------------------------------------------- /petab/v1/visualize/helper_functions.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file should contain the functions, which PEtab internally needs for 3 | plotting, but which are not meant to be used by non-developers and should 4 | hence not be directly visible/usable when using `import petab.visualize`. 5 | """ 6 | 7 | 8 | import pandas as pd 9 | 10 | from ..C import * 11 | 12 | # for typehints 13 | IdsList = list[str] 14 | NumList = list[int] 15 | __all__ = [ 16 | "create_dataset_id_list_new", 17 | "generate_dataset_id_col", 18 | ] 19 | 20 | 21 | def generate_dataset_id_col(exp_data: pd.DataFrame) -> list[str]: 22 | """ 23 | Generate DATASET_ID column from condition_ids and observable_ids. 24 | 25 | Parameters 26 | ---------- 27 | exp_data: 28 | A measurement (simulation) DataFrame in the PEtab format. 29 | 30 | Returns 31 | ------- 32 | A list with generated datasetIds for each entry in the measurement 33 | (simulation) DataFrame 34 | """ 35 | # create a column of dummy datasetIDs and legend entries: preallocate 36 | dataset_id_column = [] 37 | 38 | # loop over experimental data table, create datasetId for each entry 39 | tmp_simcond = list(exp_data[SIMULATION_CONDITION_ID]) 40 | tmp_obs = list(exp_data[OBSERVABLE_ID]) 41 | 42 | for ind, cond_id in enumerate(tmp_simcond): 43 | # create and add dummy datasetID 44 | dataset_id = cond_id + "_" + tmp_obs[ind] 45 | dataset_id_column.append(dataset_id) 46 | 47 | return dataset_id_column 48 | 49 | 50 | def create_dataset_id_list_new( 51 | df: pd.DataFrame, group_by: str, id_list: list[IdsList] 52 | ) -> list[IdsList]: 53 | """ 54 | Create dataset ID list from a list of simulation condition IDs or 55 | observable IDs. 56 | 57 | Parameters: 58 | df: Measurements or simulations DataFrame. 59 | group_by: Defines grouping of data to plot. 60 | id_list: 61 | Grouping list. Each sublist corresponds to a subplot in a figure, 62 | and contains the IDs of observables or simulation conditions for 63 | the subplot. 64 | 65 | Returns: 66 | A list of datasetIds 67 | 68 | """ 69 | if DATASET_ID not in df.columns: 70 | raise ValueError(f"{DATASET_ID} column must be in exp_data DataFrame") 71 | 72 | dataset_id_list = [] 73 | 74 | if group_by == "simulation": 75 | grouping_col = SIMULATION_CONDITION_ID 76 | elif group_by == "observable": 77 | grouping_col = OBSERVABLE_ID 78 | if id_list is None: 79 | # this is the default case. If no grouping is specified, 80 | # all observables are plotted. One observable per plot. 81 | unique_obs_list = df[OBSERVABLE_ID].unique() 82 | id_list = [[obs_id] for obs_id in unique_obs_list] 83 | else: 84 | raise ValueError 85 | 86 | for sublist in id_list: 87 | plot_id_list = [] 88 | for cond_id in sublist: 89 | plot_id_list.extend( 90 | list(df[df[grouping_col] == cond_id][DATASET_ID].unique()) 91 | ) 92 | dataset_id_list.append(plot_id_list) 93 | return dataset_id_list 94 | -------------------------------------------------------------------------------- /petab/v1/visualize/lint.py: -------------------------------------------------------------------------------- 1 | """Validation of PEtab visualization files""" 2 | from __future__ import annotations 3 | 4 | import logging 5 | 6 | import pandas as pd 7 | 8 | from .. import C, Problem 9 | from ..C import VISUALIZATION_DF_REQUIRED_COLS 10 | 11 | logger = logging.getLogger(__name__) 12 | 13 | __all__ = ["validate_visualization_df"] 14 | 15 | 16 | def validate_visualization_df(problem: Problem) -> bool: 17 | """Validate visualization table 18 | 19 | Arguments: 20 | problem: The PEtab problem containing a visualization table 21 | 22 | Returns: 23 | ``True`` if errors occurred, ``False`` otherwise 24 | """ 25 | vis_df = problem.visualization_df 26 | if vis_df is None or vis_df.empty: 27 | return False 28 | 29 | errors = False 30 | 31 | if missing_req_cols := ( 32 | set(VISUALIZATION_DF_REQUIRED_COLS) - set(vis_df.columns) 33 | ): 34 | logger.error( 35 | f"Missing required columns {missing_req_cols} " 36 | "in visualization table." 37 | ) 38 | errors = True 39 | 40 | # Set all unspecified optional values to their defaults to simplify 41 | # validation 42 | vis_df = vis_df.copy() 43 | _apply_defaults(vis_df) 44 | 45 | if unknown_types := ( 46 | set(vis_df[C.PLOT_TYPE_SIMULATION].unique()) 47 | - set(C.PLOT_TYPES_SIMULATION) 48 | ): 49 | logger.error( 50 | f"Unknown {C.PLOT_TYPE_SIMULATION}: {unknown_types}. " 51 | f"Must be one of {C.PLOT_TYPES_SIMULATION}" 52 | ) 53 | errors = True 54 | 55 | if unknown_types := ( 56 | set(vis_df[C.PLOT_TYPE_DATA].unique()) - set(C.PLOT_TYPES_DATA) 57 | ): 58 | logger.error( 59 | f"Unknown {C.PLOT_TYPE_DATA}: {unknown_types}. " 60 | f"Must be one of {C.PLOT_TYPES_DATA}" 61 | ) 62 | errors = True 63 | 64 | if unknown_scale := (set(vis_df[C.X_SCALE].unique()) - set(C.X_SCALES)): 65 | logger.error( 66 | f"Unknown {C.X_SCALE}: {unknown_scale}. " 67 | f"Must be one of {C.X_SCALES}" 68 | ) 69 | errors = True 70 | 71 | if any( 72 | (vis_df[C.X_SCALE] == "order") 73 | & (vis_df[C.PLOT_TYPE_SIMULATION] != C.LINE_PLOT) 74 | ): 75 | logger.error( 76 | f"{C.X_SCALE}=order is only allowed with " 77 | f"{C.PLOT_TYPE_SIMULATION}={C.LINE_PLOT}." 78 | ) 79 | errors = True 80 | 81 | if unknown_scale := (set(vis_df[C.Y_SCALE].unique()) - set(C.Y_SCALES)): 82 | logger.error( 83 | f"Unknown {C.Y_SCALE}: {unknown_scale}. " 84 | f"Must be one of {C.Y_SCALES}" 85 | ) 86 | errors = True 87 | 88 | if problem.condition_df is not None: 89 | # check for ambiguous values 90 | reserved_names = {C.TIME, "condition"} 91 | for reserved_name in reserved_names: 92 | if ( 93 | reserved_name in problem.condition_df 94 | and reserved_name in vis_df[C.X_VALUES] 95 | ): 96 | logger.error( 97 | f"Ambiguous value for `{C.X_VALUES}`: " 98 | f"`{reserved_name}` has a special meaning as " 99 | f"`{C.X_VALUES}`, but there exists also a model " 100 | "entity with that name." 101 | ) 102 | errors = True 103 | 104 | # check xValues exist in condition table 105 | for xvalue in set(vis_df[C.X_VALUES].unique()) - reserved_names: 106 | if xvalue not in problem.condition_df: 107 | logger.error( 108 | f"{C.X_VALUES} was set to `{xvalue}`, but no " 109 | "such column exists in the conditions table." 110 | ) 111 | errors = True 112 | 113 | if problem.observable_df is not None: 114 | # yValues must be an observable 115 | for yvalue in vis_df[C.Y_VALUES].unique(): 116 | if pd.isna(yvalue): 117 | # if there is only one observable, we default to that 118 | if len(problem.observable_df.index.unique()) == 1: 119 | continue 120 | 121 | logger.error( 122 | f"{C.Y_VALUES} must be specified if there is more " 123 | "than one observable." 124 | ) 125 | errors = True 126 | 127 | if yvalue not in problem.observable_df.index: 128 | logger.error( 129 | f"{C.Y_VALUES} was set to `{yvalue}`, but no such " 130 | "observable exists in the observables table." 131 | ) 132 | errors = True 133 | 134 | if problem.measurement_df is not None: 135 | referenced_datasets = set(filter(bool, vis_df[C.DATASET_ID].unique())) 136 | if referenced_datasets: 137 | existing_datasets = set( 138 | filter(bool, problem.measurement_df[C.DATASET_ID].unique()) 139 | ) 140 | if not referenced_datasets.issubset(existing_datasets): 141 | logger.error( 142 | f"Visualization table references {C.DATASET_ID}(s) " 143 | f"{referenced_datasets - existing_datasets}, but no such " 144 | "dataset(s) exist in the measurement table." 145 | ) 146 | errors = True 147 | 148 | return errors 149 | 150 | 151 | def _apply_defaults(vis_df: pd.DataFrame): 152 | """ 153 | Set default values. 154 | 155 | Adds default values to the given visualization table where no value was 156 | specified. 157 | """ 158 | 159 | def set_default(column: str, value): 160 | if column not in vis_df: 161 | vis_df[column] = value 162 | elif value is not None: 163 | if isinstance(value, str): 164 | vis_df[column] = vis_df[column].astype("object") 165 | vis_df.fillna({column: value}, inplace=True) 166 | 167 | set_default(C.PLOT_NAME, "") 168 | set_default(C.PLOT_TYPE_SIMULATION, C.LINE_PLOT) 169 | set_default(C.PLOT_TYPE_DATA, C.MEAN_AND_SD) 170 | set_default(C.DATASET_ID, None) 171 | set_default(C.X_VALUES, C.TIME) 172 | set_default(C.X_OFFSET, 0) 173 | set_default(C.X_LABEL, vis_df[C.X_VALUES]) 174 | set_default(C.X_SCALE, C.LIN) 175 | set_default(C.Y_VALUES, None) 176 | set_default(C.Y_OFFSET, 0) 177 | set_default(C.Y_LABEL, vis_df[C.Y_VALUES]) 178 | set_default(C.Y_SCALE, C.LIN) 179 | set_default(C.LEGEND_ENTRY, vis_df[C.DATASET_ID]) 180 | -------------------------------------------------------------------------------- /petab/v1/visualize/plot_residuals.py: -------------------------------------------------------------------------------- 1 | """ 2 | Functions for plotting residuals. 3 | """ 4 | from pathlib import Path 5 | 6 | import matplotlib 7 | import matplotlib.pyplot as plt 8 | import numpy as np 9 | import pandas as pd 10 | from scipy import stats 11 | 12 | from ..C import * 13 | from ..calculate import calculate_residuals 14 | from ..core import get_simulation_df 15 | from ..problem import Problem 16 | 17 | __all__ = ["plot_goodness_of_fit", "plot_residuals_vs_simulation"] 18 | 19 | 20 | def plot_residuals_vs_simulation( 21 | petab_problem: Problem, 22 | simulations_df: str | Path | pd.DataFrame, 23 | size: tuple | None = (10, 7), 24 | axes: tuple[plt.Axes, plt.Axes] | None = None, 25 | ) -> matplotlib.axes.Axes: 26 | """ 27 | Plot residuals versus simulation values for measurements with normal noise 28 | assumption. 29 | 30 | Parameters 31 | ---------- 32 | petab_problem: 33 | A PEtab problem. 34 | simulations_df: 35 | A simulation DataFrame in the PEtab format or path to the simulation 36 | output data file. 37 | size: 38 | Figure size. 39 | axes: 40 | Axis object. 41 | 42 | Returns 43 | ------- 44 | ax: Axis object of the created plot. 45 | """ 46 | if isinstance(simulations_df, str | Path): 47 | simulations_df = get_simulation_df(simulations_df) 48 | 49 | if NOISE_DISTRIBUTION in petab_problem.observable_df: 50 | if OBSERVABLE_TRANSFORMATION in petab_problem.observable_df: 51 | observable_ids = petab_problem.observable_df[ 52 | (petab_problem.observable_df[NOISE_DISTRIBUTION] == NORMAL) 53 | & ( 54 | petab_problem.observable_df[OBSERVABLE_TRANSFORMATION] 55 | == LIN 56 | ) 57 | ].index 58 | 59 | else: 60 | observable_ids = petab_problem.observable_df[ 61 | petab_problem.observable_df[NOISE_DISTRIBUTION] == NORMAL 62 | ].index 63 | else: 64 | observable_ids = petab_problem.observable_df.index 65 | 66 | if observable_ids.empty: 67 | raise ValueError( 68 | "Residuals plot is only applicable for normal " 69 | "additive noise assumption" 70 | ) 71 | 72 | if axes is None: 73 | fig, axes = plt.subplots( 74 | 1, 2, sharey=True, figsize=size, width_ratios=[2, 1] 75 | ) 76 | fig.set_layout_engine("tight") 77 | fig.suptitle("Residuals") 78 | 79 | residual_df = calculate_residuals( 80 | measurement_dfs=petab_problem.measurement_df, 81 | simulation_dfs=simulations_df, 82 | observable_dfs=petab_problem.observable_df, 83 | parameter_dfs=petab_problem.parameter_df, 84 | )[0] 85 | 86 | normal_residuals = residual_df[ 87 | residual_df[OBSERVABLE_ID].isin(observable_ids) 88 | ] 89 | simulations_normal = simulations_df[ 90 | simulations_df[OBSERVABLE_ID].isin(observable_ids) 91 | ] 92 | 93 | # compare to standard normal distribution 94 | ks_result = stats.kstest(normal_residuals[RESIDUAL], stats.norm.cdf) 95 | 96 | # plot the residuals plot 97 | axes[0].hlines( 98 | y=0, 99 | xmin=min(simulations_normal[SIMULATION]), 100 | xmax=max(simulations_normal[SIMULATION]), 101 | ls="--", 102 | color="gray", 103 | ) 104 | axes[0].scatter(simulations_normal[SIMULATION], normal_residuals[RESIDUAL]) 105 | axes[0].text( 106 | 0.15, 107 | 0.85, 108 | f"Kolmogorov-Smirnov test results:\n" 109 | f"statistic: {ks_result[0]:.2f}\n" 110 | f"pvalue: {ks_result[1]:.2e} ", 111 | transform=axes[0].transAxes, 112 | ) 113 | axes[0].set_xlabel("simulated values") 114 | axes[0].set_ylabel("residuals") 115 | 116 | # plot histogram 117 | axes[1].hist( 118 | normal_residuals[RESIDUAL], density=True, orientation="horizontal" 119 | ) 120 | axes[1].set_xlabel("distribution") 121 | 122 | ymin, ymax = axes[0].get_ylim() 123 | ylim = max(abs(ymin), abs(ymax)) 124 | axes[0].set_ylim(-ylim, ylim) 125 | axes[1].tick_params( 126 | left=False, labelleft=False, right=True, labelright=True 127 | ) 128 | 129 | return axes 130 | 131 | 132 | def plot_goodness_of_fit( 133 | petab_problem: Problem, 134 | simulations_df: str | Path | pd.DataFrame, 135 | size: tuple = (10, 7), 136 | ax: plt.Axes | None = None, 137 | ) -> matplotlib.axes.Axes: 138 | """ 139 | Plot goodness of fit. 140 | 141 | Parameters 142 | ---------- 143 | petab_problem: 144 | A PEtab problem. 145 | simulations_df: 146 | A simulation DataFrame in the PEtab format or path to the simulation 147 | output data file. 148 | size: 149 | Figure size. 150 | ax: 151 | Axis object. 152 | 153 | Returns 154 | ------- 155 | ax: Axis object of the created plot. 156 | """ 157 | if isinstance(simulations_df, str | Path): 158 | simulations_df = get_simulation_df(simulations_df) 159 | 160 | if simulations_df is None or petab_problem.measurement_df is None: 161 | raise NotImplementedError( 162 | "Both measurements and simulation data " 163 | "are needed for goodness_of_fit" 164 | ) 165 | 166 | residual_df = calculate_residuals( 167 | measurement_dfs=petab_problem.measurement_df, 168 | simulation_dfs=simulations_df, 169 | observable_dfs=petab_problem.observable_df, 170 | parameter_dfs=petab_problem.parameter_df, 171 | )[0] 172 | slope, intercept, r_value, p_value, std_err = stats.linregress( 173 | petab_problem.measurement_df["measurement"], 174 | simulations_df["simulation"], 175 | ) # x, y 176 | 177 | if ax is None: 178 | fig, ax = plt.subplots(figsize=size) 179 | fig.set_layout_engine("tight") 180 | 181 | ax.scatter( 182 | petab_problem.measurement_df["measurement"], 183 | simulations_df["simulation"], 184 | ) 185 | 186 | ax.axis("square") 187 | xlim = ax.get_xlim() 188 | ylim = ax.get_ylim() 189 | lim = [min([xlim[0], ylim[0]]), max([xlim[1], ylim[1]])] 190 | ax.set_xlim(lim) 191 | ax.set_ylim(lim) 192 | x = np.linspace(lim, 100) 193 | ax.plot(x, x, linestyle="--", color="gray") 194 | ax.plot(x, intercept + slope * x, "r", label="fitted line") 195 | 196 | mse = np.mean(np.abs(residual_df["residual"])) 197 | ax.text( 198 | 0.1, 199 | 0.70, 200 | f"$R^2$: {r_value**2:.2f}\n" 201 | f"slope: {slope:.2f}\n" 202 | f"intercept: {intercept:.2f}\n" 203 | f"pvalue: {std_err:.2e}\n" 204 | f"mean squared error: {mse:.2e}\n", 205 | transform=ax.transAxes, 206 | ) 207 | 208 | ax.set_title("Goodness of fit") 209 | ax.set_xlabel("simulated values") 210 | ax.set_ylabel("measurements") 211 | return ax 212 | -------------------------------------------------------------------------------- /petab/v1/visualize/templates/mystyle.css: -------------------------------------------------------------------------------- 1 | /* Vertical table column headers */ 2 | .vrt-header thead th { 3 | writing-mode: vertical-lr; 4 | min-width: 50px; /* for firefox */ 5 | } 6 | 7 | .vrt-header tbody th { 8 | white-space: nowrap; 9 | } 10 | 11 | table { 12 | border-collapse: collapse; 13 | text-align: right; 14 | } 15 | 16 | table, th, td { 17 | border: 1px solid black; 18 | } 19 | 20 | th { 21 | background-color: #4CAF50; 22 | color: white; 23 | } 24 | 25 | tr:nth-child(even) {background-color: #f2f2f2;} 26 | -------------------------------------------------------------------------------- /petab/v1/visualize/templates/report.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{model_name}} 5 | 6 | 7 | 8 | 9 | 10 |

Summary for {{model_name}}

11 | 12 | 13 |

Basic stats

14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
Number of conditions / data points / observables parameters
Number of conditions{{ num_conditions }}
Number of data points{{ problem.measurement_df|length }}
Number of observables{{ problem.measurement_df.observableId.unique()|length }}
Number of parameters{{ problem.parameter_df|length }}
36 | 37 | 38 |

Data points per observable / condition

39 | 40 | {{ data_per_observable.to_html(classes='vrt-header', border=None) }} 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /petab/v2/__init__.py: -------------------------------------------------------------------------------- 1 | """The PEtab 2.0 subpackage. 2 | 3 | Contains all functionality related to handling PEtab 2.0 problems. 4 | """ 5 | from warnings import warn 6 | 7 | from ..v1 import * # noqa: F403, F401, E402 8 | 9 | # import after v1 10 | from .problem import Problem # noqa: F401 11 | 12 | warn( 13 | "Support for PEtab2.0 and all of petab.v2 is experimental " 14 | "and subject to changes!", 15 | stacklevel=1, 16 | ) 17 | -------------------------------------------------------------------------------- /petab/v2/models/__init__.py: -------------------------------------------------------------------------------- 1 | """Handling of different model types supported by PEtab.""" 2 | from ...v1.models import * # noqa: F401, F403 3 | -------------------------------------------------------------------------------- /petab/v2/models/model.py: -------------------------------------------------------------------------------- 1 | """PEtab model abstraction""" 2 | from ...v1.models.model import * # noqa: F401, F403 3 | -------------------------------------------------------------------------------- /petab/v2/models/pysb_model.py: -------------------------------------------------------------------------------- 1 | """Functions for handling PySB models""" 2 | from ...v1.models.pysb_model import * # noqa: F401, F403 3 | -------------------------------------------------------------------------------- /petab/v2/models/sbml_model.py: -------------------------------------------------------------------------------- 1 | """Functions for handling SBML models""" 2 | from ...v1.models.sbml_model import * # noqa: F401, F403 3 | -------------------------------------------------------------------------------- /petab/v2/petab1to2.py: -------------------------------------------------------------------------------- 1 | """Convert PEtab version 1 problems to version 2.""" 2 | import shutil 3 | from itertools import chain 4 | from pathlib import Path 5 | 6 | from pandas.io.common import get_handle, is_url 7 | 8 | import petab.v1.C as C 9 | from petab.models import MODEL_TYPE_SBML 10 | from petab.v1 import Problem as ProblemV1 11 | from petab.v2.lint import lint_problem as lint_v2_problem 12 | from petab.yaml import get_path_prefix 13 | 14 | from ..v1 import lint_problem as lint_v1_problem 15 | from ..v1.yaml import load_yaml, validate, write_yaml 16 | from ..versions import get_major_version 17 | 18 | __all__ = ["petab1to2"] 19 | 20 | 21 | def petab1to2(yaml_config: Path | str, output_dir: Path | str = None): 22 | """Convert from PEtab 1.0 to PEtab 2.0 format. 23 | 24 | Convert a PEtab problem from PEtab 1.0 to PEtab 2.0 format. 25 | 26 | Parameters 27 | ---------- 28 | yaml_config: dict | Path | str 29 | The PEtab problem as dictionary or YAML file name. 30 | output_dir: Path | str 31 | The output directory to save the converted PEtab problem, or ``None``, 32 | to return a :class:`petab.v2.Problem` instance. 33 | 34 | Raises 35 | ------ 36 | ValueError 37 | If the input is invalid or does not pass linting or if the generated 38 | files do not pass linting. 39 | """ 40 | if output_dir is None: 41 | # TODO requires petab.v2.Problem 42 | raise NotImplementedError("Not implemented yet.") 43 | elif isinstance(yaml_config, dict): 44 | raise ValueError("If output_dir is given, yaml_config must be a file.") 45 | 46 | if isinstance(yaml_config, Path | str): 47 | yaml_file = str(yaml_config) 48 | path_prefix = get_path_prefix(yaml_file) 49 | yaml_config = load_yaml(yaml_config) 50 | get_src_path = lambda filename: f"{path_prefix}/{filename}" # noqa: E731 51 | else: 52 | yaml_file = None 53 | path_prefix = None 54 | get_src_path = lambda filename: filename # noqa: E731 55 | 56 | get_dest_path = lambda filename: f"{output_dir}/{filename}" # noqa: E731 57 | 58 | # Validate original PEtab problem 59 | validate(yaml_config, path_prefix=path_prefix) 60 | if get_major_version(yaml_config) != 1: 61 | raise ValueError("PEtab problem is not version 1.") 62 | petab_problem = ProblemV1.from_yaml(yaml_file or yaml_config) 63 | if lint_v1_problem(petab_problem): 64 | raise ValueError("PEtab problem does not pass linting.") 65 | 66 | # Update YAML file 67 | new_yaml_config = _update_yaml(yaml_config) 68 | 69 | # Write new YAML file 70 | output_dir = Path(output_dir) 71 | output_dir.mkdir(parents=True, exist_ok=True) 72 | new_yaml_file = output_dir / Path(yaml_file).name 73 | write_yaml(new_yaml_config, new_yaml_file) 74 | 75 | # Update tables 76 | # condition tables, observable tables, SBML files, parameter table: 77 | # no changes - just copy 78 | file = yaml_config[C.PARAMETER_FILE] 79 | _copy_file(get_src_path(file), get_dest_path(file)) 80 | 81 | for problem_config in yaml_config[C.PROBLEMS]: 82 | for file in chain( 83 | problem_config.get(C.CONDITION_FILES, []), 84 | problem_config.get(C.OBSERVABLE_FILES, []), 85 | ( 86 | model[C.MODEL_LOCATION] 87 | for model in problem_config.get(C.MODEL_FILES, {}).values() 88 | ), 89 | problem_config.get(C.MEASUREMENT_FILES, []), 90 | problem_config.get(C.VISUALIZATION_FILES, []), 91 | ): 92 | _copy_file(get_src_path(file), get_dest_path(file)) 93 | 94 | # TODO: Measurements: preequilibration to experiments/timecourses once 95 | # finalized 96 | ... 97 | 98 | # validate updated Problem 99 | validation_issues = lint_v2_problem(new_yaml_file) 100 | 101 | if validation_issues: 102 | raise ValueError( 103 | "Generated PEtab v2 problem did not pass linting: " 104 | f"{validation_issues}" 105 | ) 106 | 107 | 108 | def _update_yaml(yaml_config: dict) -> dict: 109 | """Update PEtab 1.0 YAML to PEtab 2.0 format.""" 110 | yaml_config = yaml_config.copy() 111 | 112 | # Update format_version 113 | yaml_config[C.FORMAT_VERSION] = "2.0.0" 114 | 115 | # Add extensions 116 | yaml_config[C.EXTENSIONS] = [] 117 | 118 | # Move models and set IDs (filename for now) 119 | for problem in yaml_config[C.PROBLEMS]: 120 | problem[C.MODEL_FILES] = {} 121 | models = problem[C.MODEL_FILES] 122 | for sbml_file in problem[C.SBML_FILES]: 123 | model_id = sbml_file.split("/")[-1].split(".")[0] 124 | models[model_id] = { 125 | C.MODEL_LANGUAGE: MODEL_TYPE_SBML, 126 | C.MODEL_LOCATION: sbml_file, 127 | } 128 | problem[C.MODEL_FILES] = problem.get(C.MODEL_FILES, {}) 129 | del problem[C.SBML_FILES] 130 | 131 | return yaml_config 132 | 133 | 134 | def _copy_file(src: Path | str, dest: Path | str): 135 | """Copy file.""" 136 | src = str(src) 137 | dest = str(dest) 138 | 139 | if is_url(src): 140 | with get_handle(src, mode="r") as src_handle: 141 | with open(dest, "w") as dest_handle: 142 | dest_handle.write(src_handle.handle.read()) 143 | return 144 | 145 | shutil.copy(str(src), str(dest)) 146 | -------------------------------------------------------------------------------- /petab/version.py: -------------------------------------------------------------------------------- 1 | """PEtab library version""" 2 | __version__ = "0.5.0" 3 | -------------------------------------------------------------------------------- /petab/versions.py: -------------------------------------------------------------------------------- 1 | """Handling of PEtab version numbers.""" 2 | from __future__ import annotations 3 | 4 | from pathlib import Path 5 | 6 | from petab.v1 import Problem as V1Problem 7 | from petab.v1.C import FORMAT_VERSION 8 | from petab.v1.yaml import load_yaml 9 | from petab.v2 import Problem as V2Problem 10 | 11 | __all__ = [ 12 | "get_major_version", 13 | ] 14 | 15 | 16 | def get_major_version( 17 | problem: str | dict | Path | V1Problem | V2Problem, 18 | ) -> int: 19 | """Get the major version number of the given problem.""" 20 | if isinstance(problem, V1Problem): 21 | return 1 22 | 23 | if isinstance(problem, V2Problem): 24 | return 2 25 | 26 | if isinstance(problem, str | Path): 27 | yaml_config = load_yaml(problem) 28 | version = yaml_config.get(FORMAT_VERSION) 29 | elif isinstance(problem, dict): 30 | version = problem.get(FORMAT_VERSION) 31 | else: 32 | raise ValueError(f"Unsupported argument type: {type(problem)}") 33 | 34 | version = str(version) 35 | return int(version.split(".")[0]) 36 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=62", 4 | "wheel", 5 | ] 6 | build-backend = "setuptools.build_meta" 7 | 8 | [project] 9 | name = "petab" 10 | dynamic = ["version", "readme"] 11 | description = "Parameter estimation tabular data" 12 | requires-python = ">=3.10" 13 | dependencies = [ 14 | "numpy>=1.15.1", 15 | "pandas>=1.2.0", 16 | # remove when pandas >= 3, see also 17 | # https://github.com/pandas-dev/pandas/issues/54466 18 | "pyarrow", 19 | "python-libsbml>=5.17.0", 20 | "sympy", 21 | "colorama", 22 | "pyyaml", 23 | "jsonschema", 24 | "antlr4-python3-runtime==4.13.1", 25 | ] 26 | license = {text = "MIT License"} 27 | authors = [ 28 | {name = "The PEtab developers"}, 29 | ] 30 | maintainers = [ 31 | {name = "Daniel Weindl", email = "sci@danielweindl.de"}, 32 | {name = "Dilan Pathirana", email = "dilan.pathirana@uni-bonn.de"}, 33 | {name = "Maren Philipps", email = "maren.philipps@uni-bonn.de"}, 34 | ] 35 | 36 | [project.optional-dependencies] 37 | tests = [ 38 | "pytest", 39 | "pytest-cov", 40 | "simplesbml", 41 | "scipy", 42 | "pysb", 43 | ] 44 | quality = [ 45 | "pre-commit", 46 | ] 47 | reports = [ 48 | # https://github.com/spatialaudio/nbsphinx/issues/641 49 | "Jinja2==3.0.3", 50 | ] 51 | combine = [ 52 | "python-libcombine>=0.2.6", 53 | ] 54 | doc = [ 55 | "sphinx>=3.5.3, !=5.1.0", 56 | "sphinxcontrib-napoleon>=0.7", 57 | "sphinx-markdown-tables>=0.0.15", 58 | "sphinx-rtd-theme>=0.5.1", 59 | "m2r2", 60 | "myst-nb>=0.14.0", 61 | # https://github.com/spatialaudio/nbsphinx/issues/687#issuecomment-1339271312 62 | "ipython>=7.21.0, !=8.7.0", 63 | "pysb", 64 | ] 65 | vis = [ 66 | "matplotlib>=3.6.0", 67 | "seaborn", 68 | "scipy" 69 | ] 70 | 71 | [project.scripts] 72 | petablint = "petab.petablint:main" 73 | petab_visualize = "petab.v1.visualize.cli:_petab_visualize_main" 74 | 75 | [project.urls] 76 | Repository = "https://github.com/PEtab-dev/libpetab-python" 77 | Documentation = "https://petab.readthedocs.io/projects/libpetab-python/" 78 | 79 | [tool.setuptools.packages.find] 80 | include = ["petab", "petab.*"] 81 | namespaces = false 82 | 83 | [tool.setuptools.package-data] 84 | petab = ["petab/schemas/*", "petab/visualize/templates/*"] 85 | 86 | [tool.ruff] 87 | line-length = 79 88 | lint.extend-select = [ 89 | "F", # Pyflakes 90 | "I", # isort 91 | "S", # flake8-bandit 92 | "B", # flake8-bugbear 93 | "C4", # flake8-comprehensions 94 | "T20", # flake8-print 95 | "W", # pycodestyle Warnings 96 | "E", # pycodestyle Errors 97 | "UP", # pyupgrade 98 | # TODO: "ANN001", "D", # pydocstyle (PEP 257) 99 | ] 100 | lint.extend-ignore = ["F403", "F405", "S101"] 101 | lint.exclude = [ 102 | "petab/v1/math/_generated/*", # auto-generated 103 | ] 104 | 105 | [tool.ruff.lint.pydocstyle] 106 | convention = "pep257" 107 | 108 | [tool.ruff.lint.per-file-ignores] 109 | "tests/*" = ["T201"] 110 | 111 | [tool.ruff.format] 112 | exclude = [ 113 | "petab/math/_generated/*", # auto-generated 114 | ] 115 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | filterwarnings = 3 | error 4 | # TODO: until tests are reorganized for petab.v1 5 | ignore::DeprecationWarning 6 | ignore:Support for PEtab2.0 and all of petab.v2 is experimental:UserWarning 7 | ignore:Support for PEtab2.0 is experimental:UserWarning 8 | ignore:.*inspect.getargspec\(\) is deprecated.*:DeprecationWarning 9 | ignore:.*Passing unrecognized arguments to super\(PyDevIPCompleter6\).*:DeprecationWarning 10 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | tox >= 3.26.0 2 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | 4 | from setuptools import setup 5 | 6 | 7 | def read(fname): 8 | """Read a file.""" 9 | return open(fname).read() 10 | 11 | 12 | def absolute_links(txt): 13 | """Replace relative petab github links by absolute links.""" 14 | raw_base = ( 15 | "(https://raw.githubusercontent.com/petab-dev/libpetab-python/master/" 16 | ) 17 | embedded_base = ( 18 | "(https://github.com/petab-dev/libpetab-python/tree/master/" 19 | ) 20 | # iterate over links 21 | for var in re.findall(r"\[.*?\]\((?!http).*?\)", txt): 22 | if re.match(r".*?.(png|svg)\)", var): 23 | # link to raw file 24 | rep = var.replace("(", raw_base) 25 | else: 26 | # link to github embedded file 27 | rep = var.replace("(", embedded_base) 28 | txt = txt.replace(var, rep) 29 | return txt 30 | 31 | 32 | # read version from file 33 | __version__ = "" 34 | version_file = os.path.join("petab", "version.py") 35 | # sets __version__ 36 | exec(read(version_file)) # pylint: disable=W0122 # nosec # noqa: S102 37 | 38 | # project metadata 39 | # noinspection PyUnresolvedReferences 40 | setup( 41 | long_description=absolute_links(read("README.md")), 42 | long_description_content_type="text/markdown", 43 | version=__version__, 44 | ) 45 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_deprecation_warnings.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import pytest 4 | 5 | 6 | def test_deprecated_global(): 7 | with pytest.warns(DeprecationWarning): 8 | from petab import Problem # noqa 9 | 10 | with pytest.warns(DeprecationWarning): 11 | import petab 12 | 13 | petab.Problem() 14 | 15 | with pytest.warns(DeprecationWarning): 16 | import petab.parameters 17 | 18 | petab.parameters # noqa 19 | 20 | with warnings.catch_warnings(): 21 | warnings.simplefilter("error") 22 | from petab.v1 import Problem # noqa 23 | 24 | Problem() 25 | 26 | import petab.v1.parameters 27 | -------------------------------------------------------------------------------- /tests/v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/tests/v1/__init__.py -------------------------------------------------------------------------------- /tests/v1/math/__init__.py: -------------------------------------------------------------------------------- 1 | """PEtab math handling functionality.""" 2 | -------------------------------------------------------------------------------- /tests/v1/math/test_math.py: -------------------------------------------------------------------------------- 1 | import importlib.resources 2 | from pathlib import Path 3 | 4 | import numpy as np 5 | import pytest 6 | import sympy as sp 7 | import yaml 8 | from sympy.abc import _clash 9 | from sympy.logic.boolalg import Boolean 10 | 11 | from petab.math import sympify_petab 12 | 13 | 14 | def test_sympify_numpy(): 15 | assert sympify_petab(np.float64(1.0)) == sp.Float(1.0) 16 | 17 | 18 | def test_parse_simple(): 19 | """Test simple numeric expressions.""" 20 | assert float(sympify_petab("1 + 2")) == 3 21 | assert float(sympify_petab("1 + 2 * 3")) == 7 22 | assert float(sympify_petab("(1 + 2) * 3")) == 9 23 | assert float(sympify_petab("1 + 2 * (3 + 4)")) == 15 24 | assert float(sympify_petab("1 + 2 * (3 + 4) / 2")) == 8 25 | 26 | 27 | def read_cases(): 28 | """Read test cases from YAML file in the petab_test_suite package.""" 29 | yaml_file = importlib.resources.files("petabtests.cases").joinpath( 30 | str(Path("v2.0.0", "math", "math_tests.yaml")) 31 | ) 32 | with importlib.resources.as_file(yaml_file) as file, open(file) as file: 33 | data = yaml.safe_load(file) 34 | 35 | cases = [] 36 | for item in data["cases"]: 37 | expr_str = item["expression"] 38 | if item["expected"] is True or item["expected"] is False: 39 | expected = item["expected"] 40 | else: 41 | try: 42 | expected = float(item["expected"]) 43 | except ValueError: 44 | expected = sp.sympify(item["expected"], locals=_clash) 45 | expected = expected.subs( 46 | { 47 | s: sp.Symbol(s.name, real=True) 48 | for s in expected.free_symbols 49 | } 50 | ) 51 | cases.append((expr_str, expected)) 52 | return cases 53 | 54 | 55 | @pytest.mark.parametrize("expr_str, expected", read_cases()) 56 | def test_parse_cases(expr_str, expected): 57 | """Test PEtab math expressions for the PEtab test suite.""" 58 | result = sympify_petab(expr_str) 59 | if isinstance(result, Boolean): 60 | assert result == expected 61 | else: 62 | try: 63 | result = float(result.evalf()) 64 | assert np.isclose( 65 | result, expected 66 | ), f"{expr_str}: Expected {expected}, got {result}" 67 | except TypeError: 68 | assert ( 69 | result == expected 70 | ), f"{expr_str}: Expected {expected}, got {result}" 71 | 72 | 73 | def test_ids(): 74 | """Test symbols in expressions.""" 75 | assert sympify_petab("bla * 2") == 2.0 * sp.Symbol("bla", real=True) 76 | 77 | 78 | def test_syntax_error(): 79 | """Test exceptions upon syntax errors.""" 80 | # parser error 81 | with pytest.raises(ValueError, match="Syntax error"): 82 | sympify_petab("1 + ") 83 | 84 | # lexer error 85 | with pytest.raises(ValueError, match="Syntax error"): 86 | sympify_petab("0.") 87 | 88 | 89 | def test_complex(): 90 | """Test expressions producing (unsupported) complex numbers.""" 91 | with pytest.raises(ValueError, match="not real-valued"): 92 | sympify_petab("sqrt(-1)") 93 | with pytest.raises(ValueError, match="not real-valued"): 94 | sympify_petab("arctanh(inf)") 95 | -------------------------------------------------------------------------------- /tests/v1/test_combine.py: -------------------------------------------------------------------------------- 1 | """Test COMBINE archive""" 2 | import tempfile 3 | from pathlib import Path 4 | 5 | import pandas as pd 6 | 7 | import petab 8 | from petab.C import * 9 | 10 | # import fixtures 11 | pytest_plugins = [ 12 | "tests.v1.test_petab", 13 | ] 14 | 15 | 16 | def test_combine_archive(): 17 | """Test `create_combine_archive` and `Problem.from_combine`""" 18 | # Create test files 19 | import simplesbml 20 | 21 | ss_model = simplesbml.SbmlModel() 22 | 23 | # Create tables with arbitrary content 24 | measurement_df = pd.DataFrame( 25 | data={ 26 | OBSERVABLE_ID: ["obs1", "obs2"], 27 | OBSERVABLE_PARAMETERS: ["", "p1;p2"], 28 | NOISE_PARAMETERS: ["p3;p4", "p5"], 29 | } 30 | ) 31 | 32 | condition_df = pd.DataFrame( 33 | data={ 34 | CONDITION_ID: ["condition1", "condition2"], 35 | CONDITION_NAME: ["", "Condition 2"], 36 | "fixedParameter1": [1.0, 2.0], 37 | } 38 | ) 39 | condition_df.set_index(CONDITION_ID, inplace=True) 40 | 41 | parameter_df = pd.DataFrame( 42 | data={ 43 | PARAMETER_ID: ["dynamicParameter1", "dynamicParameter2"], 44 | PARAMETER_NAME: ["", "..."], 45 | } 46 | ) 47 | parameter_df.set_index(PARAMETER_ID, inplace=True) 48 | 49 | observable_df = pd.DataFrame( 50 | data={ 51 | OBSERVABLE_ID: ["observable_1"], 52 | OBSERVABLE_FORMULA: ["observable_1"], 53 | NOISE_FORMULA: [1], 54 | } 55 | ) 56 | observable_df.set_index(OBSERVABLE_ID, inplace=True) 57 | 58 | sbml_file_name = "model.xml" 59 | measurement_file_name = "measurements.tsv" 60 | condition_file_name = "conditions.tsv" 61 | parameter_file_name = "parameters.tsv" 62 | observable_file_name = "observables.tsv" 63 | yaml_file_name = "test.yaml" 64 | 65 | yaml_config = { 66 | FORMAT_VERSION: petab.__format_version__, 67 | PARAMETER_FILE: parameter_file_name, 68 | PROBLEMS: [ 69 | { 70 | SBML_FILES: [sbml_file_name], 71 | MEASUREMENT_FILES: [measurement_file_name], 72 | CONDITION_FILES: [condition_file_name], 73 | OBSERVABLE_FILES: [observable_file_name], 74 | } 75 | ], 76 | } 77 | 78 | with tempfile.TemporaryDirectory( 79 | prefix="petab_test_combine_archive" 80 | ) as tempdir: 81 | # Write test data 82 | outdir = Path(tempdir) 83 | petab.write_sbml(ss_model.document, outdir / sbml_file_name) 84 | petab.write_measurement_df( 85 | measurement_df, outdir / measurement_file_name 86 | ) 87 | petab.write_parameter_df(parameter_df, outdir / parameter_file_name) 88 | petab.write_observable_df(observable_df, outdir / observable_file_name) 89 | petab.write_condition_df(condition_df, outdir / condition_file_name) 90 | petab.write_yaml(yaml_config, outdir / yaml_file_name) 91 | 92 | archive_file_name = outdir / "test.omex" 93 | 94 | # Create COMBINE archive 95 | petab.create_combine_archive( 96 | outdir / yaml_file_name, archive_file_name, family_name="Tester" 97 | ) 98 | 99 | # Read COMBINE archive 100 | problem = petab.Problem.from_combine(archive_file_name) 101 | 102 | assert problem.parameter_df is not None 103 | assert problem.condition_df is not None 104 | assert problem.measurement_df is not None 105 | assert problem.observable_df is not None 106 | -------------------------------------------------------------------------------- /tests/v1/test_conditions.py: -------------------------------------------------------------------------------- 1 | """Tests related to petab.conditions""" 2 | import os 3 | import tempfile 4 | from pathlib import Path 5 | 6 | import numpy as np 7 | import pandas as pd 8 | import pytest 9 | 10 | import petab 11 | from petab import conditions 12 | from petab.C import * 13 | 14 | 15 | def test_get_parametric_overrides(): 16 | condition_df = pd.DataFrame( 17 | data={ 18 | CONDITION_ID: ["condition1", "condition2"], 19 | CONDITION_NAME: ["", "Condition 2"], 20 | "fixedParameter1": [1.0, 2.0], 21 | } 22 | ) 23 | 24 | assert conditions.get_parametric_overrides(condition_df) == [] 25 | 26 | condition_df.fixedParameter1 = condition_df.fixedParameter1.values.astype( 27 | int 28 | ) 29 | 30 | assert conditions.get_parametric_overrides(condition_df) == [] 31 | 32 | condition_df["fixedParameter1"] = condition_df["fixedParameter1"].astype( 33 | "object" 34 | ) 35 | condition_df.loc[0, "fixedParameter1"] = "parameterId" 36 | 37 | assert conditions.get_parametric_overrides(condition_df) == ["parameterId"] 38 | 39 | 40 | def test_get_condition_df(): 41 | """Test conditions.get_condition_df.""" 42 | # condition df missing ids 43 | condition_df = pd.DataFrame( 44 | data={ 45 | CONDITION_NAME: ["Condition 1", "Condition 2"], 46 | "fixedParameter1": [1.0, 2.0], 47 | } 48 | ) 49 | 50 | with tempfile.NamedTemporaryFile(mode="w", delete=False) as fh: 51 | file_name = fh.name 52 | condition_df.to_csv(fh, sep="\t", index=False) 53 | 54 | with pytest.raises(KeyError): 55 | petab.get_condition_df(file_name) 56 | 57 | os.remove(file_name) 58 | 59 | # with ids 60 | condition_df = pd.DataFrame( 61 | data={ 62 | CONDITION_ID: ["condition1", "condition2"], 63 | CONDITION_NAME: ["", "Condition 2"], 64 | "fixedParameter1": [1.0, 2.0], 65 | } 66 | ) 67 | 68 | with tempfile.NamedTemporaryFile(mode="w", delete=False) as fh: 69 | file_name = fh.name 70 | condition_df.to_csv(fh, sep="\t", index=False) 71 | 72 | df = petab.get_condition_df(file_name).replace(np.nan, "") 73 | assert (df == condition_df.set_index(CONDITION_ID)).all().all() 74 | 75 | os.remove(file_name) 76 | 77 | # test other arguments 78 | assert (petab.get_condition_df(condition_df) == condition_df).all().all() 79 | assert petab.get_condition_df(None) is None 80 | 81 | 82 | def test_write_condition_df(): 83 | """Test conditions.write_condition_df.""" 84 | condition_df = pd.DataFrame( 85 | data={ 86 | CONDITION_ID: ["condition1", "condition2"], 87 | CONDITION_NAME: ["Condition 1", "Condition 2"], 88 | "fixedParameter1": [1.0, 2.0], 89 | } 90 | ).set_index(CONDITION_ID) 91 | 92 | with tempfile.TemporaryDirectory() as temp_dir: 93 | file_name = Path(temp_dir) / "conditions.tsv" 94 | petab.write_condition_df(condition_df, file_name) 95 | re_df = petab.get_condition_df(file_name) 96 | assert (condition_df == re_df).all().all() 97 | 98 | 99 | def test_create_condition_df(): 100 | """Test conditions.create_condition_df.""" 101 | parameter_ids = ["par1", "par2", "par3"] 102 | condition_ids = ["condition1", "condition2"] 103 | 104 | df = petab.create_condition_df(parameter_ids, condition_ids) 105 | 106 | expected = pd.DataFrame( 107 | data={ 108 | CONDITION_ID: ["condition1", "condition2"], 109 | "par1": [np.nan, np.nan], 110 | "par2": [np.nan, np.nan], 111 | "par3": [np.nan, np.nan], 112 | } 113 | ).set_index(CONDITION_ID) 114 | 115 | assert ((df == expected) | df.isna() == expected.isna()).all().all() 116 | -------------------------------------------------------------------------------- /tests/v1/test_deprecated.py: -------------------------------------------------------------------------------- 1 | """Check that deprecated functionality raises but still works.""" 2 | import tempfile 3 | from pathlib import Path 4 | 5 | import pytest 6 | 7 | import petab 8 | 9 | from .test_petab import petab_problem # noqa: F401 10 | from .test_sbml import check_model, create_test_data 11 | 12 | 13 | def test_problem_with_sbml_model(): 14 | """Test that a problem can be correctly created from sbml model.""" 15 | # retrieve test data 16 | ( 17 | ss_model, 18 | condition_df, 19 | observable_df, 20 | measurement_df, 21 | parameter_df, 22 | ) = create_test_data() 23 | 24 | with pytest.deprecated_call(): 25 | petab_problem = petab.Problem( # noqa: F811 26 | sbml_model=ss_model.model, 27 | condition_df=condition_df, 28 | measurement_df=measurement_df, 29 | parameter_df=parameter_df, 30 | ) 31 | 32 | with pytest.warns( 33 | UserWarning, 34 | match="An SBML rule was removed to set the component " 35 | "species_2 to a constant value.", 36 | ): 37 | _, condition_model = petab.get_model_for_condition( 38 | petab_problem, "condition_1" 39 | ) 40 | 41 | check_model(condition_model) 42 | 43 | 44 | def test_to_files_with_sbml_model(petab_problem): # noqa: F811 45 | """Test problem.to_files.""" 46 | with tempfile.TemporaryDirectory() as outdir: 47 | # create target files 48 | sbml_file = Path(outdir, "model.xml") 49 | condition_file = Path(outdir, "conditions.tsv") 50 | measurement_file = Path(outdir, "measurements.tsv") 51 | parameter_file = Path(outdir, "parameters.tsv") 52 | observable_file = Path(outdir, "observables.tsv") 53 | 54 | # write contents to files 55 | with pytest.deprecated_call(): 56 | petab_problem.to_files( 57 | sbml_file=sbml_file, 58 | condition_file=condition_file, 59 | measurement_file=measurement_file, 60 | parameter_file=parameter_file, 61 | visualization_file=None, 62 | observable_file=observable_file, 63 | yaml_file=None, 64 | ) 65 | 66 | # exemplarily load some 67 | parameter_df = petab.get_parameter_df(parameter_file) 68 | same_nans = parameter_df.isna() == petab_problem.parameter_df.isna() 69 | assert ( 70 | ((parameter_df == petab_problem.parameter_df) | same_nans) 71 | .all() 72 | .all() 73 | ) 74 | -------------------------------------------------------------------------------- /tests/v1/test_mapping.py: -------------------------------------------------------------------------------- 1 | """Tests related to petab.mapping""" 2 | import tempfile 3 | 4 | import pandas as pd 5 | import pytest 6 | 7 | from petab.C import * # noqa: F403 8 | from petab.mapping import * 9 | 10 | 11 | def test_get_mapping_df(): 12 | """Test parameters.get_mapping_df.""" 13 | # Missing columns 14 | mapping_df = pd.DataFrame( 15 | data={ 16 | PETAB_ENTITY_ID: ["e1"], 17 | } 18 | ) 19 | 20 | with pytest.raises(KeyError): 21 | get_mapping_df(mapping_df) 22 | 23 | # check index is correct 24 | mapping_df = pd.DataFrame( 25 | data={ 26 | PETAB_ENTITY_ID: ["e1"], 27 | MODEL_ENTITY_ID: ["m1"], 28 | } 29 | ) 30 | with tempfile.NamedTemporaryFile(mode="w", delete=False) as fh: 31 | file_name = fh.name 32 | write_mapping_df(mapping_df, file_name) 33 | 34 | assert get_mapping_df(file_name).index == ["e1"] 35 | -------------------------------------------------------------------------------- /tests/v1/test_measurements.py: -------------------------------------------------------------------------------- 1 | """Tests related to petab.measurements""" 2 | import tempfile 3 | from pathlib import Path 4 | 5 | import numpy as np 6 | import pandas as pd 7 | 8 | import petab 9 | from petab.C import * 10 | 11 | 12 | def test_get_measurement_df(): 13 | """Test measurements.get_measurement_df.""" 14 | measurement_df = pd.DataFrame( 15 | data={ 16 | OBSERVABLE_ID: ["obs1", "obs2"], 17 | OBSERVABLE_PARAMETERS: ["", "p1;p2"], 18 | NOISE_PARAMETERS: ["p3;p4", "p5"], 19 | } 20 | ) 21 | 22 | with tempfile.NamedTemporaryFile(mode="w", delete=False) as fh: 23 | file_name = fh.name 24 | measurement_df.to_csv(fh, sep="\t", index=False) 25 | 26 | df = petab.get_measurement_df(file_name).replace(np.nan, "") 27 | assert (df == measurement_df).all().all() 28 | 29 | # test other arguments 30 | assert ( 31 | (petab.get_measurement_df(measurement_df) == measurement_df) 32 | .all() 33 | .all() 34 | ) 35 | assert petab.get_measurement_df(None) is None 36 | 37 | 38 | def test_write_measurement_df(): 39 | """Test measurements.get_measurement_df.""" 40 | measurement_df = pd.DataFrame( 41 | data={ 42 | OBSERVABLE_ID: ["obs1", "obs2"], 43 | OBSERVABLE_PARAMETERS: ["", "p1;p2"], 44 | NOISE_PARAMETERS: ["p3;p4", "p5"], 45 | } 46 | ) 47 | 48 | with tempfile.TemporaryDirectory() as temp_dir: 49 | file_name = Path(temp_dir) / "parameters.tsv" 50 | petab.write_measurement_df(measurement_df, file_name) 51 | re_df = petab.get_measurement_df(file_name).replace(np.nan, "") 52 | assert (measurement_df == re_df).all().all() 53 | 54 | 55 | def test_create_measurement_df(): 56 | """Test measurements.create_measurement_df.""" 57 | df = petab.create_measurement_df() 58 | assert set(df.columns.values) == set(MEASUREMENT_DF_COLS) 59 | 60 | 61 | def test_measurements_have_replicates(): 62 | """Test measurements.measurements_have_replicates.""" 63 | measurement_df = pd.DataFrame( 64 | data={ 65 | OBSERVABLE_ID: ["obs1", "obs1"], 66 | OBSERVABLE_PARAMETERS: ["", "p1;p2"], 67 | NOISE_PARAMETERS: ["p3;p4", "p5"], 68 | TIME: [0, 1], 69 | MEASUREMENT: [42, 137.01], 70 | } 71 | ) 72 | assert not petab.measurements_have_replicates(measurement_df) 73 | 74 | measurement_df[TIME] = [1, 1] 75 | assert petab.measurements_have_replicates(measurement_df) 76 | 77 | 78 | def test_get_simulation_conditions(): 79 | """Test get_simulation_conditions""" 80 | # only simulation condition 81 | measurement_df = pd.DataFrame( 82 | data={ 83 | SIMULATION_CONDITION_ID: ["c0", "c1", "c0", "c1"], 84 | } 85 | ) 86 | expected = pd.DataFrame( 87 | data={ 88 | SIMULATION_CONDITION_ID: ["c0", "c1"], 89 | } 90 | ) 91 | actual = petab.get_simulation_conditions(measurement_df) 92 | assert actual.equals(expected) 93 | 94 | # simulation and preequilibration condition 95 | measurement_df = pd.DataFrame( 96 | data={ 97 | SIMULATION_CONDITION_ID: ["c0", "c1", "c0", "c1"], 98 | PREEQUILIBRATION_CONDITION_ID: ["c1", "c0", "c1", "c0"], 99 | } 100 | ) 101 | expected = pd.DataFrame( 102 | data={ 103 | SIMULATION_CONDITION_ID: ["c0", "c1"], 104 | PREEQUILIBRATION_CONDITION_ID: ["c1", "c0"], 105 | } 106 | ) 107 | actual = petab.get_simulation_conditions(measurement_df) 108 | assert actual.equals(expected) 109 | 110 | # simulation with and without preequilibration 111 | measurement_df = pd.DataFrame( 112 | data={ 113 | SIMULATION_CONDITION_ID: ["c0", "c1", "c0", "c1"], 114 | PREEQUILIBRATION_CONDITION_ID: ["", "", "c1", "c0"], 115 | } 116 | ) 117 | expected = pd.DataFrame( 118 | data={ 119 | SIMULATION_CONDITION_ID: ["c0", "c1", "c0", "c1"], 120 | PREEQUILIBRATION_CONDITION_ID: ["", "", "c1", "c0"], 121 | } 122 | ).sort_values( 123 | [SIMULATION_CONDITION_ID, PREEQUILIBRATION_CONDITION_ID], 124 | ignore_index=True, 125 | ) 126 | actual = petab.get_simulation_conditions(measurement_df) 127 | assert actual.equals(expected) 128 | 129 | # simulation with and without preequilibration; NaNs 130 | measurement_df = pd.DataFrame( 131 | data={ 132 | SIMULATION_CONDITION_ID: ["c0", "c1", "c0", "c1"], 133 | PREEQUILIBRATION_CONDITION_ID: [np.nan, np.nan, "c1", "c0"], 134 | } 135 | ) 136 | expected = pd.DataFrame( 137 | data={ 138 | SIMULATION_CONDITION_ID: ["c0", "c1", "c0", "c1"], 139 | PREEQUILIBRATION_CONDITION_ID: ["", "", "c1", "c0"], 140 | } 141 | ).sort_values( 142 | [SIMULATION_CONDITION_ID, PREEQUILIBRATION_CONDITION_ID], 143 | ignore_index=True, 144 | ) 145 | actual = petab.get_simulation_conditions(measurement_df) 146 | assert actual.equals(expected) 147 | -------------------------------------------------------------------------------- /tests/v1/test_model_pysb.py: -------------------------------------------------------------------------------- 1 | """Test related to petab.models.model_pysb""" 2 | import pysb 3 | import pytest 4 | 5 | from petab.models.pysb_model import ( 6 | PySBModel, 7 | parse_species_name, 8 | pattern_from_string, 9 | ) 10 | 11 | 12 | @pytest.fixture(scope="function") 13 | def uses_pysb(): 14 | """Cleanup PySB auto-exported symbols before and after test""" 15 | pysb.SelfExporter.cleanup() 16 | yield () 17 | pysb.SelfExporter.cleanup() 18 | 19 | 20 | def test_parse_species_name(): 21 | assert parse_species_name("cyclin(Y='U', b=None)") == [ 22 | ("cyclin", None, {"Y": "U", "b": None}) 23 | ] 24 | 25 | assert parse_species_name("cdc2(Y='P', b=1) % cyclin(Y='P', b=1)") == [ 26 | ("cdc2", None, {"Y": "P", "b": 1}), 27 | ("cyclin", None, {"Y": "P", "b": 1}), 28 | ] 29 | 30 | assert parse_species_name("A()") == [("A", None, {})] 31 | 32 | assert parse_species_name( 33 | "Bax(s1=1, s2=2, t=None) % Bax(s1=3, s2=1, t=None) % " 34 | "Bax(s1=2, s2=3, t=None)" 35 | ) == [ 36 | ("Bax", None, {"s1": 1, "s2": 2, "t": None}), 37 | ("Bax", None, {"s1": 3, "s2": 1, "t": None}), 38 | ("Bax", None, {"s1": 2, "s2": 3, "t": None}), 39 | ] 40 | 41 | assert parse_species_name("A(b=None) ** X") == [("A", "X", {"b": None})] 42 | 43 | assert parse_species_name("A(b=1) ** X % B(a=1) ** X") == [ 44 | ("A", "X", {"b": 1}), 45 | ("B", "X", {"a": 1}), 46 | ] 47 | 48 | # TODO: MultiState 49 | 50 | 51 | def test_pysb_model(uses_pysb): 52 | model = pysb.Model() 53 | pysb.Compartment("c1") 54 | pysb.Monomer("A") 55 | pysb.Monomer("B", ["s"], {"s": ["a", "b"]}) 56 | petab_model = PySBModel(model=model, model_id="test_model") 57 | 58 | assert petab_model.is_state_variable("A()") is True 59 | assert petab_model.is_state_variable("B(s='a')") is True 60 | 61 | # a compartment 62 | assert petab_model.is_state_variable("c1") is False 63 | # a monomer 64 | assert petab_model.is_state_variable("A") is False 65 | assert petab_model.is_state_variable("B") is False 66 | 67 | # not concrete 68 | assert petab_model.is_state_variable("B()") is False 69 | 70 | # non-existing compartment 71 | assert petab_model.is_state_variable("A() ** c2") is False 72 | 73 | # non-existing site 74 | assert petab_model.is_state_variable("A(s='a')") is False 75 | 76 | 77 | def test_pattern_parsing(uses_pysb): 78 | model = pysb.Model() 79 | c1 = pysb.Compartment("c1") 80 | A = pysb.Monomer("A") 81 | B = pysb.Monomer("B", ["s"], {"s": ["a", "b"]}) 82 | 83 | pattern = pysb.as_complex_pattern(A() ** c1) 84 | assert pattern_from_string(str(pattern), model).matches(pattern) 85 | assert str(pattern) == str(pattern_from_string("A() ** c1", model)) 86 | 87 | pattern = pysb.as_complex_pattern(B(s="a") ** c1) 88 | assert pattern_from_string(str(pattern), model).matches(pattern) 89 | assert str(pattern) == str(pattern_from_string("B(s='a') ** c1", model)) 90 | 91 | 92 | def test_pysb_model_repr(uses_pysb): 93 | model = pysb.Model(name="test") 94 | petab_model = PySBModel(model) 95 | assert repr(petab_model) == "" 96 | -------------------------------------------------------------------------------- /tests/v1/test_observables.py: -------------------------------------------------------------------------------- 1 | """Tests for petab.observables""" 2 | import tempfile 3 | from pathlib import Path 4 | 5 | import pandas as pd 6 | import pytest 7 | 8 | import petab 9 | from petab.C import * 10 | 11 | # import fixtures 12 | pytest_plugins = [ 13 | "tests.v1.test_petab", 14 | ] 15 | 16 | 17 | def test_get_observable_df(): 18 | """Test measurements.get_measurement_df.""" 19 | # without id 20 | observable_df = pd.DataFrame( 21 | data={ 22 | OBSERVABLE_NAME: ["observable name 1"], 23 | OBSERVABLE_FORMULA: ["observable_1"], 24 | NOISE_FORMULA: [1], 25 | } 26 | ) 27 | 28 | with tempfile.NamedTemporaryFile(mode="w", delete=False) as fh: 29 | file_name = fh.name 30 | observable_df.to_csv(fh, sep="\t", index=False) 31 | 32 | with pytest.raises(KeyError): 33 | petab.get_observable_df(file_name) 34 | 35 | # with id 36 | observable_df[OBSERVABLE_ID] = ["observable_1"] 37 | 38 | with tempfile.NamedTemporaryFile(mode="w", delete=False) as fh: 39 | file_name = fh.name 40 | observable_df.to_csv(fh, sep="\t", index=False) 41 | 42 | df = petab.get_observable_df(file_name) 43 | assert (df == observable_df.set_index(OBSERVABLE_ID)).all().all() 44 | 45 | # test other arguments 46 | assert ( 47 | (petab.get_observable_df(observable_df) == observable_df).all().all() 48 | ) 49 | assert petab.get_observable_df(None) is None 50 | 51 | 52 | def test_write_observable_df(): 53 | """Test measurements.get_measurement_df.""" 54 | observable_df = pd.DataFrame( 55 | data={ 56 | OBSERVABLE_ID: ["observable_1"], 57 | OBSERVABLE_NAME: ["observable name 1"], 58 | OBSERVABLE_FORMULA: ["observable_1"], 59 | NOISE_FORMULA: [1], 60 | } 61 | ).set_index(OBSERVABLE_ID) 62 | 63 | with tempfile.TemporaryDirectory() as temp_dir: 64 | file_name = Path(temp_dir) / "observables.tsv" 65 | petab.write_observable_df(observable_df, file_name) 66 | re_df = petab.get_observable_df(file_name) 67 | assert (observable_df == re_df).all().all() 68 | 69 | 70 | def test_get_output_parameters(): 71 | """Test measurements.get_output_parameters.""" 72 | # sbml model 73 | import simplesbml 74 | 75 | from petab.models.sbml_model import SbmlModel 76 | 77 | ss_model = simplesbml.SbmlModel() 78 | ss_model.addParameter("fixedParameter1", 1.0) 79 | ss_model.addParameter("observable_1", 1.0) 80 | 81 | # observable file 82 | observable_df = pd.DataFrame( 83 | data={ 84 | OBSERVABLE_ID: ["observable_1"], 85 | OBSERVABLE_NAME: ["observable name 1"], 86 | OBSERVABLE_FORMULA: ["observable_1 * scaling + offset"], 87 | NOISE_FORMULA: [1], 88 | } 89 | ).set_index(OBSERVABLE_ID) 90 | 91 | output_parameters = petab.get_output_parameters( 92 | observable_df, SbmlModel(sbml_model=ss_model.model) 93 | ) 94 | 95 | assert output_parameters == ["offset", "scaling"] 96 | 97 | # test sympy-special symbols (e.g. N, beta, ...) 98 | # see https://github.com/ICB-DCM/pyPESTO/issues/1048 99 | observable_df = pd.DataFrame( 100 | data={ 101 | OBSERVABLE_ID: ["observable_1"], 102 | OBSERVABLE_NAME: ["observable name 1"], 103 | OBSERVABLE_FORMULA: ["observable_1 * N + beta"], 104 | NOISE_FORMULA: [1], 105 | } 106 | ).set_index(OBSERVABLE_ID) 107 | 108 | output_parameters = petab.get_output_parameters( 109 | observable_df, SbmlModel(sbml_model=ss_model.model) 110 | ) 111 | 112 | assert output_parameters == ["N", "beta"] 113 | 114 | 115 | def test_get_formula_placeholders(): 116 | """Test get_formula_placeholders""" 117 | # no placeholder 118 | assert petab.get_formula_placeholders("1.0", "any", "observable") == [] 119 | 120 | # multiple placeholders 121 | assert petab.get_formula_placeholders( 122 | "observableParameter1_twoParams * " 123 | "observableParameter2_twoParams + otherParam", 124 | "twoParams", 125 | "observable", 126 | ) == ["observableParameter1_twoParams", "observableParameter2_twoParams"] 127 | 128 | # noise placeholder 129 | assert petab.get_formula_placeholders( 130 | "3.0 * noiseParameter1_oneParam", "oneParam", "noise" 131 | ) == ["noiseParameter1_oneParam"] 132 | 133 | # multiple instances and in 'wrong' order 134 | assert petab.get_formula_placeholders( 135 | "observableParameter2_twoParams * " 136 | "observableParameter1_twoParams + " 137 | "otherParam / observableParameter2_twoParams", 138 | "twoParams", 139 | "observable", 140 | ) == ["observableParameter1_twoParams", "observableParameter2_twoParams"] 141 | 142 | # non-consecutive numbering 143 | with pytest.raises(AssertionError): 144 | petab.get_formula_placeholders( 145 | "observableParameter2_twoParams + observableParameter2_twoParams", 146 | "twoParams", 147 | "observable", 148 | ) 149 | 150 | # empty 151 | assert petab.get_formula_placeholders("", "any", "observable") == [] 152 | 153 | # non-string 154 | assert petab.get_formula_placeholders(1, "any", "observable") == [] 155 | 156 | 157 | def test_create_observable_df(): 158 | """Test observables.create_measurement_df.""" 159 | df = petab.create_observable_df() 160 | assert set(df.columns.values) == set(OBSERVABLE_DF_COLS) 161 | 162 | 163 | def test_get_placeholders(): 164 | """Test get_placeholders""" 165 | observable_df = pd.DataFrame( 166 | data={ 167 | OBSERVABLE_ID: ["obs_1", "obs_2"], 168 | OBSERVABLE_FORMULA: [ 169 | "observableParameter1_obs_1 * 2 * foo", 170 | "1 + observableParameter1_obs_2", 171 | ], 172 | } 173 | ).set_index(OBSERVABLE_ID) 174 | 175 | # test with missing noiseFormula 176 | expected = ["observableParameter1_obs_1", "observableParameter1_obs_2"] 177 | actual = petab.get_placeholders(observable_df) 178 | assert actual == expected 179 | 180 | # test with noiseFormula 181 | observable_df[NOISE_FORMULA] = ["noiseParameter1_obs_1", "2.0"] 182 | expected = [ 183 | "observableParameter1_obs_1", 184 | "noiseParameter1_obs_1", 185 | "observableParameter1_obs_2", 186 | ] 187 | actual = petab.get_placeholders(observable_df) 188 | assert actual == expected 189 | -------------------------------------------------------------------------------- /tests/v1/test_priors.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | from pathlib import Path 3 | 4 | import benchmark_models_petab 5 | import numpy as np 6 | import pandas as pd 7 | import pytest 8 | from scipy.stats import norm 9 | 10 | import petab.v1 11 | from petab.v1 import get_simulation_conditions 12 | from petab.v1.priors import priors_to_measurements 13 | 14 | 15 | @pytest.mark.parametrize( 16 | "problem_id", ["Schwen_PONE2014", "Isensee_JCB2018", "Raimundez_PCB2020"] 17 | ) 18 | def test_priors_to_measurements(problem_id): 19 | """Test the conversion of priors to measurements.""" 20 | petab_problem_priors: petab.v1.Problem = ( 21 | benchmark_models_petab.get_problem(problem_id) 22 | ) 23 | petab_problem_priors.visualization_df = None 24 | assert petab.v1.lint_problem(petab_problem_priors) is False 25 | 26 | if problem_id == "Isensee_JCB2018": 27 | # required to match the stored simulation results below 28 | petab.v1.flatten_timepoint_specific_output_overrides( 29 | petab_problem_priors 30 | ) 31 | assert petab.v1.lint_problem(petab_problem_priors) is False 32 | original_problem = deepcopy(petab_problem_priors) 33 | 34 | petab_problem_measurements = priors_to_measurements(petab_problem_priors) 35 | 36 | # check that the original problem is not modified 37 | for attr in [ 38 | "condition_df", 39 | "parameter_df", 40 | "observable_df", 41 | "measurement_df", 42 | ]: 43 | assert ( 44 | diff := getattr(petab_problem_priors, attr).compare( 45 | getattr(original_problem, attr) 46 | ) 47 | ).empty, diff 48 | # check that measurements and observables were added 49 | assert petab.v1.lint_problem(petab_problem_measurements) is False 50 | assert ( 51 | petab_problem_measurements.parameter_df.shape[0] 52 | == petab_problem_priors.parameter_df.shape[0] 53 | ) 54 | assert ( 55 | petab_problem_measurements.observable_df.shape[0] 56 | > petab_problem_priors.observable_df.shape[0] 57 | ) 58 | assert ( 59 | petab_problem_measurements.measurement_df.shape[0] 60 | > petab_problem_priors.measurement_df.shape[0] 61 | ) 62 | # ensure we didn't introduce any new conditions 63 | assert len( 64 | get_simulation_conditions(petab_problem_measurements.measurement_df) 65 | ) == len(get_simulation_conditions(petab_problem_priors.measurement_df)) 66 | 67 | # verify that the objective function value is the same 68 | 69 | # load/construct the simulation results 70 | simulation_df_priors = petab.v1.get_simulation_df( 71 | Path( 72 | benchmark_models_petab.MODELS_DIR, 73 | problem_id, 74 | f"simulatedData_{problem_id}.tsv", 75 | ) 76 | ) 77 | simulation_df_measurements = pd.concat( 78 | [ 79 | petab_problem_measurements.measurement_df.rename( 80 | columns={petab.v1.MEASUREMENT: petab.v1.SIMULATION} 81 | )[ 82 | petab_problem_measurements.measurement_df[ 83 | petab.v1.C.OBSERVABLE_ID 84 | ].str.startswith("prior_") 85 | ], 86 | simulation_df_priors, 87 | ] 88 | ) 89 | 90 | llh_priors = petab.v1.calculate_llh_for_table( 91 | petab_problem_priors.measurement_df, 92 | simulation_df_priors, 93 | petab_problem_priors.observable_df, 94 | petab_problem_priors.parameter_df, 95 | ) 96 | llh_measurements = petab.v1.calculate_llh_for_table( 97 | petab_problem_measurements.measurement_df, 98 | simulation_df_measurements, 99 | petab_problem_measurements.observable_df, 100 | petab_problem_measurements.parameter_df, 101 | ) 102 | 103 | # get prior objective function contribution 104 | parameter_ids = petab_problem_priors.parameter_df.index.values[ 105 | (petab_problem_priors.parameter_df[petab.v1.ESTIMATE] == 1) 106 | & petab_problem_priors.parameter_df[ 107 | petab.v1.OBJECTIVE_PRIOR_TYPE 108 | ].notna() 109 | ] 110 | priors = petab.v1.get_priors_from_df( 111 | petab_problem_priors.parameter_df, 112 | mode="objective", 113 | parameter_ids=parameter_ids, 114 | ) 115 | prior_contrib = 0 116 | for parameter_id, prior in zip(parameter_ids, priors, strict=True): 117 | prior_type, prior_pars, par_scale, par_bounds = prior 118 | if prior_type == petab.v1.PARAMETER_SCALE_NORMAL: 119 | prior_contrib += norm.logpdf( 120 | petab_problem_priors.x_nominal_free_scaled[ 121 | petab_problem_priors.x_free_ids.index(parameter_id) 122 | ], 123 | loc=prior_pars[0], 124 | scale=prior_pars[1], 125 | ) 126 | else: 127 | # enable other models, once libpetab has proper support for 128 | # evaluating the prior contribution. until then, two test 129 | # problems should suffice 130 | assert problem_id == "Raimundez_PCB2020" 131 | pytest.skip(f"Prior type {prior_type} not implemented") 132 | 133 | assert np.isclose( 134 | llh_priors + prior_contrib, llh_measurements, rtol=1e-3, atol=1e-16 135 | ), (llh_priors + prior_contrib, llh_measurements) 136 | # check that the tolerance is not too high 137 | assert np.abs(prior_contrib) > 1e-3 * np.abs(llh_priors) 138 | -------------------------------------------------------------------------------- /tests/v1/test_sbml.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | import libsbml 5 | import pandas as pd 6 | import pytest 7 | 8 | from petab.v1.models.sbml_model import SbmlModel 9 | 10 | sys.path.append(os.getcwd()) 11 | import petab # noqa: E402 12 | 13 | 14 | def create_test_data(): 15 | # Create test model and data files 16 | import simplesbml 17 | 18 | ss_model = simplesbml.SbmlModel() 19 | ss_model.addCompartment(comp_id="compartment_1", vol=1) 20 | for i in range(1, 4): 21 | ss_model.addParameter(f"parameter_{i}", i) 22 | 23 | for i in range(1, 5): 24 | ss_model.addSpecies(f"[species_{i}]", 10 * i) 25 | 26 | ss_model.addAssignmentRule("species_2", "25") 27 | 28 | condition_df = pd.DataFrame( 29 | { 30 | petab.CONDITION_ID: ["condition_1"], 31 | "parameter_3": ["parameter_2"], 32 | "species_1": [15], 33 | "species_2": [25], 34 | "species_3": ["parameter_1"], 35 | "species_4": ["not_a_model_parameter"], 36 | "compartment_1": [2], 37 | } 38 | ) 39 | condition_df.set_index([petab.CONDITION_ID], inplace=True) 40 | 41 | observable_df = pd.DataFrame( 42 | { 43 | petab.OBSERVABLE_ID: ["observable_1"], 44 | petab.OBSERVABLE_FORMULA: ["2 * species_1"], 45 | } 46 | ) 47 | observable_df.set_index([petab.OBSERVABLE_ID], inplace=True) 48 | 49 | measurement_df = pd.DataFrame( 50 | { 51 | petab.OBSERVABLE_ID: ["observable_1"], 52 | petab.SIMULATION_CONDITION_ID: ["condition_1"], 53 | petab.TIME: [0.0], 54 | } 55 | ) 56 | 57 | parameter_df = pd.DataFrame( 58 | { 59 | petab.PARAMETER_ID: [ 60 | "parameter_1", 61 | "parameter_2", 62 | "not_a_model_parameter", 63 | ], 64 | petab.PARAMETER_SCALE: [petab.LOG10] * 3, 65 | petab.NOMINAL_VALUE: [1.25, 2.25, 3.25], 66 | petab.ESTIMATE: [0, 1, 0], 67 | } 68 | ) 69 | parameter_df.set_index([petab.PARAMETER_ID], inplace=True) 70 | 71 | return ss_model, condition_df, observable_df, measurement_df, parameter_df 72 | 73 | 74 | def check_model(condition_model): 75 | assert ( 76 | condition_model.getSpecies("species_1").getInitialConcentration() == 15 77 | ) 78 | assert ( 79 | condition_model.getSpecies("species_2").getInitialConcentration() == 25 80 | ) 81 | assert ( 82 | condition_model.getSpecies("species_3").getInitialConcentration() 83 | == 1.25 84 | ) 85 | assert ( 86 | condition_model.getSpecies("species_4").getInitialConcentration() 87 | == 3.25 88 | ) 89 | assert ( 90 | len(condition_model.getListOfInitialAssignments()) == 0 91 | ), "InitialAssignment not removed" 92 | assert condition_model.getCompartment("compartment_1").getSize() == 2.0 93 | assert condition_model.getParameter("parameter_1").getValue() == 1.25 94 | assert condition_model.getParameter("parameter_2").getValue() == 2.25 95 | assert condition_model.getParameter("parameter_3").getValue() == 2.25 96 | 97 | 98 | def test_get_condition_specific_models(): 99 | """Test for petab.sbml.get_condition_specific_models""" 100 | # retrieve test data 101 | ( 102 | ss_model, 103 | condition_df, 104 | observable_df, 105 | measurement_df, 106 | parameter_df, 107 | ) = create_test_data() 108 | 109 | petab_problem = petab.Problem( 110 | model=petab.models.sbml_model.SbmlModel(ss_model.model), 111 | condition_df=condition_df, 112 | observable_df=observable_df, 113 | measurement_df=measurement_df, 114 | parameter_df=parameter_df, 115 | ) 116 | 117 | # create SBML model for condition with parameters updated from problem 118 | with pytest.warns( 119 | UserWarning, 120 | match="An SBML rule was removed to set the " 121 | "component species_2 to a constant value.", 122 | ): 123 | _, condition_model = petab.get_model_for_condition( 124 | petab_problem, "condition_1" 125 | ) 126 | 127 | check_model(condition_model) 128 | 129 | 130 | def test_sbml_model_repr(): 131 | sbml_document = libsbml.SBMLDocument() 132 | sbml_model = sbml_document.createModel() 133 | sbml_model.setId("test") 134 | petab_model = SbmlModel(sbml_model) 135 | assert repr(petab_model) == "" 136 | -------------------------------------------------------------------------------- /tests/v1/test_simplify.py: -------------------------------------------------------------------------------- 1 | """Tests for petab.simplify.*""" 2 | from math import nan 3 | 4 | import pandas as pd 5 | import pytest 6 | import simplesbml 7 | from pandas.testing import * 8 | 9 | from petab import Problem 10 | from petab.C import * # noqa: F403 11 | from petab.models.sbml_model import SbmlModel 12 | from petab.simplify import * 13 | 14 | 15 | @pytest.fixture 16 | def problem() -> Problem: 17 | ss_model = simplesbml.SbmlModel() 18 | ss_model.addParameter("some_parameter", val=1.0) 19 | ss_model.addParameter("same_value_for_all_conditions", val=1.0) 20 | 21 | observable_df = pd.DataFrame( 22 | { 23 | OBSERVABLE_ID: ["obs_used", "obs_unused", "obs_used_2"], 24 | OBSERVABLE_FORMULA: [1.0, 2.0, 3.0], 25 | NOISE_FORMULA: [1.0, 2.0, 3.0], 26 | } 27 | ) 28 | observable_df.set_index(OBSERVABLE_ID, inplace=True) 29 | 30 | conditions_df = pd.DataFrame( 31 | { 32 | CONDITION_ID: [ 33 | "condition_used_1", 34 | "condition_unused", 35 | "condition_used_2", 36 | ], 37 | "some_parameter": [1.0, 2.0, 3.0], 38 | "same_value_for_all_conditions": [4.0] * 3, 39 | } 40 | ) 41 | conditions_df.set_index(CONDITION_ID, inplace=True) 42 | 43 | measurement_df = pd.DataFrame( 44 | { 45 | OBSERVABLE_ID: ["obs_used", "obs_used_2", "obs_used"], 46 | MEASUREMENT: [1.0, 1.5, 2.0], 47 | SIMULATION_CONDITION_ID: [ 48 | "condition_used_1", 49 | "condition_used_1", 50 | "condition_used_2", 51 | ], 52 | TIME: [1.0] * 3, 53 | } 54 | ) 55 | yield Problem( 56 | model=SbmlModel(sbml_model=ss_model.getModel()), 57 | condition_df=conditions_df, 58 | observable_df=observable_df, 59 | measurement_df=measurement_df, 60 | ) 61 | 62 | 63 | def test_remove_nan_measurements(problem): 64 | expected = pd.DataFrame( 65 | { 66 | OBSERVABLE_ID: ["obs_used"] * 2, 67 | MEASUREMENT: [1.0, 2.0], 68 | SIMULATION_CONDITION_ID: ["condition_used_1", "condition_used_2"], 69 | TIME: [1.0] * 2, 70 | } 71 | ) 72 | 73 | problem.measurement_df = pd.DataFrame( 74 | { 75 | OBSERVABLE_ID: ["obs_used", "obs_with_nan", "obs_used"], 76 | MEASUREMENT: [1.0, nan, 2.0], 77 | SIMULATION_CONDITION_ID: [ 78 | "condition_used_1", 79 | "condition_used_1", 80 | "condition_used_2", 81 | ], 82 | TIME: [1.0] * 3, 83 | } 84 | ) 85 | assert not problem.measurement_df.equals(expected) 86 | 87 | remove_nan_measurements(problem) 88 | 89 | assert_frame_equal(problem.measurement_df, expected) 90 | 91 | 92 | def test_remove_unused_observables(problem): 93 | expected = pd.DataFrame( 94 | { 95 | OBSERVABLE_ID: ["obs_used", "obs_used_2"], 96 | OBSERVABLE_FORMULA: [1.0, 3.0], 97 | NOISE_FORMULA: [1.0, 3.0], 98 | } 99 | ) 100 | expected.set_index(OBSERVABLE_ID, inplace=True) 101 | assert not problem.observable_df.equals(expected) 102 | 103 | remove_unused_observables(problem) 104 | 105 | assert_frame_equal(problem.observable_df, expected) 106 | 107 | 108 | def test_remove_unused_conditions(problem): 109 | expected = pd.DataFrame( 110 | { 111 | CONDITION_ID: ["condition_used_1", "condition_used_2"], 112 | "some_parameter": [1.0, 3.0], 113 | "same_value_for_all_conditions": [4.0] * 2, 114 | } 115 | ) 116 | expected.set_index(CONDITION_ID, inplace=True) 117 | assert not problem.condition_df.equals(expected) 118 | 119 | remove_unused_conditions(problem) 120 | 121 | assert_frame_equal(problem.condition_df, expected) 122 | 123 | 124 | def test_condition_parameters_to_parameter_table(problem): 125 | expected_conditions = pd.DataFrame( 126 | { 127 | CONDITION_ID: [ 128 | "condition_used_1", 129 | "condition_unused", 130 | "condition_used_2", 131 | ], 132 | "some_parameter": [1.0, 2.0, 3.0], 133 | } 134 | ) 135 | expected_conditions.set_index(CONDITION_ID, inplace=True) 136 | assert not problem.condition_df.equals(expected_conditions) 137 | 138 | expected_parameters = pd.DataFrame( 139 | { 140 | PARAMETER_ID: ["same_value_for_all_conditions"], 141 | PARAMETER_SCALE: [LIN], 142 | LOWER_BOUND: [nan], 143 | UPPER_BOUND: [nan], 144 | NOMINAL_VALUE: [4.0], 145 | ESTIMATE: [0], 146 | } 147 | ) 148 | expected_parameters.set_index(PARAMETER_ID, inplace=True) 149 | assert problem.parameter_df is None 150 | 151 | condition_parameters_to_parameter_table(problem) 152 | 153 | assert_frame_equal(problem.condition_df, expected_conditions) 154 | assert_frame_equal(problem.parameter_df, expected_parameters) 155 | 156 | 157 | def test_simplify_problem(problem): 158 | # simplify_problem checks whether the result is valid 159 | simplify_problem(problem) 160 | -------------------------------------------------------------------------------- /tests/v1/test_visualization_data_overview.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from tempfile import TemporaryDirectory 3 | 4 | import petab 5 | from petab.visualize.data_overview import create_report 6 | 7 | 8 | def test_data_overview(): 9 | """Data overview generation with Fujita example data from this 10 | repository""" 11 | with TemporaryDirectory() as temp_dir: 12 | outfile = Path(temp_dir) / "Fujita.html" 13 | repo_root = Path(__file__).parents[2] 14 | yaml_filename = ( 15 | repo_root / "doc" / "example" / "example_Fujita" / "Fujita.yaml" 16 | ) 17 | problem = petab.Problem.from_yaml(yaml_filename) 18 | create_report(problem, "Fujita", output_path=temp_dir) 19 | assert outfile.is_file() 20 | -------------------------------------------------------------------------------- /tests/v1/test_yaml.py: -------------------------------------------------------------------------------- 1 | """Test for petab.yaml""" 2 | import tempfile 3 | from pathlib import Path 4 | 5 | import pytest 6 | from jsonschema.exceptions import ValidationError 7 | 8 | from petab.yaml import create_problem_yaml, get_path_prefix, validate 9 | 10 | 11 | def test_validate(): 12 | data = {"format_version": "1"} 13 | 14 | # should fail because we miss some information 15 | with pytest.raises(ValidationError): 16 | validate(data) 17 | 18 | # should be well-formed 19 | file_ = ( 20 | Path(__file__).parents[2] 21 | / "doc" 22 | / "example" 23 | / "example_Fujita" 24 | / "Fujita.yaml" 25 | ) 26 | validate(file_) 27 | 28 | 29 | def test_create_problem_yaml(): 30 | with tempfile.TemporaryDirectory() as outdir: 31 | # test with single problem files 32 | # create target files 33 | sbml_file = Path(outdir, "model.xml") 34 | condition_file = Path(outdir, "conditions.tsv") 35 | measurement_file = Path(outdir, "measurements.tsv") 36 | parameter_file = Path(outdir, "parameters.tsv") 37 | observable_file = Path(outdir, "observables.tsv") 38 | yaml_file = Path(outdir, "problem.yaml") 39 | visualization_file = Path(outdir, "visualization.tsv") 40 | 41 | _create_dummy_sbml_model(sbml_file) 42 | 43 | for file in ( 44 | condition_file, 45 | measurement_file, 46 | parameter_file, 47 | observable_file, 48 | visualization_file, 49 | ): 50 | file.touch() 51 | create_problem_yaml( 52 | sbml_file, 53 | condition_file, 54 | measurement_file, 55 | parameter_file, 56 | observable_file, 57 | yaml_file, 58 | visualization_file, 59 | ) 60 | validate(yaml_file) 61 | 62 | # test for list of files 63 | # create additional target files 64 | sbml_file2 = Path(outdir, "model2.xml") 65 | condition_file2 = Path(outdir, "conditions2.tsv") 66 | measurement_file2 = Path(outdir, "measurements2.tsv") 67 | observable_file2 = Path(outdir, "observables2.tsv") 68 | yaml_file2 = Path(outdir, "problem2.yaml") 69 | for file in ( 70 | condition_file2, 71 | measurement_file2, 72 | observable_file2, 73 | ): 74 | file.touch() 75 | 76 | _create_dummy_sbml_model(sbml_file2) 77 | 78 | sbml_files = [sbml_file, sbml_file2] 79 | condition_files = [condition_file, condition_file2] 80 | measurement_files = [measurement_file, measurement_file2] 81 | observable_files = [observable_file, observable_file2] 82 | create_problem_yaml( 83 | sbml_files, 84 | condition_files, 85 | measurement_files, 86 | parameter_file, 87 | observable_files, 88 | yaml_file2, 89 | ) 90 | validate(yaml_file2) 91 | 92 | 93 | def test_get_path_prefix(): 94 | assert get_path_prefix("/some/dir/file.yaml") == str(Path("/some/dir")) 95 | assert get_path_prefix("some/dir/file.yaml") == str(Path("some/dir")) 96 | assert ( 97 | get_path_prefix("https://petab.rocks/dir/file.yaml") 98 | == "https://petab.rocks/dir" 99 | ) 100 | 101 | 102 | def test_validate_remote(): 103 | yaml_url = ( 104 | "https://raw.githubusercontent.com/PEtab-dev/petab_test_suite" 105 | "/main/petabtests/cases/v1.0.0/sbml/0001/_0001.yaml" 106 | ) 107 | 108 | validate(yaml_url) 109 | 110 | 111 | def _create_dummy_sbml_model(sbml_file: Path | str): 112 | import libsbml 113 | 114 | sbml_doc = libsbml.SBMLDocument() 115 | sbml_doc.createModel() 116 | libsbml.writeSBMLToFile(sbml_doc, str(sbml_file)) 117 | -------------------------------------------------------------------------------- /tests/v2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PEtab-dev/libpetab-python/99373c4340512def5a23bf2a75805c3f88251251/tests/v2/__init__.py -------------------------------------------------------------------------------- /tests/v2/test_conversion.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import tempfile 3 | 4 | from petab.v2.petab1to2 import petab1to2 5 | 6 | 7 | def test_petab1to2_remote(): 8 | yaml_url = ( 9 | "https://raw.githubusercontent.com/PEtab-dev/petab_test_suite" 10 | "/main/petabtests/cases/v1.0.0/sbml/0001/_0001.yaml" 11 | ) 12 | 13 | with tempfile.TemporaryDirectory(prefix="test_petab1to2") as tmpdirname: 14 | # TODO verify that the v2 files match "ground truth" 15 | # in `petabtests/cases/v2.0.0/sbml/0001/_0001.yaml` 16 | petab1to2(yaml_url, tmpdirname) 17 | 18 | 19 | def test_benchmark_collection(): 20 | """Test that we can upgrade all benchmark collection models.""" 21 | import benchmark_models_petab 22 | 23 | logging.basicConfig(level=logging.DEBUG) 24 | 25 | for problem_id in benchmark_models_petab.MODELS: 26 | if problem_id == "Lang_PLOSComputBiol2024": 27 | # Does not pass initial linting 28 | continue 29 | 30 | yaml_path = benchmark_models_petab.get_problem_yaml_path(problem_id) 31 | with tempfile.TemporaryDirectory( 32 | prefix=f"test_petab1to2_{problem_id}" 33 | ) as tmpdirname: 34 | petab1to2(yaml_path, tmpdirname) 35 | -------------------------------------------------------------------------------- /tests/v2/test_problem.py: -------------------------------------------------------------------------------- 1 | from petab.v2 import Problem 2 | 3 | 4 | def test_load_remote(): 5 | """Test loading remote files""" 6 | yaml_url = ( 7 | "https://raw.githubusercontent.com/PEtab-dev/petab_test_suite" 8 | "/main/petabtests/cases/v2.0.0/sbml/0001/_0001.yaml" 9 | ) 10 | petab_problem = Problem.from_yaml(yaml_url) 11 | 12 | assert ( 13 | petab_problem.measurement_df is not None 14 | and not petab_problem.measurement_df.empty 15 | ) 16 | 17 | assert petab_problem.validate() == [] 18 | 19 | 20 | def test_auto_upgrade(): 21 | yaml_url = ( 22 | "https://raw.githubusercontent.com/PEtab-dev/petab_test_suite" 23 | "/main/petabtests/cases/v1.0.0/sbml/0001/_0001.yaml" 24 | ) 25 | problem = Problem.from_yaml(yaml_url) 26 | # TODO check something specifically different in a v2 problem 27 | assert isinstance(problem, Problem) 28 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = quality,unit 3 | isolated_build = True 4 | 5 | [testenv] 6 | 7 | [testenv:quality] 8 | extras = quality 9 | commands = 10 | pre-commit run --all-files 11 | description = 12 | Quality tests 13 | 14 | [testenv:unit] 15 | extras = tests,reports,combine,vis 16 | deps= 17 | git+https://github.com/PEtab-dev/petab_test_suite@main 18 | git+https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab.git@master\#subdirectory=src/python 19 | 20 | commands = 21 | python -m pip install sympy>=1.12.1 22 | python -m pytest --cov=petab --cov-report=xml --cov-append \ 23 | tests 24 | description = 25 | Basic tests 26 | --------------------------------------------------------------------------------