5.5. Step 5: Base Migration¶
5.5.1. Model Description¶
At this step we add a module for internal migration based on age and sex specific origin-destination matrices. This is the base version of migration resembling a typical macro population projection approach. It will be complemented with refined models going beyond age and sex when modeling migration.
5.5.2. The new module: MigrationAgeSex.mpp¶
This module implements a base version of internal migration. It is based on age and sex specific transition matrices, which is a typical approach in cohort-component models. As the transitions are typically obtained from Census data recording the place of residence now and one year ago, only one transition per year is allowed. The module has three parameters, one to switch migration on/off, one containing the probabilities to move away (by origin, age, sex), and one to sample the destination (by origin, age and sex).
The module introduces and maintains a new state district_int - the district of residence. The state is of type DISTRICT_INT, which is a classification of districts incl. abroad. As the number and names of districts is country-specific, the classification is declare in the _CountryContext.mpp module. The district of residence is available from the starting population file, is inherited from the mother, or set at immigration. This is done in the Start() function of the Person actor. The initialization was added there when introducing this module.
A state is_resident indicates if a person currently resides in the country. If so, another derived state district_nat (including all national districts, i.e. not containing a level for abroad) can be used. Districts are the smallest geographical level in the model. They are automatically aggregated to regions in the corresponding states region_int and region_nat. The number and names of regions as well as the aggregation rules are country-specific and declared in the _CountryContext.mpp module.
The module is prepared for being replaced by a refined model accounting for more detailed personal characteristics than age and sex. For this purpose a logical state use_base_migration_model is introduced and initialized with TRUE; Other modules can override this module by setting the state to FALSE whenever an alternative model is applied.
////////////////////////////////////////////////////////////////////////////////////////////////////
// Types
////////////////////////////////////////////////////////////////////////////////////////////////////
partition AGE5_PART{ 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60 }; //EN Age Groups
////////////////////////////////////////////////////////////////////////////////////////////////////
// Parameters
////////////////////////////////////////////////////////////////////////////////////////////////////
parameters
{
//EN Migration switched on/off
logical ModelMigration;
//EN Migration probability
double MigrationProbability[SEX][AGE5_PART][DISTRICT_NAT];
//EN Migration Destination
cumrate MigrationDestination[SEX][DISTRICT_NAT][AGE5_PART][DISTRICT_NAT];
};
parameter_group PG_MigrationBase //EN Internal Migration Base Version
{
ModelMigration, MigrationProbability, MigrationDestination
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor block
////////////////////////////////////////////////////////////////////////////////////////////////////
actor Person
{
DISTRICT_INT district_int = { DISTI_00 }; //EN District of residence
//EN District of residence (residents only)
DISTRICT_NAT district_nat = aggregate( district_int, DISTRICT_NAT );
//EN Region of residence
REGION_INT region_int = aggregate( district_int, REGION_INT);
//EN Region of residence (residents only)
REGION_NAT region_nat = aggregate( region_int, REGION_NAT);
//EN Currently a resident
logical is_resident = (district_int != DISTI_ABROAD) ? TRUE : FALSE;
logical use_base_migration_model = { TRUE }; //EN Use the base model
integer age_at_last_move = { 999 }; //EN Age at last migration
integer number_migrations = { 0 }; //EN Number of internal migrations
event timeMigrationEvent, MigrationEvent; //EN Migration Event
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////////////////////////
TIME Person::timeMigrationEvent()
{
// Check if a person is at risk for moving
if (ModelMigration && use_base_migration_model && in_projected_time
&& age_at_last_move != integer_age && is_resident)
{
// get the current age index using SPLIT()
int nAge5 = SPLIT(integer_age, AGE5_PART);
// get the probability to move
double dMoveProb = MigrationProbability[sex][nAge5][district_nat];
if (dMoveProb <= 0.0) return TIME_INFINITE; // Not at risk
else if (dMoveProb >= 1.0) return WAIT(0); // 100% move immediately
else // positive probability below 100%
{
// calculate a random waiting time based on the given probability converted to
// a hazard rate = -log(1-probability)
return WAIT(-log(RandUniform(5)) / -log(1 - dMoveProb));
}
}
return TIME_INFINITE;
}
void Person::MigrationEvent()
{
int nDestination;
int nAge5 = SPLIT(integer_age, AGE5_PART);
// Sample the destination
Lookup_MigrationDestination(RandUniform(6), sex, district_nat, nAge5, &nDestination);
// Move the actor to the destination
district_int = (DISTRICT_INT)nDestination;
// Updates ndicators
age_at_last_move = integer_age;
number_migrations++;
}
5.5.3. Update of the Start() function in PersonCore.mpp¶
The Start() function is updated in order to initialize the new state for district of residence (district_nat).
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;
district_int = (DISTRICT_INT)(int)peObservation->pmc[PMC_DISTRICT];
// (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;
district_int = pePers->district_int;
// (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);
}
//
5.5.4. Declaration of the List of Districts in _CountryContext.mpp¶
As the number and names of districts is country-specific, it is declared in the module _CountryContext.mpp.
classification DISTRICT_NAT //EN District
{
DISTN_00, //EN Far-West Mountains
DISTN_01, //EN Far-West Hills
DISTN_02, //EN Far-West Lowlands
DISTN_03, //EN West Mountains
DISTN_04, //EN West Hills
DISTN_05, //EN West Lowlands
DISTN_06, //EN Central Mountains
DISTN_07, //EN Central Hills
DISTN_08, //EN Central Lowlands
DISTN_09, //EN East Mountains
DISTN_10, //EN The Capital
DISTN_11 //EN East Lowlands
};
classification DISTRICT_INT //EN District
{
DISTI_00, //EN Far-West Mountains
DISTI_01, //EN Far-West Hills
DISTI_02, //EN Far-West Lowlands
DISTI_03, //EN West Mountains
DISTI_04, //EN West Hills
DISTI_05, //EN West Lowlands
DISTI_06, //EN Central Mountains
DISTI_07, //EN Central Hills
DISTI_08, //EN Central Lowlands
DISTI_09, //EN East Mountains
DISTI_10, //EN The Capital
DISTI_11, //EN East Lowlands
DISTI_ABROAD //EN Abroad
};
classification REGION_NAT //EN Region
{
REGN_00, //EN Far-West
REGN_01, //EN West
REGN_02, //EN Central
REGN_03, //EN The Capital
REGN_04 //EN East
};
classification REGION_INT //EN Region
{
REGI_00, //EN Far-West
REGI_01, //EN West
REGI_02, //EN Central
REGI_03, //EN The Capital
REGI_04, //EN East
REGI_ABROAD //EN Abroad
};
//EN Aggregation District International to National (use with filter is_resident only)
aggregation DISTRICT_NAT, DISTRICT_INT
{
DISTN_00, DISTI_00,
DISTN_01, DISTI_01,
DISTN_02, DISTI_02,
DISTN_03, DISTI_03,
DISTN_04, DISTI_04,
DISTN_05, DISTI_05,
DISTN_06, DISTI_06,
DISTN_07, DISTI_07,
DISTN_08, DISTI_08,
DISTN_09, DISTI_09,
DISTN_10, DISTI_10,
DISTN_11, DISTI_11,
DISTN_11, DISTI_ABROAD
};
//EN Aggregation Region International to National (use with filter is_resident only )
aggregation REGION_NAT, REGION_INT
{
REGN_00, REGI_00,
REGN_01, REGI_01,
REGN_02, REGI_02,
REGN_03, REGI_03,
REGN_04, REGI_04,
REGN_04, REGI_ABROAD
};
//EN Aggregation District to Region
aggregation REGION_INT, DISTRICT_INT
{
REGI_00, DISTI_00,
REGI_00, DISTI_01,
REGI_00, DISTI_02,
REGI_01, DISTI_03,
REGI_01, DISTI_04,
REGI_01, DISTI_05,
REGI_02, DISTI_06,
REGI_02, DISTI_07,
REGI_02, DISTI_08,
REGI_04, DISTI_09,
REGI_03, DISTI_10,
REGI_04, DISTI_11,
REGI_ABROAD, DISTI_ABROAD
};
//