5.4. Step 4: Base Fertility¶
5.4.1. Model Description¶
At this step we add a module for fertility based on age-specific fertility profiles and projected total fertility rates (TFRs). This is the base version of fertility resembling a typical macro population projection approach. It will be complemented with refined models going beyond age and sex when modeling fertility. Besides the introduction of the new module FertilityAgeTFR.mpp, the Start() function of the PeronCore.mpp module is updated for initializing states at birth of new actors born in the simulation. These new baby actors can access characteristics of their mother what is used to set the current time and the state time_of_birth.
5.4.2. The new module: FertilityAgeTFR.mpp¶
This module implements fertility based on age-specific fertility rates calculated from two parameters: an age distribution of fertility and a projected total fertility rate (TFR) for future years. Another parameter is the sex-ratio. This module is a microsimulation implementation of a typical cohort component model.
The actual age-specific period fertility rates are calculated in the PreSimulation function to meet the projected TFR for each year.
The model is prepared for being complemented or over-ridden by an alternative refined fertility model. This is done by three logical states:
- The state use_base_fertility_model is initialized as TRUE; it indicates that the base model is to be used. When adding another model choice this flag can be changed in another module.
- The state use_base_fertility_for_alignment is initialized with FALSE; it indicates if another model is to be aligned to the fertility outcome of this base model.
- The state baby_looking_for_mother is set to TRUE at a birth event if the base model is used for alignment only and the actual birth has to be assigned to another person of the population.
////////////////////////////////////////////////////////////////////////////////////////////////////
// Types
////////////////////////////////////////////////////////////////////////////////////////////////////
range FERTILE_AGE_RANGE { 10, 49 }; //EN Fertile age range
range PARITY_RANGE { 0, 15 }; //EN Parity range
////////////////////////////////////////////////////////////////////////////////////////////////////
// Parameters
////////////////////////////////////////////////////////////////////////////////////////////////////
parameters
{
//EN Age distribution of fertility
double AgeSpecificFertility[FERTILE_AGE_RANGE][SIM_YEAR_RANGE];
//EN Total fertility rate
double TotalFertilityRate[SIM_YEAR_RANGE];
//EN Sex ratio (male per 100 female)
double SexRatio[SIM_YEAR_RANGE];
//EN Age specific fertility rate
model_generated double AgeSpecificFertilityRate[FERTILE_AGE_RANGE][SIM_YEAR_RANGE];
};
parameter_group PG03a_Fertility_Model_A //EN Fertility Base Model
{
AgeSpecificFertility, TotalFertilityRate, SexRatio
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor declarations
////////////////////////////////////////////////////////////////////////////////////////////////////
actor Person
{
logical use_base_fertility_model = { TRUE }; //EN Use the base model
logical use_base_fertility_for_alignment = { FALSE }; //EN Use the model for alignment
logical baby_looking_for_mother = { FALSE }; //EN A birth is still to be created
//EN Indicator that perion is a potential mother
logical is_potential_mother = (sex == FEMALE && WITHIN(FERTILE_AGE_RANGE, integer_age)
&& parity < MAX(PARITY_RANGE) && in_projected_time && ever_resident) ? TRUE : FALSE;
PARITY_RANGE parity; //EN Parity
event timeBirthEvent, BirthEvent; //EN Birth event
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Event Implementations
////////////////////////////////////////////////////////////////////////////////////////////////////
TIME Person::timeBirthEvent()
{
double dEventTime = TIME_INFINITE;
double dHazard = 0.0;
if (is_potential_mother && (use_base_fertility_model || use_base_fertility_for_alignment))
{
dHazard = AgeSpecificFertilityRate[RANGE_POS(FERTILE_AGE_RANGE, integer_age)]
[RANGE_POS(SIM_YEAR_RANGE, calendar_year)];
if (dHazard > 0.0) dEventTime = WAIT(-TIME(log(RandUniform(3)) / dHazard));
}
return dEventTime;
}
void Person::BirthEvent()
{
// event applies to individual without alignment
if (use_base_fertility_model)
{
parity++; // increment parity
auto peChild = new Person; // Create and point to a new actor
peChild->Start(NULL, this); // Call Start() function of baby and pass own address
}
else if (use_base_fertility_for_alignment)
{
baby_looking_for_mother = TRUE;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Pre-Simulation
////////////////////////////////////////////////////////////////////////////////////////////////////
void PreSimulation()
{
double dSum;
for (int nYear = 0; nYear < SIZE(SIM_YEAR_RANGE); nYear++)
{
dSum = 0.0;
// check if distribution parameter adds up too 1
for (int nAge = 0; nAge < SIZE(FERTILE_AGE_RANGE); nAge++)
{
dSum = dSum + AgeSpecificFertility[nAge][nYear];
}
// scale distribution to 1 and convert to fertility rates; copy to model generated parameter
for (int nAge = 0; nAge < SIZE(FERTILE_AGE_RANGE); nAge++)
{
if (dSum > 0.0)
{
AgeSpecificFertilityRate[nAge][nYear]
= AgeSpecificFertility[nAge][nYear] / dSum * TotalFertilityRate[nYear];
}
else AgeSpecificFertilityRate[nAge][nYear] = 0.0;
}
}
}
5.4.3. Update of the Start() function in PersonCore.mpp¶
The Start() function is updated in order to initialize all states at the birth of a baby born in the simulation. In this case values do not come from the starting popiulation file but have to be derived otherwise, e.g. by accessing mother’s characteristics (e.g. for setting the time) or by sampling (e.g. sex according to a parameter for sex ratio).
void Person::Start(Observation *peObservation, Person *pePers)
{
// Setting the actor weight
Set_actor_weight(asGlobals->Item(0)->person_weight);
Set_actor_subsample_weight(asGlobals->Item(0)->person_weight);
// Determine the person type
if (!peObservation && pePers) person_type = PT_CHILD; // Born in simulation
else if (peObservation) person_type = PT_START; // From Starting Pop
else person_type = PT_IMMIGRANT; // Immigrant
// 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;
// (B) Other states
time_of_birth = time;
calendar_year = (int)time_of_birth;
// (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;
// (B) Other states
time_of_birth = time;
calendar_year = (int)time_of_birth;
// (C) Links to head resp. spouse
// (uncomment when modeling families) if (pePers) peHHead = pePers;
}
else // Person is an immigrant
{
// do nothing (immigrants not modeled yet)
}
time_set_alive = WAIT(0);
}
//