Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/populace-build/src/populace/build/us/fiscal_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,16 @@
"count_filter_variable": "is_aca_ptc_eligible",
},
),
("cms_aca", "bronze_aptc_consumers"): (
"selected_marketplace_plan_benchmark_ratio",
"cms_aca",
{
"target_role": "aca_bronze_aptc_consumers",
"measure_mode": "less_than_count",
"count_less_than": "1.0",
"count_filter_variable": "assigned_aca_ptc",
},
),
("cms_medicaid", "total_medicaid_enrollment"): (
"medicaid_enrolled",
"cms_medicaid",
Expand Down
50 changes: 50 additions & 0 deletions packages/populace-build/tests/test_us_fiscal_refresh_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,44 @@ def calculate(self, variable, *, period, map_to=None):
assert np.array_equal(values, np.asarray([1.0, 1.0]))


def test_combined_household_values_threshold_count_keeps_domain_filter(
small_frame,
) -> None:
builder = _load_builder_module()

mapped_values = {
"selected_marketplace_plan_benchmark_ratio": np.asarray([0.8, 1.2, 0.7]),
"assigned_aca_ptc": np.asarray([500.0, 500.0, 0.0]),
}

class FakeSimulation:
def calculate(self, variable, *, period, map_to=None):
assert period == builder.PERIOD
assert map_to is None
return mapped_values[variable]

system = SimpleNamespace(
variables={
"selected_marketplace_plan_benchmark_ratio": SimpleNamespace(
entity=SimpleNamespace(key="tax_unit")
),
"assigned_aca_ptc": SimpleNamespace(entity=SimpleNamespace(key="tax_unit")),
}
)

values = builder._combined_household_values(
frame=small_frame,
simulation=FakeSimulation(),
system=system,
variables=("selected_marketplace_plan_benchmark_ratio",),
tax_unit_positions=np.asarray([0, 0, 1], dtype=np.int64),
filter_variable="assigned_aca_ptc",
less_than=1.0,
)

assert np.array_equal(values, np.asarray([1.0, 0.0]))


def test_release_gate_failures_are_not_unconditional() -> None:
builder = _load_builder_module()
result = SimpleNamespace(
Expand Down Expand Up @@ -527,9 +565,21 @@ def test_fiscal_target_value_basis_keeps_person_counts_separate_from_amounts() -
"count_map_to": "person",
},
)
bronze_count = TargetSpec(
name="bronze_count",
entity="household",
value=100.0,
source="fixture",
metadata={
"measure_mode": "less_than_count",
"source_measure_id": "bronze_aptc_consumers",
"target_role": "aca_bronze_aptc_consumers",
},
)

assert builder._fiscal_target_value_basis(amount) == "amount"
assert builder._fiscal_target_value_basis(person_count) == "person_count"
assert builder._fiscal_target_value_basis(bronze_count) == "person_count"


def test_release_gate_failures_reject_bad_ctc_fit() -> None:
Expand Down
21 changes: 21 additions & 0 deletions packages/populace-build/tests/test_us_fiscal_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ def test_cms_aca_references_use_current_annual_aca_variables() -> None:
"cms_aca.oep2024.state_marketplace.ca.marketplace_enrollment"
)
aptc_source_record_id = "cms_aca.oep2024.state_marketplace.ca.aptc_recipients"
bronze_source_record_id = "cms_aca.oep2024.state_metal.ca.bronze_aptc_consumers"
registry = compile_us_fiscal_target_registry(
[
*packaged_reference_facts(),
Expand All @@ -486,6 +487,15 @@ def test_cms_aca_references_use_current_annual_aca_variables() -> None:
geography_id="0400000US06",
groupby_value_id="ca",
),
_dynamic_ledger_fact(
source_record_id=bronze_source_record_id,
source_name="cms_aca",
measure_id="bronze_aptc_consumers",
value=1_000_000,
geography_level="state",
geography_id="0400000US06",
groupby_value_id="ca",
),
]
)

Expand All @@ -509,6 +519,17 @@ def test_cms_aca_references_use_current_annual_aca_variables() -> None:
assert aptc.metadata["count_filter_variable"] == "is_aca_ptc_eligible"
assert aptc.metadata["state_fips"] == "06"

bronze = specs[bronze_source_record_id]
assert bronze.family == "cms_aca"
assert bronze.metadata["target_role"] == "aca_bronze_aptc_consumers"
assert bronze.metadata["measure_mode"] == "less_than_count"
assert (
bronze.metadata["base_variable"] == "selected_marketplace_plan_benchmark_ratio"
)
assert bronze.metadata["count_less_than"] == "1.0"
assert bronze.metadata["count_filter_variable"] == "assigned_aca_ptc"
assert bronze.metadata["state_fips"] == "06"


def test_soi_premium_tax_credit_targets_use_annual_assigned_ptc() -> None:
amount_source_record_id = (
Expand Down
58 changes: 52 additions & 6 deletions tools/build_us_fiscal_refresh_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,7 @@ def _household_values(
positive_indicator: bool = False,
map_to: str | None = None,
filter_variable: str | None = None,
less_than: float | None = None,
) -> np.ndarray:
entity = _variable_entity(system, variable)
if entity is None:
Expand All @@ -853,16 +854,32 @@ def _household_values(
entity = map_to
if entity == "household":
values = _calculate_array(simulation, variable, map_to=map_to)
filter_values = None
if filter_variable is not None:
filter_values = _calculate_array(simulation, filter_variable, map_to=map_to)
if less_than is not None:
indicator = values < less_than
if filter_values is not None:
indicator &= filter_values > 0
return indicator.astype(np.float64)
if filter_values is not None:
values = np.where(filter_values > 0, values, 0)
return (values > 0).astype(np.float64) if positive_indicator else values
raw = _calculate_array(simulation, variable, map_to=map_to)
filter_values = None
if filter_variable is not None:
filter_values = _calculate_array(simulation, filter_variable, map_to=map_to)
raw = np.where(filter_values > 0, raw, 0)
if positive_indicator:
if less_than is not None:
indicator = raw < less_than
if filter_values is not None:
indicator &= filter_values > 0
raw = indicator.astype(np.float64)
elif positive_indicator:
if filter_values is not None:
raw = np.where(filter_values > 0, raw, 0)
raw = (raw > 0).astype(np.float64)
elif filter_values is not None:
raw = np.where(filter_values > 0, raw, 0)
if entity == "tax_unit":
return _collapse_tax_unit(
raw,
Expand Down Expand Up @@ -892,6 +909,16 @@ def _base_variables_from_metadata(metadata: Mapping[str, str]) -> tuple[str, ...
return (metadata["base_variable"],)


def _less_than_from_metadata(metadata: Mapping[str, str]) -> float | None:
mode = metadata.get("measure_mode", "sum")
threshold = metadata.get("count_less_than")
if mode != "less_than_count":
return None
if threshold is None:
raise ValueError("less_than_count targets must set count_less_than metadata.")
return float(threshold)


def _combined_household_values(
*,
frame: Frame,
Expand All @@ -902,6 +929,7 @@ def _combined_household_values(
positive_indicator: bool = False,
map_to: str | None = None,
filter_variable: str | None = None,
less_than: float | None = None,
) -> np.ndarray:
if len(variables) == 1:
return _household_values(
Expand All @@ -913,6 +941,7 @@ def _combined_household_values(
positive_indicator=positive_indicator,
map_to=map_to,
filter_variable=filter_variable,
less_than=less_than,
)

entities = tuple(_variable_entity(system, variable) for variable in variables)
Expand Down Expand Up @@ -942,7 +971,13 @@ def _combined_household_values(
else:
raw = np.sum(raw_arrays, axis=0, dtype=np.float64)

if filter_variable is not None:
if less_than is not None:
raw = raw < less_than
if filter_variable is not None:
filter_values = _calculate_array(simulation, filter_variable, map_to=map_to)
raw &= filter_values > 0
raw = raw.astype(np.float64)
elif filter_variable is not None:
filter_values = _calculate_array(simulation, filter_variable, map_to=map_to)
raw = np.where(filter_values > 0, raw, 0)

Expand Down Expand Up @@ -1082,13 +1117,22 @@ def _materialize_target_frame(
for spec in target_specs
if spec.metadata.get("materializer") == "policyengine_variable"
]
direct_value_cache: dict[tuple[tuple[str, ...], str, str, str], np.ndarray] = {}
direct_value_cache: dict[
tuple[tuple[str, ...], str, str, str, str], np.ndarray
] = {}
for spec in direct_target_specs:
base_variables = _base_variables_from_metadata(spec.metadata)
mode = spec.metadata.get("measure_mode", "sum")
map_to = spec.metadata.get("count_map_to")
filter_variable = spec.metadata.get("count_filter_variable")
cache_key = (base_variables, mode, map_to or "", filter_variable or "")
less_than = _less_than_from_metadata(spec.metadata)
cache_key = (
base_variables,
mode,
map_to or "",
filter_variable or "",
"" if less_than is None else str(less_than),
)
if cache_key not in direct_value_cache:
variables_to_check = (
*base_variables,
Expand All @@ -1105,6 +1149,7 @@ def _materialize_target_frame(
positive_indicator=mode == "positive_count",
map_to=map_to,
filter_variable=filter_variable,
less_than=less_than,
)
values = direct_value_cache[cache_key]
state_fips = spec.metadata.get("state_fips")
Expand Down Expand Up @@ -1358,9 +1403,10 @@ def _fiscal_target_value_basis(spec) -> str:
if _fiscal_target_is_return_count_measure(source_measure_id)
else "count"
)
if measure_mode in {"count", "positive_count"}:
if measure_mode in {"count", "positive_count", "less_than_count"}:
if metadata.get("count_map_to") == "person" or target_role in {
"aca_enrollment",
"aca_bronze_aptc_consumers",
"aca_ptc_recipients",
"medicaid_enrollment",
"medicaid_chip_enrollment",
Expand Down
Loading