diff --git a/.github/workflows/test_petab_test_suite.yml b/.github/workflows/test_petab_test_suite.yml index 6301269e03..b6465d554b 100644 --- a/.github/workflows/test_petab_test_suite.yml +++ b/.github/workflows/test_petab_test_suite.yml @@ -57,7 +57,7 @@ jobs: - name: Install petab run: | - source ./build/venv/bin/activate \ + source ./venv/bin/activate \ && pip3 install wheel pytest shyaml pytest-cov pysb # retrieve test models @@ -65,19 +65,19 @@ jobs: run: | git clone --depth 1 --branch main \ https://github.com/PEtab-dev/petab_test_suite \ - && source ./build/venv/bin/activate \ + && source ./venv/bin/activate \ && cd petab_test_suite && pip3 install -e . - name: Run PEtab-related unit tests run: | - source ./build/venv/bin/activate \ + source ./venv/bin/activate \ && pytest --cov-report=xml:coverage.xml \ --cov=./ python/tests/test_*petab*.py python/tests/petab/ # run test models - name: Run PEtab test suite run: | - source ./build/venv/bin/activate \ + source ./venv/bin/activate \ && AMICI_PARALLEL_COMPILE="" pytest -v \ --cov-report=xml:coverage.xml \ --cov-append \ diff --git a/.github/workflows/test_python_cplusplus.yml b/.github/workflows/test_python_cplusplus.yml index 58dd5480e5..f729d47867 100644 --- a/.github/workflows/test_python_cplusplus.yml +++ b/.github/workflows/test_python_cplusplus.yml @@ -45,11 +45,11 @@ jobs: run: scripts/installAmiciSource.sh - name: Check OpenMP support - run: source build/venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" + run: source venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" - name: Python tests (part 1) run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && pytest \ --ignore-glob=*petab* \ --ignore-glob=*test_splines.py \ @@ -64,7 +64,7 @@ jobs: - name: Python tests splines if: ${{ github.base_ref == 'master' || github.event.merge_group.base_ref == 'master'}} run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && pytest \ --cov=amici \ --cov-report=xml:"${AMICI_DIR}/build/coverage_py.xml" \ @@ -138,7 +138,7 @@ jobs: - name: Python tests run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && pytest \ --cov=amici \ --cov-report=xml:"${AMICI_DIR}/build/coverage_py.xml" \ @@ -214,7 +214,7 @@ jobs: - name: Install notebook dependencies run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && pip install jax[cpu] - name: example notebooks @@ -251,7 +251,7 @@ jobs: run: scripts/installAmiciSource.sh - name: Check OpenMP support - run: source build/venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" + run: source venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" - name: cppcheck run: scripts/run-cppcheck.sh @@ -296,7 +296,7 @@ jobs: scripts/installAmiciSource.sh - name: Check OpenMP support - run: source build/venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" + run: source venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" - name: Get BioNetGen run: scripts/buildBNGL.sh diff --git a/.github/workflows/test_python_ver_matrix.yml b/.github/workflows/test_python_ver_matrix.yml index 5f9d96d295..414daadccc 100644 --- a/.github/workflows/test_python_ver_matrix.yml +++ b/.github/workflows/test_python_ver_matrix.yml @@ -50,20 +50,16 @@ jobs: - name: Install python package run: scripts/installAmiciSource.sh - # until https://github.com/dateutil/dateutil >2.8.2 is released https://github.com/dateutil/dateutil/issues/1314 - - run: source build/venv/bin/activate && pip3 install git+https://github.com/dateutil/dateutil.git@296d419fe6bf3b22897f8f210735ac9c4e1cb796 - if: matrix.python-version == '3.12' - # install pysb before sympy to allow for sympy>=1.12 (https://github.com/pysb/pysb/commit/e83937cb8c74afc9b2fa96595b68464946745f33) - - run: source build/venv/bin/activate && pip3 install git+https://github.com/pysb/pysb + - run: source venv/bin/activate && pip3 install git+https://github.com/pysb/pysb # until sympy>1.12 is released - - run: source build/venv/bin/activate && pip3 install git+https://github.com/sympy/sympy.git@master + - run: source venv/bin/activate && pip3 install git+https://github.com/sympy/sympy.git@master if: matrix.python-version == '3.12' - name: Python tests run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && python3 -m pytest \ --durations=10 \ --ignore-glob=*petab* \ diff --git a/.gitignore b/.gitignore index 60b9ff5031..4dc2884415 100644 --- a/.gitignore +++ b/.gitignore @@ -202,3 +202,4 @@ CS_Signalling_ERBB_RAS_AKT/ cache_fiddy/* debug/* tests/benchmark-models/cache_fiddy/* +venv/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c1fd68c5c..7052c85b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,81 @@ ## v0.X Series +### v0.23.1 (2024-03-11) + +* Fixes installation issues related to building SuiteSparse on some systems + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2375 + +### v0.23.0 (2024-03-07) + +**Features** + +* SBML `InitialAssignment` are no longer absorbed into other model expressions, + but are available as parameters or expressions (`w`) in the amici model + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2304, + https://github.com/AMICI-dev/AMICI/pull/2305, + https://github.com/AMICI-dev/AMICI/pull/2345, + https://github.com/AMICI-dev/AMICI/pull/2359 +* Upgraded to SuiteSparse 7.6 + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2316 +* Model expressions `w` are now split into static and dynamic expressions, + and only evaluated as needed + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2303 +* Exposed additional solver settings: + * `Solver.setMaxConvFails()`: maximum number of non-linear solver + convergence failures + * `Solver.setMaxNonlinIters()`: maximum number of non-linear solver + iterations + * `Solver.setMaxStepSize()`: maximum step size + * `Solver.setConstraints()`: for setting (non)negativity/positivity + constraints on state variables + + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2335, + https://github.com/AMICI-dev/AMICI/pull/2360, + https://github.com/AMICI-dev/AMICI/pull/2340 +* Improved output for debugging simulation failures: + `ReturnData.{xdot,J}` now contain the respective + values from the timepoint of failure, not the last output timepoint. + NaN/Inf warnings now always include the timepoint at which the issue + occurred. Note that C++ stacktraces are now only logged for debug builds. + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2349, + https://github.com/AMICI-dev/AMICI/pull/2347, + https://github.com/AMICI-dev/AMICI/pull/2366 +* Updated dataframes import/export to include parameter values and scales + by @FFroehlich in https://github.com/AMICI-dev/AMICI/pull/2351 + +**Fixes** + +* CMake: Updated BLAS detection and some minor fixes + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2318 + and https://github.com/AMICI-dev/AMICI/pull/2357 +* Deterministic ordering of source files in generated `CMakeLists.txt` + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2322 +* Fixed size check in `Model::setStateIsNonNegative` + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2332 +* Fixed uncaught C++ exception in `runAmiciSimulation` that may crash Python + in case of invalid values for standard deviations + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2338 +* Fixed missing import in `amici/petab/petab_import.py` + by @plakrisenko in https://github.com/AMICI-dev/AMICI/pull/2342 +* Fixed `ReturnDataView` `AttributeError: messages` + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2341 +* Added a missing return code constant `LSETUP_FAIL` + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2353 +* Fixed in-place building of model wheels + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2352 +* Made is-zero-checks compatible with the upcoming sympy>1.12 + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2350 +* Fixed issues with paths containing blanks for sundials + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2361 +* Added `amici.petab.conditions` to the API documentation + by @PaulJonasJost in https://github.com/AMICI-dev/AMICI/pull/2364 +* Improved type annotations in swig-wrappers + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2344, + https://github.com/AMICI-dev/AMICI/pull/2365 + +**Full Changelog**: https://github.com/AMICI-dev/AMICI/compare/v0.22.0...v0.23.0 + ### v0.22.0 (2024-02-23) **Features** diff --git a/CMakeLists.txt b/CMakeLists.txt index 324426f2a7..d8a1109d90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,7 @@ endif() # find dependencies include(GNUInstallDirs) +include(AmiciFindBLAS) find_package(OpenMP) find_package(Boost COMPONENTS chrono) @@ -132,9 +133,16 @@ elseif(AMICI_TRY_ENABLE_HDF5) endif() set(VENDORED_SUNDIALS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ThirdParty/sundials) -set(VENDORED_SUNDIALS_BUILD_DIR ${VENDORED_SUNDIALS_DIR}/build) -set(VENDORED_SUNDIALS_INSTALL_DIR ${VENDORED_SUNDIALS_BUILD_DIR}) set(SUNDIALS_PRIVATE_INCLUDE_DIRS "${VENDORED_SUNDIALS_DIR}/src") +# Handle different sundials build/install dirs, depending on whether we are +# building the Python extension only or the full C++ interface +if(AMICI_PYTHON_BUILD_EXT_ONLY) + set(VENDORED_SUNDIALS_BUILD_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + set(VENDORED_SUNDIALS_INSTALL_DIR ${VENDORED_SUNDIALS_BUILD_DIR}) +else() + set(VENDORED_SUNDIALS_BUILD_DIR ${VENDORED_SUNDIALS_DIR}/build) + set(VENDORED_SUNDIALS_INSTALL_DIR ${VENDORED_SUNDIALS_BUILD_DIR}) +endif() find_package( SUNDIALS REQUIRED PATHS "${VENDORED_SUNDIALS_INSTALL_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/sundials/") @@ -142,75 +150,6 @@ message(STATUS "Found SUNDIALS: ${SUNDIALS_DIR}") set(GSL_LITE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ThirdParty/gsl") -# AMICI requires BLAS, currently Intel MKL, CBLAS or MATLAB BLAS can be used. -# The latter is not supported via CMake yet. -set(BLAS - "CBLAS" - CACHE STRING "BLAS library to use") -set_property(CACHE BLAS PROPERTY STRINGS "CBLAS" "MKL" "ACCELERATE") -if(${BLAS} STREQUAL "MKL" OR DEFINED ENV{MKLROOT}) - if(DEFINED ENV{MKLROOT}) - # This is set by Environment Modules - message(STATUS "Using MKL_INCDIR and MKL_LIB from environment module") - set(BLAS - "MKL" - CACHE STRING "BLAS library to use" FORCE) - set(BLAS_INCLUDE_DIRS - "$ENV{MKL_INCDIR}" - CACHE STRING "" FORCE) - set(BLAS_LIBRARIES - "$ENV{MKL_LIB}" - CACHE STRING "" FORCE) - else() - set(BLAS_INCLUDE_DIRS - "" - CACHE STRING "") - set(BLAS_LIBRARIES - -lmkl - CACHE STRING "") - endif() -elseif( - NOT DEFINED ENV{BLAS_LIBS} - AND NOT DEFINED ENV{BLAS_CFLAGS} - AND NOT BLAS_FOUND) - # if nothing is specified via environment variables, let's try FindBLAS - if($(CMAKE_VERSION) VERSION_GREATER_EQUAL 3.22) - set(BLA_SIZEOF_INTEGER 8) - endif() - - if(APPLE AND (NOT DEFINED BLA_VENDOR OR BLA_VENDOR STREQUAL "All")) - set(BLA_VENDOR Apple) - find_package(BLAS) - if(BLAS_FOUND) - set_property( - TARGET BLAS::BLAS - APPEND - PROPERTY INTERFACE_COMPILE_DEFINITIONS ACCELERATE_NEW_LAPACK) - set_property( - TARGET BLAS::BLAS - APPEND - PROPERTY INTERFACE_COMPILE_DEFINITIONS ACCELERATE_LAPACK_ILP64) - else() - set(BLA_VENDOR "All") - endif() - - endif() - if(NOT BLAS_FOUND) - find_package(BLAS) - endif() - if(NOT BLAS_FOUND) - # Nothing specified by the user and FindBLAS didn't find anything; let's try - # if cblas is available on the system paths. - set(BLAS_INCLUDE_DIRS - "" - CACHE STRING "") - set(BLAS_LIBRARIES - -lcblas - CACHE STRING "") - endif() -endif() -add_compile_definitions(AMICI_BLAS_${BLAS}) - # Add target to create version file add_custom_target( version @@ -285,16 +224,6 @@ set(AMICI_SRC_LIST add_library(${PROJECT_NAME} ${AMICI_SRC_LIST}) -# legacy python package environment variables: -if(DEFINED ENV{BLAS_CFLAGS}) - target_compile_options(${PROJECT_NAME} PRIVATE "$ENV{BLAS_CFLAGS}") -endif() -if(DEFINED ENV{BLAS_LIBS}) - # Note that, on Windows, at least for ninja, this will only work with dashes - # instead of slashes in any linker options - target_link_libraries(${PROJECT_NAME} PUBLIC "$ENV{BLAS_LIBS}") -endif() - set(AMICI_CXX_OPTIONS "" CACHE STRING "C++ options for libamici (semicolon-separated)") @@ -315,10 +244,6 @@ target_include_directories( $ PRIVATE ${SUNDIALS_PRIVATE_INCLUDE_DIRS}) -if(NOT "${BLAS_INCLUDE_DIRS}" STREQUAL "") - target_include_directories(${PROJECT_NAME} PUBLIC ${BLAS_INCLUDE_DIRS}) -endif() - if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}" OR CMAKE_BUILD_TYPE MATCHES "Debug") @@ -354,11 +279,11 @@ target_link_libraries( SUNDIALS::sunnonlinsolfixedpoint_static SUNDIALS::cvodes_static SUNDIALS::idas_static - ${BLAS_LIBRARIES} $<$:Boost::chrono> $<$:OpenMP::OpenMP_CXX> ${CMAKE_DL_LIBS} PRIVATE + BLAS::BLAS $<$:SUNDIALS::sundials_sunlinsolsuperlumt> ) @@ -457,9 +382,11 @@ install( EXPORT AmiciTargets DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Amici" NAMESPACE Upstream::) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/AmiciConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/AmiciConfigVersion.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Amici) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/AmiciConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/AmiciConfigVersion.cmake + ${CMAKE_CURRENT_LIST_DIR}/cmake/AmiciFindBLAS.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Amici) install(DIRECTORY ThirdParty/gsl/gsl TYPE INCLUDE) # When running from setup.py, this is a symlink we need to dereference @@ -467,6 +394,9 @@ get_filename_component(_swig_realpath "swig" REALPATH) install(DIRECTORY "${_swig_realpath}" DESTINATION ${CMAKE_INSTALL_DATADIR}/amici) +configure_file(cmake/AmiciFindBLAS.cmake + ${CMAKE_CURRENT_BINARY_DIR}/AmiciFindBLAS.cmake COPYONLY) + # Register package? if(EXPORT_PACKAGE) export(PACKAGE Amici) diff --git a/ThirdParty/sundials/CMakeLists.txt b/ThirdParty/sundials/CMakeLists.txt index f535def9d0..e23332cf31 100644 --- a/ThirdParty/sundials/CMakeLists.txt +++ b/ThirdParty/sundials/CMakeLists.txt @@ -27,9 +27,9 @@ project(SUNDIALS C) # Specify the location of additional CMAKE modules set(CMAKE_MODULE_PATH - ${PROJECT_SOURCE_DIR}/cmake - ${PROJECT_SOURCE_DIR}/cmake/macros - ${PROJECT_SOURCE_DIR}/cmake/tpl + "${PROJECT_SOURCE_DIR}/cmake" + "${PROJECT_SOURCE_DIR}/cmake/macros" + "${PROJECT_SOURCE_DIR}/cmake/tpl" ) # MACRO definitions diff --git a/ThirdParty/sundials/cmake/tpl/FindKLU.cmake b/ThirdParty/sundials/cmake/tpl/FindKLU.cmake index 9e25883c4f..98465aa180 100644 --- a/ThirdParty/sundials/cmake/tpl/FindKLU.cmake +++ b/ThirdParty/sundials/cmake/tpl/FindKLU.cmake @@ -101,7 +101,7 @@ if (NOT SUITESPARSECONFIG_LIBRARY) mark_as_advanced(SUITESPARSECONFIG_LIBRARY) endif () -set(KLU_LIBRARIES ${KLU_LIBRARY} ${AMD_LIBRARY} ${COLAMD_LIBRARY} ${BTF_LIBRARY} ${SUITESPARSECONFIG_LIBRARY}) +set(KLU_LIBRARIES "${KLU_LIBRARY}" "${AMD_LIBRARY}" "${COLAMD_LIBRARY}" "${BTF_LIBRARY}" "${SUITESPARSECONFIG_LIBRARY}") # set package variables including KLU_FOUND include(FindPackageHandleStandardArgs) diff --git a/ThirdParty/sundials/cmake/tpl/SundialsKLU.cmake b/ThirdParty/sundials/cmake/tpl/SundialsKLU.cmake index 8a9e111c6c..fd7947cac4 100644 --- a/ThirdParty/sundials/cmake/tpl/SundialsKLU.cmake +++ b/ThirdParty/sundials/cmake/tpl/SundialsKLU.cmake @@ -49,7 +49,8 @@ find_package(KLU REQUIRED) message(STATUS "KLU_LIBRARIES: ${KLU_LIBRARIES}") message(STATUS "KLU_INCLUDE_DIR: ${KLU_INCLUDE_DIR}") - +list(JOIN KLU_LIBRARIES "\" \"" KLU_LIBRARIES_TMP) +set(KLU_LIBRARIES_TMP \"${KLU_LIBRARIES_TMP}\") # ----------------------------------------------------------------------------- # Section 4: Test the TPL # ----------------------------------------------------------------------------- @@ -58,11 +59,11 @@ if(KLU_FOUND AND (NOT KLU_WORKS)) # Do any checks which don't require compilation first. # Create the KLU_TEST directory - set(KLU_TEST_DIR ${PROJECT_BINARY_DIR}/KLU_TEST) + set(KLU_TEST_DIR "${PROJECT_BINARY_DIR}/KLU_TEST") file(MAKE_DIRECTORY ${KLU_TEST_DIR}) # Create a CMakeLists.txt file - file(WRITE ${KLU_TEST_DIR}/CMakeLists.txt + file(WRITE "${KLU_TEST_DIR}/CMakeLists.txt" "CMAKE_MINIMUM_REQUIRED(VERSION 3.1.3)\n" "PROJECT(ltest C)\n" "SET(CMAKE_VERBOSE_MAKEFILE ON)\n" @@ -72,12 +73,12 @@ if(KLU_FOUND AND (NOT KLU_WORKS)) "SET(CMAKE_C_FLAGS_DEBUG \"${CMAKE_C_FLAGS_DEBUG}\")\n" "SET(CMAKE_C_FLAGS_RELWITHDEBUGINFO \"${CMAKE_C_FLAGS_RELWITHDEBUGINFO}\")\n" "SET(CMAKE_C_FLAGS_MINSIZE \"${CMAKE_C_FLAGS_MINSIZE}\")\n" - "INCLUDE_DIRECTORIES(${KLU_INCLUDE_DIR})\n" + "INCLUDE_DIRECTORIES(\"${KLU_INCLUDE_DIR}\")\n" "ADD_EXECUTABLE(ltest ltest.c)\n" - "TARGET_LINK_LIBRARIES(ltest ${KLU_LIBRARIES})\n") + "TARGET_LINK_LIBRARIES(ltest ${KLU_LIBRARIES_TMP})\n") # Create a C source file which calls a KLU function - file(WRITE ${KLU_TEST_DIR}/ltest.c + file(WRITE "${KLU_TEST_DIR}/ltest.c" "\#include \"klu.h\"\n" "int main(){\n" "klu_common Common;\n" @@ -87,10 +88,10 @@ if(KLU_FOUND AND (NOT KLU_WORKS)) # To ensure we do not use stuff from the previous attempts, # we must remove the CMakeFiles directory. - file(REMOVE_RECURSE ${KLU_TEST_DIR}/CMakeFiles) + file(REMOVE_RECURSE "${KLU_TEST_DIR}/CMakeFiles") # Attempt to build and link the "ltest" executable - try_compile(COMPILE_OK ${KLU_TEST_DIR} ${KLU_TEST_DIR} ltest + try_compile(COMPILE_OK "${KLU_TEST_DIR}" "${KLU_TEST_DIR}" ltest OUTPUT_VARIABLE COMPILE_OUTPUT) # Process test result diff --git a/cmake/AmiciConfig.cmake b/cmake/AmiciConfig.cmake index ebef45d6e0..d1e86c151e 100644 --- a/cmake/AmiciConfig.cmake +++ b/cmake/AmiciConfig.cmake @@ -1,12 +1,5 @@ @PACKAGE_INIT@ -# TODO remove after cmake files for test models have been regenerated -# cmake >=3.27 -if(POLICY CMP0144) - cmake_policy(SET CMP0144 NEW) -endif(POLICY CMP0144) - - include(CMakeFindDependencyMacro) find_package(OpenMP) @@ -31,11 +24,13 @@ endif() if(NOT DEFINED KLU_ROOT) set(KLU_ROOT @CMAKE_SOURCE_DIR@/ThirdParty/SuiteSparse/) endif() -find_package(SuiteSparse_config REQUIRED) -find_package(AMD REQUIRED) -find_package(BTF REQUIRED) -find_package(COLAMD REQUIRED) -find_package(KLU REQUIRED) +find_dependency(SuiteSparse_config REQUIRED) +find_dependency(AMD REQUIRED) +find_dependency(BTF REQUIRED) +find_dependency(COLAMD REQUIRED) +find_dependency(KLU REQUIRED) + +include("${CMAKE_CURRENT_LIST_DIR}/AmiciFindBLAS.cmake") add_library(SUNDIALS::KLU INTERFACE IMPORTED) target_link_libraries( @@ -48,15 +43,15 @@ target_link_libraries( set_target_properties(SUNDIALS::KLU PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${KLU_INCLUDE_DIR}") -find_package(SUNDIALS REQUIRED PATHS +find_dependency(SUNDIALS REQUIRED PATHS "@CMAKE_SOURCE_DIR@/ThirdParty/sundials/build/@CMAKE_INSTALL_LIBDIR@/cmake/sundials/") if(@Boost_CHRONO_FOUND@) - find_package(Boost COMPONENTS chrono REQUIRED) + find_dependency(Boost COMPONENTS chrono REQUIRED) endif() if(@HDF5_FOUND@) - find_package( + find_dependency( HDF5 COMPONENTS C HL CXX REQUIRED) diff --git a/cmake/AmiciFindBLAS.cmake b/cmake/AmiciFindBLAS.cmake new file mode 100644 index 0000000000..51d9c9b257 --- /dev/null +++ b/cmake/AmiciFindBLAS.cmake @@ -0,0 +1,111 @@ +# Find a BLAS +# +# AMICI requires BLAS, currently Intel MKL, CBLAS or MATLAB BLAS can be used. +# The latter is not supported via CMake yet. +# +# This module defines the BLAS::BLAS IMPORTED target. + +set(BLAS + "CBLAS" + CACHE STRING "BLAS library to use") +set_property(CACHE BLAS PROPERTY STRINGS "CBLAS" "MKL" "ACCELERATE") + +if(${BLAS} STREQUAL "MKL" OR DEFINED ENV{MKLROOT}) + if(DEFINED ENV{MKLROOT}) + # This is set by Environment Modules + message(STATUS "Using MKL_INCDIR and MKL_LIB from environment module") + set(BLAS + "MKL" + CACHE STRING "BLAS library to use" FORCE) + set(BLAS_INCLUDE_DIRS + "$ENV{MKL_INCDIR}" + CACHE STRING "" FORCE) + set(BLAS_LIBRARIES + "$ENV{MKL_LIB}" + CACHE STRING "" FORCE) + else() + set(BLAS_INCLUDE_DIRS + "" + CACHE STRING "") + set(BLAS_LIBRARIES + -lmkl + CACHE STRING "") + endif() +elseif( + NOT DEFINED ENV{BLAS_LIBS} + AND NOT DEFINED ENV{BLAS_CFLAGS} + AND NOT BLAS_FOUND) + # if nothing is specified via environment variables, let's try FindBLAS + if($(CMAKE_VERSION) VERSION_GREATER_EQUAL 3.22) + set(BLA_SIZEOF_INTEGER 8) + endif() + + if(APPLE AND (NOT DEFINED BLA_VENDOR OR BLA_VENDOR STREQUAL "All")) + set(BLA_VENDOR Apple) + find_package(BLAS) + if(BLAS_FOUND) + message(STATUS "Found Apple Accelerate BLAS") + set_property( + TARGET BLAS::BLAS + APPEND + PROPERTY INTERFACE_COMPILE_DEFINITIONS ACCELERATE_NEW_LAPACK) + set_property( + TARGET BLAS::BLAS + APPEND + PROPERTY INTERFACE_COMPILE_DEFINITIONS ACCELERATE_LAPACK_ILP64) + else() + set(BLA_VENDOR "All") + endif() + + endif() + if(NOT BLAS_FOUND) + find_package(BLAS) + if(BLAS_FOUND) + message(STATUS "Found BLAS via FindBLAS") + endif() + endif() + if(NOT BLAS_FOUND) + # Nothing specified by the user and FindBLAS didn't find anything; let's try + # if cblas is available on the system paths. + set(BLAS_INCLUDE_DIRS + "" + CACHE STRING "") + set(BLAS_LIBRARIES + -lcblas + CACHE STRING "") + endif() +endif() + +# Create an imported target +if(NOT TARGET BLAS::BLAS) + add_library(BLAS INTERFACE) + set_target_properties(BLAS PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${BLAS_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${BLAS_LIBRARIES}") + add_library(BLAS::BLAS ALIAS BLAS) + if("${PROJECT_NAME}" STREQUAL "amici") + install(TARGETS BLAS EXPORT BLAS) + export(EXPORT BLAS NAMESPACE BLAS::) + install( + EXPORT BLAS + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Amici" + NAMESPACE BLAS::) + endif() + + # legacy python package environment variables: + if(DEFINED ENV{BLAS_CFLAGS}) + target_compile_options(BLAS INTERFACE "$ENV{BLAS_CFLAGS}") + endif() + if(DEFINED ENV{BLAS_LIBS}) + # Note that, on Windows, at least for ninja, this will only work with dashes + # instead of slashes in any linker options + target_link_libraries(BLAS INTERFACE "$ENV{BLAS_LIBS}") + endif() + + if(NOT "${BLAS_INCLUDE_DIRS}" STREQUAL "") + target_include_directories(BLAS INTERFACE ${BLAS_INCLUDE_DIRS}) + endif() + target_compile_definitions(BLAS INTERFACE "AMICI_BLAS_${BLAS}") +else() + target_compile_definitions(BLAS::BLAS INTERFACE "AMICI_BLAS_${BLAS}") +endif() diff --git a/documentation/ExampleJax.ipynb b/documentation/ExampleJax.ipynb deleted file mode 100644 index 53e03788da..0000000000 --- a/documentation/ExampleJax.ipynb +++ /dev/null @@ -1,1113 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d4d2bc5c", - "metadata": {}, - "source": [ - "The purpose of this guide is to showcase how AMICI can be combined with differentiable programming in JAX. We will do so by reimplementing the parameter transformations available in AMICI in JAX and comparing it to the native implementation." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "b0a66e18", - "metadata": {}, - "outputs": [], - "source": [ - "import jax\n", - "import jax.numpy as jnp" - ] - }, - { - "cell_type": "markdown", - "id": "aa587260", - "metadata": {}, - "source": [ - "# Preparation" - ] - }, - { - "cell_type": "markdown", - "id": "fb2fe897", - "metadata": {}, - "source": [ - "To get started we will import a model using the [petab](https://petab.readthedocs.io). To this end, we will use the [benchmark collection](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab), which features a variety of different models. For more details about petab import, see the respective notebook petab [notebook](https://amici.readthedocs.io/en/latest/petab.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "04804185", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cloning into 'tmp/benchmark-models'...\n", - "remote: Enumerating objects: 336, done.\u001B[K\n", - "remote: Counting objects: 100% (336/336), done.\u001B[K\n", - "remote: Compressing objects: 100% (285/285), done.\u001B[K\n", - "remote: Total 336 (delta 88), reused 216 (delta 39), pack-reused 0\u001B[K\n", - "Receiving objects: 100% (336/336), 2.11 MiB | 7.48 MiB/s, done.\n", - "Resolving deltas: 100% (88/88), done.\n" - ] - } - ], - "source": [ - "!git clone --depth 1 https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab.git tmp/benchmark-models || (cd tmp/benchmark-models && git pull)\n", - "from pathlib import Path\n", - "\n", - "folder_base = Path(\".\") / \"tmp\" / \"benchmark-models\" / \"Benchmark-Models\"" - ] - }, - { - "cell_type": "markdown", - "id": "8552f123", - "metadata": {}, - "source": [ - "From the benchmark collection, we now import the Boehm model." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "9166e3bf", - "metadata": {}, - "outputs": [], - "source": [ - "import petab\n", - "\n", - "model_name = \"Boehm_JProteomeRes2014\"\n", - "yaml_file = folder_base / model_name / (model_name + \".yaml\")\n", - "petab_problem = petab.Problem.from_yaml(yaml_file)" - ] - }, - { - "cell_type": "markdown", - "id": "d4038fc4", - "metadata": {}, - "source": [ - "The petab problem includes information about parameter scaling in it's the parameter table. For the boehm model, all estimated parameters (`petab.ESTIMATE` column equal to `1`) have a `petab.LOG10` as parameter scaling." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "b04ca561", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
parameterNameparameterScalelowerBoundupperBoundnominalValueestimate
parameterId
Epo_degradation_BaF3EPO_{degradation,BaF3}log100.000011000000.0269831
k_exp_heterok_{exp,hetero}log100.000011000000.0000101
k_exp_homok_{exp,homo}log100.000011000000.0061701
k_imp_heterok_{imp,hetero}log100.000011000000.0163681
k_imp_homok_{imp,homo}log100.0000110000097749.3794021
k_phosk_{phos}log100.0000110000015766.5070201
ratioratiolin-5.0000050.6930000
sd_pSTAT5A_rel\\sigma_{pSTAT5A,rel}log100.000011000003.8526121
sd_pSTAT5B_rel\\sigma_{pSTAT5B,rel}log100.000011000006.5914781
sd_rSTAT5A_rel\\sigma_{rSTAT5A,rel}log100.000011000003.1527131
specC17specC17lin-5.0000050.1070000
\n", - "
" - ], - "text/plain": [ - " parameterName parameterScale lowerBound \\\n", - "parameterId \n", - "Epo_degradation_BaF3 EPO_{degradation,BaF3} log10 0.00001 \n", - "k_exp_hetero k_{exp,hetero} log10 0.00001 \n", - "k_exp_homo k_{exp,homo} log10 0.00001 \n", - "k_imp_hetero k_{imp,hetero} log10 0.00001 \n", - "k_imp_homo k_{imp,homo} log10 0.00001 \n", - "k_phos k_{phos} log10 0.00001 \n", - "ratio ratio lin -5.00000 \n", - "sd_pSTAT5A_rel \\sigma_{pSTAT5A,rel} log10 0.00001 \n", - "sd_pSTAT5B_rel \\sigma_{pSTAT5B,rel} log10 0.00001 \n", - "sd_rSTAT5A_rel \\sigma_{rSTAT5A,rel} log10 0.00001 \n", - "specC17 specC17 lin -5.00000 \n", - "\n", - " upperBound nominalValue estimate \n", - "parameterId \n", - "Epo_degradation_BaF3 100000 0.026983 1 \n", - "k_exp_hetero 100000 0.000010 1 \n", - "k_exp_homo 100000 0.006170 1 \n", - "k_imp_hetero 100000 0.016368 1 \n", - "k_imp_homo 100000 97749.379402 1 \n", - "k_phos 100000 15766.507020 1 \n", - "ratio 5 0.693000 0 \n", - "sd_pSTAT5A_rel 100000 3.852612 1 \n", - "sd_pSTAT5B_rel 100000 6.591478 1 \n", - "sd_rSTAT5A_rel 100000 3.152713 1 \n", - "specC17 5 0.107000 0 " - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "petab_problem.parameter_df" - ] - }, - { - "cell_type": "markdown", - "id": "8914a18d", - "metadata": {}, - "source": [ - "We now import the petab problem using [`amici.petab_import`](https://amici.readthedocs.io/en/latest/generated/amici.petab_import.html#amici.petab_import.import_petab_problem)." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "6ada3fb8", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-02-16 12:37:18.049 - amici.petab_import - INFO - Importing model ...\n", - "2023-02-16 12:37:18.050 - amici.petab_import - INFO - Validating PEtab problem ...\n", - "2023-02-16 12:37:18.343 - amici.petab_import - INFO - Model name is 'Boehm_JProteomeRes2014'.\n", - "Writing model code to '/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014'.\n", - "2023-02-16 12:37:18.344 - amici.petab_import - INFO - Species: 8\n", - "2023-02-16 12:37:18.344 - amici.petab_import - INFO - Global parameters: 9\n", - "2023-02-16 12:37:18.344 - amici.petab_import - INFO - Reactions: 9\n", - "2023-02-16 12:37:18.353 - amici.petab_import - INFO - Observables: 3\n", - "2023-02-16 12:37:18.353 - amici.petab_import - INFO - Sigmas: 3\n", - "2023-02-16 12:37:18.357 - amici.petab_import - DEBUG - Adding output parameters to model: ['noiseParameter1_pSTAT5A_rel', 'noiseParameter1_pSTAT5B_rel', 'noiseParameter1_rSTAT5A_rel']\n", - "2023-02-16 12:37:18.357 - amici.petab_import - DEBUG - Adding initial assignments for []\n", - "2023-02-16 12:37:18.363 - amici.petab_import - DEBUG - Condition table: (1, 1)\n", - "2023-02-16 12:37:18.364 - amici.petab_import - DEBUG - Fixed parameters are ['ratio', 'specC17']\n", - "2023-02-16 12:37:18.364 - amici.petab_import - INFO - Overall fixed parameters: 2\n", - "2023-02-16 12:37:18.364 - amici.petab_import - INFO - Variable parameters: 10\n", - "2023-02-16 12:37:18.398 - amici.sbml_import - DEBUG - Finished gathering local SBML symbols ++ (1.08E-02s)\n", - "2023-02-16 12:37:18.403 - amici.sbml_import - DEBUG - Finished processing SBML parameters ++ (2.27E-03s)\n", - "2023-02-16 12:37:18.405 - amici.sbml_import - DEBUG - Finished processing SBML compartments ++ (1.18E-04s)\n", - "2023-02-16 12:37:18.411 - amici.sbml_import - DEBUG - Finished processing SBML species initials +++ (2.19E-03s)\n", - "2023-02-16 12:37:18.413 - amici.sbml_import - DEBUG - Finished processing SBML rate rules +++ (1.46E-05s)\n", - "2023-02-16 12:37:18.413 - amici.sbml_import - DEBUG - Finished processing SBML species ++ (5.96E-03s)\n", - "2023-02-16 12:37:18.417 - amici.sbml_import - DEBUG - Finished processing SBML reactions ++ (1.01E-03s)\n", - "2023-02-16 12:37:18.420 - amici.sbml_import - DEBUG - Finished processing SBML rules ++ (1.15E-03s)\n", - "2023-02-16 12:37:18.422 - amici.sbml_import - DEBUG - Finished processing SBML initial assignments++ (4.30E-05s)\n", - "2023-02-16 12:37:18.424 - amici.sbml_import - DEBUG - Finished processing SBML species references ++ (1.96E-04s)\n", - "2023-02-16 12:37:18.426 - amici.sbml_import - DEBUG - Finished processing SBML events ++ (3.40E-05s)\n", - "2023-02-16 12:37:18.426 - amici.sbml_import - DEBUG - Finished importing SBML + (4.08E-02s)\n", - "2023-02-16 12:37:18.457 - amici.sbml_import - DEBUG - Finished processing SBML observables + (2.87E-02s)\n", - "2023-02-16 12:37:18.460 - amici.sbml_import - DEBUG - Finished processing SBML event observables + (1.12E-06s)\n", - "2023-02-16 12:37:18.476 - amici.ode_export - DEBUG - Finished running smart_multiply ++ (1.06E-03s)\n", - "2023-02-16 12:37:18.499 - amici.ode_export - DEBUG - Finished importing SbmlImporter + (2.54E-02s)\n", - "2023-02-16 12:37:18.520 - amici.ode_export - DEBUG - Finished simplifying Jy ++++ (1.33E-02s)\n", - "2023-02-16 12:37:18.521 - amici.ode_export - DEBUG - Finished computing Jy +++ (1.53E-02s)\n", - "2023-02-16 12:37:18.549 - amici.ode_export - DEBUG - Finished simplifying y ++++ (2.28E-02s)\n", - "2023-02-16 12:37:18.549 - amici.ode_export - DEBUG - Finished computing y +++ (2.48E-02s)\n", - "2023-02-16 12:37:18.554 - amici.ode_export - DEBUG - Finished simplifying sigmay ++++ (7.19E-05s)\n", - "2023-02-16 12:37:18.554 - amici.ode_export - DEBUG - Finished computing sigmay +++ (2.17E-03s)\n", - "2023-02-16 12:37:18.570 - amici.ode_export - DEBUG - Finished writing Jy.cpp ++ (6.58E-02s)\n", - "2023-02-16 12:37:18.592 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (1.63E-02s)\n", - "2023-02-16 12:37:18.601 - amici.ode_export - DEBUG - Finished simplifying dJydsigma ++++ (5.78E-03s)\n", - "2023-02-16 12:37:18.601 - amici.ode_export - DEBUG - Finished computing dJydsigma +++ (2.73E-02s)\n", - "2023-02-16 12:37:18.604 - amici.ode_export - DEBUG - Finished writing dJydsigma.cpp ++ (3.18E-02s)\n", - "2023-02-16 12:37:18.619 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (9.30E-03s)\n", - "2023-02-16 12:37:18.630 - amici.ode_export - DEBUG - Finished simplifying dJydy ++++ (7.63E-03s)\n", - "2023-02-16 12:37:18.630 - amici.ode_export - DEBUG - Finished computing dJydy +++ (2.19E-02s)\n", - "2023-02-16 12:37:18.635 - amici.ode_export - DEBUG - Finished writing dJydy.cpp ++ (2.79E-02s)\n", - "2023-02-16 12:37:18.640 - amici.ode_export - DEBUG - Finished simplifying Jz ++++ (3.06E-05s)\n", - "2023-02-16 12:37:18.641 - amici.ode_export - DEBUG - Finished computing Jz +++ (1.71E-03s)\n", - "2023-02-16 12:37:18.643 - amici.ode_export - DEBUG - Finished computing z +++ (6.17E-05s)\n", - "2023-02-16 12:37:18.647 - amici.ode_export - DEBUG - Finished simplifying sigmaz ++++ (2.92E-05s)\n", - "2023-02-16 12:37:18.647 - amici.ode_export - DEBUG - Finished computing sigmaz +++ (2.01E-03s)\n", - "2023-02-16 12:37:18.647 - amici.ode_export - DEBUG - Finished writing Jz.cpp ++ (9.91E-03s)\n", - "2023-02-16 12:37:18.653 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.68E-05s)\n", - "2023-02-16 12:37:18.655 - amici.ode_export - DEBUG - Finished simplifying dJzdsigma ++++ (3.75E-05s)\n", - "2023-02-16 12:37:18.656 - amici.ode_export - DEBUG - Finished computing dJzdsigma +++ (4.13E-03s)\n", - "2023-02-16 12:37:18.656 - amici.ode_export - DEBUG - Finished writing dJzdsigma.cpp ++ (6.25E-03s)\n", - "2023-02-16 12:37:18.661 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.62E-05s)\n", - "2023-02-16 12:37:18.663 - amici.ode_export - DEBUG - Finished simplifying dJzdz ++++ (3.29E-05s)\n", - "2023-02-16 12:37:18.664 - amici.ode_export - DEBUG - Finished computing dJzdz +++ (3.72E-03s)\n", - "2023-02-16 12:37:18.664 - amici.ode_export - DEBUG - Finished writing dJzdz.cpp ++ (5.33E-03s)\n", - "2023-02-16 12:37:18.669 - amici.ode_export - DEBUG - Finished simplifying Jrz ++++ (3.16E-05s)\n", - "2023-02-16 12:37:18.670 - amici.ode_export - DEBUG - Finished computing Jrz +++ (1.69E-03s)\n", - "2023-02-16 12:37:18.672 - amici.ode_export - DEBUG - Finished computing rz +++ (5.45E-05s)\n", - "2023-02-16 12:37:18.672 - amici.ode_export - DEBUG - Finished writing Jrz.cpp ++ (5.46E-03s)\n", - "2023-02-16 12:37:18.677 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.60E-05s)\n", - "2023-02-16 12:37:18.679 - amici.ode_export - DEBUG - Finished simplifying dJrzdsigma ++++ (3.63E-05s)\n", - "2023-02-16 12:37:18.679 - amici.ode_export - DEBUG - Finished computing dJrzdsigma +++ (3.57E-03s)\n", - "2023-02-16 12:37:18.679 - amici.ode_export - DEBUG - Finished writing dJrzdsigma.cpp ++ (5.15E-03s)\n", - "2023-02-16 12:37:18.684 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.39E-05s)\n", - "2023-02-16 12:37:18.686 - amici.ode_export - DEBUG - Finished simplifying dJrzdz ++++ (3.45E-05s)\n", - "2023-02-16 12:37:18.687 - amici.ode_export - DEBUG - Finished computing dJrzdz +++ (3.68E-03s)\n", - "2023-02-16 12:37:18.687 - amici.ode_export - DEBUG - Finished writing dJrzdz.cpp ++ (5.31E-03s)\n", - "2023-02-16 12:37:18.692 - amici.ode_export - DEBUG - Finished simplifying root ++++ (3.28E-05s)\n", - "2023-02-16 12:37:18.693 - amici.ode_export - DEBUG - Finished computing root +++ (1.74E-03s)\n", - "2023-02-16 12:37:18.693 - amici.ode_export - DEBUG - Finished writing root.cpp ++ (3.46E-03s)\n", - "2023-02-16 12:37:18.707 - amici.ode_export - DEBUG - Finished simplifying w +++++ (7.04E-03s)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-02-16 12:37:18.707 - amici.ode_export - DEBUG - Finished computing w ++++ (8.93E-03s)\n", - "2023-02-16 12:37:18.719 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (9.60E-03s)\n", - "2023-02-16 12:37:18.726 - amici.ode_export - DEBUG - Finished simplifying dwdp ++++ (4.59E-03s)\n", - "2023-02-16 12:37:18.726 - amici.ode_export - DEBUG - Finished computing dwdp +++ (2.93E-02s)\n", - "2023-02-16 12:37:18.730 - amici.ode_export - DEBUG - Finished writing dwdp.cpp ++ (3.43E-02s)\n", - "2023-02-16 12:37:18.743 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (8.10E-03s)\n", - "2023-02-16 12:37:18.749 - amici.ode_export - DEBUG - Finished simplifying dwdx ++++ (3.24E-03s)\n", - "2023-02-16 12:37:18.749 - amici.ode_export - DEBUG - Finished computing dwdx +++ (1.54E-02s)\n", - "2023-02-16 12:37:18.753 - amici.ode_export - DEBUG - Finished writing dwdx.cpp ++ (2.02E-02s)\n", - "2023-02-16 12:37:18.762 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (3.16E-03s)\n", - "2023-02-16 12:37:18.767 - amici.ode_export - DEBUG - Finished simplifying dwdw ++++ (2.23E-03s)\n", - "2023-02-16 12:37:18.767 - amici.ode_export - DEBUG - Finished computing dwdw +++ (9.56E-03s)\n", - "2023-02-16 12:37:18.769 - amici.ode_export - DEBUG - Finished writing dwdw.cpp ++ (1.30E-02s)\n", - "2023-02-16 12:37:18.780 - amici.ode_export - DEBUG - Finished simplifying xdot +++++ (3.54E-03s)\n", - "2023-02-16 12:37:18.780 - amici.ode_export - DEBUG - Finished computing xdot ++++ (5.53E-03s)\n", - "2023-02-16 12:37:18.790 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (6.83E-03s)\n", - "2023-02-16 12:37:18.792 - amici.ode_export - DEBUG - Finished simplifying dxdotdw ++++ (2.24E-04s)\n", - "2023-02-16 12:37:18.793 - amici.ode_export - DEBUG - Finished computing dxdotdw +++ (1.98E-02s)\n", - "2023-02-16 12:37:18.797 - amici.ode_export - DEBUG - Finished writing dxdotdw.cpp ++ (2.55E-02s)\n", - "2023-02-16 12:37:18.804 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (5.02E-04s)\n", - "2023-02-16 12:37:18.806 - amici.ode_export - DEBUG - Finished simplifying dxdotdx_explicit ++++ (3.57E-05s)\n", - "2023-02-16 12:37:18.806 - amici.ode_export - DEBUG - Finished computing dxdotdx_explicit +++ (4.47E-03s)\n", - "2023-02-16 12:37:18.806 - amici.ode_export - DEBUG - Finished writing dxdotdx_explicit.cpp ++ (6.56E-03s)\n", - "2023-02-16 12:37:18.812 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (5.50E-04s)\n", - "2023-02-16 12:37:18.814 - amici.ode_export - DEBUG - Finished simplifying dxdotdp_explicit ++++ (3.08E-05s)\n", - "2023-02-16 12:37:18.815 - amici.ode_export - DEBUG - Finished computing dxdotdp_explicit +++ (4.37E-03s)\n", - "2023-02-16 12:37:18.815 - amici.ode_export - DEBUG - Finished writing dxdotdp_explicit.cpp ++ (6.87E-03s)\n", - "2023-02-16 12:37:18.854 - amici.ode_export - DEBUG - Finished running smart_jacobian +++++ (3.12E-02s)\n", - "2023-02-16 12:37:18.897 - amici.ode_export - DEBUG - Finished simplifying dydx +++++ (4.02E-02s)\n", - "2023-02-16 12:37:18.898 - amici.ode_export - DEBUG - Finished computing dydx ++++ (7.70E-02s)\n", - "2023-02-16 12:37:18.903 - amici.ode_export - DEBUG - Finished running smart_jacobian +++++ (4.23E-04s)\n", - "2023-02-16 12:37:18.905 - amici.ode_export - DEBUG - Finished simplifying dydw +++++ (2.99E-05s)\n", - "2023-02-16 12:37:18.906 - amici.ode_export - DEBUG - Finished computing dydw ++++ (4.61E-03s)\n", - "2023-02-16 12:37:18.942 - amici.ode_export - DEBUG - Finished simplifying dydx ++++ (3.36E-02s)\n", - "2023-02-16 12:37:18.942 - amici.ode_export - DEBUG - Finished computing dydx +++ (1.23E-01s)\n", - "2023-02-16 12:37:18.958 - amici.ode_export - DEBUG - Finished writing dydx.cpp ++ (1.40E-01s)\n", - "2023-02-16 12:37:18.966 - amici.ode_export - DEBUG - Finished running smart_jacobian +++++ (3.85E-04s)\n", - "2023-02-16 12:37:18.968 - amici.ode_export - DEBUG - Finished simplifying dydp +++++ (3.45E-05s)\n", - "2023-02-16 12:37:18.968 - amici.ode_export - DEBUG - Finished computing dydp ++++ (4.15E-03s)\n", - "2023-02-16 12:37:18.971 - amici.ode_export - DEBUG - Finished simplifying dydp ++++ (3.38E-05s)\n", - "2023-02-16 12:37:18.971 - amici.ode_export - DEBUG - Finished computing dydp +++ (8.39E-03s)\n", - "2023-02-16 12:37:18.971 - amici.ode_export - DEBUG - Finished writing dydp.cpp ++ (1.04E-02s)\n", - "2023-02-16 12:37:18.975 - amici.ode_export - DEBUG - Finished computing dzdx +++ (5.68E-05s)\n", - "2023-02-16 12:37:18.975 - amici.ode_export - DEBUG - Finished writing dzdx.cpp ++ (1.63E-03s)\n", - "2023-02-16 12:37:18.979 - amici.ode_export - DEBUG - Finished computing dzdp +++ (4.66E-05s)\n", - "2023-02-16 12:37:18.979 - amici.ode_export - DEBUG - Finished writing dzdp.cpp ++ (1.61E-03s)\n", - "2023-02-16 12:37:18.982 - amici.ode_export - DEBUG - Finished computing drzdx +++ (4.78E-05s)\n", - "2023-02-16 12:37:18.983 - amici.ode_export - DEBUG - Finished writing drzdx.cpp ++ (1.67E-03s)\n", - "2023-02-16 12:37:18.986 - amici.ode_export - DEBUG - Finished computing drzdp +++ (5.38E-05s)\n", - "2023-02-16 12:37:18.986 - amici.ode_export - DEBUG - Finished writing drzdp.cpp ++ (1.69E-03s)\n", - "2023-02-16 12:37:18.992 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (1.11E-04s)\n", - "2023-02-16 12:37:18.994 - amici.ode_export - DEBUG - Finished simplifying dsigmaydy ++++ (3.44E-05s)\n", - "2023-02-16 12:37:18.994 - amici.ode_export - DEBUG - Finished computing dsigmaydy +++ (3.81E-03s)\n", - "2023-02-16 12:37:18.994 - amici.ode_export - DEBUG - Finished writing dsigmaydy.cpp ++ (5.42E-03s)\n", - "2023-02-16 12:37:19.000 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (4.32E-04s)\n", - "2023-02-16 12:37:19.002 - amici.ode_export - DEBUG - Finished simplifying dsigmaydp ++++ (7.44E-05s)\n", - "2023-02-16 12:37:19.002 - amici.ode_export - DEBUG - Finished computing dsigmaydp +++ (4.23E-03s)\n", - "2023-02-16 12:37:19.003 - amici.ode_export - DEBUG - Finished writing dsigmaydp.cpp ++ (6.96E-03s)\n", - "2023-02-16 12:37:19.006 - amici.ode_export - DEBUG - Finished writing sigmay.cpp ++ (5.00E-04s)\n", - "2023-02-16 12:37:19.011 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.56E-05s)\n", - "2023-02-16 12:37:19.013 - amici.ode_export - DEBUG - Finished simplifying dsigmazdp ++++ (3.78E-05s)\n", - "2023-02-16 12:37:19.013 - amici.ode_export - DEBUG - Finished computing dsigmazdp +++ (3.67E-03s)\n", - "2023-02-16 12:37:19.014 - amici.ode_export - DEBUG - Finished writing dsigmazdp.cpp ++ (5.26E-03s)\n", - "2023-02-16 12:37:19.016 - amici.ode_export - DEBUG - Finished writing sigmaz.cpp ++ (1.64E-05s)\n", - "2023-02-16 12:37:19.019 - amici.ode_export - DEBUG - Finished computing stau +++ (5.81E-05s)\n", - "2023-02-16 12:37:19.019 - amici.ode_export - DEBUG - Finished writing stau.cpp ++ (1.65E-03s)\n", - "2023-02-16 12:37:19.023 - amici.ode_export - DEBUG - Finished computing deltax +++ (5.10E-05s)\n", - "2023-02-16 12:37:19.024 - amici.ode_export - DEBUG - Finished writing deltax.cpp ++ (1.91E-03s)\n", - "2023-02-16 12:37:19.027 - amici.ode_export - DEBUG - Finished computing deltasx +++ (5.45E-05s)\n", - "2023-02-16 12:37:19.028 - amici.ode_export - DEBUG - Finished writing deltasx.cpp ++ (1.86E-03s)\n", - "2023-02-16 12:37:19.032 - amici.ode_export - DEBUG - Finished writing w.cpp ++ (2.53E-03s)\n", - "2023-02-16 12:37:19.038 - amici.ode_export - DEBUG - Finished simplifying x0 ++++ (8.98E-04s)\n", - "2023-02-16 12:37:19.038 - amici.ode_export - DEBUG - Finished computing x0 +++ (2.79E-03s)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-02-16 12:37:19.040 - amici.ode_export - DEBUG - Finished writing x0.cpp ++ (5.34E-03s)\n", - "2023-02-16 12:37:19.046 - amici.ode_export - DEBUG - Finished simplifying x0_fixedParameters ++++ (3.45E-04s)\n", - "2023-02-16 12:37:19.046 - amici.ode_export - DEBUG - Finished computing x0_fixedParameters +++ (2.33E-03s)\n", - "2023-02-16 12:37:19.047 - amici.ode_export - DEBUG - Finished writing x0_fixedParameters.cpp ++ (4.79E-03s)\n", - "2023-02-16 12:37:19.053 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (9.02E-04s)\n", - "2023-02-16 12:37:19.055 - amici.ode_export - DEBUG - Finished simplifying sx0 ++++ (3.90E-05s)\n", - "2023-02-16 12:37:19.055 - amici.ode_export - DEBUG - Finished computing sx0 +++ (4.79E-03s)\n", - "2023-02-16 12:37:19.056 - amici.ode_export - DEBUG - Finished writing sx0.cpp ++ (6.54E-03s)\n", - "2023-02-16 12:37:19.061 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (8.95E-05s)\n", - "2023-02-16 12:37:19.063 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (1.41E-04s)\n", - "2023-02-16 12:37:19.066 - amici.ode_export - DEBUG - Finished simplifying sx0_fixedParameters ++++ (2.92E-05s)\n", - "2023-02-16 12:37:19.066 - amici.ode_export - DEBUG - Finished computing sx0_fixedParameters +++ (6.44E-03s)\n", - "2023-02-16 12:37:19.067 - amici.ode_export - DEBUG - Finished writing sx0_fixedParameters.cpp ++ (8.77E-03s)\n", - "2023-02-16 12:37:19.075 - amici.ode_export - DEBUG - Finished writing xdot.cpp ++ (5.99E-03s)\n", - "2023-02-16 12:37:19.080 - amici.ode_export - DEBUG - Finished writing y.cpp ++ (2.52E-03s)\n", - "2023-02-16 12:37:19.085 - amici.ode_export - DEBUG - Finished simplifying x_rdata ++++ (7.20E-05s)\n", - "2023-02-16 12:37:19.086 - amici.ode_export - DEBUG - Finished computing x_rdata +++ (2.21E-03s)\n", - "2023-02-16 12:37:19.087 - amici.ode_export - DEBUG - Finished writing x_rdata.cpp ++ (4.64E-03s)\n", - "2023-02-16 12:37:19.092 - amici.ode_export - DEBUG - Finished simplifying total_cl ++++ (3.50E-05s)\n", - "2023-02-16 12:37:19.093 - amici.ode_export - DEBUG - Finished computing total_cl +++ (1.79E-03s)\n", - "2023-02-16 12:37:19.093 - amici.ode_export - DEBUG - Finished writing total_cl.cpp ++ (3.50E-03s)\n", - "2023-02-16 12:37:19.098 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.68E-05s)\n", - "2023-02-16 12:37:19.100 - amici.ode_export - DEBUG - Finished simplifying dtotal_cldp ++++ (3.98E-05s)\n", - "2023-02-16 12:37:19.100 - amici.ode_export - DEBUG - Finished computing dtotal_cldp +++ (3.62E-03s)\n", - "2023-02-16 12:37:19.100 - amici.ode_export - DEBUG - Finished writing dtotal_cldp.cpp ++ (5.25E-03s)\n", - "2023-02-16 12:37:19.105 - amici.ode_export - DEBUG - Finished simplifying dtotal_cldx_rdata ++++ (2.96E-05s)\n", - "2023-02-16 12:37:19.106 - amici.ode_export - DEBUG - Finished computing dtotal_cldx_rdata +++ (1.73E-03s)\n", - "2023-02-16 12:37:19.106 - amici.ode_export - DEBUG - Finished writing dtotal_cldx_rdata.cpp ++ (3.50E-03s)\n", - "2023-02-16 12:37:19.111 - amici.ode_export - DEBUG - Finished simplifying x_solver ++++ (7.02E-05s)\n", - "2023-02-16 12:37:19.112 - amici.ode_export - DEBUG - Finished computing x_solver +++ (1.82E-03s)\n", - "2023-02-16 12:37:19.113 - amici.ode_export - DEBUG - Finished writing x_solver.cpp ++ (4.36E-03s)\n", - "2023-02-16 12:37:19.118 - amici.ode_export - DEBUG - Finished simplifying dx_rdatadx_solver ++++ (2.82E-04s)\n", - "2023-02-16 12:37:19.118 - amici.ode_export - DEBUG - Finished computing dx_rdatadx_solver +++ (1.94E-03s)\n", - "2023-02-16 12:37:19.119 - amici.ode_export - DEBUG - Finished writing dx_rdatadx_solver.cpp ++ (4.05E-03s)\n", - "2023-02-16 12:37:19.125 - amici.ode_export - DEBUG - Finished simplifying dx_rdatadp ++++ (3.14E-04s)\n", - "2023-02-16 12:37:19.125 - amici.ode_export - DEBUG - Finished computing dx_rdatadp +++ (2.11E-03s)\n", - "2023-02-16 12:37:19.126 - amici.ode_export - DEBUG - Finished writing dx_rdatadp.cpp ++ (4.04E-03s)\n", - "2023-02-16 12:37:19.131 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.58E-05s)\n", - "2023-02-16 12:37:19.133 - amici.ode_export - DEBUG - Finished simplifying dx_rdatadtcl ++++ (3.95E-05s)\n", - "2023-02-16 12:37:19.133 - amici.ode_export - DEBUG - Finished computing dx_rdatadtcl +++ (3.71E-03s)\n", - "2023-02-16 12:37:19.133 - amici.ode_export - DEBUG - Finished writing dx_rdatadtcl.cpp ++ (5.36E-03s)\n", - "2023-02-16 12:37:19.136 - amici.ode_export - DEBUG - Finished writing z.cpp ++ (1.84E-05s)\n", - "2023-02-16 12:37:19.138 - amici.ode_export - DEBUG - Finished writing rz.cpp ++ (1.69E-05s)\n", - "2023-02-16 12:37:19.147 - amici.ode_export - DEBUG - Finished generating cpp code + (6.45E-01s)\n", - "2023-02-16 12:37:31.424 - amici.ode_export - DEBUG - Finished compiling cpp code + (1.23E+01s)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "running AmiciInstall\n", - "hdf5.h found in /opt/homebrew/Cellar/hdf5/1.12.2_2/include\n", - "libhdf5.a found in /opt/homebrew/Cellar/hdf5/1.12.2_2/lib\n", - "running build_ext\n", - "Changed extra_compile_args for unix to ['-std=c++14']\n", - "Building model extension in /Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014\n", - "building 'Boehm_JProteomeRes2014._Boehm_JProteomeRes2014' extension\n", - "Testing SWIG executable swig4.0... FAILED.\n", - "Testing SWIG executable swig3.0... FAILED.\n", - "Testing SWIG executable swig... SUCCEEDED.\n", - "swigging swig/Boehm_JProteomeRes2014.i to swig/Boehm_JProteomeRes2014_wrap.cpp\n", - "swig -python -c++ -modern -outdir Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/swig -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -o swig/Boehm_JProteomeRes2014_wrap.cpp swig/Boehm_JProteomeRes2014.i\n", - "Deprecated command line option: -modern. Ignored, this option is now always on.\n", - "creating build\n", - "creating build/temp.macosx-13-arm64-cpython-310\n", - "creating build/temp.macosx-13-arm64-cpython-310/swig\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_Jy.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_Jy.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dJydsigma.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydsigma.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dJydy.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dJydy_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dJydy_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dsigmaydp.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dsigmaydp.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdp.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdp_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdp_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdw.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdw_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdw_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdx.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdx_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdx_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dxdotdw.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dxdotdw_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dxdotdw_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dydx.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dydx.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_sigmay.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_sigmay.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_sx0_fixedParameters.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_sx0_fixedParameters.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_w.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_w.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_x0.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x0.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_x0_fixedParameters.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x0_fixedParameters.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_x_rdata.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x_rdata.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_x_solver.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x_solver.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_xdot.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_xdot.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_y.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_y.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c swig/Boehm_JProteomeRes2014_wrap.cpp -o build/temp.macosx-13-arm64-cpython-310/swig/Boehm_JProteomeRes2014_wrap.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c wrapfunctions.cpp -o build/temp.macosx-13-arm64-cpython-310/wrapfunctions.o -std=c++14\n", - "clang++ -bundle -undefined dynamic_lookup -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_Jy.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydsigma.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dsigmaydp.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dydx.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_sigmay.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_sx0_fixedParameters.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_w.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x0.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x0_fixedParameters.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x_rdata.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x_solver.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_xdot.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_y.o build/temp.macosx-13-arm64-cpython-310/swig/Boehm_JProteomeRes2014_wrap.o build/temp.macosx-13-arm64-cpython-310/wrapfunctions.o -L/opt/homebrew/Cellar/hdf5/1.12.2_2/lib -L/Users/fabian/Documents/projects/AMICI/python/sdist/amici/libs -lamici -lsundials -lsuitesparse -lcblas -lhdf5_hl_cpp -lhdf5_hl -lhdf5_cpp -lhdf5 -o /Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014/Boehm_JProteomeRes2014/_Boehm_JProteomeRes2014.cpython-310-darwin.so\n", - "ld: warning: -undefined dynamic_lookup may not work with chained fixups\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-02-16 12:37:31.673 - amici.petab_import - INFO - Finished Importing PEtab model (1.36E+01s)\n", - "2023-02-16 12:37:31.684 - amici.petab_import - INFO - Successfully loaded model Boehm_JProteomeRes2014 from /Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014.\n" - ] - } - ], - "source": [ - "from amici.petab.petab_import import import_petab_problem\n", - "\n", - "amici_model = import_petab_problem(petab_problem, compile_=True)" - ] - }, - { - "cell_type": "markdown", - "id": "7827aaf7", - "metadata": {}, - "source": [ - "# JAX implementation" - ] - }, - { - "cell_type": "markdown", - "id": "e2ef051a", - "metadata": {}, - "source": [ - "For full jax support, we would have to implement a new [primitive](https://jax.readthedocs.io/en/latest/notebooks/How_JAX_primitives_work.html), which would require quite a bit of engineering, and in the end wouldn't add much benefit since AMICI can't run on GPUs. Instead, we will interface AMICI using the experimental jax module [`host_callback`](https://jax.readthedocs.io/en/latest/jax.experimental.host_callback.html). " - ] - }, - { - "cell_type": "markdown", - "id": "6bbf2f06", - "metadata": {}, - "source": [ - "To do so, we define a base function that only takes a single argument (the parameters) and runs simulation using petab via [`simulate_petab`](https://amici.readthedocs.io/en/latest/generated/amici.petab_objective.html#amici.petab_objective.simulate_petab). To enable gradient computation later on, we create a solver object and set the sensitivity order to first order and pass it to `simulate_petab`. Moreover, `simulate_petab` expects a dictionary of parameters, so we create a dictionary using the free parameter ids from the petab problem. As we want to implement parameter transformation in JAX, we disable parameter scaling in petab by passing `scaled_parameters=True`." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "72053647", - "metadata": {}, - "outputs": [], - "source": [ - "from amici.petab.simulations import simulate_petab\n", - "import amici\n", - "\n", - "amici_solver = amici_model.getSolver()\n", - "amici_solver.setSensitivityOrder(amici.SensitivityOrder.first)\n", - "\n", - "\n", - "def amici_hcb_base(parameters: jnp.array):\n", - " return simulate_petab(\n", - " petab_problem,\n", - " amici_model,\n", - " problem_parameters=dict(zip(petab_problem.x_free_ids, parameters)),\n", - " scaled_parameters=True,\n", - " solver=amici_solver,\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "6f6201e8", - "metadata": {}, - "source": [ - "Now we can use this base function to create two functions separate functions that compute the log-likelihood (`llh`) and it's gradient (`sllh`) in two individual routines. Note that, as we are using the same base function here, the log-likelihood computation will also run with sensitivities which is not necessary and will add some overhead. This is only out of convenience and should be fixed in an application where efficiency is important." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "2dd50b53", - "metadata": {}, - "outputs": [], - "source": [ - "def amici_hcb_llh(parameters: jnp.array):\n", - " return amici_hcb_base(parameters)[\"llh\"]\n", - "\n", - "\n", - "def amici_hcb_sllh(parameters: jnp.array):\n", - " sllh = amici_hcb_base(parameters)[\"sllh\"]\n", - " return jnp.asarray(\n", - " tuple(sllh[par_id] for par_id in petab_problem.x_free_ids)\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "98e819bd", - "metadata": {}, - "source": [ - "Now we can finally define the JAX function that runs amici simulation using the host callback. We add a `custom_jvp` decorator so that we can define a custom jacobian vector product function in the next step. More details about custom jacobian vector product functions can be found in the [JAX documentation](https://jax.readthedocs.io/en/latest/notebooks/Custom_derivative_rules_for_Python_code.html)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "6e1f4f43", - "metadata": {}, - "outputs": [], - "source": [ - "import jax.experimental.host_callback as hcb\n", - "from jax import custom_jvp\n", - "\n", - "import numpy as np\n", - "\n", - "\n", - "@custom_jvp\n", - "def jax_objective(parameters: jnp.array):\n", - " return hcb.call(\n", - " amici_hcb_llh,\n", - " parameters,\n", - " result_shape=jax.ShapeDtypeStruct((), np.float64),\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "c75535a5", - "metadata": {}, - "source": [ - "Now we define the function that implement the jacobian vector product. This effectively just returns the objective function value (computed using the previously defined `jax_objective`) as well as the inner product of the gradient (computed using a host callback to the previously defined `amici_hcb_sllh`) and the tangents vector. Note that this implementation performs two simulation runs, one for the function value and one for the gradient, which is inefficient and could be avoided by caching solutions." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "5a68c812", - "metadata": {}, - "outputs": [], - "source": [ - "@jax_objective.defjvp\n", - "def jax_objective_jvp(primals: jnp.array, tangents: jnp.array):\n", - " (parameters,) = primals\n", - " (x_dot,) = tangents\n", - " llh = jax_objective(parameters)\n", - " sllh = hcb.call(\n", - " amici_hcb_sllh,\n", - " parameters,\n", - " result_shape=jax.ShapeDtypeStruct(\n", - " (petab_problem.parameter_df.estimate.sum(),), np.float64\n", - " ),\n", - " )\n", - " return llh, sllh.dot(x_dot)" - ] - }, - { - "cell_type": "markdown", - "id": "379485ca", - "metadata": {}, - "source": [ - "As last step, we implement the parameter transformation in jax. This effectively just extracts parameter scales from the petab problem, implements rescaling in jax and then passes the scaled parameters to the previously objective function we previously defined. We add the `value_and_grad` decorator such that the generated jax function returns both function value and function gradient in a tuple. Moreover, we add the `jax.jit` decorator such that the function is [just in time compiled](https://jax.readthedocs.io/en/latest/jax-101/02-jitting.html) upon the first function call." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "3ab8fde9", - "metadata": {}, - "outputs": [], - "source": [ - "from jax import value_and_grad\n", - "\n", - "parameter_scales = petab_problem.parameter_df.loc[\n", - " petab_problem.x_free_ids, petab.PARAMETER_SCALE\n", - "].values\n", - "\n", - "\n", - "@jax.jit\n", - "@value_and_grad\n", - "def jax_objective_with_parameter_transform(parameters: jnp.array):\n", - " par_scaled = jnp.asarray(\n", - " tuple(\n", - " value\n", - " if scale == petab.LIN\n", - " else jnp.log(value)\n", - " if scale == petab.LOG\n", - " else jnp.log10(value)\n", - " for value, scale in zip(parameters, parameter_scales)\n", - " )\n", - " )\n", - " return jax_objective(par_scaled)" - ] - }, - { - "cell_type": "markdown", - "id": "bce56636", - "metadata": {}, - "source": [ - "# Testing" - ] - }, - { - "cell_type": "markdown", - "id": "293e29fb", - "metadata": {}, - "source": [ - "We can now run the function to compute the log-likelihood and the gradient. " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "fb3085a8", - "metadata": {}, - "outputs": [], - "source": [ - "llh_jax, sllh_jax = jax_objective_with_parameter_transform(\n", - " petab_problem.x_nominal_free\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "6aa4a5f7", - "metadata": {}, - "source": [ - "As a sanity check, we compare the computed value to native parameter transformation in amici. " - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "48451b0e", - "metadata": {}, - "outputs": [], - "source": [ - "r = simulate_petab(petab_problem, amici_model, solver=amici_solver)\n", - "# TODO remove me as soon as sllh in simulate_petab is fixed\n", - "sllh = {\n", - " name: value / (np.log(10) * par_value)\n", - " for (name, value), par_value in zip(\n", - " r[\"sllh\"].items(), petab_problem.x_nominal_free\n", - " )\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "2628db12", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "amici -138.221997\n", - "jax -138.222000\n", - "dtype: float64" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "pd.Series(dict(amici=r[\"llh\"], jax=float(llh_jax)))" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "0846523f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
amicijax
Epo_degradation_BaF3-3.546026e-01-3.640394e-01
k_exp_hetero-2.401005e+03-2.401010e+03
k_exp_homo-4.073832e-01-4.106763e-01
k_imp_hetero-1.432855e-01-1.639030e-01
k_imp_homo2.006412e-102.006412e-10
k_phos-2.179950e-07-2.089803e-07
sd_pSTAT5A_rel-1.215545e-03-1.222887e-03
sd_pSTAT5B_rel-1.583889e-03-1.580870e-03
sd_rSTAT5A_rel-2.643776e-03-2.641361e-03
\n", - "
" - ], - "text/plain": [ - " amici jax\n", - "Epo_degradation_BaF3 -3.546026e-01 -3.640394e-01\n", - "k_exp_hetero -2.401005e+03 -2.401010e+03\n", - "k_exp_homo -4.073832e-01 -4.106763e-01\n", - "k_imp_hetero -1.432855e-01 -1.639030e-01\n", - "k_imp_homo 2.006412e-10 2.006412e-10\n", - "k_phos -2.179950e-07 -2.089803e-07\n", - "sd_pSTAT5A_rel -1.215545e-03 -1.222887e-03\n", - "sd_pSTAT5B_rel -1.583889e-03 -1.580870e-03\n", - "sd_rSTAT5A_rel -2.643776e-03 -2.641361e-03" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.DataFrame(\n", - " index=sllh.keys(), data=dict(amici=sllh.values(), jax=np.asarray(sllh_jax))\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "4b00dcb2", - "metadata": {}, - "source": [ - "We see quite some differences in the gradient calculation. The primary reason is that running JAX in default configuration will use float32 precision for the parameters that are passed to AMICI, which uses float64, and the derivative of the parameter transformation \n", - "As AMICI simulations that run on the CPU are the most expensive operation, there is barely any tradeoff for using float32 vs float64 in JAX. Therefore, we configure JAX to use float64 instead and rerun simulations." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "5f81c693", - "metadata": {}, - "outputs": [], - "source": [ - "jax.config.update(\"jax_enable_x64\", True)\n", - "llh_jax, sllh_jax = jax_objective_with_parameter_transform(\n", - " petab_problem.x_nominal_free\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "ab39311d", - "metadata": {}, - "source": [ - "We can now evaluate the results again and see that differences between pure AMICI and AMICI/JAX implementations are now much smaller." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "25e8b301", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "amici -138.221997\n", - "jax -138.221997\n", - "dtype: float64" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.Series(dict(amici=r[\"llh\"], jax=float(llh_jax)))" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "f31a3927", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
amicijax
Epo_degradation_BaF3-3.546026e-01-3.546504e-01
k_exp_hetero-2.401005e+03-2.401005e+03
k_exp_homo-4.073832e-01-4.074248e-01
k_imp_hetero-1.432855e-01-1.433139e-01
k_imp_homo2.006412e-102.006412e-10
k_phos-2.179950e-07-2.179076e-07
sd_pSTAT5A_rel-1.215545e-03-1.215596e-03
sd_pSTAT5B_rel-1.583889e-03-1.583805e-03
sd_rSTAT5A_rel-2.643776e-03-2.643703e-03
\n", - "
" - ], - "text/plain": [ - " amici jax\n", - "Epo_degradation_BaF3 -3.546026e-01 -3.546504e-01\n", - "k_exp_hetero -2.401005e+03 -2.401005e+03\n", - "k_exp_homo -4.073832e-01 -4.074248e-01\n", - "k_imp_hetero -1.432855e-01 -1.433139e-01\n", - "k_imp_homo 2.006412e-10 2.006412e-10\n", - "k_phos -2.179950e-07 -2.179076e-07\n", - "sd_pSTAT5A_rel -1.215545e-03 -1.215596e-03\n", - "sd_pSTAT5B_rel -1.583889e-03 -1.583805e-03\n", - "sd_rSTAT5A_rel -2.643776e-03 -2.643703e-03" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.DataFrame(\n", - " index=sllh.keys(), data=dict(amici=sllh.values(), jax=np.asarray(sllh_jax))\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/documentation/ExampleJax.ipynb b/documentation/ExampleJax.ipynb new file mode 120000 index 0000000000..af2929d76b --- /dev/null +++ b/documentation/ExampleJax.ipynb @@ -0,0 +1 @@ +../python/examples/example_jax/ExampleJax.ipynb \ No newline at end of file diff --git a/documentation/conf.py b/documentation/conf.py index 8b2379a299..25c6dab647 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -9,19 +9,33 @@ import subprocess import sys from enum import EnumType - -# need to import before setting typing.TYPE_CHECKING=True, fails otherwise -import amici import exhale.deploy -import exhale_multiproject_monkeypatch from unittest import mock -import pandas as pd import sphinx -import sympy as sp from exhale import configs as exhale_configs from sphinx.transforms.post_transforms import ReferencesResolver -exhale_multiproject_monkeypatch, pd, sp # to avoid removal of unused import +try: + import exhale_multiproject_monkeypatch # noqa: F401 +except ModuleNotFoundError: + # for unclear reasons, the import of exhale_multiproject_monkeypatch + # fails on some systems, because the the location of the editable install + # is not automatically added to sys.path ¯\_(ツ)_/¯ + from importlib.metadata import Distribution + import json + from urllib.parse import unquote_plus, urlparse + + dist = Distribution.from_name("sphinx-contrib-exhale-multiproject") + url = json.loads(dist.read_text("direct_url.json"))["url"] + package_dir = unquote_plus(urlparse(url).path) + sys.path.append(package_dir) + import exhale_multiproject_monkeypatch # noqa: F401 + +# need to import before setting typing.TYPE_CHECKING=True, fails otherwise +import amici +import pandas as pd # noqa: F401 +import sympy as sp # noqa: F401 + # BEGIN Monkeypatch exhale from exhale.deploy import _generate_doxygen as exhale_generate_doxygen diff --git a/documentation/python_modules.rst b/documentation/python_modules.rst index 2ec565c5fa..2607447f0d 100644 --- a/documentation/python_modules.rst +++ b/documentation/python_modules.rst @@ -12,6 +12,7 @@ AMICI Python API amici.pysb_import amici.bngl_import amici.petab + amici.petab.conditions amici.petab.import_helpers amici.petab.parameter_mapping amici.petab.petab_import diff --git a/include/amici/defines.h b/include/amici/defines.h index f5ed1e62bb..6ccba89923 100644 --- a/include/amici/defines.h +++ b/include/amici/defines.h @@ -68,8 +68,10 @@ constexpr int AMICI_TOO_MUCH_WORK= -1; constexpr int AMICI_TOO_MUCH_ACC= -2; constexpr int AMICI_ERR_FAILURE= -3; constexpr int AMICI_CONV_FAILURE= -4; +constexpr int AMICI_LSETUP_FAIL= -6; constexpr int AMICI_RHSFUNC_FAIL= -8; constexpr int AMICI_FIRST_RHSFUNC_ERR= -9; +constexpr int AMICI_CONSTR_FAIL= -15; constexpr int AMICI_ILL_INPUT= -22; constexpr int AMICI_ERROR= -99; constexpr int AMICI_NO_STEADY_STATE= -81; @@ -254,6 +256,15 @@ enum class SplineExtrapolation { periodic = 3, }; +/** Constraints on state variables */ +enum class Constraint { + none = 0, + non_negative = 1, + non_positive = -1, + positive = 2, + negative = -2, +}; + // clang-format on } // namespace amici diff --git a/include/amici/forwardproblem.h b/include/amici/forwardproblem.h index 8c500bf73c..67658ebee4 100644 --- a/include/amici/forwardproblem.h +++ b/include/amici/forwardproblem.h @@ -316,7 +316,7 @@ class ForwardProblem { * @brief Creates a carbon copy of the current simulation state variables * @return state */ - SimulationState getSimulationState() const; + SimulationState getSimulationState(); /** array of index vectors (dimension ne) indicating whether the respective * root has been detected for all so far encountered discontinuities, diff --git a/include/amici/model.h b/include/amici/model.h index 13de007e00..29b98aa913 100644 --- a/include/amici/model.h +++ b/include/amici/model.h @@ -1334,10 +1334,12 @@ class Model : public AbstractModel, public ModelDimensions { * * @param array * @param model_quantity The model quantity `array` corresponds to + * @param t Current timepoint * @return */ int checkFinite( - gsl::span array, ModelQuantity model_quantity + gsl::span array, ModelQuantity model_quantity, + realtype t ) const; /** * @brief Check if the given array has only finite elements. @@ -1347,11 +1349,12 @@ class Model : public AbstractModel, public ModelDimensions { * @param array Flattened matrix * @param model_quantity The model quantity `array` corresponds to * @param num_cols Number of columns of the non-flattened matrix + * @param t Current timepoint * @return */ int checkFinite( gsl::span array, ModelQuantity model_quantity, - size_t num_cols + size_t num_cols, realtype t ) const; /** diff --git a/include/amici/rdata.h b/include/amici/rdata.h index 6357d24748..b5b4c269b4 100644 --- a/include/amici/rdata.h +++ b/include/amici/rdata.h @@ -104,12 +104,12 @@ class ReturnData : public ModelDimensions { */ std::vector ts; - /** time derivative (shape `nx`) */ + /** time derivative (shape `nx`) evaluated at `t_last`. */ std::vector xdot; /** * Jacobian of differential equation right hand side (shape `nx` x `nx`, - * row-major) + * row-major) evaluated at `t_last`. */ std::vector J; @@ -456,6 +456,9 @@ class ReturnData : public ModelDimensions { /** log messages */ std::vector messages; + /** The final internal time of the solver. */ + realtype t_last{std::numeric_limits::quiet_NaN()}; + protected: /** offset for sigma_residuals */ realtype sigma_offset; diff --git a/include/amici/serialization.h b/include/amici/serialization.h index 6cab4f0353..e4b1e3afe5 100644 --- a/include/amici/serialization.h +++ b/include/amici/serialization.h @@ -5,6 +5,7 @@ #include "amici/rdata.h" #include "amici/solver.h" #include "amici/solver_cvodes.h" +#include "amici/vector.h" #include @@ -85,6 +86,10 @@ void serialize(Archive& ar, amici::Solver& s, unsigned int const /*version*/) { ar & s.check_sensi_steadystate_conv_; ar & s.rdata_mode_; ar & s.maxtime_; + ar & s.max_conv_fails_; + ar & s.max_nonlin_iters_; + ar & s.constraints_; + ar & s.max_step_size_; } /** @@ -275,6 +280,25 @@ void serialize( ar & m.ubw; ar & m.lbw; } + +/** + * @brief Serialize AmiVector to a boost archive + * @param ar archive + * @param v AmiVector + */ +template +void serialize( + Archive& ar, amici::AmiVector& v, unsigned int const /*version*/ +) { + if (Archive::is_loading::value) { + std::vector tmp; + ar & tmp; + v = amici::AmiVector(tmp); + } else { + auto tmp = v.getVector(); + ar & tmp; + } +} #endif } // namespace serialization } // namespace boost diff --git a/include/amici/solver.h b/include/amici/solver.h index 92ae4c47fb..661a9fac25 100644 --- a/include/amici/solver.h +++ b/include/amici/solver.h @@ -936,6 +936,64 @@ class Solver { check_sensi_steadystate_conv_ = flag; } + /** + * @brief Set the maximum number of nonlinear solver iterations permitted + * per step. + * @param max_nonlin_iters maximum number of nonlinear solver iterations + */ + void setMaxNonlinIters(int max_nonlin_iters); + + /** + * @brief Get the maximum number of nonlinear solver iterations permitted + * per step. + * @return maximum number of nonlinear solver iterations + */ + int getMaxNonlinIters() const; + + /** + * @brief Set the maximum number of nonlinear solver convergence failures + * permitted per step. + * @param max_conv_fails maximum number of nonlinear solver convergence + */ + void setMaxConvFails(int max_conv_fails); + + /** + * @brief Get the maximum number of nonlinear solver convergence failures + * permitted per step. + * @return maximum number of nonlinear solver convergence + */ + int getMaxConvFails() const; + + /** + * @brief Set constraints on the model state. + * + * See + * https://sundials.readthedocs.io/en/latest/cvode/Usage/index.html#c.CVodeSetConstraints. + * + * @param constraints + */ + void setConstraints(std::vector const& constraints); + + /** + * @brief Get constraints on the model state. + * @return constraints + */ + std::vector getConstraints() const { + return constraints_.getVector(); + } + + /** + * @brief Set the maximum step size + * @param max_step_size maximum step size. `0.0` means no limit. + */ + void setMaxStepSize(realtype max_step_size); + + /** + * @brief Get the maximum step size + * @return maximum step size + */ + realtype getMaxStepSize() const; + /** * @brief Serialize Solver (see boost::serialization::serialize) * @param ar Archive to serialize to @@ -1090,7 +1148,7 @@ class Solver { virtual void rootInit(int ne) const = 0; /** - * @brief Initalize non-linear solver for sensitivities + * @brief Initialize non-linear solver for sensitivities * @param model Model instance */ void initializeNonLinearSolverSens(Model const* model) const; @@ -1608,6 +1666,11 @@ class Solver { */ void applySensitivityTolerances() const; + /** + * @brief Apply the constraints to the solver. + */ + virtual void apply_constraints() const; + /** pointer to solver memory block */ mutable std::unique_ptr solver_memory_; @@ -1712,6 +1775,23 @@ class Solver { SensitivityMethod const sensi_meth, bool preequilibration ) const; + /** + * @brief Apply the maximum number of nonlinear solver iterations permitted + * per step. + */ + virtual void apply_max_nonlin_iters() const = 0; + + /** + * @brief Apply the maximum number of nonlinear solver convergence failures + * permitted per step. + */ + virtual void apply_max_conv_fails() const = 0; + + /** + * @brief Apply the allowed maximum stepsize to the solver. + */ + virtual void apply_max_step_size() const = 0; + /** state (dimension: nx_solver) */ mutable AmiVector x_{0}; @@ -1752,6 +1832,9 @@ class Solver { /** flag indicating whether sensInit1 was called */ mutable bool sens_initialized_{false}; + /** Vector of constraints on the solution */ + mutable AmiVector constraints_; + private: /** * @brief applies total number of steps for next solver call @@ -1844,6 +1927,16 @@ class Solver { */ bool check_sensi_steadystate_conv_{true}; + /** Maximum number of nonlinear solver iterations permitted per step */ + int max_nonlin_iters_{3}; + + /** Maximum number of nonlinear solver convergence failures permitted per + * step */ + int max_conv_fails_{10}; + + /** Maximum allowed step size */ + realtype max_step_size_{0.0}; + /** CPU time, forward solve */ mutable realtype cpu_time_{0.0}; diff --git a/include/amici/solver_cvodes.h b/include/amici/solver_cvodes.h index f98fb34c1a..8d04b22a34 100644 --- a/include/amici/solver_cvodes.h +++ b/include/amici/solver_cvodes.h @@ -249,6 +249,14 @@ class CVodeSolver : public Solver { void setJacTimesVecFnB(int which) const override; void setSparseJacFn_ss() const override; + + void apply_max_nonlin_iters() const override; + + void apply_max_conv_fails() const override; + + void apply_constraints() const override; + + void apply_max_step_size() const override; }; } // namespace amici diff --git a/include/amici/solver_idas.h b/include/amici/solver_idas.h index b985a090af..c8efc69c0c 100644 --- a/include/amici/solver_idas.h +++ b/include/amici/solver_idas.h @@ -229,6 +229,14 @@ class IDASolver : public Solver { void setJacTimesVecFnB(int which) const override; void setSparseJacFn_ss() const override; + + void apply_max_nonlin_iters() const override; + + void apply_max_conv_fails() const override; + + void apply_constraints() const override; + + void apply_max_step_size() const override; }; } // namespace amici diff --git a/include/amici/vector.h b/include/amici/vector.h index b1b496c26e..486ea77682 100644 --- a/include/amici/vector.h +++ b/include/amici/vector.h @@ -10,6 +10,18 @@ #include +namespace amici { +class AmiVector; +} + +// for serialization friend +namespace boost { +namespace serialization { +template +void serialize(Archive& ar, amici::AmiVector& s, unsigned int version); +} +} // namespace boost + namespace amici { /** Since const N_Vector is not what we want */ @@ -54,7 +66,7 @@ class AmiVector { * @brief constructor from gsl::span, * @param rvec vector from which the data will be copied */ - explicit AmiVector(gsl::span rvec) + explicit AmiVector(gsl::span rvec) : AmiVector(std::vector(rvec.begin(), rvec.end())) {} /** @@ -213,6 +225,17 @@ class AmiVector { */ void abs() { N_VAbs(getNVector(), getNVector()); }; + /** + * @brief Serialize AmiVector (see boost::serialization::serialize) + * @param ar Archive to serialize to + * @param s Data to serialize + * @param version Version number + */ + template + friend void boost::serialization::serialize( + Archive& ar, AmiVector& s, unsigned int version + ); + private: /** main data storage */ std::vector vec_; @@ -405,6 +428,16 @@ namespace gsl { inline span make_span(N_Vector nv) { return span(N_VGetArrayPointer(nv), N_VGetLength_Serial(nv)); } + +/** + * @brief Create span from N_Vector + * @param nv + * + */ +inline span make_span(amici::AmiVector const& av) { + return make_span(av.getVector()); +} + } // namespace gsl #endif /* AMICI_VECTOR_H */ diff --git a/python/examples/example_jax/ExampleJax.ipynb b/python/examples/example_jax/ExampleJax.ipynb index 62391ce9be..931dfb7e28 100644 --- a/python/examples/example_jax/ExampleJax.ipynb +++ b/python/examples/example_jax/ExampleJax.ipynb @@ -5,7 +5,10 @@ "id": "d4d2bc5c", "metadata": {}, "source": [ - "# Overview\n", + "# AMICI & JAX\n", + "\n", + "## Overview\n", + "\n", "The purpose of this guide is to showcase how AMICI can be combined with differentiable programming in [JAX](https://jax.readthedocs.io/en/latest/index.html). We will do so by reimplementing the parameter transformations available in AMICI in JAX and comparing it to the native implementation." ] }, @@ -25,9 +28,9 @@ "id": "fb2fe897", "metadata": {}, "source": [ - "# Preparation\n", + "## Preparation\n", "\n", - "To get started we will import a model using the [petab](https://petab.readthedocs.io). To this end, we will use the [benchmark collection](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab), which features a variety of different models. For more details about petab import, see the respective notebook petab [notebook](https://amici.readthedocs.io/en/latest/petab.html)." + "To get started, we will import a model using the [petab](https://petab.readthedocs.io). To this end, we will use the [benchmark collection](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab), which features a variety of different models. For more details about petab import, see the respective notebook petab [notebook](https://amici.readthedocs.io/en/latest/petab.html)." ] }, { @@ -274,7 +277,7 @@ "id": "e2ef051a", "metadata": {}, "source": [ - "# JAX implementation\n", + "## JAX implementation\n", "\n", "For full jax support, we would have to implement a new [primitive](https://jax.readthedocs.io/en/latest/notebooks/How_JAX_primitives_work.html), which would require quite a bit of engineering, and in the end wouldn't add much benefit since AMICI can't run on GPUs. Instead, will interface AMICI using the experimental jax module [host_callback](https://jax.readthedocs.io/en/latest/jax.experimental.host_callback.html)." ] @@ -439,7 +442,7 @@ "id": "293e29fb", "metadata": {}, "source": [ - "# Testing\n", + "## Testing\n", "\n", "We can now run the function to compute the log-likelihood and the gradient." ] @@ -473,7 +476,7 @@ "id": "6aa4a5f7", "metadata": {}, "source": [ - "As a sanity check, we compare the computed value to native parameter transformation in amici. " + "As a sanity check, we compare the computed value to native parameter transformation in amici." ] }, { diff --git a/python/sdist/amici/MANIFEST.template.in b/python/sdist/amici/MANIFEST.template.in index eb3b1b450f..fd78129853 100644 --- a/python/sdist/amici/MANIFEST.template.in +++ b/python/sdist/amici/MANIFEST.template.in @@ -1 +1,3 @@ include *.cpp *.h +include CMakeLists.txt +recursive-include swig/ * diff --git a/python/sdist/amici/cxxcodeprinter.py b/python/sdist/amici/cxxcodeprinter.py index adc4c25454..fb98b0aca0 100644 --- a/python/sdist/amici/cxxcodeprinter.py +++ b/python/sdist/amici/cxxcodeprinter.py @@ -339,7 +339,7 @@ def csc_matrix( for col in range(ncols): symbol_col_ptrs.append(idx) for row in range(nrows): - if matrix[row, col] == 0: + if matrix[row, col].is_zero: continue symbol_row_vals.append(row) diff --git a/python/sdist/amici/de_model.py b/python/sdist/amici/de_model.py index b69cc6ba68..ea2807df52 100644 --- a/python/sdist/amici/de_model.py +++ b/python/sdist/amici/de_model.py @@ -2115,7 +2115,7 @@ def state_is_constant(self, ix: int) -> bool: if isinstance(state, AlgebraicState): return False - return state.get_dt() == 0.0 + return state.get_dt().is_zero def conservation_law_has_multispecies(self, tcl: ConservationLaw) -> bool: """ @@ -2179,7 +2179,7 @@ def _get_unique_root( return None for root in roots: - if sp.simplify(root_found - root.get_val()) == 0: + if sp.simplify(root_found - root.get_val()).is_zero: return root.get_id() # create an event for a new root function diff --git a/python/sdist/amici/numpy.py b/python/sdist/amici/numpy.py index 6e2966ba4b..f40d0f4c6e 100644 --- a/python/sdist/amici/numpy.py +++ b/python/sdist/amici/numpy.py @@ -9,7 +9,7 @@ import itertools from typing import Literal, Union from collections.abc import Iterator - +from numbers import Number import amici import numpy as np import sympy as sp @@ -55,15 +55,18 @@ def __getitem__(self, item: str) -> Union[np.ndarray, float]: if item in self._cache: return self._cache[item] - if item == "id": - return getattr(self._swigptr, item) + if item in self._field_names: + value = _field_as_numpy( + self._field_dimensions, item, self._swigptr + ) + self._cache[item] = value - if item not in self._field_names: - self.__missing__(item) + return value - value = _field_as_numpy(self._field_dimensions, item, self._swigptr) - self._cache[item] = value - return value + if not item.startswith("_") and hasattr(self._swigptr, item): + return getattr(self._swigptr, item) + + self.__missing__(item) def __missing__(self, key: str) -> None: """ @@ -238,6 +241,8 @@ class ReturnDataView(SwigPtrView): "numnonlinsolvconvfailsB", "cpu_timeB", "cpu_time_total", + "messages", + "t_last", ] def __init__(self, rdata: Union[ReturnDataPtr, ReturnData]): @@ -440,7 +445,11 @@ def _field_as_numpy( attr = getattr(data, field) if field_dim := field_dimensions.get(field, None): return None if len(attr) == 0 else np.array(attr).reshape(field_dim) - return float(attr) + + if isinstance(attr, Number): + return float(attr) + + return attr def _entity_type_from_id( diff --git a/python/sdist/amici/pandas.py b/python/sdist/amici/pandas.py index 745cbfb767..b776d2d5ef 100644 --- a/python/sdist/amici/pandas.py +++ b/python/sdist/amici/pandas.py @@ -410,6 +410,20 @@ def _fill_conditions_dict( ] else: datadict[par + "_presim"] = np.nan + + for i_par, par in enumerate( + _get_names_or_ids(model, "Parameter", by_id=by_id) + ): + if len(edata.parameters): + datadict[par] = edata.parameters[i_par] + else: + datadict[par] = model.getParameters()[i_par] + + if len(edata.pscale): + datadict[par + "_scale"] = edata.pscale[i_par] + else: + datadict[par + "_scale"] = model.getParameterScale()[i_par] + return datadict @@ -438,6 +452,11 @@ def _get_extended_observable_cols(model: AmiciModel, by_id: bool) -> list[str]: name + "_presim" for name in _get_names_or_ids(model, "FixedParameter", by_id=by_id) ] + + _get_names_or_ids(model, "Parameter", by_id=by_id) + + [ + name + "_scale" + for name in _get_names_or_ids(model, "Parameter", by_id=by_id) + ] + _get_names_or_ids(model, "Observable", by_id=by_id) + [ name + "_std" @@ -471,6 +490,11 @@ def _get_observable_cols(model: AmiciModel, by_id: bool) -> list[str]: name + "_presim" for name in _get_names_or_ids(model, "FixedParameter", by_id=by_id) ] + + _get_names_or_ids(model, "Parameter", by_id=by_id) + + [ + name + "_scale" + for name in _get_names_or_ids(model, "Parameter", by_id=by_id) + ] + _get_names_or_ids(model, "Observable", by_id=by_id) ) @@ -500,6 +524,11 @@ def _get_state_cols(model: AmiciModel, by_id: bool) -> list[str]: name + "_presim" for name in _get_names_or_ids(model, "FixedParameter", by_id=by_id) ] + + _get_names_or_ids(model, "Parameter", by_id=by_id) + + [ + name + "_scale" + for name in _get_names_or_ids(model, "Parameter", by_id=by_id) + ] + _get_names_or_ids(model, "State", by_id=by_id) ) @@ -528,6 +557,11 @@ def _get_expression_cols(model: AmiciModel, by_id: bool) -> list[str]: name + "_presim" for name in _get_names_or_ids(model, "FixedParameter", by_id=by_id) ] + + _get_names_or_ids(model, "Parameter", by_id=by_id) + + [ + name + "_scale" + for name in _get_names_or_ids(model, "Parameter", by_id=by_id) + ] + _get_names_or_ids(model, "Expression", by_id=by_id) ) @@ -641,10 +675,11 @@ def constructEdataFromDataFrame( Model instance. :param condition: - pd.Series with FixedParameter Names/Ids as columns. + pd.Series with (Fixed)Parameter Names/Ids as columns. Preequilibration conditions may be specified by appending '_preeq' as suffix. Presimulation conditions may be specified by - appending '_presim' as suffix. + appending '_presim' as suffix. Parameter scales may be specified by + appending '_scale' as suffix. :param by_id: Indicate whether in the arguments, column headers are based on ids or @@ -681,6 +716,20 @@ def constructEdataFromDataFrame( .values ) + # fill in parameters + edata.parameters = ( + condition[_get_names_or_ids(model, "Parameter", by_id=by_id)] + .astype(float) + .values + ) + + edata.pscale = amici.parameterScalingFromIntVector( + [ + amici.ParameterScaling(condition[par + "_scale"].astype(int)) + for par in list(_get_names_or_ids(model, "Parameter", by_id=by_id)) + ] + ) + # fill in preequilibration parameters if any( [overwrite_preeq[key] != condition[key] for key in overwrite_preeq] @@ -767,6 +816,10 @@ def getEdataFromDataFrame( condition_parameters.append(par + "_preeq") if par + "_presim" in df.columns: condition_parameters.append(par + "_presim") + # parameters & scales + for par in _get_names_or_ids(model, "Parameter", by_id=by_id): + condition_parameters.append(par) + condition_parameters.append(par + "_scale") # presimulation time if "t_presim" in df.columns: condition_parameters.append("t_presim") diff --git a/python/sdist/amici/petab/parameter_mapping.py b/python/sdist/amici/petab/parameter_mapping.py index 9c527f0395..369ad13a96 100644 --- a/python/sdist/amici/petab/parameter_mapping.py +++ b/python/sdist/amici/petab/parameter_mapping.py @@ -486,12 +486,11 @@ def create_parameter_mapping_for_condition( condition_scale_map_preeq, preeq_value, ) - else: - # need to set dummy value for preeq parameter anyways, as it - # is expected below (set to 0, not nan, because will be - # multiplied with indicator variable in initial assignment) - condition_map_sim[init_par_id] = 0.0 - condition_scale_map_sim[init_par_id] = LIN + # need to set dummy value for preeq parameter anyways, as it + # is expected below (set to 0, not nan, because will be + # multiplied with indicator variable in initial assignment) + condition_map_sim[init_par_id] = 0.0 + condition_scale_map_sim[init_par_id] = LIN # for simulation condition_id = condition[SIMULATION_CONDITION_ID] @@ -505,6 +504,10 @@ def create_parameter_mapping_for_condition( condition_scale_map_sim, value, ) + # set dummy value as above + if condition_map_preeq: + condition_map_preeq[init_par_id] = 0.0 + condition_scale_map_preeq[init_par_id] = LIN ########################################################################## # separate fixed and variable AMICI parameters, because we may have diff --git a/python/sdist/amici/petab/petab_import.py b/python/sdist/amici/petab/petab_import.py index 902bf837ef..cb896b39e3 100644 --- a/python/sdist/amici/petab/petab_import.py +++ b/python/sdist/amici/petab/petab_import.py @@ -10,6 +10,7 @@ import shutil from pathlib import Path from typing import Union +from warnings import warn import amici import petab diff --git a/python/sdist/amici/petab/sbml_import.py b/python/sdist/amici/petab/sbml_import.py index 6388d6f8b0..2484d57a7a 100644 --- a/python/sdist/amici/petab/sbml_import.py +++ b/python/sdist/amici/petab/sbml_import.py @@ -300,6 +300,8 @@ def import_model_sbml( init_par = sbml_model.createParameter() init_par.setId(init_par_id) init_par.setName(init_par_id) + # must be a fixed parameter in any case to allow reinitialization + fixed_parameters.append(init_par_id) assignment = sbml_model.getInitialAssignment(assignee_id) if assignment is None: assignment = sbml_model.createInitialAssignment() @@ -518,14 +520,26 @@ def _get_fixed_parameters_sbml( petab_problem, non_estimated_parameters_as_constants ) - # exclude targets of rules or initial assignments + # exclude targets of rules or initial assignments that are not numbers sbml_model = petab_problem.model.sbml_model + parser_settings = libsbml.L3ParserSettings() + parser_settings.setModel(sbml_model) + parser_settings.setParseUnits(libsbml.L3P_NO_UNITS) + for fixed_parameter in fixed_parameters.copy(): # check global parameters - if sbml_model.getInitialAssignmentBySymbol( - fixed_parameter - ) or sbml_model.getRuleByVariable(fixed_parameter): + if sbml_model.getRuleByVariable(fixed_parameter): fixed_parameters.remove(fixed_parameter) + continue + if ia := sbml_model.getInitialAssignmentBySymbol(fixed_parameter): + sym_math = sp.sympify( + libsbml.formulaToL3StringWithSettings( + ia.getMath(), parser_settings + ) + ) + if not sym_math.evalf().is_Number: + fixed_parameters.remove(fixed_parameter) + continue return list(sorted(fixed_parameters)) diff --git a/python/sdist/amici/plotting.py b/python/sdist/amici/plotting.py index 25607638d7..19dbe05f89 100644 --- a/python/sdist/amici/plotting.py +++ b/python/sdist/amici/plotting.py @@ -12,6 +12,7 @@ import seaborn as sns from matplotlib.axes import Axes +import amici from . import Model, ReturnDataView from .numpy import StrOrExpr, evaluate @@ -66,10 +67,11 @@ def plot_state_trajectories( for ix, label in zip(state_indices, labels): ax.plot(rdata["t"], rdata["x"][:, ix], marker=marker, label=label) - ax.set_xlabel("$t$") - ax.set_ylabel("$x(t)$") - ax.legend() - ax.set_title("State trajectories") + + ax.set_xlabel("$t$") + ax.set_ylabel("$x(t)$") + ax.legend() + ax.set_title("State trajectories") def plot_observable_trajectories( @@ -79,6 +81,7 @@ def plot_observable_trajectories( model: Model = None, prefer_names: bool = True, marker=None, + edata: Union[amici.ExpData, amici.ExpDataView] = None, ) -> None: """ Plot observable trajectories. @@ -97,12 +100,16 @@ def plot_observable_trajectories( :param marker: Point marker for plotting (see `matplotlib documentation `_). - + :param edata: + Experimental data to be plotted (no event observables yet). """ + if isinstance(edata, amici.amici.ExpData): + edata = amici.ExpDataView(edata) + if not ax: fig, ax = plt.subplots() if not observable_indices: - observable_indices = range(rdata["y"].shape[1]) + observable_indices = range(rdata.ny) if marker is None: # Show marker if only one time point is available, @@ -125,11 +132,30 @@ def plot_observable_trajectories( labels = np.asarray(rdata.ptr.observable_ids)[list(observable_indices)] for iy, label in zip(observable_indices, labels): - ax.plot(rdata["t"], rdata["y"][:, iy], marker=marker, label=label) - ax.set_xlabel("$t$") - ax.set_ylabel("$y(t)$") - ax.legend() - ax.set_title("Observable trajectories") + (l,) = ax.plot( + rdata["t"], rdata["y"][:, iy], marker=marker, label=label + ) + + if edata is not None: + ax.plot( + edata.ts, + edata.observedData[:, iy], + "x", + label=f"exp. {label}", + color=l.get_color(), + ) + ax.errorbar( + edata.ts, + edata.observedData[:, iy], + yerr=rdata.sigmay[:, iy], + fmt="none", + color=l.get_color(), + ) + + ax.set_xlabel("$t$") + ax.set_ylabel("$y(t)$") + ax.set_title("Observable trajectories") + ax.legend() def plot_jacobian(rdata: ReturnDataView): diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index 61cb79043e..8f7f67b02f 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -187,18 +187,11 @@ def __init__( self._reset_symbols() - # http://sbml.org/Software/libSBML/5.18.0/docs/python-api/classlibsbml_1_1_l3_parser_settings.html#abcfedd34efd3cae2081ba8f42ea43f52 + # https://sbml.org/software/libsbml/5.18.0/docs/formatted/python-api/classlibsbml_1_1_l3_parser_settings.html#ab30d7ed52ca24cbb842d0a7fed7f4bfd # all defaults except disable unit parsing - self.sbml_parser_settings = sbml.L3ParserSettings( - self.sbml, - sbml.L3P_PARSE_LOG_AS_LOG10, - sbml.L3P_EXPAND_UNARY_MINUS, - sbml.L3P_NO_UNITS, - sbml.L3P_AVOGADRO_IS_CSYMBOL, - sbml.L3P_COMPARE_BUILTINS_CASE_INSENSITIVE, - None, - sbml.L3P_MODULO_IS_PIECEWISE, - ) + self.sbml_parser_settings = sbml.L3ParserSettings() + self.sbml_parser_settings.setModel(self.sbml) + self.sbml_parser_settings.setParseUnits(sbml.L3P_NO_UNITS) self._discard_annotations: bool = discard_annotations @@ -1143,7 +1136,12 @@ def _process_parameters( # parameter ID => initial assignment sympy expression par_id_to_ia = { - par.getId(): ia + par.getId(): ia.subs( + { + BooleanTrue(): sp.Float(1.0), + BooleanFalse(): sp.Float(0.0), + } + ).evalf() for par in self.sbml.getListOfParameters() if (ia := self._get_element_initial_assignment(par.getId())) is not None diff --git a/python/sdist/amici/swig.py b/python/sdist/amici/swig.py index 902145ff3e..5ba8017005 100644 --- a/python/sdist/amici/swig.py +++ b/python/sdist/amici/swig.py @@ -1,11 +1,12 @@ """Functions related to SWIG or SWIG-generated code""" +from __future__ import annotations import ast import contextlib import re class TypeHintFixer(ast.NodeTransformer): - """Replaces SWIG-generated C++ typehints by corresponding Python types""" + """Replaces SWIG-generated C++ typehints by corresponding Python types.""" mapping = { "void": None, @@ -15,6 +16,7 @@ class TypeHintFixer(ast.NodeTransformer): "ptrdiff_t": ast.Name("int"), "size_t": ast.Name("int"), "bool": ast.Name("bool"), + "boolean": ast.Name("bool"), "std::unique_ptr< amici::Solver >": ast.Constant("Solver"), "amici::InternalSensitivityMethod": ast.Constant( "InternalSensitivityMethod" @@ -40,8 +42,10 @@ class TypeHintFixer(ast.NodeTransformer): "SteadyStateSensitivityMode" ), "amici::realtype": ast.Name("float"), - "DoubleVector": ast.Constant("Sequence[float]"), + "DoubleVector": ast.Name("Sequence[float]"), + "BoolVector": ast.Name("Sequence[bool]"), "IntVector": ast.Name("Sequence[int]"), + "StringVector": ast.Name("Sequence[str]"), "std::string": ast.Name("str"), "std::string const &": ast.Name("str"), "std::unique_ptr< amici::ExpData >": ast.Constant("ExpData"), @@ -50,11 +54,17 @@ class TypeHintFixer(ast.NodeTransformer): "std::allocator< amici::ParameterScaling > > const &": ast.Constant( "ParameterScalingVector" ), + "H5::H5File": None, } def visit_FunctionDef(self, node): + # convert type/rtype from docstring to annotation, if possible. + # those may be c++ types, not valid in python, that need to be + # converted to python types below. + self._annotation_from_docstring(node) + # Has a return type annotation? - if node.returns: + if node.returns and isinstance(node.returns, ast.Constant): node.returns = self._new_annot(node.returns.value) # Has arguments? @@ -62,14 +72,17 @@ def visit_FunctionDef(self, node): for arg in node.args.args: if not arg.annotation: continue - if isinstance(arg.annotation, ast.Name): + if not isinstance(arg.annotation, ast.Constant): # there is already proper annotation continue arg.annotation = self._new_annot(arg.annotation.value) return node - def _new_annot(self, old_annot: str): + def _new_annot(self, old_annot: str | ast.Name): + if isinstance(old_annot, ast.Name): + old_annot = old_annot.id + with contextlib.suppress(KeyError): return self.mapping[old_annot] @@ -103,13 +116,87 @@ def _new_annot(self, old_annot: str): return ast.Constant(old_annot) + def _annotation_from_docstring(self, node: ast.FunctionDef): + """Add annotations based on docstring. + + If any argument or return type of the function is not annotated, but + the corresponding docstring contains a type hint (``:rtype:`` or + ``:type:``), the type hint is used as the annotation. + + Swig sometimes generates ``:type solver: :py:class:`Solver`` instead of + ``:type solver: Solver``. Those need special treatment. + + Overloaded functions are skipped. + """ + docstring = ast.get_docstring(node, clean=False) + if not docstring or "*Overload 1:*" in docstring: + # skip overloaded methods + return + + docstring = docstring.split("\n") + lines_to_remove = set() + + for line_no, line in enumerate(docstring): + if type_str := self.extract_rtype(line): + # handle `:rtype:` + node.returns = ast.Constant(type_str) + lines_to_remove.add(line_no) + continue + + arg_name, type_str = self.extract_type(line) + if arg_name is not None: + # handle `:type ...:` + for arg in node.args.args: + if arg.arg == arg_name: + arg.annotation = ast.Constant(type_str) + lines_to_remove.add(line_no) + + if lines_to_remove: + # Update docstring with type annotations removed + assert isinstance(node.body[0].value, ast.Constant) + new_docstring = "\n".join( + line + for line_no, line in enumerate(docstring) + if line_no not in lines_to_remove + ) + node.body[0].value = ast.Str(new_docstring) + + @staticmethod + def extract_type(line: str) -> tuple[str, str] | tuple[None, None]: + """Extract argument name and type string from ``:type:`` docstring + line.""" + match = re.match(r"\s*:type\s+(\w+):\s+(.+?)(?:, optional)?\s*$", line) + if not match: + return None, None + + arg_name = match.group(1) + + # get rid of any :py:class`...` in the type string if necessary + if not match.group(2).startswith(":py:"): + return arg_name, match.group(2) + + match = re.match(r":py:\w+:`(.+)`", match.group(2)) + assert match + return arg_name, match.group(1) + + @staticmethod + def extract_rtype(line: str) -> str | None: + """Extract type string from ``:rtype:`` docstring line.""" + match = re.match(r"\s*:rtype:\s+(.+)\s*$", line) + if not match: + return None + + # get rid of any :py:class`...` in the type string if necessary + if not match.group(1).startswith(":py:"): + return match.group(1) + + match = re.match(r":py:\w+:`(.+)`", match.group(1)) + assert match + return match.group(1) + def fix_typehints(infilename, outfilename): """Change SWIG-generated C++ typehints to Python typehints""" - # Only available from Python3.9 - if not getattr(ast, "unparse", None): - return - # file -> AST with open(infilename) as f: source = f.read() diff --git a/python/sdist/setup.cfg b/python/sdist/setup.cfg index 0d27a0918e..d34d42f98f 100644 --- a/python/sdist/setup.cfg +++ b/python/sdist/setup.cfg @@ -47,7 +47,7 @@ zip_safe = False # Don't include any URLs here - they are not supported by PyPI: # HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/ # Invalid value for requires_dist. Error: Can't have direct dependency: ... -petab = petab>=0.2.1 +petab = petab>=0.2.9 pysb = pysb>=1.13.1 test = benchmark_models_petab @ git+https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab.git@master#subdirectory=src/python diff --git a/python/sdist/setup.py b/python/sdist/setup.py index 0da5ac9878..2f44a18342 100755 --- a/python/sdist/setup.py +++ b/python/sdist/setup.py @@ -41,6 +41,7 @@ def get_extensions(): # Used by all extensions global_cmake_configure_options = [ "-DCMAKE_VERBOSE_MAKEFILE=ON", + f"-DCMAKE_MODULE_PATH={prefix_path.as_posix()}", ] # SuiteSparse Config @@ -51,6 +52,7 @@ def get_extensions(): cmake_configure_options=[ *global_cmake_configure_options, "-DCMAKE_POSITION_INDEPENDENT_CODE=ON", + "-DBUILD_SHARED_LIBS=OFF", # Building SuiteSparse_config does not require a BLAS # we just set BLAS_LIBRARIES to skip the search, # the value is not used @@ -68,6 +70,8 @@ def get_extensions(): source_dir="amici/ThirdParty/SuiteSparse/AMD", cmake_configure_options=[ *global_cmake_configure_options, + "-DBUILD_SHARED_LIBS=OFF", + "-DCMAKE_POSITION_INDEPENDENT_CODE=ON", "-DSUITESPARSE_USE_FORTRAN=OFF", ], ) @@ -79,6 +83,8 @@ def get_extensions(): cmake_configure_options=[ *global_cmake_configure_options, "-DSUITESPARSE_USE_FORTRAN=OFF", + "-DBUILD_SHARED_LIBS=OFF", + "-DCMAKE_POSITION_INDEPENDENT_CODE=ON", ], ) # SuiteSparse COLAMD @@ -89,6 +95,8 @@ def get_extensions(): cmake_configure_options=[ *global_cmake_configure_options, "-DSUITESPARSE_USE_FORTRAN=OFF", + "-DBUILD_SHARED_LIBS=OFF", + "-DCMAKE_POSITION_INDEPENDENT_CODE=ON", ], ) # SuiteSparse KLU @@ -101,6 +109,8 @@ def get_extensions(): "-DKLU_USE_CHOLMOD=OFF", "-DSUITESPARSE_USE_CUDA=OFF", "-DSUITESPARSE_USE_FORTRAN=OFF", + "-DBUILD_SHARED_LIBS=OFF", + "-DCMAKE_POSITION_INDEPENDENT_CODE=ON", ], ) # SUNDIALS diff --git a/python/tests/test_hdf5.py b/python/tests/test_hdf5.py index 232f22be8c..ee9d5a3e3b 100644 --- a/python/tests/test_hdf5.py +++ b/python/tests/test_hdf5.py @@ -24,6 +24,8 @@ def _modify_solver_attrs(solver): elif attr == "setMaxTime": # default value is the maximum, must not add to that cval = random.random() + elif attr == "setConstraints": + cval = [1.0, 1.0] elif isinstance(val, int): cval = val + 1 else: diff --git a/python/tests/test_petab_import.py b/python/tests/test_petab_import.py index 7a476f272d..fca319e11f 100644 --- a/python/tests/test_petab_import.py +++ b/python/tests/test_petab_import.py @@ -36,8 +36,30 @@ def simple_sbml_model(): return document, model +@pytest.fixture() +def get_fixed_parameters_model(): + """Create test SBML model for test_get_fixed_parameters""" + ant_model = """ + p1 = 1 + p2 = 2 + p3 = 3 + p4 = 4 + p5 = 5 + p6 = 3^2 + p7 = p6 + p8 = 8 + p8' = 1 + p9 := p8 + """ + from amici.antimony_import import antimony2sbml + + sbml_str = antimony2sbml(ant_model) + sbml_doc = libsbml.SBMLReader().readSBMLFromString(sbml_str) + return sbml_doc, sbml_doc.getModel() + + @skip_on_valgrind -def test_get_fixed_parameters(simple_sbml_model): +def test_get_fixed_parameters(get_fixed_parameters_model): """Check for correct identification of fixed parameters: p1: fixed (via condition table) @@ -45,13 +67,18 @@ def test_get_fixed_parameters(simple_sbml_model): p3: fixed (via parameter table `estimate=0`) p4: not fixed (via parameter table `estimate=1`) p5: fixed (implicitly, because not listed as estimated) + p6: fixed (implicitly, because not listed as estimated + initial assignment is a number) + p7: not fixed (initial assignment is not a number) + p8: not fixed (rate rule target) + p9: not fixed (assignment rule target) """ from amici.petab.sbml_import import ( _get_fixed_parameters_sbml as get_fixed_parameters, ) from petab.models.sbml_model import SbmlModel - sbml_doc, sbml_model = simple_sbml_model + sbml_doc, sbml_model = get_fixed_parameters_model condition_df = petab.get_condition_df( pd.DataFrame( { @@ -77,13 +104,14 @@ def test_get_fixed_parameters(simple_sbml_model): "p1", "p3", "p5", + "p6", } assert set( get_fixed_parameters( petab_problem, non_estimated_parameters_as_constants=False ) - ) == {"p1", "p5"} + ) == {"p1", "p5", "p6"} @skip_on_valgrind diff --git a/python/tests/test_preequilibration.py b/python/tests/test_preequilibration.py index be447b0c54..d003507199 100644 --- a/python/tests/test_preequilibration.py +++ b/python/tests/test_preequilibration.py @@ -608,8 +608,6 @@ def test_simulation_errors(preeq_fixture): ) assert rdata._swigptr.messages[1].severity == amici.LogSeverity_error assert rdata._swigptr.messages[1].identifier == "OTHER" - assert rdata._swigptr.messages[2].severity == amici.LogSeverity_debug - assert rdata._swigptr.messages[2].identifier == "BACKTRACE" # too long simulations solver.setMaxSteps(int(1e4)) @@ -632,8 +630,6 @@ def test_simulation_errors(preeq_fixture): ) assert rdata._swigptr.messages[2].severity == amici.LogSeverity_error assert rdata._swigptr.messages[2].identifier == "OTHER" - assert rdata._swigptr.messages[3].severity == amici.LogSeverity_debug - assert rdata._swigptr.messages[3].identifier == "BACKTRACE" def test_get_model_for_preeq(preeq_fixture): diff --git a/python/tests/test_sbml_import.py b/python/tests/test_sbml_import.py index 74a51d020a..aaab5688cc 100644 --- a/python/tests/test_sbml_import.py +++ b/python/tests/test_sbml_import.py @@ -368,7 +368,7 @@ def test_solver_reuse(model_steadystate_module): assert rdata1.status == amici.AMICI_SUCCESS for attr in rdata1: - if "time" in attr: + if "time" in attr or attr == "messages": continue val1 = getattr(rdata1, attr) @@ -722,3 +722,53 @@ def test_hardcode_parameters(simple_sbml_model): constant_parameters=["p1"], hardcode_symbols=["p1"], ) + + +def test_constraints(): + """Test non-negativity constraint handling.""" + from amici.antimony_import import antimony2amici + from amici import Constraint + + ant_model = """ + model test_non_negative_species + species A = 10 + species B = 0 + # R1: A => B; k1f * sqrt(A) + R1: A => B; k1f * max(0, A) + k1f = 1e10 + end + """ + module_name = "test_non_negative_species" + with TemporaryDirectory(prefix=module_name) as outdir: + antimony2amici( + ant_model, + model_name=module_name, + output_dir=outdir, + compute_conservation_laws=False, + ) + model_module = amici.import_model_module( + module_name=module_name, module_path=outdir + ) + amici_model = model_module.getModel() + amici_model.setTimepoints(np.linspace(0, 100, 200)) + amici_solver = amici_model.getSolver() + rdata = amici.runAmiciSimulation(amici_model, amici_solver) + assert rdata.status == amici.AMICI_SUCCESS + # should be non-negative in theory, but is expected to become negative + # in practice + assert np.any(rdata.x < 0) + + amici_solver.setRelativeTolerance(1e-14) + amici_solver.setConstraints( + [Constraint.non_negative, Constraint.non_negative] + ) + rdata = amici.runAmiciSimulation(amici_model, amici_solver) + assert rdata.status == amici.AMICI_SUCCESS + assert np.all(rdata.x >= 0) + assert np.all( + np.sum(rdata.x, axis=1) - np.sum(rdata.x[0]) + < max( + np.sum(rdata.x[0]) * amici_solver.getRelativeTolerance(), + amici_solver.getAbsoluteTolerance(), + ) + ) diff --git a/python/tests/test_swig_interface.py b/python/tests/test_swig_interface.py index f214519f26..b5063ca3cc 100644 --- a/python/tests/test_swig_interface.py +++ b/python/tests/test_swig_interface.py @@ -511,6 +511,9 @@ def test_rdataview(sbml_example_presimulation_module): rdata = amici.runAmiciSimulation(model, model.getSolver()) assert isinstance(rdata, amici.ReturnDataView) + # check that non-array attributes are looked up in the wrapped object + assert rdata.ptr.ny == rdata.ny + # fields are accessible via dot notation and [] operator, # __contains__ and __getattr__ are implemented correctly with pytest.raises(AttributeError): diff --git a/python/tests/valgrind-python.supp b/python/tests/valgrind-python.supp index b4e0177033..01bc776aec 100644 --- a/python/tests/valgrind-python.supp +++ b/python/tests/valgrind-python.supp @@ -213,6 +213,19 @@ fun:__Pyx__PyObject_CallOneArg } +{ + other + Memcheck:Leak + match-leak-kinds: definite + fun:realloc + fun:resize_compact + fun:_PyUnicodeWriter_Finish + fun:PyUnicode_FromFormatV + fun:PyUnicode_FromFormat + fun:PyFortranObject_NewAsAttr + ... +} + { other Memcheck:Value8 diff --git a/scripts/buildAmici.sh b/scripts/buildAmici.sh index 507a391621..80b724c8c3 100755 --- a/scripts/buildAmici.sh +++ b/scripts/buildAmici.sh @@ -25,7 +25,28 @@ else fi # required for build swig interface -pip show numpy > /dev/null || python3 -m pip install numpy +venv_dir="${amici_path}/venv" +set +e +mkdir -p "${venv_dir}" +python3 -m venv "${venv_dir}" --clear +# in case this fails (usually due to missing ensurepip, try getting pip +# manually +if [[ $? ]]; then + set -e + python3 -m venv "${venv_dir}" --clear --without-pip + source "${venv_dir}/bin/activate" + get_pip=${amici_path}/get-pip.py + curl "https://bootstrap.pypa.io/get-pip.py" -o "${get_pip}" + python3 "${get_pip}" + rm "${get_pip}" +else + set -e + source "${venv_dir}/bin/activate" +fi + +# set python executable for cmake +export PYTHON_EXECUTABLE="${amici_path}/venv/bin/python" +python3 -m pip install numpy ${cmake} \ -Wdev -DAMICI_CXX_OPTIONS="-Wall;-Wextra${extra_cxx_flags}" \ diff --git a/scripts/installAmiciArchive.sh b/scripts/installAmiciArchive.sh index 25de4f9f93..f427a91256 100755 --- a/scripts/installAmiciArchive.sh +++ b/scripts/installAmiciArchive.sh @@ -18,18 +18,18 @@ rm -f ${AMICI_PATH}/python/sdist/amici/amici_without_hdf5.py # test install from archive set +e -python3 -m venv ${AMICI_PATH}/build/venvArchive --clear +python3 -m venv ${AMICI_PATH}/venvArchive --clear # in case this fails (usually due to missing ensurepip, try getting pip # manually if [[ $? ]]; then set -e - python3 -m venv ${AMICI_PATH}/build/venvArchive --clear --without-pip - source ${AMICI_PATH}/build/venvArchive/bin/activate + python3 -m venv ${AMICI_PATH}/venvArchive --clear --without-pip + source ${AMICI_PATH}/venvArchive/bin/activate curl https://bootstrap.pypa.io/get-pip.py -o ${AMICI_PATH}/build/get-pip.py python ${AMICI_PATH}/build/get-pip.py else set -e - source ${AMICI_PATH}/build/venvArchive/bin/activate + source ${AMICI_PATH}/venvArchive/bin/activate fi pip install $(ls -t ${AMICI_PATH}/build/python/amici-*.tar.gz | head -1) diff --git a/scripts/installAmiciSource.sh b/scripts/installAmiciSource.sh index bbb4bf4a83..c074c89d46 100755 --- a/scripts/installAmiciSource.sh +++ b/scripts/installAmiciSource.sh @@ -5,12 +5,12 @@ set -e SCRIPT_PATH=$(dirname $BASH_SOURCE) AMICI_PATH=$(cd "$SCRIPT_PATH/.." && pwd) -venv_dir="${AMICI_PATH}/build/venv" # Disabled until cmake package is made compatible with updated setup.py #make python-wheel #pip3 install --user --prefix= `ls -t ${AMICI_PATH}/build/python/amici-*.whl | head -1` # test install from setup.py +venv_dir="${AMICI_PATH}/venv" set +e mkdir -p "${venv_dir}" python3 -m venv "${venv_dir}" --clear @@ -20,7 +20,7 @@ if [[ $? ]]; then set -e python3 -m venv "${venv_dir}" --clear --without-pip source "${venv_dir}/bin/activate" - get_pip=${AMICI_PATH}/build/get-pip.py + get_pip=${AMICI_PATH}/get-pip.py curl "https://bootstrap.pypa.io/get-pip.py" -o "${get_pip}" python3 "${get_pip}" rm "${get_pip}" @@ -29,6 +29,9 @@ else source "${venv_dir}/bin/activate" fi +# set python executable for cmake +export PYTHON_EXECUTABLE="${AMICI_PATH}/venv/bin/python" + python -m pip install --upgrade pip wheel python -m pip install --upgrade pip setuptools cmake_build_extension numpy python -m pip install git+https://github.com/FFroehlich/pysb@fix_pattern_matching # pin to PR for SPM with compartments diff --git a/scripts/run-SBMLTestsuite.sh b/scripts/run-SBMLTestsuite.sh index 97c2033751..a3dcee1681 100755 --- a/scripts/run-SBMLTestsuite.sh +++ b/scripts/run-SBMLTestsuite.sh @@ -9,7 +9,7 @@ if [[ ! -d "tests/sbml-test-suite" ]]; then mv -f ./sbml-test-suite ./tests/sbml-test-suite fi -source build/venv/bin/activate +source venv/bin/activate pip show pytest-xdist > /dev/null 2>&1 || pip install pytest-xdist pip install coverage pytest-cov diff --git a/scripts/run-codecov.sh b/scripts/run-codecov.sh index 42d76f7a0e..f5f253b5c9 100755 --- a/scripts/run-codecov.sh +++ b/scripts/run-codecov.sh @@ -4,7 +4,7 @@ script_path=$(dirname $BASH_SOURCE) amici_path=$(cd "$script_path"/.. && pwd) -source "${amici_path}"/build/venv/bin/activate +source "${amici_path}"/venv/bin/activate pip install coverage pytest pytest-cov if [[ -z "${BNGPATH}" ]]; then diff --git a/scripts/run-python-tests.sh b/scripts/run-python-tests.sh index d58a1c8dec..0fed628fce 100755 --- a/scripts/run-python-tests.sh +++ b/scripts/run-python-tests.sh @@ -12,7 +12,7 @@ if [[ -z "${BNGPATH}" ]]; then fi cd "${amici_path}"/python/tests -source "${amici_path}"/build/venv/bin/activate +source "${amici_path}"/venv/bin/activate # PEtab tests are run separately pytest \ diff --git a/scripts/run-valgrind-py.sh b/scripts/run-valgrind-py.sh index c2a6239ad4..9621c24d31 100755 --- a/scripts/run-valgrind-py.sh +++ b/scripts/run-valgrind-py.sh @@ -15,7 +15,7 @@ if [ $# -eq 0 ] then # No arguments supplied, run all tests cd "${amici_path}"/python/tests - source "${amici_path}"/build/venv/bin/activate + source "${amici_path}"/venv/bin/activate command=(python -m pytest -vv --ignore-glob=*petab* -W 'ignore:Signature ') # ^ ignores the following warning that occurs only under valgrind, # e.g. `valgrind python -c "import h5py"`: diff --git a/scripts/runNotebook.sh b/scripts/runNotebook.sh index bf1ef8d5e0..ee62b59cfc 100755 --- a/scripts/runNotebook.sh +++ b/scripts/runNotebook.sh @@ -25,7 +25,7 @@ if [ $# -eq 0 ]; then exit 1 fi -source ${AMICI_PATH}/build/venv/bin/activate +source ${AMICI_PATH}/venv/bin/activate pip3 show nbconvert || pip3 install --upgrade nbconvert pip3 show ipykernel || (pip3 install --upgrade ipykernel && python3 -m ipykernel install --user --name amici --display-name "Python (amici)") diff --git a/src/amici.cpp b/src/amici.cpp index 6e85dde857..c74c88e3a5 100644 --- a/src/amici.cpp +++ b/src/amici.cpp @@ -59,6 +59,7 @@ std::map simulation_status_to_str_map = { {AMICI_ERR_FAILURE, "AMICI_ERR_FAILURE"}, {AMICI_CONV_FAILURE, "AMICI_CONV_FAILURE"}, {AMICI_FIRST_RHSFUNC_ERR, "AMICI_FIRST_RHSFUNC_ERR"}, + {AMICI_CONSTR_FAIL, "AMICI_CONSTR_FAIL"}, {AMICI_RHSFUNC_FAIL, "AMICI_RHSFUNC_FAIL"}, {AMICI_ILL_INPUT, "AMICI_ILL_INPUT"}, {AMICI_ERROR, "AMICI_ERROR"}, @@ -69,6 +70,7 @@ std::map simulation_status_to_str_map = { {AMICI_MAX_TIME_EXCEEDED, "AMICI_MAX_TIME_EXCEEDED"}, {AMICI_SUCCESS, "AMICI_SUCCESS"}, {AMICI_NOT_RUN, "AMICI_NOT_RUN"}, + {AMICI_LSETUP_FAIL, "AMICI_LSETUP_FAIL"}, }; std::unique_ptr runAmiciSimulation( @@ -205,11 +207,27 @@ std::unique_ptr runAmiciSimulation( LogSeverity::error, "OTHER", "AMICI simulation failed: %s", ex.what() ); +#ifndef NDEBUG logger.log( LogSeverity::debug, "BACKTRACE", "The previous error occurred at:\n%s", ex.getBacktrace() ); +#endif + } catch (std::exception const& ex) { + rdata->status = AMICI_ERROR; + if (rethrow) + throw; + logger.log( + LogSeverity::error, "OTHER", "AMICI simulation failed: %s", + ex.what() + ); + } + try { + rdata->processSimulationObjects( + preeq.get(), fwd.get(), bwd_success ? bwd.get() : nullptr, + posteq.get(), model, solver, edata + ); } catch (std::exception const& ex) { rdata->status = AMICI_ERROR; if (rethrow) @@ -220,10 +238,7 @@ std::unique_ptr runAmiciSimulation( ); } - rdata->processSimulationObjects( - preeq.get(), fwd.get(), bwd_success ? bwd.get() : nullptr, posteq.get(), - model, solver, edata - ); + rdata->t_last = solver.gett(); rdata->cpu_time_total = cpu_timer.elapsed_milliseconds(); diff --git a/src/forwardproblem.cpp b/src/forwardproblem.cpp index b4bcd9740f..ef4585f9e9 100644 --- a/src/forwardproblem.cpp +++ b/src/forwardproblem.cpp @@ -416,7 +416,10 @@ void ForwardProblem::getAdjointUpdates(Model& model, ExpData const& edata) { } } -SimulationState ForwardProblem::getSimulationState() const { +SimulationState ForwardProblem::getSimulationState() { + if (std::isfinite(solver->gett())) { + solver->writeSolution(&t_, x_, dx_, sx_, dx_); + } auto state = SimulationState(); state.t = t_; state.x = x_; diff --git a/src/hdf5.cpp b/src/hdf5.cpp index e459eee138..0454b634f1 100644 --- a/src/hdf5.cpp +++ b/src/hdf5.cpp @@ -532,6 +532,10 @@ void writeReturnDataDiagnosis( &rdata.cpu_time_total, 1 ); + H5LTset_attribute_double( + file.getId(), hdf5Location.c_str(), "t_last", &rdata.t_last, 1 + ); + if (!rdata.J.empty()) createAndWriteDouble2DDataset( file, hdf5Location + "/J", rdata.J, rdata.nx, rdata.nx @@ -802,6 +806,11 @@ void writeSolverSettingsToHDF5( file.getId(), hdf5Location.c_str(), "maxtime", &dbuffer, 1 ); + dbuffer = solver.getMaxStepSize(); + H5LTset_attribute_double( + file.getId(), hdf5Location.c_str(), "max_step_size", &dbuffer, 1 + ); + ibuffer = gsl::narrow(solver.getMaxSteps()); H5LTset_attribute_int( file.getId(), hdf5Location.c_str(), "maxsteps", &ibuffer, 1 @@ -895,6 +904,20 @@ void writeSolverSettingsToHDF5( file.getId(), hdf5Location.c_str(), "check_sensi_steadystate_conv", &ibuffer, 1 ); + + ibuffer = static_cast(solver.getMaxNonlinIters()); + H5LTset_attribute_int( + file.getId(), hdf5Location.c_str(), "max_nonlin_iters", &ibuffer, 1 + ); + + ibuffer = static_cast(solver.getMaxConvFails()); + H5LTset_attribute_int( + file.getId(), hdf5Location.c_str(), "max_conv_fails", &ibuffer, 1 + ); + + createAndWriteDouble1DDataset( + file, hdf5Location + "/constraints", solver.getConstraints() + ); } void readSolverSettingsFromHDF5( @@ -990,6 +1013,12 @@ void readSolverSettingsFromHDF5( ); } + if (attributeExists(file, datasetPath, "max_step_size")) { + solver.setMaxStepSize( + getDoubleScalarAttribute(file, datasetPath, "max_step_size") + ); + } + if (attributeExists(file, datasetPath, "maxsteps")) { solver.setMaxSteps(getIntScalarAttribute(file, datasetPath, "maxsteps") ); @@ -1106,6 +1135,24 @@ void readSolverSettingsFromHDF5( file, datasetPath, "check_sensi_steadystate_conv" )); } + + if (attributeExists(file, datasetPath, "max_nonlin_iters")) { + solver.setMaxNonlinIters( + getIntScalarAttribute(file, datasetPath, "max_nonlin_iters") + ); + } + + if (attributeExists(file, datasetPath, "max_conv_fails")) { + solver.setMaxConvFails( + getIntScalarAttribute(file, datasetPath, "max_conv_fails") + ); + } + + if (locationExists(file, datasetPath + "/constraints")) { + solver.setConstraints( + getDoubleDataset1D(file, datasetPath + "/constraints") + ); + } } void readSolverSettingsFromHDF5( diff --git a/src/model.cpp b/src/model.cpp index 54363d8d1b..452e484f58 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -372,7 +372,7 @@ void Model::initializeStates(AmiVector& x) { std::copy(x0_solver.cbegin(), x0_solver.cend(), x.data()); } - checkFinite(x.getVector(), ModelQuantity::x0); + checkFinite(x.getVector(), ModelQuantity::x0, t0()); } void Model::initializeSplines() { @@ -883,11 +883,11 @@ void Model::setStateIsNonNegative(std::vector const& nonNegative) { // in case of conservation laws return; } - if (state_is_non_negative_.size() != gsl::narrow(nx_rdata)) { + if (nonNegative.size() != gsl::narrow(nx_rdata)) { throw AmiException( "Dimension of input stateIsNonNegative (%u) does " "not agree with number of state variables (%d)", - state_is_non_negative_.size(), nx_rdata + nonNegative.size(), nx_rdata ); } state_is_non_negative_ = nonNegative; @@ -1482,7 +1482,7 @@ void Model::addStateEventUpdate( ); if (always_check_finite_) { - checkFinite(derived_state_.deltax_, ModelQuantity::deltax); + checkFinite(derived_state_.deltax_, ModelQuantity::deltax, t); } // update @@ -1536,7 +1536,7 @@ void Model::addAdjointStateEventUpdate( ); if (always_check_finite_) { - checkFinite(derived_state_.deltaxB_, ModelQuantity::deltaxB); + checkFinite(derived_state_.deltaxB_, ModelQuantity::deltaxB, t); } // apply update @@ -1582,7 +1582,7 @@ void Model::updateHeavisideB(int const* rootsfound) { } int Model::checkFinite( - gsl::span array, ModelQuantity model_quantity + gsl::span array, ModelQuantity model_quantity, realtype t ) const { auto it = std::find_if(array.begin(), array.end(), [](realtype x) { return !std::isfinite(x); @@ -1654,23 +1654,26 @@ int Model::checkFinite( gsl_ExpectsDebug(false); model_quantity_str = std::to_string(static_cast(model_quantity)); } - if (logger) + if (logger) { + auto t_msg = std::isfinite(t) + ? std::string(" at t=" + std::to_string(t) + " ") + : std::string(); + logger->log( LogSeverity::warning, msg_id, - "AMICI encountered a %s value for %s[%i] (%s)", + "AMICI encountered a %s value for %s[%i] (%s)%s", non_finite_type.c_str(), model_quantity_str.c_str(), - gsl::narrow(flat_index), element_id.c_str() + gsl::narrow(flat_index), element_id.c_str(), t_msg.c_str() ); - + } // check upstream, without infinite recursion if (model_quantity != ModelQuantity::k && model_quantity != ModelQuantity::p && model_quantity != ModelQuantity::ts) { - checkFinite(state_.fixedParameters, ModelQuantity::k); - checkFinite(state_.unscaledParameters, ModelQuantity::p); - checkFinite(simulation_parameters_.ts_, ModelQuantity::ts); + checkFinite(state_.fixedParameters, ModelQuantity::k, t); + checkFinite(state_.unscaledParameters, ModelQuantity::p, t); if (!always_check_finite_ && model_quantity != ModelQuantity::w) { // don't check twice if always_check_finite_ is true - checkFinite(derived_state_.w_, ModelQuantity::w); + checkFinite(derived_state_.w_, ModelQuantity::w, t); } } return AMICI_RECOVERABLE_ERROR; @@ -1678,7 +1681,7 @@ int Model::checkFinite( int Model::checkFinite( gsl::span array, ModelQuantity model_quantity, - size_t num_cols + size_t num_cols, realtype t ) const { auto it = std::find_if(array.begin(), array.end(), [](realtype x) { return !std::isfinite(x); @@ -1768,19 +1771,24 @@ int Model::checkFinite( model_quantity_str = std::to_string(static_cast(model_quantity)); } - if (logger) + if (logger) { + auto t_msg = std::isfinite(t) + ? std::string(" at t=" + std::to_string(t) + " ") + : std::string(); + logger->log( LogSeverity::warning, msg_id, - "AMICI encountered a %s value for %s[%i] (%s, %s)", + "AMICI encountered a %s value for %s[%i] (%s, %s)%s", non_finite_type.c_str(), model_quantity_str.c_str(), - gsl::narrow(flat_index), row_id.c_str(), col_id.c_str() + gsl::narrow(flat_index), row_id.c_str(), col_id.c_str(), + t_msg.c_str() ); + } // check upstream - checkFinite(state_.fixedParameters, ModelQuantity::k); - checkFinite(state_.unscaledParameters, ModelQuantity::p); - checkFinite(simulation_parameters_.ts_, ModelQuantity::ts); - checkFinite(derived_state_.w_, ModelQuantity::w); + checkFinite(state_.fixedParameters, ModelQuantity::k, t); + checkFinite(state_.unscaledParameters, ModelQuantity::p, t); + checkFinite(derived_state_.w_, ModelQuantity::w, t); return AMICI_RECOVERABLE_ERROR; } @@ -1868,10 +1876,9 @@ int Model::checkFinite(SUNMatrix m, ModelQuantity model_quantity, realtype t) ); // check upstream - checkFinite(state_.fixedParameters, ModelQuantity::k); - checkFinite(state_.unscaledParameters, ModelQuantity::p); - checkFinite(simulation_parameters_.ts_, ModelQuantity::ts); - checkFinite(derived_state_.w_, ModelQuantity::w); + checkFinite(state_.fixedParameters, ModelQuantity::k, t); + checkFinite(state_.unscaledParameters, ModelQuantity::p, t); + checkFinite(derived_state_.w_, ModelQuantity::w, t); return AMICI_RECOVERABLE_ERROR; } @@ -1895,7 +1902,7 @@ void Model::fx0(AmiVector& x) { state_.unscaledParameters.data(), state_.fixedParameters.data() ); - checkFinite(derived_state_.x_rdata_, ModelQuantity::x0_rdata); + checkFinite(derived_state_.x_rdata_, ModelQuantity::x0_rdata, t0()); } void Model::fx0_fixedParameters(AmiVector& x) { @@ -1982,7 +1989,10 @@ void Model::fx_rdata(AmiVector& x_rdata, AmiVector const& x) { state_.unscaledParameters.data(), state_.fixedParameters.data() ); if (always_check_finite_) - checkFinite(x_rdata.getVector(), ModelQuantity::x_rdata); + checkFinite( + x_rdata.getVector(), ModelQuantity::x_rdata, + std::numeric_limits::quiet_NaN() + ); } void Model::fsx_rdata( @@ -2072,7 +2082,7 @@ void Model::fy(realtype const t, AmiVector const& x) { if (always_check_finite_) { checkFinite( - gsl::make_span(derived_state_.y_.data(), ny), ModelQuantity::y + gsl::make_span(derived_state_.y_.data(), ny), ModelQuantity::y, t ); } } @@ -2875,7 +2885,7 @@ void Model::fw(realtype const t, realtype const* x, bool include_static) { state_.spl_.data(), include_static); if (always_check_finite_) { - checkFinite(derived_state_.w_, ModelQuantity::w); + checkFinite(derived_state_.w_, ModelQuantity::w, t); } } diff --git a/src/model_dae.cpp b/src/model_dae.cpp index ad397bc82f..22025e1181 100644 --- a/src/model_dae.cpp +++ b/src/model_dae.cpp @@ -138,7 +138,8 @@ void Model_DAE::fJDiag( fJSparse(t, 0.0, x.getNVector(), dx.getNVector(), derived_state_.J_); derived_state_.J_.refresh(); derived_state_.J_.to_diag(JDiag.getNVector()); - if (checkFinite(JDiag.getVector(), ModelQuantity::JDiag) != AMICI_SUCCESS) + if (checkFinite(JDiag.getVector(), ModelQuantity::JDiag, t) + != AMICI_SUCCESS) throw AmiException("Evaluation of fJDiag failed!"); } diff --git a/src/model_ode.cpp b/src/model_ode.cpp index e3e401e1bf..787df210ef 100644 --- a/src/model_ode.cpp +++ b/src/model_ode.cpp @@ -122,7 +122,8 @@ void Model_ODE::fJDiag( AmiVector const& x, AmiVector const& /*dx*/ ) { fJDiag(t, JDiag.getNVector(), x.getNVector()); - if (checkFinite(JDiag.getVector(), ModelQuantity::JDiag) != AMICI_SUCCESS) + if (checkFinite(JDiag.getVector(), ModelQuantity::JDiag, t) + != AMICI_SUCCESS) throw AmiException("Evaluation of fJDiag failed!"); } diff --git a/src/newton_solver.cpp b/src/newton_solver.cpp index 9f011bac1e..c14b05c7f2 100644 --- a/src/newton_solver.cpp +++ b/src/newton_solver.cpp @@ -188,9 +188,7 @@ void NewtonSolverSparse::prepareLinearSystemB( Model& model, SimulationState const& state ) { /* Get sparse Jacobian */ - model.fJSparseB( - state.t, 0.0, state.x, state.dx, xB_, dxB_, xdot_, Jtmp_ - ); + model.fJSparseB(state.t, 0.0, state.x, state.dx, xB_, dxB_, xdot_, Jtmp_); Jtmp_.refresh(); auto status = SUNLinSolSetup_KLU(linsol_, Jtmp_); if (status != SUNLS_SUCCESS) diff --git a/src/solver.cpp b/src/solver.cpp index 2caa9d8bc0..b9e497f309 100644 --- a/src/solver.cpp +++ b/src/solver.cpp @@ -17,6 +17,7 @@ Solver::Solver(Solver const& other) , maxsteps_(other.maxsteps_) , maxtime_(other.maxtime_) , simulation_timer_(other.simulation_timer_) + , constraints_(other.constraints_) , sensi_meth_(other.sensi_meth_) , sensi_meth_preeq_(other.sensi_meth_preeq_) , stldet_(other.stldet_) @@ -44,6 +45,9 @@ Solver::Solver(Solver const& other) , rdata_mode_(other.rdata_mode_) , newton_step_steadystate_conv_(other.newton_step_steadystate_conv_) , check_sensi_steadystate_conv_(other.check_sensi_steadystate_conv_) + , max_nonlin_iters_(other.max_nonlin_iters_) + , max_conv_fails_(other.max_conv_fails_) + , max_step_size_(other.max_step_size_) , maxstepsB_(other.maxstepsB_) , sensi_(other.sensi_) {} @@ -191,8 +195,14 @@ void Solver::setup( if (model->nt() > 1) calcIC(model->getTimepoint(1)); + apply_max_nonlin_iters(); + apply_max_conv_fails(); + apply_max_step_size(); + cpu_time_ = 0.0; cpu_timeB_ = 0.0; + + apply_constraints(); } void Solver::setupB( @@ -553,7 +563,11 @@ bool operator==(Solver const& a, Solver const& b) { == b.newton_step_steadystate_conv_) && (a.check_sensi_steadystate_conv_ == b.check_sensi_steadystate_conv_) - && (a.rdata_mode_ == b.rdata_mode_); + && (a.rdata_mode_ == b.rdata_mode_) + && (a.max_conv_fails_ == b.max_conv_fails_) + && (a.max_nonlin_iters_ == b.max_nonlin_iters_) + && (a.max_step_size_ == b.max_step_size_) + && (a.constraints_.getVector() == b.constraints_.getVector()); } void Solver::applyTolerances() const { @@ -637,6 +651,15 @@ void Solver::applySensitivityTolerances() const { } } +void Solver::apply_constraints() const { + if (constraints_.getLength() != 0 + && gsl::narrow(constraints_.getLength()) != nx()) { + throw std::invalid_argument( + "Constraints must have the same size as the state vector." + ); + } +} + SensitivityMethod Solver::getSensitivityMethod() const { return sensi_meth_; } SensitivityMethod Solver::getSensitivityMethodPreequilibration() const { @@ -666,6 +689,47 @@ void Solver::checkSensitivityMethod( resetMutableMemory(nx(), nplist(), nquad()); } +void Solver::setMaxNonlinIters(int max_nonlin_iters) { + if (max_nonlin_iters < 0) + throw AmiException("max_nonlin_iters must be a non-negative number"); + + max_nonlin_iters_ = max_nonlin_iters; +} + +int Solver::getMaxNonlinIters() const { return max_nonlin_iters_; } + +void Solver::setMaxConvFails(int max_conv_fails) { + if (max_conv_fails < 0) + throw AmiException("max_conv_fails must be a non-negative number"); + + max_conv_fails_ = max_conv_fails; +} + +int Solver::getMaxConvFails() const { return max_conv_fails_; } + +void Solver::setConstraints(std::vector const& constraints) { + auto any_constraint + = std::any_of(constraints.begin(), constraints.end(), [](bool x) { + return x != 0.0; + }); + + if (!any_constraint) { + // all-0 must be converted to empty, otherwise sundials will fail + constraints_ = AmiVector(); + return; + } + + constraints_ = AmiVector(constraints); +} + +void Solver::setMaxStepSize(realtype max_step_size) { + if (max_step_size < 0) + throw AmiException("max_step_size must be non-negative."); + max_step_size_ = max_step_size; +} + +realtype Solver::getMaxStepSize() const { return max_step_size_; } + int Solver::getNewtonMaxSteps() const { return newton_maxsteps_; } void Solver::setNewtonMaxSteps(int const newton_maxsteps) { @@ -1151,6 +1215,8 @@ void Solver::resetMutableMemory(int const nx, int const nplist, int const nquad) sx_ = AmiVectorArray(nx, nplist); sdx_ = AmiVectorArray(nx, nplist); + dky_ = AmiVector(nx); + xB_ = AmiVector(nx); dxB_ = AmiVector(nx); xQB_ = AmiVector(nquad); diff --git a/src/solver_cvodes.cpp b/src/solver_cvodes.cpp index f5150a87c7..e5771ff391 100644 --- a/src/solver_cvodes.cpp +++ b/src/solver_cvodes.cpp @@ -257,6 +257,37 @@ void CVodeSolver::setSparseJacFn_ss() const { throw CvodeException(status, "CVodeSetJacFn"); } +void CVodeSolver::apply_max_nonlin_iters() const { + int status + = CVodeSetMaxNonlinIters(solver_memory_.get(), getMaxNonlinIters()); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeSetMaxNonlinIters"); +} + +void CVodeSolver::apply_max_conv_fails() const { + int status = CVodeSetMaxConvFails(solver_memory_.get(), getMaxConvFails()); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeSetMaxConvFails"); +} + +void CVodeSolver::apply_constraints() const { + Solver::apply_constraints(); + + int status = CVodeSetConstraints( + solver_memory_.get(), + constraints_.getLength() > 0 ? constraints_.getNVector() : nullptr + ); + if (status != CV_SUCCESS) { + throw CvodeException(status, "CVodeSetConstraints"); + } +} + +void CVodeSolver::apply_max_step_size() const { + int status = CVodeSetMaxStep(solver_memory_.get(), getMaxStepSize()); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeSetMaxStep"); +} + Solver* CVodeSolver::clone() const { return new CVodeSolver(*this); } void CVodeSolver::allocateSolver() const { @@ -914,7 +945,7 @@ fJB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, SUNMatrix JB, Expects(model); model->fJB(t, x, xB, xBdot, JB); - return model->checkFinite(gsl::make_span(JB), ModelQuantity::JB); + return model->checkFinite(gsl::make_span(JB), ModelQuantity::JB, t); } /** @@ -965,7 +996,7 @@ static int fJSparseB( Expects(model); model->fJSparseB(t, x, xB, xBdot, JB); - return model->checkFinite(gsl::make_span(JB), ModelQuantity::JB); + return model->checkFinite(gsl::make_span(JB), ModelQuantity::JB, t); } /** @@ -1028,7 +1059,7 @@ fJv(N_Vector v, N_Vector Jv, realtype t, N_Vector x, N_Vector /*xdot*/, Expects(model); model->fJv(v, Jv, t, x); - return model->checkFinite(gsl::make_span(Jv), ModelQuantity::Jv); + return model->checkFinite(gsl::make_span(Jv), ModelQuantity::Jv, t); } /** @@ -1054,7 +1085,7 @@ static int fJvB( Expects(model); model->fJvB(vB, JvB, t, x, xB); - return model->checkFinite(gsl::make_span(JvB), ModelQuantity::JvB); + return model->checkFinite(gsl::make_span(JvB), ModelQuantity::JvB, t); } /** @@ -1081,7 +1112,7 @@ static int froot(realtype t, N_Vector x, realtype* root, void* user_data) { model->froot(t, x, gsl::make_span(root, model->ne_solver)); } return model->checkFinite( - gsl::make_span(root, model->ne_solver), ModelQuantity::root + gsl::make_span(root, model->ne_solver), ModelQuantity::root, t ); } @@ -1106,7 +1137,7 @@ static int fxdot(realtype t, N_Vector x, N_Vector xdot, void* user_data) { } if (t > 1e200 - && !model->checkFinite(gsl::make_span(x), ModelQuantity::xdot)) { + && !model->checkFinite(gsl::make_span(x), ModelQuantity::xdot, t)) { /* when t is large (typically ~1e300), CVODES may pass all NaN x to fxdot from which we typically cannot recover. To save time on normal execution, we do not always want to check finiteness @@ -1115,7 +1146,7 @@ static int fxdot(realtype t, N_Vector x, N_Vector xdot, void* user_data) { } model->fxdot(t, x, xdot); - return model->checkFinite(gsl::make_span(xdot), ModelQuantity::xdot); + return model->checkFinite(gsl::make_span(xdot), ModelQuantity::xdot, t); } /** @@ -1141,7 +1172,7 @@ fxBdot(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, void* user_data) { } model->fxBdot(t, x, xB, xBdot); - return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot); + return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot, t); } /** @@ -1161,7 +1192,7 @@ fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot, void* user_data) { Expects(model); model->fqBdot(t, x, xB, qBdot); - return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot); + return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot, t); } /** @@ -1180,7 +1211,9 @@ static int fxBdot_ss(realtype t, N_Vector xB, N_Vector xBdot, void* user_data) { Expects(model); model->fxBdot_ss(t, xB, xBdot); - return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot_ss); + return model->checkFinite( + gsl::make_span(xBdot), ModelQuantity::xBdot_ss, t + ); } /** @@ -1199,7 +1232,9 @@ static int fqBdot_ss(realtype t, N_Vector xB, N_Vector qBdot, void* user_data) { Expects(model); model->fqBdot_ss(t, xB, qBdot); - return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot_ss); + return model->checkFinite( + gsl::make_span(qBdot), ModelQuantity::qBdot_ss, t + ); } /** @@ -1215,8 +1250,8 @@ static int fqBdot_ss(realtype t, N_Vector xB, N_Vector qBdot, void* user_data) { * @return status flag indicating successful execution */ static int fJSparseB_ss( - realtype /*t*/, N_Vector /*x*/, N_Vector xBdot, SUNMatrix JB, - void* user_data, N_Vector /*tmp1*/, N_Vector /*tmp2*/, N_Vector /*tmp3*/ + realtype t, N_Vector /*x*/, N_Vector xBdot, SUNMatrix JB, void* user_data, + N_Vector /*tmp1*/, N_Vector /*tmp2*/, N_Vector /*tmp3*/ ) { auto typed_udata = static_cast(user_data); Expects(typed_udata); @@ -1225,7 +1260,7 @@ static int fJSparseB_ss( model->fJSparseB_ss(JB); return model->checkFinite( - gsl::make_span(xBdot), ModelQuantity::JSparseB_ss + gsl::make_span(xBdot), ModelQuantity::JSparseB_ss, t ); } @@ -1254,7 +1289,7 @@ static int fsxdot( Expects(model); model->fsxdot(t, x, ip, sx, sxdot); - return model->checkFinite(gsl::make_span(sxdot), ModelQuantity::sxdot); + return model->checkFinite(gsl::make_span(sxdot), ModelQuantity::sxdot, t); } bool operator==(CVodeSolver const& a, CVodeSolver const& b) { diff --git a/src/solver_idas.cpp b/src/solver_idas.cpp index dac085e98d..8093b336e5 100644 --- a/src/solver_idas.cpp +++ b/src/solver_idas.cpp @@ -17,7 +17,7 @@ namespace amici { /* - * The following static members are callback function to CVODES. + * The following static members are callback function to IDAS. * Their signatures must not be changes. */ @@ -254,6 +254,37 @@ void IDASolver::setSparseJacFn_ss() const { throw IDAException(status, "IDASetJacFn"); } +void IDASolver::apply_max_nonlin_iters() const { + int status + = IDASetMaxNonlinIters(solver_memory_.get(), getMaxNonlinIters()); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDASetMaxNonlinIters"); +} + +void IDASolver::apply_max_conv_fails() const { + int status = IDASetMaxConvFails(solver_memory_.get(), getMaxConvFails()); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDASetMaxConvFails"); +} + +void IDASolver::apply_constraints() const { + Solver::apply_constraints(); + + int status = IDASetConstraints( + solver_memory_.get(), + constraints_.getLength() > 0 ? constraints_.getNVector() : nullptr + ); + if (status != IDA_SUCCESS) { + throw IDAException(status, "IDASetConstraints"); + } +} + +void IDASolver::apply_max_step_size() const { + int status = IDASetMaxStep(solver_memory_.get(), getMaxStepSize()); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDASetMaxStep"); +} + Solver* IDASolver::clone() const { return new IDASolver(*this); } void IDASolver::allocateSolver() const { @@ -406,7 +437,7 @@ void IDASolver::reInitPostProcess( auto status = IDASetStopTime(ida_mem, tout); if (status != IDA_SUCCESS) - throw IDAException(status, "CVodeSetStopTime"); + throw IDAException(status, "IDASetStopTime"); status = IDASolve( ami_mem, tout, t, yout->getNVector(), ypout->getNVector(), IDA_ONE_STEP @@ -822,7 +853,7 @@ void IDASolver::setNonLinearSolver() const { solver_memory_.get(), non_linear_solver_->get() ); if (status != IDA_SUCCESS) - throw CvodeException(status, "CVodeSetNonlinearSolver"); + throw IDAException(status, "IDASetNonlinearSolver"); } void IDASolver::setNonLinearSolverSens() const { @@ -852,7 +883,7 @@ void IDASolver::setNonLinearSolverSens() const { } if (status != IDA_SUCCESS) - throw CvodeException(status, "CVodeSolver::setNonLinearSolverSens"); + throw IDAException(status, "IDASolver::setNonLinearSolverSens"); } void IDASolver::setNonLinearSolverB(int which) const { @@ -860,7 +891,7 @@ void IDASolver::setNonLinearSolverB(int which) const { solver_memory_.get(), which, non_linear_solver_B_->get() ); if (status != IDA_SUCCESS) - throw CvodeException(status, "CVodeSetNonlinearSolverB"); + throw IDAException(status, "IDASetNonlinearSolverB"); } /** @@ -1052,7 +1083,7 @@ int fJv( Expects(model); model->fJv(t, x, dx, v, Jv, cj); - return model->checkFinite(gsl::make_span(Jv), ModelQuantity::Jv); + return model->checkFinite(gsl::make_span(Jv), ModelQuantity::Jv, t); } /** @@ -1083,7 +1114,7 @@ int fJvB( Expects(model); model->fJvB(t, x, dx, xB, dxB, vB, JvB, cj); - return model->checkFinite(gsl::make_span(JvB), ModelQuantity::JvB); + return model->checkFinite(gsl::make_span(JvB), ModelQuantity::JvB, t); } /** @@ -1105,7 +1136,7 @@ int froot( model->froot(t, x, dx, gsl::make_span(root, model->ne)); return model->checkFinite( - gsl::make_span(root, model->ne), ModelQuantity::root + gsl::make_span(root, model->ne), ModelQuantity::root, t ); } @@ -1131,7 +1162,7 @@ int fxdot(realtype t, N_Vector x, N_Vector dx, N_Vector xdot, void* user_data) { } if (t > 1e200 - && !model->checkFinite(gsl::make_span(x), ModelQuantity::xdot)) { + && !model->checkFinite(gsl::make_span(x), ModelQuantity::xdot, t)) { /* when t is large (typically ~1e300), CVODES may pass all NaN x to fxdot from which we typically cannot recover. To save time on normal execution, we do not always want to check finiteness @@ -1140,7 +1171,7 @@ int fxdot(realtype t, N_Vector x, N_Vector dx, N_Vector xdot, void* user_data) { } model->fxdot(t, x, dx, xdot); - return model->checkFinite(gsl::make_span(xdot), ModelQuantity::xdot); + return model->checkFinite(gsl::make_span(xdot), ModelQuantity::xdot, t); } /** @@ -1170,7 +1201,7 @@ int fxBdot( } model->fxBdot(t, x, dx, xB, dxB, xBdot); - return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot); + return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot, t); } /** @@ -1195,7 +1226,7 @@ int fqBdot( Expects(model); model->fqBdot(t, x, dx, xB, dxB, qBdot); - return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot); + return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot, t); } /** @@ -1217,7 +1248,9 @@ static int fxBdot_ss( Expects(model); model->fxBdot_ss(t, xB, dxB, xBdot); - return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot_ss); + return model->checkFinite( + gsl::make_span(xBdot), ModelQuantity::xBdot_ss, t + ); } /** @@ -1239,7 +1272,9 @@ static int fqBdot_ss( Expects(model); model->fqBdot_ss(t, xB, dxB, qBdot); - return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot_ss); + return model->checkFinite( + gsl::make_span(qBdot), ModelQuantity::qBdot_ss, t + ); } /** @@ -1257,7 +1292,7 @@ static int fqBdot_ss( * @return status flag indicating successful execution */ static int fJSparseB_ss( - realtype /*t*/, realtype /*cj*/, N_Vector /*x*/, N_Vector /*dx*/, + realtype t, realtype /*cj*/, N_Vector /*x*/, N_Vector /*dx*/, N_Vector xBdot, SUNMatrix JB, void* user_data, N_Vector /*tmp1*/, N_Vector /*tmp2*/, N_Vector /*tmp3*/ ) { @@ -1268,7 +1303,7 @@ static int fJSparseB_ss( model->fJSparseB_ss(JB); return model->checkFinite( - gsl::make_span(xBdot), ModelQuantity::JSparseB_ss + gsl::make_span(xBdot), ModelQuantity::JSparseB_ss, t ); } @@ -1301,7 +1336,9 @@ int fsxdot( for (int ip = 0; ip < model->nplist(); ip++) { model->fsxdot(t, x, dx, ip, sx[ip], sdx[ip], sxdot[ip]); - if (model->checkFinite(gsl::make_span(sxdot[ip]), ModelQuantity::sxdot) + if (model->checkFinite( + gsl::make_span(sxdot[ip]), ModelQuantity::sxdot, t + ) != AMICI_SUCCESS) return AMICI_RECOVERABLE_ERROR; } diff --git a/src/vector.cpp b/src/vector.cpp index 78b66d7954..460b92c71c 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -53,7 +53,6 @@ void AmiVector::copy(AmiVector const& other) { getLength(), other.getLength() ); std::copy(other.vec_.begin(), other.vec_.end(), vec_.begin()); - synchroniseNVector(); } void AmiVector::synchroniseNVector() { diff --git a/swig/amici.i b/swig/amici.i index 3518b296fe..46a58f8365 100644 --- a/swig/amici.i +++ b/swig/amici.i @@ -235,6 +235,14 @@ def __repr__(self): %} }; +%extend amici::LogItem { +%pythoncode %{ +def __repr__(self): + return (f"{self.__class__.__name__}(severity={self.severity}, " + f"identifier={self.identifier!r}, message={self.message!r})") +%} +}; + // Convert integer values to enum class // defeats the purpose of enum class, but didn't find a better way to allow for @@ -319,6 +327,7 @@ SteadyStateStatus = enum('SteadyStateStatus') NewtonDampingFactorMode = enum('NewtonDampingFactorMode') FixedParameterContext = enum('FixedParameterContext') RDataReporting = enum('RDataReporting') +Constraint = enum('Constraint') %} %template(SteadyStateStatusVector) std::vector; diff --git a/swig/misc.i b/swig/misc.i index 8015e28bfe..af166b48ed 100644 --- a/swig/misc.i +++ b/swig/misc.i @@ -4,6 +4,8 @@ %ignore amici::regexErrorToString; %ignore amici::writeSlice; %ignore ContextManager; +%ignore amici::scaleParameters; +%ignore amici::unscaleParameters; // Add necessary symbols to generated header %{ diff --git a/swig/std_unique_ptr.i b/swig/std_unique_ptr.i index c44513bcee..f73babfd9e 100644 --- a/swig/std_unique_ptr.i +++ b/swig/std_unique_ptr.i @@ -17,7 +17,7 @@ namespace std { pointer operator-> () const; pointer release (); - void reset (pointer __p=pointer()); + void reset (pointer __p=std::unique_ptr::pointer()); void swap (unique_ptr &__u); pointer get () const; operator bool () const; diff --git a/tests/cpp/testfunctions.cpp b/tests/cpp/testfunctions.cpp index 3e03eedfc4..8a8054f147 100644 --- a/tests/cpp/testfunctions.cpp +++ b/tests/cpp/testfunctions.cpp @@ -192,13 +192,6 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, // CHECK_EQUAL(AMICI_O2MODE_FULL, udata->o2mode); - if(hdf5::locationExists(file, resultPath + "/diagnosis/J")) { - expected = hdf5::getDoubleDataset2D(file, resultPath + "/diagnosis/J", m, n); - checkEqualArray(expected, rdata->J, atol, rtol, "J"); - } else { - ASSERT_TRUE(rdata->J.empty()); - } - if(hdf5::locationExists(file, resultPath + "/y")) { expected = hdf5::getDoubleDataset2D(file, resultPath + "/y", m, n); checkEqualArray(expected, rdata->y, atol, rtol, "y"); @@ -234,12 +227,22 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, ASSERT_TRUE(rdata->sigmaz.empty()); } - expected = hdf5::getDoubleDataset1D(file, resultPath + "/diagnosis/xdot"); - checkEqualArray(expected, rdata->xdot, atol, rtol, "xdot"); - expected = hdf5::getDoubleDataset1D(file, resultPath + "/x0"); checkEqualArray(expected, rdata->x0, atol, rtol, "x0"); + if(rdata->status == AMICI_SUCCESS) { + // for the failed cases, the stored results don't match + // since https://github.com/AMICI-dev/AMICI/pull/2349 + expected = hdf5::getDoubleDataset1D(file, resultPath + "/diagnosis/xdot"); + checkEqualArray(expected, rdata->xdot, atol, rtol, "xdot"); + + if(hdf5::locationExists(file, resultPath + "/diagnosis/J")) { + expected = hdf5::getDoubleDataset2D(file, resultPath + "/diagnosis/J", m, n); + checkEqualArray(expected, rdata->J, atol, rtol, "J"); + } else { + ASSERT_TRUE(rdata->J.empty()); + } + } if(rdata->sensi >= SensitivityOrder::first) { verifyReturnDataSensitivities(file, resultPath, rdata, model, atol, rtol); } else { diff --git a/version.txt b/version.txt index 2157409059..610e28725b 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.22.0 +0.23.1