Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: calculate constraints all at once #300

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,6 @@ Thumbs.db
prereise/gather/winddata/data/StatePowerCurves.csv

# Jupyter Notebook
share/
share/

.devcontainer
Empty file.
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import calendar
import inspect
import os
import pathlib

import numpy as np
import pandas as pd
from scipy.io import loadmat

import prereise
from prereise.gather.demanddata.transportation_electrification import const


Expand Down Expand Up @@ -51,10 +54,13 @@ def load_data(census_region: int, filepath: str = "nhts_census_updated.mat"):
"""
if not (1 <= census_region <= 9):
raise ValueError("census_region must be between 1 and 9 (inclusive).")

nhts_census = loadmat(filepath)
raw_data = nhts_census[f"census_{census_region}_updated_dwell"]
return pd.DataFrame(raw_data, columns=const.nhts_census_column_names)
if pathlib.Path(filepath).suffix == ".csv":
census_data = pd.read_csv(filepath)
else:
nhts_census = loadmat(filepath)
raw_data = nhts_census[f"census_{census_region}_updated_dwell"]
census_data = pd.DataFrame(raw_data, columns=const.nhts_census_column_names)
return census_data


def remove_ldt(data: pd.DataFrame):
Expand Down Expand Up @@ -111,7 +117,13 @@ def generate_daily_weighting(year, area_type="urban"):
allowable_area_types = {"urban", "rural"}
if area_type not in allowable_area_types:
raise ValueError(f"area_type must be one of {allowable_area_types}")
data_dir = os.path.join(os.path.dirname(__file__), "data")
data_dir = os.path.join(
os.path.dirname(inspect.getsourcefile(prereise)),
"gather",
"demanddata",
"transportation_electrification",
"data",
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of the change? Just being curious.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just consistent with the method I used on ECTF, I had some issues with file paths on these files

monthly_distribution = pd.read_csv(
os.path.join(data_dir, "moves_monthly.csv"), index_col=0
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,23 +55,21 @@
]


def get_constraints(individual, kwhmi, power, trip_strategy, location_strategy, cost):
def get_constraints(constraints_df, kwhmi, power, trip_strategy, location_strategy):
"""Determine the consumption and charging constraints for each trip (hour segment)

:param pandas.DataFrame individual: trip data of an individual vehicle
:param pandas.DataFrame constraints_df: trip data of vehicles for optimization constraints
:param int kwhmi: fuel efficiency, should vary based on vehicle type and model_year.
:param float power: charger power, EVSE kW.
:param int trip_strategy: a toggle that determines if should charge on any trip or
only after last trip (1-anytrip number, 2-last trip)
:param int location_strategy: where the vehicle can charge-1, 2, 3, 4, 5, or 6;
1-home only, 2-home and work related, 3-anywhere if possibile,
4-home and school only, 5-home and work and school, 6-only work
:param numpy.array cost: cost function
:return: (*pandas.DataFrame*) -- a DataFrame adding the calculated constraints
to an individual vehicle's data
"""
constraints_df = individual.copy()
grouped_trips = individual.groupby("sample vehicle number")
grouped_trips = constraints_df.groupby("sample vehicle number")

# for "power" - setting power value based on "why to"
constraints_df.loc[
Expand Down Expand Up @@ -135,13 +133,6 @@ def get_constraints(individual, kwhmi, power, trip_strategy, location_strategy,
axis=1,
)

constraints_df["rates"] = constraints_df.apply(
lambda d: dwelling.get_rates(
cost, d["End time (hour decimal)"], d["Dwell time (hour decimal)"]
),
axis=1,
)

return constraints_df


Expand All @@ -158,9 +149,7 @@ def calculate_optimization(
:param list segcum: cumulative sum of the segments
:param int total_trips: total number of trips for the current vehicle
:param float kwh: kwhmi * veh_range, amount of energy needed to charge vehicle.
:return: (*scipy.optimize.OptimizeResult*) -- contains the result from the
optimization, such as "x", an array of the optimal values, and "status", which
tells the exit status of the algorithm.
:return: (*dict*) -- contains the necessary inputs for the linprog optimization
"""
f = np.array(rates) / const.charging_efficiency

Expand Down Expand Up @@ -222,14 +211,14 @@ def calculate_optimization(

Aineq[(m - 1) * j : (m - 1) * (j + 1), :] = -a

return linprog(
c=f,
A_ub=Aineq,
b_ub=Bineq,
A_eq=Aeq,
b_eq=Beq,
bounds=bounds,
)
return {
"c": f,
"A_ub": Aineq,
"b_ub": Bineq,
"A_eq": Aeq,
"b_eq": Beq,
"bounds": bounds,
}
dmuldrew marked this conversation as resolved.
Show resolved Hide resolved


def smart_charging(
Expand Down Expand Up @@ -262,7 +251,7 @@ def smart_charging(
:param str filepath: the path to the nhts mat file.
:param pandas.Series daily_values: daily weight factors returned from
:func:`generate_daily_weighting`.
:param np.array LOAD: the initial load demand
:param np.array load_demand: the initial load demand
:param int trip_strategy: determine to charge after any trip (1) or only after the
last trip (2)
:return: (*numpy.ndarray*) -- charging profiles.
Expand Down Expand Up @@ -304,6 +293,8 @@ def smart_charging(

nd_len = len(newdata)

newdata = get_constraints(newdata, kwhmi, power, trip_strategy, location_strategy)

for day_iter in range(len(input_day)):

if day_iter == len(input_day) - 1:
Expand Down Expand Up @@ -344,26 +335,31 @@ def smart_charging(
):

# copy one vehicle information to the block
individual = newdata[i : i + total_trips]

constraints = get_constraints(
individual, kwhmi, power, trip_strategy, location_strategy, cost
individual = newdata.iloc[i : i + total_trips].copy()

individual["rates"] = individual.apply(
lambda d: dwelling.get_rates(
cost,
d["End time (hour decimal)"],
d["Dwell time (hour decimal)"],
),
axis=1,
)

charging_consumption = constraints["charging consumption"].tolist()
charging_consumption = individual["charging consumption"].to_numpy()

rates = constraints["rates"]
rates = individual["rates"]
rates = [r for trip_rates in rates for r in trip_rates]

elimit = constraints["energy limit"]
elimit = individual["energy limit"]
elimit = [el for energy_lim in elimit for el in energy_lim]

seg = constraints["seg"].apply(int).tolist()
seg = individual["seg"].apply(int).to_numpy()

segsum = sum(seg)
segsum = np.sum(seg)
segcum = np.cumsum(seg)

linprog_result = calculate_optimization(
linprog_inputs = calculate_optimization(
charging_consumption,
rates,
elimit,
Expand All @@ -374,6 +370,8 @@ def smart_charging(
kwh,
)

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)
Expand All @@ -385,7 +383,6 @@ def smart_charging(
if exitflag == 0:

# can be an EV
individual = individual.copy()
individual.iloc[
:, newdata.columns.get_loc("BEV could be used")
] = 1
Expand Down Expand Up @@ -485,7 +482,7 @@ def smart_charging(
] = batterysize

# copy individual back to newdata if it can be an EV
newdata[i : i + total_trips] = individual
newdata.iloc[i : i + total_trips] = individual

# update the counter to the next vehicle
i += total_trips
Expand Down
Loading