def calc_per_veh_tech_costs(averages_dict): """ Parameters:: averages_dict: Dictionary; contains average direct and indirect costs per vehicle. Returns: The averages_dict dictionary updated with average tech costs per vehicle (direct plus indirect). Note: Direct and indirect costs apply only for ageID=0 (i.e., new sales). """ print('\nCalculating per vehicle technology costs...') calcs_avg = FleetAverages(averages_dict) age0_keys = [k for k, v in averages_dict.items() if v['ageID'] == 0] for key in age0_keys: cost = calcs_avg.get_attribute_value(key, 'DirectCost_AvgPerVeh') cost += calcs_avg.get_attribute_value(key, 'IndirectCost_AvgPerVeh') temp_dict = {'TechCost_AvgPerVeh': cost} calcs_avg.update_dict(key, temp_dict) return averages_dict
def create_weighted_cost_dict(settings, averages_dict, arg_to_weight, arg_to_weight_by): """ This function weights 'arg_to_weight' attributes by the 'arg_to_weight_by' attribute. Parameters:: settings: The SetInputs class.\n averages_dict: Dictionary; contains fleet average data (e.g., miles/year, cost/year, cost/mile).\n arg_to_weight: String; the attribute to be weighted by the arg_to_weight_by argument.\n arg_to_weight_by: String; the argument to weight by. Returns: A dictionary of arguments weighted by the weight_by argument. Note: The weighting is limited by the number of years (ages) to be included which is set in the general inputs file. The weighting is also limited to model years for which sufficient data exits to include all of those ages. For example, if the maximum calendar year included in the input data is 2045, and the maximum numbers of ages of data to include for each model year is 9 (which would be 10 years of age since year 1 is age 0) then the maximum model year included will be 2035. """ print(f'\nCalculating weighted {arg_to_weight}...') calcs_avg = FleetAverages(averages_dict) wtd_result_dict = dict() weighted_results_dict = dict() for key in averages_dict.keys(): vehicle, alt, model_year, age_id = key[0], key[1], key[2], key[3] st, rc, ft = vehicle if arg_to_weight == 'DEFCost_AvgPerMile' and ft != 2: pass else: if model_year <= (settings.year_max - settings.max_age_included - 1): wtd_result_dict_id = (vehicle, alt, model_year) numerator, denominator = 0, 0 if wtd_result_dict_id in wtd_result_dict: numerator = wtd_result_dict[wtd_result_dict_id]['numerator'] denominator = wtd_result_dict[wtd_result_dict_id]['denominator'] else: pass if age_id <= settings.max_age_included: arg_weight = calcs_avg.get_attribute_value(key, arg_to_weight) arg_weight_by = calcs_avg.get_attribute_value(key, arg_to_weight_by) numerator += arg_weight * arg_weight_by denominator += calcs_avg.get_attribute_value(key, 'VMT_AvgPerVeh') wtd_result_dict[wtd_result_dict_id] = {'numerator': numerator, 'denominator': denominator} for key in wtd_result_dict.keys(): numerator = wtd_result_dict[key]['numerator'] denominator = wtd_result_dict[key]['denominator'] vehicle, alt = key[0], key[1] st, rc, ft = vehicle source_type = Vehicle(st).sourcetype_name() weighted_results_dict[key] = {'optionID': alt, 'sourceTypeName': source_type, 'cents_per_mile': 100 * numerator / denominator} return weighted_results_dict
def calc_per_veh_direct_costs(yoy_costs_per_step_dict, cost_steps, averages_dict, program): """ Parameters: yoy_costs_per_step_dict: Dictionary; contains the package cost and cumulative sales used to calculate that package cost (learning effects depend on cumulative sales) for the passed unit in the given model year and complying with the standards set in the given cost step. \n cost_steps: List; provides the cost steps (as strings) associated with the direct costs being calculated.\n averages_dict: Dictionary; into which tech package direct costs/vehicle will be updated.\n program: String; the program identifier (i.e., 'CAP' or 'GHG'). Returns: The averages_dict dictionary updated with tech package costs/vehicle. """ print(f'\nCalculating {program} costs per vehicle...') calcs_avg = FleetAverages(averages_dict) age0_keys = [k for k, v in averages_dict.items() if v['ageID'] == 0] for key in age0_keys: vehicle, alt, model_year, age_id, disc_rate = key st, rc, ft = vehicle engine = (rc, ft) if program == 'CAP': unit = engine else: unit = vehicle if alt == 0: cost = yoy_costs_per_step_dict[(unit, alt, model_year, cost_steps[0])]['Cost_AvgPerVeh'] else: cost = yoy_costs_per_step_dict[(unit, 0, model_year, cost_steps[0])]['Cost_AvgPerVeh'] for step in cost_steps: if model_year >= int(step): cost += yoy_costs_per_step_dict[(unit, alt, model_year, step)]['Cost_AvgPerVeh'] if program == 'GHG': # GHG program costs are to be averaged over all VPOP for the given unit vpop_with_tech = calcs_avg.get_attribute_value(key, 'VPOP_withTech') vpop = calcs_avg.get_attribute_value(key, 'VPOP') cost = cost * vpop_with_tech / vpop temp_dict = {'TechCost_AvgPerVeh': cost} calcs_avg.update_dict(key, temp_dict) else: temp_dict = {'DirectCost_AvgPerVeh': cost} calcs_avg.update_dict(key, temp_dict) return averages_dict
def calc_direct_costs(totals_dict, averages_dict, sales_arg, program): """ Parameters: totals_dict: Dictionary; into which tech package direct costs will be updated.\n averages_dict: Dictionary; contains tech package direct costs/vehicle.\n sales_arg: String; specifies the sales attribute to use (e.g., "VPOP" or "VPOP_withTech")\n program: String; the program identifier (i.e., 'CAP' or 'GHG'). Returns: The totals_dict dictionary updated with tech package direct costs (package cost * sales). """ if program == 'CAP': arg = 'Direct' else: arg = 'Tech' print(f'\nCalculating {program} {arg} total costs...') calcs = FleetTotals(totals_dict) calcs_avg = FleetAverages(averages_dict) age0_keys = [k for k, v in totals_dict.items() if v['ageID'] == 0] for key in age0_keys: cost_per_veh = calcs_avg.get_attribute_value(key, f'{arg}Cost_AvgPerVeh') sales = calcs.get_attribute_value(key, sales_arg) cost = cost_per_veh * sales temp_dict = {f'{arg}Cost': cost} calcs.update_dict(key, temp_dict) return totals_dict
def calc_typical_vmt_per_year(settings, vehicle, alt, model_year, averages_dict): """ This function calculates a typical annual VMT/vehicle over a set number of years as set via the General Inputs workbook. This typical annual VMT/vehicle can then be used to estimate the ages at which warranty and useful life will be reached. When insufficient years are available -- e.g., if the typical_vmt_thru_ageID is set to >5 years and the given vehicle is a MY2041 vintage vehicle and the fleet input file contains data only thru CY2045, then insufficient data exist to calculate the typical VMT for that vehicle -- the typical VMT for that vehicle will be set equal to the last prior MY vintage for which sufficient data were present. Parameters: settings: The SetInputs class.\n vehicle: Tuple; represents a sourcetype_regclass_fueltype vehicle.\n alt: Numeric; the Alternative or option ID.\n model_year: Numeric; the model year of the passed vehicle.\n averages_dict: Dictionary; contains cumulative annual average VMT/vehicle. Returns: A single typical annual VMT/veh value for the passed vehicle of the given model year. """ calcs_avg = FleetAverages(averages_dict) vmt_thru_age_id = settings.repair_inputs_dict['typical_vmt_thru_ageID']['Value'] if model_year + vmt_thru_age_id <= settings.year_max: year = model_year else: year = settings.year_max - vmt_thru_age_id # can't get cumulative VMT when model_year + vmt_thru_age_id exceeds data cumulative_vmt = calcs_avg.get_attribute_value((vehicle, alt, year, vmt_thru_age_id, 0), 'VMT_AvgPerVeh_Cumulative') typical_vmt = cumulative_vmt / (vmt_thru_age_id + 1) return typical_vmt
def calc_emission_repair_costs(totals_dict, averages_dict, vpop_arg): """ Parameters: totals_dict: Dictionary; contains annual vehicle populations (VPOP).\n averages_dict: Dictionary; contains annual average emission repair costs/mile.\n vpop_arg: String; specifies the population attribute to use (e.g., "VPOP" or "VPOP_withTech") Returns: The totals_dict dictionary updated with annual emission repair costs for all vehicles. """ print(f'\nCalculating total emission repair costs...') calcs_avg = FleetAverages(averages_dict) calcs = FleetTotals(totals_dict) for key in totals_dict.keys(): cost_per_veh = calcs_avg.get_attribute_value(key, 'EmissionRepairCost_AvgPerVeh') vpop = calcs.get_attribute_value(key, vpop_arg) cost = cost_per_veh * vpop temp_dict = {'EmissionRepairCost': cost} calcs.update_dict(key, temp_dict) return totals_dict
def calc_tech_costs(totals_dict, averages_dict, sales_arg): """ Parameters:: totals_dict: Dictionary; contains vehicle population (VPOP) data.\n averages_dict: Dictionary; contains average tech costs per vehicle. sales_arg: String; specifies the sales attribute to use (e.g., "VPOP" or "VPOP_withTech") Returns: The totals_dict dictionary updated with annual technology costs for all vehicles. """ print('\nCalculating total technology costs...') calcs_avg = FleetAverages(averages_dict) calcs = FleetTotals(totals_dict) age0_keys = [k for k, v in totals_dict.items() if v['ageID'] == 0] for key in age0_keys: cost_per_veh = calcs_avg.get_attribute_value(key, 'TechCost_AvgPerVeh') sales = calcs.get_attribute_value(key, sales_arg) cost = cost_per_veh * sales temp_dict = {'TechCost': cost} calcs.update_dict(key, temp_dict) return totals_dict
def calc_indirect_costs(settings, totals_dict, averages_dict, sales_arg): """ Parameters: settings: The SetInputs class.\n totals_dict: Dictionary; contains sales data (e.g., sales_arg at age=0).\n averages_dict: Dictionary; contains individual indirect costs per vehicle.\n sales_arg: String; specifies the sales attribute to use (e.g., "VPOP" or "VPOP_withTech") Returns: The totals_dict dictionary updated with total indirect costs for each individual indirect cost property and a summation of those. """ print('\nCalculating CAP total indirect costs...') markup_factors = settings.markup_factors_unique_names.copy() markup_factors.append('Indirect') calcs_avg = FleetAverages(averages_dict) calcs = FleetTotals(totals_dict) age0_keys = [k for k, v in totals_dict.items() if v['ageID'] == 0] for key in age0_keys: temp_dict = dict() for markup_factor in markup_factors: cost_per_veh = calcs_avg.get_attribute_value( key, f'{markup_factor}Cost_AvgPerVeh') sales = calcs.get_attribute_value(key, sales_arg) cost = cost_per_veh * sales temp_dict[f'{markup_factor}Cost'] = cost calcs.update_dict(key, temp_dict) return totals_dict
def calc_per_veh_emission_repair_costs(averages_dict): """ Parameters: averages_dict: Dictionary; contains annual emission repair costs/mile. Returns: The passed dictionary updated with annual emission repair costs/vehicle for each dictionary key. """ print('\nCalculating emission repair costs per vehicle...') calcs_avg = FleetAverages(averages_dict) for key in averages_dict.keys(): repair_cpm = calcs_avg.get_attribute_value(key, 'EmissionRepairCost_AvgPerMile') vmt_per_veh = calcs_avg.get_attribute_value(key, 'VMT_AvgPerVeh') cost_per_veh = repair_cpm * vmt_per_veh temp_dict = {'EmissionRepairCost_AvgPerVeh': cost_per_veh} calcs_avg.update_dict(key, temp_dict) return averages_dict
def calc_per_veh_indirect_costs(settings, averages_dict): """ Parameters: settings: The SetInputs class.\n averages_dict: Dictionary; contains tech package direct costs/vehicle. Returns: The averages_dict dictionary updated with indirect costs associated with each markup value along with the summation of those individual indirect costs as "IndirectCost_AvgPerVeh." """ print('\nCalculating CAP per vehicle indirect costs...') calcs_avg = FleetAverages(averages_dict) markup_factors = settings.markup_factors_unique_names.copy() age0_keys = [k for k, v in averages_dict.items() if v['ageID'] == 0] for key in age0_keys: vehicle, alt, model_year, age_id, disc_rate = key st, rc, ft = vehicle engine = (rc, ft) temp_dict = dict() ic_sum = 0 for markup_factor in markup_factors: markup_value = calc_project_markup_value(settings, engine, alt, markup_factor, model_year) per_veh_direct_cost = calcs_avg.get_attribute_value( key, 'DirectCost_AvgPerVeh') cost = markup_value * per_veh_direct_cost temp_dict[f'{markup_factor}Cost_AvgPerVeh'] = cost ic_sum += cost temp_dict['IndirectCost_AvgPerVeh'] = ic_sum calcs_avg.update_dict(key, temp_dict) return averages_dict
def calc_emission_repair_costs_per_mile(settings, averages_dict): """ Parameters: settings: The SetInputs class.\n averages_dict: Dictionary; contains tech package direct costs/vehicle and cumulative annual average VMT/vehicle. Returns: The averages_dict dictionary updated to include emission repair costs/mile for each dictionary key.\n A repair cost/mile dictionary containing details used in the calculation of repair cost/mile and which is then written to an output file for the given run.\n An 'estimated ages' dictionary containing details behind the calculations and which is then written to an output file for the given run. """ print('\nCalculating emission repair costs per mile...') calcs_avg = FleetAverages(averages_dict) repair_cpm_dict = dict() estimated_ages_dict = dict() for key in averages_dict.keys(): vehicle, alt, model_year, age_id, disc_rate = key reference_direct_cost = calcs_avg.get_attribute_value(((61, 47, 2), 0, model_year, 0, 0), 'DirectCost_AvgPerVeh') # sourcetype here is arbitrary provided it is of diesel regclass 47 direct_cost = calcs_avg.get_attribute_value((vehicle, alt, model_year, 0, 0), 'DirectCost_AvgPerVeh') direct_cost_scaler = direct_cost / reference_direct_cost typical_vmt = calc_typical_vmt_per_year(settings, vehicle, alt, model_year, averages_dict) warranty_estimated_age, estimated_ages_dict = calc_estimated_age(settings, vehicle, alt, model_year, 'Warranty', typical_vmt, estimated_ages_dict) usefullife_estimated_age, estimated_ages_dict = calc_estimated_age(settings, vehicle, alt, model_year, 'Usefullife', typical_vmt, estimated_ages_dict) in_warranty_cpm = settings.repair_inputs_dict['in-warranty_R&M_CPM']['Value'] \ * settings.repair_inputs_dict['emission_repair_share']['Value'] \ * direct_cost_scaler at_usefullife_cpm = settings.repair_inputs_dict['at-usefullife_R&M_CPM']['Value'] \ * settings.repair_inputs_dict['emission_repair_share']['Value'] \ * direct_cost_scaler if usefullife_estimated_age > warranty_estimated_age: slope_within_usefullife = (at_usefullife_cpm - in_warranty_cpm) / (usefullife_estimated_age - warranty_estimated_age) else: slope_within_usefullife = 0 max_cpm = settings.repair_inputs_dict['max_R&M_CPM']['Value'] \ * settings.repair_inputs_dict['emission_repair_share']['Value'] \ * direct_cost_scaler # now calulate the cost per mile if (age_id + 1) < warranty_estimated_age: cpm = in_warranty_cpm elif warranty_estimated_age <= (age_id + 1) < usefullife_estimated_age: cpm = slope_within_usefullife * ((age_id + 1) - warranty_estimated_age) + in_warranty_cpm elif (age_id + 1) == usefullife_estimated_age: cpm = at_usefullife_cpm else: cpm = max_cpm temp_dict = {'EmissionRepairCost_AvgPerMile': cpm} calcs_avg.update_dict(key, temp_dict) repair_cpm_dict[key] = {'reference_direct_cost': reference_direct_cost, 'direct_cost_scaler': direct_cost_scaler, 'warranty_estimated_age': warranty_estimated_age, 'usefullife_estimated_age': usefullife_estimated_age, 'in_warranty_cpm': in_warranty_cpm, 'at_usefullife_cpm': at_usefullife_cpm, 'slope_within_usefullife': slope_within_usefullife, 'max_cpm': max_cpm, 'cpm': cpm } return averages_dict, repair_cpm_dict, estimated_ages_dict