diff --git a/.editorconfig b/.editorconfig
index e7006ed3c..428584c7e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,6 +10,7 @@ charset = utf-8
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
+max_line_length = 150
[Makefile]
indent_style = tab
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 3c4f0f6cc..7614c7d4d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.github.matsim-org
matsim-episim
- 22.6
+ 22.12
MATSim Episim
Epidemic simulation for MATSim
diff --git a/src/main/R/Covid19ScenarioHubSubmission.R b/src/main/R/Covid19ScenarioHubSubmission.R
new file mode 100644
index 000000000..8505c634e
--- /dev/null
+++ b/src/main/R/Covid19ScenarioHubSubmission.R
@@ -0,0 +1,98 @@
+
+library(lubridate)
+library(tidyverse)
+library(readr)
+
+
+
+rm(list=ls())
+source("/Users/jakob/git/matsim-episim/src/main/R/masterJR-utils.R", encoding = 'utf-8')
+
+# Global variables
+directory <- "/Users/jakob/git/public-svn/matsim/scenarios/countries/de/episim/battery/jakob/2022-07-27/4-eu-noAgg/"
+
+origin_date <- ymd("2022-07-24") # first day (sunday) of epiweek 30, 2022
+end_date <- ymd("2023-07-29") # last day (saturday) of epiweek 30, 2023 (latest possible value)
+
+
+
+## read & prep infections
+infections_raw <- read_combine_episim_output_zipped(directory,"infections.txt.csv")
+
+infections_incidence <- convert_infections_into_incidence(directory,infections_raw,FALSE) %>%
+ select(-c(infections_week,nShowingSymptomsCumulative, district, incidence))
+
+
+population_cologne <- infections_raw[1, "nSusceptible"]
+
+population_germany <- 83695430 #https://www.destatis.de/EN/Themes/Society-Environment/Population/Current-Population/Tables/liste-current-population.html
+scale_factor <- population_germany / population_cologne # pop germany / pop koelln
+
+infections_ready <- infections_incidence %>%
+ filter(date >= origin_date & date <= end_date) %>%
+ # mutate(weekday = lubridate::wday(date, label = TRUE)) %>%
+ mutate(year = epiyear(date)) %>%
+ mutate(epiweek = epiweek(date)) %>%
+ group_by(seed,vacCamp,vacType,year,epiweek) %>%
+ summarise(value = sum(infections) * scale_factor, target_end_date = last(date) ) %>%
+ mutate(target_variable = "inc infection") %>%
+ select(year, epiweek, target_end_date, target_variable, value, seed, vacCamp, vacType)
+
+
+## read & prep hospitalizations
+hosp_raw <- read_combine_episim_output_zipped(directory,"post.hospital.tsv")
+
+hosp_ready <- hosp_raw %>%
+ filter(date >= origin_date & date <= end_date) %>%
+ mutate(year = year(date)) %>%
+ mutate(wkday = lubridate::wday(date, label = TRUE)) %>%
+ filter(wkday == "Sat") %>%
+ filter(measurement == "intakesHosp") %>%
+ filter(severity == "Omicron") %>%
+ mutate(epiweek = epiweek(date)) %>%
+ rename("target_end_date" = date, value = n) %>%
+ mutate(value = value * population_cologne / 100000 * scale_factor) %>%
+ mutate(target_variable = "inc hosp") %>%
+ select(year, epiweek, target_end_date, target_variable, value, seed, vacCamp, vacType)
+
+# combine two dataframes and modify columns to match specs
+combined <- rbind(infections_ready, hosp_ready)
+# combined <- infections_ready #todo revert
+
+
+
+
+seed <- unique(combined$seed)
+sample <- seq(length(seed))
+map <- data.frame(seed,sample)
+
+final <- combined %>% filter(vacCamp!="off") %>%
+ mutate(scenario_id = paste0(vacCamp,"_",vacType)) %>%
+ mutate(scenario_id = case_when(scenario_id == "60plus_omicronUpdate"~"A-2022-07-24",
+ scenario_id == "18plus_omicronUpdate"~"B-2022-07-24",
+ scenario_id == "60plus_mRNA"~"C-2022-07-24",
+ scenario_id == "18plus_mRNA"~"D-2022-07-24")) %>%
+ merge(map,by ="seed") %>%
+ mutate(horizon = case_when(year == 2022 ~ epiweek - 29, year == 2023~ (52-29) + epiweek)) %>%
+ mutate("origin_date" = "2022-07-24") %>%
+ mutate("location" = "DE") %>%
+ mutate(value = round(value)) %>%
+ select(origin_date,scenario_id, horizon, target_end_date, location, sample,target_variable, value) %>%
+ arrange(scenario_id,sample,horizon) %>%
+ mutate(horizon = paste0(horizon," wk"))
+
+write.csv(final,"/Users/jakob/git/covid19-scenario-hub-europe/data-processed/MODUS_Covid-Episim/2022-07-24-MODUS_Covid-Episim.csv", row.names = FALSE)
+
+
+
+# xxx <- read.delim("/Users/jakob/antibodies_2022-07-23.tsv",sep = "\t")
+#
+# yyy <- xxx %>% filter(nVaccinations == 0 & nInfections == 0)
+#
+# nrow(yyy)/nrow(xxx)
+
+
+
+
+
+
diff --git a/src/main/R/analyseCases.R b/src/main/R/analyseCases.R
new file mode 100644
index 000000000..e552fce58
--- /dev/null
+++ b/src/main/R/analyseCases.R
@@ -0,0 +1,89 @@
+library(lubridate)
+library(tidyverse)
+library(readr)
+
+
+
+rm(list=ls())
+source("/Users/jakob/git/matsim-episim/src/main/R/masterJR-utils.R", encoding = 'utf-8')
+
+# directory_snap_old <- "/Users/jakob/git/public-svn/matsim/scenarios/countries/de/episim/battery/jakob/2022-11-05/2-imm-snap/"
+directory_base <- "/Users/jakob/git/public-svn/matsim/scenarios/countries/de/episim/battery/jakob/2022-11-24/1-makeImmHist/"
+directory_imm <- "/Users/jakob/git/public-svn/matsim/scenarios/countries/de/episim/battery/jakob/2022-11-24/3-imm-20seeds/"
+# file_root<- "antibodies.tsv"
+
+#infections
+file_root_inf<- "infections.txt.csv"
+snap_inf_raw <- read_combine_episim_output_zipped(directory_base, file_root_inf )
+# snap_inf_raw_old <- read_combine_episim_output_zipped(directory_snap, file_root_inf )
+imm_inf_raw <- read_combine_episim_output_zipped(directory_imm, file_root_inf)
+
+unique(snap_inf_raw$seed)
+
+
+start_date <- ymd("2022-04-01")
+end_date <- ymd("2022-09-01")
+snap_inf <- snap_inf_raw %>%
+ filter(date >= start_date) %>%
+ filter(date <= end_date) %>%
+ filter(seed %in% unique(imm_inf_raw$seed))
+ # filter(pHh == 0.0, immuneSigma == 0.0)
+ # mutate(vax = generic + mRNA + vector + ba1Update + ba5Update + natural)
+
+
+imm_inf <- imm_inf_raw %>%
+ filter(date >= start_date) %>%
+ filter(date <= end_date) %>%
+ filter(StrainA == 2.0 & startFromImm =="sepSeeds")
+
+
+ # mutate(vax = generic + mRNA + vector + ba1Update + ba5Update + natural)
+ggplot() + #nShowingSymptoms # SARS_CoV_2
+ geom_line(imm_inf, mapping = aes(date, nShowingSymptoms , group = seed, col = "imm-hist")) +
+ geom_line(snap_inf, mapping = aes(date, nShowingSymptoms , group = seed, col = "snapshot")) +
+ scale_color_manual(name='Regression Model',
+ breaks=c('snapshot', 'imm-hist'),
+ values=c('snapshot'='red', 'imm-hist'='blue'))+
+ labs(alt = "hello world") +
+ ggtitle("Infections")
+
+
+
+# antibodies
+file_root_ab<- "antibodies.tsv"
+snap_ab_raw <- read_combine_episim_output_zipped(directory_base, file_root_ab )
+imm_ab_raw <- read_combine_episim_output_zipped(directory_imm, file_root_ab)
+
+
+start_date <- ymd("2021-11-15")
+end_date <- ymd("2029-11-30")
+snap_ab <- snap_ab_raw %>%
+ filter(date >= start_date) %>%
+ filter(date <= end_date) %>%
+ filter(pHh == 0.0, immuneSigma == 0.0)
+# mutate(vax = generic + mRNA + vector + ba1Update + ba5Update + natural)
+imm_ab <- imm_ab_raw %>%
+ filter(date >= start_date) %>%
+ filter(date <= end_date) %>%
+ filter(pHh == 0.0, immuneSigma == 0.0)
+# mutate(vax = generic + mRNA + vector + ba1Update + ba5Update + natural)
+ggplot() + #nShowingSymptoms # SARS_CoV_2
+ geom_line(imm_ab, mapping = aes(date, SARS_CoV_2 , group = seed, col = "imm-hist")) +
+ geom_line(snap_ab, mapping = aes(date, SARS_CoV_2 , group = seed, col = "snapshot")) +
+ scale_color_manual(name='Regression Model',
+ breaks=c('snapshot', 'imm-hist'),
+ values=c('snapshot'='red', 'imm-hist'='blue'))+
+ ggtitle("Antibodies")
+
+
+
+
+ # scale_colour_manual(name = "scenario", values = c("red"="red", "blue"="blue"), labels = c("snapshot", "immune history")) +
+ # facet_wrap(pHh ~ immuneSigma)
+
+# antibodies are a bit lower for immune history people
+# jump in snapshot on first day is a bit sus... (maybe there is something wrong there..., not with immune history))
+# what happens to Antibodies from June 30 to July 1?? Why do they jump?
+
+# infections: now imm-Hist (blue) run has lower case numbers... too many antibodies or whats going on?
+# but blue also has slightly lower antibodies. How can this be?
\ No newline at end of file
diff --git a/src/main/R/masterJR-utils.R b/src/main/R/masterJR-utils.R
new file mode 100644
index 000000000..7d633dd3e
--- /dev/null
+++ b/src/main/R/masterJR-utils.R
@@ -0,0 +1,621 @@
+# Title : TODO
+# Objective : TODO
+# Created by: jakob
+# Created on: 7/22/2021
+
+library(data.table)
+
+
+# Functions:
+# read_and_process_episim_infections <- function(directory, facilities_to_district_map) {
+# fac_to_district_map <- read_delim(facilities_to_district_map,
+# ";", escape_double = FALSE, col_names = FALSE,
+# trim_ws = TRUE) %>%
+# rename("facility" = "X1") %>%
+# rename("district" = "X2")
+#
+# fac_to_district_map[is.na(fac_to_district_map)] <- "not_berlin"
+#
+# info_df <- read_delim(paste0(directory, "_info.txt"), delim = ";")
+#
+# # gathers column names that should be included in final dataframe
+# col_names <- colnames(info_df)
+# relevant_cols <- col_names[!col_names %in% c("RunScript", "RunId", "Config", "Output")]
+#
+# episim_df_all_runs <- data.frame()
+#
+# for (row in seq_len(nrow(info_df))) {
+#
+# runId <- info_df$RunId[row]
+# seed <- info_df$seed[row]
+#
+# file_name <- paste0(directory, runId, ".infectionEvents.txt")
+#
+# if (!file.exists(file_name)) {
+# warning(paste0(file_name, " does not exist"))
+# next
+# }
+#
+# df_for_run <- read_delim(file = file_name,
+# "\t", escape_double = FALSE, trim_ws = TRUE) %>%
+# select(date, facility)
+#
+# # adds important variables concerning run to df, so that individual runs can be filtered in later steps
+# for (var in relevant_cols) {
+# df_for_run[var] <- info_df[row, var]
+# }
+#
+# episim_df_all_runs <- rbind(episim_df_all_runs, df_for_run)
+#
+# }
+#
+# episim_df2 <- episim_df_all_runs %>% filter(!grepl("^tr_", facility))
+#
+# merged <- episim_df2 %>%
+# left_join(fac_to_district_map, by = c("facility"), keep = TRUE)
+#
+# na_facs <- merged %>%
+# filter(is.na(district)) %>%
+# pull(facility.x)
+# length(unique(na_facs))
+#
+# episim_final <- merged %>%
+# filter(!is.na(district)) %>%
+# filter(district != "not_berlin") %>%
+# select(!starts_with("facility")) %>%
+# group_by_all() %>%
+# count() %>%
+# group_by(across(c(-n, -seed))) %>%
+# summarise(infections = mean(n))
+#
+# return(episim_final)
+# }
+
+convert_infections_into_incidence <- function(directory, infections_raw, aggregate_seeds) {
+ run_params <- get_run_parameters(directory)
+ infections <- infections_raw %>%
+ select(date, nShowingSymptomsCumulative, nSusceptible, district, run_params) %>%
+ filter(district != "unknown") %>%
+ arrange(date) %>%
+ group_by(district, across(run_params)) %>%
+ mutate(infections_1dayAgo = lag(nShowingSymptomsCumulative, default = 0, order_by = date)) %>%
+ mutate(infections_7daysAgo = lag(nShowingSymptomsCumulative, default = 0, n = 7, order_by = date)) %>%
+ mutate(infections = nShowingSymptomsCumulative - infections_1dayAgo) %>%
+ mutate(infections_week = nShowingSymptomsCumulative - infections_7daysAgo) %>%
+ mutate(population = first(nSusceptible)) %>%
+ mutate(incidence = infections_week / population * 100000) %>%
+ ungroup() %>%
+ select(-c(population, infections_1dayAgo, infections_7daysAgo, nSusceptible)) %>%
+ arrange(date)
+
+ if (aggregate_seeds == FALSE) {
+ return(infections)
+ }
+
+ infections_aggregated <- infections %>%
+ group_by(across(-c(nShowingSymptomsCumulative, infections, infections_week, incidence, seed))) %>%
+ summarise(infections = mean(infections),
+ nShowingSymptomsCumulative = mean(nShowingSymptomsCumulative),
+ infections_week = mean(infections_week),
+ incidence = mean(incidence))
+ return(infections_aggregated)
+
+}
+
+
+geolocate_infections <- function(infections_raw, facilities_to_district_map) {
+
+ # read facilities
+ fac_to_district_map <- read_delim(facilities_to_district_map,
+ ";", escape_double = FALSE, col_names = FALSE,
+ trim_ws = TRUE) %>%
+ rename("facility" = "X1") %>%
+ rename("district" = "X2")
+
+ fac_to_district_map[is.na(fac_to_district_map)] <- "not_berlin"
+
+ # filter, merge, & find count per district
+ merged <- infections_raw %>%
+ select(-c(time, infector, infected, infectionType, groupSize, virusStrain, probability)) %>%
+ filter(!grepl("^tr_", facility)) %>%
+ left_join(fac_to_district_map, by = c("facility"), keep = TRUE) %>%
+ filter(!is.na(district)) %>%
+ filter(district != "not_berlin") %>%
+ select(!starts_with("facility")) %>%
+ group_by_all() %>%
+ count() %>%
+ rename("infections" = "n")
+
+ return(merged)
+
+}
+
+
+# read_and_process_episim_timeUse <- function(directory) {
+#
+# info_df <- read_delim(paste0(directory, "_info.txt"), delim = ";")
+#
+# # gathers column names that should be included in final dataframe
+# col_names <- colnames(info_df)
+# relevant_cols <- col_names[!col_names %in% c("RunScript", "RunId", "Config", "Output")]
+#
+# episim_df_all_runs <- data.frame()
+# for (row in seq_len(nrow(info_df))) {
+#
+# runId <- info_df$RunId[row]
+#
+# file_name <- paste0(directory, runId, ".timeUse.txt")
+#
+# if (!file.exists(file_name)) {
+# warning(paste0(file_name, " does not exist"))
+# next
+# }
+#
+# df_for_run <- read_delim(file = file_name,
+# "\t", escape_double = FALSE, trim_ws = TRUE) %>%
+# pivot_longer(!c("day", "date"), names_to = "activity", values_to = "time")
+#
+# # adds important variables concerning run to df, so that individual runs can be filtered in later steps
+# for (var in relevant_cols) {
+# df_for_run[var] <- info_df[row, var]
+# }
+#
+# episim_df_all_runs <- rbind(episim_df_all_runs, df_for_run)
+#
+# }
+# }
+
+get_run_parameters <- function(directory) {
+ info_df <- read_delim(paste0(directory, "_info.txt"), delim = ";")
+ col_names <- colnames(info_df)
+ run_params <- col_names[!col_names %in% c("RunScript", "RunId", "Config", "Output")]
+ return(run_params)
+}
+
+read_combine_episim_output <- function(directory, file_root, allow_missing_files) {
+
+ info_df <- read_delim(paste0(directory, "_info.txt"), delim = ";")
+
+ # gathers column names that should be included in final dataframe
+ col_names <- colnames(info_df)
+ relevant_cols <- col_names[!col_names %in% c("RunScript", "RunId", "Config", "Output")]
+
+ episim_df_all_runs <- data.frame()
+ for (row in seq_len(nrow(info_df))) {
+
+ runId <- info_df$RunId[row]
+
+ file_name <- paste0(directory, runId, ".", file_root)
+
+ if (!file.exists(file_name) & allow_missing_files) {
+ warning(paste0(file_name, " does not exist"))
+ next
+ }
+
+
+ df_for_run <- read_delim(file = file_name, "\t", escape_double = FALSE, trim_ws = TRUE)
+
+ if (dim(df_for_run)[1] == 0) {
+ warning(paste0(file_name, " is empty"))
+ next
+ }
+
+ # adds important variables concerning run to df, so that individual runs can be filtered in later steps
+ for (var in relevant_cols) {
+ df_for_run[var] <- info_df[row, var]
+ }
+
+ episim_df_all_runs <- rbindlist(list(episim_df_all_runs, df_for_run))
+ # episim_df_all_runs <- rbind(episim_df_all_runs, df_for_run) # inefficient
+
+ }
+
+ return(data.frame(episim_df_all_runs))
+}
+
+read_combine_episim_output_zipped <- function(directory, file_root) {
+
+ info_df <- read_delim(paste0(directory, "_info.txt"), delim = ";")
+
+ # gathers column names that should be included in final dataframe
+ col_names <- colnames(info_df)
+ relevant_cols <- col_names[!col_names %in% c("RunScript", "RunId", "Config", "Output")]
+
+ episim_df_all_runs <- data.frame()
+
+ # runsToInclude <- c("calibration1824","calibration288","calibration1056", "calibration2208","calibration672","calibration1440")
+ for (row in seq_len(nrow(info_df))) {
+
+ runId <- info_df$RunId[row]
+
+ # if(runId %in% runsToInclude){
+ #
+ # } else{
+ # next
+ # }
+
+
+ zipDir <- paste0(directory,"summaries/",runId,".zip")
+
+ file_name <- paste0(runId, ".", file_root)
+
+ df_for_run <- read_delim(unz(zipDir, file_name))
+
+ if (dim(df_for_run)[1] == 0) {
+ warning(paste0(file_name, " is empty"))
+ next
+ }
+
+ # adds important variables concerning run to df, so that individual runs can be filtered in later steps
+ for (var in relevant_cols) {
+ df_for_run[var] <- info_df[row, var]
+ }
+
+ episim_df_all_runs <- rbindlist(list(episim_df_all_runs, df_for_run))
+
+ }
+
+ return(data.frame(episim_df_all_runs))
+}
+
+
+
+read_and_process_new_rki_data_incidenz <- function(filename) {
+ rki <- read_excel(filename,
+ sheet = "LK_7-Tage-Inzidenz (fixiert)", skip = 4)
+
+ rki_berlin <- rki %>%
+ filter(grepl("berlin", LK, ignore.case = TRUE)) %>%
+ select(-c("...1", "LKNR")) %>%
+ pivot_longer(!contains("LK"), names_to = "date", values_to = "cases")
+
+ for (i in seq_len(nrow(rki_berlin))) {
+ dateX <- as.character(rki_berlin$date[i])
+ if (grepl("44", dateX)) {
+ date_improved <- as.character(excel_numeric_to_date(as.numeric(dateX)))
+ rki_berlin$date[i] <- date_improved
+ } else {
+ date_improved <- dateX
+ rki_berlin$date[i] <- date_improved
+ }
+ }
+
+ ymd <- ymd(rki_berlin$date)
+ dmy <- dmy(rki_berlin$date)
+ ymd[is.na(ymd)] <- dmy[is.na(ymd)] # some dates are ambiguous, here we give
+ rki_berlin$date <- ymd
+
+
+ rki_berlin$LK <- rki_berlin$LK %>%
+ str_replace("SK Berlin ", "") %>%
+ str_replace("-", "_") %>%
+ str_replace("ö", "oe")
+
+
+ rki_berlin <- rki_berlin %>%
+ rename(district = LK, incidence = cases)
+
+ return(rki_berlin)
+}
+
+read_and_process_new_rki_data <- function(filename) {
+ rki <- read_excel(filename,
+ sheet = "LK_7-Tage-Fallzahlen (fixiert)", skip = 4)
+
+ rki_berlin <- rki %>%
+ filter(grepl("berlin", LK, ignore.case = TRUE)) %>%
+ select(-c("...1", "LKNR")) %>%
+ pivot_longer(!contains("LK"), names_to = "date", values_to = "cases")
+
+ for (i in seq_len(nrow(rki_berlin))) {
+ dateX <- as.character(rki_berlin$date[i])
+ if (grepl("44", dateX)) {
+ date_improved <- as.character(excel_numeric_to_date(as.numeric(dateX)))
+ rki_berlin$date[i] <- date_improved
+ } else {
+ date_improved <- dateX
+ rki_berlin$date[i] <- date_improved
+ }
+ }
+
+ ymd <- ymd(rki_berlin$date)
+ dmy <- dmy(rki_berlin$date)
+ ymd[is.na(ymd)] <- dmy[is.na(ymd)] # some dates are ambiguous, here we give
+ rki_berlin$date <- ymd
+
+
+ rki_berlin$LK <- rki_berlin$LK %>%
+ str_replace("SK Berlin ", "") %>%
+ str_replace("-", "_") %>%
+ str_replace("ö", "oe")
+
+ glimpse(rki_berlin)
+
+ rki_berlin <- rki_berlin %>%
+ mutate(cases = cases / 7) %>%
+ rename(district = LK, rki_new = cases)
+
+ return(rki_berlin)
+}
+
+read_and_process_old_rki_data <- function(filename) {
+ rki_old <- read_csv(filename)
+ rki_berlin_old <- rki_old %>%
+ filter(grepl("berlin", Landkreis, ignore.case = TRUE)) %>%
+ mutate(date = as.Date(Refdatum, format = "%m/%d/%Y"), district = Landkreis) %>% ## TODO: RefDatum or Meldedaturm
+ select(district, AnzahlFall, date) %>%
+ group_by(district, date) %>%
+ summarise(rki_cases_old = sum(AnzahlFall)) %>%
+ mutate(district = str_replace(district, "SK Berlin ", "")) %>%
+ mutate(district = str_replace(district, "-", "_")) %>%
+ mutate(district = str_replace(district, "ö", "oe")) %>%
+ rename(rki_old = rki_cases_old)
+ return(rki_berlin_old)
+}
+
+merge_tidy_average <- function(episim_all_runs, rki_new, rki_old) {
+ # BEFORE MERGING:
+ # each dataset should have "date", "district" + a seperate column per situation (with good name)
+ # delete all other columns!
+ merged_tidy <- episim_all_runs %>%
+ full_join(rki_new, by = c("date", "district")) %>%
+ full_join(rki_old, by = c("date", "district")) %>%
+ pivot_longer(!c("date", "district"), names_to = "scenario", values_to = "infections")
+
+ merged_weekly <- merged_tidy %>%
+ mutate(week = isoweek(date)) %>% # iso 8601 standard: week always begins with Monday; week 1 must contains January 4th
+ mutate(year = isoyear(date)) %>%
+ group_by(across(-c(infections, date))) %>%
+ summarise(infections = mean(infections, na.rm = TRUE), date = mean(date, na.rm = TRUE)) %>%
+ ungroup() %>%
+ select(!c(week, year))
+
+ return(merged_weekly)
+
+}
+
+### Plotting functions
+build_plot <- function(df, scale_colors) {
+ plot <- ggplot(df) +
+ geom_line(aes(date, incidence, col = Scenario)) +
+ theme_minimal(base_size = 11) +
+ theme(legend.position = "bottom", axis.text.x = element_text(angle = 45, hjust=1)) +
+ labs(x = "Date", y = "7-Day Infections / 100k Pop.") +
+ scale_x_date(date_breaks = "2 month", date_labels = "%b-%y") +
+ facet_wrap(~district, ncol = 3) +
+ scale_color_manual(values = scale_colors)
+
+ print(plot)
+
+ return(plot)
+}
+
+save_png_pdf <- function(.data, name) {
+ # print(.data)
+ ggsave(.data, filename = paste0(name, ".png"), path = gbl_image_output, width = 16, height = 12, units = "cm")
+ ggsave(.data, filename = paste0(name, ".pdf"), path = gbl_image_output, width = 16, height = 12, units = "cm")
+}
+
+
+### TIMELINE FUNCTIONS FOR ADAPTIVE RESTRICTIONS
+make_timeline <- function(ar_filtered, title) {
+ timeline_data <- data.frame()
+
+ locations <- unique(ar_filtered$location)
+
+ for (loc in locations) {
+
+ policy_filtered <- ar_filtered %>% filter(location == loc)
+
+ timeline_data_district <- data.frame()
+ policy <- policy_filtered$policy[1]
+ start <- policy_filtered$date[1]
+
+ for (row in seq(2, nrow(policy_filtered))) {
+
+ if (policy_filtered$policy[row] == policy) {
+ next
+ }
+
+ end <- policy_filtered$date[row]
+ single <- data.frame(location = loc, policy = policy, start = start, end = end)
+ timeline_data_district <- rbind(timeline_data_district, single)
+
+ start <- end
+ policy <- policy_filtered$policy[row]
+
+ }
+
+ end <- policy_filtered$date[row]
+
+ if (start != end) {
+ single <- data.frame(location = loc, policy = policy, start = start, end = end)
+ timeline_data_district <- rbind(timeline_data_district, single)
+ }
+
+ timeline_data <- rbind(timeline_data, timeline_data_district)
+ }
+
+
+ timeline_data_final <- timeline_data %>%
+ mutate(location = str_replace(location, "_", "-")) %>%
+ mutate(color = policy) %>%
+ mutate(color = str_replace(color, "initial", "gray")) %>%
+ mutate(color = str_replace(color, "restricted", "indianred1")) %>%
+ mutate(color = str_replace(color, "open", "royalblue1"))
+
+
+ # following was adapted from https://github.com/wlhamilton/Patient-ward-movement-timelines/blob/main/R%20script%20for%20formatting%20ward%20movement%20data.R
+
+ plot_data <- gg_vistime(data = timeline_data_final, col.group = "location", col.event = "policy", col.start = "start", col.end = "end", col.color = "color", show_labels = FALSE) + #theme_bw() +
+ ggplot2::theme(
+ plot.title = element_text(size = 14),
+ axis.text.x = element_text(size = 12, color = "black", angle = 30, vjust = 1, hjust = 1),
+ axis.text.y = element_text(size = 12, color = "black")) +
+ scale_x_datetime(breaks = breaks_width("1 month"), labels = date_format("%b %y")) +
+ labs(title = title)
+
+ return(plot_data)
+
+}
+
+### SETUP TIMELINE DATA
+make_timeline_data <- function(ar_filtered) {
+ timeline_data <- data.frame()
+
+ locations <- unique(ar_filtered$location)
+
+ for (loc in locations) {
+
+ policy_filtered <- ar_filtered %>% filter(location == loc)
+
+ timeline_data_district <- data.frame()
+ policy <- policy_filtered$policy[1]
+ start <- policy_filtered$date[1]
+
+ for (row in seq(2, nrow(policy_filtered))) {
+
+ if (policy_filtered$policy[row] == policy) {
+ next
+ }
+
+ end <- policy_filtered$date[row]
+ single <- data.frame(location = loc, policy = policy, start = start, end = end)
+ timeline_data_district <- rbind(timeline_data_district, single)
+
+ start <- end
+ policy <- policy_filtered$policy[row]
+
+ }
+
+ end <- policy_filtered$date[row]
+
+ if (start != end) {
+ single <- data.frame(location = loc, policy = policy, start = start, end = end)
+ timeline_data_district <- rbind(timeline_data_district, single)
+ }
+
+ timeline_data <- rbind(timeline_data, timeline_data_district)
+ }
+
+
+ timeline_data_final <- timeline_data %>%
+ mutate(location = str_replace(location, "_", "-")) %>%
+ mutate(color = policy) %>%
+ mutate(color = str_replace(color, "initial", "gray")) %>%
+ mutate(color = str_replace(color, "restricted", "indianred1")) %>%
+ mutate(color = str_replace(color, "open", "royalblue1"))
+
+ return(timeline_data_final)
+}
+
+make_legend <- function() {
+ data_legend <- data.frame(policy = c("Restriction Policy:", "Initial", "Restricted", "Open"), color = c(rgb(0, 0, 0, 0), "gray", "indianred1", "royalblue1"))
+ data_legend$start <- c(as.Date("2020-01-01"), as.Date("2020-01-07"), as.Date("2020-01-13"), as.Date("2020-01-19"))
+ data_legend$end <- c(as.Date("2020-01-06"), as.Date("2020-01-12"), as.Date("2020-01-18"), as.Date("2020-01-24"))
+ data_legend
+ plot_legend <- gg_vistime(data = data_legend,
+ col.event = "policy",
+ col.color = "color",
+ show_labels = TRUE,
+ linewidth = 20,
+ title = "Legend")
+ plot_legend
+
+ # Tweak the legend plot
+ plot_legend <- plot_legend +
+ theme_void() +
+ ggplot2::theme(
+ # plot.title = element_text(size = 11),
+ plot.title = element_blank(),
+ # plot.title.position = "plot",
+ axis.title.x = element_blank(),
+ axis.text.x = element_blank(),
+ axis.ticks.x = element_blank(),
+ axis.title.y = element_blank(),
+ axis.text.y = element_blank(),
+ axis.ticks.y = element_blank())
+
+ return(plot_legend)
+}
+
+make_text <- function(ar) {
+
+
+ lockdown_weeks <- ar %>%
+ group_by(location,policy) %>%
+ count() %>%
+ pivot_wider(names_from = policy, values_from = n, values_fill = 0) %>%
+ mutate(weeks_restricted = paste0(round(restricted / 7, 1), " wks")) %>%
+ arrange(location)
+
+
+ # data = timeline_data_final, col.group = "location",
+ lockdown_weeks$color <- rgb(0, 0, 0, 0)
+ lockdown_weeks$start <- c(as.Date("2020-01-1"))
+ lockdown_weeks$end <- c(as.Date("2020-01-2"))
+ lockdown_weeks
+ plot_text <- gg_vistime(data = lockdown_weeks,
+ col.group = "location",
+ col.event = "weeks_restricted",
+ col.color = "color",
+ show_labels = TRUE,
+ linewidth = 20,
+ title = "Lockdown")
+
+ # Tweak the legend plot
+ plot_text <- plot_text +
+ ggplot2::theme(
+ plot.title = element_text(size = 14),
+ axis.ticks.length = unit(0, "in"),
+ axis.text.x = element_text(size = 12, color = rgb(0, 0, 0, 0), angle = 30, vjust = 1, hjust = 1),
+ axis.text.y = element_blank(),
+ axis.ticks = element_blank(),
+ axis.title.y = element_blank(),
+ axis.line.y = element_blank(),
+ ) +
+ scale_x_datetime(breaks = breaks_width("1 month"), labels = date_format("%b %y"))
+
+ return(plot_text)
+
+
+ make_gt_table <- function(.data) {
+ gt(.data, rowname_col = "Rf") %>%
+ tab_stubhead(label = "Rf") %>%
+ tab_spanner(
+ label = "Trigger",
+ columns = trigs
+ ) %>%
+ fmt_number(
+ columns = trigs,
+ decimals = 1,
+ use_seps = FALSE
+ )
+ }
+
+ localMaxima <- function(x) {
+ # Use -Inf instead if x is numeric (non-integer)
+ y <- diff(c(-.Machine$integer.max, x)) > 0L
+ rle(y)$lengths
+ y <- cumsum(rle(y)$lengths)
+ y <- y[seq.int(1L, length(y), 2L)]
+ if (x[[1]] == x[[2]]) {
+ y <- y[-1]
+ }
+ y
+ }
+
+
+ localMinima <- function(x) {
+ # Use -Inf instead if x is numeric (non-integer)
+ y <- diff(c(.Machine$integer.max, x)) < 0L
+ rle(y)$lengths
+ y <- cumsum(rle(y)$lengths)
+ y <- y[seq.int(1L, length(y), 2L)]
+ if (x[[1]] == x[[2]]) {
+ y <- y[-1]
+ }
+ y
+ }
+}
+
diff --git a/src/main/R/mobilityAndWeather.R b/src/main/R/mobilityAndWeather.R
new file mode 100644
index 000000000..7cc6fd72b
--- /dev/null
+++ b/src/main/R/mobilityAndWeather.R
@@ -0,0 +1,68 @@
+library(tidyverse)
+library(lubridate)
+library (RCurl)
+library(gridExtra)
+
+
+# Weather Data
+weatherData <- read_delim("https://bulk.meteostat.net/daily/10382.csv.gz", delim = ",", col_names = FALSE, col_types = cols(
+ X1 = col_date(format = ""),
+ X2 = col_double(),
+ X3 = col_double(),
+ X4 = col_double(),
+ X5 = col_double(),
+ X6 = col_double(),
+ X7 = col_double(),
+ X8 = col_double(),
+ X9 = col_double(),
+ X10 = col_double(),
+ X11 = col_double()
+))
+colnames(weatherData) <- c("date", "tavg", "tmin", "tmax", "prcp", "snow", "wdir", "wspd", "wpgt", "pres", "tsun")
+
+weatherDataByWeek <- weatherData %>%
+ mutate( week = paste0(isoweek(date), "-", isoyear(date))) %>%
+ group_by( week ) %>%
+ summarize( date=mean(date), tavg=mean(tavg), tmin=mean(tmin), tmax=mean(tmax), prcp=mean(prcp), snow=mean(snow), wdir=mean(wdir), wspd=mean(wspd), wpgt=mean(wpgt), pres=mean(pres), tsun=mean(tsun))
+
+
+# Google Mobility Report
+googleMobilityReportRaw <- read_csv(getURL("https://www.gstatic.com/covid19/mobility/Global_Mobility_Report.csv"))
+
+googleMobilityReport <- googleMobilityReportRaw %>%
+ filter(sub_region_1 == "Berlin") %>%
+ select(-c(country_region_code, country_region, sub_region_1, sub_region_2, metro_area, iso_3166_2_code, census_fips_code, place_id)) %>%
+ mutate(notAtHome = -residential_percent_change_from_baseline) %>%
+ pivot_longer(!date, names_to = "type", values_to = "restriction") %>%
+ filter(type == "notAtHome") %>%
+ mutate(weekday = wday(date, week_start = 1)) %>%
+ filter(weekday < "6") %>%
+ mutate( week = paste0(isoweek(date), "-", isoyear(date))) %>%
+ group_by( week, type ) %>%
+ summarize( restriction=mean(restriction), date=mean(date))
+
+# Senozon Restrictions
+snzRestrictionsFile <- "BerlinSnzData_daily_until20220204.csv"
+svnLocation <- "/Users/sebastianmuller/git/shared-svn/projects/episim/matsim-files/snz/BerlinV2/episim-input/"
+
+snzRestrictions <- read_delim(paste0(svnLocation, snzRestrictionsFile), delim = "\t") %>%
+ pivot_longer(!date, names_to = "type", values_to = "restriction") %>%
+ mutate(newDate = as.Date(strptime(date, "%Y%m%d"))) %>%
+ mutate(weekday = wday(newDate, week_start = 1)) %>%
+ filter(weekday < "6") %>%
+ filter(type == "notAtHome") %>%
+ mutate( week = paste0(isoweek(newDate), "-", isoyear(newDate))) %>%
+ group_by( week, type ) %>%
+ summarize( restriction=mean(restriction), newDate=mean(newDate))
+
+# Google Mobility and weather
+ggplot() +
+ geom_point(data = googleMobilityReport, mapping=aes(x = date, y = restriction), colour = "red") +
+ geom_point(data = snzRestrictions, mapping=aes(x = newDate, y = restriction), colour = "blue") +
+ geom_point(data = weatherDataByWeek, mapping=aes(x = date, y = tmax), colour = "black") +
+ theme(legend.position = "bottom") +
+ xlim(c(as.Date("2020-02-24"), as.Date("2022-07-30"))) +
+ labs(
+ title="Time spent not at home (google and senozon) and max temperature (Berlin)",
+ caption="Source: Google, Senozon",
+ x="date", y="Reduction in % / tmax")
diff --git a/src/main/java/org/matsim/episim/EpisimConfigGroup.java b/src/main/java/org/matsim/episim/EpisimConfigGroup.java
index ebe364d1a..d0e5be474 100644
--- a/src/main/java/org/matsim/episim/EpisimConfigGroup.java
+++ b/src/main/java/org/matsim/episim/EpisimConfigGroup.java
@@ -66,12 +66,11 @@ public final class EpisimConfigGroup extends ReflectiveConfigGroup {
private static final String START_DATE = "startDate";
private static final String SNAPSHOT_INTERVAL = "snapshotInterval";
private static final String START_FROM_SNAPSHOT = "startFromSnapshot";
+ private static final String START_FROM_IMMUNIZATION = "startFromImmunization";
private static final String SNAPSHOT_PREFIX = "snapshotPrefix";
private static final String SNAPSHOT_SEED = "snapshotSeed";
private static final String LEISUREOUTDOORFRACTION = "leisureOutdoorFraction";
private static final String INPUT_DAYS = "inputDays";
- private static final String AGE_SUSCEPTIBILITY = "ageSusceptibility";
- private static final String AGE_INFECTIVITY = "ageInfectivity";
private static final String DAYS_INFECTIOUS = "daysInfectious";
private static final String ACTIVITY_HANDLING = "activityHandling";
private static final String THREADS = "threads";
@@ -143,6 +142,7 @@ public final class EpisimConfigGroup extends ReflectiveConfigGroup {
* Path to snapshot file.
*/
private String startFromSnapshot = null;
+ private String startFromImmunization = null;
/**
* Filename prefix for snapshot.
@@ -167,23 +167,7 @@ public final class EpisimConfigGroup extends ReflectiveConfigGroup {
private SingleEventFile singleEventFile = SingleEventFile.yes;
private boolean endEarly = false;
private int threads = 2;
- /**
- * Child susceptibility used in AgeDependentInfectionModelWithSeasonality.
- * Taken from https://doi.org/10.1101/2020.06.03.20121145
- */
- private final NavigableMap ageSusceptibility = new TreeMap<>(Map.of(
- 19, 0.45,
- 20, 1d
- ));
- /**
- * Child infectivity used in AgeDependentInfectionModelWithSeasonality.
- * Taken from https://doi.org/10.1101/2020.06.03.20121145
- */
- private final NavigableMap ageInfectivity = new TreeMap<>(Map.of(
- 19, 0.85,
- 20, 1d
- ));
/**
* Compliance if a curfew is set.
@@ -389,6 +373,16 @@ public void setStartFromSnapshot(String startFromSnapshot) {
this.startFromSnapshot = startFromSnapshot;
}
+ @StringGetter(START_FROM_IMMUNIZATION)
+ public String getStartFromImmunization() {
+ return startFromImmunization;
+ }
+
+ @StringSetter(START_FROM_IMMUNIZATION)
+ public void setStartFromImmunization(String startFromImmunization) {
+ this.startFromImmunization = startFromImmunization;
+ }
+
@StringGetter(SNAPSHOT_PREFIX)
public String getSnapshotPrefix() {
return snapshotPrefix;
@@ -543,62 +537,6 @@ public void setDaysInfectious(int daysInfectious) {
this.daysInfectious = daysInfectious;
}
- @StringGetter(AGE_SUSCEPTIBILITY)
- String getAgeSusceptibilityString() {
- return JOINER.join(ageSusceptibility);
- }
-
- @StringSetter(AGE_SUSCEPTIBILITY)
- void setAgeSusceptibility(String config) {
- Map map = SPLITTER.split(config);
- setAgeSusceptibility(map.entrySet().stream().collect(Collectors.toMap(
- e -> Integer.parseInt(e.getKey()), e -> Double.parseDouble(e.getValue())
- )));
- }
-
- /**
- * Return susceptibility for different age groups.
- */
- public NavigableMap getAgeSusceptibility() {
- return ageSusceptibility;
- }
-
- /**
- * Set susceptibility for all age groups, previous entries will be overwritten.
- */
- public void setAgeSusceptibility(Map ageSusceptibility) {
- this.ageSusceptibility.clear();
- this.ageSusceptibility.putAll(ageSusceptibility);
- }
-
- @StringGetter(AGE_INFECTIVITY)
- String getAgeInfectivityString() {
- return JOINER.join(ageInfectivity);
- }
-
- @StringSetter(AGE_INFECTIVITY)
- void setAgeInfectivity(String config) {
- Map map = SPLITTER.split(config);
- setAgeInfectivity(map.entrySet().stream().collect(Collectors.toMap(
- e -> Integer.parseInt(e.getKey()), e -> Double.parseDouble(e.getValue())
- )));
- }
-
- /**
- * Return infectivity for different age groups.
- */
- public NavigableMap getAgeInfectivity() {
- return ageInfectivity;
- }
-
- /**
- * Set infectivity for all age groups, previous entries will be overwritten.
- */
- public void setAgeInfectivity(Map ageSusceptibility) {
- this.ageInfectivity.clear();
- this.ageInfectivity.putAll(ageSusceptibility);
- }
-
/**
* Sets the leisure outdoor fraction for the whole simulation period.
*/
diff --git a/src/main/java/org/matsim/episim/EpisimPerson.java b/src/main/java/org/matsim/episim/EpisimPerson.java
index 92e5453a6..197c1ebf4 100644
--- a/src/main/java/org/matsim/episim/EpisimPerson.java
+++ b/src/main/java/org/matsim/episim/EpisimPerson.java
@@ -49,8 +49,7 @@
import java.util.function.BiFunction;
import java.util.stream.Collectors;
-import static org.matsim.episim.EpisimUtils.readChars;
-import static org.matsim.episim.EpisimUtils.writeChars;
+import static org.matsim.episim.EpisimUtils.*;
/**
* Persons current state in the simulation.
@@ -156,7 +155,7 @@ public final class EpisimPerson implements Immunizable, Attributable {
/**
* Iteration when this person got into quarantine. Negative if person was never quarantined.
*/
- private int quarantineDate = -1;
+ private int quarantineDate = Integer.MIN_VALUE;
/**
* Iteration when this person was tested. Negative if person was never tested.
@@ -208,10 +207,15 @@ public final class EpisimPerson implements Immunizable, Attributable {
*/
private final Object2DoubleMap antibodies = new Object2DoubleOpenHashMap<>();
+ /**
+ * Maximal antibody level reached by agent w/ respect to each strain
+ */
+ private final Object2DoubleMap maxAntibodies = new Object2DoubleOpenHashMap<>();
+
/**
* Antibody level at last infection.
*/
- private double antibodyLevelAtInfection = 0;
+ private double antibodyLevelAtInfection = 0.;
/**
* Immune response multiplier, which is used to scale the antibody increase due to an immunity event
@@ -304,6 +308,12 @@ void read(ObjectInput in, Map, EpisimPerson> persons) throws IOExcept
antibodies.put(strain, in.readDouble());
}
+ n = in.readInt();
+ for (int i = 0; i < n; i++) {
+ VirusStrain strain = VirusStrain.values()[in.readInt()];
+ maxAntibodies.put(strain, in.readDouble());
+ }
+
status = DiseaseStatus.values()[in.readInt()];
quarantineStatus = QuarantineStatus.values()[in.readInt()];
quarantineDate = in.readInt();
@@ -371,6 +381,12 @@ void write(ObjectOutput out) throws IOException {
out.writeDouble(kv.getDoubleValue());
}
+ out.writeInt(maxAntibodies.size());
+ for (Object2DoubleMap.Entry kv : maxAntibodies.object2DoubleEntrySet()) {
+ out.writeInt(kv.getKey().ordinal());
+ out.writeDouble(kv.getDoubleValue());
+ }
+
out.writeInt(status.ordinal());
out.writeInt(quarantineStatus.ordinal());
out.writeInt(quarantineDate);
@@ -411,7 +427,7 @@ public void setDiseaseStatus(double now, DiseaseStatus status) {
*/
public void setInitialInfection(double now, VirusStrain strain) {
- reporting.reportInfection(new EpisimInitialInfectionEvent(now, getPersonId(), strain, antibodies.getDouble(strain)));
+ reporting.reportInfection(new EpisimInitialInfectionEvent(now, getPersonId(), strain, antibodies.getDouble(strain), maxAntibodies.getDouble(strain),getNumInfections()));
virusStrains.add(strain);
setDiseaseStatus(now, EpisimPerson.DiseaseStatus.infectedButNotContagious);
@@ -419,6 +435,7 @@ public void setInitialInfection(double now, VirusStrain strain) {
antibodyLevelAtInfection = antibodies.getDouble(strain);
+ // TODO: add max antibodies
}
/**
@@ -576,6 +593,32 @@ public double getAntibodyLevelAtInfection() {
return antibodyLevelAtInfection;
}
+ /**
+ * get map with max antibodies reached per strain (before current infection)
+ */
+ public Object2DoubleMap getMaxAntibodies() {
+ return maxAntibodies;
+ }
+
+ /**
+ * Get max antibodies reached for a particular strain (before current infection)
+ */
+ public double getMaxAntibodies(VirusStrain virusStrain) {
+ return maxAntibodies.getDouble(virusStrain);
+ }
+
+ /**
+ * Updates maximum antibodies agent has had versus a particular strain (only if maxAb is in fact higher
+ * than previous maximum)
+ */
+ public void updateMaxAntibodies(VirusStrain strain, double maxAb) {
+
+ if (!this.maxAntibodies.containsKey(strain) || maxAb > this.maxAntibodies.getDouble(strain)) {
+ this.maxAntibodies.put(strain, maxAb);
+ }
+
+ }
+
public double getAntibodies(VirusStrain strain) {
return antibodies.getDouble(strain);
}
@@ -585,7 +628,9 @@ public Object2DoubleMap getAntibodies() {
}
public double setAntibodies(VirusStrain strain, double value) {
+
return antibodies.put(strain, value);
+
}
/**
@@ -653,10 +698,15 @@ public boolean hadStrain(VirusStrain strain) {
*/
@Beta
public int daysSinceQuarantine(int currentDay) {
-
// yyyy since this API is so unstable, I would prefer to have the class non-public. kai, apr'20
// -> api now marked as unstable and containing an api note, because it is used by the models it has to be public. chr, apr'20
- if (quarantineDate < 0) throw new IllegalStateException("Person was never quarantined");
+
+ //check removed; when starting simulation with immunisation history, quarantine date can very well be negative. -jr, nov'22
+ if (quarantineDate == Integer.MIN_VALUE) {
+
+ throw new IllegalStateException("Person was never quarantined");
+
+ }
return currentDay - quarantineDate;
}
@@ -1046,6 +1096,7 @@ public PerformedActivity getNextActivity(DayOfWeek day, double time) {
return null;
}
+
/**
* Disease status of a person.
*/
diff --git a/src/main/java/org/matsim/episim/EpisimReporting.java b/src/main/java/org/matsim/episim/EpisimReporting.java
index 93c612905..633b25754 100644
--- a/src/main/java/org/matsim/episim/EpisimReporting.java
+++ b/src/main/java/org/matsim/episim/EpisimReporting.java
@@ -29,6 +29,8 @@
import it.unimi.dsi.fastutil.objects.ObjectIntPair;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.Id;
@@ -50,6 +52,7 @@
import java.nio.file.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
+import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -64,6 +67,23 @@
*/
public final class EpisimReporting implements BasicEventHandler, Closeable, Externalizable {
+
+ /**
+ * Age groups used for various outputs. AgeGroup -> minimum age of age group.
+ * Important: age groups must be in descending order
+ */
+ public enum AgeGroup {
+ age_60_plus(60),
+ age_18_59(18),
+ age_12_17(12),
+ age_0_11(0);
+
+ public final int lowerBoundAge;
+
+ AgeGroup(int lowerBoundAge) {
+ this.lowerBoundAge = lowerBoundAge;
+ }
+ }
private static final Logger log = LogManager.getLogger(EpisimReporting.class);
private static final AtomicInteger specificInfectionsCnt = new AtomicInteger(300);
@@ -100,7 +120,7 @@ public final class EpisimReporting implements BasicEventHandler, Closeable, Exte
public final Object2IntMap vaccinations = new Object2IntOpenHashMap<>();
/**
- * Map of (VaccinationType, nth Vaccination) -> Number per day
+ * Map of (VaccinationType, nth Vaccination) -> Number per day
*/
public final Object2IntMap> vaccinationStats = new Object2IntOpenHashMap<>();
@@ -110,6 +130,8 @@ public final class EpisimReporting implements BasicEventHandler, Closeable, Exte
private final NumberFormat decimalFormat = DecimalFormat.getInstance(Locale.GERMAN);
private final double sampleSize;
+ private int totalContacts;
+
/**
* Whether all events are written into one file.
*/
@@ -126,7 +148,6 @@ public final class EpisimReporting implements BasicEventHandler, Closeable, Exte
private final ByteArrayOutputStream os;
-
private final Config config;
private final EpisimConfigGroup episimConfig;
private final VaccinationConfigGroup vaccinationConfig;
@@ -147,6 +168,8 @@ public final class EpisimReporting implements BasicEventHandler, Closeable, Exte
private BufferedWriter vaccinationsPerType;
private BufferedWriter vaccinationsPerTypeAndNumber;
+ private final Map externalWriters = new HashMap<>();
+
private String memorizedDate = null;
/**
@@ -205,7 +228,7 @@ public final class EpisimReporting implements BasicEventHandler, Closeable, Exte
outdoorFraction = EpisimWriter.prepare(base + "outdoorFraction.tsv", "day", "date", "outdoorFraction");
virusStrains = EpisimWriter.prepare(base + "strains.tsv", "day", "date", (Object[]) VirusStrain.values());
cpuTime = EpisimWriter.prepare(base + "cputime.tsv", "iteration", "where", "what", "when", "thread");
- antibodiesPerPerson = EpisimWriter.prepare(base + "antibodies.tsv", "day", "date", (Object[]) VirusStrain.values());
+ antibodiesPerPerson = EpisimWriter.prepare(base + "antibodies.tsv", "day", "date", (Object[]) VirusStrain.values());
vaccinationsPerType = EpisimWriter.prepare(base + "vaccinations.tsv", "day", "date", (Object[]) VaccinationType.values());
vaccinationsPerTypeAndNumber = EpisimWriter.prepare(base + "vaccinationsDetailed.tsv", "day", "date", "type", "number", "amount");
@@ -263,7 +286,7 @@ void append(String date) throws IOException {
// Copy non prefixed files to base output
if (!base.equals(outDir))
for (String file : List.of("infections.txt", "infectionEvents.txt", "restrictions.txt", "timeUse.txt", "diseaseImport.tsv",
- "outdoorFraction.tsv", "strains.tsv", "antibodies.tsv", "vaccinations.tsv", "vaccinationsDetailed.tsv", "events.tar")) {
+ "outdoorFraction.tsv", "strains.tsv", "antibodies.tsv", "vaccinations.tsv", "vaccinationsDetailed.tsv", "events.tar")) {
Path path = Path.of(outDir, file);
if (Files.exists(path)) {
Files.move(path, Path.of(base + file), StandardCopyOption.REPLACE_EXISTING);
@@ -292,6 +315,35 @@ void append(String date) throws IOException {
writeConfigFiles();
}
+ /**
+ * Create and registered a new writer. Note that this writer should not be used directly, instead use {@link #writeAsync(BufferedWriter, String)}
+ */
+ public BufferedWriter registerWriter(String filename) {
+
+ if (externalWriters.containsKey(filename))
+ throw new IllegalStateException("Writer already registered: " + filename);
+
+ BufferedWriter writer = EpisimWriter.prepare(base + filename);
+ externalWriters.put(filename, writer);
+
+ return writer;
+ }
+
+ /**
+ * Appends some content asynchronously to a writer in thread-safe manner.
+ */
+ public void writeAsync(BufferedWriter writer, String content) {
+ this.writer.append(writer, content);
+ }
+
+ /**
+ * Close writer asynchronously.
+ */
+ public void closeAsync(BufferedWriter writer) {
+ externalWriters.values().removeIf(next -> next == writer);
+ this.writer.close(writer);
+ }
+
/**
* Checks whether a person is vaccinated (and has full effectiveness).
*/
@@ -670,6 +722,17 @@ public synchronized void reportContact(double now, EpisimPerson person, EpisimPe
}
+ /**
+ * Set number of total contacts.
+ * @param totalContacts
+ */
+ public void reportTotalContacts(int totalContacts) {
+ this.totalContacts = totalContacts;
+ }
+
+ public int getTotalContacts() {
+ return totalContacts;
+ }
/**
* Report the successful tracing between two persons.
@@ -754,7 +817,7 @@ void reportVaccination(Id personId, int iteration, VaccinationType type,
* Write container statistic to file.
*/
void reportContainerUsage(Object2IntMap> maxGroupSize, Object2IntMap> totalUsers,
- Map, Object2IntMap> activityUsage) {
+ Map, Object2IntMap> activityUsage) {
BufferedWriter out = EpisimWriter.prepare(base + "containerUsage.txt.gz", "id", "types", "totalUsers", "maxGroupSize");
@@ -798,12 +861,48 @@ void reportAntibodyLevel(Object2DoubleMap antibodies, int n, int it
out[1] = date;
for (int i = 0; i < VirusStrain.values().length; i++) {
- out[i+2] = String.valueOf(antibodies.getDouble(VirusStrain.values()[i]) / n);
+ out[i + 2] = String.valueOf(antibodies.getDouble(VirusStrain.values()[i]) / n);
}
writer.append(antibodiesPerPerson, out);
}
+ /**
+ * Write detailed person information. Huge files and for debugging only.
+ */
+ void reportDetailedPersonStats(LocalDate date, Collection persons) {
+
+ try (CSVPrinter csv = new CSVPrinter(Files.newBufferedWriter(Path.of(base + "antibodies_" + date + ".tsv")), CSVFormat.TDF)) {
+
+ csv.print("personId");
+ csv.print("age");
+ csv.print("nVaccinations");
+ csv.print("nInfections");
+ csv.print("immuneResponseMultiplier");
+
+ for (VirusStrain strain : VirusStrain.values()) {
+ csv.print(strain.toString());
+ }
+ csv.println();
+
+ for (EpisimPerson person : persons) {
+ csv.print(person.getPersonId().toString());
+ csv.print(person.getAge());
+ csv.print(person.getNumVaccinations());
+ csv.print(person.getNumInfections());
+ csv.print(person.getImmuneResponseMultiplier());
+
+ for (VirusStrain strain : VirusStrain.values()) {
+ csv.print(person.getAntibodies(strain));
+ }
+ csv.println();
+
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
/**
* Write outdoor fraction for each day.
*/
@@ -835,6 +934,10 @@ synchronized void reportCpuTime(int iteration, String where, String what, int ta
String.valueOf(taskId)});
}
+ void reportStart(LocalDate startDate, String startFromImmunization) {
+ manager.processEvent(new EpisimStartEvent(startDate, startFromImmunization));
+ }
+
@Override
public void close() {
@@ -850,6 +953,10 @@ public void close() {
writer.close(vaccinationsPerType);
writer.close(vaccinationsPerTypeAndNumber);
+ for (BufferedWriter v : externalWriters.values()) {
+ writer.close(v);
+ }
+
if (singleEvents) {
try {
zipOut.close();
@@ -867,11 +974,11 @@ public void close() {
public void handleEvent(Event event) {
// Events on 0th day are not needed
- if (iteration == 0) return;
+ if (iteration == 0 && !(event instanceof EpisimStartEvent)) return;
// Crucial episim events are always written, others only if enabled
- if (event instanceof EpisimPersonStatusEvent || event instanceof EpisimInfectionEvent || event instanceof EpisimVaccinationEvent || event instanceof EpisimPotentialInfectionEvent ||
- event instanceof EpisimInitialInfectionEvent
+ if (event instanceof EpisimPersonStatusEvent || event instanceof EpisimInfectionEvent || event instanceof EpisimVaccinationEvent || event instanceof EpisimPotentialInfectionEvent
+ || event instanceof EpisimInitialInfectionEvent || event instanceof EpisimStartEvent
|| (writeEvents == EpisimConfigGroup.WriteEvents.tracing && event instanceof EpisimTracingEvent)
|| (writeEvents == EpisimConfigGroup.WriteEvents.tracing && event instanceof EpisimContactEvent)) {
@@ -1001,7 +1108,7 @@ public void readExternal(ObjectInput in) throws IOException {
enum InfectionsWriterFields {
time, day, date, nSusceptible, nSusceptibleVaccinated, nInfectedButNotContagious, nInfectedButNotContagiousVaccinated, nContagious, nContagiousVaccinated, nShowingSymptoms, nShowingSymptomsVaccinated, nSeriouslySick, nSeriouslySickVaccinated, nCritical, nCriticalVaccinated, nTotalInfected,
nTotalInfectedVaccinated, nInfectedCumulative, nInfectedCumulativeVaccinated, nContagiousCumulative, nContagiousCumulativeVaccinated, nShowingSymptomsCumulative, nShowingSymptomsCumulativeVaccinated, nSeriouslySickCumulative, nSeriouslySickCumulativeVaccinated, nCriticalCumulative,
- nCriticalCumulativeVaccinated, nRecovered, nRecoveredVaccinated, nInQuarantineFull, nInQuarantineHome, nVaccinated, nReVaccinated, nTested, nDeceasedCumulative, nDeceasedCumulativeVaccinated, district
+ nCriticalCumulativeVaccinated, nRecovered, nRecoveredVaccinated, nInQuarantineFull, nInQuarantineHome, nVaccinated, nReVaccinated, nTested, nDeceasedCumulative, nDeceasedCumulativeVaccinated, district
}
enum InfectionEventsWriterFields {time, infector, infected, infectionType, date, groupSize, facility, virusStrain, probability}
diff --git a/src/main/java/org/matsim/episim/EpisimRunner.java b/src/main/java/org/matsim/episim/EpisimRunner.java
index 39aae36f1..e091c3744 100644
--- a/src/main/java/org/matsim/episim/EpisimRunner.java
+++ b/src/main/java/org/matsim/episim/EpisimRunner.java
@@ -24,6 +24,9 @@
import com.google.inject.Provider;
import org.apache.commons.compress.archivers.*;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.events.Event;
@@ -35,17 +38,13 @@
import org.matsim.episim.model.AntibodyModel;
import org.matsim.episim.model.ProgressionModel;
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.DayOfWeek;
import java.util.List;
import java.util.Map;
-import java.util.Random;
/**
* Main entry point and runner of one epidemic simulation.
@@ -67,7 +66,7 @@ public final class EpisimRunner {
@Inject
public EpisimRunner(Config config, EventsManager manager, Provider handlerProvider, Provider replay,
- Provider reportingProvider, Provider progressionProvider, Provider antibodyModelProvider) {
+ Provider reportingProvider, Provider progressionProvider, Provider antibodyModelProvider) {
this.config = config;
this.handlerProvider = handlerProvider;
this.manager = manager;
@@ -104,7 +103,9 @@ public void run(int maxIterations) {
Path output = Path.of(config.controler().getOutputDirectory());
int iteration = 1;
- if (episimConfig.getStartFromSnapshot() != null) {
+ if (episimConfig.getStartFromSnapshot() != null && episimConfig.getStartFromImmunization() != null) {
+ throw new RuntimeException("Cannot start from snapshot and immunization history simultaneously. Choose one.");
+ } else if (episimConfig.getStartFromSnapshot() != null) {
reporting.close();
iteration = readSnapshot(output, Path.of(episimConfig.getStartFromSnapshot()));
try {
@@ -115,15 +116,21 @@ public void run(int maxIterations) {
}
handler.onSnapshotLoaded(iteration);
- }
- // recalculate antibodies for every agent if starting from snapshot.
- // The antibodies profile is generated using the immunity event history in the
- // snapshot; the antibody model config of the snapshot simulation will
- // be superceded by the config of the current simulation. Thus, the antibody development
- // during the snapshot can be rewritten without modifying the immunity event history.
+ // recalculate antibodies for every agent if starting from snapshot.
+ // The antibodies profile is generated using the immunity event history in the
+ // snapshot; the antibody model config of the snapshot simulation will
+ // be superceded by the config of the current simulation. Thus, the antibody development
+ // during the snapshot can be rewritten without modifying the immunity event history.
+ antibodyModel.recalculateAntibodiesAfterSnapshot(handler.getPersons(), iteration);
+
+ } else if (episimConfig.getStartFromImmunization() != null) {
- antibodyModel.init(handler.getPersons(), iteration);
+ antibodyModel.init(handler.getPersons(), iteration);
+ handler.initImmunization(Path.of(episimConfig.getStartFromImmunization()));
+ } else {
+ antibodyModel.init(handler.getPersons(), iteration);
+ }
reporting.reportCpuTime(0, "Init", "finished", -1);
@@ -131,8 +138,9 @@ public void run(int maxIterations) {
for (; iteration <= maxIterations; iteration++) {
- if (episimConfig.getSnapshotInterval() > 0 && iteration % episimConfig.getSnapshotInterval() == 0)
+ if (episimConfig.getSnapshotInterval() > 0 && iteration % episimConfig.getSnapshotInterval() == 0) {
writeSnapshot(output, iteration);
+ }
if (iteration % 10 == 0)
Gbl.printMemoryUsage();
@@ -149,6 +157,7 @@ public void run(int maxIterations) {
/**
* Update events data and internal person data structure.
+ *
* @param events
*/
public void updateEvents(Map> events) {
diff --git a/src/main/java/org/matsim/episim/EpisimUtils.java b/src/main/java/org/matsim/episim/EpisimUtils.java
index 5972fa323..78cd0cb8f 100644
--- a/src/main/java/org/matsim/episim/EpisimUtils.java
+++ b/src/main/java/org/matsim/episim/EpisimUtils.java
@@ -61,7 +61,7 @@ public final class EpisimUtils {
/**
* Seconds in one day.
*/
- static final double DAY = 24. * 3600;
+ public static final double DAY = 24. * 3600;
private EpisimUtils() {
}
@@ -565,14 +565,14 @@ public static Map getOutDoorFractionFromDateAndTemp2(File wea
double tMax = Double.parseDouble(record.get("tmax"));
double prcp = Double.parseDouble(record.get("prcp"));
-
+
if (date.isBefore(LocalDate.parse("2021-01-01"))) {
outdoorFractions.put(date, maxOutdoorFraction * getOutDoorFractionFromDateAndTemp(date, TmidSpring2020, TmidFall2020, Trange, tMax, prcp, rainThreshold, alpha));
}
else {
outdoorFractions.put(date, maxOutdoorFraction * getOutDoorFractionFromDateAndTemp(date, TmidSpring, TmidFall, Trange, tMax, prcp, rainThreshold, alpha));
}
-
+
lastDate = date;
}
diff --git a/src/main/java/org/matsim/episim/Immunizable.java b/src/main/java/org/matsim/episim/Immunizable.java
index 46f8ab93e..bd2208d2a 100644
--- a/src/main/java/org/matsim/episim/Immunizable.java
+++ b/src/main/java/org/matsim/episim/Immunizable.java
@@ -2,6 +2,7 @@
import it.unimi.dsi.fastutil.doubles.DoubleList;
import it.unimi.dsi.fastutil.ints.IntList;
+import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import org.matsim.core.api.internal.HasPersonId;
import org.matsim.episim.model.VirusStrain;
@@ -47,7 +48,20 @@ public interface Immunizable extends HasPersonId {
*/
double getAntibodyLevelAtInfection();
+ /**
+ * Returns highest antibody level that agent has had in their past for all strains
+ */
+ Object2DoubleMap getMaxAntibodies();
+ /**
+ * Returns highest antibody level that agent has had in their past for a specific strain.
+ */
+ double getMaxAntibodies(VirusStrain strain);
+
+ /**
+ * sets max antibody level that agent has had in their past for a specific strain.
+ */
+ void updateMaxAntibodies(VirusStrain strain, double maxAb);
/**
* Returns whether agent has experienced given disease status at any time in the course of the simulation
*/
diff --git a/src/main/java/org/matsim/episim/InfectionEventHandler.java b/src/main/java/org/matsim/episim/InfectionEventHandler.java
index fccaf2aea..81f3641bd 100644
--- a/src/main/java/org/matsim/episim/InfectionEventHandler.java
+++ b/src/main/java/org/matsim/episim/InfectionEventHandler.java
@@ -37,7 +37,7 @@
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.utils.collections.Tuple;
-import org.matsim.episim.events.EpisimInfectionEvent;
+import org.matsim.episim.events.*;
import org.matsim.episim.model.*;
import org.matsim.episim.model.activity.ActivityParticipationModel;
import org.matsim.episim.model.testing.TestingModel;
@@ -45,22 +45,21 @@
import org.matsim.episim.policy.Restriction;
import org.matsim.episim.policy.ShutdownPolicy;
import org.matsim.facilities.ActivityFacility;
+import org.matsim.run.AnalysisCommand;
import org.matsim.utils.objectattributes.attributable.Attributes;
import org.matsim.vehicles.Vehicle;
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
+import java.io.*;
+import java.nio.file.Path;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutorService;
+import java.util.function.Function;
-import static org.matsim.episim.EpisimUtils.readChars;
-import static org.matsim.episim.EpisimUtils.writeChars;
+import static org.matsim.episim.EpisimUtils.*;
/**
* Main event handler of episim.
@@ -201,7 +200,7 @@ public InfectionEventHandler(Injector injector, SplittableRandom rnd) {
this.policy = injector.getInstance(ShutdownPolicy.class);
this.restrictions = episimConfig.createInitialRestrictions();
this.reporting = injector.getInstance(EpisimReporting.class);
- this.localRnd = new SplittableRandom( 65536); // fixed seed, because it should not change between snapshots
+ this.localRnd = new SplittableRandom(65536); // fixed seed, because it should not change between snapshots
this.progressionModel = injector.getInstance(ProgressionModel.class);
this.antibodyModel = injector.getInstance(AntibodyModel.class);
this.initialInfections = injector.getInstance(InitialInfectionHandler.class);
@@ -253,9 +252,9 @@ void init(Map> events) {
.sorted(Comparator.comparingInt(p -> ((EpisimPerson) p).getAgeOrDefault(-1)).reversed()
.thenComparing(p -> ((EpisimPerson) p).getPersonId()))
.forEach(p -> {
- Double compliance = EpisimUtils.findValidEntry(vaccinationConfig.getCompliancePerAge(), 1.0, p.getAgeOrDefault(-1));
- p.setVaccinable(localRnd.nextDouble() < compliance);
- });
+ Double compliance = EpisimUtils.findValidEntry(vaccinationConfig.getCompliancePerAge(), 1.0, p.getAgeOrDefault(-1));
+ p.setVaccinable(localRnd.nextDouble() < compliance);
+ });
listener = (Set) injector.getInstance(Key.get(Types.setOf(SimulationListener.class)));
vaccinations = (Set) injector.getInstance(Key.get(Types.setOf(VaccinationModel.class)));
@@ -282,6 +281,7 @@ void init(Map> events) {
/**
* Update events data and internal person data structure.
+ *
* @param events
*/
void updateEvents(Map> events) {
@@ -560,8 +560,7 @@ void updateEvents(Map> events) {
*/
void onSnapshotLoaded(int iteration) {
- listener = (Set) injector.getInstance(Key.get(Types.setOf(SimulationListener.class)));
- vaccinations = (Set) injector.getInstance(Key.get(Types.setOf(VaccinationModel.class)));
+ // Listener and vaccinations should already be present
for (SimulationListener s : listener) {
s.onSnapshotLoaded(iteration, localRnd, personMap, pseudoFacilityMap, vehicleMap);
@@ -577,16 +576,16 @@ void onSnapshotLoaded(int iteration) {
/**
* Distribute the containers to the different ReplayEventTasks, by setting
* the taskId attribute of the containers to values between 0 and episimConfig.getThreds() - 1,
- * so that the sum of numUsers * maxGroupSize has an even distribution
+ * so that the sum of numUsers * maxGroupSize has an even distribution
*/
private void balanceContainersByLoad(List, Double>> estimatedLoad) {
// We need the containers sorted by the load, with the highest load first.
// To get a deterministic distribution, we use the containerId for
// sorting the containers with the same estimatedLoad.
Comparator, Double>> loadComperator =
- Comparator., Double>,Double>comparing(
- t -> t.getSecond(), Comparator.reverseOrder()).
- thenComparing(t -> t.getFirst().getContainerId().toString());
+ Comparator., Double>, Double>comparing(
+ t -> t.getSecond(), Comparator.reverseOrder()).
+ thenComparing(t -> t.getFirst().getContainerId().toString());
Collections.sort(estimatedLoad, loadComperator);
final int numThreads = episimConfig.getThreads();
@@ -595,7 +594,7 @@ private void balanceContainersByLoad(List, Double>> est
for (int i = 0; i < numThreads; i++)
loadPerThread[i] = 0.0;
- for(Tuple, Double> tuple : estimatedLoad) {
+ for (Tuple, Double> tuple : estimatedLoad) {
// search for the thread/taskId with the minimal load
int useThread = 0;
Double minLoad = loadPerThread[0];
@@ -618,8 +617,9 @@ private void balanceContainersByLoad(List, Double>> est
*/
private void balanceContainersByHash(List, Double>> estimatedLoad) {
for (Tuple, Double> tuple : estimatedLoad) {
- final EpisimContainer> container = tuple.getFirst();
- final int useThread = Math.abs(container.getContainerId().hashCode()) % episimConfig.getThreads(); container.setTaskId(useThread);
+ final EpisimContainer> container = tuple.getFirst();
+ final int useThread = Math.abs(container.getContainerId().hashCode()) % episimConfig.getThreads();
+ container.setTaskId(useThread);
}
}
@@ -753,6 +753,9 @@ public void reset(int iteration) {
if (paramsMap.size() > 1000)
log.warn("Params map contains many entries. Activity types may not be .intern() Strings");
+ if (iteration == 1)
+ reporting.reportStart(episimConfig.getStartDate(), episimConfig.getStartFromImmunization());
+
double now = EpisimUtils.getCorrectedTime(episimConfig.getStartOffset(), 0, iteration);
LocalDate date = episimConfig.getStartDate().plusDays(iteration - 1);
@@ -772,6 +775,14 @@ public void reset(int iteration) {
}
}
+ // uncomment if you want immunization stats to be printed on a certain
+ // date or e.g. every month. This produces a lot of large files so use
+ // sparingly.
+// if (date.getDayOfMonth() == 1) {
+// reporting.reportDetailedPersonStats(date, personMap.values());
+// }
+
+
reporting.reportCpuTime(iteration, "ProgressionModelParallel", "start", -2);
progressionModel.afterStateUpdates(personMap, iteration);
reporting.reportCpuTime(iteration, "ProgressionModelParallel", "finished", -2);
@@ -789,7 +800,7 @@ public void reset(int iteration) {
// additional vaccinations:
for (VaccinationModel vaccination : vaccinations) {
- vaccination.handleVaccination(personMap, date, iteration, now);
+ vaccination.handleVaccination(personMap, date, iteration, now);
}
reporting.reportCpuTime(iteration, "VaccinationModel", "finished", -1);
@@ -978,12 +989,35 @@ void handleEvents(DayOfWeek day, List events) {
infections.stream().sorted()
.forEach(reporting::reportInfection);
+
+ int totalContacts = handlers.stream().mapToInt(TrajectoryHandler::getNumContacts).sum();
+
+ reporting.reportTotalContacts(totalContacts);
+
for (SimulationListener l : listener) {
l.onIterationEnd(iteration, episimConfig.getStartDate().plusDays(iteration - 1));
}
}
+
+ /**
+ * Read immunization history and init persons.
+ */
+ void initImmunization(Path history) {
+
+ log.info("Reading immunization from {}", history);
+
+ InitialImmunizationHandler handler = new InitialImmunizationHandler(personMap,episimConfig, antibodyModel,progressionModel);
+ List days = AnalysisCommand.forEachEvent(history, handler, true, handler);
+
+
+ if (handler.isContinueProcessingEvents()) {
+ throw new RuntimeException("Immunisation history is not long enough (only contains " + days.size() + "days)");
+ }
+
+ }
+
/**
* Container that is always a vehicle.
*/
diff --git a/src/main/java/org/matsim/episim/TracingConfigGroup.java b/src/main/java/org/matsim/episim/TracingConfigGroup.java
index f58949c9b..8ca429b3c 100644
--- a/src/main/java/org/matsim/episim/TracingConfigGroup.java
+++ b/src/main/java/org/matsim/episim/TracingConfigGroup.java
@@ -493,7 +493,7 @@ public enum QuarantineRelease {
/**
* Release persons without showing symptoms.
*/
- NON_SYMPTOMS
+ NON_SYMPTOMATIC
}
diff --git a/src/main/java/org/matsim/episim/TrajectoryHandler.java b/src/main/java/org/matsim/episim/TrajectoryHandler.java
index 2326e9a7f..d15d55f92 100644
--- a/src/main/java/org/matsim/episim/TrajectoryHandler.java
+++ b/src/main/java/org/matsim/episim/TrajectoryHandler.java
@@ -46,9 +46,9 @@ final class TrajectoryHandler {
@Inject
public TrajectoryHandler(EpisimConfigGroup episimConfig, EpisimReporting reporting, ContactModel model, SplittableRandom rnd,
- @Named("personMap") Map, EpisimPerson> personMap,
- @Named("vehicleMap") Map, InfectionEventHandler.EpisimVehicle> vehicleMap,
- @Named("pseudoFacilityMap") Map, InfectionEventHandler.EpisimFacility> pseudoFacilityMap) {
+ @Named("personMap") Map, EpisimPerson> personMap,
+ @Named("vehicleMap") Map, InfectionEventHandler.EpisimVehicle> vehicleMap,
+ @Named("pseudoFacilityMap") Map, InfectionEventHandler.EpisimFacility> pseudoFacilityMap) {
this.rnd = rnd;
this.episimConfig = episimConfig;
this.reporting = reporting;
@@ -68,6 +68,13 @@ void setRestrictionsForIteration(int iteration, ImmutableMap
@@ -132,7 +139,7 @@ void checkAndHandleEndOfNonCircularTrajectory(EpisimPerson person, DayOfWeek day
* @param responsible predicate for checking if the handler is responsible for a certain facility
*/
public void onStartDay(Predicate> responsibleFacility,
- Predicate> responsibleVehicle) {
+ Predicate> responsibleVehicle) {
double now = EpisimUtils.getCorrectedTime(episimConfig.getStartOffset(), 0, iteration);
DayOfWeek day = EpisimUtils.getDayOfWeek(episimConfig, iteration);
@@ -263,7 +270,7 @@ public void handleEvent(ActivityEndEvent activityEndEvent) {
reporting.handleEvent(activityEndEvent);
if (episimConfig.getContagiousOptimization() == EpisimConfigGroup.ContagiousOptimization.no ||
- episimFacility.containsContagious()) {
+ episimFacility.containsContagious()) {
contactModel.infectionDynamicsFacility(episimPerson, episimFacility, now);
}
@@ -311,8 +318,8 @@ public void handleEvent(PersonLeavesVehicleEvent leavesVehicleEvent) {
reporting.handleEvent(leavesVehicleEvent);
- if (episimConfig.getContagiousOptimization() == EpisimConfigGroup.ContagiousOptimization.no ||
- episimVehicle.containsContagious()) {
+ if (episimConfig.getContagiousOptimization() == EpisimConfigGroup.ContagiousOptimization.no ||
+ episimVehicle.containsContagious()) {
contactModel.infectionDynamicsVehicle(episimPerson, episimVehicle, now);
}
diff --git a/src/main/java/org/matsim/episim/VaccinationConfigGroup.java b/src/main/java/org/matsim/episim/VaccinationConfigGroup.java
index 1c7cb027a..8a2595ffb 100644
--- a/src/main/java/org/matsim/episim/VaccinationConfigGroup.java
+++ b/src/main/java/org/matsim/episim/VaccinationConfigGroup.java
@@ -36,7 +36,6 @@ public class VaccinationConfigGroup extends ReflectiveConfigGroup {
private static final String GROUPNAME = "episimVaccination";
-
/**
* Amount of vaccinations available per day.
*/
@@ -253,7 +252,7 @@ public boolean getUseIgA() {
}
@StringSetter(TIME_PERIOD_IGA)
- public void setTimePeriodIgA(double timePeriodIgA){
+ public void setTimePeriodIgA(double timePeriodIgA) {
this.timePeriodIgA = timePeriodIgA;
}
diff --git a/src/main/java/org/matsim/episim/VirusStrainConfigGroup.java b/src/main/java/org/matsim/episim/VirusStrainConfigGroup.java
index 9498d57de..8c3dcacd9 100644
--- a/src/main/java/org/matsim/episim/VirusStrainConfigGroup.java
+++ b/src/main/java/org/matsim/episim/VirusStrainConfigGroup.java
@@ -1,17 +1,25 @@
package org.matsim.episim;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
import org.matsim.core.config.ConfigGroup;
import org.matsim.core.config.ReflectiveConfigGroup;
import org.matsim.episim.model.VirusStrain;
import java.util.EnumMap;
import java.util.Map;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
/**
* Config option specific to {@link org.matsim.episim.model.VirusStrain}.
*/
public class VirusStrainConfigGroup extends ReflectiveConfigGroup {
+ private static final Splitter.MapSplitter SPLITTER = Splitter.on(";").withKeyValueSeparator("=");
+ private static final Joiner.MapJoiner JOINER = Joiner.on(";").withKeyValueSeparator("=");
+
private static final String GROUPNAME = "virusStrains";
/**
@@ -53,6 +61,13 @@ public StrainParams getOrAddParams(VirusStrain strain) {
return strains.get(strain);
}
+ /**
+ * Whether params for strain are present.
+ */
+ public boolean hasParams(VirusStrain strain) {
+ return strains.containsKey(strain);
+ }
+
@Override
public ConfigGroup createParameterSet(String type) {
if (StrainParams.SET_TYPE.equals(type)) {
@@ -84,6 +99,8 @@ public static final class StrainParams extends ReflectiveConfigGroup {
private static final String FACTOR_SERIOUSLY_SICK = "factorSeriouslySick";
private static final String FACTOR_CRITICAL = "factorCritical";
private static final String FACTOR_SERIOUSLY_SICK_VAC = "factorSeriouslySickVaccinated";
+ private static final String AGE_SUSCEPTIBILITY = "ageSusceptibility";
+ private static final String AGE_INFECTIVITY = "ageInfectivity";
/**
* Type of the strain.
@@ -110,6 +127,24 @@ public static final class StrainParams extends ReflectiveConfigGroup {
*/
private double factorSeriouslySickVaccinated = 1.0;
+ /**
+ * Child susceptibility used in AgeDependentInfectionModelWithSeasonality.
+ * Taken from https://doi.org/10.1101/2020.06.03.20121145
+ */
+ private final NavigableMap ageSusceptibility = new TreeMap<>(Map.of(
+ 19, 0.45,
+ 20, 1d
+ ));
+
+ /**
+ * Child infectivity used in AgeDependentInfectionModelWithSeasonality.
+ * Taken from https://doi.org/10.1101/2020.06.03.20121145
+ */
+ private final NavigableMap ageInfectivity = new TreeMap<>(Map.of(
+ 19, 0.85,
+ 20, 1d
+ ));
+
StrainParams() {
super(SET_TYPE);
}
@@ -187,5 +222,65 @@ public void setFactorSeriouslySickVaccinated(double factorSeriouslySickVaccinate
public double getFactorSeriouslySickVaccinated() {
return factorSeriouslySickVaccinated;
}
+
+
+ @StringGetter(AGE_SUSCEPTIBILITY)
+ String getAgeSusceptibilityString() {
+ return JOINER.join(ageSusceptibility);
+ }
+
+ @StringSetter(AGE_SUSCEPTIBILITY)
+ void setAgeSusceptibility(String config) {
+ Map map = SPLITTER.split(config);
+ setAgeSusceptibility(map.entrySet().stream().collect(Collectors.toMap(
+ e -> Integer.parseInt(e.getKey()), e -> Double.parseDouble(e.getValue())
+ )));
+ }
+
+ /**
+ * Return susceptibility for different age groups.
+ */
+ public NavigableMap getAgeSusceptibility() {
+ return ageSusceptibility;
+ }
+
+ /**
+ * Set susceptibility for all age groups, previous entries will be overwritten.
+ */
+ public void setAgeSusceptibility(Map ageSusceptibility) {
+ this.ageSusceptibility.clear();
+ this.ageSusceptibility.putAll(ageSusceptibility);
+ }
+
+ @StringGetter(AGE_INFECTIVITY)
+ String getAgeInfectivityString() {
+ return JOINER.join(ageInfectivity);
+ }
+
+ @StringSetter(AGE_INFECTIVITY)
+ void setAgeInfectivity(String config) {
+ Map map = SPLITTER.split(config);
+ setAgeInfectivity(map.entrySet().stream().collect(Collectors.toMap(
+ e -> Integer.parseInt(e.getKey()), e -> Double.parseDouble(e.getValue())
+ )));
+ }
+
+ /**
+ * Return infectivity for different age groups.
+ */
+ public NavigableMap getAgeInfectivity() {
+ return ageInfectivity;
+ }
+
+ /**
+ * Set infectivity for all age groups, previous entries will be overwritten.
+ */
+ public void setAgeInfectivity(Map ageInfectivity) {
+ this.ageInfectivity.clear();
+ this.ageInfectivity.putAll(ageInfectivity);
+ }
+
}
+
+
}
diff --git a/src/main/java/org/matsim/episim/analysis/ExtractInfectionsByAge.java b/src/main/java/org/matsim/episim/analysis/ExtractInfectionsByAge.java
index 363f58e58..b81904462 100644
--- a/src/main/java/org/matsim/episim/analysis/ExtractInfectionsByAge.java
+++ b/src/main/java/org/matsim/episim/analysis/ExtractInfectionsByAge.java
@@ -232,7 +232,7 @@ private void readScenario(Path path) throws IOException {
}
}
,
- (EpisimPersonStatusEventHandler) e -> {
+ false, (EpisimPersonStatusEventHandler) e -> {
if (!counts.containsKey(e.getDiseaseStatus()))
return;
diff --git a/src/main/java/org/matsim/episim/analysis/FilterEvents.java b/src/main/java/org/matsim/episim/analysis/FilterEvents.java
index b93bf76f8..64e182980 100644
--- a/src/main/java/org/matsim/episim/analysis/FilterEvents.java
+++ b/src/main/java/org/matsim/episim/analysis/FilterEvents.java
@@ -9,6 +9,8 @@
import org.matsim.api.core.v01.events.Event;
import org.matsim.core.events.handler.BasicEventHandler;
import org.matsim.episim.events.EpisimInfectionEvent;
+import org.matsim.episim.events.EpisimInitialInfectionEvent;
+import org.matsim.episim.events.EpisimStartEvent;
import org.matsim.episim.events.EpisimVaccinationEvent;
import org.matsim.episim.reporting.EpisimWriter;
import org.matsim.run.AnalysisCommand;
@@ -30,12 +32,12 @@ public class FilterEvents implements OutputAnalysis {
private static final Logger log = LogManager.getLogger(FilterEvents.class);
- // @CommandLine.Option(names = "--output", defaultValue = "../public-svn/matsim/scenarios/countries/de/episim/battery/cologne/2022-02-17/1/output-filtered")
- @CommandLine.Option(names = "--output", defaultValue = "./output/")
+ @CommandLine.Option(names = "--output", defaultValue = "../public-svn/matsim/scenarios/countries/de/episim/battery/jakob/2022-08-02/2-vax-b/analysis")
+// @CommandLine.Option(names = "--output", defaultValue = "./output/")
private Path output;
@CommandLine.Parameters(paramLabel = "TYPE", arity = "0..*", description = "Names of event types to keep")
- private Set filter = Set.of(EpisimInfectionEvent.EVENT_TYPE, EpisimVaccinationEvent.EVENT_TYPE);
+ private Set filter = Set.of(EpisimStartEvent.EVENT_TYPE, EpisimInitialInfectionEvent.EVENT_TYPE, EpisimInfectionEvent.EVENT_TYPE, EpisimVaccinationEvent.EVENT_TYPE);
public static void main(String[] args) {
System.exit(new CommandLine(new FilterEvents()).execute(args));
@@ -77,7 +79,7 @@ public void analyzeOutput(Path output) throws IOException {
AnalysisCommand.forEachEvent(output, s -> {
handler.reset(-1);
- }, handler);
+ }, false, handler);
handler.closeEntry();
zipOut.close();
diff --git a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java
index be464ea69..6dd17f5f1 100644
--- a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java
+++ b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java
@@ -57,20 +57,23 @@
name = "hospitalNumbers",
description = "Calculate hospital numbers from events"
)
+
public class HospitalNumbersFromEvents implements OutputAnalysis {
- @CommandLine.Option(names = "--output", defaultValue = "./output/")
-// @CommandLine.Option(names = "--output", defaultValue = "../public-svn/matsim/scenarios/countries/de/episim/battery/jakob/2022-06-16/2/analysis/policy_leis75/")
+ @CommandLine.Option(names = "--output", defaultValue = "/Users/jakob/git/matsim-episim/A_originalImmHist")
+// @CommandLine.Option(names = "--output", defaultValue = "/Users/jakob/git/matsim-episim/B_startedFromImmHist")
+// @CommandLine.Option(names = "--output", defaultValue = "/Users/jakob/git/public-svn/matsim/scenarios/countries/de/episim/battery/jakob/2022-10-18/3-meas/analysis/")
private Path output;
- @CommandLine.Option(names = "--input", defaultValue = "/scratch/projects/bzz0020/episim-input")
-// @CommandLine.Option(names = "--input", defaultValue = "../shared-svn/projects/episim/matsim-files/snz/Cologne/episim-input")
+// @CommandLine.Option(names = "--input", defaultValue = "/scratch/projects/bzz0020/episim-input")
+ @CommandLine.Option(names = "--input", defaultValue = "../shared-svn/projects/episim/matsim-files/snz/Cologne/episim-input")
private String input;
@CommandLine.Option(names = "--population-file", defaultValue = "/cologne_snz_entirePopulation_emptyPlans_withDistricts_25pt_split.xml.gz")
private String populationFile;
- @CommandLine.Option(names = "--start-date", defaultValue = "2020-02-24")
+// @CommandLine.Option(names = "--start-date", defaultValue = "2022-04-01")
+ @CommandLine.Option(names = "--start-date", defaultValue = "2020-02-25")
private LocalDate startDate;
@CommandLine.Option(names = "--district", description = "District to filter for", defaultValue = "Köln")
@@ -81,18 +84,14 @@ public class HospitalNumbersFromEvents implements OutputAnalysis {
private final String DATE = "date";
private final String DAY = "day";
- private final String INTAKES_HOSP = "intakesHosp";
- private final String INTAKES_ICU = "intakesIcu";
- private final String OCCUPANCY_HOSP = "occupancyHosp";
- private final String OCCUPANCY_ICU = "occupancyIcu";
+
@Inject
private Scenario scenario;
private Population population;
- private List> filteredPopulationIds;
-
+ // TODO: check age or strain based lags in literature
// source: incidence wave vs. hospitalization wave in cologne/nrw (see https://docs.google.com/spreadsheets/d/1jmaerl27LKidD1uk3azdIL1LmvHuxazNQlhVo9xO1z8/edit?usp=sharing)
private static final Object2IntMap lagBetweenInfectionAndHospitalisation = new Object2IntAVLTreeMap<>(
Map.of(VirusStrain.SARS_CoV_2, 14,
@@ -101,7 +100,8 @@ public class HospitalNumbersFromEvents implements OutputAnalysis {
VirusStrain.OMICRON_BA1, 14,
VirusStrain.OMICRON_BA2, 14,
VirusStrain.OMICRON_BA5, 14,
- VirusStrain.STRAIN_A, 14
+ VirusStrain.STRAIN_A, 14,
+ VirusStrain.STRAIN_B, 14
));
// source: hospitalization wave vs. ICU wave in cologne/nrw (see https://docs.google.com/spreadsheets/d/1jmaerl27LKidD1uk3azdIL1LmvHuxazNQlhVo9xO1z8/edit?usp=sharing)
@@ -112,7 +112,8 @@ public class HospitalNumbersFromEvents implements OutputAnalysis {
VirusStrain.OMICRON_BA1, 6,
VirusStrain.OMICRON_BA2, 6,
VirusStrain.OMICRON_BA5, 6,
- VirusStrain.STRAIN_A, 6
+ VirusStrain.STRAIN_A, 6,
+ VirusStrain.STRAIN_B, 6
));
// Austria study in https://docs.google.com/spreadsheets/d/1jmaerl27LKidD1uk3azdIL1LmvHuxazNQlhVo9xO1z8/edit#gid=0
@@ -123,58 +124,65 @@ public class HospitalNumbersFromEvents implements OutputAnalysis {
VirusStrain.OMICRON_BA1, 7,
VirusStrain.OMICRON_BA2, 7,
VirusStrain.OMICRON_BA5,7,
- VirusStrain.STRAIN_A, 7
+ VirusStrain.STRAIN_A, 7,
+ VirusStrain.STRAIN_B, 7
));
private static final Object2IntMap daysInICU = new Object2IntAVLTreeMap<>(
Map.of(VirusStrain.SARS_CoV_2, 15, // Debeka & Ireland studies
VirusStrain.ALPHA, 15, // Debeka & Ireland studies
VirusStrain.DELTA, 15, // this and following values come from nrw analysis on Tabellenblatt 5
- VirusStrain.OMICRON_BA1, 10,
+ VirusStrain.OMICRON_BA1, 10, // TODO: Where does this number come from?
VirusStrain.OMICRON_BA2, 10,
VirusStrain.OMICRON_BA5,10,
- VirusStrain.STRAIN_A, 10
+ VirusStrain.STRAIN_A, 10,
+ VirusStrain.STRAIN_B, 10
));
// ??
private static final Object2IntMap daysInHospitalGivenICU = new Object2IntAVLTreeMap<>(
- Map.of(VirusStrain.SARS_CoV_2, 60,
+ Map.of(VirusStrain.SARS_CoV_2, 60, // TODO: Where does this number come from?
VirusStrain.ALPHA, 60,
VirusStrain.DELTA, 60,
VirusStrain.OMICRON_BA1, 60,
VirusStrain.OMICRON_BA2, 60,
VirusStrain.OMICRON_BA5,60,
- VirusStrain.STRAIN_A, 60
+ VirusStrain.STRAIN_A, 60,
+ VirusStrain.STRAIN_B, 60
));
- private static final double beta = 1.2;
- private final int populationCntOfficialKoelln = 919_936;
- private final int populationCntOfficialNrw = 17_930_000;
+ private static final double beta = 1.2;
- private static final double hospitalFactor = 0.4;
+ private static final double hospitalFactor = 0.3; // Based on "guess & check", accounts for unreported cases TODO: Potential follow-up
- // base
private static final double factorWild = 1.0;
private static final double factorAlpha = 1.0 * factorWild;
// delta: 2.3x more severe than alpha - Hospital admission and emergency care attendance risk for SARS-CoV-2 delta (B.1.617.2) compared with alpha (B.1.1.7) variants of concern: a cohort study
- private static final double factorDelta = 1.6 * factorWild;
+ private static final double factorDelta = 1.2 * factorWild; //1.6 * factorWild;
// omicron: approx 0.3x (intrinsic) severity of delta - Comparative analysis of the risks of hospitalisation and death associated with SARS-CoV-2 omicron (B.1.1.529) and delta (B.1.617.2) variants in England: a cohort study
- private static final double factorOmicron = 0.3 * factorDelta; // * reportedShareOmicron / reportedShareDelta
+ private static final double factorOmicron = 0.45 * factorDelta; // reportedShareOmicron / reportedShareDelta
+// private static final double factorOmicron = 0.6 * factorDelta;// reportedShareOmicron / reportedShareDelta
+
+ private static final double factorBA5 = 1.0 * factorOmicron; // old: 1.5
+
+ private static final double factorScen2 = factorBA5; // reportedShareOmicron / reportedShareDelta
+ private static final double factorScen3 = factorBA5 * 3;// reportedShareOmicron / reportedShareDelta
+
+
+// private static final double factorBA5 = 1.0 * factorOmicron;
-// private static final List strainFactors = List.of(factorOmicron, factorDelta);
// ??
- private static final double factorWildAndAlphaICU = 1.;
+ private static final double factorWildAndAlphaICU = 1.; // TODO : Check literature for reasonable values
private static final double factorDeltaICU = 1.;
private static final double factorOmicronICU = 1.;
-
- private String outputAppendix = "";
+ private static final double factorBA5ICU = 1.;
public static void main(String[] args) {
System.exit(new CommandLine(new HospitalNumbersFromEvents()).execute(args));
@@ -182,28 +190,27 @@ public static void main(String[] args) {
@Override
public Integer call() throws Exception {
+ // logger configuration
Configurator.setLevel("org.matsim.core.config", Level.WARN);
Configurator.setLevel("org.matsim.core.controler", Level.WARN);
Configurator.setLevel("org.matsim.core.events", Level.WARN);
Configurator.setLevel("org.matsim.core.utils", Level.WARN);
+ // check if events file exists
if (!Files.exists(output)) {
log.error("Output path {} does not exist.", output);
return 2;
}
-
+ // read population
population = PopulationUtils.readPopulation(input + populationFile);
- // Here we define values factorSeriouslySickStrainA should have
-
-
// Part 1: calculate hospitalizations for each seed and save as csv
-// List pathList = new ArrayList<>();
+ List pathList = new ArrayList<>();
AnalysisCommand.forEachScenario(output, pathToScenario -> {
try {
-// pathList.add(pathToScenario);
+ pathList.add(pathToScenario);
// analyzeOutput is where the hospitalization post processing occurs
analyzeOutput(pathToScenario);
@@ -217,6 +224,11 @@ public Integer call() throws Exception {
// Part 2: aggregate over multiple seeds & produce tsv output & plot
// HospitalNumbersFromEventsPlotter.aggregateAndProducePlots(output, pathList);
+ //TODO: move to other class
+// HospitalNumbersFromEventsPlotter.aggregateAndProducePlots(output, pathList, "_Omicron", startDate, "Omicron");
+// HospitalNumbersFromEventsPlotter.aggregateAndProducePlots(output, pathList, "_Delta", startDate, "Delta");
+
+
// }
@@ -232,7 +244,7 @@ public void analyzeOutput(Path pathToScenario) throws IOException {
String id = AnalysisCommand.getScenarioPrefix(pathToScenario);
// builds the path to the output file that is produced by this analysis
- final Path tsvPath = pathToScenario.resolve(id + "post.hospital" + outputAppendix + ".tsv");
+ final Path tsvPath = pathToScenario.resolve(id + "post.hospital.tsv");
// calculates hospitalizations
calculateHospitalizationsAndWriteOutput(pathToScenario, tsvPath);
@@ -254,44 +266,20 @@ private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path t
BufferedWriter bw = Files.newBufferedWriter(tsvPath);
bw.write(AnalysisCommand.TSV.join(DAY, DATE,"measurement", "severity", "n")); // + "\thospNoImmunity\thospBaseImmunity\thospBoosted\tincNoImmunity\tincBaseImmunity\tincBoosted"));
- ConfigHolder holderOmicron = configure(factorOmicron,factorOmicronICU) ;
- ConfigHolder holderDelta = configure(factorDelta,factorDeltaICU) ;
+ ConfigHolder holderOmicron = configure(factorScen2, 1.0); // scenario 2
+ ConfigHolder holderDelta = configure(factorScen3, 1.0); //scenario 3
List handlers = List.of(
- new Handler("Omicron", population, holderOmicron ),
+ new Handler("Omicron", population, holderOmicron),
new Handler("Delta", population, holderDelta)
);
// feed the output events file to the handler, so that the hospitalizations may be calculated
- AnalysisCommand.forEachEvent(pathToScenario, s -> {
- }, handlers.toArray(new Handler[0]));
-
-// for (Double facA : strainFactors) {
-
- // configure post processing run
-// double facAICU = 0.;
-// String diseaseSevName = "";
-// if (facA == factorWild) {
-// diseaseSevName = "Alpha";
-// facAICU = factorWildAndAlphaICU;
-// } else if (facA == factorDelta) {
-// diseaseSevName = "Delta";
-// facAICU = factorDeltaICU;
-// } else if (facA == factorOmicron) {
-// diseaseSevName = "Omicron";
-// facAICU = factorOmicronICU;
-// } else {
-// throw new RuntimeException("not clear what to do");
-// }
+ List eventFiles = AnalysisCommand.forEachEvent(pathToScenario, s -> {
+ }, true, handlers.toArray(new Handler[0]));
for (Handler handler : handlers) {
- int maxIteration = Math.max(
- Math.max(handler.postProcessHospitalAdmissions.keySet().lastInt(),
- handler.postProcessICUAdmissions.keySet().lastInt()),
- Math.max(handler.postProcessHospitalFilledBeds.keySet().lastInt(),
- handler.postProcessHospitalFilledBedsICU.keySet().lastInt()));
-
// calculates the number of agents in the scenario's population (25% sample) who live in Cologne
// this is used to normalize the hospitalization values
@@ -299,7 +287,7 @@ private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path t
.filter(x -> x.getAttributes().getAttribute("district").equals(district)).count();
- for (int day = 0; day <= maxIteration; day++) {
+ for (int day = 0; day < eventFiles.size(); day++) {
LocalDate date = startDate.plusDays(day);
// calculates Incidence - 7day hospitalizations per 100,000 residents
@@ -312,13 +300,13 @@ private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path t
double occupancyIcu = handler.postProcessHospitalFilledBedsICU.getOrDefault(day, 0) * 100_000. / popSize;
bw.newLine();
- bw.write(AnalysisCommand.TSV.join(day, date, "intakesHosp", handler.name , intakesHosp));
+ bw.write(AnalysisCommand.TSV.join(day, date, HospitalNumbersFromEventsPlotter.INTAKES_HOSP, handler.name , intakesHosp));
bw.newLine();
- bw.write(AnalysisCommand.TSV.join(day, date, "intakesICU", handler.name, intakesIcu));
+ bw.write(AnalysisCommand.TSV.join(day, date, HospitalNumbersFromEventsPlotter.INTAKES_ICU, handler.name, intakesIcu));
bw.newLine();
- bw.write(AnalysisCommand.TSV.join(day, date, "occupancyHosp ", handler.name, occupancyHosp));
+ bw.write(AnalysisCommand.TSV.join(day, date, HospitalNumbersFromEventsPlotter.OCCUPANCY_HOSP, handler.name, occupancyHosp));
bw.newLine();
- bw.write(AnalysisCommand.TSV.join(day, date, "occupancyICU", handler.name, occupancyIcu));
+ bw.write(AnalysisCommand.TSV.join(day, date, HospitalNumbersFromEventsPlotter.OCCUPANCY_ICU, handler.name, occupancyIcu));
}
}
@@ -327,7 +315,7 @@ private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path t
}
- private int getWeeklyHospitalizations(Int2IntMap hospMap, Integer today) {
+ static int getWeeklyHospitalizations(Int2IntMap hospMap, Integer today) {
int weeklyHospitalizations = 0;
for (int i = 0; i < 7; i++) {
try {
@@ -340,10 +328,7 @@ private int getWeeklyHospitalizations(Int2IntMap hospMap, Integer today) {
}
- public static final class Handler implements EpisimVaccinationEventHandler, EpisimInfectionEventHandler {
-
-
-
+ public static final class Handler implements EpisimInfectionEventHandler, EpisimInitialInfectionEventHandler{
final Map, ImmunizablePerson> data;
private final String name;
private final Population population;
@@ -355,24 +340,8 @@ public static final class Handler implements EpisimVaccinationEventHandler, Epis
final Int2IntSortedMap postProcessHospitalFilledBeds;
final Int2IntSortedMap postProcessHospitalFilledBedsICU;
- private final Int2IntSortedMap changeBaseImmunity;
- private final Int2IntMap changeNoImmunity;
- private final Int2IntMap changeBoostered;
- private final Int2IntMap hospNoImmunity;
- private final Int2IntMap hospBoostered;
- private final Int2IntMap hospBaseImmunity;
- private final Int2IntMap incNoImmunity;
- private final Int2IntMap incBaseImmunity;
- private final Int2IntMap incBoostered;
-
-// private final EpisimWriter episimWriter;
- BufferedWriter hospCalibration;
-
-// private CSVPrinter printer;
-
private final AgeDependentDiseaseStatusTransitionModel transitionModel;
-
Handler(String name, Population population, ConfigHolder holder) {
// instantiate the custom event handler that calculates hospitalizations based on events
@@ -382,21 +351,12 @@ public static final class Handler implements EpisimVaccinationEventHandler, Epis
this.rnd = new Random(1234);
this.holder = holder;
+ // key : iteration, value : admissions/filled beds
this.postProcessHospitalAdmissions = new Int2IntAVLTreeMap();
this.postProcessICUAdmissions = new Int2IntAVLTreeMap();
this.postProcessHospitalFilledBeds = new Int2IntAVLTreeMap();
this.postProcessHospitalFilledBedsICU = new Int2IntAVLTreeMap();
- this.changeNoImmunity = new Int2IntAVLTreeMap();
- this.changeBaseImmunity = new Int2IntAVLTreeMap();
- this.changeBoostered = new Int2IntAVLTreeMap();
- this.hospNoImmunity = new Int2IntAVLTreeMap();
- this.hospBoostered = new Int2IntAVLTreeMap();
- this.hospBaseImmunity = new Int2IntAVLTreeMap();
- this.incNoImmunity = new Int2IntAVLTreeMap();
- this.incBaseImmunity = new Int2IntAVLTreeMap();
- this.incBoostered = new Int2IntAVLTreeMap();
-
this.transitionModel = new AgeDependentDiseaseStatusTransitionModel(new SplittableRandom(1234), holder.episimConfig, holder.vaccinationConfig, holder.strainConfig);
// try {
@@ -407,9 +367,11 @@ public static final class Handler implements EpisimVaccinationEventHandler, Epis
// }
}
+
@Override
public void handleEvent(EpisimInfectionEvent event) {
+
ImmunizablePerson person = data.computeIfAbsent(event.getPersonId(),
personId -> new ImmunizablePerson(personId, getAge(personId)));
@@ -419,21 +381,18 @@ public void handleEvent(EpisimInfectionEvent event) {
return;
}
+ VirusStrain virusStrain = event.getVirusStrain();
person.addInfection(event.getTime());
- person.setAntibodyLevelAtInfection(event.getAntibodies());
- person.setVirusStrain(event.getVirusStrain());
+ person.setVirusStrain(virusStrain);
+ person.setNumVaccinations(event.getNumVaccinations());
+
+ person.updateMaxAntibodies(virusStrain, event.getMaxAntibodies());
int day = (int) (event.getTime() / 86_400);
- updateHospitalizationsPost(person, event.getVirusStrain(), day);
- if (person.getNumVaccinations()==0) {
- incNoImmunity.mergeInt(day, 1, Integer::sum);
- } else if (person.getNumVaccinations()==1) {
- incBaseImmunity.mergeInt(day, 1, Integer::sum);
- } else {
- incBoostered.mergeInt(day, 1, Integer::sum);
- }
+ updateHospitalizationsPost(person, virusStrain, day);
+
// print to csv
@@ -454,31 +413,40 @@ public void handleEvent(EpisimInfectionEvent event) {
}
-
-
@Override
- public void handleEvent(EpisimVaccinationEvent event) {
- ImmunizablePerson person = data.computeIfAbsent(event.getPersonId(), personId -> new ImmunizablePerson(personId, getAge(personId)));
-
- String district = (String) population.getPersons().get(person.personId).getAttributes().getAttribute("district");
-
- if (!district.equals("Köln")){
- return;
- }
-
- int day = (int) (event.getTime() / 86_400);
+ public void handleEvent(EpisimInitialInfectionEvent event) {
+ handleEvent(event.asInfectionEvent());
+ }
- if (person.getNumVaccinations()==0) {
- changeBaseImmunity.mergeInt(day, 1, Integer::sum);
- changeNoImmunity.mergeInt(day, -1, Integer::sum);
- } else if (person.getNumVaccinations() == 1) {
- changeBoostered.mergeInt(day, 1, Integer::sum);
- changeBaseImmunity.mergeInt(day, -1, Integer::sum);
- }
+// @Override
+// public void handleEvent(EpisimVaccinationEvent event) {
+//
+//// if (!event.getPersonId().toString().equals("12102f5"))
+//// return;
+//
+// ImmunizablePerson person = data.computeIfAbsent(event.getPersonId(), personId -> new ImmunizablePerson(personId, getAge(personId)));
+//
+// String district = (String) population.getPersons().get(person.personId).getAttributes().getAttribute("district");
+//
+// if (!district.equals("Köln")){
+// return;
+// }
+//
+// int day = (int) (event.getTime() / 86_400);
+//
+// if (person.getNumVaccinations()==0) {
+// changeBaseImmunity.mergeInt(day, 1, Integer::sum);
+// changeNoImmunity.mergeInt(day, -1, Integer::sum);
+// } else if (person.getNumVaccinations() == 1) {
+// changeBoostered.mergeInt(day, 1, Integer::sum);
+// changeBaseImmunity.mergeInt(day, -1, Integer::sum);
+// }
+//
+//
+// person.addVaccination(day);
- person.addVaccination(day);
- }
+// }
private int getAge(Id personId) {
return (int) population.getPersons().get(personId).getAttributes().getAttribute("microm:modeled:age");
@@ -486,7 +454,7 @@ private int getAge(Id personId) {
private void updateHospitalizationsPost(ImmunizablePerson person, VirusStrain strain, int infectionIteration) {
-
+ // check whether we entered all information for the strain
if (!lagBetweenInfectionAndHospitalisation.containsKey(strain)
|| !lagBetweenHospitalizationAndICU.containsKey(strain)
|| !daysInHospitalGivenNoICU.containsKey(strain)
@@ -496,22 +464,13 @@ private void updateHospitalizationsPost(ImmunizablePerson person, VirusStrain st
}
+ // check if go to hospital
if (goToHospital(person, infectionIteration)) {
// newly admitted to hospital
int inHospital = infectionIteration + lagBetweenInfectionAndHospitalisation.getInt(strain);
postProcessHospitalAdmissions.mergeInt(inHospital, 1, Integer::sum);
-
- if (person.getNumVaccinations()==0) {
- hospNoImmunity.mergeInt(inHospital, 1, Integer::sum);
- } else if (person.getNumVaccinations()==1) {
- hospBaseImmunity.mergeInt(inHospital, 1, Integer::sum);
- } else {
- hospBoostered.mergeInt(inHospital, 1, Integer::sum);
- }
-
-
if (goToICU(person, inHospital)) {
// newly admitted to ICU
@@ -580,7 +539,6 @@ private boolean goToICU(ImmunizablePerson person, int day) {
}
-
/**
* Data holder for attributes
*/
@@ -611,8 +569,15 @@ static final class ImmunizablePerson implements Immunizable{
* Antibody level at last infection.
*/
private double antibodyLevelAtInfection = 0;
- private int age;
+ /**
+ * Maximal antibody level reached by agent w/ respect to each strain
+ */
+ private final Object2DoubleMap maxAntibodies = new Object2DoubleOpenHashMap<>();
+
+ private final int age;
+
+ private int numVaccinations;
ImmunizablePerson(Id personId, int age) {
this.personId = personId;
@@ -626,7 +591,11 @@ public Id getPersonId() {
@Override
public int getNumVaccinations() {
- return vaccinationDates.size();
+ return numVaccinations;
+ }
+ public void setNumVaccinations(int numVaccinations) {
+ this.numVaccinations = numVaccinations;
+
}
@Override
@@ -644,9 +613,9 @@ public VirusStrain getVirusStrain() {
return strain;
}
- public void addVaccination(int day) {
- vaccinationDates.add(day);
- }
+// public void addVaccination(int day) {
+// vaccinationDates.add(day);
+// }
@Override
public IntList getVaccinationDates() {
@@ -673,6 +642,20 @@ public double getAntibodyLevelAtInfection() {
return antibodyLevelAtInfection;
}
+ @Override
+ public Object2DoubleMap getMaxAntibodies() {
+ return maxAntibodies;
+ }
+
+ @Override
+ public double getMaxAntibodies(VirusStrain strain) {
+ return maxAntibodies.getDouble(strain);
+ }
+
+ public void updateMaxAntibodies(VirusStrain strain, double maxAb){
+ this.maxAntibodies.put(strain, maxAb);
+ }
+
@Override
public boolean hadDiseaseStatus(EpisimPerson.DiseaseStatus status) {
throw new UnsupportedOperationException("this method is not supported by Holder");
@@ -702,7 +685,7 @@ public int getAge() {
* necessary for post processing.
* @param
*/
- private ConfigHolder configure(double facA, double facAICU) {
+ private static ConfigHolder configure(double facA, double facAICU) {
Config config = ConfigUtils.createConfig(new EpisimConfigGroup());
@@ -724,12 +707,14 @@ private ConfigHolder configure(double facA, double facAICU) {
strainConfig.getOrAddParams(VirusStrain.OMICRON_BA1).setFactorCritical(factorOmicronICU);
strainConfig.getOrAddParams(VirusStrain.OMICRON_BA2).setFactorSeriouslySick(factorOmicron);
strainConfig.getOrAddParams(VirusStrain.OMICRON_BA2).setFactorCritical(factorOmicronICU);
- strainConfig.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorSeriouslySick(factorOmicron);
- strainConfig.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorCritical(factorOmicronICU);
+ strainConfig.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorSeriouslySick(factorBA5);
+ strainConfig.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorCritical(factorBA5ICU);
strainConfig.getOrAddParams(VirusStrain.STRAIN_A).setFactorSeriouslySick(facA);
strainConfig.getOrAddParams(VirusStrain.STRAIN_A).setFactorCritical(facAICU);
+ strainConfig.getOrAddParams(VirusStrain.STRAIN_B).setFactorSeriouslySick(facA);
+ strainConfig.getOrAddParams(VirusStrain.STRAIN_B).setFactorCritical(facAICU);
// configure vaccinationConfig: set beta factor
VaccinationConfigGroup vaccinationConfig = ConfigUtils.addOrGetModule(config, VaccinationConfigGroup.class);
@@ -738,13 +723,13 @@ private ConfigHolder configure(double facA, double facAICU) {
return new ConfigHolder(episimConfig, vaccinationConfig, strainConfig);
}
- private static final class ConfigHolder {
+ static final class ConfigHolder {
private final EpisimConfigGroup episimConfig;
private final VaccinationConfigGroup vaccinationConfig;
private final VirusStrainConfigGroup strainConfig;
- private ConfigHolder(EpisimConfigGroup episimConfig, VaccinationConfigGroup vaccinationConfig, VirusStrainConfigGroup strainConfig) {
+ ConfigHolder(EpisimConfigGroup episimConfig, VaccinationConfigGroup vaccinationConfig, VirusStrainConfigGroup strainConfig) {
this.episimConfig = episimConfig;
this.vaccinationConfig = vaccinationConfig;
this.strainConfig = strainConfig;
diff --git a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEventsPlotter.java b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEventsPlotter.java
index e4b5d7ca0..383c405a1 100644
--- a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEventsPlotter.java
+++ b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEventsPlotter.java
@@ -1,104 +1,146 @@
-//package org.matsim.episim.analysis;
-//
-//import it.unimi.dsi.fastutil.ints.*;
-//import org.apache.commons.csv.CSVFormat;
-//import org.apache.commons.csv.CSVParser;
-//import org.apache.commons.csv.CSVPrinter;
-//import org.apache.commons.csv.CSVRecord;
-//import org.matsim.run.AnalysisCommand;
-//import tech.tablesaw.api.*;
-//import tech.tablesaw.plotly.components.Axis;
-//import tech.tablesaw.plotly.components.Figure;
-//import tech.tablesaw.plotly.components.Layout;
-//import tech.tablesaw.plotly.components.Page;
-//import tech.tablesaw.plotly.traces.ScatterTrace;
-//import tech.tablesaw.table.TableSliceGroup;
-//
-//import java.io.*;
-//import java.nio.charset.StandardCharsets;
-//import java.nio.file.Files;
-//import java.nio.file.Path;
-//import java.time.LocalDate;
-//import java.time.format.DateTimeFormatter;
-//import java.time.temporal.ChronoUnit;
-//import java.util.List;
-//
-//public class HospitalNumbersFromEventsPlotter {
-//
-//
-// private static void aggregateAndProducePlots(Path output, List pathList) throws IOException {
-//
-//
-// // read hospitalization tsv for all seeds and aggregate them!
-// // NOTE: all other parameters should be the same, otherwise the results will be useless!
-// Int2DoubleSortedMap intakeHosp = new Int2DoubleAVLTreeMap();
-// Int2DoubleSortedMap intakeIcu = new Int2DoubleAVLTreeMap();
-// Int2DoubleSortedMap occupancyHosp = new Int2DoubleAVLTreeMap();
-// Int2DoubleSortedMap occupancyIcu = new Int2DoubleAVLTreeMap();
-//
-//// Int2DoubleSortedMap hospNoImmunity = new Int2DoubleAVLTreeMap();
-//// Int2DoubleSortedMap hospBaseImmunity = new Int2DoubleAVLTreeMap();
-//// Int2DoubleSortedMap hospBoosted = new Int2DoubleAVLTreeMap();
-////
-//// Int2DoubleSortedMap incNoImmunity = new Int2DoubleAVLTreeMap();
-//// Int2DoubleSortedMap incBaseImmunity = new Int2DoubleAVLTreeMap();
-//// Int2DoubleSortedMap incBoosted = new Int2DoubleAVLTreeMap();
-//
-//
-//
-//
-// for (Path path : pathList) {
-//
-// String id = AnalysisCommand.getScenarioPrefix(path);
-//
-// final Path tsvPath = path.resolve(id + "post.hospital" + outputAppendix + ".tsv");
-//
-// try (CSVParser parser = new CSVParser(Files.newBufferedReader(tsvPath), CSVFormat.DEFAULT.withDelimiter('\t').withFirstRecordAsHeader())) {
-//
-// for (CSVRecord record : parser) {
-//
-// int day = Integer.parseInt(record.get(DAY));
+package org.matsim.episim.analysis;
+
+import it.unimi.dsi.fastutil.ints.*;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.matsim.episim.model.VirusStrain;
+import org.matsim.run.AnalysisCommand;
+import tech.tablesaw.api.*;
+import tech.tablesaw.plotly.components.Axis;
+import tech.tablesaw.plotly.components.Figure;
+import tech.tablesaw.plotly.components.Layout;
+import tech.tablesaw.plotly.components.Page;
+import tech.tablesaw.plotly.traces.ScatterTrace;
+import tech.tablesaw.table.TableSliceGroup;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+
+public class HospitalNumbersFromEventsPlotter {
+ private static final String DATE = "date";
+ private static final String DAY = "day";
+ final static String INTAKES_HOSP = "intakesHosp";
+ final static String INTAKES_ICU = "intakesIcu";
+ final static String OCCUPANCY_HOSP = "occupancyHosp";
+ final static String OCCUPANCY_ICU = "occupancyIcu";
+
+ private final static double populationCntOfficialNrw = 17_930_000;
+ private final static double populationCntOfficialKoelln = 919_936;
+
+
+
+
+ static void aggregateAndProducePlots(Path output, List pathList, String outputAppendix, LocalDate startDate, String strainToPlot) throws IOException {
+
+
+ // read hospitalization tsv for all seeds and aggregate them!
+ // NOTE: all other parameters should be the same, otherwise the results will be useless!
+ Int2DoubleSortedMap intakeHosp = new Int2DoubleAVLTreeMap();
+ Int2DoubleSortedMap intakeIcu = new Int2DoubleAVLTreeMap();
+ Int2DoubleSortedMap occupancyHosp = new Int2DoubleAVLTreeMap();
+ Int2DoubleSortedMap occupancyIcu = new Int2DoubleAVLTreeMap();
+
+// Int2DoubleSortedMap hospNoImmunity = new Int2DoubleAVLTreeMap();
+// Int2DoubleSortedMap hospBaseImmunity = new Int2DoubleAVLTreeMap();
+// Int2DoubleSortedMap hospBoosted = new Int2DoubleAVLTreeMap();
+//
+// Int2DoubleSortedMap incNoImmunity = new Int2DoubleAVLTreeMap();
+// Int2DoubleSortedMap incBaseImmunity = new Int2DoubleAVLTreeMap();
+// Int2DoubleSortedMap incBoosted = new Int2DoubleAVLTreeMap();
+
+
+
+
+ for (Path path : pathList) {
+
+ String id = AnalysisCommand.getScenarioPrefix(path);
+
+ final Path tsvPath = path.resolve(id + "post.hospital.tsv");
+
+ try (CSVParser parser = new CSVParser(Files.newBufferedReader(tsvPath), CSVFormat.DEFAULT.withDelimiter('\t').withFirstRecordAsHeader())) {
+
+ for (CSVRecord record : parser) {
+
+ if (!record.get("severity").equals(strainToPlot)) {
+ continue;
+ }
+
+ int day = Integer.parseInt(record.get(DAY));
+
+ double n = Double.parseDouble(record.get("n"));
+ switch (record.get("measurement")) {
+ case INTAKES_HOSP:
+ intakeHosp.mergeDouble(day, n / pathList.size(), Double::sum);
+ break;
+ case INTAKES_ICU:
+ intakeIcu.mergeDouble(day, n / pathList.size(), Double::sum);
+ break;
+ case OCCUPANCY_HOSP:
+ occupancyHosp.mergeDouble(day, n / pathList.size(), Double::sum);
+ break;
+ case OCCUPANCY_ICU:
+ occupancyIcu.mergeDouble(day, n / pathList.size(), Double::sum);
+ break;
+ default:
+ throw new RuntimeException("not valid measurement");
+ }
+
// intakeHosp.mergeDouble(day, Double.parseDouble(record.get(INTAKES_HOSP)) / pathList.size(), Double::sum);
// intakeIcu.mergeDouble(day, Double.parseDouble(record.get(INTAKES_ICU)) / pathList.size(), Double::sum);
// occupancyHosp.mergeDouble(day, Double.parseDouble(record.get(OCCUPANCY_HOSP)) / pathList.size(), Double::sum);
// occupancyIcu.mergeDouble(day, Double.parseDouble(record.get(OCCUPANCY_ICU)) / pathList.size(), Double::sum);
-//
-//// hospNoImmunity.mergeDouble(day, Double.parseDouble(record.get("hospNoImmunity")) / pathList.size(), Double::sum);
-//// hospBaseImmunity.mergeDouble(day, Double.parseDouble(record.get("hospBaseImmunity")) / pathList.size(), Double::sum);
-//// hospBoosted.mergeDouble(day, Double.parseDouble(record.get("hospBoosted")) / pathList.size(), Double::sum);
-////
-//// incNoImmunity.mergeDouble(day, Double.parseDouble(record.get("incNoImmunity")) / pathList.size(), Double::sum);
-//// incBaseImmunity.mergeDouble(day, Double.parseDouble(record.get("incBaseImmunity")) / pathList.size(), Double::sum);
-//// incBoosted.mergeDouble(day, Double.parseDouble(record.get("incBoosted")) / pathList.size(), Double::sum);
-// }
-// }
-// }
-//
-// // read rki data and add to tsv
-// Int2DoubleMap rkiHospIncidence = new Int2DoubleAVLTreeMap();
-// Int2DoubleMap rkiHospIncidenceAdj = new Int2DoubleAVLTreeMap();
-// try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../covid-sim/src/assets/rki-deutschland-hospitalization.csv")),
-// CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
-//
-// for (CSVRecord record : parser) {
-// if (!record.get("Bundesland").equals("Nordrhein-Westfalen")) {
-// continue;
-// }
-// LocalDate date = LocalDate.parse((record.get("Datum")));
-// int day = (int) startDate.until(date, ChronoUnit.DAYS);
-//
-// double incidence;
-// try {
-// incidence = Double.parseDouble(record.get("PS_adjustierte_7T_Hospitalisierung_Inzidenz"));
-// } catch (NumberFormatException e) {
-// incidence = Double.NaN;
-//
-// }
-//
-//
-// rkiHospIncidence.put(day, incidence);
-//
-// double incidenceAdj;
+
+// hospNoImmunity.mergeDouble(day, Double.parseDouble(record.get("hospNoImmunity")) / pathList.size(), Double::sum);
+// hospBaseImmunity.mergeDouble(day, Double.parseDouble(record.get("hospBaseImmunity")) / pathList.size(), Double::sum);
+// hospBoosted.mergeDouble(day, Double.parseDouble(record.get("hospBoosted")) / pathList.size(), Double::sum);
+//
+// incNoImmunity.mergeDouble(day, Double.parseDouble(record.get("incNoImmunity")) / pathList.size(), Double::sum);
+// incBaseImmunity.mergeDouble(day, Double.parseDouble(record.get("incBaseImmunity")) / pathList.size(), Double::sum);
+// incBoosted.mergeDouble(day, Double.parseDouble(record.get("incBoosted")) / pathList.size(), Double::sum);
+ }
+ }
+ }
+
+ // read rki data and add to tsv
+ Int2DoubleMap rkiHospIncidence = new Int2DoubleAVLTreeMap();
+ Int2DoubleMap rkiHospIncidenceAdj = new Int2DoubleAVLTreeMap();
+ try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../covid-sim/src/assets/rki-deutschland-hospitalization.csv")),
+ CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
+
+ for (CSVRecord record : parser) {
+ if (!record.get("Bundesland").equals("Nordrhein-Westfalen")) {
+ continue;
+ }
+ LocalDate date = LocalDate.parse((record.get("Datum")));
+ int day = (int) startDate.until(date, ChronoUnit.DAYS);
+
+ double incidence;
+ try {
+ incidence = Double.parseDouble(record.get("PS_adjustierte_7T_Hospitalisierung_Inzidenz"));
+ } catch (NumberFormatException e) {
+ incidence = Double.NaN;
+
+ }
+
+
+ rkiHospIncidence.put(day, incidence);
+
+ double incidenceAdj;
+ if (date.isBefore(LocalDate.of(2022, 11, 1))) {
+ incidenceAdj = incidence * 2 / 3;
+ } else{
+ incidenceAdj = incidence / 3;
+ }
+
+
// if (date.isBefore(LocalDate.of(2020, 12, 10))) {
// incidenceAdj = incidence;
// } else if (date.isBefore(LocalDate.of(2021, 1, 11))) {
@@ -116,133 +158,133 @@
// } else {
// incidenceAdj = 11./14 * incidence;
// }
-// rkiHospIncidenceAdj.put(day, incidenceAdj);
-// }
-// }
-//
-// Int2IntMap reportedIcuCases = new Int2IntAVLTreeMap();
-//
-// try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/Fallzahlen/DIVI/nrw-divi-processed-ICUincidence-until20220504.csv")),
-// CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
-//
-// for (CSVRecord record : parser) {
-// String dateStr = record.get("date").split("T")[0];
-// LocalDate date = LocalDate.parse(dateStr);
-// int day = (int) startDate.until(date, ChronoUnit.DAYS);
-//
-// int cases = 0;
-// try {
-// cases = Integer.parseInt(record.get("erstaufnahmen"));
-// } catch (NumberFormatException ignored) {
-//
-// }
-//
-// reportedIcuCases.put(day, cases);
-// }
-// }
-//
-//
-// Int2DoubleMap reportedIcuIncidence = new Int2DoubleAVLTreeMap();
-// for (Integer day : reportedIcuCases.keySet()) {
-// // calculates Incidence - 7day hospitalizations per 100,000 residents
-//
-// double xxx = getWeeklyHospitalizations(reportedIcuCases, day) * 100_000. / populationCntOfficialNrw;
-// reportedIcuIncidence.put((int) day, xxx);
-//
-// }
-//
-// Int2DoubleMap hospIncidenceKoeln = new Int2DoubleAVLTreeMap();
-// try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/hospital-cases/cologne/KoelnHospIncidence.csv")),
-// CSVFormat.DEFAULT.withDelimiter(';').withFirstRecordAsHeader())) {
-//
-// for (CSVRecord record : parser) {
-// String dateStr = record.get("date").split("T")[0];
-// LocalDate date = LocalDate.parse(dateStr);
-// int day = (int) startDate.until(date, ChronoUnit.DAYS);
-//
-// double incidence;
-// try {
-// incidence = Double.parseDouble(record.get("7-Tage-KH-Inz-Koelln")) * 2 ; //TODO
-//
-// } catch (NumberFormatException e) {
-// incidence = 0.;
-// }
-//
-// hospIncidenceKoeln.put(day, incidence);
-// }
-// }
-//
-// // read rki data and add to columns
-// // pink plot from covid-sim: general beds
-// // https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/episim/original-data/hospital-cases/cologne/KoelnAllgemeinpatienten.csv (pinke Linie)
-// Int2DoubleMap reportedBeds = new Int2DoubleAVLTreeMap();
-// Int2DoubleMap reportedBedsAdj = new Int2DoubleAVLTreeMap();
-// try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/hospital-cases/cologne/KoelnAllgemeinpatienten.csv")),
-// CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
-//
-// for (CSVRecord record : parser) {
-// String dateStr = record.get("date").split("T")[0];
-// LocalDate date = LocalDate.parse(dateStr);
-// int day = (int) startDate.until(date, ChronoUnit.DAYS);
-//
-// double incidence;
-// try {
-// incidence = Double.parseDouble(record.get("allgemeinpatienten")) * 100_000. / populationCntOfficialKoelln;
-// } catch (NumberFormatException e) {
-// incidence = 0.;
-// }
-//
-// reportedBeds.put(day, incidence);
-//
-//
-//
-// double incidenceAdj;
-// if (date.isBefore(LocalDate.of(2020, 12, 10))) {
-// incidenceAdj = incidence;
-// } else if (date.isBefore(LocalDate.of(2021, 1, 11))) {
-// incidenceAdj = 23. / 16. * incidence;
-// } else if (date.isBefore(LocalDate.of(2021, 3, 22))) {
-// incidenceAdj = 8. / 6. * incidence;
-// } else if (date.isBefore(LocalDate.of(2021, 5, 3))) {
-// incidenceAdj = 15./11. * incidence;
-// } else if (date.isBefore(LocalDate.of(2021, 11, 8))) {
-// incidenceAdj = incidence;
-// } else if (date.isBefore(LocalDate.of(2021, 12, 6))) {
-// incidenceAdj = 16. / 13. * incidence;
-// } else if (date.isBefore(LocalDate.of(2022, 1, 24))) {
-// incidenceAdj = incidence;
-// } else {
-// incidenceAdj = 11./14 * incidence;
-// }
-// reportedBedsAdj.put(day, incidenceAdj);
-// }
-// }
-//
-//
-// //green plot from covid-sim (Ich denke, das ist die Spalte "faelle_covid_aktuell", aber ich bin nicht ganz sicher.)
-// //https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/episim/original-data/Fallzahlen/DIVI/cologne-divi-processed.csv (grüne Linie)
-// Int2DoubleMap reportedBedsICU = new Int2DoubleAVLTreeMap();
-// try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/Fallzahlen/DIVI/cologne-divi-processed.csv")),
-// CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
-//
-// for (CSVRecord record : parser) {
-// String dateStr = record.get("date").split("T")[0];
-// LocalDate date = LocalDate.parse(dateStr);
-// int day = (int) startDate.until(date, ChronoUnit.DAYS);
-//
-// double incidence = 0.;
-// try {
-// incidence = Double.parseDouble(record.get("faelle_covid_aktuell")) * 100_000. / populationCntOfficialKoelln;
-// } catch (NumberFormatException ignored) {
-//
-// }
-//
-// reportedBedsICU.put(day, incidence);
-// }
-// }
-//
-//
-// //https://www.dkgev.de/dkg/coronavirus-fakten-und-infos/aktuelle-bettenbelegung/
+ rkiHospIncidenceAdj.put(day, incidenceAdj);
+ }
+ }
+
+ Int2IntMap reportedIcuCases = new Int2IntAVLTreeMap();
+
+ try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/Fallzahlen/DIVI/nrw-divi-processed-ICUincidence-until20220504.csv")),
+ CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
+
+ for (CSVRecord record : parser) {
+ String dateStr = record.get("date").split("T")[0];
+ LocalDate date = LocalDate.parse(dateStr);
+ int day = (int) startDate.until(date, ChronoUnit.DAYS);
+
+ int cases = 0;
+ try {
+ cases = Integer.parseInt(record.get("erstaufnahmen"));
+ } catch (NumberFormatException ignored) {
+
+ }
+
+ reportedIcuCases.put(day, cases);
+ }
+ }
+
+
+ Int2DoubleMap reportedIcuIncidence = new Int2DoubleAVLTreeMap();
+ for (Integer day : reportedIcuCases.keySet()) {
+ // calculates Incidence - 7day hospitalizations per 100,000 residents
+
+ double xxx = HospitalNumbersFromEvents.getWeeklyHospitalizations(reportedIcuCases, day) * 100_000. / populationCntOfficialNrw;
+ reportedIcuIncidence.put((int) day, xxx);
+
+ }
+
+ Int2DoubleMap hospIncidenceKoeln = new Int2DoubleAVLTreeMap();
+ try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/hospital-cases/cologne/KoelnHospIncidence.csv")),
+ CSVFormat.DEFAULT.withDelimiter(';').withFirstRecordAsHeader())) {
+
+ for (CSVRecord record : parser) {
+ String dateStr = record.get("date").split("T")[0];
+ LocalDate date = LocalDate.parse(dateStr);
+ int day = (int) startDate.until(date, ChronoUnit.DAYS);
+
+ double incidence;
+ try {
+ incidence = Double.parseDouble(record.get("7-Tage-KH-Inz-Koelln")) * 2 ; //TODO
+
+ } catch (NumberFormatException e) {
+ incidence = 0.;
+ }
+
+ hospIncidenceKoeln.put(day, incidence);
+ }
+ }
+
+ // read rki data and add to columns
+ // pink plot from covid-sim: general beds
+ // https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/episim/original-data/hospital-cases/cologne/KoelnAllgemeinpatienten.csv (pinke Linie)
+ Int2DoubleMap reportedBeds = new Int2DoubleAVLTreeMap();
+ Int2DoubleMap reportedBedsAdj = new Int2DoubleAVLTreeMap();
+ try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/hospital-cases/cologne/KoelnAllgemeinpatienten.csv")),
+ CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
+
+ for (CSVRecord record : parser) {
+ String dateStr = record.get("date").split("T")[0];
+ LocalDate date = LocalDate.parse(dateStr);
+ int day = (int) startDate.until(date, ChronoUnit.DAYS);
+
+ double incidence;
+ try {
+ incidence = Double.parseDouble(record.get("allgemeinpatienten")) * 100_000. / populationCntOfficialKoelln;
+ } catch (NumberFormatException e) {
+ incidence = 0.;
+ }
+
+ reportedBeds.put(day, incidence);
+
+
+
+ double incidenceAdj;
+ if (date.isBefore(LocalDate.of(2020, 12, 10))) {
+ incidenceAdj = incidence;
+ } else if (date.isBefore(LocalDate.of(2021, 1, 11))) {
+ incidenceAdj = 23. / 16. * incidence;
+ } else if (date.isBefore(LocalDate.of(2021, 3, 22))) {
+ incidenceAdj = 8. / 6. * incidence;
+ } else if (date.isBefore(LocalDate.of(2021, 5, 3))) {
+ incidenceAdj = 15./11. * incidence;
+ } else if (date.isBefore(LocalDate.of(2021, 11, 8))) {
+ incidenceAdj = incidence;
+ } else if (date.isBefore(LocalDate.of(2021, 12, 6))) {
+ incidenceAdj = 16. / 13. * incidence;
+ } else if (date.isBefore(LocalDate.of(2022, 1, 24))) {
+ incidenceAdj = incidence;
+ } else {
+ incidenceAdj = 11./14 * incidence;
+ }
+ reportedBedsAdj.put(day, incidenceAdj);
+ }
+ }
+
+
+ //green plot from covid-sim (Ich denke, das ist die Spalte "faelle_covid_aktuell", aber ich bin nicht ganz sicher.)
+ //https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/episim/original-data/Fallzahlen/DIVI/cologne-divi-processed.csv (grüne Linie)
+ Int2DoubleMap reportedBedsICU = new Int2DoubleAVLTreeMap();
+ try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/Fallzahlen/DIVI/cologne-divi-processed.csv")),
+ CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
+
+ for (CSVRecord record : parser) {
+ String dateStr = record.get("date").split("T")[0];
+ LocalDate date = LocalDate.parse(dateStr);
+ int day = (int) startDate.until(date, ChronoUnit.DAYS);
+
+ double incidence = 0.;
+ try {
+ incidence = Double.parseDouble(record.get("faelle_covid_aktuell")) * 100_000. / populationCntOfficialKoelln;
+ } catch (NumberFormatException ignored) {
+
+ }
+
+ reportedBedsICU.put(day, incidence);
+ }
+ }
+
+
+ //https://www.dkgev.de/dkg/coronavirus-fakten-und-infos/aktuelle-bettenbelegung/
// Int2DoubleMap reportedBedsNrw = new Int2DoubleAVLTreeMap();
// Int2DoubleMap reportedBedsIcuNrw = new Int2DoubleAVLTreeMap();
// try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("/Users/jakob/Downloads/Covid_csvgesamt(2).csv")),
@@ -272,208 +314,208 @@
//
// }
// }
-//
-//
-// // https://datawrapper.dwcdn.net/sjUZF/334/
-// Int2DoubleMap reportedBedsNrw2 = new Int2DoubleAVLTreeMap();
-// Int2DoubleMap reportedBedsIcuNrw2 = new Int2DoubleAVLTreeMap();
-// try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/hospital-cases/cologne/nrwBettBelegung.csv")),
-// CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
-//
-// for (CSVRecord record : parser) {
-//
-//
-// String dateStr = record.get("Datum");
-// LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("d.M.yyyy"));
-// int day = (int) startDate.until(date, ChronoUnit.DAYS);
-//
-// try {
-// double incidence = Double.parseDouble(record.get("Stationär")) * 100_000. / populationCntOfficialNrw;
-// reportedBedsNrw2.put(day, incidence);
-// } catch (NumberFormatException ignored) {
-// }
-//
-// try {
-// double incidence = Double.parseDouble(record.get("Patienten auf der
Intensivstation")) * 100_000. / populationCntOfficialNrw;
-// reportedBedsIcuNrw2.put(day, incidence);
-// } catch (NumberFormatException ignored) {
-// }
-//
-//
-// }
-// }
-//
-//
-// // Produce TSV w/ aggregated data as well as all rki numbers
-// try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(output.resolve("post.hospital.agg" + outputAppendix + ".tsv")), CSVFormat.DEFAULT.withDelimiter('\t'))) {
-//
-// printer.printRecord(DAY, DATE, INTAKES_HOSP, INTAKES_ICU, OCCUPANCY_HOSP, OCCUPANCY_ICU, "rkiIncidence", "rkiHospRate", "rkiCriticalRate"); //"hospNoImmunity", "hospBaseImmunity", "hospBoosted", "incNoImmunity", "incBaseImmunity", "incBoosted");
-//
-// double maxIteration = Double.max(Double.max(intakeHosp.lastIntKey(), intakeIcu.lastIntKey()), Double.max(occupancyHosp.lastIntKey(), occupancyIcu.lastIntKey()));
-//
-// for (int day = 0; day <= maxIteration; day++) {
-// LocalDate date = startDate.plusDays(day);
-// printer.printRecord(
-// day,
-// date,
-// intakeHosp.get(day),
-// intakeIcu.get(day),
-// occupancyHosp.get(day),
-// occupancyIcu.get(day),
-// rkiHospIncidence.get(day),
-// reportedBeds.get(day),
-// reportedBedsICU.get(day)
-//// hospNoImmunity.get(day),
-//// hospBaseImmunity.get(day),
-//// hospBoosted.get(day),
-//// incNoImmunity.get(day),
-//// incBaseImmunity.get(day),
-//// incBoosted.get(day)
-// );
-// }
-// }
-//
-// // PLOT 1: People admitted to hospital
-// {
-// IntColumn records = IntColumn.create("day");
-// DateColumn recordsDate = DateColumn.create("date");
-// DoubleColumn values = DoubleColumn.create("hospitalizations");
-// StringColumn groupings = StringColumn.create("scenario");
-//
-// // model: intakeHosp
-// for (Int2DoubleMap.Entry entry : intakeHosp.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-// values.append(intakeHosp.getOrDefault(day, Double.NaN));
-// groupings.append("model: intakeHosp");
-// }
-//
-// // model: intakeIcu
-// for (Int2DoubleMap.Entry entry : intakeIcu.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-// values.append(intakeIcu.getOrDefault(day, Double.NaN));
-// groupings.append("model: intakeICU");
-// }
-//
-//
-// for (Int2DoubleMap.Entry entry : rkiHospIncidence.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-// final double value = rkiHospIncidence.getOrDefault(day, Double.NaN);
-// if (Double.isNaN(value)) {
-// values.appendMissing();
-// } else {
-// values.append(value);
-// }
-// groupings.append("reported: intakeHosp (rki, nrw adjusted)");
-// }
-//
-// for (Int2DoubleMap.Entry entry : rkiHospIncidenceAdj.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-// final double value = rkiHospIncidenceAdj.getOrDefault(day, Double.NaN);
-// if (Double.isNaN(value)) {
-// values.appendMissing();
-// } else {
-// values.append(value);
-// }
-// groupings.append("reported: intakeHosp (rki, nrw adjusted, SARI)");
-// }
-//
-// for (Int2DoubleMap.Entry entry : hospIncidenceKoeln.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-// final double value = hospIncidenceKoeln.getOrDefault(day, Double.NaN);
-// if (Double.isNaN(value)) {
-// values.appendMissing();
-// } else {
-// values.append(value);
-// }
-// groupings.append("reported: intakeHosp (köln)");
-// }
-//
-// for (Int2DoubleMap.Entry entry : reportedIcuIncidence.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-// final double value = reportedIcuIncidence.getOrDefault(day, Double.NaN);
-// if (Double.isNaN(value)) {
-// values.appendMissing();
-// } else {
-// values.append(value);
-// }
-// groupings.append("reported: intakeIcu (divi, nrw)");
-// }
-//
-//
-// producePlot(recordsDate, values, groupings, "", "7-Tage Hospitalisierungsinzidenz", "HospIncidence" + outputAppendix + ".html");
-// }
-//
-//
-// // PLOT 2: People taking up beds in hospital (regular and ICU)
-// {
-// IntColumn records = IntColumn.create("day");
-// DateColumn recordsDate = DateColumn.create("date");
-// DoubleColumn values = DoubleColumn.create("hospitalizations");
-// StringColumn groupings = StringColumn.create("scenario");
-//
-//
-// for (Int2DoubleMap.Entry entry : occupancyHosp.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-//
-// values.append(occupancyHosp.get(day));
-// groupings.append("generalBeds");
-// }
-//
-// for (Int2DoubleMap.Entry entry : occupancyIcu.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-//
-// values.append(occupancyIcu.get(day));
-// groupings.append("ICUBeds");
-// }
-//
-//
-// for (Int2DoubleMap.Entry entry : reportedBeds.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-//
-// values.append(entry.getDoubleValue());
-// groupings.append("Reported: General Beds");
-//
-// }
-//
-// for (Int2DoubleMap.Entry entry : reportedBedsAdj.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-//
-// values.append(entry.getDoubleValue());
-// groupings.append("Reported: General Beds (SARI)");
-// }
-//
-//
-// for (Int2DoubleMap.Entry entry : reportedBedsICU.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-//
-// values.append(entry.getDoubleValue());
-// groupings.append("Reported: ICU Beds");
-//
-// }
-//
-//
+
+
+ // https://datawrapper.dwcdn.net/sjUZF/334/
+ Int2DoubleMap reportedBedsNrw2 = new Int2DoubleAVLTreeMap();
+ Int2DoubleMap reportedBedsIcuNrw2 = new Int2DoubleAVLTreeMap();
+ try (CSVParser parser = new CSVParser(Files.newBufferedReader(Path.of("../public-svn/matsim/scenarios/countries/de/episim/original-data/hospital-cases/cologne/nrwBettBelegung.csv")),
+ CSVFormat.DEFAULT.withDelimiter(',').withFirstRecordAsHeader())) {
+
+ for (CSVRecord record : parser) {
+
+
+ String dateStr = record.get("Datum");
+ LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("d.M.yyyy"));
+ int day = (int) startDate.until(date, ChronoUnit.DAYS);
+
+ try {
+ double incidence = Double.parseDouble(record.get("Stationär")) * 100_000. / populationCntOfficialNrw;
+ reportedBedsNrw2.put(day, incidence);
+ } catch (NumberFormatException ignored) {
+ }
+
+ try {
+ double incidence = Double.parseDouble(record.get("Patienten auf der
Intensivstation")) * 100_000. / populationCntOfficialNrw;
+ reportedBedsIcuNrw2.put(day, incidence);
+ } catch (NumberFormatException ignored) {
+ }
+
+
+ }
+ }
+
+
+ // Produce TSV w/ aggregated data as well as all rki numbers
+ try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(output.resolve("post.hospital.agg.tsv")), CSVFormat.DEFAULT.withDelimiter('\t'))) {
+
+ printer.printRecord(DAY, DATE, INTAKES_HOSP, INTAKES_ICU, OCCUPANCY_HOSP, OCCUPANCY_ICU, "rkiIncidence", "rkiHospRate", "rkiCriticalRate"); //"hospNoImmunity", "hospBaseImmunity", "hospBoosted", "incNoImmunity", "incBaseImmunity", "incBoosted");
+
+ double maxIteration = Double.max(Double.max(intakeHosp.lastIntKey(), intakeIcu.lastIntKey()), Double.max(occupancyHosp.lastIntKey(), occupancyIcu.lastIntKey()));
+
+ for (int day = 0; day <= maxIteration; day++) {
+ LocalDate date = startDate.plusDays(day);
+ printer.printRecord(
+ day,
+ date,
+ intakeHosp.get(day),
+ intakeIcu.get(day),
+ occupancyHosp.get(day),
+ occupancyIcu.get(day),
+ rkiHospIncidence.get(day),
+ reportedBeds.get(day),
+ reportedBedsICU.get(day)
+// hospNoImmunity.get(day),
+// hospBaseImmunity.get(day),
+// hospBoosted.get(day),
+// incNoImmunity.get(day),
+// incBaseImmunity.get(day),
+// incBoosted.get(day)
+ );
+ }
+ }
+
+ // PLOT 1: People admitted to hospital
+ {
+ IntColumn records = IntColumn.create("day");
+ DateColumn recordsDate = DateColumn.create("date");
+ DoubleColumn values = DoubleColumn.create("hospitalizations");
+ StringColumn groupings = StringColumn.create("scenario");
+
+ // model: intakeHosp
+ for (Int2DoubleMap.Entry entry : intakeHosp.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+ values.append(intakeHosp.getOrDefault(day, Double.NaN));
+ groupings.append("model: intakeHosp");
+ }
+
+ // model: intakeIcu
+ for (Int2DoubleMap.Entry entry : intakeIcu.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+ values.append(intakeIcu.getOrDefault(day, Double.NaN));
+ groupings.append("model: intakeICU");
+ }
+
+
+ for (Int2DoubleMap.Entry entry : rkiHospIncidence.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+ final double value = rkiHospIncidence.getOrDefault(day, Double.NaN);
+ if (Double.isNaN(value)) {
+ values.appendMissing();
+ } else {
+ values.append(value);
+ }
+ groupings.append("reported: intakeHosp (rki, nrw adjusted) WITH Covid");
+ }
+
+ for (Int2DoubleMap.Entry entry : rkiHospIncidenceAdj.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+ final double value = rkiHospIncidenceAdj.getOrDefault(day, Double.NaN);
+ if (Double.isNaN(value)) {
+ values.appendMissing();
+ } else {
+ values.append(value);
+ }
+ groupings.append("reported: intakeHosp (rki, nrw adjusted) FROM Covid");
+ }
+
+ for (Int2DoubleMap.Entry entry : hospIncidenceKoeln.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+ final double value = hospIncidenceKoeln.getOrDefault(day, Double.NaN);
+ if (Double.isNaN(value)) {
+ values.appendMissing();
+ } else {
+ values.append(value);
+ }
+ groupings.append("reported: intakeHosp (köln)");
+ }
+
+ for (Int2DoubleMap.Entry entry : reportedIcuIncidence.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+ final double value = reportedIcuIncidence.getOrDefault(day, Double.NaN);
+ if (Double.isNaN(value)) {
+ values.appendMissing();
+ } else {
+ values.append(value);
+ }
+ groupings.append("reported: intakeIcu (divi, nrw)");
+ }
+
+
+ producePlot(recordsDate, values, groupings, "", "7-Tage Hospitalisierungsinzidenz", "HospIncidence" + outputAppendix + ".html", output);
+ }
+
+
+ // PLOT 2: People taking up beds in hospital (regular and ICU)
+ {
+ IntColumn records = IntColumn.create("day");
+ DateColumn recordsDate = DateColumn.create("date");
+ DoubleColumn values = DoubleColumn.create("hospitalizations");
+ StringColumn groupings = StringColumn.create("scenario");
+
+
+ for (Int2DoubleMap.Entry entry : occupancyHosp.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+
+ values.append(occupancyHosp.get(day));
+ groupings.append("generalBeds");
+ }
+
+ for (Int2DoubleMap.Entry entry : occupancyIcu.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+
+ values.append(occupancyIcu.get(day));
+ groupings.append("ICUBeds");
+ }
+
+
+ for (Int2DoubleMap.Entry entry : reportedBeds.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+
+ values.append(entry.getDoubleValue());
+ groupings.append("Reported: General Beds");
+
+ }
+
+ for (Int2DoubleMap.Entry entry : reportedBedsAdj.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+
+ values.append(entry.getDoubleValue());
+ groupings.append("Reported: General Beds (SARI)");
+ }
+
+
+ for (Int2DoubleMap.Entry entry : reportedBedsICU.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+
+ values.append(entry.getDoubleValue());
+ groupings.append("Reported: ICU Beds");
+
+ }
+
+
// for (Int2DoubleMap.Entry entry : reportedBedsNrw.int2DoubleEntrySet()) {
// int day = entry.getIntKey();
// records.append(day);
@@ -483,8 +525,8 @@
// groupings.append("Reported: General Beds (NRW)");
//
// }
-//
-//
+
+
// for (Int2DoubleMap.Entry entry : reportedBedsIcuNrw.int2DoubleEntrySet()) {
// int day = entry.getIntKey();
// records.append(day);
@@ -494,68 +536,68 @@
// groupings.append("Reported: ICU Beds (NRW)");
//
// }
-//
-// for (Int2DoubleMap.Entry entry : reportedBedsNrw2.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-//
-// values.append(entry.getDoubleValue());
-// groupings.append("Reported: General Beds (NRW2)");
-//
-// }
-//
-// for (Int2DoubleMap.Entry entry : reportedBedsIcuNrw2.int2DoubleEntrySet()) {
-// int day = entry.getIntKey();
-// records.append(day);
-// recordsDate.append(startDate.plusDays(day));
-//
-// values.append(entry.getDoubleValue());
-// groupings.append("Reported: ICU Beds (NRW2)");
-//
-// }
-//
-//
-//
-// // Make plot
-// producePlot(recordsDate, values, groupings, "Filled Beds", "Beds Filled / 100k Population", "FilledBeds" + outputAppendix + ".html");
-// }
-//
-//
-// }
-//
-// private static void producePlot(DateColumn records, DoubleColumn values, StringColumn groupings, String title, String yAxisTitle, String filename) {
-// // Make plot
-// Table table = Table.create(title);
-// table.addColumns(records);
-// table.addColumns(values);
-// table.addColumns(groupings);
-//
-// TableSliceGroup tables = table.splitOn(table.categoricalColumn("scenario"));
-//
-// Axis xAxis = Axis.builder().title("Datum").build();
-// Axis yAxis = Axis.builder().range(0., 20.)
-// // .type(Axis.Type.LOG)
-// .title(yAxisTitle).build();
-//
-// Layout layout = Layout.builder(title).xAxis(xAxis).yAxis(yAxis).showLegend(true).height(500).width(1000).build();
-//
-// ScatterTrace[] traces = new ScatterTrace[tables.size()];
-// for (int i = 0; i < tables.size(); i++) {
-// List tableList = tables.asTableList();
-// traces[i] = ScatterTrace.builder(tableList.get(i).dateColumn("date"), tableList.get(i).numberColumn("hospitalizations"))
-// .showLegend(true)
-// .name(tableList.get(i).name())
-// .mode(ScatterTrace.Mode.LINE)
-// .build();
-// }
-// var figure = new Figure(layout, traces);
-//
-// try (Writer writer = new OutputStreamWriter(new FileOutputStream(output.resolve(filename).toString()), StandardCharsets.UTF_8)) {
-// writer.write(Page.pageBuilder(figure, "target").build().asJavascript());
-// } catch (IOException e) {
-// throw new UncheckedIOException(e);
-// }
-// }
-//
-//}
+
+ for (Int2DoubleMap.Entry entry : reportedBedsNrw2.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+
+ values.append(entry.getDoubleValue());
+ groupings.append("Reported: General Beds (NRW2)");
+
+ }
+
+ for (Int2DoubleMap.Entry entry : reportedBedsIcuNrw2.int2DoubleEntrySet()) {
+ int day = entry.getIntKey();
+ records.append(day);
+ recordsDate.append(startDate.plusDays(day));
+
+ values.append(entry.getDoubleValue());
+ groupings.append("Reported: ICU Beds (NRW2)");
+
+ }
+
+
+
+ // Make plot
+ producePlot(recordsDate, values, groupings, "Filled Beds", "Beds Filled / 100k Population", "FilledBeds" + outputAppendix + ".html", output);
+ }
+
+
+ }
+
+ private static void producePlot(DateColumn records, DoubleColumn values, StringColumn groupings, String title, String yAxisTitle, String filename, Path output) {
+ // Make plot
+ Table table = Table.create(title);
+ table.addColumns(records);
+ table.addColumns(values);
+ table.addColumns(groupings);
+
+ TableSliceGroup tables = table.splitOn(table.categoricalColumn("scenario"));
+
+ Axis xAxis = Axis.builder().title("Datum").build();
+ Axis yAxis = Axis.builder().range(0., 20.)
+ // .type(Axis.Type.LOG)
+ .title(yAxisTitle).build();
+
+ Layout layout = Layout.builder(title).xAxis(xAxis).yAxis(yAxis).showLegend(true).height(500).width(1000).build();
+
+ ScatterTrace[] traces = new ScatterTrace[tables.size()];
+ for (int i = 0; i < tables.size(); i++) {
+ List tableList = tables.asTableList();
+ traces[i] = ScatterTrace.builder(tableList.get(i).dateColumn("date"), tableList.get(i).numberColumn("hospitalizations"))
+ .showLegend(true)
+ .name(tableList.get(i).name())
+ .mode(ScatterTrace.Mode.LINE)
+ .build();
+ }
+ var figure = new Figure(layout, traces);
+
+ try (Writer writer = new OutputStreamWriter(new FileOutputStream(output.resolve(filename).toString()), StandardCharsets.UTF_8)) {
+ writer.write(Page.pageBuilder(figure, "target").build().asJavascript());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+}
diff --git a/src/main/java/org/matsim/episim/analysis/InicidencePerStrain.java b/src/main/java/org/matsim/episim/analysis/InicidencePerStrain.java
index 1e99c72ec..1ac629133 100644
--- a/src/main/java/org/matsim/episim/analysis/InicidencePerStrain.java
+++ b/src/main/java/org/matsim/episim/analysis/InicidencePerStrain.java
@@ -25,26 +25,15 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
-import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.Scenario;
-import org.matsim.api.core.v01.events.ActivityStartEvent;
-import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.Population;
-import org.matsim.core.api.experimental.events.EventsManager;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
-import org.matsim.core.events.EventsUtils;
-import org.matsim.core.events.MatsimEventsReader;
import org.matsim.core.scenario.ScenarioUtils;
-import org.matsim.core.utils.io.UncheckedIOException;
-import org.matsim.episim.EpisimUtils;
import org.matsim.episim.EpisimPerson.DiseaseStatus;
import org.matsim.episim.events.*;
-import org.matsim.episim.model.VaccinationType;
-import org.matsim.episim.model.VirusStrain;
import org.matsim.run.AnalysisCommand;
-import org.matsim.run.modules.AbstractSnzScenario2020;
import org.matsim.utils.objectattributes.attributable.Attributes;
import picocli.CommandLine;
@@ -54,11 +43,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
-import java.time.temporal.ChronoUnit;
import java.util.*;
-import java.util.Map.Entry;
import java.util.concurrent.Callable;
-import java.util.stream.Collectors;
/**
@@ -140,7 +126,7 @@ private void calcValues(Path scenario) throws IOException {
Handler handler = new Handler(population, startDate, symptoms, seriouslySick);
- AnalysisCommand.forEachEvent(scenario, s -> {}, handler);
+ AnalysisCommand.forEachEvent(scenario, s -> {}, false, handler);
int persons = 0;
for (Person p : population.getPersons().values()) {
diff --git a/src/main/java/org/matsim/episim/analysis/REAnalyzeTimelineOfEvents.java b/src/main/java/org/matsim/episim/analysis/REAnalyzeTimelineOfEvents.java
index baf2bc6d1..3a833cdf1 100644
--- a/src/main/java/org/matsim/episim/analysis/REAnalyzeTimelineOfEvents.java
+++ b/src/main/java/org/matsim/episim/analysis/REAnalyzeTimelineOfEvents.java
@@ -1,88 +1,88 @@
-package org.matsim.episim.analysis;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.matsim.api.core.v01.events.ActivityEndEvent;
-import org.matsim.api.core.v01.events.handler.ActivityEndEventHandler;
-import org.matsim.api.core.v01.population.Population;
-import org.matsim.core.api.experimental.events.EventsManager;
-import org.matsim.core.events.EventsUtils;
-import org.matsim.core.events.MatsimEventsReader;
-import org.matsim.core.population.PopulationUtils;
-
-public class REAnalyzeTimelineOfEvents {
-
- private final static Map> mapOfActivityEnds = new HashMap<>();
- private static int numberEndAct = 0;
- private static Population population;
-
- public static void main(String[] args) {
-// String inputFileEvents = "../shared-svn/projects/episim/matsim-files/snz/BerlinV2/episim-input/be_2020-week_snz_episim_events_wt_25pt_split.xml.gz";
- String inputFileEvents = "../shared-svn/projects/episim/matsim-files/snz/BerlinV2/episim-input/be_2020-week_snz_episim_events_sa_25pt_split.xml.gz";
-// String inputFileEvents = "../shared-svn/projects/episim/matsim-files/snz/BerlinV2/episim-input/be_2020-week_snz_episim_events_so_25pt_split.xml.gz";
- String inputFilePop = "../shared-svn/projects/episim/matsim-files/snz/BerlinV2/episim-input/be_2020-week_snz_entirePopulation_emptyPlans_withDistricts_25pt_split.xml.gz";
-
- population = PopulationUtils.readPopulation(inputFilePop);
-
- EventsManager events = EventsUtils.createEventsManager();
-
- REActivityTimelinenEventHandler reActivityDurationEventHandler = new REActivityTimelinenEventHandler();
-
- events.addHandler(reActivityDurationEventHandler);
-
- MatsimEventsReader reader = new MatsimEventsReader(events);
-
- reader.readFile(inputFileEvents);
-
- for (int i = 0; i < Types.values().length; i++) {
- System.out.print(Types.values()[i].toString() + ";");
- }
-
- for (Integer hours = 0; hours < 30; hours++) {
- System.out.println();
- System.out.print(hours + ";");
- for (int i = 0; i < Types.values().length; i++) {
-
- String actType = Types.values()[i].toString();
- if (mapOfActivityEnds.get(actType).containsKey(hours))
- System.out.print(mapOfActivityEnds.get(actType).get(hours) * 4 + ";");
- else
- System.out.print(0 + ";");
- }
- System.out.println();
- }
- System.out.println("Gesamt: " + numberEndAct * 4);
-
- }
-
- private static class REActivityTimelinenEventHandler implements ActivityEndEventHandler {
-
- @Override
- public void handleEvent(ActivityEndEvent event) {
-
- if (population.getPersons().get(event.getPersonId()).getAttributes().getAttribute("district") != null
- && population.getPersons().get(event.getPersonId()).getAttributes().getAttribute("district")
- .toString().equals("Berlin")) {
- numberEndAct++;
- Integer beginningHour = Integer.valueOf((int) Math.floor(event.getTime() / 3600));
- if (mapOfActivityEnds.containsKey(event.getActType()))
- if (mapOfActivityEnds.get(event.getActType()).containsKey(beginningHour))
- mapOfActivityEnds.get(event.getActType()).put(beginningHour,
- mapOfActivityEnds.get(event.getActType()).get(beginningHour) + 1);
- else {
- mapOfActivityEnds.get(event.getActType()).put(beginningHour, 1);
- }
- else {
- mapOfActivityEnds.put(event.getActType(), new HashMap<>());
- mapOfActivityEnds.get(event.getActType()).put(beginningHour, 1);
- }
- }
- }
- }
-
- private enum Types {
- educ_kiga, business, errands, home, leisure, shop_daily, shop_other, visit, work, educ_higher, educ_tertiary,
- educ_other, educ_primary, educ_secondary
- }
-}
+package org.matsim.episim.analysis;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.matsim.api.core.v01.events.ActivityEndEvent;
+import org.matsim.api.core.v01.events.handler.ActivityEndEventHandler;
+import org.matsim.api.core.v01.population.Population;
+import org.matsim.core.api.experimental.events.EventsManager;
+import org.matsim.core.events.EventsUtils;
+import org.matsim.core.events.MatsimEventsReader;
+import org.matsim.core.population.PopulationUtils;
+
+public class REAnalyzeTimelineOfEvents {
+
+ private final static Map> mapOfActivityEnds = new HashMap<>();
+ private static int numberEndAct = 0;
+ private static Population population;
+
+ public static void main(String[] args) {
+// String inputFileEvents = "../shared-svn/projects/episim/matsim-files/snz/BerlinV2/episim-input/be_2020-week_snz_episim_events_wt_25pt_split.xml.gz";
+ String inputFileEvents = "../shared-svn/projects/episim/matsim-files/snz/BerlinV2/episim-input/be_2020-week_snz_episim_events_sa_25pt_split.xml.gz";
+// String inputFileEvents = "../shared-svn/projects/episim/matsim-files/snz/BerlinV2/episim-input/be_2020-week_snz_episim_events_so_25pt_split.xml.gz";
+ String inputFilePop = "../shared-svn/projects/episim/matsim-files/snz/BerlinV2/episim-input/be_2020-week_snz_entirePopulation_emptyPlans_withDistricts_25pt_split.xml.gz";
+
+ population = PopulationUtils.readPopulation(inputFilePop);
+
+ EventsManager events = EventsUtils.createEventsManager();
+
+ REActivityTimelinenEventHandler reActivityDurationEventHandler = new REActivityTimelinenEventHandler();
+
+ events.addHandler(reActivityDurationEventHandler);
+
+ MatsimEventsReader reader = new MatsimEventsReader(events);
+
+ reader.readFile(inputFileEvents);
+
+ for (int i = 0; i < Types.values().length; i++) {
+ System.out.print(Types.values()[i].toString() + ";");
+ }
+
+ for (Integer hours = 0; hours < 30; hours++) {
+ System.out.println();
+ System.out.print(hours + ";");
+ for (int i = 0; i < Types.values().length; i++) {
+
+ String actType = Types.values()[i].toString();
+ if (mapOfActivityEnds.get(actType).containsKey(hours))
+ System.out.print(mapOfActivityEnds.get(actType).get(hours) * 4 + ";");
+ else
+ System.out.print(0 + ";");
+ }
+ System.out.println();
+ }
+ System.out.println("Gesamt: " + numberEndAct * 4);
+
+ }
+
+ private static class REActivityTimelinenEventHandler implements ActivityEndEventHandler {
+
+ @Override
+ public void handleEvent(ActivityEndEvent event) {
+
+ if (population.getPersons().get(event.getPersonId()).getAttributes().getAttribute("district") != null
+ && population.getPersons().get(event.getPersonId()).getAttributes().getAttribute("district")
+ .toString().equals("Berlin")) {
+ numberEndAct++;
+ Integer beginningHour = Integer.valueOf((int) Math.floor(event.getTime() / 3600));
+ if (mapOfActivityEnds.containsKey(event.getActType()))
+ if (mapOfActivityEnds.get(event.getActType()).containsKey(beginningHour))
+ mapOfActivityEnds.get(event.getActType()).put(beginningHour,
+ mapOfActivityEnds.get(event.getActType()).get(beginningHour) + 1);
+ else {
+ mapOfActivityEnds.get(event.getActType()).put(beginningHour, 1);
+ }
+ else {
+ mapOfActivityEnds.put(event.getActType(), new HashMap<>());
+ mapOfActivityEnds.get(event.getActType()).put(beginningHour, 1);
+ }
+ }
+ }
+ }
+
+ private enum Types {
+ educ_kiga, business, errands, home, leisure, leisPrivate, leisPublic, shop_daily, shop_other, visit, work, educ_higher, educ_tertiary,
+ educ_other, educ_primary, educ_secondary
+ }
+}
diff --git a/src/main/java/org/matsim/episim/analysis/RValuesFromEvents.java b/src/main/java/org/matsim/episim/analysis/RValuesFromEvents.java
index 6de4fffda..c42f2fb60 100644
--- a/src/main/java/org/matsim/episim/analysis/RValuesFromEvents.java
+++ b/src/main/java/org/matsim/episim/analysis/RValuesFromEvents.java
@@ -45,7 +45,6 @@
import java.time.LocalDate;
import java.util.*;
import java.util.Map.Entry;
-import java.util.concurrent.Callable;
import java.util.stream.Collectors;
@@ -66,7 +65,7 @@ public class RValuesFromEvents implements OutputAnalysis {
* Activity types used by this analysis.
*/
private static final List ACTIVITY_TYPES = List.of(
- "home", "leisure", "schools", "day care", "university", "work&business", "pt", "other"
+ "home", "leisure", "leisPrivate", "leisPublic", "schools", "day care", "university", "work&business", "pt", "other"
);
@CommandLine.Option(names = "--output", defaultValue = "./output/")
@@ -115,7 +114,7 @@ public void analyzeOutput(Path output) throws IOException {
RHandler rHandler = new RHandler();
List eventFiles = AnalysisCommand.forEachEvent(output, s -> {
- }, infHandler, rHandler);
+ }, false, infHandler, rHandler);
BufferedWriter bw = Files.newBufferedWriter(output.resolve(id + "infectionsPerActivity.txt"));
bw.write("day\tdate\tactivity\tinfections\tinfectionsShare\tscenario");
@@ -286,6 +285,8 @@ private static String getActivityType(String infectionType) {
else if (infectionType.endsWith("educ_higher")) activityType = "university";
else if (infectionType.endsWith("educ_kiga")) activityType = "day care";
else if (infectionType.endsWith("leisure")) activityType = "leisure";
+ else if (infectionType.endsWith("leisPublic")) activityType = "leisPublic";
+ else if (infectionType.endsWith("leisPrivate")) activityType = "leisPrivate";
else if (infectionType.endsWith("work") || infectionType.endsWith("business")) activityType = "work&business";
else if (infectionType.endsWith("home")) activityType = "home";
else if (infectionType.startsWith("pt")) activityType = "pt";
diff --git a/src/main/java/org/matsim/episim/analysis/SecondaryAttackRateFromEvents.java b/src/main/java/org/matsim/episim/analysis/SecondaryAttackRateFromEvents.java
new file mode 100644
index 000000000..93a5e2eaf
--- /dev/null
+++ b/src/main/java/org/matsim/episim/analysis/SecondaryAttackRateFromEvents.java
@@ -0,0 +1,257 @@
+/* *********************************************************************** *
+ * project: org.matsim.*
+ * EditRoutesTest.java
+ * *
+ * *********************************************************************** *
+ * *
+ * copyright : (C) 2020 by the members listed in the COPYING, *
+ * LICENSE and WARRANTY file. *
+ * email : info at matsim dot org *
+ * *
+ * *********************************************************************** *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * See also COPYING, LICENSE and WARRANTY file *
+ * *
+ * *********************************************************************** */
+
+package org.matsim.episim.analysis;
+
+import com.google.inject.Inject;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.matsim.api.core.v01.Scenario;
+import org.matsim.api.core.v01.population.Person;
+import org.matsim.api.core.v01.population.Population;
+import org.matsim.core.population.PopulationUtils;
+import org.matsim.episim.EpisimPerson.DiseaseStatus;
+import org.matsim.episim.events.EpisimPersonStatusEvent;
+import org.matsim.episim.events.EpisimPersonStatusEventHandler;
+import org.matsim.run.AnalysisCommand;
+import picocli.CommandLine;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+
+/**
+ * @author jakobrehmann
+ * Calculates secondary attack rate for all runs in given directory
+ * Output is written to secondaryAttackRate.txt in the working directory
+ */
+
+@CommandLine.Command(
+ name = "calculateSecondaryAttackRate",
+ description = "Calculate Secondary Attack Rate"
+)
+public class SecondaryAttackRateFromEvents implements OutputAnalysis {
+
+ private static final Logger log = LogManager.getLogger(SecondaryAttackRateFromEvents.class);
+
+ @CommandLine.Option(names = "--output", defaultValue = "./output/")
+// @CommandLine.Option(names = "--output", defaultValue = "../public-svn/matsim/scenarios/countries/de/episim/battery/jakob/2022-07-22/1-calibration/output")
+ private Path output;
+
+ @CommandLine.Option(names = "--start-date", defaultValue = "2020-02-24")
+ private LocalDate startDate;
+
+ @CommandLine.Option(names = "--input", defaultValue = "/scratch/projects/bzz0020/episim-input")
+// @CommandLine.Option(names = "--input", defaultValue = "../shared-svn/projects/episim/matsim-files/snz/Cologne/episim-input")
+ private String input;
+
+ @CommandLine.Option(names = "--population-file", defaultValue = "/cologne_snz_entirePopulation_emptyPlans_withDistricts_25pt_split.xml.gz")
+ private String populationFile;
+
+
+ @Inject
+ private Scenario scenario;
+
+ private Population population;
+
+
+ public static void main(String[] args) {
+ System.exit(new CommandLine(new SecondaryAttackRateFromEvents()).execute(args));
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ Configurator.setLevel("org.matsim.core.config", Level.WARN);
+ Configurator.setLevel("org.matsim.core.controler", Level.WARN);
+ Configurator.setLevel("org.matsim.core.events", Level.WARN);
+ Configurator.setLevel("org.matsim.core.utils", Level.WARN);
+
+ if (!Files.exists(output)) {
+ log.error("Output path {} does not exist.", output);
+ return 2;
+ }
+
+ population = PopulationUtils.readPopulation(input + populationFile);
+
+ AnalysisCommand.forEachScenario(output, scenario -> {
+ try {
+ analyzeOutput(scenario);
+ } catch (IOException e) {
+ log.error("Failed processing {}", scenario, e);
+ }
+ });
+
+ log.info("Done");
+
+ return 0;
+ }
+
+ @Override
+ public void analyzeOutput(Path output) throws IOException {
+
+ String id = AnalysisCommand.getScenarioPrefix(output);
+
+ if (scenario != null)
+ population = scenario.getPopulation();
+
+
+ Map personToHousehold = new HashMap<>();
+ for (Person person : population.getPersons().values()) {
+ if(person.getAttributes().getAttribute("district").equals("Köln"))
+ personToHousehold.put(person.getId().toString(), person.getAttributes().getAttribute("homeId").toString());
+ }
+
+ Map personCountPerHousehold = personToHousehold.values().stream()
+ .collect(Collectors.groupingBy(Function.identity(),
+ Collectors.counting()));
+
+
+ SecondaryAttackRateHandler hhHandler = new SecondaryAttackRateHandler(personToHousehold);
+
+ List eventFiles = AnalysisCommand.forEachEvent(output, s -> {
+ }, false, hhHandler);
+
+ Map> itToHouseholdToInfections = hhHandler.getItToHouseholdToInfections();
+
+ BufferedWriter bw = Files.newBufferedWriter(output.resolve(id + "secondaryAttackRate.txt"));
+ bw.write("day\tdate\trate");
+
+ int rollingAverage = 3;
+ for (int i = 0 + rollingAverage; i <= eventFiles.size() - rollingAverage; i++) {
+
+ if (startDate.plusDays(i).getDayOfWeek() != DayOfWeek.THURSDAY) {
+ continue;
+ }
+
+ long totalHhInfectionsForWeek = 0;
+ long totalHhMemberCnt = 0;
+ for (int j = i - rollingAverage; j <= i + rollingAverage; j++) {
+
+ if (itToHouseholdToInfections.containsKey(j)) {
+ for (Entry hhToInfections : itToHouseholdToInfections.get(j).entrySet()) {
+ totalHhInfectionsForWeek += hhToInfections.getValue();
+ totalHhMemberCnt = totalHhMemberCnt + personCountPerHousehold.get(hhToInfections.getKey()) - 1;
+ }
+ }
+ }
+ double secondaryAttackRate = (double) totalHhInfectionsForWeek / totalHhMemberCnt;
+ bw.write("\n" + i + "\t" + startDate.plusDays(i).toString() + "\t" + secondaryAttackRate);
+ }
+ bw.close();
+ log.info("Calculated results for scenario {}", output);
+ }
+
+ private static class SecondaryAttackRateHandler implements EpisimPersonStatusEventHandler {
+
+ /**
+ * personID to hh Id
+ */
+ Map personToHousehold;
+
+ /**
+ * keys: all agents who are currently the index agent for their household
+ * values: day at which they became contagious
+ */
+ Map indexPersons = new HashMap<>();
+
+ /**
+ * keys: all households that currently contain an index agent.
+ * values: count of how many agents in index agent's hh are infected before index agent recovers
+ */
+ Map householdToInfections = new HashMap<>();
+
+ /**
+ * This map aggregates all information required to calculate secondary attack rate. Households are
+ * entered here once the index agent recovers, but are backdated to the day they become contagious.
+ * keys: iterations at which index agents become contagious
+ * values: map containing household id and how many house mates were infected
+ */
+ Map> itToHouseholdToInfections = new HashMap<>();
+
+
+ public SecondaryAttackRateHandler(Map personToHousehold) {
+ this.personToHousehold = personToHousehold;
+ }
+
+ public Map> getItToHouseholdToInfections() {
+ return itToHouseholdToInfections;
+ }
+
+ @Override
+ public void handleEvent(EpisimPersonStatusEvent event) {
+
+ int day = (int) (event.getTime() / 86400);
+ String personId = event.getPersonId().toString();
+
+ // if agent does not live in district being evaluated
+ if (!personToHousehold.containsKey(personId)) {
+ return;
+ }
+
+
+ String hhId = personToHousehold.get(personId);
+
+ if (event.getDiseaseStatus() == DiseaseStatus.contagious) {
+ if (indexPersons.containsKey(personId)) {
+ throw new RuntimeException("person was already contagious, but was never removed from indexPersons when recovered");
+ }
+
+ //todo: if they become contagious on the same day, don't count that case?
+ if (householdToInfections.containsKey(hhId) ) {
+ householdToInfections.merge(hhId, 1, Integer::sum);
+ } else {
+ indexPersons.put(personId, day);
+ householdToInfections.put(hhId, 0);
+ }
+ }
+
+ if (event.getDiseaseStatus() == DiseaseStatus.recovered) {
+ if (indexPersons.containsKey(personId)) {
+
+ // update global map with household infections for index agent who has just recovered (back-dated to day contagious)
+ Integer dayContagious = indexPersons.get(personId);
+ itToHouseholdToInfections.putIfAbsent(dayContagious, new HashMap<>());
+ itToHouseholdToInfections.get(dayContagious).put(hhId, householdToInfections.get(hhId));
+
+ // now that hh infections have been saved to global map, remove from temp maps.
+ householdToInfections.remove(hhId);
+ indexPersons.remove(personId);
+
+ }
+ }
+ }
+
+ }
+
+}
+
+
+
+
diff --git a/src/main/java/org/matsim/episim/analysis/VaccinationEffectiveness.java b/src/main/java/org/matsim/episim/analysis/VaccinationEffectiveness.java
index 8c3c6f8b4..f9434418b 100644
--- a/src/main/java/org/matsim/episim/analysis/VaccinationEffectiveness.java
+++ b/src/main/java/org/matsim/episim/analysis/VaccinationEffectiveness.java
@@ -47,7 +47,6 @@
import java.nio.file.Path;
import java.time.LocalDate;
import java.util.*;
- import java.util.concurrent.Callable;
/**
@@ -159,7 +158,7 @@ public void analyzeOutput(Path output) throws IOException {
Handler handler = new Handler(data, startDate);
AnalysisCommand.forEachEvent(output, s -> {
- }, handler);
+ }, false, handler);
int days4aggregation = 14;
@@ -399,7 +398,7 @@ public void analyzeOutput(Path output) throws IOException {
if (vacOmicronPerPeriod.containsKey(i))
omicronInfected = vacOmicronPerPeriod.get(i);
-
+
int omicronBA2Infected = 0;
if (vacOmicronBA2PerPeriod.containsKey(i))
@@ -429,7 +428,7 @@ public void analyzeOutput(Path output) throws IOException {
if (cgOmicronPerPeriod.containsKey(i))
cgOmicronInfected = cgOmicronPerPeriod.get(i);
-
+
int cgOmicronBA2Infected = 0;
if (cgOmicronBA2PerPeriod.containsKey(i))
diff --git a/src/main/java/org/matsim/episim/analysis/VaccinationEffectivenessFromPotentialInfections.java b/src/main/java/org/matsim/episim/analysis/VaccinationEffectivenessFromPotentialInfections.java
index d70d27466..f35cb0d02 100644
--- a/src/main/java/org/matsim/episim/analysis/VaccinationEffectivenessFromPotentialInfections.java
+++ b/src/main/java/org/matsim/episim/analysis/VaccinationEffectivenessFromPotentialInfections.java
@@ -43,7 +43,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
-import java.util.concurrent.Callable;
@CommandLine.Command(
@@ -99,7 +98,7 @@ public void analyzeOutput(Path output) throws IOException {
Handler handler = new Handler();
- AnalysisCommand.forEachEvent(output, s -> {}, handler);
+ AnalysisCommand.forEachEvent(output, s -> {}, false, handler);
// Entries with rarely used vaccines are filtered
List collect = new ArrayList<>(handler.vac.keySet());
diff --git a/src/main/java/org/matsim/episim/events/EpisimEventsReader.java b/src/main/java/org/matsim/episim/events/EpisimEventsReader.java
index 8c6511983..ba09a0948 100644
--- a/src/main/java/org/matsim/episim/events/EpisimEventsReader.java
+++ b/src/main/java/org/matsim/episim/events/EpisimEventsReader.java
@@ -35,6 +35,7 @@
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
+import java.time.LocalDate;
import java.util.Map;
import java.util.Stack;
@@ -54,6 +55,7 @@ public EpisimEventsReader(EventsManager events) {
delegate.addCustomEventMapper(EpisimPersonStatusEvent.EVENT_TYPE, getEpisimPersonStatusEventMapper());
delegate.addCustomEventMapper(EpisimContactEvent.EVENT_TYPE, getEpisimContactEventMapper());
delegate.addCustomEventMapper(EpisimVaccinationEvent.EVENT_TYPE, getEpisimVaccinationEventMapper());
+ delegate.addCustomEventMapper(EpisimStartEvent.EVENT_TYPE, getEpisimStartEventMapper());
}
public void characters(char[] ch, int start, int length) throws SAXException {
@@ -92,8 +94,17 @@ private MatsimEventsReader.CustomEventMapper getEpisimInfectionEventMapper() {
antibodies = Double.parseDouble(attributes.get(EpisimInfectionEvent.ANTIBODIES));
}
+ double maxAntibodies = -1;
+ if (attributes.containsKey(EpisimInfectionEvent.MAX_ANTIBODIES)) {
+ maxAntibodies = Double.parseDouble(attributes.get(EpisimInfectionEvent.MAX_ANTIBODIES));
+ }
+
+ int vaccinationCnt = -1;
+ attr = attributes.get(EpisimInfectionEvent.NUM_VACCINATIONS);
+ if (attr != null)
+ vaccinationCnt = Integer.parseInt(attr);
- return new EpisimInfectionEvent(time, person, infector, container, type, groupSize, virusStrain, probability, antibodies);
+ return new EpisimInfectionEvent(time, person, infector, container, type, groupSize, virusStrain, probability, antibodies, maxAntibodies, vaccinationCnt);
};
}
@@ -121,6 +132,7 @@ private MatsimEventsReader.CustomEventMapper getEpisimPotentialInfectionEventMap
}
return new EpisimPotentialInfectionEvent(time, person, infector, container, type, groupSize, virusStrain, probability, unVacProb, antibodies, rnd);
+
};
}
@@ -137,7 +149,17 @@ private MatsimEventsReader.CustomEventMapper getEpisimInitialInfectionEventMappe
antibodies = Double.parseDouble(attributes.get(EpisimInfectionEvent.ANTIBODIES));
}
- return new EpisimInitialInfectionEvent(time, person,virusStrain, antibodies);
+ double maxAntibodies = -1;
+ if (attributes.containsKey(EpisimInfectionEvent.MAX_ANTIBODIES)) {
+ maxAntibodies = Double.parseDouble(attributes.get(EpisimInfectionEvent.MAX_ANTIBODIES));
+ }
+
+ int vaccinationCnt = -1;
+ String attr = attributes.get(EpisimInfectionEvent.NUM_VACCINATIONS);
+ if (attr != null)
+ vaccinationCnt = Integer.parseInt(attr);
+
+ return new EpisimInitialInfectionEvent(time, person,virusStrain, antibodies, maxAntibodies, vaccinationCnt);
};
}
@@ -182,6 +204,17 @@ private MatsimEventsReader.CustomEventMapper getEpisimVaccinationEventMapper() {
};
}
+ private MatsimEventsReader.CustomEventMapper getEpisimStartEventMapper() {
+ return event -> {
+
+ Map attr = event.getAttributes();
+ return new EpisimStartEvent(
+ LocalDate.parse(attr.get(EpisimStartEvent.START_DATE)),
+ attr.get(EpisimStartEvent.IMMUNIZATION)
+ );
+ };
+ }
+
@Override
public void startTag(String name, Attributes atts, Stack context) {
diff --git a/src/main/java/org/matsim/episim/events/EpisimInfectionEvent.java b/src/main/java/org/matsim/episim/events/EpisimInfectionEvent.java
index 0a1e28e90..74007cbbf 100644
--- a/src/main/java/org/matsim/episim/events/EpisimInfectionEvent.java
+++ b/src/main/java/org/matsim/episim/events/EpisimInfectionEvent.java
@@ -25,6 +25,8 @@ public class EpisimInfectionEvent extends Event implements HasPersonId, Comparab
static final String PROBABILITY = "probability";
static final String GROUP_SIZE = "groupSize";
static final String ANTIBODIES = "antibodies";
+ static final String MAX_ANTIBODIES = "maxAntibodies";
+ static final String NUM_VACCINATIONS = "numVaccinations";
private final Id personId;
private final Id infectorId;
@@ -34,13 +36,16 @@ public class EpisimInfectionEvent extends Event implements HasPersonId, Comparab
private final VirusStrain virusStrain;
private final double probability;
private final double antibodies;
+ private final double maxAntibodies;
+
+ private final int numVaccinations;
/**
* Constructor.
*/
public EpisimInfectionEvent(double time, Id personId, Id infectorId, Id> containerId, String infectionType,
- int groupSize, VirusStrain strain, double probability, double antibodies) {
+ int groupSize, VirusStrain strain, double probability, double antibodies, double maxAntibodies, int numVaccinations) {
super(time);
this.personId = personId;
@@ -51,6 +56,8 @@ public EpisimInfectionEvent(double time, Id personId, Id infecto
this.virusStrain = strain;
this.probability = probability;
this.antibodies = antibodies;
+ this.maxAntibodies = maxAntibodies;
+ this.numVaccinations = numVaccinations;
}
@Override
@@ -103,6 +110,20 @@ public double getAntibodies() {
return antibodies;
}
+ /**
+ * Maximum antibodies ever reached by agent with respect to infecting strain
+ */
+ public double getMaxAntibodies() {
+ return maxAntibodies;
+ }
+
+ /**
+ * Number of vaccinations agent has received at time of infection
+ */
+ public int getNumVaccinations(){
+ return numVaccinations;
+ }
+
@Override
public Map getAttributes() {
Map attr = super.getAttributes();
@@ -114,6 +135,8 @@ public Map getAttributes() {
attr.put(PROBABILITY, Double.toString(probability));
attr.put(VIRUS_STRAIN, virusStrain.toString());
attr.put(ANTIBODIES, Double.toString(antibodies));
+ attr.put(MAX_ANTIBODIES, Double.toString(maxAntibodies));
+ attr.put(NUM_VACCINATIONS, Integer.toString(numVaccinations));
return attr;
}
diff --git a/src/main/java/org/matsim/episim/events/EpisimInitialInfectionEvent.java b/src/main/java/org/matsim/episim/events/EpisimInitialInfectionEvent.java
index 00fe8f89c..c05a6c2c9 100644
--- a/src/main/java/org/matsim/episim/events/EpisimInitialInfectionEvent.java
+++ b/src/main/java/org/matsim/episim/events/EpisimInitialInfectionEvent.java
@@ -14,22 +14,34 @@
*/
public class EpisimInitialInfectionEvent extends Event implements HasPersonId, Comparable {
- static final String EVENT_TYPE = "episimInitialInfection";
+ public static final String EVENT_TYPE = "episimInitialInfection";
private final Id personId;
private final VirusStrain virusStrain;
private final double antibodies;
+ private final double maxAntibodies;
+ private final int numVaccinations;
/**
* Constructor.
*/
- public EpisimInitialInfectionEvent(double time, Id personId, VirusStrain strain, double antibodies) {
+ public EpisimInitialInfectionEvent(double time, Id personId, VirusStrain strain, double antibodies, double maxAntibodies, int numVaccinations) {
+
super(time);
this.personId = personId;
this.virusStrain = strain;
this.antibodies = antibodies;
+ this.maxAntibodies = maxAntibodies;
+ this.numVaccinations = numVaccinations;
+ }
+
+ /**
+ * Return initial infection as "normal" infection event.
+ */
+ public EpisimInfectionEvent asInfectionEvent() {
+ return new EpisimInfectionEvent(getTime(), personId, null, null, null, -1, virusStrain, 0, antibodies, maxAntibodies, numVaccinations);
}
@Override
@@ -51,6 +63,8 @@ public Map getAttributes() {
Map attr = super.getAttributes();
attr.put(EpisimInfectionEvent.VIRUS_STRAIN, virusStrain.toString());
attr.put(EpisimInfectionEvent.ANTIBODIES, Double.toString(antibodies));
+ attr.put(EpisimInfectionEvent.MAX_ANTIBODIES, Double.toString(maxAntibodies));
+ attr.put(EpisimInfectionEvent.NUM_VACCINATIONS, Integer.toString(numVaccinations));
return attr;
}
diff --git a/src/main/java/org/matsim/episim/events/EpisimStartEvent.java b/src/main/java/org/matsim/episim/events/EpisimStartEvent.java
new file mode 100644
index 000000000..ab9c3142c
--- /dev/null
+++ b/src/main/java/org/matsim/episim/events/EpisimStartEvent.java
@@ -0,0 +1,49 @@
+package org.matsim.episim.events;
+
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.events.Event;
+import org.matsim.api.core.v01.population.Person;
+import org.matsim.episim.model.VaccinationType;
+
+import java.time.LocalDate;
+import java.util.Map;
+
+/**
+ * Notifies begin of episim simulation
+ */
+public class EpisimStartEvent extends Event {
+
+ public static final String EVENT_TYPE = "episimStart";
+ public static final String START_DATE = "startDate";
+ public static final String IMMUNIZATION = "immunization";
+
+ private final LocalDate startDate;
+ private final String immunization;
+
+ public EpisimStartEvent(LocalDate startDate, String immunization) {
+ super(0);
+ this.startDate = startDate;
+ this.immunization = immunization;
+ }
+
+ public LocalDate getStartDate() {
+ return startDate;
+ }
+
+ @Override
+ public String getEventType() {
+ return EVENT_TYPE;
+ }
+
+
+
+ @Override
+ public Map getAttributes() {
+ Map attr = super.getAttributes();
+
+ attr.put(START_DATE, startDate.toString());
+ attr.put(IMMUNIZATION, String.valueOf(immunization));
+
+ return attr;
+ }
+}
diff --git a/src/main/java/org/matsim/episim/events/EpisimStartEventHandler.java b/src/main/java/org/matsim/episim/events/EpisimStartEventHandler.java
new file mode 100644
index 000000000..8f8aff7e5
--- /dev/null
+++ b/src/main/java/org/matsim/episim/events/EpisimStartEventHandler.java
@@ -0,0 +1,27 @@
+/* *********************************************************************** *
+ * project: org.matsim.*
+ * *
+ * *********************************************************************** *
+ * *
+ * copyright : (C) 2007 by the members listed in the COPYING, *
+ * LICENSE and WARRANTY file. *
+ * email : info at matsim dot org *
+ * *
+ * *********************************************************************** *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * See also COPYING, LICENSE and WARRANTY file *
+ * *
+ * *********************************************************************** */
+
+package org.matsim.episim.events;
+
+import org.matsim.core.events.handler.EventHandler;
+
+public interface EpisimStartEventHandler extends EventHandler {
+ void handleEvent(EpisimStartEvent event);
+
+}
diff --git a/src/main/java/org/matsim/episim/events/InitialImmunizationHandler.java b/src/main/java/org/matsim/episim/events/InitialImmunizationHandler.java
new file mode 100644
index 000000000..056f90ee3
--- /dev/null
+++ b/src/main/java/org/matsim/episim/events/InitialImmunizationHandler.java
@@ -0,0 +1,100 @@
+package org.matsim.episim.events;
+
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.population.Person;
+import org.matsim.episim.EpisimConfigGroup;
+import org.matsim.episim.EpisimPerson;
+import org.matsim.episim.EpisimUtils;
+import org.matsim.episim.model.AntibodyModel;
+import org.matsim.episim.model.ProgressionModel;
+import org.matsim.episim.model.VirusStrain;
+
+import java.time.temporal.ChronoUnit;
+import java.util.Map;
+import java.util.function.Function;
+
+import static org.matsim.episim.EpisimUtils.DAY;
+
+public final class InitialImmunizationHandler implements Function,
+ EpisimVaccinationEventHandler, EpisimInfectionEventHandler,
+ EpisimInitialInfectionEventHandler, EpisimStartEventHandler {
+
+ private final Map, EpisimPerson> personMap;
+ private final EpisimConfigGroup episimConfig;
+ private final AntibodyModel antibodyModel;
+ private final ProgressionModel progressionModel;
+
+ private Double startTimeOffset = null;
+
+ private int iterationOffset;
+ private boolean continueProcessingEvents = true;
+
+ int maxIterationReachedSoFar = 0;
+
+ public InitialImmunizationHandler(Map, EpisimPerson> personMap, EpisimConfigGroup episimConfig, AntibodyModel antibodyModel, ProgressionModel progressionModel) {
+ this.personMap = personMap;
+ this.episimConfig = episimConfig;
+ this.antibodyModel = antibodyModel;
+ this.progressionModel = progressionModel;
+ }
+
+ @Override
+ public void handleEvent(EpisimStartEvent event) {
+ this.iterationOffset = (int) ChronoUnit.DAYS.between(event.getStartDate(), episimConfig.getStartDate());
+ this.startTimeOffset = this.iterationOffset * DAY;
+ }
+
+ @Override
+ public void handleEvent(EpisimInfectionEvent event) {
+ int currentIteration = (int) (event.getTime() / EpisimUtils.DAY);
+ if (currentIteration >= iterationOffset + 1) { // starts returning when current iteration = 5
+ continueProcessingEvents = false;
+ return;
+ } else if (maxIterationReachedSoFar < currentIteration) {
+ newDay(currentIteration);
+ }
+
+ //TODO why should this be an initial infection?
+ personMap.get(event.getPersonId()).setInitialInfection(event.getTime() - startTimeOffset, event.getVirusStrain());
+ }
+
+ @Override
+ public void handleEvent(EpisimInitialInfectionEvent event) {
+
+ handleEvent(event.asInfectionEvent());
+
+ }
+
+ @Override
+ public void handleEvent(EpisimVaccinationEvent event) {
+ int currentIteration = (int) (event.getTime() / EpisimUtils.DAY);
+ if (currentIteration >= iterationOffset + 1) {
+ continueProcessingEvents = false;
+ return;
+ } else if (maxIterationReachedSoFar < currentIteration) {
+ newDay(currentIteration);
+ }
+
+ personMap.get(event.getPersonId()).setVaccinationStatus(EpisimPerson.VaccinationStatus.yes, event.getVaccinationType(), currentIteration - iterationOffset);
+ }
+
+ public void newDay(int currentIteration) {
+ while (this.maxIterationReachedSoFar < currentIteration) {
+ this.maxIterationReachedSoFar++;
+ for (EpisimPerson person : personMap.values()) {
+ antibodyModel.updateAntibodies(person, this.maxIterationReachedSoFar - this.iterationOffset);
+ progressionModel.updateState(person, this.maxIterationReachedSoFar - this.iterationOffset);
+ }
+ }
+ }
+
+ @Override
+ public Boolean apply(String s) {
+ return continueProcessingEvents;
+ }
+
+ public boolean isContinueProcessingEvents() {
+ return continueProcessingEvents;
+ }
+}
+
diff --git a/src/main/java/org/matsim/episim/model/AbstractContactModel.java b/src/main/java/org/matsim/episim/model/AbstractContactModel.java
index cdf0df3a7..096f3bcaa 100644
--- a/src/main/java/org/matsim/episim/model/AbstractContactModel.java
+++ b/src/main/java/org/matsim/episim/model/AbstractContactModel.java
@@ -72,6 +72,11 @@ public abstract class AbstractContactModel implements ContactModel {
protected DayOfWeek day;
private Map restrictions;
+ /**
+ * Count number of contacts per day.
+ */
+ protected int numContacts = 0;
+
/**
* Curfew compliance valid for the day.
*/
@@ -355,6 +360,11 @@ public void setRestrictionsForIteration(int iteration, Map
this.infectionModel.setIteration(iteration);
this.curfewCompliance = EpisimUtils.findValidEntry(episimConfig.getCurfewCompliance(), 1.0,
episimConfig.getStartDate().plusDays(iteration - 1));
+ this.numContacts = 0;
+ }
+
+ public int getNumContacts() {
+ return numContacts;
}
/**
@@ -388,8 +398,8 @@ protected void infectPerson(EpisimPerson personWrapper, EpisimPerson infector, d
personWrapper.possibleInfection(
new EpisimInfectionEvent(now, personWrapper.getPersonId(), infector.getPersonId(),
- container.getContainerId(), infectionType.toString(), container.getPersons().size(), infector.getVirusStrain(), prob,
- personWrapper.getAntibodies(infector.getVirusStrain()))
+ container.getContainerId(), infectionType.toString(), container.getPersons().size(), infector.getVirusStrain(), prob,
+ personWrapper.getAntibodies(infector.getVirusStrain()), personWrapper.getMaxAntibodies(infector.getVirusStrain()), personWrapper.getNumVaccinations())
);
// check infection immediately if there is only one thread
diff --git a/src/main/java/org/matsim/episim/model/AgeAndProgressionDependentInfectionModelWithSeasonality.java b/src/main/java/org/matsim/episim/model/AgeAndProgressionDependentInfectionModelWithSeasonality.java
index 77c495b71..869a8a262 100644
--- a/src/main/java/org/matsim/episim/model/AgeAndProgressionDependentInfectionModelWithSeasonality.java
+++ b/src/main/java/org/matsim/episim/model/AgeAndProgressionDependentInfectionModelWithSeasonality.java
@@ -8,6 +8,7 @@
import org.matsim.episim.*;
import org.matsim.episim.policy.Restriction;
+import java.util.EnumMap;
import java.util.Map;
import java.util.SplittableRandom;
@@ -26,8 +27,8 @@ public final class AgeAndProgressionDependentInfectionModelWithSeasonality imple
private final VaccinationConfigGroup vaccinationConfig;
private final VirusStrainConfigGroup virusStrainConfig;
- private final double[] susceptibility = new double[128];
- private final double[] infectivity = new double[susceptibility.length];
+ private final Map susceptibility = new EnumMap<>(VirusStrain.class);
+ private final Map infectivity = new EnumMap<>(VirusStrain.class);
private final RealDistribution distribution;
/**
@@ -50,11 +51,8 @@ public final class AgeAndProgressionDependentInfectionModelWithSeasonality imple
this.reporting = reporting;
this.rnd = rnd;
- // pre-compute interpolated age dependent entries
- for (int i = 0; i < susceptibility.length; i++) {
- susceptibility[i] = EpisimUtils.interpolateEntry(episimConfig.getAgeSusceptibility(), i);
- infectivity[i] = EpisimUtils.interpolateEntry(episimConfig.getAgeInfectivity(), i);
- }
+ AgeDependentInfectionModelWithSeasonality.preComputeAgeDependency(susceptibility, infectivity, virusStrainConfig);
+
// based on https://arxiv.org/abs/2007.06602
distribution = new NormalDistribution(0.5, 2.6);
scale = 1 / distribution.density(distribution.getNumericalMean());
@@ -81,8 +79,8 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto
//noinspection ConstantConditions // ci corr can not be null, because sim is initialized with non null value
double ciCorrection = Math.min(restrictions.get(act1.getContainerName()).getCiCorrection(), restrictions.get(act2.getContainerName()).getCiCorrection());
- double susceptibility = this.susceptibility[target.getAge()];
- double infectivity = this.infectivity[infector.getAge()];
+ double susceptibility = this.susceptibility.get(infector.getVirusStrain())[target.getAge()];
+ double infectivity = this.infectivity.get(infector.getVirusStrain())[infector.getAge()];
// apply reduced susceptibility of vaccinated persons
VirusStrainConfigGroup.StrainParams strain = virusStrainConfig.getParams(infector.getVirusStrain());
@@ -110,8 +108,8 @@ private double calcUnVacInfectionProbability(EpisimPerson target, EpisimPerson i
//noinspection ConstantConditions // ci corr can not be null, because sim is initialized with non null value
double ciCorrection = Math.min(restrictions.get(act1.getContainerName()).getCiCorrection(), restrictions.get(act2.getContainerName()).getCiCorrection());
- double susceptibility = this.susceptibility[target.getAge()];
- double infectivity = this.infectivity[infector.getAge()];
+ double susceptibility = this.susceptibility.get(infector.getVirusStrain())[target.getAge()];
+ double infectivity = this.infectivity.get(infector.getVirusStrain())[infector.getAge()];
// apply reduced susceptibility of vaccinated persons
VirusStrainConfigGroup.StrainParams strain = virusStrainConfig.getParams(infector.getVirusStrain());
diff --git a/src/main/java/org/matsim/episim/model/AgeDependentInfectionModelWithSeasonality.java b/src/main/java/org/matsim/episim/model/AgeDependentInfectionModelWithSeasonality.java
index 99df4019d..081bba8bc 100644
--- a/src/main/java/org/matsim/episim/model/AgeDependentInfectionModelWithSeasonality.java
+++ b/src/main/java/org/matsim/episim/model/AgeDependentInfectionModelWithSeasonality.java
@@ -6,6 +6,7 @@
import org.matsim.episim.*;
import org.matsim.episim.policy.Restriction;
+import java.util.EnumMap;
import java.util.Map;
import java.util.SplittableRandom;
@@ -23,8 +24,8 @@ public final class AgeDependentInfectionModelWithSeasonality implements Infectio
private final VaccinationConfigGroup vaccinationConfig;
private final VirusStrainConfigGroup virusStrainConfig;
- private final double[] susceptibility = new double[128];
- private final double[] infectivity = new double[susceptibility.length];
+ private final Map susceptibility = new EnumMap<>(VirusStrain.class);
+ private final Map infectivity = new EnumMap<>(VirusStrain.class);
private double outdoorFactor;
private int iteration;
@@ -38,10 +39,28 @@ public final class AgeDependentInfectionModelWithSeasonality implements Infectio
this.reporting = reporting;
this.rnd = rnd;
- // pre-compute interpolated age dependent entries
- for (int i = 0; i < susceptibility.length; i++) {
- susceptibility[i] = EpisimUtils.interpolateEntry(episimConfig.getAgeSusceptibility(), i);
- infectivity[i] = EpisimUtils.interpolateEntry(episimConfig.getAgeInfectivity(), i);
+ preComputeAgeDependency(susceptibility, infectivity, virusStrainConfig);
+ }
+
+ /**
+ * Pre-compute interpolated age dependent entries
+ */
+ static void preComputeAgeDependency(Map susceptibility, Map infectivity, VirusStrainConfigGroup virusStrainConfig) {
+
+ for (VirusStrain strain : VirusStrain.values()) {
+
+ if (!virusStrainConfig.hasParams(strain))
+ continue;
+
+ double[] susp = susceptibility.computeIfAbsent(strain, k -> new double[128]);
+ double[] inf = infectivity.computeIfAbsent(strain, k -> new double[susp.length]);
+
+ VirusStrainConfigGroup.StrainParams strainConfig = virusStrainConfig.getParams(strain);
+
+ for (int i = 0; i < susp.length; i++) {
+ susp[i] = EpisimUtils.interpolateEntry(strainConfig.getAgeSusceptibility(), i);
+ inf[i] = EpisimUtils.interpolateEntry(strainConfig.getAgeInfectivity(), i);
+ }
}
}
@@ -61,8 +80,8 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto
//noinspection ConstantConditions // ci corr can not be null, because sim is initialized with non null value
double ciCorrection = Math.min(restrictions.get(act1.getContainerName()).getCiCorrection(), restrictions.get(act2.getContainerName()).getCiCorrection());
- double susceptibility = this.susceptibility[target.getAge()];
- double infectivity = this.infectivity[infector.getAge()];
+ double susceptibility = this.susceptibility.get(infector.getVirusStrain())[target.getAge()];
+ double infectivity = this.infectivity.get(infector.getVirusStrain())[infector.getAge()];
// apply reduced susceptibility of vaccinated persons
VirusStrainConfigGroup.StrainParams params = virusStrainConfig.getParams(infector.getVirusStrain());
diff --git a/src/main/java/org/matsim/episim/model/AntibodyModel.java b/src/main/java/org/matsim/episim/model/AntibodyModel.java
index d58e9e43c..bbda67d6f 100644
--- a/src/main/java/org/matsim/episim/model/AntibodyModel.java
+++ b/src/main/java/org/matsim/episim/model/AntibodyModel.java
@@ -41,6 +41,8 @@ static AntibodyModel.Config newConfig(Map persons, int iteration);
+ void recalculateAntibodiesAfterSnapshot(Collection persons, int iteration);
+
/**
* Class for antibody model configurations.
*/
@@ -50,7 +52,6 @@ public static class Config {
final Map> antibodyRefreshFactors;
private double immuneReponseSigma = 0.;
-
public Config() {
//initial antibodies
@@ -80,6 +81,10 @@ public Config() {
//mRNAAlpha, mRNADelta, mRNABA1 comes from Sydney's calibration.
//The other values come from Rössler et al.
+ double mutEscDelta = 29.2 / 10.9;
+ double mutEscBa1 = 10.9 / 1.9;
+ double mutEscBa5 = 2.9;
+
//Wildtype
double mRNAAlpha = 29.2;
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.SARS_CoV_2, mRNAAlpha);
@@ -89,6 +94,9 @@ public Config() {
initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 210. / 700.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.SARS_CoV_2, 0.01);
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
//Alpha
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.ALPHA, mRNAAlpha);
@@ -98,43 +106,65 @@ public Config() {
initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.ALPHA, mRNAAlpha * 210. / 700.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.ALPHA, 0.01);
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
//DELTA
- double mRNADelta = 10.9;
+ double mRNADelta = mRNAAlpha / mutEscDelta;
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.DELTA, mRNADelta);
- initialAntibodies.get(VaccinationType.vector).put(VirusStrain.DELTA, mRNADelta * 150. / 300.);
- initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.DELTA, mRNADelta * 64. / 300.);
- initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.DELTA, mRNADelta * 64. / 300.);
- initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.DELTA, mRNADelta * 450. / 300.);
- initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.DELTA, 0.2 / 6.4);
- initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.DELTA, 0.2 / 6.4);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.DELTA, mRNADelta * 150./300.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.DELTA, mRNADelta * 64./300.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.DELTA, mRNADelta * 64./300.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.DELTA, mRNADelta * 450./300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1 / mutEscBa5);
//BA.1
- double mRNABA1 = 1.9;
+ double mRNABA1 = mRNADelta / mutEscBa1;
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA1, mRNABA1);
- initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA1, mRNABA1 * 4. / 20.); //???
- initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6. / 20.);
- initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6. / 20.);
- initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 8. / 20.);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA1, mRNABA1 * 4./20.); //???
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 8./20.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA1, 64.0 / 300.);
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / 1.4);
-
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscBa5); //todo: is 1.4
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha / mutEscBa5);
//BA.2
- double mRNABA2 = mRNABA1 / 1.4;
+ double mRNABA2 = mRNABA1;
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA2, mRNABA2);
- initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA2, mRNABA2 * 4. / 20.);
- initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6. / 20.);
- initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6. / 20.);
- initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 8. / 20.);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA2, mRNABA2 * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 8./20.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / 1.4);
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA2, 64.0 / 300.);
-
-
- //refresh factors
- Map> antibodyRefreshFactors = new HashMap<>();
-
- for (VaccinationType immunityType : VaccinationType.values()) {
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscBa5);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha / mutEscBa5);
+
+
+ //BA.5
+ double mRNABa5 = mRNABA2 / mutEscBa5;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA5, mRNABa5);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA5, mRNABa5 * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA5, 64.0 / 300. / mutEscBa5);// todo: do we need 1.4?
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA5, 64.0 / 300./ mutEscBa5);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA5, 64.0 / 300.);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha / mutEscBa5);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha);
+ Map> antibodyRefreshFactors = new HashMap<>();
+
+ for (VaccinationType immunityType : VaccinationType.values()) {
antibodyRefreshFactors.put(immunityType, new EnumMap<>(VirusStrain.class));
for (VirusStrain virusStrain : VirusStrain.values()) {
@@ -142,7 +172,14 @@ public Config() {
antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
} else if (immunityType == VaccinationType.vector) {
antibodyRefreshFactors.get(immunityType).put(virusStrain, 5.0);
- } else {
+ }
+ else if (immunityType == VaccinationType.ba1Update) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else if (immunityType == VaccinationType.ba5Update) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else {
antibodyRefreshFactors.get(immunityType).put(virusStrain, Double.NaN);
}
@@ -173,6 +210,7 @@ public double getImmuneReponseSigma() {
public void setImmuneReponseSigma(double immuneReponseSigma) {
this.immuneReponseSigma = immuneReponseSigma;
}
+
}
}
diff --git a/src/main/java/org/matsim/episim/model/ConfigurableProgressionModel.java b/src/main/java/org/matsim/episim/model/ConfigurableProgressionModel.java
index 6bb31850f..a0e2e3a15 100644
--- a/src/main/java/org/matsim/episim/model/ConfigurableProgressionModel.java
+++ b/src/main/java/org/matsim/episim/model/ConfigurableProgressionModel.java
@@ -227,7 +227,7 @@ private boolean releasePerson(EpisimPerson person) {
if (release == TracingConfigGroup.QuarantineRelease.SUSCEPTIBLE && status == DiseaseStatus.susceptible)
return true;
- if (release == TracingConfigGroup.QuarantineRelease.NON_SYMPTOMS &&
+ if (release == TracingConfigGroup.QuarantineRelease.NON_SYMPTOMATIC &&
(status == DiseaseStatus.susceptible || status == DiseaseStatus.contagious || status == DiseaseStatus.infectedButNotContagious))
return true;
diff --git a/src/main/java/org/matsim/episim/model/ContactModel.java b/src/main/java/org/matsim/episim/model/ContactModel.java
index 1cee7e9ca..bb56340c2 100644
--- a/src/main/java/org/matsim/episim/model/ContactModel.java
+++ b/src/main/java/org/matsim/episim/model/ContactModel.java
@@ -35,12 +35,14 @@ public interface ContactModel {
* This method is called when a persons leave a vehicle at {@code now}.
*/
void infectionDynamicsVehicle(EpisimPerson personLeavingVehicle, InfectionEventHandler.EpisimVehicle vehicle, double now);
+
void notifyEnterVehicle(EpisimPerson personEnteringVehicle, InfectionEventHandler.EpisimVehicle vehicle, double now);
/**
* This method is called when a persons leaves a facility at {@code now}.
*/
void infectionDynamicsFacility(EpisimPerson personLeavingFacility, InfectionEventHandler.EpisimFacility facility, double now);
+
void notifyEnterFacility(EpisimPerson personEnteringFacility, InfectionEventHandler.EpisimFacility facility, double now);
/**
@@ -48,4 +50,10 @@ public interface ContactModel {
*/
void setRestrictionsForIteration(int iteration, Map restrictions);
+ /**
+ * Number of processed contacts for the day.
+ */
+ int getNumContacts();
+
+
}
diff --git a/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java b/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java
index 7345c8927..b040e796f 100644
--- a/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java
+++ b/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java
@@ -2,6 +2,7 @@
import com.google.inject.Inject;
+import org.matsim.episim.EpisimConfigGroup;
import org.matsim.episim.EpisimPerson;
import org.matsim.episim.EpisimUtils;
@@ -10,15 +11,21 @@
public class DefaultAntibodyModel implements AntibodyModel {
+ public static final double HALF_LIFE_DAYS = 60; // todo: would 40 work better?
+
private final AntibodyModel.Config antibodyConfig;
private final SplittableRandom localRnd;
+ private final EpisimConfigGroup episimConfig;
+
@Inject
- DefaultAntibodyModel(AntibodyModel.Config antibodyConfig) {
+ DefaultAntibodyModel(AntibodyModel.Config antibodyConfig, EpisimConfigGroup episimConfigGroup) {
this.antibodyConfig = antibodyConfig;
+ this.episimConfig = episimConfigGroup;
localRnd = new SplittableRandom(2938); // todo: should it be a fixed seed, i.e not change btwn snapshots
+
}
@Override
@@ -28,6 +35,7 @@ public void init(Collection persons, int iteration) {
// mu = log(median); log(1)=0
+
// we assume immune response multiplier follows log-normal distribution, bounded by 0.01 and 10.
double immuneResponseMultiplier = 0;
while (immuneResponseMultiplier < 0.1 || immuneResponseMultiplier > 10) {
@@ -36,19 +44,26 @@ public void init(Collection persons, int iteration) {
person.setImmuneResponseMultiplier(immuneResponseMultiplier);
+ }
+
+
+ }
+
+ @Override
+ public void recalculateAntibodiesAfterSnapshot(Collection persons, int iteration) {
+ for (EpisimPerson person : persons) {
+
+ // reset to 0.0
for (VirusStrain strain : VirusStrain.values()) {
person.setAntibodies(strain, 0.0);
}
- if (iteration > 1) {
- for (int it = 1; it < iteration; it++) {
- updateAntibodies(person, it);
- }
+ // recalculate antibodies from immune history
+ for (int it = 1; it < iteration; it++) {
+ updateAntibodies(person, it);
}
}
-
-
}
/**
@@ -62,13 +77,6 @@ public void init(Collection persons, int iteration) {
@Override
public void updateAntibodies(EpisimPerson person, int day) {
- // todo: is this needed, now that we have an init
- if (day == 0) {
- for (VirusStrain strain : VirusStrain.values()) {
- person.setAntibodies(strain, 0.0);
- }
- }
-
//handle vaccination
if (person.getVaccinationDates().contains(day - 1)) {
int vaccinationIndex = person.getVaccinationDates().indexOf(day - 1);
@@ -88,9 +96,8 @@ public void updateAntibodies(EpisimPerson person, int day) {
// if no immunity event: exponential decay, day by day:
for (VirusStrain strain : VirusStrain.values()) {
- double halfLife_days = 60.;
double oldAntibodyLevel = person.getAntibodies(strain);
- person.setAntibodies(strain, oldAntibodyLevel * Math.pow(0.5, 1 / halfLife_days));
+ person.setAntibodies(strain, oldAntibodyLevel * Math.pow(0.5, 1 / HALF_LIFE_DAYS));
}
}
@@ -107,6 +114,10 @@ private void handleImmunization(EpisimPerson person, ImmunityEvent immunityEvent
antibodies = Math.min(150., antibodies * person.getImmuneResponseMultiplier());
person.setAntibodies(strain2, antibodies);
+
+ // if antibodies against a strain2 are higher than previous maximum, replace maximum
+ // should always be the case for initial immunization
+ person.updateMaxAntibodies(strain2, antibodies);
}
@@ -117,10 +128,8 @@ private void handleImmunization(EpisimPerson person, ImmunityEvent immunityEvent
// antibodies before refresh
double antibodies = person.getAntibodies(strain2);
- // refresh antibodies; ensure that antibody level does not decrease.
- if (refreshFactor * person.getImmuneResponseMultiplier() >= 1) {
- antibodies = antibodies * refreshFactor * person.getImmuneResponseMultiplier();
- }
+ // refresh antibodies
+ antibodies = antibodies * refreshFactor;
// check that new antibody level at least as high as initial antibodies
double initialAntibodies = antibodyConfig.initialAntibodies.get(immunityEventType).get(strain2) * person.getImmuneResponseMultiplier();
@@ -130,8 +139,10 @@ private void handleImmunization(EpisimPerson person, ImmunityEvent immunityEvent
antibodies = Math.min(150., antibodies);
person.setAntibodies(strain2, antibodies);
- }
+ // if antibodies against a strain2 are higher than previous maximum, replace maximum
+ person.updateMaxAntibodies(strain2, antibodies);
+ }
}
}
diff --git a/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java b/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java
index 24444e702..d70712dfb 100644
--- a/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java
+++ b/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java
@@ -8,12 +8,14 @@
import org.matsim.episim.*;
import org.matsim.episim.policy.Restriction;
+import java.util.ArrayList;
+import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.SplittableRandom;
/**
- * Extension of the {@link DefaultInfectionModel}, with age, time and seasonality-dependen additions.
+ * Extension of the {@link DefaultInfectionModel}, with age, time and seasonality-dependent additions.
*/
public final class InfectionModelWithAntibodies implements InfectionModel {
@@ -25,8 +27,8 @@ public final class InfectionModelWithAntibodies implements InfectionModel {
private final VaccinationConfigGroup vaccinationConfig;
private final VirusStrainConfigGroup virusStrainConfig;
- private final double[] susceptibility = new double[128];
- private final double[] infectivity = new double[susceptibility.length];
+ private final Map susceptibility = new EnumMap<>(VirusStrain.class);
+ private final Map infectivity = new EnumMap<>(VirusStrain.class);
private final RealDistribution distribution;
/**
@@ -49,11 +51,8 @@ public final class InfectionModelWithAntibodies implements InfectionModel {
this.reporting = reporting;
this.rnd = rnd;
- // pre-compute interpolated age dependent entries
- for (int i = 0; i < susceptibility.length; i++) {
- susceptibility[i] = EpisimUtils.interpolateEntry(episimConfig.getAgeSusceptibility(), i);
- infectivity[i] = EpisimUtils.interpolateEntry(episimConfig.getAgeInfectivity(), i);
- }
+ AgeDependentInfectionModelWithSeasonality.preComputeAgeDependency(susceptibility, infectivity, virusStrainConfig);
+
// based on https://arxiv.org/abs/2007.06602
distribution = new NormalDistribution(0.5, 2.6);
scale = 1 / distribution.density(distribution.getNumericalMean());
@@ -80,8 +79,8 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto
//noinspection ConstantConditions // ci corr can not be null, because sim is initialized with non null value
double ciCorrection = Math.min(restrictions.get(act1.getContainerName()).getCiCorrection(), restrictions.get(act2.getContainerName()).getCiCorrection());
- double susceptibility = this.susceptibility[target.getAge()];
- double infectivity = this.infectivity[infector.getAge()];
+ double susceptibility = this.susceptibility.get(infector.getVirusStrain())[target.getAge()];
+ double infectivity = this.infectivity.get(infector.getVirusStrain())[infector.getAge()];
VirusStrainConfigGroup.StrainParams strain = virusStrainConfig.getParams(infector.getVirusStrain());
@@ -97,7 +96,6 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto
{
double igaFactor = 0.0;
-
double igaTimePeriod = vaccinationConfig.getTimePeriodIgA();
if (target.hadStrain(infector.getVirusStrain())) {
@@ -110,14 +108,41 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto
// igaFactor = Math.exp( - target.daysSinceInfection(lastInfectionWithStrain, iteration) / 120.0);
igaFactor = 1.0 / (1.0 + Math.exp(-2.0 * (1.0 - target.daysSinceInfection(lastInfectionWithStrain, iteration) / igaTimePeriod)));
- } else if (vaccinationConfig.getUseIgA()) {
- List crossImmunityStrains = List.of(VirusStrain.OMICRON_BA1,VirusStrain.OMICRON_BA2,VirusStrain.OMICRON_BA5,VirusStrain.STRAIN_A);
+ }
+
+ ArrayList strainsLineA = new ArrayList();
+ strainsLineA.add(VirusStrain.OMICRON_BA1);
+ strainsLineA.add(VirusStrain.OMICRON_BA2);
+ strainsLineA.add(VirusStrain.OMICRON_BA5);
+ strainsLineA.add(VirusStrain.STRAIN_A);
+ strainsLineA.add(VirusStrain.STRAIN_B);
+
+ ArrayList strainsLineB = new ArrayList();
+ strainsLineB.add(VirusStrain.OMICRON_BA1);
+ strainsLineB.add(VirusStrain.OMICRON_BA2);
+ strainsLineB.add(VirusStrain.OMICRON_BA5);
+ strainsLineB.add(VirusStrain.STRAIN_A);
+ strainsLineB.add(VirusStrain.STRAIN_B);
+
+ if (vaccinationConfig.getUseIgA()) {
+
+ for (VirusStrain str : VirusStrain.values()) {
+ if (str.toString().startsWith("A_"))
+ strainsLineA.add(str);
+ }
+ for (VirusStrain str : VirusStrain.values()) {
+ if (str.toString().startsWith("B_"))
+ strainsLineB.add(str);
+ }
+ }
+
+// if (vaccinationConfig.getUseIgA()) {
- if(crossImmunityStrains.contains(infector.getVirusStrain())){
+ if(strainsLineA.contains(infector.getVirusStrain())){
int lastInfectionWithStrain = 0;
boolean targetHadStrain = false;
for (int ii = 0; ii < target.getNumInfections(); ii++) {
- if (crossImmunityStrains.contains(target.getVirusStrain(ii))){
+ if (strainsLineA.contains(target.getVirusStrain(ii))){
targetHadStrain = true;
lastInfectionWithStrain = ii;
}
@@ -129,13 +154,49 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto
igaFactor = Math.max(fac, igaFactor);
}
}
- }
- susceptibility = susceptibility * (1.0 - igaFactor);
+
+ if(strainsLineB.contains(infector.getVirusStrain())){
+ int lastInfectionWithStrain = 0;
+ boolean targetHadStrain = false;
+ for (int ii = 0; ii < target.getNumInfections(); ii++) {
+ if (strainsLineB.contains(target.getVirusStrain(ii))){
+ targetHadStrain = true;
+ lastInfectionWithStrain = ii;
+ }
+ }
+
+ if (targetHadStrain) {
+ double fac = 1.0 / (1.0 + Math.exp(-2.0 * (1.0 - target.daysSinceInfection(lastInfectionWithStrain, iteration) / igaTimePeriod)));
+ fac = fac / 1.4;
+ igaFactor = Math.max(fac, igaFactor);
+ }
+ }
+
+// if(strainsLineA.contains(infector.getVirusStrain()) || strainsLineB.contains(infector.getVirusStrain())){
+// int lastInfectionWithStrain = 0;
+// boolean targetHadStrain = false;
+// for (int ii = 0; ii < target.getNumInfections(); ii++) {
+// if (strainsLineA.contains(target.getVirusStrain(ii)) || strainsLineB.contains(target.getVirusStrain(ii))){
+// targetHadStrain = true;
+// lastInfectionWithStrain = ii;
+// }
+// }
+//
+// if (targetHadStrain) {
+// double fac = 1.0 / (1.0 + Math.exp(-2.0 * (1.0 - target.daysSinceInfection(lastInfectionWithStrain, iteration) / igaTimePeriod)));
+// fac = fac / 1.4 / 1.4;
+// igaFactor = Math.max(fac, igaFactor);
+// }
+// }
+
+ susceptibility = susceptibility * (1.0 - igaFactor);
+// }
}
lastUnVac = calcInfectionProbabilityWoImmunity(target, infector, restrictions, act1, act2, contactIntensity, jointTimeInContainer, indoorOutdoorFactor, shedding, intake, infectivity, susceptibility);
+ // remaining risk --> lower val, lower risk, max risk at 1
double immunityFactor = 1.0 / (1.0 + Math.pow(relativeAntibodyLevelTarget, vaccinationConfig.getBeta()));
return 1 - Math.exp(-episimConfig.getCalibrationParameter() * susceptibility * infectivity * contactIntensity * jointTimeInContainer * ciCorrection
diff --git a/src/main/java/org/matsim/episim/model/SymmetricContactModel.java b/src/main/java/org/matsim/episim/model/SymmetricContactModel.java
index 0b51b8382..a1f456915 100644
--- a/src/main/java/org/matsim/episim/model/SymmetricContactModel.java
+++ b/src/main/java/org/matsim/episim/model/SymmetricContactModel.java
@@ -131,6 +131,9 @@ private void infectionDynamicsGeneralized(EpisimPerson personLeavingContainer, E
continue;
}
+ // counted as contact
+ numContacts++;
+
// we have thrown the random numbers, so we can bail out in some cases if we are not tracking:
if (!trackingEnabled) {
if (personLeavingContainer.getDiseaseStatus() == DiseaseStatus.infectedButNotContagious) {
diff --git a/src/main/java/org/matsim/episim/model/VaccinationType.java b/src/main/java/org/matsim/episim/model/VaccinationType.java
index c51b94efb..57f9be945 100644
--- a/src/main/java/org/matsim/episim/model/VaccinationType.java
+++ b/src/main/java/org/matsim/episim/model/VaccinationType.java
@@ -8,7 +8,8 @@ public enum VaccinationType implements ImmunityEvent {
generic,
mRNA,
vector,
- omicronUpdate,
+ ba1Update,
+ ba5Update,
/**
* Not a real vaccination, but used to describe the profile for persons that have been infected and gained a natural immunity.
diff --git a/src/main/java/org/matsim/episim/model/VirusStrain.java b/src/main/java/org/matsim/episim/model/VirusStrain.java
index cb117106c..cc278b5c8 100644
--- a/src/main/java/org/matsim/episim/model/VirusStrain.java
+++ b/src/main/java/org/matsim/episim/model/VirusStrain.java
@@ -37,9 +37,88 @@ public enum VirusStrain implements ImmunityEvent {
OMICRON_BA2,
OMICRON_BA5,
-
+
STRAIN_A,
- STRAIN_B
+ STRAIN_B,
+
+ A_1,
+
+ A_2,
+
+ A_3,
+
+ A_4,
+
+ A_5,
+
+ A_6,
+
+ A_7,
+
+ A_8,
+
+ A_9,
+
+ A_10,
+
+ A_11,
+
+ A_12,
+
+ A_13,
+
+ A_14,
+
+ A_15,
+
+ A_16,
+
+ A_17,
+
+ A_18,
+
+ A_19,
+
+ A_20,
+
+ B_1,
+ B_2,
+
+ B_3,
+
+ B_4,
+
+ B_5,
+
+ B_6,
+
+ B_7,
+
+ B_8,
+
+ B_9,
+
+ B_10,
+
+ B_11,
+
+ B_12,
+
+ B_13,
+
+ B_14,
+
+ B_15,
+
+ B_16,
+
+ B_17,
+
+ B_18,
+
+ B_19,
+
+ B_20
}
diff --git a/src/main/java/org/matsim/episim/model/input/CreateRestrictionsFromSnz.java b/src/main/java/org/matsim/episim/model/input/CreateRestrictionsFromSnz.java
index 12171e614..27842d819 100644
--- a/src/main/java/org/matsim/episim/model/input/CreateRestrictionsFromSnz.java
+++ b/src/main/java/org/matsim/episim/model/input/CreateRestrictionsFromSnz.java
@@ -227,7 +227,7 @@ static HashMap> readDurations(File file, HashMa
sums.mergeDouble("notAtHome", duration, Double::sum);
- if (!actType.equals("education") && !actType.equals("leisure")) {
+ if (!actType.equals("education") && !actType.startsWith("leis")) {
sums.mergeDouble("notAtHomeExceptLeisureAndEdu", duration, Double::sum);
}
if (!actType.equals("education")) {
@@ -267,7 +267,7 @@ static Object2DoubleMap readDurations(File file, IntSet zipCodes) throws
sums.mergeDouble("notAtHome", duration, Double::sum);
- if (!actType.equals("education") && !actType.equals("leisure")) {
+ if (!actType.equals("education") && !actType.startsWith("leis")) {
sums.mergeDouble("notAtHomeExceptLeisureAndEdu", duration, Double::sum);
}
if (!actType.equals("education")) {
@@ -896,8 +896,8 @@ public HashMap findZipCodesForAnyArea(String anyArea) throws IOE
+ possibleAreas.toString() + " Choose one and start again.");
return zipCodes;
}
-
-
+
+
/** Finds the date after the last day in the given output file.
* @param startDateStillUsingBaseDays
* @param filesWithData
diff --git a/src/main/java/org/matsim/episim/model/listener/WriteAntibodies.java b/src/main/java/org/matsim/episim/model/listener/WriteAntibodies.java
new file mode 100644
index 000000000..5c2ae65d5
--- /dev/null
+++ b/src/main/java/org/matsim/episim/model/listener/WriteAntibodies.java
@@ -0,0 +1,67 @@
+package org.matsim.episim.model.listener;
+
+import com.google.inject.Inject;
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.population.Person;
+import org.matsim.episim.EpisimPerson;
+import org.matsim.episim.EpisimReporting;
+import org.matsim.episim.InfectionEventHandler;
+import org.matsim.episim.model.SimulationListener;
+import org.matsim.episim.model.VirusStrain;
+import org.matsim.facilities.ActivityFacility;
+import org.matsim.vehicles.Vehicle;
+
+import java.io.BufferedWriter;
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.SplittableRandom;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * Writes antibody leven into a matrix
+ */
+public class WriteAntibodies implements SimulationListener {
+
+ private Map, EpisimPerson> persons;
+ @Inject
+ private EpisimReporting reporting;
+
+ @Override
+ public void init(SplittableRandom rnd, Map, EpisimPerson> persons, Map, InfectionEventHandler.EpisimFacility> facilities, Map, InfectionEventHandler.EpisimVehicle> vehicles) {
+ this.persons = persons;
+ }
+
+ @Override
+ public void onIterationEnd(int iteration, LocalDate date) {
+
+ String header = VirusStrain.class.getSimpleName() + "\t" + IntStream.range(0, 120).mapToObj(String::valueOf).collect(Collectors.joining("\t")) + "\n";
+
+ BufferedWriter writer = reporting.registerWriter(String.format("antibodiesPerAge-%s.tsv", date.toString()));
+
+ reporting.writeAsync(writer, header);
+
+ for (VirusStrain strain : VirusStrain.values()) {
+
+ // Rolling mean per age group
+ int[] n = new int[120];
+ double[] values = new double[120];
+
+ for (EpisimPerson p : persons.values()) {
+
+ int i = p.getAge();
+ n[i]++;
+ values[i] = values[i] + (p.getAntibodies(strain) - values[i]) / n[i];
+
+ }
+
+ String row = strain.name() + "\t" + Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining("\t")) + "\n";
+
+ reporting.writeAsync(writer, row);
+ }
+
+ reporting.closeAsync(writer);
+ }
+
+}
diff --git a/src/main/java/org/matsim/episim/model/listener/WriteContactsPerDay.java b/src/main/java/org/matsim/episim/model/listener/WriteContactsPerDay.java
new file mode 100644
index 000000000..0f37ea086
--- /dev/null
+++ b/src/main/java/org/matsim/episim/model/listener/WriteContactsPerDay.java
@@ -0,0 +1,48 @@
+package org.matsim.episim.model.listener;
+
+import com.google.inject.Inject;
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.population.Person;
+import org.matsim.episim.EpisimPerson;
+import org.matsim.episim.EpisimReporting;
+import org.matsim.episim.InfectionEventHandler;
+import org.matsim.episim.model.SimulationListener;
+import org.matsim.episim.model.VirusStrain;
+import org.matsim.facilities.ActivityFacility;
+import org.matsim.vehicles.Vehicle;
+
+import java.io.BufferedWriter;
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.SplittableRandom;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * Writes contacts for each day.
+ */
+public class WriteContactsPerDay implements SimulationListener {
+
+ private Map, EpisimPerson> persons;
+ @Inject
+ private EpisimReporting reporting;
+ private BufferedWriter writer;
+
+ @Override
+ public void init(SplittableRandom rnd, Map, EpisimPerson> persons, Map, InfectionEventHandler.EpisimFacility> facilities, Map, InfectionEventHandler.EpisimVehicle> vehicles) {
+ this.persons = persons;
+ }
+
+ @Override
+ public void onIterationEnd(int iteration, LocalDate date) {
+
+ if (writer == null) {
+ writer = reporting.registerWriter("contactsPerDay.tsv");
+ reporting.writeAsync(writer, "date\tavgContacts\n");
+ }
+
+ reporting.writeAsync(writer, date + "\t" + reporting.getTotalContacts() / (double) persons.size() + "\n");
+
+ }
+}
diff --git a/src/main/java/org/matsim/episim/model/progression/AgeDependentDiseaseStatusTransitionModel.java b/src/main/java/org/matsim/episim/model/progression/AgeDependentDiseaseStatusTransitionModel.java
index 85b7e564e..6f72b99c0 100644
--- a/src/main/java/org/matsim/episim/model/progression/AgeDependentDiseaseStatusTransitionModel.java
+++ b/src/main/java/org/matsim/episim/model/progression/AgeDependentDiseaseStatusTransitionModel.java
@@ -94,6 +94,8 @@ public double getProbaOfTransitioningToSeriouslySick(Immunizable person) {
proba = 36. / 100;
}
+ return proba * episimConfig.getHospitalFactor();
+
// source 2
// if (age < 10) {
@@ -153,7 +155,7 @@ public double getProbaOfTransitioningToSeriouslySick(Immunizable person) {
// proba = 27.3 / 100;
// }
- return proba * episimConfig.getHospitalFactor();
+
}
@Override
diff --git a/src/main/java/org/matsim/episim/model/progression/AntibodyDependentTransitionModel.java b/src/main/java/org/matsim/episim/model/progression/AntibodyDependentTransitionModel.java
index db92cacf5..63dc0dc36 100644
--- a/src/main/java/org/matsim/episim/model/progression/AntibodyDependentTransitionModel.java
+++ b/src/main/java/org/matsim/episim/model/progression/AntibodyDependentTransitionModel.java
@@ -30,8 +30,8 @@ public final EpisimPerson.DiseaseStatus decideNextState(EpisimPerson person, Epi
switch (status) {
case infectedButNotContagious:
return EpisimPerson.DiseaseStatus.contagious;
-
case contagious:
+
if (rnd.nextDouble() < getProbaOfTransitioningToShowingSymptoms(person) * getShowingSymptomsFactor(person, vaccinationConfig, day))
return EpisimPerson.DiseaseStatus.showingSymptoms;
else
@@ -114,94 +114,28 @@ public double getSeriouslySickFactor(Immunizable person, VaccinationConfigGroup
int numVaccinations = person.getNumVaccinations();
int numInfections = person.getNumInfections() - 1;
- // Version from Sander
- // --
-// if (numVaccinations + numInfections == 1) {
-// return 0.3;
-// }
-//
-// if (numVaccinations + numInfections > 1) {
-// return 0.1;
-// }
-//
-// return 1.0;
-
- // --
- // version with antibodies
- if (numVaccinations == 0 && numInfections == 0)
- return 1.0;
-
- VirusStrain strain = person.getVirusStrain();
-
- int lastVaccination = 0;
-
- if (numVaccinations > 0)
- lastVaccination = person.getVaccinationDates().getInt(numVaccinations - 1);
-
- int lastInfection = 0;
-
- if (numInfections > 0)
- lastInfection = (int) (person.getInfectionDates().getDouble(numInfections - 1) / 86400.);
- int lastImmunityEvent = Math.max(lastVaccination, lastInfection);
- int daysSinceLastImmunityEvent = day - lastImmunityEvent;
+// if (numVaccinations == 0 && numInfections == 0)
+// return 1.0;
+ VirusStrain strain = person.getVirusStrain();
- double antibodiesAfterLastImmunityEvent = person.getAntibodyLevelAtInfection() * Math.pow(2., daysSinceLastImmunityEvent / 60.);
+ double abNoWaning = person.getMaxAntibodies(strain);
// Two modifications to antibody level below:
// a) we multiply the antibody level by 4 if the agent is boostered
if (numVaccinations > 1) {
- antibodiesAfterLastImmunityEvent *= 4;
+ abNoWaning *= 4;
}
// b) if strain is omicron, an additional factor of 3.7 is applied
- if (strain.equals(VirusStrain.OMICRON_BA1) || strain.equals(VirusStrain.OMICRON_BA2) || strain.equals(VirusStrain.OMICRON_BA5) || strain.equals(VirusStrain.STRAIN_A)) {
- antibodiesAfterLastImmunityEvent *= 3.7;
+ if (strain.equals(VirusStrain.OMICRON_BA1) || strain.equals(VirusStrain.OMICRON_BA2) || strain.equals(VirusStrain.OMICRON_BA5) || strain.equals(VirusStrain.STRAIN_A) || strain.equals(VirusStrain.STRAIN_B)
+ || strain.toString().startsWith("A_") || strain.toString().startsWith("B_")) {
+ abNoWaning *= 3.7;
}
- return 1. / (1. + Math.pow( antibodiesAfterLastImmunityEvent, vaccinationConfig.getBeta()));
-
-
- // --
- // even older version
-//
-// double veSeriouslySick = 0.0;
-//
-// //vaccinated persons that are boostered either by infection or by 3rd shot
-// if (numVaccinations > 1 || (numVaccinations > 0 && numInfections > 1)) {
-// if (strain == VirusStrain.OMICRON_BA1 || strain == VirusStrain.OMICRON_BA2)
-// veSeriouslySick = 0.9;
-// else
-// veSeriouslySick = 0.95;
-// }
-//
-// //vaccinated persons or persons who have had a severe course of disease in the past
-// // I think this does not work, because old states are removed when changing from recovered to susceptible. SM
-// else if (numVaccinations == 1 || person.hadDiseaseStatus(DiseaseStatus.seriouslySick)) {
-//// else if (numVaccinations == 1 || person.hadStrain(VirusStrain.SARS_CoV_2) || person.hadStrain(VirusStrain.ALPHA) || person.hadStrain(VirusStrain.DELTA))
-//
-// if (strain == VirusStrain.OMICRON_BA1 || strain == VirusStrain.OMICRON_BA2)
-// veSeriouslySick = 0.55;
-// else
-// veSeriouslySick = 0.9;
-// }
-//
-//
-// else {
-// if (strain == VirusStrain.OMICRON_BA1 || strain == VirusStrain.OMICRON_BA2)
-// veSeriouslySick = 0.55;
-// else
-// veSeriouslySick = 0.6;
-// }
-//
-// double factorInf = person.getImmunityFactor(vaccinationConfig.getBeta());
-//
-// double factorSeriouslySick = (1.0 - veSeriouslySick) / factorInf;
-//
-// factorSeriouslySick = Math.min(1.0, factorSeriouslySick);
-// factorSeriouslySick = Math.max(0.0, factorSeriouslySick);
-//
-// return factorSeriouslySick;
+ // returns remaining risk of infection (1 is full risk, 0 is no risk), opposite of vaccine effectiveness
+ return 1. / (1. + Math.pow(abNoWaning,vaccinationConfig.getBeta()));
+
}
@Override
@@ -215,71 +149,20 @@ public double getCriticalFactor(Immunizable person, VaccinationConfigGroup vacci
VirusStrain strain = person.getVirusStrain();
- int lastVaccination = 0;
-
- if (numVaccinations > 0)
- lastVaccination = person.getVaccinationDates().getInt(numVaccinations - 1);
-
- int lastInfection = 0;
-
- if (numInfections > 0)
- lastInfection = (int) (person.getInfectionDates().getDouble(numInfections - 1) / 86400.);
-
- int lastImmunityEvent = Math.max(lastVaccination, lastInfection);
- int daysSinceLastImmunityEvent = day - lastImmunityEvent;
-
- double antibodiesAfterLastImmunityEvent = person.getAntibodyLevelAtInfection() * Math.pow(2., daysSinceLastImmunityEvent / 60.);
+ double abNoWaning = person.getMaxAntibodies(strain);
// Two modifications to antibody level below:
// a) we multiply the antibody level by 4 if the agent is boostered
if (numVaccinations > 1) {
- antibodiesAfterLastImmunityEvent *= 4;
+ abNoWaning *= 4;
}
// b) if strain is omicron, an additional factor of 3.7 is applied
if (strain.equals(VirusStrain.OMICRON_BA1) || strain.equals(VirusStrain.OMICRON_BA2)) {
- antibodiesAfterLastImmunityEvent *= 3.7;
+ abNoWaning *= 3.7;
}
- return 1. / (1. + Math.pow(antibodiesAfterLastImmunityEvent, vaccinationConfig.getBeta()));
-
-//
-// double veSeriouslySick = 0.0;
-//
-// //vaccinated persons that are boostered either by infection or by 3rd shot
-// if (numVaccinations > 1 || (numVaccinations > 0 && numInfections > 1)) {
-// if (strain == VirusStrain.OMICRON_BA1 || strain == VirusStrain.OMICRON_BA2)
-// veSeriouslySick = 0.9;
-// else
-// veSeriouslySick = 0.95;
-// }
-//
-// //vaccinated persons or persons who have had a severe course of disease in the past
-// // I think this does not work, because old states are removed when changing from recovered to susceptible. SM
-// else if (numVaccinations == 1 || person.hadDiseaseStatus(DiseaseStatus.seriouslySick)) {
-//// else if (numVaccinations == 1 || person.hadStrain(VirusStrain.SARS_CoV_2) || person.hadStrain(VirusStrain.ALPHA) || person.hadStrain(VirusStrain.DELTA))
-//
-// if (strain == VirusStrain.OMICRON_BA1 || strain == VirusStrain.OMICRON_BA2)
-// veSeriouslySick = 0.55;
-// else
-// veSeriouslySick = 0.9;
-// }
-//
-//
-// else {
-// if (strain == VirusStrain.OMICRON_BA1 || strain == VirusStrain.OMICRON_BA2)
-// veSeriouslySick = 0.55;
-// else
-// veSeriouslySick = 0.6;
-// }
-//
-// double factorInf = person.getImmunityFactor(vaccinationConfig.getBeta());
-//
-// double factorSeriouslySick = (1.0 - veSeriouslySick) / factorInf;
-//
-// factorSeriouslySick = Math.min(1.0, factorSeriouslySick);
-// factorSeriouslySick = Math.max(0.0, factorSeriouslySick);
-//
-// return factorSeriouslySick;
+ return 1. / (1. + Math.pow(abNoWaning, vaccinationConfig.getBeta()));
+
}
@@ -287,11 +170,5 @@ protected double getProbaOfTransitioningToDeceased(EpisimPerson person) {
return 0.0;
}
-// @Override
-// public double getCriticalFactor(Immunizable person, VaccinationConfigGroup vaccinationConfig, int day) {
-// return 1.0;
-// }
-//
-
}
diff --git a/src/main/java/org/matsim/episim/model/testing/DefaultTestingModel.java b/src/main/java/org/matsim/episim/model/testing/DefaultTestingModel.java
index 9ba82116a..2036656dc 100644
--- a/src/main/java/org/matsim/episim/model/testing/DefaultTestingModel.java
+++ b/src/main/java/org/matsim/episim/model/testing/DefaultTestingModel.java
@@ -203,9 +203,13 @@ protected boolean testAndQuarantine(EpisimPerson person, int day, TestingConfigG
double rate = params.getFalseNegativeRate();
// TODO: configurable
- if (params.getType().equals (TestType.RAPID_TEST) && (person.getVirusStrain() == VirusStrain.OMICRON_BA1 ||
+ if (params.getType().equals(TestType.RAPID_TEST) && (person.getVirusStrain() == VirusStrain.OMICRON_BA1 ||
person.getVirusStrain() == VirusStrain.OMICRON_BA2 ||
- person.getVirusStrain() == VirusStrain.OMICRON_BA5) ){
+ person.getVirusStrain() == VirusStrain.OMICRON_BA5 ||
+ person.getVirusStrain() == VirusStrain.STRAIN_A ||
+ person.getVirusStrain() == VirusStrain.STRAIN_B ||
+ person.getVirusStrain().toString().startsWith("A_") ||
+ person.getVirusStrain().toString().startsWith("B_"))) {
rate = 0.5;
}
diff --git a/src/main/java/org/matsim/episim/model/vaccination/VaccinationFromData.java b/src/main/java/org/matsim/episim/model/vaccination/VaccinationFromData.java
index eca9f62c5..2e74533a4 100644
--- a/src/main/java/org/matsim/episim/model/vaccination/VaccinationFromData.java
+++ b/src/main/java/org/matsim/episim/model/vaccination/VaccinationFromData.java
@@ -224,6 +224,7 @@ private int vaccinate(Map, EpisimPerson> persons, TreeMap candidates = perAge[ii];
diff --git a/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java b/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java
new file mode 100644
index 000000000..c2604d694
--- /dev/null
+++ b/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java
@@ -0,0 +1,166 @@
+package org.matsim.episim.model.vaccination;
+
+import com.google.inject.Inject;
+import org.matsim.api.core.v01.Id;
+import org.matsim.api.core.v01.IdSet;
+import org.matsim.api.core.v01.Scenario;
+import org.matsim.api.core.v01.population.Person;
+import org.matsim.api.core.v01.population.Population;
+import org.matsim.episim.EpisimPerson;
+import org.matsim.episim.EpisimUtils;
+import org.matsim.episim.model.VaccinationType;
+
+import java.time.LocalDate;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Update vaccination campaign.
+ */
+public class VaccinationStrategyReoccurringCampaigns implements VaccinationModel {
+
+ private final int dailyVaccinationsToBeDistributed;
+
+ private final SplittableRandom rnd;
+ private final Config config;
+
+ private final IdSet boostBa5Yes = new IdSet<>(Person.class);
+
+ private final IdSet boostBa5Emergency = new IdSet<>(Person.class);
+
+
+ @Inject
+ public VaccinationStrategyReoccurringCampaigns(SplittableRandom rnd, Config config, Scenario scenario) {
+ this.rnd = rnd;
+ this.config = config;
+
+ Population population = scenario.getPopulation();
+
+ for (Person person : population.getPersons().values()) {
+
+ double randomNum = rnd.nextDouble();
+ if (randomNum < 0.5) {
+ boostBa5Yes.add(person.getId());
+ }
+ if (randomNum < 0.75) {
+ boostBa5Emergency.add(person.getId());
+ }
+ }
+
+ // calculate total number of vaccinations:
+ dailyVaccinationsToBeDistributed = 1_500 / 4;
+
+ }
+
+ @Override
+ public void handleVaccination(Map, EpisimPerson> persons, LocalDate date, int iteration, double now) {
+
+ // we check that the compliance of at least one age group is greater than 0.0. If not, there will be no vaccinations anyway
+ if (dailyVaccinationsToBeDistributed <= 0) {
+ return;
+ }
+
+ // Loop through all vaccination campaigns (via the start date of said campaign)
+ for (LocalDate vaccinationCampaignStartDate : config.startDateToVaccinationCampaign.keySet()) {
+ // Check whether current date falls within vaccination campaign
+ if (date.isAfter(vaccinationCampaignStartDate.minusDays(1)) && date.isBefore(vaccinationCampaignStartDate.plusDays(config.campaignDuration))) {
+
+ // vaccine type associated with campaign
+ VaccinationType vaccinationType = config.startDateToVaccinationCampaign.get(vaccinationCampaignStartDate);
+
+ // define eligible candidates for booster campaigns:
+ // ?) if the person is vaccinable, whatever that means
+ // a) not infected at the moment
+ // b) is either already vaccinated or boostered, depending on the configuration
+ // c) hasn't been vaccinated in the previous 90 days
+ final int minDaysAfterInfection;
+ if (date.isBefore(config.dateToTurnDownMinDaysAfterInfectionTo90)) {
+ minDaysAfterInfection = config.minDaysAfterInfection;
+ } else {
+ minDaysAfterInfection = 90;
+ }
+
+ List candidates = persons.values().stream()
+ .filter(EpisimPerson::isVaccinable)
+ .filter(p -> p.getDiseaseStatus() == EpisimPerson.DiseaseStatus.susceptible)
+ .filter(p -> p.getNumVaccinations() >= config.vaccinationPool.vaxCnt)
+ .filter(p -> p.getNumVaccinations() == 0 || p.daysSinceVaccination(p.getNumVaccinations() - 1, iteration) > config.minDaysAfterVaccination) // only people who've had their last vaccination more than 90 days ago
+ .filter(p -> p.getNumInfections() == 0 || p.daysSinceInfection(p.getNumInfections() - 1, iteration) > minDaysAfterInfection) // only people who've had their last vaccination more than 90 days ago
+ .filter(p -> date.isAfter(config.emergencyDate.minusDays(1)) ? boostBa5Emergency.contains(p.getPersonId()) : boostBa5Yes.contains(p.getPersonId()))
+ .filter(p -> !p.hadVaccinationType(vaccinationType)) // todo remove in future
+ .collect(Collectors.toList());
+
+
+
+ // create vaccinations-remaining counter for current day
+ int vaccinationsLeft = this.dailyVaccinationsToBeDistributed;
+ if (date.isAfter(config.emergencyDate.minusDays(1))) {
+ vaccinationsLeft *= 10;
+ }
+
+ // list is shuffled to avoid eventual bias
+ if (candidates.size() != 0)
+ Collections.shuffle(candidates, new Random(EpisimUtils.getSeed(rnd)));
+
+ int n = Math.min(candidates.size(), vaccinationsLeft);
+ for (int i = 0; i < n; i++) {
+ EpisimPerson person = candidates.get(i);
+ vaccinate(person, iteration, vaccinationType);
+ vaccinationsLeft--;
+ }
+ }
+ }
+ }
+
+
+ public static class Config {
+
+ /**
+ * Start Dates of vaccination campaigns.
+ */
+ private final Map startDateToVaccinationCampaign;
+ /**
+ * Duration of vaccination campaign.
+ */
+ private final int campaignDuration;
+
+ private final VaccinationPool vaccinationPool;
+
+ private final int minDaysAfterVaccination;
+
+ private final int minDaysAfterInfection;
+
+ private final LocalDate emergencyDate;
+ private final LocalDate dateToTurnDownMinDaysAfterInfectionTo90;
+
+ public enum VaccinationPool {
+
+ unvaccinated(0),
+
+ vaccinated(1),
+
+ boostered(2);
+
+ private final int vaxCnt;
+
+ VaccinationPool(int vaxCnt) {
+ this.vaxCnt = vaxCnt;
+ }
+
+ }
+
+
+ public Config(Map startDateToVaccinationCampaign, int campaignDuration, VaccinationPool vaccinationPool, int minDaysAfterInfection, int minDaysAfterVaccination, LocalDate emergencyDate, LocalDate dateToTurnDownMinDaysAfterInfectionTo90) {
+
+ this.startDateToVaccinationCampaign = startDateToVaccinationCampaign;
+ this.campaignDuration = campaignDuration;
+ this.vaccinationPool = vaccinationPool;
+ this.minDaysAfterInfection = minDaysAfterInfection;
+ this.minDaysAfterVaccination = minDaysAfterVaccination;
+ this.emergencyDate = emergencyDate;
+ this.dateToTurnDownMinDaysAfterInfectionTo90 = dateToTurnDownMinDaysAfterInfectionTo90;
+
+ }
+ }
+
+}
diff --git a/src/main/java/org/matsim/episim/policy/FixedPolicy.java b/src/main/java/org/matsim/episim/policy/FixedPolicy.java
index d2a763906..5d5bee740 100644
--- a/src/main/java/org/matsim/episim/policy/FixedPolicy.java
+++ b/src/main/java/org/matsim/episim/policy/FixedPolicy.java
@@ -33,12 +33,10 @@
import javax.inject.Named;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
+import java.util.stream.Collectors;
/**
* Set the restrictions based on fixed rules with day and {@link Restriction#getRemainingFraction()}.
@@ -96,12 +94,16 @@ static void initRestrictions(LocalDate start, ImmutableMap
Config actConfig = config.getConfig(entry.getKey());
- for (Map.Entry days : actConfig.root().entrySet()) {
+ List> entries = actConfig.root().entrySet().stream().filter(e -> !e.getKey().startsWith("day"))
+ .sorted(Comparator.comparing(e -> LocalDate.parse(e.getKey())))
+ .collect(Collectors.toList());
+
+ for (Map.Entry days : entries) {
if (days.getKey().startsWith("day")) continue;
LocalDate date = LocalDate.parse(days.getKey());
- if (date.isBefore(start)) {
+ if (date.isBefore(start.plusDays(1))) {
Restriction r = Restriction.fromConfig(actConfig.getConfig(days.getKey()));
entry.getValue().update(r);
diff --git a/src/main/java/org/matsim/run/AnalysisCommand.java b/src/main/java/org/matsim/run/AnalysisCommand.java
index ff7610d0d..df4261ccc 100644
--- a/src/main/java/org/matsim/run/AnalysisCommand.java
+++ b/src/main/java/org/matsim/run/AnalysisCommand.java
@@ -42,6 +42,7 @@
import java.nio.file.Path;
import java.util.*;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
@@ -57,7 +58,7 @@
CommandLine.HelpCommand.class, AutoComplete.GenerateCompletion.class,
RValuesFromEvents.class, ExtractInfectionsByAge.class, CreateContactGraph.class,
ExtractInfectionGraph.class, VaccinationEffectivenessFromPotentialInfections.class,
- VaccinationEffectiveness.class, FilterEvents.class, HospitalNumbersFromEvents.class
+ VaccinationEffectiveness.class, FilterEvents.class, HospitalNumbersFromEvents.class, SecondaryAttackRateFromEvents.class
},
subcommandsRepeatable = true
)
@@ -106,17 +107,28 @@ public static void forEachScenario(Path output, Consumer function) throws
});
}
+ /**
+ * See {@link #forEachEvent(Path, Function, boolean, EventHandler...)}. Callback will always return true.
+ */
+ public static List forEachEvent(Path scenario, Consumer callback, boolean preferReducedEvents, EventHandler... handler) {
+ return forEachEvent(scenario, s-> {
+ callback.accept(s);
+ return true;
+ }, preferReducedEvents, handler);
+ }
+
/**
* Reads in all event file from a scenario.
*
- * @param scenario path of the scenario, which contains the event folder
- * @param callback will be executed before reading an event file and pass the path
- * @param handler handler for the events
+ * @param scenario path of the scenario, which contains the event folder
+ * @param callback will be executed before reading an event file and pass the path. If false is returned, no more events will be read.
+ * @param preferReducedEvents
+ * @param handler handler for the events
* @return list of read event files
*/
- public static List forEachEvent(Path scenario, Consumer callback, EventHandler... handler) {
+ public static List forEachEvent(Path scenario, Function callback, boolean preferReducedEvents, EventHandler... handler) {
- Path events = getEvents(scenario);
+ Path events = getEvents(scenario, preferReducedEvents);
if (events == null) {
log.warn("No events found at {}", scenario);
return List.of();
@@ -145,7 +157,9 @@ public static List forEachEvent(Path scenario, Consumer callback
for (Path p : eventFiles) {
try {
String name = p.getFileName().toString();
- callback.accept(name);
+ if (!callback.apply(name)) {
+ break;
+ }
new EpisimEventsReader(manager).readFile(p.toString());
read.add(name);
@@ -159,7 +173,10 @@ public static List forEachEvent(Path scenario, Consumer callback
ArchiveEntry entry;
while ((entry = ar.getNextEntry()) != null) {
- callback.accept(entry.getName());
+
+ if (!callback.apply(entry.getName())) {
+ break;
+ }
new EpisimEventsReader(manager).parse(new NonClosingGZIPStream(ar));
@@ -208,19 +225,42 @@ public static String getScenarioPrefix(Path scenario) throws IOException {
* Check if events are present for the scenario. This method fallbacks to reduced events, if original are not present.
*/
@Nullable
- public static Path getEvents(Path scenario) {
+ public static Path getEvents(Path scenario, boolean preferReducedEvents) {
+
+ // if a path to an events file is entered, return that directly
+ if (Files.isRegularFile(scenario)) {
+ if (scenario.getFileName().toString().endsWith("events_reduced.tar") || scenario.getFileName().toString().endsWith("events.tar")) {
+ return scenario;
+ } else {
+ throw new RuntimeException("A file was specified; however, it doesn't follow the naming conventions for events files");
+ }
+ }
+
+ // if a path to a directory called "events is passed", return that directory
if (Files.isDirectory(scenario.resolve("events")) && !isEmpty(scenario.resolve("events"))) {
return scenario.resolve("events");
}
+ // otherwise, search directory for *events_reduced.tar or *events.tar
try {
- Optional o = Files.list(scenario).filter(p -> p.getFileName().toString().endsWith("events.tar")).findFirst();
+ Optional o;
+ if (preferReducedEvents) {
+ o = Files.list(scenario).filter(p -> p.getFileName().toString().endsWith("events_reduced.tar")).findFirst();
- if (o.isEmpty())
- o = Files.list(scenario).filter(p -> p.getFileName().toString().endsWith("events_reduced.tar")).findFirst();
+ if (o.isEmpty()) {
+ o = Files.list(scenario).filter(p -> p.getFileName().toString().endsWith("events.tar")).findFirst();
+ }
+ } else {
+ o = Files.list(scenario).filter(p -> p.getFileName().toString().endsWith("events.tar")).findFirst();
+
+ if (o.isEmpty()) {
+ o = Files.list(scenario).filter(p -> p.getFileName().toString().endsWith("events_reduced.tar")).findFirst();
+ }
+ }
return o.orElse(null);
+
} catch (IOException e) {
log.error("Error finding event files for {}", scenario);
return null;
diff --git a/src/main/java/org/matsim/run/CreateBatteryForCluster.java b/src/main/java/org/matsim/run/CreateBatteryForCluster.java
index 2f8a78654..0f59fc630 100644
--- a/src/main/java/org/matsim/run/CreateBatteryForCluster.java
+++ b/src/main/java/org/matsim/run/CreateBatteryForCluster.java
@@ -84,10 +84,10 @@ public class CreateBatteryForCluster implements Callable {
@CommandLine.Option(names = "--jvm-opts", description = "Additional options for JVM", defaultValue = "-Xms82G -Xmx82G -XX:+UseParallelGC")
private String jvmOpts;
- @CommandLine.Option(names = "--setup", defaultValue = "org.matsim.run.batch.CologneJR")
+ @CommandLine.Option(names = "--setup", defaultValue = "org.matsim.run.batch.CologneBMBF202212XX_bq1")
private Class extends BatchRun> setup;
- @CommandLine.Option(names = "--params", defaultValue = "org.matsim.run.batch.CologneJR$Params")
+ @CommandLine.Option(names = "--params", defaultValue = "org.matsim.run.batch.CologneBMBF202212XX_bq1$Params")
private Class params;
@SuppressWarnings("rawtypes")
@@ -262,6 +262,7 @@ static void writeMetadata(Path dir, PreparedRun run) throws IOException {
metadata.put("info", "_info.txt");
metadata.put("zipFolder", "summaries");
metadata.put("timestamp", LocalDate.now());
+ metadata.put("viewerVersion", 2);
metadata.putAll(run.getMetadata());
mapper.writeValue(yamlWriter, metadata);
diff --git a/src/main/java/org/matsim/run/batch/Berlin220215.java b/src/main/java/org/matsim/run/batch/Berlin220215.java
index 3506f74e6..4edb83da6 100644
--- a/src/main/java/org/matsim/run/batch/Berlin220215.java
+++ b/src/main/java/org/matsim/run/batch/Berlin220215.java
@@ -597,7 +597,7 @@ private void adaptVacinationEffectiveness(VaccinationConfigGroup vaccinationConf
)
;
- vaccinationConfig.getOrAddParams(VaccinationType.omicronUpdate)
+ vaccinationConfig.getOrAddParams(VaccinationType.ba1Update)
.setDaysBeforeFullEffect(fullEffectMRNA)
.setFactorShowingSymptoms(VaccinationConfigGroup.forStrain(VirusStrain.SARS_CoV_2)
.atFullEffect(factorSymptomsMRNA)
@@ -697,7 +697,7 @@ private void configureBooster(VaccinationConfigGroup vaccinationConfig, double b
.setBoostWaitPeriod(boostAfter * 30 + 6 * 7);
;
- vaccinationConfig.getOrAddParams(VaccinationType.omicronUpdate)
+ vaccinationConfig.getOrAddParams(VaccinationType.ba1Update)
.setBoostWaitPeriod(boostAfter * 30 + 6 * 7);
;
diff --git a/src/main/java/org/matsim/run/batch/CologneBMBF20220805.java b/src/main/java/org/matsim/run/batch/CologneBMBF20220805.java
new file mode 100644
index 000000000..9b5267e15
--- /dev/null
+++ b/src/main/java/org/matsim/run/batch/CologneBMBF20220805.java
@@ -0,0 +1,729 @@
+package org.matsim.run.batch;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Module;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.util.Modules;
+import it.unimi.dsi.fastutil.ints.Int2DoubleAVLTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2DoubleMap;
+import org.matsim.core.config.Config;
+import org.matsim.core.config.ConfigUtils;
+import org.matsim.episim.*;
+import org.matsim.episim.analysis.*;
+import org.matsim.episim.model.*;
+import org.matsim.episim.model.testing.TestType;
+import org.matsim.episim.model.vaccination.VaccinationModel;
+import org.matsim.episim.model.vaccination.VaccinationStrategyBMBF0617;
+import org.matsim.episim.policy.FixedPolicy;
+import org.matsim.episim.policy.Restriction;
+import org.matsim.run.RunParallel;
+import org.matsim.run.modules.SnzCologneProductionScenario;
+
+import javax.annotation.Nullable;
+import java.time.LocalDate;
+import java.util.*;
+
+
+/**
+ * Batch for Bmbf runs
+ */
+public class CologneBMBF20220805 implements BatchRun {
+
+ boolean DEBUG_MODE = false;
+ int runCount = 0;
+
+ @Nullable
+ @Override
+ public Module getBindings(int id, @Nullable Params params) {
+ return Modules.override(getBindings(0.0, params)).with(new AbstractModule() {
+ @Override
+ protected void configure() {
+
+ Multibinder set = Multibinder.newSetBinder(binder(), VaccinationModel.class);
+
+ set.addBinding().to(VaccinationStrategyBMBF0617.class).in(Singleton.class);
+
+ double mutEscDelta = 29.2 / 10.9;
+ double mutEscBa1 = 10.9 / 1.9;
+ double mutEscBa5 = 2.9;
+
+ double mutEscStrainA = 0.;
+ double mutEscStrainB = 0.;
+
+ LocalDate start = null;
+ VaccinationType vaccinationType = VaccinationType.mRNA;
+
+ Int2DoubleMap compliance = new Int2DoubleAVLTreeMap();
+ compliance.put(60, 0.0);
+ compliance.put(18, 0.0);
+ compliance.put(12, 0.0);
+ compliance.put(0, 0.0);
+
+ String vacCamp = "off";
+
+ if (params != null) {
+// mutEscBa5 = params.ba5Esc;
+
+ if (!params.vacType.equals("off")) {
+ vacCamp = "age";
+ vaccinationType = VaccinationType.valueOf(params.vacType);
+ }
+ if (!params.StrainA.equals("off")) {
+ mutEscStrainA = Double.parseDouble(params.StrainA);
+ }
+ if (!params.StrainB.equals("off")) {
+ mutEscStrainB = Double.parseDouble(params.StrainB);
+ }
+
+ start = LocalDate.parse(params.resDate);
+
+
+
+ if (vacCamp.equals("age")) {
+ compliance.put(60, 0.85); // 60+
+ compliance.put(18, 0.55); // 18-59
+ compliance.put(12, 0.20); // 12-17
+ compliance.put(0, 0.0); // 0 - 11
+ }
+ else if (vacCamp.equals("eu")) {
+ compliance.put(60, 0.40); // half of 80% (which reflects the current percentage of people in Dland who are boostered)
+ compliance.put(18, 0.);
+ compliance.put(12, 0.);
+ compliance.put(0, 0.);
+ }
+ else if (vacCamp.equals("off")) {
+
+ } else {
+ throw new RuntimeException("Not a valid option for vaccinationCampaignType");
+ }
+ }
+//
+ bind(VaccinationStrategyBMBF0617.Config.class).toInstance(new VaccinationStrategyBMBF0617.Config(start, 30, vaccinationType, compliance));
+
+ //initial antibodies
+ Map> initialAntibodies = new HashMap<>();
+ Map> antibodyRefreshFactors = new HashMap<>();
+ configureAntibodies(initialAntibodies, antibodyRefreshFactors, mutEscDelta, mutEscBa1, mutEscBa5, mutEscStrainA, mutEscStrainB);
+
+ AntibodyModel.Config antibodyConfig = new AntibodyModel.Config(initialAntibodies, antibodyRefreshFactors);
+
+ double immuneSigma = 3.0;
+ if (params != null) {
+ antibodyConfig.setImmuneReponseSigma(immuneSigma);
+ }
+
+ bind(AntibodyModel.Config.class).toInstance(antibodyConfig);
+
+ }
+
+ private void configureAntibodies(Map> initialAntibodies,
+ Map> antibodyRefreshFactors,
+ double mutEscDelta, double mutEscBa1, double mutEscBa5, double mutEscStrainA, double mutEscStrainB) {
+ for (VaccinationType immunityType : VaccinationType.values()) {
+ initialAntibodies.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+
+ if (immunityType == VaccinationType.mRNA) {
+ initialAntibodies.get(immunityType).put(virusStrain, 29.2); //10.0
+ }
+ else if (immunityType == VaccinationType.vector) {
+ initialAntibodies.get(immunityType).put(virusStrain, 6.8); //2.5
+ }
+ else {
+ initialAntibodies.get(immunityType).put(virusStrain, 5.0);
+ }
+ }
+ }
+
+ for (VirusStrain immunityType : VirusStrain.values()) {
+ initialAntibodies.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+ initialAntibodies.get(immunityType).put(virusStrain, 5.0);
+ }
+ }
+
+ //mRNAAlpha, mRNADelta, mRNABA1 comes from Sydney's calibration.
+ //The other values come from Rössler et al.
+
+ //Wildtype
+ double mRNAAlpha = 29.2;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.SARS_CoV_2, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
+
+ //Alpha
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.ALPHA, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.ALPHA, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.ALPHA, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.ALPHA, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.ALPHA, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
+
+ //DELTA
+ double mRNADelta = mRNAAlpha / mutEscDelta;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.DELTA, mRNADelta);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.DELTA, mRNADelta * 150./300.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.DELTA, mRNADelta * 64./300.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.DELTA, mRNADelta * 64./300.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.DELTA, mRNADelta * 450./300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1 / mutEscBa5);
+
+ //BA.1
+ double mRNABA1 = mRNADelta / mutEscBa1;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA1, mRNABA1);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA1, mRNABA1 * 4./20.); //???
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA1, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / 1.4);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscBa5); //todo: is 1.4
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscBa5 / mutEscStrainA);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha / mutEscBa5);
+
+ //BA.2
+ double mRNABA2 = mRNABA1;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA2, mRNABA2);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA2, mRNABA2 * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / 1.4);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA2, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscBa5);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscBa5 / mutEscStrainA);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha / mutEscBa5);
+
+
+ //BA.5
+ double mRNABa5 = mRNABA2 / mutEscBa5;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA5, mRNABa5);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA5, mRNABa5 * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA5, 64.0 / 300. / mutEscBa5);// todo: do we need 1.4?
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA5, 64.0 / 300./ mutEscBa5);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA5, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.OMICRON_BA5, 64.0 / 300./ mutEscStrainA); //todo ???
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.OMICRON_BA5, 64.0 / 300. / mutEscBa5 / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha / mutEscBa5);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha);
+
+ //StrainA
+ double mRNAStrainA = mRNABa5 / mutEscStrainA;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_A, mRNAStrainA);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_A, mRNAStrainA * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_A, mRNAStrainA * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_A, mRNAStrainA * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_A, mRNAStrainA * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscBa5 /mutEscStrainA);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_A, 64.0 / 300./ mutEscBa5 /mutEscStrainA);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscStrainA);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_A, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscStrainA / mutEscStrainB / mutEscBa5);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscBa5 / mutEscStrainA);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainA);
+
+ //StrainB
+ double mRNAStrainB = mRNABA2 / mutEscStrainB;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_B, mRNAStrainB);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_B, mRNAStrainB * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_B, mRNAStrainB * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_B, mRNAStrainB * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_B, mRNAStrainB * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscStrainB);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_B, 64.0 / 300./ mutEscStrainB);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscStrainB / mutEscBa5);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_B, 64.0 / 300./ mutEscStrainA / mutEscStrainB / mutEscBa5);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_B, 64.0 / 300.);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainB / mutEscBa5);
+
+
+ for (VaccinationType immunityType : VaccinationType.values()) {
+ antibodyRefreshFactors.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+
+ if (immunityType == VaccinationType.mRNA) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else if (immunityType == VaccinationType.vector) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 5.0);
+ }
+ else if (immunityType == VaccinationType.ba1Update) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else if (immunityType == VaccinationType.ba5Update) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, Double.NaN);
+ }
+
+ }
+ }
+
+ for (VirusStrain immunityType : VirusStrain.values()) {
+ antibodyRefreshFactors.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ }
+
+
+
+// System.out.print("immunityGiver");
+// for (VirusStrain immunityFrom : VirusStrain.values()) {
+// if (immunityFrom == VirusStrain.OMICRON_BA1) {
+// System.out.print( "," + "BA.1");
+// } else if (immunityFrom == VirusStrain.OMICRON_BA2) {
+// System.out.print( "," + "BA.2");
+// } else {
+// System.out.print( "," + immunityFrom);
+// }
+// }
+//
+//
+// for (ImmunityEvent immunityGiver : VaccinationType.values()) {
+// System.out.print("\n" + immunityGiver);
+// for (VirusStrain immunityFrom : VirusStrain.values()) {
+// System.out.print("," + String.format("%.3g", initialAntibodies.get(immunityGiver).get(immunityFrom)));
+// }
+// }
+// for (ImmunityEvent immunityGiver : VirusStrain.values()) {
+// System.out.print("\n" + immunityGiver);
+// for (VirusStrain immunityFrom : VirusStrain.values()) {
+// System.out.print("," + String.format("%.3g", initialAntibodies.get(immunityGiver).get(immunityFrom)));
+// }
+// }
+//
+// System.out.println();
+
+ }
+ });
+
+ }
+
+ private SnzCologneProductionScenario getBindings(double pHousehold, Params params) {
+ return new SnzCologneProductionScenario.Builder()
+ .setCarnivalModel(SnzCologneProductionScenario.CarnivalModel.yes)
+ .setSebastianUpdate(true)
+ .setLeisureCorrection(1.3) //params == null ? 0.0 : params.actCorrection)
+ .setScaleForActivityLevels(1.3)
+ .setSuscHouseholds_pct(pHousehold)
+ .setActivityHandling(EpisimConfigGroup.ActivityHandling.startOfDay)
+// .setTestingModel(params != null ? FlexibleTestingModel.class : DefaultTestingModel.class)
+ .setInfectionModel(InfectionModelWithAntibodies.class)
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return Metadata.of("cologne", "calibration");
+ }
+
+ @Override
+ public Collection postProcessing() {
+ return List.of(
+ new VaccinationEffectiveness().withArgs(),
+ new RValuesFromEvents().withArgs(),
+ new VaccinationEffectivenessFromPotentialInfections().withArgs("--remove-infected"),
+ new FilterEvents().withArgs("--output","./output/"),
+ new HospitalNumbersFromEvents().withArgs("--output","./output/","--input","/scratch/projects/bzz0020/episim-input")
+// new SecondaryAttackRateFromEvents().withArgs()
+ );
+ }
+
+ @Override
+ public Config prepareConfig(int id, Params params) {
+
+ if (DEBUG_MODE) {
+ if (runCount == 0){ //&& params.strAEsc != 0.0 && params.ba5Inf == 0. && params.eduTest.equals("true")) {
+ runCount++;
+ } else {
+ return null;
+ }
+ }
+
+ SnzCologneProductionScenario module = getBindings(0.0, params);
+
+ Config config = module.config();
+
+
+ config.global().setRandomSeed(params.seed);
+
+ EpisimConfigGroup episimConfig = ConfigUtils.addOrGetModule(config, EpisimConfigGroup.class);
+
+
+ episimConfig.setCalibrationParameter(episimConfig.getCalibrationParameter() * 1.2);
+
+
+
+ //---------------------------------------
+ // S T R A I N S
+ //---------------------------------------
+
+ VirusStrainConfigGroup virusStrainConfigGroup = ConfigUtils.addOrGetModule(config, VirusStrainConfigGroup.class);
+
+
+// virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * params.deltaTheta);
+
+ //BA5
+ double ba5Inf = 1.0;
+ double oHos = virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA2).getFactorSeriouslySick();
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA2).getInfectiousness() * ba5Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorSeriouslySick(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorSeriouslySickVaccinated(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorCritical(oHos);
+
+
+// STRAIN_A
+ if (!params.StrainA.equals("off")) {
+
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA5).getInfectiousness() * ba5Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setFactorSeriouslySick(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setFactorSeriouslySickVaccinated(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setFactorCritical(oHos);
+ }
+
+// STRAIN_B
+ if (!params.StrainB.equals("off")) {
+
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA5).getInfectiousness() * ba5Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setFactorSeriouslySick(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setFactorSeriouslySickVaccinated(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setFactorCritical(oHos);
+ }
+
+ // remove age-based susceptibility of strains starting with DELTA
+
+ String ageSusc = "false";
+ if (!Boolean.parseBoolean(ageSusc)) {
+ TreeMap nonSteppedAgeSusceptibility = new TreeMap<>(Map.of(
+ 19, 1d,
+ 20, 1d
+ ));
+
+ for (VirusStrain strain : List.of(VirusStrain.DELTA, VirusStrain.OMICRON_BA1, VirusStrain.OMICRON_BA2, VirusStrain.OMICRON_BA5, VirusStrain.STRAIN_A)) {
+ virusStrainConfigGroup.getOrAddParams(strain).setAgeSusceptibility(nonSteppedAgeSusceptibility);
+ }
+ }
+
+ // increase infectivity of alpha
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.ALPHA).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.ALPHA).getInfectiousness() * 1.4);
+
+ double deltaTheta = 0.9;
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * deltaTheta);
+ double ba1Inf = 1.9; // 2.0,2.1,2.2
+ double ba2Inf = 1.7;
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA1).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * ba1Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA2).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * ba1Inf * ba2Inf);
+
+
+
+
+
+
+ //---------------------------------------
+ // I M P O R T
+ //---------------------------------------
+
+ Map infPerDayAlpha = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.ALPHA, new TreeMap<>()));
+
+
+ // reconfig disease import of alpha
+ LocalDate startDateAlpha = LocalDate.parse("2021-01-15");
+
+ for (int i = 0; i < 7; i++) {
+ infPerDayAlpha.put(startDateAlpha.plusDays(i), 4);
+ }
+
+
+ infPerDayAlpha.put(startDateAlpha.plusDays(7), 1);
+
+ episimConfig.setInfections_pers_per_day(VirusStrain.ALPHA, infPerDayAlpha);
+
+
+ configureFutureDiseaseImport(params, episimConfig);
+
+ //---------------------------------------
+ // R E S T R I C T I O N S
+ //---------------------------------------
+
+ FixedPolicy.ConfigBuilder builder = FixedPolicy.parse(episimConfig.getPolicy());
+
+ //school
+ String schoolUpdate = "yes";
+ if(schoolUpdate.equals("yes")) {
+ // school closed completely until 21.2.2022
+ builder.restrict(LocalDate.parse("2021-01-11"), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other");
+ builder.restrict(LocalDate.parse("2021-02-21"), 0.5, "educ_primary");
+ builder.restrict(LocalDate.parse("2021-03-15"), 0.5, "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other");
+
+ } else if (schoolUpdate.equals("no")) {
+
+ } else {
+ throw new RuntimeException("param value doesn't exist");
+ }
+
+ String schoolTest = "later";
+ if (schoolTest.equals("later")) {
+ TestingConfigGroup testingConfigGroup = ConfigUtils.addOrGetModule(config, TestingConfigGroup.class);
+ TestingConfigGroup.TestingParams rapidTest = testingConfigGroup.getOrAddParams(TestType.RAPID_TEST);
+// TestingConfigGroup.TestingParams pcrTest = testingConfigGroup.getOrAddParams(TestType.PCR);
+ Map> testingRateForActivitiesRapid = rapidTest.getTestingRateForActivities();
+// Map> testingRateForActivitiesPCR = pcrTest.getTestingRateForActivities();
+
+
+ for (LocalDate date = LocalDate.parse("2021-03-19"); date.isBefore(LocalDate.parse("2021-04-25")); date = date.plusDays(1)) {
+
+ testingRateForActivitiesRapid.get("educ_kiga").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_primary").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_secondary").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_tertiary").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_other").put(date, 0.);
+
+ }
+
+ testingRateForActivitiesRapid.get("educ_kiga").put(LocalDate.parse("2021-09-20"), 0.);
+ testingRateForActivitiesRapid.get("educ_primary").put(LocalDate.parse("2021-09-20"), 0.);
+
+// testingRateForActivitiesPCR.get("educ_primary").put(LocalDate.parse("2021-05-10"), 0.4);
+ testingRateForActivitiesRapid.get("educ_secondary").put(LocalDate.parse("2021-05-10"), 0.4);
+ testingRateForActivitiesRapid.get("educ_tertiary").put(LocalDate.parse("2021-05-10"), 0.4);
+ testingRateForActivitiesRapid.get("educ_other").put(LocalDate.parse("2021-05-10"), 0.4);
+
+ } else if (schoolTest.equals("base")) {
+
+ }else {
+ throw new RuntimeException("param value doesn't exist");
+ }
+
+
+ // masks
+ //pt: masks
+ String maskType = "45to45";
+ if (maskType.equals("45to45")) {
+ for (LocalDate date = LocalDate.parse("2020-04-21"); date.isBefore(LocalDate.parse("2021-05-01")); date = date.plusDays(1)) {
+ builder.restrict(date, Restriction.ofMask(Map.of(FaceMask.CLOTH, 0.45, FaceMask.SURGICAL, 0.45)), "pt", "errands", "shop_daily", "shop_other");
+
+ }
+ } else if (maskType.equals("base")) {
+
+ } else {
+ throw new RuntimeException("param value doesn't exist");
+ }
+
+ episimConfig.setPolicy(builder.build());
+
+
+ //---------------------------------------
+ // M I S C
+ //---------------------------------------
+
+ // vaccination
+ VaccinationConfigGroup vaccinationConfig = ConfigUtils.addOrGetModule(config, VaccinationConfigGroup.class);
+ vaccinationConfig.setUseIgA(Boolean.parseBoolean("true"));
+ vaccinationConfig.setTimePeriodIgA(730.);
+
+
+ //modify contact intensity
+ double workCi = 0.75;
+ episimConfig.getOrAddContainerParams("work").setContactIntensity(episimConfig.getOrAddContainerParams("work").getContactIntensity() * workCi);
+ episimConfig.getOrAddContainerParams("business").setContactIntensity(episimConfig.getOrAddContainerParams("business").getContactIntensity() * workCi);
+
+
+ double leisureCi = 0.4;
+ episimConfig.getOrAddContainerParams("leisure").setContactIntensity(episimConfig.getOrAddContainerParams("leisure").getContactIntensity() * leisureCi);
+ episimConfig.getOrAddContainerParams("visit").setContactIntensity(episimConfig.getOrAddContainerParams("visit").getContactIntensity() * leisureCi);
+
+
+ double schoolCi = 0.75;
+ episimConfig.getOrAddContainerParams("educ_kiga").setContactIntensity(episimConfig.getOrAddContainerParams("educ_kiga").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_primary").setContactIntensity(episimConfig.getOrAddContainerParams("educ_primary").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_secondary").setContactIntensity(episimConfig.getOrAddContainerParams("educ_secondary").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_tertiary").setContactIntensity(episimConfig.getOrAddContainerParams("educ_tertiary").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_higher").setContactIntensity(episimConfig.getOrAddContainerParams("educ_higher").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_other").setContactIntensity(episimConfig.getOrAddContainerParams("educ_other").getContactIntensity() * schoolCi);
+
+
+ if (DEBUG_MODE) {
+ UtilsJR.produceDiseaseImportPlot(episimConfig.getInfections_pers_per_day());
+
+ }
+
+ return config;
+ }
+
+ private void configureFutureDiseaseImport(Params params, EpisimConfigGroup episimConfig) {
+ Map infPerDayBa1 = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.OMICRON_BA1, new TreeMap<>()));
+ Map infPerDayBa2 = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.OMICRON_BA2, new TreeMap<>()));
+ Map infPerDayBa5 = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.OMICRON_BA5, new TreeMap<>()));
+ Map infPerDayStrA = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.STRAIN_A, new TreeMap<>()));
+ Map infPerDayStrB = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.STRAIN_B, new TreeMap<>()));
+
+
+ // add initial impulses for strains
+ //BA.1
+// LocalDate ba1Date = LocalDate.parse(params.ba1Date);
+// for (int i = 0; i < 7; i++) {
+// infPerDayBa1.put(ba1Date.plusDays(i), 4);
+// }
+// infPerDayBa1.put(ba1Date.plusDays(7), 1);
+
+
+ //BA.2
+ LocalDate ba2Date = LocalDate.parse("2021-12-18");
+ for (int i = 0; i < 7; i++) {
+ infPerDayBa2.put(ba2Date.plusDays(i), 4);
+ }
+ infPerDayBa2.put(ba2Date.plusDays(7), 1);
+
+ //BA.5
+ LocalDate ba5Date = LocalDate.parse("2022-04-10");
+ for (int i = 0; i < 7; i++) {
+ infPerDayBa5.put(ba5Date.plusDays(i), 4);
+ }
+ infPerDayBa5.put(ba5Date.plusDays(7), 1);
+
+ //StrainA
+ if (!params.StrainA.equals("off")) {
+ infPerDayStrA.put(LocalDate.parse("2020-01-01"), 0);
+ LocalDate strADate = LocalDate.parse("2022-11-01");
+ for (int i = 0; i < 7; i++) {
+ infPerDayStrA.put(strADate.plusDays(i), 4);
+ }
+ infPerDayStrA.put(strADate.plusDays(7), 1);
+ }
+
+ //StrainB
+ if (!params.StrainB.equals("off")) {
+ infPerDayStrB.put(LocalDate.parse("2020-01-01"), 0);
+ LocalDate strBDate = LocalDate.parse("2022-11-01");
+ for (int i = 0; i < 7; i++) {
+ infPerDayStrB.put(strBDate.plusDays(i), 4);
+ }
+ infPerDayStrB.put(strBDate.plusDays(7), 1);
+ }
+
+
+ // add projected disease import for vacation waves after initial disease import
+ int facBa2 = 4;
+ int facBa5 = 4;
+ int facStrAB = 4;
+
+ LocalDate dateBa2 = LocalDate.parse("2022-01-27"); // local min of disease import
+ LocalDate dateBa5 = LocalDate.parse("2022-05-01"); // after vaca import
+ LocalDate dateStrainAB = LocalDate.parse("2022-11-18"); // after vaca import
+
+
+ NavigableMap data = DataUtils.readDiseaseImport(SnzCologneProductionScenario.INPUT.resolve("cologneDiseaseImport_Projected.csv"));
+ LocalDate date = null;
+ for (Map.Entry entry : data.entrySet()) {
+ date = entry.getKey();
+ double factor = 0.25 * 2352476. / 919936.; //25% sample, data is given for Cologne City so we have to scale it to the whole model
+//
+ double cases = factor * entry.getValue();
+
+ if (date.isAfter(dateStrainAB) && (!params.StrainA.equals("off") || !params.StrainB.equals("off"))) {
+ if (!params.StrainA.equals("off") && !params.StrainB.equals("off")) {
+ infPerDayStrA.put(date, ((int) cases * facStrAB) == 0 ? 1 : (int) (0.5 * cases * facStrAB));
+ infPerDayStrB.put(date, ((int) cases * facStrAB) == 0 ? 1 : (int) (0.5 * cases * facStrAB));
+ }
+ else if (!params.StrainA.equals("off")) {
+ infPerDayStrA.put(date, ((int) cases * facStrAB) == 0 ? 1 : (int) (cases * facStrAB));
+ }
+ else if (!params.StrainB.equals("off")) {
+ infPerDayStrB.put(date, ((int) cases * facStrAB) == 0 ? 1 : (int) (cases * facStrAB));
+ }
+ else {
+ throw new RuntimeException();
+ }
+ infPerDayBa5.put(date, 1);
+ infPerDayBa2.put(date, 1);
+ } else if (date.isAfter(dateBa5)) {
+ infPerDayBa5.put(date, ((int) cases * facBa5) == 0 ? 1 : (int) (cases * facBa5));
+ infPerDayBa2.put(date, 1);
+ } else if (date.isAfter(dateBa2)) {
+ infPerDayBa2.put(date, ((int) cases * facBa2) == 0 ? 1 : (int) (cases * facBa2));
+ }
+
+ }
+
+ // save disease import
+ episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA1, infPerDayBa1);
+ episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA2, infPerDayBa2);
+ episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA5, infPerDayBa5);
+
+ if (!params.StrainA.equals("off")) {
+ episimConfig.setInfections_pers_per_day(VirusStrain.STRAIN_A, infPerDayStrA);
+ }
+ if (!params.StrainB.equals("off")) {
+ episimConfig.setInfections_pers_per_day(VirusStrain.STRAIN_B, infPerDayStrB);
+ }
+ }
+
+ public static final class Params {
+ // general
+ @GenerateSeeds(5)
+ public long seed;
+
+ @StringParameter({"off", "3.0", "6.0"})
+ public String StrainA;
+
+ @StringParameter({"off", "3.0", "6.0"})
+ public String StrainB;
+
+ @StringParameter({"2022-12-01"})
+ public String resDate;
+
+// @StringParameter({"false", "true"})
+// public String igA;
+ // vaccination campaign
+ @StringParameter({"ba1Update", "ba5Update", "mRNA", "off"})
+ public String vacType;
+ }
+
+
+ public static void main(String[] args) {
+ String[] args2 = {
+ RunParallel.OPTION_SETUP, CologneBMBF20220805.class.getName(),
+ RunParallel.OPTION_PARAMS, Params.class.getName(),
+ RunParallel.OPTION_TASKS, Integer.toString(1),
+ RunParallel.OPTION_ITERATIONS, Integer.toString(1000),
+ RunParallel.OPTION_METADATA
+ };
+
+ RunParallel.main(args2);
+ }
+
+
+}
+
diff --git a/src/main/java/org/matsim/run/batch/CologneBMBF20220805_IfSG.java b/src/main/java/org/matsim/run/batch/CologneBMBF20220805_IfSG.java
new file mode 100644
index 000000000..57bc3a72e
--- /dev/null
+++ b/src/main/java/org/matsim/run/batch/CologneBMBF20220805_IfSG.java
@@ -0,0 +1,993 @@
+package org.matsim.run.batch;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Module;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.util.Modules;
+import it.unimi.dsi.fastutil.ints.Int2DoubleAVLTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2DoubleMap;
+import org.matsim.core.config.Config;
+import org.matsim.core.config.ConfigUtils;
+import org.matsim.episim.*;
+import org.matsim.episim.analysis.*;
+import org.matsim.episim.model.*;
+import org.matsim.episim.model.testing.DefaultTestingModel;
+import org.matsim.episim.model.testing.FlexibleTestingModel;
+import org.matsim.episim.model.testing.TestType;
+import org.matsim.episim.model.vaccination.VaccinationModel;
+import org.matsim.episim.model.vaccination.VaccinationStrategyBMBF0617;
+import org.matsim.episim.policy.FixedPolicy;
+import org.matsim.episim.policy.Restriction;
+import org.matsim.run.RunParallel;
+import org.matsim.run.modules.SnzCologneProductionScenario;
+
+import javax.annotation.Nullable;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.function.BiFunction;
+
+
+/**
+ * Batch for Bmbf runs
+ */
+public class CologneBMBF20220805_IfSG implements BatchRun {
+
+ boolean DEBUG_MODE = false;
+ int runCount = 0;
+
+ @Nullable
+ @Override
+ public Module getBindings(int id, @Nullable Params params) {
+ return Modules.override(getBindings(0.0, params)).with(new AbstractModule() {
+ @Override
+ protected void configure() {
+
+ // BIND ANTIBODY MODEL
+ double mutEscDelta = 29.2 / 10.9;
+ double mutEscBa1 = 10.9 / 1.9;
+ double mutEscBa5 = 2.9;
+
+ double mutEscStrainA = 0.;
+ double mutEscStrainB = 0.;
+
+ if (params != null && !params.StrainA.equals("off")) {
+ mutEscStrainA = Double.parseDouble(params.StrainA);
+ }
+ if (params != null && !params.StrainB.equals("off")) {
+ mutEscStrainB = Double.parseDouble(params.StrainB);
+ }
+
+ Map> initialAntibodies = new HashMap<>();
+ Map> antibodyRefreshFactors = new HashMap<>();
+ configureAntibodies(initialAntibodies, antibodyRefreshFactors, mutEscDelta, mutEscBa1, mutEscBa5, mutEscStrainA, mutEscStrainB);
+
+ AntibodyModel.Config antibodyConfig = new AntibodyModel.Config(initialAntibodies, antibodyRefreshFactors);
+
+ double immuneSigma = 3.0;
+ if (params != null) {
+ antibodyConfig.setImmuneReponseSigma(immuneSigma);
+ }
+
+ bind(AntibodyModel.Config.class).toInstance(antibodyConfig);
+
+
+ // BIND VACCINATION MODEL
+
+ Multibinder set = Multibinder.newSetBinder(binder(), VaccinationModel.class);
+
+ set.addBinding().to(VaccinationStrategyBMBF0617.class).in(Singleton.class);
+
+ LocalDate start = LocalDate.parse("2022-12-01");
+
+ VaccinationType vaccinationType = VaccinationType.mRNA;
+
+ Int2DoubleMap compliance = new Int2DoubleAVLTreeMap();
+ compliance.put(60, 0.0);
+ compliance.put(18, 0.0);
+ compliance.put(12, 0.0);
+ compliance.put(0, 0.0);
+
+ String vacCamp = "off";
+
+ if (params != null) {
+
+ if (!params.vacType.equals("off")) {
+ vacCamp = "age";
+ vaccinationType = VaccinationType.valueOf(params.vacType);
+ }
+
+// start = LocalDate.parse(params.resDate);
+
+
+ switch (vacCamp) {
+ case "age":
+ compliance.put(60, 0.85); // 60+
+ compliance.put(18, 0.55); // 18-59
+ compliance.put(12, 0.20); // 12-17
+ compliance.put(0, 0.0); // 0 - 11
+ break;
+ case "eu":
+ compliance.put(60, 0.40); // half of 80% (which reflects the current percentage of people in Dland who are boostered)
+ compliance.put(18, 0.);
+ compliance.put(12, 0.);
+ compliance.put(0, 0.);
+ break;
+ case "off":
+ break;
+ default:
+ throw new RuntimeException("Not a valid option for vaccinationCampaignType");
+ }
+ }
+
+ bind(VaccinationStrategyBMBF0617.Config.class).toInstance(new VaccinationStrategyBMBF0617.Config(start, 30, vaccinationType, compliance));
+
+
+
+ // BIND TESTING MODEL
+ if (params != null){
+
+ // date of no restrictions and new restrictions
+ String unResDate = "2022-04-25";
+ LocalDate unresDate = LocalDate.parse(unResDate);
+ LocalDate resDate = LocalDate.parse(params.resDate);
+
+// String[] s = params.gpMonths.split("-");
+
+ // Green pass validity for vaccinated and infected
+// int vacDays = Integer.parseInt(s[0]) * 30;
+// int infDays = Integer.parseInt(s[1]) * 30;
+
+ // set days gp is valid
+ int vacDays = 3 * 30;
+ int infDays = 3 * 30;
+
+ // set testing scheme for each activity type
+ final CologneBMBF220628_3G.TestScheme leisTest;
+ final CologneBMBF220628_3G.TestScheme workTest;
+ final CologneBMBF220628_3G.TestScheme eduTest;
+ if (params.leis.equals("test") || params.leis.equals("all")) {
+ leisTest= CologneBMBF220628_3G.TestScheme.gp;
+ } else if (params.leis.equals("none") || params.leis.equals("mask")) {
+ leisTest = CologneBMBF220628_3G.TestScheme.none;
+ } else {
+ throw new RuntimeException();
+ }
+
+
+ if (params.work.equals("test") || params.work.equals("all")) {
+ workTest= CologneBMBF220628_3G.TestScheme.all;
+ } else if (params.work.equals("none") || params.work.equals("mask")|| params.work.equals("homeOff")) {
+ workTest = CologneBMBF220628_3G.TestScheme.none;
+ } else {
+ throw new RuntimeException();
+ }
+
+ if (params.edu.equals("maskVentTest")) {
+ eduTest = CologneBMBF220628_3G.TestScheme.all;
+ } else if (params.edu.equals("none")) {
+ eduTest = CologneBMBF220628_3G.TestScheme.none;
+ } else {throw new RuntimeException();}
+
+ bind(FlexibleTestingModel.TestRate.class).toInstance((person, day, dow, date, test, vac) -> {
+
+ if (date.isBefore(unresDate))
+ return vac.hasValidVaccination(person, day, date);
+
+ // When restrictions have been lifted, days valid is set to a high number
+ // many tests are voluntary
+ if (date.isBefore(resDate))
+ return vac.hasValidVaccination(person, day, date, 360);
+
+ // this returns true if for any activities, the person requires increased testing regime
+ BiFunction anyUnVac = (act, red) -> {
+
+ boolean res = false;
+ CologneBMBF220628_3G.TestScheme scheme = null;
+
+
+ if (act.equals("leisure"))
+ scheme = leisTest;
+ else if (act.equals("work"))
+ scheme = workTest;
+ else if (act.startsWith("edu"))
+ scheme = eduTest;
+
+ // null and none, will be false
+ if (scheme == CologneBMBF220628_3G.TestScheme.all)
+ res = true;
+ else if (scheme == CologneBMBF220628_3G.TestScheme.gp) {
+ res = (person.getNumVaccinations() == 0 || person.daysSince(EpisimPerson.VaccinationStatus.yes, day) > vacDays)
+ && !person.isRecentlyRecovered(day, infDays);
+
+ }
+
+ return red || res;
+ };
+
+ return !person.matchActivities(dow, anyUnVac, false);
+ });
+
+ bind(FlexibleTestingModel.TestPolicy.class).toInstance(new FlexibleTestingModel.TestPolicy() {
+ @Override
+ public boolean shouldTest(EpisimPerson person, int day, DayOfWeek dow, LocalDate date,
+ TestingConfigGroup test, VaccinationConfigGroup vac) {
+
+ if (date.isBefore(unresDate)) {
+
+ boolean testAllPersons = test.getTestAllPersonsAfter() != null && date.isAfter(test.getTestAllPersonsAfter());
+ return testAllPersons || !vac.hasGreenPass(person, day, date);
+ }
+
+ // after restrictions everybody is tested according to the rates
+ return true;
+ }
+ });
+
+ }
+
+ }
+
+ private void configureAntibodies(Map> initialAntibodies,
+ Map> antibodyRefreshFactors,
+ double mutEscDelta, double mutEscBa1, double mutEscBa5, double mutEscStrainA, double mutEscStrainB) {
+ for (VaccinationType immunityType : VaccinationType.values()) {
+ initialAntibodies.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+
+ if (immunityType == VaccinationType.mRNA) {
+ initialAntibodies.get(immunityType).put(virusStrain, 29.2); //10.0
+ }
+ else if (immunityType == VaccinationType.vector) {
+ initialAntibodies.get(immunityType).put(virusStrain, 6.8); //2.5
+ }
+ else {
+ initialAntibodies.get(immunityType).put(virusStrain, 5.0);
+ }
+ }
+ }
+
+ for (VirusStrain immunityType : VirusStrain.values()) {
+ initialAntibodies.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+ initialAntibodies.get(immunityType).put(virusStrain, 5.0);
+ }
+ }
+
+ //mRNAAlpha, mRNADelta, mRNABA1 comes from Sydney's calibration.
+ //The other values come from Rössler et al.
+
+ //Wildtype
+ double mRNAAlpha = 29.2;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.SARS_CoV_2, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
+
+ //Alpha
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.ALPHA, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.ALPHA, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.ALPHA, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.ALPHA, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.ALPHA, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
+
+ //DELTA
+ double mRNADelta = mRNAAlpha / mutEscDelta;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.DELTA, mRNADelta);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.DELTA, mRNADelta * 150./300.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.DELTA, mRNADelta * 64./300.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.DELTA, mRNADelta * 64./300.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.DELTA, mRNADelta * 450./300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1 / mutEscBa5);
+
+ //BA.1
+ double mRNABA1 = mRNADelta / mutEscBa1;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA1, mRNABA1);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA1, mRNABA1 * 4./20.); //???
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA1, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / 1.4);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscBa5); //todo: is 1.4
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscBa5 / mutEscStrainA);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha / mutEscBa5);
+
+ //BA.2
+ double mRNABA2 = mRNABA1;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA2, mRNABA2);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA2, mRNABA2 * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / 1.4);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA2, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscBa5);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscBa5 / mutEscStrainA);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha / mutEscBa5);
+
+
+ //BA.5
+ double mRNABa5 = mRNABA2 / mutEscBa5;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA5, mRNABa5);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA5, mRNABa5 * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA5, 64.0 / 300. / mutEscBa5);// todo: do we need 1.4?
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA5, 64.0 / 300./ mutEscBa5);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA5, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.OMICRON_BA5, 64.0 / 300./ mutEscStrainA); //todo ???
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.OMICRON_BA5, 64.0 / 300. / mutEscBa5 / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha / mutEscBa5);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha);
+
+ //StrainA
+ double mRNAStrainA = mRNABa5 / mutEscStrainA;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_A, mRNAStrainA);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_A, mRNAStrainA * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_A, mRNAStrainA * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_A, mRNAStrainA * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_A, mRNAStrainA * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscBa5 /mutEscStrainA);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_A, 64.0 / 300./ mutEscBa5 /mutEscStrainA);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscStrainA);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_A, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscStrainA / mutEscStrainB / mutEscBa5);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscBa5 / mutEscStrainA);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainA);
+
+ //StrainB
+ double mRNAStrainB = mRNABA2 / mutEscStrainB;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_B, mRNAStrainB);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_B, mRNAStrainB * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_B, mRNAStrainB * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_B, mRNAStrainB * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_B, mRNAStrainB * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscStrainB);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_B, 64.0 / 300./ mutEscStrainB);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscStrainB / mutEscBa5);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_B, 64.0 / 300./ mutEscStrainA / mutEscStrainB / mutEscBa5);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_B, 64.0 / 300.);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainB / mutEscBa5);
+
+
+ for (VaccinationType immunityType : VaccinationType.values()) {
+ antibodyRefreshFactors.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+
+ if (immunityType == VaccinationType.mRNA) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else if (immunityType == VaccinationType.vector) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 5.0);
+ }
+ else if (immunityType == VaccinationType.ba1Update) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else if (immunityType == VaccinationType.ba5Update) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, Double.NaN);
+ }
+
+ }
+ }
+
+ for (VirusStrain immunityType : VirusStrain.values()) {
+ antibodyRefreshFactors.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ }
+
+
+
+// System.out.print("immunityGiver");
+// for (VirusStrain immunityFrom : VirusStrain.values()) {
+// if (immunityFrom == VirusStrain.OMICRON_BA1) {
+// System.out.print( "," + "BA.1");
+// } else if (immunityFrom == VirusStrain.OMICRON_BA2) {
+// System.out.print( "," + "BA.2");
+// } else {
+// System.out.print( "," + immunityFrom);
+// }
+// }
+//
+//
+// for (ImmunityEvent immunityGiver : VaccinationType.values()) {
+// System.out.print("\n" + immunityGiver);
+// for (VirusStrain immunityFrom : VirusStrain.values()) {
+// System.out.print("," + String.format("%.3g", initialAntibodies.get(immunityGiver).get(immunityFrom)));
+// }
+// }
+// for (ImmunityEvent immunityGiver : VirusStrain.values()) {
+// System.out.print("\n" + immunityGiver);
+// for (VirusStrain immunityFrom : VirusStrain.values()) {
+// System.out.print("," + String.format("%.3g", initialAntibodies.get(immunityGiver).get(immunityFrom)));
+// }
+// }
+//
+// System.out.println();
+
+ }
+ });
+
+ }
+
+ private SnzCologneProductionScenario getBindings(double pHousehold, Params params) {
+ return new SnzCologneProductionScenario.Builder()
+ .setCarnivalModel(SnzCologneProductionScenario.CarnivalModel.yes)
+ .setSebastianUpdate(true)
+ .setLeisureCorrection(1.3) //params == null ? 0.0 : params.actCorrection)
+ .setScaleForActivityLevels(1.3)
+ .setSuscHouseholds_pct(pHousehold)
+ .setActivityHandling(EpisimConfigGroup.ActivityHandling.startOfDay)
+ .setTestingModel(params != null ? FlexibleTestingModel.class : DefaultTestingModel.class)
+ .setInfectionModel(InfectionModelWithAntibodies.class)
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return Metadata.of("cologne", "calibration");
+ }
+
+ @Override
+ public Collection postProcessing() {
+ return List.of(
+ new VaccinationEffectiveness().withArgs(),
+ new RValuesFromEvents().withArgs(),
+ new VaccinationEffectivenessFromPotentialInfections().withArgs("--remove-infected"),
+ new FilterEvents().withArgs("--output","./output/"),
+ new HospitalNumbersFromEvents().withArgs("--output","./output/","--input","/scratch/projects/bzz0020/episim-input")
+// new SecondaryAttackRateFromEvents().withArgs()
+ );
+ }
+
+ @Override
+ public Config prepareConfig(int id, Params params) {
+
+ if (DEBUG_MODE ) {
+ if (runCount == 0){ //&& params.strAEsc != 0.0 && params.ba5Inf == 0. && params.eduTest.equals("true")) {
+ runCount++;
+ } else {
+ return null;
+ }
+ }
+
+ SnzCologneProductionScenario module = getBindings(0.0, params);
+
+ Config config = module.config();
+
+
+ config.global().setRandomSeed(params.seed);
+
+ EpisimConfigGroup episimConfig = ConfigUtils.addOrGetModule(config, EpisimConfigGroup.class);
+
+
+ episimConfig.setCalibrationParameter(episimConfig.getCalibrationParameter() * 1.2);
+
+
+
+ //---------------------------------------
+ // S T R A I N S
+ //---------------------------------------
+
+ VirusStrainConfigGroup virusStrainConfigGroup = ConfigUtils.addOrGetModule(config, VirusStrainConfigGroup.class);
+
+
+// virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * params.deltaTheta);
+
+ //BA5
+ double ba5Inf = 1.0;
+ double oHos = virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA2).getFactorSeriouslySick();
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA2).getInfectiousness() * ba5Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorSeriouslySick(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorSeriouslySickVaccinated(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorCritical(oHos);
+
+
+// STRAIN_A
+ if (!params.StrainA.equals("off")) {
+
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA5).getInfectiousness() * ba5Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setFactorSeriouslySick(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setFactorSeriouslySickVaccinated(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setFactorCritical(oHos);
+ }
+
+// STRAIN_B
+ if (!params.StrainB.equals("off")) {
+
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA5).getInfectiousness() * ba5Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setFactorSeriouslySick(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setFactorSeriouslySickVaccinated(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setFactorCritical(oHos);
+ }
+
+ // remove age-based susceptibility of strains starting with DELTA
+
+ String ageSusc = "false";
+ if (!Boolean.parseBoolean(ageSusc)) {
+ TreeMap nonSteppedAgeSusceptibility = new TreeMap<>(Map.of(
+ 19, 1d,
+ 20, 1d
+ ));
+
+ for (VirusStrain strain : List.of(VirusStrain.DELTA, VirusStrain.OMICRON_BA1, VirusStrain.OMICRON_BA2, VirusStrain.OMICRON_BA5, VirusStrain.STRAIN_A)) {
+ virusStrainConfigGroup.getOrAddParams(strain).setAgeSusceptibility(nonSteppedAgeSusceptibility);
+ }
+ }
+
+ // increase infectivity of alpha
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.ALPHA).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.ALPHA).getInfectiousness() * 1.4);
+
+ double deltaTheta = 0.9;
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * deltaTheta);
+ double ba1Inf = 1.9; // 2.0,2.1,2.2
+ double ba2Inf = 1.7;
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA1).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * ba1Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA2).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * ba1Inf * ba2Inf);
+
+
+ //---------------------------------------
+ // I M P O R T
+ //---------------------------------------
+
+ Map infPerDayAlpha = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.ALPHA, new TreeMap<>()));
+
+
+ // reconfig disease import of alpha
+ LocalDate startDateAlpha = LocalDate.parse("2021-01-15");
+
+ for (int i = 0; i < 7; i++) {
+ infPerDayAlpha.put(startDateAlpha.plusDays(i), 4);
+ }
+
+
+ infPerDayAlpha.put(startDateAlpha.plusDays(7), 1);
+
+ episimConfig.setInfections_pers_per_day(VirusStrain.ALPHA, infPerDayAlpha);
+
+
+ configureFutureDiseaseImport(params, episimConfig);
+
+ //---------------------------------------
+ // R E S T R I C T I O N S
+ //---------------------------------------
+
+ FixedPolicy.ConfigBuilder builder = FixedPolicy.parse(episimConfig.getPolicy());
+
+ //school
+ String schoolUpdate = "yes";
+ if(schoolUpdate.equals("yes")) {
+ // school closed completely until 21.2.2022
+ builder.restrict(LocalDate.parse("2021-01-11"), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other");
+ builder.restrict(LocalDate.parse("2021-02-21"), 0.5, "educ_primary");
+ builder.restrict(LocalDate.parse("2021-03-15"), 0.5, "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other");
+
+ } else if (schoolUpdate.equals("no")) {
+
+ } else {
+ throw new RuntimeException("param value doesn't exist");
+ }
+
+ String schoolTest = "later";
+ if (schoolTest.equals("later")) {
+ TestingConfigGroup testingConfigGroup = ConfigUtils.addOrGetModule(config, TestingConfigGroup.class);
+ TestingConfigGroup.TestingParams rapidTest = testingConfigGroup.getOrAddParams(TestType.RAPID_TEST);
+// TestingConfigGroup.TestingParams pcrTest = testingConfigGroup.getOrAddParams(TestType.PCR);
+ Map> testingRateForActivitiesRapid = rapidTest.getTestingRateForActivities();
+// Map> testingRateForActivitiesPCR = pcrTest.getTestingRateForActivities();
+
+
+ for (LocalDate date = LocalDate.parse("2021-03-19"); date.isBefore(LocalDate.parse("2021-04-25")); date = date.plusDays(1)) {
+
+ testingRateForActivitiesRapid.get("educ_kiga").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_primary").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_secondary").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_tertiary").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_other").put(date, 0.);
+
+ }
+
+ testingRateForActivitiesRapid.get("educ_kiga").put(LocalDate.parse("2021-09-20"), 0.);
+ testingRateForActivitiesRapid.get("educ_primary").put(LocalDate.parse("2021-09-20"), 0.);
+
+// testingRateForActivitiesPCR.get("educ_primary").put(LocalDate.parse("2021-05-10"), 0.4);
+ testingRateForActivitiesRapid.get("educ_secondary").put(LocalDate.parse("2021-05-10"), 0.4);
+ testingRateForActivitiesRapid.get("educ_tertiary").put(LocalDate.parse("2021-05-10"), 0.4);
+ testingRateForActivitiesRapid.get("educ_other").put(LocalDate.parse("2021-05-10"), 0.4);
+
+ } else if (schoolTest.equals("base")) {
+
+ }else {
+ throw new RuntimeException("param value doesn't exist");
+ }
+
+
+ // masks
+ //pt: masks
+ String maskType = "45to45";
+ if (maskType.equals("45to45")) {
+ for (LocalDate date = LocalDate.parse("2020-04-21"); date.isBefore(LocalDate.parse("2021-05-01")); date = date.plusDays(1)) {
+ builder.restrict(date, Restriction.ofMask(Map.of(FaceMask.CLOTH, 0.45, FaceMask.SURGICAL, 0.45)), "pt", "errands", "shop_daily", "shop_other");
+
+ }
+ } else if (maskType.equals("base")) {
+
+ } else {
+ throw new RuntimeException("param value doesn't exist");
+ }
+
+ // -----------------------------------------
+
+ // new restrictions from IfSG
+ LocalDate restrictionDate = LocalDate.parse(params.resDate);
+
+ // testing rates
+
+ double gpTestRate = 0.;
+
+ TestingConfigGroup testingConfigGroup = ConfigUtils.addOrGetModule(config, TestingConfigGroup.class);
+ TestingConfigGroup.TestingParams pcrTest = testingConfigGroup.getOrAddParams(TestType.PCR);
+ Map> testingRateForActivitiesPcr = pcrTest.getTestingRateForActivities();
+ Map> testingRateForActivitiesPcrVac = pcrTest.getTestingRateForActivitiesVaccinated();
+
+ TestingConfigGroup.TestingParams rapidTest = testingConfigGroup.getOrAddParams(TestType.RAPID_TEST);
+ Map> testingRateForActivitiesRapid = rapidTest.getTestingRateForActivities();
+ Map> testingRateForActivitiesRapidVac = rapidTest.getTestingRateForActivitiesVaccinated();
+
+
+ // school
+ {
+ //pcr tests for younger kids
+ testingRateForActivitiesPcr.get("educ_kiga").put(restrictionDate, 0.4);
+ testingRateForActivitiesPcr.get("educ_primary").put(restrictionDate, 0.4);
+ testingRateForActivitiesPcrVac.get("educ_kiga").put(restrictionDate, gpTestRate);
+ testingRateForActivitiesPcrVac.get("educ_primary").put(restrictionDate, gpTestRate);
+
+ //add rapid tests for older kids
+ testingRateForActivitiesRapid.get("educ_secondary").put(restrictionDate, 0.6);
+ testingRateForActivitiesRapid.get("educ_tertiary").put(restrictionDate, 0.6);
+ testingRateForActivitiesRapid.get("educ_higher").put(restrictionDate, 0.6);
+ testingRateForActivitiesRapid.get("educ_other").put(restrictionDate, 0.6);
+ testingRateForActivitiesRapidVac.get("educ_secondary").put(restrictionDate, gpTestRate);
+ testingRateForActivitiesRapidVac.get("educ_tertiary").put(restrictionDate, gpTestRate);
+ testingRateForActivitiesRapidVac.get("educ_higher").put(restrictionDate, gpTestRate);
+ testingRateForActivitiesRapidVac.get("educ_other").put(restrictionDate, gpTestRate);
+ }
+
+ // work
+ {
+ testingRateForActivitiesRapid.get("work").put(restrictionDate, 0.6);
+ testingRateForActivitiesRapidVac.get("work").put(restrictionDate, gpTestRate);
+ }
+
+ // leisure:
+ {
+ testingRateForActivitiesRapid.get("leisure").put(restrictionDate, 0.45);
+ testingRateForActivitiesRapidVac.get("leisure").put(restrictionDate, gpTestRate);
+ }
+
+ //WORK
+ double homeOfficeFactor = 0.5;
+ switch (params.work) {
+ case "none":
+ break;
+ case "homeOff":
+ builder.restrict(restrictionDate, 0.78 * homeOfficeFactor, "work"); // dont include business bc harder to do from home office
+ builder.applyToRf(restrictionDate.plusDays(1).toString(), restrictionDate.plusDays(1000).toString(), (d, rf) -> rf * homeOfficeFactor, "work");
+ break;
+ case "test":
+ // handled in getBindings
+ break;
+ case "mask":
+ builder.restrict(restrictionDate, Restriction.ofMask(Map.of(FaceMask.SURGICAL, 0.9)), "work", "business");
+ break;
+ case "all":
+ builder.restrict(restrictionDate, 0.78 * homeOfficeFactor, "work");
+ builder.applyToRf(restrictionDate.plusDays(1).toString(), restrictionDate.plusDays(1000).toString(), (d, rf) -> rf * homeOfficeFactor, "work");
+ builder.restrict(restrictionDate, Restriction.ofMask(Map.of(FaceMask.SURGICAL, 0.9)), "work", "business");
+ break;
+ default:
+ throw new RuntimeException("invalid parameter");
+ }
+
+ //LEISURE
+ switch (params.leis) {
+ case "none":
+ break;
+ case "test":
+ // handled in getBindings
+ break;
+ case "mask":
+ builder.restrict(restrictionDate, Restriction.ofMask(Map.of(FaceMask.N95, 0.45)), "leisure");
+ case "all":
+ builder.restrict(restrictionDate, Restriction.ofMask(Map.of(FaceMask.N95, 0.45)), "leisure");
+ break;
+ default:
+ throw new RuntimeException("invalid parameter");
+ }
+
+ // shop, errands
+ switch (params.errands) {
+ case "none":
+ break;
+ case "mask":
+ builder.restrict(restrictionDate, Restriction.ofMask(Map.of(FaceMask.N95, 0.9)), "shop_daily", "shop_other", "errands");
+
+ break;
+ default:
+ throw new RuntimeException("invalid parameter");
+ }
+
+ //SCHOOL
+ // todo check mask rate
+ if (params.edu.equals("maskVentTest")) {
+ builder.restrict(restrictionDate, Restriction.ofCiCorrection(0.5), "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other", "educ_higher");
+ builder.restrict(restrictionDate, Restriction.ofMask(Map.of(
+ FaceMask.CLOTH, 0.0,
+ FaceMask.N95, 0.25,
+ FaceMask.SURGICAL, 0.25)),
+ "educ_secondary", "educ_higher", "educ_tertiary", "educ_other");
+
+ } else if (params.edu.equals("none")) {
+
+ } else {
+ throw new RuntimeException("invalid parameter");
+ }
+
+
+ // pt
+ switch (params.pt) {
+ case "none":
+ break;
+ case "mask":
+ builder.restrict(restrictionDate, Restriction.ofMask(Map.of(FaceMask.N95, 0.9)), "pt");
+ break;
+ default:
+ throw new RuntimeException("invalid parameter");
+ }
+
+
+ episimConfig.setPolicy(builder.build());
+
+
+ //---------------------------------------
+ // M I S C
+ //---------------------------------------
+
+ // vaccination
+ VaccinationConfigGroup vaccinationConfig = ConfigUtils.addOrGetModule(config, VaccinationConfigGroup.class);
+ vaccinationConfig.setUseIgA(Boolean.parseBoolean("true"));
+ vaccinationConfig.setTimePeriodIgA(730.);
+
+
+ //modify contact intensity
+ double workCi = 0.75;
+ episimConfig.getOrAddContainerParams("work").setContactIntensity(episimConfig.getOrAddContainerParams("work").getContactIntensity() * workCi);
+ episimConfig.getOrAddContainerParams("business").setContactIntensity(episimConfig.getOrAddContainerParams("business").getContactIntensity() * workCi);
+
+
+ double leisureCi = 0.4;
+ episimConfig.getOrAddContainerParams("leisure").setContactIntensity(episimConfig.getOrAddContainerParams("leisure").getContactIntensity() * leisureCi);
+ episimConfig.getOrAddContainerParams("visit").setContactIntensity(episimConfig.getOrAddContainerParams("visit").getContactIntensity() * leisureCi);
+
+
+ double schoolCi = 0.75;
+ episimConfig.getOrAddContainerParams("educ_kiga").setContactIntensity(episimConfig.getOrAddContainerParams("educ_kiga").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_primary").setContactIntensity(episimConfig.getOrAddContainerParams("educ_primary").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_secondary").setContactIntensity(episimConfig.getOrAddContainerParams("educ_secondary").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_tertiary").setContactIntensity(episimConfig.getOrAddContainerParams("educ_tertiary").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_higher").setContactIntensity(episimConfig.getOrAddContainerParams("educ_higher").getContactIntensity() * schoolCi);
+ episimConfig.getOrAddContainerParams("educ_other").setContactIntensity(episimConfig.getOrAddContainerParams("educ_other").getContactIntensity() * schoolCi);
+
+
+ if (DEBUG_MODE) {
+ UtilsJR.produceDiseaseImportPlot(episimConfig.getInfections_pers_per_day());
+
+ }
+
+ return config;
+ }
+
+ private void configureFutureDiseaseImport(Params params, EpisimConfigGroup episimConfig) {
+ Map infPerDayBa1 = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.OMICRON_BA1, new TreeMap<>()));
+ Map infPerDayBa2 = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.OMICRON_BA2, new TreeMap<>()));
+ Map infPerDayBa5 = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.OMICRON_BA5, new TreeMap<>()));
+ Map infPerDayStrA = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.STRAIN_A, new TreeMap<>()));
+ Map infPerDayStrB = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.STRAIN_B, new TreeMap<>()));
+
+
+ // add initial impulses for strains
+ //BA.1
+// LocalDate ba1Date = LocalDate.parse(params.ba1Date);
+// for (int i = 0; i < 7; i++) {
+// infPerDayBa1.put(ba1Date.plusDays(i), 4);
+// }
+// infPerDayBa1.put(ba1Date.plusDays(7), 1);
+
+
+ //BA.2
+ LocalDate ba2Date = LocalDate.parse("2021-12-18");
+ for (int i = 0; i < 7; i++) {
+ infPerDayBa2.put(ba2Date.plusDays(i), 4);
+ }
+ infPerDayBa2.put(ba2Date.plusDays(7), 1);
+
+ //BA.5
+ LocalDate ba5Date = LocalDate.parse("2022-04-10");
+ for (int i = 0; i < 7; i++) {
+ infPerDayBa5.put(ba5Date.plusDays(i), 4);
+ }
+ infPerDayBa5.put(ba5Date.plusDays(7), 1);
+
+ //StrainA
+ if (!params.StrainA.equals("off")) {
+ infPerDayStrA.put(LocalDate.parse("2020-01-01"), 0);
+ LocalDate strADate = LocalDate.parse("2022-11-01");
+ for (int i = 0; i < 7; i++) {
+ infPerDayStrA.put(strADate.plusDays(i), 4);
+ }
+ infPerDayStrA.put(strADate.plusDays(7), 1);
+ }
+
+ //StrainB
+ if (!params.StrainB.equals("off")) {
+ infPerDayStrB.put(LocalDate.parse("2020-01-01"), 0);
+ LocalDate strBDate = LocalDate.parse("2022-11-01");
+ for (int i = 0; i < 7; i++) {
+ infPerDayStrB.put(strBDate.plusDays(i), 4);
+ }
+ infPerDayStrB.put(strBDate.plusDays(7), 1);
+ }
+
+
+ // add projected disease import for vacation waves after initial disease import
+ int facBa2 = 4;
+ int facBa5 = 4;
+ int facStrAB = 4;
+
+ LocalDate dateBa2 = LocalDate.parse("2022-01-27"); // local min of disease import
+ LocalDate dateBa5 = LocalDate.parse("2022-05-01"); // after vaca import
+ LocalDate dateStrainAB = LocalDate.parse("2022-11-18"); // after vaca import
+
+
+ NavigableMap data = DataUtils.readDiseaseImport(SnzCologneProductionScenario.INPUT.resolve("cologneDiseaseImport_Projected.csv"));
+ LocalDate date = null;
+ for (Map.Entry entry : data.entrySet()) {
+ date = entry.getKey();
+ double factor = 0.25 * 2352476. / 919936.; //25% sample, data is given for Cologne City so we have to scale it to the whole model
+//
+ double cases = factor * entry.getValue();
+
+ if (date.isAfter(dateStrainAB) && (!params.StrainA.equals("off") || !params.StrainB.equals("off"))) {
+ if (!params.StrainA.equals("off") && !params.StrainB.equals("off")) {
+ infPerDayStrA.put(date, ((int) cases * facStrAB) == 0 ? 1 : (int) (0.5 * cases * facStrAB));
+ infPerDayStrB.put(date, ((int) cases * facStrAB) == 0 ? 1 : (int) (0.5 * cases * facStrAB));
+ }
+ else if (!params.StrainA.equals("off")) {
+ infPerDayStrA.put(date, ((int) cases * facStrAB) == 0 ? 1 : (int) (cases * facStrAB));
+ }
+ else if (!params.StrainB.equals("off")) {
+ infPerDayStrB.put(date, ((int) cases * facStrAB) == 0 ? 1 : (int) (cases * facStrAB));
+ }
+ else {
+ throw new RuntimeException();
+ }
+ infPerDayBa5.put(date, 1);
+ infPerDayBa2.put(date, 1);
+ } else if (date.isAfter(dateBa5)) {
+ infPerDayBa5.put(date, ((int) cases * facBa5) == 0 ? 1 : (int) (cases * facBa5));
+ infPerDayBa2.put(date, 1);
+ } else if (date.isAfter(dateBa2)) {
+ infPerDayBa2.put(date, ((int) cases * facBa2) == 0 ? 1 : (int) (cases * facBa2));
+ }
+
+ }
+
+ // save disease import
+ episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA1, infPerDayBa1);
+ episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA2, infPerDayBa2);
+ episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA5, infPerDayBa5);
+
+ if (!params.StrainA.equals("off")) {
+ episimConfig.setInfections_pers_per_day(VirusStrain.STRAIN_A, infPerDayStrA);
+ }
+ if (!params.StrainB.equals("off")) {
+ episimConfig.setInfections_pers_per_day(VirusStrain.STRAIN_B, infPerDayStrB);
+ }
+ }
+
+ public static final class Params {
+ // general
+ @GenerateSeeds(5)
+ public long seed;
+
+ @StringParameter({"off","3.0","6.0"})
+ public String StrainA;
+
+ @StringParameter({"off", "3.0", "6.0"})
+ public String StrainB;
+
+ @StringParameter({"2022-10-01"})
+ public String resDate;
+
+ // @StringParameter({"false", "true"})
+// public String igA;
+ // vaccination campaign
+ @StringParameter({"ba1Update","ba5Update", "mRNA", "off"})
+ public String vacType;
+
+
+ //measures in the work context:
+ // homeOff = 50% home office = work Rf cut in half
+ //
+// @StringParameter({"none", "homeOff", "test", "mask", "all"})
+ @StringParameter({"none"})
+ public String work;
+
+// @StringParameter({"none", "mask", "test", "all"})
+ @StringParameter({"none"})
+ public String leis;
+
+ // mask restrictions for "shop_daily", "shop_other", "errands"
+// @StringParameter({"none", "mask"})
+ @StringParameter({"none"})
+ public String errands;
+
+// @StringParameter({"none", "maskVentTest"})
+ @StringParameter({"none"})
+ public String edu;
+
+// @StringParameter({"mask"})
+ @StringParameter({"none"})
+ public String pt;
+ }
+
+
+ public static void main(String[] args) {
+ String[] args2 = {
+ RunParallel.OPTION_SETUP, CologneBMBF20220805_IfSG.class.getName(),
+ RunParallel.OPTION_PARAMS, Params.class.getName(),
+ RunParallel.OPTION_TASKS, Integer.toString(1),
+ RunParallel.OPTION_ITERATIONS, Integer.toString(1000),
+ RunParallel.OPTION_METADATA
+ };
+
+ RunParallel.main(args2);
+ }
+
+
+}
+
diff --git a/src/main/java/org/matsim/run/batch/CologneBMBF20220805_leisSplit.java b/src/main/java/org/matsim/run/batch/CologneBMBF20220805_leisSplit.java
new file mode 100644
index 000000000..b3d96ffbf
--- /dev/null
+++ b/src/main/java/org/matsim/run/batch/CologneBMBF20220805_leisSplit.java
@@ -0,0 +1,1008 @@
+package org.matsim.run.batch;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Module;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.util.Modules;
+import it.unimi.dsi.fastutil.ints.Int2DoubleAVLTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2DoubleMap;
+import org.matsim.core.config.Config;
+import org.matsim.core.config.ConfigUtils;
+import org.matsim.episim.*;
+import org.matsim.episim.analysis.*;
+import org.matsim.episim.model.*;
+import org.matsim.episim.model.testing.DefaultTestingModel;
+import org.matsim.episim.model.testing.FlexibleTestingModel;
+import org.matsim.episim.model.testing.TestType;
+import org.matsim.episim.model.vaccination.VaccinationModel;
+import org.matsim.episim.model.vaccination.VaccinationStrategyBMBF0617;
+import org.matsim.episim.policy.FixedPolicy;
+import org.matsim.episim.policy.Restriction;
+import org.matsim.run.RunParallel;
+import org.matsim.run.modules.SnzCologneProductionScenario;
+
+import javax.annotation.Nullable;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.function.BiFunction;
+
+
+/**
+ * Batch for Bmbf runs
+ */
+public class CologneBMBF20220805_leisSplit implements BatchRun {
+
+ boolean DEBUG_MODE = false;
+ int runCount = 0;
+
+ @Nullable
+ @Override
+ public Module getBindings(int id, @Nullable Params params) {
+ return Modules.override(getBindings(0.0, params)).with(new AbstractModule() {
+ @Override
+ protected void configure() {
+
+ // BIND ANTIBODY MODEL
+ double mutEscDelta = 29.2 / 10.9;
+ double mutEscBa1 = 10.9 / 1.9;
+ double mutEscBa5 = 2.9;
+
+ double mutEscStrainA = 0.;
+ double mutEscStrainB = 0.;
+
+ if (params != null && !params.StrainA.equals("off")) {
+ mutEscStrainA = Double.parseDouble(params.StrainA);
+ }
+ if (params != null && !params.StrainB.equals("off")) {
+ mutEscStrainB = Double.parseDouble(params.StrainB);
+ }
+
+ Map> initialAntibodies = new HashMap<>();
+ Map> antibodyRefreshFactors = new HashMap<>();
+ configureAntibodies(initialAntibodies, antibodyRefreshFactors, mutEscDelta, mutEscBa1, mutEscBa5, mutEscStrainA, mutEscStrainB);
+
+ AntibodyModel.Config antibodyConfig = new AntibodyModel.Config(initialAntibodies, antibodyRefreshFactors);
+
+ double immuneSigma = 3.0;
+ if (params != null) {
+ antibodyConfig.setImmuneReponseSigma(immuneSigma);
+ }
+
+ bind(AntibodyModel.Config.class).toInstance(antibodyConfig);
+
+
+ // BIND VACCINATION MODEL
+
+ Multibinder set = Multibinder.newSetBinder(binder(), VaccinationModel.class);
+
+ set.addBinding().to(VaccinationStrategyBMBF0617.class).in(Singleton.class);
+
+ LocalDate start = LocalDate.parse("2022-12-01");
+
+ VaccinationType vaccinationType = VaccinationType.mRNA;
+
+ Int2DoubleMap compliance = new Int2DoubleAVLTreeMap();
+ compliance.put(60, 0.0);
+ compliance.put(18, 0.0);
+ compliance.put(12, 0.0);
+ compliance.put(0, 0.0);
+
+ String vacCamp = "off";
+
+ if (params != null) {
+
+ if (!params.vacType.equals("off")) {
+ vacCamp = "age";
+ vaccinationType = VaccinationType.valueOf(params.vacType);
+ }
+
+// start = LocalDate.parse(params.resDate);
+
+
+ switch (vacCamp) {
+ case "age":
+ compliance.put(60, 0.85); // 60+
+ compliance.put(18, 0.55); // 18-59
+ compliance.put(12, 0.20); // 12-17
+ compliance.put(0, 0.0); // 0 - 11
+ break;
+ case "eu":
+ compliance.put(60, 0.40); // half of 80% (which reflects the current percentage of people in Dland who are boostered)
+ compliance.put(18, 0.);
+ compliance.put(12, 0.);
+ compliance.put(0, 0.);
+ break;
+ case "off":
+ break;
+ default:
+ throw new RuntimeException("Not a valid option for vaccinationCampaignType");
+ }
+ }
+
+ bind(VaccinationStrategyBMBF0617.Config.class).toInstance(new VaccinationStrategyBMBF0617.Config(start, 30, vaccinationType, compliance));
+
+
+
+ // BIND TESTING MODEL
+ if (params != null){
+
+ // date of no restrictions and new restrictions
+ String unResDate = "2022-04-25";
+ LocalDate unresDate = LocalDate.parse(unResDate);
+ LocalDate resDate = LocalDate.parse(params.resDate);
+
+// String[] s = params.gpMonths.split("-");
+
+ // Green pass validity for vaccinated and infected
+// int vacDays = Integer.parseInt(s[0]) * 30;
+// int infDays = Integer.parseInt(s[1]) * 30;
+
+ // set days gp is valid
+ int vacDays = 3 * 30;
+ int infDays = 3 * 30;
+
+ // set testing scheme for each activity type
+ final CologneBMBF220628_3G.TestScheme leisTest;
+ final CologneBMBF220628_3G.TestScheme workTest;
+ final CologneBMBF220628_3G.TestScheme eduTest;
+ if (params.leis.equals("test") || params.leis.equals("all")) {
+ leisTest= CologneBMBF220628_3G.TestScheme.gp;
+ } else if (params.leis.equals("none") || params.leis.equals("mask")) {
+ leisTest = CologneBMBF220628_3G.TestScheme.none;
+ } else {
+ throw new RuntimeException();
+ }
+
+
+ if (params.work.equals("test") || params.work.equals("all")) {
+ workTest= CologneBMBF220628_3G.TestScheme.all;
+ } else if (params.work.equals("none") || params.work.equals("mask")|| params.work.equals("homeOff")) {
+ workTest = CologneBMBF220628_3G.TestScheme.none;
+ } else {
+ throw new RuntimeException();
+ }
+
+ if (params.edu.equals("maskVentTest")) {
+ eduTest = CologneBMBF220628_3G.TestScheme.all;
+ } else if (params.edu.equals("none")) {
+ eduTest = CologneBMBF220628_3G.TestScheme.none;
+ } else {throw new RuntimeException();}
+
+ bind(FlexibleTestingModel.TestRate.class).toInstance((person, day, dow, date, test, vac) -> {
+
+ if (date.isBefore(unresDate))
+ return vac.hasValidVaccination(person, day, date);
+
+ // When restrictions have been lifted, days valid is set to a high number
+ // many tests are voluntary
+ if (date.isBefore(resDate))
+ return vac.hasValidVaccination(person, day, date, 360);
+
+ // this returns true if for any activities, the person requires increased testing regime
+ BiFunction anyUnVac = (act, red) -> {
+
+ boolean res = false;
+ CologneBMBF220628_3G.TestScheme scheme = null;
+
+
+ if (act.startsWith("leis"))
+ scheme = leisTest;
+ else if (act.equals("work"))
+ scheme = workTest;
+ else if (act.startsWith("edu"))
+ scheme = eduTest;
+
+ // null and none, will be false
+ if (scheme == CologneBMBF220628_3G.TestScheme.all)
+ res = true;
+ else if (scheme == CologneBMBF220628_3G.TestScheme.gp) {
+ res = (person.getNumVaccinations() == 0 || person.daysSince(EpisimPerson.VaccinationStatus.yes, day) > vacDays)
+ && !person.isRecentlyRecovered(day, infDays);
+
+ }
+
+ return red || res;
+ };
+
+ return !person.matchActivities(dow, anyUnVac, false);
+ });
+
+ bind(FlexibleTestingModel.TestPolicy.class).toInstance(new FlexibleTestingModel.TestPolicy() {
+ @Override
+ public boolean shouldTest(EpisimPerson person, int day, DayOfWeek dow, LocalDate date,
+ TestingConfigGroup test, VaccinationConfigGroup vac) {
+
+ if (date.isBefore(unresDate)) {
+
+ boolean testAllPersons = test.getTestAllPersonsAfter() != null && date.isAfter(test.getTestAllPersonsAfter());
+ return testAllPersons || !vac.hasGreenPass(person, day, date);
+ }
+
+ // after restrictions everybody is tested according to the rates
+ return true;
+ }
+ });
+
+ }
+
+ }
+
+ private void configureAntibodies(Map> initialAntibodies,
+ Map> antibodyRefreshFactors,
+ double mutEscDelta, double mutEscBa1, double mutEscBa5, double mutEscStrainA, double mutEscStrainB) {
+ for (VaccinationType immunityType : VaccinationType.values()) {
+ initialAntibodies.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+
+ if (immunityType == VaccinationType.mRNA) {
+ initialAntibodies.get(immunityType).put(virusStrain, 29.2); //10.0
+ }
+ else if (immunityType == VaccinationType.vector) {
+ initialAntibodies.get(immunityType).put(virusStrain, 6.8); //2.5
+ }
+ else {
+ initialAntibodies.get(immunityType).put(virusStrain, 5.0);
+ }
+ }
+ }
+
+ for (VirusStrain immunityType : VirusStrain.values()) {
+ initialAntibodies.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+ initialAntibodies.get(immunityType).put(virusStrain, 5.0);
+ }
+ }
+
+ //mRNAAlpha, mRNADelta, mRNABA1 comes from Sydney's calibration.
+ //The other values come from Rössler et al.
+
+ //Wildtype
+ double mRNAAlpha = 29.2;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.SARS_CoV_2, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.SARS_CoV_2, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
+
+ //Alpha
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.ALPHA, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.ALPHA, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.ALPHA, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.ALPHA, mRNAAlpha * 300. / 700.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.ALPHA, mRNAAlpha * 210. / 700.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.ALPHA, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
+
+ //DELTA
+ double mRNADelta = mRNAAlpha / mutEscDelta;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.DELTA, mRNADelta);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.DELTA, mRNADelta * 150./300.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.DELTA, mRNADelta * 64./300.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.DELTA, mRNADelta * 64./300.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.DELTA, mRNADelta * 450./300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.DELTA, 0.01);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1 / mutEscBa5);
+
+ //BA.1
+ double mRNABA1 = mRNADelta / mutEscBa1;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA1, mRNABA1);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA1, mRNABA1 * 4./20.); //???
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA1, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / 1.4);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscBa5); //todo: is 1.4
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscBa5 / mutEscStrainA);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha / mutEscBa5);
+
+ //BA.2
+ double mRNABA2 = mRNABA1;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA2, mRNABA2);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA2, mRNABA2 * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / 1.4);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA2, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscBa5);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscBa5 / mutEscStrainA);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha / mutEscBa5);
+
+
+ //BA.5
+ double mRNABa5 = mRNABA2 / mutEscBa5;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA5, mRNABa5);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA5, mRNABa5 * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA5, 64.0 / 300. / mutEscBa5);// todo: do we need 1.4?
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA5, 64.0 / 300./ mutEscBa5);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA5, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.OMICRON_BA5, 64.0 / 300./ mutEscStrainA); //todo ???
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.OMICRON_BA5, 64.0 / 300. / mutEscBa5 / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha / mutEscBa5);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha);
+
+ //StrainA
+ double mRNAStrainA = mRNABa5 / mutEscStrainA;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_A, mRNAStrainA);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_A, mRNAStrainA * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_A, mRNAStrainA * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_A, mRNAStrainA * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_A, mRNAStrainA * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscBa5 /mutEscStrainA);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_A, 64.0 / 300./ mutEscBa5 /mutEscStrainA);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscStrainA);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_A, 64.0 / 300.);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscStrainA / mutEscStrainB / mutEscBa5);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscBa5 / mutEscStrainA);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainA);
+
+ //StrainB
+ double mRNAStrainB = mRNABA2 / mutEscStrainB;
+ initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_B, mRNAStrainB);
+ initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_B, mRNAStrainB * 4./20.);
+ initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_B, mRNAStrainB * 6./20.);
+ initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_B, mRNAStrainB * 6./20.);
+ initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_B, mRNAStrainB * 8./20.);
+ initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscStrainB);
+ initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_B, 64.0 / 300./ mutEscStrainB);
+ initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscStrainB / mutEscBa5);
+ initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_B, 64.0 / 300./ mutEscStrainA / mutEscStrainB / mutEscBa5);
+ initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_B, 64.0 / 300.);
+ initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainB);
+ initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainB / mutEscBa5);
+
+
+ for (VaccinationType immunityType : VaccinationType.values()) {
+ antibodyRefreshFactors.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+
+ if (immunityType == VaccinationType.mRNA) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else if (immunityType == VaccinationType.vector) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 5.0);
+ }
+ else if (immunityType == VaccinationType.ba1Update) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else if (immunityType == VaccinationType.ba5Update) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ else {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, Double.NaN);
+ }
+
+ }
+ }
+
+ for (VirusStrain immunityType : VirusStrain.values()) {
+ antibodyRefreshFactors.put(immunityType, new EnumMap<>( VirusStrain.class ) );
+ for (VirusStrain virusStrain : VirusStrain.values()) {
+ antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
+ }
+ }
+
+
+
+// System.out.print("immunityGiver");
+// for (VirusStrain immunityFrom : VirusStrain.values()) {
+// if (immunityFrom == VirusStrain.OMICRON_BA1) {
+// System.out.print( "," + "BA.1");
+// } else if (immunityFrom == VirusStrain.OMICRON_BA2) {
+// System.out.print( "," + "BA.2");
+// } else {
+// System.out.print( "," + immunityFrom);
+// }
+// }
+//
+//
+// for (ImmunityEvent immunityGiver : VaccinationType.values()) {
+// System.out.print("\n" + immunityGiver);
+// for (VirusStrain immunityFrom : VirusStrain.values()) {
+// System.out.print("," + String.format("%.3g", initialAntibodies.get(immunityGiver).get(immunityFrom)));
+// }
+// }
+// for (ImmunityEvent immunityGiver : VirusStrain.values()) {
+// System.out.print("\n" + immunityGiver);
+// for (VirusStrain immunityFrom : VirusStrain.values()) {
+// System.out.print("," + String.format("%.3g", initialAntibodies.get(immunityGiver).get(immunityFrom)));
+// }
+// }
+//
+// System.out.println();
+
+ }
+ });
+
+ }
+
+ private SnzCologneProductionScenario getBindings(double pHousehold, Params params) {
+ return new SnzCologneProductionScenario.Builder()
+ .setCarnivalModel(SnzCologneProductionScenario.CarnivalModel.yes)
+ .setSebastianUpdate(true)
+ .setLeisureCorrection(1.3) //params == null ? 0.0 : params.actCorrection)
+ .setScaleForActivityLevels(1.3)
+ .setSuscHouseholds_pct(pHousehold)
+ .setActivityHandling(EpisimConfigGroup.ActivityHandling.startOfDay)
+ .setTestingModel(params != null ? FlexibleTestingModel.class : DefaultTestingModel.class)
+ .setInfectionModel(InfectionModelWithAntibodies.class)
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return Metadata.of("cologne", "calibration");
+ }
+
+ @Override
+ public Collection postProcessing() {
+ return List.of(
+ new VaccinationEffectiveness().withArgs(),
+ new RValuesFromEvents().withArgs(),
+ new VaccinationEffectivenessFromPotentialInfections().withArgs("--remove-infected"),
+ new FilterEvents().withArgs("--output","./output/"),
+ new HospitalNumbersFromEvents().withArgs("--output","./output/","--input","/scratch/projects/bzz0020/episim-input")
+// new SecondaryAttackRateFromEvents().withArgs()
+ );
+ }
+
+ @Override
+ public Config prepareConfig(int id, Params params) {
+
+ if (DEBUG_MODE) {
+ if (runCount == 0){ //&& params.strAEsc != 0.0 && params.ba5Inf == 0. && params.eduTest.equals("true")) {
+ runCount++;
+ } else {
+ return null;
+ }
+ }
+
+ SnzCologneProductionScenario module = getBindings(0.0, params);
+
+ Config config = module.config();
+
+
+ config.global().setRandomSeed(params.seed);
+
+ EpisimConfigGroup episimConfig = ConfigUtils.addOrGetModule(config, EpisimConfigGroup.class);
+
+
+ episimConfig.setCalibrationParameter(episimConfig.getCalibrationParameter() * 1.2);
+
+
+
+ //---------------------------------------
+ // S T R A I N S
+ //---------------------------------------
+
+ VirusStrainConfigGroup virusStrainConfigGroup = ConfigUtils.addOrGetModule(config, VirusStrainConfigGroup.class);
+
+
+// virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * params.deltaTheta);
+
+ //BA5
+ double ba5Inf = 1.0;
+ double oHos = virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA2).getFactorSeriouslySick();
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA2).getInfectiousness() * ba5Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorSeriouslySick(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorSeriouslySickVaccinated(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorCritical(oHos);
+
+
+// STRAIN_A
+ if (!params.StrainA.equals("off")) {
+
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA5).getInfectiousness() * ba5Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setFactorSeriouslySick(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setFactorSeriouslySickVaccinated(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_A).setFactorCritical(oHos);
+ }
+
+// STRAIN_B
+ if (!params.StrainB.equals("off")) {
+
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA5).getInfectiousness() * ba5Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setFactorSeriouslySick(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setFactorSeriouslySickVaccinated(oHos);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.STRAIN_B).setFactorCritical(oHos);
+ }
+
+ // remove age-based susceptibility of strains starting with DELTA
+
+ String ageSusc = "false";
+ if (!Boolean.parseBoolean(ageSusc)) {
+ TreeMap nonSteppedAgeSusceptibility = new TreeMap<>(Map.of(
+ 19, 1d,
+ 20, 1d
+ ));
+
+ for (VirusStrain strain : List.of(VirusStrain.DELTA, VirusStrain.OMICRON_BA1, VirusStrain.OMICRON_BA2, VirusStrain.OMICRON_BA5, VirusStrain.STRAIN_A)) {
+ virusStrainConfigGroup.getOrAddParams(strain).setAgeSusceptibility(nonSteppedAgeSusceptibility);
+ }
+ }
+
+ // increase infectivity of alpha
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.ALPHA).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.ALPHA).getInfectiousness() * 1.4);
+
+ double deltaTheta = 0.9;
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * deltaTheta);
+ double ba1Inf = 1.9; // 2.0,2.1,2.2
+ double ba2Inf = 1.7;
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA1).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * ba1Inf);
+ virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA2).setInfectiousness(virusStrainConfigGroup.getOrAddParams(VirusStrain.DELTA).getInfectiousness() * ba1Inf * ba2Inf);
+
+
+ //---------------------------------------
+ // I M P O R T
+ //---------------------------------------
+
+ Map infPerDayAlpha = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(VirusStrain.ALPHA, new TreeMap<>()));
+
+
+ // reconfig disease import of alpha
+ LocalDate startDateAlpha = LocalDate.parse("2021-01-15");
+
+ for (int i = 0; i < 7; i++) {
+ infPerDayAlpha.put(startDateAlpha.plusDays(i), 4);
+ }
+
+
+ infPerDayAlpha.put(startDateAlpha.plusDays(7), 1);
+
+ episimConfig.setInfections_pers_per_day(VirusStrain.ALPHA, infPerDayAlpha);
+
+
+ configureFutureDiseaseImport(params, episimConfig);
+
+ //---------------------------------------
+ // R E S T R I C T I O N S
+ //---------------------------------------
+
+ FixedPolicy.ConfigBuilder builder = FixedPolicy.parse(episimConfig.getPolicy());
+
+ //school
+ String schoolUpdate = "yes";
+ if(schoolUpdate.equals("yes")) {
+ // school closed completely until 21.2.2022
+ builder.restrict(LocalDate.parse("2021-01-11"), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other");
+ builder.restrict(LocalDate.parse("2021-02-21"), 0.5, "educ_primary");
+ builder.restrict(LocalDate.parse("2021-03-15"), 0.5, "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other");
+
+ } else if (schoolUpdate.equals("no")) {
+
+ } else {
+ throw new RuntimeException("param value doesn't exist");
+ }
+
+ String schoolTest = "later";
+ if (schoolTest.equals("later")) {
+ TestingConfigGroup testingConfigGroup = ConfigUtils.addOrGetModule(config, TestingConfigGroup.class);
+ TestingConfigGroup.TestingParams rapidTest = testingConfigGroup.getOrAddParams(TestType.RAPID_TEST);
+// TestingConfigGroup.TestingParams pcrTest = testingConfigGroup.getOrAddParams(TestType.PCR);
+ Map> testingRateForActivitiesRapid = rapidTest.getTestingRateForActivities();
+// Map> testingRateForActivitiesPCR = pcrTest.getTestingRateForActivities();
+
+
+ for (LocalDate date = LocalDate.parse("2021-03-19"); date.isBefore(LocalDate.parse("2021-04-25")); date = date.plusDays(1)) {
+
+ testingRateForActivitiesRapid.get("educ_kiga").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_primary").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_secondary").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_tertiary").put(date, 0.);
+ testingRateForActivitiesRapid.get("educ_other").put(date, 0.);
+
+ }
+
+ testingRateForActivitiesRapid.get("educ_kiga").put(LocalDate.parse("2021-09-20"), 0.);
+ testingRateForActivitiesRapid.get("educ_primary").put(LocalDate.parse("2021-09-20"), 0.);
+
+// testingRateForActivitiesPCR.get("educ_primary").put(LocalDate.parse("2021-05-10"), 0.4);
+ testingRateForActivitiesRapid.get("educ_secondary").put(LocalDate.parse("2021-05-10"), 0.4);
+ testingRateForActivitiesRapid.get("educ_tertiary").put(LocalDate.parse("2021-05-10"), 0.4);
+ testingRateForActivitiesRapid.get("educ_other").put(LocalDate.parse("2021-05-10"), 0.4);
+
+ } else if (schoolTest.equals("base")) {
+
+ }else {
+ throw new RuntimeException("param value doesn't exist");
+ }
+
+
+ // masks
+ //pt: masks
+ String maskType = "45to45";
+ if (maskType.equals("45to45")) {
+ for (LocalDate date = LocalDate.parse("2020-04-21"); date.isBefore(LocalDate.parse("2021-05-01")); date = date.plusDays(1)) {
+ builder.restrict(date, Restriction.ofMask(Map.of(FaceMask.CLOTH, 0.45, FaceMask.SURGICAL, 0.45)), "pt", "errands", "shop_daily", "shop_other");
+
+ }
+ } else if (maskType.equals("base")) {
+
+ } else {
+ throw new RuntimeException("param value doesn't exist");
+ }
+
+ // -----------------------------------------
+
+ // new restrictions from IfSG
+ LocalDate restrictionDate = LocalDate.parse(params.resDate);
+
+ // testing rates
+
+ double gpTestRate = 0.;
+
+ TestingConfigGroup testingConfigGroup = ConfigUtils.addOrGetModule(config, TestingConfigGroup.class);
+ TestingConfigGroup.TestingParams pcrTest = testingConfigGroup.getOrAddParams(TestType.PCR);
+ Map> testingRateForActivitiesPcr = pcrTest.getTestingRateForActivities();
+ Map