diff --git a/prereise/gather/demanddata/transportation_electrification/const.py b/prereise/gather/demanddata/transportation_electrification/const.py index ae56eaa1d..4f1b145c3 100644 --- a/prereise/gather/demanddata/transportation_electrification/const.py +++ b/prereise/gather/demanddata/transportation_electrification/const.py @@ -141,3 +141,21 @@ ER = 1 emfacvmt = 758118400 + +census_region2state = { + 1: ["CT", "MA", "ME", "NH", "RI", "VT"], + 2: ["PA", "NJ", "NY"], + 3: ["IL", "IN", "MI", "OH", "WI"], + 4: ["IA", "KS", "MN", "MO", "ND", "NE", "SD"], + 5: ["DE", "FL", "GA", "MD", "NC", "SC", "VA", "WV"], + 6: ["AL", "KY", "MS", "TN"], + 7: ["AR", "LA", "OK", "TX"], + 8: ["AZ", "CO", "ID", "MT", "NM", "NV", "UT", "WY"], + 9: ["AK", "CA", "HI", "OR", "WA"], +} + +state2census_region = { + state: census_region + for census_region, state_list in census_region2state.items() + for state in state_list +} diff --git a/prereise/gather/demanddata/transportation_electrification/generate_BEV_vehicle_profiles.py b/prereise/gather/demanddata/transportation_electrification/generate_BEV_vehicle_profiles.py new file mode 100644 index 000000000..51eb59a94 --- /dev/null +++ b/prereise/gather/demanddata/transportation_electrification/generate_BEV_vehicle_profiles.py @@ -0,0 +1,167 @@ +import os + +import pandas as pd + +from prereise.gather.const import abv2state +from prereise.gather.demanddata.transportation_electrification import ( + const, + immediate, + immediate_charging_HDV, + smart_charging, +) +from prereise.gather.demanddata.transportation_electrification.data_helper import ( + generate_daily_weighting, + get_kwhmi, + load_rural_scaling_factor, + load_urbanized_scaling_factor, +) + + +def generate_bev_vehicle_profiles( + vehicle_trip_data_filepath, + charging_strategy, + veh_type, + veh_range, + projection_year, + state, + external_signal=None, + power=6.6, + location_strategy=2, + trip_strategy=1, +): + """Generate Battery Electric Vehicle (BEV) profiles + + :param str vehicle_trip_data_filepath: filepath of collected trip data from external sources + representing driving patterns + :param str charging_strategy: establishes whether charging happens immediately ("immediate") + or optimize based on external signals, i.e. smart charging ("smart") + :param str veh_type: vehicle category: LDV: light duty vehicle, LDT: light duty truck, + MDV: medium duty vehicle, HDV: heavy duty vehicle + :param int veh_range: 100, 200, or 300, represents how far vehicle can travel on + single charge in miles. + :param int projection_year: year that is being modelled/projected to, 2017, 2030, 2040, + 2050. + :param str state: US state abbreviation + :param numpy.ndarray (optional) external_signal: initial load demand (MW for each hour) + :param int power: (optional) charger power, EVSE kW; default value: 6.6 kW; + :param int location_strategy: (optional) where the vehicle can charge-1, 2, 3, 4, or 5; + 1-home only, 2-home and work related, 3-anywhere if possibile, + 4-home and school only, 5-home and work and school. + default value: 2 + :param int trip_strategy: (optional) determine to charge after any trip (1) or only after the + last trip (2); default value: 1 + :return: (*pandas.DataFrame*) -- yearly charging profiles for all urban areas and the rural area + in each state (MW for each hour) + """ + + census_region = const.state2census_region[state] + kwhmi = get_kwhmi(projection_year, veh_type, veh_range) + + daily_values = generate_daily_weighting(projection_year) + + if power > 19.2: + charging_efficiency = 0.95 + else: + charging_efficiency = 0.9 + + geographic_area_bev_vmt = {} + + urban_scaling_filepath = os.path.join( + const.data_folder_path, + "regional_scaling_factors", + "Regional_scaling_factors_UA_", + ) + urban_scaling_factors = pd.read_csv( + urban_scaling_filepath + str(projection_year) + ".csv", index_col="State" + ) + state_urban_areas = urban_scaling_factors.loc[state.upper(), "UA"] + + # scaling factors for listed urban areas + for urban_area in state_urban_areas.to_list(): + urban_bev_vmt = load_urbanized_scaling_factor( + model_year=projection_year, + veh_type=veh_type, + veh_range=veh_range, + urbanized_area=urban_area, + state=state, + filepath=urban_scaling_filepath, + ) + geographic_area_bev_vmt.update({f"{state}_{urban_area}": urban_bev_vmt}) + + # scaling factors for rural areas + rural_bev_vmt = load_rural_scaling_factor( + projection_year, + veh_type, + veh_range, + abv2state[state.upper()].upper(), + filepath=os.path.join( + const.data_folder_path, + "regional_scaling_factors", + "Regional_scaling_factors_RA_", + ), + ) + geographic_area_bev_vmt.update({f"{state}_rural": rural_bev_vmt}) + + # calculate demand for all geographic areas with scaling factors + state_demand_profiles = {} + for geographic_area, bev_vmt in geographic_area_bev_vmt.items(): + + if charging_strategy == "immediate": + + if veh_type.lower() in {"ldv", "ldt"}: + normalized_demand = immediate.immediate_charging( + census_region=census_region, + model_year=projection_year, + veh_range=veh_range, + power=power, + location_strategy=location_strategy, + veh_type=veh_type, + filepath=vehicle_trip_data_filepath, + ) + elif veh_type.lower() in {"mdv", "hdv"}: + normalized_demand = immediate_charging_HDV.immediate_charging( + model_year=projection_year, + veh_range=veh_range, + power=power, + location_strategy=location_strategy, + veh_type=veh_type, + filepath=vehicle_trip_data_filepath, + ) + + final_demand = immediate.adjust_bev( + hourly_profile=normalized_demand, + adjustment_values=daily_values, + model_year=projection_year, + veh_type=veh_type, + veh_range=veh_range, + bev_vmt=bev_vmt, + charging_efficiency=charging_efficiency, + ) + + elif charging_strategy == "smart": + final_demand = smart_charging.smart_charging( + census_region=census_region, + model_year=projection_year, + veh_range=veh_range, + kwhmi=kwhmi, + power=power, + location_strategy=location_strategy, + veh_type=veh_type, + filepath=vehicle_trip_data_filepath, + daily_values=daily_values, + external_signal=external_signal, + bev_vmt=bev_vmt, + trip_strategy=trip_strategy, + ) + + state_demand_profiles.update({geographic_area: final_demand}) + + state_demand_profiles_df = pd.DataFrame( + state_demand_profiles, + index=pd.date_range( + start=f"{projection_year}-01-01 00:00:00", + end=f"{projection_year}-12-31 23:00:00", + freq="H", + ), + ) + return state_demand_profiles_df diff --git a/prereise/gather/demanddata/transportation_electrification/smart_charging.py b/prereise/gather/demanddata/transportation_electrification/smart_charging.py index e3b3e57c3..dbd01635e 100644 --- a/prereise/gather/demanddata/transportation_electrification/smart_charging.py +++ b/prereise/gather/demanddata/transportation_electrification/smart_charging.py @@ -11,18 +11,38 @@ ) +def ldv_weekday_weekend_check(x, y): + """Helper function to select weekday/weekend data rows + + :param int x: data weekday/weekend value + :param int y: model year weekday/weekend value + :return: (*bool*) -- if data row matches whether the current day is a weekday/weekend + """ + return x == y + + +def hdv_use_all_data_rows(x, y): + """Helper function to select weekday/weekend data rows + + :param int x: data weekday/weekend value + :param int y: model year weekday/weekend value + :return: (*bool*) -- always returns true to use all data rows + """ + return True + + def smart_charging( - census_region, model_year, veh_range, - kwhmi, power, location_strategy, veh_type, filepath, - daily_values, - load_demand, + external_signal, bev_vmt, + census_region=None, + daily_values=None, + kwhmi=None, trip_strategy=1, ): """Smart charging function @@ -51,16 +71,17 @@ def smart_charging( # load NHTS data from function if veh_type.lower() == "ldv": newdata = data_helper.remove_ldt(data_helper.load_data(census_region, filepath)) + # updates the weekend and weekday values in the nhts data + newdata = data_helper.update_if_weekend(newdata) elif veh_type.lower() == "ldt": newdata = data_helper.remove_ldv(data_helper.load_data(census_region, filepath)) + # updates the weekend and weekday values in the nhts data + newdata = data_helper.update_if_weekend(newdata) elif veh_type.lower() == "mdv": newdata = data_helper.load_hdv_data("mhdv", filepath) elif veh_type.lower() == "hdv": newdata = data_helper.load_hdv_data("hhdv", filepath) - # updates the weekend and weekday values in the nhts data - newdata = data_helper.update_if_weekend(newdata) - new_columns = [ "trip start battery charge", "trip end battery charge", @@ -76,12 +97,20 @@ def smart_charging( newdata["trip_number"] = newdata.groupby("vehicle_number").cumcount() + 1 input_day = data_helper.get_input_day(data_helper.get_model_year_dti(model_year)) + external_signal = -min(external_signal) + external_signal model_year_profile = np.zeros(24 * len(input_day)) - data_day = data_helper.get_data_day(newdata) - - daily_vmt_total = data_helper.get_total_daily_vmt(newdata, input_day, daily_values) + if veh_type.lower() in {"ldv", "ldt"}: + data_day = data_helper.get_data_day(newdata) + daily_vmt_total = data_helper.get_total_daily_vmt( + newdata, input_day, daily_values + ) + elif veh_type.lower() in {"mdv", "hdv"}: + data_day = input_day + daily_vmt_total = data_helper.get_total_hdv_daily_vmt(newdata, veh_range) + if kwhmi is None: + kwhmi = data_helper.get_kwhmi(model_year, veh_type, veh_range) kwh = kwhmi * veh_range if power > 19.2: charging_efficiency = 0.95 @@ -90,13 +119,20 @@ def smart_charging( nd_len = len(newdata) + if veh_type.lower() in {"ldv", "ldt"}: + location_allowed = const.ldv_location_allowed + use_data_row = ldv_weekday_weekend_check + elif veh_type.lower() in {"mdv", "hdv"}: + location_allowed = const.hdv_location_allowed + use_data_row = hdv_use_all_data_rows + newdata = charging_optimization.get_constraints( newdata, kwhmi, power, trip_strategy, location_strategy, - const.ldv_location_allowed, + location_allowed, charging_efficiency, ) @@ -104,7 +140,7 @@ def smart_charging( for day_iter in range(day_num): adjusted_load = [ - load_demand[i] + model_year_profile[i] + external_signal[i] + model_year_profile[i] for i in range( day_iter * 24, (day_iter + 1) * 24 + min(day_num - day_iter - 1, 2) * 24 ) @@ -112,7 +148,7 @@ def smart_charging( if 3 - day_num + day_iter > 0: adjusted_load += [ - load_demand[i] + model_year_profile[i] + external_signal[i] + model_year_profile[i] for i in range(24 * (3 - day_num + day_iter)) ] @@ -128,157 +164,144 @@ def smart_charging( # trip amount for each vehicle total_trips = int(newdata.iloc[i, newdata.columns.get_loc("total_trips")]) - if data_day[i] == input_day[day_iter]: - - # only home based trips - if ( - newdata.iloc[i, newdata.columns.get_loc("why_from")] - * newdata.iloc[ - i + total_trips - 1, newdata.columns.get_loc("dwell_location") - ] - == 1 - ): - - # copy one vehicle information to the block - individual = newdata.iloc[i : i + total_trips].copy() - - individual["rates"] = individual.apply( - lambda d: dwelling.get_rates( - cost, - d["trip_end"], - d["dwell_time"], - ), - axis=1, - ) + if use_data_row(data_day[i], input_day[day_iter]): - charging_consumption = individual["charging consumption"].to_numpy() + # copy one vehicle information to the block + individual = newdata.iloc[i : i + total_trips].copy() - rates = individual["rates"] - rates = [r for trip_rates in rates for r in trip_rates] + individual["rates"] = individual.apply( + lambda d: dwelling.get_rates( + cost, + d["trip_end"], + d["dwell_time"], + ), + axis=1, + ) - elimit = individual["energy limit"] - elimit = [el for energy_lim in elimit for el in energy_lim] + charging_consumption = individual["charging consumption"].to_numpy() - seg = individual["seg"].apply(int).to_numpy() + rates = individual["rates"] + rates = [r for trip_rates in rates for r in trip_rates] - linprog_inputs = charging_optimization.calculate_optimization( - charging_consumption, - rates, - elimit, - seg, - total_trips, - kwh, - charging_efficiency, - ) + elimit = individual["energy limit"] + elimit = [el for energy_lim in elimit for el in energy_lim] + + seg = individual["seg"].apply(int).to_numpy() - linprog_result = linprog(**linprog_inputs) + linprog_inputs = charging_optimization.calculate_optimization( + charging_consumption, + rates, + elimit, + seg, + total_trips, + kwh, + charging_efficiency, + ) - # fval is the value of the final cost, exitflag is the reason why the optimization terminates - # 0-success, 1-limit reached, 2-problem infeasible, 3-problem unbounded, 4-numerical difficulties - x = np.array(linprog_result.x) - exitflag = linprog_result.status + linprog_result = linprog(**linprog_inputs) - state_of_charge = np.zeros((total_trips, 2)) + # fval is the value of the final cost, exitflag is the reason why the optimization terminates + # 0-success, 1-limit reached, 2-problem infeasible, 3-problem unbounded, 4-numerical difficulties + x = np.array(linprog_result.x) + exitflag = linprog_result.status - # find the feasible points - if exitflag == 0: + state_of_charge = np.zeros((total_trips, 2)) - # can be an EV + # find the feasible points + if exitflag == 0: + + # can be an EV + individual.iloc[:, newdata.columns.get_loc("BEV could be used")] = 1 + + for n in range(total_trips): + # SOC drop in kwh, from driving individual.iloc[ - :, newdata.columns.get_loc("BEV could be used") - ] = 1 + n, newdata.columns.get_loc("Battery discharge") + ] = charging_consumption[n] - for n in range(total_trips): - # SOC drop in kwh, from driving + # G2V results + # define the G2V load during a trip + trip_g2v_load = np.zeros((1, 72)) + start = math.floor( individual.iloc[ - n, newdata.columns.get_loc("Battery discharge") - ] = charging_consumption[n] - - # G2V results - # define the G2V load during a trip - trip_g2v_load = np.zeros((1, 72)) - start = math.floor( - individual.iloc[ - n, - individual.columns.get_loc("trip_end"), - ] - ) - end = math.floor( - individual.iloc[ - n, - individual.columns.get_loc("trip_end"), - ] - + individual.iloc[ - n, - individual.columns.get_loc("dwell_time"), - ] - ) + n, + individual.columns.get_loc("trip_end"), + ] + ) + end = math.floor( + individual.iloc[ + n, + individual.columns.get_loc("trip_end"), + ] + + individual.iloc[ + n, + individual.columns.get_loc("dwell_time"), + ] + ) - dwell_location = int( - individual.iloc[ - n, newdata.columns.get_loc("dwell_location") - ] - ) + dwell_location = int( + individual.iloc[ + n, newdata.columns.get_loc("dwell_location") + ] + ) - segcum = np.cumsum(seg) - trip_g2v_load[:, start : end + 1] = ( - # possibly? x[segcum[n] - seg[n] + 1 : segcum[n]] / charging_efficiency - x[segcum[n] - seg[n] : segcum[n]] - / charging_efficiency - ) - g2v_load[dwell_location, :] += trip_g2v_load[0, :] - individual_g2v_load[i + n][:] = trip_g2v_load - trip_g2v_cost = np.matmul(trip_g2v_load, cost)[0] + segcum = np.cumsum(seg) + trip_g2v_load[:, start : end + 1] = ( + x[segcum[n] - seg[n] : segcum[n]] / charging_efficiency + ) + g2v_load[dwell_location, :] += trip_g2v_load[0, :] + individual_g2v_load[i + n][:] = trip_g2v_load + trip_g2v_cost = np.matmul(trip_g2v_load, cost)[0] - # charging charge. in DC - charge = sum(x[segcum[n] - seg[n] : segcum[n]]) + # charging charge. in DC + charge = sum(x[segcum[n] - seg[n] : segcum[n]]) - # V2G results - trip_v2g_load = np.zeros((1, 72)) + # V2G results + trip_v2g_load = np.zeros((1, 72)) - electricitycost = trip_g2v_cost - tripload = trip_v2g_load + trip_g2v_load + electricitycost = trip_g2v_cost + tripload = trip_v2g_load + trip_g2v_load - # update the cost function and convert from KW to MW - cost += ( - tripload / 1000 / daily_vmt_total[day_iter] * bev_vmt - )[0, :] + # update the cost function and convert from KW to MW + cost += (tripload / 1000 / daily_vmt_total[day_iter] * bev_vmt)[ + 0, : + ] - # SOC rise in kwh, from charging - individual.iloc[ - n, newdata.columns.get_loc("Battery charge") - ] = charge - - if n == 0: - state_of_charge[n][0] = charging_consumption[n] - state_of_charge[n][1] = state_of_charge[n][0] + charge - else: - state_of_charge[n][0] = ( - state_of_charge[n - 1][1] + charging_consumption[n] - ) - state_of_charge[n][1] = state_of_charge[n][0] + charge + # SOC rise in kwh, from charging + individual.iloc[ + n, newdata.columns.get_loc("Battery charge") + ] = charge + + if n == 0: + state_of_charge[n][0] = charging_consumption[n] + state_of_charge[n][1] = state_of_charge[n][0] + charge + else: + state_of_charge[n][0] = ( + state_of_charge[n - 1][1] + charging_consumption[n] + ) + state_of_charge[n][1] = state_of_charge[n][0] + charge - individual.iloc[ - n, newdata.columns.get_loc("Electricity cost") - ] = electricitycost + individual.iloc[ + n, newdata.columns.get_loc("Electricity cost") + ] = electricitycost - # copy SOC back - individual.iloc[ - n, newdata.columns.get_loc("trip start battery charge") - ] = state_of_charge[n, 0] - individual.iloc[ - n, newdata.columns.get_loc("trip end battery charge") - ] = state_of_charge[n, 1] + # copy SOC back + individual.iloc[ + n, newdata.columns.get_loc("trip start battery charge") + ] = state_of_charge[n, 0] + individual.iloc[ + n, newdata.columns.get_loc("trip end battery charge") + ] = state_of_charge[n, 1] - # find the acutal battery size, in DC - batterysize = max(state_of_charge[:, 1]) - min( - state_of_charge[:, 0] - ) + # find the acutal battery size, in DC + batterysize = max(state_of_charge[:, 1]) - min( + state_of_charge[:, 0] + ) - # copy to individual - individual.iloc[ - :, newdata.columns.get_loc("Battery size") - ] = batterysize + # copy to individual + individual.iloc[ + :, newdata.columns.get_loc("Battery size") + ] = batterysize # update the counter to the next vehicle i += total_trips diff --git a/prereise/gather/demanddata/transportation_electrification/smart_charging_HDV.py b/prereise/gather/demanddata/transportation_electrification/smart_charging_HDV.py deleted file mode 100644 index 35cf0f4bd..000000000 --- a/prereise/gather/demanddata/transportation_electrification/smart_charging_HDV.py +++ /dev/null @@ -1,277 +0,0 @@ -import math - -import numpy as np -from scipy.optimize import linprog - -from prereise.gather.demanddata.transportation_electrification import ( - charging_optimization, - data_helper, - dwelling, -) - -location_allowed = { - 1: {1}, # base only -} - - -def smart_charging( - model_year, - veh_range, - power, - location_strategy, - veh_type, - filepath, - initial_load, - bev_vmt, - trip_strategy=1, -): - """Smart charging function - - :param int veh_range: 100, 200, or 300, represents how far vehicle can travel on - single charge. - :param int kwhmi_f: fuel efficiency, should vary based on vehicle type and model_year. - :param int power: charger power, EVSE kW. - :param int location_strategy: where the vehicle can charge - 1 or 3; - 1-base only, 3-anywhere if possibile. - :param str veh_type: determine which category (LHDV, MHDV, or HHDT) to produce charging - profiles for - :param str filepath: the path to the HDV data file. - :param np.array initial_load: the initial load demand - :param int hdv_year: index of input year from this list [2005,2012,2030,2035,2040,2050]. - :param list hdv_penetration: penetration value for each category; LHDV, MHDV, HHDV. - :param int trip_strategy: determine to charge after any trip (1) or only after the - last trip (2) - :return: (*numpy.ndarray*) -- charging profiles. - """ - - # load NHTS data from function - if veh_type.lower() == "ldv": - newdata = data_helper.load_hdv_data("lhdv", filepath) - # hdv_cat = 1 - if veh_type.lower() == "mdv": - newdata = data_helper.load_hdv_data("mhdv", filepath) - # hdv_cat = 2 - elif veh_type.lower() == "hdv": - newdata = data_helper.load_hdv_data("hhdv", filepath) - # hdv_cat = 3 - - new_columns = [ - "trip start battery charge", - "trip end battery charge", - "BEV could be used", - "Battery size", - "Electricity cost", - "Battery discharge", - "Battery charge", - ] - newdata = newdata.reindex(list(newdata.columns) + new_columns, axis=1, fill_value=0) - - # used to be input_day - model_year_len = 365 - - load_demand = -min(initial_load) + initial_load - model_year_profile = np.zeros(24 * model_year_len) - - daily_vmt_total = data_helper.get_total_hdv_daily_vmt(newdata, veh_range) - - kwhmi = data_helper.get_kwhmi(model_year, veh_type, veh_range) - kwh = kwhmi * veh_range - - # charging_efficiency value used to be in const.py - if power > 19.2: - charging_efficiency = 0.95 - else: - charging_efficiency = 0.9 - - nd_len = len(newdata) - - newdata = charging_optimization.get_constraints( - newdata, - kwhmi, - power, - trip_strategy, - location_strategy, - location_allowed, - charging_efficiency, - ) - - day_num = model_year_len - for day_iter in range(day_num): - - adjusted_load = [ - load_demand[i] + model_year_profile[i] - for i in range( - day_iter * 24, (day_iter + 1) * 24 + min(day_num - day_iter - 1, 2) * 24 - ) - ] - - if 3 - day_num + day_iter > 0: - adjusted_load += [ - load_demand[i] + model_year_profile[i] - for i in range(24 * (3 - day_num + day_iter)) - ] - - cost = np.array(adjusted_load) - - g2v_load = np.zeros((100, 72)) - individual_g2v_load = np.zeros((nd_len, 72)) - - i = 0 - - while i < nd_len: - - # trip amount for each vehicle - total_trips = int(newdata.iloc[i, newdata.columns.get_loc("total_trips")]) - - # copy one vehicle information to the block - individual = newdata.iloc[i : i + total_trips].copy() - - individual["rates"] = individual.apply( - lambda d: dwelling.get_rates( - cost, - d["trip_end"], - d["dwell_time"], - ), - axis=1, - ) - - charging_consumption = individual["charging consumption"].to_numpy() - - rates = individual["rates"] - rates = [r for trip_rates in rates for r in trip_rates] - - elimit = individual["energy limit"] - elimit = [el for energy_lim in elimit for el in energy_lim] - - seg = individual["seg"].apply(int).to_numpy() - segcum = np.cumsum(seg) - - linprog_inputs = charging_optimization.calculate_optimization( - charging_consumption, - rates, - elimit, - seg, - total_trips, - kwh, - charging_efficiency, - ) - - linprog_result = linprog(**linprog_inputs) - - # fval is the value of the final cost, exitflag is the reason why the optimization terminates - # 0-success, 1-limit reached, 2-problem infeasible, 3-problem unbounded, 4-numerical difficulties - x = np.array(linprog_result.x) - exitflag = linprog_result.status - - state_of_charge = np.zeros((total_trips, 2)) - - # find the feasible points - if exitflag == 0: - - # can be an EV - individual.iloc[:, newdata.columns.get_loc("BEV could be used")] = 1 - - for n in range(total_trips): - # SOC drop in kwh, from driving - individual.iloc[ - n, newdata.columns.get_loc("Battery discharge") - ] = charging_consumption[n] - - # G2V results - # define the G2V load during a trip - trip_g2v_load = np.zeros((1, 72)) - start = math.floor( - individual.iloc[ - n, - individual.columns.get_loc("trip_end"), - ] - ) - end = math.floor( - individual.iloc[ - n, - individual.columns.get_loc("trip_end"), - ] - + individual.iloc[ - n, - individual.columns.get_loc("dwell_time"), - ] - ) - - why_to = int( - individual.iloc[n, newdata.columns.get_loc("Destination to")] - ) - - trip_g2v_load[:, start : end + 1] = ( - x[segcum[n] - seg[n] : segcum[n]] / charging_efficiency - ) - g2v_load[why_to, :] += trip_g2v_load[0, :] - individual_g2v_load[i + n][:] = trip_g2v_load - trip_g2v_cost = np.matmul(trip_g2v_load, cost)[0] - - # charging charge. in DC - charge = sum(x[segcum[n] - seg[n] : segcum[n]]) - - # V2G results - trip_v2g_load = np.zeros((1, 72)) - - electricitycost = trip_g2v_cost - tripload = trip_v2g_load + trip_g2v_load - - # update the cost function and vonvert from KW to MW - cost += (tripload / 1000 / daily_vmt_total[day_iter] * bev_vmt)[ - 0, : - ] - - # SOC rise in kwh, from charging - individual.iloc[ - n, newdata.columns.get_loc("Battery charge") - ] = charge - - if n == 0: - state_of_charge[n][0] = charging_consumption[n] - state_of_charge[n][1] = state_of_charge[n][0] + charge - else: - state_of_charge[n][0] = ( - state_of_charge[n - 1][1] + charging_consumption[n] - ) - state_of_charge[n][1] = state_of_charge[n][0] + charge - - individual.iloc[ - n, newdata.columns.get_loc("Electricity cost") - ] = electricitycost - - # copy SOC back - individual.iloc[ - n, newdata.columns.get_loc("trip start battery charge") - ] = state_of_charge[n, 0] - individual.iloc[ - n, newdata.columns.get_loc("trip end battery charge") - ] = state_of_charge[n, 1] - - # find the acutal battery size, in DC - batterysize = max(state_of_charge[:, 1]) - min(state_of_charge[:, 0]) - - # copy to individual - individual.iloc[ - :, newdata.columns.get_loc("Battery size") - ] = batterysize - - # # copy individual back to newdata if it can be an EV - # newdata.iloc[i : i + total_trips] = individual - - # update the counter to the next vehicle - i += total_trips - - outputelectricload = sum(g2v_load) - - # create wrap-around indexing function - trip_window_indices = np.arange(day_iter * 24, day_iter * 24 + 72) % len( - model_year_profile - ) - - # MW - model_year_profile[trip_window_indices] += ( - outputelectricload / (daily_vmt_total[day_iter] * 1000) * bev_vmt - ) - - return model_year_profile diff --git a/prereise/gather/demanddata/transportation_electrification/tests/test_generate_BEV_vehicle_profiles.py b/prereise/gather/demanddata/transportation_electrification/tests/test_generate_BEV_vehicle_profiles.py new file mode 100644 index 000000000..432072b5c --- /dev/null +++ b/prereise/gather/demanddata/transportation_electrification/tests/test_generate_BEV_vehicle_profiles.py @@ -0,0 +1,26 @@ +import os + +from prereise.gather.demanddata.transportation_electrification import const +from prereise.gather.demanddata.transportation_electrification.generate_BEV_vehicle_profiles import ( + generate_bev_vehicle_profiles, +) + + +def test_ldv_immediate_runs(): + state_demand_df = generate_bev_vehicle_profiles( + vehicle_trip_data_filepath=os.path.join( + const.data_folder_path, + "nhts_census_updated_dwell.mat", + ), + charging_strategy="immediate", + veh_type="ldv", + veh_range=100, + projection_year=2017, + state="AL", + power=6.6, + location_strategy=2, + trip_strategy=1, + ) + + assert len(state_demand_df) == 8760 + assert len(state_demand_df.columns) == 13 diff --git a/prereise/gather/demanddata/transportation_electrification/tests/test_smart_charging_integration.py b/prereise/gather/demanddata/transportation_electrification/tests/test_smart_charging_integration.py index 85e20da9d..fb34ccd54 100644 --- a/prereise/gather/demanddata/transportation_electrification/tests/test_smart_charging_integration.py +++ b/prereise/gather/demanddata/transportation_electrification/tests/test_smart_charging_integration.py @@ -7,7 +7,6 @@ const, data_helper, smart_charging, - smart_charging_HDV, ) from prereise.gather.demanddata.transportation_electrification.data_helper import ( generate_daily_weighting, @@ -36,7 +35,7 @@ def test_smart_charging(): "ldv_test_data.csv", ), daily_values=daily_values, - load_demand=load_demand, + external_signal=load_demand, bev_vmt=const.emfacvmt, trip_strategy=1, ) @@ -76,7 +75,7 @@ def test_smart_charging_hdv(): "Regional_scaling_factors_UA_", ), ) - result = smart_charging_HDV.smart_charging( + result = smart_charging.smart_charging( model_year=2050, veh_range=200, power=80, @@ -86,7 +85,7 @@ def test_smart_charging_hdv(): const.test_folder_path, "hdv_test_data.csv", ), - initial_load=load_demand, + external_signal=load_demand, bev_vmt=bev_vmt, trip_strategy=1, ) @@ -126,7 +125,7 @@ def test_smart_charging_mdv(): "Regional_scaling_factors_UA_", ), ) - result = smart_charging_HDV.smart_charging( + result = smart_charging.smart_charging( model_year=2050, veh_range=200, power=80, @@ -136,7 +135,7 @@ def test_smart_charging_mdv(): const.test_folder_path, "mdv_test_data.csv", ), - initial_load=load_demand, + external_signal=load_demand, bev_vmt=bev_vmt, trip_strategy=1, )