diff --git a/.gitignore b/.gitignore index a19fc1a..e08e70b 100644 --- a/.gitignore +++ b/.gitignore @@ -136,3 +136,4 @@ Protecs/src/main/resources/census_ipums.csv Protecs/src/main/resources/census_ipums_5perc.csv Protecs/src/main/resources/ipums_radiation_formatted.csv +Protecs/src/main/resources/ipums_5p_wp_bubbles_comb_teacher_students.csv diff --git a/Protecs/src/main/java/uk/ac/ucl/protecs/sim/Logging.java b/Protecs/src/main/java/uk/ac/ucl/protecs/sim/Logging.java index 3f11997..848859e 100644 --- a/Protecs/src/main/java/uk/ac/ucl/protecs/sim/Logging.java +++ b/Protecs/src/main/java/uk/ac/ucl/protecs/sim/Logging.java @@ -13,7 +13,217 @@ import uk.ac.ucl.protecs.objects.Person.SEX; public class Logging { + // set up commonly used variables to avoid repetition + // age boundaries to format log files + private final static List upper_age_range = Arrays.asList(1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 120); + private final static List lower_age_range = Arrays.asList(0, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95); + private final static List birthrate_upper_age_range = Arrays.asList(20, 25, 30, 35, 40, 45, 50); + private final static List birthrate_lower_age_range = Arrays.asList(15, 20, 25, 30, 35, 40, 45); + private final static String age_categories = "<1" + "\t" + "1_4" + "\t" + "5_9" + "\t" + "10_14" + "\t" + "15_19" + "\t" + "20_24" + "\t" + "25_29" + + "\t" + "30_34" + "\t" + "35_39" + "\t" + "40_44" + "\t" + "45_49" + "\t" + "50_54" + "\t" + "55_59" + "\t" + "60_64" + "\t" + "65_69" + "\t" + + "70_74" + "\t" + "75_79" + "\t" + "80_84" + "\t" + "85_89" + "\t" + "90_94" + "\t" + "95<"; + // tab shortcut + private final static String t = "\t"; + // age sex breakdown header + private final static String age_sex_categories = t + "sex" + age_categories + "\n"; + + // set up commonly used functions to avoid repetition + // get those alive of given age and sex + private static Map>> age_sex_alive_map(WorldBankCovid19Sim world) { + Map>> age_sex_alive_map = world.agents.stream().collect( + Collectors.groupingBy( + Person::getSex, + Collectors.groupingBy( + Person::getAge, + Collectors.groupingBy( + Person::isAlive, + Collectors.counting() + ) + ) + ) + ); + return age_sex_alive_map; + } + + // get those who alive with COVID of given age and sex + private static Map>>> age_sex_has_covid_map( + WorldBankCovid19Sim world) { + Map>>> age_sex_map_has_covid = world.agents.stream().collect( + Collectors.groupingBy( + Person::getSex, + Collectors.groupingBy( + Person::getAge, + Collectors.groupingBy( + Person::hasCovid, + Collectors.groupingBy( + Person::getCovidLogged, + Collectors.counting() + ) + ) + ) + ) + ); + return age_sex_map_has_covid; + } + + // get number of those alive of age and sex + private static ArrayList get_number_of_alive(WorldBankCovid19Sim world, SEX sex) { + ArrayList alive_ages = new ArrayList(); + Map>> age_sex_alive_map_copy = age_sex_alive_map(world); + // We now iterate over the age ranges, create a variable to keep track of the iterations + Integer idx = 0; + for (Integer val: upper_age_range) { + // for each age group we begin to count the number of people who fall into each category, create variables + // to store this information in + Integer count = 0; + // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) + for (int age = lower_age_range.get(idx); age < val; age++) { + + try { + // try function necessary as some ages won't be present in the population + // use the functions created earlier to calculate the number of people of each age group who fall + // into the categories we are interested in (alive, died from covid, died from other) + count += age_sex_alive_map_copy.get(sex).get(age).get(true).intValue(); + } + catch (Exception e) { + // age wasn't present in the population, skip + } + } + alive_ages.add(count); + + } + return alive_ages; + } + + // get those alive with COVID of age + private static ArrayList get_covid_counts_by_age(WorldBankCovid19Sim world, SEX sex) { + Integer idx = 0; + ArrayList covid_by_ages = new ArrayList(); + + // create a function to group the population by sex, age and whether they have covid + Map>>> age_sex_map_has_covid = age_sex_has_covid_map(world); + + // We now iterate over the age ranges, create a variable to keep track of the iterations + for (Integer val: upper_age_range) { + // for each age group we begin to count the number of people who fall into each category, create variables + // to store this information in + Integer covid_count = 0; + // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) + for (int age = lower_age_range.get(idx); age < val; age++) { + try { + // try function necessary as some ages won't be present in the population + // use the functions created earlier to calculate the number of people of each age group who fall + // into the categories we are interested in (alive, died from covid, died from other) + covid_count += age_sex_map_has_covid.get(sex).get(age).get(true).get(false).intValue(); + } + catch (Exception e) { + // age wasn't present in the population, skip + } + } + covid_by_ages.add(covid_count); + // update the idx variable for the next iteration + idx++; + + } + return covid_by_ages; + } + + // get those who died of COVID of age + private static ArrayList get_covid_death_counts_by_age(WorldBankCovid19Sim world, SEX sex) { + Integer idx = 0; + ArrayList covid_death_by_ages = new ArrayList(); + + // create a function to group the population by sex, age and whether they have covid + Map>>> age_sex_map_died_from_covid = world.agents.stream().collect( + Collectors.groupingBy( + Person::getSex, + Collectors.groupingBy( + Person::getAge, + Collectors.groupingBy( + Person::isDeadFromCovid, + Collectors.groupingBy( + Person::getDeathLogged, + Collectors.counting() + ) + ) + ) + ) + ); + + // We now iterate over the age ranges, create a variable to keep track of the iterations + for (Integer val: upper_age_range) { + // for each age group we begin to count the number of people who fall into each category, create variables + // to store this information in + Integer covid_death_count = 0; + // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) + for (int age = lower_age_range.get(idx); age < val; age++) { + try { + // try function necessary as some ages won't be present in the population + // use the functions created earlier to calculate the number of people of each age group who fall + // into the categories we are interested in (alive, died from covid, died from other) + covid_death_count += age_sex_map_died_from_covid.get(sex).get(age).get(true).get(false).intValue(); + } + catch (Exception e) { + // age wasn't present in the population, skip + } + } + covid_death_by_ages.add(covid_death_count); + // update the idx variable for the next iteration + idx++; + + } + return covid_death_by_ages; + } + + // get those alive at location + private static Map>> get_alive_at_location(WorldBankCovid19Sim world) { + // create a function to group the population by who is alive at this admin zone + Map>> aliveAtLocation = world.agents.stream().collect( + Collectors.groupingBy( + Person::isAlive, + Collectors.groupingBy( + Person::getCurrentAdminZone + ) + ) + ); + return aliveAtLocation; + } + + // get those alive with COVID at location + private static Map>>> get_covid_at_location( + WorldBankCovid19Sim world) { + Map>>> covidAtLocation = world.agents.stream().collect( + Collectors.groupingBy( + Person::isAlive, + Collectors.groupingBy( + Person::getCurrentAdminZone, + Collectors.groupingBy( + Person::hasCovid + ) + ) + ) + ); + return covidAtLocation; + } + // get those who died of COVID at location + private static Map>>> get_dead_from_covid_at_location( + WorldBankCovid19Sim world) { + Map>>> covidDeathsAtLocation = world.agents.stream().collect( + Collectors.groupingBy( + Person::getCurrentAdminZone, + Collectors.groupingBy( + Person::isDeadFromCovid, + Collectors.groupingBy( + Person::getDeathLogged + ) + ) + ) + ); + return covidDeathsAtLocation; + } + // =============================== Demographic information logging ============================================================================= + // output for birthRateOutputFilename public class BirthRateReporter implements Steppable{ WorldBankCovid19Sim world; @@ -27,28 +237,14 @@ public BirthRateReporter(WorldBankCovid19Sim myWorld) { @Override public void step(SimState arg0) { Params params = world.params; - // calculate the birth rate in age groups 15-19, 10-14, ..., 45-49 - // create a list to define our age group search ranges - List upper_age_range = Arrays.asList(20, 25, 30, 35, 40, 45, 50); - List lower_age_range = Arrays.asList(15, 20, 25, 30, 35, 40, 45); + // create list to store the counts of the number of females alive in each age range and the // number of births in each age range. ArrayList female_alive_ages = new ArrayList(); ArrayList female_pregnancy_ages = new ArrayList(); // create a function to group the population by sex, age and whether they are alive - Map>> age_sex_alive_map = world.agents.stream().collect( - Collectors.groupingBy( - Person::getSex, - Collectors.groupingBy( - Person::getAge, - Collectors.groupingBy( - Person::isAlive, - Collectors.counting() - ) - ) - ) - ); - + Map>> age_sex_alive_map_copy = age_sex_alive_map(world); + // create a function to group the population by sex, age and whether they gave birth Map>>> age_sex_map_gave_birth = world.agents.stream().collect( Collectors.groupingBy( @@ -67,19 +263,18 @@ public void step(SimState arg0) { ); // We now iterate over the age ranges, create a variable to keep track of the iterations Integer idx = 0; - for (Integer val: upper_age_range) { + for (Integer val: birthrate_upper_age_range) { // for each age group we begin to count the number of people who fall into each category, create variables // to store this information in Integer female_count = 0; - Integer dev_female_count = 0; Integer female_gave_birth_count = 0; // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) - for (int age = lower_age_range.get(idx); age < val; age++) { + for (int age = birthrate_lower_age_range.get(idx); age < val; age++) { try { // try function necessary as some ages won't be present in the population // use the functions created earlier to calculate the number of people of each age group who fall // into the categories we are interested in (female, alive) - female_count += age_sex_alive_map.get(SEX.FEMALE).get(age).get(true).intValue(); + female_count += age_sex_alive_map_copy.get(SEX.FEMALE).get(age).get(true).intValue(); } catch (Exception e) { // age wasn't present in the population, skip @@ -104,10 +299,9 @@ public void step(SimState arg0) { int time = (int) (arg0.schedule.getTime() / params.ticks_per_day); String age_dependent_birth_rate = ""; - String t = "\t"; - String age_categories = t + "15_19" + t + "20_24" + t + "25_29" + t + "30_34" + t + "35_39" + t + "40_44" + t + "45_49" + "\n"; + String birth_rate_age_categories = t + "15_19" + t + "20_24" + t + "25_29" + t + "30_34" + t + "35_39" + t + "40_44" + t + "45_49" + "\n"; if (this.firstTimeReporting) { - age_dependent_birth_rate += "day" + age_categories + String.valueOf(time); + age_dependent_birth_rate += "day" + birth_rate_age_categories + String.valueOf(time); } else { age_dependent_birth_rate += String.valueOf(time); @@ -139,9 +333,197 @@ public void step(SimState arg0) { } } + + // output for populationOutputFilename + public static Steppable ReportPopStructure (WorldBankCovid19Sim world) { + // create a function to report the overall population structure + return new Steppable(){ + @Override + public void step(SimState arg0) { + // create a list to define our age group search ranges + + // create list to store the counts of the number of males and females alive in each age range in each admin zone + ArrayList male_alive_ages = new ArrayList(); + ArrayList female_alive_ages = new ArrayList(); + // create a function to group the population by sex, age and whether they are alive + Map>> age_sex_alive_map_copy = age_sex_alive_map(world); + // We now iterate over the age ranges, create a variable to keep track of the iterations + Integer idx = 0; + for (Integer val: upper_age_range) { + // for each age group we begin to count the number of people who fall into each category, create variables + // to store this information in + Integer male_count = 0; + Integer female_count = 0; + // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) + for (int age = lower_age_range.get(idx); age < val; age++) { + try { + // try function necessary as some ages won't be present in the population + // use the functions created earlier to calculate the number of people of each age group + male_count += age_sex_alive_map_copy.get(SEX.MALE).get(age).get(true).intValue(); + } + catch (Exception e) { + // age wasn't present in the population, skip + } + try { + // try function necessary as some ages won't be present in the population + // use the functions created earlier to calculate the number of people of each age group + female_count += age_sex_alive_map_copy.get(SEX.FEMALE).get(age).get(true).intValue(); + } + catch (Exception e) { + // age wasn't present in the population, skip + } + } + + // store what we have found in the lists we created + male_alive_ages.add(male_count); + female_alive_ages.add(female_count); + // update the idx variable for the next iteration + idx++; + + } + // format the output file + int time = (int) (arg0.schedule.getTime() / world.params.ticks_per_day); + String population = ""; + + String age_sex_categories = t + "sex" + t + age_categories + "\n"; + if (time == 0) { + population += "day" + age_sex_categories + String.valueOf(time); + } + else { + population += String.valueOf(time); + } + // get the number of males in each age group + population += t + "m"; + + for (int x = 0; x male_other_deaths_by_ages = new ArrayList(); + ArrayList female_other_deaths_by_ages = new ArrayList(); + ArrayList male_alive_ages = get_number_of_alive(world, SEX.MALE); + ArrayList female_alive_ages = get_number_of_alive(world, SEX.FEMALE); + + // create a function to group the population by sex, age and whether they died from something other than covid + Map>>> age_sex_map_died_from_other = world.agents.stream().collect( + Collectors.groupingBy( + Person::getSex, + Collectors.groupingBy( + Person::getAge, + Collectors.groupingBy( + Person::isDeadFromOther, + Collectors.groupingBy(Person::getDeathLogged, + Collectors.counting() + ) + ) + ) + ) + ); + // We now iterate over the age ranges, create a variable to keep track of the iterations + Integer idx = 0; + for (Integer val: upper_age_range) { + // for each age group we begin to count the number of people who fall into each category, create variables + // to store this information in + Integer male_other_death_count = 0; + Integer female_other_death_count = 0; + // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) + for (int age = lower_age_range.get(idx); age < val; age++) { + + try { + // try function necessary as some ages won't be present in the population + // use the functions created earlier to calculate the number of people of each age group who fall + // into the categories we are interested in (alive, died from covid, died from other) + male_other_death_count += age_sex_map_died_from_other.get(SEX.MALE).get(age).get(true).get(false).intValue(); + } + catch (Exception e) { + // age wasn't present in the population, skip + } + try { + // try function necessary as some ages won't be present in the population + // use the functions created earlier to calculate the number of people of each age group who fall + // into the categories we are interested in (alive, died from covid, died from other) + female_other_death_count += age_sex_map_died_from_other.get(SEX.FEMALE).get(age).get(true).get(false).intValue(); + } + catch (Exception e) { + // age wasn't present in the population, skip + } + } + + male_other_deaths_by_ages.add(male_other_death_count); + female_other_deaths_by_ages.add(female_other_death_count); + // update the idx variable for the next iteration + idx++; + } + // format log file + String other_inc_death = ""; + + if (time == 0) { + other_inc_death += "day" + age_sex_categories + String.valueOf(time); + } + else { + other_inc_death += String.valueOf(time); + } + + // calculate incidence of other death in males this day + other_inc_death += t + "m"; + for (int x = 0; x >>> location_covid_map = world.agents.stream().collect( - Collectors.groupingBy( - Person::getCurrentAdminZone, - Collectors.groupingBy( - Person::isAlive, - Collectors.groupingBy( - Person::hasCovid, - Collectors.groupingBy( - Person::covidLogCheck, - Collectors.counting() - ) - ) - ) - ) - ); + Map>>>> location_asympt_covid_map = world.agents.stream().collect( Collectors.groupingBy( Person::getCurrentAdminZone, @@ -382,7 +749,6 @@ public void step(SimState arg0) { // name the file String covidNumberOutput = ""; // format the file - String t = "\t"; String adminZoneNames = ""; for (String zone: adminZoneList) {adminZoneNames += t + zone;} if (time == 0) { @@ -448,485 +814,127 @@ public void step(SimState arg0) { // export the file - ImportExport.exportMe(world.newLoggingFilename, covidNumberOutput, world.timer); -// calculate incidence of death in each age group by cause - // covid deaths, incidence in age groups 0-1, 1-4, 5-9, 10-14, ..., 95+ - // create a list to define our age group search ranges - List upper_age_range = Arrays.asList(1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 120); - List lower_age_range = Arrays.asList(0, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95); - // create list to store the counts of the number of males and females alive in each age range, - // the number of covid deaths in each age range and the number of 'other' cause deaths in each age range - ArrayList male_alive_ages = new ArrayList(); - ArrayList male_covid_deaths_by_ages = new ArrayList(); - ArrayList male_other_deaths_by_ages = new ArrayList(); - ArrayList female_alive_ages = new ArrayList(); - ArrayList female_covid_deaths_by_ages = new ArrayList(); - ArrayList female_other_deaths_by_ages = new ArrayList(); - // create a function to group the population by sex, age and whether they are alive - Map>> age_sex_alive_map = world.agents.stream().collect( - Collectors.groupingBy( - Person::getSex, - Collectors.groupingBy( - Person::getAge, - Collectors.groupingBy( - Person::isAlive, - Collectors.counting() - ) - ) - ) - ); - // create a function to group the population by sex, age and whether they died from covid - Map>>> age_sex_map_died_from_covid = world.agents.stream().collect( - Collectors.groupingBy( - Person::getSex, - Collectors.groupingBy( - Person::getAge, - Collectors.groupingBy( - Person::isDeadFromCovid, - Collectors.groupingBy( - Person::getDeathLogged, - Collectors.counting() - ) - ) - ) - ) - ); - // create a function to group the population by sex, age and whether they died from something other than covid - Map>>> age_sex_map_died_from_other = world.agents.stream().collect( - Collectors.groupingBy( - Person::getSex, - Collectors.groupingBy( - Person::getAge, - Collectors.groupingBy( - Person::isDeadFromOther, - Collectors.groupingBy(Person::getDeathLogged, - Collectors.counting() - ) - ) - ) - ) - ); - // We now iterate over the age ranges, create a variable to keep track of the iterations - Integer idx = 0; - for (Integer val: upper_age_range) { - // for each age group we begin to count the number of people who fall into each category, create variables - // to store this information in - Integer male_count = 0; - Integer male_covid_death_count = 0; - Integer male_other_death_count = 0; - Integer female_count = 0; - Integer female_covid_death_count = 0; - Integer female_other_death_count = 0; - // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) - for (int age = lower_age_range.get(idx); age < val; age++) { - - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - male_count += age_sex_alive_map.get(SEX.MALE).get(age).get(true).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - female_count += age_sex_alive_map.get(SEX.FEMALE).get(age).get(true).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - male_covid_death_count += age_sex_map_died_from_covid.get(SEX.MALE).get(age).get(true).get(false).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - female_covid_death_count += age_sex_map_died_from_covid.get(SEX.FEMALE).get(age).get(true).get(false).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - male_other_death_count += age_sex_map_died_from_other.get(SEX.MALE).get(age).get(true).get(false).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - female_other_death_count += age_sex_map_died_from_other.get(SEX.FEMALE).get(age).get(true).get(false).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - } - - - // store what we have found in the lists we created - male_alive_ages.add(male_count); - female_alive_ages.add(female_count); - male_covid_deaths_by_ages.add(male_covid_death_count); - female_covid_deaths_by_ages.add(female_covid_death_count); - male_other_deaths_by_ages.add(male_other_death_count); - female_other_deaths_by_ages.add(female_other_death_count); - // update the idx variable for the next iteration - idx++; - } - // format log file - String covid_inc_death = ""; - String other_inc_death = ""; - - String age_sex_categories = t + "sex" + t + "<1" + t + "1_4" + t + "5_9" + t + "10_14" + t + "15_19" + t + "20_24" + - t + "25_29" + t + "30_34" + t + "35_39" + t + "40_44" + t + "45_49" + t + "50_54" + t + "55_59" + t + - "60_64" + t + "65_69" + t + "70_74" + t + "75_79" + t + "80_84" + t + "85_89" + t + "90_94" + t + "95<" + "\n"; - if (time == 0) { - covid_inc_death += "day" + age_sex_categories + String.valueOf(time); - other_inc_death += "day" + age_sex_categories + String.valueOf(time); + ImportExport.exportMe(world.casesPerAdminZoneFilename, covidNumberOutput, world.timer); } - else { - covid_inc_death += String.valueOf(time); - other_inc_death += String.valueOf(time); - } - // calculate incidence of covid death in males this day - covid_inc_death += t + "m"; - for (int x = 0; x male_covid_by_ages = new ArrayList(); - ArrayList female_covid_by_ages = new ArrayList(); - // create a function to group the population by sex, age and whether they are alive - - // create a function to group the population by sex, age and whether they have covid - Map>>> age_sex_map_has_covid = world.agents.stream().collect( - Collectors.groupingBy( - Person::getSex, - Collectors.groupingBy( - Person::getAge, - Collectors.groupingBy( - Person::hasCovid, - Collectors.groupingBy( - Person::getCovidLogged, - Collectors.counting() - ) - ) - ) - ) - ); - - // We now iterate over the age ranges, create a variable to keep track of the iterations - idx = 0; - for (Integer val: upper_age_range) { - // for each age group we begin to count the number of people who fall into each category, create variables - // to store this information in - Integer male_count = 0; - Integer male_covid_count = 0; - Integer female_count = 0; - Integer female_covid_count = 0; - // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) - for (int age = lower_age_range.get(idx); age < val; age++) { - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - male_covid_count += age_sex_map_has_covid.get(SEX.MALE).get(age).get(true).get(false).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - female_covid_count += age_sex_map_has_covid.get(SEX.FEMALE).get(age).get(true).get(false).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } + }; + } + + // output for adminZonePopSizeOutputFilename + public static Steppable ReportAdminZonePopulationSize(WorldBankCovid19Sim world) { + return new Steppable() { + @Override + public void step(SimState arg0) { + // format the output file for population counts + int time = (int) (arg0.schedule.getTime() / world.params.ticks_per_day); + List adminZones = ((WorldBankCovid19Sim)arg0).params.adminZoneNames; + Map>> aliveAtLocation = get_alive_at_location(world); + // create a list to store the number of people and who has covid in each admin zone + ArrayList adminZonePopCounts = new ArrayList(); + // iterate over each admin zone + for (String place: adminZones) { + // get population counts in each admin zone + try { + adminZonePopCounts.add(aliveAtLocation.get(true).get(place).size()); + } + catch (Exception e) { + // age wasn't present in the population, skip + adminZonePopCounts.add(0); } - male_covid_by_ages.add(male_covid_count); - female_covid_by_ages.add(female_covid_count); - // update the idx variable for the next iteration - idx++; - } - // format the output file - String covid_inc = ""; + String pop_size_in_admin_zone = ""; + if (time == 0) { - covid_inc += "day" + age_sex_categories + String.valueOf(time); + pop_size_in_admin_zone += "day" + t; + for (String place: adminZones) { + pop_size_in_admin_zone += place + t; + } + pop_size_in_admin_zone += "\n" + String.valueOf(time); } else { - covid_inc += String.valueOf(time); + pop_size_in_admin_zone += "\n" + String.valueOf(time); } - // calculate the incidence of covid in males this day - covid_inc += t + "m"; - for (int x = 0; x status_counts = new ArrayList(); - ArrayList status_covid_counts = new ArrayList(); - ArrayList status_covid_death_counts = new ArrayList(); - // create a function to group the population by sex, age and whether they are alive - - // create a function to group the population by occupation, age and whether they have covid - Map>>> economic_alive_has_covid = - world.agents.stream().collect( - Collectors.groupingBy( - Person::getEconStatus, - Collectors.groupingBy( - Person::isAlive, - Collectors.groupingBy( - Person::hasCovid, - Collectors.groupingBy( - Person::getCovidLogged, - Collectors.counting() - ) - ) - ) - ) - ); - Map> economic_alive = world.agents.stream().collect( - Collectors.groupingBy( - Person::getEconStatus, - Collectors.groupingBy( - Person::isAlive, - Collectors.counting() - - - ) - ) - ); - // create a function to group the population by sex, age and whether they died from covid - Map>> econ_died_from_covid = world.agents.stream().collect( - Collectors.groupingBy( - Person::getEconStatus, - Collectors.groupingBy( - Person::isDeadFromCovid, - Collectors.groupingBy( - Person::getDeathLogged, - Collectors.counting() - ) - ) - ) - ); - for (OCCUPATION status: economic_status) { + Map>> aliveAtLocation = get_alive_at_location(world); + // create a function to group the population by who is alive in each admin zone and has covid + Map>>> covidAtLocation = get_covid_at_location(world); + + // get a list of admin zone to iterate over + List adminZones = ((WorldBankCovid19Sim)arg0).params.adminZoneNames; + + // create a list to store the number of people and who has covid in each admin zone + ArrayList adminZonePopCounts = new ArrayList(); + ArrayList adminZoneCovidCounts = new ArrayList(); + // iterate over each admin zone + for (String place: adminZones) { + // get population counts in each admin zone try { - status_covid_counts.add(economic_alive_has_covid.get(status).get(true).get(true).get(false).intValue()); + adminZonePopCounts.add(aliveAtLocation.get(true).get(place).size()); } catch (Exception e) { - // no one in population met criteria, skip - status_covid_counts.add(0); - } - try { - status_covid_death_counts.add(econ_died_from_covid.get(status).get(true).get(false).intValue()); + // age wasn't present in the population, skip + adminZonePopCounts.add(0); } - catch (Exception e) { - // no one in population met criteria, skip - status_covid_death_counts.add(0); - } + // get covid counts in each admin zone try { - status_counts.add(economic_alive.get(status).get(true).intValue()); + adminZoneCovidCounts.add(covidAtLocation.get(true).get(place).get(true).size()); } catch (Exception e) { - // no one in population met criteria, skip - status_counts.add(0); + // age wasn't present in the population, skip + adminZoneCovidCounts.add(0); } + } - String econ_status_categories = ""; - for (OCCUPATION job: economic_status) { - econ_status_categories += job.name() + t; - } - econ_status_categories += "\n"; - String econ_status_output = ""; + // format the output file for population counts + int time = (int) (arg0.schedule.getTime() / world.params.ticks_per_day); + + // format the output for the percent of the admin zone with covid + String percent_with_covid = ""; if (time == 0) { - econ_status_output += "day" + t + "metric" + t + econ_status_categories + String.valueOf(time); + percent_with_covid += "day" + t; + for (String place: adminZones) { + percent_with_covid += place + t; + } + percent_with_covid += "\n" + String.valueOf(time); } else { - econ_status_output += String.valueOf(time); - } - econ_status_output += t + "number_in_occ"; - for (Integer count: status_counts){ - econ_status_output += t + count; - } - econ_status_output += "\n"; - // calculate the incidence of covid in females this day - econ_status_output += String.valueOf(time) + t + "number_with_covid"; - for (Integer count: status_covid_counts){ - econ_status_output += t + count; - } - econ_status_output += "\n"; - econ_status_output += String.valueOf(time) + t + "number_died_from_covid"; - for (Integer count: status_covid_death_counts){ - econ_status_output += t + count; + percent_with_covid += "\n" + String.valueOf(time); } - econ_status_output += "\n"; - - ImportExport.exportMe(world.covidByEconOutputFilename, econ_status_output, world.timer); - // to make sure deaths and cases aren't counted multiple times, update this person's properties - - for (Person p: world.agents) { - if(p.isDeadFromCovid()) { - p.confirmDeathLogged(); - } - if (p.isDeadFromOther()) p.confirmDeathLogged(); - if(p.hasCovid() & !p.covidLogCheck()) { - p.confirmCovidLogged(); - } - if(p.hasAsymptCovid() & !p.getAsymptCovidLogged()) { - p.confirmAsymptLogged(); - } - if(p.hasMild() & !p.getMildCovidLogged()) { - p.confirmMildLogged(); - } - if(p.hasSevere() & !p.getSevereCovidLogged()) { - p.confirmSevereLogged(); - } - if(p.hasCritical() & !p.getCovidLogged()) { - p.confirmCriticalLogged(); - } - } + int idx = 0; + // calculate the percentage in the admin zone with covid + for (float count: adminZoneCovidCounts) { + float perc_with_covid = count / adminZonePopCounts.get(idx); + percent_with_covid += t + perc_with_covid; + idx++; + } + // export the file + ImportExport.exportMe(world.adminZoneCovidPrevalenceOutputFilename, percent_with_covid, world.timer); } - }; + }; } - - public static Steppable UpdateAdminZoneLevelInfo(WorldBankCovid19Sim world) { + // output for adminZonePopBreakdownOutputFilename + public static Steppable ReportAdminZoneAgeSexBreakdown(WorldBankCovid19Sim world) { return new Steppable() { @Override public void step(SimState arg0) { - // create a function to group the population by who is alive at this admin zone - Map>> aliveAtLocation = world.agents.stream().collect( - Collectors.groupingBy( - Person::isAlive, - Collectors.groupingBy( - Person::getCurrentAdminZone - ) - ) - ); - // create a function to group the population by who is alive in each admin zone and has covid - Map>>> covidAtLocation = world.agents.stream().collect( - Collectors.groupingBy( - Person::isAlive, - Collectors.groupingBy( - Person::getCurrentAdminZone, - Collectors.groupingBy( - Person::hasCovid - ) - ) - ) - ); Map>>>> aliveAtLocationAgeSex = world.agents.stream().collect( Collectors.groupingBy( Person::isAlive, @@ -941,358 +949,499 @@ public void step(SimState arg0) { ) ) ); - // get list of ages to iterate over - List upper_age_range = Arrays.asList(1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 120); - List lower_age_range = Arrays.asList(0, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95); // get a list of admin zone to iterate over List adminZones = ((WorldBankCovid19Sim)arg0).params.adminZoneNames; + // format the output file for population counts + int time = (int) (arg0.schedule.getTime() / world.params.ticks_per_day); + int idx = 0; + + // export the file + String adminZoneLevelPopBreakdown = ""; + + String admin_zone_age_sex_categories = t + "admin_zone" + t + "sex" + t + age_categories + "\n"; + if (time == 0) { + adminZoneLevelPopBreakdown += "day" + admin_zone_age_sex_categories; + } + for (String place: adminZones) { + adminZoneLevelPopBreakdown += time + t + place; + // create lists to store the age gender breakdown of people in this admin zone + ArrayList male_alive_ages = new ArrayList(); + ArrayList female_alive_ages = new ArrayList(); + idx = 0; + for (Integer val: upper_age_range) { + // for each age group we begin to count the number of people who fall into each category, create variables + // to store this information in + Integer male_count = 0; + Integer female_count = 0; + for (int age = lower_age_range.get(idx); age < val; age++) { + try { + // try function necessary as some ages won't be present in the population + // use the functions created earlier to calculate the number of people of each age group who fall + // into the categories we are interested in (alive, died from covid, died from other) + male_count += aliveAtLocationAgeSex.get(true).get(place).get(age).get(SEX.MALE).size(); + } + catch (Exception e) { + // age wasn't present in the population, skip + } + try { + // try function necessary as some ages won't be present in the population + // use the functions created earlier to calculate the number of people of each age group who fall + // into the categories we are interested in (alive, died from covid, died from other) + female_count += aliveAtLocationAgeSex.get(true).get(place).get(age).get(SEX.FEMALE).size(); + } + catch (Exception e) { + // age wasn't present in the population, skip + } + } + // store what we have found in the lists we created + male_alive_ages.add(male_count); + female_alive_ages.add(female_count); + } + adminZoneLevelPopBreakdown += t + "m"; + for (int count: male_alive_ages){ + adminZoneLevelPopBreakdown += t + String.valueOf(count); + } + adminZoneLevelPopBreakdown += "\n"; + adminZoneLevelPopBreakdown += time + t + place; + adminZoneLevelPopBreakdown += t + "f"; + for (int count: female_alive_ages){ + adminZoneLevelPopBreakdown += t + String.valueOf(count); + } + adminZoneLevelPopBreakdown += "\n"; + } + ImportExport.exportMe(world.adminZonePopBreakdownOutputFilename, adminZoneLevelPopBreakdown, world.timer); + + } + }; + } + // output for adminZonePercentCovidCasesFatalOutputFilename + public static Steppable ReportPercentOfCovidCasesThatAreFatalPerAdminZone(WorldBankCovid19Sim world) { + return new Steppable() { + + @Override + public void step(SimState arg0) { + // create a function to group the population by who is alive in each admin zone and has covid + Map>>> covidAtLocation = get_covid_at_location(world); + Map>>> covidDeathsAtLocation = get_dead_from_covid_at_location( + world); + // get a list of admin zone to iterate over + List adminZones = ((WorldBankCovid19Sim)arg0).params.adminZoneNames; + // format the output file for population counts + int time = (int) (arg0.schedule.getTime() / world.params.ticks_per_day); // create a list to store the number of people and who has covid in each admin zone - ArrayList adminZonePopCounts = new ArrayList(); - ArrayList adminZoneCovidCounts = new ArrayList(); + ArrayList adminZonePercentCovidCasesFatal = new ArrayList(); // iterate over each admin zone for (String place: adminZones) { // get population counts in each admin zone try { - adminZonePopCounts.add(aliveAtLocation.get(true).get(place).size()); + // numerator = number of people at location who have died from covid, but have not had their deaths recorded + int numerator = covidDeathsAtLocation.get(place).get(true).get(false).size(); + // denominator = number of people at location who currently are alive with covid plus those at location who have died from covid but not had their deaths recorded + int denominator = covidAtLocation.get(true).get(place).get(true).size() + numerator; + adminZonePercentCovidCasesFatal.add((float) numerator / denominator); } catch (Exception e) { // age wasn't present in the population, skip - adminZonePopCounts.add(0); - } - // get covid counts in each admin zone - try { - adminZoneCovidCounts.add(covidAtLocation.get(true).get(place).get(true).size()); - } - catch (Exception e) { - // age wasn't present in the population, skip - adminZoneCovidCounts.add(0); + adminZonePercentCovidCasesFatal.add(0f); } - } - // format the output file for population counts - int time = (int) (arg0.schedule.getTime() / world.params.ticks_per_day); + // format log file + String percent_covid_death_per_admin = ""; - String pop_size_in_admin_zone = ""; - - String t = "\t"; if (time == 0) { - pop_size_in_admin_zone += "day" + t; + percent_covid_death_per_admin += "day" + t; for (String place: adminZones) { - pop_size_in_admin_zone += place + t; + percent_covid_death_per_admin += place + t; } - pop_size_in_admin_zone += "\n" + String.valueOf(time); + percent_covid_death_per_admin += "\n" + String.valueOf(time); } else { - pop_size_in_admin_zone += "\n" + String.valueOf(time); + percent_covid_death_per_admin += "\n" + String.valueOf(time); } - // store the population counts per admin zone - for (int count: adminZonePopCounts) { - pop_size_in_admin_zone += t + count; + // calculate the percentage in the admin zone with covid + for (float percent: adminZonePercentCovidCasesFatal) {; + percent_covid_death_per_admin += t + percent; } // export the file - ImportExport.exportMe(world.adminZonePopSizeOutputFilename, pop_size_in_admin_zone, world.timer); - // format the output for the percent of the admin zone with covid - String percent_with_covid = ""; + ImportExport.exportMe(world.adminZonePercentCovidCasesFatalOutputFilename, percent_covid_death_per_admin, world.timer); + } + }; + } + + // output for adminZonePercentCovidCasesFatalOutputFilename + public static Steppable adminZonePercentDiedFromCovidOutputFilename(WorldBankCovid19Sim world) { + return new Steppable() { + + @Override + public void step(SimState arg0) { + // create a function to group the population by who is alive in each admin zone and has covid + Map>> aliveAtLocation = get_alive_at_location(world); + // create a function to group the population by who died from covid at each admin zone + Map>>> covidDeathsAtLocation = get_dead_from_covid_at_location( + world); + // get a list of admin zone to iterate over + List adminZones = ((WorldBankCovid19Sim)arg0).params.adminZoneNames; + // format the output file for population counts + int time = (int) (arg0.schedule.getTime() / world.params.ticks_per_day); + // create a list to store the number of people and who has covid in each admin zone + ArrayList adminZonePercentCovidFatal = new ArrayList(); + // iterate over each admin zone + for (String place: adminZones) { + // get population counts in each admin zone + try { + // numerator = number of people at location who have died from covid, but have not had their deaths recorded + int numerator = covidDeathsAtLocation.get(place).get(true).get(false).size(); + // denominator = number of people at location who currently are alive with covid plus those at location who have died from covid but not had their deaths recorded + int denominator = aliveAtLocation.get(true).get(place).size() + numerator; + adminZonePercentCovidFatal.add((float) numerator / denominator); + } + catch (Exception e) { + // age wasn't present in the population, skip + adminZonePercentCovidFatal.add(0f); + } + } + // format log file + String percent_covid_death_per_admin = ""; + if (time == 0) { - percent_with_covid += "day" + t; + percent_covid_death_per_admin += "day" + t; for (String place: adminZones) { - percent_with_covid += place + t; + percent_covid_death_per_admin += place + t; } - percent_with_covid += "\n" + String.valueOf(time); + percent_covid_death_per_admin += "\n" + String.valueOf(time); } else { - percent_with_covid += "\n" + String.valueOf(time); + percent_covid_death_per_admin += "\n" + String.valueOf(time); } - int idx = 0; // calculate the percentage in the admin zone with covid - for (float count: adminZoneCovidCounts) { - float perc_with_covid = count / adminZonePopCounts.get(idx); - percent_with_covid += t + perc_with_covid; - idx++; + for (float percent: adminZonePercentCovidFatal) {; + percent_covid_death_per_admin += t + percent; + } + // export the file + ImportExport.exportMe(world.adminZonePercentDiedFromCovidOutputFilename, percent_covid_death_per_admin, world.timer); + } + }; + } + // =============================== Non-spatial disease logging ================================================================================ + + // output for covidIncDeathOutputFilename + public static Steppable ReportCovidIncidenceOfDeath(WorldBankCovid19Sim world) { + + return new Steppable() { + + @Override + public void step(SimState arg0) { + int time = (int) (arg0.schedule.getTime() / world.params.ticks_per_day); + + // calculate incidence of death in each age group by cause + // covid deaths, incidence in age groups 0-1, 1-4, 5-9, 10-14, ..., 95+ + // create a list to define our age group search ranges + + // create list to store the counts of the number of males and females alive in each age range, + // the number of covid deaths in each age range and the number of 'other' cause deaths in each age range + ArrayList male_covid_deaths_by_ages = get_covid_death_counts_by_age(world, SEX.MALE); + ArrayList female_covid_deaths_by_ages = get_covid_death_counts_by_age(world, SEX.FEMALE); + ArrayList male_alive_ages = get_number_of_alive(world, SEX.MALE); + ArrayList female_alive_ages = get_number_of_alive(world, SEX.FEMALE); + + // format log file + String covid_inc_death = ""; + + if (time == 0) { + covid_inc_death += "day" + age_sex_categories + String.valueOf(time); + } + else { + covid_inc_death += String.valueOf(time); + } + // calculate incidence of covid death in males this day + covid_inc_death += t + "m"; + for (int x = 0; x male_alive_ages = get_number_of_alive(world, SEX.MALE); + ArrayList female_alive_ages = get_number_of_alive(world, SEX.FEMALE); + // calculate incidence of Covid in each age group + // covid incidence in age groups 0-1, 1-4, 5-9, 10-14, ..., 95+ + // create a list to define our age group search ranges + // create list to store the counts of the number of males and females alive in each age range and + // the number of covid cases in each age range + ArrayList male_covid_by_ages = get_covid_counts_by_age(world, SEX.MALE); + ArrayList female_covid_by_ages = get_covid_counts_by_age(world, SEX.FEMALE); + // create a function to group the population by sex, age and whether they are alive + + // format the output file + String covid_inc = ""; + if (time == 0) { + covid_inc += "day" + age_sex_categories + String.valueOf(time); + } + else { + covid_inc += String.valueOf(time); + } + // calculate the incidence of covid in males this day + covid_inc += t + "m"; + for (int x = 0; x male_covid_by_ages = get_covid_counts_by_age(world, SEX.MALE); + ArrayList male_covid_deaths_by_ages = get_covid_death_counts_by_age(world, SEX.MALE); + ArrayList female_covid_by_ages = get_covid_counts_by_age(world, SEX.FEMALE); + ArrayList female_covid_deaths_by_ages = get_covid_death_counts_by_age(world, SEX.FEMALE); + + // calculate the number of counts in each age group + String covid_number_and_deaths = ""; if (time == 0) { - adminZoneLevelPopBreakdown += "day" + admin_zone_age_sex_categories; + covid_number_and_deaths += "day" + t + "metric" + age_sex_categories + String.valueOf(time); } - for (String place: adminZones) { - adminZoneLevelPopBreakdown += time + t + place; - // create lists to store the age gender breakdown of people in this admin zone - ArrayList male_alive_ages = new ArrayList(); - ArrayList female_alive_ages = new ArrayList(); - idx = 0; - for (Integer val: upper_age_range) { - // for each age group we begin to count the number of people who fall into each category, create variables - // to store this information in - Integer male_count = 0; - Integer female_count = 0; - for (int age = lower_age_range.get(idx); age < val; age++) { - - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - male_count += aliveAtLocationAgeSex.get(true).get(place).get(age).get(SEX.MALE).size(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (alive, died from covid, died from other) - female_count += aliveAtLocationAgeSex.get(true).get(place).get(age).get(SEX.FEMALE).size(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - } - // store what we have found in the lists we created - male_alive_ages.add(male_count); - female_alive_ages.add(female_count); + else { + covid_number_and_deaths += String.valueOf(time); } - adminZoneLevelPopBreakdown += t + "m"; - for (int count: male_alive_ages){ - adminZoneLevelPopBreakdown += t + String.valueOf(count); + covid_number_and_deaths += t + "cases" + t + "m"; + for (Integer count: male_covid_by_ages){ + covid_number_and_deaths += t + count; } - adminZoneLevelPopBreakdown += "\n"; - adminZoneLevelPopBreakdown += time + t + place; - adminZoneLevelPopBreakdown += t + "f"; - for (int count: female_alive_ages){ - adminZoneLevelPopBreakdown += t + String.valueOf(count); + covid_number_and_deaths += "\n"; + // calculate the incidence of covid in females this day + covid_number_and_deaths += String.valueOf(time) + t + "deaths" + t + "m"; + for (Integer count: male_covid_deaths_by_ages){ + covid_number_and_deaths += t + count; } - adminZoneLevelPopBreakdown += "\n"; + covid_number_and_deaths += "\n"; + covid_number_and_deaths += String.valueOf(time) + t + "cases" + t + "f"; + for (Integer count: female_covid_by_ages){ + covid_number_and_deaths += t + count; } - ImportExport.exportMe(world.adminZonePopBreakdownOutputFilename, adminZoneLevelPopBreakdown, world.timer); - + covid_number_and_deaths += "\n"; + // calculate the incidence of covid in females this day + covid_number_and_deaths += String.valueOf(time) + t + "deaths" + t + "f"; + for (Integer count: female_covid_deaths_by_ages){ + covid_number_and_deaths += t + count; + } + covid_number_and_deaths += "\n"; + ImportExport.exportMe(world.covidCountsOutputFilename, covid_number_and_deaths, world.timer); } }; - } - public static Steppable ReportPopStructure (WorldBankCovid19Sim world) { - // create a function to report the overall population structure - return new Steppable(){ - - @Override - public void step(SimState arg0) { - // calculate the number of people in each age group 0-1, 1-4, 5-9, 10-14, ..., 95+ - // create a list to define our age group search ranges - List upper_age_range = Arrays.asList(1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 120); - List lower_age_range = Arrays.asList(0, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95); - // create list to store the counts of the number of males and females alive in each age range in each admin zone - ArrayList male_alive_ages = new ArrayList(); - ArrayList female_alive_ages = new ArrayList(); - // create a function to group the population by sex, age and whether they are alive - Map>> age_sex_alive_map = world.agents.stream().collect( - Collectors.groupingBy( - Person::getSex, - Collectors.groupingBy( - Person::getAge, - Collectors.groupingBy( - Person::isAlive, - Collectors.counting() - ) - ) - ) - ); - - // We now iterate over the age ranges, create a variable to keep track of the iterations - Integer idx = 0; - for (Integer val: upper_age_range) { - // for each age group we begin to count the number of people who fall into each category, create variables - // to store this information in - Integer male_count = 0; - Integer female_count = 0; - // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) - for (int age = lower_age_range.get(idx); age < val; age++) { - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group - male_count += age_sex_alive_map.get(SEX.MALE).get(age).get(true).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group - female_count += age_sex_alive_map.get(SEX.FEMALE).get(age).get(true).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - } - - // store what we have found in the lists we created - male_alive_ages.add(male_count); - female_alive_ages.add(female_count); - // update the idx variable for the next iteration - idx++; - - } - // format the output file - int time = (int) (arg0.schedule.getTime() / world.params.ticks_per_day); - String population = ""; - - String t = "\t"; - String age_sex_categories = t + "sex" + t + "<1" + t + "1_4" + t + "5_9" + t + "10_14" + t + "15_19" + t + "20_24" + - t + "25_29" + t + "30_34" + t + "35_39" + t + "40_44" + t + "45_49" + t + "50_54" + t + "55_59" + t + - "60_64" + t + "65_69" + t + "70_74" + t + "75_79" + t + "80_84" + t + "85_89" + t + "90_94" + t + "95<" + "\n"; - if (time == 0) { - population += "day" + age_sex_categories + String.valueOf(time); - } - else { - population += String.valueOf(time); - } - // get the number of males in each age group - population += t + "m"; - - for (int x = 0; x upper_age_range = Arrays.asList(20, 25, 30, 35, 40, 45, 50); - List lower_age_range = Arrays.asList(15, 20, 25, 30, 35, 40, 45); - // create list to store the counts of the number of females alive in each age range and the - // number of births in each age range. - ArrayList female_alive_ages = new ArrayList(); - ArrayList female_pregnancy_ages = new ArrayList(); + OCCUPATION[] economic_status = OCCUPATION.values(); + ArrayList status_counts = new ArrayList(); + ArrayList status_covid_counts = new ArrayList(); + ArrayList status_covid_death_counts = new ArrayList(); // create a function to group the population by sex, age and whether they are alive - Map>> age_sex_alive_map = world.agents.stream().collect( + + // create a function to group the population by occupation, age and whether they have covid + Map>>> economic_alive_has_covid = + world.agents.stream().collect( Collectors.groupingBy( - Person::getSex, + Person::getEconStatus, Collectors.groupingBy( - Person::getAge, + Person::isAlive, Collectors.groupingBy( - Person::isAlive, - Collectors.counting() + Person::hasCovid, + Collectors.groupingBy( + Person::getCovidLogged, + Collectors.counting() ) ) ) + ) ); - // create a function to group the population by sex, age and whether they gave birth - Map>>> age_sex_map_gave_birth = world.agents.stream().collect( + Map> economic_alive = world.agents.stream().collect( Collectors.groupingBy( - Person::getSex, + Person::getEconStatus, Collectors.groupingBy( - Person::getAge, - Collectors.groupingBy( - Person::gaveBirthLastYear, - Collectors.groupingBy( - Person::getBirthLogged, + Person::isAlive, Collectors.counting() + + + ) + ) + ); + // create a function to group the population by sex, age and whether they died from covid + Map>> econ_died_from_covid = world.agents.stream().collect( + Collectors.groupingBy( + Person::getEconStatus, + Collectors.groupingBy( + Person::isDeadFromCovid, + Collectors.groupingBy( + Person::getDeathLogged, + Collectors.counting() ) ) ) - ) ); - - // We now iterate over the age ranges, create a variable to keep track of the iterations - Integer idx = 0; - for (Integer val: upper_age_range) { - // for each age group we begin to count the number of people who fall into each category, create variables - // to store this information in - Integer female_count = 0; - Integer female_gave_birth_count = 0; - // iterate over the ages set in the age ranges (lower value from lower_age_range, upper from upper_age_range) - for (int age = lower_age_range.get(idx); age < val; age++) { - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (female, alive) - female_count += age_sex_alive_map.get(SEX.FEMALE).get(age).get(true).intValue(); - } - catch (Exception e) { - // age wasn't present in the population, skip - } - try { - // try function necessary as some ages won't be present in the population - // use the functions created earlier to calculate the number of people of each age group who fall - // into the categories we are interested in (female, alive and gave birth) - female_gave_birth_count += age_sex_map_gave_birth.get(SEX.FEMALE).get(age).get(true).get(false).intValue(); + for (OCCUPATION status: economic_status) { + try { + status_covid_counts.add(economic_alive_has_covid.get(status).get(true).get(true).get(false).intValue()); + } + catch (Exception e) { + // no one in population met criteria, skip + status_covid_counts.add(0); + } + try { + status_covid_death_counts.add(econ_died_from_covid.get(status).get(true).get(false).intValue()); } - catch (Exception e) { - // age wasn't present in the population, skip - } + catch (Exception e) { + // no one in population met criteria, skip + status_covid_death_counts.add(0); + } + try { + status_counts.add(economic_alive.get(status).get(true).intValue()); + } + catch (Exception e) { + // no one in population met criteria, skip + status_counts.add(0); } - // store what we have found in the lists we created - female_alive_ages.add(female_count); - female_pregnancy_ages.add(female_gave_birth_count); - // update the idx variable for the next iteration - idx++; } - // calculate the birth rate per 1000 this day - int time = (int) (arg0.schedule.getTime() / params.ticks_per_day); - String age_dependent_birth_rate = ""; - - String t = "\t"; - String age_categories = t + "15_19" + t + "20_24" + t + "25_29" + t + "30_34" + t + "35_39" + t + "40_44" + t + "45_49" + "\n"; + String econ_status_categories = ""; + for (OCCUPATION job: economic_status) { + econ_status_categories += job.name() + t; + } + econ_status_categories += "\n"; + String econ_status_output = ""; if (time == 0) { - age_dependent_birth_rate += "day" + age_categories + String.valueOf(time); + econ_status_output += "day" + t + "metric" + t + econ_status_categories + String.valueOf(time); } else { - age_dependent_birth_rate += String.valueOf(time); + econ_status_output += String.valueOf(time); } - age_dependent_birth_rate += t; - for (int x = 0; x testingAgeDist = new ArrayList (); @@ -75,19 +78,21 @@ public WorldBankCovid19Sim(long seed, Params params, String outputFilename) { super(seed); this.params = params; this.outputFilename = outputFilename + ".txt"; - this.covidIncOutputFilename = outputFilename + "_Incidence_Of_Covid_" + ".txt"; - this.populationOutputFilename = outputFilename + "_Overall_Demographics_" + ".txt"; - this.covidIncDeathOutputFilename = outputFilename + "_Incidence_Of_Covid_Death_" + ".txt"; - this.otherIncDeathOutputFilename = outputFilename + "_Incidence_Of_Other_Death_" + ".txt"; - this.birthRateOutputFilename = outputFilename + "_Birth_Rate_" + ".txt"; - this.adminZonePopSizeOutputFilename = outputFilename + "_Admin_Zone_Level_Population_Size_" + ".txt"; - this.newLoggingFilename = outputFilename + "_Cases_Per_Admin_Zone_" + ".txt"; - this.infections_export_filename = outputFilename + "_Infections_" + ".txt"; - this.adminZoneCovidPrevalenceOutputFilename = outputFilename + "_Percent_In_Admin_Zone_With_Covid_" + ".txt"; - this.adminZonePopBreakdownOutputFilename = outputFilename + "_Overall_Demographics_" + ".txt"; - this.sim_info_filename = outputFilename + "_Sim_Information_" + ".txt"; - this.covidCountsOutputFilename = outputFilename + "_Age_Gender_Demographics_Covid_" + ".txt"; - this.covidByEconOutputFilename = outputFilename + "_Economic_Status_Covid_.txt"; + this.covidIncOutputFilename = outputFilename + "_Incidence_Of_Covid.txt"; + this.populationOutputFilename = outputFilename + "_Overall_Demographics.txt"; + this.covidIncDeathOutputFilename = outputFilename + "_Incidence_Of_Covid_Death.txt"; + this.otherIncDeathOutputFilename = outputFilename + "_Incidence_Of_Other_Death.txt"; + this.birthRateOutputFilename = outputFilename + "_Birth_Rate.txt"; + this.adminZonePopSizeOutputFilename = outputFilename + "_Admin_Zone_Level_Population_Size.txt"; + this.casesPerAdminZoneFilename = outputFilename + "_Cases_Per_Admin_Zone.txt"; + this.infections_export_filename = outputFilename + "_Infections.txt"; + this.adminZoneCovidPrevalenceOutputFilename = outputFilename + "_Percent_In_Admin_Zone_With_Covid.txt"; + this.adminZonePopBreakdownOutputFilename = outputFilename + "_Admin_Zone_level_Demographics.txt"; + this.sim_info_filename = outputFilename + "_Sim_Information.txt"; + this.covidCountsOutputFilename = outputFilename + "_Age_Gender_Demographics_Covid.txt"; + this.covidByEconOutputFilename = outputFilename + "_Economic_Status_Covid.txt"; + this.adminZonePercentDiedFromCovidOutputFilename = outputFilename + "_Percent_In_Admin_Zone_Died_From_Covid.txt"; + this.adminZonePercentCovidCasesFatalOutputFilename = outputFilename + "_Percent_Covid_Cases_Fatal_In_Admin_Zone.txt"; } public void start(){ @@ -184,7 +189,7 @@ public void step(SimState arg0) { }; schedule.scheduleRepeating(0, this.param_schedule_updating_locations, updateLocationLists); - + // =============================== Schedule demography events if using ============================================================ if (this.params.demography) { Demography myDemography = new Demography(); for(Person a: agents) { @@ -202,21 +207,48 @@ public void step(SimState arg0) { } Logging logger = new Logging(); Logging.BirthRateReporter birthRateLog = logger.new BirthRateReporter(this); + // schedule the birth rate reporter (birthRateOutputFilename) schedule.scheduleOnce(params.ticks_per_year, this.param_schedule_reporting, birthRateLog); - - + // schedule the 'other deaths' reporter (otherIncDeathOutputFilename) + schedule.scheduleRepeating(Logging.ReportOtherIncidenceOfDeath(this), this.param_schedule_reporting, params.ticks_per_day); } - - // This function tracks the epidemic over time - schedule.scheduleRepeating(Logging.TestLoggingCase(this), this.param_schedule_reporting, params.ticks_per_day); + // =============================== Schedule core logging events ================================================================== + // Report on the age sex breakdown of the population (populationOutputFilename) + schedule.scheduleRepeating(Logging.ReportPopStructure(this), this.param_schedule_reporting, params.ticks_per_day); - // Create a function to keep track of the population and epidemic at the scale of admin zone level - schedule.scheduleRepeating(Logging.UpdateAdminZoneLevelInfo(this), this.param_schedule_reporting, params.ticks_per_day); + // Report on the number of cases by type and their location (casesPerAdminZoneFilename) + schedule.scheduleRepeating(Logging.ReportCovidCasesByTypeAndLocation(this), this.param_schedule_reporting, params.ticks_per_day); - schedule.scheduleRepeating(Logging.ReportPopStructure(this), this.param_schedule_reporting, params.ticks_per_day); + // Report on the breakdown of population size by space (adminZonePopSizeOutputFilename) + schedule.scheduleRepeating(Logging.ReportAdminZonePopulationSize(this), this.param_schedule_reporting, params.ticks_per_day); + + // Report on the percent of the population with COVID by space (adminZoneCovidPrevalenceOutputFilename) + schedule.scheduleRepeating(Logging.ReportPercentInAdminZoneWithCovid(this), this.param_schedule_reporting, params.ticks_per_day); + // Report on the age-sex structure of each admin zone (adminZonePopBreakdownOutputFilename) + schedule.scheduleRepeating(Logging.ReportAdminZoneAgeSexBreakdown(this), this.param_schedule_reporting, params.ticks_per_day); + // Report on the incidence of COVID death (covidIncDeathOutputFilename) + schedule.scheduleRepeating(Logging.ReportCovidIncidenceOfDeath(this), this.param_schedule_reporting, params.ticks_per_day); + // Report on the incidence of COVID (covidIncOutputFilename) + schedule.scheduleRepeating(Logging.ReportIncidenceOfCovid(this), this.param_schedule_reporting, params.ticks_per_day); + + // Report on the number of COVID counts in each area (covidCountsOutputFilename) + schedule.scheduleRepeating(Logging.ReportCovidCounts(this), this.param_schedule_reporting, params.ticks_per_day); + + // Report on the number of COVID counts in each occupation (covidByEconOutputFilename) + schedule.scheduleRepeating(Logging.ReportCovidCountsByOccupation(this), this.param_schedule_reporting, params.ticks_per_day); + + // Report on the percent of COVID cases that are fatal per admin zone (adminZonePercentCovidCasesFatalOutputFilename) + schedule.scheduleRepeating(Logging.ReportPercentOfCovidCasesThatAreFatalPerAdminZone(this), this.param_schedule_reporting, params.ticks_per_day); + + // Report on the prevalence of COVID death per admin zone (adminZonePercentDiedFromCovidOutputFilename) + schedule.scheduleRepeating(Logging.adminZonePercentDiedFromCovidOutputFilename(this), this.param_schedule_reporting, params.ticks_per_day); + + // Schedule the resetting of COVID reporting properties in the agents + schedule.scheduleRepeating(Logging.ResetLoggedProperties(this), this.param_schedule_reporting_reset, params.ticks_per_day); + // SCHEDULE LOCKDOWNS Steppable lockdownTrigger = new Steppable() { @@ -396,7 +428,7 @@ public static void main(String [] args){ int numDays = 7; // by default, one week double myBeta = .016; long seed = 12345; - String outputFilename = "dailyReport_" + myBeta + "_" + numDays + "_" + seed + ".txt"; + String outputFilename = "dailyReport_" + myBeta + "_" + numDays + "_" + seed; String infectionsOutputFilename = "infections_" + myBeta + "_" + numDays + "_" + seed + ".txt"; String paramsFilename = "src/main/resources/params.txt"; // read in any extra settings from the command line