Step 10: Education Pattern
Model Description
At this step we add a module for education pattern: current school attendance, school type, and fulltime/part-time status. Pattern are sampled for a given highest educational attainment ‘fate’ and gender.
The new EducationPattern.mpp Module
The module implements school patterns of school attendance, school type, and enrolment type for a given education fate. School types correspond to the levels low, medium, high but additionally differentiate between dual, vocational, and general tracks. Attendence can be fulltime or parttime. The model is a ‘fate-model’ where for a given final outcome a pattern is assigned early in life. Patterns depend on final outcome (which itself depends on year of birth, sex and parents’s characteristics) and sex. For people of the starting population, educational pattern are imputed using the same model, but if possible respecting the variables on current school attendance. This is archieved in two steps. First for a given fate a pattern is assigned. When all perspms of a birth cohort have their fates assigned, these fates and pattern can be ‘traded’ with others in order to match the school attendance status in the starting population. These trades are within groups by sex and parents’ education thus don not affect the aggregate modeled school attendance.
Once assigned, the actual school attendance pattern are then updated in yearly schoolyear steps. For a given final fate and education pattern, three states are set:
educ_level: the current highest education attainment
educ_status: the current education status (ful-time, part-time, dual, pause etc.)
educ_pattern_status: the current school type and attendence pattern (place in assigned pattern)
//TODO check if for all who need it parents education is available
///////////////////////////////////////////////////////////////////////////////////////////////////
// Dimensions
///////////////////////////////////////////////////////////////////////////////////////////////////
//TODO set exact years, move to _CountryContext
//EN Year of birth for which education patterns have to be checked against school attendance status in startpop
range YOB_CHECK_SCHOOL{ 1980,1990 };
classification EDUC_STATUS //EN Education Status
{
ES_NEVER, //EN Not entered school
ES_FULLTIME, //EN Fulltime Student
ES_PARTTIME, //EN Parttime Student
ES_DUAL, //EN Dual system student
ES_PAUSE, //EN Pause (interruption e.g. military)
ES_FIN //EN Finished schooling
};
classification EDUC_PATTERN //EN Education pattern
{
EP_LOW, //EN Low
EP_MED_DUAL, //EN Medium Dual
EP_MED_VOC, //EN Medium Vocational
EP_MED_GEN, //EN Medium General
EP_OUT1, //EN Out of school spell 1
EP_HIGH1_FT, //EN High Episode 1 (Full-time)
EP_HIGH1_PT, //EN High Episode 1 (Part-time)
EP_OUT2, //EN Out of school spell 2
EP_HIGH2_FT, //EN High Episode 2 (Full-time)
EP_HIGH2_PT, //EN High Episode 2 (Part-time)
EP_OUT3, //EN Out of school spell 3
EP_HIGH3_FT, //EN High Episode 3 (Full-time)
EP_HIGH3_PT //EN High Episode 3 (Part-time)
};
range EDUC_PATTERN_RANGE{ 0, 11 }; //EN Education Pattern
///////////////////////////////////////////////////////////////////////////////////////////////////
// Parameters
///////////////////////////////////////////////////////////////////////////////////////////////////
parameters
{
//EN Education Pattern
int EducPattern[EDUC_LEVEL3][EDUC_PATTERN_RANGE][EDUC_PATTERN];
//EN Education Pattern Distribution
cumrate[1] EducPatternDist[SEX][EDUC_LEVEL3][EDUC_PATTERN_RANGE];
int SchoolEntryAge; //EN School entry age
double StartSchoolYear; //EN Start of school year
};
parameter_group PG_Education //EN Education
{
SchoolEntryAge, StartSchoolYear,
EducPattern, EducPatternDist
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// Actor sets
///////////////////////////////////////////////////////////////////////////////////////////////////
//EN Actor set of all potential students
actor_set Person asAllPotentialStudents
filter is_alive && integer_age >= SchoolEntryAge && year_finish_school >= calendar_year;
//EN Persons who study in startpop and have no matching fate
actor_set Person asWantTradeEducPatternToInSchool[educ_group][sex]
filter integer_age == 2 && want_trade_educ_pattern_to_inschool;
//EN Persons who do not study in startpop and have no matching fate
actor_set Person asWantTradeEducPatternToOutSchool[educ_group][sex]
filter integer_age == 2 && want_trade_educ_pattern_to_outschool;
///////////////////////////////////////////////////////////////////////////////////////////////////
// Actor declarations
///////////////////////////////////////////////////////////////////////////////////////////////////
actor Person
{
EDUC_LEVEL5 educ_level = { EL5_LOW }; //EN Current education level
EDUC_STATUS educ_status = { ES_NEVER }; //EN Current Education Status
logical in_school_startpop = { FALSE }; //EN Attending school in starting population
int year_finish_school = { 9999 }; //EN Year finishing school
EDUC_PATTERN_RANGE educ_pattern_number = { 0 }; //EN Educ Pattern Number
EDUC_PATTERN educ_pattern_status = { EP_LOW }; //EN Education pattern status
void SampleEducPattern(); //EN Sample education fate and pattern
hook SampleEducPattern, YearEnd;
//EN Set Education states for given spell
void SetCurrentEducLevelPatternStatus(int nSchoolSpell);
void SchoolYearChange(); //EN School year change
logical want_trade_educ_pattern_to_inschool = { FALSE };
logical want_trade_educ_pattern_to_outschool = { FALSE };
};
actor Clock
{
void SetNextSchoolYear();
hook SetNextSchoolYear, StartYearClock;
void TradeEducationFatesAndPatterns();
hook TradeEducationFatesAndPatterns, StartYearClock;
TIME next_school_year = { TIME_INFINITE }; //EN Next School Year
event timeSchoolYearClock, SchoolYearClock; //EN School year clock event
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation Clock Functions
///////////////////////////////////////////////////////////////////////////////////////////////////
TIME Clock::timeSchoolYearClock() { return next_school_year; }
void Clock::SchoolYearClock()
{
long nPopSize = asAllPotentialStudents->Count();
for (long nIndex = 0; nIndex < nPopSize; nIndex++)
{
Person *prPerson = asAllPotentialStudents->Item(nIndex);
prPerson->SchoolYearChange();
}
next_school_year = TIME_INFINITE;
}
void Clock::TradeEducationFatesAndPatterns()
{
for (int nGroup = 0; nGroup < SIZE(EDUC_GROUP); nGroup++)
{
for (int nSex = 0; nSex < SIZE(SEX); nSex++)
{
while (asWantTradeEducPatternToInSchool[nGroup][nSex]->Count() > 0 && asWantTradeEducPatternToOutSchool[nGroup][nSex]->Count() > 0)
{
auto prPersonA = asWantTradeEducPatternToInSchool[nGroup][nSex]->GetRandom(RandUniform(24));
auto prPersonB = asWantTradeEducPatternToOutSchool[nGroup][nSex]->GetRandom(RandUniform(25));
EDUC_LEVEL3 cFate = prPersonA->educ_fate;
EDUC_PATTERN_RANGE cPattern = prPersonA->educ_pattern_number;
prPersonA->educ_fate = prPersonB->educ_fate;
prPersonA->educ_pattern_number = prPersonB->educ_pattern_number;
prPersonA->want_trade_educ_pattern_to_inschool = FALSE;
prPersonB->educ_fate = cFate;
prPersonB->educ_pattern_number = cPattern;
prPersonB->want_trade_educ_pattern_to_outschool = FALSE;
}
}
}
}
void Clock::SetNextSchoolYear()
{
next_school_year = WAIT(StartSchoolYear); // set school year clock
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation Person Functions
///////////////////////////////////////////////////////////////////////////////////////////////////
void Person::SampleEducPattern()
{
if (integer_age == 1)
{
int nPattern;
Lookup_EducPatternDist(RandUniform(6), (int)sex, (int)educ_fate, &nPattern);
educ_pattern_number = (EDUC_PATTERN_RANGE)nPattern;
// checks if in_school_startpop contradicts the fate
if (person_type == PT_START && WITHIN(YOB_CHECK_SCHOOL, year_of_birth))
{
int nSchoolTerm = MIN(SIM_YEAR_RANGE) - year_of_birth - SchoolEntryAge - 1;
SetCurrentEducLevelPatternStatus(nSchoolTerm);
if (educ_status == ES_FULLTIME || educ_status == ES_PARTTIME || educ_status == ES_DUAL)
{
if (!in_school_startpop) want_trade_educ_pattern_to_outschool = TRUE;
}
else if (in_school_startpop) want_trade_educ_pattern_to_inschool = TRUE;
}
}
}
void Person::SetCurrentEducLevelPatternStatus(int nSchoolSpell)
{
EDUC_PATTERN cPreviousPatternStatus = educ_pattern_status; //EN Store the current status
//Calculate maximal number of spells for a given educ_fate and educ_pattern_number
int nSumSpells = 0;
for (int nIndex = 0; nIndex < SIZE(EDUC_PATTERN); nIndex++)
{
nSumSpells = nSumSpells + EducPattern[educ_fate][educ_pattern_number][nIndex];
}
if (nSchoolSpell == 0) // Not Started School
{
educ_status = ES_NEVER;
educ_level = EL5_LOW;
}
else if (nSchoolSpell > nSumSpells) // Beyond max spells
{
educ_status = ES_FIN; // Finished school
}
else // Somewhere in system
{
// Find current educ_pattern_status
bool bFound = FALSE; int nColumn = 0; int nItem = 0; int nCount = 0;
while (!bFound)
{
nItem++; nCount++;
while (nItem > EducPattern[educ_fate][educ_pattern_number][nColumn])
{
nItem = 1; nColumn++;
}
if (nCount == nSchoolSpell) // found current educ_pattern_status
{
bFound = TRUE;
educ_pattern_status = ( EDUC_PATTERN )nColumn;
}
}
// Update educ_status
if (educ_pattern_status == EP_HIGH1_PT || educ_pattern_status == EP_HIGH2_PT
|| educ_pattern_status == EP_HIGH3_PT )
{
educ_status = ES_PARTTIME;
}
else if (educ_pattern_status == EP_MED_DUAL )
{
educ_status = ES_DUAL;
}
else if (educ_pattern_status == EP_OUT1 || educ_pattern_status == EP_OUT2
|| educ_pattern_status == EP_OUT3)
{
educ_status = ES_PAUSE;
}
else educ_status = ES_FULLTIME;
}
// Update current education level
if (educ_status == ES_FIN) //End of studies reached
{
EDUC_LEVEL5 elEducLevel;
if (educ_fate == EL3_LOW)
{
elEducLevel = EL5_LOW;
}
else if (educ_fate == EL3_HIGH)
{
elEducLevel = EL5_HIGH;
}
else if (educ_fate == EL3_MEDIUM && educ_level == EL5_LOW && cPreviousPatternStatus == EP_MED_DUAL)
{
elEducLevel = EL5_MEDIUMD;
}
else if (educ_fate == EL3_MEDIUM && educ_level == EL5_LOW && cPreviousPatternStatus == EP_MED_VOC)
{
elEducLevel = EL5_MEDIUMV;
}
else if (educ_fate == EL3_MEDIUM && educ_level == EL5_LOW && cPreviousPatternStatus == EP_MED_GEN)
{
elEducLevel = EL5_MEDIUMG;
}
else elEducLevel = educ_level;
educ_level = elEducLevel;
}
// Change of school type to high or pause (must have finished medium)
else if (educ_level == EL5_LOW && (educ_status == ES_PAUSE
|| educ_pattern_status == EP_HIGH1_FT || educ_pattern_status == EP_HIGH1_PT))
{
if (cPreviousPatternStatus == EP_MED_DUAL) educ_level = EL5_MEDIUMD;
else if (cPreviousPatternStatus == EP_MED_VOC) educ_level = EL5_MEDIUMV;
else if (cPreviousPatternStatus == EP_MED_GEN) educ_level = EL5_MEDIUMG;
}
}
void Person::SchoolYearChange()
{
if (integer_age >= SchoolEntryAge) SetCurrentEducLevelPatternStatus(integer_age - SchoolEntryAge + 1);
if (educ_status == ES_FIN && year_finish_school > calendar_year) year_finish_school = calendar_year;
}
table Person TabEducTrade2 //EN TEST Trading school age 2
[integer_age == 2]
{
educ_group + *
sex + *
{
duration(want_trade_educ_pattern_to_inschool,TRUE) / duration(), //EN Wants trade to inschool decimals=4
duration(want_trade_educ_pattern_to_outschool,TRUE) / duration() //EN Wants trade to outschool decimals=4
}
*year_of_birth
};
table Person TabEducTrade3 //EN TEST Trading school age 3
[integer_age == 4]
{
educ_group + *
sex + *
{
duration(want_trade_educ_pattern_to_inschool,TRUE) / duration(), //EN Wants trade to inschool decimals=4
duration(want_trade_educ_pattern_to_outschool,TRUE) / duration() //EN Wants trade to outschool decimals=4
}
*year_of_birth
};
table Person TabEducParents2 //EN TEST Education of parents
[integer_age == 2]
{
{
duration(educ_parents,EL3_LOW) / duration(), //EN LOW decimals=4
duration(educ_parents,EL3_MEDIUM) / duration(), //EN MED decimals=4
duration(educ_parents,EL3_HIGH) / duration() //EN HIG decimals=4
}
*year_of_birth
};
Initialisations in the Start() function in PersonCore.mpp
The state in_school_startpop os initialized in the Start function for those coming from the starting population.
// Initialize states
if (person_type == PT_START) // Person comes from starting population
{
// (A) States from Starting population file
time = peObservation->pmc[PMC_BIRTH] + RandUniform(2);
sex = (SEX)(int)peObservation->pmc[PMC_SEX];
family_role = (FAM_ROLE)( int )peObservation->pmc[PMC_ROLE];
educ_startpop = (EDUC_LEVEL5)(int)peObservation->pmc[PMC_EDUC];
in_school_startpop = (bool)(int)peObservation->pmc[PMC_INSCHOOL];
//