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

Dmuldrew/smart calculate charging #324

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
09a85f4
feat: adding data processing script (#243)
isond Jan 5, 2022
11d0905
feat: generate profiles for immediate charging (#266)
isond Mar 12, 2022
7dad265
style: update style from #266
danielolsen Mar 14, 2022
3086e56
feat: add function to calculate VMT share for each day of the year (#…
danielolsen May 26, 2022
89ec675
fix: negative dwell time calculation in data processing (#299)
isond Jun 13, 2022
41d4cdb
feat: add smart_charging file
isond Apr 8, 2022
1bf9c87
feat: add dwelling file
isond Apr 8, 2022
dba5573
refactor: add get_total_daily_vmt function
isond Apr 8, 2022
27e6299
refactor: fix get_segment function
isond Apr 18, 2022
ee67a54
refactor: fix get_energy_limit function
isond Apr 18, 2022
938cb77
docs: update docstrings for get_segment and get_energy_limit
isond Apr 18, 2022
cdedb6f
refactor: fix how to get daily_vmt_total
isond Apr 19, 2022
1488be8
refactor: update locationstrategy to location_strategy and its usage
isond Apr 19, 2022
cfd5c0d
docs: update docstrings for get_total_daily_vmt
isond Apr 19, 2022
eb3b775
fix: change type hints in get_total_daily_vmt
isond Apr 19, 2022
65b6890
refactor: add more helper functions
isond Apr 27, 2022
9c4292c
refactor: add additional newdata columns
isond May 5, 2022
6204028
refactor: add get_constrtaints function
isond May 5, 2022
872b566
refactor: update constraints section in main function
isond May 5, 2022
a4ecaa5
refactor: add calculate_optimization function
isond May 5, 2022
07f07fd
refactor: update optimization section in main function
isond May 5, 2022
634c28e
refactor: change start and end values
isond May 5, 2022
2653a5b
refactor: fix indexing and tripG2Vload calculation
isond May 5, 2022
21d021b
refactor: fix trip start battery charge and trip end battery charge v…
isond May 5, 2022
8aee61d
refactor: remove else-statement
isond May 5, 2022
3cdc32e
fix: add import statements
isond May 5, 2022
c77657e
refactor: add location_allowed and why_to_list
isond May 5, 2022
ba716e9
refactor: remove if-statement in get_total_daily_vmt
isond May 5, 2022
259972c
refactor: update daily_vmt_total to a dict
isond May 5, 2022
dfe007b
refactor: update get_segment calculation
isond May 5, 2022
cf89d1d
refactor: update get_energy_limit calculation
isond May 5, 2022
86ef396
refactor: use math.floor instead of round in get_rates
isond May 5, 2022
39c97ca
refactor: add values to trip number
isond May 5, 2022
317d603
refactor: fix daily_vmt_total indexing
isond May 5, 2022
b9812eb
fix: fix smart_charging parameters
isond May 5, 2022
9d9fd9b
refactor: update smart_charging function
isond May 5, 2022
63db004
refactor: update get_total_daily_vmt
isond May 27, 2022
dd9d76a
fix: add daily_values to smart_charging params
isond May 27, 2022
fbde869
refactor: update daily_vmt_total indexing
isond May 27, 2022
bc38392
fix: update linprog method to default method
isond May 27, 2022
6b5d0c4
test: add smart charging test and data
dmuldrew Aug 23, 2022
5362e22
refactor: calculate all optimization constraints at once
dmuldrew Aug 23, 2022
b2f56d5
feat: add regional scaling factors
dmuldrew Sep 13, 2022
bf31961
chore: additional data files, move all data files to data folder
dmuldrew Sep 13, 2022
c8d960e
feat: add immediate hdv implementation
dmuldrew Sep 13, 2022
12e9553
test: add immediate hdv test
dmuldrew Sep 13, 2022
9d06f35
refactor: update total_hdv_daily_vmt function
dmuldrew Sep 14, 2022
bee5e71
feat: add HDV smart charging implementation
dmuldrew Sep 14, 2022
da28277
refactor: transportation electrification to common data columns (#311)
dmuldrew Sep 29, 2022
f2f41d5
refactor: maximum LDV dwell period to 72 hours, finish charging effic…
dmuldrew Oct 7, 2022
b2dd326
refactor: short hdv tests, common optimization functions (#318)
dmuldrew Oct 22, 2022
9dc4801
refactor: LDV uses bev_vmt scaling; simplify model_year_profile updat…
dmuldrew Oct 31, 2022
6f44de3
refactor: modify immediate adjust_bev (#323)
dmuldrew Nov 16, 2022
b655e7b
refactor: add optional kwhmi parameter
dmuldrew Nov 17, 2022
0830d14
refactor: add calculate daily smart charging function
dmuldrew Nov 17, 2022
316407b
refactor: wraparound loop update
dmuldrew Nov 14, 2022
f2b1198
test: update immediate scaling tests
dmuldrew Nov 14, 2022
8831f6d
doc: add transportation architecture diagram to README
dmuldrew Nov 18, 2022
3261571
doc: add mermaid rendering block
dmuldrew Nov 18, 2022
0d14aca
doc: update subgraph text
dmuldrew Nov 18, 2022
679f2f7
refactor: filtered vmt_total; bev_vmt daily_values
dmuldrew Dec 2, 2022
d3025c5
test: debugging printouts for optimization failures
dmuldrew Dec 2, 2022
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
16 changes: 16 additions & 0 deletions ATTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,22 @@ These datasets are used to generate flexibility profiles that are realized throu
These datasets are generously provided by NREL, which is operated for the U.S. Department of Energy by the Alliance for Sustainable Energy, LLC. Before using these datasets, please read [this disclaimer](https://www.nrel.gov/disclaimer.html) first.


#### U.S. Environmental Protection Agency
##### Source
* Name: MOVES2010 Highway Vehicle Population and Activity Data
* Author: U.S. Environmental Protection Agency
* Description: Vehicle Miles Travelled disribution by month and by weekday/weekend
* Source: https://www.epa.gov/moves/moves-onroad-technical-reports
* Exact Source Location: https://nepis.epa.gov/Exe/ZyPDF.cgi?Dockey=P100ABRO.pdf

##### Destination
* Modifications to source file(s): None
* Location:
* ***prereise/gather/demanddata/transportation_electrification/moves_daily.csv***
* ***prereise/gather/demanddata/transportation_electrification/moves_monthly.csv***

##### General Purpose
The dataset is used to distribute the annual vehicle miles traveled (VMT) using seasonal weight factors for the final charging profiles.

---
### Hydro
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def test_download_data():
os.remove("project_resstock_efs_2013.zip")


@pytest.mark.integration
def test_extract_data():
# Create a dummy demand data set
cont_states = sorted(set(abv2state) - {"AK", "HI"})
Expand Down Expand Up @@ -135,6 +136,7 @@ def test_extract_data():
os.remove("test_demand.csv")


@pytest.mark.integration
def test_partition_demand_by_sector():
# Create a dummy demand data set
cont_states = sorted(set(abv2state) - {"AK", "HI"})
Expand Down Expand Up @@ -174,6 +176,7 @@ def test_partition_demand_by_sector():
os.remove("EFSLoadProfile_High_Rapid.csv")


@pytest.mark.integration
def test_partition_flexibility_by_sector():
# Create a dummy flexibility data set
cont_states = sorted(set(abv2state) - {"AK", "HI"})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Architecture Diagram

``` mermaid
graph TD
A[Vehicle Demand Interface Function] -->|choose vehicle type, vehicle range, model year, charging strategy| B(Load Data)
I --> |evaluate whether charging is available| C{calculate charging over \n given trip window}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe we are trying to roll into a new line by \n here but I don't see this deployed properly in the preview. Not sure what is the right way to do so in mermaid.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, this is what I see in the diagram:
image

J --> H[Geospecific Hourly Load Profile]
H --> F[fa:fa-car Vehicle Demand Profiles]
H --> E[Vehicle Load Plots]
H --> G[Vehicle Load Statistics]
B --> |parse out relevant columns| I[Charging availability and strategy]

subgraph Trip Window Loop
C --> D(Normalized Trip Demand)
D --> |scale for daily/monthly driving patterns, yearly regional scaling factors| J(Scaled Trip Demand)
C --> |loop over days in year| C
end
```
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import numpy as np
import pandas as pd

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


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

: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 dict location_allowed: starting locations allowed in the dataset
:param float charging_efficiency: from grid to battery efficiency.
:return: (*pandas.DataFrame*) -- a DataFrame adding the calculated constraints
to an individual vehicle's data
"""
grouped_trips = constraints_df.groupby("vehicle_number")

constraints_df.loc[
constraints_df["dwell_location"].isin(const.dwell_location_list),
"power_allowed",
] = power
constraints_df["power_allowed"].fillna(0, inplace=True)

# for "power" - location
if location_strategy == 3:
constraints_df["location_allowed"] = True
else:
allowed = location_allowed[location_strategy]
constraints_df["location_allowed"] = constraints_df["dwell_location"].map(
lambda x: x in allowed
)

# for "power" - trip_number
if trip_strategy == 1:
constraints_df["trip_allowed"] = True
elif trip_strategy == 2:
constraints_df["trip_allowed"] = (
constraints_df["trip_number"] == constraints_df["total_trips"]
)

# for "power" - dwell
constraints_df["dwell_allowed"] = constraints_df["dwell_time"] > 0.2

# for "power" - determine if can charge
allowed_cols = [
"power_allowed",
"location_allowed",
"trip_allowed",
"dwell_allowed",
]
constraints_df["charging_allowed"] = constraints_df[allowed_cols].apply(all, axis=1)

for trip_num, group in grouped_trips:
constraints_df.loc[group.index, "charging consumption"] = (
constraints_df.loc[group.index, "trip_miles"] * kwhmi * -1
)
constraints_df.loc[group.index, "seg"] = dwelling.get_segment(
constraints_df.loc[group.index, "trip_end"],
constraints_df.loc[group.index, "dwell_time"],
)

constraints_df.loc[
constraints_df["charging_allowed"] == True, "power" # noqa: E712
] = constraints_df["power_allowed"]
constraints_df["power"].fillna(0, inplace=True)

constraints_df["segcum"] = constraints_df["seg"].transform(pd.Series.cumsum)

constraints_df["energy limit"] = constraints_df.apply(
lambda d: dwelling.get_energy_limit(
d["power"],
d["seg"],
d["trip_end"],
d["dwell_time"],
charging_efficiency,
),
axis=1,
)

return constraints_df


def calculate_optimization(
charging_consumption,
rates,
elimit,
seg,
total_trips,
kwh,
charging_efficiency,
):
"""Calculates the minimized charging cost during a specific dwelling activity

:param list charging_consumption: the charging consumption for each trip
:param list rates: rates to be used for the cost function
:param list elimit: energy limits during the time span of available charging
:param list seg: the amount of the segments in the dwelling activity
: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.
:param float charging_efficiency: from grid to battery efficiency.
:return: (*dict*) -- contains the necessary inputs for the linprog optimization
"""

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

f = np.array(rates) / charging_efficiency

# form all the constraints
# equality constraint
Aeq = np.ones((1, segsum)) # noqa: N806

# equality constraint
Beq = -sum(charging_consumption) # noqa: N806

# G2V power upper bound in DC
ub = elimit
lb = [0] * segsum
bounds = list(zip(lb, ub))

# formulate the constraints matrix in Ax <= b, A can be divided into m
# generate the cumulative sum array of seg in segcum

# the amount of trips. submatrix dimension is m-1 * m
m = total_trips

# 'a' is a m-1 * segsum matrix
a = np.zeros((m - 1, segsum))
Aineq = np.zeros(((m - 1) * m, segsum)) # noqa: N806

b = np.tril(np.ones((m - 1, m)), 1)
Bineq = np.zeros((m * (m - 1), 1)) # noqa: N806

for j in range(m):
# part of the A matrix
a = np.zeros((m - 1, segsum))

if j > 0:
# switch components in b matrix
bb = np.concatenate((b[:, m - j : m], b[:, : m - j]), axis=1)

else:
# do not switch if j is 0
bb = b

charging_consumption = np.array(charging_consumption)
cc = charging_consumption.reshape((charging_consumption.shape[0], 1))

# set the constraints in DC
Bineq[(m - 1) * j : (m - 1) * (j + 1), :] = kwh + (np.dot(bb, cc))

for ii in range(m - 1):
# indicate the number of the trips
k = j + ii

if k < m:
# ones part of the column
a[ii : m - 1, segcum[k] - seg[k] : segcum[k]] = 1

else:
k = k - m
# ones part of the column
a[ii : m - 1, segcum[k] - seg[k] : segcum[k]] = 1

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

return {
"c": f,
"A_ub": Aineq,
"b_ub": Bineq,
"A_eq": Aeq,
"b_eq": Beq,
"bounds": bounds,
}
Loading