Step 14: Education Alignment

Overview

At this step we add a module EducationAlignment.mpp which allows aligning school attendance to external school enrolment parameters. The module is optional and can be switched off by the user.

The new EducationAlignemnt.mpp Module

This module allows aligning school attendance to external school enrolment parameters. This module is optional and can be switched off by the user. The module works on top of the education pattern module and does not interfere with the school attendance patterns produced there. Alignment of education rates works in one direction only - namely increasing the number of students. This is to add studies which are not essential to reach the highest grade and to reproduce external enrolment targets. If the expected number of students by age and sex is higher in the alignment targets than produced by the pattern model, additional people are flagged as students by setting the state in_other_education to TRUE. The second state affected is in_school which can be true due to ‘normal’ school attendance (in_regular_school) or due to the additional attendance.

The algorithm is currently kept very simple: eligible for becoming a student in_other_education are those who have been in this status the school year before or those just finishing regular education. A second criterion is family: those living with children are excluded from the pool. People available for additional studies are defined in the actor set asAvailableForAdditionalStudies which can be easily modified to add realism. Alignments are made by the function AlignAfterSchoolYearChange(). The function does not force alignment if no additional students are found. This could be changed by increasing the pool of potential students, e.g. allowing people resuming studies after having left school before, or by allowing people with parenting obligations continuing or resuming studies.



////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor sets
////////////////////////////////////////////////////////////////////////////////////////////////////

//EN People eligible for additional studies after finishing school
actor_set Person asAvailableForAdditionalStudies[sex][integer_age]
    filter (year_finish_school == calendar_year || in_other_education)
    && children_in_household == 0 && !is_flagged_enrol_other_school;

//EN All Persons by age and sex
actor_set Person asAllPersonsSexAge[sex][integer_age] filter is_alive;

//EN All in regular education
actor_set Person asAllInRegularSchool[sex][integer_age] filter in_regular_school;

range AGE_EDUC_ALIGN { 15,30 }; //EN Age


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

parameters
{
    //EN School Enrolment rates (for alignment)
    double SchoolEnrolmentRates[SEX][AGE_EDUC_ALIGN][SIM_YEAR_RANGE];

    //EN Align school enrolment rates
    logical AlignSchoolEnrolmentRates;
};

parameter_group PG_EducAlignment    //EN Education Alignment
{
  SchoolEnrolmentRates, AlignSchoolEnrolmentRates
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor states and functions
////////////////////////////////////////////////////////////////////////////////////////////////////

actor Person
{
    //EN Person gegularely enrolled in school
    logical  in_regular_school = (educ_status == ES_FULLTIME || educ_status == ES_PARTTIME
            || educ_status == ES_DUAL) ? TRUE : FALSE;

    //EN Person in other education (used to align in_school rates to higher targets)
    logical in_other_education = { FALSE };

    //EN Person enrolled in school incl. other (alignment)
    logical  in_school = (in_regular_school || in_other_education) ? TRUE : FALSE;

    //EN Person flagged for enrolling in other education
    logical is_flagged_enrol_other_school = { FALSE };
};

actor Clock
{
    void AlignAfterSchoolYearChange();                  //EN Align school attendance
    hook AlignAfterSchoolYearChange, SchoolYearClock;   //EN Hook school alignment to clock

};

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


void Clock::AlignAfterSchoolYearChange()
{
    if (AlignSchoolEnrolmentRates)
    {
        for (int nAge = MIN(AGE_EDUC_ALIGN); nAge <= MAX(AGE_EDUC_ALIGN); nAge++)
        {
            for (int nSex = 0; nSex < SIZE(SEX); nSex++)
            {
                long nPopAvailable = asAvailableForAdditionalStudies[nSex][nAge]->Count();
                long nPop = asAllPersonsSexAge[nSex][nAge]->Count();
                long nAllInRegularSchool = asAllInRegularSchool[nSex][nAge]->Count();

                long nMissing = long(nPop * SchoolEnrolmentRates[nSex]
                    [RANGE_POS(AGE_EDUC_ALIGN, nAge)][RANGE_POS(SIM_YEAR_RANGE, clock_year)]
                    - nAllInRegularSchool);

                while (nMissing > 0 && asAvailableForAdditionalStudies[nSex][nAge]->Count() > 0)
                {
                    auto prNewStudent = asAvailableForAdditionalStudies[nSex][nAge]
                        ->GetRandom(RandUniform(34));
                    prNewStudent->is_flagged_enrol_other_school = TRUE;
                    nMissing--;
                }
                for (long nIndex = 0; nIndex < nPop; nIndex++)
                {
                    auto prPerson = asAllPersonsSexAge[nSex][nAge]->Item(nIndex);
                    if (prPerson->is_flagged_enrol_other_school) prPerson->in_other_education = TRUE;
                    else  prPerson->in_other_education = FALSE;
                    prPerson->is_flagged_enrol_other_school = FALSE;
                }
            }
        }
        // kick those too old out of school
        long nPop = asAllPersonsSexAge[FEMALE][MAX(AGE_EDUC_ALIGN)+1]->Count();
        for (long nIndex = 0; nIndex < nPop; nIndex++)
        {
            asAllPersonsSexAge[FEMALE][MAX(AGE_EDUC_ALIGN) + 1]
                ->Item(nIndex)->in_other_education = FALSE;
        }
        nPop = asAllPersonsSexAge[MALE][MAX(AGE_EDUC_ALIGN)+1]->Count();
        for (long nIndex = 0; nIndex < nPop; nIndex++)
        {
            asAllPersonsSexAge[MALE][MAX(AGE_EDUC_ALIGN) + 1]->Item(nIndex)
                ->in_other_education = FALSE;
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Validation
////////////////////////////////////////////////////////////////////////////////////////////////////

table Person TabEducAlignmentValidation     //EN Education Alignment
{
    {
        duration(in_school, TRUE) / duration(),           //EN In any school decimals=4
        duration(in_regular_school, TRUE) / duration(),   //EN In regular school decimals=4
        duration(in_other_education, TRUE) / duration()   //EN In other school decimals=4
    }
    * integer_age
    * calendar_year
};