Skip to content
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
14 changes: 11 additions & 3 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Dispatch Release Notes
.. _release-v0-2-0:

---------------------------------------------------------------------------------------
0.2.0 (2022-XX-XX)
0.2.0 (2022-09-15)
---------------------------------------------------------------------------------------

What's New?
Expand All @@ -24,14 +24,22 @@ What's New?
``retirement_date`` columns in ``fossil_plant_specs`` determine the period during
dispatch that a generator may operate. This provides a straightforward method for
having the portfolio you wish to dispatch change over time.
* Cleanup and rationalization of :meth:`dispatch.model.DispatchModel.to_file` and
:meth:`dispatch.model.DispatchModel.from_file` methods.
* Updates to system for storing and processing marginal cost data. This is now a
separate argument to :meth:`dispatch.model.DispatchModel.__init__` rather than a
messy confusing part of ``fossil_plant_specs``. This is now consistent with how
``patio`` prepares and stores the data.

Bug Fixes
^^^^^^^^^
* ...
* :meth:`dispatch.model.DispatchModel.to_file` and
:meth:`dispatch.model.DispatchModel.from_file` now properly deal with
internal data stored in both :class:`pd.DataFrame` and :class:`pd.Series`.

Known Issues
^^^^^^^^^^^^
* ...
* Tests are still pretty rudimentary.

.. _release-v0-1-0:

Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ dependencies:
- numexpr ~= 2.8
- numpy >= 1.18.5,<2
- pandas >= 1.4,<1.5
- pandera >= 0.12
- pyarrow >= 7,<10
- plotly

Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ install_requires =
numexpr ~= 2.8
numpy >= 1.18.5,<2
pandas >= 1.4,<1.5
pandera ~= 0.12
pyarrow>=7, <10

[options.packages.find]
Expand All @@ -40,7 +41,6 @@ doc =
sphinx-autoapi>=1.8,<1.10
sphinx-autodoc-typehints
sphinxcontrib-mermaid
; furo>=2022.4.7
pydata-sphinx-theme>=0.10
sphinx-issues>=1.2,<3.1
tests =
Expand Down
19 changes: 15 additions & 4 deletions src/dispatch/__init__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
"""A template repository for a Python package created by Catalyst Cooperative."""
import logging

import pkg_resources
from importlib.metadata import PackageNotFoundError, version

from dispatch.engine import dispatch_engine, dispatch_engine_compiled
from dispatch.helpers import apply_op_ret_date, copy_profile
from dispatch.model import DispatchModel

__all__ = ["DispatchModel", "dispatch_engine", "dispatch_engine_compiled"]
__all__ = [
"DispatchModel",
"dispatch_engine",
"dispatch_engine_compiled",
"copy_profile",
"apply_op_ret_date",
]

__author__ = "RMI"
__contact__ = "aengel@rmi.org"
__maintainer__ = "Alex Engel"
__license__ = "BSD 3-Clause License"
__maintainer_email__ = "aengel@rmi.org"
__version__ = pkg_resources.get_distribution("rmi.dispatch").version
__docformat__ = "restructuredtext en"
__description__ = "A simple and efficient dispatch model."

try:
__version__ = version("rmi.dispatch")
except PackageNotFoundError:
# package is not installed
pass

__projecturl__ = "https://github.com/rmi-electricity/dispatch"
__downloadurl__ = "https://github.com/rmi-electricity/dispatch"

Expand Down
77 changes: 77 additions & 0 deletions src/dispatch/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Some helpers for profiles and such."""

from __future__ import annotations

import pandas as pd


def copy_profile(
profiles: pd.DataFrame | pd.Series, years: range | tuple
) -> pd.DataFrame | pd.Series:
"""Create multiple 'years' of hourly profile data.

Args:
profiles: the profile to make copies of
years: the years, each of which will be a copy
of `profile`.

Returns: Copied profiles.

"""
dfs = []
assert isinstance(profiles.index, pd.DatetimeIndex)
if isinstance(profiles, pd.Series):
profiles = profiles.to_frame()
if len(profiles.index.year.unique()) > 1:
raise AssertionError("`profile` must be for a single year")
for yr in years:
dfs.append(
profiles.assign(
datetime=lambda x: x.index.map(lambda y: y.replace(year=yr)),
).set_index("datetime")
)
return pd.concat(dfs, axis=0).squeeze()


def apply_op_ret_date(
profiles: pd.DataFrame,
operating_date: pd.Series,
retirement_date: pd.Series,
capacity_mw: pd.Series | None = None,
) -> pd.DataFrame:
"""Zero profile unless it is between operating and retirement date.

Args:
profiles: profiles of plants with a DatetimeIndex
operating_date: in service date for each plant, the index of operating date is
used throughout
retirement_date: retirement date for each plant
capacity_mw: capacity of each plant (only used when `profiles` are normalized)

Returns: Profiles reflecting operating and retirement dates.

"""
assert isinstance(profiles.index, pd.DatetimeIndex)
if capacity_mw is None:
capacity_mw = pd.Series(1, index=operating_date.index, name="capacity_mw")
if profiles.shape[1] == len(operating_date) == len(retirement_date):
pass
else:
raise AssertionError(
"`profiles` must have same number of columns as lengths of `op_date` and `ret_date`"
)
# duplicate the DatetimeIndex so it is the same shape as `profiles`
dt_idx = pd.concat(
[profiles.index.to_series()] * profiles.shape[1],
axis=1,
).to_numpy()
return pd.DataFrame(
(
(dt_idx <= retirement_date.fillna(profiles.index.max()).to_numpy())
& (dt_idx >= operating_date.fillna(profiles.index.min()).to_numpy())
)
* profiles.to_numpy()
* capacity_mw.to_numpy(),
index=profiles.index,
columns=operating_date.index,
)
Loading