Skip to content
Merged
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
2 changes: 1 addition & 1 deletion packages/populace-build/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ dependencies = [
# The US extra adds the rules engine for formula-owned export checks. Source
# content is declared in packaged manifests and interpreted by shared Populace
# runtimes; country source loaders must not depend on incumbent data packages.
us = ["policyengine-us>=1.729,<2", "h5py>=3", "microunit>=0.1.0", "tables>=3"]
us = ["policyengine-us>=1.745.0,<2", "h5py>=3", "microunit>=0.1.0", "tables>=3"]
# The UK extra adds the rules engine for local metric generation from a
# Populace UK H5. Target tables remain explicit inputs, and the base package
# still does not import policyengine-uk at import time.
Expand Down
2 changes: 2 additions & 0 deletions packages/populace-build/src/populace/build/source_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@
"assign_by_plan_type",
"assign_binary_from_rate",
"calibrate_binary_assignment",
"calibrate_binary_assignment_joint_targets",
"convert_interest_to_structural_mortgage_inputs",
"compute_ratio",
"derive",
"derive_puf_policyengine_variables",
"derive_mortgage_balance_hints",
"disaggregate_aggregate_records",
"fit_labor_market_models",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
"E00200",
"P23250",
"P22250",
"E00650",
"qualified_dividend_income",
"E00300",
"E26270",
"E00900",
"E02100",
"E00400",
"E00600"
"non_qualified_dividend_income"
],
"buckets": {
"999996": {
Expand Down
90 changes: 79 additions & 11 deletions packages/populace-build/src/populace/build/us/source_stages.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@
"table": "puf_tax_unit",
"weight": "s006"
},
{
"kind": "derive_puf_policyengine_variables",
"ordinary_dividend_source": "E00600",
"qualified_dividend_source": "E00650",
"qualified_dividend_output": "qualified_dividend_income",
"non_qualified_dividend_output": "non_qualified_dividend_income"
},
{
"kind": "disaggregate_aggregate_records",
"method": "donor_template_calibration",
Expand All @@ -42,7 +49,8 @@
"employment_income",
"self_employment_income",
"taxable_interest_income",
"ordinary_dividends",
"qualified_dividend_income",
"non_qualified_dividend_income",
"capital_gains",
"filing_status"
]
Expand All @@ -53,21 +61,65 @@
}
],
"outputs": [
"salt_deduction",
"medical_expense_deduction",
"charitable_deduction",
"interest_deduction",
"qualified_business_income",
"employment_income_before_lsr",
"self_employment_income_before_lsr",
"taxable_interest_income",
"qualified_dividend_income",
"non_qualified_dividend_income",
"tax_exempt_interest_income",
"short_term_capital_gains",
"long_term_capital_gains_before_response",
"non_sch_d_capital_gains",
"taxable_private_pension_income",
"taxable_ira_distributions",
"social_security_retirement",
"social_security_disability",
"social_security_dependents",
"social_security_survivors",
"charitable_cash_donations",
"charitable_non_cash_donations",
"real_estate_taxes",
"home_mortgage_interest",
"student_loan_interest",
"rental_income",
"estate_income",
"farm_income",
"miscellaneous_income",
"partnership_income",
"s_corp_income",
"partnership_self_employment_net_earnings",
"partnership_s_corp_loss"
"first_home_mortgage_balance",
"second_home_mortgage_balance",
"first_home_mortgage_interest",
"second_home_mortgage_interest",
"first_home_mortgage_origination_year",
"second_home_mortgage_origination_year"
],
"nonnegative_outputs": [
"salt_deduction",
"medical_expense_deduction",
"charitable_deduction",
"interest_deduction"
"employment_income_before_lsr",
"self_employment_income_before_lsr",
"taxable_interest_income",
"qualified_dividend_income",
"non_qualified_dividend_income",
"tax_exempt_interest_income",
"long_term_capital_gains_before_response",
"taxable_private_pension_income",
"taxable_ira_distributions",
"social_security_retirement",
"social_security_disability",
"social_security_dependents",
"social_security_survivors",
"charitable_cash_donations",
"charitable_non_cash_donations",
"real_estate_taxes",
"home_mortgage_interest",
"student_loan_interest",
"first_home_mortgage_balance",
"second_home_mortgage_balance",
"first_home_mortgage_interest",
"second_home_mortgage_interest",
"first_home_mortgage_origination_year",
"second_home_mortgage_origination_year"
],
"notes": "PUF detail is a primary-source donor and must stay separate from benchmark comparisons. IRS disclosure aggregate rows are replaced from raw PUF aggregate totals before uprating; Forbes top-tail synthesis is not enabled."
},
Expand Down Expand Up @@ -533,6 +585,22 @@
"domain": "is_aca_ptc_eligible",
"weight": "tax_unit_weight"
},
{
"kind": "calibrate_binary_assignment_joint_targets",
"variable": "takes_up_aca_if_eligible",
"count_targets": [
"irs_soi_premium_tax_credit_returns_by_state"
],
"amount_targets": [
"irs_soi_premium_tax_credit_amount_by_state"
],
"optional": true,
"preserve_true_anchors": true,
"preserve_true_anchor": "reported_has_subsidized_marketplace_health_coverage_at_interview",
"domain": "is_aca_ptc_eligible",
"count_weight": "household_weight",
"amount_weight": "weighted_assigned_aca_ptc"
},
{
"kind": "compute_ratio",
"output": "selected_marketplace_plan_benchmark_ratio",
Expand Down
12 changes: 12 additions & 0 deletions packages/populace-build/src/populace/build/us_runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
load_asec_h5_tables,
pool_asec_sources,
)
from populace.build.us_runtime.cps_carried import (
CPS_CARRIED_FORMULA_OWNED_COLUMNS,
CPS_CARRIED_PERSON_INPUTS,
derive_us_cps_carried_inputs,
)
from populace.build.us_runtime.demographics import (
AGE_BANDS,
DEMOGRAPHICS_SCHEMA_VERSION,
Expand Down Expand Up @@ -69,6 +74,8 @@
)
from populace.build.us_runtime.puf_support import (
BASE_ASEC_SUPPORT_CHANNEL,
PUF_TAX_DETAIL_DEFAULT_PERSON_OUTPUTS,
PUF_TAX_DETAIL_DEFAULT_TAX_UNIT_OUTPUTS,
PUF_TAX_DETAIL_SUPPORT_CHANNEL,
US_PUF_SUPPORT_STAGE_NAME,
clone_us_frame_for_puf_support,
Expand Down Expand Up @@ -107,6 +114,8 @@
"BuildConfig",
"AsecSource",
"BASE_ASEC_SUPPORT_CHANNEL",
"CPS_CARRIED_FORMULA_OWNED_COLUMNS",
"CPS_CARRIED_PERSON_INPUTS",
"SimpleTaxExpenditureReform",
"ReformValidationSpec",
"REFORM_VALIDATION_SCHEMA_VERSION",
Expand Down Expand Up @@ -138,13 +147,16 @@
"US_SOURCE_MANIFEST",
"US_SOURCE_STAGE_SPECS",
"US_STAGE_NAMES",
"PUF_TAX_DETAIL_DEFAULT_PERSON_OUTPUTS",
"PUF_TAX_DETAIL_DEFAULT_TAX_UNIT_OUTPUTS",
"PUF_TAX_DETAIL_SUPPORT_CHANNEL",
"US_PUF_SUPPORT_STAGE_NAME",
"US_STATE_INCOME_TAX_TARGET_SPECS",
"US_STATE_INCOME_TAX_TARGET_REFERENCES",
"compile_us_fiscal_target_registry",
"build_pooled_asec_unit_frame",
"clone_us_frame_for_puf_support",
"derive_us_cps_carried_inputs",
"disaggregate_us_puf_aggregate_records_from_manifest",
"hard_target_package_aliases",
"impute_us_puf_tax_detail_support",
Expand Down
49 changes: 49 additions & 0 deletions packages/populace-build/src/populace/build/us_runtime/asec_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def build_pooled_asec_unit_frame(
tax_unit_mode=tax_unit_mode,
strata=strata,
)
frame = _attach_household_attributes(frame, ("state_fips",))
return frame, pooled.metadata


Expand Down Expand Up @@ -279,6 +280,18 @@ def _remap_source_year(
result["source_household_id"] = result["PH_SEQ"].to_numpy()
result["source_person_id"] = _source_person_id(result)
result["source_row_id"] = np.arange(len(result), dtype=np.int64)
if "GESTFIPS" in household:
state_by_household = (
household[["H_SEQ", "GESTFIPS"]]
.drop_duplicates("H_SEQ")
.set_index("H_SEQ")["GESTFIPS"]
)
result["state_fips"] = (
result["source_household_id"]
.map(state_by_household)
.astype("int64")
.to_numpy()
)
result["PH_SEQ"] = result["PH_SEQ"].map(household_map).astype("int64")
result["household_id"] = result["PH_SEQ"]
result[ASEC_PERSON_WEIGHT_COLUMN] = (
Expand All @@ -287,6 +300,42 @@ def _remap_source_year(
return result, next_offset


def _attach_household_attributes(frame: Frame, columns: tuple[str, ...]) -> Frame:
person = frame.table("person")
available = [column for column in columns if column in person]
if not available:
return frame

household = frame.table("household").copy()
tables = {entity: frame.table(entity).copy() for entity in frame.entities}
for column in available:
values = person.groupby("person_household_id", sort=True)[column]
low = values.min()
high = values.max()
unequal = low.to_numpy() != high.to_numpy()
if unequal.any():
bad = low.index.to_numpy()[unequal][:5].tolist()
raise ValueError(
f"Household attribute {column!r} must be constant within "
f"household; household id(s) {bad} carry unequal values."
)
household[column] = (
pd.Series(household["household_id"])
.map(low)
.astype(person[column].dtype)
.to_numpy()
)
tables["person"] = tables["person"].drop(columns=[column])
tables["household"] = household
return Frame(
tables,
frame.schema,
{entity: frame.weights_for(entity) for entity in frame.weighted_entities},
frame.strata,
mass_log=frame.mass_log,
)


def _globalize_source_unit_column(person: pd.DataFrame, column: str) -> pd.DataFrame:
if column not in person.columns:
return person
Expand Down
Loading
Loading