diff --git a/.github/workflows/test_install.yml b/.github/workflows/test_install.yml index b075d8d6f2..b47ae6b090 100644 --- a/.github/workflows/test_install.yml +++ b/.github/workflows/test_install.yml @@ -33,10 +33,6 @@ jobs: run: | scripts/buildSundials.sh - - name: Build cpputest - run: | - scripts/buildCpputest.sh - - name: Build AMICI run: | scripts/buildAmici.sh diff --git a/.github/workflows/test_python_cplusplus.yml b/.github/workflows/test_python_cplusplus.yml index 2d26cd2884..81d32223cd 100644 --- a/.github/workflows/test_python_cplusplus.yml +++ b/.github/workflows/test_python_cplusplus.yml @@ -69,7 +69,7 @@ jobs: - name: C++ tests run: | - scripts/run-cpputest.sh + scripts/run-cpp-tests.sh - name: Install python package run: | @@ -85,7 +85,7 @@ jobs: --cov-report=xml:"${AMICI_DIR}/build/coverage_py.xml" \ --cov-append \ ${AMICI_DIR}/python/tests - + - name: example notebooks run: | scripts/runNotebook.sh python/examples/example_*/ @@ -96,7 +96,7 @@ jobs: - name: Codecov Python uses: codecov/codecov-action@v1 - with: + with: token: ${{ secrets.CODECOV_TOKEN }} file: ./build/coverage_py.xml flags: python @@ -163,4 +163,4 @@ jobs: - name: C++ tests run: | - scripts/run-cpputest.sh + scripts/run-cpp-tests.sh diff --git a/.gitignore b/.gitignore index 44053581ec..4b17a59451 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,9 @@ build/* build-debug/* build_xcode/* swig/python/build/* -tests/cpputest/build/* -tests/cpputest/build_xcode/* -tests/cpputest/Testing/* +tests/cpp/build/* +tests/cpp/build_xcode/* +tests/cpp/Testing/* doc-venv/* doc/* @@ -136,8 +136,8 @@ tests/test/* */tests/fricker_2010_apoptosis_amici/* */tests/explicit_amici/* */tests/fixed_initial_amici/* -tests/cpputest/writeResults.h5 -tests/cpputest/writeResults.h5.bak +tests/cpp/writeResults.h5 +tests/cpp/writeResults.h5.bak tests/sbml-test-suite/* tests/sbml-test-suite/ tests/sedml-test-suite/ @@ -171,7 +171,6 @@ AMICI_guide.pdf ThirdParty/bionetgen.tar.gz ThirdParty/BioNetGen-* -ThirdParty/cpputest-master* ThirdParty/doxygen/* ThirdParty/mtocpp-master* ThirdParty/sundials/build/* diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e2a7f1f95..09d4643528 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -268,7 +268,7 @@ if(BUILD_TESTS) if(ENABLE_HDF5) enable_testing() - add_subdirectory(tests/cpputest) + add_subdirectory(tests/cpp) else() message(WARNING "Cannot build tests with ENABLE_HDF5=OFF.") endif() diff --git a/documentation/CI.md b/documentation/CI.md index 93fd106dc2..3fd72d99f9 100644 --- a/documentation/CI.md +++ b/documentation/CI.md @@ -18,7 +18,7 @@ tests are integrated with CMake, see `make help` in the build directory. ## C++ unit and integration tests To run C++ tests, build AMICI with `make` or `scripts/buildAll.sh`, -then run `scripts/run-cpputest.sh`. +then run `scripts/run-cpp-tests.sh`. ## Python unit and integration tests @@ -58,7 +58,7 @@ To execute the Matlab test suite, run `tests/testModels.m`. Many of our integration tests are model simulations. The simulation results obtained from the Python and C++ are compared to results saved in an HDF5 file -(`tests/cpputest/expectedResults.h5`). +(`tests/cpp/expectedResults.h5`). Settings and data for the test simulations are also specified in this file. **Note:** The C++ code for the models is included in the repository under @@ -73,7 +73,7 @@ the Matlab model import routines change. This is done with - tests/cpputest/wrapTestModels.m + tests/cpp/wrapTestModels.m **Note:** This is currently only possible from Matlab < R2018a. This should change as soon as 1) all second-order sensitivity code is ported to C++/Python, @@ -84,13 +84,13 @@ for Python. ### Regenerating expected results To update test results, run `make test` in the build directory, -replace `tests/cpputest/expectedResults.h5` by -`tests/cpputest/writeResults.h5.bak` +replace `tests/cpp/expectedResults.h5` by +`tests/cpp/writeResults.h5.bak` [ONLY DO THIS AFTER TRIPLE CHECKING CORRECTNESS OF RESULTS] Before replacing the test results, confirm that only expected datasets have changed, e.g. using - h5diff -v --relative 1e-8 tests/cpputest/expectedResults.h5 tests/cpputest/writeResults.h5.bak | less + h5diff -v --relative 1e-8 tests/cpp/expectedResults.h5 tests/cpp/writeResults.h5.bak | less ## Adding/Updating tests diff --git a/documentation/cpp_installation.rst b/documentation/cpp_installation.rst index bd0ada57bb..f0c5ed1c03 100644 --- a/documentation/cpp_installation.rst +++ b/documentation/cpp_installation.rst @@ -24,8 +24,8 @@ To use AMICI from C++, run the .. code-block:: bash + ./scripts/buildSuiteSparse.sh ./scripts/buildSundials.sh - ./scripts/buildSuitesparse.sh ./scripts/buildAmici.sh script to build the AMICI library. diff --git a/documentation/development.rst b/documentation/development.rst index 0e4899bd27..365da13c67 100644 --- a/documentation/development.rst +++ b/documentation/development.rst @@ -60,7 +60,7 @@ process described below: (our CI pipeline will do this for you) - When adding new functionality, please also provide test cases (see - ``tests/cpputest/`` and + ``tests/cpp/`` and `documentation/CI.md `__) - Write meaningful commit messages @@ -68,10 +68,10 @@ process described below: - Run all tests to ensure nothing was broken (`more details `__) - - Run ``scripts/buildAll.sh && scripts/run-cpputest.sh``. + - Run ``scripts/buildAll.sh && scripts/run-cpp-tests.sh``. - If you made changes to the Matlab or C++ code and have a Matlab - license, please also run ``tests/cpputest/wrapTestModels.m`` and + license, please also run ``tests/cpp/wrapTestModels.m`` and ``tests/testModels.m`` - If you made changes to the Python or C++ code, run diff --git a/matlab/tests/testModels.m b/matlab/tests/testModels.m index baf1c57bda..047f86daf2 100644 --- a/matlab/tests/testModels.m +++ b/matlab/tests/testModels.m @@ -18,18 +18,18 @@ function testModels() model_dir = [fileparts(mfilename('fullpath')) '/../../models/']; cd(fileparts(mfilename('fullpath'))) - addpath(genpath('../../tests/cpputest')); + addpath(genpath('../../tests/cpp')); addpath(genpath('../examples')); % wrapTestModels() cd(fileparts(mfilename('fullpath'))) hdf5file = fullfile(fileparts(mfilename('fullpath')), ... - '../../tests/cpputest', 'expectedResults.h5'); - + '../../tests/cpp', 'expectedResults.h5'); + info = h5info(hdf5file); for imodel = 1:length(info.Groups) modelname = info.Groups(imodel).Name(2:end); - + if(~isempty(regexp(modelname,'^model_neuron'))) model_atol = 1e-9; model_rtol = 1e-4; @@ -42,18 +42,18 @@ function testModels() if(ismember(testname, ignoredTests)) continue end - + display(testname); [results,options,data,t,theta,kappa] = readDataFromHDF5(info.Groups(imodel).Groups(itest),hdf5file); - + % rebuild model old_path = addpath([model_dir modelname]); old_pwd = cd([model_dir modelname]); rebuild = str2func(['rebuild_' modelname]); rebuild(); cd(old_pwd); - + sol = getResults(modelname,options,data,t,theta,kappa); compareResults(sol,results); path(old_path); diff --git a/python/tests/test_pregenerated_models.py b/python/tests/test_pregenerated_models.py index 6bd63768b2..470cc8ed86 100755 --- a/python/tests/test_pregenerated_models.py +++ b/python/tests/test_pregenerated_models.py @@ -3,19 +3,18 @@ """Run simulations with Matlab-AMICI pre-generated models and verify using saved expectations.""" -import h5py -import amici import os -from amici.gradient_check import check_derivatives, check_results -import pytest +from pathlib import Path +import amici +import h5py import numpy as np +import pytest +from amici.gradient_check import check_derivatives, check_results - -options_file = os.path.join(os.path.dirname(__file__), '..', '..', - 'tests', 'cpputest', 'testOptions.h5') -expected_results_file = os.path.join(os.path.dirname(__file__), '..', '..', - 'tests', 'cpputest', 'expectedResults.h5') +cpp_test_dir = Path(__file__).parents[2] / 'tests' / 'cpp' +options_file = str(cpp_test_dir / 'testOptions.h5') +expected_results_file = str(cpp_test_dir / 'expectedResults.h5') expected_results = h5py.File(expected_results_file, 'r') model_cases = [(sub_test, case) @@ -43,10 +42,9 @@ def test_pregenerated_model(sub_test, case): else: model_name = sub_test - model_swig_folder = \ - os.path.join(os.path.dirname(__file__), '..', '..', 'build', 'tests', - 'cpputest', f'external_{model_name}-prefix', - 'src', f'external_{model_name}-build', 'swig') + model_swig_folder = str(Path(__file__).parents[2] / 'build' / 'tests' + / 'cpp' / f'external_{model_name}-prefix' / 'src' + / f'external_{model_name}-build' / 'swig') test_model_module = amici.import_model_module( module_name=model_name, module_path=model_swig_folder) @@ -64,7 +62,7 @@ def test_pregenerated_model(sub_test, case): edata = None if 'data' in expected_results[sub_test][case].keys(): edata = amici.readSimulationExpData( - expected_results_file, + str(expected_results_file), f'/{sub_test}/{case}/data', model.get() ) rdata = amici.runAmiciSimulation(model, solver, diff --git a/scripts/README.md b/scripts/README.md index 5434d511b9..67f64dca5c 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -14,12 +14,7 @@ This directory contains a number of build, installation, and CI scripts. Download and build [BioNetGen](https://www.csb.pitt.edu/Faculty/Faeder/?page_id=409) (required for some tests) - -* `buildCpputest.sh` - - Download and build [CppUTest](https://cpputest.github.io/) - (required for C++ test suite) - + * `buildSuiteSparse.sh` Build [SuiteSparse](http://faculty.cse.tamu.edu/davis/suitesparse.html) @@ -64,7 +59,7 @@ This directory contains a number of build, installation, and CI scripts. Run static code analysis -* `run-cpputest.sh` +* `run-cpp-tests.sh` Run C++ unit and integration tests diff --git a/scripts/buildAmici.sh b/scripts/buildAmici.sh index 446fe1d8bd..735e05fd3b 100755 --- a/scripts/buildAmici.sh +++ b/scripts/buildAmici.sh @@ -2,7 +2,8 @@ # # Build libamici # -set -e +set -eou pipefail + cmake=${CMAKE:-cmake} make=${MAKE:-make} @@ -12,28 +13,26 @@ amici_build_dir="${amici_path}/build" mkdir -p "${amici_build_dir}" cd "${amici_build_dir}" -cpputest_build_dir="${amici_path}/ThirdParty/cpputest-master/build/" - -if [[ $TRAVIS = true ]] || [[ $GITHUB_ACTIONS = true ]] || [[ $ENABLE_AMICI_DEBUGGING = TRUE ]]; -then +if [ "${TRAVIS:-}" = true ] || + [ "${GITHUB_ACTIONS:-}" = true ] || + [ "${ENABLE_AMICI_DEBUGGING:-}" = TRUE ]; then # Running on CI server build_type="Debug" else build_type="RelWithDebInfo" fi -CppUTest_DIR=${cpputest_build_dir} \ - ${cmake} \ - -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror" \ - -DCMAKE_BUILD_TYPE=$build_type \ - -DPython3_EXECUTABLE="$(command -v python3)" .. +${cmake} \ + -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror" \ + -DCMAKE_BUILD_TYPE=$build_type \ + -DPython3_EXECUTABLE="$(command -v python3)" .. # build, with or without sonarcloud wrapper -if [[ "$CI_SONARCLOUD" == "TRUE" ]]; then +if [ "${CI_SONARCLOUD:-}" = "TRUE" ]; then build-wrapper-linux-x86-64 \ --out-dir "${amici_path}/bw-output" \ cmake --build . --parallel -elif [[ "$TRAVIS" == "true" ]]; then +elif [ "${TRAVIS:-}" = "true" ]; then cmake --build . ${make} python-sdist else diff --git a/scripts/buildCpputest.sh b/scripts/buildCpputest.sh deleted file mode 100755 index 1d4a8f468c..0000000000 --- a/scripts/buildCpputest.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# -# Build CppUTest -# -set -e - -script_path=$(dirname "$BASH_SOURCE") -amici_path=$(cd "$script_path/.." && pwd) - -cmake=${CMAKE:-cmake} -make=${MAKE:-make} - -# Cpputest -mkdir -p "${amici_path}/ThirdParty" -cd "${amici_path}/ThirdParty" -export CPPUTEST_BUILD_DIR="${amici_path}/ThirdParty/cpputest-master/" - -if [ ! -d "cpputest-master" ]; then - if [ ! -e "cpputest-master.zip" ]; then - wget -q -O cpputest-master.zip https://codeload.github.com/cpputest/cpputest/zip/master - fi - unzip -q cpputest-master.zip - #cd cpputest-master/ && ./autogen.sh && ./configure && make -fi - -cd cpputest-master -mkdir -p build -cd build -${cmake} -DTESTS=OFF -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release \ - -DC++11=ON -DMEMORY_LEAK_DETECTION=OFF .. -${make} -j4 - diff --git a/scripts/buildDependencies.sh b/scripts/buildDependencies.sh index 51a971a88d..1caaf0eb48 100755 --- a/scripts/buildDependencies.sh +++ b/scripts/buildDependencies.sh @@ -9,5 +9,4 @@ script_path=$(cd "$script_path" && pwd) "${script_path}/buildSuiteSparse.sh" "${script_path}/buildSundials.sh" -"${script_path}/buildCpputest.sh" "${script_path}/buildBNGL.sh" diff --git a/scripts/buildXcode.sh b/scripts/buildXcode.sh index d78edde4bd..97dfbf24e7 100755 --- a/scripts/buildXcode.sh +++ b/scripts/buildXcode.sh @@ -12,18 +12,16 @@ CMAKE=${CMAKE:-cmake} ${AMICI_PATH}/scripts/buildSuiteSparse.sh ${AMICI_PATH}/scripts/buildSundials.sh ${AMICI_PATH}/scripts/buildAmici.sh -${AMICI_PATH}/scripts/buildCpputest.sh -cp ${AMICI_PATH}/tests/cpputest/expectedResults.h5 ./expectedResults.h5 +cp ${AMICI_PATH}/tests/cpp/expectedResults.h5 ./expectedResults.h5 mkdir -p ${AMICI_PATH}/build_xcode cd ${AMICI_PATH}/build_xcode -CPPUTEST_BUILD_DIR=${AMICI_PATH}/ThirdParty/cpputest-master/build/ -CppUTest_DIR=${CPPUTEST_BUILD_DIR} ${CMAKE} -G"Xcode" -DCMAKE_BUILD_TYPE=Debug .. +${CMAKE} -G"Xcode" -DCMAKE_BUILD_TYPE=Debug .. for model in steadystate robertson neuron neuron_o2 jakstat_adjoint jakstat_adjoint_o2 dirac events nested_events do - cp ${AMICI_PATH}/build/tests/cpputest/external_model_${model}-prefix/src/external_model_${model}-build/libmodel_${model}.a \ - ${AMICI_PATH}/build_xcode/tests/cpputest/external_model_${model}-prefix/src/external_model_${model}-build/libmodel_${model}.a + cp ${AMICI_PATH}/build/tests/cpp/external_model_${model}-prefix/src/external_model_${model}-build/libmodel_${model}.a \ + ${AMICI_PATH}/build_xcode/tests/cpp/external_model_${model}-prefix/src/external_model_${model}-build/libmodel_${model}.a done diff --git a/scripts/run-cpp-tests.sh b/scripts/run-cpp-tests.sh new file mode 100755 index 0000000000..963ef3c51c --- /dev/null +++ b/scripts/run-cpp-tests.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -eou pipefail + +SCRIPT_PATH=$(dirname "$BASH_SOURCE") +AMICI_PATH=$(cd "$SCRIPT_PATH/.." && pwd) + +if [[ "${ENABLE_GCOV_COVERAGE:-}" == TRUE ]]; then + lcov --base-directory "${AMICI_PATH}" \ + --directory "${AMICI_PATH}/build/CMakeFiles/amici.dir/src" \ + --zerocounters -q +fi + +# run tests +cd "${AMICI_PATH}/build" + +ctest -V +ret=$? +if [[ $ret != 0 ]]; then exit $ret; fi +mv "${AMICI_PATH}/tests/cpp/writeResults.h5" \ + "${AMICI_PATH}/tests/cpp/writeResults.h5.bak" diff --git a/scripts/run-cppcheck.sh b/scripts/run-cppcheck.sh index 82018977ea..57c669439a 100755 --- a/scripts/run-cppcheck.sh +++ b/scripts/run-cppcheck.sh @@ -1,15 +1,18 @@ #!/bin/bash # Check test suite with valgrind -# Note: CppuTest memcheck should be disabled # Note: Consider using ctest -T memcheck instead +set -euo pipefail + SCRIPT_PATH=$(dirname "$BASH_SOURCE") AMICI_PATH=$(cd "$SCRIPT_PATH"/.. && pwd) -cd ${AMICI_PATH} +cd "${AMICI_PATH}" -cppcheck -i"${AMICI_PATH}"/src/doc "${AMICI_PATH}"/src \ - -I$"{AMICI_PATH}"/include/ \ - --enable=style \ - --exitcode-suppressions="${AMICI_PATH}"/.cppcheck-exitcode-suppressions +cppcheck \ + "-i${AMICI_PATH}/src/doc" \ + "${AMICI_PATH}/src" \ + "-I${AMICI_PATH}/include/" \ + --enable=style \ + "--exitcode-suppressions=${AMICI_PATH}/.cppcheck-exitcode-suppressions" diff --git a/scripts/run-cpputest.sh b/scripts/run-cpputest.sh deleted file mode 100755 index 781a31d32f..0000000000 --- a/scripts/run-cpputest.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -SCRIPT_PATH=$(dirname $BASH_SOURCE) -AMICI_PATH=$(cd $SCRIPT_PATH/.. && pwd) - -if [[ "$ENABLE_GCOV_COVERAGE" == TRUE ]]; then lcov --base-directory ${AMICI_PATH} --directory ${AMICI_PATH}/build/CMakeFiles/amici.dir/src --zerocounters -q; fi - -# run tests -cd ${AMICI_PATH}/build - -ctest -V -ret=$? -if [[ $ret != 0 ]]; then exit $ret; fi -mv ${AMICI_PATH}/tests/cpputest/writeResults.h5 ${AMICI_PATH}/tests/cpputest/writeResults.h5.bak diff --git a/scripts/run-valgrind-cpp.sh b/scripts/run-valgrind-cpp.sh index af0daa95b9..7d868d98ef 100755 --- a/scripts/run-valgrind-cpp.sh +++ b/scripts/run-valgrind-cpp.sh @@ -1,19 +1,19 @@ #!/bin/bash # Check test suite with valgrind -# Note: CppuTest memcheck should be disabled # Note: Consider using ctest -T memcheck instead -SCRIPT_PATH=$(dirname $BASH_SOURCE) -AMICI_PATH=$(cd $SCRIPT_PATH/.. && pwd) +SCRIPT_PATH=$(dirname "$BASH_SOURCE") +AMICI_PATH=$(cd "$SCRIPT_PATH/.." && pwd) -set -e +set -eou pipefail # run tests -cd ${AMICI_PATH}/build/tests/cpputest/ +cd "${AMICI_PATH}/build/tests/cpp/" VALGRIND_OPTS="--leak-check=full --error-exitcode=1 --trace-children=yes --show-leak-kinds=definite" set -x for MODEL in $(ctest -N | grep "Test[ ]*#" | grep -v unittests | sed --regexp-extended 's/ *Test[ ]*#[0-9]+: model_(.*)_test/\1/') - do cd ${AMICI_PATH}/build/tests/cpputest/${MODEL}/ && valgrind ${VALGRIND_OPTS} ./model_${MODEL}_test + do cd "${AMICI_PATH}/build/tests/cpp/${MODEL}/" && valgrind ${VALGRIND_OPTS} "./model_${MODEL}_test" done -cd ${AMICI_PATH}/build/tests/cpputest/unittests/ && valgrind ${VALGRIND_OPTS} ./unittests +cd "${AMICI_PATH}/build/tests/cpp/unittests/" +valgrind ${VALGRIND_OPTS} ./unittests diff --git a/tests/README.md b/tests/README.md index 488d136f05..0758daf484 100644 --- a/tests/README.md +++ b/tests/README.md @@ -2,7 +2,7 @@ This directory contains: -- C++ unit tests and integration tests (`cpputest/`) +- C++ unit tests and integration tests (`cpp/`) - Scripts for running the SBML semantic test suite, exercising the Python interface - Scripts for running the PEtab test suite, exercising the Python interface diff --git a/tests/cpputest/CMakeLists.txt b/tests/cpp/CMakeLists.txt similarity index 60% rename from tests/cpputest/CMakeLists.txt rename to tests/cpp/CMakeLists.txt index fa441f3245..6586fb3ec4 100644 --- a/tests/cpputest/CMakeLists.txt +++ b/tests/cpp/CMakeLists.txt @@ -1,15 +1,43 @@ -project(amiciIntegrationTests) +# ------------------------------------------------------------------------------ +# Set up google test +# ------------------------------------------------------------------------------ + +# Download and unpack googletest at configure time +configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) +execute_process( + COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download) +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() +execute_process( + COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download) +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker settings on Windows +set(gtest_force_shared_crt + ON + CACHE BOOL "" FORCE) -find_package(CppUTest REQUIRED) -# because Cpputest doesn't seem to care about MEMORY_LEAK_DETECTION=OFF -add_definitions(-DD_MemoryLeakWarningPlugin_h) +# Add googletest directly to our build. This defines the gtest and gtest_main +# targets. +add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src + ${CMAKE_CURRENT_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL) + +# ------------------------------------------------------------------------------ +# AMICI C++ tests +# ------------------------------------------------------------------------------ + +project(amiciIntegrationTests) # models depend on Upstream::amici add_library(Upstream::amici ALIAS amici) -set(CMAKE_CXX_FLAGS_OLD "${CMAKE_CXX_FLAGS}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include sstream -include functional") - # Amici testing library add_library(amici-testing testfunctions.cpp) target_compile_definitions(amici-testing @@ -19,11 +47,10 @@ target_compile_definitions(amici-testing ) target_include_directories(amici-testing PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} - PUBLIC ${CppUTest_INCLUDE_DIRS} ) target_link_libraries(amici-testing PUBLIC Upstream::amici - PUBLIC ${CppUTest_LIBRARIES} + PUBLIC gtest_main ) # Names of models for which tests are to be run diff --git a/tests/cpp/CMakeLists.txt.in b/tests/cpp/CMakeLists.txt.in new file mode 100644 index 0000000000..6e80530a76 --- /dev/null +++ b/tests/cpp/CMakeLists.txt.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/tests/cpputest/robertson/CMakeLists.txt b/tests/cpp/calvetti/CMakeLists.txt similarity index 67% rename from tests/cpputest/robertson/CMakeLists.txt rename to tests/cpp/calvetti/CMakeLists.txt index 388fdf9152..5f3db0773e 100644 --- a/tests/cpputest/robertson/CMakeLists.txt +++ b/tests/cpp/calvetti/CMakeLists.txt @@ -2,18 +2,20 @@ get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) project(model_${MODEL_NAME}_test) set(SRC_LIST - ../main.cpp tests1.cpp ) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - add_executable(${PROJECT_NAME} ${SRC_LIST}) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) target_link_libraries(${PROJECT_NAME} amici-testing model_${MODEL_NAME} + gtest_main ) -add_test(NAME ${PROJECT_NAME} COMMAND ./${PROJECT_NAME} -c) +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/calvetti/tests1.cpp b/tests/cpp/calvetti/tests1.cpp similarity index 50% rename from tests/cpputest/calvetti/tests1.cpp rename to tests/cpp/calvetti/tests1.cpp index dfde30fd9d..fb093dc5bc 100644 --- a/tests/cpputest/calvetti/tests1.cpp +++ b/tests/cpp/calvetti/tests1.cpp @@ -1,13 +1,10 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include "wrapfunctions.h" #include #include -TEST_GROUP(groupCalvetti){}; +#include -TEST(groupCalvetti, testSimulation) +TEST(ExampleCalvetti, Simulation) { amici::simulateVerifyWrite("/model_calvetti/nosensi/"); } diff --git a/tests/cpputest/calvetti/CMakeLists.txt b/tests/cpp/dirac/CMakeLists.txt similarity index 67% rename from tests/cpputest/calvetti/CMakeLists.txt rename to tests/cpp/dirac/CMakeLists.txt index 388fdf9152..5f3db0773e 100644 --- a/tests/cpputest/calvetti/CMakeLists.txt +++ b/tests/cpp/dirac/CMakeLists.txt @@ -2,18 +2,20 @@ get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) project(model_${MODEL_NAME}_test) set(SRC_LIST - ../main.cpp tests1.cpp ) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - add_executable(${PROJECT_NAME} ${SRC_LIST}) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) target_link_libraries(${PROJECT_NAME} amici-testing model_${MODEL_NAME} + gtest_main ) -add_test(NAME ${PROJECT_NAME} COMMAND ./${PROJECT_NAME} -c) +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/dirac/tests1.cpp b/tests/cpp/dirac/tests1.cpp similarity index 54% rename from tests/cpputest/dirac/tests1.cpp rename to tests/cpp/dirac/tests1.cpp index 89d71f1f9b..d1d79af7fc 100644 --- a/tests/cpputest/dirac/tests1.cpp +++ b/tests/cpp/dirac/tests1.cpp @@ -1,19 +1,17 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include #include "wrapfunctions.h" #include -TEST_GROUP(groupDirac){}; +#include + -TEST(groupDirac, testSimulation) +TEST(ExampleDirac, Simulation) { amici::simulateVerifyWrite("/model_dirac/nosensi/"); } -TEST(groupDirac, testSensitivityForward) +TEST(ExampleDirac, SensitivityForward) { amici::simulateVerifyWrite("/model_dirac/sensiforward/"); } diff --git a/tests/cpputest/dirac/CMakeLists.txt b/tests/cpp/events/CMakeLists.txt similarity index 54% rename from tests/cpputest/dirac/CMakeLists.txt rename to tests/cpp/events/CMakeLists.txt index 99958ded68..5f3db0773e 100644 --- a/tests/cpputest/dirac/CMakeLists.txt +++ b/tests/cpp/events/CMakeLists.txt @@ -2,17 +2,20 @@ get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) project(model_${MODEL_NAME}_test) set(SRC_LIST - ../main.cpp tests1.cpp ) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - add_executable(${PROJECT_NAME} ${SRC_LIST}) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) + target_link_libraries(${PROJECT_NAME} amici-testing model_${MODEL_NAME} + gtest_main ) -add_test(NAME ${PROJECT_NAME} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME} -c) +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/events/tests1.cpp b/tests/cpp/events/tests1.cpp similarity index 55% rename from tests/cpputest/events/tests1.cpp rename to tests/cpp/events/tests1.cpp index f5ee53a7fb..a9b1ff8448 100644 --- a/tests/cpputest/events/tests1.cpp +++ b/tests/cpp/events/tests1.cpp @@ -1,24 +1,21 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include "testfunctions.h" #include "wrapfunctions.h" #include -TEST_GROUP(groupEvents){}; +#include -TEST(groupEvents, testDefault) +TEST(ExampleEvents, Default) { amici::simulateWithDefaultOptions(); } -TEST(groupEvents, testSimulation) +TEST(ExampleEvents, Simulation) { amici::simulateVerifyWrite("/model_events/nosensi/"); } -TEST(groupEvents, testSensitivityForward) +TEST(ExampleEvents, SensitivityForward) { amici::simulateVerifyWrite("/model_events/sensiforward/"); } diff --git a/tests/cpputest/expectedResults.h5 b/tests/cpp/expectedResults.h5 similarity index 100% rename from tests/cpputest/expectedResults.h5 rename to tests/cpp/expectedResults.h5 diff --git a/tests/cpputest/jakstat_adjoint/CMakeLists.txt b/tests/cpp/jakstat_adjoint/CMakeLists.txt similarity index 54% rename from tests/cpputest/jakstat_adjoint/CMakeLists.txt rename to tests/cpp/jakstat_adjoint/CMakeLists.txt index 3197ed7a72..5f3db0773e 100644 --- a/tests/cpputest/jakstat_adjoint/CMakeLists.txt +++ b/tests/cpp/jakstat_adjoint/CMakeLists.txt @@ -2,17 +2,20 @@ get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) project(model_${MODEL_NAME}_test) set(SRC_LIST - ../main.cpp tests1.cpp ) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - add_executable(${PROJECT_NAME} ${SRC_LIST}) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) + target_link_libraries(${PROJECT_NAME} amici-testing model_${MODEL_NAME} + gtest_main ) -add_test(NAME ${PROJECT_NAME} COMMAND ./${PROJECT_NAME} -c) +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/jakstat_adjoint/tests1.cpp b/tests/cpp/jakstat_adjoint/tests1.cpp similarity index 84% rename from tests/cpputest/jakstat_adjoint/tests1.cpp rename to tests/cpp/jakstat_adjoint/tests1.cpp index a69ed24a50..2ca15fdf6e 100644 --- a/tests/cpputest/jakstat_adjoint/tests1.cpp +++ b/tests/cpp/jakstat_adjoint/tests1.cpp @@ -1,46 +1,43 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include "testfunctions.h" #include "wrapfunctions.h" #include -TEST_GROUP(groupJakstatAdjoint){}; +#include -TEST(groupJakstatAdjoint, testSimulation) +TEST(ExampleJakstatAdjoint, Simulation) { amici::simulateVerifyWrite("/model_jakstat_adjoint/nosensi/"); } -TEST(groupJakstatAdjoint, testSensitivityForward) +TEST(ExampleJakstatAdjoint, SensitivityForward) { amici::simulateVerifyWrite("/model_jakstat_adjoint/sensiforward/"); } -TEST(groupJakstatAdjoint, testSensitivityForwardLogParam) +TEST(ExampleJakstatAdjoint, SensitivityForwardLogParam) { amici::simulateVerifyWrite("/model_jakstat_adjoint/sensiforwardlogparam/"); } -TEST(groupJakstatAdjoint, testSensitivityAdjoint) +TEST(ExampleJakstatAdjoint, SensitivityAdjoint) { amici::simulateVerifyWrite("/model_jakstat_adjoint/sensiadjoint/"); } -TEST(groupJakstatAdjoint, testSensitivityForwardEmptySensInd) +TEST(ExampleJakstatAdjoint, SensitivityForwardEmptySensInd) { amici::simulateVerifyWrite( "/model_jakstat_adjoint/sensiforwardemptysensind/"); } -TEST(groupJakstatAdjoint, testSensitivityAdjointEmptySensInd) +TEST(ExampleJakstatAdjoint, SensitivityAdjointEmptySensInd) { amici::simulateVerifyWrite( "/model_jakstat_adjoint/sensiadjointemptysensind/"); } -IGNORE_TEST(groupJakstatAdjoint, testSensitivityAdjointUnusedNanOutputs) +TEST(ExampleJakstatAdjoint, DISABLED_SensitivityAdjointUnusedNanOutputs) { /* UN-IGNORE ONCE THIS MODEL HAS BEEN IMPORTED VIA PYTHON INTERFACE */ auto model = amici::generic_model::getModel(); @@ -71,10 +68,10 @@ IGNORE_TEST(groupJakstatAdjoint, testSensitivityAdjointUnusedNanOutputs) auto rdata = runAmiciSimulation(*solver, edata.get(), *model); for (int i = 0; i < model->nplist(); ++i) - CHECK_FALSE(std::isnan(rdata->sllh[i])); + ASSERT_FALSE(std::isnan(rdata->sllh[i])); } -TEST(groupJakstatAdjoint, testSensitivityReplicates) +TEST(ExampleJakstatAdjoint, SensitivityReplicates) { // Check that we can handle replicates correctly @@ -124,11 +121,11 @@ TEST(groupJakstatAdjoint, testSensitivityReplicates) solver->setSensitivityMethod(amici::SensitivityMethod::forward); auto rdata2 = runAmiciSimulation(*solver, &edata, *model); auto llh2 = rdata2->llh; - DOUBLES_EQUAL(2.0 * llh1, llh2, 1e-6); + ASSERT_NEAR(2.0 * llh1, llh2, 1e-6); // adjoint + replicates solver->setSensitivityMethod(amici::SensitivityMethod::adjoint); auto rdata3 = runAmiciSimulation(*solver, &edata, *model); auto llh3 = rdata3->llh; - DOUBLES_EQUAL(llh2, llh3, 1e-6); + ASSERT_NEAR(llh2, llh3, 1e-6); } diff --git a/tests/cpp/jakstat_adjoint_o2/CMakeLists.txt b/tests/cpp/jakstat_adjoint_o2/CMakeLists.txt new file mode 100644 index 0000000000..5f3db0773e --- /dev/null +++ b/tests/cpp/jakstat_adjoint_o2/CMakeLists.txt @@ -0,0 +1,21 @@ +get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +project(model_${MODEL_NAME}_test) + +set(SRC_LIST + tests1.cpp +) + +add_executable(${PROJECT_NAME} ${SRC_LIST}) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) + +target_link_libraries(${PROJECT_NAME} + amici-testing + model_${MODEL_NAME} + gtest_main +) + +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/jakstat_adjoint_o2/tests1.cpp b/tests/cpp/jakstat_adjoint_o2/tests1.cpp similarity index 53% rename from tests/cpputest/jakstat_adjoint_o2/tests1.cpp rename to tests/cpp/jakstat_adjoint_o2/tests1.cpp index 1331c0c369..b03b9da138 100644 --- a/tests/cpputest/jakstat_adjoint_o2/tests1.cpp +++ b/tests/cpp/jakstat_adjoint_o2/tests1.cpp @@ -1,24 +1,22 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include "testfunctions.h" #include "wrapfunctions.h" #include -TEST_GROUP(groupJakstatAdjointO2){}; +#include + -TEST(groupJakstatAdjointO2, testSensitivityForward2) +TEST(ExampleJakstatAdjointO2, SensitivityForward2) { amici::simulateVerifyWrite("/model_jakstat_adjoint/sensi2forward/"); } -TEST(groupJakstatAdjointO2, testSensitivityForward2LogParam) +TEST(ExampleJakstatAdjointO2, SensitivityForward2LogParam) { amici::simulateVerifyWrite("/model_jakstat_adjoint/sensi2forwardlogparam/"); } -TEST(groupJakstatAdjointO2, testSensitivityAdjoint2) +TEST(ExampleJakstatAdjointO2, SensitivityAdjoint2) { amici::simulateVerifyWrite("/model_jakstat_adjoint/sensi2adjoint/"); } diff --git a/tests/cpp/nested_events/CMakeLists.txt b/tests/cpp/nested_events/CMakeLists.txt new file mode 100644 index 0000000000..5f3db0773e --- /dev/null +++ b/tests/cpp/nested_events/CMakeLists.txt @@ -0,0 +1,21 @@ +get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +project(model_${MODEL_NAME}_test) + +set(SRC_LIST + tests1.cpp +) + +add_executable(${PROJECT_NAME} ${SRC_LIST}) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) + +target_link_libraries(${PROJECT_NAME} + amici-testing + model_${MODEL_NAME} + gtest_main +) + +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/nested_events/tests1.cpp b/tests/cpp/nested_events/tests1.cpp similarity index 55% rename from tests/cpputest/nested_events/tests1.cpp rename to tests/cpp/nested_events/tests1.cpp index 7208b713de..7a74f5465b 100644 --- a/tests/cpputest/nested_events/tests1.cpp +++ b/tests/cpp/nested_events/tests1.cpp @@ -1,19 +1,16 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include "testfunctions.h" #include "wrapfunctions.h" #include -TEST_GROUP(groupEvents){}; +#include -TEST(groupEvents, testSimulation) +TEST(ExampleNestedEvents, Simulation) { amici::simulateVerifyWrite("/model_nested_events/nosensi/"); } -TEST(groupEvents, testSensitivityForward) +TEST(ExampleNestedEvents, SensitivityForward) { amici::simulateVerifyWrite("/model_nested_events/sensiforward/"); } diff --git a/tests/cpp/neuron/CMakeLists.txt b/tests/cpp/neuron/CMakeLists.txt new file mode 100644 index 0000000000..5f3db0773e --- /dev/null +++ b/tests/cpp/neuron/CMakeLists.txt @@ -0,0 +1,21 @@ +get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +project(model_${MODEL_NAME}_test) + +set(SRC_LIST + tests1.cpp +) + +add_executable(${PROJECT_NAME} ${SRC_LIST}) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) + +target_link_libraries(${PROJECT_NAME} + amici-testing + model_${MODEL_NAME} + gtest_main +) + +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/neuron/tests1.cpp b/tests/cpp/neuron/tests1.cpp similarity index 62% rename from tests/cpputest/neuron/tests1.cpp rename to tests/cpp/neuron/tests1.cpp index f5d645b7af..cfdc04ef9c 100644 --- a/tests/cpputest/neuron/tests1.cpp +++ b/tests/cpp/neuron/tests1.cpp @@ -1,20 +1,17 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include "testfunctions.h" #include "wrapfunctions.h" #include -TEST_GROUP(groupNeuron){}; +#include -TEST(groupNeuron, testSimulation) +TEST(ExampleNeuron, Simulation) { amici::simulateVerifyWrite( "/model_neuron/nosensi/", 100 * TEST_ATOL, 100 * TEST_RTOL); } -TEST(groupNeuron, testSensitivityForward) +TEST(ExampleNeuron, SensitivityForward) { amici::simulateVerifyWrite( "/model_neuron/sensiforward/", 10 * TEST_ATOL, 10 * TEST_RTOL); diff --git a/tests/cpp/neuron_o2/CMakeLists.txt b/tests/cpp/neuron_o2/CMakeLists.txt new file mode 100644 index 0000000000..5f3db0773e --- /dev/null +++ b/tests/cpp/neuron_o2/CMakeLists.txt @@ -0,0 +1,21 @@ +get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +project(model_${MODEL_NAME}_test) + +set(SRC_LIST + tests1.cpp +) + +add_executable(${PROJECT_NAME} ${SRC_LIST}) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) + +target_link_libraries(${PROJECT_NAME} + amici-testing + model_${MODEL_NAME} + gtest_main +) + +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/neuron_o2/tests1.cpp b/tests/cpp/neuron_o2/tests1.cpp similarity index 56% rename from tests/cpputest/neuron_o2/tests1.cpp rename to tests/cpp/neuron_o2/tests1.cpp index 57b9ac47ba..5be0c9ea54 100644 --- a/tests/cpputest/neuron_o2/tests1.cpp +++ b/tests/cpp/neuron_o2/tests1.cpp @@ -1,14 +1,11 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include "testfunctions.h" #include "wrapfunctions.h" #include -TEST_GROUP(groupNeuronO2){}; +#include -TEST(groupNeuronO2, testSensitivity2) +TEST(ExampleNeuronO2, Sensitivity2) { amici::simulateVerifyWrite( "/model_neuron/sensi2forward/", 10 * TEST_ATOL, 10 * TEST_RTOL); diff --git a/tests/cpp/robertson/CMakeLists.txt b/tests/cpp/robertson/CMakeLists.txt new file mode 100644 index 0000000000..5f3db0773e --- /dev/null +++ b/tests/cpp/robertson/CMakeLists.txt @@ -0,0 +1,21 @@ +get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +project(model_${MODEL_NAME}_test) + +set(SRC_LIST + tests1.cpp +) + +add_executable(${PROJECT_NAME} ${SRC_LIST}) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) + +target_link_libraries(${PROJECT_NAME} + amici-testing + model_${MODEL_NAME} + gtest_main +) + +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/robertson/tests1.cpp b/tests/cpp/robertson/tests1.cpp similarity index 63% rename from tests/cpputest/robertson/tests1.cpp rename to tests/cpp/robertson/tests1.cpp index 441eac0b14..3cb74ada3a 100644 --- a/tests/cpputest/robertson/tests1.cpp +++ b/tests/cpp/robertson/tests1.cpp @@ -1,30 +1,27 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include "wrapfunctions.h" #include #include -TEST_GROUP(groupRobertson){}; +#include -TEST(groupRobertson, testSimulation) +TEST(ExampleRobertson, Simulation) { amici::simulateVerifyWrite("/model_robertson/nosensi/"); } -TEST(groupRobertson, testSensitivityForward) +TEST(ExampleRobertson, SensitivityForward) { amici::simulateVerifyWrite( "/model_robertson/sensiforward/", 1e6 * TEST_ATOL, 1e2 * TEST_RTOL); } -TEST(groupRobertson, testSensitivityForwardDense) +TEST(ExampleRobertson, SensitivityForwardDense) { amici::simulateVerifyWrite( "/model_robertson/sensiforwarddense/", 1e6 * TEST_ATOL, 1e2 * TEST_RTOL); } -TEST(groupRobertson, testSensitivityForwardSPBCG) +TEST(ExampleRobertson, SensitivityForwardSPBCG) { amici::simulateVerifyWrite( "/model_robertson/sensiforwardSPBCG/", 1e7 * TEST_ATOL, 1e2 * TEST_RTOL); diff --git a/tests/cpp/steadystate/CMakeLists.txt b/tests/cpp/steadystate/CMakeLists.txt new file mode 100644 index 0000000000..5f3db0773e --- /dev/null +++ b/tests/cpp/steadystate/CMakeLists.txt @@ -0,0 +1,21 @@ +get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +project(model_${MODEL_NAME}_test) + +set(SRC_LIST + tests1.cpp +) + +add_executable(${PROJECT_NAME} ${SRC_LIST}) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_dependencies(${PROJECT_NAME} external_model_${MODEL_NAME}) + +target_link_libraries(${PROJECT_NAME} + amici-testing + model_${MODEL_NAME} + gtest_main +) + +include(GoogleTest) +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpputest/steadystate/tests1.cpp b/tests/cpp/steadystate/tests1.cpp similarity index 64% rename from tests/cpputest/steadystate/tests1.cpp rename to tests/cpp/steadystate/tests1.cpp index 78be0a2adc..505f8f15ed 100644 --- a/tests/cpputest/steadystate/tests1.cpp +++ b/tests/cpp/steadystate/tests1.cpp @@ -1,19 +1,16 @@ -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - #include "testfunctions.h" #include "wrapfunctions.h" #include -TEST_GROUP(groupSteadystate){}; +#include -TEST(groupSteadystate, testDefault) +TEST(ExampleSteadystate, Default) { amici::simulateWithDefaultOptions(); } -TEST(groupSteadystate, testModelFromHDF5) +TEST(ExampleSteadystate, ModelFromHDF5) { // Test reading some python-written options std::vector pExp{ 1, 0.5, 0.4, 2, 0.1 }; @@ -25,43 +22,43 @@ TEST(groupSteadystate, testModelFromHDF5) amici::checkEqualArray( kExp, model->getFixedParameters(), TEST_ATOL, TEST_RTOL, "k"); - CHECK_EQUAL(51, model->nt()); - CHECK_EQUAL(0.0, model->getTimepoint(0)); - CHECK_EQUAL(100.0, model->getTimepoint(model->nt() - 2)); - CHECK_EQUAL(INFINITY, model->getTimepoint(model->nt() - 1)); + ASSERT_EQ(51, model->nt()); + ASSERT_EQ(0.0, model->getTimepoint(0)); + ASSERT_EQ(100.0, model->getTimepoint(model->nt() - 2)); + ASSERT_EQ(INFINITY, model->getTimepoint(model->nt() - 1)); for (int i = 0; i < model->np(); ++i) { - CHECK_EQUAL(pExp[i], model->getUnscaledParameters()[i]); - CHECK_EQUAL(log10(pExp[i]), model->getParameters()[i]); + ASSERT_EQ(pExp[i], model->getUnscaledParameters()[i]); + ASSERT_EQ(log10(pExp[i]), model->getParameters()[i]); } } -TEST(groupSteadystate, testInequality) +TEST(ExampleSteadystate, Inequality) { auto modelA = amici::generic_model::getModel(); - auto modelB = std::unique_ptr(new amici::Model_Test()); + auto modelB = std::make_unique(); - CHECK_FALSE(*modelA == *modelB); + ASSERT_FALSE(*modelA == *modelB); } -TEST(groupSteadystate, testCopyModel) +TEST(ExampleSteadystate, CopyModel) { auto modelA = amici::generic_model::getModel(); auto modelB = std::unique_ptr(modelA->clone()); - CHECK_TRUE(*modelA == *modelB); + ASSERT_EQ(*modelA, *modelB); } -TEST(groupSteadystate, testCloneModel) +TEST(ExampleSteadystate, CloneModel) { auto modelA = amici::generic_model::getModel(); - auto modelB = std::unique_ptr( - new amici::model_model_steadystate::Model_model_steadystate()); + auto modelB = std::make_unique< + amici::model_model_steadystate::Model_model_steadystate>(); - CHECK_TRUE(*modelA == *modelB); + ASSERT_EQ(*modelA, *modelB); } -TEST(groupSteadystate, testExpDataFromReturnData) +TEST(ExampleSteadystate, ExpDataFromReturnData) { auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); @@ -76,7 +73,7 @@ TEST(groupSteadystate, testExpDataFromReturnData) runAmiciSimulation(*solver, &edata, *model); } -TEST(groupSteadystate, testReuseSolver) +TEST(ExampleSteadystate, ReuseSolver) { auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); @@ -90,7 +87,7 @@ TEST(groupSteadystate, testReuseSolver) runAmiciSimulation(*solver, nullptr, *model); } -TEST(groupSteadystate, testRethrow) +TEST(ExampleSteadystate, Rethrow) { auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); @@ -109,12 +106,12 @@ TEST(groupSteadystate, testRethrow) runAmiciSimulation(*solver, nullptr, *model); // must throw - CHECK_THROWS(amici::IntegrationFailure, - runAmiciSimulation(*solver, nullptr, *model, true)); + ASSERT_THROW(runAmiciSimulation(*solver, nullptr, *model, true), + amici::IntegrationFailure); } -TEST(groupSteadystate, testMaxtime) +TEST(ExampleSteadystate, Maxtime) { auto model = amici::generic_model::getModel(); auto solver = model->getSolver(); @@ -125,100 +122,100 @@ TEST(groupSteadystate, testMaxtime) NEW_OPTION_FILE, *solver, "/model_steadystate/nosensi/options"); auto rdata = runAmiciSimulation(*solver, nullptr, *model); - CHECK_EQUAL(amici::AMICI_SUCCESS, rdata->status); + ASSERT_EQ(amici::AMICI_SUCCESS, rdata->status); solver->setMaxTime(0.000001); // must throw rdata = runAmiciSimulation(*solver, nullptr, *model); - CHECK_EQUAL(amici::AMICI_MAX_TIME_EXCEEDED, rdata->status); + ASSERT_EQ(amici::AMICI_MAX_TIME_EXCEEDED, rdata->status); } -TEST(groupSteadystate, testInitialStatesNonEmpty) +TEST(ExampleSteadystate, InitialStatesNonEmpty) { auto model = amici::generic_model::getModel(); - CHECK_FALSE(model->getInitialStates().empty()); + ASSERT_FALSE(model->getInitialStates().empty()); } -TEST(groupSteadystate, testInitialStateSensitivitiesNonEmpty) +TEST(ExampleSteadystate, InitialStateSensitivitiesNonEmpty) { auto model = amici::generic_model::getModel(); - CHECK_FALSE(model->getInitialStateSensitivities().empty()); + ASSERT_FALSE(model->getInitialStateSensitivities().empty()); } -TEST(groupSteadystate, testSimulation) +TEST(ExampleSteadystate, Simulation) { amici::simulateVerifyWrite( "/model_steadystate/nosensi/", 100 * TEST_ATOL, 100 * TEST_RTOL); } -TEST(groupSteadystate, testSensitivityForward) +TEST(ExampleSteadystate, SensitivityForward) { amici::simulateVerifyWrite("/model_steadystate/sensiforward/"); } -TEST(groupSteadystate, testSensitivityForwardPlist) +TEST(ExampleSteadystate, SensitivityForwardPlist) { amici::simulateVerifyWrite("/model_steadystate/sensiforwardplist/"); } -TEST(groupSteadystate, testSensitivityForwardErrorInt) +TEST(ExampleSteadystate, SensitivityForwardErrorInt) { amici::simulateVerifyWrite("/model_steadystate/sensiforwarderrorint/"); } -TEST(groupSteadystate, testSensitivityForwardErrorNewt) +TEST(ExampleSteadystate, SensitivityForwardErrorNewt) { amici::simulateVerifyWrite("/model_steadystate/sensiforwarderrornewt/"); } -TEST(groupSteadystate, testSensitivityForwardDense) +TEST(ExampleSteadystate, SensitivityForwardDense) { amici::simulateVerifyWrite("/model_steadystate/sensiforwarddense/"); } -TEST(groupSteadystate, testSensitivityForwardSPBCG) +TEST(ExampleSteadystate, SensitivityForwardSPBCG) { amici::simulateVerifyWrite( "/model_steadystate/nosensiSPBCG/", 10 * TEST_ATOL, 10 * TEST_RTOL); } -TEST(groupSteadystate, testSensiFwdNewtonPreeq) +TEST(ExampleSteadystate, SensiFwdNewtonPreeq) { amici::simulateVerifyWrite("/model_steadystate/sensifwdnewtonpreeq/"); } -TEST(groupSteadystate, testSensiAdjNewtonPreeq) +TEST(ExampleSteadystate, SensiAdjNewtonPreeq) { amici::simulateVerifyWrite("/model_steadystate/sensiadjnewtonpreeq/"); } -TEST(groupSteadystate, testSensiFwdSimPreeq) +TEST(ExampleSteadystate, SensiFwdSimPreeq) { amici::simulateVerifyWrite("/model_steadystate/sensifwdsimpreeq/"); } -TEST(groupSteadystate, testSensiFwdSimPreeqFSA) +TEST(ExampleSteadystate, SensiFwdSimPreeqFSA) { amici::simulateVerifyWrite("/model_steadystate/sensifwdsimpreeqFSA/"); } -TEST(groupSteadystate, testSensiAdjSimPreeq) +TEST(ExampleSteadystate, SensiAdjSimPreeq) { amici::simulateVerifyWrite("/model_steadystate/sensiadjsimpreeq/"); } -TEST(groupSteadystate, testSensiAdjSimPreeqFSA) +TEST(ExampleSteadystate, SensiAdjSimPreeqFSA) { amici::simulateVerifyWrite("/model_steadystate/sensiadjsimpreeqFSA/"); } -TEST(groupSteadystate, testSensiFwdByhandPreeq) +TEST(ExampleSteadystate, SensiFwdByhandPreeq) { amici::simulateVerifyWrite("/model_steadystate/sensifwdbyhandpreeq/"); } -TEST(groupSteadystate, testSensiAdjByhandPreeq) +TEST(ExampleSteadystate, SensiAdjByhandPreeq) { amici::simulateVerifyWrite("/model_steadystate/sensiadjbyhandpreeq/"); } diff --git a/tests/cpputest/testOptions.h5 b/tests/cpp/testOptions.h5 similarity index 100% rename from tests/cpputest/testOptions.h5 rename to tests/cpp/testOptions.h5 diff --git a/tests/cpputest/testfunctions.cpp b/tests/cpp/testfunctions.cpp similarity index 91% rename from tests/cpputest/testfunctions.cpp rename to tests/cpp/testfunctions.cpp index 382e7fa43d..3e03eedfc4 100644 --- a/tests/cpputest/testfunctions.cpp +++ b/tests/cpp/testfunctions.cpp @@ -9,8 +9,7 @@ #include #include -#include -#include +#include "gtest/gtest.h" namespace amici { @@ -120,12 +119,12 @@ bool withinTolerance(double expected, double actual, double atol, double rtol, i void checkEqualArray(std::vector const& expected, std::vector const& actual, double atol, double rtol, std::string const& name) { - CHECK_EQUAL(expected.size(), actual.size()); + ASSERT_EQ(expected.size(), actual.size()); for(int i = 0; (unsigned) i < expected.size(); ++i) { bool withinTol = withinTolerance(expected[i], actual[i], atol, rtol, i, name.c_str()); - CHECK_TRUE(withinTol); + ASSERT_TRUE(withinTol); } } @@ -135,12 +134,12 @@ void checkEqualArray(const double *expected, const double *actual, const int len if(!length) return; - CHECK_TRUE(expected && actual); + ASSERT_TRUE(expected && actual); for(int i = 0; i < length; ++i) { bool withinTol = withinTolerance(expected[i], actual[i], atol, rtol, i, name); - CHECK_TRUE(withinTol); + ASSERT_TRUE(withinTol); } } @@ -148,19 +147,19 @@ void checkEqualArrayStrided(const double *expected, const double *actual, int le if(!expected && !actual) return; - CHECK_TRUE(expected && actual); + ASSERT_TRUE(expected && actual); for(int i = 0; i < length; ++i) { bool withinTol = withinTolerance(expected[i * strideExpected], actual[i * strideActual], atol, rtol, i, name); - CHECK_TRUE(withinTol); + ASSERT_TRUE(withinTol); } } void verifyReturnData(std::string const& hdffile, std::string const& resultPath, const ReturnData *rdata, const Model *model, double atol, double rtol) { - CHECK_FALSE(rdata == nullptr); + ASSERT_FALSE(rdata == nullptr); if(!hdf5::locationExists(hdffile, resultPath)) { fprintf(stderr, "ERROR: No results available for %s!\n", @@ -176,19 +175,19 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, std::vector expected; auto statusExp = hdf5::getIntScalarAttribute(file, resultPath, "status"); - CHECK_EQUAL(statusExp, rdata->status); + ASSERT_EQ(statusExp, rdata->status); double llhExp = hdf5::getDoubleScalarAttribute(file, resultPath, "llh"); - CHECK_TRUE(withinTolerance(llhExp, rdata->llh, atol, rtol, 1, "llh")); + ASSERT_TRUE(withinTolerance(llhExp, rdata->llh, atol, rtol, 1, "llh")); double chi2Exp = hdf5::getDoubleScalarAttribute(file, resultPath, "chi2"); - CHECK_TRUE(withinTolerance(chi2Exp, rdata->chi2, atol, rtol, 1, "chi2")); + ASSERT_TRUE(withinTolerance(chi2Exp, rdata->chi2, atol, rtol, 1, "chi2")); if(hdf5::locationExists(file, resultPath + "/x")) { expected = hdf5::getDoubleDataset2D(file, resultPath + "/x", m, n); checkEqualArray(expected, rdata->x, atol, rtol, "x"); } else { - CHECK_TRUE(rdata->x.empty()); + ASSERT_TRUE(rdata->x.empty()); } // CHECK_EQUAL(AMICI_O2MODE_FULL, udata->o2mode); @@ -197,42 +196,42 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, expected = hdf5::getDoubleDataset2D(file, resultPath + "/diagnosis/J", m, n); checkEqualArray(expected, rdata->J, atol, rtol, "J"); } else { - CHECK_TRUE(rdata->J.empty()); + 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"); } else { - CHECK_TRUE(rdata->y.empty()); + ASSERT_TRUE(rdata->y.empty()); } if(hdf5::locationExists(file, resultPath + "/res")) { expected = hdf5::getDoubleDataset1D(file, resultPath + "/res"); checkEqualArray(expected, rdata->res, atol, rtol, "res"); } else { - CHECK_TRUE(rdata->res.empty()); + ASSERT_TRUE(rdata->res.empty()); } if(hdf5::locationExists(file, resultPath + "/z")) { expected = hdf5::getDoubleDataset2D(file, resultPath + "/z", m, n); checkEqualArray(expected, rdata->z, atol, rtol, "z"); } else { - CHECK_TRUE(rdata->z.empty()); + ASSERT_TRUE(rdata->z.empty()); } if(hdf5::locationExists(file, resultPath + "/rz")) { expected = hdf5::getDoubleDataset2D(file, resultPath + "/rz", m, n); checkEqualArray(expected, rdata->rz, atol, rtol, "rz"); } else { - CHECK_TRUE(rdata->rz.empty()); + ASSERT_TRUE(rdata->rz.empty()); } if(hdf5::locationExists(file, resultPath + "/sigmaz")) { expected = hdf5::getDoubleDataset2D(file, resultPath + "/sigmaz", m, n); checkEqualArray(expected, rdata->sigmaz, atol, rtol, "sigmaz"); } else { - CHECK_TRUE(rdata->sigmaz.empty()); + ASSERT_TRUE(rdata->sigmaz.empty()); } expected = hdf5::getDoubleDataset1D(file, resultPath + "/diagnosis/xdot"); @@ -244,8 +243,8 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, if(rdata->sensi >= SensitivityOrder::first) { verifyReturnDataSensitivities(file, resultPath, rdata, model, atol, rtol); } else { - CHECK_EQUAL(0, rdata->sllh.size()); - CHECK_EQUAL(0, rdata->s2llh.size()); + ASSERT_EQ(0, rdata->sllh.size()); + ASSERT_EQ(0, rdata->s2llh.size()); } } @@ -257,7 +256,7 @@ void verifyReturnDataSensitivities(H5::H5File const& file, std::string const& re expected = hdf5::getDoubleDataset1D(file, resultPath + "/sllh"); checkEqualArray(expected, rdata->sllh, atol, rtol, "sllh"); } else { - CHECK_TRUE(rdata->sllh.empty()); + ASSERT_TRUE(rdata->sllh.empty()); } if(rdata->sensi_meth == SensitivityMethod::forward) { @@ -266,21 +265,21 @@ void verifyReturnDataSensitivities(H5::H5File const& file, std::string const& re expected = hdf5::getDoubleDataset2D(file, resultPath + "/sx0", m, n); checkEqualArray(expected, rdata->sx0, atol, rtol, "sx0"); } else { - CHECK_TRUE(rdata->sx0.empty()); + ASSERT_TRUE(rdata->sx0.empty()); } if(hdf5::locationExists(file, resultPath + "/sres")) { expected = hdf5::getDoubleDataset2D(file, resultPath + "/sres", m, n); checkEqualArray(expected, rdata->sres, atol, rtol, "sres"); } else { - CHECK_TRUE(rdata->sres.empty()); + ASSERT_TRUE(rdata->sres.empty()); } if(hdf5::locationExists(file, resultPath + "/FIM")) { expected = hdf5::getDoubleDataset2D(file, resultPath + "/FIM", m, n); checkEqualArray(expected, rdata->FIM, atol, rtol, "FIM"); } else { - CHECK_TRUE(rdata->FIM.empty()); + ASSERT_TRUE(rdata->FIM.empty()); } @@ -295,7 +294,7 @@ void verifyReturnDataSensitivities(H5::H5File const& file, std::string const& re &rdata->sx[ip * model->nt() * rdata->nx], model->nt() * model->nxtrue_rdata, atol, rtol, "sx"); } else { - CHECK_TRUE(rdata->sx.empty()); + ASSERT_TRUE(rdata->sx.empty()); } if(hdf5::locationExists(file, resultPath + "/sy")) { @@ -305,7 +304,7 @@ void verifyReturnDataSensitivities(H5::H5File const& file, std::string const& re &rdata->sy[ip * model->nt() * model->ny], model->nt() * model->nytrue, atol, rtol, "sy"); } else { - CHECK_TRUE(rdata->sy.empty()); + ASSERT_TRUE(rdata->sy.empty()); } @@ -349,8 +348,8 @@ void verifyReturnDataSensitivities(H5::H5File const& file, std::string const& re expected = hdf5::getDoubleDataset2D(file, resultPath + "/s2llh", m, n); checkEqualArray(expected, rdata->s2llh, atol, rtol, "s2llh"); } else { - CHECK_EQUAL(0, rdata->s2llh.size()); - CHECK_EQUAL(0, rdata->s2rz.size()); + ASSERT_EQ(0, rdata->s2llh.size()); + ASSERT_EQ(0, rdata->s2rz.size()); } } diff --git a/tests/cpputest/testfunctions.h b/tests/cpp/testfunctions.h similarity index 98% rename from tests/cpputest/testfunctions.h rename to tests/cpp/testfunctions.h index 2cb4658220..2d1d0f7325 100644 --- a/tests/cpputest/testfunctions.h +++ b/tests/cpp/testfunctions.h @@ -10,12 +10,9 @@ #include #endif -#include // make std::ostringstream available (needs to come before TestHarness.h) +#include #include -#include -#include - namespace amici { class ReturnData; diff --git a/tests/cpp/unittests/CMakeLists.txt b/tests/cpp/unittests/CMakeLists.txt new file mode 100644 index 0000000000..5e1f7e68ac --- /dev/null +++ b/tests/cpp/unittests/CMakeLists.txt @@ -0,0 +1,27 @@ +project(unittests) + +find_package(Boost COMPONENTS serialization) + +set(SRC_LIST + testMisc.cpp + testExpData.cpp +) + +add_executable(${PROJECT_NAME} ${SRC_LIST}) + +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +if(Boost_FOUND) + target_sources(${PROJECT_NAME} PRIVATE testSerialization.cpp) + target_include_directories(${PROJECT_NAME} PRIVATE "${Boost_INCLUDE_DIR}") +endif() +target_link_libraries(${PROJECT_NAME} + amici-testing + Upstream::amici + ${Boost_LIBRARIES} + gtest_main + ) + +include(GoogleTest) + +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/cpp/unittests/testExpData.cpp b/tests/cpp/unittests/testExpData.cpp new file mode 100644 index 0000000000..4cf947341c --- /dev/null +++ b/tests/cpp/unittests/testExpData.cpp @@ -0,0 +1,328 @@ +#include "testfunctions.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace amici { +namespace generic_model { +std::unique_ptr getModel(); +} // namespace generic_model +} // namespace amici + +using namespace amici; + +namespace { + +class ExpDataTest : public ::testing::Test { + protected: + void SetUp() override { + model->setTimepoints(timepoints); + model->setNMaxEvent(nmaxevent); + testModel.setTimepoints(timepoints); + testModel.setNMaxEvent(nmaxevent); + } + + int nx = 1, ny = 2, nz = 3, nmaxevent = 4; + std::vector timepoints = { 1, 2, 3, 4 }; + + std::unique_ptr model = generic_model::getModel(); + + Model_Test testModel = Model_Test( + ModelDimensions( + nx, // nx_rdata + nx, // nxtrue_rdata + nx, // nx_solver + nx, // nxtrue_solver + 0, // nx_solver_reinit + 1, // np + 3, // nk + ny, // ny + ny, // nytrue + nz, // nz + nz, // nztrue + nmaxevent, // ne + 0, // nJ + 0, // nw + 0, // ndwdx + 0, // ndwdp + 0, // dwdw + 0, // ndxdotdw + {}, // ndJydy + 0, // nnz + 0, // ubw + 0 // lbw + ), + SimulationParameters( + std::vector(3, 0.0), + std::vector(1, 0.0), + std::vector(2, 1) + ), + SecondOrderMode::none, + std::vector(), + std::vector()); +}; + +TEST_F(ExpDataTest, DefaultConstructable) +{ + ExpData edata{}; + ASSERT_EQ(edata.nytrue(), 0); + ASSERT_EQ(edata.nztrue(), 0); + ASSERT_EQ(edata.nmaxevent(), 0); +} +TEST_F(ExpDataTest, ModelCtor) +{ + ExpData edata(model->nytrue, model->nztrue, model->nMaxEvent()); + ASSERT_EQ(edata.nytrue(), model->nytrue); + ASSERT_EQ(edata.nztrue(), model->nztrue); + ASSERT_EQ(edata.nmaxevent(), model->nMaxEvent()); +} + +TEST_F(ExpDataTest, DimensionCtor) +{ + ExpData edata(model->nytrue, model->nztrue, model->nMaxEvent(), timepoints); + ASSERT_EQ(edata.nytrue(), model->nytrue); + ASSERT_EQ(edata.nztrue(), model->nztrue); + ASSERT_EQ(edata.nmaxevent(), model->nMaxEvent()); + ASSERT_EQ(edata.nt(), model->nt()); + checkEqualArray( + timepoints, edata.getTimepoints(), TEST_ATOL, TEST_RTOL, "ts"); +} + +TEST_F(ExpDataTest, MeasurementCtor) +{ + std::vector y(ny * timepoints.size(), 0.0); + std::vector y_std(ny * timepoints.size(), 0.1); + std::vector z(nz * nmaxevent, 0.0); + std::vector z_std(nz * nmaxevent, 0.1); + + ExpData edata(testModel.nytrue, + testModel.nztrue, + testModel.nMaxEvent(), + timepoints, + y, + y_std, + z, + z_std); + ASSERT_EQ(edata.nytrue(), testModel.nytrue); + ASSERT_EQ(edata.nztrue(), testModel.nztrue); + ASSERT_EQ(edata.nmaxevent(), testModel.nMaxEvent()); + ASSERT_EQ(edata.nt(), testModel.nt()); + checkEqualArray( + timepoints, edata.getTimepoints(), TEST_ATOL, TEST_RTOL, "ts"); + checkEqualArray( + y, edata.getObservedData(), TEST_ATOL, TEST_RTOL, "observedData"); + checkEqualArray(y_std, + edata.getObservedDataStdDev(), + TEST_ATOL, + TEST_RTOL, + "observedDataStdDev"); + checkEqualArray( + z, edata.getObservedEvents(), TEST_ATOL, TEST_RTOL, "observedEvents"); + checkEqualArray(z_std, + edata.getObservedEventsStdDev(), + TEST_ATOL, + TEST_RTOL, + "observedEventsStdDev"); + + ExpData edata_copy(edata); + ASSERT_EQ(edata.nytrue(), edata_copy.nytrue()); + ASSERT_EQ(edata.nztrue(), edata_copy.nztrue()); + ASSERT_EQ(edata.nmaxevent(), edata_copy.nmaxevent()); + ASSERT_EQ(edata.nt(), edata_copy.nt()); + checkEqualArray(edata_copy.getTimepoints(), + edata.getTimepoints(), + TEST_ATOL, + TEST_RTOL, + "ts"); + checkEqualArray(edata_copy.getObservedData(), + edata.getObservedData(), + TEST_ATOL, + TEST_RTOL, + "observedData"); + checkEqualArray(edata_copy.getObservedDataStdDev(), + edata.getObservedDataStdDev(), + TEST_ATOL, + TEST_RTOL, + "observedDataStdDev"); + checkEqualArray(edata_copy.getObservedEvents(), + edata.getObservedEvents(), + TEST_ATOL, + TEST_RTOL, + "observedEvents"); + checkEqualArray(edata_copy.getObservedEventsStdDev(), + edata.getObservedEventsStdDev(), + TEST_ATOL, + TEST_RTOL, + "observedEventsStdDev"); +} + +TEST_F(ExpDataTest, CopyConstructable) +{ + testModel.setTimepoints(timepoints); + auto edata = ExpData(testModel); + ASSERT_EQ(edata.nytrue(), testModel.nytrue); + ASSERT_EQ(edata.nztrue(), testModel.nztrue); + ASSERT_EQ(edata.nmaxevent(), testModel.nMaxEvent()); + ASSERT_EQ(edata.nt(), testModel.nt()); + checkEqualArray(testModel.getTimepoints(), + edata.getTimepoints(), + TEST_ATOL, + TEST_RTOL, + "ts"); +} + +TEST_F(ExpDataTest, DimensionChecks) +{ + std::vector bad_std(ny, -0.1); + std::vector y(ny * timepoints.size(), 0.0); + std::vector y_std(ny * timepoints.size(), 0.1); + std::vector z(nz * nmaxevent, 0.0); + std::vector z_std(nz * nmaxevent, 0.1); + + ASSERT_THROW(ExpData(testModel.nytrue, + testModel.nztrue, + testModel.nMaxEvent(), + timepoints, + z, + z_std, + z, + z_std), + AmiException); + + ASSERT_THROW(ExpData(testModel.nytrue, + testModel.nztrue, + testModel.nMaxEvent(), + timepoints, + z, + bad_std, + z, + z_std), + AmiException); + + ExpData edata(testModel); + + std::vector bad_y(ny * timepoints.size() + 1, 0.0); + std::vector bad_y_std(ny * timepoints.size() + 1, 0.1); + std::vector bad_z(nz * nmaxevent + 1, 0.0); + std::vector bad_z_std(nz * nmaxevent + 1, 0.1); + + ASSERT_THROW(edata.setObservedData(bad_y), AmiException); + ASSERT_THROW(edata.setObservedDataStdDev(bad_y_std), AmiException); + ASSERT_THROW(edata.setObservedEvents(bad_z), AmiException); + ASSERT_THROW(edata.setObservedEventsStdDev(bad_y_std), AmiException); + + std::vector bad_single_y(edata.nt() + 1, 0.0); + std::vector bad_single_y_std(edata.nt() + 1, 0.1); + std::vector bad_single_z(edata.nmaxevent() + 1, 0.0); + std::vector bad_single_z_std(edata.nmaxevent() + 1, 0.1); + + ASSERT_THROW(edata.setObservedData(bad_single_y, 0), + AmiException); + ASSERT_THROW(edata.setObservedDataStdDev(bad_single_y_std, 0), + AmiException); + ASSERT_THROW(edata.setObservedEvents(bad_single_z, 0), + AmiException); + ASSERT_THROW(edata.setObservedEventsStdDev(bad_single_y_std, 0), + AmiException); + + ASSERT_THROW(edata.setTimepoints(std::vector{ 0.0, 1.0, 0.5 }), + AmiException); +} + +TEST_F(ExpDataTest, SettersGetters) +{ + ExpData edata(testModel); + + std::vector y(ny * timepoints.size(), 0.0); + std::vector y_std(ny * timepoints.size(), 0.1); + std::vector z(nz * nmaxevent, 0.0); + std::vector z_std(nz * nmaxevent, 0.1); + + edata.setObservedData(y); + checkEqualArray( + edata.getObservedData(), y, TEST_ATOL, TEST_RTOL, "ObservedData"); + edata.setObservedDataStdDev(y_std); + checkEqualArray(edata.getObservedDataStdDev(), + y_std, + TEST_ATOL, + TEST_RTOL, + "ObservedDataStdDev"); + edata.setObservedEvents(z); + checkEqualArray( + edata.getObservedEvents(), z, TEST_ATOL, TEST_RTOL, "ObservedEvents"); + edata.setObservedEventsStdDev(z_std); + checkEqualArray(edata.getObservedEventsStdDev(), + z_std, + TEST_ATOL, + TEST_RTOL, + "ObservedEventsStdDev"); + + std::vector single_y(edata.nt(), 0.0); + std::vector single_y_std(edata.nt(), 0.1); + + for (int iy = 0; iy < ny; ++iy) { + edata.setObservedData(single_y, iy); + edata.setObservedDataStdDev(single_y_std, iy); + } + ASSERT_THROW(edata.setObservedData(single_y, ny), std::exception); + ASSERT_THROW(edata.setObservedData(single_y, -1), std::exception); + ASSERT_THROW(edata.setObservedDataStdDev(single_y_std, ny), std::exception); + ASSERT_THROW(edata.setObservedDataStdDev(single_y_std, -1), std::exception); + + std::vector single_z(edata.nmaxevent(), 0.0); + std::vector single_z_std(edata.nmaxevent(), 0.1); + + for (int iz = 0; iz < nz; ++iz) { + edata.setObservedEvents(single_z, iz); + edata.setObservedEventsStdDev(single_z_std, iz); + } + + ASSERT_THROW(edata.setObservedEvents(single_z, nz), std::exception); + ASSERT_THROW(edata.setObservedEvents(single_z, -1), std::exception); + ASSERT_THROW(edata.setObservedEventsStdDev(single_z_std, nz), + std::exception); + ASSERT_THROW(edata.setObservedEventsStdDev(single_z_std, -1), + std::exception); + + ASSERT_TRUE(edata.getObservedDataPtr(0)); + ASSERT_TRUE(edata.getObservedDataStdDevPtr(0)); + ASSERT_TRUE(edata.getObservedEventsPtr(0)); + ASSERT_TRUE(edata.getObservedEventsStdDevPtr(0)); + + std::vector empty(0, 0.0); + + edata.setObservedData(empty); + edata.setObservedDataStdDev(empty); + edata.setObservedEvents(empty); + edata.setObservedEventsStdDev(empty); + + ASSERT_TRUE(!edata.getObservedDataPtr(0)); + ASSERT_TRUE(!edata.getObservedDataStdDevPtr(0)); + ASSERT_TRUE(!edata.getObservedEventsPtr(0)); + ASSERT_TRUE(!edata.getObservedEventsStdDevPtr(0)); + + checkEqualArray( + edata.getObservedData(), empty, TEST_ATOL, TEST_RTOL, "ObservedData"); + checkEqualArray(edata.getObservedDataStdDev(), + empty, + TEST_ATOL, + TEST_RTOL, + "ObservedDataStdDev"); + checkEqualArray( + edata.getObservedEvents(), empty, TEST_ATOL, TEST_RTOL, "ObservedEvents"); + checkEqualArray(edata.getObservedEventsStdDev(), + empty, + TEST_ATOL, + TEST_RTOL, + "ObservedEventsStdDev"); +} + +} // namespace diff --git a/tests/cpp/unittests/testMisc.cpp b/tests/cpp/unittests/testMisc.cpp new file mode 100644 index 0000000000..4106742dbd --- /dev/null +++ b/tests/cpp/unittests/testMisc.cpp @@ -0,0 +1,597 @@ +#include "testfunctions.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace amici { +namespace generic_model { + +std::unique_ptr getModel() +{ + return std::make_unique(); +} + +} // namespace generic_model +} // namespace amici + +using namespace amici; + +namespace { + +void +testSolverGetterSetters(CVodeSolver solver, + SensitivityMethod sensi_meth, + SensitivityOrder sensi, + InternalSensitivityMethod ism, + InterpolationType interp, + NonlinearSolverIteration iter, + LinearMultistepMethod lmm, + int steps, + int badsteps, + double tol, + double badtol); + +class ModelTest : public ::testing::Test { + protected: + int nx = 1, ny = 2, nz = 3, nmaxevent = 4; + std::vector p{ 1.0 }; + std::vector k{ 0.5, 0.4, 0.7 }; + std::vector plist{ 1 }; + std::vector idlist{ 0 }; + std::vector z2event{ 0, 0, 0 }; + Model_Test model = Model_Test( + ModelDimensions( + nx, // nx_rdata + nx, // nxtrue_rdata + nx, // nx_solver + nx, // nxtrue_solver + 0, // nx_solver_reinit + static_cast(p.size()), // np + static_cast(k.size()), // nk + ny, // ny + ny, // nytrue + nz, // nz + nz, // nztrue + nmaxevent, // ne + 0, // nJ + 0, // nw + 0, // ndwdx + 0, // ndwdp + 0, // dwdw + 0, // ndxdotdw + {}, // ndJydy + 0, // nnz + 0, // ubw + 0 // lbw + ), + SimulationParameters(k, p, plist), + SecondOrderMode::none, + idlist, + z2event); + std::vector unscaled{ NAN }; +}; + + +TEST_F(ModelTest, LinScaledParameterIsNotTransformed) +{ + model.setParameterScale(ParameterScaling::none); + + ASSERT_EQ(p[0], model.getParameters()[0]); +} + +TEST_F(ModelTest, LogScaledParameterIsTransformed) +{ + model.setParameterScale(ParameterScaling::ln); + + ASSERT_NEAR(std::log(p[0]), model.getParameters()[0], 1e-16); +} + +TEST_F(ModelTest, Log10ScaledParameterIsTransformed) +{ + model.setParameterScale(ParameterScaling::log10); + + ASSERT_NEAR(std::log10(p[0]), model.getParameters()[0], 1e-16); +} + +TEST_F(ModelTest, ParameterScaleTooShort) +{ + std::vector pscale(p.size() - 1, + ParameterScaling::log10); + ASSERT_THROW(model.setParameterScale(pscale), AmiException); + +} + +TEST_F(ModelTest, ParameterScaleTooLong) +{ + std::vector pscale (p.size() + 1, + ParameterScaling::log10); + ASSERT_THROW(model.setParameterScale(pscale), AmiException); +} + +TEST_F(ModelTest, UnsortedTimepointsThrow){ + ASSERT_THROW(model.setTimepoints(std::vector{ 0.0, 1.0, 0.5 }), + AmiException); +} + +TEST_F(ModelTest, ParameterNameIdGetterSetter) +{ + model.setParameterById("p0", 3.0); + ASSERT_NEAR(model.getParameterById("p0"), 3.0, 1e-16); + ASSERT_THROW(model.getParameterById("p1"), AmiException); + ASSERT_NEAR( + model.setParametersByIdRegex("p[\\d]+", 5.0), p.size(), 1e-16); + for (const auto& ip : model.getParameters()) + ASSERT_NEAR(ip, 5.0, 1e-16); + ASSERT_THROW(model.setParametersByIdRegex("k[\\d]+", 5.0), AmiException); + + model.setParameterByName("p0", 3.0); + ASSERT_NEAR(model.getParameterByName("p0"), 3.0, 1e-16); + ASSERT_THROW(model.getParameterByName("p1"), AmiException); + ASSERT_NEAR( + model.setParametersByNameRegex("p[\\d]+", 5.0), p.size(), 1e-16); + for (const auto& ip : model.getParameters()) + ASSERT_NEAR(ip, 5.0, 1e-16); + ASSERT_THROW(model.setParametersByNameRegex("k[\\d]+", 5.0), AmiException); + + model.setFixedParameterById("k0", 3.0); + ASSERT_NEAR(model.getFixedParameterById("k0"), 3.0, 1e-16); + ASSERT_THROW(model.getFixedParameterById("k4"), AmiException); + ASSERT_NEAR( + model.setFixedParametersByIdRegex("k[\\d]+", 5.0), k.size(), 1e-16); + for (const auto& ik : model.getFixedParameters()) + ASSERT_NEAR(ik, 5.0, 1e-16); + ASSERT_THROW(model.setFixedParametersByIdRegex("p[\\d]+", 5.0), AmiException); + + model.setFixedParameterByName("k0", 3.0); + ASSERT_NEAR(model.getFixedParameterByName("k0"), 3.0, 1e-16); + ASSERT_THROW(model.getFixedParameterByName("k4"), AmiException); + ASSERT_NEAR( + model.setFixedParametersByNameRegex("k[\\d]+", 5.0), k.size(), 1e-16); + for (const auto& ik : model.getFixedParameters()) + ASSERT_NEAR(ik, 5.0, 1e-16); + ASSERT_THROW(model.setFixedParametersByNameRegex("p[\\d]+", 5.0), + AmiException); +} + +TEST_F(ModelTest, ReinitializeFixedParameterInitialStates) +{ + ASSERT_THROW(model.setReinitializeFixedParameterInitialStates(true), + AmiException); + model.setReinitializeFixedParameterInitialStates(false); + ASSERT_TRUE(!model.getReinitializeFixedParameterInitialStates()); + AmiVector x(nx); + AmiVectorArray sx(model.np(), nx); +} + +TEST(SymbolicFunctionsTest, Sign) +{ + ASSERT_EQ(-1, sign(-2)); + ASSERT_EQ(0, sign(0)); + ASSERT_EQ(1, sign(2)); +} + +TEST(SymbolicFunctionsTest, Heaviside) +{ + ASSERT_EQ(0, heaviside(-1)); + ASSERT_EQ(1, heaviside(0)); + ASSERT_EQ(1, heaviside(1)); +} + +TEST(SymbolicFunctionsTest, Min) +{ + ASSERT_EQ(-1, min(-1, 2, 0)); + ASSERT_EQ(-2, min(1, -2, 0)); + ASSERT_TRUE(isNaN(min(getNaN(), getNaN(), 0))); + ASSERT_EQ(-1, min(-1, getNaN(), 0)); + ASSERT_EQ(-1, min(getNaN(), -1, 0)); +} + +TEST(SymbolicFunctionsTest, Max) +{ + ASSERT_EQ(2, max(-1, 2, 0)); + ASSERT_EQ(1, max(1, -2, 0)); + ASSERT_TRUE(isNaN(max(getNaN(), getNaN(), 0))); + ASSERT_EQ(-1, max(-1, getNaN(), 0)); + ASSERT_EQ(-1, max(getNaN(), -1, 0)); +} + +TEST(SymbolicFunctionsTest, DMin) +{ + ASSERT_EQ(0, Dmin(1, -1, -2, 0)); + ASSERT_EQ(1, Dmin(1, -1, 2, 0)); + ASSERT_EQ(1, Dmin(2, -1, -2, 0)); + ASSERT_EQ(0, Dmin(2, -1, 2, 0)); +} + +TEST(SymbolicFunctionsTest, DMax) +{ + ASSERT_EQ(1, Dmax(1, -1, -2, 0)); + ASSERT_EQ(0, Dmax(1, -1, 2, 0)); + ASSERT_EQ(0, Dmax(2, -1, -2, 0)); + ASSERT_EQ(1, Dmax(2, -1, 2, 0)); +} + +TEST(SymbolicFunctionsTest, pos_pow) +{ + ASSERT_EQ(0, pos_pow(-0.1, 3)); + ASSERT_EQ(pow(0.1, 3), pos_pow(0.1, 3)); +} + +TEST(SolverTestBasic, Equality) +{ + IDASolver i1, i2; + CVodeSolver c1, c2; + + ASSERT_EQ(i1, i2); + ASSERT_EQ(c1, c2); + ASSERT_FALSE(i1 == c1); +} + +TEST(SolverTestBasic, Clone) +{ + IDASolver i1; + std::unique_ptr i2(i1.clone()); + ASSERT_EQ(i1, *i2); + + CVodeSolver c1; + std::unique_ptr c2(c1.clone()); + ASSERT_TRUE(c1 == *c2); + ASSERT_FALSE(*i2 == *c2); +} + +TEST(SolverIdasTest, DefaultConstructableAndNotLeaky) +{ + IDASolver solver; +} + + +class SolverTest : public ::testing::Test { + protected: + void SetUp() override { + tol = 0.01; + badtol = -0.01; + sensi_meth = SensitivityMethod::adjoint; + sensi = SensitivityOrder::first; + steps = 1000; + badsteps = -1; + lmm = LinearMultistepMethod::adams; + iter = NonlinearSolverIteration::fixedpoint; + ism = InternalSensitivityMethod::staggered1; + interp = InterpolationType::polynomial; + } + + int nx = 1, ny = 2, nz = 3, ne = 0; + double tol, badtol; + std::vector timepoints = { 1, 2, 3, 4 }; + + std::unique_ptr model = generic_model::getModel(); + SensitivityMethod sensi_meth; + SensitivityOrder sensi; + int steps, badsteps; + LinearMultistepMethod lmm; + NonlinearSolverIteration iter; + InternalSensitivityMethod ism; + InterpolationType interp; + + Model_Test testModel = Model_Test( + ModelDimensions( + nx, // nx_rdata + nx, // nxtrue_rdata + nx, // nx_solver + nx, // nxtrue_solver + 0, // nx_solver_reinit + 1, // np + 3, // nk + ny, // ny + ny, // nytrue + nz, // nz + nz, // nztrue + ne, // ne + 0, // nJ + 0, // nw + 0, // ndwdx + 0, // ndwdp + 0, // dwdw + 0, // ndxdotdw + {}, // ndJydy + 1, // nnz + 0, // ubw + 0 // lbw + ), + SimulationParameters( + std::vector(3, 0.0), + std::vector(1, 0.0), + std::vector(2, 1) + ), + SecondOrderMode::none, + std::vector(0, 0.0), + std::vector()); + + CVodeSolver solver = CVodeSolver(); +}; + +TEST_F(SolverTest, SettersGettersNoSetup) +{ + testSolverGetterSetters(solver, + sensi_meth, + sensi, + ism, + interp, + iter, + lmm, + steps, + badsteps, + tol, + badtol); +} + +TEST_F(SolverTest, SettersGettersWithSetup) +{ + + solver.setSensitivityMethod(sensi_meth); + ASSERT_EQ(static_cast(solver.getSensitivityMethod()), + static_cast(sensi_meth)); + + auto rdata = std::make_unique(solver, testModel); + AmiVector x(nx), dx(nx); + AmiVectorArray sx(nx, 1), sdx(nx, 1); + + testModel.setInitialStates(std::vector{ 0 }); + + solver.setup(0, &testModel, x, dx, sx, sdx); + + testSolverGetterSetters(solver, + sensi_meth, + sensi, + ism, + interp, + iter, + lmm, + steps, + badsteps, + tol, + badtol); +} + +void +testSolverGetterSetters(CVodeSolver solver, + SensitivityMethod sensi_meth, + SensitivityOrder sensi, + InternalSensitivityMethod ism, + InterpolationType interp, + NonlinearSolverIteration iter, + LinearMultistepMethod lmm, + int steps, + int badsteps, + double tol, + double badtol) +{ + + solver.setSensitivityMethod(sensi_meth); + ASSERT_EQ(static_cast(solver.getSensitivityMethod()), + static_cast(sensi_meth)); + + solver.setSensitivityOrder(sensi); + ASSERT_EQ(static_cast(solver.getSensitivityOrder()), + static_cast(sensi)); + + solver.setInternalSensitivityMethod(ism); + ASSERT_EQ(static_cast(solver.getInternalSensitivityMethod()), + static_cast(ism)); + + solver.setInterpolationType(interp); + ASSERT_EQ(static_cast(solver.getInterpolationType()), + static_cast(interp)); + + solver.setNonlinearSolverIteration(iter); + ASSERT_EQ(static_cast(solver.getNonlinearSolverIteration()), + static_cast(iter)); + + solver.setLinearMultistepMethod(lmm); + ASSERT_EQ(static_cast(solver.getLinearMultistepMethod()), + static_cast(lmm)); + + solver.setPreequilibration(true); + ASSERT_EQ(solver.getPreequilibration(), true); + + solver.setStabilityLimitFlag(true); + ASSERT_EQ(solver.getStabilityLimitFlag(), true); + + ASSERT_THROW(solver.setNewtonMaxSteps(badsteps), AmiException); + solver.setNewtonMaxSteps(steps); + ASSERT_EQ(solver.getNewtonMaxSteps(), steps); + + ASSERT_THROW(solver.setNewtonMaxLinearSteps(badsteps), AmiException); + solver.setNewtonMaxLinearSteps(steps); + ASSERT_EQ(solver.getNewtonMaxLinearSteps(), steps); + + ASSERT_THROW(solver.setMaxSteps(badsteps), AmiException); + solver.setMaxSteps(steps); + ASSERT_EQ(solver.getMaxSteps(), steps); + + ASSERT_THROW(solver.setMaxStepsBackwardProblem(badsteps), AmiException); + solver.setMaxStepsBackwardProblem(steps); + ASSERT_EQ(solver.getMaxStepsBackwardProblem(), steps); + + ASSERT_THROW(solver.setRelativeTolerance(badtol), AmiException); + solver.setRelativeTolerance(tol); + ASSERT_EQ(solver.getRelativeTolerance(), tol); + + ASSERT_THROW(solver.setAbsoluteTolerance(badtol), AmiException); + solver.setAbsoluteTolerance(tol); + ASSERT_EQ(solver.getAbsoluteTolerance(), tol); + + ASSERT_THROW(solver.setRelativeToleranceQuadratures(badtol), AmiException); + solver.setRelativeToleranceQuadratures(tol); + ASSERT_EQ(solver.getRelativeToleranceQuadratures(), tol); + + ASSERT_THROW(solver.setAbsoluteToleranceQuadratures(badtol), AmiException); + solver.setAbsoluteToleranceQuadratures(tol); + ASSERT_EQ(solver.getAbsoluteToleranceQuadratures(), tol); + + ASSERT_THROW(solver.setRelativeToleranceSteadyState(badtol), AmiException); + solver.setRelativeToleranceSteadyState(tol); + ASSERT_EQ(solver.getRelativeToleranceSteadyState(), tol); + + ASSERT_THROW(solver.setAbsoluteToleranceSteadyState(badtol), AmiException); + solver.setAbsoluteToleranceSteadyState(tol); + ASSERT_EQ(solver.getAbsoluteToleranceSteadyState(), tol); +} + +class AmiVectorTest : public ::testing::Test { + protected: + std::vector vec1{ 1, 2, 4, 3 }; + std::vector vec2{ 4, 1, 2, 3 }; + std::vector vec3{ 4, 4, 2, 1 }; +}; + +TEST_F(AmiVectorTest, Vector) +{ + AmiVector av(vec1); + N_Vector nvec = av.getNVector(); + for (int i = 0; i < av.getLength(); ++i) + ASSERT_EQ(av.at(i), NV_Ith_S(nvec, i)); +} + +TEST_F(AmiVectorTest, VectorArray) +{ + AmiVectorArray ava(4, 3); + AmiVector av1(vec1), av2(vec2), av3(vec3); + std::vector avs{ av1, av2, av3 }; + for (int i = 0; i < ava.getLength(); ++i) + ava[i] = avs.at(i); + + std::vector badLengthVector(13, 0.0); + std::vector flattened(12, 0.0); + + ASSERT_THROW(ava.flatten_to_vector(badLengthVector), AmiException); + ava.flatten_to_vector(flattened); + for (int i = 0; i < ava.getLength(); ++i) { + const AmiVector av = ava[i]; + for (int j = 0; j < av.getLength(); ++j) + ASSERT_EQ(flattened.at(i * av.getLength() + j), av.at(j)); + } +} + +class SunMatrixWrapperTest : public ::testing::Test { + protected: + void SetUp() override { + A.set_data(0, 0, 0.69); + A.set_data(1, 0, 0.32); + A.set_data(2, 0, 0.95); + A.set_data(0, 1, 0.03); + A.set_data(1, 1, 0.44); + A.set_data(2, 1, 0.38); + + B.set_indexptr(0, 0); + B.set_indexptr(1, 2); + B.set_indexptr(2, 4); + B.set_indexptr(3, 5); + B.set_indexptr(4, 7); + B.set_data(0, 3); + B.set_data(1, 1); + B.set_data(2, 3); + B.set_data(3, 7); + B.set_data(4, 1); + B.set_data(5, 2); + B.set_data(6, 9); + B.set_indexval(0, 1); + B.set_indexval(1, 3); + B.set_indexval(2, 0); + B.set_indexval(3, 2); + B.set_indexval(4, 0); + B.set_indexval(5, 1); + B.set_indexval(6, 3); + } + + //inputs + std::vector a{0.82, 0.91, 0.13}; + std::vector b{0.77, 0.80}; + SUNMatrixWrapper A = SUNMatrixWrapper(3, 2); + SUNMatrixWrapper B = SUNMatrixWrapper(4, 4, 7, CSC_MAT); + // result + std::vector d{1.3753, 1.5084, 1.1655}; +}; + +TEST_F(SunMatrixWrapperTest, SparseMultiply) +{ + + auto A_sparse = SUNMatrixWrapper(A, 0.0, CSC_MAT); + auto c(a); //copy c + A_sparse.multiply(c, b); + checkEqualArray(d, c, TEST_ATOL, TEST_RTOL, "multiply"); +} + +TEST_F(SunMatrixWrapperTest, SparseMultiplyEmpty) +{ + // Ensure empty Matrix vector multiplication succeeds + auto A_sparse = SUNMatrixWrapper(1, 1, 0, CSR_MAT); + std::vector b {0.1}; + std::vector c {0.1}; + A_sparse.multiply(c, b); + ASSERT_TRUE(c[0] == 0.1); + + A_sparse = SUNMatrixWrapper(1, 1, 0, CSC_MAT); + A_sparse.multiply(c, b); + ASSERT_TRUE(c[0] == 0.1); +} + +TEST_F(SunMatrixWrapperTest, DenseMultiply) +{ + auto c(a); //copy c + A.multiply(c, b); + checkEqualArray(d, c, TEST_ATOL, TEST_RTOL, "multiply"); +} + +TEST_F(SunMatrixWrapperTest, StdVectorCtor) +{ + auto b_amivector = AmiVector(b); + auto a_amivector = AmiVector(a); +} + +TEST_F(SunMatrixWrapperTest, TransformThrows) +{ + ASSERT_THROW(SUNMatrixWrapper(A, 0.0, 13), std::invalid_argument); + auto A_sparse = SUNMatrixWrapper(A, 0.0, CSR_MAT); + ASSERT_THROW(SUNMatrixWrapper(A_sparse, 0.0, CSR_MAT), + std::invalid_argument); +} + +TEST_F(SunMatrixWrapperTest, BlockTranspose) +{ + SUNMatrixWrapper B_sparse(4, 4, 7, CSR_MAT); + ASSERT_THROW(B.transpose(B_sparse, 1.0, 4), std::domain_error); + + B_sparse = SUNMatrixWrapper(4, 4, 7, CSC_MAT); + B.transpose(B_sparse, -1.0, 2); + for (int idx = 0; idx < 7; idx++) { + ASSERT_EQ(SM_INDEXVALS_S(B.get())[idx], + SM_INDEXVALS_S(B_sparse.get())[idx]); + if (idx == 1) { + ASSERT_EQ(SM_DATA_S(B.get())[idx], + -SM_DATA_S(B_sparse.get())[3]); + } else if (idx == 3) { + ASSERT_EQ(SM_DATA_S(B.get())[idx], + -SM_DATA_S(B_sparse.get())[1]); + } else { + ASSERT_EQ(SM_DATA_S(B.get())[idx], + -SM_DATA_S(B_sparse.get())[idx]); + } + } + for (int icol = 0; icol <= 4; icol++) + ASSERT_EQ(SM_INDEXPTRS_S(B.get())[icol], + SM_INDEXPTRS_S(B_sparse.get())[icol]); +} + +} // namespace diff --git a/tests/cpp/unittests/testSerialization.cpp b/tests/cpp/unittests/testSerialization.cpp new file mode 100644 index 0000000000..15c8df9d84 --- /dev/null +++ b/tests/cpp/unittests/testSerialization.cpp @@ -0,0 +1,257 @@ +#include +#include +#include + +#include "testfunctions.h" + +#include + +#include + +void +checkReturnDataEqual(amici::ReturnData const& r, amici::ReturnData const& s) +{ + ASSERT_EQ(r.np, s.np); + ASSERT_EQ(r.nk, s.nk); + ASSERT_EQ(r.nx, s.nx); + ASSERT_EQ(r.nxtrue, s.nxtrue); + ASSERT_EQ(r.nx_solver, s.nx_solver); + ASSERT_EQ(r.nx_solver_reinit, s.nx_solver_reinit); + ASSERT_EQ(r.ny, s.ny); + ASSERT_EQ(r.nytrue, s.nytrue); + ASSERT_EQ(r.nz, s.nz); + ASSERT_EQ(r.nztrue, s.nztrue); + ASSERT_EQ(r.ne, s.ne); + ASSERT_EQ(r.nJ, s.nJ); + ASSERT_EQ(r.nplist, s.nplist); + ASSERT_EQ(r.nmaxevent, s.nmaxevent); + ASSERT_EQ(r.nt, s.nt); + ASSERT_EQ(r.newton_maxsteps, s.newton_maxsteps); + ASSERT_EQ(r.pscale, s.pscale); + ASSERT_EQ(static_cast(r.o2mode), static_cast(s.o2mode)); + ASSERT_EQ(static_cast(r.sensi), static_cast(s.sensi)); + ASSERT_EQ(static_cast(r.sensi_meth), static_cast(s.sensi_meth)); + + using amici::checkEqualArray; + checkEqualArray(r.ts, s.ts, 1e-16, 1e-16, "ts"); + checkEqualArray(r.xdot, s.xdot, 1e-16, 1e-16, "xdot"); + checkEqualArray(r.J, s.J, 1e-16, 1e-16, "J"); + checkEqualArray(r.z, s.z, 1e-16, 1e-16, "z"); + checkEqualArray(r.sigmaz, s.sigmaz, 1e-16, 1e-16, "sigmaz"); + checkEqualArray(r.sz, s.sz, 1e-16, 1e-16, "sz"); + checkEqualArray(r.ssigmaz, s.ssigmaz, 1e-16, 1e-16, "ssigmaz"); + checkEqualArray(r.rz, s.rz, 1e-16, 1e-16, "rz"); + checkEqualArray(r.srz, s.srz, 1e-16, 1e-16, "srz"); + checkEqualArray(r.s2rz, s.s2rz, 1e-16, 1e-16, "s2rz"); + checkEqualArray(r.x, s.x, 1e-16, 1e-16, "x"); + checkEqualArray(r.sx, s.sx, 1e-16, 1e-16, "sx"); + + checkEqualArray(r.y, s.y, 1e-16, 1e-16, "y"); + checkEqualArray(r.sigmay, s.sigmay, 1e-16, 1e-16, "sigmay"); + checkEqualArray(r.sy, s.sy, 1e-16, 1e-16, "sy"); + checkEqualArray(r.ssigmay, s.ssigmay, 1e-16, 1e-16, "ssigmay"); + + ASSERT_EQ(r.numsteps, s.numsteps); + ASSERT_EQ(r.numstepsB, s.numstepsB); + ASSERT_EQ(r.numrhsevals, s.numrhsevals); + ASSERT_EQ(r.numrhsevalsB, s.numrhsevalsB); + ASSERT_EQ(r.numerrtestfails, s.numerrtestfails); + ASSERT_EQ(r.numerrtestfailsB, s.numerrtestfailsB); + ASSERT_EQ(r.numnonlinsolvconvfails, s.numnonlinsolvconvfails); + ASSERT_EQ(r.numnonlinsolvconvfailsB, s.numnonlinsolvconvfailsB); + ASSERT_EQ(r.order, s.order); + ASSERT_EQ(r.cpu_time, s.cpu_time); + ASSERT_EQ(r.cpu_timeB, s.cpu_timeB); + + ASSERT_EQ(r.preeq_status, s.preeq_status); + ASSERT_TRUE(r.preeq_t == s.preeq_t || + (std::isnan(r.preeq_t) && std::isnan(s.preeq_t))); + ASSERT_TRUE(r.preeq_wrms == s.preeq_wrms || + (std::isnan(r.preeq_wrms) && std::isnan(s.preeq_wrms))); + ASSERT_EQ(r.preeq_numsteps, s.preeq_numsteps); + ASSERT_EQ(r.preeq_numlinsteps, s.preeq_numlinsteps); + EXPECT_NEAR(r.preeq_cpu_time, s.preeq_cpu_time, 1e-16); + + ASSERT_EQ(r.posteq_status, s.posteq_status); + ASSERT_TRUE(r.posteq_t == s.posteq_t || + (std::isnan(r.posteq_t) && std::isnan(s.posteq_t))); + ASSERT_TRUE(r.posteq_wrms == s.posteq_wrms || + (std::isnan(r.posteq_wrms) && std::isnan(s.posteq_wrms))); + ASSERT_EQ(r.posteq_numsteps, s.posteq_numsteps); + ASSERT_EQ(r.posteq_numlinsteps, s.posteq_numlinsteps); + EXPECT_NEAR(r.posteq_cpu_time, s.posteq_cpu_time, 1e-16); + + checkEqualArray(r.x0, s.x0, 1e-16, 1e-16, "x0"); + checkEqualArray(r.sx0, s.sx0, 1e-16, 1e-16, "sx0"); + + ASSERT_TRUE(r.llh == s.llh || (std::isnan(r.llh) && std::isnan(s.llh))); + ASSERT_TRUE(r.chi2 == s.chi2 || (std::isnan(r.llh) && std::isnan(s.llh))); + ASSERT_EQ(r.status, s.status); + + checkEqualArray(r.sllh, s.sllh, 1e-5, 1e-5, "sllh"); + checkEqualArray(r.s2llh, s.s2llh, 1e-5, 1e-5, "s2llh"); +} + +class SolverSerializationTest : public ::testing::Test { + protected: + void SetUp() override { + // set non-default values for all members + solver.setAbsoluteTolerance(1e-4); + solver.setRelativeTolerance(1e-5); + solver.setAbsoluteToleranceQuadratures(1e-6); + solver.setRelativeToleranceQuadratures(1e-7); + solver.setAbsoluteToleranceSteadyState(1e-8); + solver.setRelativeToleranceSteadyState(1e-9); + solver.setSensitivityMethod(amici::SensitivityMethod::adjoint); + solver.setSensitivityOrder(amici::SensitivityOrder::second); + solver.setMaxSteps(1e1); + solver.setMaxStepsBackwardProblem(1e2); + solver.setNewtonMaxSteps(1e3); + solver.setNewtonMaxLinearSteps(1e4); + solver.setPreequilibration(true); + solver.setStateOrdering(static_cast(amici::SUNLinSolKLU::StateOrdering::COLAMD)); + solver.setInterpolationType(amici::InterpolationType::polynomial); + solver.setStabilityLimitFlag(false); + solver.setLinearSolver(amici::LinearSolver::dense); + solver.setLinearMultistepMethod(amici::LinearMultistepMethod::adams); + solver.setNonlinearSolverIteration(amici::NonlinearSolverIteration::newton); + solver.setInternalSensitivityMethod(amici::InternalSensitivityMethod::staggered); + solver.setReturnDataReportingMode(amici::RDataReporting::likelihood); + } + + amici::CVodeSolver solver; +}; + +TEST(ModelSerializationTest, ToFile) +{ + int np = 1; + int nk = 2; + int nx = 3; + int ny = 4; + int nz = 5; + int ne = 6; + amici::CVodeSolver solver; + amici::Model_Test m = amici::Model_Test( + amici::ModelDimensions( + nx, // nx_rdata + nx, // nxtrue_rdata + nx, // nx_solver + nx, // nxtrue_solver + 0, // nx_solver_reinit + np, // np + nk, // nk + ny, // ny + ny, // nytrue + nz, // nz + nz, // nztrue + ne, // ne + 0, // nJ + 9, // nw + 2, // ndwdx + 2, // ndwdp + 2, // dwdw + 13, // ndxdotdw + {}, // ndJydy + 15, // nnz + 16, // ubw + 17 // lbw + ), + amici::SimulationParameters( + std::vector(nk, 0.0), + std::vector(np, 0.0), + std::vector(np, 0) + ), + amici::SecondOrderMode::none, + std::vector(nx, 0.0), + std::vector(nz, 0)); + + { + std::ofstream ofs("sstore.dat"); + boost::archive::text_oarchive oar(ofs); + // oar & static_cast(solver); + oar& static_cast(m); + } + { + std::ifstream ifs("sstore.dat"); + boost::archive::text_iarchive iar(ifs); + amici::CVodeSolver v; + amici::Model_Test n; + // iar &static_cast(v); + iar& static_cast(n); + // CHECK_TRUE(solver == v); + ASSERT_EQ(m, n); + } +} + +TEST(ReturnDataSerializationTest, ToString) +{ + int np = 1; + int nk = 2; + int nx = 3; + int ny = 4; + int nz = 5; + int ne = 6; + amici::CVodeSolver solver; + amici::Model_Test m = amici::Model_Test( + amici::ModelDimensions( + nx, // nx_rdata + nx, // nxtrue_rdata + nx, // nx_solver + nx, // nxtrue_solver + 0, // nx_solver_reinit + np, // np + nk, // nk + ny, // ny + ny, // nytrue + nz, // nz + nz, // nztrue + ne, // ne + 0, // nJ + 9, // nw + 10, // ndwdx + 2, // ndwdp + 12, // dwdw + 13, // ndxdotdw + {}, // ndJydy + 15, // nnz + 16, // ubw + 17 // lbw + ), + amici::SimulationParameters( + std::vector(nk, 0.0), + std::vector(np, 0.0), + std::vector(np, 0) + ), + amici::SecondOrderMode::none, + std::vector(nx, 0.0), + std::vector(nz, 0)); + + amici::ReturnData r(solver, m); + + std::string serialized = amici::serializeToString(r); + + checkReturnDataEqual( + r, amici::deserializeFromString(serialized)); +} + +TEST_F(SolverSerializationTest, ToChar) +{ + int length; + char* buf = amici::serializeToChar(solver, &length); + + amici::CVodeSolver v = + amici::deserializeFromChar(buf, length); + + delete[] buf; + ASSERT_EQ(solver, v); +} + +TEST_F(SolverSerializationTest, ToStdVec) +{ + + auto buf = amici::serializeToStdVec(solver); + amici::CVodeSolver v = + amici::deserializeFromChar(buf.data(), buf.size()); + + ASSERT_EQ(solver, v); +} diff --git a/tests/cpputest/wrapTestModels.m b/tests/cpp/wrapTestModels.m similarity index 100% rename from tests/cpputest/wrapTestModels.m rename to tests/cpp/wrapTestModels.m diff --git a/tests/cpputest/events/CMakeLists.txt b/tests/cpputest/events/CMakeLists.txt deleted file mode 100644 index 3197ed7a72..0000000000 --- a/tests/cpputest/events/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) -project(model_${MODEL_NAME}_test) - -set(SRC_LIST - ../main.cpp - tests1.cpp -) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - -add_executable(${PROJECT_NAME} ${SRC_LIST}) - -target_link_libraries(${PROJECT_NAME} - amici-testing - model_${MODEL_NAME} -) - -add_test(NAME ${PROJECT_NAME} COMMAND ./${PROJECT_NAME} -c) diff --git a/tests/cpputest/jakstat_adjoint_o2/CMakeLists.txt b/tests/cpputest/jakstat_adjoint_o2/CMakeLists.txt deleted file mode 100644 index 3197ed7a72..0000000000 --- a/tests/cpputest/jakstat_adjoint_o2/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) -project(model_${MODEL_NAME}_test) - -set(SRC_LIST - ../main.cpp - tests1.cpp -) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - -add_executable(${PROJECT_NAME} ${SRC_LIST}) - -target_link_libraries(${PROJECT_NAME} - amici-testing - model_${MODEL_NAME} -) - -add_test(NAME ${PROJECT_NAME} COMMAND ./${PROJECT_NAME} -c) diff --git a/tests/cpputest/main.cpp b/tests/cpputest/main.cpp deleted file mode 100644 index e588e8ed53..0000000000 --- a/tests/cpputest/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -#include "CppUTest/CommandLineTestRunner.h" -#include "CppUTest/TestHarness.h" - -int main(int argc, char** argv) -{ - return CommandLineTestRunner::RunAllTests(argc, argv); -} diff --git a/tests/cpputest/nested_events/CMakeLists.txt b/tests/cpputest/nested_events/CMakeLists.txt deleted file mode 100644 index 3197ed7a72..0000000000 --- a/tests/cpputest/nested_events/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) -project(model_${MODEL_NAME}_test) - -set(SRC_LIST - ../main.cpp - tests1.cpp -) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - -add_executable(${PROJECT_NAME} ${SRC_LIST}) - -target_link_libraries(${PROJECT_NAME} - amici-testing - model_${MODEL_NAME} -) - -add_test(NAME ${PROJECT_NAME} COMMAND ./${PROJECT_NAME} -c) diff --git a/tests/cpputest/neuron/CMakeLists.txt b/tests/cpputest/neuron/CMakeLists.txt deleted file mode 100644 index 3197ed7a72..0000000000 --- a/tests/cpputest/neuron/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) -project(model_${MODEL_NAME}_test) - -set(SRC_LIST - ../main.cpp - tests1.cpp -) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - -add_executable(${PROJECT_NAME} ${SRC_LIST}) - -target_link_libraries(${PROJECT_NAME} - amici-testing - model_${MODEL_NAME} -) - -add_test(NAME ${PROJECT_NAME} COMMAND ./${PROJECT_NAME} -c) diff --git a/tests/cpputest/neuron_o2/CMakeLists.txt b/tests/cpputest/neuron_o2/CMakeLists.txt deleted file mode 100644 index 3197ed7a72..0000000000 --- a/tests/cpputest/neuron_o2/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) -project(model_${MODEL_NAME}_test) - -set(SRC_LIST - ../main.cpp - tests1.cpp -) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - -add_executable(${PROJECT_NAME} ${SRC_LIST}) - -target_link_libraries(${PROJECT_NAME} - amici-testing - model_${MODEL_NAME} -) - -add_test(NAME ${PROJECT_NAME} COMMAND ./${PROJECT_NAME} -c) diff --git a/tests/cpputest/steadystate/CMakeLists.txt b/tests/cpputest/steadystate/CMakeLists.txt deleted file mode 100644 index 3197ed7a72..0000000000 --- a/tests/cpputest/steadystate/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -get_filename_component(MODEL_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) -project(model_${MODEL_NAME}_test) - -set(SRC_LIST - ../main.cpp - tests1.cpp -) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CppUTest_INCLUDE_DIRS}) - -add_executable(${PROJECT_NAME} ${SRC_LIST}) - -target_link_libraries(${PROJECT_NAME} - amici-testing - model_${MODEL_NAME} -) - -add_test(NAME ${PROJECT_NAME} COMMAND ./${PROJECT_NAME} -c) diff --git a/tests/cpputest/unittests/CMakeLists.txt b/tests/cpputest/unittests/CMakeLists.txt deleted file mode 100644 index 376a2dbe96..0000000000 --- a/tests/cpputest/unittests/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -project(unittests) - -# cannot mix CppuTest new override togeter with Boost -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_OLD}") -find_package(Boost COMPONENTS serialization) - -set(SRC_LIST - ../main.cpp - tests1.cpp -) - -if(Boost_FOUND) - set(SRC_LIST ${SRC_LIST} testsSerialization.cpp) - include_directories("${Boost_INCLUDE_DIR}") -endif() - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - -add_executable(${PROJECT_NAME} ${SRC_LIST}) - -target_link_libraries(${PROJECT_NAME} - amici-testing - Upstream::amici - ${Boost_LIBRARIES} - ) - -add_test(NAME unittests COMMAND ./unittests -c) diff --git a/tests/cpputest/unittests/tests1.cpp b/tests/cpputest/unittests/tests1.cpp deleted file mode 100644 index 869c6dc9fd..0000000000 --- a/tests/cpputest/unittests/tests1.cpp +++ /dev/null @@ -1,911 +0,0 @@ -#include "testfunctions.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - -namespace amici { -namespace generic_model { - -std::unique_ptr getModel() -{ - return std::make_unique(); -} - -} // namespace generic_model -} // namespace amici - -using namespace amici; - -void -testSolverGetterSetters(CVodeSolver solver, - SensitivityMethod sensi_meth, - SensitivityOrder sensi, - InternalSensitivityMethod ism, - InterpolationType interp, - NonlinearSolverIteration iter, - LinearMultistepMethod lmm, - int steps, - int badsteps, - double tol, - double badtol); - -TEST_GROUP(amici){}; - -TEST_GROUP(model) -{ - int nx = 1, ny = 2, nz = 3, nmaxevent = 4; - std::vector p{ 1.0 }; - std::vector k{ 0.5, 0.4, 0.7 }; - std::vector plist{ 1 }; - std::vector idlist{ 0 }; - std::vector z2event{ 0, 0, 0 }; - Model_Test model = Model_Test( - ModelDimensions( - nx, // nx_rdata - nx, // nxtrue_rdata - nx, // nx_solver - nx, // nxtrue_solver - 0, // nx_solver_reinit - static_cast(p.size()), // np - static_cast(k.size()), // nk - ny, // ny - ny, // nytrue - nz, // nz - nz, // nztrue - nmaxevent, // ne - 0, // nJ - 0, // nw - 0, // ndwdx - 0, // ndwdp - 0, // dwdw - 0, // ndxdotdw - {}, // ndJydy - 0, // nnz - 0, // ubw - 0 // lbw - ), - SimulationParameters(k, p, plist), - SecondOrderMode::none, - idlist, - z2event); - - std::vector unscaled{ NAN }; -}; - -TEST(model, testScalingLin) -{ - model.setParameterScale(ParameterScaling::none); - - CHECK_EQUAL(p[0], model.getParameters()[0]); -} - -TEST(model, testScalingLog) -{ - model.setParameterScale(ParameterScaling::ln); - - DOUBLES_EQUAL(std::log(p[0]), model.getParameters()[0], 1e-16); -} - -TEST(model, testScalingLog10) -{ - model.setParameterScale(ParameterScaling::log10); - - DOUBLES_EQUAL(std::log10(p[0]), model.getParameters()[0], 1e-16); -} - -TEST(model, testParameterScalingLengthMismatch) -{ - // too short - auto pscale = - std::vector(p.size() - 1, ParameterScaling::log10); - CHECK_THROWS(AmiException, model.setParameterScale(pscale)); - - // too long - pscale = - std::vector(p.size() + 1, ParameterScaling::log10); - CHECK_THROWS(AmiException, model.setParameterScale(pscale)); -} - -TEST(model, testSetTimepoints){ - CHECK_THROWS(AmiException, - model.setTimepoints(std::vector{ 0.0, 1.0, 0.5 })); -} - -TEST(model, testNameIdGetterSetter) -{ - model.setParameterById("p0", 3.0); - DOUBLES_EQUAL(model.getParameterById("p0"), 3.0, 1e-16); - CHECK_THROWS(AmiException, model.getParameterById("p1")); - DOUBLES_EQUAL( - model.setParametersByIdRegex("p[\\d]+", 5.0), p.size(), 1e-16); - for (const auto& ip : model.getParameters()) - DOUBLES_EQUAL(ip, 5.0, 1e-16); - CHECK_THROWS(AmiException, model.setParametersByIdRegex("k[\\d]+", 5.0)); - - model.setParameterByName("p0", 3.0); - DOUBLES_EQUAL(model.getParameterByName("p0"), 3.0, 1e-16); - CHECK_THROWS(AmiException, model.getParameterByName("p1")); - DOUBLES_EQUAL( - model.setParametersByNameRegex("p[\\d]+", 5.0), p.size(), 1e-16); - for (const auto& ip : model.getParameters()) - DOUBLES_EQUAL(ip, 5.0, 1e-16); - CHECK_THROWS(AmiException, model.setParametersByNameRegex("k[\\d]+", 5.0)); - - model.setFixedParameterById("k0", 3.0); - DOUBLES_EQUAL(model.getFixedParameterById("k0"), 3.0, 1e-16); - CHECK_THROWS(AmiException, model.getFixedParameterById("k4")); - DOUBLES_EQUAL( - model.setFixedParametersByIdRegex("k[\\d]+", 5.0), k.size(), 1e-16); - for (const auto& ik : model.getFixedParameters()) - DOUBLES_EQUAL(ik, 5.0, 1e-16); - CHECK_THROWS(AmiException, - model.setFixedParametersByIdRegex("p[\\d]+", 5.0)); - - model.setFixedParameterByName("k0", 3.0); - DOUBLES_EQUAL(model.getFixedParameterByName("k0"), 3.0, 1e-16); - CHECK_THROWS(AmiException, model.getFixedParameterByName("k4")); - DOUBLES_EQUAL( - model.setFixedParametersByNameRegex("k[\\d]+", 5.0), k.size(), 1e-16); - for (const auto& ik : model.getFixedParameters()) - DOUBLES_EQUAL(ik, 5.0, 1e-16); - CHECK_THROWS(AmiException, - model.setFixedParametersByNameRegex("p[\\d]+", 5.0)); -} - -TEST(model, reinitializeFixedParameterInitialStates) -{ - CHECK_THROWS(AmiException, - model.setReinitializeFixedParameterInitialStates(true)); - model.setReinitializeFixedParameterInitialStates(false); - CHECK_TRUE(!model.getReinitializeFixedParameterInitialStates()); - AmiVector x(nx); - AmiVectorArray sx(model.np(), nx); -} - -TEST_GROUP(symbolicFunctions){}; - -TEST(symbolicFunctions, testSign) -{ - CHECK_EQUAL(-1, sign(-2)); - CHECK_EQUAL(0, sign(0)); - CHECK_EQUAL(1, sign(2)); -} - -TEST(symbolicFunctions, testHeaviside) -{ - CHECK_EQUAL(0, heaviside(-1)); - CHECK_EQUAL(1, heaviside(0)); - CHECK_EQUAL(1, heaviside(1)); -} - -TEST(symbolicFunctions, testMin) -{ - CHECK_EQUAL(-1, amici::min(-1, 2, 0)); - CHECK_EQUAL(-2, amici::min(1, -2, 0)); - CHECK_TRUE(amici::isNaN(amici::min(amici::getNaN(), amici::getNaN(), 0))); - CHECK_EQUAL(-1, amici::min(-1, amici::getNaN(), 0)); - CHECK_EQUAL(-1, amici::min(amici::getNaN(), -1, 0)); -} - -TEST(symbolicFunctions, testMax) -{ - CHECK_EQUAL(2, amici::max(-1, 2, 0)); - CHECK_EQUAL(1, amici::max(1, -2, 0)); - CHECK_TRUE(amici::isNaN(amici::max(amici::getNaN(), amici::getNaN(), 0))); - CHECK_EQUAL(-1, amici::max(-1, amici::getNaN(), 0)); - CHECK_EQUAL(-1, amici::max(amici::getNaN(), -1, 0)); -} - -TEST(symbolicFunctions, testDMin) -{ - CHECK_EQUAL(0, amici::Dmin(1, -1, -2, 0)); - CHECK_EQUAL(1, amici::Dmin(1, -1, 2, 0)); - CHECK_EQUAL(1, amici::Dmin(2, -1, -2, 0)); - CHECK_EQUAL(0, amici::Dmin(2, -1, 2, 0)); -} - -TEST(symbolicFunctions, testDMax) -{ - CHECK_EQUAL(1, amici::Dmax(1, -1, -2, 0)); - CHECK_EQUAL(0, amici::Dmax(1, -1, 2, 0)); - CHECK_EQUAL(0, amici::Dmax(2, -1, -2, 0)); - CHECK_EQUAL(1, amici::Dmax(2, -1, 2, 0)); -} - -TEST(symbolicFunctions, testpos_pow) -{ - CHECK_EQUAL(0, amici::pos_pow(-0.1, 3)); - CHECK_EQUAL(pow(0.1, 3), amici::pos_pow(0.1, 3)); -} - -TEST_GROUP(amiciSolver){ }; - -TEST(amiciSolver, testEquality) -{ - IDASolver i1, i2; - CVodeSolver c1, c2; - - CHECK_TRUE(i1 == i2); - CHECK_TRUE(c1 == c2); - CHECK_FALSE(i1 == c1); -} - -TEST(amiciSolver, testClone) -{ - IDASolver i1; - auto i2 = std::unique_ptr(i1.clone()); - CHECK_TRUE(i1 == *i2); - - CVodeSolver c1; - auto c2 = std::unique_ptr(c1.clone()); - CHECK_TRUE(c1 == *c2); - CHECK_FALSE(*i2 == *c2); -} - -TEST_GROUP(amiciSolverIdas){}; - -TEST(amiciSolverIdas, testConstructionDestruction) -{ - IDASolver solver; -} - -TEST_GROUP(edata) -{ - int nx = 1, ny = 2, nz = 3, nmaxevent = 4; - std::vector timepoints = { 1, 2, 3, 4 }; - - std::unique_ptr model = amici::generic_model::getModel(); - - Model_Test testModel = Model_Test( - ModelDimensions( - nx, // nx_rdata - nx, // nxtrue_rdata - nx, // nx_solver - nx, // nxtrue_solver - 0, // nx_solver_reinit - 1, // np - 3, // nk - ny, // ny - ny, // nytrue - nz, // nz - nz, // nztrue - nmaxevent, // ne - 0, // nJ - 0, // nw - 0, // ndwdx - 0, // ndwdp - 0, // dwdw - 0, // ndxdotdw - {}, // ndJydy - 0, // nnz - 0, // ubw - 0 // lbw - ), - SimulationParameters( - std::vector(3, 0.0), - std::vector(1, 0.0), - std::vector(2, 1) - ), - SecondOrderMode::none, - std::vector(), - std::vector()); - void setup() override - { - model->setTimepoints(timepoints); - model->setNMaxEvent(nmaxevent); - testModel.setTimepoints(timepoints); - testModel.setNMaxEvent(nmaxevent); - } - - void teardown() override {} -}; - -TEST(edata, testConstructors1) -{ - auto edata = ExpData(); - CHECK_TRUE(edata.nytrue() == 0); - CHECK_TRUE(edata.nztrue() == 0); - CHECK_TRUE(edata.nmaxevent() == 0); -} -TEST(edata, testConstructors2) -{ - auto edata = ExpData(model->nytrue, model->nztrue, model->nMaxEvent()); - CHECK_TRUE(edata.nytrue() == model->nytrue); - CHECK_TRUE(edata.nztrue() == model->nztrue); - CHECK_TRUE(edata.nmaxevent() == model->nMaxEvent()); -} - -TEST(edata, testConstructors3) -{ - auto edata = - ExpData(model->nytrue, model->nztrue, model->nMaxEvent(), timepoints); - CHECK_TRUE(edata.nytrue() == model->nytrue); - CHECK_TRUE(edata.nztrue() == model->nztrue); - CHECK_TRUE(edata.nmaxevent() == model->nMaxEvent()); - CHECK_TRUE(edata.nt() == model->nt()); - checkEqualArray( - timepoints, edata.getTimepoints(), TEST_ATOL, TEST_RTOL, "ts"); -} - -TEST(edata, testConstructors4) -{ - std::vector y(ny * timepoints.size(), 0.0); - std::vector y_std(ny * timepoints.size(), 0.1); - std::vector z(nz * nmaxevent, 0.0); - std::vector z_std(nz * nmaxevent, 0.1); - - auto edata = ExpData(testModel.nytrue, - testModel.nztrue, - testModel.nMaxEvent(), - timepoints, - y, - y_std, - z, - z_std); - CHECK_TRUE(edata.nytrue() == testModel.nytrue); - CHECK_TRUE(edata.nztrue() == testModel.nztrue); - CHECK_TRUE(edata.nmaxevent() == testModel.nMaxEvent()); - CHECK_TRUE(edata.nt() == testModel.nt()); - checkEqualArray( - timepoints, edata.getTimepoints(), TEST_ATOL, TEST_RTOL, "ts"); - checkEqualArray( - y, edata.getObservedData(), TEST_ATOL, TEST_RTOL, "observedData"); - checkEqualArray(y_std, - edata.getObservedDataStdDev(), - TEST_ATOL, - TEST_RTOL, - "observedDataStdDev"); - checkEqualArray( - z, edata.getObservedEvents(), TEST_ATOL, TEST_RTOL, "observedEvents"); - checkEqualArray(z_std, - edata.getObservedEventsStdDev(), - TEST_ATOL, - TEST_RTOL, - "observedEventsStdDev"); - - auto edata_copy = ExpData(edata); - CHECK_TRUE(edata.nytrue() == edata_copy.nytrue()); - CHECK_TRUE(edata.nztrue() == edata_copy.nztrue()); - CHECK_TRUE(edata.nmaxevent() == edata_copy.nmaxevent()); - CHECK_TRUE(edata.nt() == edata_copy.nt()); - checkEqualArray(edata_copy.getTimepoints(), - edata.getTimepoints(), - TEST_ATOL, - TEST_RTOL, - "ts"); - checkEqualArray(edata_copy.getObservedData(), - edata.getObservedData(), - TEST_ATOL, - TEST_RTOL, - "observedData"); - checkEqualArray(edata_copy.getObservedDataStdDev(), - edata.getObservedDataStdDev(), - TEST_ATOL, - TEST_RTOL, - "observedDataStdDev"); - checkEqualArray(edata_copy.getObservedEvents(), - edata.getObservedEvents(), - TEST_ATOL, - TEST_RTOL, - "observedEvents"); - checkEqualArray(edata_copy.getObservedEventsStdDev(), - edata.getObservedEventsStdDev(), - TEST_ATOL, - TEST_RTOL, - "observedEventsStdDev"); -} - -TEST(edata, testConstructors5) -{ - testModel.setTimepoints(timepoints); - auto edata = ExpData(testModel); - CHECK_TRUE(edata.nytrue() == testModel.nytrue); - CHECK_TRUE(edata.nztrue() == testModel.nztrue); - CHECK_TRUE(edata.nmaxevent() == testModel.nMaxEvent()); - CHECK_TRUE(edata.nt() == testModel.nt()); - checkEqualArray(testModel.getTimepoints(), - edata.getTimepoints(), - TEST_ATOL, - TEST_RTOL, - "ts"); -} - -TEST(edata, testDimensionChecks) -{ - - std::vector bad_std(ny, -0.1); - - std::vector y(ny * timepoints.size(), 0.0); - std::vector y_std(ny * timepoints.size(), 0.1); - std::vector z(nz * nmaxevent, 0.0); - std::vector z_std(nz * nmaxevent, 0.1); - - CHECK_THROWS(AmiException, - ExpData(testModel.nytrue, - testModel.nztrue, - testModel.nMaxEvent(), - timepoints, - z, - z_std, - z, - z_std)); - - CHECK_THROWS(AmiException, - ExpData(testModel.nytrue, - testModel.nztrue, - testModel.nMaxEvent(), - timepoints, - z, - bad_std, - z, - z_std)); - - auto edata = ExpData(testModel); - - std::vector bad_y(ny * timepoints.size() + 1, 0.0); - std::vector bad_y_std(ny * timepoints.size() + 1, 0.1); - std::vector bad_z(nz * nmaxevent + 1, 0.0); - std::vector bad_z_std(nz * nmaxevent + 1, 0.1); - - CHECK_THROWS(AmiException, edata.setObservedData(bad_y)); - CHECK_THROWS(AmiException, edata.setObservedDataStdDev(bad_y_std)); - CHECK_THROWS(AmiException, edata.setObservedEvents(bad_z)); - CHECK_THROWS(AmiException, edata.setObservedEventsStdDev(bad_y_std)); - - std::vector bad_single_y(edata.nt() + 1, 0.0); - std::vector bad_single_y_std(edata.nt() + 1, 0.1); - std::vector bad_single_z(edata.nmaxevent() + 1, 0.0); - std::vector bad_single_z_std(edata.nmaxevent() + 1, 0.1); - - CHECK_THROWS(AmiException, edata.setObservedData(bad_single_y, 0)); - CHECK_THROWS(AmiException, - edata.setObservedDataStdDev(bad_single_y_std, 0)); - CHECK_THROWS(AmiException, edata.setObservedEvents(bad_single_z, 0)); - CHECK_THROWS(AmiException, - edata.setObservedEventsStdDev(bad_single_y_std, 0)); - - CHECK_THROWS(AmiException, - edata.setTimepoints(std::vector{ 0.0, 1.0, 0.5 })); -} - -TEST(edata, testSettersGetters) -{ - auto edata = ExpData(testModel); - - std::vector y(ny * timepoints.size(), 0.0); - std::vector y_std(ny * timepoints.size(), 0.1); - std::vector z(nz * nmaxevent, 0.0); - std::vector z_std(nz * nmaxevent, 0.1); - - edata.setObservedData(y); - checkEqualArray( - edata.getObservedData(), y, TEST_ATOL, TEST_RTOL, "ObservedData"); - edata.setObservedDataStdDev(y_std); - checkEqualArray(edata.getObservedDataStdDev(), - y_std, - TEST_ATOL, - TEST_RTOL, - "ObservedDataStdDev"); - edata.setObservedEvents(z); - checkEqualArray( - edata.getObservedEvents(), z, TEST_ATOL, TEST_RTOL, "ObservedEvents"); - edata.setObservedEventsStdDev(z_std); - checkEqualArray(edata.getObservedEventsStdDev(), - z_std, - TEST_ATOL, - TEST_RTOL, - "ObservedEventsStdDev"); - - std::vector single_y(edata.nt(), 0.0); - std::vector single_y_std(edata.nt(), 0.1); - - for (int iy = 0; iy < ny; ++iy) { - edata.setObservedData(single_y, iy); - edata.setObservedDataStdDev(single_y_std, iy); - } - CHECK_THROWS(std::exception, edata.setObservedData(single_y, ny)); - CHECK_THROWS(std::exception, edata.setObservedData(single_y, -1)); - CHECK_THROWS(std::exception, edata.setObservedDataStdDev(single_y_std, ny)); - CHECK_THROWS(std::exception, edata.setObservedDataStdDev(single_y_std, -1)); - - std::vector single_z(edata.nmaxevent(), 0.0); - std::vector single_z_std(edata.nmaxevent(), 0.1); - - for (int iz = 0; iz < nz; ++iz) { - edata.setObservedEvents(single_z, iz); - edata.setObservedEventsStdDev(single_z_std, iz); - } - - CHECK_THROWS(std::exception, edata.setObservedEvents(single_z, nz)); - CHECK_THROWS(std::exception, edata.setObservedEvents(single_z, -1)); - CHECK_THROWS(std::exception, - edata.setObservedEventsStdDev(single_z_std, nz)); - CHECK_THROWS(std::exception, - edata.setObservedEventsStdDev(single_z_std, -1)); - - CHECK_TRUE(edata.getObservedDataPtr(0)); - CHECK_TRUE(edata.getObservedDataStdDevPtr(0)); - CHECK_TRUE(edata.getObservedEventsPtr(0)); - CHECK_TRUE(edata.getObservedEventsStdDevPtr(0)); - - std::vector empty(0, 0.0); - - edata.setObservedData(empty); - edata.setObservedDataStdDev(empty); - edata.setObservedEvents(empty); - edata.setObservedEventsStdDev(empty); - - CHECK_TRUE(!edata.getObservedDataPtr(0)); - CHECK_TRUE(!edata.getObservedDataStdDevPtr(0)); - CHECK_TRUE(!edata.getObservedEventsPtr(0)); - CHECK_TRUE(!edata.getObservedEventsStdDevPtr(0)); - - checkEqualArray( - edata.getObservedData(), empty, TEST_ATOL, TEST_RTOL, "ObservedData"); - checkEqualArray(edata.getObservedDataStdDev(), - empty, - TEST_ATOL, - TEST_RTOL, - "ObservedDataStdDev"); - checkEqualArray( - edata.getObservedEvents(), empty, TEST_ATOL, TEST_RTOL, "ObservedEvents"); - checkEqualArray(edata.getObservedEventsStdDev(), - empty, - TEST_ATOL, - TEST_RTOL, - "ObservedEventsStdDev"); -} - -TEST_GROUP(solver) -{ - int nx = 1, ny = 2, nz = 3, ne = 0; - double tol, badtol; - std::vector timepoints = { 1, 2, 3, 4 }; - - std::unique_ptr model = amici::generic_model::getModel(); - SensitivityMethod sensi_meth; - SensitivityOrder sensi; - int steps, badsteps; - LinearMultistepMethod lmm; - NonlinearSolverIteration iter; - InternalSensitivityMethod ism; - InterpolationType interp; - - Model_Test testModel = Model_Test( - ModelDimensions( - nx, // nx_rdata - nx, // nxtrue_rdata - nx, // nx_solver - nx, // nxtrue_solver - 0, // nx_solver_reinit - 1, // np - 3, // nk - ny, // ny - ny, // nytrue - nz, // nz - nz, // nztrue - ne, // ne - 0, // nJ - 0, // nw - 0, // ndwdx - 0, // ndwdp - 0, // dwdw - 0, // ndxdotdw - {}, // ndJydy - 1, // nnz - 0, // ubw - 0 // lbw - ), - SimulationParameters( - std::vector(3, 0.0), - std::vector(1, 0.0), - std::vector(2, 1) - ), - SecondOrderMode::none, - std::vector(0, 0.0), - std::vector()); - - CVodeSolver solver = CVodeSolver(); - - void setup() - { - tol = 0.01; - badtol = -0.01; - sensi_meth = SensitivityMethod::adjoint; - sensi = SensitivityOrder::first; - steps = 1000; - badsteps = -1; - lmm = LinearMultistepMethod::adams; - iter = NonlinearSolverIteration::fixedpoint; - ism = InternalSensitivityMethod::staggered1; - interp = InterpolationType::polynomial; - } - - void teardown() {} -}; - -TEST(solver, testSettersGettersNoSetup) -{ - testSolverGetterSetters(solver, - sensi_meth, - sensi, - ism, - interp, - iter, - lmm, - steps, - badsteps, - tol, - badtol); -} - -TEST(solver, testSettersGettersWithSetup) -{ - - solver.setSensitivityMethod(sensi_meth); - CHECK_EQUAL(static_cast(solver.getSensitivityMethod()), - static_cast(sensi_meth)); - - auto rdata = - std::unique_ptr(new ReturnData(solver, testModel)); - AmiVector x(nx), dx(nx); - AmiVectorArray sx(nx, 1), sdx(nx, 1); - - testModel.setInitialStates(std::vector{ 0 }); - - solver.setup(0, &testModel, x, dx, sx, sdx); - - testSolverGetterSetters(solver, - sensi_meth, - sensi, - ism, - interp, - iter, - lmm, - steps, - badsteps, - tol, - badtol); -} - -void -testSolverGetterSetters(CVodeSolver solver, - SensitivityMethod sensi_meth, - SensitivityOrder sensi, - InternalSensitivityMethod ism, - InterpolationType interp, - NonlinearSolverIteration iter, - LinearMultistepMethod lmm, - int steps, - int badsteps, - double tol, - double badtol) -{ - - solver.setSensitivityMethod(sensi_meth); - CHECK_EQUAL(static_cast(solver.getSensitivityMethod()), - static_cast(sensi_meth)); - - solver.setSensitivityOrder(sensi); - CHECK_EQUAL(static_cast(solver.getSensitivityOrder()), - static_cast(sensi)); - - solver.setInternalSensitivityMethod(ism); - CHECK_EQUAL(static_cast(solver.getInternalSensitivityMethod()), - static_cast(ism)); - - solver.setInterpolationType(interp); - CHECK_EQUAL(static_cast(solver.getInterpolationType()), - static_cast(interp)); - - solver.setNonlinearSolverIteration(iter); - CHECK_EQUAL(static_cast(solver.getNonlinearSolverIteration()), - static_cast(iter)); - - solver.setLinearMultistepMethod(lmm); - CHECK_EQUAL(static_cast(solver.getLinearMultistepMethod()), - static_cast(lmm)); - - solver.setPreequilibration(true); - CHECK_EQUAL(solver.getPreequilibration(), true); - - solver.setStabilityLimitFlag(true); - CHECK_EQUAL(solver.getStabilityLimitFlag(), true); - - CHECK_THROWS(AmiException, solver.setNewtonMaxSteps(badsteps)); - solver.setNewtonMaxSteps(steps); - CHECK_EQUAL(solver.getNewtonMaxSteps(), steps); - - CHECK_THROWS(AmiException, solver.setNewtonMaxLinearSteps(badsteps)); - solver.setNewtonMaxLinearSteps(steps); - CHECK_EQUAL(solver.getNewtonMaxLinearSteps(), steps); - - CHECK_THROWS(AmiException, solver.setMaxSteps(badsteps)); - solver.setMaxSteps(steps); - CHECK_EQUAL(solver.getMaxSteps(), steps); - - CHECK_THROWS(AmiException, solver.setMaxStepsBackwardProblem(badsteps)); - solver.setMaxStepsBackwardProblem(steps); - CHECK_EQUAL(solver.getMaxStepsBackwardProblem(), steps); - - CHECK_THROWS(AmiException, solver.setRelativeTolerance(badtol)); - solver.setRelativeTolerance(tol); - CHECK_EQUAL(solver.getRelativeTolerance(), tol); - - CHECK_THROWS(AmiException, solver.setAbsoluteTolerance(badtol)); - solver.setAbsoluteTolerance(tol); - CHECK_EQUAL(solver.getAbsoluteTolerance(), tol); - - CHECK_THROWS(AmiException, solver.setRelativeToleranceQuadratures(badtol)); - solver.setRelativeToleranceQuadratures(tol); - CHECK_EQUAL(solver.getRelativeToleranceQuadratures(), tol); - - CHECK_THROWS(AmiException, solver.setAbsoluteToleranceQuadratures(badtol)); - solver.setAbsoluteToleranceQuadratures(tol); - CHECK_EQUAL(solver.getAbsoluteToleranceQuadratures(), tol); - - CHECK_THROWS(AmiException, solver.setRelativeToleranceSteadyState(badtol)); - solver.setRelativeToleranceSteadyState(tol); - CHECK_EQUAL(solver.getRelativeToleranceSteadyState(), tol); - - CHECK_THROWS(AmiException, solver.setAbsoluteToleranceSteadyState(badtol)); - solver.setAbsoluteToleranceSteadyState(tol); - CHECK_EQUAL(solver.getAbsoluteToleranceSteadyState(), tol); -} - -TEST_GROUP(amivector) -{ - std::vector vec1{ 1, 2, 4, 3 }; - std::vector vec2{ 4, 1, 2, 3 }; - std::vector vec3{ 4, 4, 2, 1 }; -}; - -TEST(amivector, vector) -{ - AmiVector av(vec1); - N_Vector nvec = av.getNVector(); - for (int i = 0; i < av.getLength(); ++i) - CHECK_EQUAL(av.at(i), NV_Ith_S(nvec, i)); -} - -TEST(amivector, vectorArray) -{ - AmiVectorArray ava(4, 3); - AmiVector av1(vec1), av2(vec2), av3(vec3); - std::vector avs{ av1, av2, av3 }; - for (int i = 0; i < ava.getLength(); ++i) - ava[i] = avs.at(i); - - std::vector badLengthVector(13, 0.0); - std::vector flattened(12, 0.0); - - CHECK_THROWS(AmiException, ava.flatten_to_vector(badLengthVector)); - ava.flatten_to_vector(flattened); - for (int i = 0; i < ava.getLength(); ++i) { - const AmiVector av = ava[i]; - for (int j = 0; j < av.getLength(); ++j) - CHECK_EQUAL(flattened.at(i * av.getLength() + j), av.at(j)); - } -} - -TEST_GROUP(sunmatrixwrapper) -{ - //inputs - std::vector a{0.82, 0.91, 0.13}; - std::vector b{0.77, 0.80}; - SUNMatrixWrapper A = SUNMatrixWrapper(3, 2); - SUNMatrixWrapper B = SUNMatrixWrapper(4, 4, 7, CSC_MAT); - // result - std::vector d{1.3753, 1.5084, 1.1655}; - - void setup() override { - A.set_data(0, 0, 0.69); - A.set_data(1, 0, 0.32); - A.set_data(2, 0, 0.95); - A.set_data(0, 1, 0.03); - A.set_data(1, 1, 0.44); - A.set_data(2, 1, 0.38); - - B.set_indexptr(0, 0); - B.set_indexptr(1, 2); - B.set_indexptr(2, 4); - B.set_indexptr(3, 5); - B.set_indexptr(4, 7); - B.set_data(0, 3); - B.set_data(1, 1); - B.set_data(2, 3); - B.set_data(3, 7); - B.set_data(4, 1); - B.set_data(5, 2); - B.set_data(6, 9); - B.set_indexval(0, 1); - B.set_indexval(1, 3); - B.set_indexval(2, 0); - B.set_indexval(3, 2); - B.set_indexval(4, 0); - B.set_indexval(5, 1); - B.set_indexval(6, 3); - - } -}; - -TEST(sunmatrixwrapper, sparse_multiply) -{ - - auto A_sparse = SUNMatrixWrapper(A, 0.0, CSC_MAT); - auto c(a); //copy c - A_sparse.multiply(c, b); - checkEqualArray(d, c, TEST_ATOL, TEST_RTOL, "multiply"); -} - -TEST(sunmatrixwrapper, sparse_multiply_empty) -{ - // Ensure empty Matrix vector multiplication succeeds - auto A_sparse = SUNMatrixWrapper(1, 1, 0, CSR_MAT); - std::vector b {0.1}; - std::vector c {0.1}; - A_sparse.multiply(c, b); - CHECK_TRUE(c[0] == 0.1); - - A_sparse = SUNMatrixWrapper(1, 1, 0, CSC_MAT); - A_sparse.multiply(c, b); - CHECK_TRUE(c[0] == 0.1); -} - -TEST(sunmatrixwrapper, dense_multiply) -{ - auto c(a); //copy c - A.multiply(c, b); - checkEqualArray(d, c, TEST_ATOL, TEST_RTOL, "multiply"); -} - -TEST(sunmatrixwrapper, multiply_throws) -{ - auto b_amivector = AmiVector(b); - auto a_amivector = AmiVector(a); -} - -TEST(sunmatrixwrapper, transform_throws) -{ - CHECK_THROWS(std::invalid_argument, SUNMatrixWrapper(A, 0.0, 13)); - auto A_sparse = SUNMatrixWrapper(A, 0.0, CSR_MAT); - CHECK_THROWS(std::invalid_argument, SUNMatrixWrapper(A_sparse, 0.0, CSR_MAT)); -} - -TEST(sunmatrixwrapper, block_transpose) -{ - auto B_sparse = SUNMatrixWrapper(4, 4, 7, CSR_MAT); - CHECK_THROWS(std::domain_error, B.transpose(B_sparse, 1.0, 4)); - - B_sparse = SUNMatrixWrapper(4, 4, 7, CSC_MAT); - B.transpose(B_sparse, -1.0, 2); - for (int idx = 0; idx < 7; idx++) { - CHECK_TRUE(SM_INDEXVALS_S(B.get())[idx] - == SM_INDEXVALS_S(B_sparse.get())[idx]); - if (idx == 1) { - CHECK_TRUE(SM_DATA_S(B.get())[idx] - == -SM_DATA_S(B_sparse.get())[3]); - } else if (idx == 3) { - CHECK_TRUE(SM_DATA_S(B.get())[idx] - == -SM_DATA_S(B_sparse.get())[1]); - } else { - CHECK_TRUE(SM_DATA_S(B.get())[idx] - == -SM_DATA_S(B_sparse.get())[idx]); - } - } - for (int icol = 0; icol <= 4; icol++) - CHECK_TRUE(SM_INDEXPTRS_S(B.get())[icol] - == SM_INDEXPTRS_S(B_sparse.get())[icol]); -} diff --git a/tests/cpputest/unittests/testsSerialization.cpp b/tests/cpputest/unittests/testsSerialization.cpp deleted file mode 100644 index 520f3b34e6..0000000000 --- a/tests/cpputest/unittests/testsSerialization.cpp +++ /dev/null @@ -1,258 +0,0 @@ -#include -#include // needs to be included before cpputest -#include - -#include "testfunctions.h" - -#include - -#include "CppUTest/TestHarness.h" -#include "CppUTestExt/MockSupport.h" - -void -checkReturnDataEqual(amici::ReturnData const& r, amici::ReturnData const& s) -{ - CHECK_EQUAL(r.np, s.np); - CHECK_EQUAL(r.nk, s.nk); - CHECK_EQUAL(r.nx, s.nx); - CHECK_EQUAL(r.nxtrue, s.nxtrue); - CHECK_EQUAL(r.nx_solver, s.nx_solver); - CHECK_EQUAL(r.nx_solver_reinit, s.nx_solver_reinit); - CHECK_EQUAL(r.ny, s.ny); - CHECK_EQUAL(r.nytrue, s.nytrue); - CHECK_EQUAL(r.nz, s.nz); - CHECK_EQUAL(r.nztrue, s.nztrue); - CHECK_EQUAL(r.ne, s.ne); - CHECK_EQUAL(r.nJ, s.nJ); - CHECK_EQUAL(r.nplist, s.nplist); - CHECK_EQUAL(r.nmaxevent, s.nmaxevent); - CHECK_EQUAL(r.nt, s.nt); - CHECK_EQUAL(r.newton_maxsteps, s.newton_maxsteps); - CHECK_TRUE(r.pscale == s.pscale); - CHECK_EQUAL(static_cast(r.o2mode), static_cast(s.o2mode)); - CHECK_EQUAL(static_cast(r.sensi), static_cast(s.sensi)); - CHECK_EQUAL(static_cast(r.sensi_meth), static_cast(s.sensi_meth)); - - using amici::checkEqualArray; - checkEqualArray(r.ts, s.ts, 1e-16, 1e-16, "ts"); - checkEqualArray(r.xdot, s.xdot, 1e-16, 1e-16, "xdot"); - checkEqualArray(r.J, s.J, 1e-16, 1e-16, "J"); - checkEqualArray(r.z, s.z, 1e-16, 1e-16, "z"); - checkEqualArray(r.sigmaz, s.sigmaz, 1e-16, 1e-16, "sigmaz"); - checkEqualArray(r.sz, s.sz, 1e-16, 1e-16, "sz"); - checkEqualArray(r.ssigmaz, s.ssigmaz, 1e-16, 1e-16, "ssigmaz"); - checkEqualArray(r.rz, s.rz, 1e-16, 1e-16, "rz"); - checkEqualArray(r.srz, s.srz, 1e-16, 1e-16, "srz"); - checkEqualArray(r.s2rz, s.s2rz, 1e-16, 1e-16, "s2rz"); - checkEqualArray(r.x, s.x, 1e-16, 1e-16, "x"); - checkEqualArray(r.sx, s.sx, 1e-16, 1e-16, "sx"); - - checkEqualArray(r.y, s.y, 1e-16, 1e-16, "y"); - checkEqualArray(r.sigmay, s.sigmay, 1e-16, 1e-16, "sigmay"); - checkEqualArray(r.sy, s.sy, 1e-16, 1e-16, "sy"); - checkEqualArray(r.ssigmay, s.ssigmay, 1e-16, 1e-16, "ssigmay"); - - CHECK_TRUE(r.numsteps == s.numsteps); - CHECK_TRUE(r.numstepsB == s.numstepsB); - CHECK_TRUE(r.numrhsevals == s.numrhsevals); - CHECK_TRUE(r.numrhsevalsB == s.numrhsevalsB); - CHECK_TRUE(r.numerrtestfails == s.numerrtestfails); - CHECK_TRUE(r.numerrtestfailsB == s.numerrtestfailsB); - CHECK_TRUE(r.numnonlinsolvconvfails == s.numnonlinsolvconvfails); - CHECK_TRUE(r.numnonlinsolvconvfailsB == s.numnonlinsolvconvfailsB); - CHECK_TRUE(r.order == s.order); - CHECK_TRUE(r.cpu_time == s.cpu_time); - CHECK_TRUE(r.cpu_timeB == s.cpu_timeB); - - CHECK_TRUE(r.preeq_status == s.preeq_status); - CHECK_TRUE(r.preeq_t == s.preeq_t || - (std::isnan(r.preeq_t) && std::isnan(s.preeq_t))); - CHECK_TRUE(r.preeq_wrms == s.preeq_wrms || - (std::isnan(r.preeq_wrms) && std::isnan(s.preeq_wrms))); - CHECK_TRUE(r.preeq_numsteps == s.preeq_numsteps); - CHECK_TRUE(r.preeq_numlinsteps == s.preeq_numlinsteps); - DOUBLES_EQUAL(r.preeq_cpu_time, s.preeq_cpu_time, 1e-16); - - CHECK_TRUE(r.posteq_status == s.posteq_status); - CHECK_TRUE(r.posteq_t == s.posteq_t || - (std::isnan(r.posteq_t) && std::isnan(s.posteq_t))); - CHECK_TRUE(r.posteq_wrms == s.posteq_wrms || - (std::isnan(r.posteq_wrms) && std::isnan(s.posteq_wrms))); - CHECK_TRUE(r.posteq_numsteps == s.posteq_numsteps); - CHECK_TRUE(r.posteq_numlinsteps == s.posteq_numlinsteps); - DOUBLES_EQUAL(r.posteq_cpu_time, s.posteq_cpu_time, 1e-16); - - checkEqualArray(r.x0, s.x0, 1e-16, 1e-16, "x0"); - checkEqualArray(r.sx0, s.sx0, 1e-16, 1e-16, "sx0"); - - CHECK_TRUE(r.llh == s.llh || (std::isnan(r.llh) && std::isnan(s.llh))); - CHECK_TRUE(r.chi2 == s.chi2 || (std::isnan(r.llh) && std::isnan(s.llh))); - CHECK_EQUAL(r.status, s.status); - - checkEqualArray(r.sllh, s.sllh, 1e-5, 1e-5, "sllh"); - checkEqualArray(r.s2llh, s.s2llh, 1e-5, 1e-5, "s2llh"); -} - -// clang-format off -TEST_GROUP(dataSerialization){ - amici::CVodeSolver solver; - void setup() override { - // set non-default values for all members - solver.setAbsoluteTolerance(1e-4); - solver.setRelativeTolerance(1e-5); - solver.setAbsoluteToleranceQuadratures(1e-6); - solver.setRelativeToleranceQuadratures(1e-7); - solver.setAbsoluteToleranceSteadyState(1e-8); - solver.setRelativeToleranceSteadyState(1e-9); - solver.setSensitivityMethod(amici::SensitivityMethod::adjoint); - solver.setSensitivityOrder(amici::SensitivityOrder::second); - solver.setMaxSteps(1e1); - solver.setMaxStepsBackwardProblem(1e2); - solver.setNewtonMaxSteps(1e3); - solver.setNewtonMaxLinearSteps(1e4); - solver.setPreequilibration(true); - solver.setStateOrdering(static_cast(amici::SUNLinSolKLU::StateOrdering::COLAMD)); - solver.setInterpolationType(amici::InterpolationType::polynomial); - solver.setStabilityLimitFlag(false); - solver.setLinearSolver(amici::LinearSolver::dense); - solver.setLinearMultistepMethod(amici::LinearMultistepMethod::adams); - solver.setNonlinearSolverIteration(amici::NonlinearSolverIteration::newton); - solver.setInternalSensitivityMethod(amici::InternalSensitivityMethod::staggered); - solver.setReturnDataReportingMode(amici::RDataReporting::likelihood); - } -}; -// clang-format on - -TEST(dataSerialization, testFile) -{ - int np = 1; - int nk = 2; - int nx = 3; - int ny = 4; - int nz = 5; - int ne = 6; - amici::CVodeSolver solver; - amici::Model_Test m = amici::Model_Test( - amici::ModelDimensions( - nx, // nx_rdata - nx, // nxtrue_rdata - nx, // nx_solver - nx, // nxtrue_solver - 0, // nx_solver_reinit - np, // np - nk, // nk - ny, // ny - ny, // nytrue - nz, // nz - nz, // nztrue - ne, // ne - 0, // nJ - 9, // nw - 2, // ndwdx - 2, // ndwdp - 2, // dwdw - 13, // ndxdotdw - {}, // ndJydy - 15, // nnz - 16, // ubw - 17 // lbw - ), - amici::SimulationParameters( - std::vector(nk, 0.0), - std::vector(np, 0.0), - std::vector(np, 0) - ), - amici::SecondOrderMode::none, - std::vector(nx, 0.0), - std::vector(nz, 0)); - - { - std::ofstream ofs("sstore.dat"); - boost::archive::text_oarchive oar(ofs); - // oar & static_cast(solver); - oar& static_cast(m); - } - { - std::ifstream ifs("sstore.dat"); - boost::archive::text_iarchive iar(ifs); - amici::CVodeSolver v; - amici::Model_Test n; - // iar &static_cast(v); - iar& static_cast(n); - // CHECK_TRUE(solver == v); - CHECK_TRUE(m == n); - } -} - -TEST(dataSerialization, testString) -{ - int np = 1; - int nk = 2; - int nx = 3; - int ny = 4; - int nz = 5; - int ne = 6; - amici::CVodeSolver solver; - amici::Model_Test m = amici::Model_Test( - amici::ModelDimensions( - nx, // nx_rdata - nx, // nxtrue_rdata - nx, // nx_solver - nx, // nxtrue_solver - 0, // nx_solver_reinit - np, // np - nk, // nk - ny, // ny - ny, // nytrue - nz, // nz - nz, // nztrue - ne, // ne - 0, // nJ - 9, // nw - 10, // ndwdx - 2, // ndwdp - 12, // dwdw - 13, // ndxdotdw - {}, // ndJydy - 15, // nnz - 16, // ubw - 17 // lbw - ), - amici::SimulationParameters( - std::vector(nk, 0.0), - std::vector(np, 0.0), - std::vector(np, 0) - ), - amici::SecondOrderMode::none, - std::vector(nx, 0.0), - std::vector(nz, 0)); - - amici::ReturnData r(solver, m); - - std::string serialized = amici::serializeToString(r); - - checkReturnDataEqual( - r, amici::deserializeFromString(serialized)); -} - -TEST(dataSerialization, testChar) -{ - int length; - char* buf = amici::serializeToChar(solver, &length); - - amici::CVodeSolver v = - amici::deserializeFromChar(buf, length); - - delete[] buf; - CHECK_TRUE(solver == v); -} - -TEST(dataSerialization, testStdVec) -{ - - auto buf = amici::serializeToStdVec(solver); - amici::CVodeSolver v = - amici::deserializeFromChar(buf.data(), buf.size()); - - CHECK_TRUE(solver == v); -} diff --git a/tests/generateTestConfigurationForExamples.sh b/tests/generateTestConfigurationForExamples.sh index 578228ee31..e54f6f5ecc 100755 --- a/tests/generateTestConfigurationForExamples.sh +++ b/tests/generateTestConfigurationForExamples.sh @@ -1,22 +1,24 @@ #!/bin/bash # Generate AMICI configuration for test models +set -eou pipefail + # AMICI root directory -AMICI_PATH="`dirname \"$BASH_SOURCE\"`" -AMICI_PATH="`( cd \"$AMICI_PATH/..\" && pwd )`" +AMICI_PATH=$(dirname "$BASH_SOURCE") +AMICI_PATH=$( cd "$AMICI_PATH/.." && pwd ) # File with test configuration -TEST_FILE="${AMICI_PATH}/tests/cpputest/testOptions.h5" +TEST_FILE="${AMICI_PATH}/tests/cpp/testOptions.h5" # Delete old config -rm ${TEST_FILE} +rm "${TEST_FILE}" -cd ${AMICI_PATH}/tests/generateTestConfig -./example_dirac.py ${TEST_FILE} -./example_events.py ${TEST_FILE} -./example_jakstat.py ${TEST_FILE} -./example_nested_events.py ${TEST_FILE} -./example_neuron.py ${TEST_FILE} -./example_robertson.py ${TEST_FILE} -./example_steadystate.py ${TEST_FILE} -./example_calvetti.py ${TEST_FILE} +cd "${AMICI_PATH}/tests/generateTestConfig" +./example_dirac.py "${TEST_FILE}" +./example_events.py "${TEST_FILE}" +./example_jakstat.py "${TEST_FILE}" +./example_nested_events.py "${TEST_FILE}" +./example_neuron.py "${TEST_FILE}" +./example_robertson.py "${TEST_FILE}" +./example_steadystate.py "${TEST_FILE}" +./example_calvetti.py "${TEST_FILE}"