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

feature: Option to Convert Quadratic Value Curves to PWL for Plexos Parser. Fix Reserve Units. #45

Merged
merged 29 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
36dc981
Plexos: Fix date_from date_to Filtering (#36)
ktehranchi Sep 13, 2024
44dc46f
Plexos: Functionalizes field filtering and preparation of ext data (#37)
ktehranchi Sep 13, 2024
d181c55
Fixes ext nested dict export
ktehranchi Sep 14, 2024
e957c12
Adds default variable data
ktehranchi Sep 16, 2024
731cb6a
Adds scenario filtering to DataFiles
ktehranchi Sep 17, 2024
f7e1a64
resolve comment
ktehranchi Sep 17, 2024
b855041
bump plexosdb vers
ktehranchi Sep 17, 2024
69c7c23
WIP curve conversion
ktehranchi Sep 18, 2024
357000a
ci: Adding publish to pypy
pesap Sep 17, 2024
81a7191
ci: Add codecoverage
pesap Sep 17, 2024
313b32e
ci: Add capability to run the CI manually
pesap Sep 17, 2024
f86a2b5
feat: Add compatibility with more operational cost representation on …
pesap Sep 17, 2024
ef399bd
ci: Adding action on push to main
pesap Sep 17, 2024
1abea63
docs: Update README.md
pesap Sep 17, 2024
374534d
fix(docs): Update README.md
pesap Sep 17, 2024
39546ab
docs: Adding first version of documentation (#42)
pesap Sep 17, 2024
7c9d605
fi: Update README.md
pesap Sep 17, 2024
1ed58cc
fix: Update link on README
pesap Sep 17, 2024
0673620
Fix start up and units of proportional term in FuelCurve
ktehranchi Sep 18, 2024
8a7ee96
WIP Quadratic to PWL
ktehranchi Sep 19, 2024
959454d
output initial storage level
ktehranchi Sep 19, 2024
cf8f300
implements quad2pwl feature #41
ktehranchi Sep 19, 2024
1ed5159
option to specify n_tranches
ktehranchi Sep 19, 2024
57df8c1
feat: Add ReEDS parser to the public version and some Plexos exporter…
pesap Sep 18, 2024
91cb291
simplify curve construction for bid-cost-markup
ktehranchi Sep 19, 2024
d1fa424
Redo Reserve Definition to fix units. Update max gen rating based on …
ktehranchi Sep 20, 2024
e4b5c77
Remove all changes to the reserve model. Remove units in parser
ktehranchi Sep 20, 2024
c4e3ce1
new field active_power_limit_max
ktehranchi Sep 21, 2024
ff1c145
Merge branch 'main' into kt/curve_conversion
ktehranchi Sep 26, 2024
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: 4 additions & 0 deletions src/r2x/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def _add_operation_cost_data( # noqa: C901
fields: list | None = None,
):
operation_cost_fields = set()
x_y_coords = None
for sub_dict in data:
if "operation_cost" not in sub_dict.keys():
continue
Expand Down Expand Up @@ -104,6 +105,9 @@ def _add_operation_cost_data( # noqa: C901
operation_cost_fields.add("heat_rate_a2")
if "x_coords" in function_data.model_fields:
x_y_coords = dict(zip(function_data.x_coords, function_data.y_coords))
if "points" in function_data.model_fields:
x_y_coords = dict((xyCoord.x, xyCoord.y) for xyCoord in function_data.points)
if x_y_coords:
match type(variable_cost):
case infrasys.cost_curves.CostCurve:
for i, (x_coord, y_coord) in enumerate(x_y_coords.items()):
Expand Down
3 changes: 3 additions & 0 deletions src/r2x/exporter/sienna.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ def process_gen_data(self, fname="gen.csv"):
"rating",
"unit_type",
"active_power",
"active_power_limits_max",
"min_rated_capacity",
"min_down_time",
"min_up_time",
Expand Down Expand Up @@ -286,6 +287,7 @@ def process_reserves_data(self, fname="reserves.csv") -> None:
output_dict = reserve
output_dict["direction"] = reserve["direction"].name
output_dict["eligible_device_categories"] = "(Generator,Storage)"
output_dict["requirement"] = reserve["max_requirement"]
contributing_devices = reserve_map.get(reserve["name"])
output_dict["contributing_devices"] = str(tuple(contributing_devices)).replace( # type: ignore
"'", ""
Expand Down Expand Up @@ -322,6 +324,7 @@ def process_storage_data(self, fname="storage.csv") -> None:
"rating",
"input_efficiency",
"output_efficiency",
"initial_energy",
"storage_capacity",
"min_storage_capacity",
"max_storage_capacity",
Expand Down
22 changes: 7 additions & 15 deletions src/r2x/models/costs.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,21 @@ class RenewableGenerationCost(OperationalCost):


class HydroGenerationCost(OperationalCost):
fixed: Annotated[FuelPrice, Field(description="Cost of using fuel in $/MWh.")] = FuelPrice(0.0, "usd/MWh")
fixed: Annotated[float, Field(ge=0, description="Cost of using fuel in $.")] = 0.0
variable: ProductionVariableCostCurve | None = None


class ThermalGenerationCost(OperationalCost):
start_up: Annotated[FuelPrice, Field(description="Cost of using fuel in $/MWh.")] = FuelPrice(
0.0, "usd/MWh"
)
fixed: Annotated[FuelPrice, Field(description="Cost of using fuel in $/MWh.")] = FuelPrice(0.0, "usd/MWh")
shut_down: Annotated[FuelPrice, Field(description="Cost of using fuel in $/MWh.")] = FuelPrice(
0.0, "usd/MWh"
)
start_up: Annotated[float, Field(ge=0, description="Cost of using fuel in $.")] = 0.0
fixed: Annotated[float, Field(ge=0, description="Cost of using fuel in $.")] = 0.0
shut_down: Annotated[float, Field(ge=0, description="Cost of using fuel in $.")] = 0.0
variable: ProductionVariableCostCurve | None = None


class StorageCost(OperationalCost):
start_up: Annotated[FuelPrice, Field(description="Cost of using fuel in $/MWh.")] = FuelPrice(
0.0, "usd/MWh"
)
fixed: Annotated[FuelPrice, Field(description="Cost of using fuel in $/MWh.")] = FuelPrice(0.0, "usd/MWh")
shut_down: Annotated[FuelPrice, Field(description="Cost of using fuel in $/MWh.")] = FuelPrice(
0.0, "usd/MWh"
)
start_up: Annotated[float, Field(ge=0, description="Cost of using fuel in $.")] = 0.0
fixed: Annotated[float, Field(ge=0, description="Cost of using fuel in $.")] = 0.0
shut_down: Annotated[float, Field(ge=0, description="Cost of using fuel in $.")] = 0.0
energy_surplus_cost: Annotated[FuelPrice, Field(description="Cost of using fuel in $/MWh.")] = FuelPrice(
0.0, "usd/MWh"
)
Expand Down
3 changes: 3 additions & 0 deletions src/r2x/models/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ class Generator(Device):
shutdown_cost: (
Annotated[NonNegativeFloat, Field(description="Cost in $ of shuting down a unit.")] | None
) = None
active_power_limits_max: Annotated[
ApparentPower | None, Field(ge=0, description="Maximum output power rating of the unit (MVA).")
] = None


class RenewableGen(Generator):
Expand Down
34 changes: 34 additions & 0 deletions src/r2x/parser/parser_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import polars as pl
import pandas as pd
from datetime import datetime
import numpy as np
from typing import NamedTuple, List

from infrasys.function_data import LinearFunctionData, QuadraticFunctionData, PiecewiseLinearData, XYCoords


def pl_filter_year(df, year: int | None = None, year_columns=["t", "year"], **kwargs):
Expand Down Expand Up @@ -189,3 +193,33 @@ def resample_data_to_hourly(data_file: pl.DataFrame):
)
.select(["year", "month", "day", "hour", "value"])
)


def construct_pwl_from_quadtratic(fn, mapped_records, num_tranches=6):
"""
Given function data of quadratic curve, construct piecewise linear curve with num_tranches tranches.
"""
assert isinstance(fn, QuadraticFunctionData), "Input function data must be of type QuadraticFunctionData"

a = fn.quadratic_term
b = fn.proportional_term
c = fn.constant_term
x_min = mapped_records["min_rated_capacity"].magnitude
x_max = mapped_records["rating"].magnitude

# Use evenly spaced X values for the tranches
# Future iteration should accept custom X values for Bid Cost Markup
x_vals = np.linspace(x_min, x_max, num_tranches)
y_vals = a * x_vals**2 + b * x_vals + c

pwl_fn = PiecewiseLinearData(points=[XYCoords(x, y) for x, y in zip(x_vals, y_vals)])
return pwl_fn


def bid_cost_mark_up(fn, mapped_records):
# TODO(ktehranchi): Implement bid-cost markup
# First we need to convert whichever type of function we have to a piecewise linear function
# This PWL function must have X values definted at the mark-up points
# We can easily modify the mark-up prices by changing the Y values of the PWL function
# Issue right now is we need to do this for time-varying data but market bid cost isnt implemented
pass
Loading