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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# see https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners

# default owners = active maintainers
* @Doresic @PaulJonasJost @vwiela
* @Doresic @PaulJonasJost @MoR1chter

# Examples
/doc/example/censored_data.ipynb @Doresic
Expand Down Expand Up @@ -35,22 +35,22 @@
/pypesto/optimize/ @PaulJonasJost
/pypesto/petab/ @dweindl @FFroehlich
/pypesto/predict/ @dilpath
/pypesto/problem/ @PaulJonasJost @vwiela
/pypesto/problem/ @PaulJonasJost @MoR1chter
/pypesto/profile/ @PaulJonasJost @Doresic
/pypesto/result/ @PaulJonasJost
/pypesto/sample/ @dilpath @arrjon
/pypesto/sample/ @dilpath @arrjon @vwiela
/pypesto/select/ @dilpath
/pypesto/startpoint/ @PaulJonasJost
/pypesto/store/ @PaulJonasJost
/pypesto/visualize/ @stephanmg
/pypesto/visualize/ @Doresic

# Tests
/test/base/ @PaulJonasJost @vwiela
/test/base/ @PaulJonasJost @MoR1chter
/test/doc/ @PaulJonasJost
/test/hierarchical/ @dweindl @Doresic
/test/julia/ @PaulJonasJost @vwiela
/test/optimize/ @PaulJonasJost
/test/petab/ @dweindl @FFroehlich
/test/profile/ @PaulJonasJost @Doresic
/test/sample/ @dilpath @arrjon
/test/sample/ @dilpath @arrjon @vwiela
/test/select/ @dilpath
29 changes: 7 additions & 22 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
CXX: clang++

- name: Coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
Expand Down Expand Up @@ -91,7 +91,7 @@ jobs:
run: ulimit -n 65536 65536 && tox -e base

- name: Coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
Expand Down Expand Up @@ -163,7 +163,7 @@ jobs:
CXX: clang++

- name: Coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
Expand All @@ -174,11 +174,6 @@ jobs:
matrix:
python-version: ['3.11', '3.13']

# needed to allow julia-actions/cache to delete old caches that it has created
permissions:
actions: write
contents: read

steps:
- name: Check out repository
uses: actions/checkout@v6
Expand All @@ -196,25 +191,15 @@ jobs:
.tox/
key: "${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-ci-${{ github.job }}"

- name: Install julia
uses: julia-actions/setup-julia@v2
with:
version: 1.11

- name: Install dependencies
run: .github/workflows/install_deps.sh

- name: Install PEtabJL dependencies
run: >
julia -e 'using Pkg; Pkg.add("PEtab");
Pkg.add("OrdinaryDiffEq"); Pkg.add("Sundials")'

- name: Run tests
timeout-minutes: 25
run: tox -e julia

- name: Coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
Expand Down Expand Up @@ -250,7 +235,7 @@ jobs:
run: tox -e optimize

- name: Coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
Expand Down Expand Up @@ -286,7 +271,7 @@ jobs:
run: tox -e hierarchical

- name: Coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
Expand Down Expand Up @@ -322,7 +307,7 @@ jobs:
run: tox -e select

- name: Coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
Expand Down
24 changes: 15 additions & 9 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ jobs:
matrix:
python-version: ['3.12']

environment:
name: PyPI
url: https://pypi.org/p/pypesto

permissions:
id-token: write

steps:
- name: Check out repository
uses: actions/checkout@v6
Expand All @@ -25,15 +32,14 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
- name: dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
python -m pip install -U build

- name: Build and publish
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
- name: Build distribution
run:
python -m build

- name: Publish a Python distribution to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
26 changes: 22 additions & 4 deletions doc/example/getting_started.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@
"name": "#%% md\n"
}
},
"source": "Define lower and upper parameter bounds and create an optimization problem."
"source": [
"Define lower and upper parameter bounds and create an optimization problem."
]
},
{
"cell_type": "code",
Expand Down Expand Up @@ -632,7 +634,7 @@
"outputs": [],
"source": [
"# adapt x_labels.\n",
"x_labels = [f\"Log10({name})\" for name in problem.x_names]\n",
"x_labels = [f\"Log({name})\" for name in problem.x_names]\n",
"\n",
"ax = visualize.profiles(result, x_labels=x_labels, show_bounds=True)\n",
"# visualize optimal parameter values\n",
Expand All @@ -650,6 +652,22 @@
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The 2D profile visualization shows joint parameter paths across all profile pairs. Diagonal plots show 1D profiles (likelihood ratio vs. parameter value). Off-diagonal plots show how each non-profiled parameter moves while another is profiled, with color indicating the likelihood ratio.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig, axes = pypesto.visualize.visualize_2d_profile(result)"
]
},
{
"cell_type": "markdown",
"metadata": {
Expand All @@ -675,7 +693,7 @@
" result, confidence_level=0.95, show_bounds=True\n",
")\n",
"\n",
"ax.set_xlabel(\"Log10(Parameter value)\");"
"ax.set_xlabel(\"Log(Parameter value)\");"
]
},
{
Expand All @@ -695,7 +713,7 @@
" result, confidence_levels=[0.99, 0.95, 0.9]\n",
")\n",
"\n",
"ax.set_xlabel(\"Log10(Parameter value)\");"
"ax.set_xlabel(\"Log(Parameter value)\");"
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion pypesto/hierarchical/inner_calculator_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ def __call__(
"Cannot use least squares solver with"
"parameter dependent sigma! Support can be "
"enabled via "
"amici_model.setAddSigmaResiduals()."
"amici_model.set_add_sigma_residuals()."
)
self._known_least_squares_safe = True # don't check this again

Expand Down
2 changes: 1 addition & 1 deletion pypesto/hierarchical/ordinal/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ def calculate_gradients(
par_sim_ids:
Ids of outer simulation parameters, includes fixed parameters.
par_edata_indices:
Indices of parameters from `amici_model.getParameterIds()` that are needed for
Indices of parameters from `amici_model.get_free_parameter_ids()` that are needed for
sensitivity calculation. Comes from `edata.plist` for each condition.
snllh:
A zero-initialized vector of the same length as ``par_opt_ids`` to store the
Expand Down
2 changes: 1 addition & 1 deletion pypesto/objective/amici/amici.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def __init__(
derivatives.
amici_reporting:
Determines which quantities will be computed by AMICI,
see ``amici.Solver.setReturnDataReportingMode``. Set to ``None``
see ``amici.Solver.set_return_data_reporting_mode``. Set to ``None``
to compute only the minimum required information.
"""
import amici
Expand Down
2 changes: 1 addition & 1 deletion pypesto/objective/amici/amici_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def __call__(
"Cannot use least squares solver with"
"parameter dependent sigma! Support can be "
"enabled via "
"amici_model.setAddSigmaResiduals()."
"amici_model.set_add_sigma_residuals()."
)
self._known_least_squares_safe = True # don't check this again

Expand Down
66 changes: 23 additions & 43 deletions pypesto/objective/julia/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
"""Interface to Julia via pyjulia."""
"""Interface to Julia via juliacall."""

from collections.abc import Callable

# Import juliacall early to avoid conflicts with other libraries (especially numpy)
# See: https://juliapy.github.io/PythonCall.jl/dev/faq/
try:
from juliacall import Main as jl # noqa: F401
except ImportError:
jl = None

import numpy as np

from ..function import Objective
Expand All @@ -27,10 +34,10 @@ def _read_source(module_name: str, source_file: str) -> None:
module_name: Julia module name.
source_file: Qualified Julia source file.
"""
from julia import Main
from juliacall import Main as jl

if not hasattr(Main, module_name):
Main.include(source_file)
if not hasattr(jl, module_name):
jl.include(source_file)


class JuliaObjective(Objective):
Expand All @@ -40,45 +47,18 @@ class JuliaObjective(Objective):
It expects the corresponding Julia objects to be defined in a
`source_file` within a `module`.

We use the PyJulia package to access Julia from inside Python.
It can be installed via `pip install pypesto[julia]`, however requires
additional Julia dependencies to be installed via:
We use the juliacall package (part of PythonCall.jl) to access Julia
from inside Python. It can be installed via `pip install pypesto[julia]`.

>>> python -c "import julia; julia.install()"
juliacall automatically manages the Julia installation and configuration,
so no additional setup steps are required beyond pip installation.

For further information, see
https://pyjulia.readthedocs.io/en/latest/installation.html.

There are some known problems, e.g. with statically linked Python
interpreters, see
https://pyjulia.readthedocs.io/en/latest/troubleshooting.html
for details.
Possible solutions are to pass ``compiled_modules=False`` to the Julia
constructor early in your code:

>>> from julia.api import Julia
>>> jl = Julia(compiled_modules=False)

This however slows down loading and using Julia packages, especially for
large ones.
An alternative is to use the ``python-jl`` command shipped with PyJulia:

>>> python-jl MY_SCRIPT.py

This basically launches a Python interpreter inside Julia.
When using Jupyter notebooks, this wrapper can be installed as an
additional kernel via:

>>> python -m ipykernel install --name python-jl [--prefix=/path/to/python/env]

And changing the first argument in
``/path/to/python/env/share/jupyter/kernels/python-jl/kernel.json``
to ``python-jl``.
https://juliapy.github.io/PythonCall.jl/stable/juliacall/

Model simulations are eagerly converted to Python objects
(specifically, `numpy.ndarray` and `pandas.DataFrame`).
This can introduce overhead and could be avoided by an alternative
lazy implementation.
Model simulations are efficiently handled with minimal overhead.
By default, juliacall wraps mutable objects instead of copying them,
providing better performance than PyJulia.

Parameters
----------
Expand All @@ -103,10 +83,10 @@ def __init__(
):
# lazy imports
try:
from julia import Main # noqa: F401
from juliacall import Main as jl # noqa: F401
except ImportError:
raise ImportError(
"Install PyJulia, e.g. via `pip install pypesto[julia]`, "
"Install juliacall, e.g. via `pip install pypesto[julia]`, "
"and see the class documentation",
) from None

Expand All @@ -133,10 +113,10 @@ def get(self, name: str, as_array: bool = False) -> Callable | None:

Use this function to access any variable from the Julia module.
"""
from julia import Main
from juliacall import Main as jl

if name is not None:
ret = getattr(getattr(Main, self.module), name, None)
ret = getattr(getattr(jl, self.module), name, None)
if as_array:
ret = _as_array(ret)
return ret
Expand Down
Loading
Loading