diff --git a/.github/workflows/simulate.yml b/.github/workflows/simulate.yml new file mode 100644 index 0000000..2ae1397 --- /dev/null +++ b/.github/workflows/simulate.yml @@ -0,0 +1,41 @@ +name: Simulate +on: + push: + branches: + - master + workflow_dispatch: + merge_group: + schedule: + - cron: '0 0 * * *' + +jobs: + simulate_amici: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v5 + + - name: Prepare Python + uses: actions/setup-python@v6 + with: + python-version: "3.13" + + - name: Install AMICI + env: + AMICI_PARALLEL_COMPILE: "" + run: | + pip install --upgrade pip + # TODO: once amici 1.0 is released, replace with: + # pip install amici[petab] + pip install petab + pip install "git+https://github.com/dweindl/amici.git@6a85422ad233fc268fb71272bba39f5b82db387a#egg=amici&subdirectory=python/sdist" + + - name: Simulate with nominal parameters + env: + AMICI_PARALLEL_COMPILE: "" + run: | + for problem in `ls -1 Benchmark-Models/`; do + python src/python/simulate.py "$problem" -j + echo + echo + done diff --git a/src/python/simulate.py b/src/python/simulate.py new file mode 100755 index 0000000..e867a20 --- /dev/null +++ b/src/python/simulate.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +""" +Script to simulate a model using AMICI. + +Basic usage: simulate.py +See --help for more options. +""" + +import os +import argparse +import benchmark_models_petab +import amici.sim.sundials as ass +from amici.importers.petab.v1 import ( + import_petab_problem, + simulate_petab, + LLH, + RDATAS, +) +import logging +from petab.v1.lint import measurement_table_has_timepoint_specific_mappings +from petab.v1.core import flatten_timepoint_specific_output_overrides + + +def parse_cli_args(): + """Parse command line arguments.""" + parser = argparse.ArgumentParser( + description="Simulate a model using AMICI." + ) + parser.add_argument( + "problem_id", + type=str, + help="Identifier for the problem/model to simulate.", + ) + parser.add_argument( + "-j", + dest="num_threads", + nargs="?", + default=None, + const="all", + help=( + "Number of cores to use. " + "`-j` (no value) uses all available cores. " + "If omitted, threading is left unchanged." + ), + ) + args = parser.parse_args() + + args.num_threads = ( + os.cpu_count() + if args.num_threads == "all" + else 1 + if args.num_threads is None + else max(1, int(args.num_threads)) + ) + + return args + + +def main(): + """Simulate a PEtab problem with AMICI using nominal parameter values.""" + args = parse_cli_args() + + # Import and simulate + print(args.problem_id) + print("-" * len(args.problem_id), flush=True) + + problem = benchmark_models_petab.get_problem(args.problem_id) + + if measurement_table_has_timepoint_specific_mappings( + problem.measurement_df, + ): + flatten_timepoint_specific_output_overrides(problem) + + model = import_petab_problem( + problem, generate_sensitivity_code=False, verbose=logging.INFO + ) + solver = model.create_solver() + solver.set_return_data_reporting_mode( + ass.RDataReporting.observables_likelihood + ) + res = simulate_petab( + problem, model, solver=solver, num_threads=args.num_threads + ) + + for rdata in res[RDATAS]: + print( + f"{rdata.id}: llh = {rdata.llh}, chi2 = {rdata.chi2}, status = {rdata.status}" + ) + + print() + print("Total log-likelihood:", res[LLH]) + print() + + +if __name__ == "__main__": + main()