Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

155 add vaccination model from paper #233

Merged
merged 67 commits into from
Jul 12, 2022
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
ba3e5e1
[ci skip] added new secir_vacinated model with first modifications
WadimKoslow Jan 26, 2022
bc4226e
remove implicit euler for vaccine model
dabele Feb 21, 2022
eba127d
remove unused files and comments
dabele Mar 18, 2022
b7076be
move shared analyze_result functions to main library
dabele Mar 18, 2022
91d1305
move read/write_graph to main library
dabele Mar 18, 2022
e81a741
move read/save_result to main library
dabele Mar 18, 2022
3c887c8
move age_group to main library
dabele Mar 18, 2022
739d393
generic read rki data in main library
dabele Mar 19, 2022
3d9a5a2
clean up parameter space for vaccine model
dabele Mar 19, 2022
40b9475
fix read_rki_data
dabele Mar 22, 2022
467e6af
read divi and population data in memilio main library
dabele Mar 23, 2022
d6483fb
move interpolation of population data to main library
dabele Mar 23, 2022
5be43f0
move get_county_ids to main lib
dabele Mar 23, 2022
8bacba7
move parameter_studies to main library
dabele Mar 23, 2022
5ba9ea2
add secir vaccine model after review
dabele Mar 29, 2022
245451e
fix pybindings for parameter studies
dabele Mar 29, 2022
e5caf2f
rename namespace secirv
dabele Mar 30, 2022
f8a9b62
rename secir vaccine files
dabele Mar 30, 2022
7b891a3
fix mobility
dabele Mar 30, 2022
3f73d2a
readme
dabele Mar 30, 2022
c554f35
rename vaccination parameters
dabele Mar 30, 2022
4be2ed2
fix compile issues
dabele Mar 30, 2022
766e6a5
Readme for vaccination model
dabele Mar 30, 2022
641b24c
use two dimensional array for vaccination parameters
dabele Mar 30, 2022
1341e9b
revert commenting out of cmake install
dabele Mar 30, 2022
67c6274
remove obsolete function
dabele Mar 30, 2022
3749267
fix license file header
dabele Mar 30, 2022
e11b423
disable warning that can't be fixed
dabele Mar 30, 2022
d543860
fix conversion warnings
dabele Mar 30, 2022
c27c1e6
epi_data requires jsoncpp
dabele Mar 30, 2022
46739c6
fix msvc warnings
dabele Mar 30, 2022
76866b3
change model name, directory and namespace
dabele Apr 7, 2022
cda84d1
load rki case data with new file name
dabele Apr 7, 2022
54b1181
review changes
dabele May 31, 2022
e7c2277
review changes
dabele May 31, 2022
06dfa3c
review changes
dabele May 31, 2022
fc90289
review changes
dabele Jun 1, 2022
b45c035
review changes
dabele Jun 1, 2022
d9d2870
review changes
dabele Jun 1, 2022
8eda497
review changes
dabele Jun 1, 2022
4cdb322
review changes
dabele Jun 1, 2022
a219cbb
review changes
dabele Jun 1, 2022
6dba103
review changes
dabele Jun 1, 2022
087929f
review changes
dabele Jun 1, 2022
d5cf3cd
review changes
dabele Jun 1, 2022
58dbfbb
review changes
dabele Jun 1, 2022
580a3e9
review changes
dabele Jun 1, 2022
2083b67
review changes
dabele Jun 2, 2022
c18c665
review changes
dabele Jun 2, 2022
66c63c1
review changes
dabele Jun 2, 2022
a85408c
[skip ci] first test for secirvvs (does not work!)
dabele Jun 22, 2022
c5a50ef
[skip ci] unit test for osecirvvs model
dabele Jun 22, 2022
df19f5a
full tests for secirvvs ODE model
dabele Jun 23, 2022
5a92474
tests for metaprogramming
dabele Jun 23, 2022
4262a3c
Merge branch 'main' into 155-merge-vacciantion-functionality-into-mai…
dabele Jun 24, 2022
948e6da
file formatting
dabele Jun 24, 2022
34c3206
[ci skip] fix msvc build: conversion warning
dabele Jun 24, 2022
d0b8d5a
fix gcc build: ambiguous implicit conversion
dabele Jun 24, 2022
7ce3fb1
exclude osecirvvs tests that require IO
dabele Jun 24, 2022
a03d3e1
fix gcc build without optional dependencies: include what you use!
dabele Jun 24, 2022
8892d10
review suggestion: fix typo
dabele Jul 11, 2022
d5b5fbe
Merge branch 'main' into 155-merge-vacciantion-functionality-into-mai…
dabele Jul 11, 2022
8a11bf5
review suggestions: variable names
dabele Jul 11, 2022
310f8d9
review suggestions: switch county and state id
dabele Jul 11, 2022
cfe6552
Merge branch '155-merge-vacciantion-functionality-into-main-branch' o…
dabele Jul 11, 2022
85aba4f
fix oseir bindings: template arguments
dabele Jul 11, 2022
bf1ea01
move/rename startsummer parameter
dabele Jul 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ add_subdirectory(memilio)
if (MEMILIO_BUILD_MODELS)
add_subdirectory(models/abm)
add_subdirectory(models/secir)
add_subdirectory(models/ode_secirvvs)
add_subdirectory(models/seir)
endif()
if (MEMILIO_BUILD_EXAMPLES)
Expand Down
18 changes: 12 additions & 6 deletions cpp/examples/parameter_study_secir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
*/
#include "secir/secir_parameters_io.h"
#include "secir/parameter_space.h"
#include "secir/parameter_studies.h"
#include "memilio/compartments/parameter_studies.h"
#include "memilio/mobility/mobility.h"
#include "memilio/io/result_io.h"

/**
* @brief creates xml file with a single run parameter study with std 0 (used to save parameters of individual runs)
Expand Down Expand Up @@ -68,8 +69,10 @@ write_single_run_result(const int run,
std::transform(graph.nodes().begin(), graph.nodes().end(), std::back_inserter(ids), [](auto& node) {
return node.id;
});
auto num_groups = (int)(size_t)graph.nodes()[0].property.get_simulation().get_model().parameters.get_num_groups();
BOOST_OUTCOME_TRY(
mio::save_result(all_results, ids, mio::path_join(abs_path, ("Results_run" + std::to_string(run) + ".h5"))));
mio::save_result(all_results, ids, num_groups,
mio::path_join(abs_path, ("Results_run" + std::to_string(run) + ".h5"))));

return mio::success();
}
Expand Down Expand Up @@ -163,17 +166,20 @@ int main()

//create study
auto num_runs = size_t(1);
mio::ParameterStudy<mio::SecirSimulation<>> parameter_study(model, t0, tmax, 0.2, num_runs);
mio::ParameterStudy<mio::SecirSimulation<>> parameter_study(model, t0, tmax, num_runs);

//run study
int run = 0;
auto lambda = [&run](auto&& graph) {
int run = 0;
auto sample_graph = [](auto&& graph) {
return mio::draw_sample(graph);
};
auto handle_result = [&run](auto&& graph) {
auto write_result_status = write_single_run_result(run++, graph);
if (!write_result_status) {
std::cout << "Error writing result: " << write_result_status.error().formatted_message();
}
};
parameter_study.run(lambda);
parameter_study.run(sample_graph, handle_result);

return 0;
}
4 changes: 3 additions & 1 deletion cpp/examples/read_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
* limitations under the License.
*/
#include "memilio/mobility/mobility.h"
#include "secir/secir_parameters_io.h"
#include "memilio/io/mobility_io.h"
#include "memilio/compartments/parameter_studies.h"
#include "secir/parameter_space.h"
#include "secir/secir_parameters_io.h"
#include <data_dir.h>
#include <iostream>

Expand Down
8 changes: 8 additions & 0 deletions cpp/memilio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ configure_file(config_internal.h.in memilio/config_internal.h)

add_library(memilio
config.h
data/analyze_result.h
data/analyze_result.cpp
epidemiology/age_group.h
epidemiology/populations.h
epidemiology/damping.cpp
epidemiology/damping.h
Expand All @@ -18,13 +21,18 @@ add_library(memilio
epidemiology/holiday_data_de.ipp
compartments/compartmentalmodel.h
compartments/simulation.h
compartments/parameter_studies.h
io/io.h
io/io.cpp
io/hdf5_cpp.h
io/json_serializer.h
io/json_serializer.cpp
io/mobility_io.h
io/mobility_io.cpp
io/result_io.h
io/result_io.cpp
io/epi_data.h
io/epi_data.cpp
math/euler.cpp
math/euler.h
math/smoother.h
Expand Down
3 changes: 2 additions & 1 deletion cpp/memilio/compartments/compartmentalmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ using has_apply_constraints_member_function = is_expression_valid<details::apply
* studies
*
*/
dabele marked this conversation as resolved.
Show resolved Hide resolved
template <class Pop, class Params>
template <class Comp, class Pop, class Params>
struct CompartmentalModel {
public:
using Compartments = Comp;
using Populations = Pop;
using ParameterSet = Params;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
#ifndef PARAMETER_STUDIES_H
#define PARAMETER_STUDIES_H

#include "secir/secir.h"
#include "secir/parameter_space.h"
#include "memilio/utils/time_series.h"
#include "memilio/mobility/mobility.h"
#include "memilio/compartments/simulation.h"
Expand Down Expand Up @@ -89,33 +87,18 @@ class ParameterStudy
m_graph.add_node(0, model);
}

/**
* @brief create study for single compartment model with normal distributions.
* Sets all parameters to normal distribution with specified relative deviation.
* @param params SecirParams object
* @param t0 start time of simulations
* @param tmax end time of simulations
* @param dev_rel relative deviation of parameters distributions
* @param num_runs number of runs in ensemble run
*/
ParameterStudy(typename Simulation::Model const& model, double t0, double tmax, double dev_rel, size_t num_runs)
: ParameterStudy(model, t0, tmax, num_runs)
{
set_params_distributions_normal(m_graph.nodes()[0].property, t0, tmax, dev_rel);
}

/*
* @brief Carry out all simulations in the parameter study.
* Save memory and enable more runs by immediately processing and/or discarding the result.
* @param result_processing_function Processing function for simulation results, e.g., output function.
* Receives the result after each run is completed.
*/
template<class HandleSimulationResultFunction>
void run(HandleSimulationResultFunction result_processing_function)
template <class SampleGraphFunction, class HandleSimulationResultFunction>
void run(SampleGraphFunction sample_graph, HandleSimulationResultFunction result_processing_function)
{
// Iterate over all parameters in the parameter space
for (size_t i = 0; i < m_num_runs; i++) {
auto sim = create_sampled_simulation();
auto sim = create_sampled_simulation(sample_graph);
sim.advance(m_tmax);

result_processing_function(std::move(sim).get_graph());
Expand All @@ -127,12 +110,13 @@ class ParameterStudy
* Convinience function for a few number of runs, but uses a lot of memory.
dabele marked this conversation as resolved.
Show resolved Hide resolved
* @return vector of results of each run.
*/
std::vector<mio::Graph<mio::SimulationNode<Simulation>, mio::MigrationEdge>> run()
template <class SampleGraphFunction>
std::vector<mio::Graph<mio::SimulationNode<Simulation>, mio::MigrationEdge>> run(SampleGraphFunction sample_graph)
{
std::vector<mio::Graph<mio::SimulationNode<Simulation>, mio::MigrationEdge>> ensemble_result;
ensemble_result.reserve(m_num_runs);

run([&ensemble_result](auto&& r) {
run(sample_graph, [&ensemble_result](auto&& r) {
ensemble_result.emplace_back(std::move(r));
});

Expand Down Expand Up @@ -219,47 +203,18 @@ class ParameterStudy

private:
//sample parameters and create simulation
mio::GraphSimulation<mio::Graph<mio::SimulationNode<Simulation>, mio::MigrationEdge>> create_sampled_simulation()
template <class SampleGraphFunction>
mio::GraphSimulation<mio::Graph<mio::SimulationNode<Simulation>, mio::MigrationEdge>>
create_sampled_simulation(SampleGraphFunction sample_graph)
{
mio::Graph<mio::SimulationNode<Simulation>, mio::MigrationEdge> sim_graph;

//sample global parameters
auto& shared_params_model = m_graph.nodes()[0].property;
draw_sample_infection(shared_params_model);
auto& shared_contacts = shared_params_model.parameters.template get<mio::ContactPatterns>();
shared_contacts.draw_sample_dampings();
auto& shared_dynamic_npis = shared_params_model.parameters.template get<DynamicNPIsInfected>();
shared_dynamic_npis.draw_sample();

for (auto& params_node : m_graph.nodes()) {
auto& node_model = params_node.property;

//sample local parameters
draw_sample_demographics(params_node.property);

//copy global parameters
//save demographic parameters so they aren't overwritten
auto local_icu_capacity = node_model.parameters.template get<ICUCapacity>();
auto local_tnt_capacity = node_model.parameters.template get<TestAndTraceCapacity>();
auto local_holidays = node_model.parameters.template get<ContactPatterns>().get_school_holidays();
node_model.parameters = shared_params_model.parameters;
node_model.parameters.template get<ICUCapacity>() = local_icu_capacity;
node_model.parameters.template get<TestAndTraceCapacity>() = local_tnt_capacity;
node_model.parameters.template get<ContactPatterns>().get_school_holidays() = local_holidays;

node_model.parameters.template get<ContactPatterns>().make_matrix();
node_model.apply_constraints();

sim_graph.add_node(params_node.id, node_model, m_t0, m_dt_integration);
auto sampled_graph = sample_graph(m_graph);
for (auto&& node : sampled_graph.nodes()) {
sim_graph.add_node(node.id, node.property, m_t0, m_dt_integration);
}

for (auto& edge : m_graph.edges()) {
auto edge_params = edge.property;
apply_dampings(edge_params.get_coefficients(), shared_contacts.get_dampings(), [&edge_params](auto& v) {
return make_migration_damping_vector(edge_params.get_coefficients().get_shape(), v);
});
edge_params.set_dynamic_npis_infected(shared_dynamic_npis);
sim_graph.add_edge(edge.start_node_idx, edge.end_node_idx, edge_params);
for (auto&& edge : sampled_graph.edges()) {
sim_graph.add_edge(edge.start_node_idx, edge.end_node_idx, edge.property);
}

return make_migration_sim(m_t0, m_dt_graph_sim, std::move(sim_graph));
Expand Down
165 changes: 165 additions & 0 deletions cpp/memilio/data/analyze_result.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Copyright (C) 2020-2021 German Aerospace Center (DLR-SC)
*
* Authors: Wadim Koslow, Daniel Abele
*
* Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
*
* 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/data/analyze_result.h"

#include <algorithm>
#include <cassert>

namespace mio
{

TimeSeries<double> interpolate_simulation_result(const TimeSeries<double>& simulation_result)
{
assert(simulation_result.get_num_time_points() > 0 && "TimeSeries must not be empty.");

const auto t0 = simulation_result.get_time(0);
const auto tmax = simulation_result.get_last_time();
const auto day0 = static_cast<int>(floor(t0));
const auto day_max = static_cast<int>(ceil(tmax));

auto day = day0;
TimeSeries<double> interpolated(simulation_result.get_num_elements());
interpolated.reserve(day_max - day0 + 1);
interpolated.add_time_point(day, simulation_result.get_value(0));
day++;

//interpolate between pair of time points that lie on either side of each integer day
//TODO: extrapolate first and last point
for (int i = 0; i < simulation_result.get_num_time_points() - 1;) {
//only go to next pair of time points if no time point is added.
//otherwise check the same time points again
//in case there is more than one day between the two time points
if (simulation_result.get_time(i) < day && simulation_result.get_time(i + 1) >= day) {
auto weight = (day - simulation_result.get_time(i)) /
(simulation_result.get_time(i + 1) - simulation_result.get_time(i));
interpolated.add_time_point(day, simulation_result[i] +
(simulation_result[i + 1] - simulation_result[i]) * weight);
++day;
}
else {
++i;
}
}

if (day_max > tmax) {
interpolated.add_time_point(day, simulation_result.get_last_value());
}

return interpolated;
}

std::vector<std::vector<TimeSeries<double>>>
sum_nodes(const std::vector<std::vector<TimeSeries<double>>>& ensemble_result)
{
auto num_runs = ensemble_result.size();
auto num_nodes = ensemble_result[0].size();
auto num_time_points = ensemble_result[0][0].get_num_time_points();
auto num_elements = ensemble_result[0][0].get_num_elements();

std::vector<std::vector<TimeSeries<double>>> sum_result(
num_runs, std::vector<TimeSeries<double>>(1, TimeSeries<double>::zero(num_time_points, num_elements)));

for (size_t run = 0; run < num_runs; run++) {
for (Eigen::Index time = 0; time < num_time_points; time++) {
sum_result[run][0].get_time(time) = ensemble_result[run][0].get_time(time);
for (size_t node = 0; node < num_nodes; node++) {
sum_result[run][0][time] += ensemble_result[run][node][time];
}
}
}
return sum_result;
}

std::vector<TimeSeries<double>> ensemble_mean(const std::vector<std::vector<TimeSeries<double>>>& ensemble_result)
{
auto num_runs = ensemble_result.size();
auto num_nodes = ensemble_result[0].size();
auto num_time_points = ensemble_result[0][0].get_num_time_points();
auto num_elements = ensemble_result[0][0].get_num_elements();

std::vector<TimeSeries<double>> mean(num_nodes, TimeSeries<double>::zero(num_time_points, num_elements));

for (size_t run = 0; run < num_runs; run++) {
assert(ensemble_result[run].size() == num_nodes && "ensemble results not uniform.");
for (size_t node = 0; node < num_nodes; node++) {
assert(ensemble_result[run][node].get_num_time_points() == num_time_points &&
"ensemble results not uniform.");
for (Eigen::Index time = 0; time < num_time_points; time++) {
assert(ensemble_result[run][node].get_num_elements() == num_elements &&
"ensemble results not uniform.");
mean[node].get_time(time) = ensemble_result[run][node].get_time(time);
mean[node][time] += ensemble_result[run][node][time] / num_runs;
}
}
}

return mean;
}

std::vector<TimeSeries<double>> ensemble_percentile(const std::vector<std::vector<TimeSeries<double>>>& ensemble_result,
double p)
{
assert(p > 0.0 && p < 1.0 && "Invalid percentile value.");

auto num_runs = ensemble_result.size();
auto num_nodes = ensemble_result[0].size();
auto num_time_points = ensemble_result[0][0].get_num_time_points();
auto num_elements = ensemble_result[0][0].get_num_elements();

std::vector<TimeSeries<double>> percentile(num_nodes, TimeSeries<double>::zero(num_time_points, num_elements));

std::vector<double> single_element_ensemble(num_runs); //reused for each element
for (size_t node = 0; node < num_nodes; node++) {
for (Eigen::Index time = 0; time < num_time_points; time++) {
percentile[node].get_time(time) = ensemble_result[0][node].get_time(time);
for (Eigen::Index elem = 0; elem < num_elements; elem++) {
std::transform(ensemble_result.begin(), ensemble_result.end(), single_element_ensemble.begin(),
[=](auto& run) {
return run[node][time][elem];
});
std::sort(single_element_ensemble.begin(), single_element_ensemble.end());
percentile[node][time][elem] = single_element_ensemble[static_cast<size_t>(num_runs * p)];
}
}
}
return percentile;
}

double result_distance_2norm(const std::vector<mio::TimeSeries<double>>& result1,
const std::vector<mio::TimeSeries<double>>& result2)
{
assert(result1.size() == result2.size());
assert(result1.size() > 0);
assert(result1[0].get_num_time_points() > 0);
assert(result1[0].get_num_elements() > 0);

auto norm_sqr = 0.0;
for (auto iter_node1 = result1.begin(), iter_node2 = result2.begin(); iter_node1 < result1.end();
++iter_node1, ++iter_node2) {
for (Eigen::Index time_idx = 0; time_idx < iter_node1->get_num_time_points(); ++time_idx) {
auto v1 = (*iter_node1)[time_idx];
auto v2 = (*iter_node2)[time_idx];
norm_sqr += ((v1 - v2).array() * (v1 - v2).array()).sum();
}
}
return std::sqrt(norm_sqr);
}

} // namespace mio
Loading