Clean vehicle credit#
The clean vehicle tax credit was introduced in 2008 and overhauled in the Inflation Reduction Act (IRA), signed in August 2022.
Examples#
Consider a filer in Massachusetts who buys a new Tesla Model Y—the top-selling clean vehicle as of July 2022—in 2023. Under pre-IRA law, they would not be eligible as Tesla has surpassed its manufacturer cap, but the IRA repeals that cap. The IRA adds new requirements to the credit around the manufacturer retail selling price, battery components and elements countries of origin, and filer income. It leaves the credit non-refundable, producing a phase-in.
from policyengine_us import IndividualSim
import pandas as pd
import plotly.express as px
def make(adults, children, purchased_qualifying_new_clean_vehicle):
sim = IndividualSim(year=2023)
# Specify age 25 to qualify for EITC.
sim.add_person(name="head", age=25, is_tax_unit_head=True)
members = ["head"]
if adults == 2:
sim.add_person(name="spouse")
members.append("spouse")
for i in range(children):
child = "child{}".format(i)
sim.add_person(name=child, age=5)
members.append(child)
sim.add_tax_unit(
name="tax_unit",
members=members,
purchased_qualifying_new_clean_vehicle=purchased_qualifying_new_clean_vehicle,
new_clean_vehicle_battery_capacity=70,
# Assume it meets both requirements.
new_clean_vehicle_battery_critical_minerals_extracted_in_trading_partner_country=0.5,
new_clean_vehicle_battery_components_made_in_north_america=0.5,
new_clean_vehicle_classification="SUV",
new_clean_vehicle_msrp=65_990, # Per Google.
premium_tax_credit=0,
)
sim.add_spm_unit(name="spm_unit", members=members)
sim.add_household(name="household", members=members, state_code="MA")
sim.vary("employment_income", max=350_000)
return pd.DataFrame(
dict(
employment_income=sim.calc("employment_income")[0],
spm_unit_net_income=sim.calc("spm_unit_net_income")[0],
credit=sim.calc("new_clean_vehicle_credit")[0],
adults=adults,
children=children,
purchased_qualifying_new_clean_vehicle=purchased_qualifying_new_clean_vehicle,
)
)
l = []
for adults in [1, 2]:
for children in range(0, 4):
for purchased_qualifying_new_clean_vehicle in [True, False]:
l.append(
make(adults, children, purchased_qualifying_new_clean_vehicle)
)
df = pd.concat(l)
wide = df.pivot(
index=["employment_income", "adults", "children"],
columns="purchased_qualifying_new_clean_vehicle",
values="spm_unit_net_income",
).reset_index()
wide["benefit"] = wide[True] - wide[False]
LABELS = dict(
employment_income="Employment income",
benefit="Net clean vehicle credit",
children="Children",
adults="Adults",
)
fig = px.line(
wide,
"employment_income",
"benefit",
color="children",
animation_frame="adults",
labels=LABELS,
title="Net benefit from clean vehicle credit under Inflation Reduction Act",
)
fig.update_layout(xaxis_tickformat="$,", yaxis_tickformat="$,")
fig.show()
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/individual_sim.py:261, in IndividualSim.calc(self, var, period, target, index, map_to, reform)
260 try:
--> 261 result = self.simulation.calculate(var, period)
262 except:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:684, in Simulation._run_formula(self, variable, population, period)
683 for added_variable in adds_list:
--> 684 values = values + self.calculate(
685 added_variable, period, map_to=variable.entity.key
686 )
687 if variable.subtracts is not None:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py:34, in spm_unit_benefits.formula(spm_unit, period, parameters)
33 BENEFITS.append("spm_unit_capped_housing_subsidy")
---> 34 return add(spm_unit, period, BENEFITS)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/commons/formulas.py:225, in add(entity, period, variables, options)
211 """Sums a list of variables.
212
213 Args:
(...)
223 ArrayLike: The result of the operation.
224 """
--> 225 return for_each_variable(
226 entity, period, variables, agg_func="add", options=options
227 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/commons/formulas.py:184, in for_each_variable(entity, period, variables, agg_func, group_agg_func, options)
182 elif variable_entity.is_person:
183 values = group_agg_func(
--> 184 entity.members(variable, period, options=options)
185 )
186 elif entity.entity.is_person:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/ssi.py:16, in ssi.formula(person, period, parameters)
15 return 0
---> 16 return max_(0, person("uncapped_ssi", period))
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/uncapped_ssi.py:13, in uncapped_ssi.formula(person, period, parameters)
12 def formula(person, period, parameters):
---> 13 amount = person("ssi_amount_if_eligible", period)
14 meets_resource_test = person("meets_ssi_resource_test", period)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/ssi_amount_if_eligible.py:16, in ssi_amount_if_eligible.formula(person, period, parameters)
13 ssi = parameters(period).gov.ssa.ssi.amount
14 return (
15 where(
---> 16 person("ssi_claim_is_joint", period),
17 ssi.couple,
18 ssi.individual,
19 )
20 * MONTHS_IN_YEAR
21 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/ssi_claim_is_joint.py:12, in ssi_claim_is_joint.formula(person, period, parameters)
11 eligible = person("is_ssi_aged_blind_disabled", period)
---> 12 both_eligible = person.marital_unit.sum(eligible) == 2
13 income_is_deemed = (
14 person("ssi_income_deemed_from_ineligible_spouse", period) > 0
15 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/projectors/projector.py:28, in Projector.__getattr__.<locals>.projector_function(*args, **kwargs)
27 result = reference_attr(*args, **kwargs)
---> 28 return self.transform_and_bubble_up(result)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/projectors/projector.py:37, in Projector.transform_and_bubble_up(self, result)
36 def transform_and_bubble_up(self, result):
---> 37 transformed_result = self.transform(result)
38 if self.parent is None:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/projectors/entity_to_person_projector.py:19, in EntityToPersonProjector.transform(self, result)
18 def transform(self, result: ArrayLike) -> ArrayLike:
---> 19 return self.reference_entity.project(result)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/group_population.py:335, in GroupPopulation.project(self, array, role)
334 def project(self, array: ArrayLike, role: Role = None) -> ArrayLike:
--> 335 self.check_array_compatible_with_entity(array)
336 self.entity.check_role_validity(role)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:60, in Population.check_array_compatible_with_entity(self, array)
59 if not self.count == array.size:
---> 60 raise ValueError(
61 "Input {} is not a valid value for the entity {} (size = {} != {} = count)".format(
62 array, self.entity.key, array.size, self.count
63 )
64 )
ValueError: Input [0. 0. 0. ... 0. 0. 0.] is not a valid value for the entity marital_unit (size = 7001 != 7002 = count)
During handling of the above exception, another exception occurred:
ValueError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/individual_sim.py:264, in IndividualSim.calc(self, var, period, target, index, map_to, reform)
263 try:
--> 264 result = self.sim.calculate_add(var, period)
265 except:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:597, in Simulation.calculate_add(self, variable_name, period, decode_enums)
591 raise ValueError(
592 "Unable to sum constant variable '{}' over period {}: only variables defined daily, monthly, or yearly can be summed over time.".format(
593 variable.name, period
594 )
595 )
--> 597 return sum(
598 self.calculate(variable_name, sub_period)
599 for sub_period in period.get_subperiods(variable.definition_period)
600 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:598, in <genexpr>(.0)
591 raise ValueError(
592 "Unable to sum constant variable '{}' over period {}: only variables defined daily, monthly, or yearly can be summed over time.".format(
593 variable.name, period
594 )
595 )
597 return sum(
--> 598 self.calculate(variable_name, sub_period)
599 for sub_period in period.get_subperiods(variable.definition_period)
600 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:684, in Simulation._run_formula(self, variable, population, period)
683 for added_variable in adds_list:
--> 684 values = values + self.calculate(
685 added_variable, period, map_to=variable.entity.key
686 )
687 if variable.subtracts is not None:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py:34, in spm_unit_benefits.formula(spm_unit, period, parameters)
33 BENEFITS.append("spm_unit_capped_housing_subsidy")
---> 34 return add(spm_unit, period, BENEFITS)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/commons/formulas.py:225, in add(entity, period, variables, options)
211 """Sums a list of variables.
212
213 Args:
(...)
223 ArrayLike: The result of the operation.
224 """
--> 225 return for_each_variable(
226 entity, period, variables, agg_func="add", options=options
227 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/commons/formulas.py:184, in for_each_variable(entity, period, variables, agg_func, group_agg_func, options)
182 elif variable_entity.is_person:
183 values = group_agg_func(
--> 184 entity.members(variable, period, options=options)
185 )
186 elif entity.entity.is_person:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/ssi.py:16, in ssi.formula(person, period, parameters)
15 return 0
---> 16 return max_(0, person("uncapped_ssi", period))
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/uncapped_ssi.py:13, in uncapped_ssi.formula(person, period, parameters)
12 def formula(person, period, parameters):
---> 13 amount = person("ssi_amount_if_eligible", period)
14 meets_resource_test = person("meets_ssi_resource_test", period)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/ssi_amount_if_eligible.py:16, in ssi_amount_if_eligible.formula(person, period, parameters)
13 ssi = parameters(period).gov.ssa.ssi.amount
14 return (
15 where(
---> 16 person("ssi_claim_is_joint", period),
17 ssi.couple,
18 ssi.individual,
19 )
20 * MONTHS_IN_YEAR
21 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/ssi_claim_is_joint.py:12, in ssi_claim_is_joint.formula(person, period, parameters)
11 eligible = person("is_ssi_aged_blind_disabled", period)
---> 12 both_eligible = person.marital_unit.sum(eligible) == 2
13 income_is_deemed = (
14 person("ssi_income_deemed_from_ineligible_spouse", period) > 0
15 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/projectors/projector.py:28, in Projector.__getattr__.<locals>.projector_function(*args, **kwargs)
27 result = reference_attr(*args, **kwargs)
---> 28 return self.transform_and_bubble_up(result)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/projectors/projector.py:37, in Projector.transform_and_bubble_up(self, result)
36 def transform_and_bubble_up(self, result):
---> 37 transformed_result = self.transform(result)
38 if self.parent is None:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/projectors/entity_to_person_projector.py:19, in EntityToPersonProjector.transform(self, result)
18 def transform(self, result: ArrayLike) -> ArrayLike:
---> 19 return self.reference_entity.project(result)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/group_population.py:335, in GroupPopulation.project(self, array, role)
334 def project(self, array: ArrayLike, role: Role = None) -> ArrayLike:
--> 335 self.check_array_compatible_with_entity(array)
336 self.entity.check_role_validity(role)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:60, in Population.check_array_compatible_with_entity(self, array)
59 if not self.count == array.size:
---> 60 raise ValueError(
61 "Input {} is not a valid value for the entity {} (size = {} != {} = count)".format(
62 array, self.entity.key, array.size, self.count
63 )
64 )
ValueError: Input [0. 0. 0. ... 0. 0. 0.] is not a valid value for the entity marital_unit (size = 7001 != 7002 = count)
During handling of the above exception, another exception occurred:
ValueError Traceback (most recent call last)
Cell In[1], line 51
48 for children in range(0, 4):
49 for purchased_qualifying_new_clean_vehicle in [True, False]:
50 l.append(
---> 51 make(adults, children, purchased_qualifying_new_clean_vehicle)
52 )
54 df = pd.concat(l)
56 wide = df.pivot(
57 index=["employment_income", "adults", "children"],
58 columns="purchased_qualifying_new_clean_vehicle",
59 values="spm_unit_net_income",
60 ).reset_index()
Cell In[1], line 37, in make(adults, children, purchased_qualifying_new_clean_vehicle)
32 sim.add_household(name="household", members=members, state_code="MA")
33 sim.vary("employment_income", max=350_000)
34 return pd.DataFrame(
35 dict(
36 employment_income=sim.calc("employment_income")[0],
---> 37 spm_unit_net_income=sim.calc("spm_unit_net_income")[0],
38 credit=sim.calc("new_clean_vehicle_credit")[0],
39 adults=adults,
40 children=children,
41 purchased_qualifying_new_clean_vehicle=purchased_qualifying_new_clean_vehicle,
42 )
43 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/individual_sim.py:266, in IndividualSim.calc(self, var, period, target, index, map_to, reform)
264 result = self.sim.calculate_add(var, period)
265 except:
--> 266 result = self.simulation.calculate_divide(var, period)
267 if (
268 target is not None
269 and target not in self.situation_data[entity.plural]
270 ):
271 map_to = self.get_entity(target).key
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:634, in Simulation.calculate_divide(self, variable_name, period, decode_enums)
630 return (
631 self.calculate(variable_name, period=computation_period) / 12.0
632 )
633 elif period.unit == periods.YEAR:
--> 634 return self.calculate(variable_name, period)
636 raise ValueError(
637 "Unable to divide the value of '{}' to match period {}.".format(
638 variable_name, period
639 )
640 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
315 self.tracer.record_calculation_start(
316 variable_name, period, self.branch_name
317 )
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
322 result = result.decode_to_str()
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
479 try:
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
484 if array is None:
485 # Check if the variable has a previously defined value
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:684, in Simulation._run_formula(self, variable, population, period)
682 values = 0
683 for added_variable in adds_list:
--> 684 values = values + self.calculate(
685 added_variable, period, map_to=variable.entity.key
686 )
687 if variable.subtracts is not None:
688 if isinstance(variable.subtracts, str):
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
315 self.tracer.record_calculation_start(
316 variable_name, period, self.branch_name
317 )
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
322 result = result.decode_to_str()
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
479 try:
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
484 if array is None:
485 # Check if the variable has a previously defined value
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
719 array = formula(population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py:34, in spm_unit_benefits.formula(spm_unit, period, parameters)
32 if not parameters(period).gov.hud.abolition:
33 BENEFITS.append("spm_unit_capped_housing_subsidy")
---> 34 return add(spm_unit, period, BENEFITS)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/commons/formulas.py:225, in add(entity, period, variables, options)
205 def add(
206 entity: Population,
207 period: Period,
208 variables: List[str],
209 options: List[str] = None,
210 ):
211 """Sums a list of variables.
212
213 Args:
(...)
223 ArrayLike: The result of the operation.
224 """
--> 225 return for_each_variable(
226 entity, period, variables, agg_func="add", options=options
227 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/commons/formulas.py:184, in for_each_variable(entity, period, variables, agg_func, group_agg_func, options)
181 values = entity(variable, period, options=options)
182 elif variable_entity.is_person:
183 values = group_agg_func(
--> 184 entity.members(variable, period, options=options)
185 )
186 elif entity.entity.is_person:
187 raise ValueError(
188 f"You requested to aggregate {variable} (defined for {variable_entity.plural}) to {entity.entity.plural}, but this is not yet implemented."
189 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
130 return self.simulation.calculate_divide(
131 variable_name, period, **calculate_kwargs
132 )
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
315 self.tracer.record_calculation_start(
316 variable_name, period, self.branch_name
317 )
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
322 result = result.decode_to_str()
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
479 try:
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
484 if array is None:
485 # Check if the variable has a previously defined value
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
719 array = formula(population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/ssi.py:16, in ssi.formula(person, period, parameters)
14 if parameters(period).gov.ssa.ssi.abolish_ssi:
15 return 0
---> 16 return max_(0, person("uncapped_ssi", period))
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
130 return self.simulation.calculate_divide(
131 variable_name, period, **calculate_kwargs
132 )
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
315 self.tracer.record_calculation_start(
316 variable_name, period, self.branch_name
317 )
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
322 result = result.decode_to_str()
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
479 try:
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
484 if array is None:
485 # Check if the variable has a previously defined value
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
719 array = formula(population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/uncapped_ssi.py:13, in uncapped_ssi.formula(person, period, parameters)
12 def formula(person, period, parameters):
---> 13 amount = person("ssi_amount_if_eligible", period)
14 meets_resource_test = person("meets_ssi_resource_test", period)
15 eligible = person("is_ssi_eligible_individual", period)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
130 return self.simulation.calculate_divide(
131 variable_name, period, **calculate_kwargs
132 )
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
315 self.tracer.record_calculation_start(
316 variable_name, period, self.branch_name
317 )
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
322 result = result.decode_to_str()
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
479 try:
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
484 if array is None:
485 # Check if the variable has a previously defined value
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
719 array = formula(population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/ssi_amount_if_eligible.py:16, in ssi_amount_if_eligible.formula(person, period, parameters)
12 def formula(person, period, parameters):
13 ssi = parameters(period).gov.ssa.ssi.amount
14 return (
15 where(
---> 16 person("ssi_claim_is_joint", period),
17 ssi.couple,
18 ssi.individual,
19 )
20 * MONTHS_IN_YEAR
21 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:134, in Population.__call__(self, variable_name, period, options)
130 return self.simulation.calculate_divide(
131 variable_name, period, **calculate_kwargs
132 )
133 else:
--> 134 return self.simulation.calculate(
135 variable_name, period, **calculate_kwargs
136 )
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:320, in Simulation.calculate(self, variable_name, period, map_to, decode_enums)
315 self.tracer.record_calculation_start(
316 variable_name, period, self.branch_name
317 )
319 try:
--> 320 result = self._calculate(variable_name, period)
321 if isinstance(result, EnumArray) and decode_enums:
322 result = result.decode_to_str()
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:481, in Simulation._calculate(self, variable_name, period)
479 try:
480 self._check_for_cycle(variable.name, period)
--> 481 array = self._run_formula(variable, population, period)
483 # If no result, use the default value and cache it
484 if array is None:
485 # Check if the variable has a previously defined value
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/simulations/simulation.py:721, in Simulation._run_formula(self, variable, population, period)
719 array = formula(population, period)
720 else:
--> 721 array = formula(population, period, parameters_at)
723 return array
File ~/work/policyengine-us/policyengine-us/policyengine_us/variables/gov/ssa/ssi/ssi_claim_is_joint.py:12, in ssi_claim_is_joint.formula(person, period, parameters)
10 def formula(person, period, parameters):
11 eligible = person("is_ssi_aged_blind_disabled", period)
---> 12 both_eligible = person.marital_unit.sum(eligible) == 2
13 income_is_deemed = (
14 person("ssi_income_deemed_from_ineligible_spouse", period) > 0
15 )
16 return both_eligible | income_is_deemed
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/projectors/projector.py:28, in Projector.__getattr__.<locals>.projector_function(*args, **kwargs)
26 def projector_function(*args, **kwargs):
27 result = reference_attr(*args, **kwargs)
---> 28 return self.transform_and_bubble_up(result)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/projectors/projector.py:37, in Projector.transform_and_bubble_up(self, result)
36 def transform_and_bubble_up(self, result):
---> 37 transformed_result = self.transform(result)
38 if self.parent is None:
39 return transformed_result
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/projectors/entity_to_person_projector.py:19, in EntityToPersonProjector.transform(self, result)
18 def transform(self, result: ArrayLike) -> ArrayLike:
---> 19 return self.reference_entity.project(result)
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/group_population.py:335, in GroupPopulation.project(self, array, role)
334 def project(self, array: ArrayLike, role: Role = None) -> ArrayLike:
--> 335 self.check_array_compatible_with_entity(array)
336 self.entity.check_role_validity(role)
337 if role is None:
File /opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/policyengine_core/populations/population.py:60, in Population.check_array_compatible_with_entity(self, array)
58 def check_array_compatible_with_entity(self, array: numpy.ndarray) -> None:
59 if not self.count == array.size:
---> 60 raise ValueError(
61 "Input {} is not a valid value for the entity {} (size = {} != {} = count)".format(
62 array, self.entity.key, array.size, self.count
63 )
64 )
ValueError: Input [0. 0. 0. ... 0. 0. 0.] is not a valid value for the entity marital_unit (size = 7001 != 7002 = count)
Since the used clean vehicle credit is also non-refundable, filers must have a certain level of income to benefit from it. For example, a single filer purchasing a used clean vehicle will receive the full benefit when they earn $48,000, and then lose the entire benefit when they earn $75,000. Married filers and those with children have to earn more to receive the full benefit, and continue to receive the benefit with higher incomes before losing it.
def make_used(adults, children, purchased_qualifying_used_clean_vehicle):
sim = IndividualSim(year=2023)
# Specify age 25 to qualify for EITC.
sim.add_person(name="head", age=25, is_tax_unit_head=True)
members = ["head"]
if adults == 2:
sim.add_person(name="spouse")
members.append("spouse")
for i in range(children):
child = "child{}".format(i)
sim.add_person(name=child, age=5)
members.append(child)
sim.add_tax_unit(
name="tax_unit",
members=members,
purchased_qualifying_used_clean_vehicle=purchased_qualifying_used_clean_vehicle,
used_clean_vehicle_sale_price=20_000,
premium_tax_credit=0,
)
sim.add_spm_unit(name="spm_unit", members=members)
sim.add_household(name="household", members=members, state_code="MA")
sim.vary("employment_income", max=350_000)
return pd.DataFrame(
dict(
employment_income=sim.calc("employment_income")[0],
spm_unit_net_income=sim.calc("spm_unit_net_income")[0],
credit=sim.calc("used_clean_vehicle_credit")[0],
adults=adults,
children=children,
purchased_qualifying_used_clean_vehicle=purchased_qualifying_used_clean_vehicle,
)
)
l = []
for adults in [1, 2]:
for children in range(0, 4):
for purchased_qualifying_used_clean_vehicle in [True, False]:
l.append(
make_used(
adults,
children,
purchased_qualifying_used_clean_vehicle,
)
)
df = pd.concat(l)
wide = df.pivot(
index=["employment_income", "adults", "children"],
columns="purchased_qualifying_used_clean_vehicle",
values="spm_unit_net_income",
).reset_index()
wide["benefit"] = wide[True] - wide[False]
LABELS = dict(
employment_income="Employment income",
benefit="Net used clean vehicle credit",
children="Children",
adults="Adults",
)
fig = px.line(
wide,
"employment_income",
"benefit",
color="children",
animation_frame="adults",
labels=LABELS,
title="Net benefit from used clean vehicle credit under Inflation Reduction Act",
)
fig.update_layout(xaxis_tickformat="$,", yaxis_tickformat="$,")
fig.show()