Release Notes¶
0.6.1 (2025-XX-XX)¶
What’s New?¶
Transition to uv and tox-uv.
Downgrading kaleido version below v1.0 to avoid chrome requirement.
Bug Fixes¶
Fixed a bug where net_load of zero breaks
dynamic_reserve()because it looks for relative increase. Now when net load is zero we raise the whole profile by the period’s max. Shifting up the whole profile by the max mutes the % change relative to shifting by the average, median, etc.Fixed a bug in
dispatch_engine()where checks for values not exceeding their limit failed when they did exceed the limit but within the error of machine precision.
0.6.0 (2025-03-28)¶
What’s New?¶
Initial implementation of dynamic storage reserves. If storage does not have a reserve or the reserve is
0.0, we calculate a dynamic reserve based on the next 24 hours of net load using (1). The value ofcoeffcan be set manually when creatingDispatchModel, or automatically (default) by trying a number of values between 0.0 and 1.5 and selecting the one that best minimizes deficit and curtailment, usingdispatch.engine.choose_best_coefficient().
Additional deficit and curtailment metrics in
DispatchModel.system_level_summary().DispatchModel.dispatchable_summary()andDispatchModel.full_output()now include all columns provided in<x>_specs.Enable multiple storage generators under a single
plant_id_eiaso long as they don’t share aplant_id_eiawith a renewable generator.DispatchModel.system_level_summary()allows for the roll-up of storage facilities to create higher-level metrics using thestorage_rollupparameter.DispatchModel.hourly_data_check()allows exploration of hours preceding and including both deficit and curtailment hours.DispatchModelnow acceptsdispatchable_costwith monthly frequency.Added
DispatchModel.set_metadata()to safely set metadata.DispatchModel.__getattr__()allows retrieving metadata using attribute access.Added
marginal_for_startup_rankflag todispatch_engine()andDispatchModelconfigto use marginal cost rank to order generators for startup rather than startup cost. Given costs fromrmi.gencosthave very low startup cost relative to marginal costs, marginal costs can be a better metric for committing units.Update build tool versions in
pyproject.tomlandenvironment.yml.Address
pandasDeprecationWarninginpandas.DataFrame.groupby()andpandas.value_counts().Remove local pytest and blackdoc hooks from pre-commit.
Switch from black to ruff format for autoformatting.
New storage features to represent more types of storage:
Storage charge rate can be different from discharge rate, to use, provide
charge_mwcolumn instorage_specs.charge_effanddischarge_effwill replaceroundtrip_effinstorage_specsto enable finer-grained control of when losses occur. Previouslyroundtrip_effwas effectively treated as the charge efficiency and there were no discharge losses.
Add support for Python 3.12.
New
DispatchModel.redispatch_lambda()andDispatchModel.historical_lambda()to calculate hourly marginal costs.Updates to narrative description of dispatch logic in
approach.rst.Attempts to reduce memory use and unnecessary allocations in
zero_profiles_outside_operating_dates()and by validate inputs inplace.Create new
DispatchModel.system_summary_core()that includes only a subset of the columns inDispatchModel.system_level_summary()that can be produced faster and excludes storage metrics.
Bug Fixes¶
Fixed a bug where
operating_dateandretirement_datedid not apply to dispatchable resources, whereno_limitisTrue.Fixed a bug where
capacity_mwfor storage and renewables was not zero in outputs before their operating date. We now compare the modeled year to the operating year rather than the date. This provides the expected output when outputs are aggregated annually as is the typical case.Fixed renewable name maps for plotting in
dispatch.constants.PLOT_MAP.Added a second fallback method for determining the frequency of cost data in
Validator.dispatchable_cost(). While this isn’t needed within the model anymore, it is used to determine if there is missing data.Fixed a bug where profile index validation failed because
panderapandas.DatetimeIndextype validation was applied inconsistently betweenpandas.DataFrameandpandas.Series.Fixed a bug where the
capacity_mwcolumn returned byDispatchModel.re_summary()andDispatchModel.storage_summary()was zero in the first year of operations whenfreq='YS'.
0.5.0 (2023-05-15)¶
What’s New?¶
Added checks to make sure that the datetime indexes of
load_profile,dispatchable_profiles, andre_profilesmatch.Prep for deprecating
DispatchModel.from_patio()andDispatchModel.from_fresh().Extracted
calculate_generator_output()fromdispatch_engine()to make the latter easier to read and to more easily test the former’s logic.Many updates to internal variable names in
engineto make the code easier to read.Renamed
apply_op_ret_date()tozero_profiles_outside_operating_dates()for clarity, use of the former name will be removed in the future.Code cleanup along with adoption of ruff and removal of bandit, flake8, isort, etc.
Added the ability to specify in
dispatchable_specsvia ano_limitcolumn that a generator not limited to its historical hourly output by the model without affecting historical dispatch data.Added the ability to specify in
dispatchable_specsvia amin_uptimecolumn the minimum number of hours a generator must have been operating before it can start ramping down.Adjusted process of determining the provisional deficit used to dispatch currently operating generators. Previously, we adjusted our target for dispatchable generation based on the assumption we would want to use up all storage state of charge before dispatching operating generators. We now set the provisional deficit so that we hold 2x
reservestate of charge in reserve. If state of charge is belowreserve, we increase the provisional deficit in order to replenish the reserve.Changed battery discharge so that only a part of storage can be used before dispatchable start-up, only down to the
reserve. After dispatchable start-up, storage is dispatched a second time in case a deficit remains, in this part of the sequence, all storage state of charge can be used.dispatch now works with Python 3.11 using newly released
numbaversion 0.57.dispatch now works with
pandas2.0.
0.4.0 (2023-01-25)¶
What’s New?¶
Tests for
engine.dispatch_engine(),copy_profile().DispatchModel.hourly_data_check()to help in checking for dispatch errors, and running down why deficits are occuring.DispatchModelnow takesload_profilethat resources will be dispatched against. Ifre_profilesandre_plant_specsare not provided, this should be a net load profile. If they are provided, this must be a gross load profile, or at least, gross of those RE resources. These calculations are done byDispatchModel.re_and_net_load().DispatchModelnow accepts (and requires) raw DCre_profiles, it determines actual renewable output using capacity data and ilr provided inre_plant_specs. This will allowDispatchModelto model DC-coupled RE+Storage facilities that can charge from otherwise clipped generation. The calculations for the amount of charging from DC-coupled RE is inDispatchModel.dc_charge().Updates to
engine.dispatch_engine()andengine.validate_inputs()to accommodate DC-coupled RE charging data. Storage can now be charged from DC-coupled RE in addition to the grid. This includes trackinggridchargein addition tocharge, where the latter includes charging from the grid and DC-coupled RE.All output charging metrics use the
gridchargedata because from the grid’s perspective, this is what matters.dischargedata does not distinguish, so in some cases net charge data may be positive, this reflects RE generation run through the battery that otherwise would have been curtailed.DataZip, a subclass ofzipfile.ZipFilethat has methods for easily reading and writingpandas.DataFrameasparquetanddictasjson. This includes storing column names separately that cannot be included in aparquet.Extracted
engine.charge_storage()andengine.make_rank_arrays()fromengine.dispatch_engine(). This allows easier unit testing and, in the former case, makes sure all charging is implemented consistently.Added plotting functions
DispatchModel.plot_output()to visualize columns fromDispatchModel.full_output()and updatedDispatchModel.plot_period()to display data by generator ifby_gen=True.DispatchModel.plot_year()can now display the results with daily or hourly frequency.For renewables,
plant_id_eiano longer need by unique, now for renewables,plant_id_eiaandgenerator_idmust be jointly unique. In cases where a singleplant_id_eiahas two renewable generator’s as well as storage,DispatchModel.dc_charge()assumes excess renewable generation from the several generators can be combined to charge the facility’s storage.re_plant_specs,dispatchable_specs, andstorage_specs, now allow zeros forcapacity_mwandduration_hrs.DataZip,DispatchModel.to_file(), andDispatchModel.from_file()now supportio.BytesIOasfileorpath. This now allows any object that implementsto_file/from_filemethods usingDataZip, to be written into and recovered from anotherDataZip.Added the ability to specify in
dispatchable_specsvia anexcludecolumn that a generator not be dispatched by the model without affecting historical dispatch data.Migrating
DataZipfunctionality toetoolbox.datazip.DataZip.Updates to constants to allow Nuclear and Conventional Hydroelectric to be properly displayed in plots.
Updates to
re_plant_specs, its validation, andDispatchModel.re_and_net_load()for a new column,interconnect_mw, that allows interconnection capacity for a renewable facility to independent of its capacity. By default, this is the same ascapacity_mwbut can be reduced to reflect facility-specific transmission / interconnection constraints. If the facility has storage, storage can be charged by the constrained excess.Added
compare_histargument toDispatchModel.plot_period()which creates panel plot showing both historical dispatch and redispatch for the period.DispatchModel.plot_output()adds a row facet to show both historical and redispatch versions of the requested data if available.Cleanup of configuration and packaging files. Contents of
setup.cfgandtox.inimoved topyproject.toml.Added the ability to specify FOM for renewables in
re_plant_specsvia an optionalfom_per_kwcolumn. This allowsDispatchModel.re_summary()and derived outputs to include aredispatch_cost_fomcolumn.DispatchModelnow contains examples as doctests.DispatchModel.plot_all_years()to create daily redispatch plot faceted by month and year.DispatchModel.dispatchable_summary()now includes mmbtu and co2 data for historical, redispatch, and avoided column groupings. These metrics are based onheat_rateandco2_factorcolumns indispatchable_cost, these columns are optional.Updates to
DispatchModelto work with the new simpler, cleanerDataZip.
Bug Fixes¶
Fixed an issue in
engine.dispatch_engine()where a storage resource’s state of charge would not be carried forward if it wasn’t charged or discharged in that hour.Fixed a bug where storage metrics in
DispatchModel.system_level_summary()werenumpy.nanbecause selecting of data fromstorage_specsreturned apandas.Seriesrather than aintorfloat. Further, in cases of division be zero in these calculations, the result is now 0 rather thannumpy.nan. Tests now make sure that no newnumpy.nanshow up.Fixed a bug in
DispatchModel.dispatchable_summary()wherepct_replacedwould benumpy.nanbecause of division by zero in these calculations, the result is now 0 rather thannumpy.nan. Tests now make sure that no newnumpy.nanshow up.Fixed an issue where
DispatchModel.full_output()and methods that use it, i.e.DispatchModel.plot_output()improperly aggregatedDispatchModel.system_datawhenfreqwas not ‘YS’.Fixed an issue where
DispatchModel.full_output()didn’t properly showCurtailmentandStorage.
Known Issues¶
The storage in DC-coupled RE+Storage system can be charged by either the grid or excess RE that would have been curtailed because of the size of the inverter. It is not possible to restrict grid charging in these systems. It is also not possible to charge storage rather than export to the grid when RE output can fit through the inverter.
It is possible that output from DC-coupled RE+Storage facilities during some hours will exceed the system’s inverter capacity because when we discharge these storage facilities, we do not know how much ‘room’ there is in the inverter because we do not know the RE-side’s output. This issue is now in some sense compounded when
interconnect_mwis less thancapacity_mw.DataZipare effectively immutable once they are created so theamode is not allowed and thewmode is not allowed on existing files. This is because it is not possible to overwrite or remove a file already in azipfile.ZipFile. That fact prevents us from updating metadata aboutpandas.DataFramethat cannot be stored in theparquetitself. Ways of addressing this get messy and still wouldn’t allow updating existing data without copying everything which a user can do if that is needed.
0.3.0 (2022-10-08)¶
What’s New?¶
DispatchModel.to_file()can create an output with summary outputs.Adopting
panderafor metadata and validation usingValidatorto organize and specialize data input checking.Adding cost component details and capacity data to
DispatchModel.dispatchable_summary().We now automatically apply
operating_dateandretirement_datefromDispatchModel.dispatchable_plant_specstoDispatchModel.dispatchable_profilesusingapply_op_ret_date().Added validation and processing for
DispatchModel.re_plant_specsandDispatchModel.re_profiles, as well asDispatchModel.re_summary()to, when the data is provided create a summary of renewable operations analogous toDispatchModel.dispatchable_summary().Added
DispatchModel.storage_summary()to create a summary of storage operations analogous toDispatchModel.dispatchable_summary().Added
DispatchModel.full_output()to create the kind of outputs needed by Optimus and other post-dispatch analysis tools.Added validation steps for each type of specs that raise an error when an operating_date is after the dispatch period which would otherwise result in dispatch errors.
New helpers (
DataZip.dfs_to_zip()andDataZip.dfs_from_zip()) that simplify saving and reading in groups ofpandas.DataFrame.Added plotting functions
DispatchModel.plot_period()andDispatchModel.plot_year().
Known Issues¶
DispatchModel.re_summary()andDispatchModel.storage_summary()have null operations cost data.There is still no nice way to include nuclear and hydro resources.
DispatchModel.plot_year()doesn’t seem to really work. At all.
Bug Fixes¶
A validation check throws an error when ramp rates are zero which otherwise would prevent plant output from ever changing on a fresh dispatch.
Fixed a
TypeErrorissue inapply_op_ret_date()when some dates were inexplicably converted tointrather thannumpy.datetime64bypandas.DataFrame.to_numpy().
0.2.0 (2022-09-15)¶
What’s New?¶
DispatchModelnow uses__slots__New
DispatchModel.to_file()andDispatchModel.from_file()methods that allow aDispatchModelobject to be saved to disk and recreated from a file. This uses azipof manyparquetfiles for size and to avoidpicklebeing tied to a particular module layout.Methods to calculate hourly cost for historical and redispatch.
Method to simplify aggregating hourly generator-level data to less granular frequencies and asset specificity.
Storage resources can now be added to the portfolio over time based on their
operating_dateinstorage_specs.When using
DispatchModel.from_fresh(),operating_dateandretirement_datecolumns indispatchable_plant_specsdetermine 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
DispatchModel.to_file()andDispatchModel.from_file()methods.Updates to system for storing and processing marginal cost data. This is now a separate argument to
DispatchModel.__init__()rather than a messy confusing part ofdispatchable_plant_specs. This is now consistent with howpatioprepares and stores the data.
Bug Fixes¶
DispatchModel.to_file()andDispatchModel.from_file()now properly deal with internal data stored in bothpandas.DataFrameandpandas.Series.
Known Issues¶
Tests are still pretty rudimentary.
0.1.0 (2022-08-23)¶
What’s New?¶
A dispatch model with no RMI dependencies and in its own repository!
Repository built off of catalyst-cooperative.cheshire that uses cool tools like
tox,sphinx, etc.
Bug Fixes¶
Known Issues¶
DispatchModelonly set up to work properly with patio-model.Test thoroughness is lacking.
No substantive readme or documentation.