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
};
//