diff --git a/.github/actions/linux-build/action.yml b/.github/actions/linux-build/action.yml index 344b9a45ff..01326592b2 100644 --- a/.github/actions/linux-build/action.yml +++ b/.github/actions/linux-build/action.yml @@ -39,16 +39,15 @@ runs: run: | sudo apt-get -qq update sudo apt-get -qq -y install lcov ccache + sudo apt-get -qq -y install gfortran-9 if [[ "${{ inputs.optional-dependencies }}" == "ON" ]]; then sudo apt-get -qq -y install libhdf5-dev fi if [[ "${{ inputs.compiler }}" == "gcc" ]]; then if [[ "${{ inputs.version }}" == "min" ]]; then - sudo apt-get -qq -y install gcc-9 - sudo apt-get -qq -y install g++-9 + sudo apt-get -qq -y install gcc-9 g++-9 else - sudo apt-get -qq -y install gcc-11 - sudo apt-get -qq -y install g++-11 + sudo apt-get -qq -y install gcc-11 g++-11 fi elif [[ "${{ inputs.compiler }}" == "clang" ]]; then if [[ "${{ inputs.version }}" == "min" ]]; then @@ -76,6 +75,7 @@ runs: shell: bash run: | cd cpp + export FC=/usr/bin/gfortran-9 if [[ "${{ inputs.compiler }}" == "gcc" ]]; then if [[ "${{ inputs.version }}" == "min" ]]; then export CC=/usr/bin/gcc-9 @@ -97,7 +97,7 @@ runs: exit 1 fi mkdir -p build && cd build - cmake -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=${{ inputs.config }} -DMEMILIO_ENABLE_IPOPT=ON -DMEMILIO_TEST_COVERAGE=${{ inputs.coverage }} -DMEMILIO_SANITIZE_ADDRESS=${{ inputs.sanitizers }} -DMEMILIO_SANITIZE_UNDEFINED=${{ inputs.sanitizers }} -DMEMILIO_USE_BUNDLED_JSONCPP=${{ inputs.optional-dependencies }} -DMEMILIO_ENABLE_OPENMP=${{ inputs.openmp }} .. + cmake -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_Fortran_COMPILER=/usr/bin/gfortran-9 -DCMAKE_BUILD_TYPE=${{ inputs.config }} -DMEMILIO_ENABLE_IPOPT=ON -DMEMILIO_TEST_COVERAGE=${{ inputs.coverage }} -DMEMILIO_SANITIZE_ADDRESS=${{ inputs.sanitizers }} -DMEMILIO_SANITIZE_UNDEFINED=${{ inputs.sanitizers }} -DMEMILIO_USE_BUNDLED_JSONCPP=${{ inputs.optional-dependencies }} -DMEMILIO_ENABLE_OPENMP=${{ inputs.openmp }} .. make -j4 - name: create build dir archive shell: bash diff --git a/.github/actions/windows-build/action.yml b/.github/actions/windows-build/action.yml index 84ae042567..1b60b028e4 100644 --- a/.github/actions/windows-build/action.yml +++ b/.github/actions/windows-build/action.yml @@ -48,7 +48,7 @@ runs: call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64 ) cmake --version - cmake -G "Ninja" -DCMAKE_BUILD_TYPE=${{ inputs.config }} -DMEMILIO_USE_BUNDLED_JSONCPP=${{ inputs.optional-dependencies }} -DHDF5_USE_STATIC_LIBRARIES=ON -DHDF5_DIR="${{github.workspace}}/hdf5/share/cmake/hdf5" .. + cmake -G "Ninja" -DCMAKE_BUILD_TYPE=${{ inputs.config }} -DMEMILIO_ENABLE_IPOPT=OFF -DMEMILIO_USE_BUNDLED_JSONCPP=${{ inputs.optional-dependencies }} -DHDF5_USE_STATIC_LIBRARIES=ON -DHDF5_DIR="${{github.workspace}}/hdf5/share/cmake/hdf5" .. cmake --build . -- -j 4 - name: Upload built binary files uses: actions/upload-artifact@v4 diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 45a3d67773..fdf8774a66 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,219 +1,549 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.24) + +project(memilio + VERSION 2.0.0 + DESCRIPTION "A library for the simulations of infectious dynamics." + HOMEPAGE_URL "https://github.com/SciCompMod/memilio" + LANGUAGES CXX) + +#------------------------------------------------------- +# System requirements and compatibility +#------------------------------------------------------- +# Define minimum supported compiler versions +set(MEMILIO_MIN_GCC_VERSION "9.0") +set(MEMILIO_MIN_CLANG_VERSION "6.0") +set(MEMILIO_MIN_MSVC_VERSION "19.20") + +# Set default build type to Release if not specified +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the build type: Debug, Release, RelWithDebInfo, MinSizeRel" FORCE) + message(STATUS "No build type specified. Setting to Release.") +endif() -project(memilio VERSION 1.0.0) +# Set C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +#------------------------------------------------------- +# Build options +#------------------------------------------------------- +# Library options +option(MEMILIO_ENABLE_INSTALL "Enable installation of memilio" OFF) +option(MEMILIO_BUILD_SHARED_LIBS "Build memilio as a shared library (faster compilation, useful for development)" OFF) +if(MEMILIO_BUILD_SHARED_LIBS AND MSVC) + message(WARNING "Building shared libs is not supported on Windows. Building static libs instead.") + set(MEMILIO_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) +endif() +set(BUILD_SHARED_LIBS ${MEMILIO_BUILD_SHARED_LIBS}) +# Component options option(MEMILIO_BUILD_TESTS "Build memilio unit tests." ON) option(MEMILIO_BUILD_EXAMPLES "Build memilio examples." ON) option(MEMILIO_BUILD_MODELS "Build memilio models." ON) -option(MEMILIO_BUILD_SIMULATIONS "Build memilio simulations that were used for scientific articles." ON) -option(MEMILIO_BUILD_BENCHMARKS "Build memilio benchmarks with google benchmark." OFF) -option(MEMILIO_USE_BUNDLED_SPDLOG "Use spdlog bundled with epi" ON) -option(MEMILIO_USE_BUNDLED_EIGEN "Use eigen bundled with epi" ON) -option(MEMILIO_USE_BUNDLED_BOOST "Use boost bundled with epi (only for epi-io)" ON) -option(MEMILIO_USE_BUNDLED_JSONCPP "Use jsoncpp bundled with epi (only for epi-io)" ON) -option(MEMILIO_SANITIZE_ADDRESS "Enable address sanitizer." OFF) -option(MEMILIO_SANITIZE_UNDEFINED "Enable undefined behavior sanitizer." OFF) -option(MEMILIO_BUILD_SHARED_LIBS "Build memilio as a shared library." ON) -option(MEMILIO_BUILD_STATIC_LIBS "Build memilio as a static library." ON) +option(MEMILIO_BUILD_BENCHMARKS "Build memilio benchmarks with google benchmark." ON) + +# Third-party dependency options +option(MEMILIO_USE_BUNDLED_EIGEN "Use eigen bundled with memilio" ON) +option(MEMILIO_USE_BUNDLED_BOOST "Use boost bundled with memilio (only for memilio-io)" ON) +option(MEMILIO_USE_BUNDLED_JSONCPP "Use jsoncpp bundled with memilio (only for memilio-io)" ON) +option(MEMILIO_USE_BUNDLED_SPDLOG "Use spdlog bundled with memilio" ON) + +# Performance and debugging options option(MEMILIO_ENABLE_MPI "Build memilio with MPI." OFF) option(MEMILIO_ENABLE_OPENMP "Enable Multithreading with OpenMP." OFF) -option(MEMILIO_ENABLE_WARNINGS "Build memilio with warnings." ON) -option(MEMILIO_ENABLE_WARNINGS_AS_ERRORS "Build memilio with warnings as errors." ON) option(MEMILIO_ENABLE_IPOPT "Enable numerical optimization with Ipopt, requires a Fortran compiler" OFF) -option(MEMILIO_ENABLE_PROFILING "Enable runtime performance profiling of memilio" OFF) +option(MEMILIO_ENABLE_PROFILING "Enable runtime performance profiling of memilio" OFF) +option(MEMILIO_SANITIZE_ADDRESS "Enable address sanitizer (Debug builds only)." OFF) +option(MEMILIO_SANITIZE_UNDEFINED "Enable undefined behavior sanitizer (Debug builds only)." OFF) +option(MEMILIO_TEST_COVERAGE "Enable GCov coverage analysis (adds a 'coverage' target)" OFF) -mark_as_advanced(MEMILIO_USE_BUNDLED_SPDLOG MEMILIO_SANITIZE_ADDRESS MEMILIO_SANITIZE_UNDEFINED) +# Build quality options +option(MEMILIO_ENABLE_WARNINGS "Build memilio with warnings." ON) +option(MEMILIO_ENABLE_WARNINGS_AS_ERRORS "Build memilio with warnings as errors." ON) -# try to treat AppleClang as Clang, but warn about missing support -if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - message(WARNING "The compiler ID \"AppleClang\" is not supported, trying to compile with \"Clang\" options.") - set(CMAKE_CXX_COMPILER_ID "Clang") +mark_as_advanced( + # Hide advanced build options + MEMILIO_SANITIZE_ADDRESS + MEMILIO_SANITIZE_UNDEFINED + MEMILIO_TEST_COVERAGE + MEMILIO_ENABLE_PROFILING + MEMILIO_USE_BUNDLED_EIGEN + MEMILIO_USE_BUNDLED_BOOST + MEMILIO_USE_BUNDLED_JSONCPP + MEMILIO_USE_BUNDLED_SPDLOG + MEMILIO_ENABLE_IPOPT + MEMILIO_ENABLE_INSTALL +) +file(TO_CMAKE_PATH "${PROJECT_SOURCE_DIR}/.." MEMILIO_BASE_DIR) +#------------------------------------------------------- +# Helper functions +#------------------------------------------------------- + +# Function to check compiler version against minimum +function(check_compiler_version COMPILER_ID CURRENT_VERSION MIN_VERSION) + if(CMAKE_CXX_COMPILER_ID STREQUAL ${COMPILER_ID} AND + CURRENT_VERSION VERSION_LESS ${MIN_VERSION}) + message(WARNING "${COMPILER_ID} version ${CURRENT_VERSION} is below the recommended version ${MIN_VERSION}. Some features may not work correctly.") + endif() +endfunction() + +# Function to add a component conditionally +function(add_memilio_component COMPONENT_TYPE) + string(TOUPPER ${COMPONENT_TYPE} COMPONENT_TYPE_UPPER) + if(MEMILIO_BUILD_${COMPONENT_TYPE_UPPER}) + message(STATUS "Building memilio ${COMPONENT_TYPE}") + add_subdirectory(${COMPONENT_TYPE}) + endif() +endfunction() + +# Function to install header directories +function(install_headers DIR) + install( + DIRECTORY ${DIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING + PATTERN "*.h" + PATTERN "*.hpp" + ) +endfunction() + +# Function to print a configuration item with consistent formatting +function(print_config_item ITEM_NAME ITEM_VALUE) + string(LENGTH "${ITEM_NAME}" NAME_LEN) + set(PADDING_LEN 25) + math(EXPR SPACES_NEEDED "${PADDING_LEN} - ${NAME_LEN}") + string(REPEAT " " ${SPACES_NEEDED} PADDING_SPACES) + if(SPACES_NEEDED LESS 0) + set(PADDING_SPACES "") + endif() + message(STATUS " ${ITEM_NAME}:${PADDING_SPACES} ${ITEM_VALUE}") +endfunction() + +#------------------------------------------------------- +# Check for required dependencies +#------------------------------------------------------- +if(MEMILIO_ENABLE_MPI) + find_package(MPI QUIET) + if(NOT MPI_FOUND) + message(FATAL_ERROR "MPI not found. MEMILIO_ENABLE_MPI will be disabled.") + set(MEMILIO_ENABLE_MPI OFF CACHE BOOL "Disabled because MPI was not found" FORCE) + return() + endif() + message(STATUS "MPI found: ${MPI_VERSION}") endif() -set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Please choose Release or Debug. Default is Release." FORCE) +message(STATUS "MEMILIO_ENABLE_IPOPT is: ${MEMILIO_ENABLE_IPOPT}") +if(MEMILIO_ENABLE_IPOPT) + enable_language(Fortran) + message(STATUS "Ipopt enabled, ensuring Fortran language support is enabled.") endif() -if(MEMILIO_BUILD_SHARED_LIBS) - set(BUILD_SHARED_LIBS ON) +if(MEMILIO_ENABLE_OPENMP) + find_package(OpenMP QUIET) # Find quietly first + if(OpenMP_CXX_FOUND) + message(STATUS "OpenMP found via find_package.") + set(MEMILIO_OPENMP_FOUND TRUE) + elseif(APPLE) + message(STATUS "OpenMP not found by find_package, attempting macOS Homebrew workaround...") + # (Homebrew lookup logic remains the same) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64" OR APPLE_SILICON) + set(HOMEBREW_PREFIX "/opt/homebrew") + else() + set(HOMEBREW_PREFIX "/usr/local") + endif() + if(EXISTS "${HOMEBREW_PREFIX}/opt/libomp/lib/cmake/libomp") + list(APPEND CMAKE_PREFIX_PATH "${HOMEBREW_PREFIX}/opt/libomp") + find_package(OpenMP QUIET) # Try finding again with the hint + if (OpenMP_CXX_FOUND) + message(STATUS "Found OpenMP via Homebrew libomp CMake package.") + set(MEMILIO_OPENMP_FOUND TRUE) + endif() + endif() + # Manual target creation fallback if CMake package didn't work/exist + if (NOT MEMILIO_OPENMP_FOUND AND + EXISTS "${HOMEBREW_PREFIX}/opt/libomp/include" AND + EXISTS "${HOMEBREW_PREFIX}/opt/libomp/lib/libomp.dylib") + message(STATUS "Found Homebrew libomp files, attempting manual target setup for OpenMP.") + # Ensure target doesn't exist before creating + if(NOT TARGET OpenMP::OpenMP_CXX) + add_library(OpenMP::OpenMP_CXX INTERFACE IMPORTED) + set_target_properties(OpenMP::OpenMP_CXX PROPERTIES + INTERFACE_COMPILE_OPTIONS "-Xpreprocessor -fopenmp" # Clang flag + INTERFACE_INCLUDE_DIRECTORIES "${HOMEBREW_PREFIX}/opt/libomp/include" + INTERFACE_LINK_LIBRARIES "${HOMEBREW_PREFIX}/opt/libomp/lib/libomp.dylib") + endif() + set(MEMILIO_OPENMP_FOUND TRUE) # Mark as found via manual setup + endif() + endif() - if(MSVC) - # Current workaround for windows to not build shared libs as we neeed to plugin export variables - # TODO: add expoerts for windows files - message(WARNING "Building shared libs is not supported on windows. Building static libs instead.") - set(BUILD_SHARED_LIBS OFF) - set(BUILD_STATIC_LIBS ON) + # Final check and disable if not found + if(NOT MEMILIO_OPENMP_FOUND) + message(WARNING "OpenMP not found or configured. Install OpenMP (e.g., 'brew install libomp' on macOS) or disable MEMILIO_ENABLE_OPENMP.") + set(MEMILIO_ENABLE_OPENMP OFF CACHE BOOL "Disabled because OpenMP was not found/configured" FORCE) endif() -else() - set(BUILD_SHARED_LIBS OFF) endif() -if(MEMILIO_BUILD_STATIC_LIBS) - set(BUILD_STATIC_LIBS ON) +#------------------------------------------------------- +# Compiler detection and platform-specific settings +#------------------------------------------------------- +# Detect compiler and set appropriate flags +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + message(STATUS "Detected MSVC compiler (${CMAKE_CXX_COMPILER_VERSION})") + set(USING_MSVC TRUE) + check_compiler_version("MSVC" ${CMAKE_CXX_COMPILER_VERSION} ${MEMILIO_MIN_MSVC_VERSION}) + add_compile_options(/bigobj) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + message(STATUS "Detected GNU compiler (${CMAKE_CXX_COMPILER_VERSION})") + set(USING_GNU TRUE) + check_compiler_version("GNU" ${CMAKE_CXX_COMPILER_VERSION} ${MEMILIO_MIN_GCC_VERSION}) + +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + message(STATUS "Detected AppleClang compiler (${CMAKE_CXX_COMPILER_VERSION} - not officially supported") + set(USING_CLANG_COMPATIBLE TRUE) + set(USING_APPLECLANG TRUE) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64") + message(STATUS "Detected Apple Silicon (ARM64) architecture") + set(APPLE_SILICON TRUE) + set(APPLE_SILICON_FLAGS "-march=native") + endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + message(STATUS "Detected Clang compiler (${CMAKE_CXX_COMPILER_VERSION})") + set(USING_CLANG_COMPATIBLE TRUE) + check_compiler_version("Clang" ${CMAKE_CXX_COMPILER_VERSION} ${MEMILIO_MIN_CLANG_VERSION}) else() - set(BUILD_STATIC_LIBS OFF) + message(WARNING "Unsupported compiler: ${CMAKE_CXX_COMPILER_ID}. Build may not work correctly.") endif() -# Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24 and above -if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") - cmake_policy(SET CMP0135 NEW) +# Set platform-specific settings +if(APPLE) + set(CMAKE_MACOSX_RPATH ON) +endif() +if(APPLE_SILICON) + add_compile_options(${APPLE_SILICON_FLAGS}) + message(STATUS "Applied Apple Silicon optimization flags: ${APPLE_SILICON_FLAGS}") endif() -include(GNUInstallDirs) # set to gnu folders. No cache variable so this is not global +#------------------------------------------------------- +# Basic build system configuration +#------------------------------------------------------- +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +include(GNUInstallDirs) # Provides standard installation directories set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") -set(CMAKE_INSTALL_RPATH "${CMAKE_BINARY_DIR}/lib" "${CMAKE_BINARY_DIR}/bin") - -# code coverage analysis -# Note: this only works under linux and with make -# Ninja creates different directory names which do not work together with this scrupt -# as STREQUAL is case-sensitive https://github.com/TriBITSPub/TriBITS/issues/131, also allow DEBUG as accepted input -if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") - option(MEMILIO_TEST_COVERAGE "Enable GCov coverage analysis (adds a 'coverage' target)" OFF) - mark_as_advanced(MEMILIO_TEST_COVERAGE) - - if(MEMILIO_TEST_COVERAGE) - message(STATUS "Coverage enabled") - include(CodeCoverage) - append_coverage_compiler_flags() - - # In addition to standard flags, disable elision and inlining to prevent e.g. closing brackets being marked as - # uncovered. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-elide-constructors -fno-default-inline") - setup_target_for_coverage_lcov( - NAME coverage - EXECUTABLE memilio-test - EXCLUDE "${CMAKE_SOURCE_DIR}/tests*" "${CMAKE_SOURCE_DIR}/simulations*" "${CMAKE_SOURCE_DIR}/examples*" - "${CMAKE_SOURCE_DIR}/memilio/ad*" "${CMAKE_BINARY_DIR}/*" "/usr*" "${CMAKE_SOURCE_DIR}/*.F" +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") + +# Generate version header +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/memilio/version.h +) + +#------------------------------------------------------- +# Code coverage configuration +#------------------------------------------------------- +set(MEMILIO_COVERAGE_FLAGS "") +if((CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") AND MEMILIO_TEST_COVERAGE) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + message(STATUS "Coverage enabled (GCC/Clang Debug build)") + include(CodeCoverage) + + # Define flags for coverage generation and better reporting + set(MEMILIO_COVERAGE_FLAGS "--coverage;-fno-elide-constructors;-fno-default-inline;-fno-inline") + + # Define standard exclusions for coverage reports (used by setup_target_for_coverage_lcov) + set(COVERAGE_EXCLUDES + "${CMAKE_SOURCE_DIR}/tests*" + "${CMAKE_SOURCE_DIR}/simulations*" + "${CMAKE_SOURCE_DIR}/examples*" + "${CMAKE_SOURCE_DIR}/memilio/ad*" + "${CMAKE_BINARY_DIR}/*" + "/usr*" + "${CMAKE_SOURCE_DIR}/*.F" # Assuming Fortran files if any + "${CMAKE_SOURCE_DIR}/thirdparty/*" # Exclude fetched sources + "${PROJECT_BINARY_DIR}/*" # Exclude build artifacts more broadly ) + + set(MEMILIO_COVERAGE_SETUP_NEEDED TRUE) + + if(CMAKE_GENERATOR MATCHES "Ninja") + message(WARNING "Using Ninja generator with code coverage may affect results.") + endif() + else() + message(WARNING "Coverage requested but not supported for compiler ${CMAKE_CXX_COMPILER_ID} in this script. Disabling.") + set(MEMILIO_TEST_COVERAGE OFF CACHE BOOL "Disabled: Compiler not supported" FORCE) endif() endif() -# set sanitizer compiler flags -if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7)) +# Function to apply coverage flags (call this in tests/CMakeLists.txt) +function(memilio_set_coverage_flags target_name) + if(MEMILIO_TEST_COVERAGE AND MEMILIO_COVERAGE_FLAGS) + # Apply flags using generator expression for Debug config only + target_compile_options(${target_name} PRIVATE $<$:${MEMILIO_COVERAGE_FLAGS}>) + target_link_options(${target_name} PRIVATE $<$:--coverage>) # Linker flag often needed too + endif() +endfunction() + +#------------------------------------------------------- +# Sanitizer configuration +#------------------------------------------------------- +set(MEMILIO_SANITIZER_COMPILE_FLAGS "") +set(MEMILIO_SANITIZER_LINK_FLAGS "") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" OR USING_CLANG_COMPATIBLE) # Check using refined variables + set(SANITIZERS_ENABLED FALSE) if(MEMILIO_SANITIZE_ADDRESS) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fsanitize=address") - string(APPEND CMAKE_LINKER_FLAGS_DEBUG " -fsanitize=address") - endif(MEMILIO_SANITIZE_ADDRESS) - + list(APPEND MEMILIO_SANITIZER_COMPILE_FLAGS "-fsanitize=address") + list(APPEND MEMILIO_SANITIZER_LINK_FLAGS "-fsanitize=address") + set(SANITIZERS_ENABLED TRUE) + endif() if(MEMILIO_SANITIZE_UNDEFINED) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fsanitize=undefined") - string(APPEND CMAKE_LINKER_FLAGS_DEBUG " -fsanitize=undefined") - endif(MEMILIO_SANITIZE_UNDEFINED) + list(APPEND MEMILIO_SANITIZER_COMPILE_FLAGS "-fsanitize=undefined") + list(APPEND MEMILIO_SANITIZER_LINK_FLAGS "-fsanitize=undefined") + set(SANITIZERS_ENABLED TRUE) + endif() + if(SANITIZERS_ENABLED) + list(APPEND MEMILIO_SANITIZER_COMPILE_FLAGS "-fno-omit-frame-pointer") + # Linker flags already have the sanitizer flags + message(STATUS "Sanitizers enabled for Debug builds: ${MEMILIO_SANITIZER_COMPILE_FLAGS}") + endif() +else() if(MEMILIO_SANITIZE_ADDRESS OR MEMILIO_SANITIZE_UNDEFINED) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit-frame-pointer") - string(APPEND CMAKE_LINKER_FLAGS_DEBUG " -fno-omit-frame-pointer") - endif(MEMILIO_SANITIZE_ADDRESS OR MEMILIO_SANITIZE_UNDEFINED) -endif((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7)) - -# define flags to enable most warnings and treat them as errors for different compilers -# add flags to each target separately instead of globally so users have the choice to use their own flags -if(MEMILIO_ENABLE_WARNINGS) - if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - string(APPEND MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS - "/W4;") - else() - string(APPEND MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS - "-Wall;-Wextra;-Wshadow;--pedantic;") + message(WARNING "Sanitizers requested but not supported for compiler ${CMAKE_CXX_COMPILER_ID}.") endif() endif() -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - string(APPEND MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS - "-Wno-unknown-warning;-Wno-pragmas;-Wno-deprecated-copy;-Wno-expansion-to-defined;") -elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - string(APPEND MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS - "-Wno-unknown-warning-option;-Wno-deprecated;-Wno-gnu-zero-variadic-macro-arguments;") -endif() +# Function to apply sanitizer flags (call this after defining targets) +function(memilio_set_sanitizer_flags target_name) + if(MEMILIO_SANITIZER_COMPILE_FLAGS) + # Apply flags using generator expression for Debug config only + target_compile_options(${target_name} PRIVATE $<$:${MEMILIO_SANITIZER_COMPILE_FLAGS}>) + target_link_options(${target_name} PRIVATE $<$:${MEMILIO_SANITIZER_LINK_FLAGS}>) + endif() +endfunction() + -if(MEMILIO_ENABLE_WARNINGS_AS_ERRORS) + + +#------------------------------------------------------- +# Warning and compiler flags configuration +#------------------------------------------------------- +# Define flags to enable most warnings and treat them as errors for different compilers. +# Initialize variables for different warning configurations +set(MEMILIO_CXX_FLAGS_ENABLE_WARNINGS "") +set(MEMILIO_CXX_FLAGS_DISABLE_WARNINGS "") +set(MEMILIO_CXX_FLAGS_WARNINGS_AS_ERRORS "") + +# Set compiler-specific warning flags +if(MEMILIO_ENABLE_WARNINGS) if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - string(APPEND MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS - "/WX") + # MSVC warning flags + set(MEMILIO_CXX_FLAGS_ENABLE_WARNINGS "/W4;") else() - string(APPEND MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS - "-Werror") + # GCC/Clang common warning flags + set(MEMILIO_CXX_FLAGS_ENABLE_WARNINGS + "-Wall" + "-Wextra" + "-Wshadow" + "--pedantic" + ) + + # Compiler-specific warning suppressions + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + # GCC-specific suppressions + list(APPEND MEMILIO_CXX_FLAGS_DISABLE_WARNINGS + "-Wno-unknown-warning" + "-Wno-pragmas" + "-Wno-deprecated-copy" + "-Wno-expansion-to-defined" + ) + elseif(USING_CLANG_COMPATIBLE) + # Clang/AppleClang suppressions + list(APPEND MEMILIO_CXX_FLAGS_DISABLE_WARNINGS + "-Wno-unknown-warning-option" + "-Wno-deprecated" + "-Wno-gnu-zero-variadic-macro-arguments" + ) + endif() + endif() + + # Set warnings-as-errors flags if enabled + if(MEMILIO_ENABLE_WARNINGS_AS_ERRORS) + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + set(MEMILIO_CXX_FLAGS_WARNINGS_AS_ERRORS "/WX") + else() + set(MEMILIO_CXX_FLAGS_WARNINGS_AS_ERRORS "-Werror") + endif() endif() endif() -# add parts of the project -include(thirdparty/CMakeLists.txt) -add_subdirectory(memilio/ad) -add_subdirectory(memilio) +# Combine all warning flags into one list +set(MEMILIO_CXX_WARNING_FLAGS + ${MEMILIO_CXX_FLAGS_ENABLE_WARNINGS} + ${MEMILIO_CXX_FLAGS_DISABLE_WARNINGS} + ${MEMILIO_CXX_FLAGS_WARNINGS_AS_ERRORS} +) -if(MEMILIO_BUILD_MODELS) - add_subdirectory(models/abm) - add_subdirectory(models/d_abm) - add_subdirectory(models/ode_secir) - add_subdirectory(models/ode_secirts) - add_subdirectory(models/ode_secirvvs) - add_subdirectory(models/lct_secir) - add_subdirectory(models/glct_secir) - add_subdirectory(models/ide_secir) - add_subdirectory(models/ide_seir) - add_subdirectory(models/ode_seir) - add_subdirectory(models/ode_seair) - add_subdirectory(models/ode_sir) - add_subdirectory(models/sde_sir) - add_subdirectory(models/sde_sirs) - add_subdirectory(models/sde_seirvv) - add_subdirectory(models/graph_abm) - add_subdirectory(models/smm) -endif() +# Define a function to apply warning flags to targets +function(memilio_set_warning_flags target_name) + if(MEMILIO_ENABLE_WARNINGS) + target_compile_options(${target_name} PRIVATE ${MEMILIO_CXX_WARNING_FLAGS}) + endif() +endfunction() -if(MEMILIO_BUILD_EXAMPLES) - add_subdirectory(examples) -endif() -if(MEMILIO_BUILD_TESTS) - add_subdirectory(tests) -endif() -if(MEMILIO_BUILD_SIMULATIONS) - add_subdirectory(simulations) -endif() +#------------------------------------------------------- +# Add project components +#------------------------------------------------------- +# First add third-party dependencies +include(FetchContent) +include(thirdparty/CMakeLists.txt) + +# Core library +add_subdirectory(memilio) -if(MEMILIO_BUILD_BENCHMARKS) - add_subdirectory(benchmarks) +# Conditional components based on build options +if(MEMILIO_BUILD_MODELS) + message(STATUS "Building memilio models") + add_subdirectory(models) endif() -install(TARGETS memilio - EXPORT memilio-targets - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) +# Use the component function for other directories +add_memilio_component(examples) +add_memilio_component(tests) +add_memilio_component(simulations) +add_memilio_component(benchmarks) -install(DIRECTORY memilio DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN memilio/*/*.h) -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/memilio DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN memilio/*/*.h) +#------------------------------------------------------- +# Package configuration +#------------------------------------------------------- include(CMakePackageConfigHelpers) +# Create package config files configure_package_config_file( ${CMAKE_CURRENT_LIST_DIR}/cmake/memilio-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/memilio-config.cmake - INSTALL_DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/memilio + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/memilio + PATH_VARS + CMAKE_INSTALL_LIBDIR + CMAKE_INSTALL_INCLUDEDIR ) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/memilio-config-version.cmake" VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion -) + COMPATIBILITY SameMinorVersion + ) + +#------------------------------------------------------- +# Installation configuration +#------------------------------------------------------- +# Check if installation is enabled +if(MEMILIO_ENABLE_INSTALL) + message(STATUS "Installation enabled.") + + # Set installation prefix if not set + if(NOT CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/install" CACHE PATH "Installation directory" FORCE) + message(STATUS "No installation prefix specified. Setting to ${CMAKE_INSTALL_PREFIX}.") + endif() -install( - FILES - "${CMAKE_CURRENT_BINARY_DIR}/memilio-config-version.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/memilio-config.cmake" - DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/memilio -) + # Set default install component to runtime + set(CMAKE_INSTALL_COMPONENT_DEFAULT "runtime") + + install(TARGETS memilio + # EXPORT memilio-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT development + ) + + # Install header files using the helper function + install_headers(memilio) + install_headers(${CMAKE_CURRENT_BINARY_DIR}/include) + + # Export targets for use in client projects + install( + EXPORT memilio-targets + FILE memilio-targets.cmake + NAMESPACE memilio:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/memilio + COMPONENT Development + ) + + # Install CMake config files + install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/memilio-config-version.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/memilio-config.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/memilio + ) +endif() + + +#------------------------------------------------------- +# Configuration summary +#------------------------------------------------------- +message(STATUS "") +message(STATUS "-------------------- Memilio Configuration Summary --------------------") +print_config_item("Version" "${PROJECT_VERSION}") +print_config_item("Build type" "${CMAKE_BUILD_TYPE}") +print_config_item("Generator" "${CMAKE_GENERATOR}") +print_config_item("Installaion" "${MEMILIO_ENABLE_INSTALL} (Prefix: ${CMAKE_INSTALL_PREFIX})") + +message(STATUS "") +message(STATUS "-- Compiler Info --") +print_config_item("C++ Compiler ID" "${CMAKE_CXX_COMPILER_ID}") +print_config_item("C++ Compiler" "${CMAKE_CXX_COMPILER}") +print_config_item("C++ Version" "${CMAKE_CXX_COMPILER_VERSION}") +print_config_item("C++ Standard" "C++${CMAKE_CXX_STANDARD}") +if(MEMILIO_ENABLE_IPOPT AND CMAKE_Fortran_COMPILER) + print_config_item("Fortran Compiler ID" "${CMAKE_Fortran_COMPILER_ID}") + print_config_item("Fortran Compiler" "${CMAKE_Fortran_COMPILER}") + print_config_item("Fortran Version" "${CMAKE_Fortran_COMPILER_VERSION}") +endif() + +message(STATUS "") +message(STATUS "-- Components --") +print_config_item("Core Library" "ON") # Assuming memilio target exists +print_config_item("Models" "${MEMILIO_BUILD_MODELS}") +print_config_item("Examples" "${MEMILIO_BUILD_EXAMPLES}") +print_config_item("Tests" "${MEMILIO_BUILD_TESTS}") +print_config_item("Benchmarks" "${MEMILIO_BUILD_BENCHMARKS}") + +message(STATUS "") +message(STATUS "-- Dependencies & Features --") +# Check third-party library status using targets or MEMILIO_HAS_* variables +print_config_item("Eigen3" "${MEMILIO_HAS_EIGEN}") +print_config_item("spdlog" "${MEMILIO_HAS_SPDLOG}") +print_config_item("Boost" "${MEMILIO_HAS_EIGEN} ") +print_config_item("HDF5" "${MEMILIO_HAS_HDF5}") +print_config_item("JsonCpp" "${MEMILIO_HAS_JSONCPP}") +print_config_item("Ipopt" "${IPOPT_FOUND} (Enabled: ${MEMILIO_ENABLE_IPOPT})") +print_config_item("gperftools" "${GPERFTOOLS_FOUND} (Enabled: ${MEMILIO_ENABLE_PROFILING})") +print_config_item("OpenMP" "${MEMILIO_OPENMP_FOUND} (Enabled: ${MEMILIO_ENABLE_OPENMP})") +print_config_item("MPI" "${MPI_FOUND} (Enabled: ${MEMILIO_ENABLE_MPI})") + +message(STATUS "") +message(STATUS "-- Build Flags --") +print_config_item("Shared libs" "${MEMILIO_BUILD_SHARED_LIBS}") +print_config_item("Warnings" "${MEMILIO_ENABLE_WARNINGS} (As Errors: ${MEMILIO_ENABLE_WARNINGS_AS_ERRORS})") +set(SANITIZER_SUMMARY "OFF") +if(MEMILIO_SANITIZER_COMPILE_FLAGS) + set(SANITIZER_SUMMARY "ON (Debug Only)") +endif() +print_config_item("Sanitizers (ASan/UBSan)" "${SANITIZER_SUMMARY}") +set(COVERAGE_SUMMARY "OFF") +if(MEMILIO_TEST_COVERAGE) + set(COVERAGE_SUMMARY "ON (Debug Only, GCC/Clang)") +endif() +print_config_item("Coverage (gcov)" "${COVERAGE_SUMMARY}") +message(STATUS "======================================================================") \ No newline at end of file diff --git a/cpp/CMakePresets.json b/cpp/CMakePresets.json new file mode 100644 index 0000000000..13ad94c461 --- /dev/null +++ b/cpp/CMakePresets.json @@ -0,0 +1,228 @@ +{ + "version": 5, + "cmakeMinimumRequired": { + "major": 3, + "minor": 24, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base-config", + "hidden": true, + "description": "Base settings common to all configurations.", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}", + "CMAKE_CXX_STANDARD": "17", + "CMAKE_CXX_STANDARD_REQUIRED": "ON", + "CMAKE_CXX_EXTENSIONS": "OFF", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "MEMILIO_BUILD_TESTS": "ON", + "MEMILIO_BUILD_EXAMPLES": "ON", + "MEMILIO_BUILD_MODELS": "ON", + "MEMILIO_BUILD_BENCHMARKS": "ON", + "MEMILIO_USE_BUNDLED_EIGEN": "ON", + "MEMILIO_USE_BUNDLED_BOOST": "ON", + "MEMILIO_USE_BUNDLED_JSONCPP": "ON", + "MEMILIO_USE_BUNDLED_SPDLOG": "ON", + "MEMILIO_ENABLE_MPI": "OFF", + "MEMILIO_ENABLE_OPENMP": "OFF", + "MEMILIO_ENABLE_IPOPT": "OFF", + "MEMILIO_ENABLE_PROFILING": "OFF", + "MEMILIO_SANITIZE_ADDRESS": "OFF", + "MEMILIO_SANITIZE_UNDEFINED": "OFF", + "MEMILIO_TEST_COVERAGE": "OFF", + "MEMILIO_ENABLE_WARNINGS": "ON", + "MEMILIO_ENABLE_WARNINGS_AS_ERRORS": "ON", + "MEMILIO_BUILD_SHARED_LIBS": "OFF", + "MEMILIO_ENABLE_INSTALL": "OFF" + } + }, + { + "name": "unix-base", + "hidden": true, + "inherits": "base-config", + "description": "Base settings for Unix-like systems (Linux, macOS)", + "generator": "Ninja", + "condition": { + "type": "not", + "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" } + } + }, + { + "name": "windows-base", + "hidden": true, + "inherits": "base-config", + "description": "Base settings for Windows.", + "generator": "Visual Studio 17 2022", + "architecture": "x64", + "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" }, + "cacheVariables": { "MEMILIO_BUILD_SHARED_LIBS": "OFF" } + }, + { + "name": "system-libs-mixin", + "hidden": true, + "description": "Mixin to use system libraries instead of bundled ones.", + "cacheVariables": { + "MEMILIO_USE_BUNDLED_EIGEN": "OFF", + "MEMILIO_USE_BUNDLED_BOOST": "OFF", + "MEMILIO_USE_BUNDLED_JSONCPP": "OFF", + "MEMILIO_USE_BUNDLED_SPDLOG": "OFF" + } + }, + { + "name": "unix-debug", + "displayName": "Unix Debug (Ninja, Bundled Libs)", + "inherits": "unix-base", + "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } + }, + { + "name": "windows-debug", + "displayName": "Windows Debug (VS 2022, Bundled Libs)", + "inherits": "windows-base", + "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } + }, + { + "name": "unix-debug-system", + "displayName": "Unix Debug (Ninja, System Libs)", + "inherits": ["unix-debug", "system-libs-mixin"] + }, + { + "name": "windows-debug-system", + "displayName": "Windows Debug (VS 2022, System Libs)", + "inherits": ["windows-debug", "system-libs-mixin"] + }, + { + "name": "unix-release", + "displayName": "Unix Release (Ninja, Bundled Libs)", + "inherits": "unix-base", + "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } + }, + { + "name": "windows-release", + "displayName": "Windows Release (VS 2022, Bundled Libs)", + "inherits": "windows-base", + "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } + }, + { + "name": "unix-release-system", + "displayName": "Unix Release (Ninja, System Libs)", + "inherits": ["unix-release", "system-libs-mixin"] + }, + { + "name": "windows-release-system", + "displayName": "Windows Release (VS 2022, System Libs)", + "inherits": ["windows-release", "system-libs-mixin"] + }, + { + "name": "unix-relwithdebinfo", + "displayName": "Unix RelWithDebInfo (Ninja, Bundled Libs)", + "inherits": "unix-base", + "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } + }, + { + "name": "windows-relwithdebinfo", + "displayName": "Windows RelWithDebInfo (VS 2022, Bundled Libs)", + "inherits": "windows-base", + "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } + }, + { + "name": "unix-debug-asan", + "displayName": "Unix Debug + Address Sanitizer", + "inherits": "unix-debug", + "cacheVariables": { "MEMILIO_SANITIZE_ADDRESS": "ON" } + }, + { + "name": "unix-debug-ubsan", + "displayName": "Unix Debug + Undefined Behavior Sanitizer", + "inherits": "unix-debug", + "cacheVariables": { "MEMILIO_SANITIZE_UNDEFINED": "ON" } + }, + { + "name": "unix-debug-asan-ubsan", + "displayName": "Unix Debug + ASan + UBSan", + "inherits": "unix-debug", + "cacheVariables": { "MEMILIO_SANITIZE_ADDRESS": "ON", "MEMILIO_SANITIZE_UNDEFINED": "ON" } + }, + { + "name": "unix-debug-coverage", + "displayName": "Unix Debug + Code Coverage", + "inherits": "unix-debug", + "cacheVariables": { "MEMILIO_TEST_COVERAGE": "ON" } + }, + { + "name": "unix-release-openmp", + "displayName": "Unix Release + OpenMP", + "inherits": "unix-release", + "cacheVariables": { "MEMILIO_ENABLE_OPENMP": "ON" } + }, + { + "name": "unix-release-mpi", + "displayName": "Unix Release + MPI", + "inherits": "unix-release", + "cacheVariables": { "MEMILIO_ENABLE_MPI": "ON" } + }, + { + "name": "unix-release-ipopt", + "displayName": "Unix Release + Ipopt", + "inherits": "unix-release", + "cacheVariables": { "MEMILIO_ENABLE_IPOPT": "ON" } + }, + { + "name": "unix-release-profiling", + "displayName": "Unix Release + Profiling", + "inherits": "unix-release", + "cacheVariables": { "MEMILIO_ENABLE_PROFILING": "ON" } + }, + { + "name": "unix-release-install", + "displayName": "Unix Release + Install", + "inherits": "unix-release", + "cacheVariables": { "MEMILIO_ENABLE_INSTALL": "ON" } + }, + { + "name": "windows-release-install", + "displayName": "Windows Release + Install", + "inherits": "windows-release", + "cacheVariables": { "MEMILIO_ENABLE_INSTALL": "ON" } + } + ], + "buildPresets": [ + { "name": "build-unix-debug", "configurePreset": "unix-debug", "configuration": "Debug" }, + { "name": "build-unix-debug-system", "configurePreset": "unix-debug-system", "configuration": "Debug" }, + { "name": "build-unix-release", "configurePreset": "unix-release", "configuration": "Release" }, + { "name": "build-unix-release-system", "configurePreset": "unix-release-system", "configuration": "Release" }, + { "name": "build-unix-relwithdebinfo", "configurePreset": "unix-relwithdebinfo", "configuration": "RelWithDebInfo" }, + { "name": "build-unix-debug-asan", "configurePreset": "unix-debug-asan", "configuration": "Debug" }, + { "name": "build-unix-debug-ubsan", "configurePreset": "unix-debug-ubsan", "configuration": "Debug" }, + { "name": "build-unix-debug-asan-ubsan", "configurePreset": "unix-debug-asan-ubsan", "configuration": "Debug" }, + { "name": "build-unix-debug-coverage", "configurePreset": "unix-debug-coverage", "configuration": "Debug" }, + { "name": "build-unix-release-openmp", "configurePreset": "unix-release-openmp", "configuration": "Release" }, + { "name": "build-unix-release-mpi", "configurePreset": "unix-release-mpi", "configuration": "Release" }, + { "name": "build-unix-release-ipopt", "configurePreset": "unix-release-ipopt", "configuration": "Release" }, + { "name": "build-unix-release-profiling", "configurePreset": "unix-release-profiling", "configuration": "Release" }, + { "name": "build-unix-release-install", "configurePreset": "unix-release-install", "configuration": "Release" }, + { "name": "build-windows-debug", "configurePreset": "windows-debug", "configuration": "Debug" }, + { "name": "build-windows-debug-system", "configurePreset": "windows-debug-system", "configuration": "Debug" }, + { "name": "build-windows-release", "configurePreset": "windows-release", "configuration": "Release" }, + { "name": "build-windows-release-system", "configurePreset": "windows-release-system", "configuration": "Release" }, + { "name": "build-windows-relwithdebinfo", "configurePreset": "windows-relwithdebinfo", "configuration": "RelWithDebInfo" }, + { "name": "build-windows-release-install", "configurePreset": "windows-release-install", "configuration": "Release" } + ], + "testPresets": [ + { "name": "test-unix-debug", "configurePreset": "unix-debug", "configuration": "Debug", "output": {"outputOnFailure": true} }, + { "name": "test-unix-debug-system", "configurePreset": "unix-debug-system", "configuration": "Debug", "output": {"outputOnFailure": true} }, + { "name": "test-unix-release", "configurePreset": "unix-release", "configuration": "Release", "output": {"outputOnFailure": true} }, + { "name": "test-unix-release-system", "configurePreset": "unix-release-system", "configuration": "Release", "output": {"outputOnFailure": true} }, + { "name": "test-unix-relwithdebinfo", "configurePreset": "unix-relwithdebinfo", "configuration": "RelWithDebInfo", "output": {"outputOnFailure": true} }, + { "name": "test-unix-debug-asan", "configurePreset": "unix-debug-asan", "configuration": "Debug", "output": {"outputOnFailure": true} }, + { "name": "test-unix-debug-ubsan", "configurePreset": "unix-debug-ubsan", "configuration": "Debug", "output": {"outputOnFailure": true} }, + { "name": "test-unix-debug-asan-ubsan", "configurePreset": "unix-debug-asan-ubsan", "configuration": "Debug", "output": {"outputOnFailure": true} }, + { "name": "test-unix-debug-coverage", "configurePreset": "unix-debug-coverage", "configuration": "Debug", "output": {"outputOnFailure": true} }, + { "name": "test-windows-debug", "configurePreset": "windows-debug", "configuration": "Debug", "output": {"outputOnFailure": true} }, + { "name": "test-windows-debug-system", "configurePreset": "windows-debug-system", "configuration": "Debug", "output": {"outputOnFailure": true} }, + { "name": "test-windows-release", "configurePreset": "windows-release", "configuration": "Release", "output": {"outputOnFailure": true} }, + { "name": "test-windows-release-system", "configurePreset": "windows-release-system", "configuration": "Release", "output": {"outputOnFailure": true} }, + { "name": "test-windows-relwithdebinfo", "configurePreset": "windows-relwithdebinfo", "configuration": "RelWithDebInfo", "output": {"outputOnFailure": true} } + ] + } \ No newline at end of file diff --git a/cpp/benchmarks/CMakeLists.txt b/cpp/benchmarks/CMakeLists.txt index 731fe8d566..6a5a8d242d 100755 --- a/cpp/benchmarks/CMakeLists.txt +++ b/cpp/benchmarks/CMakeLists.txt @@ -1,38 +1,70 @@ -set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Disable benchmark testing" FORCE) +# Attempt to find pre-installed Google Benchmark +set(MEMILIO_BENCHMARK_VERSION "v1.9.2" CACHE STRING "GoogleTest version to use") -# set(BENCHMARK_ENABLE_EXCEPTIONS OFF CACHE BOOL "Disable benchmark exceptions" FORCE) -set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "Don't install benchmark" FORCE) -set(BENCHMARK_DOWNLOAD_DEPENDENCIES OFF CACHE BOOL "Don't download dependencies" FORCE) -set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "Disable Google Test in benchmark" FORCE) +# Configure Google Benchmark build options BEFORE MakeAvailable +set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE) # Don't build benchmark's tests +set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "" FORCE) # Don't install benchmark +set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "" FORCE) # Don't require gtest -include(FetchContent) -FetchContent_Declare(benchmark +FetchContent_Declare(google_benchmark GIT_REPOSITORY https://github.com/google/benchmark.git - GIT_TAG v1.6.1) -FetchContent_GetProperties(benchmark) + GIT_TAG ${MEMILIO_BENCHMARK_VERSION} + GIT_SHALLOW TRUE +) +FetchContent_MakeAvailable(google_benchmark) -if(NOT benchmark_POPULATED) - FetchContent_Populate(benchmark) - set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "") - add_subdirectory(${benchmark_SOURCE_DIR} ${benchmark_BINARY_DIR} EXCLUDE_FROM_ALL) - unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS) -endif() -set_target_properties(benchmark PROPERTIES FOLDER "Extern") +if(TARGET benchmark::benchmark) + set(MEMILIO_BENCHMARK_LIBRARY benchmark::benchmark) +else() + message(FATAL_ERROR "FetchContent for Google Benchmark did not provide target 'benchmark::benchmark'.") +endif() -add_executable(integrator_step_benchmark integrator_step.cpp) -target_link_libraries(integrator_step_benchmark PRIVATE memilio ode_secir benchmark::benchmark) -add_executable(flow_simulation_ode_secirvvs_benchmark flow_simulation_ode_secirvvs.cpp) -target_link_libraries(flow_simulation_ode_secirvvs_benchmark PRIVATE memilio ode_secirvvs benchmark::benchmark) -add_executable(flow_simulation_ode_seir_benchmark flow_simulation_ode_seir.cpp) -target_link_libraries(flow_simulation_ode_seir_benchmark PRIVATE memilio ode_seir benchmark::benchmark) +# Helper function to add benchmark executables +function(add_memilio_benchmark NAME SOURCES) + set(MEMILIO_DEPS ${ARGN}) -add_executable(simulation_benchmark simulation.cpp) -target_link_libraries(simulation_benchmark PRIVATE memilio ode_secir benchmark::benchmark) -add_executable(graph_simulation_benchmark graph_simulation.cpp) -target_link_libraries(graph_simulation_benchmark PRIVATE memilio ode_secirvvs benchmark::benchmark) + add_executable(${NAME} ${SOURCES}) + target_link_libraries(${NAME} PRIVATE + memilio + ${MEMILIO_DEPS} + ${MEMILIO_BENCHMARK_LIBRARY} + ) +endfunction() -add_executable(abm_benchmark abm.cpp) -target_link_libraries(abm_benchmark PRIVATE abm benchmark::benchmark) + +# Define benchmark executables +add_memilio_benchmark(memilio_abm_benchmark + abm.cpp + abm +) + +if(MEMILIO_HAS_JSONCPP) + add_memilio_benchmark(memilio_graph_simulation_benchmark + graph_simulation.cpp + ode_secirvvs + ) + + add_memilio_benchmark(memilio_flow_simulation_ode_seir_benchmark + flow_simulation_ode_seir.cpp + ode_seir + ) + + + add_memilio_benchmark(memilio_flow_simulation_ode_secirvvs_benchmark + flow_simulation_ode_secirvvs.cpp + ode_secirvvs + ) + + add_memilio_benchmark(integrator_secir_benchmark + integrator_secir_sim.cpp + ode_secir + ) + + add_memilio_benchmark(memilio_integrator_step_benchmark + integrator_step.cpp + ode_secir + ) +endif() \ No newline at end of file diff --git a/cpp/benchmarks/simulation.config b/cpp/benchmarks/configs/flow_simulation.config similarity index 100% rename from cpp/benchmarks/simulation.config rename to cpp/benchmarks/configs/flow_simulation.config diff --git a/cpp/benchmarks/graph_simulation.config b/cpp/benchmarks/configs/graph_simulation.config similarity index 100% rename from cpp/benchmarks/graph_simulation.config rename to cpp/benchmarks/configs/graph_simulation.config diff --git a/cpp/benchmarks/integrator_step.config b/cpp/benchmarks/configs/integrator_step.config similarity index 100% rename from cpp/benchmarks/integrator_step.config rename to cpp/benchmarks/configs/integrator_step.config diff --git a/cpp/benchmarks/scorep-filter-abm b/cpp/benchmarks/configs/scorep-filter-abm similarity index 100% rename from cpp/benchmarks/scorep-filter-abm rename to cpp/benchmarks/configs/scorep-filter-abm diff --git a/cpp/benchmarks/flow_simulation_ode_secirvvs.cpp b/cpp/benchmarks/flow_simulation_ode_secirvvs.cpp index dac067512c..ab78f8d287 100644 --- a/cpp/benchmarks/flow_simulation_ode_secirvvs.cpp +++ b/cpp/benchmarks/flow_simulation_ode_secirvvs.cpp @@ -17,15 +17,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "benchmarks/simulation.h" +#include "benchmarks/integrator_secir_sim.h" #include "benchmarks/flow_simulation_ode_secirvvs.h" #include "memilio/compartments/flow_simulation.h" #include "memilio/compartments/simulation.h" #include "ode_secirvvs/model.h" +#include "memilio/utils/base_dir.h" #include -const std::string config_path = "../../benchmarks/simulation.config"; - // simulation without flows (not in Model definition and not calculated by Simulation) void flowless_sim(::benchmark::State& state) { @@ -33,7 +32,7 @@ void flowless_sim(::benchmark::State& state) // suppress non-critical messages mio::set_log_level(mio::LogLevel::critical); // load config - auto cfg = mio::benchmark::SimulationConfig::initialize(config_path); + auto cfg = mio::benchmark::SimulationConfig::initialize(mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/flow_simulation.config")); // create model Model model(cfg.num_agegroups); mio::benchmark::setup_model(model); @@ -58,7 +57,7 @@ void flow_sim_comp_only(::benchmark::State& state) // suppress non-critical messages mio::set_log_level(mio::LogLevel::critical); // load config - auto cfg = mio::benchmark::SimulationConfig::initialize(config_path); + auto cfg = mio::benchmark::SimulationConfig::initialize(mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/graph_simulation.config")); // create model Model model(cfg.num_agegroups); mio::benchmark::setup_model(model); @@ -83,7 +82,7 @@ void flow_sim(::benchmark::State& state) // suppress non-critical messages mio::set_log_level(mio::LogLevel::critical); // load config - auto cfg = mio::benchmark::SimulationConfig::initialize(config_path); + auto cfg = mio::benchmark::SimulationConfig::initialize(mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/graph_simulation.config")); // create model Model model(cfg.num_agegroups); mio::benchmark::setup_model(model); diff --git a/cpp/benchmarks/flow_simulation_ode_secirvvs.h b/cpp/benchmarks/flow_simulation_ode_secirvvs.h index 1d2f793b93..02bb77d1fd 100644 --- a/cpp/benchmarks/flow_simulation_ode_secirvvs.h +++ b/cpp/benchmarks/flow_simulation_ode_secirvvs.h @@ -19,6 +19,7 @@ */ #include "memilio/compartments/simulation.h" #include "models/ode_secirvvs/model.h" +#include "memilio/utils/base_dir.h" namespace mio { diff --git a/cpp/benchmarks/flow_simulation_ode_seir.cpp b/cpp/benchmarks/flow_simulation_ode_seir.cpp index 09e8a2b937..da1f0d71ab 100644 --- a/cpp/benchmarks/flow_simulation_ode_seir.cpp +++ b/cpp/benchmarks/flow_simulation_ode_seir.cpp @@ -17,12 +17,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "benchmarks/simulation.h" +#include "benchmarks/integrator_secir_sim.h" #include "memilio/compartments/flow_simulation.h" #include "ode_seir/model.h" #include - -const std::string config_path = "../../benchmarks/simulation.config"; +#include "memilio/utils/base_dir.h" #include "memilio/compartments/simulation.h" #include "models/ode_seir/model.h" @@ -120,7 +119,7 @@ void flowless_sim(::benchmark::State& state) // suppress non-critical messages mio::set_log_level(mio::LogLevel::critical); // load config - auto cfg = mio::benchmark::SimulationConfig::initialize(config_path); + auto cfg = mio::benchmark::SimulationConfig::initialize(mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/graph_simulation.config")); // create model Model model(cfg.num_agegroups); mio::benchmark::setup_model(model); @@ -143,7 +142,7 @@ void flow_sim_comp_only(::benchmark::State& state) // suppress non-critical messages mio::set_log_level(mio::LogLevel::critical); // load config - auto cfg = mio::benchmark::SimulationConfig::initialize(config_path); + auto cfg = mio::benchmark::SimulationConfig::initialize(mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/graph_simulation.config")); // create model Model model(cfg.num_agegroups); mio::benchmark::setup_model(model); @@ -166,7 +165,7 @@ void flow_sim(::benchmark::State& state) // suppress non-critical messages mio::set_log_level(mio::LogLevel::critical); // load config - auto cfg = mio::benchmark::SimulationConfig::initialize(config_path); + auto cfg = mio::benchmark::SimulationConfig::initialize(mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/graph_simulation.config")); // create model Model model(cfg.num_agegroups); mio::benchmark::setup_model(model); diff --git a/cpp/benchmarks/graph_simulation.cpp b/cpp/benchmarks/graph_simulation.cpp index 87883779d9..123138d297 100644 --- a/cpp/benchmarks/graph_simulation.cpp +++ b/cpp/benchmarks/graph_simulation.cpp @@ -25,8 +25,6 @@ #include "memilio/math/adapt_rk.h" #include -const std::string config_path = "../../benchmarks/graph_simulation.config"; - mio::osecirvvs::Model create_model(size_t num_agegroups, const ScalarType tmax) { mio::osecirvvs::Model model(num_agegroups); @@ -113,7 +111,7 @@ mio::osecirvvs::Model create_model(size_t num_agegroups, const Scala template auto create_simulation() { - auto cfg = mio::benchmark::GraphConfig::initialize(config_path); + auto cfg = mio::benchmark::GraphConfig::initialize(mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/graph_simulation.config")); mio::osecirvvs::Model model = create_model(cfg.num_agegroups, cfg.t_max); @@ -152,7 +150,7 @@ template void graph_sim_secirvvs(::benchmark::State& state) { mio::set_log_level(mio::LogLevel::critical); - auto cfg = mio::benchmark::GraphConfig::initialize(config_path); + auto cfg = mio::benchmark::GraphConfig::initialize(mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/graph_simulation.config")); for (auto _ : state) { // This code gets timed diff --git a/cpp/benchmarks/graph_simulation.h b/cpp/benchmarks/graph_simulation.h index 5947109e24..09a9b3af1d 100644 --- a/cpp/benchmarks/graph_simulation.h +++ b/cpp/benchmarks/graph_simulation.h @@ -22,6 +22,7 @@ #include "memilio/io/json_serializer.h" #include "memilio/utils/logging.h" +#include "memilio/utils/base_dir.h" #include "benchmark/benchmark.h" diff --git a/cpp/benchmarks/simulation.cpp b/cpp/benchmarks/integrator_secir_sim.cpp similarity index 89% rename from cpp/benchmarks/simulation.cpp rename to cpp/benchmarks/integrator_secir_sim.cpp index 58f7dd26d7..a0164a8e40 100644 --- a/cpp/benchmarks/simulation.cpp +++ b/cpp/benchmarks/integrator_secir_sim.cpp @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "benchmarks/simulation.h" +#include "benchmarks/integrator_secir_sim.h" #include "benchmarks/secir_ageres_setups.h" #include "memilio/math/adapt_rk.h" @@ -29,8 +29,8 @@ void simulation(::benchmark::State& state) // suppress non-critical messages mio::set_log_level(mio::LogLevel::critical); // setup benchmark parameters - auto cfg = mio::benchmark::SimulationConfig::initialize("benchmarks/simulation.config"); - //auto cfg = mio::benchmark::SimulationConfig::initialize(10); + const std::string config_path = mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/integrator_step.config"); + auto cfg = mio::benchmark::SimulationConfig::initialize(config_path); auto model = mio::benchmark::model::SecirAgeres(cfg.num_agegroups); for (auto _ : state) { diff --git a/cpp/benchmarks/simulation.h b/cpp/benchmarks/integrator_secir_sim.h similarity index 94% rename from cpp/benchmarks/simulation.h rename to cpp/benchmarks/integrator_secir_sim.h index caf956551d..4bd8c61180 100644 --- a/cpp/benchmarks/simulation.h +++ b/cpp/benchmarks/integrator_secir_sim.h @@ -17,12 +17,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef ODE_SIMULATION_CONFIG_H -#define ODE_SIMULATION_CONFIG_H +#ifndef INTEGRATOR_SECIR_SIM_H +#define INTEGRATOR_SECIR_SIM_H #include "memilio/io/json_serializer.h" #include "memilio/utils/logging.h" - +#include "memilio/utils/base_dir.h" #include "benchmark/benchmark.h" namespace mio @@ -89,4 +89,4 @@ struct SimulationConfig { } // namespace mio -#endif // ODE_SIMULATION_CONFIG_H +#endif // INTEGRATOR_SECIR_SIM_H diff --git a/cpp/benchmarks/integrator_step.cpp b/cpp/benchmarks/integrator_step.cpp index 4050ba5606..b62696d901 100644 --- a/cpp/benchmarks/integrator_step.cpp +++ b/cpp/benchmarks/integrator_step.cpp @@ -32,7 +32,8 @@ void integrator_step(::benchmark::State& state) // with "num_agegroups" agegroups, and taking "yt" as the state of the simulation at "t_init" // NOTE: yt must have #agegroups * #compartments entries // benchmark setup - auto cfg = mio::benchmark::IntegratorStepConfig::initialize("benchmarks/integrator_step.config"); + const std::string config_path = mio::path_join(mio::memilio_dir(), "cpp/benchmarks/configs/integrator_step.config"); + auto cfg = mio::benchmark::IntegratorStepConfig::initialize(config_path); //auto cfg = mio::benchmark::IntegratorStepConfig::initialize(); auto model = mio::benchmark::model::SecirAgeres(cfg.num_agegroups); // set deriv function and integrator diff --git a/cpp/benchmarks/integrator_step.h b/cpp/benchmarks/integrator_step.h index 35b49c5720..0d9c8a976e 100644 --- a/cpp/benchmarks/integrator_step.h +++ b/cpp/benchmarks/integrator_step.h @@ -22,6 +22,8 @@ #include "memilio/io/json_serializer.h" #include "memilio/utils/logging.h" +#include "memilio/utils/base_dir.h" +#include #include "benchmark/benchmark.h" diff --git a/cpp/cmake/DownloadProject.CMakeLists.cmake.in b/cpp/cmake/DownloadProject.CMakeLists.cmake.in deleted file mode 100644 index 49a8887380..0000000000 --- a/cpp/cmake/DownloadProject.CMakeLists.cmake.in +++ /dev/null @@ -1,17 +0,0 @@ -# Distributed under the OSI-approved MIT License. See accompanying -# file LICENSE or https://github.com/Crascit/DownloadProject for details. - -cmake_minimum_required(VERSION 2.8.2) - -project(${DL_ARGS_PROJ}-download NONE) - -include(ExternalProject) -ExternalProject_Add(${DL_ARGS_PROJ}-download - ${DL_ARGS_UNPARSED_ARGUMENTS} - SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" - BINARY_DIR "${DL_ARGS_BINARY_DIR}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" -) diff --git a/cpp/cmake/DownloadProject.cmake b/cpp/cmake/DownloadProject.cmake deleted file mode 100644 index 76aaa01f67..0000000000 --- a/cpp/cmake/DownloadProject.cmake +++ /dev/null @@ -1,164 +0,0 @@ -# Distributed under the OSI-approved MIT License. See accompanying -# file LICENSE or https://github.com/Crascit/DownloadProject for details. -# -# MODULE: DownloadProject -# -# PROVIDES: -# download_project( PROJ projectName -# [PREFIX prefixDir] -# [DOWNLOAD_DIR downloadDir] -# [SOURCE_DIR srcDir] -# [BINARY_DIR binDir] -# [QUIET] -# ... -# ) -# -# Provides the ability to download and unpack a tarball, zip file, git repository, -# etc. at configure time (i.e. when the cmake command is run). How the downloaded -# and unpacked contents are used is up to the caller, but the motivating case is -# to download source code which can then be included directly in the build with -# add_subdirectory() after the call to download_project(). Source and build -# directories are set up with this in mind. -# -# The PROJ argument is required. The projectName value will be used to construct -# the following variables upon exit (obviously replace projectName with its actual -# value): -# -# projectName_SOURCE_DIR -# projectName_BINARY_DIR -# -# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically -# need to be provided. They can be specified if you want the downloaded source -# and build directories to be located in a specific place. The contents of -# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the -# locations used whether you provide SOURCE_DIR/BINARY_DIR or not. -# -# The DOWNLOAD_DIR argument does not normally need to be set. It controls the -# location of the temporary CMake build used to perform the download. -# -# The PREFIX argument can be provided to change the base location of the default -# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments -# are provided, then PREFIX will have no effect. The default value for PREFIX is -# CMAKE_BINARY_DIR. -# -# The QUIET option can be given if you do not want to show the output associated -# with downloading the specified project. -# -# In addition to the above, any other options are passed through unmodified to -# ExternalProject_Add() to perform the actual download, patch and update steps. -# The following ExternalProject_Add() options are explicitly prohibited (they -# are reserved for use by the download_project() command): -# -# CONFIGURE_COMMAND -# BUILD_COMMAND -# INSTALL_COMMAND -# TEST_COMMAND -# -# Only those ExternalProject_Add() arguments which relate to downloading, patching -# and updating of the project sources are intended to be used. Also note that at -# least one set of download-related arguments are required. -# -# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to -# prevent a check at the remote end for changes every time CMake is run -# after the first successful download. See the documentation of the ExternalProject -# module for more information. It is likely you will want to use this option if it -# is available to you. Note, however, that the ExternalProject implementation contains -# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when -# using the URL download method or when specifying a SOURCE_DIR with no download -# method. Fixes for these have been created, the last of which is scheduled for -# inclusion in CMake 3.8.0. Details can be found here: -# -# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c -# https://gitlab.kitware.com/cmake/cmake/issues/16428 -# -# If you experience build errors related to the update step, consider avoiding -# the use of UPDATE_DISCONNECTED. -# -# EXAMPLE USAGE: -# -# include(DownloadProject) -# download_project(PROJ googletest -# GIT_REPOSITORY https://github.com/google/googletest.git -# GIT_TAG master -# UPDATE_DISCONNECTED 1 -# QUIET -# ) -# -# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) -# -#======================================================================================== - - -set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}") - -include(CMakeParseArguments) - -function(download_project) - - set(options QUIET) - set(oneValueArgs - PROJ - PREFIX - DOWNLOAD_DIR - SOURCE_DIR - BINARY_DIR - # Prevent the following from being passed through - CONFIGURE_COMMAND - BUILD_COMMAND - INSTALL_COMMAND - TEST_COMMAND - ) - set(multiValueArgs "") - - cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # Hide output if requested - if (DL_ARGS_QUIET) - set(OUTPUT_QUIET "OUTPUT_QUIET") - else() - unset(OUTPUT_QUIET) - message(STATUS "Downloading/updating ${DL_ARGS_PROJ}") - endif() - - # Set up where we will put our temporary CMakeLists.txt file and also - # the base point below which the default source and binary dirs will be - if (NOT DL_ARGS_PREFIX) - set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}") - endif() - if (NOT DL_ARGS_DOWNLOAD_DIR) - set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download") - endif() - - # Ensure the caller can know where to find the source and build directories - if (NOT DL_ARGS_SOURCE_DIR) - set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src") - endif() - if (NOT DL_ARGS_BINARY_DIR) - set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build") - endif() - set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE) - set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE) - - # Create and build a separate CMake project to carry out the download. - # If we've already previously done these steps, they will not cause - # anything to be updated, so extra rebuilds of the project won't occur. - configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in" - "${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt") - execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . - RESULT_VARIABLE result - ${OUTPUT_QUIET} - WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" - ) - if(result) - message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}") - endif() - execute_process(COMMAND ${CMAKE_COMMAND} --build . - RESULT_VARIABLE result - ${OUTPUT_QUIET} - WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" - ) - if(result) - message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}") - endif() - -endfunction() diff --git a/cpp/cmake/FindSphinx.cmake b/cpp/cmake/FindSphinx.cmake deleted file mode 100644 index 24e0d072c1..0000000000 --- a/cpp/cmake/FindSphinx.cmake +++ /dev/null @@ -1,11 +0,0 @@ -#Look for an executable called sphinx-build -find_program(SPHINX_EXECUTABLE - NAMES sphinx-build - DOC "Path to sphinx-build executable") - -include(FindPackageHandleStandardArgs) - -#Handle standard arguments to find_package like REQUIRED and QUIET -find_package_handle_standard_args(Sphinx - "Failed to find sphinx-build executable" - SPHINX_EXECUTABLE) diff --git a/cpp/cmake/memilio-config.cmake.in b/cpp/cmake/memilio-config.cmake.in index 12c44ee5f8..79605cc154 100644 --- a/cpp/cmake/memilio-config.cmake.in +++ b/cpp/cmake/memilio-config.cmake.in @@ -1,7 +1,16 @@ +@PACKAGE_INIT@ + +# Include helper macro for finding dependencies +include(CMakeFindDependencyMacro) + +# Find dependencies required by the public interface of memilio +# Adjust versions and components to match your project's requirements +find_dependency(Eigen3 3.4 REQUIRED) # Replace 3.4 with your minimum Eigen version +find_dependency(Boost 1.76 REQUIRED COMPONENTS filesystem) # Replace 1.70 and add any other PUBLIC Boost components +find_dependency(Random123 REQUIRED) # If Random123 is found via find_package + get_filename_component(MEMILIO_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) if(NOT TARGET @PROJECT_NAME@::@PROJECT_NAME@) include("${MEMILIO_CMAKE_DIR}/@PROJECT_NAME@-targets.cmake") -endif() - -set(MEMILIO_LIBRARIES @PROJECT_NAME@::@PROJECT_NAME@) +endif() \ No newline at end of file diff --git a/cpp/cmake/version.h.in b/cpp/cmake/version.h.in new file mode 100644 index 0000000000..ff43cf4247 --- /dev/null +++ b/cpp/cmake/version.h.in @@ -0,0 +1,7 @@ +#pragma once + +#define MIO_VERSION_MAJOR @MIO_VERSION_MAJOR@ +#define MIO_VERSION_MINOR @MIO_VERSION_MINOR@ +#define MIO_VERSION_PATCH @MIO_VERSION_PATCH@ +#define MIO_VERSION_TWEAK @MIO_VERSION_TWEAK@ +#define MIO_VERSION_STRING "@MIO_VERSION_STRING@" diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 57e7033d5f..529def31d4 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -1,182 +1,78 @@ -# configure directory that contains the data files used by examples -file(TO_CMAKE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../data" MEMILIO_DATA_DIR) -configure_file(data_dir.h.in data_dir.h) - -add_executable(euler_example euler_test.cpp) -target_link_libraries(euler_example PRIVATE memilio) -target_compile_options(euler_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_secir_parameter_sampling_example ode_secir_parameter_sampling.cpp) -target_link_libraries(ode_secir_parameter_sampling_example PRIVATE memilio ode_secir) -target_compile_options(ode_secir_parameter_sampling_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(adapt_rk_example adapt_rk_test.cpp) -target_link_libraries(adapt_rk_example PRIVATE memilio) -target_compile_options(adapt_rk_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_seir_example ode_seir.cpp) -target_link_libraries(ode_seir_example PRIVATE memilio ode_seir) -target_compile_options(ode_seir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_seir_ageres_example ode_seir_ageres.cpp) -target_link_libraries(ode_seir_ageres_example PRIVATE memilio ode_seir) -target_compile_options(ode_seir_ageres_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_sir_example ode_sir.cpp) -target_link_libraries(ode_sir_example PRIVATE memilio ode_sir) -target_compile_options(ode_sir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(sde_sir_example sde_sir.cpp) -target_link_libraries(sde_sir_example PRIVATE memilio sde_sir) -target_compile_options(sde_sir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(sde_sirs_example sde_sirs.cpp) -target_link_libraries(sde_sirs_example PRIVATE memilio sde_sirs) -target_compile_options(sde_sirs_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(sde_seirvv_example sde_seirvv.cpp) -target_link_libraries(sde_seirvv_example PRIVATE memilio sde_seirvv) -target_compile_options(sde_seirvv_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_seair_example ode_seair.cpp) -target_link_libraries(ode_seair_example PRIVATE memilio ode_seair AD::AD) -target_compile_options(ode_seair_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +#------------------------------------------------------- +# Helper Function for Examples +#------------------------------------------------------- +function(add_memilio_example NAME SOURCES) + set(EXTRA_DEPS ${ARGN}) + add_executable(${NAME} ${SOURCES}) + target_link_libraries(${NAME} PRIVATE memilio ${EXTRA_DEPS}) + memilio_set_warning_flags(${NAME}) + memilio_set_sanitizer_flags(${NAME}) +endfunction() + +#------------------------------------------------------- +# Example Executable Definitions +#------------------------------------------------------- +add_memilio_example(memilio_example_euler euler_test.cpp) +add_memilio_example(memilio_example_adapt_rk adapt_rk_test.cpp) +add_memilio_example(memilio_example_history history.cpp) + +add_memilio_example(memilio_example_ode_sir ode_sir.cpp ode_sir) +add_memilio_example(memilio_example_ode_sir_ageres ode_sir_ageres.cpp ode_sir) +add_memilio_example(memilio_example_ode_seir ode_seir.cpp ode_seir) +add_memilio_example(memilio_example_ode_seir_ageres ode_seir_ageres.cpp ode_seir) +add_memilio_example(memilio_example_seir_flows ode_seir_flows.cpp ode_seir) +add_memilio_example(memilio_example_ode_secir ode_secir.cpp ode_secir) +add_memilio_example(memilio_example_ode_secir_ageres ode_secir_ageres.cpp ode_secir) +add_memilio_example(memilio_example_ode_secir_contacts ode_secir_contact_changes.cpp ode_secir) +add_memilio_example(memilio_example_ode_secir_feedback ode_secir_feedback.cpp ode_secir) +add_memilio_example(memilio_example_ode_secir_graph ode_secir_graph.cpp ode_secir) +add_memilio_example(memilio_example_ode_secirvvs ode_secirvvs.cpp ode_secirvvs) +add_memilio_example(memilio_example_ode_secirts ode_secirts.cpp ode_secirts) +add_memilio_example(memilio_example_graph_stochastic_mobility graph_stochastic_mobility.cpp ode_secir) +add_memilio_example(memilio_example_ode_secir_param_sampling ode_secir_parameter_sampling.cpp ode_secir) + +add_memilio_example(memilio_example_sde_sir sde_sir.cpp sde_sir) +add_memilio_example(memilio_example_sde_sirs sde_sirs.cpp sde_sirs) +add_memilio_example(memilio_example_sde_seirvv sde_seirvv.cpp sde_seirvv) + +add_memilio_example(memilio_example_ad_square ad_square_example.cpp) +add_memilio_example(memilio_example_ad_odeint ad_odeint_example.cpp Boost::boost) +add_memilio_example(memilio_example_ode_seair ode_seair.cpp ode_seair) + +add_memilio_example(memilio_example_ide_seir ide_seir.cpp ide_seir) +add_memilio_example(memilio_example_ide_secir ide_secir.cpp ide_secir) +add_memilio_example(memilio_example_ide_secir_ageres ide_secir_ageres.cpp ide_secir) + +add_memilio_example(memilio_example_lct_secir lct_secir.cpp lct_secir) +add_memilio_example(memilio_example_glct_secir glct_secir.cpp glct_secir) + +add_memilio_example(memilio_example_abm_minimal abm_minimal.cpp abm) +add_memilio_example(memilio_example_abm_history abm_history_object.cpp abm) +add_memilio_example(memilio_example_graph_abm graph_abm.cpp graph_abm abm) +add_memilio_example(memilio_example_dabm d_abm.cpp d_abm) + +add_memilio_example(memilio_example_smm smm.cpp smm) if(MEMILIO_ENABLE_IPOPT) - add_executable(ode_seair_optimization ode_seair_optimization.cpp) - target_link_libraries(ode_seair_optimization PRIVATE memilio ode_seair AD::AD Ipopt::Ipopt) - target_compile_options(ode_seair_optimization PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -endif() - -add_executable(ad_square_example ad_square_example.cpp) -target_link_libraries(ad_square_example PRIVATE memilio AD::AD) -target_compile_options(ad_square_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ad_odeint_example ad_odeint_example.cpp) -target_link_libraries(ad_odeint_example PRIVATE memilio AD::AD Boost::boost) -target_compile_options(ad_odeint_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_sir_ageres_example ode_sir_ageres.cpp) -target_link_libraries(ode_sir_ageres_example PRIVATE memilio ode_sir) -target_compile_options(ode_sir_ageres_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(seir_flows_example ode_seir_flows.cpp) -target_link_libraries(seir_flows_example PRIVATE memilio ode_seir) -target_compile_options(seir_flows_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_secir_example ode_secir.cpp) -target_link_libraries(ode_secir_example PRIVATE memilio ode_secir) -target_compile_options(ode_secir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_secir_contact_changes ode_secir_contact_changes.cpp) -target_link_libraries(ode_secir_contact_changes PRIVATE memilio ode_secir) -target_compile_options(ode_secir_contact_changes PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_secir_feedback ode_secir_feedback.cpp) -target_link_libraries(ode_secir_feedback PRIVATE memilio ode_secir) -target_compile_options(ode_secir_feedback PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_secirvvs_example ode_secirvvs.cpp) -target_link_libraries(ode_secirvvs_example PRIVATE memilio ode_secirvvs) -target_compile_options(ode_secirvvs_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_secirts_example ode_secirts.cpp) -target_link_libraries(ode_secirts_example PRIVATE memilio ode_secirts) -target_compile_options(ode_secirts_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_secir_ageres_example ode_secir_ageres.cpp) -target_link_libraries(ode_secir_ageres_example PRIVATE memilio ode_secir) -target_compile_options(ode_secir_ageres_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_secir_graph_example ode_secir_graph.cpp) -target_link_libraries(ode_secir_graph_example PRIVATE memilio ode_secir) -target_compile_options(ode_secir_graph_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(graph_stochastic_mobility_example graph_stochastic_mobility.cpp) -target_link_libraries(graph_stochastic_mobility_example PRIVATE memilio ode_secir) -target_compile_options(graph_stochastic_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(abm_minimal_example abm_minimal.cpp) -target_link_libraries(abm_minimal_example PRIVATE memilio abm) -target_compile_options(abm_minimal_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(abm_history_example abm_history_object.cpp) -target_link_libraries(abm_history_example PRIVATE memilio abm) -target_compile_options(abm_history_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ide_seir_example ide_seir.cpp) -target_link_libraries(ide_seir_example PRIVATE memilio ide_seir) -target_compile_options(ide_seir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ide_secir_example ide_secir.cpp) -target_link_libraries(ide_secir_example PRIVATE memilio ide_secir) -target_compile_options(ide_secir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ide_secir_ageres_example ide_secir_ageres.cpp) -target_link_libraries(ide_secir_ageres_example PRIVATE memilio ide_secir) -target_compile_options(ide_secir_ageres_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(lct_secir_example lct_secir.cpp) -target_link_libraries(lct_secir_example PRIVATE memilio lct_secir) -target_compile_options(lct_secir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(glct_secir_example glct_secir.cpp) -target_link_libraries(glct_secir_example PRIVATE memilio glct_secir) -target_compile_options(glct_secir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(history_example history.cpp) -target_link_libraries(history_example PRIVATE memilio) -target_compile_options(history_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(graph_abm_example graph_abm.cpp) -target_link_libraries(graph_abm_example PRIVATE memilio graph_abm abm) -target_compile_options(graph_abm_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(dabm_example d_abm.cpp) -target_link_libraries(dabm_example PRIVATE memilio d_abm) -target_compile_options(dabm_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(smm_example smm.cpp) -target_link_libraries(smm_example PRIVATE memilio smm) -target_compile_options(smm_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -if(MEMILIO_HAS_JSONCPP) - add_executable(ode_secir_read_graph_example ode_secir_read_graph.cpp) - target_link_libraries(ode_secir_read_graph_example PRIVATE memilio ode_secir) - target_include_directories(ode_secir_read_graph_example PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) # configured headers - target_compile_options(ode_secir_read_graph_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -endif() - -if(MEMILIO_HAS_HDF5 AND MEMILIO_HAS_JSONCPP) - add_executable(ode_secir_parameter_study_example ode_secir_parameter_study.cpp) - target_link_libraries(ode_secir_parameter_study_example PRIVATE memilio ode_secir) - target_compile_options(ode_secir_parameter_study_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - - add_executable(ode_secir_parameter_study_graph ode_secir_parameter_study_graph.cpp) - target_link_libraries(ode_secir_parameter_study_graph PRIVATE memilio ode_secir) - target_compile_options(ode_secir_parameter_study_graph PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + message(STATUS "Building examples requiring Ipopt.") + add_memilio_example(memilio_example_ode_seair_optimization ode_seair_optimization.cpp ode_seair Ipopt::Ipopt) endif() if(MEMILIO_HAS_JSONCPP) - add_executable(cli_example cli.cpp) - target_link_libraries(cli_example PRIVATE memilio) - target_compile_options(cli_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -endif() - -if(MEMILIO_HAS_JSONCPP) - add_executable(serialize_example serialize.cpp) - target_link_libraries(serialize_example PRIVATE memilio) - target_compile_options(serialize_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + message(STATUS "Building examples requiring JsonCpp.") + add_memilio_example(memilio_example_cli cli.cpp JsonCpp::JsonCpp) + add_memilio_example(memilio_example_serialize serialize.cpp JsonCpp::JsonCpp) + add_memilio_example(memilio_example_ode_read_graph ode_secir_read_graph.cpp ode_secir JsonCpp::JsonCpp) + add_memilio_example(memilio_example_ide_init ide_initialization.cpp ide_secir JsonCpp::JsonCpp) endif() if(MEMILIO_HAS_HDF5) - add_executable(ode_secir_save_results_example ode_secir_save_results.cpp) - target_link_libraries(ode_secir_save_results_example PRIVATE memilio ode_secir) - target_compile_options(ode_secir_save_results_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + message(STATUS "Building examples requiring HDF5.") + add_memilio_example(memilio_example_ode_save_results ode_secir_save_results.cpp ode_secir HDF5::HDF5) endif() -if(MEMILIO_HAS_JSONCPP) - add_executable(ide_initialization_example ide_initialization.cpp) - target_link_libraries(ide_initialization_example PRIVATE memilio ide_secir) - target_compile_options(ide_initialization_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +if(MEMILIO_HAS_HDF5 AND MEMILIO_HAS_JSONCPP) + message(STATUS "Building examples requiring HDF5 and JsonCpp.") + add_memilio_example(memilio_example_ode_param_study ode_secir_parameter_study.cpp ode_secir HDF5::HDF5 JsonCpp::JsonCpp) + add_memilio_example(memilio_example_ode_param_study_graph ode_secir_parameter_study_graph.cpp ode_secir HDF5::HDF5 JsonCpp::JsonCpp) endif() diff --git a/cpp/examples/ad_odeint_example.cpp b/cpp/examples/ad_odeint_example.cpp index 03e64fcc72..2f000c6c8f 100644 --- a/cpp/examples/ad_odeint_example.cpp +++ b/cpp/examples/ad_odeint_example.cpp @@ -18,12 +18,12 @@ * limitations under the License. */ -#include "ad/ad.hpp" +#include "memilio/ad/ad.hpp" #include "boost/numeric/odeint.hpp" #include // This program shows that boost::numeric::odeint::runge_kutta_cash_karp54 can be fully -// algorithmically diffentiated using the algorithmic differentiation (AD) data types of ad/ad.hpp. +// algorithmically diffentiated using the algorithmic differentiation (AD) data types of memilio/ad/ad.hpp. using ad_forward_type = typename ad::gt1s::type; // AD data type for scalar forward mode diff --git a/cpp/examples/ad_square_example.cpp b/cpp/examples/ad_square_example.cpp index 1ba1039fca..2f8747512e 100644 --- a/cpp/examples/ad_square_example.cpp +++ b/cpp/examples/ad_square_example.cpp @@ -18,7 +18,7 @@ * limitations under the License. */ -#include "ad/ad.hpp" +#include "memilio/ad/ad.hpp" #include /* This example computes the derivative of f(x) = x^2 in two different ways: diff --git a/cpp/examples/ode_seair.cpp b/cpp/examples/ode_seair.cpp index d948c71202..f4c77aa1c4 100644 --- a/cpp/examples/ode_seair.cpp +++ b/cpp/examples/ode_seair.cpp @@ -23,7 +23,7 @@ // A detailed description of the model can be found in the publication // Tsay et al. (2020), Modeling, state estimation, and optimal control for the US COVID-19 outbreak. -#include "ad/ad.hpp" +#include "memilio/ad/ad.hpp" #include "ode_seair/model.h" #include "ode_seair/infection_state.h" diff --git a/cpp/examples/ode_seair_optimization.cpp b/cpp/examples/ode_seair_optimization.cpp index f86066cd52..142a2cbd5b 100644 --- a/cpp/examples/ode_seair_optimization.cpp +++ b/cpp/examples/ode_seair_optimization.cpp @@ -21,7 +21,7 @@ * is extracted from the Ipopt documentation */ -#include "ad/ad.hpp" +#include "memilio/ad/ad.hpp" #include "memilio/utils/compiler_diagnostics.h" #include "ode_seair/model.h" diff --git a/cpp/examples/ode_secir_read_graph.cpp b/cpp/examples/ode_secir_read_graph.cpp index 4e086bdffc..a2f226c996 100644 --- a/cpp/examples/ode_secir_read_graph.cpp +++ b/cpp/examples/ode_secir_read_graph.cpp @@ -22,8 +22,8 @@ #include "memilio/compartments/parameter_studies.h" #include "ode_secir/parameter_space.h" #include "ode_secir/parameters_io.h" -#include #include +#include "memilio/utils/base_dir.h" std::string setup(int argc, char** argv, const std::string data_dir) { @@ -52,7 +52,7 @@ std::string setup(int argc, char** argv, const std::string data_dir) int main(int argc, char** argv) { mio::set_log_level(mio::LogLevel::critical); - std::string data_dir = DATA_DIR; + std::string data_dir = mio::path_join(mio::memilio_dir(), "data"); std::string filename = setup(argc, argv, data_dir); const auto t0 = 0.; diff --git a/cpp/memilio/CMakeLists.txt b/cpp/memilio/CMakeLists.txt index b62d972e9a..24b66953ce 100644 --- a/cpp/memilio/CMakeLists.txt +++ b/cpp/memilio/CMakeLists.txt @@ -1,7 +1,14 @@ -configure_file(config_internal.h.in memilio/config_internal.h) +# Configure internal header based on CMake settings +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config_internal.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/memilio/config_internal.h" + ) add_library(memilio + # Config & Core config.h + memilio/config_internal.h # Generated file + + # Data & Epidemiology data/analyze_result.h data/analyze_result.cpp epidemiology/age_group.h @@ -19,20 +26,26 @@ add_library(memilio epidemiology/lct_infection_state.h epidemiology/lct_populations.h epidemiology/adoption_rate.h + epidemiology/simulation_day.h + + # Geography geography/regions.h geography/regions.cpp - epidemiology/simulation_day.h - geography/holiday_data.ipp + geography/holiday_data.ipp # Note: .ipp files are usually included by .h/.cpp + + # Compartments & Simulation compartments/compartmentalmodel.h compartments/flow_model.h compartments/simulation.h compartments/flow_simulation.h compartments/parameter_studies.h + + # IO io/default_serialize.h io/default_serialize.cpp io/io.h io/io.cpp - io/hdf5_cpp.h + io/hdf5_cpp.h # Helper, might not need explicit listing if header-only/internal io/json_serializer.h io/json_serializer.cpp io/binary_serializer.h @@ -45,6 +58,8 @@ add_library(memilio io/epi_data.h io/epi_data.cpp io/cli.h + + # Math math/euler.cpp math/euler.h math/smoother.h @@ -62,6 +77,8 @@ add_library(memilio math/interpolation.cpp math/time_series_functor.h math/time_series_functor.cpp + + # Mobility & Graphs mobility/metapopulation_mobility_instant.h mobility/metapopulation_mobility_instant.cpp mobility/metapopulation_mobility_stochastic.h @@ -70,6 +87,8 @@ add_library(memilio mobility/graph_simulation.cpp mobility/graph.h mobility/graph.cpp + + # Utilities utils/visitor.h utils/uncertain_value.h utils/uncertain_value.cpp @@ -95,36 +114,50 @@ add_library(memilio utils/miompi.cpp utils/mioomp.h utils/type_list.h + + #ad library + ad/ad.hpp ) +# Include directories for build and install interfaces target_include_directories(memilio PUBLIC - $ - $ # includes configured by cmake - $ + $ # Project root include dir (e.g., for memilio/...) + $ # For configured headers (config_internal.h) + $ # Standard install include dir ) -target_compile_features(memilio PUBLIC cxx_std_17) -target_link_libraries(memilio PUBLIC spdlog::spdlog Eigen3::Eigen Boost::boost Boost::filesystem Boost::disable_autolinking Random123 AD::AD) -target_compile_options(memilio - PRIVATE - ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS} - PUBLIC - $<$: /bigobj> +# Link core dependencies +target_link_libraries(memilio PUBLIC + spdlog::spdlog # Logging + Eigen3::Eigen # Linear algebra + Boost::boost # General Boost utilities (if needed directly) + Boost::filesystem # Filesystem operations + Boost::disable_autolinking # MSVC specific, ensure provided by FindBoost + Random123 # Random number generation (ensure target exists) ) +# Apply project-wide compiler settings +memilio_set_warning_flags(memilio) +memilio_set_sanitizer_flags(memilio) + + +# Optional dependencies if(MEMILIO_HAS_HDF5) - target_link_libraries(memilio PUBLIC ${HDF5_C_LIBRARIES}) - target_include_directories(memilio PUBLIC ${HDF5_INCLUDE_DIRS}) + message(STATUS "Linking memilio against HDF5") + target_link_libraries(memilio PUBLIC HDF5::HDF5) endif() if(MEMILIO_HAS_JSONCPP) + message(STATUS "Linking memilio against JsonCpp") target_link_libraries(memilio PUBLIC JsonCpp::JsonCpp) endif() if(MEMILIO_ENABLE_MPI) - target_link_libraries(memilio PUBLIC MPI::MPI_CXX) + message(STATUS "Linking memilio against MPI") + target_link_libraries(memilio PUBLIC MPI::MPI_CXX) endif() if(MEMILIO_ENABLE_OPENMP) - target_link_libraries(memilio PUBLIC OpenMP::OpenMP_CXX) + message(STATUS "Enabling OpenMP for memilio (interface)") + target_link_libraries(memilio INTERFACE OpenMP::OpenMP_CXX) endif() diff --git a/cpp/memilio/ad/CMakeLists.txt b/cpp/memilio/ad/CMakeLists.txt deleted file mode 100644 index e260bdcc7f..0000000000 --- a/cpp/memilio/ad/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -cmake_minimum_required(VERSION 3.5) -project(AD CXX) - -add_library(AD INTERFACE) -add_library(AD::AD ALIAS AD) - -target_include_directories(AD INTERFACE - $ - $) - -target_link_libraries(AD INTERFACE spdlog::spdlog) - -### installation related stuff #### - - install(TARGETS AD - EXPORT ADConfig - LIBRARY DESTINATION lib COMPONENT AD - ARCHIVE DESTINATION lib COMPONENT AD - RUNTIME DESTINATION bin COMPONENT AD - INCLUDES DESTINATION include) - - install(EXPORT ADConfig - FILE ADConfig.cmake - NAMESPACE AD:: - DESTINATION lib/cmake/ADConfig - COMPONENT AD) - - - install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" - DESTINATION "include" - COMPONENT AD - ) - \ No newline at end of file diff --git a/cpp/memilio/ad/include/ad/ad.hpp b/cpp/memilio/ad/ad.hpp similarity index 100% rename from cpp/memilio/ad/include/ad/ad.hpp rename to cpp/memilio/ad/ad.hpp diff --git a/cpp/memilio/config_internal.h.in b/cpp/memilio/config_internal.h.in index 5dd86c3a61..07983f513d 100644 --- a/cpp/memilio/config_internal.h.in +++ b/cpp/memilio/config_internal.h.in @@ -31,4 +31,6 @@ #cmakedefine MEMILIO_ENABLE_OPENMP #cmakedefine MEMILIO_ENABLE_PROFILING +const char* const MEMILIO_BASE_DIR = "${MEMILIO_BASE_DIR}"; + #endif diff --git a/cpp/examples/data_dir.h.in b/cpp/memilio/utils/base_dir.h similarity index 67% rename from cpp/examples/data_dir.h.in rename to cpp/memilio/utils/base_dir.h index 8f5dc001d5..7d3343b862 100644 --- a/cpp/examples/data_dir.h.in +++ b/cpp/memilio/utils/base_dir.h @@ -1,7 +1,8 @@ + /* * Copyright (C) 2020-2025 MEmilio * -* Authors: Daniel Abele +* Authors: Julia Bicker * * Contact: Martin J. Kuehn * @@ -17,9 +18,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef DATA_DIR_H -#define DATA_DIR_H +#ifndef MIO_UTILS_BASE_DIR_H +#define MIO_UTILS_BASE_DIR_H + +#include "memilio/config.h" +#include +namespace mio +{ +/** + * @brief Returns path to the repo directory. +*/ +inline const std::string memilio_dir() +{ + return MEMILIO_BASE_DIR; +} -const char* const DATA_DIR = "${MEMILIO_DATA_DIR}"; +} -#endif //DATA_DIR_H +#endif // MIO_UTILS_BASE_DIR_H \ No newline at end of file diff --git a/cpp/memilio/utils/logging.h b/cpp/memilio/utils/logging.h index b875d41812..eee245964d 100644 --- a/cpp/memilio/utils/logging.h +++ b/cpp/memilio/utils/logging.h @@ -27,7 +27,7 @@ #endif #include "memilio/utils/compiler_diagnostics.h" -#include "ad/ad.hpp" +#include "memilio/ad/ad.hpp" // C4996: Some stdext functions used in spdlog 1.11 are marked as deprecated in version 19.38.33135.0 of MSVC. Maybe a future version of spdlog will fix this. MSVC_WARNING_DISABLE_PUSH(4996) diff --git a/cpp/models/CMakeLists.txt b/cpp/models/CMakeLists.txt new file mode 100644 index 0000000000..e18ce067cf --- /dev/null +++ b/cpp/models/CMakeLists.txt @@ -0,0 +1,229 @@ +function(add_memilio_model MODEL_NAME) + if (${MODEL_NAME} STREQUAL "abm") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/abm/location.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/location.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/location_id.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/household.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/household.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/simulation.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/simulation.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/person.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/person.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/person_id.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/personal_rng.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/personal_rng.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/testing_strategy.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/testing_strategy.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/location_type.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/parameters.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/mobility_rules.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/mobility_rules.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/model_functions.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/model_functions.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/trip_list.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/trip_list.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/lockdown_rules.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/lockdown_rules.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/infection.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/infection.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/virus_variant.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/protection_event.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/mask.h" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/mask.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/abm/common_abm_loggers.h" + ) + elseif(${MODEL_NAME} STREQUAL "d_abm") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/d_abm/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/d_abm/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/d_abm/simulation.h" + "${CMAKE_CURRENT_SOURCE_DIR}/d_abm/simulation.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/d_abm/parameters.h" + ) + elseif(${MODEL_NAME} STREQUAL "glct_secir") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/glct_secir/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/glct_secir/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/glct_secir/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/glct_secir/parameters.h" + ) + elseif(${MODEL_NAME} STREQUAL "graph_abm") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/graph_abm/graph_abmodel.h" + "${CMAKE_CURRENT_SOURCE_DIR}/graph_abm/graph_abmodel.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/graph_abm/graph_abm_mobility.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/graph_abm/graph_abm_mobility.h" + ) + elseif(${MODEL_NAME} STREQUAL "ide_secir") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/ide_secir/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ide_secir/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ide_secir/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ide_secir/simulation.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ide_secir/simulation.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ide_secir/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ide_secir/parameters_io.h" + ) + elseif(${MODEL_NAME} STREQUAL "ide_seir") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/ide_seir/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ide_seir/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ide_seir/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ide_seir/infection_state.h" + ) + elseif(${MODEL_NAME} STREQUAL "lct_secir") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/lct_secir/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/lct_secir/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/lct_secir/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/lct_secir/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/lct_secir/initializer_flows.h" + "${CMAKE_CURRENT_SOURCE_DIR}/lct_secir/parameters_io.h" + ) + elseif(${MODEL_NAME} STREQUAL "ode_seair") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/ode_seair/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_seair/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_seair/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_seair/parameters.h" + ) + elseif(${MODEL_NAME} STREQUAL "ode_secir") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/analyze_result.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/analyze_result.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/parameter_space.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/parameter_space.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/parameters_io.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/parameters_io.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secir/model.cpp" + ) + elseif(${MODEL_NAME} STREQUAL "ode_secirts") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/analyze_result.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/analyze_result.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/parameter_space.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/parameter_space.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/parameters_io.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/parameters_io.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirts/model.cpp" + ) + elseif(${MODEL_NAME} STREQUAL "ode_secirvvs") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/analyze_result.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/analyze_result.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/parameter_space.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/parameter_space.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/parameters_io.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/parameters_io.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_secirvvs/model.cpp" + ) + elseif(${MODEL_NAME} STREQUAL "ode_seir") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/ode_seir/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_seir/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_seir/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_seir/parameters.h" + ) + elseif(${MODEL_NAME} STREQUAL "ode_sir") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/ode_sir/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_sir/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_sir/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ode_sir/parameters.h" + ) + elseif(${MODEL_NAME} STREQUAL "sde_seirvv") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/sde_seirvv/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_seirvv/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_seirvv/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_seirvv/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_seirvv/simulation.h" + ) + elseif(${MODEL_NAME} STREQUAL "sde_sir") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sir/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sir/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sir/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sir/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sir/simulation.h" + ) + elseif(${MODEL_NAME} STREQUAL "sde_sirs") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sirs/infection_state.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sirs/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sirs/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sirs/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sde_sirs/simulation.h" + ) + elseif(${MODEL_NAME} STREQUAL "smm") + set(MODEL_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/smm/parameters.h" + "${CMAKE_CURRENT_SOURCE_DIR}/smm/model.h" + "${CMAKE_CURRENT_SOURCE_DIR}/smm/model.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/smm/simulation.h" + "${CMAKE_CURRENT_SOURCE_DIR}/smm/simulation.cpp" + ) + else() + message(FATAL_ERROR "Source list not defined for model ${MODEL_NAME}") + endif() + + # Optional extra sources handling remains the same + foreach(EXTRA_SOURCE ${ARGN}) + list(APPEND MODEL_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/${EXTRA_SOURCE}") + endforeach() + + if(NOT MODEL_SOURCES) + message(WARNING "No sources specified for model '${MODEL_NAME}'. Skipping.") + return() + endif() + + add_library(${MODEL_NAME} ${MODEL_SOURCES}) # Use the explicitly set list + + target_link_libraries(${MODEL_NAME} PRIVATE memilio) + + # Includes, warnings, sanitizers remain the same + target_include_directories(${MODEL_NAME} PUBLIC + $ # Keep this for includes like "models/ode_secir/model.h" + $ + ) + memilio_set_warning_flags(${MODEL_NAME}) + memilio_set_sanitizer_flags(${MODEL_NAME}) + +endfunction() + +# --- Add Models --- +add_memilio_model(abm) +add_memilio_model(d_abm) +add_memilio_model(graph_abm) + +add_memilio_model(glct_secir) +add_memilio_model(lct_secir) + +add_memilio_model(ide_secir) +add_memilio_model(ide_seir) + +add_memilio_model(ode_seair) +add_memilio_model(ode_secir) +add_memilio_model(ode_secirts) +add_memilio_model(ode_secirvvs) +add_memilio_model(ode_seir) +add_memilio_model(ode_sir) + +add_memilio_model(sde_seirvv) +add_memilio_model(sde_sir) +add_memilio_model(sde_sirs) +add_memilio_model(smm) diff --git a/cpp/models/abm/CMakeLists.txt b/cpp/models/abm/CMakeLists.txt deleted file mode 100644 index 50ce4258f6..0000000000 --- a/cpp/models/abm/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -add_library(abm - location.cpp - location.h - location_id.h - household.cpp - household.h - simulation.cpp - simulation.h - person.cpp - person.h - person_id.h - personal_rng.cpp - personal_rng.h - testing_strategy.cpp - testing_strategy.h - model.cpp - model.h - location_type.h - parameters.h - parameters.cpp - mobility_rules.cpp - mobility_rules.h - model_functions.cpp - model_functions.h - trip_list.cpp - trip_list.h - lockdown_rules.cpp - lockdown_rules.h - infection.cpp - infection.h - infection_state.h - virus_variant.h - protection_event.h - mask.h - mask.cpp - common_abm_loggers.h -) -target_link_libraries(abm PUBLIC memilio) -target_include_directories(abm PUBLIC - $ - $ -) -target_compile_options(abm PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/d_abm/CMakeLists.txt b/cpp/models/d_abm/CMakeLists.txt deleted file mode 100644 index b1dfe1eceb..0000000000 --- a/cpp/models/d_abm/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_library(d_abm - model.h - model.cpp - simulation.h - simulation.cpp - parameters.h -) -target_link_libraries(d_abm PUBLIC memilio) -target_include_directories(d_abm PUBLIC - $ - $ -) -target_compile_options(d_abm PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/glct_secir/CMakeLists.txt b/cpp/models/glct_secir/CMakeLists.txt deleted file mode 100644 index 4534e383ef..0000000000 --- a/cpp/models/glct_secir/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_library(glct_secir - infection_state.h - model.h - model.cpp - parameters.h -) -target_link_libraries(glct_secir PUBLIC memilio) -target_include_directories(glct_secir PUBLIC - $ - $ -) -target_compile_options(glct_secir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) \ No newline at end of file diff --git a/cpp/models/graph_abm/CMakeLists.txt b/cpp/models/graph_abm/CMakeLists.txt deleted file mode 100644 index 982b3512c3..0000000000 --- a/cpp/models/graph_abm/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -add_library(graph_abm - graph_abmodel.h - graph_abmodel.cpp - graph_abm_mobility.cpp - graph_abm_mobility.h -) - -target_link_libraries(graph_abm PUBLIC memilio) -target_include_directories(graph_abm PUBLIC - $ - $ -) - -target_compile_options(graph_abm PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ide_secir/CMakeLists.txt b/cpp/models/ide_secir/CMakeLists.txt deleted file mode 100644 index 4ee0cd4dae..0000000000 --- a/cpp/models/ide_secir/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_library(ide_secir - infection_state.h - model.h - model.cpp - simulation.h - simulation.cpp - parameters.h - parameters_io.h -) -target_link_libraries(ide_secir PUBLIC memilio) -target_include_directories(ide_secir PUBLIC - $ - $ -) -target_compile_options(ide_secir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ide_seir/CMakeLists.txt b/cpp/models/ide_seir/CMakeLists.txt deleted file mode 100755 index c706715363..0000000000 --- a/cpp/models/ide_seir/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_library(ide_seir - model.h - model.cpp - parameters.h - infection_state.h -) -target_link_libraries(ide_seir PUBLIC memilio) -target_include_directories(ide_seir PUBLIC - $ - $ -) -target_compile_options(ide_seir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/lct_secir/CMakeLists.txt b/cpp/models/lct_secir/CMakeLists.txt deleted file mode 100644 index d10ab7b98d..0000000000 --- a/cpp/models/lct_secir/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -add_library(lct_secir - infection_state.h - model.h - model.cpp - parameters.h - initializer_flows.h - parameters_io.h -) -target_link_libraries(lct_secir PUBLIC memilio) -target_include_directories(lct_secir PUBLIC - $ - $ -) -target_compile_options(lct_secir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_seair/CMakeLists.txt b/cpp/models/ode_seair/CMakeLists.txt deleted file mode 100644 index 550585cc73..0000000000 --- a/cpp/models/ode_seair/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_library(ode_seair - infection_state.h - model.h - model.cpp - parameters.h -) - -target_link_libraries(ode_seair PUBLIC memilio AD::AD) -target_include_directories(ode_seair PUBLIC - $ - $ -) -target_compile_options(ode_seair PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_secir/CMakeLists.txt b/cpp/models/ode_secir/CMakeLists.txt deleted file mode 100644 index 0c27cebbe3..0000000000 --- a/cpp/models/ode_secir/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -add_library(ode_secir - analyze_result.h - analyze_result.cpp - infection_state.h - parameter_space.h - parameter_space.cpp - parameters.h - parameters_io.h - parameters_io.cpp - model.h - model.cpp -) -target_link_libraries(ode_secir PUBLIC memilio) -target_include_directories(ode_secir PUBLIC - $ - $ -) -target_compile_options(ode_secir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_secirts/CMakeLists.txt b/cpp/models/ode_secirts/CMakeLists.txt deleted file mode 100644 index 07f1970526..0000000000 --- a/cpp/models/ode_secirts/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -add_library(ode_secirts - analyze_result.h - analyze_result.cpp - infection_state.h - parameter_space.h - parameter_space.cpp - parameters.h - parameters_io.h - parameters_io.cpp - model.h - model.cpp -) -target_link_libraries(ode_secirts PUBLIC memilio) -target_include_directories(ode_secirts PUBLIC - $ - $ -) -target_compile_options(ode_secirts PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_secirts/parameters_io.cpp b/cpp/models/ode_secirts/parameters_io.cpp index 2fa7f3b3d5..6cedca5838 100644 --- a/cpp/models/ode_secirts/parameters_io.cpp +++ b/cpp/models/ode_secirts/parameters_io.cpp @@ -18,11 +18,20 @@ * limitations under the License. */ +#include "memilio/utils/compiler_diagnostics.h" + +//see below for line that causes this warning +GCC_CLANG_DIAGNOSTIC(push) +GCC_CLANG_DIAGNOSTIC(ignored "-Wmaybe-uninitialized") + #include "ode_secirts/parameters_io.h" #include "memilio/geography/regions.h" #include "memilio/io/io.h" #include "ode_secirts/parameters.h" + + + #ifdef MEMILIO_HAS_JSONCPP #include "memilio/io/epi_data.h" @@ -97,3 +106,4 @@ IOResult>> read_population_data(const std::vecto } // namespace mio #endif // MEMILIO_HAS_JSONCPP +GCC_CLANG_DIAGNOSTIC(pop) \ No newline at end of file diff --git a/cpp/models/ode_secirvvs/CMakeLists.txt b/cpp/models/ode_secirvvs/CMakeLists.txt deleted file mode 100644 index 67454ae88b..0000000000 --- a/cpp/models/ode_secirvvs/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -add_library(ode_secirvvs - analyze_result.h - analyze_result.cpp - infection_state.h - parameter_space.h - parameter_space.cpp - parameters.h - parameters_io.h - parameters_io.cpp - model.h - model.cpp -) -target_link_libraries(ode_secirvvs PUBLIC memilio) -target_include_directories(ode_secirvvs PUBLIC - $ - $ -) -target_compile_options(ode_secirvvs PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_secirvvs/parameters_io.cpp b/cpp/models/ode_secirvvs/parameters_io.cpp index 32132cbf8e..53521dfc90 100644 --- a/cpp/models/ode_secirvvs/parameters_io.cpp +++ b/cpp/models/ode_secirvvs/parameters_io.cpp @@ -17,6 +17,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + + +#include "memilio/utils/compiler_diagnostics.h" + +//see below for line that causes this warning +GCC_CLANG_DIAGNOSTIC(push) +GCC_CLANG_DIAGNOSTIC(ignored "-Wmaybe-uninitialized") + + #include "memilio/config.h" #ifdef MEMILIO_HAS_JSONCPP @@ -354,3 +363,4 @@ IOResult>> read_population_data(const std::vecto } // namespace mio #endif // MEMILIO_HAS_JSONCPP +GCC_CLANG_DIAGNOSTIC(pop) \ No newline at end of file diff --git a/cpp/models/ode_seir/CMakeLists.txt b/cpp/models/ode_seir/CMakeLists.txt deleted file mode 100644 index c94c6b0aa7..0000000000 --- a/cpp/models/ode_seir/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_library(ode_seir - infection_state.h - model.h - model.cpp - parameters.h -) -target_link_libraries(ode_seir PUBLIC memilio) -target_include_directories(ode_seir PUBLIC - $ - $ -) -target_compile_options(ode_seir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_sir/CMakeLists.txt b/cpp/models/ode_sir/CMakeLists.txt deleted file mode 100644 index 1ff538927f..0000000000 --- a/cpp/models/ode_sir/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_library(ode_sir - infection_state.h - model.h - model.cpp - parameters.h -) -target_link_libraries(ode_sir PUBLIC memilio) -target_include_directories(ode_sir PUBLIC - $ - $ -) -target_compile_options(ode_sir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/sde_seirvv/CMakeLists.txt b/cpp/models/sde_seirvv/CMakeLists.txt deleted file mode 100644 index dfee7132de..0000000000 --- a/cpp/models/sde_seirvv/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_library(sde_seirvv - infection_state.h - model.h - model.cpp - parameters.h - simulation.h -) -target_link_libraries(sde_seirvv PUBLIC memilio) -target_include_directories(sde_seirvv PUBLIC - $ - $ -) -target_compile_options(sde_seirvv PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/sde_sir/CMakeLists.txt b/cpp/models/sde_sir/CMakeLists.txt deleted file mode 100644 index 7862ad7195..0000000000 --- a/cpp/models/sde_sir/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_library(sde_sir - infection_state.h - model.h - model.cpp - parameters.h - simulation.h -) -target_link_libraries(sde_sir PUBLIC memilio) -target_include_directories(sde_sir PUBLIC - $ - $ -) -target_compile_options(sde_sir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/sde_sirs/CMakeLists.txt b/cpp/models/sde_sirs/CMakeLists.txt deleted file mode 100644 index 14bf6a8b4b..0000000000 --- a/cpp/models/sde_sirs/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_library(sde_sirs - infection_state.h - model.h - model.cpp - parameters.h - simulation.h -) -target_link_libraries(sde_sirs PUBLIC memilio) -target_include_directories(sde_sirs PUBLIC - $ - $ -) -target_compile_options(sde_sirs PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/smm/CMakeLists.txt b/cpp/models/smm/CMakeLists.txt deleted file mode 100644 index 74996b370f..0000000000 --- a/cpp/models/smm/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_library(smm - parameters.h - model.h - model.cpp - simulation.h - simulation.cpp -) -target_link_libraries(smm PUBLIC memilio) -target_include_directories(smm PUBLIC - $ - $ -) -target_compile_options(smm PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/simulations/2020_npis_sarscov2_wildtype_germany.cpp b/cpp/simulations/2020_npis_sarscov2_wildtype_germany.cpp deleted file mode 100644 index 2729b3f4ba..0000000000 --- a/cpp/simulations/2020_npis_sarscov2_wildtype_germany.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/* -* Copyright (C) 2020-2025 MEmilio -* -* Authors: Daniel Abele -* -* Contact: Martin J. Kuehn -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "memilio/compartments/parameter_studies.h" -#include "memilio/geography/regions.h" -#include "memilio/io/epi_data.h" -#include "memilio/io/result_io.h" -#include "memilio/io/mobility_io.h" -#include "memilio/mobility/metapopulation_mobility_instant.h" -#include "memilio/utils/miompi.h" -#include "memilio/utils/random_number_generator.h" -#include "ode_secir/parameters_io.h" -#include "ode_secir/parameter_space.h" -#include "memilio/utils/stl_util.h" -#include "boost/filesystem.hpp" -#include -#include - -namespace fs = boost::filesystem; - -/** - * indices of contact matrix corresponding to locations where contacts occur. - */ -enum class ContactLocation -{ - Home = 0, - School, - Work, - Other, - Count, -}; - -/** - * different types of NPI, used as DampingType. - */ -enum class Intervention -{ - Home, - SchoolClosure, - HomeOffice, - GatheringBanFacilitiesClosure, - PhysicalDistanceAndMasks, - SeniorAwareness, -}; - -/** - * different level of NPI, used as DampingLevel. - */ -enum class InterventionLevel -{ - Main, - PhysicalDistanceAndMasks, - SeniorAwareness, - Holidays, -}; - -/** - * Set a value and distribution of an UncertainValue. - * Assigns average of min and max as a value and UNIFORM(min, max) as a distribution. - * @param p uncertain value to set. - * @param min minimum of distribution. - * @param max minimum of distribution. - */ -void assign_uniform_distribution(mio::UncertainValue& p, double min, double max) -{ - p = mio::UncertainValue(0.5 * (max + min)); - p.set_distribution(mio::ParameterDistributionUniform(min, max)); -} - -/** - * Set a value and distribution of an array of UncertainValues. - * Assigns average of min[i] and max[i] as a value and UNIFORM(min[i], max[i]) as a distribution for - * each element i of the array. - * @param array array of UncertainValues to set. - * @param min minimum of distribution for each element of array. - * @param max minimum of distribution for each element of array. - */ -template -void array_assign_uniform_distribution(mio::CustomIndexArray, mio::AgeGroup>& array, - const double (&min)[N], const double (&max)[N]) -{ - assert(N == array.numel()); - for (auto i = mio::AgeGroup(0); i < mio::AgeGroup(N); ++i) { - assign_uniform_distribution(array[i], min[size_t(i)], max[size_t(i)]); - } -} - -/** - * Set a value and distribution of an array of UncertainValues. - * Assigns average of min and max as a value and UNIFORM(min, max) as a distribution to every element of the array. - * @param array array of UncertainValues to set. - * @param min minimum of distribution. - * @param max minimum of distribution. - */ -void array_assign_uniform_distribution(mio::CustomIndexArray, mio::AgeGroup>& array, - double min, double max) -{ - for (auto i = mio::AgeGroup(0); i < array.size(); ++i) { - assign_uniform_distribution(array[i], min, max); - } -} - -/** - * Set epidemiological parameters of Sars-CoV-2 for a immune-naive - * population and wild type variant. - * @param params Object that the parameters will be added to. - * @returns Currently generates no errors. - */ -mio::IOResult set_covid_parameters(mio::osecir::Parameters& params) -{ - //times - // TimeExposed and TimeInfectedNoSymptoms are calculated as described in - // Khailaie et al. (https://doi.org/10.1186/s12916-020-01884-4) - // given SI_min = 3.935, SI_max = 4.6, INC = 5.2 - const double timeExposedMin = 2.67; - const double timeExposedMax = 4.; - const double timeInfectedNoSymptomsMin = 1.2; - const double timeInfectedNoSymptomsMax = 2.53; - - const double timeInfectedSymptomsMin[] = {5.6255, 5.6255, 5.6646, 5.5631, 5.501, 5.465}; - const double timeInfectedSymptomsMax[] = {8.427, 8.427, 8.4684, 8.3139, 8.169, 8.085}; - const double timeInfectedSevereMin[] = {3.925, 3.925, 4.85, 6.4, 7.2, 9.}; - const double timeInfectedSevereMax[] = {6.075, 6.075, 7., 8.7, 9.8, 13.}; - const double timeInfectedCriticalMin[] = {4.95, 4.95, 4.86, 14.14, 14.4, 10.}; - const double timeInfectedCriticalMax[] = {8.95, 8.95, 8.86, 20.58, 19.8, 13.2}; - - array_assign_uniform_distribution(params.get>(), timeExposedMin, timeExposedMax); - array_assign_uniform_distribution(params.get>(), - timeInfectedNoSymptomsMin, timeInfectedNoSymptomsMax); - array_assign_uniform_distribution(params.get>(), timeInfectedSymptomsMin, - timeInfectedSymptomsMax); - array_assign_uniform_distribution(params.get>(), timeInfectedSevereMin, - timeInfectedSevereMax); - array_assign_uniform_distribution(params.get>(), timeInfectedCriticalMin, - timeInfectedCriticalMax); - - //probabilities - const double transmissionProbabilityOnContactMin[] = {0.02, 0.05, 0.05, 0.05, 0.08, 0.15}; - const double transmissionProbabilityOnContactMax[] = {0.04, 0.07, 0.07, 0.07, 0.10, 0.20}; - const double relativeTransmissionNoSymptomsMin = 1; - const double relativeTransmissionNoSymptomsMax = 1; - // The precise value between Risk* (situation under control) and MaxRisk* (situation not under control) - // depends on incidence and test and trace capacity - const double riskOfInfectionFromSymptomaticMin = 0.1; - const double riskOfInfectionFromSymptomaticMax = 0.3; - const double maxRiskOfInfectionFromSymptomaticMin = 0.3; - const double maxRiskOfInfectionFromSymptomaticMax = 0.5; - const double recoveredPerInfectedNoSymptomsMin[] = {0.2, 0.2, 0.15, 0.15, 0.15, 0.15}; - const double recoveredPerInfectedNoSymptomsMax[] = {0.3, 0.3, 0.25, 0.25, 0.25, 0.25}; - const double severePerInfectedSymptomsMin[] = {0.006, 0.006, 0.015, 0.049, 0.15, 0.20}; - const double severePerInfectedSymptomsMax[] = {0.009, 0.009, 0.023, 0.074, 0.18, 0.25}; - const double criticalPerSevereMin[] = {0.05, 0.05, 0.05, 0.10, 0.25, 0.35}; - const double criticalPerSevereMax[] = {0.10, 0.10, 0.10, 0.20, 0.35, 0.45}; - const double deathsPerCriticalMin[] = {0.00, 0.00, 0.10, 0.10, 0.30, 0.5}; - const double deathsPerCriticalMax[] = {0.10, 0.10, 0.18, 0.18, 0.50, 0.7}; - - array_assign_uniform_distribution(params.get>(), - transmissionProbabilityOnContactMin, transmissionProbabilityOnContactMax); - array_assign_uniform_distribution(params.get>(), - relativeTransmissionNoSymptomsMin, relativeTransmissionNoSymptomsMax); - array_assign_uniform_distribution(params.get>(), - riskOfInfectionFromSymptomaticMin, riskOfInfectionFromSymptomaticMax); - array_assign_uniform_distribution(params.get>(), - maxRiskOfInfectionFromSymptomaticMin, maxRiskOfInfectionFromSymptomaticMax); - array_assign_uniform_distribution(params.get>(), - recoveredPerInfectedNoSymptomsMin, recoveredPerInfectedNoSymptomsMax); - array_assign_uniform_distribution(params.get>(), - severePerInfectedSymptomsMin, severePerInfectedSymptomsMax); - array_assign_uniform_distribution(params.get>(), criticalPerSevereMin, - criticalPerSevereMax); - array_assign_uniform_distribution(params.get>(), deathsPerCriticalMin, - deathsPerCriticalMax); - - //sasonality - const double seasonality_min = 0.1; - const double seasonality_max = 0.3; - - assign_uniform_distribution(params.get>(), seasonality_min, seasonality_max); - - return mio::success(); -} - -static const std::map contact_locations = {{ContactLocation::Home, "home"}, - {ContactLocation::School, "school_pf_eig"}, - {ContactLocation::Work, "work"}, - {ContactLocation::Other, "other"}}; - -/** - * Set contact matrices. - * Reads contact matrices from files in the data directory. - * @param data_dir data directory. - * @param params Object that the contact matrices will be added to. - * @returns any io errors that happen during reading of the files. - */ -mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::osecir::Parameters& params) -{ - //TODO: io error handling - auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_groups())); - for (auto&& contact_location : contact_locations) { - BOOST_OUTCOME_TRY( - auto&& baseline, - mio::read_mobility_plain( - (data_dir / "Germany" / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); - BOOST_OUTCOME_TRY( - auto&& minimum, - mio::read_mobility_plain( - (data_dir / "Germany" / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); - contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; - contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; - } - params.get>() = mio::UncertainContactMatrix(contact_matrices); - - return mio::success(); -} - -/** - * Set NPIs. - * @param start_date start date of the simulation. - * @param end_date end date of the simulation. - * @param params Object that the NPIs will be added to. - * @returns Currently generates no errors. - */ -mio::IOResult set_npis(mio::Date start_date, mio::Date end_date, mio::osecir::Parameters& params) -{ - auto& contacts = params.get>(); - auto& contact_dampings = contacts.get_dampings(); - - //weights for age groups affected by an NPI - auto group_weights_all = Eigen::VectorXd::Constant(size_t(params.get_num_groups()), 1.0); - auto group_weights_seniors = Eigen::VectorXd::NullaryExpr(size_t(params.get_num_groups()), [](auto&& i) { - return i == 5 ? 1.0 : i == 4 ? 0.5 : 0.0; //65-80 only partially - }); - - //helper functions that create dampings for specific NPIs - auto contacts_at_home = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::Home)), t, - {size_t(ContactLocation::Home)}, group_weights_all); - }; - auto school_closure = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::SchoolClosure)), t, - {size_t(ContactLocation::School)}, group_weights_all); - }; - auto home_office = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::HomeOffice)), t, - {size_t(ContactLocation::Work)}, group_weights_all); - }; - auto social_events = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::GatheringBanFacilitiesClosure)), t, - {size_t(ContactLocation::Other)}, group_weights_all); - }; - auto social_events_work = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::GatheringBanFacilitiesClosure)), t, - {size_t(ContactLocation::Work)}, group_weights_all); - }; - auto physical_distancing_home_school = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::PhysicalDistanceAndMasks)), - mio::DampingType(int(Intervention::PhysicalDistanceAndMasks)), t, - {size_t(ContactLocation::Home), size_t(ContactLocation::School)}, - group_weights_all); - }; - auto physical_distancing_work_other = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::PhysicalDistanceAndMasks)), - mio::DampingType(int(Intervention::PhysicalDistanceAndMasks)), t, - {size_t(ContactLocation::Work), size_t(ContactLocation::Other)}, - group_weights_all); - }; - auto senior_awareness = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::SeniorAwareness)), - mio::DampingType(int(Intervention::SeniorAwareness)), t, - {size_t(ContactLocation::Home), size_t(ContactLocation::Other)}, - group_weights_seniors); - }; - - //SPRING 2020 LOCKDOWN SCENARIO - auto start_spring_date = mio::Date(2020, 3, 18); - if (start_spring_date < end_date) { - auto start_spring = mio::SimulationTime(mio::get_offset_in_days(start_spring_date, start_date)); - contact_dampings.push_back(contacts_at_home(start_spring, 0.6, 0.8)); - contact_dampings.push_back(school_closure(start_spring, 1.0, 1.0)); - contact_dampings.push_back(home_office(start_spring, 0.2, 0.3)); - contact_dampings.push_back(social_events(start_spring, 0.6, 0.8)); - contact_dampings.push_back(social_events_work(start_spring, 0.1, 0.2)); - contact_dampings.push_back(physical_distancing_home_school(start_spring, 0.4, 0.6)); - contact_dampings.push_back(physical_distancing_work_other(start_spring, 0.4, 0.6)); - contact_dampings.push_back(senior_awareness(start_spring, 0.0, 0.0)); - } - - // SUMMER 2020 SCENARIO - auto start_summer_date = mio::Date(2020, 5, 15); - if (start_summer_date < end_date) { - auto start_summer = mio::SimulationTime(mio::get_offset_in_days(start_summer_date, start_date)); - auto school_reopen_time = mio::SimulationTime(mio::get_offset_in_days(mio::Date(2020, 6, 15), start_date)); - contact_dampings.push_back(contacts_at_home(start_summer, 0.0, 0.2)); - contact_dampings.push_back(school_closure(start_summer, 0.5, 0.5)); //schools partially reopened - contact_dampings.push_back(school_closure(school_reopen_time, 0.0, 0.0)); //school fully reopened - contact_dampings.push_back(home_office(start_summer, 0.2, 0.3)); - contact_dampings.push_back(social_events(start_summer, 0.0, 0.2)); - contact_dampings.push_back(social_events_work(start_summer, 0.0, 0.05)); - contact_dampings.push_back(physical_distancing_home_school(start_summer, 0.0, 0.2)); - contact_dampings.push_back(physical_distancing_work_other(start_summer, 0.0, 0.2)); - contact_dampings.push_back(senior_awareness(start_summer, 0.0, 0.0)); - } - - //autumn enforced attention - auto start_autumn_date = mio::Date(2020, 10, 1); - if (start_autumn_date < end_date) { - auto start_autumn = mio::SimulationTime(mio::get_offset_in_days(start_autumn_date, start_date)); - contact_dampings.push_back(contacts_at_home(start_autumn, 0.2, 0.4)); - contact_dampings.push_back(physical_distancing_home_school(start_autumn, 0.2, 0.4)); - contact_dampings.push_back(physical_distancing_work_other(start_autumn, 0.2, 0.4)); - } - - //autumn lockdown light - auto start_autumn_lockdown_date = mio::Date(2020, 11, 1); - if (start_autumn_lockdown_date < end_date) { - auto start_autumn_lockdown = - mio::SimulationTime(mio::get_offset_in_days(start_autumn_lockdown_date, start_date)); - contact_dampings.push_back(contacts_at_home(start_autumn_lockdown, 0.4, 0.6)); - contact_dampings.push_back(school_closure(start_autumn_lockdown, 0.0, 0.0)); - contact_dampings.push_back(home_office(start_autumn_lockdown, 0.2, 0.3)); - contact_dampings.push_back(social_events(start_autumn_lockdown, 0.6, 0.8)); - contact_dampings.push_back(social_events_work(start_autumn_lockdown, 0.0, 0.1)); - contact_dampings.push_back(physical_distancing_home_school(start_autumn_lockdown, 0.2, 0.4)); - contact_dampings.push_back(physical_distancing_work_other(start_autumn_lockdown, 0.4, 0.6)); - contact_dampings.push_back(senior_awareness(start_autumn_lockdown, 0.0, 0.0)); - } - - //winter lockdown - auto start_winter_lockdown_date = mio::Date(2020, 12, 16); - if (start_winter_lockdown_date < end_date) { - double min = 0.6, max = 0.8; //for strictest scenario: 0.8 - 1.0 - auto start_winter_lockdown = - mio::SimulationTime(mio::get_offset_in_days(start_winter_lockdown_date, start_date)); - contact_dampings.push_back(contacts_at_home(start_winter_lockdown, min, max)); - contact_dampings.push_back(school_closure(start_winter_lockdown, 1.0, 1.0)); - contact_dampings.push_back(home_office(start_winter_lockdown, 0.2, 0.3)); - contact_dampings.push_back(social_events(start_winter_lockdown, min, max)); - contact_dampings.push_back(social_events_work(start_winter_lockdown, 0.1, 0.2)); - contact_dampings.push_back(physical_distancing_home_school(start_winter_lockdown, 0.2, 0.4)); - contact_dampings.push_back(physical_distancing_work_other(start_winter_lockdown, min, max)); - contact_dampings.push_back(senior_awareness(start_winter_lockdown, 0.0, 0.0)); - - //relaxing of restrictions over christmas days - auto xmas_date = mio::Date(2020, 12, 24); - auto xmas = mio::SimulationTime(mio::get_offset_in_days(xmas_date, start_date)); - contact_dampings.push_back(contacts_at_home(xmas, 0.0, 0.0)); - contact_dampings.push_back(home_office(xmas, 0.4, 0.5)); - contact_dampings.push_back(social_events(xmas, 0.4, 0.6)); - contact_dampings.push_back(physical_distancing_home_school(xmas, 0.0, 0.0)); - contact_dampings.push_back(physical_distancing_work_other(xmas, 0.4, 0.6)); - - // after christmas - auto after_xmas_date = mio::Date(2020, 12, 27); - auto after_xmas = mio::SimulationTime(mio::get_offset_in_days(after_xmas_date, start_date)); - contact_dampings.push_back(contacts_at_home(after_xmas, min, max)); - contact_dampings.push_back(home_office(after_xmas, 0.2, 0.3)); - contact_dampings.push_back(social_events(after_xmas, 0.6, 0.8)); - contact_dampings.push_back(physical_distancing_home_school(after_xmas, 0.2, 0.4)); - contact_dampings.push_back(physical_distancing_work_other(after_xmas, min, max)); - } - - //local dynamic NPIs - auto& dynamic_npis = params.get>(); - auto dynamic_npi_dampings = std::vector>(); - dynamic_npi_dampings.push_back( - contacts_at_home(mio::SimulationTime(0), 0.6, 0.8)); // increased from [0.4, 0.6] in Nov - dynamic_npi_dampings.push_back(school_closure(mio::SimulationTime(0), 0.25, 0.25)); // see paper - dynamic_npi_dampings.push_back(home_office(mio::SimulationTime(0), 0.2, 0.3)); // ... - dynamic_npi_dampings.push_back(social_events(mio::SimulationTime(0), 0.6, 0.8)); - dynamic_npi_dampings.push_back(social_events_work(mio::SimulationTime(0), 0.1, 0.2)); - dynamic_npi_dampings.push_back(physical_distancing_home_school(mio::SimulationTime(0), 0.6, 0.8)); - dynamic_npi_dampings.push_back(physical_distancing_work_other(mio::SimulationTime(0), 0.6, 0.8)); - dynamic_npi_dampings.push_back(senior_awareness(mio::SimulationTime(0), 0.0, 0.0)); - dynamic_npis.set_interval(mio::SimulationTime(3.0)); - dynamic_npis.set_duration(mio::SimulationTime(14.0)); - dynamic_npis.set_base_value(100'000); - dynamic_npis.set_threshold(200.0, dynamic_npi_dampings); - - //school holidays (holiday periods are set per node, see set_nodes) - auto school_holiday_value = mio::UncertainValue(); - assign_uniform_distribution(school_holiday_value, 1.0, 1.0); - contacts.get_school_holiday_damping() = - mio::DampingSampling(school_holiday_value, mio::DampingLevel(int(InterventionLevel::Holidays)), - mio::DampingType(int(Intervention::SchoolClosure)), mio::SimulationTime(0.0), - {size_t(ContactLocation::School)}, group_weights_all); - - return mio::success(); -} - -/** - * Set synthetic population data for testing. - * Same total populaton but different spread of infection in each county. - * @param counties parameters for each county. - */ -void set_synthetic_population_data(std::vector>& counties) -{ - for (size_t county_idx = 0; county_idx < counties.size(); ++county_idx) { - double nb_total_t0 = 10000, nb_exp_t0 = 2, nb_inf_t0 = 0, nb_car_t0 = 0, nb_hosp_t0 = 0, nb_icu_t0 = 0, - nb_rec_t0 = 0, nb_dead_t0 = 0; - - nb_exp_t0 = (double)(county_idx % 10 + 1) * 3; - - for (mio::AgeGroup i = 0; i < counties[county_idx].parameters.get_num_groups(); i++) { - counties[county_idx].populations[{i, mio::osecir::InfectionState::Exposed}] = nb_exp_t0; - counties[county_idx].populations[{i, mio::osecir::InfectionState::InfectedNoSymptoms}] = nb_car_t0; - counties[county_idx].populations[{i, mio::osecir::InfectionState::InfectedSymptoms}] = nb_inf_t0; - counties[county_idx].populations[{i, mio::osecir::InfectionState::InfectedSevere}] = nb_hosp_t0; - counties[county_idx].populations[{i, mio::osecir::InfectionState::InfectedCritical}] = nb_icu_t0; - counties[county_idx].populations[{i, mio::osecir::InfectionState::Recovered}] = nb_rec_t0; - counties[county_idx].populations[{i, mio::osecir::InfectionState::Dead}] = nb_dead_t0; - counties[county_idx].populations.set_difference_from_group_total( - {i, mio::osecir::InfectionState::Susceptible}, nb_total_t0); - } - } -} - -/** - * Create the input graph for the parameter study. - * Reads files from the data directory. - * @param start_date start date of the simulation. - * @param end_date end date of the simulation. - * @param data_dir data directory. - * @returns created graph or any io errors that happen during reading of the files. - */ -mio::IOResult, mio::MobilityParameters>> -get_graph(mio::Date start_date, mio::Date end_date, const fs::path& data_dir) -{ - const auto start_day = mio::get_day_in_year(start_date); - - // global parameters - const int num_age_groups = 6; - mio::osecir::Parameters params(num_age_groups); - params.get() = start_day; - BOOST_OUTCOME_TRY(set_covid_parameters(params)); - BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, params)); - BOOST_OUTCOME_TRY(set_npis(start_date, end_date, params)); - - auto scaling_factor_infected = std::vector(size_t(params.get_num_groups()), 2.5); - auto scaling_factor_icu = 1.0; - auto tnt_capacity_factor = 7.5 / 100000.; - auto mobile_compartments = {mio::osecir::InfectionState::Susceptible, mio::osecir::InfectionState::Exposed, - mio::osecir::InfectionState::InfectedNoSymptoms, - mio::osecir::InfectionState::InfectedSymptoms, mio::osecir::InfectionState::Recovered}; - - // graph of counties with populations and local parameters - // and mobility between counties - mio::Graph, mio::MobilityParameters> params_graph; - const auto& read_function_nodes = mio::osecir::read_input_data_county>; - const auto& read_function_edges = mio::read_mobility_plain; - const auto& node_id_function = mio::get_node_ids; - - const auto data_dir_Germany = mio::path_join(data_dir.string(), "Germany"); - - const auto mobility_data_file = mio::path_join(data_dir_Germany, "mobility", "commuter_mobility_2022.txt"); - const auto pydata_dir = mio::path_join(data_dir_Germany, "pydata"); - - const auto& set_node_function = - mio::set_nodes, mio::osecir::ContactPatterns, - mio::osecir::Model, mio::MobilityParameters, mio::osecir::Parameters, - decltype(read_function_nodes), decltype(node_id_function)>; - const auto& set_edge_function = - mio::set_edges, mio::MobilityParameters, - mio::MobilityCoefficientGroup, mio::osecir::InfectionState, decltype(read_function_edges)>; - BOOST_OUTCOME_TRY(set_node_function(params, start_date, end_date, pydata_dir, - mio::path_join(pydata_dir, "county_current_population.json"), true, - params_graph, read_function_nodes, node_id_function, scaling_factor_infected, - scaling_factor_icu, tnt_capacity_factor, 0, false, true)); - BOOST_OUTCOME_TRY(set_edge_function(mobility_data_file, params_graph, mobile_compartments, contact_locations.size(), - read_function_edges, std::vector{0., 0., 1.0, 1.0, 0.33, 0., 0.}, - {})); - - return mio::success(params_graph); -} - -/** - * Different modes for running the parameter study. - */ -enum class RunMode -{ - Load, - Save, -}; - -/** - * Run the parameter study. - * Load a previously stored graph or create a new one from data. - * The graph is the input for the parameter study. - * A newly created graph is saved and can be reused. - * @param mode Mode for running the parameter study. - * @param data_dir data directory. Not used if mode is RunMode::Load. - * @param save_dir directory where the graph is loaded from if mode is RunMOde::Load or save to if mode is RunMode::Save. - * @param result_dir directory where all results of the parameter study will be stored. - * @param save_single_runs [Default: true] Defines if single run results are written to the disk. - * @returns any io error that occurs during reading or writing of files. - */ -mio::IOResult run(RunMode mode, const fs::path& data_dir, const fs::path& save_dir, const fs::path& result_dir, - bool save_single_runs = true) -{ - const auto start_date = mio::Date(2020, 12, 12); - const auto num_days_sim = 5.0; - const auto end_date = mio::offset_date_by_days(start_date, int(std::ceil(num_days_sim))); - const auto num_runs = 5; - - //create or load graph - mio::Graph, mio::MobilityParameters> params_graph; - if (mode == RunMode::Save) { - BOOST_OUTCOME_TRY(auto&& created, get_graph(start_date, end_date, data_dir)); - BOOST_OUTCOME_TRY(write_graph(created, save_dir.string())); - params_graph = created; - } - else { - BOOST_OUTCOME_TRY(auto&& loaded, mio::read_graph>(save_dir.string())); - params_graph = loaded; - } - - std::vector county_ids(params_graph.nodes().size()); - std::transform(params_graph.nodes().begin(), params_graph.nodes().end(), county_ids.begin(), [](auto& n) { - return n.id; - }); - - //run parameter study - auto parameter_study = - mio::ParameterStudy>{params_graph, 0.0, num_days_sim, 0.5, size_t(num_runs)}; - - // parameter_study.get_rng().seed( - // {114381446, 2427727386, 806223567, 832414962, 4121923627, 1581162203}); //set seeds, e.g., for debugging - if (mio::mpi::is_root()) { - printf("Seeds: "); - for (auto s : parameter_study.get_rng().get_seeds()) { - printf("%u, ", s); - } - printf("\n"); - } - - auto save_single_run_result = mio::IOResult(mio::success()); - auto ensemble = parameter_study.run( - [](auto&& graph) { - return draw_sample(graph); - }, - [&](auto results_graph, auto&& run_idx) { - auto interpolated_result = mio::interpolate_simulation_result(results_graph); - - auto params = std::vector>{}; - params.reserve(results_graph.nodes().size()); - std::transform(results_graph.nodes().begin(), results_graph.nodes().end(), std::back_inserter(params), - [](auto&& node) { - return node.property.get_simulation().get_model(); - }); - - if (save_single_run_result && save_single_runs) { - save_single_run_result = - save_result_with_params(interpolated_result, params, county_ids, result_dir, run_idx); - } - return std::make_pair(std::move(interpolated_result), std::move(params)); - }); - - if (ensemble.size() > 0) { - auto ensemble_results = std::vector>>{}; - ensemble_results.reserve(ensemble.size()); - auto ensemble_params = std::vector>>{}; - ensemble_params.reserve(ensemble.size()); - for (auto&& run : ensemble) { - ensemble_results.emplace_back(std::move(run.first)); - ensemble_params.emplace_back(std::move(run.second)); - } - - BOOST_OUTCOME_TRY(save_single_run_result); - BOOST_OUTCOME_TRY(save_results(ensemble_results, ensemble_params, county_ids, result_dir, save_single_runs)); - } - - return mio::success(); -} - -int main(int argc, char** argv) -{ - //TODO: proper command line interface to set: - //- number of runs - //- start and end date (may be incompatible with runmode::load) - //- seeds - //- log level - //- ... - - mio::set_log_level(mio::LogLevel::warn); - mio::mpi::init(); - - RunMode mode; - std::string save_dir; - std::string data_dir; - std::string result_dir; - bool save_single_runs = true; - if (argc == 5) { - mode = RunMode::Save; - data_dir = argv[1]; - save_dir = argv[2]; - result_dir = argv[3]; - if (atoi(argv[4]) == 0) { - save_single_runs = false; - } - if (mio::mpi::is_root()) { - printf("\n Reading data from \"%s\", saving graph to \"%s\".\n", data_dir.c_str(), save_dir.c_str()); - printf("\n Exporting single run results and parameters: %d.\n", (int)save_single_runs); - } - } - else if (argc == 4) { - mode = RunMode::Save; - data_dir = argv[1]; - save_dir = argv[2]; - result_dir = argv[3]; - if (mio::mpi::is_root()) { - printf("Reading data from \"%s\", saving graph to \"%s\".\n", data_dir.c_str(), save_dir.c_str()); - printf("Exporting single run results and parameters: %d.\n", (int)save_single_runs); - } - } - else if (argc == 3) { - mode = RunMode::Load; - save_dir = argv[1]; - result_dir = argv[2]; - data_dir = ""; - if (mio::mpi::is_root()) { - printf("Loading graph from \"%s\".\n", save_dir.c_str()); - printf("Exporting single run results and parameters: %d.\n", (int)save_single_runs); - } - } - else { - if (mio::mpi::is_root()) { - printf("Usage:\n"); - printf("2020_npis_wildtype \n"); - printf("\tMake graph with data from and save at , then run the simulation.\n"); - printf("\tStore the results in \n"); - printf("2020_npis_wildtype \n"); - printf("\tLoad graph from , then run the simulation.\n"); - } - mio::mpi::finalize(); - return 0; - } - if (mio::mpi::is_root()) { - printf("Saving results to \"%s\".\n", result_dir.c_str()); - } - - auto result = run(mode, data_dir, save_dir, result_dir, save_single_runs); - if (!result) { - printf("%s\n", result.error().formatted_message().c_str()); - mio::mpi::finalize(); - return -1; - } - mio::mpi::finalize(); - return 0; -} diff --git a/cpp/simulations/2021_vaccination_sarscov2_delta_germany.cpp b/cpp/simulations/2021_vaccination_sarscov2_delta_germany.cpp deleted file mode 100644 index ba81b6f46f..0000000000 --- a/cpp/simulations/2021_vaccination_sarscov2_delta_germany.cpp +++ /dev/null @@ -1,847 +0,0 @@ -/* -* Copyright (C) 2020-2025 MEmilio -* -* Authors: Daniel Abele, Wadim Koslow, Martin Kühn -* -* Contact: Martin J. Kuehn -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "memilio/compartments/parameter_studies.h" -#include "memilio/geography/regions.h" -#include "memilio/io/epi_data.h" -#include "memilio/io/result_io.h" -#include "memilio/io/mobility_io.h" -#include "memilio/utils/date.h" -#include "memilio/utils/miompi.h" -#include "memilio/utils/random_number_generator.h" -#include "ode_secirvvs/parameters_io.h" -#include "ode_secirvvs/parameter_space.h" -#include "memilio/mobility/metapopulation_mobility_instant.h" -#include "memilio/utils/stl_util.h" -#include "boost/filesystem.hpp" -#include -#include - -namespace fs = boost::filesystem; - -/** - * indices of contact matrix corresponding to locations where contacts occur. - */ -enum class ContactLocation -{ - Home = 0, - School, - Work, - Other, - Count, -}; - -/** - * different types of NPI, used as DampingType. - */ -enum class Intervention -{ - Home, - SchoolClosure, - HomeOffice, - GatheringBanFacilitiesClosure, - PhysicalDistanceAndMasks, - SeniorAwareness, -}; - -/** - * different level of NPI, used as DampingLevel. - */ -enum class InterventionLevel -{ - Main, - PhysicalDistanceAndMasks, - SeniorAwareness, - Holidays, -}; - -/** - * Set a value and distribution of an UncertainValue. - * Assigns average of min and max as a value and UNIFORM(min, max) as a distribution. - * @param p uncertain value to set. - * @param min minimum of distribution. - * @param max minimum of distribution. - */ -void assign_uniform_distribution(mio::UncertainValue& p, double min, double max) -{ - p = mio::UncertainValue(0.5 * (max + min)); - p.set_distribution(mio::ParameterDistributionUniform(min, max)); -} - -/** - * Set a value and distribution of an array of UncertainValues. - * Assigns average of min[i] and max[i] as a value and UNIFORM(min[i], max[i]) as a distribution for - * each element i of the array. - * @param array array of UncertainValues to set. - * @param min minimum of distribution for each element of array. - * @param max minimum of distribution for each element of array. - */ -template -void array_assign_uniform_distribution(mio::CustomIndexArray, mio::AgeGroup>& array, - const double (&min)[N], const double (&max)[N]) -{ - assert(N == array.numel()); - for (auto i = mio::AgeGroup(0); i < mio::AgeGroup(N); ++i) { - assign_uniform_distribution(array[i], min[size_t(i)], max[size_t(i)]); - } -} - -/** - * Set a value and distribution of an array of UncertainValues. - * Assigns average of min and max as a value and UNIFORM(min, max) as a distribution to every element of the array. - * @param array array of UncertainValues to set. - * @param min minimum of distribution. - * @param max minimum of distribution. - */ -void array_assign_uniform_distribution(mio::CustomIndexArray, mio::AgeGroup>& array, - double min, double max) -{ - for (auto i = mio::AgeGroup(0); i < array.size(); ++i) { - assign_uniform_distribution(array[i], min, max); - } -} - -/** - * Set epidemiological parameters of Covid19. - * @param params Object that the parameters will be added to. - * @returns Currently generates no errors. - */ -mio::IOResult set_covid_parameters(mio::osecirvvs::Parameters& params, bool long_time) -{ - //times - // TimeExposed and TimeInfectedNoSymptoms are calculated as described in - // Khailaie et al. (https://doi.org/10.1186/s12916-020-01884-4) - // given SI_min = 3.935, SI_max = 4.6, INC = 5.2 - const double timeExposedMin = 2.67; - const double timeExposedMax = 4.; - const double timeInfectedNoSymptomsMin = 1.2; - const double timeInfectedNoSymptomsMax = 2.53; - - const double timeInfectedSymptomsMin[] = {5.6255, 5.6255, 5.6646, 5.5631, 5.501, 5.465}; - const double timeInfectedSymptomsMax[] = {8.427, 8.427, 8.4684, 8.3139, 8.169, 8.085}; - const double timeInfectedSevereMin[] = {3.925, 3.925, 4.85, 6.4, 7.2, 9.}; - const double timeInfectedSevereMax[] = {6.075, 6.075, 7., 8.7, 9.8, 13.}; - const double timeInfectedCriticalMin[] = {4.95, 4.95, 4.86, 14.14, 14.4, 10.}; - const double timeInfectedCriticalMax[] = {8.95, 8.95, 8.86, 20.58, 19.8, 13.2}; - - array_assign_uniform_distribution(params.get>(), timeExposedMin, - timeExposedMax); - array_assign_uniform_distribution(params.get>(), - timeInfectedNoSymptomsMin, timeInfectedNoSymptomsMax); - array_assign_uniform_distribution(params.get>(), - timeInfectedSymptomsMin, timeInfectedSymptomsMax); - array_assign_uniform_distribution(params.get>(), timeInfectedSevereMin, - timeInfectedSevereMax); - array_assign_uniform_distribution(params.get>(), - timeInfectedCriticalMin, timeInfectedCriticalMax); - - //probabilities - double fac_variant = 1.4; - const double transmissionProbabilityOnContactMin[] = {0.02 * fac_variant, 0.05 * fac_variant, 0.05 * fac_variant, - 0.05 * fac_variant, 0.08 * fac_variant, 0.1 * fac_variant}; - - const double transmissionProbabilityOnContactMax[] = {0.04 * fac_variant, 0.07 * fac_variant, 0.07 * fac_variant, - 0.07 * fac_variant, 0.10 * fac_variant, 0.15 * fac_variant}; - const double relativeTransmissionNoSymptomsMin = 0.5; - const double relativeTransmissionNoSymptomsMax = 0.5; - // The precise value between Risk* (situation under control) and MaxRisk* (situation not under control) - // depends on incidence and test and trace capacity - const double riskOfInfectionFromSymptomaticMin = 0.0; - const double riskOfInfectionFromSymptomaticMax = 0.2; - const double maxRiskOfInfectionFromSymptomaticMin = 0.4; - const double maxRiskOfInfectionFromSymptomaticMax = 0.5; - const double recoveredPerInfectedNoSymptomsMin[] = {0.2, 0.2, 0.15, 0.15, 0.15, 0.15}; - const double recoveredPerInfectedNoSymptomsMax[] = {0.3, 0.3, 0.25, 0.25, 0.25, 0.25}; - const double severePerInfectedSymptomsMin[] = {0.006, 0.006, 0.015, 0.049, 0.15, 0.20}; - const double severePerInfectedSymptomsMax[] = {0.009, 0.009, 0.023, 0.074, 0.18, 0.25}; - const double criticalPerSevereMin[] = {0.05, 0.05, 0.05, 0.10, 0.25, 0.35}; - const double criticalPerSevereMax[] = {0.10, 0.10, 0.10, 0.20, 0.35, 0.45}; - const double deathsPerCriticalMin[] = {0.00, 0.00, 0.10, 0.10, 0.30, 0.5}; - const double deathsPerCriticalMax[] = {0.10, 0.10, 0.18, 0.18, 0.50, 0.7}; - - const double reducExposedPartialImmunityMin = 0.75; - const double reducExposedPartialImmunityMax = 0.85; - const double reducExposedImprovedImmunityMin = 0.281; - const double reducExposedImprovedImmunityMax = 0.381; - const double reducInfectedSymptomsPartialImmunityMin = 0.6; - const double reducInfectedSymptomsPartialImmunityMax = 0.7; - const double reducInfectedSymptomsImprovedImmunityMin = 0.193; - const double reducInfectedSymptomsImprovedImmunityMax = 0.293; - const double reducInfectedSevereCriticalDeadPartialImmunityMin = 0.05; - const double reducInfectedSevereCriticalDeadPartialImmunityMax = 0.15; - const double reducInfectedSevereCriticalDeadImprovedImmunityMin = 0.041; - const double reducInfectedSevereCriticalDeadImprovedImmunityMax = 0.141; - - double temp_reducTimeInfectedMild; - if (long_time) { - temp_reducTimeInfectedMild = 1.0; - } - else { - temp_reducTimeInfectedMild = 0.5; - } - const double reducTimeInfectedMild = temp_reducTimeInfectedMild; - - array_assign_uniform_distribution(params.get>(), - transmissionProbabilityOnContactMin, transmissionProbabilityOnContactMax); - array_assign_uniform_distribution(params.get>(), - relativeTransmissionNoSymptomsMin, relativeTransmissionNoSymptomsMax); - array_assign_uniform_distribution(params.get>(), - riskOfInfectionFromSymptomaticMin, riskOfInfectionFromSymptomaticMax); - array_assign_uniform_distribution(params.get>(), - maxRiskOfInfectionFromSymptomaticMin, maxRiskOfInfectionFromSymptomaticMax); - array_assign_uniform_distribution(params.get>(), - recoveredPerInfectedNoSymptomsMin, recoveredPerInfectedNoSymptomsMax); - array_assign_uniform_distribution(params.get>(), - severePerInfectedSymptomsMin, severePerInfectedSymptomsMax); - array_assign_uniform_distribution(params.get>(), criticalPerSevereMin, - criticalPerSevereMax); - array_assign_uniform_distribution(params.get>(), deathsPerCriticalMin, - deathsPerCriticalMax); - - array_assign_uniform_distribution(params.get>(), - reducExposedPartialImmunityMin, reducExposedPartialImmunityMax); - array_assign_uniform_distribution(params.get>(), - reducExposedImprovedImmunityMin, reducExposedImprovedImmunityMax); - array_assign_uniform_distribution(params.get>(), - reducInfectedSymptomsPartialImmunityMin, reducInfectedSymptomsPartialImmunityMax); - array_assign_uniform_distribution(params.get>(), - reducInfectedSymptomsImprovedImmunityMin, - reducInfectedSymptomsImprovedImmunityMax); - array_assign_uniform_distribution( - params.get>(), - reducInfectedSevereCriticalDeadPartialImmunityMin, reducInfectedSevereCriticalDeadPartialImmunityMax); - array_assign_uniform_distribution( - params.get>(), - reducInfectedSevereCriticalDeadImprovedImmunityMin, reducInfectedSevereCriticalDeadImprovedImmunityMax); - array_assign_uniform_distribution(params.get>(), - reducTimeInfectedMild, reducTimeInfectedMild); - - //sasonality - const double seasonality_min = 0.1; - const double seasonality_max = 0.3; - - assign_uniform_distribution(params.get>(), seasonality_min, seasonality_max); - - // Delta specific parameter - params.get() = mio::get_day_in_year(mio::Date(2021, 6, 6)); - - return mio::success(); -} - -static const std::map contact_locations = {{ContactLocation::Home, "home"}, - {ContactLocation::School, "school_pf_eig"}, - {ContactLocation::Work, "work"}, - {ContactLocation::Other, "other"}}; - -/** - * Set contact matrices. - * Reads contact matrices from files in the data directory. - * @param data_dir data directory. - * @param params Object that the contact matrices will be added to. - * @returns any io errors that happen during reading of the files. - */ -mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::osecirvvs::Parameters& params) -{ - //TODO: io error handling - auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_groups())); - for (auto&& contact_location : contact_locations) { - BOOST_OUTCOME_TRY( - auto&& baseline, - mio::read_mobility_plain( - (data_dir / "Germany" / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); - - contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; - contact_matrices[size_t(contact_location.first)].get_minimum() = Eigen::MatrixXd::Zero(6, 6); - } - params.get>() = mio::UncertainContactMatrix(contact_matrices); - - return mio::success(); -} - -/** - * Set NPIs. - * @param start_date start date of the simulation. - * @param end_date end date of the simulation. - * @param params Object that the NPIs will be added to. - * @returns Currently generates no errors. - */ -mio::IOResult set_npis(mio::Date start_date, mio::Date end_date, mio::osecirvvs::Parameters& params, - bool late, bool masks, bool test) -{ - auto& contacts = params.get>(); - auto& contact_dampings = contacts.get_dampings(); - - if (test) { - params.get_commuter_nondetection() = 0.85; - } - else { - params.get_commuter_nondetection() = 1.0; - } - - //weights for age groups affected by an NPI - auto group_weights_all = Eigen::VectorXd::Constant(size_t(params.get_num_groups()), 1.0); - auto group_weights_seniors = Eigen::VectorXd::NullaryExpr(size_t(params.get_num_groups()), [](auto&& i) { - return i == 5 ? 1.0 : i == 4 ? 0.5 : 0.0; //65-80 only partially - }); - - //helper functions that create dampings for specific NPIs - auto contacts_at_home = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::Home)), t, - {size_t(ContactLocation::Home)}, group_weights_all); - }; - auto school_closure = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::SchoolClosure)), t, - {size_t(ContactLocation::School)}, group_weights_all); - }; - auto home_office = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::HomeOffice)), t, - {size_t(ContactLocation::Work)}, group_weights_all); - }; - auto social_events = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::GatheringBanFacilitiesClosure)), t, - {size_t(ContactLocation::Other)}, group_weights_all); - }; - auto social_events_work = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::Main)), - mio::DampingType(int(Intervention::GatheringBanFacilitiesClosure)), t, - {size_t(ContactLocation::Work)}, group_weights_all); - }; - auto physical_distancing_home = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::PhysicalDistanceAndMasks)), - mio::DampingType(int(Intervention::PhysicalDistanceAndMasks)), t, - {size_t(ContactLocation::Home)}, group_weights_all); - }; - auto physical_distancing_school = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::PhysicalDistanceAndMasks)), - mio::DampingType(int(Intervention::PhysicalDistanceAndMasks)), t, - {size_t(ContactLocation::School)}, group_weights_all); - }; - auto physical_distancing_work = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::PhysicalDistanceAndMasks)), - mio::DampingType(int(Intervention::PhysicalDistanceAndMasks)), t, - {size_t(ContactLocation::Work)}, group_weights_all); - }; - auto physical_distancing_other = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::PhysicalDistanceAndMasks)), - mio::DampingType(int(Intervention::PhysicalDistanceAndMasks)), t, - {size_t(ContactLocation::Other)}, group_weights_all); - }; - auto senior_awareness = [=](auto t, auto min, auto max) { - auto v = mio::UncertainValue(); - assign_uniform_distribution(v, min, max); - return mio::DampingSampling(v, mio::DampingLevel(int(InterventionLevel::SeniorAwareness)), - mio::DampingType(int(Intervention::SeniorAwareness)), t, - {size_t(ContactLocation::Home), size_t(ContactLocation::Other)}, - group_weights_seniors); - }; - - //OPEN SCENARIO SPRING - auto start_year = mio::Date(2021, 1, 1); - double narrow = 0.05; - if (start_year < end_date) { - auto static_open_scenario_spring = mio::SimulationTime(mio::get_offset_in_days(start_year, start_date)); - contact_dampings.push_back(contacts_at_home(static_open_scenario_spring, 0.0, 0.0)); - contact_dampings.push_back(school_closure(static_open_scenario_spring, 0.0, 0.0)); - contact_dampings.push_back(home_office(static_open_scenario_spring, 0.0, 0.0)); - contact_dampings.push_back(social_events(static_open_scenario_spring, 0.0, 0.0)); - contact_dampings.push_back(social_events_work(static_open_scenario_spring, 0.0, 0.0)); - contact_dampings.push_back(physical_distancing_home(static_open_scenario_spring, 0.0, 0.0)); - contact_dampings.push_back(physical_distancing_school(static_open_scenario_spring, 0.2 + narrow, 0.4 - narrow)); - contact_dampings.push_back(physical_distancing_work(static_open_scenario_spring, 0.2 + narrow, 0.4 - narrow)); - contact_dampings.push_back(physical_distancing_other(static_open_scenario_spring, 0.2 + narrow, 0.4 - narrow)); - contact_dampings.push_back(senior_awareness(static_open_scenario_spring, 0.0, 0.0)); - } - - //OPEN SCENARIO - int month_open; - if (late) { - month_open = 8; - } - else { - month_open = 7; - } - double masks_low, masks_high, masks_low_school, masks_high_school, masks_narrow; - if (masks) { - masks_low_school = 0.2; - masks_high_school = 0.4; - masks_low = 0.2; - masks_high = 0.4; - masks_narrow = narrow; - } - else { - - masks_low_school = 0.0; - masks_high_school = 0.0; - masks_low = 0.0; - masks_high = 0.0; - masks_narrow = 0.0; - } - auto start_open = mio::Date(2021, month_open, 1); - if (start_open < end_date) { - auto start_summer = mio::SimulationTime(mio::get_offset_in_days(start_open, start_date)); - contact_dampings.push_back(contacts_at_home(start_summer, 0.0, 0.0)); - contact_dampings.push_back(school_closure(start_summer, 0.0, 0.0)); - contact_dampings.push_back(home_office(start_summer, 0.0, 0.0)); - contact_dampings.push_back(social_events(start_summer, 0.0, 0.0)); - contact_dampings.push_back(social_events_work(start_summer, 0.0, 0.0)); - contact_dampings.push_back(physical_distancing_home(start_summer, 0.0, 0.0)); - contact_dampings.push_back(physical_distancing_school(start_summer, masks_low_school + masks_narrow, - masks_high_school - masks_narrow)); - contact_dampings.push_back( - physical_distancing_work(start_summer, masks_low + masks_narrow, masks_high - masks_narrow)); - contact_dampings.push_back( - physical_distancing_other(start_summer, masks_low + masks_narrow, masks_high - masks_narrow)); - contact_dampings.push_back(senior_awareness(start_summer, 0.0, 0.0)); - } - - auto start_autumn = mio::SimulationTime(mio::get_offset_in_days(mio::Date(2021, 10, 1), start_date)); - contact_dampings.push_back(contacts_at_home(start_autumn, 0.0, 0.0)); - contact_dampings.push_back(school_closure(start_autumn, 0.3 + narrow, 0.5 - narrow)); - // contact_dampings.push_back(home_office(start_autumn, 0.3 + narrow, 0.5 - narrow)); // S3F only - contact_dampings.push_back(social_events(start_autumn, 0.3 + narrow, 0.5 - narrow)); - contact_dampings.push_back(social_events_work(start_autumn, 0.0, 0.0)); - - contact_dampings.push_back(home_office(start_autumn, 0.0 + narrow, 0.2 - narrow)); // S2F - - //contact_dampings.push_back(school_closure(start_autumn, 0.0 + narrow, 0.2 - narrow)); // S1F - //contact_dampings.push_back(home_office(start_autumn, 0.0 + narrow, 0.2 - narrow)); // S1F - //contact_dampings.push_back(social_events(start_autumn, 0.0 + narrow, 0.2 - narrow)); // S1F - - narrow = 0.0; - //local dynamic NPIs - params.get>() = 7; - auto& dynamic_npis = params.get>(); - auto dynamic_npi_dampings = std::vector>(); - - dynamic_npi_dampings.push_back(contacts_at_home(mio::SimulationTime(0), 0.1 + narrow, 0.3 - narrow)); - dynamic_npi_dampings.push_back(school_closure(mio::SimulationTime(0), 0.2 + narrow, - 0.4 - narrow)); //0.25 - 0.25 in autumn - dynamic_npi_dampings.push_back(home_office(mio::SimulationTime(0), 0.1 + narrow, 0.3 - narrow)); - dynamic_npi_dampings.push_back(social_events(mio::SimulationTime(0), 0.2 + narrow, 0.4 - narrow)); - dynamic_npi_dampings.push_back(social_events_work(mio::SimulationTime(0), 0.0, 0.0)); - dynamic_npi_dampings.push_back(physical_distancing_home(mio::SimulationTime(0), 0.0, 0.0)); - dynamic_npi_dampings.push_back(physical_distancing_school(mio::SimulationTime(0), 0.2 + narrow, 0.4 - narrow)); - dynamic_npi_dampings.push_back(physical_distancing_work(mio::SimulationTime(0), 0.2 + narrow, 0.4 - narrow)); - dynamic_npi_dampings.push_back(physical_distancing_other(mio::SimulationTime(0), 0.2 + narrow, 0.4 - narrow)); - dynamic_npi_dampings.push_back(senior_awareness(mio::SimulationTime(0), 0.0, 0.0)); - - auto dynamic_npi_dampings2 = std::vector>(); - dynamic_npi_dampings2.push_back(contacts_at_home(mio::SimulationTime(0), 0.5 + narrow, 0.7 - narrow)); - dynamic_npi_dampings2.push_back(school_closure(mio::SimulationTime(0), 0.4 + narrow, - 0.6 - narrow)); //0.25 - 0.25 in autumn - dynamic_npi_dampings2.push_back(home_office(mio::SimulationTime(0), 0.2 + narrow, 0.4 - narrow)); - dynamic_npi_dampings2.push_back(social_events(mio::SimulationTime(0), 0.7 + narrow, 0.9 - narrow)); - dynamic_npi_dampings2.push_back(social_events_work(mio::SimulationTime(0), 0.0, 0.0)); - dynamic_npi_dampings2.push_back(physical_distancing_home(mio::SimulationTime(0), 0.0 + narrow, 0.2 - narrow)); - dynamic_npi_dampings2.push_back(physical_distancing_school(mio::SimulationTime(0), 0.2 + narrow, 0.4 - narrow)); - dynamic_npi_dampings2.push_back(physical_distancing_work(mio::SimulationTime(0), 0.2 + narrow, 0.4 - narrow)); - dynamic_npi_dampings2.push_back(physical_distancing_other(mio::SimulationTime(0), 0.2 + narrow, 0.4 - narrow)); - dynamic_npi_dampings2.push_back(senior_awareness(mio::SimulationTime(0), 0.0, 0.0)); - - dynamic_npis.set_interval(mio::SimulationTime(1.0)); - dynamic_npis.set_duration(mio::SimulationTime(14.0)); - dynamic_npis.set_base_value(100'000); - dynamic_npis.set_threshold(35.0, dynamic_npi_dampings); - dynamic_npis.set_threshold(100.0, dynamic_npi_dampings2); - - //school holidays (holiday periods are set per node, see set_nodes) - auto school_holiday_value = mio::UncertainValue(); - assign_uniform_distribution(school_holiday_value, 1.0, 1.0); - contacts.get_school_holiday_damping() = - mio::DampingSampling(school_holiday_value, mio::DampingLevel(int(InterventionLevel::Holidays)), - mio::DampingType(int(Intervention::SchoolClosure)), mio::SimulationTime(0.0), - {size_t(ContactLocation::School)}, group_weights_all); - - return mio::success(); -} - -/** - * Set synthetic population data for testing. - * Only sets immune-naive part of the population. The remaining part is zero. - * Same total populaton but different spread of infection in each county. - * @param counties parameters for each county. - */ -void set_synthetic_population_data(std::vector>& counties) -{ - for (size_t county_idx = 0; county_idx < counties.size(); ++county_idx) { - double nb_total_t0 = 10000, nb_exp_t0 = 2, nb_inf_t0 = 0, nb_car_t0 = 0, nb_hosp_t0 = 0, nb_icu_t0 = 0, - nb_rec_t0 = 0, nb_dead_t0 = 0; - - nb_exp_t0 = (double)((county_idx % 10 + 1) * 3); - - for (mio::AgeGroup i = 0; i < counties[county_idx].parameters.get_num_groups(); i++) { - counties[county_idx].populations[{i, mio::osecirvvs::InfectionState::ExposedNaive}] = nb_exp_t0; - counties[county_idx].populations[{i, mio::osecirvvs::InfectionState::InfectedNoSymptomsNaive}] = nb_car_t0; - counties[county_idx].populations[{i, mio::osecirvvs::InfectionState::InfectedSymptomsNaive}] = nb_inf_t0; - counties[county_idx].populations[{i, mio::osecirvvs::InfectionState::InfectedSevereNaive}] = nb_hosp_t0; - counties[county_idx].populations[{i, mio::osecirvvs::InfectionState::InfectedCriticalNaive}] = nb_icu_t0; - counties[county_idx].populations[{i, mio::osecirvvs::InfectionState::SusceptibleImprovedImmunity}] = - nb_rec_t0; - counties[county_idx].populations[{i, mio::osecirvvs::InfectionState::DeadNaive}] = nb_dead_t0; - counties[county_idx].populations.set_difference_from_group_total( - {i, mio::osecirvvs::InfectionState::SusceptibleNaive}, nb_total_t0); - } - } -} - -/** - * Create the input graph for the parameter study. - * Reads files from the data directory. - * @param start_date start date of the simulation. - * @param end_date end date of the simulation. - * @param data_dir data directory. - * @returns created graph or any io errors that happen during reading of the files. - */ -mio::IOResult, mio::MobilityParameters>> -get_graph(mio::Date start_date, mio::Date end_date, const fs::path& data_dir, bool late, bool masks, bool test, - bool long_time) -{ - const auto summer_date = late ? mio::Date(2021, 8, 1) : mio::Date(2021, 7, 1); - - // global parameters - const int num_age_groups = 6; - mio::osecirvvs::Parameters params(num_age_groups); - params.get() = mio::get_day_in_year(start_date); - params.get_end_dynamic_npis() = mio::get_offset_in_days(start_date, summer_date); - BOOST_OUTCOME_TRY(set_covid_parameters(params, long_time)); - BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, params)); - BOOST_OUTCOME_TRY(set_npis(start_date, end_date, params, late, masks, test)); - - auto scaling_factor_infected = std::vector(size_t(params.get_num_groups()), 1.0); - auto scaling_factor_icu = 1.0; - auto tnt_capacity_factor = 1.43 / 100000.; - auto mobile_compartments = {mio::osecirvvs::InfectionState::SusceptibleNaive, - mio::osecirvvs::InfectionState::ExposedNaive, - mio::osecirvvs::InfectionState::InfectedNoSymptomsNaive, - mio::osecirvvs::InfectionState::InfectedSymptomsNaive, - mio::osecirvvs::InfectionState::SusceptibleImprovedImmunity, - mio::osecirvvs::InfectionState::SusceptiblePartialImmunity, - mio::osecirvvs::InfectionState::ExposedPartialImmunity, - mio::osecirvvs::InfectionState::InfectedNoSymptomsPartialImmunity, - mio::osecirvvs::InfectionState::InfectedSymptomsPartialImmunity, - mio::osecirvvs::InfectionState::ExposedImprovedImmunity, - mio::osecirvvs::InfectionState::InfectedNoSymptomsImprovedImmunity, - mio::osecirvvs::InfectionState::InfectedSymptomsImprovedImmunity}; - - // graph of counties with populations and local parameters - // and mobility between counties - mio::Graph, mio::MobilityParameters> params_graph; - const auto& read_function_nodes = mio::osecirvvs::read_input_data_county>; - const auto& read_function_edges = mio::read_mobility_plain; - const auto& node_id_function = mio::get_node_ids; - const auto data_dir_Germany = mio::path_join(data_dir.string(), "Germany"); - - const auto mobility_data_file = mio::path_join(data_dir_Germany, "mobility", "commuter_mobility_2022.txt"); - const auto pydata_dir = mio::path_join(data_dir_Germany, "pydata"); - - const auto& set_node_function = - mio::set_nodes, mio::osecirvvs::ContactPatterns, - mio::osecirvvs::Model, mio::MobilityParameters, - mio::osecirvvs::Parameters, decltype(read_function_nodes), decltype(node_id_function)>; - const auto& set_edge_function = - mio::set_edges, mio::MobilityParameters, - mio::MobilityCoefficientGroup, mio::osecirvvs::InfectionState, decltype(read_function_edges)>; - BOOST_OUTCOME_TRY(set_node_function( - params, start_date, end_date, pydata_dir, mio::path_join(pydata_dir, "county_current_population.json"), true, - params_graph, read_function_nodes, node_id_function, scaling_factor_infected, scaling_factor_icu, - tnt_capacity_factor, mio::get_offset_in_days(end_date, start_date), false, true)); - BOOST_OUTCOME_TRY(set_edge_function(mobility_data_file, params_graph, mobile_compartments, contact_locations.size(), - read_function_edges, std::vector{0., 0., 1.0, 1.0, 0.33, 0., 0.}, - {})); - - return mio::success(params_graph); -} - -/** - * Different modes for running the parameter study. - */ -enum class RunMode -{ - Load, - Save, -}; - -/** - * Run the parameter study. - * Load a previously stored graph or create a new one from data. - * The graph is the input for the parameter study. - * A newly created graph is saved and can be reused. - * @param mode Mode for running the parameter study. - * @param data_dir data directory. Not used if mode is RunMode::Load. - * @param save_dir directory where the graph is loaded from if mode is RunMOde::Load or save to if mode is RunMode::Save. - * @param result_dir directory where all results of the parameter study will be stored. - * @param save_single_runs [Default: true] Defines if single run results are written to the disk. - * @returns any io error that occurs during reading or writing of files. - */ -mio::IOResult run(RunMode mode, const fs::path& data_dir, const fs::path& save_dir, const fs::path& result_dir, - bool save_single_runs, bool late, bool masks, bool test, bool high, bool long_time, bool future) -{ - mio::Date temp_date; - if (future) { - temp_date = mio::Date(2021, 10, 15); - } - else { - temp_date = mio::Date(2021, 6, 6); - } - const auto start_date = temp_date; - const auto num_days_sim = 90.0; - const auto end_date = mio::offset_date_by_days(start_date, int(std::ceil(num_days_sim))); - const auto num_runs = 500; - - //create or load graph - mio::Graph, mio::MobilityParameters> params_graph; - if (mode == RunMode::Save) { - BOOST_OUTCOME_TRY(auto&& created, get_graph(start_date, end_date, data_dir, late, masks, test, long_time)); - BOOST_OUTCOME_TRY(write_graph(created, save_dir.string())); - params_graph = created; - } - else { - BOOST_OUTCOME_TRY(auto&& loaded, mio::read_graph>(save_dir.string())); - params_graph = loaded; - } - - std::vector county_ids(params_graph.nodes().size()); - std::transform(params_graph.nodes().begin(), params_graph.nodes().end(), county_ids.begin(), [](auto& n) { - return n.id; - }); - - //run parameter study - auto parameter_study = - mio::ParameterStudy>{params_graph, 0.0, num_days_sim, 0.5, num_runs}; - - // parameter_study.get_rng().seed( - // {114381446, 2427727386, 806223567, 832414962, 4121923627, 1581162203}); //set seeds, e.g., for debugging - if (mio::mpi::is_root()) { - printf("Seeds: "); - for (auto s : parameter_study.get_rng().get_seeds()) { - printf("%u, ", s); - } - printf("\n"); - } - - auto save_single_run_result = mio::IOResult(mio::success()); - auto ensemble = parameter_study.run( - [&](auto&& graph) { - return draw_sample(graph, high); - }, - [&](auto results_graph, auto&& run_idx) { - auto interpolated_result = mio::interpolate_simulation_result(results_graph); - auto params = std::vector>(); - params.reserve(results_graph.nodes().size()); - std::transform(results_graph.nodes().begin(), results_graph.nodes().end(), std::back_inserter(params), - [](auto&& node) { - return node.property.get_simulation().get_model(); - }); - - if (save_single_run_result && save_single_runs) { - save_single_run_result = - save_result_with_params(interpolated_result, params, county_ids, result_dir, run_idx); - } - std::cout << "run " << run_idx << " complete." << std::endl; - return std::make_pair(interpolated_result, params); - }); - - if (ensemble.size() > 0) { - auto ensemble_results = std::vector>>{}; - ensemble_results.reserve(ensemble.size()); - auto ensemble_params = std::vector>>{}; - ensemble_params.reserve(ensemble.size()); - for (auto&& run : ensemble) { - ensemble_results.emplace_back(std::move(run.first)); - ensemble_params.emplace_back(std::move(run.second)); - } - - BOOST_OUTCOME_TRY(save_single_run_result); - BOOST_OUTCOME_TRY(save_results(ensemble_results, ensemble_params, county_ids, result_dir, save_single_runs)); - } - - return mio::success(); -} - -int main(int argc, char** argv) -{ - //TODO: proper command line interface to set: - //- number of runs - //- start and end date (may be incompatible with runmode::load) - //- seeds - //- log level - //- ... - - mio::set_log_level(mio::LogLevel::warn); - mio::mpi::init(); - - bool late = false; - bool masks = true; - bool test = true; - bool high = false; - bool long_time = false; - bool future = false; - - RunMode mode; - std::string save_dir; - std::string data_dir; - std::string result_dir; - bool save_single_runs = true; - if (argc == 10) { - mode = RunMode::Save; - data_dir = argv[1]; - save_dir = argv[2]; - result_dir = argv[3]; - if (atoi(argv[4]) == 0) { - save_single_runs = false; - } - if (atoi(argv[5]) == 1) { - high = true; - } - else { - high = false; - } - if (atoi(argv[6]) == 1) { - late = true; - } - else { - late = false; - } - if (atoi(argv[7]) == 1) { - masks = true; - test = true; - } - else { - masks = false; - test = false; - } - if (atoi(argv[8]) == 1) { - long_time = true; - } - else { - long_time = false; - } - if (atoi(argv[9]) == 1) { - future = true; - } - else { - future = false; - } - if (mio::mpi::is_root()) { - printf("Options: masks set to: %d, late set to: %d, high set to: %d, long set to: %d, future set to: %d\n", - (int)masks, (int)late, (int)high, (int)long_time, (int)future); - printf("Reading data from \"%s\", saving graph to \"%s\".\n", data_dir.c_str(), save_dir.c_str()); - printf("Exporting single run results and parameters: %d.\n", (int)save_single_runs); - } - } - else if (argc == 4) { - mode = RunMode::Load; - save_dir = argv[1]; - result_dir = argv[2]; - data_dir = ""; - if (mio::mpi::is_root()) { - printf("Loading graph from \"%s\".\n", save_dir.c_str()); - printf("Exporting single run results and parameters: %d.\n", (int)save_single_runs); - } - } - else if (argc == 5) { - mode = RunMode::Save; - data_dir = argv[1]; - save_dir = argv[2]; - result_dir = argv[3]; - if (atoi(argv[4]) == 0) { - save_single_runs = false; - } - if (mio::mpi::is_root()) { - printf("Options: masks set to: %d, late set to: %d, high set to: %d, long set to: %d, future set to: %d\n", - (int)masks, (int)late, (int)high, (int)long_time, (int)future); - printf("Reading data from \"%s\", saving graph to \"%s\".\n", data_dir.c_str(), save_dir.c_str()); - printf("Exporting single run results and parameters: %d.\n", (int)save_single_runs); - } - } - else { - if (mio::mpi::is_root()) { - printf("Usage:\n"); - printf("2021_vaccination_delta \n"); - printf("\tMake graph with data from and save at , then run the simulation.\n"); - printf("\tStore the results in \n"); - printf("\t are either 0 or 1 to define a particular scenario\n"); - printf("2021_vaccination_delta \n"); - printf("\tLoad graph from , then run the simulation.\n"); - } - mio::mpi::finalize(); - return 0; - } - - if (future) { - result_dir += "_future"; - } - if (long_time) { - result_dir += "_long"; - } - if (high) { - result_dir += "_high"; - } - if (late) { - result_dir += "_late"; - } - if (masks) { - result_dir += "_mask"; - } - if (test) { - result_dir += "_test"; - } - if (mio::mpi::is_root()) { - boost::filesystem::path dir(result_dir); - bool created = boost::filesystem::create_directories(dir); - - if (created) { - mio::log_info("Directory '{:s}' was created.", dir.string()); - } - printf("Saving results to \"%s\".\n", result_dir.c_str()); - } - - auto result = - run(mode, data_dir, save_dir, result_dir, save_single_runs, late, masks, test, high, long_time, future); - if (!result) { - printf("%s\n", result.error().formatted_message().c_str()); - mio::mpi::finalize(); - return -1; - } - mio::mpi::finalize(); - return 0; -} diff --git a/cpp/simulations/CMakeLists.txt b/cpp/simulations/CMakeLists.txt deleted file mode 100644 index a784b83ba5..0000000000 --- a/cpp/simulations/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -if(MEMILIO_HAS_JSONCPP AND MEMILIO_HAS_HDF5) - add_executable(2020_npis_wildtype 2020_npis_sarscov2_wildtype_germany.cpp) - target_link_libraries(2020_npis_wildtype PRIVATE memilio ode_secir Boost::filesystem ${HDF5_C_LIBRARIES}) - target_compile_options(2020_npis_wildtype PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - - add_executable(2021_vaccination_delta 2021_vaccination_sarscov2_delta_germany.cpp) - target_link_libraries(2021_vaccination_delta PRIVATE memilio ode_secirvvs Boost::filesystem ${HDF5_C_LIBRARIES}) - target_compile_options(2021_vaccination_delta PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - - add_executable(abm_simulation abm.cpp) - target_link_libraries(abm_simulation PRIVATE memilio abm Boost::filesystem ${HDF5_C_LIBRARIES}) - target_compile_options(abm_simulation PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - - add_executable(munich_graph_sim munich_graph_sim) - target_link_libraries(munich_graph_sim PRIVATE memilio ode_secir abm Boost::filesystem ${HDF5_C_LIBRARIES}) - target_compile_options(munich_graph_sim PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - - add_executable(abm_braunschweig abm_braunschweig.cpp) - target_link_libraries(abm_braunschweig PRIVATE memilio abm Boost::filesystem ${HDF5_C_LIBRARIES}) - target_compile_options(abm_braunschweig PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -endif() diff --git a/cpp/simulations/README.md b/cpp/simulations/README.md deleted file mode 100644 index 74de6b8389..0000000000 --- a/cpp/simulations/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Simulations # - -This folder provides three spatially resolved simulations. There are two graph-ODE (or metapopulation) models using one ODE model for each county and realizing inter-county mobility via a graph approach. An agent-based model (abm) using German statistical data is also included. -The Parameters `TimeExposed` and `TimeInfectedNoSymptoms` can be derived from the serial interval and incubation period, as delineated by Khailaie and Mitra et al. (https://doi.org/10.1186/s12916-020-01884-4). - -- 2020_npis_wildtype: Focus on a SECIR model using parameters for Sars-CoV-2 wild type variant and -implementing static nonpharmaceutical interventions (NPIs) as well as dynamic NPIs. Dynamic NPIs -get into play once predefined incidence thresholds (50 and 200) are exceeded. - -- 2021_vaccination_delta: Extending the model of 2020_npis_wildtype by vaccination and reinfection and -considering the effect of vaccination in combination with the lifting of NPIs during the arrival of Delta. -The data which is necessary to run these simulations is generated by the MEmilio epidata package. -This can be done by calling the particular python routines manually or by running the `data_generation.sh` shell script. -The shell script assumes the existence of a python environment and only the path activation function of the environment -must be given to the script. The path can either be set in the script or by calling the script directly with the option -"-PATH_ENV YOUR_PATH_TO_VIRTUAL_ENV/ACTIVATION_EXEC". -The script needs to be executed from the `simulations` folder directly by `./data_generation.sh`. - -- abm: An agent-based model using statistical data taken from Destatis (https://www-genesis.destatis.de/genesis/online?operation=statistic&levelindex=0&levelid=1627908577036&code=12211#abreadcrumb). \ No newline at end of file diff --git a/cpp/simulations/abm.cpp b/cpp/simulations/abm.cpp deleted file mode 100644 index 655a078892..0000000000 --- a/cpp/simulations/abm.cpp +++ /dev/null @@ -1,763 +0,0 @@ -/* -* Copyright (C) 2020-2025 MEmilio -* -* Authors: Daniel Abele, Khoa Nguyen, David Kerkmann -* -* Contact: Martin J. Kuehn -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "abm/analyze_result.h" -#include "abm/common_abm_loggers.h" -#include "abm/household.h" -#include "abm/lockdown_rules.h" -#include "memilio/config.h" -#include "memilio/io/result_io.h" -#include "memilio/utils/random_number_generator.h" -#include "memilio/utils/uncertain_value.h" - -namespace fs = boost::filesystem; - -// Assign the name to general age group. -size_t num_age_groups = 6; -const auto age_group_0_to_4 = mio::AgeGroup(0); -const auto age_group_5_to_14 = mio::AgeGroup(1); -const auto age_group_15_to_34 = mio::AgeGroup(2); -const auto age_group_35_to_59 = mio::AgeGroup(3); -const auto age_group_60_to_79 = mio::AgeGroup(4); -const auto age_group_80_plus = mio::AgeGroup(5); - -/** - * Set a value and distribution of an UncertainValue. - * Assigns average of min and max as a value and UNIFORM(min, max) as a distribution. - * @param p uncertain value to set. - * @param min minimum of distribution. - * @param max minimum of distribution. - */ -void assign_uniform_distribution(mio::UncertainValue<>& p, ScalarType min, ScalarType max) -{ - p = mio::UncertainValue<>(0.5 * (max + min)); - p.set_distribution(mio::ParameterDistributionUniform(min, max)); -} - -/** - * Determine the infection state of a person at the beginning of the simulation. - * The infection states are chosen randomly. They are distributed according to the probabilites set in the example. - * @return random infection state - */ -mio::abm::InfectionState determine_infection_state(mio::abm::PersonalRandomNumberGenerator& rng, ScalarType exposed, - ScalarType infected_no_symptoms, ScalarType infected_symptoms, - ScalarType recovered) -{ - ScalarType susceptible = 1 - exposed - infected_no_symptoms - infected_symptoms - recovered; - std::vector weights = { - susceptible, exposed, infected_no_symptoms, infected_symptoms / 3, infected_symptoms / 3, - infected_symptoms / 3, recovered}; - if (weights.size() != (size_t)mio::abm::InfectionState::Count - 1) { - mio::log_error("Initialization in ABM wrong, please correct vector length."); - } - auto state = mio::DiscreteDistribution::get_instance()(rng, weights); - return (mio::abm::InfectionState)state; -} - -/** - * Calculates a vector in which each entry describes the amount of people living in the corresponding household. - * This is done with equal distribution and if the number of people is not divisible by number of households the last one gets the rest. E.g. number_of_people = 10, number_of_households = 3. Then the vector household_sizes = {3,3,4}. - * @param number_of_people The total amount of people to be distributed. - * @param number_of_households The total amount of households. - * @return A vector with the size of each household. - */ -std::vector last_household_gets_the_rest(int number_of_people, int number_of_households) -{ - std::vector household_sizes(number_of_households, 0); - int avarage_household_size_round_down = number_of_people / number_of_households; //int rounds down. - int people_left = number_of_people - - avarage_household_size_round_down * - number_of_households; // People left if everyone got the same rounded down amount of people. - for (auto i = 0; i < number_of_households - 1; i++) { - household_sizes.at(i) = avarage_household_size_round_down; - } - household_sizes.at(number_of_households - 1) = - avarage_household_size_round_down + people_left; // Last one gets the people which would've been left out. - return household_sizes; -} - -/** - * Constructs a household group which has a single member to represent them all, e.g. all people have the same age distribution. - * @param age_dist A vector with the amount of people in each age group - * @param number_of_people The total amount of people living in this household group. - * @param number_of_hh The number of households in this household group. - * @return householdGroup A Class Household Group. - */ -mio::abm::HouseholdGroup make_uniform_households(const mio::abm::HouseholdMember& member, int number_of_people, - int number_of_hh) -{ - - // The size of each household is calculated in a vector household_size_list. - auto households_size_list = last_household_gets_the_rest(number_of_people, number_of_hh); - - auto householdGroup = mio::abm::HouseholdGroup(); - for (auto& household_size : households_size_list) { - auto household = mio::abm::Household(); - household.add_members(member, household_size); // Add members according to the amount of people in the list. - householdGroup.add_households(household, 1); // Add the household to the household group. - - // assuming 22 square meters per person and 3 meters of room height - // see: https://doi.org/10.1371/journal.pone.0259037 - household.set_space_per_member(66); - } - return householdGroup; -} - -/** - * Constructs a household group with families. - * @param child Child Household Member. - * @param parent Parent Household Member. - * @param random Random Household Member. This is for the rest Group where no exact age distribution can be found. - * @param number_of_persons_in_household Amount of people in this household - * @param number_of_full_familes Amount of full families, e.g. two parents and (number_of_persons_in_household - 2) children. - * @param number_of_half_familes Amount of half families, e.g. one parent and (number_of_persons_in_household - 1) children. - * @param number_of_other_familes number_of_persons_in_household random persons. - * @return A Household group. - */ -mio::abm::HouseholdGroup make_homes_with_families(const mio::abm::HouseholdMember& child, - const mio::abm::HouseholdMember& parent, - const mio::abm::HouseholdMember& random, - int number_of_persons_in_household, int number_of_full_familes, - int number_of_half_familes, int number_of_other_familes) -{ - - auto private_household_group = mio::abm::HouseholdGroup(); - - // Add full families. - auto household_full = mio::abm::Household(); - household_full.add_members(child, number_of_persons_in_household - 2); - household_full.add_members(parent, 2); - private_household_group.add_households(household_full, number_of_full_familes); - - // Add half families. - auto household_half = mio::abm::Household(); - household_half.add_members(child, number_of_persons_in_household - 1); - household_half.add_members(parent, 1); - private_household_group.add_households(household_half, number_of_half_familes); - - // Add other families. - if (number_of_persons_in_household < 5) { - auto household_others = mio::abm::Household(); - household_others.add_members(random, number_of_persons_in_household); - private_household_group.add_households(household_others, number_of_other_familes); - } - else if (number_of_persons_in_household == 5) { - // For 5 and more people in one household we have to distribute the rest onto the left over households. - int people_left_size5 = 545; - - auto households_size_list = last_household_gets_the_rest(people_left_size5, number_of_other_familes); - - auto household_rest = mio::abm::HouseholdGroup(); - for (auto& household_size : households_size_list) { - auto household = mio::abm::Household(); - household.add_members(random, household_size); // Add members according to the amount of people in the list. - household_rest.add_households(household, 1); // Add the household to the household group. - } - } - return private_household_group; -} - -void create_model_from_statistical_data(mio::abm::Model& model) -{ - - /** The data is taken from - * https://www-genesis.destatis.de/genesis/online?operation=statistic&levelindex=0&levelid=1627908577036&code=12211#abreadcrumb - * All numbers are in 1000. - * Destatis divides the Households into community households and private households. - * Community Households are: Refugee, Disabled, Retirement and Others. We have an explicit age distribution, amount of households and amount of people for them but not the exact amount of people in each household. - * The private Households are divided with respect to the amount of people living in each household. For a one person household we have the exact age distribution. For the rest we have data about which kind of family lives in them. The different kinds of families are: A family with two parents and the rest are children, a family with one parent and the rest are children and "other" families with no exact data about their age. - */ - - // Refugee - auto refugee = mio::abm::HouseholdMember(num_age_groups); - refugee.set_age_weight(age_group_0_to_4, 25); - refugee.set_age_weight(age_group_5_to_14, 12); - refugee.set_age_weight(age_group_15_to_34, 25); - refugee.set_age_weight(age_group_35_to_59, 9); - refugee.set_age_weight(age_group_60_to_79, 1); - refugee.set_age_weight(age_group_80_plus, 1); - int refugee_number_of_people = 74; - int refugee_number_of_households = 12; - auto refugeeGroup = make_uniform_households(refugee, refugee_number_of_people, refugee_number_of_households); - - add_household_group_to_model(model, refugeeGroup); - - // Disabled - auto disabled = mio::abm::HouseholdMember(num_age_groups); - disabled.set_age_weight(age_group_0_to_4, 2); - disabled.set_age_weight(age_group_5_to_14, 6); - disabled.set_age_weight(age_group_15_to_34, 13); - disabled.set_age_weight(age_group_35_to_59, 42); - disabled.set_age_weight(age_group_60_to_79, 97); - disabled.set_age_weight(age_group_80_plus, 32); - int disabled_number_of_people = 194; - int disabled_number_of_households = 8; - - auto disabledGroup = make_uniform_households(disabled, disabled_number_of_people, disabled_number_of_households); - - add_household_group_to_model(model, disabledGroup); - - // Retirement - auto retired = mio::abm::HouseholdMember(num_age_groups); - retired.set_age_weight(age_group_15_to_34, 1); - retired.set_age_weight(age_group_35_to_59, 30); - retired.set_age_weight(age_group_60_to_79, 185); - retired.set_age_weight(age_group_80_plus, 530); - int retirement_number_of_people = 744; - int retirement_number_of_households = 16; - - auto retirementGroup = - make_uniform_households(retired, retirement_number_of_people, retirement_number_of_households); - - add_household_group_to_model(model, retirementGroup); - - // Others - auto other = mio::abm::HouseholdMember(num_age_groups); - other.set_age_weight(age_group_0_to_4, 30); - other.set_age_weight(age_group_5_to_14, 40); - other.set_age_weight(age_group_15_to_34, 72); - other.set_age_weight(age_group_35_to_59, 40); - other.set_age_weight(age_group_60_to_79, 30); - other.set_age_weight(age_group_80_plus, 10); - int others_number_of_people = 222; - int others_number_of_households = 20; - - auto otherGroup = make_uniform_households(other, others_number_of_people, others_number_of_households); - - add_household_group_to_model(model, otherGroup); - - // One Person Household (we have exact age data about this) - auto one_person_household_member = mio::abm::HouseholdMember(num_age_groups); - one_person_household_member.set_age_weight(age_group_15_to_34, 4364); - one_person_household_member.set_age_weight(age_group_35_to_59, 7283); - one_person_household_member.set_age_weight(age_group_60_to_79, 4100); - one_person_household_member.set_age_weight(age_group_80_plus, 1800); - int one_person_number_of_people = 15387; - int one_person_number_of_households = 15387; - - auto onePersonGroup = make_uniform_households(one_person_household_member, one_person_number_of_people, - one_person_number_of_households); - - add_household_group_to_model(model, onePersonGroup); - - // For more than 1 family households we need families. These are parents and children and randoms (which are distributed like the data we have for these households). - auto child = mio::abm::HouseholdMember(num_age_groups); // A child is 50/50% 0-4 or 5-14. - child.set_age_weight(age_group_0_to_4, 1); - child.set_age_weight(age_group_5_to_14, 1); - - auto parent = mio::abm::HouseholdMember(num_age_groups); // A child is 40/40/20% 15-34, 35-59 or 60-79. - parent.set_age_weight(age_group_15_to_34, 2); - parent.set_age_weight(age_group_35_to_59, 2); - parent.set_age_weight(age_group_60_to_79, 1); - - auto random = - mio::abm::HouseholdMember(num_age_groups); // Randoms are distributed according to the left over persons. - random.set_age_weight(age_group_0_to_4, 5000); - random.set_age_weight(age_group_5_to_14, 6000); - random.set_age_weight(age_group_15_to_34, 14943); - random.set_age_weight(age_group_35_to_59, 22259); - random.set_age_weight(age_group_60_to_79, 11998); - random.set_age_weight(age_group_80_plus, 5038); - - // Two person households - int two_person_full_families = 11850; - int two_person_half_families = 1765; - int two_person_other_families = 166; - auto twoPersonHouseholds = make_homes_with_families(child, parent, random, 2, two_person_full_families, - two_person_half_families, two_person_other_families); - add_household_group_to_model(model, twoPersonHouseholds); - - // Three person households - int three_person_full_families = 4155; - int three_person_half_families = 662; - int three_person_other_families = 175; - auto threePersonHouseholds = make_homes_with_families(child, parent, random, 3, three_person_full_families, - three_person_half_families, three_person_other_families); - add_household_group_to_model(model, threePersonHouseholds); - - // Four person households - int four_person_full_families = 3551; - int four_person_half_families = 110; - int four_person_other_families = 122; - auto fourPersonHouseholds = make_homes_with_families(child, parent, random, 4, four_person_full_families, - four_person_half_families, four_person_other_families); - add_household_group_to_model(model, fourPersonHouseholds); - - // Five plus person households - int fiveplus_person_full_families = 1245; - int fiveplus_person_half_families = 80; - int fiveplus_person_other_families = 82; - auto fivePlusPersonHouseholds = - make_homes_with_families(child, parent, random, 5, fiveplus_person_full_families, fiveplus_person_half_families, - fiveplus_person_other_families); - add_household_group_to_model(model, fivePlusPersonHouseholds); -} - -/** - * Add locations to the model and assign locations to the people. - */ -void create_assign_locations(mio::abm::Model& model) -{ - // Add one social event with 100 maximum contacts. - // Maximum contacs limit the number of people that a person can infect while being at this location. - // A high percentage of people (50-100%) have to get tested in the 2 days before the event - // For the capacity we assume an area of 1.25 m^2 per person (https://doi.org/10.1371/journal.pone.0259037) and a - // room height of 3 m - auto event = model.add_location(mio::abm::LocationType::SocialEvent); - model.get_location(event).get_infection_parameters().set(100); - model.get_location(event).set_capacity(100, 375); - - auto testing_criteria = mio::abm::TestingCriteria(); - auto validity_period = mio::abm::days(2); - auto start_date = mio::abm::TimePoint(0); - auto end_date = mio::abm::TimePoint(0) + mio::abm::days(60); - - auto probability = mio::UncertainValue<>(); - assign_uniform_distribution(probability, 0.5, 1.0); - - auto test_params = model.parameters.get()[mio::abm::TestType::Antigen]; - auto testing_scheme = mio::abm::TestingScheme(testing_criteria, validity_period, start_date, end_date, test_params, - probability.draw_sample()); - - model.get_testing_strategy().add_testing_scheme(mio::abm::LocationType::SocialEvent, testing_scheme); - - // Add hospital and ICU with 5 maximum contacs. - // For the number of agents in this example we assume a capacity of 584 persons (80 beds per 10000 residents in - // Germany (Statistisches Bundesamt, 2022) and a volume of 26242 m^3 - // (https://doi.org/10.1016/j.buildenv.2021.107926)) - // For the ICUs we assume a capacity of 30 agents and the same volume. - auto hospital = model.add_location(mio::abm::LocationType::Hospital); - model.get_location(hospital).get_infection_parameters().set(5); - model.get_location(hospital).set_capacity(584, 26242); - auto icu = model.add_location(mio::abm::LocationType::ICU); - model.get_location(icu).get_infection_parameters().set(5); - model.get_location(icu).set_capacity(30, 1350); - - // Add schools, workplaces and shops. - // At every school there are 600 students. The maximum contacs are 40. - // Students have to get tested once a week. - // We assume 2 m^2 per student (https://doi.org/10.1371/journal.pone.0259037) and a room height of 3 m. - // At every workplace work 100 people (needs to be varified), maximum contacts are 40. - // People can get tested at work (and do this with 0.5 probability). - // Per person we assume an area of 10 m^2 (https://doi.org/10.1371/journal.pone.0259037) and a room height of 3 m. - // Add one supermarked per 15.000 people, maximum constacts are assumed to be 20. - // A shop has a capacity of 240 persons (https://doi.org/10.1016/j.buildenv.2021.107926) - // and a volume of 7200 cubic meters (10 m^2 per person (https://doi.org/10.1371/journal.pone.0259037) and 3 m - // room height). - auto shop = model.add_location(mio::abm::LocationType::BasicsShop); - model.get_location(shop).get_infection_parameters().set(20); - model.get_location(shop).set_capacity(240, 7200); - - auto school = model.add_location(mio::abm::LocationType::School); - model.get_location(school).get_infection_parameters().set(40); - model.get_location(school).set_capacity(600, 3600); - - auto work = model.add_location(mio::abm::LocationType::Work); - model.get_location(work).get_infection_parameters().set(40); - model.get_location(work).set_capacity(100, 3000); - - int counter_event = 0; - int counter_school = 0; - int counter_work = 0; - int counter_shop = 0; - //Assign locations to the people - auto persons = model.get_persons(); - for (auto& person : persons) { - const auto id = person.get_id(); - //assign shop and event - model.assign_location(id, event); - counter_event++; - model.assign_location(id, shop); - counter_shop++; - //assign hospital and ICU - model.assign_location(id, hospital); - model.assign_location(id, icu); - //assign work/school to people depending on their age - if (person.get_age() == age_group_5_to_14) { - model.assign_location(id, school); - counter_school++; - } - if (person.get_age() == age_group_15_to_34 || person.get_age() == age_group_35_to_59) { - model.assign_location(id, work); - counter_work++; - } - //add new school/work/shop if needed - if (counter_event == 1000) { - counter_event = 0; - event = model.add_location(mio::abm::LocationType::SocialEvent); - model.get_location(event).set_capacity(100, 375); - model.get_location(event).get_infection_parameters().set(100); - } - if (counter_school == 600) { - counter_school = 0; - school = model.add_location(mio::abm::LocationType::School); - model.get_location(school).get_infection_parameters().set(40); - model.get_location(school).set_capacity(600, 3600); - } - if (counter_work == 100) { - counter_work = 0; - work = model.add_location(mio::abm::LocationType::Work); - model.get_location(work).get_infection_parameters().set(40); - model.get_location(work).set_capacity(100, 3000); - } - if (counter_shop == 15000) { - counter_shop = 0; - shop = model.add_location(mio::abm::LocationType::BasicsShop); - model.get_location(shop).get_infection_parameters().set(20); - model.get_location(shop).set_capacity(240, 7200); - } - } - - // add the testing schemes for school and work - auto testing_criteria_school = mio::abm::TestingCriteria(); - validity_period = mio::abm::days(7); - auto testing_scheme_school = mio::abm::TestingScheme(testing_criteria_school, validity_period, start_date, end_date, - test_params, probability.draw_sample()); - model.get_testing_strategy().add_testing_scheme(mio::abm::LocationType::School, testing_scheme_school); - - auto test_at_work = std::vector{mio::abm::LocationType::Work}; - auto testing_criteria_work = mio::abm::TestingCriteria(); - - assign_uniform_distribution(probability, 0.1, 0.5); - auto testing_scheme_work = mio::abm::TestingScheme(testing_criteria_work, validity_period, start_date, end_date, - test_params, probability.draw_sample()); - model.get_testing_strategy().add_testing_scheme(mio::abm::LocationType::Work, testing_scheme_work); -} - -/** - * Assign an infection state to each person. - */ -void assign_infection_state(mio::abm::Model& model, mio::abm::TimePoint t, double exposed_prob, - double infected_no_symptoms_prob, double infected_symptoms_prob, double recovered_prob) -{ - auto persons = model.get_persons(); - for (auto& person : persons) { - auto rng = mio::abm::PersonalRandomNumberGenerator(person); - auto infection_state = determine_infection_state(rng, exposed_prob, infected_no_symptoms_prob, - infected_symptoms_prob, recovered_prob); - if (infection_state != mio::abm::InfectionState::Susceptible) { - person.add_new_infection(mio::abm::Infection(rng, mio::abm::VirusVariant::Wildtype, person.get_age(), - model.parameters, t, infection_state, - person.get_latest_protection(), false)); - } - } -} - -void set_parameters(mio::abm::Parameters params) -{ - // Set the age group the can go to school is AgeGroup(1) (i.e. 5-14) - params.get()[age_group_5_to_14] = true; - // Set the age group the can go to work is AgeGroup(2) and AgeGroup(3) (i.e. 15-34 and 35-59) - params.get().set_multiple({age_group_15_to_34, age_group_35_to_59}, true); - - params.set({{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, 4.}); - - //0-4 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.276; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.092; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.142; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.186; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - - //5-14 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.276; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - 0.092; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.142; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.186; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.; - - //15-34 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - 0.315; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - 0.079; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.139; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.003; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.157; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.013; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - - //35-59 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - 0.315; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - 0.079; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.136; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.009; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.113; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.02; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.05; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.; - - //60-79 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - 0.315; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - 0.079; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.123; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.024; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.083; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.; - - //80+ - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.315; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - 0.079; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.115; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.033; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.055; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.036; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.; - - // Set each parameter for vaccinated people including personal infection and vaccine protection levels. - // Summary: https://doi.org/10.1038/s41577-021-00550-x, - - //0-4 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.161; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.132; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.186; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.0; - - //5-14 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.161; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - 0.132; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.186; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.0; - - //15-34 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.142; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.157; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.013; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.0; - - //35-59 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.141; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.003; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.113; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.02; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.05; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.0; - - //60-79 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.136; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.009; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.083; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.0; - - //80+ - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.133; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.012; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.055; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.036; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.0; -} - -/** - * Create a sampled model with start time t0. - * @param t0 the start time of the simulation -*/ -mio::abm::Model create_sampled_model(const mio::abm::TimePoint& t0) -{ - // mio::thread_local_rng().seed( - // {123144124, 835345345, 123123123, 99123}); //set seeds, e.g., for debugging - printf("Parameter Sample Seeds: "); - for (auto s : mio::thread_local_rng().get_seeds()) { - printf("%u, ", s); - } - printf("\n"); - - // Assumed percentage of infection state at the beginning of the simulation. - ScalarType exposed_prob = 0.005, infected_no_symptoms_prob = 0.001, infected_symptoms_prob = 0.001, - recovered_prob = 0.0; - - //Set global infection parameters (similar to infection parameters in SECIR model) and initialize the model - auto model = mio::abm::Model(num_age_groups); - - set_parameters(model.parameters); - - // model.get_rng().seed( - // {23144124, 1835345345, 9343763, 9123}); //set seeds, e.g., for debugging - printf("ABM Simulation Seeds: "); - for (auto s : model.get_rng().get_seeds()) { - printf("%u, ", s); - } - printf("\n"); - - // Create the model object from statistical data. - create_model_from_statistical_data(model); - - // Assign an infection state to each person. - assign_infection_state(model, t0, exposed_prob, infected_no_symptoms_prob, infected_symptoms_prob, recovered_prob); - - // Add locations and assign locations to the people. - create_assign_locations(model); - - auto t_lockdown = mio::abm::TimePoint(0) + mio::abm::days(20); - - // During the lockdown, 25% of people work from home and schools are closed for 90% of students. - // Social events are very rare. - mio::abm::set_home_office(t_lockdown, 0.25, model.parameters); - mio::abm::set_school_closure(t_lockdown, 0.9, model.parameters); - mio::abm::close_social_events(t_lockdown, 0.9, model.parameters); - - return model; -} - -/** - * Run the ABM simulation. - * @param result_dir Directory where all results of the parameter study will be stored. - * @param num_runs Number of runs. - * @param save_single_runs [Default: true] Defines if single run results are written to the disk. - * @returns Any io error that occurs during reading or writing of files. - */ -mio::IOResult run(const fs::path& result_dir, size_t num_runs, bool save_single_runs = true) -{ - - auto t0 = mio::abm::TimePoint(0); // Start time per simulation - auto tmax = mio::abm::TimePoint(0) + mio::abm::days(60); // End time per simulation - auto ensemble_results = std::vector>>{}; // Vector of collected results - ensemble_results.reserve(size_t(num_runs)); - auto ensemble_params = std::vector>{}; - ensemble_params.reserve(size_t(num_runs)); - auto run_idx = size_t(1); // The run index - - // Create the sampled simulation with start time t0 - auto model = create_sampled_model(t0); - ensemble_params.push_back(std::vector{model}); - - // Loop over a number of runs - while (run_idx <= num_runs) { - // Make a simulation using a copy from the original model - auto sim = mio::abm::Simulation(t0, mio::abm::Model(model)); - // Add a time series writer to the simulation - mio::History historyTimeSeries{ - Eigen::Index(mio::abm::InfectionState::Count)}; - // Advance the model to tmax - sim.advance(tmax, historyTimeSeries); - // Collect the results from the simulation - ensemble_results.push_back(std::vector>{std::get<0>(historyTimeSeries.get_log())}); - // Increase the run index - ++run_idx; - } - // Save all results to files - BOOST_OUTCOME_TRY(save_results(ensemble_results, ensemble_params, {0}, result_dir, save_single_runs)); - return mio::success(); -} - -int main(int argc, char** argv) -{ - - mio::set_log_level(mio::LogLevel::warn); - - std::string result_dir = "."; - size_t num_runs; - bool save_single_runs = true; - - if (argc == 2) { - num_runs = atoi(argv[1]); - printf("Number of run is %s.\n", argv[1]); - printf("Saving results to the current directory.\n"); - } - - else if (argc == 3) { - num_runs = atoi(argv[1]); - result_dir = argv[2]; - printf("Number of runs is %s.\n", argv[1]); - printf("Saving results to \"%s\".\n", result_dir.c_str()); - } - else { - printf("Usage:\n"); - printf("abm_example \n"); - printf("\tRun the simulation for time(s).\n"); - printf("\tStore the results in the current directory.\n"); - printf("abm_example \n"); - printf("\tRun the simulation for time(s).\n"); - printf("\tStore the results in .\n"); - return 0; - } - - auto result = run(result_dir, num_runs, save_single_runs); - if (!result) { - printf("%s\n", result.error().formatted_message().c_str()); - return -1; - } - return 0; -} diff --git a/cpp/simulations/abm_braunschweig.cpp b/cpp/simulations/abm_braunschweig.cpp deleted file mode 100644 index f97da97de8..0000000000 --- a/cpp/simulations/abm_braunschweig.cpp +++ /dev/null @@ -1,1043 +0,0 @@ -/* -* Copyright (C) 2020-2025 MEmilio -* -* Authors: Sascha Korf, Carlotta Gerstein -* -* Contact: Martin J. Kuehn -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "abm/common_abm_loggers.h" -#include "abm/location_id.h" -#include "abm/lockdown_rules.h" -#include "abm/parameters.h" -#include "abm/person.h" -#include "abm/person_id.h" -#include "abm/simulation.h" -#include "abm/model.h" -#include "memilio/epidemiology/age_group.h" -#include "memilio/io/io.h" -#include "memilio/io/result_io.h" -#include "memilio/utils/uncertain_value.h" -#include "boost/algorithm/string/split.hpp" -#include "boost/algorithm/string/classification.hpp" - -#include -#include -#include -#include - -namespace fs = boost::filesystem; - -// Assign the name to general age group. -size_t num_age_groups = 6; -const auto age_group_0_to_4 = mio::AgeGroup(0); -const auto age_group_5_to_14 = mio::AgeGroup(1); -const auto age_group_15_to_34 = mio::AgeGroup(2); -const auto age_group_35_to_59 = mio::AgeGroup(3); -const auto age_group_60_to_79 = mio::AgeGroup(4); -const auto age_group_80_plus = mio::AgeGroup(5); - -/** - * Set a value and distribution of an UncertainValue. - * Assigns average of min and max as a value and UNIFORM(min, max) as a distribution. - * @param p uncertain value to set. - * @param min minimum of distribution. - * @param max minimum of distribution. - */ -void assign_uniform_distribution(mio::UncertainValue<>& p, ScalarType min, ScalarType max) -{ - p = mio::UncertainValue<>(0.5 * (max + min)); - p.set_distribution(mio::ParameterDistributionUniform(min, max)); -} - -/** - * Determine the infection state of a person at the beginning of the simulation. - * The infection states are chosen randomly. They are distributed according to the probabilites set in the example. - * @return random infection state - */ -mio::abm::InfectionState determine_infection_state(mio::abm::PersonalRandomNumberGenerator& rng, ScalarType exposed, - ScalarType infected_no_symptoms, ScalarType infected_symptoms, - ScalarType recovered) -{ - ScalarType susceptible = 1 - exposed - infected_no_symptoms - infected_symptoms - recovered; - std::vector weights = { - susceptible, exposed, infected_no_symptoms, infected_symptoms / 3, infected_symptoms / 3, - infected_symptoms / 3, recovered}; - if (weights.size() != (size_t)mio::abm::InfectionState::Count - 1) { - mio::log_error("Initialization in ABM wrong, please correct vector length."); - } - auto state = mio::DiscreteDistribution::get_instance()(rng, weights); - return (mio::abm::InfectionState)state; -} - -/** - * Assign an infection state to each person. - */ -void assign_infection_state(mio::abm::Model& model, mio::abm::TimePoint t, double exposed_prob, - double infected_no_symptoms_prob, double infected_symptoms_prob, double recovered_prob) -{ - auto persons = model.get_persons(); - for (auto& person : persons) { - auto rng = mio::abm::PersonalRandomNumberGenerator(person); - auto infection_state = determine_infection_state(rng, exposed_prob, infected_no_symptoms_prob, - infected_symptoms_prob, recovered_prob); - if (infection_state != mio::abm::InfectionState::Susceptible) - person.add_new_infection(mio::abm::Infection(rng, mio::abm::VirusVariant::Wildtype, person.get_age(), - model.parameters, t, infection_state)); - } -} -int stringToMinutes(const std::string& input) -{ - size_t colonPos = input.find(":"); - if (colonPos == std::string::npos) { - // Handle invalid input (no colon found) - return -1; // You can choose a suitable error code here. - } - - std::string xStr = input.substr(0, colonPos); - std::string yStr = input.substr(colonPos + 1); - - int x = std::stoi(xStr); - int y = std::stoi(yStr); - return x * 60 + y; -} - -int longLatToInt(const std::string& input) -{ - double y = std::stod(input) * 1e+5; //we want the 5 numbers after digit - return (int)y; -} -void split_line(std::string string, std::vector* row) -{ - std::vector strings; - - std::string x = ",,", y = ",-1,"; - size_t pos; - while ((pos = string.find(x)) != std::string::npos) { - string.replace(pos, 2, y); - } // Temporary fix to handle empty cells. - boost::split(strings, string, boost::is_any_of(",")); - std::transform(strings.begin(), strings.end(), std::back_inserter(*row), [&](std::string s) { - if (s.find(":") != std::string::npos) { - return stringToMinutes(s); - } - else if (s.find(".") != std::string::npos) { - return longLatToInt(s); - } - else { - return std::stoi(s); - } - }); -} - -mio::abm::LocationType get_location_type(uint32_t acitivity_end) -{ - mio::abm::LocationType type; - switch (acitivity_end) { - case 1: - type = mio::abm::LocationType::Work; - break; - case 2: - type = mio::abm::LocationType::School; - break; - case 3: - type = mio::abm::LocationType::BasicsShop; - break; - case 4: - type = mio::abm::LocationType::SocialEvent; // Freizeit - break; - case 5: - type = mio::abm::LocationType::BasicsShop; // Private Erledigung - break; - case 6: - type = mio::abm::LocationType::SocialEvent; // Sonstiges - break; - default: - type = mio::abm::LocationType::Home; - break; - } - return type; -} - -mio::AgeGroup determine_age_group(uint32_t age) -{ - if (age <= 4) { - return age_group_0_to_4; - } - else if (age <= 14) { - return age_group_5_to_14; - } - else if (age <= 34) { - return age_group_15_to_34; - } - else if (age <= 59) { - return age_group_35_to_59; - } - else if (age <= 79) { - return age_group_60_to_79; - } - else { - return age_group_80_plus; - } -} - -void create_model_from_data(mio::abm::Model& model, const std::string& filename, const mio::abm::TimePoint t0, - int max_number_persons) -{ - // Open File - const fs::path p = filename; - if (!fs::exists(p)) { - mio::log_error("Cannot read in data. File does not exist."); - } - // File pointer - std::fstream fin; - - // Open an existing file - fin.open(filename, std::ios::in); - std::vector row; - std::vector row_string; - std::string line; - - // Read the Titles from the Data file - std::getline(fin, line); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - std::vector titles; - boost::split(titles, line, boost::is_any_of(",")); - uint32_t count_of_titles = 0; - std::map index = {}; - for (auto const& title : titles) { - index.insert({title, count_of_titles}); - row_string.push_back(title); - count_of_titles++; - } - - std::map locations = {}; - std::map pids_data_to_model = {}; - std::map person_ids = {}; - std::map> locations_before; - std::map> locations_after; - - // For the model we need: Hospitals, ICUs (for both we just create one for now), Homes for each unique householdID, One Person for each person_id with respective age and home_id. - - // We assume that no person goes to an hospital, altough e.g. "Sonstiges" could be a hospital - auto hospital = model.add_location(mio::abm::LocationType::Hospital); - model.get_location(hospital).get_infection_parameters().set(5); - model.get_location(hospital).set_capacity(std::numeric_limits::max(), - std::numeric_limits::max()); - auto icu = model.add_location(mio::abm::LocationType::ICU); - model.get_location(icu).get_infection_parameters().set(5); - model.get_location(icu).set_capacity(std::numeric_limits::max(), std::numeric_limits::max()); - - // First we determine the persons number and their starting locations - int number_of_persons = 0; - - while (std::getline(fin, line)) { - row.clear(); - - // read columns in this row - split_line(line, &row); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - - uint32_t person_id = row[index["puid"]]; - auto it_person_id = person_ids.find(person_id); - if (it_person_id == person_ids.end()) { - if (number_of_persons >= max_number_persons) - break; //This is okay because the data is sorted by person_id - person_ids.insert({person_id, number_of_persons}); - number_of_persons++; - } - - // The starting location of a person is the end location of the last trip he made, either on the same day or on - // the day before - uint32_t target_location_id = std::abs(row[index["loc_id_end"]]); - int trip_start = row[index["start_time"]]; - if (trip_start < t0.hour_of_day()) { - auto it_person = locations_before.find(person_id); - if (it_person == locations_before.end()) { - locations_before.insert({person_id, std::make_pair(target_location_id, trip_start)}); - } - else { - if (it_person->second.second <= trip_start) { - it_person->second.first = target_location_id; - it_person->second.second = trip_start; - } - } - } - else { - auto it_person = locations_after.find(person_id); - if (it_person == locations_after.end()) { - locations_after.insert({person_id, std::make_pair(target_location_id, trip_start)}); - } - else { - if (it_person->second.second <= trip_start) { - it_person->second.first = target_location_id; - it_person->second.second = trip_start; - } - } - } - } - - fin.clear(); - fin.seekg(0); - std::getline(fin, line); // Skip header row - - // Add all locations to the model - while (std::getline(fin, line)) { - row.clear(); - - // read columns in this row - split_line(line, &row); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - - uint32_t person_id = row[index["puid"]]; - if (person_ids.find(person_id) == person_ids.end()) - break; - - uint32_t home_id = row[index["huid"]]; - uint32_t target_location_id = std::abs(row[index["loc_id_end"]]); - uint32_t activity_end = row[index["activity_end"]]; - mio::abm::GeographicalLocation location_long_lat = {(double)row[index["lon_end"]] / 1e+5, - (double)row[index["lat_end"]] / 1e+5}; - mio::abm::LocationId home; - auto it_home = locations.find(home_id); - if (it_home == locations.end()) { - home = model.add_location(mio::abm::LocationType::Home, 1); - locations.insert({home_id, home}); - mio::abm::GeographicalLocation location_long_lat_home = {(double)row[index["lon_start"]] / 1e+5, - (double)row[index["lat_start"]] / 1e+5}; - model.get_location(home).set_geographical_location(location_long_lat_home); - } - else { - home = it_home->second; - } - - mio::abm::LocationId location; - auto it_location = locations.find( - target_location_id); // Check if location already exists also for home which have the same id (home_id = target_location_id) - if (it_location == locations.end()) { - location = model.add_location( - get_location_type(activity_end), - 1); // Assume one place has one activity, this may be untrue but not important for now(?) - locations.insert({target_location_id, location}); - model.get_location(location).set_geographical_location(location_long_lat); - } - } - fin.clear(); - fin.seekg(0); - std::getline(fin, line); // Skip header row - - // Add the persons and trips - while (std::getline(fin, line)) { - row.clear(); - - // read columns in this row - split_line(line, &row); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - - uint64_t person_data_id = row[index["puid"]]; - if (person_ids.find(person_data_id) == person_ids.end()) - break; - - uint32_t age = row[index["age"]]; - uint32_t home_id = row[index["huid"]]; - uint32_t target_location_id = std::abs(row[index["loc_id_end"]]); - uint32_t start_location_id = std::abs(row[index["loc_id_start"]]); - uint32_t trip_start = row[index["start_time"]]; - uint32_t transport_mode = row[index["travel_mode"]]; - uint32_t acticity_end = row[index["activity_end"]]; - - // Add the trip to the trip list person and location must exist at this point - auto target_location = locations.find(target_location_id)->second; - auto start_location = locations.find(start_location_id)->second; - - auto pid_itr = pids_data_to_model.find(person_data_id); - - if (pid_itr == pids_data_to_model.end()) { // person has not been added to model yet - auto it_first_location_id = locations_before.find(person_data_id); - if (it_first_location_id == locations_before.end()) { - it_first_location_id = locations_after.find(person_data_id); - } - auto first_location_id = it_first_location_id->second.first; - auto first_location = locations.find(first_location_id)->second; - auto person_model_id = model.add_person(first_location, determine_age_group(age)); - auto home = locations.find(home_id)->second; - model.assign_location(person_model_id, home); - model.assign_location(person_model_id, hospital); - model.assign_location(person_model_id, icu); - pid_itr = pids_data_to_model.insert_or_assign(person_data_id, person_model_id).first; - } - - model.assign_location( - pid_itr->second, - target_location); //This assumes that we only have in each tripchain only one location type for each person - if (locations.find(start_location_id) == locations.end()) { - // For trips where the start location is not known use Home instead - start_location = model.get_person(pid_itr->second).get_assigned_location(mio::abm::LocationType::Home); - } - model.get_trip_list().add_trip( - mio::abm::Trip(static_cast(pid_itr->first), - mio::abm::TimePoint(0) + mio::abm::minutes(trip_start), target_location, start_location, - mio::abm::TransportMode(transport_mode), mio::abm::LocationType(acticity_end))); - } - model.get_trip_list().use_weekday_trips_on_weekend(); -} - -void set_parameters(mio::abm::Parameters params) -{ - // Set the age group the can go to school is AgeGroup(1) (i.e. 5-14) - params.get()[age_group_5_to_14] = true; - // Set the age group the can go to work is AgeGroup(2) and AgeGroup(3) (i.e. 15-34 and 35-59) - params.get().set_multiple({age_group_15_to_34, age_group_35_to_59}, true); - - params.set({{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, 4.}); - - //0-4 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.276; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.092; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.142; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.186; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - - //5-14 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.276; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - 0.092; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.142; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.186; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.; - - //15-34 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - 0.315; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - 0.079; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.139; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.003; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.157; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.013; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - - //35-59 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - 0.315; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - 0.079; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.136; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.009; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.113; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.02; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.05; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.; - - //60-79 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - 0.315; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - 0.079; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.123; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.024; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.083; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.; - - //80+ - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.315; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - 0.079; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.115; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.033; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.055; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.036; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.; - - // Set each parameter for vaccinated people including personal infection and vaccine protection levels. - // Summary: https://doi.org/10.1038/s41577-021-00550-x, - - //0-4 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.161; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.132; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.186; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.0; - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.91}, {60, 0.92}, {90, 0.88}, {120, 0.84}, {150, 0.81}, {180, 0.88}, {450, 0.5}}}; - - // Set up age-related severe protection levels, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {450, 0.5}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.88}, {60, 0.91}, {90, 0.98}, {120, 0.94}, {150, 0.88}, {450, 0.5}}}; - - //5-14 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.161; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - 0.132; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.186; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.0; - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_5_to_14, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_5_to_14, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.91}, {60, 0.92}, {90, 0.88}, {120, 0.84}, {150, 0.81}, {180, 0.88}, {450, 0.5}}}; - - // Set up age-related severe protection levels, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_5_to_14, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {450, 0.5}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_5_to_14, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.88}, {60, 0.91}, {90, 0.98}, {120, 0.94}, {150, 0.88}, {450, 0.5}}}; - - //15-34 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.142; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.157; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.013; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.0; - // Set up personal infection and vaccine protection levels, based on: https://doi.org/10.1038/s41577-021-00550-x, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_15_to_34, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_15_to_34, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.89}, {60, 0.84}, {90, 0.78}, {120, 0.68}, {150, 0.57}, {180, 0.39}, {450, 0.1}}}; - // Set up age-related severe protection levels, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_15_to_34, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {450, 0.5}}}; - // Information is from: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_15_to_34, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.88}, {60, 0.91}, {90, 0.98}, {120, 0.94}, {150, 0.88}, {180, 0.90}, {450, 0.5}}}; - - //35-59 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.141; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.003; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.113; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.02; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.05; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.0; - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_35_to_59, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_35_to_59, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.89}, {60, 0.84}, {90, 0.78}, {120, 0.68}, {150, 0.57}, {180, 0.39}, {450, 0.1}}}; - // Set up age-related severe protection levels, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_35_to_59, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {450, 0.5}}}; - // Information is from: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_35_to_59, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.88}, {60, 0.91}, {90, 0.98}, {120, 0.94}, {150, 0.88}, {180, 0.90}, {450, 0.5}}}; - //60-79 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.136; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.009; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.083; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.0; - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_60_to_79, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_60_to_79, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.87}, {60, 0.85}, {90, 0.78}, {120, 0.67}, {150, 0.61}, {180, 0.50}, {450, 0.1}}}; - // Set up personal severe protection levels. - // Protection of severe infection of age group 65 + is different from other age group, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_60_to_79, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {360, 0.5}}}; - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_60_to_79, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.91}, {60, 0.86}, {90, 0.91}, {120, 0.94}, {150, 0.95}, {180, 0.90}, {450, 0.5}}}; - - //80+ - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - 0.126; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.133; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.012; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.055; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.036; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.0; - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_80_plus, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is from: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_80_plus, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.80}, {60, 0.79}, {90, 0.75}, {120, 0.56}, {150, 0.49}, {180, 0.43}, {450, 0.1}}}; - // Set up personal severe protection levels. - // Protection of severe infection of age group 65 + is different from other age group, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {360, 0.5}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_80_plus, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.84}, {60, 0.88}, {90, 0.89}, {120, 0.86}, {150, 0.85}, {180, 0.83}, {450, 0.5}}}; -} - -/** - * Create a sampled simulation with start time t0. - * @param t0 The start time of the Simulation. - */ -mio::abm::Simulation<> create_sampled_simulation(const std::string& input_file, const mio::abm::TimePoint& t0, - int max_num_persons) -{ - // Assumed percentage of infection state at the beginning of the simulation. - ScalarType exposed_prob = 0.005, infected_no_symptoms_prob = 0.001, infected_symptoms_prob = 0.001, - recovered_prob = 0.0; - - //Set global infection parameters (similar to infection parameters in SECIR model) and initialize the model - auto model = mio::abm::Model(num_age_groups); - - set_parameters(model.parameters); - - // Create the model object from statistical data. - create_model_from_data(model, input_file, t0, max_num_persons); - model.use_mobility_rules(false); - - // Assign an infection state to each person. - assign_infection_state(model, t0, exposed_prob, infected_no_symptoms_prob, infected_symptoms_prob, recovered_prob); - - auto sim = mio::abm::Simulation(t0, std::move(model)); - return sim; -} - -template -void write_log_to_file_person_and_location_data(const T& history) -{ - auto logg = history.get_log(); - auto loc_id = std::get<0>(logg)[0]; - auto agent_id = std::get<1>(logg)[0]; - // Write lo to a text file. - std::ofstream myfile("locations_lookup.txt"); - myfile << "location_id, location_type, latitude, longitude\n"; - for (uint32_t loc_id_index = 0; loc_id_index < loc_id.size(); ++loc_id_index) { - auto id = std::get<0>(loc_id[loc_id_index]); - auto location_type = (int)std::get<1>(loc_id[loc_id_index]); - auto id_longitute = std::get<2>(loc_id[loc_id_index]).longitude; - auto id_latitude = std::get<2>(loc_id[loc_id_index]).latitude; - myfile << id << ", " << location_type << ", " << id_longitute << ", " << id_latitude << "\n"; - } - myfile.close(); - - std::ofstream myfile2("agents_lookup.txt"); - myfile2 << "agent_id, home_id, age\n"; - for (uint32_t agent_id_index = 0; agent_id_index < agent_id.size(); ++agent_id_index) { - auto id = std::get<0>(agent_id[agent_id_index]); - auto home_id = std::get<1>(agent_id[agent_id_index]); - auto age = std::get<2>(agent_id[agent_id_index]); - myfile2 << id << ", " << home_id << ", " << age << "\n"; - } - myfile2.close(); -} - -template -void write_log_to_file_trip_data(const T& history) -{ - - auto mobility_data = std::get<0>(history.get_log()); - std::ofstream myfile3("mobility_data.txt"); - myfile3 << "agent_id, trip_id, start_location, end_location, start_time, end_time, transport_mode, activity, " - "infection_state \n"; - int trips_id = 0; - for (uint32_t mobility_data_index = 2; mobility_data_index < mobility_data.size(); ++mobility_data_index) { - myfile3 << "timestep Nr.: " << mobility_data_index - 1 << "\n"; - for (uint32_t trip_index = 0; trip_index < mobility_data[mobility_data_index].size(); trip_index++) { - auto agent_id = std::get<0>(mobility_data[mobility_data_index][trip_index]); - - int start_index = mobility_data_index - 1; - using Type = std::tuple; - while (!std::binary_search(std::begin(mobility_data[start_index]), std::end(mobility_data[start_index]), - mobility_data[mobility_data_index][trip_index], - [](const Type& v1, const Type& v2) { - return std::get<0>(v1) < std::get<0>(v2); - })) { - start_index--; - } - auto start_location_iterator = - std::lower_bound(std::begin(mobility_data[start_index]), std::end(mobility_data[start_index]), - mobility_data[mobility_data_index][trip_index], [](const Type& v1, const Type& v2) { - return std::get<0>(v1) < std::get<0>(v2); - }); - auto start_location = (int)std::get<1>(*start_location_iterator).get(); - - auto end_location = (int)std::get<1>(mobility_data[mobility_data_index][trip_index]).get(); - - auto start_time = (int)std::get<2>(mobility_data[mobility_data_index][trip_index]).seconds(); - auto end_time = (int)std::get<2>(mobility_data[mobility_data_index][trip_index]).seconds(); - - auto transport_mode = (int)std::get<3>(mobility_data[mobility_data_index][trip_index]); - auto activity = (int)std::get<4>(mobility_data[mobility_data_index][trip_index]); - auto infection_state = (int)std::get<5>(mobility_data[mobility_data_index][trip_index]); - myfile3 << agent_id << ", " << trips_id << ", " << start_location << " , " << end_location << " , " - << start_time << " , " << end_time << " , " << transport_mode << " , " << activity << " , " - << infection_state << "\n"; - trips_id++; - } - } - myfile3.close(); -} - -mio::IOResult run(const std::string& input_file, const fs::path& result_dir, size_t num_runs, - bool save_single_runs = true) -{ - - auto t0 = mio::abm::TimePoint(0); // Start time per simulation - auto tmax = mio::abm::TimePoint(0) + mio::abm::days(2); // End time per simulation - auto ensemble_results = std::vector>>{}; // Vector of collected results - ensemble_results.reserve(size_t(num_runs)); - auto run_idx = size_t(1); // The run index - auto save_result_result = mio::IOResult(mio::success()); // Variable informing over successful IO operations - auto max_num_persons = 1000; - - // Loop over a number of runs - while (run_idx <= num_runs) { - - // Create the sampled simulation with start time t0. - auto sim = create_sampled_simulation(input_file, t0, max_num_persons); - //output object - mio::History - historyPersonInf; - mio::History historyTimeSeries{ - Eigen::Index(mio::abm::InfectionState::Count)}; - mio::History historyPersonInfDelta; - // Collect the id of location in model. - std::vector loc_ids; - for (auto& location : sim.get_model().get_locations()) { - loc_ids.push_back(location.get_id().get()); - } - // Advance the model to tmax - sim.advance(tmax, historyPersonInf, historyTimeSeries, historyPersonInfDelta); - // TODO: update result of the simulation to be a vector of location result. - auto temp_sim_result = std::vector>{std::get<0>(historyTimeSeries.get_log())}; - // Push result of the simulation back to the result vector - ensemble_results.push_back(temp_sim_result); - // Option to save the current run result to file - if (save_result_result && save_single_runs) { - auto result_dir_run = result_dir / ("abm_result_run_" + std::to_string(run_idx) + ".h5"); - save_result_result = save_result(ensemble_results.back(), loc_ids, 1, result_dir_run.string()); - } - write_log_to_file_person_and_location_data(historyPersonInf); - write_log_to_file_trip_data(historyPersonInfDelta); - ++run_idx; - } - BOOST_OUTCOME_TRY(save_result_result); - return mio::success(); -} - -int main(int argc, char** argv) -{ - mio::set_log_level(mio::LogLevel::warn); - - std::string result_dir = "."; - std::string input_file = ""; - size_t num_runs; - bool save_single_runs = true; - - if (argc == 2) { - num_runs = atoi(argv[1]); - printf("Number of run is %s.\n", argv[1]); - printf("Saving results to the current directory.\n"); - } - - else if (argc == 3) { - num_runs = atoi(argv[1]); - result_dir = argv[2]; - printf("Number of run is %s.\n", argv[1]); - printf("Saving results to \"%s\".\n", result_dir.c_str()); - } - else { - printf("Usage:\n"); - printf("abm_example \n"); - printf("\tRun the simulation for time(s).\n"); - printf("\tStore the results in the current directory.\n"); - printf("abm_braunschweig \n"); - printf("\tRun the simulation for time(s).\n"); - printf("\tStore the results in .\n"); - printf("Running with number of runs = 1.\n"); - num_runs = 1; - } - - // mio::thread_local_rng().seed({...}); //set seeds, e.g., for debugging - //printf("Seeds: "); - //for (auto s : mio::thread_local_rng().get_seeds()) { - // printf("%u, ", s); - //} - //printf("\n"); - - auto result = run(input_file, result_dir, num_runs, save_single_runs); - if (!result) { - printf("%s\n", result.error().formatted_message().c_str()); - return -1; - } - return 0; -} diff --git a/cpp/simulations/data_generation.sh b/cpp/simulations/data_generation.sh deleted file mode 100755 index 6e768dc422..0000000000 --- a/cpp/simulations/data_generation.sh +++ /dev/null @@ -1,41 +0,0 @@ -#! /bin/bash -# Run all scripts in memilio-epidata which are necessary to run the simulation files. - -# activate virtual_env -# The path to the virtual environment activation function has to be adjusted manually -# Otherwise the script can be called with -PATH_ENV Path argument, e.g. -# sh data_generation.sh -PATH_ENV "YOUR/PATH/TO/VIRTUAL/ENV/activate" -path_virtual_env="/localdata1/kueh_mj/virtual_envs/corona-py388/bin/activate" - -# Use/check for input argument -while [[ $# -gt 0 ]]; do - key="$1" - case $key in - -PATH_ENV) - path_virtual_env="$2" - shift - shift - ;; - *) - echo "Unknown parameter: $1" - exit 1 - ;; - esac -done - -if ! [[ -f $path_virtual_env ]] -then echo "Set path to virtual environment activation function to an existing python venv." && exit -else source $path_virtual_env -fi - -# path to MEmilio dir (assumes execution of the script from the `simulations` folder) -cd ../.. -data_dir=$PWD/data/pydata - -# download data -cd "pycode/memilio-epidata" -python setup.py install -python memilio/epidata/getSimulationData.py -o $data_dir -m 7 -python memilio/epidata/transformMobilityData.py -o $data_dir - -echo "Generation was succesful." \ No newline at end of file diff --git a/cpp/simulations/munich_graph_sim.cpp b/cpp/simulations/munich_graph_sim.cpp deleted file mode 100644 index 766743c21b..0000000000 --- a/cpp/simulations/munich_graph_sim.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* -* Copyright (C) 2020-2025 MEmilio -* -* Authors: Julia Bicker, Daniel Abele, Martin Kühn -* -* Contact: Martin J. Kuehn -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "memilio/utils/logging.h" -#include "memilio/io/io.h" -#include "memilio/utils/date.h" -#include "memilio/mobility/graph.h" -#include "ode_secir/parameters_io.h" -#include "memilio/io/mobility_io.h" -#include "memilio/io/epi_data.h" -#include "memilio/mobility/metapopulation_mobility_instant.h" -#include "memilio/data/analyze_result.h" - -namespace fs = boost::filesystem; - -/** - * Different modes for running the parameter study. - */ -enum class RunMode -{ - Load, - Save, -}; - -/** - * Set epidemiological parameters of Sars-CoV-2. - * @param params Object that the parameters will be added to. - * @returns Currently generates no errors. - */ -mio::IOResult set_covid_parameters(mio::osecir::Parameters& params) -{ - params.get>() = 3.2; - params.get>() = 2.0; - params.get>() = 5.8; - params.get>() = 9.5; - params.get>() = 7.1; - - params.get>() = 0.05; - params.get>() = 0.7; - params.get>() = 0.09; - params.get>() = 0.25; - params.get>() = 0.45; - params.get>() = 35; - params.get>() = 0.2; - params.get>() = 0.25; - params.get>() = 0.3; - - params.set>(0.2); - - return mio::success(); -} - -mio::IOResult set_nodes(mio::Graph, mio::MobilityParameters>& params_graph, - const mio::osecir::Parameters& params, const fs::path& data_dir, - mio::Date start_date) -{ - auto scaling_factor_infected = std::vector(size_t(params.get_num_groups()), 1.0); - auto scaling_factor_icu = 1.0; - - //As we have only one age group in the json file the age group name is set to 'All' - mio::ConfirmedCasesDataEntry::age_group_names = {"All"}; - - mio::PopulationDataEntry::age_group_names = { - "0-4 years", "5-9 years", "10-14 years", "15-19 years", "20-24 years", "25-29 years", "30-34 years", - "35-39 years", "40-44 years", "45-49 years", "50-54 years", "55-59 years", "60-64 years", "65-69 years", - "70-74 years", "75-79 years", "80-84 years", "85-89 years", "90+ years"}; - - //read node ids - bool is_node_for_county = false; - bool interpolate_rki_age_groups = false; - BOOST_OUTCOME_TRY(auto&& node_ids, mio::get_node_ids(mio::path_join((data_dir).string(), "population_data.json"), - is_node_for_county, interpolate_rki_age_groups)); - std::vector> nodes(node_ids.size(), - mio::osecir::Model(int(size_t(params.get_num_groups())))); - //set parameters for every node - for (auto& node : nodes) { - node.parameters = params; - } - int num_days = 90; - auto read = mio::osecir::read_input_data(nodes, start_date, node_ids, scaling_factor_infected, scaling_factor_icu, - data_dir.string(), num_days, true); - for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { - params_graph.add_node(node_ids[node_idx], nodes[node_idx]); - } - return mio::success(); -} - -mio::IOResult set_edges(mio::Graph, mio::MobilityParameters>& params_graph, - const fs::path& mobility_data_dir) -{ - auto mobile_compartments = {mio::osecir::InfectionState::Susceptible, mio::osecir::InfectionState::Exposed, - mio::osecir::InfectionState::InfectedNoSymptoms, - mio::osecir::InfectionState::InfectedSymptoms, mio::osecir::InfectionState::Recovered}; - //mobility matrix has to be provided by the user as input and should have shape num_nodes x num_nodes - BOOST_OUTCOME_TRY(auto&& mobility_data, - mio::read_mobility_plain(mio::path_join((mobility_data_dir).string(), "mobility_matrix.txt"))); - if (mobility_data.rows() != Eigen::Index(params_graph.nodes().size()) || - mobility_data.cols() != Eigen::Index(params_graph.nodes().size())) { - return mio::failure(mio::StatusCode::InvalidValue, "Mobility matrices do not have the correct size."); - } - - for (size_t node_i = 0; node_i < params_graph.nodes().size(); ++node_i) { - for (size_t node_j = 0; node_j < params_graph.nodes().size(); ++node_j) { - auto& populations = params_graph.nodes()[node_i].property.populations; - auto mobility_coeffs = mio::MobilityCoefficientGroup(1, populations.numel()); - - auto coeff = - mobility_data(node_i, node_j) < 1 ? 0 : mobility_data(node_i, node_j) / populations.get_total(); - - for (auto age = mio::AgeGroup(0); age < populations.template size(); ++age) { - for (auto compartment : mobile_compartments) { - auto coeff_idx = populations.get_flat_index({age, compartment}); - mobility_coeffs[0].get_baseline()[coeff_idx] = coeff; - } - if (coeff > 1e-5) { - params_graph.add_edge(node_i, node_j, std::move(mobility_coeffs)); - } - } - } - } - return mio::success(); -} - -/** - * -*/ -mio::IOResult, mio::MobilityParameters>> -get_graph(mio::Date start_date, const fs::path& data_dir) -{ - const int num_age_groups = 1; - mio::osecir::Parameters params(num_age_groups); - params.get() = mio::get_day_in_year(start_date); - - BOOST_OUTCOME_TRY(set_covid_parameters(params)); - double contact_freq = 10; - mio::ContactMatrixGroup& contact_matrix = params.get>(); - contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, contact_freq)); - contact_matrix.add_damping(0.7, mio::SimulationTime(30)); - contact_matrix.add_damping(0.1, mio::SimulationTime(50)); - - mio::Graph, mio::MobilityParameters> params_graph; - BOOST_OUTCOME_TRY(set_nodes(params_graph, params, data_dir, start_date)); - BOOST_OUTCOME_TRY(set_edges(params_graph, data_dir)); - - return mio::success(params_graph); -} - -/** - * Run a graph simulation for Munich. - * Load a previously stored graph or create a new one from data. - * A newly created graph is saved and can be reused. - * @param mode Mode for running the parameter study. - * @param data_dir data directory. Not used if mode is RunMode::Load. - * @param save_dir directory where the graph is loaded from if mode is RunMOde::Load or save to if mode is RunMode::Save. - * @param result_dir directory where all results of the parameter study will be stored. - * @returns any io error that occurs during reading or writing of files. -*/ -mio::IOResult run(RunMode mode, const fs::path& data_dir, const fs::path& save_dir, const fs::path& result_dir) -{ - const mio::Date start_date = mio::Date(2022, 1, 1); - const auto num_days = 90.0; - - //create or load graph - mio::Graph, mio::MobilityParameters> params_graph; - - if (mode == RunMode::Save) { - BOOST_OUTCOME_TRY(auto&& created_graph, get_graph(start_date, data_dir)); - BOOST_OUTCOME_TRY(mio::write_graph(created_graph, save_dir.string())); - params_graph = created_graph; - } - else { - BOOST_OUTCOME_TRY(auto&& loaded_graph, mio::read_graph>(save_dir.string())); - params_graph = loaded_graph; - } - - std::vector county_ids(params_graph.nodes().size()); - std::transform(params_graph.nodes().begin(), params_graph.nodes().end(), county_ids.begin(), [](auto& n) { - return n.id; - }); - - //create simulation graph - mio::Graph>>, mio::MobilityEdge> - sim_graph; - - for (auto&& node : params_graph.nodes()) { - sim_graph.add_node(node.id, node.property, 0.0); - } - for (auto&& edge : params_graph.edges()) { - sim_graph.add_edge(edge.start_node_idx, edge.end_node_idx, edge.property); - } - - auto sim = mio::make_mobility_sim(0.0, 0.5, std::move(sim_graph)); - sim.advance(num_days); - - auto params = std::vector>{}; - params.reserve(sim.get_graph().nodes().size()); - std::transform(sim.get_graph().nodes().begin(), sim.get_graph().nodes().end(), std::back_inserter(params), - [](auto&& node) { - return node.property.get_simulation().get_model(); - }); - - auto interpolated_result = mio::interpolate_simulation_result(std::move(sim).get_graph()); - - auto save_single_run_result = save_result_with_params(interpolated_result, params, county_ids, result_dir, 0); - - return mio::success(); -} - -int main(int argc, char** argv) -{ - mio::set_log_level(mio::LogLevel::warn); - - std::cout << "Current path is " << fs::current_path() << '\n'; - - RunMode mode; - std::string save_dir; - std::string data_dir; - std::string result_dir; - bool save_single_runs = true; - if (argc == 1) { - mode = RunMode::Save; - save_dir = "../../../munich_simulation/results"; - result_dir = "../../../munich_simulation/results"; - data_dir = "../../../munich_simulation/data"; - } - else if (argc == 4) { - mode = RunMode::Load; - save_dir = argv[1]; - result_dir = argv[2]; - data_dir = ""; - printf("Loading graph from \"%s\".\n", save_dir.c_str()); - printf("Exporting single run results and parameters: %d.\n", (int)save_single_runs); - } - else if (argc == 5) { - mode = RunMode::Save; - data_dir = argv[1]; - save_dir = argv[2]; - result_dir = argv[3]; - if (atoi(argv[4]) == 0) { - save_single_runs = false; - } - printf("Reading data from \"%s\", saving graph to \"%s\".\n", data_dir.c_str(), save_dir.c_str()); - printf("Exporting single run results and parameters: %d.\n", (int)save_single_runs); - } - else { - printf("Usage:\n"); - printf("munich_graph_sim "); - printf("\tMake graph with data from and save at , then run the simulation.\n"); - printf("\tStore the results in \n"); - printf("2021_vaccination_delta \n"); - printf("\tLoad graph from , then run the simulation.\n"); - return 0; - } - - boost::filesystem::path dir1(result_dir); - bool created_result_dir = boost::filesystem::create_directories(dir1); - boost::filesystem::path dir2(save_dir); - bool created_save_dir = boost::filesystem::create_directories(dir2); - - if (created_result_dir) { - mio::log_info("Result directory '{:s}' was created.", dir1.string()); - } - if (created_save_dir) { - mio::log_info("Save directory '{:s}' was created.", dir2.string()); - } - printf("Saving results to \"%s\".\n", result_dir.c_str()); - - auto result = run(mode, data_dir, save_dir, result_dir); - if (!result) { - printf("%s\n", result.error().formatted_message().c_str()); - return -1; - } - return 0; -} diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 74e59412fa..b0dfb0deab 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,11 +1,51 @@ -enable_testing() -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +#------------------------------------------------------- +# Prerequisite Checks & Setup +#------------------------------------------------------- +include(GoogleTest) +set(MEMILIO_GTEST_VERSION "release-1.12.1" CACHE STRING "GoogleTest version to use") -set(GOOGLE_TEST_INDIVIDUAL ON) -include(AddGoogleTest) +#------------------------------------------------------- +# GoogleTest Dependency Setup (using FetchContent) +#------------------------------------------------------- +message(STATUS "Configuring GoogleTest dependency for tests...") -set(TESTSOURCES +# Force shared CRT for GoogleTest on Windows - set BEFORE MakeAvailable. +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +FetchContent_Declare(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG ${MEMILIO_GTEST_VERSION} + GIT_SHALLOW TRUE +) + +# Make googletest targets available (downloads, configures, adds subdirectory) +set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS TRUE) +FetchContent_MakeAvailable(googletest) +unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS) + +#------------------------------------------------------- +# Test Source File Organization +#------------------------------------------------------- +set(CORE_TESTS testmain.cpp + test_eigen_util.cpp + test_stl_util.cpp + test_uncertain.cpp + test_math_floating_point.cpp + test_math_time_series_functor.cpp + test_type_safe.cpp + test_custom_index_array.cpp + test_matrix_shape.cpp + test_metaprogramming.cpp + test_utils.cpp + test_date.cpp + test_time_series.cpp + test_transform_iterator.cpp + test_history.cpp + test_random_number_generator.cpp +) + +set(EBM_TESTS test_populations.cpp test_odeseir.cpp test_odesir.cpp @@ -19,51 +59,15 @@ set(TESTSOURCES test_sde_sirs.cpp test_sde_seirvv.cpp test_mobility.cpp - test_date.cpp - test_eigen_util.cpp test_odesecir_ageres.cpp test_odeseair.cpp test_parameter_studies.cpp - test_graph.cpp - test_graph_simulation.cpp - test_stl_util.cpp - test_uncertain.cpp - test_random_number_generator.cpp - test_time_series.cpp - test_abm_household.cpp - test_abm_infection.cpp - test_abm_location.cpp - test_abm_lockdown_rules.cpp - test_abm_masks.cpp - test_abm_mobility_rules.cpp - test_abm_person.cpp - test_abm_simulation.cpp - test_abm_serialization.cpp - test_abm_testing_strategy.cpp - test_abm_model.cpp - test_math_floating_point.cpp - test_math_time_series_functor.cpp - test_analyze_result.cpp - test_contact_matrix.cpp - test_type_safe.cpp - test_custom_index_array.cpp - test_d_abm_model.cpp + test_dynamic_npis.cpp test_flows.cpp test_feedback.cpp test_parameter_set.cpp - test_matrix_shape.cpp test_damping_sampling.cpp - test_dynamic_npis.cpp - test_regions.cpp - test_io_cli.cpp - test_io_framework.cpp - test_binary_serializer.cpp test_compartmentsimulation.cpp - test_mobility_io.cpp - test_transform_iterator.cpp - test_metaprogramming.cpp - test_history.cpp - test_utils.cpp test_ide_seir.cpp test_ide_secir.cpp test_ide_secir_ageres.cpp @@ -71,10 +75,43 @@ set(TESTSOURCES test_lct_secir.cpp test_lct_initializer_flows.cpp test_glct_secir.cpp - test_ad.cpp test_smm_model.cpp - abm_helpers.h - abm_helpers.cpp +) + +# set(NETWORK_TESTS +# test_graph.cpp +# test_graph_simulation.cpp +# test_graph_abm.cpp +# ) + +# set(ABM_TESTS +# test_abm_household.cpp +# test_abm_infection.cpp +# test_abm_location.cpp +# test_abm_lockdown_rules.cpp +# test_abm_masks.cpp +# test_abm_mobility_rules.cpp +# test_abm_person.cpp +# test_abm_simulation.cpp +# test_abm_serialization.cpp +# test_abm_testing_strategy.cpp +# test_abm_model.cpp +# test_d_abm_model.cpp +# abm_helpers.h +# abm_helpers.cpp +# ) + +# set(IO_TESTS +# test_regions.cpp +# test_io_cli.cpp +# test_io_framework.cpp +# test_binary_serializer.cpp +# test_mobility_io.cpp +# test_contact_matrix.cpp +# test_analyze_result.cpp +# ) + +set(TEST_UTILS actions.h distributions_helpers.h distributions_helpers.cpp @@ -83,11 +120,12 @@ set(TESTSOURCES random_number_test.h sanitizers.cpp temp_file_register.h - test_graph_abm.cpp ) +# Conditionally add tests dependent on optional libraries +set(JSONCPP_TESTS "") if(MEMILIO_HAS_JSONCPP) - set(TESTSOURCES ${TESTSOURCES} + list(APPEND JSONCPP_TESTS test_json_serializer.cpp test_epi_data_io.cpp test_lct_parameters_io.cpp @@ -95,21 +133,92 @@ if(MEMILIO_HAS_JSONCPP) ) endif() +set(JSONCPP_HDF5_TESTS "") if(MEMILIO_HAS_JSONCPP AND MEMILIO_HAS_HDF5) - set(TESTSOURCES ${TESTSOURCES} + list(APPEND JSONCPP_HDF5_TESTS test_save_parameters.cpp test_save_results.cpp ) endif() -add_executable(memilio-test ${TESTSOURCES}) -target_include_directories(memilio-test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(memilio-test PRIVATE memilio ode_secir ode_seir ode_secirvvs ode_secirts ode_seair ide_seir ide_secir lct_secir glct_secir abm gtest_main AD::AD graph_abm d_abm smm) -target_compile_options(memilio-test PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +# Combine all sources +set(ALL_TEST_SOURCES + ${CORE_TESTS} + ${EBM_TESTS} + ${NETWORK_TESTS} + ${ABM_TESTS} + ${IO_TESTS} + ${TEST_UTILS} + ${JSONCPP_TESTS} + ${JSONCPP_HDF5_TESTS} +) + +#------------------------------------------------------- +# Test Executable Definition +#------------------------------------------------------- +add_executable(memilio-test ${ALL_TEST_SOURCES}) + +#------------------------------------------------------- +# Target Configuration (Includes, Links, Flags) +#------------------------------------------------------- +target_include_directories(memilio-test PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) +target_link_libraries(memilio-test PRIVATE + # Memilio Models (they lready link to the required libraries publicly) + memilio + ode_secir ode_seir ode_secirvvs ode_secirts ode_seair + ide_seir ide_secir lct_secir glct_secir + abm graph_abm d_abm smm + # Testing Framework (gmock already includes gtest_main) + GTest::gtest GTest::gmock +) + +# Apply project-wide flags via helper functions (defined in root) +memilio_set_warning_flags(memilio-test) +memilio_set_coverage_flags(memilio-test) -# make unit tests find the test data files -file(TO_CMAKE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/data" MEMILIO_TEST_DATA_DIR) -configure_file(test_data_dir.h.in test_data_dir.h) -target_include_directories(memilio-test PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -add_gtest(memilio-test) +#------------------------------------------------------- +# Test Discovery and CTest Integration +#------------------------------------------------------- +gtest_discover_tests(memilio-test + TEST_PREFIX "memilio." + PROPERTIES + FOLDER "Tests" + ENVIRONMENT "CTEST_OUTPUT_ON_FAILURE=1" + DISCOVERY_TIMEOUT 120 +) + +#------------------------------------------------------- +# Custom Test Runner Target (`memilio-check`) +#------------------------------------------------------- +if(CMAKE_CONFIGURATION_TYPES) # Multi-config generators + add_custom_target(memilio-check ALL + COMMAND ${CMAKE_CTEST_COMMAND} + --force-new-ctest-process --output-on-failure + --build-config "$" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Running memilio tests ($) with output on failure..." + VERBATIM + ) +else() # Single-config generators + add_custom_target(memilio-check ALL + COMMAND ${CMAKE_CTEST_COMMAND} + --force-new-ctest-process --output-on-failure + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Running memilio tests with output on failure..." + VERBATIM + ) +endif() + +#------------------------------------------------------- +# IDE Cleanup (Hide Internal/External Targets) +#------------------------------------------------------- +mark_as_advanced( + gtest_force_shared_crt + gtest_hide_internal_symbols + INSTALL_GTEST + BUILD_GMOCK + BUILD_GTEST +) \ No newline at end of file diff --git a/cpp/tests/cmake/AddGoogleTest.cmake b/cpp/tests/cmake/AddGoogleTest.cmake deleted file mode 100644 index dfd7b974b7..0000000000 --- a/cpp/tests/cmake/AddGoogleTest.cmake +++ /dev/null @@ -1,96 +0,0 @@ -# -# -# Downloads GTest and provides a helper macro to add tests. Add make check, as well, which -# gives output on failed tests without having to set an environment variable. -# -# -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - -if(CMAKE_VERSION VERSION_LESS 3.11) - set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1") - - include(DownloadProject) - download_project(PROJ googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.12.1 - UPDATE_DISCONNECTED 1 - QUIET - ) - - # CMake warning suppression will not be needed in version 1.9 - set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "") - add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR} EXCLUDE_FROM_ALL) - unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS) -else() - include(FetchContent) - FetchContent_Declare(googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.12.1) - FetchContent_GetProperties(googletest) - - if(NOT googletest_POPULATED) - FetchContent_Populate(googletest) - set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "") - add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) - unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS) - endif() -endif() - -if(CMAKE_CONFIGURATION_TYPES) - add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} - --force-new-ctest-process --output-on-failure - --build-config "$") -else() - add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} - --force-new-ctest-process --output-on-failure) -endif() - -set_target_properties(check PROPERTIES FOLDER "Scripts") - -# include_directories(${gtest_SOURCE_DIR}/include) - -# More modern way to do the last line, less messy but needs newish CMake: -# target_include_directories(gtest INTERFACE ${gtest_SOURCE_DIR}/include) -if(GOOGLE_TEST_INDIVIDUAL) - if(NOT CMAKE_VERSION VERSION_LESS 3.9) - include(GoogleTest) - else() - set(GOOGLE_TEST_INDIVIDUAL OFF) - endif() -endif() - -# Target must already exist -macro(add_gtest TESTNAME) - target_link_libraries(${TESTNAME} PUBLIC gtest gmock gtest_main) - - if(GOOGLE_TEST_INDIVIDUAL) - if(CMAKE_VERSION VERSION_LESS 3.10) - gtest_add_tests(TARGET ${TESTNAME} - TEST_PREFIX "${TESTNAME}." - TEST_LIST TmpTestList) - set_tests_properties(${TmpTestList} PROPERTIES FOLDER "Tests") - else() - gtest_discover_tests(${TESTNAME} - TEST_PREFIX "${TESTNAME}." - PROPERTIES FOLDER "Tests" - DISCOVERY_TIMEOUT 30) - endif() - else() - add_test(${TESTNAME} ${TESTNAME}) - set_target_properties(${TESTNAME} PROPERTIES FOLDER "Tests") - endif() -endmacro() - -mark_as_advanced( - gmock_build_tests - gtest_build_samples - gtest_build_tests - gtest_disable_pthreads - gtest_force_shared_crt - gtest_hide_internal_symbols - BUILD_GMOCK - BUILD_GTEST -) - -set_target_properties(gtest gtest_main gmock gmock_main - PROPERTIES FOLDER "Extern") diff --git a/cpp/tests/cmake/DownloadProject.CMakeLists.cmake.in b/cpp/tests/cmake/DownloadProject.CMakeLists.cmake.in deleted file mode 100644 index 49a8887380..0000000000 --- a/cpp/tests/cmake/DownloadProject.CMakeLists.cmake.in +++ /dev/null @@ -1,17 +0,0 @@ -# Distributed under the OSI-approved MIT License. See accompanying -# file LICENSE or https://github.com/Crascit/DownloadProject for details. - -cmake_minimum_required(VERSION 2.8.2) - -project(${DL_ARGS_PROJ}-download NONE) - -include(ExternalProject) -ExternalProject_Add(${DL_ARGS_PROJ}-download - ${DL_ARGS_UNPARSED_ARGUMENTS} - SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" - BINARY_DIR "${DL_ARGS_BINARY_DIR}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" -) diff --git a/cpp/tests/cmake/DownloadProject.cmake b/cpp/tests/cmake/DownloadProject.cmake deleted file mode 100644 index 76aaa01f67..0000000000 --- a/cpp/tests/cmake/DownloadProject.cmake +++ /dev/null @@ -1,164 +0,0 @@ -# Distributed under the OSI-approved MIT License. See accompanying -# file LICENSE or https://github.com/Crascit/DownloadProject for details. -# -# MODULE: DownloadProject -# -# PROVIDES: -# download_project( PROJ projectName -# [PREFIX prefixDir] -# [DOWNLOAD_DIR downloadDir] -# [SOURCE_DIR srcDir] -# [BINARY_DIR binDir] -# [QUIET] -# ... -# ) -# -# Provides the ability to download and unpack a tarball, zip file, git repository, -# etc. at configure time (i.e. when the cmake command is run). How the downloaded -# and unpacked contents are used is up to the caller, but the motivating case is -# to download source code which can then be included directly in the build with -# add_subdirectory() after the call to download_project(). Source and build -# directories are set up with this in mind. -# -# The PROJ argument is required. The projectName value will be used to construct -# the following variables upon exit (obviously replace projectName with its actual -# value): -# -# projectName_SOURCE_DIR -# projectName_BINARY_DIR -# -# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically -# need to be provided. They can be specified if you want the downloaded source -# and build directories to be located in a specific place. The contents of -# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the -# locations used whether you provide SOURCE_DIR/BINARY_DIR or not. -# -# The DOWNLOAD_DIR argument does not normally need to be set. It controls the -# location of the temporary CMake build used to perform the download. -# -# The PREFIX argument can be provided to change the base location of the default -# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments -# are provided, then PREFIX will have no effect. The default value for PREFIX is -# CMAKE_BINARY_DIR. -# -# The QUIET option can be given if you do not want to show the output associated -# with downloading the specified project. -# -# In addition to the above, any other options are passed through unmodified to -# ExternalProject_Add() to perform the actual download, patch and update steps. -# The following ExternalProject_Add() options are explicitly prohibited (they -# are reserved for use by the download_project() command): -# -# CONFIGURE_COMMAND -# BUILD_COMMAND -# INSTALL_COMMAND -# TEST_COMMAND -# -# Only those ExternalProject_Add() arguments which relate to downloading, patching -# and updating of the project sources are intended to be used. Also note that at -# least one set of download-related arguments are required. -# -# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to -# prevent a check at the remote end for changes every time CMake is run -# after the first successful download. See the documentation of the ExternalProject -# module for more information. It is likely you will want to use this option if it -# is available to you. Note, however, that the ExternalProject implementation contains -# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when -# using the URL download method or when specifying a SOURCE_DIR with no download -# method. Fixes for these have been created, the last of which is scheduled for -# inclusion in CMake 3.8.0. Details can be found here: -# -# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c -# https://gitlab.kitware.com/cmake/cmake/issues/16428 -# -# If you experience build errors related to the update step, consider avoiding -# the use of UPDATE_DISCONNECTED. -# -# EXAMPLE USAGE: -# -# include(DownloadProject) -# download_project(PROJ googletest -# GIT_REPOSITORY https://github.com/google/googletest.git -# GIT_TAG master -# UPDATE_DISCONNECTED 1 -# QUIET -# ) -# -# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) -# -#======================================================================================== - - -set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}") - -include(CMakeParseArguments) - -function(download_project) - - set(options QUIET) - set(oneValueArgs - PROJ - PREFIX - DOWNLOAD_DIR - SOURCE_DIR - BINARY_DIR - # Prevent the following from being passed through - CONFIGURE_COMMAND - BUILD_COMMAND - INSTALL_COMMAND - TEST_COMMAND - ) - set(multiValueArgs "") - - cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # Hide output if requested - if (DL_ARGS_QUIET) - set(OUTPUT_QUIET "OUTPUT_QUIET") - else() - unset(OUTPUT_QUIET) - message(STATUS "Downloading/updating ${DL_ARGS_PROJ}") - endif() - - # Set up where we will put our temporary CMakeLists.txt file and also - # the base point below which the default source and binary dirs will be - if (NOT DL_ARGS_PREFIX) - set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}") - endif() - if (NOT DL_ARGS_DOWNLOAD_DIR) - set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download") - endif() - - # Ensure the caller can know where to find the source and build directories - if (NOT DL_ARGS_SOURCE_DIR) - set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src") - endif() - if (NOT DL_ARGS_BINARY_DIR) - set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build") - endif() - set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE) - set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE) - - # Create and build a separate CMake project to carry out the download. - # If we've already previously done these steps, they will not cause - # anything to be updated, so extra rebuilds of the project won't occur. - configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in" - "${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt") - execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . - RESULT_VARIABLE result - ${OUTPUT_QUIET} - WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" - ) - if(result) - message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}") - endif() - execute_process(COMMAND ${CMAKE_COMMAND} --build . - RESULT_VARIABLE result - ${OUTPUT_QUIET} - WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" - ) - if(result) - message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}") - endif() - -endfunction() diff --git a/cpp/tests/distributions_helpers.cpp b/cpp/tests/distributions_helpers.cpp index e37782f480..a7cb7cc33b 100644 --- a/cpp/tests/distributions_helpers.cpp +++ b/cpp/tests/distributions_helpers.cpp @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include +#include "distributions_helpers.h" +#include "matchers.h" #include #include diff --git a/cpp/tests/load_test_data.h b/cpp/tests/load_test_data.h index 2cb327e690..2a3d9afd3d 100644 --- a/cpp/tests/load_test_data.h +++ b/cpp/tests/load_test_data.h @@ -17,17 +17,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "test_data_dir.h" #include "memilio/utils/stl_util.h" #include #include #include #include +#include "memilio/utils/base_dir.h" template std::string get_test_data_file_path(String&& filename) { - return mio::path_join(TEST_DATA_DIR, filename); + return mio::path_join(mio::memilio_dir(),"cpp/tests/data" ,filename); } /** diff --git a/cpp/tests/sir_example_pre_agegroups.txt b/cpp/tests/sir_example_pre_agegroups.txt deleted file mode 100644 index 53b1bc2c2b..0000000000 --- a/cpp/tests/sir_example_pre_agegroups.txt +++ /dev/null @@ -1,501 +0,0 @@ -Time S E I -0.00000 1059000.00000 1000.00000 1000.00000 -0.10020 1058729.96889 1219.93091 1050.10020 -0.20040 1058400.63359 1488.14742 1111.21898 -0.30060 1057999.01493 1815.20960 1185.77547 -0.40080 1057509.31518 2213.96699 1276.71783 -0.50100 1056912.31676 2700.04522 1387.63802 -0.60120 1056184.65788 3292.43129 1522.91083 -0.70140 1055297.96256 4014.17514 1687.86230 -0.80160 1054217.79966 4893.22706 1888.97328 -0.90180 1052902.44293 5963.43214 2134.12493 -1.00200 1051301.40267 7265.70326 2432.89408 -1.10220 1049353.69964 8849.39310 2796.90727 -1.20240 1046985.85489 10773.88148 3240.26363 -1.30261 1044109.57697 13110.38578 3780.03725 -1.40281 1040619.14330 15943.98649 4436.87021 -1.50301 1036388.49846 19375.83441 5235.66713 -1.60321 1031268.13444 23525.46525 6206.40031 -1.70341 1025081.88171 28533.08745 7385.03084 -1.80361 1017623.83388 34561.62188 8814.54424 -1.90381 1008655.75905 41798.15253 10546.08842 -2.00401 997905.52554 50454.29023 12640.18424 -2.10421 985067.28917 60764.75654 15167.95429 -2.20441 969804.44398 72983.27525 18212.28077 -2.30461 951756.59875 87374.64376 21868.75749 -2.40481 930552.04420 104201.71115 26246.24465 -2.50501 905827.21175 123706.01699 31466.77126 -2.60521 877254.33117 146081.20133 37664.46750 -2.70541 844577.66873 171439.16631 44983.16496 -2.80561 807657.17678 199770.52167 53572.30155 -2.90581 766516.03890 230903.11638 63580.84472 -3.00601 721385.67036 264465.19252 75149.13712 -3.10621 672738.91591 299862.18782 88398.89627 -3.20641 621300.67652 336277.27151 103422.05197 -3.30661 568026.44663 372703.94271 120269.61066 -3.40681 514044.27118 408013.57594 138942.15288 -3.50701 460564.07691 441052.20828 159383.71480 -3.60721 408767.87673 470751.60445 181480.51883 -3.70741 359701.22681 496233.50464 205065.26855 -3.80762 314187.13915 516886.19427 229926.66658 -3.90782 272777.52581 532399.70569 255822.76849 -4.00802 235746.62886 542757.27070 282496.10044 -4.10822 203120.24211 548191.40942 309688.34847 -4.20842 174727.76593 549119.38612 337152.84794 -4.30862 150262.69162 546073.46915 364663.83923 -4.40882 129339.87831 539637.89222 392022.22947 -4.50902 111542.63555 530399.16843 419058.19601 -4.60922 96457.07073 518911.62862 445631.30064 -4.70942 83694.28991 505676.83286 471628.87723 -4.80962 72902.66790 491133.94421 496963.38789 -4.90982 63772.86900 475657.83408 521569.29692 -5.01002 56038.08040 459562.06987 545399.84973 -5.11022 49471.40928 443104.58919 568424.00153 -5.21042 43881.83967 426494.53008 590623.63025 -5.31062 39109.66720 409899.24113 611991.09167 -5.41082 35021.96665 393450.90755 632527.12580 -5.51102 31508.39414 377252.51075 652239.09511 -5.61122 28477.46176 361383.01674 671139.52150 -5.71142 25853.32264 345901.79429 689244.88306 -5.81162 23573.04872 330852.31900 706574.63228 -5.91182 21584.35558 316265.24466 723150.39976 -6.01202 19843.71785 302160.93025 738995.35190 -6.11222 18314.81746 288551.50748 754133.67506 -6.21242 16967.27089 275442.56570 768590.16341 -6.31263 15775.58750 262834.52135 782389.89115 -6.41283 14718.31780 250723.72886 795557.95334 -6.51303 13777.35717 239103.38043 808119.26240 -6.61323 12937.37615 227964.23417 820098.38968 -6.71343 12185.35378 217295.20273 831519.44349 -6.81363 11510.19469 207083.82862 842405.97670 -6.91383 10902.41428 197316.66771 852780.91801 -7.01403 10353.87935 187979.59805 862666.52261 -7.11423 9857.59377 179058.06809 872084.33814 -7.21443 9407.52109 170537.29568 881055.18323 -7.31463 8998.43717 162402.42691 889599.13592 -7.41483 8625.80749 154638.66246 897735.53006 -7.51503 8285.68474 147231.35723 905482.95804 -7.61523 7974.62302 140166.09844 912859.27854 -7.71543 7689.60588 133428.76596 919881.62816 -7.81563 7427.98561 127005.57832 926566.43607 -7.91583 7187.43210 120883.12690 932929.44100 -8.01603 6965.88949 115048.40063 938985.70988 -8.11623 6761.53932 109488.80287 944749.65781 -8.21643 6572.76925 104192.16197 950235.06877 -8.31663 6398.14632 99146.73671 955455.11697 -8.41683 6236.39403 94341.21762 960422.38835 -8.51703 6086.37275 89764.72499 965148.90226 -8.61723 5947.06282 85406.80421 969646.13297 -8.71743 5817.54998 81257.41905 973925.03097 -8.81764 5697.01281 77306.94324 977996.04395 -8.91784 5584.71183 73546.15087 981869.13730 -9.01804 5479.98003 69966.20577 985553.81420 -9.11824 5382.21464 66558.65023 989059.13513 -9.21844 5290.86994 63315.39321 992393.73684 -9.31864 5205.45099 60228.69828 995565.85073 -9.41884 5125.50813 57291.17128 998583.32059 -9.51904 5050.63216 54495.74809 1001453.61975 -9.61924 4980.45009 51835.68226 1004183.86765 -9.71944 4914.62139 49304.53289 1006780.84572 -9.81964 4852.83473 46896.15258 1009251.01270 -9.91984 4794.80500 44604.67567 1011600.51934 -10.02004 4740.27077 42424.50670 1013835.22253 -10.12024 4688.99197 40350.30921 1015960.69882 -10.22044 4640.74788 38376.99473 1017982.25739 -10.32064 4595.33523 36499.71225 1019904.95252 -10.42084 4552.56669 34713.83789 1021733.59542 -10.52104 4512.26931 33014.96504 1023472.76565 -10.62124 4474.28330 31398.89468 1025126.82202 -10.72144 4438.46082 29861.62625 1026699.91293 -10.82164 4404.66494 28399.34866 1028195.98639 -10.92184 4372.76873 27008.43182 1029618.79945 -11.02204 4342.65437 25685.41833 1030971.92730 -11.12224 4314.21239 24427.01570 1032258.77191 -11.22244 4287.34102 23230.08869 1033482.57029 -11.32265 4261.94552 22091.65209 1034646.40239 -11.42285 4237.93764 21008.86378 1035753.19858 -11.52305 4215.23507 19979.01806 1036805.74687 -11.62325 4193.77791 18999.52241 1037806.69968 -11.72345 4173.91181 18067.50863 1038758.57956 -11.82365 4156.04662 17180.18802 1039663.76536 -11.92385 4140.42846 16335.07532 1040524.49622 -12.02405 4127.13038 15529.98285 1041342.88677 -12.12425 4116.06021 14762.99777 1042120.94202 -12.22445 4106.98283 14032.44600 1042860.57117 -12.32465 4099.55354 13336.84694 1043563.59953 -12.42485 4093.35823 12674.86354 1044231.77823 -12.52505 4087.95636 12045.25220 1044866.79143 -12.62525 4082.93409 11446.80492 1045470.26098 -12.72545 4078.16721 10878.08458 1046043.74820 -12.82565 4073.64245 10337.61512 1046588.74242 -12.92585 4069.34728 9823.99371 1047106.65901 -13.02605 4065.26981 9335.88713 1047598.84306 -13.12625 4061.39881 8872.02831 1048066.57288 -13.22645 4057.72365 8431.21307 1048511.06328 -13.32665 4054.23425 8012.29701 1048933.46874 -13.42685 4050.92108 7614.19249 1049334.88643 -13.52705 4047.77511 7235.86590 1049716.35900 -13.62725 4044.78777 6876.33491 1050078.87733 -13.72745 4041.95095 6534.66596 1050423.38309 -13.82766 4039.25699 6209.97185 1050750.77116 -13.92786 4036.69858 5901.40942 1051061.89199 -14.02806 4034.26884 5608.17737 1051357.55379 -14.12826 4031.96122 5329.51418 1051638.52460 -14.22846 4029.76952 5064.69615 1051905.53433 -14.32866 4027.68785 4813.03553 1052159.27662 -14.42886 4025.71064 4573.87869 1052400.41066 -14.52906 4023.83260 4346.60450 1052629.56290 -14.62926 4022.04871 4130.62263 1052847.32866 -14.72946 4020.35422 3925.37210 1053054.27368 -14.82966 4018.74460 3730.31979 1053250.93561 -14.92986 4017.21557 3544.95905 1053437.82538 -15.03006 4015.76308 3368.80838 1053615.42854 -15.13026 4014.38326 3201.41023 1053784.20651 -15.23046 4013.07246 3042.32974 1053944.59781 -15.33066 4011.82719 2891.15367 1054097.01914 -15.43086 4010.64418 2747.48931 1054241.86651 -15.53106 4009.52027 2610.96345 1054379.51628 -15.63126 4008.45252 2481.22141 1054510.32607 -15.73146 4007.43810 2357.92614 1054634.63576 -15.83166 4006.47432 2240.75734 1054752.76833 -15.93186 4005.55866 2129.41061 1054865.03073 -16.03206 4004.68870 2023.59668 1054971.71462 -16.13226 4003.86215 1923.04063 1055073.09722 -16.23246 4003.07683 1827.48123 1055169.44194 -16.33267 4002.33068 1736.67020 1055260.99912 -16.43287 4001.62174 1650.37161 1055348.00664 -16.53307 4000.94815 1568.36125 1055430.69059 -16.63327 4000.30814 1490.42605 1055509.26581 -16.73347 3999.70003 1416.36352 1055583.93645 -16.83367 3999.12223 1345.98122 1055654.89655 -16.93387 3998.57322 1279.09631 1055722.33048 -17.03407 3998.05156 1215.53498 1055786.41346 -17.13427 3997.55589 1155.13211 1055847.31200 -17.23447 3997.08491 1097.73074 1055905.18435 -17.33467 3996.63738 1043.18173 1055960.18088 -17.43487 3996.21214 991.34336 1056012.44450 -17.53507 3995.80808 942.08092 1056062.11100 -17.63527 3995.42413 895.26643 1056109.30944 -17.73547 3995.05930 850.77823 1056154.16247 -17.83567 3994.71263 808.50074 1056196.78663 -17.93587 3994.38321 768.32411 1056237.29268 -18.03607 3994.07019 730.14394 1056275.78587 -18.13627 3993.77275 693.86102 1056312.36623 -18.23647 3993.49011 659.38108 1056347.12880 -18.33667 3993.22154 626.61454 1056380.16393 -18.43687 3992.96632 595.47623 1056411.55744 -18.53707 3992.72381 565.88527 1056441.39092 -18.63727 3992.49336 537.76475 1056469.74189 -18.73747 3992.27438 511.04162 1056496.68401 -18.83768 3992.06628 485.64642 1056522.28729 -18.93788 3991.86854 461.51318 1056546.61828 -19.03808 3991.68064 438.57918 1056569.74018 -19.13828 3991.50208 416.78483 1056591.71309 -19.23848 3991.33240 396.07351 1056612.59409 -19.33868 3991.17116 376.39139 1056632.43745 -19.43888 3991.01794 357.68732 1056651.29474 -19.53908 3990.87234 339.91272 1056669.21494 -19.63928 3990.73398 323.02138 1056686.24464 -19.73948 3990.60250 306.96943 1056702.42807 -19.83968 3990.47756 291.71514 1056717.80730 -19.93988 3990.35883 277.21888 1056732.42229 -20.04008 3990.24600 263.44299 1056746.31101 -20.14028 3990.13878 250.35166 1056759.50956 -20.24048 3990.03689 237.91088 1056772.05223 -20.34068 3989.94007 226.08832 1056783.97161 -20.44088 3989.84807 214.85325 1056795.29868 -20.54108 3989.76063 204.17650 1056806.06287 -20.64128 3989.67755 194.03030 1056816.29215 -20.74148 3989.59859 184.38830 1056826.01311 -20.84168 3989.52356 175.22544 1056835.25100 -20.94188 3989.45226 166.51791 1056844.02983 -21.04208 3989.38450 158.24309 1056852.37241 -21.14228 3989.32011 150.37946 1056860.30042 -21.24248 3989.25893 142.90661 1056867.83446 -21.34269 3989.20078 135.80511 1056874.99411 -21.44289 3989.14552 129.05650 1056881.79798 -21.54309 3989.09301 122.64325 1056888.26373 -21.64329 3989.04311 116.54870 1056894.40818 -21.74349 3988.99570 110.75701 1056900.24730 -21.84369 3988.95063 105.25312 1056905.79625 -21.94389 3988.90781 100.02274 1056911.06945 -22.04409 3988.86712 95.05228 1056916.08061 -22.14429 3988.82845 90.32881 1056920.84275 -22.24449 3988.79170 85.84007 1056925.36824 -22.34469 3988.75677 81.57439 1056929.66884 -22.44489 3988.72359 77.52068 1056933.75573 -22.54509 3988.69205 73.66842 1056937.63954 -22.64529 3988.66208 70.00758 1056941.33034 -22.74549 3988.63360 66.52867 1056944.83773 -22.84569 3988.60653 63.22264 1056948.17083 -22.94589 3988.58081 60.08089 1056951.33830 -23.04609 3988.55637 57.09527 1056954.34836 -23.14629 3988.53314 54.25801 1056957.20885 -23.24649 3988.51107 51.56174 1056959.92718 -23.34669 3988.49010 48.99947 1056962.51044 -23.44689 3988.47016 46.56452 1056964.96532 -23.54709 3988.45122 44.25057 1056967.29821 -23.64729 3988.43322 42.05161 1056969.51518 -23.74749 3988.41611 39.96192 1056971.62197 -23.84770 3988.39986 37.97608 1056973.62407 -23.94790 3988.38441 36.08891 1056975.52668 -24.04810 3988.36973 34.29553 1056977.33474 -24.14830 3988.35577 32.59127 1056979.05295 -24.24850 3988.34252 30.97170 1056980.68578 -24.34870 3988.32992 29.43261 1056982.23747 -24.44890 3988.31795 27.97000 1056983.71205 -24.54910 3988.30657 26.58008 1056985.11335 -24.64930 3988.29575 25.25922 1056986.44502 -24.74950 3988.28548 24.00401 1056987.71051 -24.84970 3988.27572 22.81117 1056988.91312 -24.94990 3988.26644 21.67760 1056990.05596 -25.05010 3988.25762 20.60037 1056991.14201 -25.15030 3988.24924 19.57666 1056992.17410 -25.25050 3988.24127 18.60383 1056993.15489 -25.35070 3988.23371 17.67934 1056994.08695 -25.45090 3988.22652 16.80080 1056994.97269 -25.55110 3988.21968 15.96591 1056995.81441 -25.65130 3988.21319 15.17251 1056996.61431 -25.75150 3988.20702 14.41853 1056997.37445 -25.85170 3988.20115 13.70203 1056998.09682 -25.95190 3988.19558 13.02113 1056998.78330 -26.05210 3988.19028 12.37406 1056999.43566 -26.15230 3988.18525 11.75915 1057000.05560 -26.25251 3988.18046 11.17480 1057000.64474 -26.35271 3988.17592 10.61949 1057001.20460 -26.45291 3988.17160 10.09177 1057001.73663 -26.55311 3988.16749 9.59027 1057002.24223 -26.65331 3988.16359 9.11370 1057002.72271 -26.75351 3988.15988 8.66081 1057003.17931 -26.85371 3988.15636 8.23042 1057003.61322 -26.95391 3988.15301 7.82143 1057004.02556 -27.05411 3988.14983 7.43275 1057004.41742 -27.15431 3988.14681 7.06339 1057004.78980 -27.25451 3988.14394 6.71239 1057005.14368 -27.35471 3988.14120 6.37883 1057005.47997 -27.45491 3988.13861 6.06184 1057005.79955 -27.55511 3988.13614 5.76061 1057006.10325 -27.65531 3988.13380 5.47434 1057006.39186 -27.75551 3988.13157 5.20230 1057006.66612 -27.85571 3988.12946 4.94378 1057006.92676 -27.95591 3988.12745 4.69811 1057007.17444 -28.05611 3988.12554 4.46465 1057007.40982 -28.15631 3988.12372 4.24278 1057007.63350 -28.25651 3988.12199 4.03194 1057007.84606 -28.35671 3988.12035 3.83158 1057008.04806 -28.45691 3988.11880 3.64118 1057008.24003 -28.55711 3988.11731 3.46024 1057008.42245 -28.65731 3988.11591 3.28828 1057008.59581 -28.75752 3988.11457 3.12488 1057008.76055 -28.85772 3988.11330 2.96959 1057008.91711 -28.95792 3988.11209 2.82202 1057009.06589 -29.05812 3988.11094 2.68179 1057009.20727 -29.15832 3988.10985 2.54852 1057009.34163 -29.25852 3988.10882 2.42187 1057009.46931 -29.35872 3988.10783 2.30152 1057009.59065 -29.45892 3988.10689 2.18715 1057009.70595 -29.55912 3988.10600 2.07847 1057009.81553 -29.65932 3988.10516 1.97518 1057009.91966 -29.75952 3988.10436 1.87703 1057010.01862 -29.85972 3988.10359 1.78375 1057010.11266 -29.95992 3988.10287 1.69511 1057010.20202 -30.06012 3988.10218 1.61087 1057010.28695 -30.16032 3988.10152 1.53082 1057010.36765 -30.26052 3988.10090 1.45475 1057010.44435 -30.36072 3988.10031 1.38246 1057010.51723 -30.46092 3988.09974 1.31376 1057010.58649 -30.56112 3988.09921 1.24848 1057010.65231 -30.66132 3988.09870 1.18643 1057010.71486 -30.76152 3988.09822 1.12748 1057010.77430 -30.86172 3988.09776 1.07145 1057010.83079 -30.96192 3988.09733 1.01820 1057010.88447 -31.06212 3988.09691 0.96761 1057010.93548 -31.16232 3988.09652 0.91952 1057010.98396 -31.26253 3988.09614 0.87383 1057011.03003 -31.36273 3988.09579 0.83041 1057011.07381 -31.46293 3988.09545 0.78914 1057011.11541 -31.56313 3988.09513 0.74992 1057011.15495 -31.66333 3988.09482 0.71266 1057011.19252 -31.76353 3988.09453 0.67724 1057011.22822 -31.86373 3988.09426 0.64359 1057011.26215 -31.96393 3988.09400 0.61161 1057011.29440 -32.06413 3988.09375 0.58121 1057011.32504 -32.16433 3988.09351 0.55233 1057011.35416 -32.26453 3988.09329 0.52488 1057011.38183 -32.36473 3988.09307 0.49880 1057011.40813 -32.46493 3988.09287 0.47401 1057011.43312 -32.56513 3988.09268 0.45046 1057011.45686 -32.66533 3988.09249 0.42807 1057011.47943 -32.76553 3988.09232 0.40680 1057011.50088 -32.86573 3988.09216 0.38659 1057011.52126 -32.96593 3988.09200 0.36738 1057011.54063 -33.06613 3988.09185 0.34912 1057011.55903 -33.16633 3988.09171 0.33177 1057011.57652 -33.26653 3988.09157 0.31528 1057011.59315 -33.36673 3988.09144 0.29962 1057011.60894 -33.46693 3988.09132 0.28473 1057011.62395 -33.56713 3988.09121 0.27058 1057011.63822 -33.66733 3988.09110 0.25713 1057011.65177 -33.76754 3988.09099 0.24435 1057011.66465 -33.86774 3988.09089 0.23221 1057011.67690 -33.96794 3988.09080 0.22067 1057011.68853 -34.06814 3988.09071 0.20971 1057011.69959 -34.16834 3988.09062 0.19928 1057011.71009 -34.26854 3988.09054 0.18938 1057011.72008 -34.36874 3988.09046 0.17997 1057011.72957 -34.46894 3988.09039 0.17103 1057011.73858 -34.56914 3988.09032 0.16253 1057011.74715 -34.66934 3988.09026 0.15445 1057011.75529 -34.76954 3988.09019 0.14678 1057011.76303 -34.86974 3988.09013 0.13948 1057011.77038 -34.96994 3988.09008 0.13255 1057011.77737 -35.07014 3988.09002 0.12596 1057011.78401 -35.17034 3988.08997 0.11970 1057011.79032 -35.27054 3988.08992 0.11376 1057011.79632 -35.37074 3988.08988 0.10810 1057011.80202 -35.47094 3988.08983 0.10273 1057011.80744 -35.57114 3988.08979 0.09763 1057011.81258 -35.67134 3988.08975 0.09277 1057011.81747 -35.77154 3988.08971 0.08816 1057011.82212 -35.87174 3988.08968 0.08378 1057011.82654 -35.97194 3988.08964 0.07962 1057011.83074 -36.07214 3988.08961 0.07566 1057011.83473 -36.17234 3988.08958 0.07190 1057011.83852 -36.27255 3988.08955 0.06833 1057011.84212 -36.37275 3988.08952 0.06493 1057011.84554 -36.47295 3988.08950 0.06171 1057011.84880 -36.57315 3988.08947 0.05864 1057011.85189 -36.67335 3988.08945 0.05573 1057011.85483 -36.77355 3988.08942 0.05296 1057011.85762 -36.87375 3988.08940 0.05033 1057011.86027 -36.97395 3988.08938 0.04783 1057011.86279 -37.07415 3988.08936 0.04545 1057011.86519 -37.17435 3988.08934 0.04319 1057011.86747 -37.27455 3988.08933 0.04104 1057011.86963 -37.37475 3988.08931 0.03900 1057011.87169 -37.47495 3988.08929 0.03707 1057011.87364 -37.57515 3988.08928 0.03522 1057011.87550 -37.67535 3988.08926 0.03347 1057011.87726 -37.77555 3988.08925 0.03181 1057011.87894 -37.87575 3988.08924 0.03023 1057011.88053 -37.97595 3988.08923 0.02873 1057011.88205 -38.07615 3988.08921 0.02730 1057011.88349 -38.17635 3988.08920 0.02594 1057011.88485 -38.27655 3988.08919 0.02465 1057011.88615 -38.37675 3988.08918 0.02343 1057011.88739 -38.47695 3988.08917 0.02226 1057011.88856 -38.57715 3988.08916 0.02116 1057011.88968 -38.67735 3988.08916 0.02011 1057011.89074 -38.77756 3988.08915 0.01911 1057011.89175 -38.87776 3988.08914 0.01816 1057011.89270 -38.97796 3988.08913 0.01726 1057011.89361 -39.07816 3988.08913 0.01640 1057011.89448 -39.17836 3988.08912 0.01558 1057011.89530 -39.27856 3988.08911 0.01481 1057011.89608 -39.37876 3988.08911 0.01407 1057011.89682 -39.47896 3988.08910 0.01337 1057011.89753 -39.57916 3988.08909 0.01271 1057011.89820 -39.67936 3988.08909 0.01208 1057011.89883 -39.77956 3988.08908 0.01148 1057011.89944 -39.87976 3988.08908 0.01091 1057011.90001 -39.97996 3988.08908 0.01037 1057011.90056 -40.08016 3988.08907 0.00985 1057011.90108 -40.18036 3988.08907 0.00936 1057011.90157 -40.28056 3988.08906 0.00890 1057011.90204 -40.38076 3988.08906 0.00845 1057011.90249 -40.48096 3988.08906 0.00803 1057011.90291 -40.58116 3988.08905 0.00763 1057011.90331 -40.68136 3988.08905 0.00725 1057011.90370 -40.78156 3988.08905 0.00689 1057011.90406 -40.88176 3988.08904 0.00655 1057011.90440 -40.98196 3988.08904 0.00623 1057011.90473 -41.08216 3988.08904 0.00592 1057011.90504 -41.18236 3988.08904 0.00562 1057011.90534 -41.28257 3988.08903 0.00534 1057011.90562 -41.38277 3988.08903 0.00508 1057011.90589 -41.48297 3988.08903 0.00483 1057011.90614 -41.58317 3988.08903 0.00459 1057011.90639 -41.68337 3988.08903 0.00436 1057011.90662 -41.78357 3988.08902 0.00414 1057011.90683 -41.88377 3988.08902 0.00394 1057011.90704 -41.98397 3988.08902 0.00374 1057011.90724 -42.08417 3988.08902 0.00355 1057011.90743 -42.18437 3988.08902 0.00338 1057011.90760 -42.28457 3988.08902 0.00321 1057011.90777 -42.38477 3988.08902 0.00305 1057011.90793 -42.48497 3988.08901 0.00290 1057011.90809 -42.58517 3988.08901 0.00275 1057011.90823 -42.68537 3988.08901 0.00262 1057011.90837 -42.78557 3988.08901 0.00249 1057011.90850 -42.88577 3988.08901 0.00236 1057011.90863 -42.98597 3988.08901 0.00225 1057011.90874 -43.08617 3988.08901 0.00213 1057011.90886 -43.18637 3988.08901 0.00203 1057011.90896 -43.28657 3988.08901 0.00193 1057011.90907 -43.38677 3988.08901 0.00183 1057011.90916 -43.48697 3988.08901 0.00174 1057011.90925 -43.58717 3988.08900 0.00165 1057011.90934 -43.68737 3988.08900 0.00157 1057011.90942 -43.78758 3988.08900 0.00149 1057011.90950 -43.88778 3988.08900 0.00142 1057011.90958 -43.98798 3988.08900 0.00135 1057011.90965 -44.08818 3988.08900 0.00128 1057011.90972 -44.18838 3988.08900 0.00122 1057011.90978 -44.28858 3988.08900 0.00116 1057011.90984 -44.38878 3988.08900 0.00110 1057011.90990 -44.48898 3988.08900 0.00105 1057011.90995 -44.58918 3988.08900 0.00099 1057011.91001 -44.68938 3988.08900 0.00094 1057011.91006 -44.78958 3988.08900 0.00090 1057011.91010 -44.88978 3988.08900 0.00085 1057011.91015 -44.98998 3988.08900 0.00081 1057011.91019 -45.09018 3988.08900 0.00077 1057011.91023 -45.19038 3988.08900 0.00073 1057011.91027 -45.29058 3988.08900 0.00070 1057011.91031 -45.39078 3988.08900 0.00066 1057011.91034 -45.49098 3988.08900 0.00063 1057011.91038 -45.59118 3988.08900 0.00060 1057011.91041 -45.69138 3988.08900 0.00057 1057011.91044 -45.79158 3988.08900 0.00054 1057011.91047 -45.89178 3988.08900 0.00051 1057011.91049 -45.99198 3988.08899 0.00049 1057011.91052 -46.09218 3988.08899 0.00046 1057011.91054 -46.19238 3988.08899 0.00044 1057011.91057 -46.29259 3988.08899 0.00042 1057011.91059 -46.39279 3988.08899 0.00040 1057011.91061 -46.49299 3988.08899 0.00038 1057011.91063 -46.59319 3988.08899 0.00036 1057011.91065 -46.69339 3988.08899 0.00034 1057011.91067 -46.79359 3988.08899 0.00032 1057011.91068 -46.89379 3988.08899 0.00031 1057011.91070 -46.99399 3988.08899 0.00029 1057011.91071 -47.09419 3988.08899 0.00028 1057011.91073 -47.19439 3988.08899 0.00026 1057011.91074 -47.29459 3988.08899 0.00025 1057011.91076 -47.39479 3988.08899 0.00024 1057011.91077 -47.49499 3988.08899 0.00023 1057011.91078 -47.59519 3988.08899 0.00022 1057011.91079 -47.69539 3988.08899 0.00020 1057011.91080 -47.79559 3988.08899 0.00019 1057011.91081 -47.89579 3988.08899 0.00018 1057011.91082 -47.99599 3988.08899 0.00018 1057011.91083 -48.09619 3988.08899 0.00017 1057011.91084 -48.19639 3988.08899 0.00016 1057011.91085 -48.29659 3988.08899 0.00015 1057011.91086 -48.39679 3988.08899 0.00014 1057011.91086 -48.49699 3988.08899 0.00014 1057011.91087 -48.59719 3988.08899 0.00013 1057011.91088 -48.69739 3988.08899 0.00012 1057011.91089 -48.79760 3988.08899 0.00012 1057011.91089 -48.89780 3988.08899 0.00011 1057011.91090 -48.99800 3988.08899 0.00011 1057011.91090 -49.09820 3988.08899 0.00010 1057011.91091 -49.19840 3988.08899 0.00010 1057011.91091 -49.29860 3988.08899 0.00009 1057011.91092 -49.39880 3988.08899 0.00009 1057011.91092 -49.49900 3988.08899 0.00008 1057011.91093 -49.59920 3988.08899 0.00008 1057011.91093 -49.69940 3988.08899 0.00007 1057011.91093 -49.79960 3988.08899 0.00007 1057011.91094 -49.89980 3988.08899 0.00007 1057011.91094 -50.00000 3988.08899 0.00006 1057011.91095 \ No newline at end of file diff --git a/cpp/tests/test_ad.cpp b/cpp/tests/test_ad.cpp index 9403ac2993..ff6f87204f 100644 --- a/cpp/tests/test_ad.cpp +++ b/cpp/tests/test_ad.cpp @@ -24,7 +24,7 @@ #include "memilio/utils/logging.h" -#include "ad/ad.hpp" +#include "memilio/ad/ad.hpp" #include "boost/numeric/odeint.hpp" #include @@ -74,7 +74,7 @@ TEST(Testad, ad_square) // Test that the "ad" library can be used as expected with a more complex example. // This test ensures that boost::numeric::odeint::runge_kutta_cash_karp54 can be fully -// algorithmically diffentiated using the algorithmic differentiation (AD) data types of ad/ad.hpp. +// algorithmically diffentiated using the algorithmic differentiation (AD) data types of memilio/ad/ad.hpp. // Define the rhs of the ODE x' = f(x), that should be solved using odeint. template diff --git a/cpp/tests/test_data_dir.h b/cpp/tests/test_data_dir.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/tests/test_data_dir.h.in b/cpp/tests/test_data_dir.h.in deleted file mode 100644 index d8da63cf0d..0000000000 --- a/cpp/tests/test_data_dir.h.in +++ /dev/null @@ -1,26 +0,0 @@ -/* -* Copyright (C) 2020-2025 MEmilio -* -* Authors: Daniel Abele -* -* Contact: Martin J. Kuehn -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#ifndef TEST_DATA_DIR_H -#define TEST_DATA_DIR_H - -constexpr const char* TEST_DATA_DIR = "${MEMILIO_TEST_DATA_DIR}"; -constexpr const char* TEST_GERMANY_PYDATA_DIR = "${MEMILIO_TEST_DATA_DIR}/Germany/pydata"; - -#endif //TEST_DATA_DIR_H diff --git a/cpp/tests/test_epi_data_io.cpp b/cpp/tests/test_epi_data_io.cpp index 0797365323..bde4c95f1c 100644 --- a/cpp/tests/test_epi_data_io.cpp +++ b/cpp/tests/test_epi_data_io.cpp @@ -25,7 +25,7 @@ #include "matchers.h" #include "memilio/io/io.h" #include "memilio/io/mobility_io.h" -#include "test_data_dir.h" +#include "memilio/utils/base_dir.h" #include "gtest/gtest.h" #include "json/value.h" #include "ode_secirts/model.h" @@ -251,7 +251,7 @@ TEST(TestEpiDataIo, read_county_ids) 16061, 16062, 16063, 16064, 16065, 16066, 16067, 16068, 16069, 16070, 16071, 16072, 16073, 16074, 16075, 16076, 16077}; - std::string path = mio::path_join(TEST_DATA_DIR, "county_current_population.json"); + std::string path = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"); auto read_ids = mio::get_node_ids(path, true, true); ASSERT_THAT(print_wrap(read_ids), IsSuccess()); @@ -264,7 +264,7 @@ TEST(TestEpiDataIo, get_node_ids) std::vector true_ids_county = {1001}; - std::string path = mio::path_join(TEST_DATA_DIR, "test_current_population.json"); + std::string path = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "test_current_population.json"); auto read_ids_district = mio::get_node_ids(path, false, true); auto read_ids_county = mio::get_node_ids(path, true, true); ASSERT_THAT(print_wrap(read_ids_district), IsSuccess()); @@ -276,7 +276,7 @@ TEST(TestEpiDataIo, get_node_ids) TEST(TestEpiDataIo, read_divi_data) { - auto divi_data = mio::read_divi_data(mio::path_join(TEST_DATA_DIR, "test_county_divi.json")).value(); + auto divi_data = mio::read_divi_data(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "test_county_divi.json")).value(); ASSERT_EQ(divi_data.size(), 4); @@ -308,7 +308,7 @@ TEST(TestEpiDataIo, is_divi_data_available) TEST(TestEpiDataIo, read_confirmed_cases_data) { - auto case_data = mio::read_confirmed_cases_data(mio::path_join(TEST_DATA_DIR, "test_cases_all_age.json")).value(); + auto case_data = mio::read_confirmed_cases_data(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "test_cases_all_age.json")).value(); ASSERT_EQ(case_data.size(), 3); @@ -343,7 +343,7 @@ TEST(TestEpiDataIo, read_confirmed_cases_data) TEST(TestEpiDataIo, read_confirmed_cases_noage_data) { auto rki_data_noage = - mio::read_confirmed_cases_noage(mio::path_join(TEST_DATA_DIR, "cases_all_germany.json")).value(); + mio::read_confirmed_cases_noage(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_germany.json")).value(); ASSERT_EQ(rki_data_noage.size(), 15); @@ -370,7 +370,7 @@ TEST(TestEpiDataIo, read_confirmed_cases_noage_data) TEST(TestEpiDataIO, read_vaccination_data) { - auto vacc_data = mio::read_vaccination_data(mio::path_join(TEST_DATA_DIR, "test_all_ageinf_vacc.json")).value(); + auto vacc_data = mio::read_vaccination_data(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "test_all_ageinf_vacc.json")).value(); ASSERT_EQ(vacc_data.size(), 2); @@ -406,7 +406,7 @@ TEST(TestEpiData, set_vaccination_data) std::vector> model_vector{model}; auto f = mio::osecirts::details::set_vaccination_data(model_vector, - mio::path_join(TEST_DATA_DIR, "vaccination_test.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "vaccination_test.json"), mio::Date(2022, 4, 15), county_ids, num_days); auto expected_values_PI = diff --git a/cpp/tests/test_ide_parameters_io.cpp b/cpp/tests/test_ide_parameters_io.cpp index 2ff4deaf43..0b3fa133bf 100644 --- a/cpp/tests/test_ide_parameters_io.cpp +++ b/cpp/tests/test_ide_parameters_io.cpp @@ -30,7 +30,7 @@ #include "memilio/utils/logging.h" #include "memilio/io/io.h" -#include "test_data_dir.h" +#include "memilio/utils/base_dir.h" #include "load_test_data.h" #include "matchers.h" #include @@ -93,7 +93,7 @@ TEST(TestIDEParametersIo, RKIcompareWithPreviousRun) // Calculate initialization. auto status = mio::isecir::set_initial_flows( - model, dt, mio::read_confirmed_cases_noage(mio::path_join(TEST_DATA_DIR, "cases_all_germany.json")).value(), + model, dt, mio::read_confirmed_cases_noage(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_germany.json")).value(), start_date, scale_confirmed_cases); ASSERT_THAT(print_wrap(status), IsSuccess()); @@ -178,7 +178,7 @@ TEST(TestIDEParametersIo, RKIcompareWithPreviousRunAgeRes) // Calculate initialization. auto status = mio::isecir::set_initial_flows( - model, dt, mio::read_confirmed_cases_data(mio::path_join(TEST_DATA_DIR, "cases_all_age_ma7.json")).value(), + model, dt, mio::read_confirmed_cases_data(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_age_ma7.json")).value(), start_date, scale_confirmed_cases); ASSERT_THAT(print_wrap(status), IsSuccess()); @@ -246,7 +246,7 @@ TEST(TestIDEParametersIo, ParametersIoRKIFailure) mio::CustomIndexArray scale_confirmed_cases = mio::CustomIndexArray(mio::AgeGroup(num_agegroups), 1.); auto status = mio::isecir::set_initial_flows( - model, dt, mio::read_confirmed_cases_noage(mio::path_join(TEST_DATA_DIR, "test_empty_file.json")).value(), + model, dt, mio::read_confirmed_cases_noage(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "test_empty_file.json")).value(), start_date, scale_confirmed_cases); ASSERT_THAT(print_wrap(status), IsFailure(mio::StatusCode::InvalidFileFormat)); @@ -254,7 +254,7 @@ TEST(TestIDEParametersIo, ParametersIoRKIFailure) // --- Case where start_date is later than maximal provided date in file. start_date = mio::Date(2021, 06, 8); std::vector test_data = - mio::read_confirmed_cases_noage(mio::path_join(TEST_DATA_DIR, "cases_all_germany.json")).value(); + mio::read_confirmed_cases_noage(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_germany.json")).value(); status = mio::isecir::set_initial_flows(model, dt, test_data, start_date, scale_confirmed_cases); @@ -320,7 +320,7 @@ TEST(TestIDEParametersIo, ParametersIoRKIFailureAgeRes) mio::CustomIndexArray scale_confirmed_cases = mio::CustomIndexArray(mio::AgeGroup(num_agegroups), 1.); auto status = mio::isecir::set_initial_flows( - model, dt, mio::read_confirmed_cases_data(mio::path_join(TEST_DATA_DIR, "test_empty_file.json")).value(), + model, dt, mio::read_confirmed_cases_data(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "test_empty_file.json")).value(), start_date, scale_confirmed_cases); ASSERT_THAT(print_wrap(status), IsFailure(mio::StatusCode::InvalidFileFormat)); @@ -328,7 +328,7 @@ TEST(TestIDEParametersIo, ParametersIoRKIFailureAgeRes) // --- Case where start_date is later than maximal provided date in file. start_date = mio::Date(2021, 01, 05); std::vector test_data = - mio::read_confirmed_cases_data(mio::path_join(TEST_DATA_DIR, "cases_all_age_ma7.json")).value(); + mio::read_confirmed_cases_data(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_age_ma7.json")).value(); status = mio::isecir::set_initial_flows(model, dt, test_data, start_date, scale_confirmed_cases); diff --git a/cpp/tests/test_lct_parameters_io.cpp b/cpp/tests/test_lct_parameters_io.cpp index d27bbf5ec7..c718c92ac1 100644 --- a/cpp/tests/test_lct_parameters_io.cpp +++ b/cpp/tests/test_lct_parameters_io.cpp @@ -28,7 +28,7 @@ #include "memilio/utils/time_series.h" #include "memilio/utils/logging.h" #include "memilio/epidemiology/lct_infection_state.h" -#include "test_data_dir.h" +#include "memilio/utils/base_dir.h" #include "memilio/io/epi_data.h" #include "memilio/io/io.h" #include "matchers.h" diff --git a/cpp/tests/test_math_floating_point.cpp b/cpp/tests/test_math_floating_point.cpp index 3653b919f9..98b29da83c 100644 --- a/cpp/tests/test_math_floating_point.cpp +++ b/cpp/tests/test_math_floating_point.cpp @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "ad/ad.hpp" +#include "memilio/ad/ad.hpp" #include "memilio/math/floating_point.h" #include diff --git a/cpp/tests/test_odesecir.cpp b/cpp/tests/test_odesecir.cpp index a578d287e4..f1bdb67b5e 100644 --- a/cpp/tests/test_odesecir.cpp +++ b/cpp/tests/test_odesecir.cpp @@ -21,7 +21,7 @@ #include "load_test_data.h" #include "matchers.h" #include "temp_file_register.h" - +#include "memilio/utils/base_dir.h" #include "ode_secir/model.h" #include "ode_secir/parameter_space.h" #include "ode_secir/parameters.h" @@ -1219,7 +1219,7 @@ TEST(TestOdeSecir, apply_constraints_parameters) TEST(TestOdeSecir, read_population_data_one_age_group) { - std::string path = mio::path_join(TEST_DATA_DIR, "county_current_population.json"); + std::string path = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"); const std::vector region{1001}; auto result_one_age_group = mio::osecir::details::read_population_data(path, region, true).value(); auto result_multiple_age_groups = mio::osecir::details::read_population_data(path, region, false).value(); @@ -1280,15 +1280,15 @@ TEST_F(ModelTestOdeSecir, read_input_data) auto read_result1 = mio::osecir::read_input_data_county(model1, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), 1.0, - TEST_GERMANY_PYDATA_DIR, 10); + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata"), 10); auto read_result2 = mio::osecir::read_input_data(model2, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), - 1.0, TEST_GERMANY_PYDATA_DIR, 10); + 1.0, mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata"), 10); auto read_result_district = mio::osecir::read_input_data(model3, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), - 1.0, mio::path_join(TEST_DATA_DIR, "District", "pydata"), 10); + 1.0, mio::path_join(mio::memilio_dir(),"cpp/tests/data", "District", "pydata"), 10); EXPECT_THAT(read_result1, IsSuccess()); EXPECT_THAT(read_result2, IsSuccess()); @@ -1317,7 +1317,7 @@ TEST_F(ModelTestOdeSecir, export_time_series_init) TempFileRegister temp_file_register; auto tmp_results_dir = temp_file_register.get_unique_path(); EXPECT_THAT(mio::create_directory(tmp_results_dir), IsSuccess()); - const auto pydata_dir_Germany = mio::path_join(TEST_DATA_DIR, "Germany", "pydata"); + const auto pydata_dir_Germany = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany", "pydata"); // Test exporting time series std::vector> models{model}; @@ -1334,7 +1334,7 @@ TEST_F(ModelTestOdeSecir, export_time_series_init) // Values were generated by the tested function export_input_data_county_timeseries; // can only check stability of the implementation, not correctness auto expected_results = - mio::read_result(mio::path_join(TEST_DATA_DIR, "export_time_series_initialization_osecir.h5")).value(); + mio::read_result(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "export_time_series_initialization_osecir.h5")).value(); EXPECT_THAT(print_wrap(data_extrapolated.value()[0].get_groups().matrix()), MatrixNear(print_wrap(expected_results[0].get_groups().matrix()), 1e-5, 1e-5)); @@ -1347,7 +1347,7 @@ TEST_F(ModelTestOdeSecir, export_time_series_init_old_date) TempFileRegister temp_file_register; auto tmp_results_dir = temp_file_register.get_unique_path(); EXPECT_THAT(mio::create_directory(tmp_results_dir), IsSuccess()); - const auto pydata_dir_Germany = mio::path_join(TEST_DATA_DIR, "Germany", "pydata"); + const auto pydata_dir_Germany = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany", "pydata"); // Test exporting time series std::vector> models{model}; @@ -1382,7 +1382,7 @@ TEST_F(ModelTestOdeSecir, model_initialization) { // Vector assignment necessary as read_input_data_county changes model auto model_vector = std::vector>{model}; - const auto pydata_dir_Germany = mio::path_join(TEST_DATA_DIR, "Germany", "pydata"); + const auto pydata_dir_Germany = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany", "pydata"); EXPECT_THAT(mio::osecir::read_input_data_county(model_vector, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), 1.0, @@ -1409,7 +1409,7 @@ TEST_F(ModelTestOdeSecir, model_initialization_old_date) mio::set_log_level(mio::LogLevel::off); // Vector assignment necessary as read_input_data_county changes model auto model_vector = std::vector>{model}; - const auto pydata_dir_Germany = mio::path_join(TEST_DATA_DIR, "Germany", "pydata"); + const auto pydata_dir_Germany = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany", "pydata"); EXPECT_THAT(mio::osecir::read_input_data_county(model_vector, {1000, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), 1.0, @@ -1474,8 +1474,7 @@ TEST_F(ModelTestOdeSecir, set_confirmed_cases_data_with_ICU) // read case data auto case_data = - mio::read_confirmed_cases_data(mio::path_join(TEST_DATA_DIR, "cases_all_county_age_ma7.json")).value(); - + mio::read_confirmed_cases_data(mio::path_join(mio::memilio_dir(),"cpp/tests/data/Germany/pydata", "cases_all_county_age_ma7.json")).value(); // Change dates of the case data so that no ICU data is available at that time. // Also, increase the number of confirmed cases by 1 each day. const auto t0 = mio::Date(2025, 1, 1); diff --git a/cpp/tests/test_odesecirts.cpp b/cpp/tests/test_odesecirts.cpp index 5fd960a699..c7aa12409c 100644 --- a/cpp/tests/test_odesecirts.cpp +++ b/cpp/tests/test_odesecirts.cpp @@ -20,7 +20,7 @@ #include "matchers.h" #include "temp_file_register.h" -#include "test_data_dir.h" +#include "memilio/utils/base_dir.h" #include "memilio/data/analyze_result.h" #include "memilio/epidemiology/contact_matrix.h" #include "memilio/epidemiology/damping.h" @@ -43,7 +43,6 @@ #include "ode_secirts/parameters.h" #include "ode_secirts/parameters_io.h" #include "ode_secirts/analyze_result.h" - #include "gtest/gtest.h" #include "gmock/gmock-matchers.h" #include @@ -716,7 +715,7 @@ TEST(TestOdeSECIRTS, read_confirmed_cases) auto num_age_groups = 6; //reading data requires RKI data age groups auto model = std::vector>({make_model(num_age_groups)}); const std::vector region{1002}; - auto path = mio::path_join(TEST_DATA_DIR, "Germany/pydata/cases_all_county_age_ma7.json"); + auto path = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata/cases_all_county_age_ma7.json"); std::vector> num_InfectedSymptoms(1); std::vector> num_death(1); @@ -798,7 +797,7 @@ TEST(TestOdeSECIRTS, set_confirmed_cases_data_with_ICU) // read case data auto case_data = - mio::read_confirmed_cases_data(mio::path_join(TEST_DATA_DIR, "cases_all_county_age_ma7.json")).value(); + mio::read_confirmed_cases_data(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_county_age_ma7.json")).value(); // Change dates of the case data so that no ICU data is available at that time. // Also, increase the number of confirmed cases by 1 each day. @@ -859,15 +858,15 @@ TEST(TestOdeSECIRTS, read_data) auto read_result1 = mio::osecirts::read_input_data_county(model1, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), 1.0, - TEST_GERMANY_PYDATA_DIR, 10, immunity_population); + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata"), 10, immunity_population); auto read_result2 = mio::osecirts::read_input_data(model2, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), - 1.0, TEST_GERMANY_PYDATA_DIR, 10, immunity_population); + 1.0, mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata"), 10, immunity_population); auto read_result_district = mio::osecirts::read_input_data(model3, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), - 1.0, mio::path_join(TEST_DATA_DIR, "District/pydata"), 10, immunity_population); + 1.0, mio::path_join(mio::memilio_dir(),"cpp/tests/data", "District/pydata"), 10, immunity_population); ASSERT_THAT(read_result1, IsSuccess()); ASSERT_THAT(read_result2, IsSuccess()); @@ -1022,10 +1021,10 @@ TEST(TestOdeSECIRTS, export_time_series_init) ASSERT_THAT(mio::osecirts::export_input_data_county_timeseries( std::vector>{model}, tmp_results_dir, {0}, {2020, 12, 01}, std::vector(size_t(num_age_groups), 1.0), 1.0, 2, - mio::path_join(TEST_DATA_DIR, "county_divi_ma7.json"), - mio::path_join(TEST_DATA_DIR, "cases_all_county_age_ma7.json"), - mio::path_join(TEST_DATA_DIR, "county_current_population.json"), immunity_population, - mio::path_join(TEST_DATA_DIR, "vacc_county_ageinf_ma7.json")), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_divi_ma7.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_county_age_ma7.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"), immunity_population, + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "vacc_county_ageinf_ma7.json")), IsSuccess()); auto data_extrapolated = mio::read_result(mio::path_join(tmp_results_dir, "Results_rki.h5")); @@ -1034,7 +1033,7 @@ TEST(TestOdeSECIRTS, export_time_series_init) // Values were generated by the tested function export_input_data_county_timeseries; // can only check stability of the implementation, not correctness auto expected_results = - mio::read_result(mio::path_join(TEST_DATA_DIR, "export_time_series_initialization_osecirts.h5")).value(); + mio::read_result(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "export_time_series_initialization_osecirts.h5")).value(); ASSERT_THAT(print_wrap(data_extrapolated.value()[0].get_groups().matrix()), MatrixNear(print_wrap(expected_results[0].get_groups().matrix()), 1e-5, 1e-5)); @@ -1054,7 +1053,7 @@ TEST(TestOdeSECIRTS, model_initialization) ASSERT_THAT(mio::osecirts::read_input_data_county(model_vector, {2020, 12, 01}, {0}, std::vector(size_t(num_age_groups), 1.0), 1.0, - TEST_DATA_DIR, 2, immunity_population, false), + mio::memilio_dir(), 2, immunity_population, false), IsSuccess()); // Values from data/export_time_series_init_osecirts.h5, for reading in comparison diff --git a/cpp/tests/test_odesecirvvs.cpp b/cpp/tests/test_odesecirvvs.cpp index c890b5a27c..d04a646aa6 100644 --- a/cpp/tests/test_odesecirvvs.cpp +++ b/cpp/tests/test_odesecirvvs.cpp @@ -20,7 +20,7 @@ #include "matchers.h" #include "temp_file_register.h" -#include "test_data_dir.h" +#include "memilio/utils/base_dir.h" #include "memilio/data/analyze_result.h" #include "memilio/epidemiology/contact_matrix.h" #include "memilio/epidemiology/damping.h" @@ -514,7 +514,7 @@ TEST(TestOdeSECIRVVS, read_confirmed_cases) auto num_age_groups = 6; //reading data requires RKI data age groups auto model = std::vector>({make_model(num_age_groups)}); std::vector region{1002}; - auto path = mio::path_join(TEST_DATA_DIR, "Germany/pydata/cases_all_county_age_ma7.json"); + auto path = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata/cases_all_county_age_ma7.json"); std::vector> t_Exposed(1); std::vector> t_InfectedNoSymptoms(1); std::vector> t_InfectedSymptoms(1); @@ -608,7 +608,7 @@ TEST(TestOdeSECIRVVS, set_confirmed_cases_data_with_ICU) // read case data auto case_data = - mio::read_confirmed_cases_data(mio::path_join(TEST_DATA_DIR, "cases_all_county_age_ma7.json")).value(); + mio::read_confirmed_cases_data(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_county_age_ma7.json")).value(); // Change dates of the case data so that no ICU data is available at that time. // Also, increase the number of confirmed cases by 1 each day. @@ -662,15 +662,15 @@ TEST(TestOdeSECIRVVS, read_data) auto model2 = std::vector>({make_model(num_age_groups)}); auto model3 = std::vector>({make_model(num_age_groups)}); - const auto pydata_dir_District = mio::path_join(TEST_DATA_DIR, "District", "pydata"); + const auto pydata_dir_District = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "District", "pydata"); auto read_result1 = mio::osecirvvs::read_input_data_county(model1, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), 1.0, - TEST_GERMANY_PYDATA_DIR, 10); + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata"), 10); auto read_result2 = mio::osecirvvs::read_input_data(model2, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), 1.0, - TEST_GERMANY_PYDATA_DIR, 10); + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata"), 10); auto read_result_district = mio::osecirvvs::read_input_data( model3, {2020, 12, 01}, {1002}, std::vector(size_t(num_age_groups), 1.0), 1.0, pydata_dir_District, 10); @@ -828,10 +828,10 @@ TEST(TestOdeSECIRVVS, export_time_series_init) ASSERT_THAT(mio::osecirvvs::export_input_data_county_timeseries( std::vector>{model}, tmp_results_dir, {0}, {2020, 12, 01}, std::vector(size_t(num_age_groups), 1.0), 1.0, 2, - mio::path_join(TEST_DATA_DIR, "county_divi_ma7.json"), - mio::path_join(TEST_DATA_DIR, "cases_all_county_age_ma7.json"), - mio::path_join(TEST_DATA_DIR, "county_current_population.json"), - mio::path_join(TEST_DATA_DIR, "vacc_county_ageinf_ma7.json")), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_divi_ma7.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_county_age_ma7.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "vacc_county_ageinf_ma7.json")), IsSuccess()); auto data_extrapolated = mio::read_result(mio::path_join(tmp_results_dir, "Results_rki.h5")); @@ -840,7 +840,7 @@ TEST(TestOdeSECIRVVS, export_time_series_init) // Values were generated by the tested function export_input_data_county_timeseries; // can only check stability of the implementation, not correctness auto expected_results = - mio::read_result(mio::path_join(TEST_DATA_DIR, "export_time_series_initialization_osecirvvs.h5")).value(); + mio::read_result(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "export_time_series_initialization_osecirvvs.h5")).value(); ASSERT_THAT(print_wrap(data_extrapolated.value()[0].get_groups().matrix()), MatrixNear(print_wrap(expected_results[0].get_groups().matrix()), 1e-5, 1e-5)); @@ -866,10 +866,10 @@ TEST(TestOdeSECIRVVS, export_time_series_init_old_date) ASSERT_THAT(mio::osecirvvs::export_input_data_county_timeseries( std::vector>{model}, tmp_results_dir, {0}, {20, 12, 01}, std::vector(size_t(num_age_groups), 1.0), 1.0, 0, - mio::path_join(TEST_DATA_DIR, "county_divi_ma7.json"), - mio::path_join(TEST_DATA_DIR, "cases_all_county_age_ma7.json"), - mio::path_join(TEST_DATA_DIR, "county_current_population.json"), - mio::path_join(TEST_DATA_DIR, "vacc_county_ageinf_ma7.json")), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_divi_ma7.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_county_age_ma7.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "vacc_county_ageinf_ma7.json")), IsSuccess()); auto data_extrapolated = mio::read_result(mio::path_join(tmp_results_dir, "Results_rki.h5")); @@ -878,7 +878,7 @@ TEST(TestOdeSECIRVVS, export_time_series_init_old_date) // if we enter an old date, the model only should be initialized with the population data. // read population data - std::string path = mio::path_join(TEST_DATA_DIR, "county_current_population.json"); + std::string path = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"); const std::vector region{0}; auto population_data = mio::osecirvvs::details::read_population_data(path, region).value(); @@ -903,7 +903,7 @@ TEST(TestOdeSECIRVVS, model_initialization) ASSERT_THAT(mio::osecirvvs::read_input_data_county(model_vector, {2020, 12, 01}, {0}, std::vector(size_t(num_age_groups), 1.0), 1.0, - TEST_GERMANY_PYDATA_DIR, 2, false), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata"), 2, false), IsSuccess()); // Values from data/export_time_series_init_osecirvvs.h5, for reading in comparison @@ -944,12 +944,12 @@ TEST(TestOdeSECIRVVS, model_initialization_old_date) ASSERT_THAT(mio::osecirvvs::read_input_data(model_vector, {100, 12, 01}, {0}, std::vector(size_t(num_age_groups), 1.0), 1.0, - TEST_GERMANY_PYDATA_DIR, 0, false), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata"), 0, false), IsSuccess()); // if we enter an old date, the model only should be initialized with the population data. // read population data - std::string path = mio::path_join(TEST_DATA_DIR, "county_current_population.json"); + std::string path = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"); const std::vector region{0}; auto population_data = mio::osecirvvs::details::read_population_data(path, region).value(); @@ -981,12 +981,12 @@ TEST(TestOdeSECIRVVS, model_initialization_old_date_county) ASSERT_THAT(mio::osecirvvs::read_input_data_county(model_vector, {100, 12, 01}, {0}, std::vector(size_t(num_age_groups), 1.0), 1.0, - TEST_GERMANY_PYDATA_DIR, 0, false), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata"), 0, false), IsSuccess()); // if we enter an old date, the model only should be initialized with the population data. // read population data - std::string path = mio::path_join(TEST_DATA_DIR, "county_current_population.json"); + std::string path = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"); const std::vector region{0}; auto population_data = mio::osecirvvs::details::read_population_data(path, region).value(); @@ -1019,13 +1019,13 @@ TEST(TestOdeSECIRVVS, set_population_data_overflow_vacc) auto model_vector = std::vector>{model}; - std::string path_pop_data = mio::path_join(TEST_DATA_DIR, "county_current_population.json"); + std::string path_pop_data = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"); const std::vector region{0}; auto population_data = mio::osecirvvs::details::read_population_data(path_pop_data, region).value(); // we choose the date so that no case data is available ASSERT_THAT(mio::osecirvvs::details::set_population_data( - model_vector, path_pop_data, mio::path_join(TEST_DATA_DIR, "cases_all_county_age_ma7.json"), {0}, + model_vector, path_pop_data, mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_county_age_ma7.json"), {0}, {1000, 12, 01}), IsSuccess()); @@ -1059,13 +1059,13 @@ TEST(TestOdeSECIRVVS, set_population_data_no_data_avail) auto model_vector = std::vector>{model}; - std::string path_pop_data = mio::path_join(TEST_DATA_DIR, "county_current_population.json"); + std::string path_pop_data = mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json"); const std::vector region{0}; auto population_data = mio::osecirvvs::details::read_population_data(path_pop_data, region).value(); // we choose the date so that no case data is available ASSERT_THAT(mio::osecirvvs::details::set_population_data( - model_vector, path_pop_data, mio::path_join(TEST_DATA_DIR, "cases_all_county_age_ma7.json"), {200}, + model_vector, path_pop_data, mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_county_age_ma7.json"), {200}, {1000, 12, 01}), IsSuccess()); @@ -1083,7 +1083,7 @@ TEST(TestOdeSECIRVVS, run_simulation) // Load result of a previous run; only tests stability, not correctness. auto expected_result = - mio::read_result(mio::path_join(TEST_DATA_DIR, "results_osecirvvs.h5")).value()[0].get_groups(); + mio::read_result(mio::path_join(mio::memilio_dir(),"cpp/tests/data", "results_osecirvvs.h5")).value()[0].get_groups(); ASSERT_THAT(print_wrap(result.matrix()), MatrixNear(print_wrap(expected_result.matrix()), 1e-5, 1e-5)); } diff --git a/cpp/tests/test_save_parameters.cpp b/cpp/tests/test_save_parameters.cpp index 21c1820217..0f7f68f94a 100644 --- a/cpp/tests/test_save_parameters.cpp +++ b/cpp/tests/test_save_parameters.cpp @@ -18,7 +18,7 @@ * limitations under the License. */ #include "load_test_data.h" -#include "test_data_dir.h" +#include "memilio/utils/base_dir.h" #include "ode_secir/model.h" #include "ode_secir/parameter_space.h" #include "ode_secir/parameters_io.h" @@ -26,8 +26,8 @@ #include "ode_secirvvs/parameters_io.h" #include "memilio/io/mobility_io.h" #include "memilio/io/result_io.h" -#include -#include +#include "distributions_helpers.h" +#include "matchers.h" #include "temp_file_register.h" #include "memilio/utils/date.h" #include @@ -632,7 +632,7 @@ TEST(TestSaveParameters, ReadPopulationDataRKIAges) double scaling_factor_icu = 1.0; mio::Date date(2020, 12, 10); - std::string path = TEST_DATA_DIR; + std::string path = mio::path_join(mio::memilio_dir(),"cpp/tests/data"); for (auto group = mio::AgeGroup(0); group < mio::AgeGroup(6); group++) { model[0].parameters.get>()[group] = @@ -681,7 +681,7 @@ TEST(TestSaveParameters, ReadPopulationDataStateAllAges) std::vector state = {1}; - std::string path = TEST_DATA_DIR; + std::string path = mio::path_join(mio::memilio_dir(),"cpp/tests/data"); for (auto group = mio::AgeGroup(0); group < mio::AgeGroup(6); group++) { model[0].parameters.get>()[group] = @@ -752,11 +752,11 @@ TEST(TestSaveParameters, ReadPopulationDataCountyAllAges) } auto read_result1 = mio::osecir::read_input_data_county(model1, date, county, scaling_factor_inf, - scaling_factor_icu, TEST_GERMANY_PYDATA_DIR); + scaling_factor_icu, mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata")); auto read_result2 = mio::osecir::read_input_data(model2, date, county, scaling_factor_inf, scaling_factor_icu, - TEST_GERMANY_PYDATA_DIR); + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "Germany/Pydata")); auto read_result_district = mio::osecir::read_input_data( - model3, date, county, scaling_factor_inf, scaling_factor_icu, mio::path_join(TEST_DATA_DIR, "District/pydata")); + model3, date, county, scaling_factor_inf, scaling_factor_icu, mio::path_join(mio::memilio_dir(),"cpp/tests/data", "District/pydata")); ASSERT_THAT(print_wrap(read_result1), IsSuccess()); ASSERT_THAT(print_wrap(read_result2), IsSuccess()); ASSERT_THAT(print_wrap(read_result_district), IsSuccess()); @@ -840,9 +840,9 @@ TEST(TestSaveParameters, ExtrapolateRKI) boost::filesystem::create_directory(results_dir); auto extrapolate_result = mio::osecir::export_input_data_county_timeseries( model, results_dir, county, date, scaling_factor_inf, scaling_factor_icu, 1, - mio::path_join(TEST_DATA_DIR, "county_divi_ma7.json"), - mio::path_join(TEST_DATA_DIR, "cases_all_county_age_ma7.json"), - mio::path_join(TEST_DATA_DIR, "county_current_population.json")); + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_divi_ma7.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "cases_all_county_age_ma7.json"), + mio::path_join(mio::memilio_dir(),"cpp/tests/data", "county_current_population.json")); ASSERT_THAT(print_wrap(extrapolate_result), IsSuccess()); auto read_result = mio::read_result(mio::path_join(results_dir, "Results_rki.h5")); diff --git a/cpp/tests/test_uncertain.cpp b/cpp/tests/test_uncertain.cpp index fefbeba7b4..9e2809e150 100644 --- a/cpp/tests/test_uncertain.cpp +++ b/cpp/tests/test_uncertain.cpp @@ -21,7 +21,7 @@ #include "memilio/utils/uncertain_value.h" #include "memilio/epidemiology/uncertain_matrix.h" #include "memilio/utils/parameter_distributions.h" -#include +#include "distributions_helpers.h" #include #include diff --git a/cpp/thirdparty/CMakeLists.txt b/cpp/thirdparty/CMakeLists.txt index 7a6b672b4e..63fb32e0c0 100644 --- a/cpp/thirdparty/CMakeLists.txt +++ b/cpp/thirdparty/CMakeLists.txt @@ -1,223 +1,333 @@ -# Versions of the bundled libraries -# If you like to upgrade, just change the number -set(MEMILIO_EIGEN_VERSION "3.4.0") -set(MEMILIO_SPDLOG_VERSION "1.15.0") -set(MEMILIO_BOOST_VERSION "1.84.0") +#------------------------------------------------------- +# Bundled Library Versions +#------------------------------------------------------- +set(MEMILIO_BUNDLED_EIGEN_VERSION "3.4.0") +set(MEMILIO_BUNDLED_SPDLOG_VERSION "1.15.0") +set(MEMILIO_BUNDLED_BOOST_VERSION "1.84.0") set(MEMILIO_MINIMAL_BOOST_VERSION "1.76.0") -set(MEMILIO_JSONCPP_VERSION "1.9.6") -set(MEMILIO_RANDOM123_VERSION "v1.14.0") -set(MEMILIO_IPOPT_VERSION "3.14.12") +set(MEMILIO_BUNDLED_JSONCPP_VERSION "1.9.6") +set(MEMILIO_BUNDLED_RANDOM123_VERSION "v1.14.0") +set(MEMILIO_BUNDLED_IPOPT_VERSION "3.14.12") -# Gperftools for profiling; must be first, so that libraries are included in the profile +#------------------------------------------------------- +# Gperftools (Profiling - Optional, Unix-only) +#------------------------------------------------------- if(MEMILIO_ENABLE_PROFILING) if(NOT UNIX) - message(FATAL_ERROR "Profiling with gperftools currently only supported on unix systems.") + message(FATAL_ERROR "Profiling requires a Unix-like system.") endif() - find_package(PkgConfig REQUIRED) - pkg_check_modules(GPERFTOOLS REQUIRED libprofiler) - link_libraries(${GPERFTOOLS_LINK_LIBRARIES}) # link globally so all libs are included - include_directories(${GPERFTOOLS_INCLUDE_DIRS}) + pkg_check_modules(GPERFTOOLS REQUIRED libprofiler) # Find using pkg-config + + if(GPERFTOOLS_FOUND AND NOT TARGET memilio::gperftools) + add_library(memilio::gperftools INTERFACE IMPORTED) + target_include_directories(memilio::gperftools SYSTEM INTERFACE ${GPERFTOOLS_INCLUDE_DIRS}) + target_link_libraries(memilio::gperftools INTERFACE ${GPERFTOOLS_LINK_LIBRARIES}) + message(STATUS "Profiling enabled: Found system gperftools. Created target memilio::gperftools.") + elseif(NOT GPERFTOOLS_FOUND) + message(FATAL_ERROR "gperftools required for profiling but not found.") + endif() endif() -# ## SPDLOG -set(SPDLOG_INSTALL ON) - +#------------------------------------------------------- +# Spdlog (Logging - Required) +#------------------------------------------------------- +set(MEMILIO_HAS_SPDLOG FALSE CACHE BOOL "Spdlog support status" FORCE) # Initialize status variable if(MEMILIO_USE_BUNDLED_SPDLOG) - message(STATUS "Downloading Spdlog library") - - include(FetchContent) + message(STATUS "Using bundled Spdlog ${MEMILIO_BUNDLED_SPDLOG_VERSION}") FetchContent_Declare( spdlog + QUIET GIT_REPOSITORY https://github.com/gabime/spdlog.git - GIT_TAG v${MEMILIO_SPDLOG_VERSION} + GIT_TAG v${MEMILIO_BUNDLED_SPDLOG_VERSION} + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE ) - FetchContent_GetProperties(spdlog) - - if(NOT spdlog_POPULATED) - FetchContent_Populate(spdlog) - add_subdirectory(${spdlog_SOURCE_DIR} ${spdlog_BINARY_DIR} EXCLUDE_FROM_ALL) + # Set FetchContent build options before MakeAvailable + set(SPDLOG_INSTALL OFF CACHE BOOL "" FORCE) + set(SPDLOG_BUILD_EXAMPLE OFF CACHE BOOL "" FORCE) + set(SPDLOG_BUILD_TESTS OFF CACHE BOOL "" FORCE) + set(SPDLOG_BUILD_BENCH OFF CACHE BOOL "" FORCE) + set(SPDLOG_FMT_EXTERNAL OFF CACHE BOOL "" FORCE) # Use spdlog's bundled fmt library + FetchContent_MakeAvailable(spdlog) + + # Verify the expected target was created by the bundled build + if(NOT TARGET spdlog::spdlog) + if(TARGET spdlog) + message(STATUS "Creating alias spdlog::spdlog for bundled target spdlog.") + add_library(spdlog::spdlog ALIAS spdlog) + set(MEMILIO_HAS_SPDLOG TRUE CACHE BOOL "Spdlog support status" FORCE) + else() + message(FATAL_ERROR "Bundled spdlog build did not create expected target spdlog or spdlog::spdlog.") + endif() + else() + set(MEMILIO_HAS_SPDLOG TRUE CACHE BOOL "Spdlog support status" FORCE) # Update status variable endif() - else() - find_package(spdlog REQUIRED) + message(STATUS "Searching for system Spdlog...") + find_package(spdlog REQUIRED CONFIG) # Use CMake config mode for modern targets + message(STATUS "Found system spdlog: ${spdlog_VERSION}") + + # Ensure the modern spdlog::spdlog target exists, creating an alias if needed + if(TARGET spdlog AND NOT TARGET spdlog::spdlog) + message(STATUS "Creating alias spdlog::spdlog for system target spdlog.") + add_library(spdlog::spdlog ALIAS spdlog) + elseif(NOT TARGET spdlog::spdlog) + message(FATAL_ERROR "System spdlog found, but required target spdlog::spdlog is missing.") + endif() + set(MEMILIO_HAS_SPDLOG TRUE CACHE BOOL "Spdlog support status" FORCE) # Update status variable endif() -# ## EIGEN +#------------------------------------------------------- +# Eigen (Linear Algebra - Required) +#------------------------------------------------------- +set(MEMILIO_HAS_EIGEN FALSE CACHE BOOL "EIGEN support status" FORCE) if(MEMILIO_USE_BUNDLED_EIGEN) - message(STATUS "Downloading Eigen library") - - include(FetchContent) - FetchContent_Declare(eigen + message(STATUS "Using bundled Eigen ${MEMILIO_BUNDLED_EIGEN_VERSION} (headers only)") + FetchContent_Declare( + eigen + SOURCE_DIR "" GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git - GIT_TAG ${MEMILIO_EIGEN_VERSION}) + GIT_TAG ${MEMILIO_BUNDLED_EIGEN_VERSION} + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + QUIET + + ) + # SOURCE_DIR is empty to avoid building the CMake project, we only need the headers + FetchContent_GetProperties(eigen) if(NOT eigen_POPULATED) FetchContent_Populate(eigen) endif() - add_library(eigen INTERFACE) - target_include_directories(eigen SYSTEM INTERFACE ${eigen_SOURCE_DIR}) - add_library(Eigen3::Eigen ALIAS eigen) + + # Manually create the INTERFACE target since we skipped MakeAvailable + if(NOT TARGET Eigen3::Eigen) + add_library(eigen INTERFACE) + target_include_directories(eigen SYSTEM INTERFACE ${eigen_SOURCE_DIR}) + add_library(Eigen3::Eigen ALIAS eigen) + message(STATUS "Created INTERFACE target Eigen3::Eigen for bundled headers.") + endif() + set(MEMILIO_HAS_EIGEN TRUE CACHE BOOL "EIGEN support status" FORCE) else() - find_package(Eigen3 ${MEMILIO_EIGEN_VERSION} REQUIRED NO_MODULE) + # Require system Eigen version >= bundled version for consistency + set(MEMILIO_MINIMAL_EIGEN_VERSION ${MEMILIO_BUNDLED_EIGEN_VERSION}) + message(STATUS "Searching for system Eigen >= ${MEMILIO_MINIMAL_EIGEN_VERSION}...") + find_package(Eigen3 ${MEMILIO_MINIMAL_EIGEN_VERSION} REQUIRED NO_MODULE) # Use Eigen3Config.cmake + message(STATUS "Found system Eigen3: ${EIGEN3_VERSION_STRING}") + + # Verify find_package created the target + if(NOT TARGET Eigen3::Eigen) + message(FATAL_ERROR "System Eigen3 found, but required target Eigen3::Eigen is missing.") + endif() + set(MEMILIO_HAS_EIGEN TRUE CACHE BOOL "EIGEN support status" FORCE) endif() -# ## IPOPT (numerial optimization) -if(MEMILIO_ENABLE_IPOPT) - message(STATUS "Downloading Ipopt library") - include(FetchContent) - FetchContent_Declare(Ipopt +#------------------------------------------------------- +# Ipopt (Numerical Optimization - Optional) +#------------------------------------------------------- +if(MEMILIO_ENABLE_IPOPT) + # Currently, only the bundled version via a specific CMake-enabled fork is supported. + message(STATUS "Using bundled Ipopt ${MEMILIO_BUNDLED_IPOPT_VERSION} (MEMILIO_ENABLE_IPOPT=ON)") + FetchContent_Declare( + Ipopt # Uses a specific CMake-enabled fork GIT_REPOSITORY https://git.rwth-aachen.de/avt-svt/public/thirdparty/IpoptCmake.git - GIT_TAG ${MEMILIO_IPOPT_VERSION}) - + GIT_TAG ${MEMILIO_BUNDLED_IPOPT_VERSION} + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + ) FetchContent_MakeAvailable(Ipopt) + + # Verify that the Ipopt target was created successfully + # Adjust target name checks if the IpoptCmake project uses different ones + if(TARGET ipopt AND NOT TARGET Ipopt::Ipopt) + message(STATUS "Bundled Ipopt configured. Creating alias Ipopt::Ipopt.") + add_library(Ipopt::Ipopt ALIAS ipopt) + set(IPOPT_FOUND TRUE CACHE BOOL "Ipopt found (bundled)") + elseif(TARGET Ipopt::Ipopt) + message(STATUS "Bundled Ipopt configured (target Ipopt::Ipopt found).") + set(IPOPT_FOUND TRUE CACHE BOOL "Ipopt found (bundled)") + else() + # Warn but don't fail by default, allows project to proceed without Ipopt if desired + message(WARNING "Ipopt target (expected 'ipopt' or 'Ipopt::Ipopt') not found after FetchContent.") + endif() endif() -# ## BOOST +#------------------------------------------------------- +# Boost +#------------------------------------------------------- +set(BOOST_FOUND FALSE CACHE BOOL "Boost found status" FORCE) if(MEMILIO_USE_BUNDLED_BOOST) - message(STATUS "Downloading Boost library") - - string(REPLACE "." "_" MEMILIO_BOOST_VERSION_UNDERSC "${MEMILIO_BOOST_VERSION}") - - include(FetchContent) - FetchContent_Declare(boost - - # don't use the URL from github, that download isn't complete and requires more setup (subrepositories, bootstrapping) - URL https://archives.boost.io/release/${MEMILIO_BOOST_VERSION}/source/boost_${MEMILIO_BOOST_VERSION_UNDERSC}.tar.gz + message(STATUS "Using bundled Boost ${MEMILIO_BUNDLED_BOOST_VERSION} (building filesystem component)") + string(REPLACE "." "_" MEMILIO_BOOST_VERSION_UNDERSC "${MEMILIO_BUNDLED_BOOST_VERSION}") + FetchContent_Declare( + boost_download + DOWNLOAD_PROGRESS TRUE + URL https://archives.boost.io/release/${MEMILIO_BUNDLED_BOOST_VERSION}/source/boost_${MEMILIO_BOOST_VERSION_UNDERSC}.tar.gz + URL_HASH SHA256=a5800f405508f5df8114558ca9855d2640a2de8f0445f051fa1c7c3383045724 + ) - FetchContent_GetProperties(boost) - - if(NOT boost_POPULATED) - FetchContent_Populate(boost) - endif() + FetchContent_MakeAvailable(boost_download) + #NOTE: Manually building Boost::filesystem to avoid full Boost build system dependency. + # 1. Interface target for headers add_library(boost INTERFACE) - add_dependencies(boost boost-bootstrap) + target_include_directories(boost SYSTEM INTERFACE ${boost_download_SOURCE_DIR}) add_library(Boost::boost ALIAS boost) - target_include_directories(boost SYSTEM INTERFACE $) - + # Suppress common Boost header warnings if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14) - target_compile_options(boost INTERFACE "-Wno-c++20-attribute-extensions") - else() - target_compile_options(boost INTERFACE "-Wno-c++20-extensions") - endif() + target_compile_options(boost INTERFACE "-Wno-c++20-attribute-extensions") endif() + # 2. Interface target to disable MSVC auto-linking add_library(boost_disable_autolink INTERFACE) - target_compile_definitions(boost_disable_autolink INTERFACE BOOST_ALL_NO_LIB) add_library(Boost::disable_autolinking ALIAS boost_disable_autolink) + if(MSVC) + target_compile_definitions(boost_disable_autolink INTERFACE BOOST_ALL_NO_LIB) + endif() + # 3. Static library target for filesystem source files add_library(boost_filesystem STATIC - ${boost_SOURCE_DIR}/libs/filesystem/src/codecvt_error_category.cpp - ${boost_SOURCE_DIR}/libs/filesystem/src/directory.cpp - ${boost_SOURCE_DIR}/libs/filesystem/src/exception.cpp - ${boost_SOURCE_DIR}/libs/filesystem/src/operations.cpp - ${boost_SOURCE_DIR}/libs/filesystem/src/path.cpp - ${boost_SOURCE_DIR}/libs/filesystem/src/path_traits.cpp - ${boost_SOURCE_DIR}/libs/filesystem/src/portability.cpp - ${boost_SOURCE_DIR}/libs/filesystem/src/unique_path.cpp - ${boost_SOURCE_DIR}/libs/filesystem/src/utf8_codecvt_facet.cpp - ${boost_SOURCE_DIR}/libs/filesystem/src/windows_file_codecvt.cpp + ${boost_download_SOURCE_DIR}/libs/filesystem/src/codecvt_error_category.cpp + ${boost_download_SOURCE_DIR}/libs/filesystem/src/directory.cpp + ${boost_download_SOURCE_DIR}/libs/filesystem/src/exception.cpp + ${boost_download_SOURCE_DIR}/libs/filesystem/src/operations.cpp + ${boost_download_SOURCE_DIR}/libs/filesystem/src/path.cpp + ${boost_download_SOURCE_DIR}/libs/filesystem/src/path_traits.cpp + ${boost_download_SOURCE_DIR}/libs/filesystem/src/portability.cpp + ${boost_download_SOURCE_DIR}/libs/filesystem/src/unique_path.cpp + ${boost_download_SOURCE_DIR}/libs/filesystem/src/utf8_codecvt_facet.cpp + $,${boost_download_SOURCE_DIR}/libs/filesystem/src/windows_file_codecvt.cpp,> ) - - # Ensure that the boost atomic library is used instead of the standard atomic library, where some functionality is only available as of C++20. target_compile_definitions(boost_filesystem PUBLIC BOOST_FILESYSTEM_NO_CXX20_ATOMIC_REF) - - target_link_libraries(boost_filesystem PUBLIC boost_disable_autolink boost) - set_property(TARGET boost_filesystem PROPERTY POSITION_INDEPENDENT_CODE ON) - add_library(Boost::filesystem ALIAS boost_filesystem) - - if(NOT MSVC) # on gcc and apple clang we need to define BOOST_NO_CXX98_FUNCTION_BASE because a deprecated function is sometimes used in boost - target_compile_definitions(boost_filesystem PUBLIC BOOST_NO_CXX98_FUNCTION_BASE) + if(NOT MSVC) + target_compile_definitions(boost_filesystem PUBLIC BOOST_NO_CXX98_FUNCTION_BASE) endif() + target_link_libraries(boost_filesystem PUBLIC boost boost_disable_autolink) + set_property(TARGET boost_filesystem PROPERTY POSITION_INDEPENDENT_CODE ON) # Needed for static libs used in shared libs or executables + add_library(Boost::filesystem ALIAS boost_filesystem) - set(Boost_LIBRARIES Boost::boost Boost::filesystem) - set(Boost_FOUND ON) + # Signal that Boost (required parts) is available + set(BOOST_FOUND TRUE CACHE BOOL "Boost found (bundled)" FORCE) + set(Boost_VERSION_STRING ${MEMILIO_BUNDLED_BOOST_VERSION} CACHE STRING "Boost version (bundled)" FORCE) + message(VERBOSE "Bundled Boost::filesystem target created.") else() - find_package(Boost ${MEMILIO_MINIMAL_BOOST_VERSION}...${MEMILIO_BOOST_VERSION} REQUIRED COMPONENTS outcome optional filesystem) + message(STATUS "Searching for system Boost >= ${MEMILIO_MINIMAL_BOOST_VERSION} (components: filesystem)...") + find_package(Boost ${MEMILIO_MINIMAL_BOOST_VERSION} REQUIRED COMPONENTS filesystem) # find_package should define Boost::filesystem + message(STATUS "Found system Boost: ${Boost_VERSION_STRING}") + # Verify find_package created the target + if(TARGET Boost::filesystem) + message(FATAL_ERROR "System Boost found, but required target Boost::filesystem is missing.") + set(BOOST_FOUND TRUE CACHE BOOL "Boost found (system)" FORCE) + endif() endif() -# ## HDF5 -find_package(HDF5 COMPONENTS C) - +#------------------------------------------------------- +# HDF5 (IO Format) +#------------------------------------------------------- +# Check MEMILIO_ENABLE_HDF5 option set in the main CMakeLists.txt +set(MEMILIO_HAS_HDF5 FALSE CACHE BOOL "HDF5 support status" FORCE) # Initialize status variable +message(STATUS "Searching for optional system HDF5 (C library)...") +find_package(HDF5 COMPONENTS C QUIET) if(HDF5_FOUND) - set(MEMILIO_HAS_HDF5 ON) + if (TARGET HDF5::HDF5) + message(STATUS "Found system HDF5: ${HDF5_VERSION} (using target HDF5::HDF5)") + set(MEMILIO_HAS_HDF5 TRUE CACHE BOOL "HDF5 support status" FORCE) + elseif(TARGET hdf5) # Check for common non-namespaced target from older find modules + message(STATUS "Found system HDF5: ${HDF5_VERSION} (target hdf5). Creating alias HDF5::HDF5.") + add_library(HDF5::HDF5 ALIAS hdf5) + set(MEMILIO_HAS_HDF5 TRUE CACHE BOOL "HDF5 support status" FORCE) + else() + message(WARNING "System HDF5 found, but required target (HDF5::HDF5 or hdf5) missing.") + endif() else() - message(WARNING "HDF5 was not found. Memilio will be built without some IO features. Install HDF5 Libraries and set the HDF5_DIR cmake variable to the directory containing the hdf5-config.cmake file to build with HDF5.") + message(WARNING "System HDF5 not found.") endif() -# ## JSONCPP +#------------------------------------------------------- +# JsonCpp (JSON Parsing) +#------------------------------------------------------- +# Option MEMILIO_USE_BUNDLED_JSONCPP controls whether to fetch or find +set(MEMILIO_HAS_JSONCPP FALSE CACHE BOOL "JsonCpp support status" FORCE) # Initialize status variable if(MEMILIO_USE_BUNDLED_JSONCPP) - message(STATUS "Downloading jsoncpp library") - - include(FetchContent) + message(STATUS "Using bundled JsonCpp ${MEMILIO_BUNDLED_JSONCPP_VERSION}") FetchContent_Declare( jsoncpp - URL https://github.com/open-source-parsers/jsoncpp/archive/${MEMILIO_JSONCPP_VERSION}.tar.gz + QUIET + DOWNLOAD_PROGRESS TRUE + URL https://github.com/open-source-parsers/jsoncpp/archive/${MEMILIO_BUNDLED_JSONCPP_VERSION}.tar.gz + URL_HASH SHA256=f93b6dd7ce796b13d02c108bc9f79812245a82e577581c4c9aabe57075c90ea2 + ) - FetchContent_GetProperties(jsoncpp) - - if(NOT jsoncpp_POPULATED) - FetchContent_Populate(jsoncpp) - - # set jsoncpp configurations - set(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" OFF) - set(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON) - - add_subdirectory(${jsoncpp_SOURCE_DIR} ${jsoncpp_BINARY_DIR} EXCLUDE_FROM_ALL) - - # unset global cache variables to avoid clashes with our code - unset(BUILD_OBJECT_LIBS CACHE) - unset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY CACHE) - unset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY CACHE) - unset(CMAKE_PDB_OUTPUT_DIRECTORY CACHE) - unset(CMAKE_RUNTIME_OUTPUT_DIRECTORY CACHE) - endif() - - if(BUILD_SHARED_LIBS) + # Set FetchContent build options before MakeAvailable + set(JSONCPP_WITH_TESTS OFF CACHE BOOL "" FORCE) + set(JSONCPP_WITH_POST_BUILD_UNITTEST OFF CACHE BOOL "" FORCE) + set(JSONCPP_INSTALL OFF CACHE BOOL "" FORCE) + # Match shared/static build type with the main project + set(BUILD_SHARED_LIBS ${MEMILIO_BUILD_SHARED_LIBS} CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(jsoncpp) + + # Create the standard JsonCpp::JsonCpp alias target if needed + if(TARGET jsoncpp_static AND NOT TARGET JsonCpp::JsonCpp) + add_library(JsonCpp::JsonCpp ALIAS jsoncpp_static) + message(STATUS "Bundled JsonCpp (static) configured. Target JsonCpp::JsonCpp created.") + set(MEMILIO_HAS_JSONCPP TRUE CACHE BOOL "JsonCpp support status" FORCE) + elseif(TARGET jsoncpp_lib AND NOT TARGET JsonCpp::JsonCpp) add_library(JsonCpp::JsonCpp ALIAS jsoncpp_lib) + message(STATUS "Bundled JsonCpp (shared) configured. Target JsonCpp::JsonCpp created.") + set(MEMILIO_HAS_JSONCPP TRUE CACHE BOOL "JsonCpp support status" FORCE) + elseif(TARGET JsonCpp::JsonCpp) # If subproject already created the namespaced target + message(STATUS "Bundled JsonCpp configured (Target JsonCpp::JsonCpp exists).") + set(MEMILIO_HAS_JSONCPP TRUE CACHE BOOL "JsonCpp support status" FORCE) else() - add_library(JsonCpp::JsonCpp ALIAS jsoncpp_static) + message(WARNING "Failed to find expected target after configuring bundled JsonCpp.") endif() -else() - find_package(jsoncpp CONFIG) -endif() -if(TARGET JsonCpp::JsonCpp) - set(MEMILIO_HAS_JSONCPP ON) else() - message(WARNING "JsonCpp was not found. Memilio will be built without some IO features. - Set CMake variable MEMILIO_USE_BUNDLED_JSONCPP to ON or install JsonCpp and set the jsoncpp_DIR cmake variable - to the directory containing the jsoncppConfig.cmake file to build with JsonCpp.") -endif() - -if(MEMILIO_ENABLE_MPI) - find_package(MPI REQUIRED COMPONENTS CXX) -endif() - -if(MEMILIO_ENABLE_OPENMP) - find_package(OpenMP REQUIRED COMPONENTS CXX) + message(STATUS "Searching for optional system JsonCpp...") + # Find quietly using CONFIG mode first + find_package(jsoncpp CONFIG QUIET) + + if(TARGET JsonCpp::JsonCpp) # Check for the standard modern target + set(jsoncpp_version_str "unknown") + if(jsoncpp_VERSION) + set(jsoncpp_version_str ${jsoncpp_VERSION}) + elseif(JsonCpp_VERSION) + set(jsoncpp_version_str ${JsonCpp_VERSION}) + endif() + message(STATUS "Found system JsonCpp: ${jsoncpp_version_str} (using target JsonCpp::JsonCpp)") + set(MEMILIO_HAS_JSONCPP TRUE CACHE BOOL "JsonCpp support status" FORCE) + else() + message(STATUS "Optional: System JsonCpp not found or JsonCpp::JsonCpp target missing.") + endif() endif() -# Random123 library for random number generators -message(STATUS "Downloading Random123 library") - -include(FetchContent) -FetchContent_Declare(Random123 +#------------------------------------------------------- +# Random123 +#------------------------------------------------------- +# Always use the bundled version for this simple header-only library +message(STATUS "Using bundled Random123 ${MEMILIO_BUNDLED_RANDOM123_VERSION}") +FetchContent_Declare( + Random123 + QUIET GIT_REPOSITORY https://github.com/DEShawResearch/random123 - GIT_TAG ${MEMILIO_RANDOM123_VERSION} - CONFIGURE_COMMAND "" - BUILD_COMMAND "") -FetchContent_GetProperties(Random123) - -if(NOT Random123_POPULATED) - FetchContent_Populate(Random123) + GIT_TAG ${MEMILIO_BUNDLED_RANDOM123_VERSION} + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + SOURCE_SUBDIR "" +) +FetchContent_MakeAvailable(Random123) + +# Create the INTERFACE target +if(NOT TARGET Random123) + add_library(Random123 INTERFACE) + message(STATUS ${FETCHCONTENT_BASE_DIR}) + target_include_directories(Random123 SYSTEM INTERFACE ${random123_SOURCE_DIR}/include) + message(VERBOSE "Bundled Random123 configured. Target Random123 created.") endif() -add_library(Random123 INTERFACE) -target_include_directories(Random123 INTERFACE ${random123_SOURCE_DIR}/include) +