Skip to content

jbadsdata/emissions-analytics-tool

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

About

This repository is a WORK IN PROGRESS continuation of contributions made by an incredibly talented group of WattTime volunteers.

  • Synthetic data package: getting your hands on device data can be challenging. To evaluate the package functionality, you can create synthetic data. See how to generate synthetic data for two different use cases.
  • Evaluation package “Bring Your Own Data”: You can bring your own historic example data and test it using historic forecast and actual MOER data. See bring your own data.
  • Metrics package:
    • Allows you to compare emissions avoided vs compared to baseline and ideal estimates per row, each row represents a charging session.
    • Metrics:
      • emissions_avoided: Counterfactual marginal emissions difference. A negative value indicates avoided emissions.
      • expected_avoidance: Anticipated counterfactual marginal emissions avoided by following the optimized charging schedule.
      • nearness_to_ideal: Ideal emissions are generated by creating a charging schedule using historic actuals, an optimization based on perfect foresight. You cannot achieve a better outcome than ideal. Nearness to ideal tells us how close our forecasted, optimized plan came to ideal emissions.
      • forecast_error: The difference between what the charging schedule projected the sessions' emissions would be compared to the actual outcome.
import evaluation.metrics as m
import pandas as pd

df = pd.DataFrame(
    	[['2024-08-11','uuid_01',83,  4, 43, 43],['2024-08-20','uuid_2',49, 48, 48, 50]],
columns=["distinct_dates","user_type","baseline_emissions","ideal_emissions",
"forecast_emissions","actual_emissions"]
)

em = m.EvalMetrics(
    baseline_col= "baseline_emissions",
    ideal_col="ideal_emissions", 
    forecast_col="forecast_emissions",
    actuals_col="actual_emissions"
    )

em.calculate_results(
df,
keep_cols = ["distinct_dates","user_type"], 
percent=False
)

em.calculate_results(
df,
keep_cols = ["distinct_dates","user_type"], 
percent=True
)
  • Running the model with constraints::
    • Contiguous (single period, fixed length):
## AI model training - estimated runtime is 2 hours and it needs to complete by 12pm

from datetime import datetime, timedelta
import pandas as pd
from pytz import UTC
from watttime import WattTimeOptimizer
import os

username = os.getenv("WATTTIME_USER")
password = os.getenv("WATTTIME_PASSWORD")
wt_opt = WattTimeOptimizer(username, password)

# Suppose that the time now is 12 midnight
now = datetime.now(UTC)
window_start = now
window_end = now + timedelta(minutes=720)

usage_time_required_minutes=120
usage_power_kw = 12.0
region = "PJM_CHICAGO"

usage_plan = wt_opt.get_optimal_usage_plan(
    region=region,
    usage_window_start=window_start,
    usage_window_end=window_end,
    usage_time_required_minutes=usage_time_required_minutes,
    usage_power_kw=usage_power_kw,
    charge_per_interval=[usage_time_required_minutes],
    optimization_method="auto",
)

print(usage_plan.head())
print(usage_plan["usage"].tolist())
print(usage_plan.sum())
  • Contiguous (multiple periods, fixed length):
## Dishwasher - there are two cycles of length 80 min and 40 min each, and they must be completed in that order. 

from datetime import datetime, timedelta
import pandas as pd
from pytz import UTC
from watttime import WattTimeOptimizer
import os

username = os.getenv("WATTTIME_USER")
password = os.getenv("WATTTIME_PASSWORD")
wt_opt = WattTimeOptimizer(username, password)

# Suppose that the time now is 12 midnight
now = datetime.now(UTC)
window_start = now
window_end = now + timedelta(minutes=720)

usage_time_required_minutes=120
usage_power_kw = 12.0
region = "PJM_CHICAGO"

usage_plan = wt_opt.get_optimal_usage_plan(
    region=region,
    usage_window_start=window_start,
    usage_window_end=window_end,
    usage_time_required_minutes=usage_time_required_minutes,
    usage_power_kw=usage_power_kw,
    charge_per_interval=[80,40],
    optimization_method="auto",
)

print(usage_plan.head())
print(usage_plan["usage"].tolist())
print(usage_plan.sum())
  • Contiguous (multiple periods, variable length):
## Compressor - needs to run 120 minutes over the next 12 hours; each cycle needs to be at least 20 minutes long, and any number of contiguous intervals (from one to six) is okay.

from datetime import datetime, timedelta
import pandas as pd
from pytz import UTC
from watttime import WattTimeOptimizer
import os

username = os.getenv("WATTTIME_USER")
password = os.getenv("WATTTIME_PASSWORD")
wt_opt = WattTimeOptimizer(username, password)

# Suppose that the time now is 12 midnight
now = datetime.now(UTC)
window_start = now
window_end = now + timedelta(minutes=720)

usage_time_required_minutes=120
usage_power_kw = 12.0
region = "PJM_CHICAGO"

usage_plan = wt_opt.get_optimal_usage_plan(
    region=region,
    usage_window_start=window_start,
    usage_window_end=window_end,
    usage_time_required_minutes=usage_time_required_minutes,
    usage_power_kw=usage_power_kw,
    # Here _None_ implies that there is no upper bound, and replacing None by 120 would have the exact same effect.
    charge_per_interval=[(20,None),(20,None),(20,None),(20,None),(20,None),(20,None)],
    optimization_method="auto",
    use_all_intervals=False
)

print(usage_plan.head())
print(usage_plan["usage"].tolist())
print(usage_plan.sum())
  • Variable power curve:
## I know the model of my vehicle and want to match device characteristics.
## Here we suppose we have a 10 kWh battery which initially charges at 20kW,
## the charge rate then linearly decreases to 10kW as the battery is 50%
## charged, and then remains at 10kW for the rest of the charging.

from datetime import datetime, timedelta
import pandas as pd
from pytz import UTC
from watttime import WattTimeOptimizer
import evaluation.eval_framework as evu
import evaluation.battery as b
import os

username = os.getenv("WATTTIME_USER")
password = os.getenv("WATTTIME_PASSWORD")
region = "PJM_NJ"
wt_opt = WattTimeOptimizer(username, password)

now = datetime.now(UTC)
window_start = now
window_end = now + timedelta(minutes=720)

battery = b.Battery(
    initial_soc=0.0,
    charging_curve=pd.DataFrame(
        columns=["SoC", "kW"],
        data=[
            [0.0, 20.0],
            [0.5, 10.0],
            [1.0, 10.0],
        ]
    ),
    capacity_kWh=10.0,
)
time_needed = evu.get_time_needed(
    total_capacity_kWh=battery.capacity_kWh,
    usage_power_kW=battery.get_usage_power_kw_df(),
    initial_capacity_fraction=battery.initial_soc,
)

usage_plan = wt_opt.get_optimal_usage_plan(
    region=region,
    usage_window_start=window_start,
    usage_window_end=window_end,
    usage_time_required_minutes=time_needed,
    usage_power_kw=battery.get_usage_power_kw_df(),
    optimization_method="auto",
)

print(usage_plan.head())
print(usage_plan["usage"].tolist())
print(usage_plan.sum())
  • Partial charging guarantee:
## I would like to charge 75% by 8am in case of any emergencies (airport, kid bus, roadtrip)

from datetime import datetime, timedelta
import pandas as pd
from pytz import UTC
from watttime import WattTimeOptimizer
import os

username = os.getenv("WATTTIME_USER")
password = os.getenv("WATTTIME_PASSWORD")
wt_opt = WattTimeOptimizer(username, password)

# Suppose that the time now is 12 midnight
now = datetime.now(UTC)
window_start = now
window_end = now + timedelta(minutes=720)
usage_time_required_minutes = 240
constraint_time = now + timedelta(minutes=480)
constraint_usage_time_required_minutes = 180
constraints = {constraint_time:constraint_usage_time_required_minutes}
usage_power_kw = 12.0
region = "PJM_NJ"

usage_plan = wt_opt.get_optimal_usage_plan(
    region=region,
    usage_window_start=window_start,
    usage_window_end=window_end,
    usage_time_required_minutes=240,
    usage_power_kw=usage_power_kw,
    constraints=constraints,
    optimization_method="auto",
)

print(usage_plan.head())
print(usage_plan["usage"].tolist())
print(usage_plan.sum())

About

experimental tooling for testing hourly emissions forecasts on synthetic smart device data

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published