Skip to content

Commit 0310968

Browse files
FertilityCrudeBirthRate scaling and age min check (#577)
Category: bugfix JIRA issue: https://jira.ihme.washington.edu/browse/MIC-5915 Changes and notes Use initialization age max instead of untracking age when determining GBD population size of the population demographic restricted to the sim. Remove check that untracking age equals exit age. Testing Ran pytest.
1 parent b194e54 commit 0310968

File tree

4 files changed

+48
-19
lines changed

4 files changed

+48
-19
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
**4.3.18 - 01/06/26**
2+
3+
- Bugfix: Fix population scaling in FertilityCrudeBirthRate
4+
15
**4.3.17 - 12/18/25**
26

37
- Bugfix: Fix failing doc builds

src/vivarium_public_health/population/add_new_birth_cohorts.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ class FertilityCrudeBirthRate(Component):
111111
#####################
112112

113113
def setup(self, builder: Builder) -> None:
114+
config = builder.configuration.population
115+
if config.initialization_age_min != 0:
116+
raise ValueError(
117+
"Configuration key 'initialization_age_min' must be 0 if using FertilityCrudeBirthRate. "
118+
f"Provided value: {config.initialization_age_min}"
119+
)
114120
self.birth_rate = get_live_births_per_year(builder)
115121

116122
self.clock = builder.time.clock()

src/vivarium_public_health/population/data_transformations.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -566,31 +566,25 @@ def get_live_births_per_year(builder):
566566

567567

568568
def rescale_final_age_bin(builder, population_data):
569-
untracking_age = builder.configuration.population.to_dict().get("untracking_age", None)
570-
if untracking_age:
569+
initialization_age_max = builder.configuration.population.to_dict().get(
570+
"initialization_age_max", None
571+
)
572+
573+
if initialization_age_max:
571574
population_data = population_data.loc[
572-
population_data["age_start"] < untracking_age
575+
population_data["age_start"] < initialization_age_max
573576
].copy()
574-
cut_bin_idx = untracking_age <= population_data["age_end"]
577+
cut_bin_idx = initialization_age_max <= population_data["age_end"]
575578
cut_age_start = population_data.loc[cut_bin_idx, "age_start"]
576579
cut_age_end = population_data.loc[cut_bin_idx, "age_end"]
577-
population_data.loc[cut_bin_idx, "value"] *= (untracking_age - cut_age_start) / (
578-
cut_age_end - cut_age_start
579-
)
580-
population_data.loc[cut_bin_idx, "age_end"] = untracking_age
580+
population_data.loc[cut_bin_idx, "value"] *= (
581+
initialization_age_max - cut_age_start
582+
) / (cut_age_end - cut_age_start)
583+
population_data.loc[cut_bin_idx, "age_end"] = initialization_age_max
581584
return population_data
582585

583586

584587
def validate_crude_birth_rate_data(builder, data_year_max):
585-
population_config = builder.configuration.population.to_dict()
586-
untracking_age = population_config.get("untracking_age", None)
587-
age_end = population_config.get("age_end", None)
588-
if untracking_age and age_end and age_end != untracking_age:
589-
raise ValueError(
590-
"If you specify an exit age, the initial population age end must be the same "
591-
"for the crude birth rate calculation to work."
592-
)
593-
594588
exceeds_data = builder.configuration.time.end.year > data_year_max
595589
if exceeds_data and not builder.configuration.interpolation.extrapolate:
596590
raise ValueError("Trying to extrapolate beyond the end of available birth data.")

tests/population/test_add_new_birth_cohort.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def test_FertilityDeterministic(config):
5252

5353
config.update(
5454
{"fertility": {"number_of_new_simulants_each_year": annual_new_simulants}},
55-
**metadata(__file__)
55+
**metadata(__file__),
5656
)
5757

5858
components = [TestPopulation(), FertilityDeterministic()]
@@ -131,7 +131,7 @@ def test_FertilityCrudeBirthRate_extrapolate(base_config, base_plugins):
131131
}
132132
)
133133
pop_size = base_config.population.population_size
134-
true_pop_size = 25000 # What's available in the mock artifact
134+
true_pop_size = 20_000 # What's available in the mock artifact
135135
live_births_by_sex = 500
136136
components = [TestPopulation(), FertilityCrudeBirthRate()]
137137

@@ -157,6 +157,31 @@ def test_FertilityCrudeBirthRate_extrapolate(base_config, base_plugins):
157157
np.testing.assert_allclose(birth_rate, given_birth_rate, atol=0.01)
158158

159159

160+
@pytest.mark.parametrize("initialization_age_min", [0.05, 1, 10])
161+
def test_FertilityCrudeBirthRate_with_non_zero_initialization_age_min_error(
162+
base_config, base_plugins, initialization_age_min
163+
):
164+
components = [TestPopulation(), FertilityCrudeBirthRate()]
165+
base_config.update(
166+
{
167+
"population": {
168+
"initialization_age_min": initialization_age_min,
169+
},
170+
},
171+
layer="override",
172+
)
173+
174+
with pytest.raises(
175+
ValueError,
176+
match=f"'initialization_age_min' must be 0 if using FertilityCrudeBirthRate. Provided value: {initialization_age_min}",
177+
):
178+
simulation = InteractiveContext(
179+
components=components,
180+
configuration=base_config,
181+
plugin_configuration=base_plugins,
182+
)
183+
184+
160185
def test_fertility_module(base_config, base_plugins):
161186
start_population_size = 1000
162187
num_days = 1000

0 commit comments

Comments
 (0)