Skip to content

Overview of the Ferguson Model

lukedtc edited this page Sep 28, 2022 · 97 revisions

Overview of the Ferguson Model

This page provides an overview on how the Ferguson Model works.

General Information

They implement a SEIR based model with added spatial complexity. The model contains two main sections: transmission mechanisms and within host progression.

For each time-step the code loops through the population and records interactions between infected and susceptible people which may lead to infections. Individuals are allocated a susceptibility based on age and location data and pairs of individuals considered to see whether their interaction leads to infection. The likelihood of a pair interacting is weighted by spatial distance and age factors (as people are more likely to socialise with those of the same age, and children maintain close contact with parents). This incorporates the major spatial variation within the model.

Once an individual becomes exposed, their progression through the various stages of infection is determined by generating a series of random time-steps to mark their movements between infection categories. The possible paths an individual can take are indicated on the schema below.

SEIR model conceptualisation

Update Sweep Function

On each time step the simulation will update people and places within the model. This allows time dependent effects such as lock-downs of vaccination drives to be implemented, and for general movement of people around microcells and places.

Update Places

Unlike households, places have a variable population as they represent locations where people from different households but the same microcell interact. Therefore on each time-step the people in a place change. The susceptibility and infectiousness of the place can also be updated, for example if a more stringent cleaning regime is implemented.

Infection Sweep Function

A key part of the model is implementing spatially determined infections. These are decided by computing a Force of Infection parameter dependent on the two individuals involved in an infection event, and the location in which the infection takes place. The sweep function is divided in sub-classes for each location type. For each pair of infective and susceptible individuals, a Force of Infection value is calculated, and compared to a random seed in (0, 1). If the random number is less than the FOI an infection event takes place, and the infectee is queued.

Household infections

Households comprise of disjoint lists of people which is assumed constant throughout the simulation. The household is given a baseline susceptibility and infectiveness to account for variability in factors such as the size of common living areas. These parameters may also be updated, for example if lock-downs mean people spend a greater amount of time at home. The household sweep function considers infection events between individuals in the same household.

Place infections

Places comprise of lists of people (not necessarily disjoint) from the same microcell. This list is updated at each time step to model people moving to different places each day. Places are given a place_type (hotel, restaurant, park), each with its own baseline (but configurable) susceptibility and infectiveness. The place infection sweep runs similarly to household sweep: at each time-step infection events between people present in the place are considered.

Queue Sweep

After all the spatial infection sweeps have run, and infectees queued in each cell, the queue sweep function is run. This runs through all queued people in each cell, updates their status to Exposed and determines their next infection status.

Within Host Progression

At the end of each time-step, any newly exposed person has their infection status updated to mildly infected and their next infection status decided randomly by a function. This function also decides randomly a time when this person will progress to their next infection status. At the end of each time step, this function sweeps through the entire population to see if a person needs to have their infection status updated and a next infection status/ time to status update calculated. This is how the disease progresses within hosts in the model.

Susceptible to Immune

Transfers a specific person straight from susceptible to immune, used to start a simulation with a partially immune population. The DoImmune function in CovidSim takes the index of the person as a single parameter and transfers this person to recovered status (before updating the status of the cells). This should be done at the very beginning of the simulation run.

Susceptible to Exposed

Changes a person from susceptible to latently infected (exposed). The DoInfect function in CovidSim takes in the index of the person (ai) whom the status needs to change, the time (in days) and the thread for the simulation run. Here, it should be noted that ts is the time step and tn is the thread.

  • Change of status: The function first checks that the person of interest (with the chosen index) is susceptible. Then, it assigns the infectious status of the person to be latent.
  • Some recording: It sets the infection time for this person at the current time step (calculated using number of time steps per day and the current time (in days). It calculates the radius squared of the targeted person's household (x and y coordinates) with the location of initial infection (a given parameter). It uses the function ToInfected to increase by one each of the following: the number of cumulative infection, the number of cumulative infection by type of infection, and the number of cumulative infection by age (of the person ai index). It also adds the newly calculated radius squared (see previous bullet point) to the sum of radius squares. If the new radius squared is bigger than the maximum radius squares recorded previously, it updates the maximum radius squared (this variable records the maximum radius squared starting from the initial infection point in space). Using the function SusceptibletoLatent, it changes the number of susceptible people (decreases by one) and of latently infected people (increased by one), decreases by one the pointer to latent in the targeted cell, and checks that the number of susceptible people is non-negative.
  • It updates the position of the person's index, it moves it from the susceptible region to the front of the latent queue.
  • If DoLatent is true (i.e. if the latent status is enabled in the simulation, with parameter DoLatent), it assigns a latent time to the targeted person, done following the method here:
    • q = random_number * CDF, where random_number is between 0 and 1 and CDF = 20
    • i = floor function of q
    • q is redefined as q = q - i
    • t is the time (in days) in the simulation.
    • LatentPeriod (in days) is an input parameter equal to the mean of the inverse cumulative distribution function, set at 4.59 in the Ferguson's model (see here).
    • latent_icdf(i) is the i i i.e. quantile of delay distributions from the latent infected status (inverse cumulative distribution functions), where i is defined above, and the latent_icdf is an array defined in Ferguson's model as [0 0.098616903 0.171170649 0.239705594 0.307516598 0.376194441 0.446827262 0.520343677 0.597665592 0.679808341 0.767974922 0.863671993 0.968878064 1.086313899 1.219915022 1.37573215 1.563841395 1.803041398 2.135346254 2.694118208 3.964172493] (see here).
    • The latent time is defined as the floor function of (0.5 + (t - LatentPeriod * log(q * latent_icdf(i+1) + (1 - q) * latent_icdf(i))) * TimeStepsPerDay)
  • Else, the latent time is the current time step so the person will immediately move to the next infection status. (We suppose therefore that the latent time is the time at which the person stops being latent and transfers to the next infection status).
  • Some more recording: It records data relating to the person who infected the targeted person with index ai (the infector): it adds to cumulative TG (meaning to be determined) the time difference between the time of infection of the person ai and the time of infection of the infector, it adds to cumulative SI (meaning to be determined) the time difference between the latent time of the person ai and the latent time of the infector, and it increases by one the number of TG. If DoAdUnits is true (activated), it increases by one the cumulative infections per admin units in the appropriate admin unit. Moreover, if the option to output the infection per age per admin unit is activated (OutputAdUnitAge is true), the prevalence of infection and the cumulative infection by age and admin unit are updated (each increased by one) for the appropriate age and admin unit (those of the targeted person ai). If the option to output a bitmap is activated, the necessary info is updated. If the option to record infection events is activated, the information of the infection event (the time of simulation, the person infected, the run number and the thread) is recorded using the method RecordEvent (add description of method below).
  • If the time is greater than 0 (checks that we are not at initial time) and if the option DoOneGen is activated, it successively calls the methods DoIncub, DoCase, and DoRecover (add description of methods below).

Incubation Period

In Update.cpp, description of the function DoIncub. The input parameters for the method are the person index (ai), the time step (ts) and the thread number (tn).

First of all, the method assigns the person to an age group:

  • It gets the person's age (Hosts[ai].age), and assign to the parameter age = floor(Hosts[ai].age / AGE_GROUP_WIDTH), where AGE_GROUP_WIDTH = 5 in the covid-sim model.
  • It verifies that the age group is within bound of the set number of age groups. In the model, NUM_AGE_GROUPS = 17, so they work with 17 different age groups (of each 5 years of width). If age >= NUM_AGE_GROUPS, then they reassign age = NUM_AGE_GROUPS - 1.

Then, it sets the initial person's infectiousness, with the option of using the person's associated age group. If age is considered in the model, then AgeInfectiousness should be an array that can be accessible in the input parameter file to feed this parameter definition (parameter named "Age-dependent infectiousness", not currently found in the input parameter file in the covid-sim repository). If the age functionality is turned off, then AgeInfectioussness = 1, and the initial infectiousness of the person a is set to infectiousness = 1.

Prior to this part, the parameter InfectioussSD is extracted from the input parameter file (parameter named "SD of individual variation in infectiousness"), and is set to 0 if it is not found, or if the parameter k = "k of individual variation in infectiousness" is found in the input parameter file, then InfectioussSD = 1/sqrt(k). In our case, k = 1 in the parameter file of covid-sim (and the parameter "SD of individual variation in infectiousness" is absent from the file), therefore InfectioussSD = 1.

Might need to adjust regarding Infectiousness Profile

Once the InfectioussSD parameter is assigned, we update the infectiousness of the person a if InfectioussSD > 0, with infectiousness = infectiousness * gen_gamma_mt(beta, alpha, tn), where

  • beta = alpha = 1 / (InfectiousnessSD**2)
  • tn is the thread number
  • gen_gamma_mt() is their implementation of sampling from a gamma distribution, using Marsaglia-Tsang method but for multi-threading.
  • Note: if we want to implement this using numpy.random.gamma(shape,scale), then shape=alpha and scale=1/beta, although not very important in the case of gamma(1,1) distribution.

Next, they define the probability of the person to be symptomatic (ProbSymptomatic), using the person's age groupe (age) and possible features such as proportion of symptomatic cases prevented by treatment, or proportion of symptomatic cases prevented by vaccination. In the absence of these features, ProbSymptomatic = ProportionSymptom[age], where ProportionSymptom is the array containing the proportion symptomatic by age group, and is set to 0.66 for each age group in the parameters input file (see here, for parameter [Proportion symptomatic by age group]). Therefore, ProbSymptomatic = 0.66 in the model.

They use this probability to define if the person will be symptomatic or asymptomatic:

  • Using their implementation of random number generator, they generate a random number (between 0 and 1).
  • If this number is smaller to ProbSymptomatic, they set the infection status of the person to InfectiousAlmostSymptomatic,
  • they also update the infectiousness = infectiousness * SymptInfectiousness * (-1),
    • Note: they set the infectiousness of a symptomatic infected person negative for further fonctionality, and then use the absolute value to measure the true infectiousness.
  • where SymptInfectiousness is defined from the param files as P->SymptInfectiousness = Params::get_double(params, pre_params, "Symptomatic infectiousness relative to asymptomatic", 1.0, P);. Looking at the parameters file (see parameter [Symptomatic infectiousness relative to asymptomatic]), SymptInfectiousness = 1.5 in the input parameter file.
  • Otherwise (if the random number is equal or greater to ProbSymptomatic), the infection status is set to InfectiousAsymptomaticNotCase,
  • and the infectiousness is updated to infectiousness = infectiousness * AsymptInfectiousness,
  • where AsymptInfectiousness is potentially defined from a param file P->AsymptInfectiousness = Params::get_double(params, pre_params, "Asymptomatic infectiousness relative to symptomatic", 1.0, P);, and has a default value of 1. It seems no value is provided from the parameters file, and therefore AsymptInfectiousness = 1, and infectiousness is unchanged.

If the person is asymptomatic, the time until recovery is calculated as follow:

  • recovery_or_death_time = latent_time + infectious_icdf.choose(InfectionPeriod, tn, TimeStepsPerDay), where the choose function associated with an inverse cdf is defined a bit further, with intakes InfectionPeriod which is the mean of the icdf, the threadnumber and the number of time steps per day. It is applied to the infectious_icdf defined in the parameters file, with reference (Cauchemez), as
    • infectious_icdf = [0 0.171566836 0.424943468 0.464725594 0.50866631 0.55773764 0.613298069 0.67732916 0.752886568 0.843151261 0.895791527 0.955973422 1.026225109 1.110607115 1.216272375 1.336349102 1.487791911 1.701882384 1.865779085 2.126940581 2.524164972]
    • with InfectionPeriod = 14.

They have an option where severity is not taken into account in the infection states. We skip the case where the severity is ignored, and skip to the part where they consider severity in the model.

In this subsection, the first thing they do is define the CaseTime, using the latent_time, the ModelTimeStep, and the LatentToSymptDelay parameters. This last one, defined as the "Delay from end of latent period to start of symptoms", is taken from the parameters file and is set to 0.5 (they assume average time to symptom onset is a day). They define CaseTime = latent_time + floor(LatentToSymptDelay / ModelTimeStep).

Then, they define the final disease severity of the person, a function of the person's age group (age), using their method SeverityFinal = ChooseFinalDiseaseSeverity(age, tn). This method, which uses x a random number between 0 and 1 generated by their random method generator and which returns DiseaseSeverity as an output, is defined as:

  • if x < Prop_ILI_ByAge[age]_, then DiseaseSeverity = ILI,
  • else if x < (Prop_ILI_ByAge[age]_ + Prop_SARI_ByAge[age]_), then DiseaseSeverity = SARI
  • else if x < (Prop_ILI_ByAge[age]_ + Prop_SARI_ByAge[age]_ + Prop_Critical_ByAge[age]_), then DiseaseSeverity = Critical,
  • else, DiseaseSeverity = Mild.
  • In the above lines, the parameters Prop_Y_ByAge (for Y state) are taken from the parameters file, and are defined as
    • Prop_ILI_ByAge = [0.333122437 0.333153617 0.333001453 0.332654731 0.33181821 0.330417289 0.328732618 0.326716425 0.325130732 0.322392505 0.316971878 0.312809664 0.304540269 0.300182488 0.2919304 0.283276936 0.282323232]
    • Prop_SARI_ByAge = [0.000557744 0.000475283 0.000877703 0.001794658 0.004006955 0.007711884 0.012167229 0.017359248 0.021140307 0.027047193 0.03708932 0.039871236 0.040788928 0.027444452 0.101605674 0.142001415 0.150469697]
    • Prop_Critical_ByAge = [7.49444E-05 6.38641E-05 0.000117937 0.000241149 0.000538417 0.00103625 0.001634918 0.002491477 0.003467496 0.005775292 0.011995047 0.021699771 0.045590266 0.072008084 0.022603126 0.008167778 0.002560606]
    • Prop_Mild_ByAge = [0.666244874 0.666307235 0.666002907 0.665309462 0.663636419 0.660834577 0.657465236 0.65343285 0.650261465 0.64478501 0.633943755 0.625619329 0.609080537 0.600364976 0.5838608 0.566553872 0.564646465]

Immediately after they decide the final disease severity, they decide the outcome (death or recovery) for the person, with their method DecideIfPersonDies(ai, _age, tn), for the person identified by the index ai, of age group age, and at thread number tn. The function is defined as follows, where they get the person's Severity_Final, and the output is stored for each person in their attribute to_die (initialised at 0, set here to 1 if the person will die).

  • If the person's Severity_Final is Critical: the person is set to die if a generated random number is less than CFR_Critical_ByAge(age) * CFR_Critical_Scale_Current
  • If the person's Severity_Final is SARI: the person is set to die if a generated random number is less than CFR_SARI_ByAge(age) * CFR_SARI_Scale_Current
  • If the person's Severity_Final is ILI: the person is set to die if a generated random number is less than CFR_ILI_ByAge(age) * CFR_ILI_Scale_Current
  • For the other states of Severity_Final, the person has no chance of dying and will recover.
  • The parameters CFR_Y_Scale_Current (for Y state) are initialised at 1 and are updated during the simulation using "single scaling" (unsure of what is being done for this parameter, see CovidSim.cpp line 2789).
  • In the above lines, the parameters CFR_Y_ByAge (for Y state) are taken from the parameters file, and are defined as
    • CFR_Critical_ByAge = [0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896 0.5234896]
    • CFR_SARI_ByAge = [0.125893251 0.12261338 0.135672867 0.152667869 0.174303077 0.194187895 0.209361731 0.224432564 0.237013516 0.257828065 0.290874602 0.320763971 0.362563751 0.390965457 0.421151485 0.447545892 0.482]
    • CFR_ILI_ByAge = 0 for each group age. Therefore, with this set of parameters, a person with ILI as final severity of infection will not die.

Then, there are additional features if the person is a care home resident (additional mortality).

Once the final severity state and the outcome (death or recovery) are defined, they go through each of the possible final severity state to define the transition times and the final recovery or death time. They implemented the option that someone who is recovering from Critical (Stepdown state) can die.

For each of the transition time calculation, they use a method from InverseCdf to sample from the input icdf. This method, named choose, takes in the mean of the icdf, the threadnumber tn and the timesteps_per_day, and returns the Value as defined here:

  • with the generated random number x, they define q=x*CDF_RES
  • they define i = floor(q)
  • they redefine q = q - i
  • they define ti = q * icdf_values[i+1] + (1 - q) * icdf_values[i]
  • finally, Value = floor(0.5 + (ti * timesteps_per_day)

If the final severity state is mild,

  • recovery_or_death_time = CaseTime + MildToRecovery_icdf.choose with Mean_MildToRecovery

If the final severity state is ILI,

  • If set to die, recovery_or_death_time = CaseTime + ILIToDeath_icdf.choose with Mean_ILIToDeath
  • Else, if set to recover, recovery_or_death_time = CaseTime + ILIToRecovery_icdf.choose with Mean_ILIToRecovery

If the final severity state is SARI,

  • SARITime = CaseTime + ILIToSARI_icdf.choose with Mean_ILIToSARI
  • Then, if set to die, recovery_or_death_time = SARITime + SARIToDeath_icdf.choose with Mean_SARIToDeath
  • or, if set to recover, recovery_or_death_time = SARITime + SARIToRecovery_icdf.choose with Mean_SARIToRecovery

Finally, if the final severity state is critical,

  • SARITime = CaseTime + ILIToSARI_icdf.choose with Mean_ILIToSARI
  • CriticalTime = SARITime + SARIToCritical_icdf.choose with Mean_SARIToCritical
  • If set to die, recovery_or_death_time = CriticalTime + CriticalToDeath_icdf.choose with Mean_CriticalToDeath
  • or, if set to recover, Stepdown_time = CriticalTime + CriticalToCritRecover_icdf.choose with Mean_CriticalToCriticalRecovery and recovery_or_death_time = Stepdown_time + CritRecovToRecov_icdfchoose with Mean_CritRecovToRecovery

In the above lines, the parameters are taken from the parameters file, and are defined as

    • MildToRecovery_icdf = [0 0.341579599 0.436192391 0.509774887 0.574196702 0.633830053 0.690927761 0.74691114 0.802830695 0.859578883 0.918015187 0.97906363 1.043815683 1.113669859 1.190557274 1.277356871 1.378761429 1.50338422 1.670195767 1.938414132 2.511279379]
    • ILIToRecovery_icdf = [0 0.341579599 0.436192391 0.509774887 0.574196702 0.633830053 0.690927761 0.74691114 0.802830695 0.859578883 0.918015187 0.97906363 1.043815683 1.113669859 1.190557274 1.277356871 1.378761429 1.50338422 1.670195767 1.938414132 2.511279379]
    • ILIToSARI_icdf = [0 0.341579599 0.436192391 0.509774887 0.574196702 0.633830053 0.690927761 0.74691114 0.802830695 0.859578883 0.918015187 0.97906363 1.043815683 1.113669859 1.190557274 1.277356871 1.378761429 1.50338422 1.670195767 1.938414132 2.511279379]
    • ILIToDeath_icdf = [0 2.257735908 3.171065856 3.924183798 4.608738224 5.260437017 5.898728066 6.53669783 7.184755068 7.852438367 8.549591424 9.287408763 10.07967529 10.94457146 11.90769274 13.00769447 14.3081531 15.92655201 18.12320384 21.71626849 29.58154704]
    • SARIToRecovery_icdf = [0 0.634736097 1.217461548 1.805695261 2.41206761 3.044551205 3.71010552 4.415905623 5.170067405 5.982314035 6.864787504 7.833196704 8.908589322 10.12027655 11.51100029 13.14682956 15.13821107 17.69183155 21.27093904 27.35083955 41.35442157]
    • SARIToCritical_icdf = [0 0.108407687 0.220267228 0.337653773 0.46159365 0.593106462 0.733343356 0.88367093 1.045760001 1.221701998 1.414175806 1.62669998 1.864032461 2.132837436 2.442868902 2.809242289 3.257272257 3.834402667 4.647120033 6.035113821 9.253953212]
    • SARIToDeath_icdf = [0 1.703470233 2.39742257 2.970367222 3.491567676 3.988046604 4.474541783 4.960985883 5.455292802 5.964726999 6.496796075 7.06004732 7.665014091 8.325595834 9.061367792 9.901900127 10.8958347 12.133068 13.81280888 16.56124574 22.5803431]
    • CriticalToCritRecov_icdf = [0 1.308310071 1.87022015 2.338694632 2.76749788 3.177830401 3.581381361 3.986127838 4.398512135 4.824525291 5.270427517 5.743406075 6.252370864 6.809125902 7.430338867 8.141231404 8.983341913 10.03350866 11.46214198 13.80540164 18.95469153]
    • CriticalToDeath_icdf = [0 1.60649128 2.291051747 2.860938008 3.382077741 3.880425012 4.37026577 4.861330415 5.361460943 5.877935626 6.4183471 6.991401405 7.607881726 8.282065409 9.034104744 9.894486491 10.91341144 12.18372915 13.9113346 16.74394356 22.96541429]
    • CritRecovToRecov_icdf = [0 0.133993315 0.265922775 0.402188416 0.544657341 0.694774487 0.853984373 1.023901078 1.206436504 1.403942719 1.619402771 1.856711876 2.121118605 2.419957988 2.763950408 3.169692564 3.664959893 4.301777536 5.196849239 6.7222126 10.24997697]
    • Mean_MildToRecovery = 7
    • Mean_ILIToRecovery = 7
    • Mean_ILIToSARI = 5
    • Mean_ILIToDeath = 7
    • Mean_SARIToRecovery = 1
    • Mean_SARIToCritical = 1
    • Mean_SARIToDeath = 1
    • Mean_CriticalToCritRecov = 1
    • Mean_CriticalToDeath = 1
    • Mean_CritRecovToRecov = 1

Once the transition times are defined, still in the DoIncub method, they add some optional features concerning detection of new cases and digital contact tracing. Finally, pointers are updated with LatentToInfectious (one fewer person latently infected, ie exposed, and one more infectious person), and they update the cell.

Infectiousness Profile

If DoInfectiousnessProfile is true, there is one difference in the host progression sweep, where the recovery_or_death_time of an asymptomatic infected person is set to latent_time + (unsigned short int) (P.InfectiousPeriod * P.TimeStepsPerDay). If DoInfectiousnessProfile is true, in the ReadParams.cpp file, the following is done.

First, they extract the Infectiousness profile, an array defined in the parameters file as

  • Infectiousness profile = [0.487464241 1 1.229764827 1.312453175 1.307955665 1.251658756 1.166040358 1.065716869 0.960199498 0.855580145 0.755628835 0.662534099 0.577412896 0.500665739 0.432225141 0.371729322 0.318643018 0.272340645 0.232162632 0.19745264 0.167581252 0.141960133 0.120049578 0.101361532 0.085459603 0.071957123 0.060514046 0.050833195 0.04265624 0.035759641 0.029950735 0.025064045 0.02095788 0.017511251 0.014621091 0.012199802 0.010173075 0.008477992 0.007061366 0.005878301 0.00489096 0.004067488 0.003381102 0.00280931 0.002333237 0.001937064 0.001607543 0.001333589 0.001105933 0.00091683 0.000759816 0.000629496 0.000521372 0.000431695 0.000357344 0.000295719 0.000244659]
  • Then, they define k as the ceiling (therefore integer) of InfectiousPeriod / ModelTimeSteps, where InfectiousPeriod = 14.
  • With MAX_INFECTIOUS_STEPS = 2550, they make sure that k < MAX_INFECTIOUS_STEPS, or otherwise they return an error.
  • With INFPROF_RES = 56, they set Infectiousness profile[INFPROF_RES] = 0.
  • They initialise the array infectiousness (of the size MAX_INFECTIOUS_STEPS) by setting every value to 0.
  • They initialise s = 0
  • Then, for i between 0 and k (excluding k)
    • t = (i * ModelTimeStep / InfectiousPeriod) * INFPROF_RES
    • j = t (an integer)
    • t = t - j
    • If j < INFPROF_RES :+
      • infectiousness[i] = Infectious profile[j] * (1 - t) + Infectious profile[j + 1]* t
      • s = s + infectiousness[i]
    • else:
      • infectiousness[i] = Infectious profile[INFPROF_RES] (ie =0)
      • s = s + infectiousness[i]
  • After the loop, they set s = s / k (not an integer division, they trigger float division with (double))
  • Then, for i between 0 and k (including k): they set infectiousness[i] = infectiousness[i] / s

Random function

In Random.cpp, they define a pseudorandom number generator function: ranf_mt. It follows the algorithm described in the article from L'Ecuyer 1988 (Efficient and Portable Combined Random Number Generators).

Xcg1 is a 32-bit integer pointer. In the fist thread, the initial s1 is set as the integer stored in memory that is pointed to by Xcg1. In the subsequent threads, s1 is initialised by the adjacent 32-bit integers in memory. The same method is used to initialise s2, using another 32-bit integer pointer Xcg2. It is important to note that s1 and s2 must be integers greater or equal to 1, and not exceeding 21474835621. Moreover, each thread will have different initial values for s1 and s2.

Then, the algorithm is applied and the values of s1 and s2 are updated. The subsequent use of the function ranf_mt will then use these new s1 and s2 values as initial value for the algorithm.

Household Ages Sweep

They utilize a function that assigns people ages dependent on the size of their household. For example, in a single person household, the function will set the age of that person so they are the age of an adult that is likely to be living alone. Similarly, for households of size bigger than one, children may be present. If children are present then their age will be set accordingly and the remaining adults within the house will be given an age that makes them old enough to be a parent of that child. There are many different scenarios of age distributions depending on the size of the household but the general architecture for assigning ages is as follows:

  • A random number is drawn to decide what situation the household ages should correspond to, e.g if it is a two person household is it the case of two young adults or one adult and a child.
  • The number of children is calculated if necessary.
  • The age of every person is repeatedly calculated until their ages satisfy a certain conditions are satisfied. These conditions usually include a lower and/or upper bound such as minimum adult age for someone assigned to be an adult and a loop exit condition that a random number is compared to in order to favour certain age ranges for a given scenario. A loop exit condition might for example be applied in the case of a parent and child living together in order to skew the age of the parent to be younger, more in line with what is seen in reality.