Open cfe316 opened 8 months ago
I believe the core/reserves
code is incorrect and reflects older usage of the MUST_RUN
set which was originally a modifier similar to UCOMMIT
, the set of thermal resources subject to unit commitment, but is now implemented as a separate resource type that can reflect must-run or entirely non-dispatchable resources including variable renewables (like rooftop solar) or baseloaded thermal plants or CHP plants whose generation reflects exogenous heating demand patterns, etc.
Here is the code in question:
# Reg up and down requirements are symmetric
@expression(EP, eRegReq[t=1:T], inputs["pReg_Req_Load"]*sum(inputs["pD"][t,z] for z=1:Z) +
inputs["pReg_Req_VRE"]*sum(inputs["pP_Max"][y,t]*EP[:eTotalCap][y] for y in intersect(inputs["VRE"], inputs["MUST_RUN"])))
# Operating reserve up / contingency reserve requirements as ˚a percentage of load and scheduled variable renewable energy production in each hour
# and the largest single contingency (generator or transmission line outage)
@expression(EP, eRsvReq[t=1:T], inputs["pRsv_Req_Load"]*sum(inputs["pD"][t,z] for z=1:Z) +
inputs["pRsv_Req_VRE"]*sum(inputs["pP_Max"][y,t]*EP[:eTotalCap][y] for y in intersect(inputs["VRE"], inputs["MUST_RUN"])))
The intended usage here I believe is union(inputs["VRE"], inputs["MUST_RUN"])
not intersect
, with the intention being to set operating reserve requirements as a percentage of scheduled dispatchable and non-dispatchable renewables, with the idea that MUST_RUN
primarly is used to reflect non-dispatchable distributed solar. This requirement is to reflect operating reserves required to manage forecast errors for wind and solar production.
We have two options for a fix: (1) drop the set of MUST_RUN
resources from the calculation of operating reserve and assume that only utility-scale dispatchable renewables are used in determining reserve requirements; or (2) correct the code above to use union
instead of intersect
and then assume that the primary usage of MUST_RUN
is to represent non-dispatchable variable renewables, rather than baseloaded must-run thermal generators (which do not contribute in this way to operating reserve requirements).
I am inclined to go for Option 1 above.
Thanks, Jesse. Option 1 would be an easy fix.
I do think it would be nicer if we had MUST_RUN
as a modifier (like LDS
) to represent either non-curtailable variable renewables or baseloaded thermal plants rather than as a separate resource type. I've seen users wanting baseloaded nuclear fission plants and also behind-the-meter solar. Both can be represented as MUST_RUN
. For a VRE-like resource one can modify Generators_variability.csv
and set fuel to None
. But, this would lose out on any special handling of VRE-like things such as for reserves here.
In practice, the utility-scale variable renewables are significantly larger than the behind-the-meter ones in the cases I've run, so it's probably not a huge deal.
Reading the code comment again:
"a percentage of load and scheduled variable renewable energy production" indicates to me that intersect
is intentional, indicating the MUST_RUN
-VRE
's only.
If we change the intent from this "scheduled VRE production" to "forecasted VRE production" by changing intersect(MUST_RUN, VRE)
to just VRE
, we're also significantly increasing the required value of eRsvReq
.
On the
develop
branch, we've recently introduced validation which makesMUST_RUN
a type of resource distinct from all others. However,core/reserves
mentions resources which are inintersect(VRE, MUST_RUN)
, which I think is meant to represent non-curtailable variable renewables. As of now, this set must be empty.I wanted to raise this issue to stimulate discussion about a resolution.