From 4b30163533f224aaad7cb67f0bb5736c2554860b Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Thu, 1 Sep 2022 18:59:10 -0400 Subject: [PATCH 01/13] wip round3 --- .../episim/model/DefaultAntibodyModel.java | 1 - .../model/InfectionModelWithAntibodies.java | 6 +- .../matsim/episim/model/VaccinationType.java | 12 +- .../org/matsim/episim/model/VirusStrain.java | 3 +- ...ccinationStrategyReoccurringCampaigns.java | 139 ++++ .../matsim/run/CreateBatteryForCluster.java | 4 +- ...Hub.java => CologneScenarioHubRound2.java} | 6 +- .../run/batch/CologneScenarioHubRound3.java | 592 ++++++++++++++++++ .../java/org/matsim/run/batch/UtilsJR.java | 49 ++ .../modules/SnzCologneProductionScenario.java | 11 +- 10 files changed, 807 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java rename src/main/java/org/matsim/run/batch/{CologneScenarioHub.java => CologneScenarioHubRound2.java} (98%) create mode 100644 src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java diff --git a/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java b/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java index b60b19979..4112fbe22 100644 --- a/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java +++ b/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java @@ -129,7 +129,6 @@ private void handleImmunization(EpisimPerson person, ImmunityEvent immunityEvent double initialAntibodies = antibodyConfig.initialAntibodies.get(immunityEventType).get(strain2) * person.getImmuneResponseMultiplier(); antibodies = Math.max(antibodies, initialAntibodies); - // check that new antibody level is at most 150 antibodies = Math.min(150., antibodies); diff --git a/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java b/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java index 0ce86be8d..26fe673ca 100644 --- a/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java +++ b/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java @@ -97,7 +97,9 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto double igaFactor = 0.0; double igaTimePeriod = vaccinationConfig.getTimePeriodIgA(); - if (target.hadStrain(infector.getVirusStrain())) { + + + if (target.hadStrain(infector.getVirusStrain()) && !List.of(VirusStrain.STRAIN_A, VirusStrain.STRAIN_B, VirusStrain.STRAIN_C).contains(infector.getVirusStrain())) { int lastInfectionWithStrain = 0; for (int ii = 0; ii < target.getNumInfections(); ii++) { @@ -109,7 +111,7 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto igaFactor = 1.0 / (1.0 + Math.exp(-2.0 * (1.0 - target.daysSinceInfection(lastInfectionWithStrain, iteration) / igaTimePeriod))); } else if (vaccinationConfig.getUseIgA()) { - List crossImmunityStrainsOmicron = List.of(VirusStrain.OMICRON_BA1, VirusStrain.OMICRON_BA2, VirusStrain.OMICRON_BA5, VirusStrain.STRAIN_A, VirusStrain.STRAIN_B); + List crossImmunityStrainsOmicron = List.of(VirusStrain.OMICRON_BA1, VirusStrain.OMICRON_BA2, VirusStrain.OMICRON_BA5); if(crossImmunityStrainsOmicron.contains(infector.getVirusStrain())){ int lastInfectionWithStrain = 0; diff --git a/src/main/java/org/matsim/episim/model/VaccinationType.java b/src/main/java/org/matsim/episim/model/VaccinationType.java index 57f9be945..4181e9c0d 100644 --- a/src/main/java/org/matsim/episim/model/VaccinationType.java +++ b/src/main/java/org/matsim/episim/model/VaccinationType.java @@ -14,6 +14,16 @@ public enum VaccinationType implements ImmunityEvent { /** * Not a real vaccination, but used to describe the profile for persons that have been infected and gained a natural immunity. */ - natural + natural, + + fall22, + + spring23, + + fall23, + + spring24, + + } diff --git a/src/main/java/org/matsim/episim/model/VirusStrain.java b/src/main/java/org/matsim/episim/model/VirusStrain.java index cb117106c..c809e6ab6 100644 --- a/src/main/java/org/matsim/episim/model/VirusStrain.java +++ b/src/main/java/org/matsim/episim/model/VirusStrain.java @@ -40,6 +40,7 @@ public enum VirusStrain implements ImmunityEvent { STRAIN_A, - STRAIN_B + STRAIN_B, + STRAIN_C } 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..15a271bde --- /dev/null +++ b/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java @@ -0,0 +1,139 @@ +package org.matsim.episim.model.vaccination; + +import com.google.inject.Inject; +import it.unimi.dsi.fastutil.ints.Int2DoubleMap; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.population.Person; +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 SplittableRandom rnd; + private final Config config; + + @Inject + public VaccinationStrategyReoccurringCampaigns(SplittableRandom rnd, Config config) { + this.rnd = rnd; + this.config = config; + } + + @Override + public void handleVaccination(Map, EpisimPerson> persons, LocalDate date, int iteration, double now) { + + // We check whether the current date occurs during one of the vaccination campaigns. If so, vaccinations are applied + boolean occursInCampaign = false; + VaccinationType vaccinationType = null; + for (LocalDate startDate : config.startDateToVOC.keySet()) { + if (date.isAfter(startDate) && date.isBefore(startDate.plusDays(config.campaignDuration))) { + + if (occursInCampaign) { + throw new RuntimeException("this vaccination strategy doesn't allow for two vaccination campaigns to occur simultaneously"); + } + + occursInCampaign = true; + vaccinationType = config.startDateToVOC.get(startDate); + } + } + + if (!occursInCampaign) { + return; + } + + //handle young persons + if (config.complianceByAge.values().doubleStream() + .reduce(0, Double::sum) > 0) { + + List filteredPersons = new ArrayList<>(persons.values()); + + List candidates = filteredPersons.stream() + .filter(EpisimPerson::isVaccinable) // todo: what determines who is vaccinable? + .filter(p -> p.getDiseaseStatus() == EpisimPerson.DiseaseStatus.susceptible) + .filter(p -> p.getNumVaccinations() > 1) // only boostered people are reboostered + .filter(p -> p.daysSinceVaccination(p.getNumVaccinations() - 1, iteration) > 90) // only people who've had their last vaccination more than 90 days ago + .collect(Collectors.toList()); + + // Collections.shuffle(candidates, new Random(EpisimUtils.getSeed(rnd))); + + + int num0 = (int) filteredPersons.stream().filter(p -> (p.getAge() >= 0 && p.getAge() < 12)).count(); + int num12 = (int) filteredPersons.stream().filter(p -> (p.getAge() >= 12 && p.getAge() < 18)).count(); + int num18 = (int) filteredPersons.stream().filter(p -> (p.getAge() >= 18 && p.getAge() < 60)).count(); + int num60 = (int) filteredPersons.stream().filter(p -> p.getAge() >= 60).count(); + + double numVaccines = num0 * config.complianceByAge.get(0) + + num12 * config.complianceByAge.get(12) + + num18 * config.complianceByAge.get(18) + + num60 * config.complianceByAge.get(60); + + int vaccinationsLeft = (int) (numVaccines / config.campaignDuration); + + + List people0 = candidates.stream().filter(p -> (p.getAge() >= 0 && p.getAge() < 12)).collect(Collectors.toList()); + List people12 = candidates.stream().filter(p -> (p.getAge() >= 12 && p.getAge() < 18)).collect(Collectors.toList()); + List people18 = candidates.stream().filter(p -> (p.getAge() >= 18 && p.getAge() < 60)).collect(Collectors.toList()); + List people60 = candidates.stream().filter(p -> p.getAge() >= 60).collect(Collectors.toList()); + + final List[] perAge = new List[4]; + perAge[0] = people0; + perAge[1] = people12; + perAge[2] = people18; + perAge[3] = people60; + + int ageIndex = 3; + while (ageIndex >= 0 && vaccinationsLeft > 0) { + + List candidatesForAge = perAge[ageIndex]; + + // list is shuffled to avoid eventual bias + if (candidatesForAge.size() > vaccinationsLeft) + Collections.shuffle(perAge[ageIndex], new Random(EpisimUtils.getSeed(rnd))); + + + int vaccinesForDayAndAgeGroup = Math.min(candidatesForAge.size(), vaccinationsLeft); + for (int i = 0; i < vaccinesForDayAndAgeGroup; i++) { + EpisimPerson person = candidatesForAge.get(i); + vaccinate(person, iteration, vaccinationType); + vaccinationsLeft--; + } + + ageIndex--; + + } + } + + + } + + + public static class Config { + + /** + * Start Dates of vaccination campaigns. + */ + private final Map startDateToVOC; + /** + * Duration of vaccination campaign. + */ + private final int campaignDuration; + + private final Int2DoubleMap complianceByAge; + + + + public Config(Map startDateToVOC, int campaignDuration, Int2DoubleMap complianceByAge) { + this.startDateToVOC = startDateToVOC; + this.campaignDuration = campaignDuration; + this.complianceByAge = complianceByAge; + } + } + +} diff --git a/src/main/java/org/matsim/run/CreateBatteryForCluster.java b/src/main/java/org/matsim/run/CreateBatteryForCluster.java index 243c94955..1781e2666 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.CologneBMBF20220805_IfSG") + @CommandLine.Option(names = "--setup", defaultValue = "org.matsim.run.batch.CologneScenarioHubRound3") private Class> setup; - @CommandLine.Option(names = "--params", defaultValue = "org.matsim.run.batch.CologneBMBF20220805_IfSG$Params") + @CommandLine.Option(names = "--params", defaultValue = "org.matsim.run.batch.CologneScenarioHubRound3$Params") private Class params; @SuppressWarnings("rawtypes") diff --git a/src/main/java/org/matsim/run/batch/CologneScenarioHub.java b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound2.java similarity index 98% rename from src/main/java/org/matsim/run/batch/CologneScenarioHub.java rename to src/main/java/org/matsim/run/batch/CologneScenarioHubRound2.java index d521f11ce..86b05a0ed 100644 --- a/src/main/java/org/matsim/run/batch/CologneScenarioHub.java +++ b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound2.java @@ -25,9 +25,9 @@ /** * Batch for Bmbf runs */ -public class CologneScenarioHub implements BatchRun { +public class CologneScenarioHubRound2 implements BatchRun { - boolean DEBUG_MODE = true; + boolean DEBUG_MODE = false; int runCount = 0; @Nullable @@ -388,7 +388,7 @@ public static final class Params { public static void main(String[] args) { String[] args2 = { - RunParallel.OPTION_SETUP, CologneScenarioHub.class.getName(), + RunParallel.OPTION_SETUP, CologneScenarioHubRound2.class.getName(), RunParallel.OPTION_PARAMS, Params.class.getName(), RunParallel.OPTION_TASKS, Integer.toString(1), RunParallel.OPTION_ITERATIONS, Integer.toString(70), diff --git a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java new file mode 100644 index 000000000..a8d939bfe --- /dev/null +++ b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java @@ -0,0 +1,592 @@ +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.vaccination.VaccinationModel; +import org.matsim.episim.model.vaccination.VaccinationStrategyReoccurringCampaigns; +import org.matsim.run.RunParallel; +import org.matsim.run.modules.SnzCologneProductionScenario; + +import javax.annotation.Nullable; +import java.time.LocalDate; +import java.util.*; + + +/** + * ROUND 3 + * case: annual + * Sept'22 : update 1 + * Oct'22 : strainA + * Sep'23 : + */ +public class CologneScenarioHubRound3 implements BatchRun { + + boolean DEBUG_MODE = true; + 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(VaccinationStrategyReoccurringCampaigns.class).in(Singleton.class); + + + double mutEscBa5 = 3.0; + double mutEscStrainX = 3.0; + + LocalDate startSpring = LocalDate.of(2023, 4, 15); + LocalDate startAutumn = LocalDate.of(2023, 9, 15); + + Map startDateToVOC = new HashMap<>(); + startDateToVOC.put(LocalDate.of(2022, 9, 15), VaccinationType.fall22); + + if (DEBUG_MODE) { + startDateToVOC.put(LocalDate.of(2020, 3, 1), VaccinationType.fall23); + startDateToVOC.put(LocalDate.of(2020, 3, 15), VaccinationType.fall23); + + } + + + Int2DoubleMap compliance = new Int2DoubleAVLTreeMap(); + compliance.put(60, 0.0); + compliance.put(18, 0.0); + compliance.put(12, 0.0); + compliance.put(0, 0.0); + + if (params != null) { + + mutEscStrainX = params.mutEsc; + + //todo: change such that third booster is not given in 2022. + if (params.vacFreq.equals("none")) { + } else if (params.vacFreq.equals("annual")) { + startDateToVOC.put(startAutumn, VaccinationType.fall23); + } else if (params.vacFreq.equals("biannual")) { + startDateToVOC.put(startSpring, VaccinationType.spring23); + startDateToVOC.put(startAutumn, VaccinationType.fall23); + startDateToVOC.put(startSpring.plusYears(1), VaccinationType.spring24); + } else { + throw new RuntimeException(); + } + + if (params.vacCamp.equals("60plus")) { + compliance.put(60, 0.94/2); // 0.94 is boost rate July 16, 2022 + compliance.put(18, 0.); + compliance.put(12, 0.); + compliance.put(0, 0.); + } + // assumption: older age group 2boosted first, then younger, each age group + // will have rate of 50% 2boosted by end of campaign. + // motivation: if we give both age groups same rate, then the older people + // will not be boosted as much as younger people, which seems implausible... + else if (params.vacCamp.equals("18plus")) { + compliance.put(60, 0.94/2); // 0.94 is boost rate July 16, 2022 + compliance.put(18, 0.77/2); // 0.77 is boost rate July 16, 2022 + compliance.put(12, 0.); + compliance.put(0, 0.); + } + else if (params.vacCamp.equals("off")) { + + } else { + throw new RuntimeException("Not a valid option for vaccinationCampaignType"); + } + } + + int campaignDuration = 91; + + if (DEBUG_MODE) { + campaignDuration = 5; + } + + bind(VaccinationStrategyReoccurringCampaigns.Config.class).toInstance(new VaccinationStrategyReoccurringCampaigns.Config(startDateToVOC, campaignDuration, compliance)); + + //initial antibodies + Map> initialAntibodies = new HashMap<>(); + Map> antibodyRefreshFactors = new HashMap<>(); + configureAntibodies(initialAntibodies, antibodyRefreshFactors, mutEscBa5, mutEscStrainX); + + AntibodyModel.Config antibodyConfig = new AntibodyModel.Config(initialAntibodies, antibodyRefreshFactors); + + double immuneSigma = 3.0; + if (params != null) { + antibodyConfig.setImmuneReponseSigma(immuneSigma); + } + + bind(AntibodyModel.Config.class).toInstance(antibodyConfig); + + if (DEBUG_MODE && params != null && params.mutEsc == 3.) { + UtilsJR.produceAntibodiesCsv(initialAntibodies); + + } + + } + + private void configureAntibodies(Map> initialAntibodies, + Map> antibodyRefreshFactors, + double mutEscBa5, double mutEscStrainX) { + + 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); + } + } + + List newImmunityEvents = List.of(VirusStrain.STRAIN_A, VirusStrain.STRAIN_B, VirusStrain.STRAIN_C, + VaccinationType.fall22, VaccinationType.spring23, VaccinationType.fall23, VaccinationType.spring24); + + + //mRNAAlpha, mRNADelta, mRNABA1 comes from Sydney's calibration. + //The other values come from Rössler et al. + //Wildtype + double mRNAAlpha = 29.2; + + // initialAntibodies.get(IMMUNITY GIVER).put(IMMUNITY AGAINST, ab level); + 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); + + for (ImmunityEvent event : newImmunityEvents) { + initialAntibodies.get(event).put(VirusStrain.SARS_CoV_2, 0.01); + } + + + //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); + + for (ImmunityEvent event : newImmunityEvents) { + initialAntibodies.get(event).put(VirusStrain.ALPHA, 0.01); + } + + //DELTA + double mRNADelta = 10.9; + 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(VirusStrain.OMICRON_BA5).put(VirusStrain.DELTA, 0.2 / 6.4); + + for (ImmunityEvent event : newImmunityEvents) { + initialAntibodies.get(event).put(VirusStrain.DELTA, 0.01); + } + + //BA.1 + double mRNABA1 = 1.9; + 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. / 1.4); //todo: is 1.4 + + for (ImmunityEvent event : newImmunityEvents) { + initialAntibodies.get(event).put(VirusStrain.OMICRON_BA1, 0.01); + } + + + //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. / 1.4); + + for (ImmunityEvent event : newImmunityEvents) { + initialAntibodies.get(event).put(VirusStrain.OMICRON_BA2, 0.01); + } + + + //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. / 1.4 / 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.); + + for (ImmunityEvent event : newImmunityEvents) { + initialAntibodies.get(event).put(VirusStrain.OMICRON_BA5, 0.01); + } + + // NEW STRAINS + + //StrainA + + double mRNAStrainA = mRNABa5 / mutEscStrainX; + 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 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscBa5 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscStrainX); + + initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_A, mRNAAlpha); // we assume strainA produces the same amount of AB against reinfection as BA5 produces against reinfection + initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VirusStrain.STRAIN_C).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainX); // we assume the escape grow exponentially as StrainX gets further removed from StrainA + + initialAntibodies.get(VaccinationType.fall22).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VaccinationType.spring23).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VaccinationType.fall23).put(VirusStrain.STRAIN_A, mRNAAlpha); + initialAntibodies.get(VaccinationType.spring24).put(VirusStrain.STRAIN_A, mRNAAlpha); + + //StrainB + +// double mRNAStrainA = mRNABa5 / escape; + initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_B, mRNAStrainA); + initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_B, mRNAStrainA * 4. / 20.); + initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_B, mRNAStrainA * 6. / 20.); + initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_B, mRNAStrainA * 6. / 20.); + initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_B, mRNAStrainA * 8. / 20.); + + initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscBa5 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscBa5 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscStrainX); + + initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_B, mRNAAlpha); // we assume strainA produces the same amount of AB against reinfection as BA5 produces against reinfection + initialAntibodies.get(VirusStrain.STRAIN_C).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); // we assume the escape grow exponentially as StrainX gets further removed from StrainA + + initialAntibodies.get(VaccinationType.fall22).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VaccinationType.spring23).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VaccinationType.fall23).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VaccinationType.spring24).put(VirusStrain.STRAIN_B, mRNAAlpha); + + //StrainC + +// double mRNAStrainA = mRNABa5 / escape; + initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_C, mRNAStrainA); + initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_C, mRNAStrainA * 4. / 20.); + initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_C, mRNAStrainA * 6. / 20.); + initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_C, mRNAStrainA * 6. / 20.); + initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_C, mRNAStrainA * 8. / 20.); + + initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_C, 64.0 / 300. / mutEscBa5 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_C, 64.0 / 300. / mutEscBa5 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_C, 64.0 / 300. / mutEscStrainX); + + initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VirusStrain.STRAIN_C).put(VirusStrain.STRAIN_C, mRNAAlpha); + + initialAntibodies.get(VaccinationType.fall22).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VaccinationType.spring23).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VaccinationType.fall23).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); + initialAntibodies.get(VaccinationType.spring24).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); + + + List strainsX = List.of(VirusStrain.STRAIN_A, VirusStrain.STRAIN_B, VirusStrain.STRAIN_C); + 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 (List.of(VaccinationType.fall22, VaccinationType.spring23, VaccinationType.fall23, VaccinationType.spring24).contains(immunityType)) { + if (strainsX.contains(virusStrain)) { + antibodyRefreshFactors.get(immunityType).put(virusStrain, 1.0); + } else { + 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()) { + if (strainsX.contains(immunityType) && strainsX.contains(virusStrain)) { + antibodyRefreshFactors.get(immunityType).put(virusStrain, 1.0); + } else { + antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0); + } + } + } + } + }); + + } + + private SnzCologneProductionScenario getBindings(double pHousehold, Params params) { + return new SnzCologneProductionScenario.Builder() + .setLeisureCorrection(0.0) + .setCarnivalModel(SnzCologneProductionScenario.CarnivalModel.yes) + .setSebastianUpdate(true) + .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 HospitalNumbersFromEvents().withArgs(), + new SecondaryAttackRateFromEvents().withArgs() + ); + } + + @Override + public Config prepareConfig(int id, Params params) { + + if (DEBUG_MODE && params.mutEsc == 3.) { + + 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); + + // create snapshot + episimConfig.setSnapshotInterval(927); + + //mutations + VirusStrainConfigGroup virusStrainConfigGroup = ConfigUtils.addOrGetModule(config, VirusStrainConfigGroup.class); + + //configure new strains + //BA5 + double ba5Inf = 0.9; + 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); + + //StrainA/B/C + + for (VirusStrain strain : List.of(VirusStrain.STRAIN_A, VirusStrain.STRAIN_B, VirusStrain.STRAIN_C)) { + virusStrainConfigGroup.getOrAddParams(strain).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA5).getInfectiousness()); + virusStrainConfigGroup.getOrAddParams(strain).setFactorSeriouslySick(oHos); + virusStrainConfigGroup.getOrAddParams(strain).setFactorSeriouslySickVaccinated(oHos); + virusStrainConfigGroup.getOrAddParams(strain).setFactorCritical(oHos); + } + + + //Configure Disease Import + + configureFutureDiseaseImport(params, episimConfig); + + + //vaccinations + VaccinationConfigGroup vaccinationConfig = ConfigUtils.addOrGetModule(config, VaccinationConfigGroup.class); + vaccinationConfig.setUseIgA(true); + vaccinationConfig.setTimePeriodIgA(730.); + + //new vaccinations + int boostAfter = 3; + for (VaccinationType vax : List.of(VaccinationType.fall22, VaccinationType.spring23, VaccinationType.fall23, VaccinationType.spring24)) { + vaccinationConfig.getOrAddParams(vax) + .setBoostWaitPeriod(boostAfter * 30 + 6 * 7); // todo: does this make sense? + ; + } + + + + + + + return config; + } + + private void configureFutureDiseaseImport(Params params, EpisimConfigGroup episimConfig) { + 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 strainToDate = Map.of( + VirusStrain.STRAIN_A, LocalDate.of(2022, 10, 1), + VirusStrain.STRAIN_B, LocalDate.of(2023, 7, 1), + VirusStrain.STRAIN_C, LocalDate.of(2024, 4, 1) + ); + + + if (DEBUG_MODE) { + strainToDate = Map.of( + VirusStrain.STRAIN_A, LocalDate.of(2020, 3, 1), + VirusStrain.STRAIN_B, LocalDate.of(2020, 3, 1), + VirusStrain.STRAIN_C, LocalDate.of(2020, 3, 1) + ); + + } + + // add initial impulses for strains + //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/B/C + for (VirusStrain strain : strainToDate.keySet()) { + Map infPerDayStrainX = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(strain, new TreeMap<>())); + infPerDayStrainX.put(LocalDate.parse("2020-01-01"), 0); + LocalDate date = strainToDate.get(strain); + for (int i = 0; i < 7; i++) { + infPerDayStrainX.put(date.plusDays(i), 4); + } + infPerDayStrainX.put(date.plusDays(7), 1); + episimConfig.setInfections_pers_per_day(strain, infPerDayStrainX); + } + + // add projected disease import for vacation waves after initial disease import + int facBa2 = 4; + int facBa5 = 4; + + LocalDate dateBa2 = LocalDate.parse("2022-01-27"); // local min of disease import + LocalDate dateBa5 = LocalDate.parse("2022-05-01"); // after vaca import + + NavigableMap data = DataUtils.readDiseaseImport(SnzCologneProductionScenario.INPUT.resolve("cologneDiseaseImport_Projected_2032.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(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)); + } + + } + + infPerDayBa5.put(date.plusDays(1), 1); + + // save disease import + episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA2, infPerDayBa2); + episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA5, infPerDayBa5); + + } + + + public static final class Params { + + // general + @GenerateSeeds(3) + public long seed; + + + // vaccination campaign + //vaccination frequency + @StringParameter({"none", "annual", "biannual"}) + String vacFreq; + + @StringParameter({"18plus"}) +// @StringParameter({"off", "60plus", "18plus"}) + String vacCamp; + + + //new mutations + @Parameter({3.7, 44.7}) + public double mutEsc; + } + + + public static void main(String[] args) { + String[] args2 = { + RunParallel.OPTION_SETUP, CologneScenarioHubRound3.class.getName(), + RunParallel.OPTION_PARAMS, Params.class.getName(), + RunParallel.OPTION_TASKS, Integer.toString(1), + RunParallel.OPTION_ITERATIONS, Integer.toString(70), + RunParallel.OPTION_METADATA + }; + + RunParallel.main(args2); + } + + +} + diff --git a/src/main/java/org/matsim/run/batch/UtilsJR.java b/src/main/java/org/matsim/run/batch/UtilsJR.java index 3ff3edfee..d1162e905 100644 --- a/src/main/java/org/matsim/run/batch/UtilsJR.java +++ b/src/main/java/org/matsim/run/batch/UtilsJR.java @@ -2,7 +2,11 @@ import com.typesafe.config.Config; import com.typesafe.config.ConfigValue; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.episim.model.ImmunityEvent; +import org.matsim.episim.model.VaccinationType; import org.matsim.episim.model.VirusStrain; +import org.matsim.episim.reporting.EpisimWriter; import tech.tablesaw.api.DateColumn; import tech.tablesaw.api.DoubleColumn; import tech.tablesaw.api.StringColumn; @@ -59,6 +63,51 @@ static void produceDiseaseImportPlot(Map> initialAntibodies) { + + try (BufferedWriter abReport = IOUtils.getBufferedWriter(IOUtils.getFileUrl("antibodies.csv"), IOUtils.CHARSET_UTF8, false)) { + abReport.write("protectionFrom"); + for (VirusStrain strain : VirusStrain.values()) { + abReport.write("," + strain.toString()); + } + abReport.write("\n"); + + for (VirusStrain protectionFrom : VirusStrain.values()) { + abReport.write(protectionFrom.toString()); + for (VirusStrain protectionAgainst: VirusStrain.values()) { + + abReport.write("," + initialAntibodies.get(protectionFrom).get(protectionAgainst)); + + } + abReport.write("\n"); + + } + + for (VaccinationType protectionFrom : VaccinationType.values()) { + abReport.write(protectionFrom.toString()); + for (VirusStrain protectionAgainst: VirusStrain.values()) { + + abReport.write("," + initialAntibodies.get(protectionFrom).get(protectionAgainst)); + + } + abReport.write("\n"); + + } + + } catch (Exception e) { + + } + + + + // ROWS: IMMUNITY FROM (top: infection, bottom: vaccinations) + // COLUMNS : IMMUNITY AGAINST + + + + } static void produceMaskPlot(Config policyConfig) { diff --git a/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java b/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java index c54539b7b..df3ad5c76 100644 --- a/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java +++ b/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java @@ -412,12 +412,11 @@ public Config config() { builder.restrict(LocalDate.parse("2022-10-04"), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); builder.restrict(LocalDate.parse("2022-10-15"), 1.0, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); //Weihnachtsferien - //TODO: uncomment xmas again -// builder.restrict(LocalDate.parse("2022-12-23"), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); -// builder.restrict(LocalDate.parse("2023-01-06"), 1.0, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); -// -// builder.restrict(LocalDate.parse("2022-12-19"), 0.2, "educ_higher"); -// builder.restrict(LocalDate.parse("2022-12-31"), 1.0, "educ_higher"); + builder.restrict(LocalDate.parse("2022-12-23"), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + builder.restrict(LocalDate.parse("2023-01-06"), 1.0, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + + builder.restrict(LocalDate.parse("2022-12-19"), 0.2, "educ_higher"); + builder.restrict(LocalDate.parse("2022-12-31"), 1.0, "educ_higher"); { From 320c53e27037c0463c71488d713c14a7eb83986f Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Wed, 7 Sep 2022 13:59:01 -0400 Subject: [PATCH 02/13] added new vaccination types and vocs for round 3 of eu scenario hub. --- .../episim/model/DefaultAntibodyModel.java | 28 +- .../model/InfectionModelWithAntibodies.java | 13 +- .../matsim/episim/model/VaccinationType.java | 32 ++ .../org/matsim/episim/model/VirusStrain.java | 24 +- .../run/batch/CologneScenarioHubRound3.java | 308 ++++++++++-------- .../java/org/matsim/run/batch/UtilsJR.java | 34 +- .../modules/SnzCologneProductionScenario.java | 28 ++ 7 files changed, 306 insertions(+), 161 deletions(-) diff --git a/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java b/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java index 4112fbe22..0f2ef4bfd 100644 --- a/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java +++ b/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java @@ -2,9 +2,24 @@ import com.google.inject.Inject; +import it.unimi.dsi.fastutil.doubles.DoubleArrayList; +import it.unimi.dsi.fastutil.doubles.DoubleList; import org.matsim.episim.EpisimPerson; import org.matsim.episim.EpisimUtils; - +import org.matsim.run.batch.UtilsJR; +import tech.tablesaw.api.DoubleColumn; +import tech.tablesaw.api.Table; +import tech.tablesaw.plotly.api.Histogram; +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.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.SplittableRandom; @@ -28,6 +43,8 @@ public class DefaultAntibodyModel implements AntibodyModel { @Override public void init(Collection persons, int iteration) { + DoubleList values = new DoubleArrayList(); + for (EpisimPerson person : persons) { // mu = log(median); log(1)=0 @@ -39,6 +56,8 @@ public void init(Collection persons, int iteration) { } person.setImmuneResponseMultiplier(immuneResponseMultiplier); + values.add(immuneResponseMultiplier); + for (VirusStrain strain : VirusStrain.values()) { person.setAntibodies(strain, 0.0); @@ -52,6 +71,13 @@ public void init(Collection persons, int iteration) { } } + Figure fig = Histogram.create("Distribution of Immune Response Multipliers", values.toDoubleArray()); + + try (Writer writer = new OutputStreamWriter(new FileOutputStream("immuneResponseMultiplierDistribution.html"), StandardCharsets.UTF_8)) { + writer.write(Page.pageBuilder(fig, "target").build().asJavascript()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } diff --git a/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java b/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java index 26fe673ca..bd8f6bb10 100644 --- a/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java +++ b/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java @@ -14,7 +14,7 @@ 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 { @@ -93,16 +93,17 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto double immunityFactorInfector = 1.0 / (1.0 + Math.pow(infector.getAntibodyLevelAtInfection(), vaccinationConfig.getBeta())); infectivity *= (1.0 - (0.25 * (1.0 - immunityFactorInfector))); + { double igaFactor = 0.0; double igaTimePeriod = vaccinationConfig.getTimePeriodIgA(); - if (target.hadStrain(infector.getVirusStrain()) && !List.of(VirusStrain.STRAIN_A, VirusStrain.STRAIN_B, VirusStrain.STRAIN_C).contains(infector.getVirusStrain())) { + if (target.hadStrain(infector.getVirusStrain()) && !List.of(VirusStrain.STRAIN_A, VirusStrain.STRAIN_B, VirusStrain.STRAIN_C, VirusStrain.STRAIN_D, VirusStrain.STRAIN_E, VirusStrain.STRAIN_F, VirusStrain.STRAIN_G, VirusStrain.STRAIN_H, VirusStrain.STRAIN_I, VirusStrain.STRAIN_J, VirusStrain.STRAIN_K, VirusStrain.STRAIN_L, VirusStrain.STRAIN_M, VirusStrain.STRAIN_N).contains(infector.getVirusStrain())) { int lastInfectionWithStrain = 0; - for (int ii = 0; ii < target.getNumInfections(); ii++) { + for (int ii = 0; ii < target.getNumInfections(); ii++) { if (target.getVirusStrain(ii) == infector.getVirusStrain()) { lastInfectionWithStrain = ii; } @@ -113,11 +114,11 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto } else if (vaccinationConfig.getUseIgA()) { List crossImmunityStrainsOmicron = List.of(VirusStrain.OMICRON_BA1, VirusStrain.OMICRON_BA2, VirusStrain.OMICRON_BA5); - if(crossImmunityStrainsOmicron.contains(infector.getVirusStrain())){ + if (crossImmunityStrainsOmicron.contains(infector.getVirusStrain())) { int lastInfectionWithStrain = 0; boolean targetHadStrain = false; - for (int ii = 0; ii < target.getNumInfections(); ii++) { - if (crossImmunityStrainsOmicron.contains(target.getVirusStrain(ii))){ + for (int ii = 0; ii < target.getNumInfections(); ii++) { + if (crossImmunityStrainsOmicron.contains(target.getVirusStrain(ii))) { targetHadStrain = true; lastInfectionWithStrain = ii; } diff --git a/src/main/java/org/matsim/episim/model/VaccinationType.java b/src/main/java/org/matsim/episim/model/VaccinationType.java index 4181e9c0d..26b58dbd1 100644 --- a/src/main/java/org/matsim/episim/model/VaccinationType.java +++ b/src/main/java/org/matsim/episim/model/VaccinationType.java @@ -24,6 +24,38 @@ public enum VaccinationType implements ImmunityEvent { spring24, + fall24, + + spring25, + + fall25, + + spring26, + + fall26, + + spring27, + + fall27, + + spring28, + + fall28, + + spring29, + + fall29, + + spring30, + + fall30, + + spring31, + + fall31, + + spring32 + } diff --git a/src/main/java/org/matsim/episim/model/VirusStrain.java b/src/main/java/org/matsim/episim/model/VirusStrain.java index c809e6ab6..cdf5dd947 100644 --- a/src/main/java/org/matsim/episim/model/VirusStrain.java +++ b/src/main/java/org/matsim/episim/model/VirusStrain.java @@ -42,5 +42,27 @@ public enum VirusStrain implements ImmunityEvent { STRAIN_B, - STRAIN_C + STRAIN_C, + + STRAIN_D, + + STRAIN_E, + + STRAIN_F, + + STRAIN_G, + + STRAIN_H, + + STRAIN_I, + + STRAIN_J, + + STRAIN_K, + + STRAIN_L, + + STRAIN_M, + + STRAIN_N } diff --git a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java index a8d939bfe..d5bdea210 100644 --- a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java +++ b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java @@ -20,20 +20,62 @@ import javax.annotation.Nullable; import java.time.LocalDate; import java.util.*; +import java.util.stream.Collectors; /** * ROUND 3 - * case: annual - * Sept'22 : update 1 - * Oct'22 : strainA - * Sep'23 : */ public class CologneScenarioHubRound3 implements BatchRun { - boolean DEBUG_MODE = true; + boolean DEBUG_MODE = false; int runCount = 0; + + + + Map newVirusStrains = new HashMap<>(); + Map newVaccinations = new HashMap<>(); + + public CologneScenarioHubRound3() { + + newVirusStrains.put(LocalDate.of(2022,10,15),VirusStrain.STRAIN_A); + newVirusStrains.put(LocalDate.of(2023,7,15),VirusStrain.STRAIN_B); + newVirusStrains.put(LocalDate.of(2024,4,15),VirusStrain.STRAIN_C); + newVirusStrains.put(LocalDate.of(2025,1,15),VirusStrain.STRAIN_D); + newVirusStrains.put(LocalDate.of(2025,10,15),VirusStrain.STRAIN_E); + newVirusStrains.put(LocalDate.of(2026,7,15),VirusStrain.STRAIN_F); + newVirusStrains.put(LocalDate.of(2027,4,15),VirusStrain.STRAIN_G); + newVirusStrains.put(LocalDate.of(2028,1,15),VirusStrain.STRAIN_H); + newVirusStrains.put(LocalDate.of(2028,10,15),VirusStrain.STRAIN_I); + newVirusStrains.put(LocalDate.of(2029,7,15),VirusStrain.STRAIN_J); + newVirusStrains.put(LocalDate.of(2030,4,15),VirusStrain.STRAIN_K); + newVirusStrains.put(LocalDate.of(2031,1,15),VirusStrain.STRAIN_L); + newVirusStrains.put(LocalDate.of(2031,10,15),VirusStrain.STRAIN_M); + newVirusStrains.put(LocalDate.of(2032,7,15),VirusStrain.STRAIN_N); + + newVaccinations.put(LocalDate.of(2022,9,1),VaccinationType.fall22); + newVaccinations.put(LocalDate.of(2023,3,1),VaccinationType.spring23); + newVaccinations.put(LocalDate.of(2023,9,1),VaccinationType.fall23); + newVaccinations.put(LocalDate.of(2024,3,1),VaccinationType.spring24); + newVaccinations.put(LocalDate.of(2024,9,1),VaccinationType.fall24); + newVaccinations.put(LocalDate.of(2025,3,1),VaccinationType.spring25); + newVaccinations.put(LocalDate.of(2025,9,1),VaccinationType.fall25); + newVaccinations.put(LocalDate.of(2026,3,1),VaccinationType.spring26); + newVaccinations.put(LocalDate.of(2026,9,1),VaccinationType.fall26); + newVaccinations.put(LocalDate.of(2027,3,1),VaccinationType.spring27); + newVaccinations.put(LocalDate.of(2027,9,1),VaccinationType.fall27); + newVaccinations.put(LocalDate.of(2028,3,1),VaccinationType.spring28); + newVaccinations.put(LocalDate.of(2028,9,1),VaccinationType.fall28); + newVaccinations.put(LocalDate.of(2029,3,1),VaccinationType.spring29); + newVaccinations.put(LocalDate.of(2029,9,1),VaccinationType.fall29); + newVaccinations.put(LocalDate.of(2030,3,1),VaccinationType.spring30); + newVaccinations.put(LocalDate.of(2030,9,1),VaccinationType.fall30); + newVaccinations.put(LocalDate.of(2031,3,1),VaccinationType.spring31); + newVaccinations.put(LocalDate.of(2031,9,1),VaccinationType.fall31); + newVaccinations.put(LocalDate.of(2032,3,1), VaccinationType.spring32); + } + @Nullable @Override public Module getBindings(int id, @Nullable Params params) { @@ -45,22 +87,11 @@ protected void configure() { set.addBinding().to(VaccinationStrategyReoccurringCampaigns.class).in(Singleton.class); - double mutEscBa5 = 3.0; double mutEscStrainX = 3.0; - LocalDate startSpring = LocalDate.of(2023, 4, 15); - LocalDate startAutumn = LocalDate.of(2023, 9, 15); - - Map startDateToVOC = new HashMap<>(); - startDateToVOC.put(LocalDate.of(2022, 9, 15), VaccinationType.fall22); - - if (DEBUG_MODE) { - startDateToVOC.put(LocalDate.of(2020, 3, 1), VaccinationType.fall23); - startDateToVOC.put(LocalDate.of(2020, 3, 15), VaccinationType.fall23); - - } + Map startDateToVaccination = new HashMap<>(); Int2DoubleMap compliance = new Int2DoubleAVLTreeMap(); compliance.put(60, 0.0); @@ -72,14 +103,12 @@ protected void configure() { mutEscStrainX = params.mutEsc; - //todo: change such that third booster is not given in 2022. if (params.vacFreq.equals("none")) { + startDateToVaccination.put(LocalDate.of(2022, 9, 15), newVaccinations.get(LocalDate.of(2022, 9, 15))); } else if (params.vacFreq.equals("annual")) { - startDateToVOC.put(startAutumn, VaccinationType.fall23); + startDateToVaccination.putAll(newVaccinations.entrySet().stream().filter(entry -> entry.getKey().getMonthValue() == 9).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); } else if (params.vacFreq.equals("biannual")) { - startDateToVOC.put(startSpring, VaccinationType.spring23); - startDateToVOC.put(startAutumn, VaccinationType.fall23); - startDateToVOC.put(startSpring.plusYears(1), VaccinationType.spring24); + startDateToVaccination.putAll(newVaccinations); } else { throw new RuntimeException(); } @@ -109,11 +138,11 @@ else if (params.vacCamp.equals("off")) { int campaignDuration = 91; - if (DEBUG_MODE) { - campaignDuration = 5; - } +// if (DEBUG_MODE) { +// campaignDuration = 5; +// } - bind(VaccinationStrategyReoccurringCampaigns.Config.class).toInstance(new VaccinationStrategyReoccurringCampaigns.Config(startDateToVOC, campaignDuration, compliance)); + bind(VaccinationStrategyReoccurringCampaigns.Config.class).toInstance(new VaccinationStrategyReoccurringCampaigns.Config(startDateToVaccination, campaignDuration, compliance)); //initial antibodies Map> initialAntibodies = new HashMap<>(); @@ -129,7 +158,7 @@ else if (params.vacCamp.equals("off")) { bind(AntibodyModel.Config.class).toInstance(antibodyConfig); - if (DEBUG_MODE && params != null && params.mutEsc == 3.) { + if (DEBUG_MODE && params != null) { UtilsJR.produceAntibodiesCsv(initialAntibodies); } @@ -161,9 +190,6 @@ private void configureAntibodies(Map> in } } - List newImmunityEvents = List.of(VirusStrain.STRAIN_A, VirusStrain.STRAIN_B, VirusStrain.STRAIN_C, - VaccinationType.fall22, VaccinationType.spring23, VaccinationType.fall23, VaccinationType.spring24); - //mRNAAlpha, mRNADelta, mRNABA1 comes from Sydney's calibration. //The other values come from Rössler et al. @@ -180,10 +206,6 @@ private void configureAntibodies(Map> in initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.SARS_CoV_2, 0.01); initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.SARS_CoV_2, 0.01); - for (ImmunityEvent event : newImmunityEvents) { - initialAntibodies.get(event).put(VirusStrain.SARS_CoV_2, 0.01); - } - //Alpha initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.ALPHA, mRNAAlpha); @@ -195,10 +217,6 @@ private void configureAntibodies(Map> in initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.ALPHA, 0.01); initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.ALPHA, 0.01); - for (ImmunityEvent event : newImmunityEvents) { - initialAntibodies.get(event).put(VirusStrain.ALPHA, 0.01); - } - //DELTA double mRNADelta = 10.9; initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.DELTA, mRNADelta); @@ -210,9 +228,6 @@ private void configureAntibodies(Map> in initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.DELTA, 0.2 / 6.4); initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.DELTA, 0.2 / 6.4); - for (ImmunityEvent event : newImmunityEvents) { - initialAntibodies.get(event).put(VirusStrain.DELTA, 0.01); - } //BA.1 double mRNABA1 = 1.9; @@ -225,11 +240,6 @@ private void configureAntibodies(Map> in 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. / 1.4); //todo: is 1.4 - for (ImmunityEvent event : newImmunityEvents) { - initialAntibodies.get(event).put(VirusStrain.OMICRON_BA1, 0.01); - } - - //BA.2 double mRNABA2 = mRNABA1; initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA2, mRNABA2); @@ -241,10 +251,6 @@ private void configureAntibodies(Map> in initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA2, 64.0 / 300.); initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / 1.4); - for (ImmunityEvent event : newImmunityEvents) { - initialAntibodies.get(event).put(VirusStrain.OMICRON_BA2, 0.01); - } - //BA.5 double mRNABa5 = mRNABA2 / mutEscBa5; @@ -257,80 +263,84 @@ private void configureAntibodies(Map> in 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.); - for (ImmunityEvent event : newImmunityEvents) { - initialAntibodies.get(event).put(VirusStrain.OMICRON_BA5, 0.01); + // NEW STRAINS + + // A) all "new/updated/novel" vaccinations and infections give only 0.01 protection against "old" strains + + for (VirusStrain protectionAgainst : List.of(VirusStrain.SARS_CoV_2, VirusStrain.ALPHA, VirusStrain.DELTA, VirusStrain.OMICRON_BA1, VirusStrain.OMICRON_BA2, VirusStrain.OMICRON_BA5)) { + for (ImmunityEvent vax : newVaccinations.values()) { + initialAntibodies.get(vax).put(protectionAgainst, 0.01); + } + + for (ImmunityEvent strain : newVirusStrains.values()) { + initialAntibodies.get(strain).put(protectionAgainst, 0.01); + } } - // NEW STRAINS + // B) "old" vaccinations and infections give the same protection to StrainX as to BA5 PLUS an escape + double mRNAStrainX = mRNABa5 / mutEscStrainX; + + for (VirusStrain newStrain : newVirusStrains.values()) { + initialAntibodies.get(VaccinationType.mRNA).put(newStrain, mRNAStrainX); + initialAntibodies.get(VaccinationType.vector).put(newStrain, mRNAStrainX * 4. / 20.); + initialAntibodies.get(VirusStrain.SARS_CoV_2).put(newStrain, mRNAStrainX * 6. / 20.); + initialAntibodies.get(VirusStrain.ALPHA).put(newStrain, mRNAStrainX * 6. / 20.); + initialAntibodies.get(VirusStrain.DELTA).put(newStrain, mRNAStrainX * 8. / 20.); + + initialAntibodies.get(VirusStrain.OMICRON_BA1).put(newStrain, 64.0 / 300. / mutEscBa5 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA2).put(newStrain, 64.0 / 300. / mutEscBa5 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA5).put(newStrain, 64.0 / 300. / mutEscStrainX); + + } + + // C) Immunity between the novel StrainsX: + // Newer Strains give full (non-escaped) protection against themselves AND previous strains + // New Strains give escaped protection against future strainA - //StrainA + // initialAntibodies.get(IMMUNITY GIVER).put(IMMUNITY AGAINST, ab level); - double mRNAStrainA = mRNABa5 / mutEscStrainX; - 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.); + for (LocalDate dateProtectionGiver : newVirusStrains.keySet()) { - initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscBa5 / mutEscStrainX); - initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscBa5 / mutEscStrainX); - initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_A, 64.0 / 300. / mutEscStrainX); + for (LocalDate dateProtectionAgainst : newVirusStrains.keySet()) { - initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_A, mRNAAlpha); // we assume strainA produces the same amount of AB against reinfection as BA5 produces against reinfection - initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VirusStrain.STRAIN_C).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainX); // we assume the escape grow exponentially as StrainX gets further removed from StrainA + if (dateProtectionGiver.equals(dateProtectionAgainst) || dateProtectionGiver.isAfter(dateProtectionAgainst)) { + // Newer Strains give full (non-escaped) protection against themselves AND previous strains + initialAntibodies.get(newVirusStrains.get(dateProtectionGiver)).put(newVirusStrains.get(dateProtectionAgainst), mRNAAlpha); - initialAntibodies.get(VaccinationType.fall22).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VaccinationType.spring23).put(VirusStrain.STRAIN_A, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VaccinationType.fall23).put(VirusStrain.STRAIN_A, mRNAAlpha); - initialAntibodies.get(VaccinationType.spring24).put(VirusStrain.STRAIN_A, mRNAAlpha); + } else { + // New Strains give escaped protection against future strainA + initialAntibodies.get(newVirusStrains.get(dateProtectionGiver)).put(newVirusStrains.get(dateProtectionAgainst), mRNAAlpha/ mutEscStrainX); - //StrainB + } -// double mRNAStrainA = mRNABa5 / escape; - initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_B, mRNAStrainA); - initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_B, mRNAStrainA * 4. / 20.); - initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_B, mRNAStrainA * 6. / 20.); - initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_B, mRNAStrainA * 6. / 20.); - initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_B, mRNAStrainA * 8. / 20.); + } + } - initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscBa5 / mutEscStrainX); - initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscBa5 / mutEscStrainX); - initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_B, 64.0 / 300. / mutEscStrainX); + // D) Immunity provided by new vaccines against novel StrainsX: + // Provides baseline immunity if StrainX was spawned more than 6 months before vaccination campaign begins + // provides reduced immunity otherwise - initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_B, mRNAAlpha); // we assume strainA produces the same amount of AB against reinfection as BA5 produces against reinfection - initialAntibodies.get(VirusStrain.STRAIN_C).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); // we assume the escape grow exponentially as StrainX gets further removed from StrainA + for (LocalDate dateProtectionGiver : newVaccinations.keySet()) { - initialAntibodies.get(VaccinationType.fall22).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VaccinationType.spring23).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VaccinationType.fall23).put(VirusStrain.STRAIN_B, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VaccinationType.spring24).put(VirusStrain.STRAIN_B, mRNAAlpha); + for (LocalDate dateProtectionAgainst : newVirusStrains.keySet()) { - //StrainC + if (dateProtectionGiver.isAfter(dateProtectionAgainst.plusMonths(6))) { + // Provides baseline immunity if StrainX was spawned more than 6 months before vaccination campaign begins -// double mRNAStrainA = mRNABa5 / escape; - initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.STRAIN_C, mRNAStrainA); - initialAntibodies.get(VaccinationType.vector).put(VirusStrain.STRAIN_C, mRNAStrainA * 4. / 20.); - initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.STRAIN_C, mRNAStrainA * 6. / 20.); - initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.STRAIN_C, mRNAStrainA * 6. / 20.); - initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.STRAIN_C, mRNAStrainA * 8. / 20.); + initialAntibodies.get(newVaccinations.get(dateProtectionGiver)).put(newVirusStrains.get(dateProtectionAgainst), mRNAAlpha); - initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.STRAIN_C, 64.0 / 300. / mutEscBa5 / mutEscStrainX); - initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.STRAIN_C, 64.0 / 300. / mutEscBa5 / mutEscStrainX); - initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.STRAIN_C, 64.0 / 300. / mutEscStrainX); + } + else { + // provides reduced immunity otherwise + initialAntibodies.get(newVaccinations.get(dateProtectionGiver)).put(newVirusStrains.get(dateProtectionAgainst), mRNAAlpha/ mutEscStrainX); - initialAntibodies.get(VirusStrain.STRAIN_A).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VirusStrain.STRAIN_B).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VirusStrain.STRAIN_C).put(VirusStrain.STRAIN_C, mRNAAlpha); + } - initialAntibodies.get(VaccinationType.fall22).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VaccinationType.spring23).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VaccinationType.fall23).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); - initialAntibodies.get(VaccinationType.spring24).put(VirusStrain.STRAIN_C, mRNAAlpha / mutEscStrainX); + } + } - List strainsX = List.of(VirusStrain.STRAIN_A, VirusStrain.STRAIN_B, VirusStrain.STRAIN_C); + // R E F R E S H F A C T O R S for (VaccinationType immunityType : VaccinationType.values()) { antibodyRefreshFactors.put(immunityType, new EnumMap<>(VirusStrain.class)); for (VirusStrain virusStrain : VirusStrain.values()) { @@ -341,8 +351,8 @@ private void configureAntibodies(Map> in antibodyRefreshFactors.get(immunityType).put(virusStrain, 5.0); } else if (immunityType == VaccinationType.ba1Update) { antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0); - } else if (List.of(VaccinationType.fall22, VaccinationType.spring23, VaccinationType.fall23, VaccinationType.spring24).contains(immunityType)) { - if (strainsX.contains(virusStrain)) { + } else if (newVaccinations.containsValue(immunityType)) { + if (newVirusStrains.containsValue(virusStrain)) { antibodyRefreshFactors.get(immunityType).put(virusStrain, 1.0); } else { antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0); @@ -358,7 +368,7 @@ private void configureAntibodies(Map> in for (VirusStrain immunityType : VirusStrain.values()) { antibodyRefreshFactors.put(immunityType, new EnumMap<>(VirusStrain.class)); for (VirusStrain virusStrain : VirusStrain.values()) { - if (strainsX.contains(immunityType) && strainsX.contains(virusStrain)) { + if (newVirusStrains.containsValue(immunityType) && newVirusStrains.containsValue(virusStrain)) { antibodyRefreshFactors.get(immunityType).put(virusStrain, 1.0); } else { antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0); @@ -421,7 +431,9 @@ public Config prepareConfig(int id, Params params) { EpisimConfigGroup episimConfig = ConfigUtils.addOrGetModule(config, EpisimConfigGroup.class); // create snapshot - episimConfig.setSnapshotInterval(927); +// episimConfig.setSnapshotInterval(927); +// episimConfig.setStartFromSnapshot("/scratch/projects/bzz0020/episim-input/snapshots-cologne-20220218/" + params.seed + "-600-2021-10-16.zip"); +// episimConfig.setSnapshotSeed(EpisimConfigGroup.SnapshotSeed.restore); //mutations VirusStrainConfigGroup virusStrainConfigGroup = ConfigUtils.addOrGetModule(config, VirusStrainConfigGroup.class); @@ -437,7 +449,7 @@ public Config prepareConfig(int id, Params params) { //StrainA/B/C - for (VirusStrain strain : List.of(VirusStrain.STRAIN_A, VirusStrain.STRAIN_B, VirusStrain.STRAIN_C)) { + for (VirusStrain strain : newVirusStrains.values()) { virusStrainConfigGroup.getOrAddParams(strain).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA5).getInfectiousness()); virusStrainConfigGroup.getOrAddParams(strain).setFactorSeriouslySick(oHos); virusStrainConfigGroup.getOrAddParams(strain).setFactorSeriouslySickVaccinated(oHos); @@ -464,7 +476,9 @@ public Config prepareConfig(int id, Params params) { } - + if (DEBUG_MODE) { + UtilsJR.produceDiseaseImportPlot(episimConfig.getInfections_pers_per_day()); + } @@ -475,22 +489,6 @@ private void configureFutureDiseaseImport(Params params, EpisimConfigGroup episi 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 strainToDate = Map.of( - VirusStrain.STRAIN_A, LocalDate.of(2022, 10, 1), - VirusStrain.STRAIN_B, LocalDate.of(2023, 7, 1), - VirusStrain.STRAIN_C, LocalDate.of(2024, 4, 1) - ); - - - if (DEBUG_MODE) { - strainToDate = Map.of( - VirusStrain.STRAIN_A, LocalDate.of(2020, 3, 1), - VirusStrain.STRAIN_B, LocalDate.of(2020, 3, 1), - VirusStrain.STRAIN_C, LocalDate.of(2020, 3, 1) - ); - - } - // add initial impulses for strains //BA.2 LocalDate ba2Date = LocalDate.parse("2021-12-18"); @@ -506,12 +504,17 @@ private void configureFutureDiseaseImport(Params params, EpisimConfigGroup episi } infPerDayBa5.put(ba5Date.plusDays(7), 1); + episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA2, infPerDayBa2); + episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA5, infPerDayBa5); + //StrainA/B/C - for (VirusStrain strain : strainToDate.keySet()) { + for (Map.Entry entry : newVirusStrains.entrySet()) { + LocalDate date = entry.getKey(); + VirusStrain strain = entry.getValue(); + Map infPerDayStrainX = new HashMap<>(episimConfig.getInfections_pers_per_day().getOrDefault(strain, new TreeMap<>())); infPerDayStrainX.put(LocalDate.parse("2020-01-01"), 0); - LocalDate date = strainToDate.get(strain); for (int i = 0; i < 7; i++) { infPerDayStrainX.put(date.plusDays(i), 4); } @@ -520,8 +523,9 @@ private void configureFutureDiseaseImport(Params params, EpisimConfigGroup episi } // add projected disease import for vacation waves after initial disease import - int facBa2 = 4; - int facBa5 = 4; +// int facBa2 = 4; +// int facBa5 = 4; + int facStrainX = 4; LocalDate dateBa2 = LocalDate.parse("2022-01-27"); // local min of disease import LocalDate dateBa5 = LocalDate.parse("2022-05-01"); // after vaca import @@ -534,20 +538,46 @@ private void configureFutureDiseaseImport(Params params, EpisimConfigGroup episi // double cases = factor * entry.getValue(); - 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)); + //from most recent to furthest back. + Map reverseSortedVirusStrainMap = new TreeMap(Collections.reverseOrder()); + reverseSortedVirusStrainMap.putAll(newVirusStrains); + reverseSortedVirusStrainMap.put(dateBa5, VirusStrain.OMICRON_BA5); + reverseSortedVirusStrainMap.put(dateBa2, VirusStrain.OMICRON_BA2); + + + // strain map sorted from newest to oldest + // if current date is after LATEST virus's spawn date + 2 months -> give the corresponding virusStrain all the import + // if currents datae is after virusStrainDate -> give the corresponding virusStrain an import of 1. + // else: current date is before spwan of virus strain -> don't give any import + + + boolean firstTimeAfterDate = true; + for (LocalDate dateStrainX : reverseSortedVirusStrainMap.keySet()) { + + if (date.isAfter(dateStrainX.plusMonths(2)) && firstTimeAfterDate) { + episimConfig.getInfections_pers_per_day().get(reverseSortedVirusStrainMap.get(dateStrainX)).put(date, ((int) cases * facStrainX) == 0 ? 1 : (int) (cases * facStrainX)); + firstTimeAfterDate = false; + } else if (date.isAfter(dateStrainX.plusMonths(2))) { + episimConfig.getInfections_pers_per_day().get(reverseSortedVirusStrainMap.get(dateStrainX)).put(date, 1); + } else { + episimConfig.getInfections_pers_per_day().get(reverseSortedVirusStrainMap.get(dateStrainX)).put(date, 0); + } + } +// 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)); +// } + } - infPerDayBa5.put(date.plusDays(1), 1); +// infPerDayBa5.put(date.plusDays(1), 1); // save disease import - episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA2, infPerDayBa2); - episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA5, infPerDayBa5); + } diff --git a/src/main/java/org/matsim/run/batch/UtilsJR.java b/src/main/java/org/matsim/run/batch/UtilsJR.java index d1162e905..ff8feea12 100644 --- a/src/main/java/org/matsim/run/batch/UtilsJR.java +++ b/src/main/java/org/matsim/run/batch/UtilsJR.java @@ -11,6 +11,7 @@ import tech.tablesaw.api.DoubleColumn; import tech.tablesaw.api.StringColumn; import tech.tablesaw.api.Table; +import tech.tablesaw.plotly.api.Histogram; import tech.tablesaw.plotly.components.Axis; import tech.tablesaw.plotly.components.Figure; import tech.tablesaw.plotly.components.Layout; @@ -21,6 +22,7 @@ import java.io.*; import java.nio.charset.StandardCharsets; import java.time.LocalDate; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.NavigableMap; @@ -30,7 +32,7 @@ public class UtilsJR { static void produceDiseaseImportPlot(Map> infections_pers_per_day) { LocalDate startDate = LocalDate.of(2020, 2, 1); - LocalDate endDate = LocalDate.of(2023, 2, 25); + LocalDate endDate = LocalDate.of(2032, 12, 31); DateColumn recordsDate = DateColumn.create("date"); DoubleColumn values = DoubleColumn.create("import"); @@ -59,24 +61,31 @@ static void produceDiseaseImportPlot(Map> initialAntibodies) { + List relevantStrains = new ArrayList<>(List.of(VirusStrain.values())); + relevantStrains.remove(VirusStrain.B1351); + + List relevantVaccinations = new ArrayList<>(List.of(VaccinationType.values())); + relevantVaccinations.removeAll(List.of(VaccinationType.ba1Update, VaccinationType.ba5Update, VaccinationType.natural, VaccinationType.generic)); + try (BufferedWriter abReport = IOUtils.getBufferedWriter(IOUtils.getFileUrl("antibodies.csv"), IOUtils.CHARSET_UTF8, false)) { abReport.write("protectionFrom"); - for (VirusStrain strain : VirusStrain.values()) { + + + for (VirusStrain strain : relevantStrains) { abReport.write("," + strain.toString()); } abReport.write("\n"); - for (VirusStrain protectionFrom : VirusStrain.values()) { + for (VirusStrain protectionFrom : relevantStrains) { abReport.write(protectionFrom.toString()); - for (VirusStrain protectionAgainst: VirusStrain.values()) { + for (VirusStrain protectionAgainst : relevantStrains) { abReport.write("," + initialAntibodies.get(protectionFrom).get(protectionAgainst)); @@ -85,9 +94,10 @@ static void produceAntibodiesCsv(Map> in } - for (VaccinationType protectionFrom : VaccinationType.values()) { + + for (VaccinationType protectionFrom : relevantVaccinations) { abReport.write(protectionFrom.toString()); - for (VirusStrain protectionAgainst: VirusStrain.values()) { + for (VirusStrain protectionAgainst : relevantStrains) { abReport.write("," + initialAntibodies.get(protectionFrom).get(protectionAgainst)); @@ -101,13 +111,10 @@ static void produceAntibodiesCsv(Map> in } - // ROWS: IMMUNITY FROM (top: infection, bottom: vaccinations) // COLUMNS : IMMUNITY AGAINST - - } static void produceMaskPlot(Config policyConfig) { @@ -151,16 +158,15 @@ static void produceMaskPlot(Config policyConfig) { // values.append(entry.getValue()); // groupings.append(strain.toString()); // } - } + } // producePlot(recordsDate,values,groupings,"import by strain", "import", "importByStrain.html"); - // } - private static void producePlot(DateColumn records, DoubleColumn values, StringColumn groupings, String title, String yAxisTitle, String filename) { + public 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); diff --git a/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java b/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java index df3ad5c76..7bbd3423d 100644 --- a/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java +++ b/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java @@ -419,6 +419,34 @@ public Config config() { builder.restrict(LocalDate.parse("2022-12-31"), 1.0, "educ_higher"); + // repeat one year worth of school closures 10 years into the future + // exact dates won't be correct + for (int addedYear = 1; addedYear <= 10; addedYear++) { + //Osterferien + builder.restrict(LocalDate.parse("2022-04-11").plusYears(addedYear), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + builder.restrict(LocalDate.parse("2022-04-23").plusYears(addedYear), 1.0, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + //Sommerferien + builder.restrict(LocalDate.parse("2022-06-27").plusYears(addedYear), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + builder.restrict(LocalDate.parse("2022-08-09").plusYears(addedYear), 1.0, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + + builder.restrict(LocalDate.parse("2022-07-23").plusYears(addedYear), 0.2, "educ_higher"); + builder.restrict(LocalDate.parse("2022-10-17").plusYears(addedYear), 1.0, "educ_higher"); + + //Herbstferien + builder.restrict(LocalDate.parse("2022-10-04").plusYears(addedYear), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + builder.restrict(LocalDate.parse("2022-10-15").plusYears(addedYear), 1.0, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + //Weihnachtsferien + builder.restrict(LocalDate.parse("2022-12-23").plusYears(addedYear), 0.2, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + builder.restrict(LocalDate.parse("2023-01-06").plusYears(addedYear), 1.0, "educ_primary", "educ_kiga", "educ_secondary", "educ_tertiary", "educ_other"); + + builder.restrict(LocalDate.parse("2022-12-19").plusYears(addedYear), 0.2, "educ_higher"); + builder.restrict(LocalDate.parse("2022-12-31").plusYears(addedYear), 1.0, "educ_higher"); + + } + + + + { LocalDate masksCenterDate = LocalDate.of(2020, 4, 27); for (int ii = 0; ii <= 14; ii++) { From a3165cf75b5e113f3a459753f9d46c75953283ef Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Mon, 12 Sep 2022 12:37:14 -0400 Subject: [PATCH 03/13] added r script to extend disease import --- src/main/R/extendingDiseaseImport.R | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/main/R/extendingDiseaseImport.R diff --git a/src/main/R/extendingDiseaseImport.R b/src/main/R/extendingDiseaseImport.R new file mode 100644 index 000000000..c0a9b2118 --- /dev/null +++ b/src/main/R/extendingDiseaseImport.R @@ -0,0 +1,57 @@ +library(lubridate) +library(ggplot2) +raw <- read.csv("~/git/shared-svn/projects/episim/matsim-files/snz/Cologne/episim-input/cologneDiseaseImport_Projected.csv") + +x <- raw + +# first date after previous projections. +date <-dmy(tail(raw$date,1)) +1 + +# we iterate day for day until the end of 2032. Each day, we check whether to +# add a import wave from 2022 or 2023 into the current year. +while(date4) || month(date)>7){ + cases <- x[dmy(x$date)==ymd(paste0("2022","-",month(date),"-",mday(date))),]$cases + } + + + x[nrow(x) + 1,] = c(format(date,"%d.%m.%y"), cases) +} + + + +ggplot(x) + geom_line(aes(dmy(date),as.numeric(cases))) + + +# Here we add the hypothetical easter disease import +# This always begins on april 1 of the year x and continues the same number of +# days as the autumn import (absolute values are also same, copied to array below) +easter_import <-c(3,11,20,27,34,40,45,50,54,57,59,61,62,63,62,61,59,57,54,50,45,40,34,27,20,11,3) + +for(year in 2023:2032){ + + date <- ymd(paste0(year,"-04-01")) + for(import_for_day in easter_import){ + x[which(dmy(x$date)==date),"cases"] <- import_for_day + date <- date + 1 + } + +} + + +ggplot(x) + geom_line(aes(dmy(date),as.numeric(cases))) + + +write.csv(x,file='~/git/shared-svn/projects/episim/matsim-files/snz/Cologne/episim-input/cologneDiseaseImport_Projected_2032.csv', row.names=FALSE, quote = FALSE) + \ No newline at end of file From 0eb9a50c452e8f00bc23a36af48ced2bc2ce227a Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Mon, 12 Sep 2022 12:38:10 -0400 Subject: [PATCH 04/13] added new vax types & updated hospitalisation post processing to handle them (run from 09/10) --- .../analysis/HospitalNumbersFromEvents.java | 169 ++++++++++++------ .../matsim/episim/model/VaccinationType.java | 30 +++- .../run/batch/CologneScenarioHubRound3.java | 114 +++++++----- 3 files changed, 213 insertions(+), 100 deletions(-) diff --git a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java index 558ee1409..c467df423 100644 --- a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java +++ b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java @@ -41,6 +41,7 @@ import org.matsim.episim.model.VirusStrain; import org.matsim.episim.model.progression.AgeDependentDiseaseStatusTransitionModel; import org.matsim.run.AnalysisCommand; + import org.matsim.run.batch.CologneScenarioHubRound3; import picocli.CommandLine; import java.io.*; @@ -89,63 +90,114 @@ public class HospitalNumbersFromEvents implements OutputAnalysis { private Population population; // 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, - VirusStrain.ALPHA, 14, - VirusStrain.DELTA, 14, - VirusStrain.OMICRON_BA1, 14, - VirusStrain.OMICRON_BA2, 14, - VirusStrain.OMICRON_BA5, 14, - VirusStrain.STRAIN_A, 14, - VirusStrain.STRAIN_B, 14 - )); + private static final Object2IntMap lagBetweenInfectionAndHospitalisation = renderLagBetweenInfectionAndHospitalisation(); + private static Object2IntMap renderLagBetweenInfectionAndHospitalisation() { + Object2IntMap xxx = new Object2IntAVLTreeMap<>( + Map.of(VirusStrain.SARS_CoV_2, 14, + VirusStrain.ALPHA, 14, + VirusStrain.DELTA, 14, + VirusStrain.OMICRON_BA1, 14, + VirusStrain.OMICRON_BA2, 14, + VirusStrain.OMICRON_BA5, 14 +// VirusStrain.STRAIN_A, 14, +// VirusStrain.STRAIN_B, 14 + )); + + for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { + xxx.put(virusStrain, 14); + } + + return xxx; + } + // source: hospitalization wave vs. ICU wave in cologne/nrw (see https://docs.google.com/spreadsheets/d/1jmaerl27LKidD1uk3azdIL1LmvHuxazNQlhVo9xO1z8/edit?usp=sharing) - private static final Object2IntMap lagBetweenHospitalizationAndICU = new Object2IntAVLTreeMap<>( - Map.of(VirusStrain.SARS_CoV_2, 6, - VirusStrain.ALPHA, 6, - VirusStrain.DELTA, 6, - VirusStrain.OMICRON_BA1, 6, - VirusStrain.OMICRON_BA2, 6, - VirusStrain.OMICRON_BA5, 6, - VirusStrain.STRAIN_A, 6, - VirusStrain.STRAIN_B, 6 - )); + private static final Object2IntMap lagBetweenHospitalizationAndICU = renderLagBetweenHospitalizationAndICU(); + + private static Object2IntAVLTreeMap renderLagBetweenHospitalizationAndICU() { + Object2IntAVLTreeMap xxx = new Object2IntAVLTreeMap<>( + Map.of(VirusStrain.SARS_CoV_2, 6, + VirusStrain.ALPHA, 6, + VirusStrain.DELTA, 6, + VirusStrain.OMICRON_BA1, 6, + VirusStrain.OMICRON_BA2, 6, + VirusStrain.OMICRON_BA5, 6 +// VirusStrain.STRAIN_A, 6, +// VirusStrain.STRAIN_B, 6 + )); + for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { + xxx.put(virusStrain, 6); + } + + + return xxx; + } // Austria study in https://docs.google.com/spreadsheets/d/1jmaerl27LKidD1uk3azdIL1LmvHuxazNQlhVo9xO1z8/edit#gid=0 - private static final Object2IntMap daysInHospitalGivenNoICU = new Object2IntAVLTreeMap<>( - Map.of(VirusStrain.SARS_CoV_2, 12, - VirusStrain.ALPHA, 12, - VirusStrain.DELTA, 12, - VirusStrain.OMICRON_BA1, 7, - VirusStrain.OMICRON_BA2, 7, - VirusStrain.OMICRON_BA5,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_BA2, 10, - VirusStrain.OMICRON_BA5,10, - VirusStrain.STRAIN_A, 10, - VirusStrain.STRAIN_B, 10 - )); + private static final Object2IntMap daysInHospitalGivenNoICU = renderDaysInHospitalGivenNoICU(); + + private static Object2IntAVLTreeMap renderDaysInHospitalGivenNoICU() { + Object2IntAVLTreeMap xxx = new Object2IntAVLTreeMap<>( + Map.of(VirusStrain.SARS_CoV_2, 12, + VirusStrain.ALPHA, 12, + VirusStrain.DELTA, 12, + VirusStrain.OMICRON_BA1, 7, + VirusStrain.OMICRON_BA2, 7, + VirusStrain.OMICRON_BA5, 7 +// VirusStrain.STRAIN_A, 7, +// VirusStrain.STRAIN_B, 7 + )); + + for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { + xxx.put(virusStrain, 7); + } + + + return xxx; + } + + private static final Object2IntMap daysInICU = renderDaysInICU(); + + private static Object2IntAVLTreeMap renderDaysInICU() { + Object2IntAVLTreeMap xxx = 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_BA2, 10, + VirusStrain.OMICRON_BA5, 10 +// VirusStrain.STRAIN_A, 10, +// VirusStrain.STRAIN_B, 10 + )); + + for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { + xxx.put(virusStrain, 10); + } + + return xxx; + } // ?? - private static final Object2IntMap daysInHospitalGivenICU = new Object2IntAVLTreeMap<>( - Map.of(VirusStrain.SARS_CoV_2, 60, - VirusStrain.ALPHA, 60, - VirusStrain.DELTA, 60, - VirusStrain.OMICRON_BA1, 60, - VirusStrain.OMICRON_BA2, 60, - VirusStrain.OMICRON_BA5,60, - VirusStrain.STRAIN_A, 60, - VirusStrain.STRAIN_B, 60 - )); + private static final Object2IntMap daysInHospitalGivenICU = renderDaysInHospitalGivenICU(); + + private static Object2IntAVLTreeMap renderDaysInHospitalGivenICU() { + Object2IntAVLTreeMap xxx = new Object2IntAVLTreeMap<>( + Map.of(VirusStrain.SARS_CoV_2, 60, + VirusStrain.ALPHA, 60, + VirusStrain.DELTA, 60, + VirusStrain.OMICRON_BA1, 60, + VirusStrain.OMICRON_BA2, 60, + VirusStrain.OMICRON_BA5, 60 +// VirusStrain.STRAIN_A, 60, +// VirusStrain.STRAIN_B, 60 + )); + + for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { + xxx.put(virusStrain, 60); + } + + return xxx; + } private static final double beta = 1.2; @@ -508,6 +560,7 @@ private int getAge(Id personId) { private void updateHospitalizationsPost(ImmunizablePerson person, VirusStrain strain, int infectionIteration) { + if (!lagBetweenInfectionAndHospitalisation.containsKey(strain) || !lagBetweenHospitalizationAndICU.containsKey(strain) || !daysInHospitalGivenNoICU.containsKey(strain) @@ -756,11 +809,17 @@ private ConfigHolder configure(double facA, double facAICU) { 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_A).setFactorSeriouslySick(facA); +// strainConfig.getOrAddParams(VirusStrain.STRAIN_A).setFactorCritical(facAICU); +// +// strainConfig.getOrAddParams(VirusStrain.STRAIN_B).setFactorSeriouslySick(facA); +// strainConfig.getOrAddParams(VirusStrain.STRAIN_B).setFactorCritical(facAICU); + + for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { + strainConfig.getOrAddParams(virusStrain).setFactorSeriouslySick(facA); + strainConfig.getOrAddParams(virusStrain).setFactorCritical(facAICU); + } - strainConfig.getOrAddParams(VirusStrain.STRAIN_B).setFactorSeriouslySick(facA); - strainConfig.getOrAddParams(VirusStrain.STRAIN_B).setFactorCritical(facAICU); diff --git a/src/main/java/org/matsim/episim/model/VaccinationType.java b/src/main/java/org/matsim/episim/model/VaccinationType.java index 26b58dbd1..546f336d3 100644 --- a/src/main/java/org/matsim/episim/model/VaccinationType.java +++ b/src/main/java/org/matsim/episim/model/VaccinationType.java @@ -54,7 +54,35 @@ public enum VaccinationType implements ImmunityEvent { fall31, - spring32 + spring32, + + vax_STRAIN_A, + + vax_STRAIN_B, + + vax_STRAIN_C, + + vax_STRAIN_D, + + vax_STRAIN_E, + + vax_STRAIN_F, + + vax_STRAIN_G, + + vax_STRAIN_H, + + vax_STRAIN_I, + + vax_STRAIN_J, + + vax_STRAIN_K, + + vax_STRAIN_L, + + vax_STRAIN_M, + + vax_STRAIN_N diff --git a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java index d5bdea210..89cd3f9d8 100644 --- a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java +++ b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java @@ -34,46 +34,70 @@ public class CologneScenarioHubRound3 implements BatchRun newVirusStrains = new HashMap<>(); - Map newVaccinations = new HashMap<>(); - - public CologneScenarioHubRound3() { - - newVirusStrains.put(LocalDate.of(2022,10,15),VirusStrain.STRAIN_A); - newVirusStrains.put(LocalDate.of(2023,7,15),VirusStrain.STRAIN_B); - newVirusStrains.put(LocalDate.of(2024,4,15),VirusStrain.STRAIN_C); - newVirusStrains.put(LocalDate.of(2025,1,15),VirusStrain.STRAIN_D); - newVirusStrains.put(LocalDate.of(2025,10,15),VirusStrain.STRAIN_E); - newVirusStrains.put(LocalDate.of(2026,7,15),VirusStrain.STRAIN_F); - newVirusStrains.put(LocalDate.of(2027,4,15),VirusStrain.STRAIN_G); - newVirusStrains.put(LocalDate.of(2028,1,15),VirusStrain.STRAIN_H); - newVirusStrains.put(LocalDate.of(2028,10,15),VirusStrain.STRAIN_I); - newVirusStrains.put(LocalDate.of(2029,7,15),VirusStrain.STRAIN_J); - newVirusStrains.put(LocalDate.of(2030,4,15),VirusStrain.STRAIN_K); - newVirusStrains.put(LocalDate.of(2031,1,15),VirusStrain.STRAIN_L); - newVirusStrains.put(LocalDate.of(2031,10,15),VirusStrain.STRAIN_M); - newVirusStrains.put(LocalDate.of(2032,7,15),VirusStrain.STRAIN_N); - - newVaccinations.put(LocalDate.of(2022,9,1),VaccinationType.fall22); - newVaccinations.put(LocalDate.of(2023,3,1),VaccinationType.spring23); - newVaccinations.put(LocalDate.of(2023,9,1),VaccinationType.fall23); - newVaccinations.put(LocalDate.of(2024,3,1),VaccinationType.spring24); - newVaccinations.put(LocalDate.of(2024,9,1),VaccinationType.fall24); - newVaccinations.put(LocalDate.of(2025,3,1),VaccinationType.spring25); - newVaccinations.put(LocalDate.of(2025,9,1),VaccinationType.fall25); - newVaccinations.put(LocalDate.of(2026,3,1),VaccinationType.spring26); - newVaccinations.put(LocalDate.of(2026,9,1),VaccinationType.fall26); - newVaccinations.put(LocalDate.of(2027,3,1),VaccinationType.spring27); - newVaccinations.put(LocalDate.of(2027,9,1),VaccinationType.fall27); - newVaccinations.put(LocalDate.of(2028,3,1),VaccinationType.spring28); - newVaccinations.put(LocalDate.of(2028,9,1),VaccinationType.fall28); - newVaccinations.put(LocalDate.of(2029,3,1),VaccinationType.spring29); - newVaccinations.put(LocalDate.of(2029,9,1),VaccinationType.fall29); - newVaccinations.put(LocalDate.of(2030,3,1),VaccinationType.spring30); - newVaccinations.put(LocalDate.of(2030,9,1),VaccinationType.fall30); - newVaccinations.put(LocalDate.of(2031,3,1),VaccinationType.spring31); - newVaccinations.put(LocalDate.of(2031,9,1),VaccinationType.fall31); - newVaccinations.put(LocalDate.of(2032,3,1), VaccinationType.spring32); + public static Map newVirusStrains = renderNewVirusStrains(); + public static Map newVaccinations = renderNewVaccinations(); + + private static Map renderNewVaccinations() { + + Map xxx = new HashMap<>(); + xxx.put(LocalDate.of(2022,9,1),VaccinationType.fall22); + xxx.put(LocalDate.of(2023,3,1),VaccinationType.spring23); + xxx.put(LocalDate.of(2023,9,1),VaccinationType.fall23); + xxx.put(LocalDate.of(2024,3,1),VaccinationType.spring24); + xxx.put(LocalDate.of(2024,9,1),VaccinationType.fall24); + xxx.put(LocalDate.of(2025,3,1),VaccinationType.spring25); + xxx.put(LocalDate.of(2025,9,1),VaccinationType.fall25); + xxx.put(LocalDate.of(2026,3,1),VaccinationType.spring26); + xxx.put(LocalDate.of(2026,9,1),VaccinationType.fall26); + xxx.put(LocalDate.of(2027,3,1),VaccinationType.spring27); + xxx.put(LocalDate.of(2027,9,1),VaccinationType.fall27); + xxx.put(LocalDate.of(2028,3,1),VaccinationType.spring28); + xxx.put(LocalDate.of(2028,9,1),VaccinationType.fall28); + xxx.put(LocalDate.of(2029,3,1),VaccinationType.spring29); + xxx.put(LocalDate.of(2029,9,1),VaccinationType.fall29); + xxx.put(LocalDate.of(2030,3,1),VaccinationType.spring30); + xxx.put(LocalDate.of(2030,9,1),VaccinationType.fall30); + xxx.put(LocalDate.of(2031,3,1),VaccinationType.spring31); + xxx.put(LocalDate.of(2031,9,1),VaccinationType.fall31); + xxx.put(LocalDate.of(2032,3,1), VaccinationType.spring32); + + xxx.put(LocalDate.of(2022,10,15), VaccinationType.vax_STRAIN_A); + xxx.put(LocalDate.of(2023,7,15), VaccinationType.vax_STRAIN_B); + xxx.put(LocalDate.of(2024,4,15), VaccinationType.vax_STRAIN_C); + xxx.put(LocalDate.of(2025,1,15), VaccinationType.vax_STRAIN_D); + xxx.put(LocalDate.of(2025,10,15), VaccinationType.vax_STRAIN_E); + xxx.put(LocalDate.of(2026,7,15), VaccinationType.vax_STRAIN_F); + xxx.put(LocalDate.of(2027,4,15), VaccinationType.vax_STRAIN_G); + xxx.put(LocalDate.of(2028,1,15), VaccinationType.vax_STRAIN_H); + xxx.put(LocalDate.of(2028,10,15), VaccinationType.vax_STRAIN_I); + xxx.put(LocalDate.of(2029,7,15), VaccinationType.vax_STRAIN_J); + xxx.put(LocalDate.of(2030,4,15), VaccinationType.vax_STRAIN_K); + xxx.put(LocalDate.of(2031,1,15), VaccinationType.vax_STRAIN_L); + xxx.put(LocalDate.of(2031,10,15), VaccinationType.vax_STRAIN_M); + xxx.put(LocalDate.of(2032,7,15), VaccinationType.vax_STRAIN_N); + + + return xxx; + } + + private static Map renderNewVirusStrains() { + Map xxx = new HashMap<>(); + xxx.put(LocalDate.of(2022,10,15),VirusStrain.STRAIN_A); + xxx.put(LocalDate.of(2023,7,15),VirusStrain.STRAIN_B); + xxx.put(LocalDate.of(2024,4,15),VirusStrain.STRAIN_C); + xxx.put(LocalDate.of(2025,1,15),VirusStrain.STRAIN_D); + xxx.put(LocalDate.of(2025,10,15),VirusStrain.STRAIN_E); + xxx.put(LocalDate.of(2026,7,15),VirusStrain.STRAIN_F); + xxx.put(LocalDate.of(2027,4,15),VirusStrain.STRAIN_G); + xxx.put(LocalDate.of(2028,1,15),VirusStrain.STRAIN_H); + xxx.put(LocalDate.of(2028,10,15),VirusStrain.STRAIN_I); + xxx.put(LocalDate.of(2029,7,15),VirusStrain.STRAIN_J); + xxx.put(LocalDate.of(2030,4,15),VirusStrain.STRAIN_K); + xxx.put(LocalDate.of(2031,1,15),VirusStrain.STRAIN_L); + xxx.put(LocalDate.of(2031,10,15),VirusStrain.STRAIN_M); + xxx.put(LocalDate.of(2032,7,15),VirusStrain.STRAIN_N); + + return xxx; } @Nullable @@ -104,11 +128,13 @@ protected void configure() { mutEscStrainX = params.mutEsc; if (params.vacFreq.equals("none")) { - startDateToVaccination.put(LocalDate.of(2022, 9, 15), newVaccinations.get(LocalDate.of(2022, 9, 15))); + startDateToVaccination.put(LocalDate.of(2022, 9, 1), newVaccinations.get(LocalDate.of(2022, 9, 1))); } else if (params.vacFreq.equals("annual")) { - startDateToVaccination.putAll(newVaccinations.entrySet().stream().filter(entry -> entry.getKey().getMonthValue() == 9).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); + startDateToVaccination.putAll(newVaccinations.entrySet().stream().filter(entry -> entry.getValue().toString().startsWith("fall")).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); } else if (params.vacFreq.equals("biannual")) { - startDateToVaccination.putAll(newVaccinations); + startDateToVaccination.putAll(newVaccinations.entrySet().stream().filter(entry -> (entry.getValue().toString().startsWith("fall")||entry.getValue().toString().startsWith("spring"))).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); + } else if (params.vacFreq.equals("withStrain")) { + startDateToVaccination.putAll(newVaccinations.entrySet().stream().filter(entry -> entry.getValue().toString().startsWith("vax")).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); } else { throw new RuntimeException(); } @@ -591,7 +617,7 @@ public static final class Params { // vaccination campaign //vaccination frequency - @StringParameter({"none", "annual", "biannual"}) + @StringParameter({"none", "annual", "biannual","withStrain"}) String vacFreq; @StringParameter({"18plus"}) From 73bd98c616b296c37a1754b1eddd885112ec26e1 Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Mon, 12 Sep 2022 12:56:36 -0400 Subject: [PATCH 05/13] project weather 11 years into the future --- src/main/java/org/matsim/episim/EpisimUtils.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/matsim/episim/EpisimUtils.java b/src/main/java/org/matsim/episim/EpisimUtils.java index 5972fa323..a2ff2d3dc 100644 --- a/src/main/java/org/matsim/episim/EpisimUtils.java +++ b/src/main/java/org/matsim/episim/EpisimUtils.java @@ -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; } @@ -589,7 +589,8 @@ public static Map getOutDoorFractionFromDateAndTemp2(File wea prcpPerDay.put(monthDay, prcp); } - for (int i = 1; i < 365*3; i++) { + // project weather 11 years into the future + for (int i = 1; i < 365*11; i++) { LocalDate date = lastDate.plusDays(i); int month = date.getMonth().getValue(); int day = date.getDayOfMonth(); From 877eb4247bc0bf3cf9a19d16c68ced81b0c90d46 Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Thu, 15 Sep 2022 16:31:34 -0400 Subject: [PATCH 06/13] added age bin in infection post processing (needed for eu hub) --- .../java/org/matsim/episim/analysis/ExtractInfectionsByAge.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/matsim/episim/analysis/ExtractInfectionsByAge.java b/src/main/java/org/matsim/episim/analysis/ExtractInfectionsByAge.java index b81904462..cb486db64 100644 --- a/src/main/java/org/matsim/episim/analysis/ExtractInfectionsByAge.java +++ b/src/main/java/org/matsim/episim/analysis/ExtractInfectionsByAge.java @@ -53,7 +53,7 @@ public class ExtractInfectionsByAge implements Callable { private boolean detailed = false; @CommandLine.Option(names = "--age-groups", description = "Age groups as list of bin edges") - private List ageGroups = List.of(0, 5, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90); + private List ageGroups = List.of(0, 5, 10, 15, 18, 20, 25, 30, 40, 50, 60, 70, 80, 90); @CommandLine.Option(names = "--attr", defaultValue = "microm:modeled:age", description = "Name of the age attribute") private String ageAttr; From a6c3668c0de0f0af6b74ea1c1730afb8d443816f Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Thu, 15 Sep 2022 16:31:53 -0400 Subject: [PATCH 07/13] fixed bug in vaccination strategy --- ...ccinationStrategyReoccurringCampaigns.java | 200 ++++++++++++------ 1 file changed, 130 insertions(+), 70 deletions(-) diff --git a/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java b/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java index 15a271bde..7b6515ca3 100644 --- a/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java +++ b/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java @@ -1,10 +1,15 @@ package org.matsim.episim.model.vaccination; import com.google.inject.Inject; -import it.unimi.dsi.fastutil.ints.Int2DoubleMap; +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.matsim.api.core.v01.Id; +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.EpisimReporting; import org.matsim.episim.EpisimUtils; import org.matsim.episim.model.VaccinationType; @@ -17,100 +22,139 @@ */ public class VaccinationStrategyReoccurringCampaigns implements VaccinationModel { + private final int dailyVaccinationsToBeDistributed; + private final SplittableRandom rnd; private final Config config; + // LocalDate of beginning of vaccination campaign -> age-group -> number of vaccinations left + private final Map> vaccinationsLeftPerAgePerCampaign; + + @Inject - public VaccinationStrategyReoccurringCampaigns(SplittableRandom rnd, Config config) { + public VaccinationStrategyReoccurringCampaigns(SplittableRandom rnd, Config config, Scenario scenario) { this.rnd = rnd; this.config = config; + + Population population = scenario.getPopulation(); + + + // number of agents in each age group + int agentCnt_0_11 = (int) population.getPersons().values().stream().filter(p -> ((int) p.getAttributes().getAttribute("microm:modeled:age") >= 0 && (int) p.getAttributes().getAttribute("microm:modeled:age") < 12)).count(); + int agentCnt_12_17 = (int) population.getPersons().values().stream().filter(p -> ((int) p.getAttributes().getAttribute("microm:modeled:age") >= 12 && (int) p.getAttributes().getAttribute("microm:modeled:age") < 18)).count(); + int agentCnt_18_59 = (int) population.getPersons().values().stream().filter(p -> ((int) p.getAttributes().getAttribute("microm:modeled:age") >= 18 && (int) p.getAttributes().getAttribute("microm:modeled:age") < 60)).count(); + int agentCnt_60_plus = (int) population.getPersons().values().stream().filter(p -> (int) p.getAttributes().getAttribute("microm:modeled:age") >= 60).count(); + + //multiply compliance by these numbers -> total number of vaccines to be applied to age group + int vaxCnt_0_11 = (int) (agentCnt_0_11 * config.complianceByAge.getDouble(EpisimReporting.AgeGroup.age_0_11)); + int vaxCnt_12_17 = (int) (agentCnt_12_17 * config.complianceByAge.getDouble(EpisimReporting.AgeGroup.age_12_17)); + int vaxCnt_18_59 = (int) (agentCnt_18_59 * config.complianceByAge.getDouble(EpisimReporting.AgeGroup.age_18_59)); + int vaxCnt_60_plus = (int) (agentCnt_60_plus * config.complianceByAge.getDouble(EpisimReporting.AgeGroup.age_60_plus)); + + // put these vaccination counts in map form + Object2IntMap vaccinationsLeftPerAge = new Object2IntOpenHashMap(Map.of( + EpisimReporting.AgeGroup.age_0_11, vaxCnt_0_11, + EpisimReporting.AgeGroup.age_12_17, vaxCnt_12_17, + EpisimReporting.AgeGroup.age_18_59, vaxCnt_18_59, + EpisimReporting.AgeGroup.age_60_plus, vaxCnt_60_plus + )); + + // create a age-group vaccinations remaining counter for each vaccination campaign (will count down to 0) + // each map is a copy of map created above + this.vaccinationsLeftPerAgePerCampaign = new HashMap<>(); + for (LocalDate startDate : config.startDateToVaccinationCampaign.keySet()) { + this.vaccinationsLeftPerAgePerCampaign.put(startDate, new HashMap<>(vaccinationsLeftPerAge)); + } + + // calculate total number of vaccinations: + int totalVaccinationsDistributedPerCampaign = vaccinationsLeftPerAge.values().intStream().sum(); + dailyVaccinationsToBeDistributed = totalVaccinationsDistributedPerCampaign / config.campaignDuration; + } @Override public void handleVaccination(Map, EpisimPerson> persons, LocalDate date, int iteration, double now) { - // We check whether the current date occurs during one of the vaccination campaigns. If so, vaccinations are applied - boolean occursInCampaign = false; - VaccinationType vaccinationType = null; - for (LocalDate startDate : config.startDateToVOC.keySet()) { - if (date.isAfter(startDate) && date.isBefore(startDate.plusDays(config.campaignDuration))) { - - if (occursInCampaign) { - throw new RuntimeException("this vaccination strategy doesn't allow for two vaccination campaigns to occur simultaneously"); - } - - occursInCampaign = true; - vaccinationType = config.startDateToVOC.get(startDate); - } - } - if (!occursInCampaign) { + // 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; } - //handle young persons - if (config.complianceByAge.values().doubleStream() - .reduce(0, Double::sum) > 0) { - List filteredPersons = new ArrayList<>(persons.values()); + // 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))) { - List candidates = filteredPersons.stream() + // 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 + List candidates = persons.values().stream() .filter(EpisimPerson::isVaccinable) // todo: what determines who is vaccinable? .filter(p -> p.getDiseaseStatus() == EpisimPerson.DiseaseStatus.susceptible) - .filter(p -> p.getNumVaccinations() > 1) // only boostered people are reboostered + .filter(p -> p.getNumVaccinations() > config.vaccinationPool.vaxCnt) // only boostered people are reboostered .filter(p -> p.daysSinceVaccination(p.getNumVaccinations() - 1, iteration) > 90) // only people who've had their last vaccination more than 90 days ago .collect(Collectors.toList()); - // Collections.shuffle(candidates, new Random(EpisimUtils.getSeed(rnd))); - - - int num0 = (int) filteredPersons.stream().filter(p -> (p.getAge() >= 0 && p.getAge() < 12)).count(); - int num12 = (int) filteredPersons.stream().filter(p -> (p.getAge() >= 12 && p.getAge() < 18)).count(); - int num18 = (int) filteredPersons.stream().filter(p -> (p.getAge() >= 18 && p.getAge() < 60)).count(); - int num60 = (int) filteredPersons.stream().filter(p -> p.getAge() >= 60).count(); - - double numVaccines = num0 * config.complianceByAge.get(0) - + num12 * config.complianceByAge.get(12) - + num18 * config.complianceByAge.get(18) - + num60 * config.complianceByAge.get(60); - - int vaccinationsLeft = (int) (numVaccines / config.campaignDuration); - - List people0 = candidates.stream().filter(p -> (p.getAge() >= 0 && p.getAge() < 12)).collect(Collectors.toList()); - List people12 = candidates.stream().filter(p -> (p.getAge() >= 12 && p.getAge() < 18)).collect(Collectors.toList()); - List people18 = candidates.stream().filter(p -> (p.getAge() >= 18 && p.getAge() < 60)).collect(Collectors.toList()); - List people60 = candidates.stream().filter(p -> p.getAge() >= 60).collect(Collectors.toList()); + // create vaccinations-remaining counter for current day + int vaccinationsLeft = this.dailyVaccinationsToBeDistributed; - final List[] perAge = new List[4]; - perAge[0] = people0; - perAge[1] = people12; - perAge[2] = people18; - perAge[3] = people60; - - int ageIndex = 3; - while (ageIndex >= 0 && vaccinationsLeft > 0) { - - List candidatesForAge = perAge[ageIndex]; - - // list is shuffled to avoid eventual bias - if (candidatesForAge.size() > vaccinationsLeft) - Collections.shuffle(perAge[ageIndex], new Random(EpisimUtils.getSeed(rnd))); - - - int vaccinesForDayAndAgeGroup = Math.min(candidatesForAge.size(), vaccinationsLeft); - for (int i = 0; i < vaccinesForDayAndAgeGroup; i++) { - EpisimPerson person = candidatesForAge.get(i); - vaccinate(person, iteration, vaccinationType); - vaccinationsLeft--; + // group candidates into age groups + Map> candidatesPerAgeGroup = new HashMap<>(); + for (EpisimReporting.AgeGroup ageGroup : EpisimReporting.AgeGroup.values()) { + candidatesPerAgeGroup.put(ageGroup, new ArrayList<>()); + } + for (EpisimPerson person : candidates) { + for (EpisimReporting.AgeGroup ageGroup : EpisimReporting.AgeGroup.values()) { + if (person.getAge() >= ageGroup.lowerBoundAge) { + candidatesPerAgeGroup.get(ageGroup).add(person); + break; + } + } } - ageIndex--; + // Apply vaccinations, oldest age-group first. Stop vaccinations for day if: + // a) no vaccines left for the day + // b) no age-group has any more candidates + // c) no age-group has any more vaccines left (for entire campaign) + + Iterator ageGroupIterator = Arrays.stream(EpisimReporting.AgeGroup.values()).iterator(); +// int ageIndex = AgeGroup.values().length - 1; + while (ageGroupIterator.hasNext() && vaccinationsLeft > 0) { + EpisimReporting.AgeGroup ageGroup = ageGroupIterator.next(); + + int vaccinationsLeftForAgeGroup = vaccinationsLeftPerAgePerCampaign.get(vaccinationCampaignStartDate).get(ageGroup); + + // list is shuffled to avoid eventual bias + List candidatesForAge = candidatesPerAgeGroup.get(ageGroup); + Collections.shuffle(candidatesForAge, new Random(EpisimUtils.getSeed(rnd))); + +// +// int vaccinesForDayAndAgeGroup = Math.min(candidatesForAge.size(), vaccinationsLeft); + Iterator candidateIterator = candidatesForAge.stream().iterator(); + EpisimPerson person; + while(candidateIterator.hasNext() && vaccinationsLeft > 0 && vaccinationsLeftForAgeGroup > 0){ + person = candidateIterator.next(); + + vaccinate(person, iteration, vaccinationType); + vaccinationsLeft--; + vaccinationsLeftForAgeGroup--; + } + vaccinationsLeftPerAgePerCampaign.get(vaccinationCampaignStartDate).put(ageGroup, vaccinationsLeftForAgeGroup); + } + if (vaccinationsLeft > 0) { + System.out.println(vaccinationsLeft + " vaccinations were left over at end of day "); + } } } - - } @@ -119,20 +163,36 @@ public static class Config { /** * Start Dates of vaccination campaigns. */ - private final Map startDateToVOC; + private final Map startDateToVaccinationCampaign; /** * Duration of vaccination campaign. */ private final int campaignDuration; - private final Int2DoubleMap complianceByAge; + private final Object2DoubleMap complianceByAge; + + private final VaccinationPool vaccinationPool; + + public enum VaccinationPool { + + vaccinated(1), + + boostered(2); + private final int vaxCnt; + + VaccinationPool(int vaxCnt) { + this.vaxCnt = vaxCnt; + } + + } - public Config(Map startDateToVOC, int campaignDuration, Int2DoubleMap complianceByAge) { - this.startDateToVOC = startDateToVOC; + public Config(Map startDateToVaccinationCampaign, int campaignDuration, Object2DoubleMap complianceByAge, VaccinationPool vaccinationPool) { + this.startDateToVaccinationCampaign = startDateToVaccinationCampaign; this.campaignDuration = campaignDuration; this.complianceByAge = complianceByAge; + this.vaccinationPool = vaccinationPool; } } From e52e671c831d188c64dca75c8b512f4a39ce490a Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Thu, 15 Sep 2022 16:33:27 -0400 Subject: [PATCH 08/13] updated reporting to output vaccinations applied per age group --- .../java/org/matsim/episim/EpisimPerson.java | 2 +- .../org/matsim/episim/EpisimReporting.java | 65 +++++++++++++++++-- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/matsim/episim/EpisimPerson.java b/src/main/java/org/matsim/episim/EpisimPerson.java index 92e5453a6..e665d659f 100644 --- a/src/main/java/org/matsim/episim/EpisimPerson.java +++ b/src/main/java/org/matsim/episim/EpisimPerson.java @@ -549,7 +549,7 @@ public void setVaccinationStatus(VaccinationStatus vaccinationStatus, Vaccinatio vaccinations.add(type); vaccinationDates.add(iteration); - reporting.reportVaccination(personId, iteration, type, vaccinations.size()); + reporting.reportVaccination(personId, iteration, type, vaccinations.size(), age); } public TestStatus getTestStatus() { diff --git a/src/main/java/org/matsim/episim/EpisimReporting.java b/src/main/java/org/matsim/episim/EpisimReporting.java index fc5f427c2..d692db5ac 100644 --- a/src/main/java/org/matsim/episim/EpisimReporting.java +++ b/src/main/java/org/matsim/episim/EpisimReporting.java @@ -23,10 +23,9 @@ import com.google.common.collect.Lists; import com.google.inject.Inject; import com.typesafe.config.ConfigRenderOptions; -import it.unimi.dsi.fastutil.objects.Object2DoubleMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectIntPair; +import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.objects.*; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.logging.log4j.LogManager; @@ -64,6 +63,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); @@ -103,6 +119,10 @@ public final class EpisimReporting implements BasicEventHandler, Closeable, Exte * Map of (VaccinationType, nth Vaccination) -> Number per day */ public final Object2IntMap> vaccinationStats = new Object2IntOpenHashMap<>(); + /** + * Map of Age group -> Number of Vaccinations administered per day + */ + public final Object2IntMap vaccinationPerAgeGroupStats = new Object2IntOpenHashMap<>(); /** * Number format for logging output. Not static because not thread-safe. @@ -146,6 +166,8 @@ public final class EpisimReporting implements BasicEventHandler, Closeable, Exte private BufferedWriter vaccinationsPerType; private BufferedWriter vaccinationsPerTypeAndNumber; + private BufferedWriter vaccinationsPerAgeGroup; + private final Map externalWriters = new HashMap<>(); private String memorizedDate = null; @@ -209,6 +231,7 @@ public final class EpisimReporting implements BasicEventHandler, Closeable, Exte 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"); + vaccinationsPerAgeGroup = EpisimWriter.prepare(base + "vaccinationsPerAgeGroup.tsv", "day", "date", "age_group","amount"); sampleSize = episimConfig.getSampleSize(); writeEvents = episimConfig.getWriteEvents(); @@ -281,6 +304,7 @@ void append(String date) throws IOException { antibodiesPerPerson = EpisimWriter.prepare(base + "antibodies.tsv"); vaccinationsPerType = EpisimWriter.prepare(base + "vaccinations.tsv"); vaccinationsPerTypeAndNumber = EpisimWriter.prepare(base + "vaccinationsDetailed.tsv"); + vaccinationsPerAgeGroup = EpisimWriter.prepare(base + "vaccinationsPerAgeGroup.tsv"); // cpu time is overwritten cpuTime = EpisimWriter.prepare(base + "cputime.tsv", "iteration", "where", "what", "when", "thread"); memorizedDate = date; @@ -585,9 +609,22 @@ void reporting(Map reports, int iteration, String date) writer.append(vaccinationsPerTypeAndNumber, vacOut); } - vaccinationStats.clear(); + // vaccinations per age group + String[] vacPerAgeGroupOut = new String[4]; + vacPerAgeGroupOut[0] = String.valueOf(iteration); + vacPerAgeGroupOut[1] = date; + for (AgeGroup ageGroup : AgeGroup.values()) { + vacPerAgeGroupOut[2] = ageGroup.name(); + vacPerAgeGroupOut[3] = Integer.toString(vaccinationPerAgeGroupStats.getInt(ageGroup)); + + writer.append(vaccinationsPerAgeGroup, vacPerAgeGroupOut); + + } + + vaccinationPerAgeGroupStats.clear(); + // Write all reports for each district for (InfectionReport r : reports.values()) { if (r.name.equals("total")) continue; @@ -771,11 +808,26 @@ void reportPersonStatus(EpisimPerson person, EpisimPersonStatusEvent event) { /** * Report the vaccination of a person. */ - void reportVaccination(Id personId, int iteration, VaccinationType type, int n) { + void reportVaccination(Id personId, int iteration, VaccinationType type, int n, int age) { vaccinations.merge(type, 1, Integer::sum); vaccinationStats.merge(ObjectIntPair.of(type, n), 1, Integer::sum); + int previousMinAge = 1000; + + for (AgeGroup ageGroup : AgeGroup.values()) { + + int minAge = ageGroup.lowerBoundAge; + if (minAge >= previousMinAge) { + throw new RuntimeException("AGE_GROUP Map not sorted in descending order"); + } else if (age >= minAge) { + vaccinationPerAgeGroupStats.merge(ageGroup, 1, Integer::sum); + break; + } + + previousMinAge = minAge; + } + manager.processEvent(new EpisimVaccinationEvent(EpisimUtils.getCorrectedTime(episimConfig.getStartOffset(), 0, iteration), personId, type, n)); } @@ -879,6 +931,7 @@ public void close() { writer.close(cpuTime); writer.close(vaccinationsPerType); writer.close(vaccinationsPerTypeAndNumber); + writer.close(vaccinationsPerAgeGroup); for (BufferedWriter v : externalWriters.values()) { writer.close(v); From 8737cb4fc9426a40162820a34bb4aad4e25e46c8 Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Thu, 15 Sep 2022 16:34:17 -0400 Subject: [PATCH 09/13] runs for round3 of eu scenario hub (changed snz remaining fraction files as well) --- .../episim/model/DefaultAntibodyModel.java | 16 +- .../run/batch/CologneScenarioHubRound3.java | 189 ++++++++++-------- .../modules/SnzCologneProductionScenario.java | 2 +- 3 files changed, 112 insertions(+), 95 deletions(-) diff --git a/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java b/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java index 0f2ef4bfd..d0cd84dd7 100644 --- a/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java +++ b/src/main/java/org/matsim/episim/model/DefaultAntibodyModel.java @@ -71,14 +71,14 @@ public void init(Collection persons, int iteration) { } } - Figure fig = Histogram.create("Distribution of Immune Response Multipliers", values.toDoubleArray()); - - try (Writer writer = new OutputStreamWriter(new FileOutputStream("immuneResponseMultiplierDistribution.html"), StandardCharsets.UTF_8)) { - writer.write(Page.pageBuilder(fig, "target").build().asJavascript()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - +// Figure fig = Histogram.create("Distribution of Immune Response Multipliers", values.toDoubleArray()); +// +// try (Writer writer = new OutputStreamWriter(new FileOutputStream("immuneResponseMultiplierDistribution.html"), StandardCharsets.UTF_8)) { +// writer.write(Page.pageBuilder(fig, "target").build().asJavascript()); +// } catch (IOException e) { +// throw new UncheckedIOException(e); +// } +// } /** diff --git a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java index 89cd3f9d8..bf63e6496 100644 --- a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java +++ b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java @@ -5,8 +5,8 @@ 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 it.unimi.dsi.fastutil.objects.Object2DoubleAVLTreeMap; +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.episim.*; @@ -29,75 +29,73 @@ public class CologneScenarioHubRound3 implements BatchRun { boolean DEBUG_MODE = false; - int runCount = 0; - - + int runCount = 0; public static Map newVirusStrains = renderNewVirusStrains(); public static Map newVaccinations = renderNewVaccinations(); private static Map renderNewVaccinations() { - Map xxx = new HashMap<>(); - xxx.put(LocalDate.of(2022,9,1),VaccinationType.fall22); - xxx.put(LocalDate.of(2023,3,1),VaccinationType.spring23); - xxx.put(LocalDate.of(2023,9,1),VaccinationType.fall23); - xxx.put(LocalDate.of(2024,3,1),VaccinationType.spring24); - xxx.put(LocalDate.of(2024,9,1),VaccinationType.fall24); - xxx.put(LocalDate.of(2025,3,1),VaccinationType.spring25); - xxx.put(LocalDate.of(2025,9,1),VaccinationType.fall25); - xxx.put(LocalDate.of(2026,3,1),VaccinationType.spring26); - xxx.put(LocalDate.of(2026,9,1),VaccinationType.fall26); - xxx.put(LocalDate.of(2027,3,1),VaccinationType.spring27); - xxx.put(LocalDate.of(2027,9,1),VaccinationType.fall27); - xxx.put(LocalDate.of(2028,3,1),VaccinationType.spring28); - xxx.put(LocalDate.of(2028,9,1),VaccinationType.fall28); - xxx.put(LocalDate.of(2029,3,1),VaccinationType.spring29); - xxx.put(LocalDate.of(2029,9,1),VaccinationType.fall29); - xxx.put(LocalDate.of(2030,3,1),VaccinationType.spring30); - xxx.put(LocalDate.of(2030,9,1),VaccinationType.fall30); - xxx.put(LocalDate.of(2031,3,1),VaccinationType.spring31); - xxx.put(LocalDate.of(2031,9,1),VaccinationType.fall31); - xxx.put(LocalDate.of(2032,3,1), VaccinationType.spring32); - - xxx.put(LocalDate.of(2022,10,15), VaccinationType.vax_STRAIN_A); - xxx.put(LocalDate.of(2023,7,15), VaccinationType.vax_STRAIN_B); - xxx.put(LocalDate.of(2024,4,15), VaccinationType.vax_STRAIN_C); - xxx.put(LocalDate.of(2025,1,15), VaccinationType.vax_STRAIN_D); - xxx.put(LocalDate.of(2025,10,15), VaccinationType.vax_STRAIN_E); - xxx.put(LocalDate.of(2026,7,15), VaccinationType.vax_STRAIN_F); - xxx.put(LocalDate.of(2027,4,15), VaccinationType.vax_STRAIN_G); - xxx.put(LocalDate.of(2028,1,15), VaccinationType.vax_STRAIN_H); - xxx.put(LocalDate.of(2028,10,15), VaccinationType.vax_STRAIN_I); - xxx.put(LocalDate.of(2029,7,15), VaccinationType.vax_STRAIN_J); - xxx.put(LocalDate.of(2030,4,15), VaccinationType.vax_STRAIN_K); - xxx.put(LocalDate.of(2031,1,15), VaccinationType.vax_STRAIN_L); - xxx.put(LocalDate.of(2031,10,15), VaccinationType.vax_STRAIN_M); - xxx.put(LocalDate.of(2032,7,15), VaccinationType.vax_STRAIN_N); - - - return xxx; + Map newVaccinations = new TreeMap<>(); + newVaccinations.put(LocalDate.of(2022,9,1),VaccinationType.fall22); + newVaccinations.put(LocalDate.of(2023,3,1),VaccinationType.spring23); + newVaccinations.put(LocalDate.of(2023,9,1),VaccinationType.fall23); + newVaccinations.put(LocalDate.of(2024,3,1),VaccinationType.spring24); + newVaccinations.put(LocalDate.of(2024,9,1),VaccinationType.fall24); + newVaccinations.put(LocalDate.of(2025,3,1),VaccinationType.spring25); + newVaccinations.put(LocalDate.of(2025,9,1),VaccinationType.fall25); + newVaccinations.put(LocalDate.of(2026,3,1),VaccinationType.spring26); + newVaccinations.put(LocalDate.of(2026,9,1),VaccinationType.fall26); + newVaccinations.put(LocalDate.of(2027,3,1),VaccinationType.spring27); + newVaccinations.put(LocalDate.of(2027,9,1),VaccinationType.fall27); + newVaccinations.put(LocalDate.of(2028,3,1),VaccinationType.spring28); + newVaccinations.put(LocalDate.of(2028,9,1),VaccinationType.fall28); + newVaccinations.put(LocalDate.of(2029,3,1),VaccinationType.spring29); + newVaccinations.put(LocalDate.of(2029,9,1),VaccinationType.fall29); + newVaccinations.put(LocalDate.of(2030,3,1),VaccinationType.spring30); + newVaccinations.put(LocalDate.of(2030,9,1),VaccinationType.fall30); + newVaccinations.put(LocalDate.of(2031,3,1),VaccinationType.spring31); + newVaccinations.put(LocalDate.of(2031,9,1),VaccinationType.fall31); + newVaccinations.put(LocalDate.of(2032,3,1), VaccinationType.spring32); + + newVaccinations.put(LocalDate.of(2022,10,15), VaccinationType.vax_STRAIN_A); + newVaccinations.put(LocalDate.of(2023,7,15), VaccinationType.vax_STRAIN_B); + newVaccinations.put(LocalDate.of(2024,4,15), VaccinationType.vax_STRAIN_C); + newVaccinations.put(LocalDate.of(2025,1,15), VaccinationType.vax_STRAIN_D); + newVaccinations.put(LocalDate.of(2025,10,15), VaccinationType.vax_STRAIN_E); + newVaccinations.put(LocalDate.of(2026,7,15), VaccinationType.vax_STRAIN_F); + newVaccinations.put(LocalDate.of(2027,4,15), VaccinationType.vax_STRAIN_G); + newVaccinations.put(LocalDate.of(2028,1,15), VaccinationType.vax_STRAIN_H); + newVaccinations.put(LocalDate.of(2028,10,15), VaccinationType.vax_STRAIN_I); + newVaccinations.put(LocalDate.of(2029,7,15), VaccinationType.vax_STRAIN_J); + newVaccinations.put(LocalDate.of(2030,4,15), VaccinationType.vax_STRAIN_K); + newVaccinations.put(LocalDate.of(2031,1,15), VaccinationType.vax_STRAIN_L); + newVaccinations.put(LocalDate.of(2031,10,15), VaccinationType.vax_STRAIN_M); + newVaccinations.put(LocalDate.of(2032,7,15), VaccinationType.vax_STRAIN_N); + + + return newVaccinations; } private static Map renderNewVirusStrains() { - Map xxx = new HashMap<>(); - xxx.put(LocalDate.of(2022,10,15),VirusStrain.STRAIN_A); - xxx.put(LocalDate.of(2023,7,15),VirusStrain.STRAIN_B); - xxx.put(LocalDate.of(2024,4,15),VirusStrain.STRAIN_C); - xxx.put(LocalDate.of(2025,1,15),VirusStrain.STRAIN_D); - xxx.put(LocalDate.of(2025,10,15),VirusStrain.STRAIN_E); - xxx.put(LocalDate.of(2026,7,15),VirusStrain.STRAIN_F); - xxx.put(LocalDate.of(2027,4,15),VirusStrain.STRAIN_G); - xxx.put(LocalDate.of(2028,1,15),VirusStrain.STRAIN_H); - xxx.put(LocalDate.of(2028,10,15),VirusStrain.STRAIN_I); - xxx.put(LocalDate.of(2029,7,15),VirusStrain.STRAIN_J); - xxx.put(LocalDate.of(2030,4,15),VirusStrain.STRAIN_K); - xxx.put(LocalDate.of(2031,1,15),VirusStrain.STRAIN_L); - xxx.put(LocalDate.of(2031,10,15),VirusStrain.STRAIN_M); - xxx.put(LocalDate.of(2032,7,15),VirusStrain.STRAIN_N); - - return xxx; + Map newVirusStrains = new TreeMap<>(); + newVirusStrains.put(LocalDate.of(2022,10,15),VirusStrain.STRAIN_A); + newVirusStrains.put(LocalDate.of(2023,7,15),VirusStrain.STRAIN_B); + newVirusStrains.put(LocalDate.of(2024,4,15),VirusStrain.STRAIN_C); + newVirusStrains.put(LocalDate.of(2025,1,15),VirusStrain.STRAIN_D); + newVirusStrains.put(LocalDate.of(2025,10,15),VirusStrain.STRAIN_E); + newVirusStrains.put(LocalDate.of(2026,7,15),VirusStrain.STRAIN_F); + newVirusStrains.put(LocalDate.of(2027,4,15),VirusStrain.STRAIN_G); + newVirusStrains.put(LocalDate.of(2028,1,15),VirusStrain.STRAIN_H); + newVirusStrains.put(LocalDate.of(2028,10,15),VirusStrain.STRAIN_I); + newVirusStrains.put(LocalDate.of(2029,7,15),VirusStrain.STRAIN_J); + newVirusStrains.put(LocalDate.of(2030,4,15),VirusStrain.STRAIN_K); + newVirusStrains.put(LocalDate.of(2031,1,15),VirusStrain.STRAIN_L); + newVirusStrains.put(LocalDate.of(2031,10,15),VirusStrain.STRAIN_M); + newVirusStrains.put(LocalDate.of(2032,7,15),VirusStrain.STRAIN_N); + + return newVirusStrains; } @Nullable @@ -117,16 +115,30 @@ protected void configure() { Map startDateToVaccination = new HashMap<>(); - Int2DoubleMap compliance = new Int2DoubleAVLTreeMap(); - compliance.put(60, 0.0); - compliance.put(18, 0.0); - compliance.put(12, 0.0); - compliance.put(0, 0.0); + Object2DoubleMap compliance = new Object2DoubleAVLTreeMap(); + compliance.put(EpisimReporting.AgeGroup.age_60_plus, 0.0); + compliance.put(EpisimReporting.AgeGroup.age_18_59, 0.0); + compliance.put(EpisimReporting.AgeGroup.age_12_17, 0.0); + compliance.put(EpisimReporting.AgeGroup.age_0_11, 0.0); + + VaccinationStrategyReoccurringCampaigns.Config.VaccinationPool vaccinationPool = VaccinationStrategyReoccurringCampaigns.Config.VaccinationPool.vaccinated; + + int campaignDuration = 91; if (params != null) { + campaignDuration = (int) params.campDuration; + mutEscStrainX = params.mutEsc; + vaccinationPool = VaccinationStrategyReoccurringCampaigns.Config.VaccinationPool.valueOf(params.vacPool); + + + if (DEBUG_MODE) { + startDateToVaccination.put(LocalDate.of(2020, 2, 27), VaccinationType.fall23); + } + + if (params.vacFreq.equals("none")) { startDateToVaccination.put(LocalDate.of(2022, 9, 1), newVaccinations.get(LocalDate.of(2022, 9, 1))); } else if (params.vacFreq.equals("annual")) { @@ -140,35 +152,34 @@ protected void configure() { } if (params.vacCamp.equals("60plus")) { - compliance.put(60, 0.94/2); // 0.94 is boost rate July 16, 2022 - compliance.put(18, 0.); - compliance.put(12, 0.); - compliance.put(0, 0.); + compliance.put(EpisimReporting.AgeGroup.age_60_plus, 0.94/2); // 0.94 is boost rate July 16, 2022 + compliance.put(EpisimReporting.AgeGroup.age_18_59, 0.); + compliance.put(EpisimReporting.AgeGroup.age_12_17, 0.); + compliance.put(EpisimReporting.AgeGroup.age_0_11, 0.); } // assumption: older age group 2boosted first, then younger, each age group // will have rate of 50% 2boosted by end of campaign. // motivation: if we give both age groups same rate, then the older people // will not be boosted as much as younger people, which seems implausible... else if (params.vacCamp.equals("18plus")) { - compliance.put(60, 0.94/2); // 0.94 is boost rate July 16, 2022 - compliance.put(18, 0.77/2); // 0.77 is boost rate July 16, 2022 - compliance.put(12, 0.); - compliance.put(0, 0.); - } - else if (params.vacCamp.equals("off")) { + compliance.put(EpisimReporting.AgeGroup.age_60_plus, 0.94/2); // 0.94 is boost rate July 16, 2022 + compliance.put(EpisimReporting.AgeGroup.age_18_59, 0.77/2); // 0.77 is boost rate July 16, 2022 + compliance.put(EpisimReporting.AgeGroup.age_12_17, 0.); + compliance.put(EpisimReporting.AgeGroup.age_0_11, 0.); + } else if (params.vacCamp.equals("18plus50pct")) { + compliance.put(EpisimReporting.AgeGroup.age_60_plus, 0.5); + compliance.put(EpisimReporting.AgeGroup.age_18_59, 0.5); + compliance.put(EpisimReporting.AgeGroup.age_12_17, 0.); + compliance.put(EpisimReporting.AgeGroup.age_0_11, 0.); + } else if (params.vacCamp.equals("off")) { } else { throw new RuntimeException("Not a valid option for vaccinationCampaignType"); } } - int campaignDuration = 91; -// if (DEBUG_MODE) { -// campaignDuration = 5; -// } - - bind(VaccinationStrategyReoccurringCampaigns.Config.class).toInstance(new VaccinationStrategyReoccurringCampaigns.Config(startDateToVaccination, campaignDuration, compliance)); + bind(VaccinationStrategyReoccurringCampaigns.Config.class).toInstance(new VaccinationStrategyReoccurringCampaigns.Config(startDateToVaccination, campaignDuration, compliance, vaccinationPool)); //initial antibodies Map> initialAntibodies = new HashMap<>(); @@ -438,9 +449,9 @@ public Collection postProcessing() { @Override public Config prepareConfig(int id, Params params) { - if (DEBUG_MODE && params.mutEsc == 3.) { + if (DEBUG_MODE) { - if (runCount == 0) { //&& params.strAEsc != 0.0 && params.ba5Inf == 0. && params.eduTest.equals("true")) { + if (runCount == 0 && params.vacCamp.equals("18plus")) { //&& params.strAEsc != 0.0 && params.ba5Inf == 0. && params.eduTest.equals("true")) { runCount++; } else { return null; @@ -457,7 +468,7 @@ public Config prepareConfig(int id, Params params) { EpisimConfigGroup episimConfig = ConfigUtils.addOrGetModule(config, EpisimConfigGroup.class); // create snapshot -// episimConfig.setSnapshotInterval(927); + episimConfig.setSnapshotInterval(927); // episimConfig.setStartFromSnapshot("/scratch/projects/bzz0020/episim-input/snapshots-cologne-20220218/" + params.seed + "-600-2021-10-16.zip"); // episimConfig.setSnapshotSeed(EpisimConfigGroup.SnapshotSeed.restore); @@ -620,10 +631,16 @@ public static final class Params { @StringParameter({"none", "annual", "biannual","withStrain"}) String vacFreq; - @StringParameter({"18plus"}) + @StringParameter({"18plus","18plus50pct"}) // @StringParameter({"off", "60plus", "18plus"}) String vacCamp; + @StringParameter({"vaccinated","boostered"}) + String vacPool; + + @Parameter({31., 91.}) + double campDuration; + //new mutations @Parameter({3.7, 44.7}) diff --git a/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java b/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java index 7bbd3423d..59725d0af 100644 --- a/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java +++ b/src/main/java/org/matsim/run/modules/SnzCologneProductionScenario.java @@ -356,7 +356,7 @@ public Config config() { //restrictions and masks CreateRestrictionsFromCSV activityParticipation = new CreateRestrictionsFromCSV(episimConfig); - activityParticipation.setInput(INPUT.resolve("CologneSnzData_daily_until20220723.csv")); + activityParticipation.setInput(INPUT.resolve("CologneSnzData_daily_until20220910.csv")); activityParticipation.setScale(this.scale); activityParticipation.setLeisureAsNightly(this.leisureNightly); From 24f06e6da43ee3ac48e09eaf75c412c193778439 Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Thu, 15 Sep 2022 16:38:15 -0400 Subject: [PATCH 10/13] cleaned up hospital model (removed a bunch of currently superfluous stuff). added pessimistic immunity model for hospitalisations --- .../analysis/HospitalNumbersFromEvents.java | 192 +++--------------- 1 file changed, 33 insertions(+), 159 deletions(-) diff --git a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java index c467df423..ca3446c8e 100644 --- a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java +++ b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java @@ -92,22 +92,20 @@ public class HospitalNumbersFromEvents implements OutputAnalysis { // 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 = renderLagBetweenInfectionAndHospitalisation(); private static Object2IntMap renderLagBetweenInfectionAndHospitalisation() { - Object2IntMap xxx = new Object2IntAVLTreeMap<>( + Object2IntMap days = new Object2IntAVLTreeMap<>( Map.of(VirusStrain.SARS_CoV_2, 14, VirusStrain.ALPHA, 14, VirusStrain.DELTA, 14, VirusStrain.OMICRON_BA1, 14, VirusStrain.OMICRON_BA2, 14, VirusStrain.OMICRON_BA5, 14 -// VirusStrain.STRAIN_A, 14, -// VirusStrain.STRAIN_B, 14 )); for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { - xxx.put(virusStrain, 14); + days.put(virusStrain, 14); } - return xxx; + return days; } @@ -115,88 +113,77 @@ private static Object2IntMap renderLagBetweenInfectionAndHospitalis private static final Object2IntMap lagBetweenHospitalizationAndICU = renderLagBetweenHospitalizationAndICU(); private static Object2IntAVLTreeMap renderLagBetweenHospitalizationAndICU() { - Object2IntAVLTreeMap xxx = new Object2IntAVLTreeMap<>( + Object2IntAVLTreeMap days = new Object2IntAVLTreeMap<>( Map.of(VirusStrain.SARS_CoV_2, 6, VirusStrain.ALPHA, 6, VirusStrain.DELTA, 6, VirusStrain.OMICRON_BA1, 6, VirusStrain.OMICRON_BA2, 6, VirusStrain.OMICRON_BA5, 6 -// VirusStrain.STRAIN_A, 6, -// VirusStrain.STRAIN_B, 6 )); for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { - xxx.put(virusStrain, 6); + days.put(virusStrain, 6); } - - - return xxx; + return days; } // Austria study in https://docs.google.com/spreadsheets/d/1jmaerl27LKidD1uk3azdIL1LmvHuxazNQlhVo9xO1z8/edit#gid=0 private static final Object2IntMap daysInHospitalGivenNoICU = renderDaysInHospitalGivenNoICU(); private static Object2IntAVLTreeMap renderDaysInHospitalGivenNoICU() { - Object2IntAVLTreeMap xxx = new Object2IntAVLTreeMap<>( + Object2IntAVLTreeMap days = new Object2IntAVLTreeMap<>( Map.of(VirusStrain.SARS_CoV_2, 12, VirusStrain.ALPHA, 12, VirusStrain.DELTA, 12, VirusStrain.OMICRON_BA1, 7, VirusStrain.OMICRON_BA2, 7, VirusStrain.OMICRON_BA5, 7 -// VirusStrain.STRAIN_A, 7, -// VirusStrain.STRAIN_B, 7 )); for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { - xxx.put(virusStrain, 7); + days.put(virusStrain, 7); } - - return xxx; + return days; } private static final Object2IntMap daysInICU = renderDaysInICU(); private static Object2IntAVLTreeMap renderDaysInICU() { - Object2IntAVLTreeMap xxx = new Object2IntAVLTreeMap<>( + Object2IntAVLTreeMap days = 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_BA2, 10, VirusStrain.OMICRON_BA5, 10 -// VirusStrain.STRAIN_A, 10, -// VirusStrain.STRAIN_B, 10 )); for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { - xxx.put(virusStrain, 10); + days.put(virusStrain, 10); } - return xxx; + return days; } // ?? private static final Object2IntMap daysInHospitalGivenICU = renderDaysInHospitalGivenICU(); private static Object2IntAVLTreeMap renderDaysInHospitalGivenICU() { - Object2IntAVLTreeMap xxx = new Object2IntAVLTreeMap<>( + Object2IntAVLTreeMap days = new Object2IntAVLTreeMap<>( Map.of(VirusStrain.SARS_CoV_2, 60, VirusStrain.ALPHA, 60, VirusStrain.DELTA, 60, VirusStrain.OMICRON_BA1, 60, VirusStrain.OMICRON_BA2, 60, VirusStrain.OMICRON_BA5, 60 -// VirusStrain.STRAIN_A, 60, -// VirusStrain.STRAIN_B, 60 )); for (VirusStrain virusStrain : CologneScenarioHubRound3.newVirusStrains.values()) { - xxx.put(virusStrain, 60); + days.put(virusStrain, 60); } - return xxx; + return days; } @@ -245,8 +232,6 @@ public Integer call() throws Exception { 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<>(); @@ -263,18 +248,6 @@ public Integer call() throws Exception { log.info("done"); - // Part 2: aggregate over multiple seeds & produce tsv output & plot -// HospitalNumbersFromEventsPlotter.aggregateAndProducePlots(output, pathList); - -// HospitalNumbersFromEventsPlotter.aggregateAndProducePlots(output, pathList, "_Omicron", startDate, "Omicron"); -// HospitalNumbersFromEventsPlotter.aggregateAndProducePlots(output, pathList, "_Delta", startDate, "Delta"); -// HospitalNumbersFromEventsPlotter.aggregateAndProducePlots(output, pathList, "_OmicronPaxlovid", startDate, "Omicron-Paxlovid"); -// HospitalNumbersFromEventsPlotter.aggregateAndProducePlots(output, pathList, "_DeltaPaxlovid", startDate, "Delta-Paxlovid"); - - -// } - - return 0; } @@ -307,47 +280,27 @@ public void analyzeOutput(Path pathToScenario) throws IOException { private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path tsvPath) throws IOException { // open new buffered writer for hospitalization output and write the header row. BufferedWriter bw = Files.newBufferedWriter(tsvPath); - bw.write(AnalysisCommand.TSV.join(DAY, DATE,"measurement", "severity", "n")); // + "\thospNoImmunity\thospBaseImmunity\thospBoosted\tincNoImmunity\tincBaseImmunity\tincBoosted")); + bw.write(AnalysisCommand.TSV.join(DAY, DATE,"measurement", "severity", "n")); ConfigHolder holderOmicron = configure(factorBA5, factorBA5ICU); ConfigHolder holderDelta = configure(factorDelta, factorDeltaICU); List handlers = List.of( - new Handler("Omicron", population, holderOmicron, 0.0), - new Handler("Delta", population, holderDelta, 0.0), - new Handler("Omicron-Paxlovid-0.25", population, holderOmicron, 0.25), - new Handler("Delta-Paxlovid-0.25", population, holderDelta, 0.25), - new Handler("Omicron-Paxlovid-0.50", population, holderOmicron, 0.5), - new Handler("Delta-Paxlovid-0.50", population, holderDelta, 0.5), - new Handler("Omicron-Paxlovid-0.75", population, holderOmicron, 0.75), - new Handler("Delta-Paxlovid-0.75", population, holderDelta, 0.75) + new Handler("Omicron", population, holderOmicron, 0.0, false), + new Handler("Delta", population, holderDelta, 0.0, false), + new Handler("Omicron-pessimistic", population, holderOmicron, 0.0, true), + new Handler("Delta-pessimistic", population, holderDelta, 0.0, true) +// new Handler("Omicron-Paxlovid-0.75", population, holderOmicron, 0.75), +// new Handler("Delta-Paxlovid-0.75", population, holderDelta, 0.75) ); // feed the output events file to the handler, so that the hospitalizations may be calculated List eventFiles = AnalysisCommand.forEachEvent(pathToScenario, s -> { }, true, 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"); -// } for (Handler handler : handlers) { - // calculates the number of agents in the scenario's population (25% sample) who live in Cologne // this is used to normalize the hospitalization values double popSize = (int) population.getPersons().values().stream() @@ -376,9 +329,11 @@ private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path t bw.write(AnalysisCommand.TSV.join(day, date, HospitalNumbersFromEventsPlotter.OCCUPANCY_ICU, handler.name, occupancyIcu)); } + } bw.close(); + } @@ -413,26 +368,11 @@ public static final class Handler implements EpisimVaccinationEventHandler, Epis final Int2IntSortedMap postProcessICUAdmissions; 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; + private final boolean pessimisticScenario; - Handler(String name, Population population, ConfigHolder holder, double paxlovidCompliance) { + Handler(String name, Population population, ConfigHolder holder, double paxlovidCompliance, boolean pessimisticScenario) { // instantiate the custom event handler that calculates hospitalizations based on events this.name = name; @@ -443,29 +383,15 @@ public static final class Handler implements EpisimVaccinationEventHandler, Epis this.paxlovidCompliance = paxlovidCompliance; this.paxlovidDay = (int) LocalDate.of(2020, 2, 25).datesUntil(LocalDate.of(2022, 11, 1)).count(); + this.pessimisticScenario = pessimisticScenario; this.postProcessHospitalAdmissions = new Int2IntAVLTreeMap(); +// this.postProcessHospitalAdmissionsPerAgeGroup = new Int2ObjectAVLTreeMap<>(); + 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 { -// this.printer = new CSVPrinter(Files.newBufferedWriter(Path.of("hospCalibration.tsv")), CSVFormat.DEFAULT.withDelimiter('\t')); -// printer.printRecord("day", "date", "personId", "age", "strain", "numInfections","numVaccinations"); -// } catch (IOException ex) { -// ex.printStackTrace(); -// } } @Override @@ -488,31 +414,6 @@ public void handleEvent(EpisimInfectionEvent event) { 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); - } - - // print to csv - -// System.out.println(event.getVirusStrain().toString()); - -// try { -// this.printer.printRecord(String.valueOf(day) -// , LocalDate.of(2020, 2, 25).plusDays(day).toString() -// , person.getPersonId().toString() -// , String.valueOf(person.getAge()) -// , event.getVirusStrain().toString() -// , String.valueOf(person.getNumInfections() - 1) -// , String.valueOf(person.getNumVaccinations())); -// -// } catch (IOException e) { -// e.printStackTrace(); -// } - } @@ -529,15 +430,6 @@ public void handleEvent(EpisimVaccinationEvent event) { 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); } @@ -546,17 +438,6 @@ private int getAge(Id personId) { } - /* - % infected who get paxlovid (for a certain age group): - - 75% of people over 60 get paxlovid - + - 75% of people with antibodyResponse below 0.3 - - effectivity: 66% reduction, chance of hospitalization * 0.33 - - - */ private void updateHospitalizationsPost(ImmunizablePerson person, VirusStrain strain, int infectionIteration) { @@ -577,14 +458,6 @@ private void updateHospitalizationsPost(ImmunizablePerson person, VirusStrain st 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)) { @@ -640,11 +513,12 @@ private boolean goToHospital(ImmunizablePerson person, int day) { } } - // 0.36 (old) * 1.2 (delta) * ... (immunisation) = - return rnd.nextDouble() < ageFactor + double chanceOfHospitalisation = ageFactor * strainFactor - * immunityFactor + * Math.min((immunityFactor + (this.pessimisticScenario ? 0.2 : 0.0)), 1.0) * paxlovidFactor; + + return rnd.nextDouble() < chanceOfHospitalisation; } /** From 2a3631f8b64bae2a2ddc69e61bc1b2ae4610a004 Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Thu, 15 Sep 2022 17:49:48 -0400 Subject: [PATCH 11/13] extended hosp model to create hosp intake output per age-group --- .../analysis/HospitalNumbersFromEvents.java | 84 +++++++++++++++++-- src/main/resources/collect.sh | 4 +- 2 files changed, 79 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java index ca3446c8e..d74c41f03 100644 --- a/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java +++ b/src/main/java/org/matsim/episim/analysis/HospitalNumbersFromEvents.java @@ -49,6 +49,7 @@ import java.nio.file.Path; import java.time.LocalDate; import java.util.*; + import java.util.stream.Collectors; /** @@ -261,9 +262,10 @@ public void analyzeOutput(Path pathToScenario) throws IOException { // builds the path to the output file that is produced by this analysis final Path tsvPath = pathToScenario.resolve(id + "post.hospital.tsv"); + final Path tsvPathAge = pathToScenario.resolve(id + "post.hospitalAgeBased.tsv"); // calculates hospitalizations - calculateHospitalizationsAndWriteOutput(pathToScenario, tsvPath); + calculateHospitalizationsAndWriteOutput(pathToScenario, tsvPath,tsvPathAge); log.info("Calculated results for output {}", pathToScenario); @@ -277,11 +279,15 @@ public void analyzeOutput(Path pathToScenario) throws IOException { * @param tsvPath filename for the hospitalization output produced by this method * @throws IOException */ - private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path tsvPath) throws IOException { + private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path tsvPath, Path tsvPathAge) throws IOException { // open new buffered writer for hospitalization output and write the header row. BufferedWriter bw = Files.newBufferedWriter(tsvPath); bw.write(AnalysisCommand.TSV.join(DAY, DATE,"measurement", "severity", "n")); + // open new bw for age-based hospital admission + BufferedWriter bwAge = Files.newBufferedWriter(tsvPathAge); + bwAge.write(AnalysisCommand.TSV.join(DAY, DATE,"measurement", "severity", "ages","n")); + ConfigHolder holderOmicron = configure(factorBA5, factorBA5ICU); ConfigHolder holderDelta = configure(factorDelta, factorDeltaICU); @@ -303,8 +309,19 @@ private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path t // calculates the number of agents in the scenario's population (25% sample) who live in Cologne // this is used to normalize the hospitalization values - double popSize = (int) population.getPersons().values().stream() - .filter(x -> x.getAttributes().getAttribute("district").equals(district)).count(); + Set filteredPopulation = population.getPersons().values().stream() + .filter(x -> x.getAttributes().getAttribute("district").equals(district)).collect(Collectors.toSet()); + + double popSize = filteredPopulation.size(); + + Object2IntMap popSizePerAgeGroup = new Object2IntAVLTreeMap<>(); + int sizeOfPreviousAgeGroup = 0; + for (EpisimReporting.AgeGroup ageGroup : EpisimReporting.AgeGroup.values()) { + int popAboveLowerBound = (int) filteredPopulation.stream().filter(person -> ((int) person.getAttributes().getAttribute("microm:modeled:age")) >= ageGroup.lowerBoundAge).count(); + int popForAgeGroup = popAboveLowerBound - sizeOfPreviousAgeGroup; + popSizePerAgeGroup.put(ageGroup, popForAgeGroup); + sizeOfPreviousAgeGroup = popAboveLowerBound; + } for (int day = 0; day < eventFiles.size(); day++) { @@ -328,11 +345,17 @@ private void calculateHospitalizationsAndWriteOutput(Path pathToScenario, Path t bw.newLine(); bw.write(AnalysisCommand.TSV.join(day, date, HospitalNumbersFromEventsPlotter.OCCUPANCY_ICU, handler.name, occupancyIcu)); + for (EpisimReporting.AgeGroup ageGroup : EpisimReporting.AgeGroup.values()) { + bwAge.newLine(); + double intakesHospAge = getWeeklyHospitalizations(handler.postProcessHospitalAdmissions, day, ageGroup) * 100_000. / popSizePerAgeGroup.getInt(ageGroup); + bwAge.write(AnalysisCommand.TSV.join(day, date.toString(), HospitalNumbersFromEventsPlotter.INTAKES_HOSP, handler.name , ageGroup.name(), intakesHospAge)); + } } } bw.close(); + bwAge.close(); } @@ -349,6 +372,35 @@ static int getWeeklyHospitalizations(Int2IntMap hospMap, Integer today) { return weeklyHospitalizations; } + static int getWeeklyHospitalizations(Int2ObjectMap> hospMap, Integer today) { + int weeklyHospitalizations = 0; + for (int i = 0; i < 7; i++) { + try { + Object2IntMap map = hospMap.getOrDefault(today - i, new Object2IntAVLTreeMap<>()); + weeklyHospitalizations += map.values().intStream().sum(); + + } catch (Exception ignored) { + + } + } + return weeklyHospitalizations; + } + + static int getWeeklyHospitalizations(Int2ObjectMap> hospMap, Integer today, EpisimReporting.AgeGroup ageGroup) { + int weeklyHospitalizations = 0; + for (int i = 0; i < 7; i++) { + try { + Object2IntMap map = hospMap.getOrDefault(today - i, new Object2IntAVLTreeMap<>()); + weeklyHospitalizations += map.getOrDefault(ageGroup, 0); + + } catch (Exception e) { + e.printStackTrace(); + + } + } + return weeklyHospitalizations; + } + public static final class Handler implements EpisimVaccinationEventHandler, EpisimInfectionEventHandler { @@ -364,7 +416,8 @@ public static final class Handler implements EpisimVaccinationEventHandler, Epis private final int paxlovidDay; - final Int2IntSortedMap postProcessHospitalAdmissions; +// final Int2IntSortedMap postProcessHospitalAdmissions; + Int2ObjectMap> postProcessHospitalAdmissions; final Int2IntSortedMap postProcessICUAdmissions; final Int2IntSortedMap postProcessHospitalFilledBeds; final Int2IntSortedMap postProcessHospitalFilledBedsICU; @@ -384,8 +437,8 @@ public static final class Handler implements EpisimVaccinationEventHandler, Epis this.paxlovidDay = (int) LocalDate.of(2020, 2, 25).datesUntil(LocalDate.of(2022, 11, 1)).count(); this.pessimisticScenario = pessimisticScenario; - this.postProcessHospitalAdmissions = new Int2IntAVLTreeMap(); -// this.postProcessHospitalAdmissionsPerAgeGroup = new Int2ObjectAVLTreeMap<>(); +// this.postProcessHospitalAdmissions = new Int2IntAVLTreeMap(); + this.postProcessHospitalAdmissions = new Int2ObjectAVLTreeMap<>(); this.postProcessICUAdmissions = new Int2IntAVLTreeMap(); this.postProcessHospitalFilledBeds = new Int2IntAVLTreeMap(); @@ -455,7 +508,22 @@ private void updateHospitalizationsPost(ImmunizablePerson person, VirusStrain st // newly admitted to hospital int inHospital = infectionIteration + lagBetweenInfectionAndHospitalisation.getInt(strain); - postProcessHospitalAdmissions.mergeInt(inHospital, 1, Integer::sum); + boolean personAssignedToSingleAgeGroup = false; + for (EpisimReporting.AgeGroup ageGroup : EpisimReporting.AgeGroup.values()) { + if (person.getAge() >= ageGroup.lowerBoundAge) { + Object2IntMap admissionsPerAgeGroup = postProcessHospitalAdmissions.getOrDefault(inHospital, new Object2IntOpenHashMap<>()); + admissionsPerAgeGroup.mergeInt(ageGroup, 1, Integer::sum); + postProcessHospitalAdmissions.put(inHospital, admissionsPerAgeGroup); + personAssignedToSingleAgeGroup = true; + break; + + } + } + + if (!personAssignedToSingleAgeGroup) { + throw new RuntimeException("Person needs to be assigned to at least one age group"); + } + diff --git a/src/main/resources/collect.sh b/src/main/resources/collect.sh index 06b491666..82230a6cb 100755 --- a/src/main/resources/collect.sh +++ b/src/main/resources/collect.sh @@ -48,7 +48,9 @@ aggregate_run() { copy_output *.strains.tsv $tmp/$run copy_output *.vaccinations.tsv $tmp/$run copy_output *.vaccinationsDetailed.tsv $tmp/$run - copy_output *.secondaryAttackRate.txt $tmp/$run + copy_output *.vaccinationsPerAgeGroup.tsv $tmp/$run +# copy_output *.secondaryAttackRate.txt $tmp/$run + copy_output *.config.xml $tmp/$run for OUTPUT in *.post.*.*; do From 5fbe69284695fb7bfea0e362dee36d8c1b3f91b9 Mon Sep 17 00:00:00 2001 From: Jakob Rehmann Date: Fri, 16 Sep 2022 17:02:21 -0400 Subject: [PATCH 12/13] added comments & bug fixes --- ...R => Covid19ScenarioHubSubmissionRound2.R} | 0 .../R/Covid19ScenarioHubSubmissionRound3.R | 114 +++++++ .../model/InfectionModelWithAntibodies.java | 2 + ...ccinationStrategyReoccurringCampaigns.java | 2 +- .../run/batch/CologneScenarioHubRound3.java | 295 +++++++++-------- .../model/DefaultAntibodyModelTest.java | 296 ++++++++++++++++++ 6 files changed, 575 insertions(+), 134 deletions(-) rename src/main/R/{Covid19ScenarioHubSubmission.R => Covid19ScenarioHubSubmissionRound2.R} (100%) create mode 100644 src/main/R/Covid19ScenarioHubSubmissionRound3.R diff --git a/src/main/R/Covid19ScenarioHubSubmission.R b/src/main/R/Covid19ScenarioHubSubmissionRound2.R similarity index 100% rename from src/main/R/Covid19ScenarioHubSubmission.R rename to src/main/R/Covid19ScenarioHubSubmissionRound2.R diff --git a/src/main/R/Covid19ScenarioHubSubmissionRound3.R b/src/main/R/Covid19ScenarioHubSubmissionRound3.R new file mode 100644 index 000000000..3c3ee0a7c --- /dev/null +++ b/src/main/R/Covid19ScenarioHubSubmissionRound3.R @@ -0,0 +1,114 @@ + +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-09-15/1-eu-b-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) %>% + filter(campDuration == 91) %>% + filter(vacPool == "vaccinated") %>% + filter(vacFreq!="withStrain") %>% + mutate(optimistic = (mutEsc==3.7)) %>% + # 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) + + +vac <- read_combine_episim_output_zipped(directory,"vaccinationsPerAgeGroup.tsv") + +vac_filtered <- vac %>% filter(seed == 4711) %>% + filter(vacFreq=="annual") %>% + filter(vacCamp == "18plus") %>% + filter(vacPool=="vaccinated") %>% + filter(campDuration==91.) %>% + filter(mutEsc==3.7) + + +# 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/java/org/matsim/episim/model/InfectionModelWithAntibodies.java b/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java index bd8f6bb10..714693d4a 100644 --- a/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java +++ b/src/main/java/org/matsim/episim/model/InfectionModelWithAntibodies.java @@ -139,6 +139,8 @@ public double calcInfectionProbability(EpisimPerson target, EpisimPerson infecto lastUnVac = calcInfectionProbabilityWoImmunity(target, infector, restrictions, act1, act2, contactIntensity, jointTimeInContainer, indoorOutdoorFactor, shedding, intake, infectivity, susceptibility); double immunityFactor = 1.0 / (1.0 + Math.pow(relativeAntibodyLevelTarget, vaccinationConfig.getBeta())); + + // returns infection probability return 1 - Math.exp(-episimConfig.getCalibrationParameter() * susceptibility * infectivity * contactIntensity * jointTimeInContainer * ciCorrection * target.getSusceptibility() * getInfectivity(infector) diff --git a/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java b/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java index 7b6515ca3..eebd453ff 100644 --- a/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java +++ b/src/main/java/org/matsim/episim/model/vaccination/VaccinationStrategyReoccurringCampaigns.java @@ -98,7 +98,7 @@ public void handleVaccination(Map, EpisimPerson> persons, LocalDate d List candidates = persons.values().stream() .filter(EpisimPerson::isVaccinable) // todo: what determines who is vaccinable? .filter(p -> p.getDiseaseStatus() == EpisimPerson.DiseaseStatus.susceptible) - .filter(p -> p.getNumVaccinations() > config.vaccinationPool.vaxCnt) // only boostered people are reboostered + .filter(p -> p.getNumVaccinations() >= config.vaccinationPool.vaxCnt) // only boostered people are reboostered .filter(p -> p.daysSinceVaccination(p.getNumVaccinations() - 1, iteration) > 90) // only people who've had their last vaccination more than 90 days ago .collect(Collectors.toList()); diff --git a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java index bf63e6496..8fda6d6ac 100644 --- a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java +++ b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java @@ -5,8 +5,12 @@ import com.google.inject.Singleton; import com.google.inject.multibindings.Multibinder; import com.google.inject.util.Modules; +import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.Object2DoubleAVLTreeMap; import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.episim.*; @@ -16,8 +20,20 @@ import org.matsim.episim.model.vaccination.VaccinationStrategyReoccurringCampaigns; import org.matsim.run.RunParallel; import org.matsim.run.modules.SnzCologneProductionScenario; +import tech.tablesaw.api.DoubleColumn; +import tech.tablesaw.api.IntColumn; +import tech.tablesaw.api.StringColumn; +import tech.tablesaw.api.Table; +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 javax.annotation.Nullable; +import java.io.*; +import java.nio.charset.StandardCharsets; import java.time.LocalDate; import java.util.*; import java.util.stream.Collectors; @@ -32,72 +48,83 @@ public class CologneScenarioHubRound3 implements BatchRun newVirusStrains = renderNewVirusStrains(); + + /** + * Updated Vaccinations + * Shows all possible vaccinations, the selection of vaccinations for a given scenario will be done in getBindings() + * Key: First day of vaccination campaign + * Value: Vaccination Type + */ public static Map newVaccinations = renderNewVaccinations(); + private static Map renderNewVirusStrains() { + Map newVirusStrains = new TreeMap<>(); + newVirusStrains.put(LocalDate.of(2022,10,1),VirusStrain.STRAIN_A); + newVirusStrains.put(LocalDate.of(2023,7,1),VirusStrain.STRAIN_B); + newVirusStrains.put(LocalDate.of(2024,4,1),VirusStrain.STRAIN_C); + newVirusStrains.put(LocalDate.of(2025,1,1),VirusStrain.STRAIN_D); + newVirusStrains.put(LocalDate.of(2025,10,1),VirusStrain.STRAIN_E); + newVirusStrains.put(LocalDate.of(2026,7,1),VirusStrain.STRAIN_F); + newVirusStrains.put(LocalDate.of(2027,4,1),VirusStrain.STRAIN_G); + newVirusStrains.put(LocalDate.of(2028,1,1),VirusStrain.STRAIN_H); + newVirusStrains.put(LocalDate.of(2028,10,1),VirusStrain.STRAIN_I); + newVirusStrains.put(LocalDate.of(2029,7,1),VirusStrain.STRAIN_J); + newVirusStrains.put(LocalDate.of(2030,4,1),VirusStrain.STRAIN_K); + newVirusStrains.put(LocalDate.of(2031,1,1),VirusStrain.STRAIN_L); + newVirusStrains.put(LocalDate.of(2031,10,1),VirusStrain.STRAIN_M); + newVirusStrains.put(LocalDate.of(2032,7,1),VirusStrain.STRAIN_N); + + return newVirusStrains; + } + private static Map renderNewVaccinations() { Map newVaccinations = new TreeMap<>(); - newVaccinations.put(LocalDate.of(2022,9,1),VaccinationType.fall22); - newVaccinations.put(LocalDate.of(2023,3,1),VaccinationType.spring23); - newVaccinations.put(LocalDate.of(2023,9,1),VaccinationType.fall23); - newVaccinations.put(LocalDate.of(2024,3,1),VaccinationType.spring24); - newVaccinations.put(LocalDate.of(2024,9,1),VaccinationType.fall24); - newVaccinations.put(LocalDate.of(2025,3,1),VaccinationType.spring25); - newVaccinations.put(LocalDate.of(2025,9,1),VaccinationType.fall25); - newVaccinations.put(LocalDate.of(2026,3,1),VaccinationType.spring26); - newVaccinations.put(LocalDate.of(2026,9,1),VaccinationType.fall26); - newVaccinations.put(LocalDate.of(2027,3,1),VaccinationType.spring27); - newVaccinations.put(LocalDate.of(2027,9,1),VaccinationType.fall27); - newVaccinations.put(LocalDate.of(2028,3,1),VaccinationType.spring28); - newVaccinations.put(LocalDate.of(2028,9,1),VaccinationType.fall28); - newVaccinations.put(LocalDate.of(2029,3,1),VaccinationType.spring29); - newVaccinations.put(LocalDate.of(2029,9,1),VaccinationType.fall29); - newVaccinations.put(LocalDate.of(2030,3,1),VaccinationType.spring30); - newVaccinations.put(LocalDate.of(2030,9,1),VaccinationType.fall30); - newVaccinations.put(LocalDate.of(2031,3,1),VaccinationType.spring31); - newVaccinations.put(LocalDate.of(2031,9,1),VaccinationType.fall31); - newVaccinations.put(LocalDate.of(2032,3,1), VaccinationType.spring32); - - newVaccinations.put(LocalDate.of(2022,10,15), VaccinationType.vax_STRAIN_A); - newVaccinations.put(LocalDate.of(2023,7,15), VaccinationType.vax_STRAIN_B); - newVaccinations.put(LocalDate.of(2024,4,15), VaccinationType.vax_STRAIN_C); - newVaccinations.put(LocalDate.of(2025,1,15), VaccinationType.vax_STRAIN_D); - newVaccinations.put(LocalDate.of(2025,10,15), VaccinationType.vax_STRAIN_E); - newVaccinations.put(LocalDate.of(2026,7,15), VaccinationType.vax_STRAIN_F); - newVaccinations.put(LocalDate.of(2027,4,15), VaccinationType.vax_STRAIN_G); - newVaccinations.put(LocalDate.of(2028,1,15), VaccinationType.vax_STRAIN_H); - newVaccinations.put(LocalDate.of(2028,10,15), VaccinationType.vax_STRAIN_I); - newVaccinations.put(LocalDate.of(2029,7,15), VaccinationType.vax_STRAIN_J); - newVaccinations.put(LocalDate.of(2030,4,15), VaccinationType.vax_STRAIN_K); - newVaccinations.put(LocalDate.of(2031,1,15), VaccinationType.vax_STRAIN_L); - newVaccinations.put(LocalDate.of(2031,10,15), VaccinationType.vax_STRAIN_M); - newVaccinations.put(LocalDate.of(2032,7,15), VaccinationType.vax_STRAIN_N); - + newVaccinations.put(LocalDate.of(2022,9,15),VaccinationType.fall22); + newVaccinations.put(LocalDate.of(2023,3,15),VaccinationType.spring23); + newVaccinations.put(LocalDate.of(2023,9,15),VaccinationType.fall23); + newVaccinations.put(LocalDate.of(2024,3,15),VaccinationType.spring24); + newVaccinations.put(LocalDate.of(2024,9,15),VaccinationType.fall24); + newVaccinations.put(LocalDate.of(2025,3,15),VaccinationType.spring25); + newVaccinations.put(LocalDate.of(2025,9,15),VaccinationType.fall25); + newVaccinations.put(LocalDate.of(2026,3,15),VaccinationType.spring26); + newVaccinations.put(LocalDate.of(2026,9,15),VaccinationType.fall26); + newVaccinations.put(LocalDate.of(2027,3,15),VaccinationType.spring27); + newVaccinations.put(LocalDate.of(2027,9,15),VaccinationType.fall27); + newVaccinations.put(LocalDate.of(2028,3,15),VaccinationType.spring28); + newVaccinations.put(LocalDate.of(2028,9,15),VaccinationType.fall28); + newVaccinations.put(LocalDate.of(2029,3,15),VaccinationType.spring29); + newVaccinations.put(LocalDate.of(2029,9,15),VaccinationType.fall29); + newVaccinations.put(LocalDate.of(2030,3,15),VaccinationType.spring30); + newVaccinations.put(LocalDate.of(2030,9,15),VaccinationType.fall30); + newVaccinations.put(LocalDate.of(2031,3,15),VaccinationType.spring31); + newVaccinations.put(LocalDate.of(2031,9,15),VaccinationType.fall31); + newVaccinations.put(LocalDate.of(2032,3,15),VaccinationType.spring32); + + newVaccinations.put(LocalDate.of(2022,10,1), VaccinationType.vax_STRAIN_A); + newVaccinations.put(LocalDate.of(2023,7,1), VaccinationType.vax_STRAIN_B); + newVaccinations.put(LocalDate.of(2024,4,1), VaccinationType.vax_STRAIN_C); + newVaccinations.put(LocalDate.of(2025,1,1), VaccinationType.vax_STRAIN_D); + newVaccinations.put(LocalDate.of(2025,10,1), VaccinationType.vax_STRAIN_E); + newVaccinations.put(LocalDate.of(2026,7,1), VaccinationType.vax_STRAIN_F); + newVaccinations.put(LocalDate.of(2027,4,1), VaccinationType.vax_STRAIN_G); + newVaccinations.put(LocalDate.of(2028,1,1), VaccinationType.vax_STRAIN_H); + newVaccinations.put(LocalDate.of(2028,10,1), VaccinationType.vax_STRAIN_I); + newVaccinations.put(LocalDate.of(2029,7,1), VaccinationType.vax_STRAIN_J); + newVaccinations.put(LocalDate.of(2030,4,1), VaccinationType.vax_STRAIN_K); + newVaccinations.put(LocalDate.of(2031,1,1), VaccinationType.vax_STRAIN_L); + newVaccinations.put(LocalDate.of(2031,10,1), VaccinationType.vax_STRAIN_M); + newVaccinations.put(LocalDate.of(2032,7,1), VaccinationType.vax_STRAIN_N); return newVaccinations; } - private static Map renderNewVirusStrains() { - Map newVirusStrains = new TreeMap<>(); - newVirusStrains.put(LocalDate.of(2022,10,15),VirusStrain.STRAIN_A); - newVirusStrains.put(LocalDate.of(2023,7,15),VirusStrain.STRAIN_B); - newVirusStrains.put(LocalDate.of(2024,4,15),VirusStrain.STRAIN_C); - newVirusStrains.put(LocalDate.of(2025,1,15),VirusStrain.STRAIN_D); - newVirusStrains.put(LocalDate.of(2025,10,15),VirusStrain.STRAIN_E); - newVirusStrains.put(LocalDate.of(2026,7,15),VirusStrain.STRAIN_F); - newVirusStrains.put(LocalDate.of(2027,4,15),VirusStrain.STRAIN_G); - newVirusStrains.put(LocalDate.of(2028,1,15),VirusStrain.STRAIN_H); - newVirusStrains.put(LocalDate.of(2028,10,15),VirusStrain.STRAIN_I); - newVirusStrains.put(LocalDate.of(2029,7,15),VirusStrain.STRAIN_J); - newVirusStrains.put(LocalDate.of(2030,4,15),VirusStrain.STRAIN_K); - newVirusStrains.put(LocalDate.of(2031,1,15),VirusStrain.STRAIN_L); - newVirusStrains.put(LocalDate.of(2031,10,15),VirusStrain.STRAIN_M); - newVirusStrains.put(LocalDate.of(2032,7,15),VirusStrain.STRAIN_N); - - return newVirusStrains; - } - @Nullable @Override public Module getBindings(int id, @Nullable Params params) { @@ -105,14 +132,11 @@ public Module getBindings(int id, @Nullable Params params) { @Override protected void configure() { + // VACCINATION MODEL Multibinder set = Multibinder.newSetBinder(binder(), VaccinationModel.class); - set.addBinding().to(VaccinationStrategyReoccurringCampaigns.class).in(Singleton.class); - double mutEscBa5 = 3.0; - double mutEscStrainX = 3.0; - - + // default values (if params==null) Map startDateToVaccination = new HashMap<>(); Object2DoubleMap compliance = new Object2DoubleAVLTreeMap(); @@ -123,14 +147,12 @@ protected void configure() { VaccinationStrategyReoccurringCampaigns.Config.VaccinationPool vaccinationPool = VaccinationStrategyReoccurringCampaigns.Config.VaccinationPool.vaccinated; - int campaignDuration = 91; + int campaignDuration = 90; if (params != null) { campaignDuration = (int) params.campDuration; - mutEscStrainX = params.mutEsc; - vaccinationPool = VaccinationStrategyReoccurringCampaigns.Config.VaccinationPool.valueOf(params.vacPool); @@ -140,11 +162,13 @@ protected void configure() { if (params.vacFreq.equals("none")) { + + } else if (params.vacFreq.equals("fall22")) { startDateToVaccination.put(LocalDate.of(2022, 9, 1), newVaccinations.get(LocalDate.of(2022, 9, 1))); } else if (params.vacFreq.equals("annual")) { startDateToVaccination.putAll(newVaccinations.entrySet().stream().filter(entry -> entry.getValue().toString().startsWith("fall")).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); } else if (params.vacFreq.equals("biannual")) { - startDateToVaccination.putAll(newVaccinations.entrySet().stream().filter(entry -> (entry.getValue().toString().startsWith("fall")||entry.getValue().toString().startsWith("spring"))).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); + startDateToVaccination.putAll(newVaccinations.entrySet().stream().filter(entry -> (entry.getValue().toString().startsWith("fall") || entry.getValue().toString().startsWith("spring"))).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); } else if (params.vacFreq.equals("withStrain")) { startDateToVaccination.putAll(newVaccinations.entrySet().stream().filter(entry -> entry.getValue().toString().startsWith("vax")).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); } else { @@ -181,18 +205,23 @@ else if (params.vacCamp.equals("18plus")) { bind(VaccinationStrategyReoccurringCampaigns.Config.class).toInstance(new VaccinationStrategyReoccurringCampaigns.Config(startDateToVaccination, campaignDuration, compliance, vaccinationPool)); + // ANTIBODY MODEL + // default values + double mutEscBa5 = 3.0; + double mutEscStrainX = 3.0; //initial antibodies Map> initialAntibodies = new HashMap<>(); Map> antibodyRefreshFactors = new HashMap<>(); - configureAntibodies(initialAntibodies, antibodyRefreshFactors, mutEscBa5, mutEscStrainX); - - AntibodyModel.Config antibodyConfig = new AntibodyModel.Config(initialAntibodies, antibodyRefreshFactors); - double immuneSigma = 3.0; if (params != null) { - antibodyConfig.setImmuneReponseSigma(immuneSigma); + mutEscStrainX = params.mutEsc; } + configureAntibodies(initialAntibodies, antibodyRefreshFactors, mutEscBa5, mutEscStrainX); + AntibodyModel.Config antibodyConfig = new AntibodyModel.Config(initialAntibodies, antibodyRefreshFactors); + double immuneSigma = 3.0; + antibodyConfig.setImmuneReponseSigma(immuneSigma); + bind(AntibodyModel.Config.class).toInstance(antibodyConfig); if (DEBUG_MODE && params != null) { @@ -441,8 +470,9 @@ public Collection postProcessing() { new VaccinationEffectiveness().withArgs(), new RValuesFromEvents().withArgs(), new VaccinationEffectivenessFromPotentialInfections().withArgs("--remove-infected"), - new HospitalNumbersFromEvents().withArgs(), - new SecondaryAttackRateFromEvents().withArgs() + new FilterEvents().withArgs("--output","./output/"), + new HospitalNumbersFromEvents().withArgs() +// new SecondaryAttackRateFromEvents().withArgs() ); } @@ -467,14 +497,13 @@ public Config prepareConfig(int id, Params params) { EpisimConfigGroup episimConfig = ConfigUtils.addOrGetModule(config, EpisimConfigGroup.class); - // create snapshot - episimConfig.setSnapshotInterval(927); -// episimConfig.setStartFromSnapshot("/scratch/projects/bzz0020/episim-input/snapshots-cologne-20220218/" + params.seed + "-600-2021-10-16.zip"); -// episimConfig.setSnapshotSeed(EpisimConfigGroup.SnapshotSeed.restore); + // create / read snapshot +// episimConfig.setSnapshotInterval(927); + episimConfig.setStartFromSnapshot("/scratch/projects/bzz0020/episim-input/snapshots-cologne-2022-09-16/" + params.seed + "-927-2022-09-08.zip"); + episimConfig.setSnapshotSeed(EpisimConfigGroup.SnapshotSeed.restore); - //mutations + // S T R A I N S VirusStrainConfigGroup virusStrainConfigGroup = ConfigUtils.addOrGetModule(config, VirusStrainConfigGroup.class); - //configure new strains //BA5 double ba5Inf = 0.9; @@ -484,8 +513,7 @@ public Config prepareConfig(int id, Params params) { virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorSeriouslySickVaccinated(oHos); virusStrainConfigGroup.getOrAddParams(VirusStrain.OMICRON_BA5).setFactorCritical(oHos); - //StrainA/B/C - + //StrainX for (VirusStrain strain : newVirusStrains.values()) { virusStrainConfigGroup.getOrAddParams(strain).setInfectiousness(virusStrainConfigGroup.getParams(VirusStrain.OMICRON_BA5).getInfectiousness()); virusStrainConfigGroup.getOrAddParams(strain).setFactorSeriouslySick(oHos); @@ -494,12 +522,11 @@ public Config prepareConfig(int id, Params params) { } - //Configure Disease Import - + // D I S E A S E I M P O R T configureFutureDiseaseImport(params, episimConfig); - //vaccinations + // V A C C I N A T I O N S VaccinationConfigGroup vaccinationConfig = ConfigUtils.addOrGetModule(config, VaccinationConfigGroup.class); vaccinationConfig.setUseIgA(true); vaccinationConfig.setTimePeriodIgA(730.); @@ -545,7 +572,7 @@ private void configureFutureDiseaseImport(Params params, EpisimConfigGroup episi episimConfig.setInfections_pers_per_day(VirusStrain.OMICRON_BA5, infPerDayBa5); - //StrainA/B/C + //StrainX for (Map.Entry entry : newVirusStrains.entrySet()) { LocalDate date = entry.getKey(); VirusStrain strain = entry.getValue(); @@ -562,54 +589,56 @@ private void configureFutureDiseaseImport(Params params, EpisimConfigGroup episi // add projected disease import for vacation waves after initial disease import // int facBa2 = 4; // int facBa5 = 4; - int facStrainX = 4; - - LocalDate dateBa2 = LocalDate.parse("2022-01-27"); // local min of disease import - LocalDate dateBa5 = LocalDate.parse("2022-05-01"); // after vaca import - - NavigableMap data = DataUtils.readDiseaseImport(SnzCologneProductionScenario.INPUT.resolve("cologneDiseaseImport_Projected_2032.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 +// int facStrainX = 4; +// +// LocalDate dateBa2 = LocalDate.parse("2022-01-27"); // local min of disease import +// LocalDate dateBa5 = LocalDate.parse("2022-05-01"); // after vaca import +// +// NavigableMap data = DataUtils.readDiseaseImport(SnzCologneProductionScenario.INPUT.resolve("cologneDiseaseImport_Projected_2032.csv")); +// LocalDate date = null; +// +// // TODO this overwrites the original import!!! +// 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(); +// +// //from most recent to furthest back. +// Map reverseSortedVirusStrainMap = new TreeMap(Collections.reverseOrder()); +// reverseSortedVirusStrainMap.putAll(newVirusStrains); +// reverseSortedVirusStrainMap.put(dateBa5, VirusStrain.OMICRON_BA5); +// reverseSortedVirusStrainMap.put(dateBa2, VirusStrain.OMICRON_BA2); +// +// +// // strain map sorted from newest to oldest +// // if current date is after LATEST virus's spawn date + 2 months -> give the corresponding virusStrain all the import +// // if currents datae is after virusStrainDate -> give the corresponding virusStrain an import of 1. +// // else: current date is before spwan of virus strain -> don't give any import +// +// +// boolean firstTimeAfterDate = true; +// for (LocalDate dateStrainX : reverseSortedVirusStrainMap.keySet()) { +// +// if (date.isAfter(dateStrainX.plusMonths(2)) && firstTimeAfterDate) { +// episimConfig.getInfections_pers_per_day().get(reverseSortedVirusStrainMap.get(dateStrainX)).put(date, ((int) cases * facStrainX) == 0 ? 1 : (int) (cases * facStrainX)); +// firstTimeAfterDate = false; +// } else if (date.isAfter(dateStrainX.plusMonths(2))) { +// episimConfig.getInfections_pers_per_day().get(reverseSortedVirusStrainMap.get(dateStrainX)).put(date, 1); +// } else { +// episimConfig.getInfections_pers_per_day().get(reverseSortedVirusStrainMap.get(dateStrainX)).put(date, 0); +// } // - double cases = factor * entry.getValue(); - - //from most recent to furthest back. - Map reverseSortedVirusStrainMap = new TreeMap(Collections.reverseOrder()); - reverseSortedVirusStrainMap.putAll(newVirusStrains); - reverseSortedVirusStrainMap.put(dateBa5, VirusStrain.OMICRON_BA5); - reverseSortedVirusStrainMap.put(dateBa2, VirusStrain.OMICRON_BA2); - - - // strain map sorted from newest to oldest - // if current date is after LATEST virus's spawn date + 2 months -> give the corresponding virusStrain all the import - // if currents datae is after virusStrainDate -> give the corresponding virusStrain an import of 1. - // else: current date is before spwan of virus strain -> don't give any import - - - boolean firstTimeAfterDate = true; - for (LocalDate dateStrainX : reverseSortedVirusStrainMap.keySet()) { - - if (date.isAfter(dateStrainX.plusMonths(2)) && firstTimeAfterDate) { - episimConfig.getInfections_pers_per_day().get(reverseSortedVirusStrainMap.get(dateStrainX)).put(date, ((int) cases * facStrainX) == 0 ? 1 : (int) (cases * facStrainX)); - firstTimeAfterDate = false; - } else if (date.isAfter(dateStrainX.plusMonths(2))) { - episimConfig.getInfections_pers_per_day().get(reverseSortedVirusStrainMap.get(dateStrainX)).put(date, 1); - } else { - episimConfig.getInfections_pers_per_day().get(reverseSortedVirusStrainMap.get(dateStrainX)).put(date, 0); - } - - } - -// 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)); // } - - } +// +//// 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)); +//// } +// +// } // infPerDayBa5.put(date.plusDays(1), 1); @@ -628,7 +657,7 @@ public static final class Params { // vaccination campaign //vaccination frequency - @StringParameter({"none", "annual", "biannual","withStrain"}) + @StringParameter({"none", "fall22", "annual", "biannual","withStrain"}) String vacFreq; @StringParameter({"18plus","18plus50pct"}) @@ -638,12 +667,12 @@ public static final class Params { @StringParameter({"vaccinated","boostered"}) String vacPool; - @Parameter({31., 91.}) + @Parameter({30., 90.}) double campDuration; //new mutations - @Parameter({3.7, 44.7}) + @Parameter({8.5, 103}) public double mutEsc; } diff --git a/src/test/java/org/matsim/episim/model/DefaultAntibodyModelTest.java b/src/test/java/org/matsim/episim/model/DefaultAntibodyModelTest.java index 3f4a28436..dab913f00 100644 --- a/src/test/java/org/matsim/episim/model/DefaultAntibodyModelTest.java +++ b/src/test/java/org/matsim/episim/model/DefaultAntibodyModelTest.java @@ -12,6 +12,7 @@ import org.junit.*; import org.matsim.episim.EpisimPerson; import org.matsim.episim.EpisimTestUtils; +import org.matsim.run.batch.CologneScenarioHubRound3; import org.matsim.testcases.MatsimTestUtils; import tech.tablesaw.api.DoubleColumn; import tech.tablesaw.api.IntColumn; @@ -28,6 +29,7 @@ import java.io.*; import java.nio.charset.StandardCharsets; +import java.time.LocalDate; import java.util.*; import static com.google.common.math.Quantiles.*; @@ -240,6 +242,300 @@ public void testMixOfVaccinesAndInfections() { } + @Test + public void testEuScenarioHub() { + + + double mutEscBa5 = 3.0; + double mutEscStrainX = 8;//103; + + Map> initialAntibodies = new HashMap<>(); + Map> antibodyRefreshFactors = new HashMap<>(); + configureAntibodies(initialAntibodies, antibodyRefreshFactors, mutEscBa5, mutEscStrainX); + + antibodyConfig = new AntibodyModel.Config(initialAntibodies, antibodyRefreshFactors); + + model = new DefaultAntibodyModel(antibodyConfig); + + List immunityEvents = List.of(VaccinationType.mRNA, VaccinationType.mRNA, VirusStrain.OMICRON_BA5, VaccinationType.fall22); + // 2021-06-01 - mRNA + // 2021-12-01 - mRNA + // 2022-06-01 - BA5 + // 2022-10-01 - StrainA + IntList immunityEventDays = IntList.of(1, 182, 365, 480); +// List immunityEvents = List.of(VaccinationType.mRNA); +// IntList immunityEventDays = IntList.of(1); + + Int2ObjectMap> antibodyLevels = simulateAntibodyLevels(immunityEvents, immunityEventDays, 1000, EpisimTestUtils.createPerson()); + + // Plot 1: nAb + { + IntColumn records = IntColumn.create("day"); + DoubleColumn values = DoubleColumn.create("antibodies"); + StringColumn groupings = StringColumn.create("scenario"); + + for (int day : antibodyLevels.keySet()) { + Object2DoubleMap strainToAntibodyMap = antibodyLevels.get(day); + + for (Object strain : strainToAntibodyMap.keySet()) { + records.append(day); + + double nAb = strainToAntibodyMap.getOrDefault(strain, 0.); + + values.append(nAb); + groupings.append(strain.toString()); + + } + } + producePlot(records, values, groupings, "nAb", "nAb: " + immunityEvents, "euScenarioHub3-nAb.html"); + + } + + // Plot 2: ve + { + IntColumn records = IntColumn.create("day"); + DoubleColumn values = DoubleColumn.create("antibodies"); + StringColumn groupings = StringColumn.create("scenario"); + + for (int day : antibodyLevels.keySet()) { + Object2DoubleMap strainToAntibodyMap = antibodyLevels.get(day); + + for (Object strain : strainToAntibodyMap.keySet()) { + records.append(day); + + double nAb = strainToAntibodyMap.getOrDefault(strain, 0.); + + var beta = 1.; + var fact = 0.001; + double immunityFactor = 1.0 / (1.0 + Math.pow(nAb, beta)); + final double probaWVacc = 1 - Math.exp(-fact * immunityFactor); + final double probaWoVacc = 1 - Math.exp(-fact); + final double ve = 1. - probaWVacc / probaWoVacc; + + values.append(ve); + groupings.append(strain.toString()); + + } + } + producePlot(records, values, groupings, "ve", "ve: " + immunityEvents, "euScenarioHub3-ve.html"); + } + + + } + + + private void configureAntibodies(Map> initialAntibodies, + Map> antibodyRefreshFactors, + double mutEscBa5, double mutEscStrainX) { + + 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(IMMUNITY GIVER).put(IMMUNITY AGAINST, ab level); + 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); + + + //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); + + //DELTA + double mRNADelta = 10.9; + 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(VirusStrain.OMICRON_BA5).put(VirusStrain.DELTA, 0.2 / 6.4); + + + //BA.1 + double mRNABA1 = 1.9; + 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. / 1.4); //todo: is 1.4 + + //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. / 1.4); + + + //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. / 1.4 / 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.); + + // NEW STRAINS + + // A) all "new/updated/novel" vaccinations and infections give only 0.01 protection against "old" strains + + for (VirusStrain protectionAgainst : List.of(VirusStrain.SARS_CoV_2, VirusStrain.ALPHA, VirusStrain.DELTA, VirusStrain.OMICRON_BA1, VirusStrain.OMICRON_BA2, VirusStrain.OMICRON_BA5)) { + for (ImmunityEvent vax : CologneScenarioHubRound3.newVaccinations.values()) { + initialAntibodies.get(vax).put(protectionAgainst, 0.01); + } + + for (ImmunityEvent strain : CologneScenarioHubRound3.newVirusStrains.values()) { + initialAntibodies.get(strain).put(protectionAgainst, 0.01); + } + } + + // B) "old" vaccinations and infections give the same protection to StrainX as to BA5 PLUS an escape + double mRNAStrainX = mRNABa5 / mutEscStrainX; + + for (VirusStrain newStrain : CologneScenarioHubRound3.newVirusStrains.values()) { + initialAntibodies.get(VaccinationType.mRNA).put(newStrain, mRNAStrainX); + initialAntibodies.get(VaccinationType.vector).put(newStrain, mRNAStrainX * 4. / 20.); + initialAntibodies.get(VirusStrain.SARS_CoV_2).put(newStrain, mRNAStrainX * 6. / 20.); + initialAntibodies.get(VirusStrain.ALPHA).put(newStrain, mRNAStrainX * 6. / 20.); + initialAntibodies.get(VirusStrain.DELTA).put(newStrain, mRNAStrainX * 8. / 20.); + + initialAntibodies.get(VirusStrain.OMICRON_BA1).put(newStrain, 64.0 / 300. / mutEscBa5 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA2).put(newStrain, 64.0 / 300. / mutEscBa5 / mutEscStrainX); + initialAntibodies.get(VirusStrain.OMICRON_BA5).put(newStrain, 64.0 / 300. / mutEscStrainX); + + } + + // C) Immunity between the novel StrainsX: + // Newer Strains give full (non-escaped) protection against themselves AND previous strains + // New Strains give escaped protection against future strainA + + // initialAntibodies.get(IMMUNITY GIVER).put(IMMUNITY AGAINST, ab level); + + for (LocalDate dateProtectionGiver : CologneScenarioHubRound3.newVirusStrains.keySet()) { + + for (LocalDate dateProtectionAgainst : CologneScenarioHubRound3.newVirusStrains.keySet()) { + + if (dateProtectionGiver.equals(dateProtectionAgainst) || dateProtectionGiver.isAfter(dateProtectionAgainst)) { + // Newer Strains give full (non-escaped) protection against themselves AND previous strains + initialAntibodies.get(CologneScenarioHubRound3.newVirusStrains.get(dateProtectionGiver)).put(CologneScenarioHubRound3.newVirusStrains.get(dateProtectionAgainst), mRNAAlpha); + + } else { + // New Strains give escaped protection against future strainA + initialAntibodies.get(CologneScenarioHubRound3.newVirusStrains.get(dateProtectionGiver)).put(CologneScenarioHubRound3.newVirusStrains.get(dateProtectionAgainst), mRNAAlpha/ mutEscStrainX); + + } + + } + } + + // D) Immunity provided by new vaccines against novel StrainsX: + // Provides baseline immunity if StrainX was spawned more than 6 months before vaccination campaign begins + // provides reduced immunity otherwise + + for (LocalDate dateProtectionGiver : CologneScenarioHubRound3.newVaccinations.keySet()) { + + for (LocalDate dateProtectionAgainst : CologneScenarioHubRound3.newVirusStrains.keySet()) { + + if (dateProtectionGiver.isAfter(dateProtectionAgainst.plusMonths(6))) { + // Provides baseline immunity if StrainX was spawned more than 6 months before vaccination campaign begins + + initialAntibodies.get(CologneScenarioHubRound3.newVaccinations.get(dateProtectionGiver)).put(CologneScenarioHubRound3.newVirusStrains.get(dateProtectionAgainst), mRNAAlpha); + + } + else { + // provides reduced immunity otherwise + initialAntibodies.get(CologneScenarioHubRound3.newVaccinations.get(dateProtectionGiver)).put(CologneScenarioHubRound3.newVirusStrains.get(dateProtectionAgainst), mRNAAlpha/ mutEscStrainX); + + } + + + } + } + + // R E F R E S H F A C T O R S + 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 (CologneScenarioHubRound3.newVaccinations.containsValue(immunityType)) { + if (CologneScenarioHubRound3.newVirusStrains.containsValue(virusStrain)) { + antibodyRefreshFactors.get(immunityType).put(virusStrain, 1.0); + } else { + 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()) { + if (CologneScenarioHubRound3.newVirusStrains.containsValue(immunityType) && CologneScenarioHubRound3.newVirusStrains.containsValue(virusStrain)) { + antibodyRefreshFactors.get(immunityType).put(virusStrain, 1.0); + } else { + antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0); + } + } + } + } + /** * Tests the immuneResponseMultiplier of EpisimPerson; the agent w/ a higher immune response to vaccination/infection * will have a multiplier of 2 while the "normal" agent has a multiplier of 1. From 3372909543c1bf84de888052f96085d139f68dca Mon Sep 17 00:00:00 2001 From: smuellervsp Date: Mon, 26 Sep 2022 17:01:57 +0200 Subject: [PATCH 13/13] new parameters for debugging --- .../run/batch/CologneScenarioHubRound3.java | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java index 8fda6d6ac..1b464220e 100644 --- a/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java +++ b/src/main/java/org/matsim/run/batch/CologneScenarioHubRound3.java @@ -148,13 +148,17 @@ protected void configure() { VaccinationStrategyReoccurringCampaigns.Config.VaccinationPool vaccinationPool = VaccinationStrategyReoccurringCampaigns.Config.VaccinationPool.vaccinated; int campaignDuration = 90; + double refresh = 0; + int delay = 0; if (params != null) { campaignDuration = (int) params.campDuration; vaccinationPool = VaccinationStrategyReoccurringCampaigns.Config.VaccinationPool.valueOf(params.vacPool); - + + refresh = params.refresh; + delay = params.delay; if (DEBUG_MODE) { startDateToVaccination.put(LocalDate.of(2020, 2, 27), VaccinationType.fall23); @@ -217,7 +221,7 @@ else if (params.vacCamp.equals("18plus")) { mutEscStrainX = params.mutEsc; } - configureAntibodies(initialAntibodies, antibodyRefreshFactors, mutEscBa5, mutEscStrainX); + configureAntibodies(initialAntibodies, antibodyRefreshFactors, mutEscBa5, mutEscStrainX, refresh, delay); AntibodyModel.Config antibodyConfig = new AntibodyModel.Config(initialAntibodies, antibodyRefreshFactors); double immuneSigma = 3.0; antibodyConfig.setImmuneReponseSigma(immuneSigma); @@ -233,7 +237,7 @@ else if (params.vacCamp.equals("18plus")) { private void configureAntibodies(Map> initialAntibodies, Map> antibodyRefreshFactors, - double mutEscBa5, double mutEscStrainX) { + double mutEscBa5, double mutEscStrainX, double refresh, int delay) { for (VaccinationType immunityType : VaccinationType.values()) { initialAntibodies.put(immunityType, new EnumMap<>(VirusStrain.class)); @@ -390,7 +394,7 @@ private void configureAntibodies(Map> in for (LocalDate dateProtectionAgainst : newVirusStrains.keySet()) { - if (dateProtectionGiver.isAfter(dateProtectionAgainst.plusMonths(6))) { + if (dateProtectionGiver.isAfter(dateProtectionAgainst.plusMonths(delay))) { // Provides baseline immunity if StrainX was spawned more than 6 months before vaccination campaign begins initialAntibodies.get(newVaccinations.get(dateProtectionGiver)).put(newVirusStrains.get(dateProtectionAgainst), mRNAAlpha); @@ -419,7 +423,7 @@ private void configureAntibodies(Map> in antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0); } else if (newVaccinations.containsValue(immunityType)) { if (newVirusStrains.containsValue(virusStrain)) { - antibodyRefreshFactors.get(immunityType).put(virusStrain, 1.0); + antibodyRefreshFactors.get(immunityType).put(virusStrain, refresh); } else { antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0); } @@ -435,7 +439,7 @@ private void configureAntibodies(Map> in antibodyRefreshFactors.put(immunityType, new EnumMap<>(VirusStrain.class)); for (VirusStrain virusStrain : VirusStrain.values()) { if (newVirusStrains.containsValue(immunityType) && newVirusStrains.containsValue(virusStrain)) { - antibodyRefreshFactors.get(immunityType).put(virusStrain, 1.0); + antibodyRefreshFactors.get(immunityType).put(virusStrain, refresh); } else { antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0); } @@ -657,22 +661,29 @@ public static final class Params { // vaccination campaign //vaccination frequency - @StringParameter({"none", "fall22", "annual", "biannual","withStrain"}) +// @StringParameter({"none", "fall22", "annual", "biannual","withStrain"}) + @StringParameter({"none", "withStrain", "annual"}) String vacFreq; - @StringParameter({"18plus","18plus50pct"}) + @StringParameter({"18plus50pct"}) // @StringParameter({"off", "60plus", "18plus"}) String vacCamp; - @StringParameter({"vaccinated","boostered"}) + @StringParameter({"vaccinated"}) String vacPool; @Parameter({30., 90.}) double campDuration; + + @IntParameter({6, -1}) + int delay; + @Parameter({15., 1.}) + double refresh; //new mutations - @Parameter({8.5, 103}) +// @Parameter({8.5, 103}) + @Parameter({3.0, 8.5, 103.}) public double mutEsc; }