Step 11: Female Partnership Status
Overview
At this step we add a new module for maintaining the female partnership status according to observed partnership patterns by age (at last birth), age of youngest child, and education. The female partnership status is updated at the middle of each year according to model parameters. This is a base module working entirely due to alignment. It can be refined by adding union dissolution events on the micro level.
The new FemalePartnershipStatus.mpp Module
This module implements processes for maintaining the partnership status of women over the life course (union formation, disslolution, calls for matching a suitable partner). The female partnership status is updated at yearly events according to observed partnership patterns by education, age / age group at last birth, and age group of youngest child. The partnership status is modeled for all women within the age range 15-80, no more union formation events are modled thereafter when it is assumed the onlz union dissolution is due to widowhood.
Parameters:
Proportion of women living with dependent children who are in a partnership by education, age group at last birth and age group of youngest child
Proportion of women not living with dependent children who are in a partnership by education and age
The model maintaines the patterns contained in the parameters in the future, thus we assume that these patterns are stable and changes in aggregate partnership characteristics only result from compositional changes in the female population like childlessness and timing of births. The model follows a ‘minimum necessary corrections’ approach changing the union status of women only to meet aggregate numbers. In reality, unions are more unstable, i.e. the model does not move women out of a union and others in if the aggregate proportion does not change. It can be refined e.g. by adding a union dissolution module at the micro level if a higher life course consistency is important for model applications.
The core of this module is the Clock function UpdatePartnershipStatus() which is hooked to the Clock’s mid-year event. Alternatively, the function could be hooked to the mid-month event to add precision (at the cost of performance).
Code Changes in other modules:
The module requires a function FindPartner() which is declared and implemented in the module PartnerMatching.mpp.
link Person.lMother Person.mlMothersChildren[]; //EN Link between children and Mother
link Person.lFather Person.mlFathersChildren[]; //EN Link between children and Father
////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor Sets
////////////////////////////////////////////////////////////////////////////////////////////////////
//EN Women in a partnership living with dependent children
actor_set Person asPopInUnionWithChildren[educ3_level][child_agegr][moth_agegr]
filter is_alive && sex == FEMALE && in_projected_time && WITHIN(PART_AGE_RANGE, integer_age) &&
in_union && lives_with_dependent_child;
//EN Women not in a partnership living with dependent children
actor_set Person asPopNotInUnionWithChildren[educ3_level][child_agegr][moth_agegr]
filter is_alive && sex == FEMALE && in_projected_time && WITHIN(PART_AGE_RANGE, integer_age) &&
!in_union && lives_with_dependent_child;
//EN Women living with dependent children
actor_set Person asPopWithChildren[educ3_level][child_agegr][moth_agegr]
filter is_alive && sex == FEMALE && in_projected_time && WITHIN(PART_AGE_RANGE, integer_age) &&
lives_with_dependent_child;
//EN Women not living with dependent children
actor_set Person PopNoChildren[educ3_level][integer_age]
filter is_alive && sex == FEMALE && in_projected_time && WITHIN(PART_AGE_RANGE, integer_age) &&
!lives_with_dependent_child;
//EN Women in a partnership not living with dependent children
actor_set Person asPopInUnionNoChildren[educ3_level][integer_age]
filter is_alive && sex == FEMALE && in_projected_time && WITHIN(PART_AGE_RANGE, integer_age) &&
in_union && !lives_with_dependent_child;
//EN Women not in a partnership not living with dependent children
actor_set Person asPopNotInUnionNoChildren[educ3_level][integer_age]
filter is_alive && sex == FEMALE && in_projected_time && WITHIN(PART_AGE_RANGE, integer_age) &&
!in_union && !lives_with_dependent_child;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Dimensions
////////////////////////////////////////////////////////////////////////////////////////////////////
partition CHILD_AGEGR_PART { 1,3,6,9,12,15 }; //EN Age of youngest child
partition MOTH_AGEGR_PART { 20, 25, 30, 35, 40 }; //EN Age of mother at last birth
range PART_AGE_RANGE { 15, 80 }; //EN Age
classification MOTH_AGEGR //EN Age group mothers at birth
{
CMA20, //EN Below 20
CMA25, //EN 20 to 24
CMA30, //EN 25 to 19
CMA35, //EN 30 to 34
CMA40, //EN 35 to 39
CMA40P //EN 40+
};
classification CHILD_AGEGR //EN Age group child
{
CA00, //EN 0
CA01, //EN 1 to 2
CA03, //EN 3 to 5
CA06, //EN 6 to 8
CA09, //EN 9 to 11
CA12, //EN 12 to 14
CA15 //EN 15 to 17
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Parameters
////////////////////////////////////////////////////////////////////////////////////////////////////
parameters
{
//EN Probability to be in a partnership - Females living with children
double InUnionProbWithChildren[EDUC_LEVEL3][CHILD_AGEGR][MOTH_AGEGR];
//EN Probability to be in a partnership - Females not living with children
double InUnionProbNoChildren[PART_AGE_RANGE][EDUC_LEVEL3];
};
parameter_group PG_FemalePartnerships //EN Female Partnership Status
{
InUnionProbWithChildren,
InUnionProbNoChildren
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor States & Functions
////////////////////////////////////////////////////////////////////////////////////////////////////
actor Person
{
int int_age = integer_age;
EDUC_LEVEL3 educ3_level = aggregate(educ_level, EDUC_LEVEL3);
//EN Person currently in a union
logical in_union = (lSpouse != NULL) ? TRUE : FALSE;
//EN Age of youngest child of women
double age_youngest_child = (count(mlMothersChildren) > 0 && sex == FEMALE) ?
min_over(mlMothersChildren, int_age) : TIME_INFINITE;
//EN Age group of youngest child of women
int child_agegr_part = split(age_youngest_child, CHILD_AGEGR_PART);
//EN Woman lives with a child afe < 18
logical lives_with_dependent_child = (age_youngest_child < 18) ? TRUE : FALSE;
//EN Woman's age at last birth if living with children < 18
double age_last_birth = (lives_with_dependent_child) ?
integer_age - age_youngest_child : TIME_INFINITE;
//EN Age group at last birth
int moth_agegr_part = split(age_last_birth, MOTH_AGEGR_PART);
//EN Age group at last birth
MOTH_AGEGR moth_agegr = (moth_agegr_part == 0) ? CMA20 :
(moth_agegr_part == 1) ? CMA25 :
(moth_agegr_part == 2) ? CMA30 :
(moth_agegr_part == 3) ? CMA35 :
(moth_agegr_part == 4) ? CMA40 : CMA40P;
//EN Age group child
CHILD_AGEGR child_agegr = (child_agegr_part == 0) ? CA00 :
(child_agegr_part == 1) ? CA01 :
(child_agegr_part == 2) ? CA03 :
(child_agegr_part == 3) ? CA06 :
(child_agegr_part == 4) ? CA09 :
(child_agegr_part == 5) ? CA12 : CA15;
};
actor Clock
{
void UpdatePartnershipStatus(); //EN Update Female Partnership Status
hook UpdatePartnershipStatus, MidYearClockEvent; //EN hook to mid year
};
void Clock::UpdatePartnershipStatus()
{
long nTarget;
if (clock_year >= MIN(SIM_YEAR_RANGE))
{
// Women with children
for (int nEduc = 0; nEduc < SIZE(EDUC_LEVEL3); nEduc++)
{
for (int nChildAge = 0; nChildAge < SIZE(CHILD_AGEGR); nChildAge++)
{
for (int nMothAge = 0; nMothAge < SIZE(MOTH_AGEGR); nMothAge++)
{
nTarget = round(InUnionProbWithChildren[nEduc][nChildAge][nMothAge] *
asPopWithChildren[nEduc][nChildAge][nMothAge]->Count());
if (nTarget > asPopInUnionWithChildren[nEduc][nChildAge][nMothAge]->Count())
{
long nEmptyRun = 0;
while (nTarget > asPopInUnionWithChildren[nEduc][nChildAge][nMothAge]->Count() &&
asPopNotInUnionWithChildren[nEduc][nChildAge][nMothAge]->Count() > 0 && nEmptyRun < 10000)
{
auto prFam = asPopNotInUnionWithChildren[nEduc][nChildAge][nMothAge]->GetRandom(RandUniform(55));
if (!prFam->FindPartner()) nEmptyRun++;
}
}
else if (nTarget < asPopInUnionWithChildren[nEduc][nChildAge][nMothAge]->Count())
{
while (nTarget < asPopInUnionWithChildren[nEduc][nChildAge][nMothAge]->Count() &&
asPopInUnionWithChildren[nEduc][nChildAge][nMothAge]->Count() > 0)
{
auto prFam = asPopInUnionWithChildren[nEduc][nChildAge][nMothAge]->GetRandom(RandUniform(57));
prFam->lSpouse = NULL;
}
}
}
}
}
//Targets for women without children in hh
for (int nEduc = 0; nEduc < SIZE(EDUC_LEVEL3); nEduc++)
{
for (int nAge = 0; nAge < SIZE(PART_AGE_RANGE); nAge++)
{
nTarget = round(InUnionProbNoChildren[nAge][nEduc] *
PopNoChildren[nEduc][nAge + MIN(PART_AGE_RANGE)]->Count());
if (nTarget > asPopInUnionNoChildren[nEduc][nAge + MIN(PART_AGE_RANGE)]->Count())
{
long nEmptyRun = 0;
while (nTarget > asPopInUnionNoChildren[nEduc][nAge + MIN(PART_AGE_RANGE)]->Count() &&
asPopNotInUnionNoChildren[nEduc][nAge + MIN(PART_AGE_RANGE)]->Count() > 0 && nEmptyRun < 10000)
{
auto prFam = asPopNotInUnionNoChildren[nEduc][nAge + MIN(PART_AGE_RANGE)]->GetRandom(RandUniform(58));
if (!prFam->FindPartner()) nEmptyRun++;
}
}
else if (nTarget < asPopInUnionNoChildren[nEduc][nAge + MIN(PART_AGE_RANGE)]->Count())
{
while (nTarget < asPopInUnionNoChildren[nEduc][nAge + MIN(PART_AGE_RANGE)]->Count() &&
asPopInUnionNoChildren[nEduc][nAge + MIN(PART_AGE_RANGE)]->Count() > 0)
{
auto prFam = asPopInUnionNoChildren[nEduc][nAge + MIN(PART_AGE_RANGE)]->GetRandom(RandUniform(61));
prFam->lSpouse = NULL;
}
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Tables
////////////////////////////////////////////////////////////////////////////////////////////////////
table_group TabValidationPartnershipStatus //EN Female partnership status
{
TabTestPartnershipStatusWithKids2020,
TabTestPartnershipStatusNoKids2020,
TabParaPartnershipStatusWithKids,
TabParaPartnershipStatusNoKids
};
table Person TabTestPartnershipStatusWithKids2020
[lives_with_dependent_child && in_projected_time && calendar_year == 2020
&& sex == FEMALE && WITHIN(PART_AGE_RANGE, integer_age)]
{
educ3_level + *
{
duration(in_union,TRUE) / duration() //EN Proportion in partnership decimals=4
}
*moth_agegr +
*child_agegr +
};
table Person TabTestPartnershipStatusNoKids2020
[!lives_with_dependent_child && in_projected_time && calendar_year == 2020
&& sex == FEMALE && WITHIN(PART_AGE_RANGE, integer_age)]
{
{
duration(in_union, TRUE) / duration() //EN Proportion in partnership decimals=4
}
*integer_age +
*educ3_level +
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Tables for parameter generation
partition SECOND_AFTER{ 2010.01, 2010.02 };
actor Person
{
logical second_after = (self_scheduling_split(time,SECOND_AFTER) == 1) ? TRUE : FALSE;
};
//EN Proportion of women living with dependent children who are in a partnership
table Person TabParaPartnershipStatusWithKids
[trigger_entrances(second_after, TRUE) && lives_with_dependent_child && in_projected_time
&& sex == FEMALE && WITHIN(PART_AGE_RANGE, integer_age)]
{
educ3_level + *
{
value_in(in_union) / unit //EN Proportion in partnership decimals=4
}
*child_agegr +
*moth_agegr +
};
//EN Proportion of women not living with dependent children who are in a partnership
table Person TabParaPartnershipStatusNoKids
[trigger_entrances(second_after, TRUE) && !lives_with_dependent_child && in_projected_time
&& sex == FEMALE && WITHIN(PART_AGE_RANGE, integer_age)]
{
{
value_in(in_union) / unit //EN Proportion in partnership decimals=4
}
*integer_age +
*educ3_level +
};
The new module PartnerMatching.mpp
At the current step 11 of model development, this module is a dummy module only. It implements the function FindPartner which randomly chooses and links an available partner of the same age. If non is found, the function returns FALSE. This module is to be refined at a later step.
////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor Sets
////////////////////////////////////////////////////////////////////////////////////////////////////
//EN Males not in a partnershio by age
actor_set Person asAvailableMale[integer_age] filter is_alive && sex == MALE && !lSpouse;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Actor states, events and functions
////////////////////////////////////////////////////////////////////////////////////////////////////
actor Person
{
logical FindPartner();
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////////////////////////
logical Person::FindPartner()
{
if (asAvailableMale[integer_age]->Count() > 0)
{
auto prPartner = asAvailableMale[integer_age]->GetRandom(RandUniform(26));
lSpouse = prPartner;
return TRUE;
}
else return FALSE;
}