5.21. Step 21: Analysis Files Output¶
5.21.1. Model Description¶
At this step we add modules to produce simulated analysis files of the same formats as used to create the starting population and to estimate all parameters. This output can be used for retrospective model validation as well as for the creation of synthetic model test data. The module is optional and can be deactivated by the user.
5.21.2. The AnalysisDataOutput.mpp Module¶
This module implements micro-data output of analysis files in the format required to create a model starting population and to estimate all parameters. Four files are created:
- Residents: a synthetic future census
- Emigrants: emigrants of the past 12 months
- Births: retrospective birth histories
- Children: retrospective child records of births in the past 5 years for the analysis of mortality and child vaccination
Model users have the following choices:
- Switching the file output on/off
- Setting a point in time for the output
- Selecting file names for the four output files
This module is optional. For efficiency reasons, an additional actor AnalysisRecord is introduced which contains most states introduced in this module. If analysis data output is de-activated by the user, no such actors are created saving memory space.
////////////////////////////////////////////////////////////////////////////////////////////////////
// Links
////////////////////////////////////////////////////////////////////////////////////////////////////
link Person.lHHMother Person.mlHHMotherChildren[]; //EN HH Mother - Children
link Person.lAnalysisRecord AnalysisRecord.lPerson; //EN Link between analysis record and person
////////////////////////////////////////////////////////////////////////////////////////////////////
// Files
////////////////////////////////////////////////////////////////////////////////////////////////////
output_csv residents_csv; //EN Residents file
output_csv emigrants_csv; //EN Emigrants file
output_csv births_csv; //EN Births records file
output_csv children_csv; //EN Child history file
////////////////////////////////////////////////////////////////////////////////////////////////////
// Types
////////////////////////////////////////////////////////////////////////////////////////////////////
range BIRTH_INDEX { 0, 13 }; //EN Birth Index
////////////////////////////////////////////////////////////////////////////////////////////////////
// Parameters
////////////////////////////////////////////////////////////////////////////////////////////////////
parameters
{
file AnalysisFileNameResidents; //EN File name: Residents
file AnalysisFileNameEmigrants; //EN File name: Emigrants
file AnalysisFileNameBirths; //EN File name: Births
file AnalysisFileNameChildren; //EN File name: Children
logical AnalysisFileOutputYN; //EN Analysis file output Y/N
double AnalysisFileOutputTime; //EN Time of analysis file output
};
parameter_group PG_AnalysisFileOutput //EN Analysis File Output
{
AnalysisFileOutputYN, AnalysisFileOutputTime,
AnalysisFileNameResidents, AnalysisFileNameEmigrants,
AnalysisFileNameBirths, AnalysisFileNameChildren
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor declarations
////////////////////////////////////////////////////////////////////////////////////////////////////
actor Person
{
logical analysis_output_is_done = { FALSE }; //EN Analysis file output is done
event timeAnalysisOutputEvent, AnalysisOutputEvent; //EN Analysis file output event
void WriteAnalysisRecordEmigrant(); //EN Write emigrants record
void WriteAnalysisRecordChild(); //EN Write child record
hook WriteAnalysisRecordChild, MortalityEvent; //EN Hook to Mortality
void CreateAnalysisRecord(); //EN Create analysis record
hook CreateAnalysisRecord, SetAliveEvent; //EN Hook to Set Alive
void RemoveAnalysisRecord(); //EN Remove analysis record
hook RemoveAnalysisRecord, Finish; //EN Hook to Finish
};
actor AnalysisRecord
{
long pers_hh_id = { -1 }; //EN Household ID
REGION_INT pers_rob = { REGI_ABROAD }; //EN Region of birth
TIME age_at_marriage = { 999 }; //EN Age at marriage
TIME age_last_birth = { 999 }; //EN Age at last birth
TIME age_last_move = { 999 }; //EN Age at last move
REGION_INT previous_region = { REGI_ABROAD }; //EN Previous Region
DISTRICT_INT previous_district = { DISTI_ABROAD }; //EN Previous District
// Birth records variables
int month_birth[BIRTH_INDEX]; //EN Month of births 1..14
void Start(Person *prPerson); //EN Start
void Finish(); //EN Finish
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////////////////////////
void Person::CreateAnalysisRecord()
{
if (AnalysisFileOutputYN)
{
auto prAnalysisRecord = new AnalysisRecord();
prAnalysisRecord->Start(this);
}
}
void Person::RemoveAnalysisRecord()
{
if (AnalysisFileOutputYN && lAnalysisRecord) lAnalysisRecord->Finish();
}
void AnalysisRecord::Start(Person *prPerson)
{
lPerson = prPerson;
pers_rob = lPerson->region_int;
for (int nIndex = 0; nIndex < SIZE(BIRTH_INDEX); nIndex++) month_birth[nIndex] = 9999;
}
void AnalysisRecord::Finish(){}
TIME Person::timeAnalysisOutputEvent()
{
if (AnalysisFileOutputYN && !analysis_output_is_done && GetReplicate()==0
&& AnalysisFileOutputTime >= MIN(SIM_YEAR_RANGE) )
{
return AnalysisFileOutputTime;
}
else return TIME_INFINITE;
}
void Person::WriteAnalysisRecordEmigrant()
{
emigrants_csv << actor_weight; // weight
emigrants_csv << (int)DISTI_ABROAD; // district (abroad)
emigrants_csv << (int)district_nat; // previous district of residence
emigrants_csv << (int)region_nat; // previous region of residence
emigrants_csv << age; // age
emigrants_csv << (int)sex; // sex
emigrants_csv.write_record(); // write the record
}
void Person::WriteAnalysisRecordChild()
{
if (is_alive && is_resident && lHHMother && lHHMother->age < 50 - (AnalysisFileOutputTime-time))
{
int nMonthDeath = 9999;
if (!analysis_output_is_done) nMonthDeath = (int)((time - 1900) * 12);
children_csv << actor_weight; // weight
children_csv << (int)((AnalysisFileOutputTime - 1900) * 12); // Month of interview
children_csv << (int)(lHHMother->region_nat); // Region
children_csv << (int)((time - age - 1900) * 12); // month of birth
children_csv << nMonthDeath; // month of death
children_csv << (int)sex; // sex
children_csv << (int)(mother_age_at_birth * 12); // Mothers age at birth (months)
children_csv << (int)educ_mother; // Primary education of mother
children_csv << (int)ethnicity; // Ethnicity
children_csv << (int)is_immunized; // Child is vaccinated
children_csv << (int)(lHHMother->district_nat); // District
children_csv << (int)got_prenat_care; // Mother received prenatal care
children_csv << (int)is_stunted; // Stunted
children_csv.write_record(); // write the record
}
}
void Person::AnalysisOutputEvent()
{
// Never do again
analysis_output_is_done = TRUE;
///////////////////////////////////////////////////////////////////////////////////////////////
// Write Resident File
///////////////////////////////////////////////////////////////////////////////////////////////
if (is_resident && is_alive)
{
// Calculate some variables
// Household ID
long nHhId = actor_id;
if (lHHMother && age < 18 && !in_union && parity == 0) // A child knowing her mother
{
nHhId = lHHMother->actor_id;
}
// Age last birth (check if infor from staring population relevant)
if (time_since_last_birth_start > 0.0)
{
lAnalysisRecord->age_last_birth = age - time_since_last_birth_start - (time - MIN(SIM_YEAR_RANGE));
}
// Birth past 12 months
bool bBirth12 = FALSE;
if (age - lAnalysisRecord->age_last_birth >= 0.0 && age - lAnalysisRecord->age_last_birth <= 1.0)
{
bBirth12 = TRUE;
}
// District and region 12 months age
int nLastDistrict = (int)district_int;
int nLastRegion = (int)region_int;
if (age - lAnalysisRecord->age_last_move <= 1.0 && age - lAnalysisRecord->age_last_move >= 0.0)
{
nLastDistrict = (int)lAnalysisRecord->previous_district;
nLastRegion = (int)lAnalysisRecord->previous_region;
}
// Push the fields into the output record.
residents_csv << actor_id; // Actor ID
residents_csv << nHhId; // Household ID
residents_csv << actor_weight; // Weight
residents_csv << age; // Age
residents_csv << (int)sex; // Sex
residents_csv << (int)district_birth; // District of birth
residents_csv << (int)district_int; // District of residence
residents_csv << nLastDistrict; // District 12 months ago
residents_csv << (int)tab_primary_level; // Education
residents_csv << (int)parity; // Parity
residents_csv << (int)bBirth12; // Births past 12 months
residents_csv << lAnalysisRecord->age_at_marriage; // Age at marriage
residents_csv << lAnalysisRecord->age_last_birth; // Age at most recent birth
residents_csv << (int)lAnalysisRecord->pers_rob; // Region of birth
residents_csv << (int)region_int; // Region of residence
residents_csv << nLastRegion; // Region 12 months ago
residents_csv << (int)ethnicity; // Ethnicity
residents_csv.write_record();
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Write Births File
///////////////////////////////////////////////////////////////////////////////////////////////
if (is_resident && is_alive && sex == FEMALE && age >= 15 && age < 50)
{
int nMonthMarriage = 9999;
if (lAnalysisRecord->age_at_marriage > 5 && lAnalysisRecord->age_at_marriage < age)
{
nMonthMarriage = int((time - age + lAnalysisRecord->age_at_marriage - 1900) * 12);
}
for (int nIndex = 0; nIndex < SIZE(BIRTH_INDEX); nIndex++)
{
births_csv << lAnalysisRecord->month_birth[nIndex]; // Months of births
}
births_csv << actor_weight; // Weight
births_csv << int((time - age - 1900) * 12); // Month of own birth
births_csv << (int)tab_primary_level; // Primary education
births_csv << (int)region_int; // Region of residence
births_csv << (int)((time - 1900) * 12); // Month of interview
births_csv << nMonthMarriage; // Age at marriage
births_csv << (int)district_int; // District
births_csv.write_record();
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Write Child File
///////////////////////////////////////////////////////////////////////////////////////////////
WriteAnalysisRecordChild();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Pre- and Post-Simulation
////////////////////////////////////////////////////////////////////////////////////////////////////
void PreSimulation()
{
// In the pre-simulation phase the micro-data file is prepared
// for writing records in the simulation. If the user selects data output, a file is
// opened and the header row is written containing all selected states
if (AnalysisFileOutputYN)
{
// residents
std_string residentString = "M_ID,"; // ID
residentString = residentString + "M_HHID,"; // Household ID
residentString = residentString + "M_WEIGHT,"; // Weight
residentString = residentString + "M_AGE,"; // Age
residentString = residentString + "M_MALE,"; // Sex
residentString = residentString + "M_DOB,"; // District of birth
residentString = residentString + "M_DOR,"; // District of residence
residentString = residentString + "M_PDIST,"; // District 12 months ago
residentString = residentString + "M_EDUC,"; // Education
residentString = residentString + "M_PARITY,"; // Parity
residentString = residentString + "M_BIR12,"; // Births past 12 months
residentString = residentString + "M_AGEMAR,"; // Age at marriage
residentString = residentString + "M_AGEBIR,"; // Age at most recent birth
residentString = residentString + "M_ROB,"; // Region of birth
residentString = residentString + "M_ROR,"; // Region of residence
residentString = residentString + "M_PREG,"; // Region 12 months ago
residentString = residentString + "M_ETHNO,"; // Ethnicity
residents_csv.open(AnalysisFileNameResidents);
residents_csv.precision(9);
residents_csv.write_header(residentString);
// emigrants
std_string emigrantString = "M_WEIGHT,"; // weight
emigrantString = emigrantString + "M_DOR,"; // district of residence
emigrantString = emigrantString + "M_PDIST,"; // previous district
emigrantString = emigrantString + "M_PREG,"; // previous region
emigrantString = emigrantString + "M_AGE,"; // Age
emigrantString = emigrantString + "M_MALE,"; // Sex
emigrants_csv.open(AnalysisFileNameEmigrants);
emigrants_csv.precision(9);
emigrants_csv.write_header(emigrantString);
// births
std_string birthString = "M_B01,"; // Month birth 01
birthString = birthString + "M_B02,"; // Month birth 02
birthString = birthString + "M_B03,"; // Month birth 03
birthString = birthString + "M_B04,"; // Month birth 04
birthString = birthString + "M_B05,"; // Month birth 05
birthString = birthString + "M_B06,"; // Month birth 06
birthString = birthString + "M_B07,"; // Month birth 07
birthString = birthString + "M_B08,"; // Month birth 08
birthString = birthString + "M_B09,"; // Month birth 09
birthString = birthString + "M_B10,"; // Month birth 10
birthString = birthString + "M_B11,"; // Month birth 11
birthString = birthString + "M_B12,"; // Month birth 12
birthString = birthString + "M_B13,"; // Month birth 13
birthString = birthString + "M_B14,"; // Month birth 14
birthString = birthString + "M_WEIGHT,"; // Weight
birthString = birthString + "M_BIRTH,"; // Month of own birth
birthString = birthString + "M_EDUC,"; // Primary Education
birthString = birthString + "M_REG,"; // Region
birthString = birthString + "M_INTERV,"; // Month of interview
birthString = birthString + "M_MAR,"; // Month of first marriage
birthString = birthString + "M_DOR,"; // District
births_csv.open(AnalysisFileNameBirths);
births_csv.precision(9);
births_csv.write_header(birthString);
// Children
std_string childString = "M_WEIGHT,"; // Weight
childString = childString + "M_INTERV,"; // Month of interview
childString = childString + "M_REGION,"; // Region
childString = childString + "M_BIRTH,"; // Month of birth
childString = childString + "M_DEATH,"; // Month of death
childString = childString + "M_MALE,"; // Sex
childString = childString + "M_AGEMO,"; // Age of mother (months) at birth
childString = childString + "M_EDUCMO,"; // Education of mother
childString = childString + "M_ETHNO,"; // Ethnicity
childString = childString + "M_VACC,"; // Immunization
childString = childString + "M_DOR,"; // District
childString = childString + "M_PCARE,"; // Prenatal care
childString = childString + "M_STUNTED,"; // Stunted
children_csv.open(AnalysisFileNameChildren);
children_csv.precision(9);
children_csv.write_header(childString);
}
}
void PostSimulation()
{
// close files
if (AnalysisFileOutputYN)
{
residents_csv.close();
emigrants_csv.close();
births_csv.close();
children_csv.close();
}
}
5.21.3. Changes in PersonCore.mpp¶
else if (person_type == PT_CHILD) // Person born in simulation
{
// Code added at step 21
lHHMother = pePers; //EN Link Person to HH Mother
if (lHHMother->lAnalysisRecord)
{
lHHMother->lAnalysisRecord->age_last_birth = lHHMother->age;
if (lHHMother->parity <= SIZE(BIRTH_INDEX))
{
int nMonth = int((time - 1900) * 12);
lHHMother->lAnalysisRecord->month_birth[lHHMother->parity - 1] = nMonth;
}
}
5.21.4. Changes in MigrationAgeSex.mpp¶
void Person::MigrationEvent()
{
int nDestination;
int nAge5 = SPLIT(integer_age, AGE5_PART);
// Code added at step 21
if (lAnalysisRecord)
{
lAnalysisRecord->age_last_move = age;
lAnalysisRecord->previous_district = district_int;
lAnalysisRecord->previous_region = region_int;
}
// End 21
// Sample the destination
Lookup_MigrationDestination(RandUniform(6), sex, district_nat, nAge5, &nDestination);
// Move the actor to the destination
district_int = (DISTRICT_INT)nDestination;
// Updates indicators
age_at_last_move = integer_age;
number_migrations++;
}
5.21.5. Changes in ImmigrationAgeSexDistrict.mpp¶
void Person::ImmigrationEvent()
{
// Code added at step 21
if (lAnalysisRecord)
{
lAnalysisRecord->age_last_move = age;
lAnalysisRecord->previous_district = district_int;
lAnalysisRecord->previous_region = region_int;
}
// End 21
district_int = (DISTRICT_INT)(int)district_immi;
ever_resident = TRUE;
time_of_immigration = TIME_INFINITE;
IMPLEMENT_HOOK();
}
5.21.6. Changes in FirstUnionCoaleMcNeil.mpp¶
void Person::Union1FormationEvent()
{
in_union = TRUE;
// Code added at step 21
if (lAnalysisRecord) lAnalysisRecord->age_at_marriage = age;
}
5.21.7. Changes in EmigrationAgeSexDistrict.mpp¶
void Person::EmigrationEvent()
{
// Code added at step 20
if (lAnalysisRecord && AnalysisFileOutputTime - time >= 0.0 && AnalysisFileOutputTime - time <= 1.0)
{
WriteAnalysisRecordEmigrant();
}