-
Notifications
You must be signed in to change notification settings - Fork 28
Jf/add demand response component #84
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
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #84 +/- ##
==========================================
- Coverage 84.06% 83.02% -1.05%
==========================================
Files 42 45 +3
Lines 2002 2309 +307
==========================================
+ Hits 1683 1917 +234
- Misses 319 392 +73 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements the initial structure for demand response components within the PRAS system. The changes add comprehensive support for demand response resources as a new asset type alongside existing generators, storage, and generator-storage devices.
- Integration of demand response as a new core asset type with associated data structures, simulation logic, and file I/O support
- Extension of existing result collection and analysis capabilities to include demand response-specific metrics
- Update of system model constructors and file format versioning to accommodate the new component type
Reviewed Changes
Copilot reviewed 33 out of 33 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| SystemModel_HDF5_spec.md | Updated specification to allow optional system attributes in HDF5 files |
| PRASFiles.jl/test/runtests.jl | Modified test to use system attributes instead of user_attributes parameter |
| PRASFiles.jl/src/Systems/write.jl | Added demand response processing and updated metadata handling |
| PRASFiles.jl/src/Systems/read.jl | Added support for reading demand response components and system attributes |
| PRASFiles.jl/src/Results/write.jl | Updated result generation to include system attributes |
| PRASFiles.jl/src/Results/utils.jl | Added system attributes field to SystemResult struct |
| PRASFiles.jl/src/PRASFiles.jl | Updated exports and imports for demand response support |
| PRASFiles.jl/Project.toml | Version bump to 0.8.0 |
| PRASCore.jl/test/Systems/assets.jl | Added test cases for DemandResponses asset type |
| PRASCore.jl/test/Systems/SystemModel.jl | Updated SystemModel constructor tests with demand response |
| PRASCore.jl/test/Simulations/runtests.jl | Added demand response simulation tests |
| PRASCore.jl/test/Results/energy.jl | Added demand response energy result tests |
| PRASCore.jl/test/Results/availability.jl | Added demand response availability result tests |
| PRASCore.jl/src/Systems/units.jl | Added long unit symbol functions |
| PRASCore.jl/src/Systems/assets.jl | Implemented DemandResponses asset type with full functionality |
| PRASCore.jl/src/Systems/TestData.jl | Added test systems with demand response components |
| PRASCore.jl/src/Systems/Systems.jl | Updated exports to include DemandResponses |
| PRASCore.jl/src/Systems/SystemModel.jl | Enhanced SystemModel with demand response support and display methods |
| PRASCore.jl/src/Simulations/utils.jl | Added demand response payback counter logic |
| PRASCore.jl/src/Simulations/recording.jl | Extended recording for demand response metrics |
| PRASCore.jl/src/Simulations/SystemState.jl | Added demand response state variables |
| PRASCore.jl/src/Simulations/Simulations.jl | Integrated demand response in simulation flow |
| PRASCore.jl/src/Simulations/DispatchProblem.jl | Extended dispatch problem for demand response optimization |
| PRASCore.jl/src/Results/Results.jl | Added demand response result specifications |
| PRASCore.jl/src/Results/DemandResponseShortfallSamples.jl | New result type for demand response shortfall samples |
| PRASCore.jl/src/Results/DemandResponseShortfall.jl | New result type for demand response shortfall metrics |
| PRASCore.jl/src/Results/DemandResponseEnergySamples.jl | New result type for demand response energy samples |
| PRASCore.jl/src/Results/DemandResponseEnergy.jl | New result type for demand response energy metrics |
| PRASCore.jl/src/Results/DemandResponseAvailability.jl | New result type for demand response availability |
| PRASCore.jl/Project.toml | Version bump to 0.8.0 |
| PRASCapacityCredits.jl/Project.toml | Updated compatibility for PRASCore 0.8.0 |
| PRAS.jl/src/PRAS.jl | Removed deprecated import |
| PRAS.jl/Project.toml | Version bump to 0.8.0 and updated dependencies |
Comments suppressed due to low confidence (2)
PRASFiles.jl/src/Systems/read.jl:87
- Variable 'states' is used but should be 'state' (missing 's'). This will cause a compilation error.
gen_regions = getindex.(Ref(regionlookup), gen_regionnames)
PRASCore.jl/src/Systems/SystemModel.jl:198
- There are two constructors with similar signatures that both accept demandresponses parameter but have different logic. The second constructor (line 198) appears to be incorrectly defined as it creates empty demand responses despite accepting a demandresponses parameter.
function SystemModel(
0d77873 to
6561f9c
Compare
3a7d357 to
142c946
Compare
sriharisundar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had started this long back, just wanted to finish it. Also added a few comments on the SystemModel constructors/pretty printing.
I didn't do an exhaustive check of all the code, it was a quick run through since I've been involved in some pieces here. Hoping Gord and/or Surya will be able to suggest any needed code refactoring.
| soc = round(Int, soc * efficiency) | ||
|
|
||
| # Shed SoC above current energy limit | ||
| drs_energy[i] = min(soc, maxenergy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why shouldn't we allow increase beyond max_energy over here? Will that violate any DR asset struct constraints?
Since we do advance before solve and record, from the previous timestep to this, if the DR borrowed energy has ballooned over the energy capacity, either we will drop that much load, or we will payback what we can and then drop extra.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to track the case where soc is greater than maxenergy, and make sure that if its above, we track the unserved energy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did some rework to have it tracked by same state variable, example below with a 50% borrowed energy interest and a power capacity of 50, energy capacity of 200 (hits it at second 200 contribution with shortfall from DR) 3216eda

| #for demand response-we want to borrow energy in devices with the longest payback window, and payback energy from devices with the smallest payback window | ||
| minpaybacktime_dr, maxpaybacktime_dr = minmax_payback_window_dr(sys) | ||
| min_paybackcost_dr = (- maxpaybacktime_dr - 50 + min_chargecost) #add min_chargecost to always have DR devices be paybacked first, and -50 for wheeling prevention | ||
| max_borrowcost_dr = - min_paybackcost_dr + minpaybacktime_dr + 1 + max_dischargecost #add max_dischargecost to always have DR devices be borrowed last |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make the logic here a little more intuitive, I would put the min_chargecost / max_dischargecost at the start of the expression (to be clearer that the DR costs are being defined relative to those values).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably explicitly state the implicit merit order here, even after sketching a number line with the different cost bands it’s not obvious to me what we do/don’t want to allow as a far as cross charging between storage and DR (and therefore I’m not sure whether these cost offsets are right or not)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will make a number line comparison, where variables can be changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the overlap between DR payback reward (9-12) and Stor/GenStor discharge penalty (5-11) intentional? It seems like in some cases storages would be discharged to pay back DRs, but in other cases they wouldn't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't remember the offset equations off of the top of my head, but are we double-counting any offsets? Is the reason for the gap between the storage band (ends at +/- 11) to the DR band (starts at +/- 20) purely down to wheeling_cost_prevention? Same question applies for the gap between the DR payback reward (23) and the DR borrow penalty (36).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we would be double counting the max_dischargecost (in the max_borrowcost_dr we are adding them twice together). Full changes are here ca7ff88. Updated graphic below now

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@GordStephen simplified the costs here, think this is as bare bones as it can get. The cost_for_storage_wheeling_prevention seems ambiguous what on what a good number is, but I would think 75 is safe enough? 253bce0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's basically just to offset potential transmission costs, right? And since those are 1/MW/interface the offset should be around the longest distance we'd expect to be moving power from a battery to a DR repayment. 75 seems like plenty (in the ReEDS system you can get from Seattle to Miami in 32 hops)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we wanted to get really clever I guess we could set this dynamically based on the diameter of the network
…max and min times
…r out of DR class definition in assets.jl

The Demand Response component enables shifting of unserved energy to time periods when energy is more available. All parameters are time series dependent enabling greater flexibility and segment sizing, in line with the broader PRAS structure. The following key details define a demand response device:
An example load shifting event is provided below for a demand response device with energy capacity of 5MWh, borrowing and payback capacity of 3MW, and allowable payback window of a constant 4 timesteps:

