From 9dc48010ba97f3fee3a16a0f1910eece93efc808 Mon Sep 17 00:00:00 2001 From: dmuldrew Date: Mon, 31 Oct 2022 13:01:00 -0700 Subject: [PATCH] refactor: LDV uses bev_vmt scaling; simplify model_year_profile updates (#321) --- .../data/Fuel_Efficiencies.csv | 22 +++--- .../data_helper.py | 2 +- .../immediate.py | 24 ++++-- .../immediate_charging_HDV.py | 2 +- .../smart_charging.py | 56 ++++---------- .../smart_charging_HDV.py | 74 ++++++------------- .../tests/test_immediate_charging.py | 1 - .../tests/test_smart_charging.py | 1 + 8 files changed, 67 insertions(+), 115 deletions(-) diff --git a/prereise/gather/demanddata/transportation_electrification/data/Fuel_Efficiencies.csv b/prereise/gather/demanddata/transportation_electrification/data/Fuel_Efficiencies.csv index 614f6dc26..46ae5fb24 100644 --- a/prereise/gather/demanddata/transportation_electrification/data/Fuel_Efficiencies.csv +++ b/prereise/gather/demanddata/transportation_electrification/data/Fuel_Efficiencies.csv @@ -1,12 +1,10 @@ -veh_type,2017,2030,2040,2050,,,,,, -LDV_100,0.242,0.214,0.211,0.209,,,,,, -LDV_200,0.259,0.22,0.215,0.214,,,,,, -LDV_300,0.274,0.226,0.22,0.217,,,,,, -LDT_100,0.324,0.318,0.315,0.312,,,,,, -LDT_200,0.344,0.324,0.321,0.321,,,,,, -LDT_300,0.355,0.334,0.331,0.327,,,,,, -MDV,2.13,1.60,1.48,1.37,,,,,, -HDV,2.72,2.13,1.99,1.85,,,,,, -Transit,2.59,2.04,1.91,1.78,,,,,, -,,,,,,,,,, -,,,,,,,,,, +veh_type,2017,2030,2040,2050 +LDV_100,0.242,0.214,0.211,0.209 +LDV_200,0.259,0.22,0.215,0.214 +LDV_300,0.274,0.226,0.22,0.217 +LDT_100,0.324,0.318,0.315,0.312 +LDT_200,0.344,0.324,0.321,0.321 +LDT_300,0.355,0.334,0.331,0.327 +MDV,2.13,1.60,1.48,1.37 +HDV,2.72,2.13,1.99,1.85 +Transit,2.59,2.04,1.91,1.78 diff --git a/prereise/gather/demanddata/transportation_electrification/data_helper.py b/prereise/gather/demanddata/transportation_electrification/data_helper.py index 8a2b7fa02..59bdfa609 100644 --- a/prereise/gather/demanddata/transportation_electrification/data_helper.py +++ b/prereise/gather/demanddata/transportation_electrification/data_helper.py @@ -64,7 +64,7 @@ def get_kwhmi(model_year, veh_type, veh_range): data = pd.read_csv(filepath, index_col="veh_type") if (veh_type.upper() == "LDV") or (veh_type.upper() == "LDT"): - kwhmi = data.loc[f"{veh_type.upper()}_{veh_range}", model_year] + kwhmi = data.loc[f"{veh_type.upper()}_{veh_range}", str(model_year)] elif (veh_type.upper() == "MDV") or (veh_type.upper() == "HDV"): kwhmi = data.loc[f"{veh_type.upper()}", str(model_year)] diff --git a/prereise/gather/demanddata/transportation_electrification/immediate.py b/prereise/gather/demanddata/transportation_electrification/immediate.py index df69bc9ad..bdc057bd4 100644 --- a/prereise/gather/demanddata/transportation_electrification/immediate.py +++ b/prereise/gather/demanddata/transportation_electrification/immediate.py @@ -104,7 +104,6 @@ def immediate_charging( census_region, model_year, veh_range, - kwhmi, power, location_strategy, veh_type, @@ -112,10 +111,10 @@ def immediate_charging( trip_strategy=1, ): """Immediate charging function + :param int census_region: any of the 9 census regions defined by US census bureau. :param int model_year: year that is being modelled/projected to, 2017, 2030, 2040, 2050. :param int veh_range: 100, 200, or 300, represents how far vehicle can travel on single charge. - :param int kwhmi: 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, 2, 3, 4, or 5; 1-home only, 2-home and work related, 3-anywhere if possibile, @@ -125,16 +124,20 @@ def immediate_charging( :param int trip_strategy: determine to charge after any trip (1) or only after the last trip (2) :return: (*numpy.ndarray*) -- charging profiles. """ - # Constants - battery_capacity = kwhmi * veh_range - input_day = data_helper.get_input_day(data_helper.get_model_year_dti(model_year)) - # load NHTS data from function if veh_type.lower() == "ldv": trips = data_helper.remove_ldt(data_helper.load_data(census_region, filepath)) - elif veh_type.lower() == "ldt": trips = data_helper.remove_ldv(data_helper.load_data(census_region, filepath)) + elif veh_type.lower() == "mdv": + trips = data_helper.load_hdv_data("mhdv", filepath) + elif veh_type.lower() == "hdv": + trips = data_helper.load_hdv_data("hhdv", filepath) + + # Constants + kwhmi = data_helper.get_kwhmi(model_year, veh_type, veh_range) + battery_capacity = kwhmi * veh_range + input_day = data_helper.get_input_day(data_helper.get_model_year_dti(model_year)) # updates the weekend and weekday values in the nhts data trips = data_helper.update_if_weekend(trips) @@ -148,6 +151,7 @@ def immediate_charging( new_columns = [ "trip start battery charge", "trip end battery charge", + "charging power", "charging time", "charging consumption", "BEV could be used", @@ -172,7 +176,11 @@ def immediate_charging( # Add booleans for whether the dell time is long enough to allow charging trips["dwell_allowed"] = trips["dwell_time"] > 0.2 # Add boolean for whether this trip allows charging - allowed_cols = ["location_allowed", "trip_allowed", "dwell_allowed"] + allowed_cols = [ + "location_allowed", + "trip_allowed", + "dwell_allowed", + ] trips["charging_allowed"] = trips[allowed_cols].apply(all, axis=1) # Evaluate weekend vs. weekday for each trip diff --git a/prereise/gather/demanddata/transportation_electrification/immediate_charging_HDV.py b/prereise/gather/demanddata/transportation_electrification/immediate_charging_HDV.py index 72c11d21c..75178195e 100644 --- a/prereise/gather/demanddata/transportation_electrification/immediate_charging_HDV.py +++ b/prereise/gather/demanddata/transportation_electrification/immediate_charging_HDV.py @@ -237,7 +237,7 @@ def immediate_charging( if trip_strategy == 1: trips["trip_allowed"] = True elif trip_strategy == 2: - trips["trip_allowed"] = trips["trip_number"] == trips["total vehicle trips"] + trips["trip_allowed"] = trips["trip_number"] == trips["total_trips"] # Add booleans for whether the dell time is long enough to allow charging -- (1) trips["dwell_allowed"] = trips["dwell_time"] > 0.2 diff --git a/prereise/gather/demanddata/transportation_electrification/smart_charging.py b/prereise/gather/demanddata/transportation_electrification/smart_charging.py index 279674d7c..43cb5d234 100644 --- a/prereise/gather/demanddata/transportation_electrification/smart_charging.py +++ b/prereise/gather/demanddata/transportation_electrification/smart_charging.py @@ -22,6 +22,7 @@ def smart_charging( filepath, daily_values, load_demand, + bev_vmt, trip_strategy=1, ): """Smart charging function @@ -64,11 +65,11 @@ def smart_charging( "trip start battery charge", "trip end battery charge", "BEV could be used", - "trip_number", + "Battery size", "Electricity cost", "Battery discharge", "Battery charge", - "Battery size", + "trip_number", ] newdata = newdata.reindex(list(newdata.columns) + new_columns, axis=1, fill_value=0) @@ -82,7 +83,6 @@ def smart_charging( daily_vmt_total = data_helper.get_total_daily_vmt(newdata, input_day, daily_values) kwh = kwhmi * veh_range - emfacvmt = const.emfacvmt if power > 19.2: charging_efficiency = 0.95 else: @@ -222,7 +222,9 @@ def smart_charging( segcum = np.cumsum(seg) trip_g2v_load[:, start : end + 1] = ( - x[segcum[n] - seg[n] : segcum[n]] / charging_efficiency + # 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 @@ -237,9 +239,9 @@ def smart_charging( electricitycost = trip_g2v_cost tripload = trip_v2g_load + trip_g2v_load - # update the cost function and vonvert from KW to MW + # update the cost function and convert from KW to MW cost += ( - tripload / 1000 / daily_vmt_total[day_iter] * emfacvmt + tripload / 1000 / daily_vmt_total[day_iter] * bev_vmt )[0, :] # SOC rise in kwh, from charging @@ -278,45 +280,19 @@ def smart_charging( :, 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) - if day_iter == len(input_day) - 1: - # MW - model_year_profile[day_iter * 24 :] += ( - outputelectricload[:24] / (daily_vmt_total[day_iter] * 1000) * emfacvmt - ) - model_year_profile[:24] += ( - outputelectricload[24:48] - / (daily_vmt_total[day_iter] * 1000) - * emfacvmt - ) - model_year_profile[24:48] += ( - outputelectricload[48:72] - / (daily_vmt_total[day_iter] * 1000) - * emfacvmt - ) - - elif day_iter == len(input_day) - 2: - # MW - model_year_profile[day_iter * 24 : day_iter * 24 + 48] += ( - outputelectricload[:48] / (daily_vmt_total[day_iter] * 1000) * emfacvmt - ) - model_year_profile[:24] += ( - outputelectricload[48:72] - / (daily_vmt_total[day_iter] * 1000) - * emfacvmt - ) + # create wrap-around indexing function + profile_window_indices = np.arange(day_iter * 24, day_iter * 24 + 72) % len( + model_year_profile + ) - else: - # MW - model_year_profile[day_iter * 24 : day_iter * 24 + 72] += ( - outputelectricload / (daily_vmt_total[day_iter] * 1000) * emfacvmt - ) + # MW + model_year_profile[profile_window_indices] += ( + outputelectricload / (daily_vmt_total[day_iter] * 1000) * bev_vmt + ) return model_year_profile diff --git a/prereise/gather/demanddata/transportation_electrification/smart_charging_HDV.py b/prereise/gather/demanddata/transportation_electrification/smart_charging_HDV.py index ab5469d26..bf68028fe 100644 --- a/prereise/gather/demanddata/transportation_electrification/smart_charging_HDV.py +++ b/prereise/gather/demanddata/transportation_electrification/smart_charging_HDV.py @@ -60,9 +60,9 @@ def smart_charging( "trip end battery charge", "BEV could be used", "Battery size", + "Electricity cost", "Battery discharge", "Battery charge", - "Electricity cost", ] newdata = newdata.reindex(list(newdata.columns) + new_columns, axis=1, fill_value=0) @@ -95,33 +95,20 @@ def smart_charging( charging_efficiency, ) - for day_iter in range(model_year_len): - - # Expand load vector linearly to 7200 points instead of 72 - if day_iter == model_year_len - 1: # 365 - adjusted_load = [ - load_demand[i] + model_year_profile[i] - for i in range(day_iter * 24, (day_iter + 1) * 24) - ] - adjusted_load += [load_demand[i] + model_year_profile[i] for i in range(48)] + day_num = model_year_len + for day_iter in range(day_num): - elif day_iter == model_year_len - 2: # 364 - adjusted_load = [ - load_demand[i] + model_year_profile[i] - for i in range(day_iter * 24, ((day_iter + 1) * 24) + 24) - ] - adjusted_load += [load_demand[i] + model_year_profile[i] for i in range(24)] - - elif day_iter == model_year_len - 3: # 363 - adjusted_load = [ - load_demand[i] + model_year_profile[i] - for i in range(day_iter * 24, ((day_iter + 1) * 24) + 48) - ] + 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 + ) + ] - else: - adjusted_load = [ + if 3 - day_num + day_iter > 0: + adjusted_load += [ load_demand[i] + model_year_profile[i] - for i in range(day_iter * 24, (day_iter * 24) + 72) + for i in range(24 * (3 - day_num + day_iter)) ] cost = np.array(adjusted_load) @@ -269,39 +256,22 @@ def smart_charging( :, 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 + # # 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) - if day_iter == model_year_len - 1: - # MW - model_year_profile[day_iter * 24 :] += ( - outputelectricload[:24] / (daily_vmt_total[day_iter] * 1000) * bev_vmt - ) - model_year_profile[:24] += ( - outputelectricload[24:48] / (daily_vmt_total[day_iter] * 1000) * bev_vmt - ) - model_year_profile[24:48] += ( - outputelectricload[48:72] / (daily_vmt_total[day_iter] * 1000) * bev_vmt - ) + # create wrap-around indexing function + profile_window_indices = np.arange(day_iter * 24, day_iter * 24 + 72) % len( + model_year_profile + ) - elif day_iter == model_year_len - 2: - # MW - model_year_profile[day_iter * 24 : day_iter * 24 + 48] += ( - outputelectricload[:48] / (daily_vmt_total[day_iter] * 1000) * bev_vmt - ) - model_year_profile[:24] += ( - outputelectricload[48:72] / (daily_vmt_total[day_iter] * 1000) * bev_vmt - ) - - else: - # MW - model_year_profile[day_iter * 24 : day_iter * 24 + 72] += ( - outputelectricload / (daily_vmt_total[day_iter] * 1000) * bev_vmt - ) + # MW + model_year_profile[profile_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_immediate_charging.py b/prereise/gather/demanddata/transportation_electrification/tests/test_immediate_charging.py index 8e67ab3d1..31ac7bd79 100644 --- a/prereise/gather/demanddata/transportation_electrification/tests/test_immediate_charging.py +++ b/prereise/gather/demanddata/transportation_electrification/tests/test_immediate_charging.py @@ -17,7 +17,6 @@ def test_immediate_charging_region1(): census_region=1, model_year=2017, veh_range=100, - kwhmi=0.242, power=6.6, location_strategy=2, veh_type="LDV", diff --git a/prereise/gather/demanddata/transportation_electrification/tests/test_smart_charging.py b/prereise/gather/demanddata/transportation_electrification/tests/test_smart_charging.py index 6f1812ce5..85e20da9d 100644 --- a/prereise/gather/demanddata/transportation_electrification/tests/test_smart_charging.py +++ b/prereise/gather/demanddata/transportation_electrification/tests/test_smart_charging.py @@ -37,6 +37,7 @@ def test_smart_charging(): ), daily_values=daily_values, load_demand=load_demand, + bev_vmt=const.emfacvmt, trip_strategy=1, )