Source code for bca_tool_code.general_modules.fleet

from sys import exit

from bca_tool_code.general_modules.vehicle import Vehicle


[docs]class Fleet:
[docs] def __init__(self): self.sales_by_start_year = dict() # stores sales and cumulative sales per implementation start year self.vehicles = list() self.vehicles_age0 = list() self.vehicles_ft2 = list() self.vehicles_no_action = list() self.typical_vmt_dict = dict() # used for estimating ages at certain events (see estimated_age_at_event module)
[docs] def create_vehicles(self, no_action_alt, options): """ Parameters: no_action_alt: int; the no-action option_id number. options: object; an object of the Options class. Returns: Nothing but it creates vehicle objects and lists of vehicle objects. """ print('Creating vehicle objects...') for index, row in Vehicle.vehicle_df.iterrows(): vehicle = Vehicle() vehicle.year_id = int(row['year_id']) vehicle.sourcetype_id = int(row['sourcetype_id']) vehicle.sourcetype_name = vehicle.get_sourcetype_name() vehicle.regclass_id = int(row['regclass_id']) vehicle.regclass_name = vehicle.get_regclass_name() vehicle.fueltype_id = int(row['fueltype_id']) vehicle.fueltype_name = vehicle.get_fueltype_name() vehicle.modelyear_id = int(row['modelyear_id']) vehicle.age_id = int(row['age_id']) vehicle.option_id = int(row['option_id']) vehicle.engine_id = vehicle.set_engine_id() vehicle.vehicle_id = vehicle.set_vehicle_id() vehicle.option_name = options.get_option_name(vehicle.option_id) vehicle.thc_ustons = row['thc_ustons'] vehicle.co_ustons = row['co_ustons'] vehicle.nox_ustons = row['nox_ustons'] vehicle.pm25_exhaust_ustons = row['pm25_exhaust_ustons'] vehicle.pm25_brakewear_ustons = row['pm25_brakewear_ustons'] vehicle.pm25_tirewear_ustons = row['pm25_tirewear_ustons'] vehicle.pm25_ustons = row['pm25_ustons'] vehicle.voc_ustons = row['voc_ustons'] vehicle.vpop = row['vpop'] vehicle.vmt = row['vmt'] vehicle.vmt_per_veh = row['vmt_per_veh'] vehicle.odometer = row['odometer'] vehicle.gallons = row['gallons'] self.vehicles.append(vehicle) if vehicle.age_id == 0: self.vehicles_age0.append(vehicle) if vehicle.fueltype_id == 2: self.vehicles_ft2.append(vehicle) if vehicle.option_id == no_action_alt: self.vehicles_no_action.append(vehicle)
[docs] def engine_sales(self, vehicle): """ Parameters: vehicle: object; an object of the Vehicle class.. Returns: Nothing, but it updates the sales by start year object dictionary with engine sales data. """ if vehicle.age_id != 0: print(f'Improper vehicle object passed to fleet.Fleet.engine_sales method.') exit() sales = 0 key = (vehicle.engine_id, vehicle.option_id, vehicle.modelyear_id) if key in self.sales_by_start_year: sales = self.sales_by_start_year[key]['engine_sales'] else: sales = sum([ v.vpop for v in self.vehicles if v.engine_id == vehicle.engine_id and v.option_id == vehicle.option_id and v.modelyear_id == vehicle.modelyear_id and v.age_id == 0 ]) update_dict = { 'optionID': vehicle.option_id, 'engineID': vehicle.engine_id, 'regClassID': vehicle.regclass_id, 'fuelTypeID': vehicle.fueltype_id, 'modelYearID': vehicle.modelyear_id, 'optionName': vehicle.option_name, 'regClassName': vehicle.regclass_name, 'fuelTypeName': vehicle.fueltype_name, 'engine_sales': sales, } self.update_object_dict(vehicle, vehicle.engine_id, update_dict)
[docs] def cumulative_engine_sales(self, vehicle, start_year): """ Parameters: vehicle: object; an object of the Vehicle class. start_year: int; the implementation step for which cumulative sales are sought. Returns: Nothing, but it updates the sales by start year object dictionary with cumulative engine sales data. """ if vehicle.age_id != 0: print(f'Improper vehicle object passed to fleet.Fleet.cumulative_engine_sales method.') exit() sales = sum([ v['engine_sales'] for k, v in self.sales_by_start_year.items() if v['engineID'] == vehicle.engine_id and v['optionID'] == vehicle.option_id and (v['modelYearID'] >= start_year and v['modelYearID'] <= vehicle.modelyear_id) ]) update_dict = {f'cumulative_engine_sales_{start_year}_std': sales} self.update_object_dict(vehicle, vehicle.engine_id, update_dict)
[docs] def cumulative_vehicle_sales(self, vehicle, start_year): """ Parameters: vehicle: object; an object of the Vehicle class. start_year: int; the implementation step for which cumulative sales are sought. Returns: Nothing, but it updates the sales by start year object dictionary with cumulative vehicle sales data. Note: This method is not used so may not work properly. """ if vehicle.age_id != 0: print(f'Improper vehicle object passed to fleet.Fleet.cumulative_vehicle_sales method.') exit() sales = sum([ v.vpop for v in self.vehicles_age0 if v.vehicle_id == vehicle.vehicle_id and v.option_id == vehicle.option_id and (v.modelyear_id >= start_year and v.modelyear_id <= vehicle.modelyear_id) ]) update_dict = { 'optionID': vehicle.option_id, 'vehicleID': vehicle.vehicle_id, 'sourceTypeID': vehicle.sourcetype_id, 'regClassID': vehicle.regclass_id, 'fuelTypeID': vehicle.fueltype_id, 'modelYearID': vehicle.modelyear_id, 'optionName': vehicle.option_name, 'sourceTypeName': vehicle.sourcetype_name, 'regClassName': vehicle.regclass_name, 'fuelTypeName': vehicle.fueltype_name, f'cumulative_vehicle_sales_{start_year}_std': sales, } self.update_object_dict(vehicle, vehicle.vehicle_id, update_dict)
[docs] def get_typical_vmt_per_year(self, settings, vehicle): """ Parameters: settings: object; the SetInputs class object.\n vehicle: object; an object of the Vehicle class.\n Returns: A single typical annual VMT/veh value for the given vehicle. Note: This function calculates a typical annual VMT/vehicle over a set number of year_ids 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 year_ids are available -- e.g., if the typical_vmt_thru_ageID is set to >5 year_ids 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. """ vmt_thru_age_id \ = int(settings.repair_and_maintenance.get_attribute_value(('typical_vmt_thru', 'age_id'))) year_max = settings.vehicle.year_id_max key = vehicle.vehicle_id, vehicle.option_id, vehicle.modelyear_id if key in self.typical_vmt_dict: typical_vmt = self.typical_vmt_dict[key] elif vehicle.modelyear_id <= year_max and vehicle.age_id == vmt_thru_age_id: typical_vmt = vehicle.odometer / (vmt_thru_age_id + 1) self.typical_vmt_dict[key] = typical_vmt else: # Note: can't get appropriate typical VMT if modelyear+vmt_thru_age_id>year_max year = min(vehicle.modelyear_id, year_max - vmt_thru_age_id) odometer = [v.odometer for v in self.vehicles if v.vehicle_id == vehicle.vehicle_id and v.option_id == vehicle.option_id and v.modelyear_id == year and v.age_id == vmt_thru_age_id][0] typical_vmt = odometer / (vmt_thru_age_id + 1) self.typical_vmt_dict[key] = typical_vmt return typical_vmt
[docs] def update_object_dict(self, vehicle, unit, update_dict): """ Parameters: vehicle: object; an object of the Vehicle class.\n unit: tuple; the unit to use in the key (e.g., engine_id or vehicle_id).\n update_dict: Dictionary; represents the attribute-value pairs to be updated. Returns: Updates the object dictionary with each attribute updated with the appropriate value. Note: The method updates an existing key having attribute_name with attribute_value. """ key = unit, vehicle.option_id, vehicle.modelyear_id if key in self.sales_by_start_year: for attribute_name, attribute_value in update_dict.items(): self.sales_by_start_year[key][attribute_name] = attribute_value else: self.sales_by_start_year.update({key: {}}) for attribute_name, attribute_value in update_dict.items(): self.sales_by_start_year[key].update({attribute_name: attribute_value})