9  Person Properties Plugin

The person properties plugin manages the assignment of properties to individual people. As such, it is dependent on the people plugin. It also depends on the regions plugin for reports. Property definitions apply to every person in the simulation and are generally added to the person properties plugin data. However, person property definitions can be added dynamically and thus other plugins can contribute person property definitions directly rather than as inputs to the person properties plugin data.

9.1 Plugin Data Initialization

The plugin is initialized using a PersonPropertiesPluginData object that collects person property definitions and person property value assignments for the initial population.

9.2 Plugin Behavior

The plugin adds a single data manager to the simulation as an instance of the PersonPropertiesDataManager that is initialized with the PersonPropertiesPluginData.

9.3 Data Manager

The data manager manages person properties and stores their property values in a memory dense fashion that is transparent to the modeler. The data manager provides public methods that:

  • Define person properties
  • Set person property values
  • Answer various questions about:
    • The value of a person property for particular people
    • The people associated with a particular property value
    • The existence and value of property definitions

The data manager also produces observable events:

  • PersonPropertyUpdateEvent – when a person is assigned a person property value
  • PersonPropertyDefintionEvent – when a new person property is defined

9.4 Example Code (Lesson 16)

Example_16.java shows the use of the person properties plugin. In it we will examine

  • The initialization of the person properties plugin
  • The assignment of values to individuals
  • The dynamic definition of person properties

The example includes six plugins:

  • People plugin – (GCM core plugin) used to manage people
  • Person properties plugin– (GCM core plugin) used to decorate properties onto people
  • Global properties plugin– (GCM core plugin) used to store policies and initial conditions affecting vaccination
  • Stochastics plugin – (GCM core plugin) used to generate random numbers used in various decisions
  • Regions Plugin – (GCM core plugin) used to represent regions
  • Model plugin – (local plugin) used to introduce three actors that will:
    • Load the population
    • Vaccinate people
    • Educate people on the vaccine

The example’s main method starts in Code Block 9.1 by creating an instance of the example class rather than building the experiment directly since this example is somewhat more complex than previous examples. The population starts out being unvaccinated and some proportion of people initially refuse the vaccine. Attempts to both vaccinate and educate people are ongoing until a person is vaccinated. This will demonstrate the planning capability as well. If education is successful, the person is immediately vaccinated, demonstrating the cancellation of planning. At some point in the timeline, immunity will become discoverable during vaccine attempts and immune people will no longer pursue vaccination. The simulation is terminated at one year and output reports are then generated.

Code Block 9.1: Executing example 16 with an output directory.
public static void main(String[] args) throws IOException {
    if (args.length == 0) {
        throw new RuntimeException("One output directory argument is required");
    }
    Path outputPath = Paths.get(args[0]);
    if (!Files.exists(outputPath)) {
        Files.createDirectory(outputPath);
    } else {
        if (!Files.isDirectory(outputPath)) {
            throw new IOException("Provided path is not a directory");
        }
    }
    new Example_16(outputPath).execute();
}

The execution method first gathers together the six plugins in Code Block 9.2:

Code Block 9.2: The various plugins are gathered from their initial data.
private void execute() {

    /*
         * Create the global properties plugin
         */
    Plugin globalPropertiesPlugin = getGlobalPropertiesPlugin();

    /*
         * Create the reports
         */

    NIOReportItemHandler nioReportItemHandler = getNIOReportItemHandler();

    /*
         * Create the people plugin filled with 1000 people
         */
    Plugin peoplePlugin = getPeoplePlugin();

    /*
         * Create the region plugin 5 regions, each having a lat and lon and assign the
         * people to random regions.
         * 
         */
    Plugin regionsPlugin = getRegionsPlugin();

    // Create the person properties plugin
    Plugin personPropertiesPlugin = getPersonPropertiesPlugin();

    /*
         * create the stochastics plugin
         */
    Plugin stochasticsPlugin = getStochasticsPlugin();

    Plugin modelPlugin = ModelPlugin.getModelPlugin();

The first action is to generate the global properties plugin, (Code Block 9.3). All of the global properties are marked as immutable since they will not change over the course of the simulation:

  • VACCINE_ATTEMPT_INTERVAL – The maximum time between attempts to vaccinate an unvaccinated person. Specific intervals are chosen using a uniform random time between zero and the maximum.
  • EDUCATION_ATTEMPT_INTERVAL – The maximum time between attempts to educate an unvaccinated person who is currently refusing vaccination. Specific intervals are chosen using a uniform random time between zero and the maximum.
  • VACCINE_REFUSAL_PROPBABILTY – The initial probability that a person will refuse vaccination. Used to initialize the person property REFUSES_VACCINE.
  • EDUCATION_SUCCESS_RATE – The probability that an attempt to educate a person to accept vaccination will succeed.
  • IMMUNITY_START_TIME – The time when immunity is detectable in people. Used to halt attempts at vaccination and to demonstrate the dynamic addition of the person property IS_IMMUNE.
  • IMMUNITY_PROBABILITY – The probability that a person will be immune when the IS_IMMUNE person property is added.
  • POPULATION_SIZE – The number of people in the simulation.
  • SIMULATION_DURATION – The maximum time (in days) that the simulation will execute.
Code Block 9.3: The global properties plugin is initialized with several properties.
private Plugin getGlobalPropertiesPlugin() {
    GlobalPropertiesPluginData.Builder builder = GlobalPropertiesPluginData.builder();//

    PropertyDefinition propertyDefinition = PropertyDefinition.builder()//
            .setType(Double.class)//
            .setDefaultValue(0.0)//
            .setPropertyValueMutability(false)//
            .build();

    builder.defineGlobalProperty(GlobalProperty.IMMUNITY_START_TIME, propertyDefinition, 0);
    builder.defineGlobalProperty(GlobalProperty.VACCINE_ATTEMPT_INTERVAL, propertyDefinition, 0);
    builder.defineGlobalProperty(GlobalProperty.EDUCATION_ATTEMPT_INTERVAL, propertyDefinition, 0);
    builder.defineGlobalProperty(GlobalProperty.EDUCATION_SUCCESS_RATE, propertyDefinition, 0);
    builder.defineGlobalProperty(GlobalProperty.VACCINE_REFUSAL_PROBABILITY, propertyDefinition, 0);
    builder.defineGlobalProperty(GlobalProperty.IMMUNITY_PROBABILITY, propertyDefinition, 0);

    propertyDefinition = PropertyDefinition.builder()//
            .setType(Double.class)//
            .setDefaultValue(365.0)//
            .setPropertyValueMutability(false)//
            .build();
    builder.defineGlobalProperty(GlobalProperty.SIMULATION_DURATION, propertyDefinition, 0);

    propertyDefinition = PropertyDefinition.builder()//
            .setType(Integer.class)//
            .setDefaultValue(1000)//
            .setPropertyValueMutability(false)//
            .build();

    builder.defineGlobalProperty(GlobalProperty.POPULATION_SIZE, propertyDefinition, 0);

    GlobalPropertiesPluginData globalPropertiesPluginData = builder.build();

    return GlobalPropertiesPlugin.builder().setGlobalPropertiesPluginData(globalPropertiesPluginData)
            .getGlobalPropertiesPlugin();

}

The execution method then loads reports (Code Block 9.4). The person property report will be quite large and is set to only show the state of each person at the end of the simulation for brevity. The vaccine report will show the state of vaccination and immunity at the end of the simulation to allow for analysis of the experiment.

The people plugin is created without any initial people since that will be handled by one of the model plugin’s actors. The regions plugin is initialized with five regions and only plays a role in the person property report.

The person properties plugin is generated in Code Block 9.4. All of the person properties are mutable since they will change over the course of the simulation:

  • EDUCATION_ATTEMPTS – The number of attempts to change a person’s vaccine refusal.
  • VACCINE_ATTEMPTS – The number of attempts to vaccinate a person.
  • REFUSES_VACCINE – Boolean indicating whether the person will refuse vaccination attempts. Note that there is no default value and that new people must have this property set as part of the addition of the person to the simulation.
  • VACCINATED – Boolean indicating that a person has been vaccinated. People all start out with no vaccination and receive at most one vaccination.

Note that the final person property, IS_IMMUNE, is not added at the beginning of the simulation as a demonstration of the dynamic addition of person properties.

Code Block 9.4: The person properties plugin is built with the four person properties needed to model each person. The person property report is set to report only at the end of the simulation.
private Plugin getPersonPropertiesPlugin() {
    PersonPropertiesPluginData.Builder builder = PersonPropertiesPluginData.builder();
    PropertyDefinition propertyDefinition = PropertyDefinition.builder()//
            .setType(Integer.class)//
            .setDefaultValue(0)//
            .build();
    builder.definePersonProperty(PersonProperty.EDUCATION_ATTEMPTS, propertyDefinition, 0, false);
    builder.definePersonProperty(PersonProperty.VACCINE_ATTEMPTS, propertyDefinition, 0, false);

    propertyDefinition = PropertyDefinition.builder()//
            .setType(Boolean.class)//
            .build();
    builder.definePersonProperty(PersonProperty.REFUSES_VACCINE, propertyDefinition, 0, false);

    propertyDefinition = PropertyDefinition.builder()//
            .setType(Boolean.class)//
            .setDefaultValue(false)//
            .build();
    builder.definePersonProperty(PersonProperty.VACCINATED, propertyDefinition, 0, false);

    PersonPropertiesPluginData personPropertiesPluginData = builder.build();

    PersonPropertyReportPluginData personPropertyReportPluginData = PersonPropertyReportPluginData.builder()//
            .setReportLabel(ModelReportLabel.PERSON_PROPERTY_REPORT)//
            .setReportPeriod(ReportPeriod.END_OF_SIMULATION)//
            .setDefaultInclusion(true)//
            .build();//

    return PersonPropertiesPlugin.builder()//
            .setPersonPropertiesPluginData(personPropertiesPluginData)//
            .setPersonPropertyReportPluginData(personPropertyReportPluginData)//
            .getPersonPropertyPlugin();
}

Adding the stochastics plugin involves setting only the seed that will be used in every simulation instance. It will not play a role in defining the experiment space since that will be quite large already with various global property variants. Finally, the execution method generates the model plugin which in turn adds three actors:

  • Vaccinator – vaccinates people at random times
  • Vaccine Educator – seeks to get people to accept vaccination
  • Population Loader – initializes the population

The execute method finishes (Code Block 9.5) by constructing and executing the experiment.

Code Block 9.5: The experiment executes 810 scenarios on 8 threads.
        ExperimentParameterData experimentParameterData = ExperimentParameterData.builder()//
                .setThreadCount(8)//
                .build();

        Experiment.builder()//

                .addPlugin(personPropertiesPlugin)//
                .addPlugin(globalPropertiesPlugin)//
                .addPlugin(modelPlugin)//
                .addPlugin(regionsPlugin)//
                .addPlugin(peoplePlugin)//
                .addPlugin(stochasticsPlugin)//

                .addDimension(getImmunityStartTimeDimension())//
                .addDimension(getImmunityProbabilityDimension())//
                .addDimension(getVaccineAttemptIntervalDimension())//
                .addDimension(getEducationAttemptIntervalDimension())//
                .addDimension(getEducationSuccessRatedimension())//
                .addDimension(getVaccineRefusalProbabilityDimension())//
                .addExperimentContextConsumer(nioReportItemHandler)//
                .setExperimentParameterData(experimentParameterData)//
                .build()//
                .execute();//

Five dimensions are added to the experiment that define alternate values for five of the global properties resulting in 810 scenarios. These values are:

  • Immunity start time – 120 and 180 days
  • Immunity probability – 0, 10 and 20 percent
  • Vaccine attempt interval – 30, 45 and 60 days
  • Education attempt interval – 30, 60 and 180 days
  • Education success rate – 0, 10 and 20 percent
  • Initial vaccine refusal – 0, 25, 50, 75 and 100 percent

9.5 The actors

We will finish this chapter by reviewing the three actors of the model plugin and then examining the vaccine report.

The PopulationLoader actor, in Code Block 9.6, adds people to the simulation based on the number in the POPULATION_SIZE global property. Each person is assigned a random region and the person property, REFUSES_VACCINE, is randomly assigned based on the global property VACCINE_REFUSAL_PROBABILITY.

Code Block 9.6: The population loader initializes by creating people dictated by the POPULATION_SIZE global property. Each person is assigned a region and random value for the person property, REFUSES_VACCINE, based on the global property, VACCINE_REFUSAL_PROBABILITY.
public void init(ActorContext actorContext) {
    peopleDataManager = actorContext.getDataManager(PeopleDataManager.class);
    personPropertiesDataManager = actorContext.getDataManager(PersonPropertiesDataManager.class);
    globalPropertiesDataManager = actorContext.getDataManager(GlobalPropertiesDataManager.class);
    RegionsDataManager regionsDataManager = actorContext.getDataManager(RegionsDataManager.class);
    StochasticsDataManager stochasticsDataManager = actorContext.getDataManager(StochasticsDataManager.class);
    randomGenerator = stochasticsDataManager.getRandomGenerator();
    List<RegionId> regionIds = new ArrayList<>(regionsDataManager.getRegionIds());

    int populationSize = globalPropertiesDataManager.getGlobalPropertyValue(GlobalProperty.POPULATION_SIZE);
    double refusalProbability = globalPropertiesDataManager
            .getGlobalPropertyValue(GlobalProperty.VACCINE_REFUSAL_PROBABILITY);

    Builder personConstructionDataBuilder = PersonConstructionData.builder();
    for (int i = 0; i < populationSize; i++) {
        RegionId regionId = regionIds.get(randomGenerator.nextInt(regionIds.size()));
        personConstructionDataBuilder.add(regionId);

        boolean refusesVaccine = randomGenerator.nextDouble() < refusalProbability;
        PersonPropertyValueInitialization personPropertyInitialization = new PersonPropertyValueInitialization(
                PersonProperty.REFUSES_VACCINE, refusesVaccine);
        personConstructionDataBuilder.add(personPropertyInitialization);
        PersonConstructionData personConstructionData = personConstructionDataBuilder.build();
        peopleDataManager.addPerson(personConstructionData);
    }

    double simulationDuration = globalPropertiesDataManager
            .getGlobalPropertyValue(GlobalProperty.SIMULATION_DURATION);
    actorContext.addPlan((c) -> c.halt(), simulationDuration);

    double immunityStartTime = globalPropertiesDataManager
            .getGlobalPropertyValue(GlobalProperty.IMMUNITY_START_TIME);
    actorContext.addPlan((c) -> addImmunityProperty(), immunityStartTime);
}

The actor finishes its initialization by scheduling a time to halt the simulation based on the global property, SIMULATION_DURATION. It also schedules the addition of the person property, IS_IMMUNE, based on the global property, IMMUNITY_START_TIME. Code Block 9.7 shows the details of this dynamic definition.

Code Block 9.7: At the time set via the global property, IMMUNITY_START_TIME, the population loader defines the person property, IS_IMMUNE, and sets the property value for each person.
private void addImmunityProperty() {
    PersonPropertyDefinitionInitialization.Builder builder = PersonPropertyDefinitionInitialization.builder();
    builder.setPersonPropertyId(PersonProperty.IS_IMMUNE);
    PropertyDefinition propertyDefinition = PropertyDefinition.builder().setType(Boolean.class).build();
    builder.setPropertyDefinition(propertyDefinition);
    double immunityProbability = globalPropertiesDataManager
            .getGlobalPropertyValue(GlobalProperty.IMMUNITY_PROBABILITY);

    for (PersonId personId : peopleDataManager.getPeople()) {
        boolean isImmune = randomGenerator.nextDouble() < immunityProbability;
        builder.addPropertyValue(personId, isImmune);
    }
    PersonPropertyDefinitionInitialization personPropertyDefinitionInitialization = builder.build();
    personPropertiesDataManager.definePersonProperty(personPropertyDefinitionInitialization);
}

The vaccine educator (Code Block 9.8) attempts to change unvaccinated people who refuse vaccination to vaccine acceptance. It initializes by planning an educational attempt for each person in the existing population who has not been vaccinated and who will refuse vaccination. It also subscribes to the addition of people so that it might plan education for newly added people.

Code Block 9.8: The vaccine educator initializes by planning the education for each person who refuses vaccination.
public void init(ActorContext actorContext) {
    this.actorContext = actorContext;

    StochasticsDataManager stochasticsDataManager = actorContext.getDataManager(StochasticsDataManager.class);
    randomGenerator = stochasticsDataManager.getRandomGenerator();
    PeopleDataManager peopleDataManager = actorContext.getDataManager(PeopleDataManager.class);
    personPropertiesDataManager = actorContext.getDataManager(PersonPropertiesDataManager.class);
    globalPropertiesDataManager = actorContext.getDataManager(GlobalPropertiesDataManager.class);

    educationAttemptInterval = globalPropertiesDataManager
            .getGlobalPropertyValue(GlobalProperty.EDUCATION_ATTEMPT_INTERVAL);
    educationSuccessRate = globalPropertiesDataManager
            .getGlobalPropertyValue(GlobalProperty.EDUCATION_SUCCESS_RATE);

    List<PersonId> unvaccinatedPeople = personPropertiesDataManager
            .getPeopleWithPropertyValue(PersonProperty.VACCINATED, false);
    for (PersonId personId : unvaccinatedPeople) {
        Boolean refusesVaccine = personPropertiesDataManager.getPersonPropertyValue(personId,
                PersonProperty.REFUSES_VACCINE);
        if (refusesVaccine) {
            planEducation(personId);
        }
    }

    actorContext.subscribe(peopleDataManager.getEventFilterForPersonAdditionEvent(), (c, e) -> {
        handleNewPerson(e.personId());
    });
}

The education of a person (Code Block 9.9) is accomplished with planning that schedules the education at a random time between the current time and a globally defined attempt interval.

Code Block 9.9: Attempts to educate a person on vaccination are scheduled at random times in the future based on the global property, EDUCATION_ATTEMPT_INTERVAL.
private void planEducation(PersonId personId) {
    double planTime = actorContext.getTime() + randomGenerator.nextDouble() * educationAttemptInterval;
    Consumer<ActorContext> plan = (c) -> educatePerson(personId);
    actorContext.addPlan(plan, planTime);
}

private void handleNewPerson(PersonId personId) {
    boolean vaccinated = personPropertiesDataManager.getPersonPropertyValue(personId, PersonProperty.VACCINATED);
    if (!vaccinated) {
        Boolean refusesVaccine = personPropertiesDataManager.getPersonPropertyValue(personId,
                PersonProperty.REFUSES_VACCINE);
        if (refusesVaccine) {
            planEducation(personId);
        }
    }
}

The education attempt sets the vaccine refusal to false on a random draw based on the EDUCATION_SUCCESS_RATE global variable in Code Block 9.10.

Code Block 9.10: After updating the number of educational attempts for a person, the vaccine educator succeeds in educating the person to stop refusing vaccination based on the global property, EDUCATION_SUCCESS_RATE.
private void educatePerson(PersonId personId) {
    int educationAttempts = personPropertiesDataManager.getPersonPropertyValue(personId,
            PersonProperty.EDUCATION_ATTEMPTS);
    personPropertiesDataManager.setPersonPropertyValue(personId, PersonProperty.EDUCATION_ATTEMPTS,
            educationAttempts + 1);

    if (randomGenerator.nextDouble() < educationSuccessRate) {
        personPropertiesDataManager.setPersonPropertyValue(personId, PersonProperty.REFUSES_VACCINE, false);
    } else {
        planEducation(personId);
    }
}

The Vaccinator (Code Block 9.11) tries to vaccinate the population. It initializes by planning a vaccination attempt for each person in the existing population who has not yet been vaccinated. It subscribes to the addition of people so that it might plan vaccination for newly added people. It also subscribes to changes to the VACCINE_REFUSAL person property so that it can immediately attempt vaccination.

Code Block 9.11: The vaccinator initializes by planning vaccination attempts for each person who is unvaccinated. It also subscribes to changes in the vaccine refusal property for all people so that when a person stops refusing vaccine, they can be vaccinated immediately.
public void init(ActorContext actorContext) {
    this.actorContext = actorContext;
    StochasticsDataManager stochasticsDataManager = actorContext.getDataManager(StochasticsDataManager.class);
    randomGenerator = stochasticsDataManager.getRandomGenerator();
    peopleDataManager = actorContext.getDataManager(PeopleDataManager.class);
    personPropertiesDataManager = actorContext.getDataManager(PersonPropertiesDataManager.class);
    globalPropertiesDataManager = actorContext.getDataManager(GlobalPropertiesDataManager.class);

    List<PersonId> unvaccinatedPeople = personPropertiesDataManager
            .getPeopleWithPropertyValue(PersonProperty.VACCINATED, false);
    vaccineAttemptInterval = globalPropertiesDataManager
            .getGlobalPropertyValue(GlobalProperty.VACCINE_ATTEMPT_INTERVAL);
    for (PersonId personId : unvaccinatedPeople) {
        planVaccination(personId);
    }

    EventFilter<PersonPropertyUpdateEvent> eventFilter = personPropertiesDataManager//
            .getEventFilterForPersonPropertyUpdateEvent(PersonProperty.REFUSES_VACCINE);

    actorContext.subscribe(eventFilter, this::handleVaccineAcceptance);

    actorContext.subscribe(peopleDataManager.getEventFilterForPersonAdditionEvent(), (c, e) -> {
        handleNewPerson(e.personId());
    });

}

Vaccination of a person (Code Block 9.12) is accomplished with planning that schedules the vaccination at a random time between the current time and a globally defined attempt interval.

Code Block 9.12: Each unvaccinated person has a planned vaccination based on the VACCINE_ATTEMPT_INTERVAL global property.
private void planVaccination(PersonId personId) {
    double planTime = actorContext.getTime() + randomGenerator.nextDouble() * vaccineAttemptInterval;       
    ActorPlan plan = new ConsumerActorPlan(planTime, (c) -> vaccinatePerson(personId));             
    actorContext.addPlan(plan);
    //record the plan for possible cancellation
    actorPlans.put(personId, plan);
}

private void handleNewPerson(PersonId personId) {
    boolean vaccinated = personPropertiesDataManager.getPersonPropertyValue(personId, PersonProperty.VACCINATED);
    if (!vaccinated) {
        planVaccination(personId);
    }
}

Note that the plan uses a key value set to the person id. This is used when reacting to a person changing from refusal of the vaccine to acceptance. Instead of waiting for the next vaccine attempt (Code Block 9.13), the current plan to vaccinate is removed and the person is immediately vaccinated.

Code Block 9.13: When a person stops refusing vaccination, the vaccinator immediately attempts the vaccination of that person.
private void handleVaccineAcceptance(ActorContext actorContext,
        PersonPropertyUpdateEvent personPropertyUpdateEvent) {
    /*
         * We know that the person property is PersonProperty.REFUSES_VACCINE since we
         * used an event filter when subscribing
         */
    Boolean refusesVaccine = personPropertyUpdateEvent.getCurrentPropertyValue();
    if (!refusesVaccine) {
        PersonId personId = personPropertyUpdateEvent.personId();
        // drop the current plan
        ActorPlan actorPlan = actorPlans.remove(personId);
        if(actorPlan != null) {
            actorPlan.cancelPlan();             
        }           
        vaccinatePerson(personId);
    }
}

The vaccination attempt (Code Block 9.14) first considers whether the IS_IMMUNE property has been added. If it has then immunity for the person is determined. Immune people do not receive the vaccine and no more attempts to vaccinate the person will be scheduled. If the person is still refusing the vaccine, then a new attempt to vaccinate the person is scheduled. Otherwise the person is vaccinated and no further attempts are scheduled.

Code Block 9.14: With each vaccination attempt, the vaccinator updates the VACCINE_ATTEMPTS person property for the person. People who refuse vaccination are scheduled for another vaccination attempt.
private void vaccinatePerson(PersonId personId) {
    int vaccineAttempts = personPropertiesDataManager.getPersonPropertyValue(personId,
            PersonProperty.VACCINE_ATTEMPTS);
    personPropertiesDataManager.setPersonPropertyValue(personId, PersonProperty.VACCINE_ATTEMPTS,
            vaccineAttempts + 1);

    boolean isImmune = false;
    if (personPropertiesDataManager.personPropertyIdExists(PersonProperty.IS_IMMUNE)) {
        isImmune = personPropertiesDataManager.getPersonPropertyValue(personId, PersonProperty.IS_IMMUNE);
    }

    Boolean refusesVaccine = personPropertiesDataManager.getPersonPropertyValue(personId,
            PersonProperty.REFUSES_VACCINE);
    if (!isImmune) {
        if (refusesVaccine) {
            double planTime = actorContext.getTime() + randomGenerator.nextDouble() * vaccineAttemptInterval;

            ActorPlan plan = new ConsumerActorPlan(planTime, (c) -> vaccinatePerson(personId));             
            actorContext.addPlan(plan);
            //record the plan for possible cancellation
            actorPlans.put(personId, plan);
        } else {
            personPropertiesDataManager.setPersonPropertyValue(personId, PersonProperty.VACCINATED, true);
        }
    }
}

9.6 Inspecting the output

The 810 scenarios result in a large amount of output in the person properties report with over 125,000 entries. The vaccine report is a bit too large to fully present here. Its fields are:

  • Scenario – 0 to 809
  • Experiment fields that show what differentiates each scenario
    • immunity start time
    • immunity probabilty
    • vaccine attempt interval
    • education attempt interval
    • education success rate
    • intial refusal probability
  • The metric fields produced as a result of the experiment choices
    • vaccinated immune
    • vaccinated susceptible
    • unvaccinated immune
    • unvaccinated susceptible

Analyzing the output yields no surprises. Higher education attempt rates and greater probabilities of education success yield more people getting vaccinated. Similarly, early and high levels of immunity have a slight dampening effect on vaccinations.