5.9. Step 9: Primary Education Fate Base Model

5.9.1. Model Description

At this step we add the base “fate” module for primary school outcome. Based on the information in the starting population and parameters by district, year of birth and sex, the final primary school outcome is decided at birth.

5.9.2. The new Educ1BaseFate.mpp Module

This module sets the education fate and stores the underlying individual probabilities of “School One”. The education fate is decided at birth. “School One” is a generic term. There are three different outcomes: low, medium, high. The module sets three states at birth:

  • educ_one_fate: the individual outcome in 3 levels low, medium, high
  • educ_one_prob1: the individual probability to move from low to medium
  • educ_one_prob2: the individual probability to move from medium to high

In Dynamis-Pop, “School One” refers to Primary School and the interpretation of the levels is:

  • low: never entered primary school
  • medium: entered but did not finish primary school
  • high: finished primary school

Probabilities to progress from low to medium and from medium to high are given by two parameters by year of birth, district of birth, and sex. The way how the education fate is decided depends on the year of birth and the person type.

  • Persons from the starting population: the education outcome is taken from the starting population file if the person was born before the years of birth covered by the parameters. This means, up to two age cut-offs, the information of the starting population is ignored at all, or only used to decide the first progression (low to medium, but not medium to high which is modeled).
  • Persons born in the simulation: the education fate is decided based on the parameters.
  • Immigrants: for years of birth covered by parameters the education fate is modeled. For immigrants born before, the education state is sampled from foreign born residents born in the previous 12 months.

The function SetEduc1BaseFate() which decides the fate is hooked to the SetAlive() Event of the PersonCore.mpp module, ie. is called directly at birth after the actor enters the simulation and all actor sets are available (which is important for the cloning of immigrant characteristics).

This module is the base version for the education fate in “School One”. As the probabilities on which the decision was based are stored, the outcome can be adjusted by a refined model in order to account for additional individual-level characeristics (like parents’ education or ethnicity) and/or to aligne the aggregated outcome to target rates or constraints.

When adding this module, some adaptations are necessary in other modules:

  • The state district_birth and educ_one_startpop has to be initialized in the Start() function in the PersonCore.mpp module.
  • The year of birth ranges for the model parameters depend on the country and time context. The according ranges YOB_START_PRIMARY and YOB_GRAD_PRIMARY are accordingly added in _CountryContext.mpp


////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor Sets
////////////////////////////////////////////////////////////////////////////////////////////////////

// Foreign born residents of age 0
actor_set Person asForeignBornAge0[sex]
filter is_alive &&  district_birth == DISTI_ABROAD && is_resident && integer_age==0;

// Residents of age 0
actor_set Person asResidentsAge0[sex]
filter is_alive && integer_age==0 && is_resident;

////////////////////////////////////////////////////////////////////////////////////////////////////
// Types
////////////////////////////////////////////////////////////////////////////////////////////////////

classification EDUC_ONE_LEVEL       //EN Primary Education level
{
    EOL_LOW,                        //EN Never entered primary school
    EOL_MEDIUM,                     //EN Entered primary school
    EOL_HIGH                        //EN Graduated from primary school
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// Parameters
////////////////////////////////////////////////////////////////////////////////////////////////////

parameters
{
    //EN Probability to start primary school
    double  StartPrimaryDistrict[SEX][YOB_START_PRIMARY][DISTRICT_INT];

    //EN Probability to graduate from primary
    double  GradPrimaryDistrict[SEX][YOB_GRAD_PRIMARY][DISTRICT_INT];
};

//EN Primary Education Base Fate Model
parameter_group PG_SchoolOneBase
{
    StartPrimaryDistrict,
    GradPrimaryDistrict
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor States and Events
////////////////////////////////////////////////////////////////////////////////////////////////////

actor Person
{
    DISTRICT_INT    district_birth = { DISTI_00 };      //EN District at birth
    EDUC_ONE_LEVEL  educ_one_fate = { EOL_LOW };        //EN Primary Education Fate
    EDUC_ONE_LEVEL  educ_one_startpop = { EOL_LOW };    //EN Primary Education Fate

    double educ_one_prob1 = { 0.0 };                    //EN Base prob. progressing low medium
    double educ_one_prob2 = { 0.0 };                    //EN Base prob. progressing medium high

    void SetEduc1BaseFate();                            //EN Setting the primary school fate
    hook SetEduc1BaseFate, SetAliveEvent;               //EN Hook SetEduc1BaseFate to SetAlive
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////////////////////////

void Person::SetEduc1BaseFate()
{
    // Person born in simulation
    if ( person_type == PT_CHILD )
    {
        educ_one_prob1 = StartPrimaryDistrict[sex][RANGE_POS(YOB_START_PRIMARY,year_of_birth)][district_birth];
        educ_one_prob2 = GradPrimaryDistrict[sex][RANGE_POS(YOB_GRAD_PRIMARY,year_of_birth)][district_birth];
        EDUC_ONE_LEVEL eolFate = EOL_LOW;
        if ( RandUniform(13) < educ_one_prob1 ) eolFate = EOL_MEDIUM;
        if ( eolFate == EOL_MEDIUM && RandUniform(14) < educ_one_prob2 )  eolFate = EOL_HIGH;
        educ_one_fate = eolFate;
    }
    // Person from starting population
    else if ( person_type == PT_START )
    {
        // Case 1: take the education from the starting population
        if ( year_of_birth < MIN(YOB_GRAD_PRIMARY))
        {
            educ_one_fate = educ_one_startpop;
        }
        // Case 2: take first progression from the starting population
        else if ( year_of_birth < MIN(YOB_START_PRIMARY))
        {
            educ_one_prob2 = GradPrimaryDistrict[sex][RANGE_POS(YOB_GRAD_PRIMARY,year_of_birth)][district_birth];
            EDUC_ONE_LEVEL eolFate = EOL_LOW;
            if ( educ_one_startpop != EOL_LOW ) eolFate = EOL_MEDIUM;
            if ( eolFate == EOL_MEDIUM && RandUniform(15) < educ_one_prob2 )  eolFate = EOL_HIGH;
            educ_one_fate = eolFate;
        }
        // Case 3: model from parameters ignoring starting population values
        else
        {
            educ_one_prob1 = StartPrimaryDistrict[sex][RANGE_POS(YOB_START_PRIMARY,year_of_birth)][district_birth];
            educ_one_prob2 = GradPrimaryDistrict[sex][RANGE_POS(YOB_GRAD_PRIMARY,year_of_birth)][district_birth];
            EDUC_ONE_LEVEL eolFate = EOL_LOW;
            if ( RandUniform(18) < educ_one_prob1 ) eolFate = EOL_MEDIUM;
            if ( eolFate == EOL_MEDIUM && RandUniform(19) < educ_one_prob2 )  eolFate = EOL_HIGH;
            educ_one_fate = eolFate;
        }
    }
    // Person is an immigrant
    else
    {
        // Parameters available for this year of birth
        if ( year_of_birth >= MIN(YOB_START_PRIMARY))
        {
            educ_one_prob1 = StartPrimaryDistrict[sex][RANGE_POS(YOB_START_PRIMARY,year_of_birth)][district_birth];
            educ_one_prob2 = GradPrimaryDistrict[sex][RANGE_POS(YOB_GRAD_PRIMARY,year_of_birth)][district_birth];
            EDUC_ONE_LEVEL eolFate = EOL_LOW;
            if ( RandUniform(16) < educ_one_prob1 ) eolFate = EOL_MEDIUM;
            if ( eolFate == EOL_MEDIUM && RandUniform(17) < educ_one_prob2 )  eolFate = EOL_HIGH;
            educ_one_fate = eolFate;
        }
        // Education to be sampled from resident immigrants
        if (asForeignBornAge0[sex]->Count() > 0) //there are 0 year old resident foreign born
        {
            educ_one_fate = asForeignBornAge0[sex]->GetRandom(RandUniform(20))->educ_one_fate;
        }
        else // sample from whole population if no foreign born of age 0 around
        {
            educ_one_fate = asResidentsAge0[sex]->GetRandom(RandUniform(21))->educ_one_fate;
        }
    }
}


table Person TabEducTest //EN Educ Table
[is_alive]
{
    person_type+ *
    district_birth+ *
    {
        unit
    }
    * year_of_birth
    * educ_one_fate+
};

5.9.3. Initializations in the Start() Function

The states district_birth and educ_one_startpop are added to the list of variables initiated in the Start() Function.


    // Initialize states
    if (person_type == PT_START) // Person comes from starting population
    {
        // (A) States from Starting population file
        time                = peObservation->pmc[PMC_BIRTH];
        sex                 = (SEX)(int)peObservation->pmc[PMC_SEX];
        family_role         = peObservation->fam_role;
        district_int        = (DISTRICT_INT)(int)peObservation->pmc[PMC_DISTRICT];
        district_birth      = (DISTRICT_INT)(int)peObservation->pmc[PMC_DOB];
        educ_one_startpop   = (EDUC_ONE_LEVEL)(int)peObservation->pmc[PMC_EDUC];

        // (B) Other states
        time_of_birth       = time;
        calendar_year       = (int)time_of_birth;
        ever_resident       = is_resident;

        // (C) Links to head resp. spouse
        // (uncomment when modeling families) if (pePers) peHHead = pePers;
    }
    else if (person_type == PT_CHILD) // Person born in simulation
    {
        // (A) States corresponding to Starting population file variables
        if (RandUniform(4) < 100.0 / (100.0 + SexRatio[RANGE_POS(SIM_YEAR_RANGE, calendar_year)]))
        {
            sex  = FEMALE;
        }
        else sex = MALE;
        time                = pePers->time;
        family_role         = FR_CHILD;
        district_int        = pePers->district_int;
        district_birth      = district_int;

        // (B) Other states
        time_of_birth       = time;
        calendar_year       = (int)time_of_birth;
        ever_resident       = is_resident;

        // (C) Links to head resp. spouse
        // (uncomment when modeling families) if (pePers) peHHead = pePers;
    }
    else // Person is an immigrant
    {
        // (A) States corresponding to Starting population file variables
        int nSex, nYear, nAge, nDistrict;
        Lookup_NumberImmigrantsTable(RandUniform(7), &nYear, &nSex);
        Lookup_AgeImmigrants(RandUniform(8), nSex, &nAge);
        Lookup_DestinationImmigrants(RandUniform(9), nSex, SPLIT(nAge, AGE5_PART), &nDistrict);

        sex                 = (SEX)nSex;
        time_of_immigration = MIN(SIM_YEAR_RANGE) + nYear + RandUniform(12);
        family_role         = FR_HEAD;
        district_int        = DISTI_ABROAD;
        district_immi       = (DISTRICT_NAT)nDistrict;
        time                = time_of_immigration - (nAge + RandUniform(11));
        district_birth      = DISTI_ABROAD;

        // (B) Other states
        time_of_birth       = time;
        calendar_year       = (int)time;
        ever_resident       = FALSE;
    }