Dispatch Mode Guide#
Purpose#
The Dispatch and Unit Commitment flow runs the full hourly chronology, so it can enforce commitment-level constraints (startup costs, minimum generation shares, ramp limits, minimum up/down windows, storage continuity, etc.) that are otherwise invisible in a representative-day run. This document explains how to turn on the necessary switches, what the new blocks of equations do, and which features are still pending (CSP and hydrogen continuity remain to be added).
Key features active when fDispatchMode=1#
Dispatch continuity and ramping: the model keeps hourly generation (
vPwrOut) and the slot-aggregated counterpart (vPwrOutDispatch) consistent througheRampContinuity. Slot-to-slot ramp changes are constrained viaeDispatchRampUpLimit/eDispatchRampDownLimit, while the original hourlyeRampUpLimit/eRampDnLimitstay in place to respect physical ramp rates. Storage SOC transitions (eStorageHourTransition,eStorageDayWrap, etc.) also operate over the full chronology, sofDispatchModeguarantees both generation and storage trajectories are traced continuously. CSP and hydrogen modules still lack the same full-hour continuity enforcement; those will need equivalent equations once their dispatch logic is expanded.eRampContinuity(g,q,d,t,AT,y)$((Ramprate(g) and fApplyRampConstraint and fDispatchMode) and mapTS(q,d,t,AT)).. sum(gfmap(g,f), vPwrOut(g,f,q,d,t,y)) =e= vPwrOutDispatch(g,q,d,t,AT,y);Unit commitment with minimum generation, startup cost, and min up/down: generators with a
MinGenPointsee theirisOn/isStartup/isShutdownbinaries linked to both the dispatch output and the objective througheDispatchMinGenPoint,eDispatchMaxGenPoint, andeStartupCostConstraint. The commitment balance equations (eCommitmentConsistency,eCommitmentInitialization,eCommitmentSingleTransition) enforce the transition logic, while the rollingMinUp.../MinDown...constraints ensure every startup/shutdown is followed by the required persistence window. All of these only run inside dispatch mode, so the flag bundle (fApplyMinGenerationConstraintandfApplyMUDT) must be set alongsidefDispatchMode.eCommitmentConsistency(g,AT,y)$(ord(AT) > 1 and fDispatchMode).. sum((q,d,t)$mapTS(q,d,t,AT), isStartup(g,q,d,t,AT,y) - isShutdown(g,q,d,t,AT,y)) =e= sum((q,d,t)$mapTS(q,d,t,AT), isOn(g,q,d,t,AT,y)) - sum((q,d,t)$mapTS(q,d,t,AT-1), isOn(g,q,d,t,AT-1,y));These commitment binaries are tricky because nothing in dispatch mode alone forces
isOnto follow actual generation unless one of the min-generation constraints is present. We therefore tie positive output to the commitment state viaeDispatchMinGenPoint/eDispatchMaxGenPoint, and startup cost is collected througheStartupCostConstraintso flippingisOncarries a penalty. The combination ofMinGenPoint(g),fApplyMinGenerationConstraint, andfApplyStartupCostmakes the binary meaningful, but it also means you cannot activate the startup-cost reporting or min up/down without enabling the min-generation switch (unless you refactor to add your own big-M linking equation).The dispatcher uses the following limits to bind
isOnwith dispatch output. The equality ineDispatchMinGenPointforces any positive generation to raise the commitment flag, whileeDispatchMaxGenPointcaps output whenisOnis zero.eStartupCostConstraintthen counts the observed startups per slot, which feedsvYearlyStartupCost.eDispatchMinGenPoint(g,q,d,t,y)$((fDispatchMode and fApplyMinGenerationConstraint and MinGenPoint(g) and FD(q,d,t))).. sum(gfmap(g,f), vPwrOut(g,f,q,d,t,y)) =g= pGenData(g,"MinLimitShare")*pGenData(g,"Capacity") * sum(AT$mapTS(q,d,t,AT), isOn(g,q,d,t,AT,y)); eDispatchMaxGenPoint(g,q,d,t,y)$((fDispatchMode and fApplyMinGenerationConstraint and MinGenPoint(g) and FD(q,d,t))).. sum(gfmap(g,f), vPwrOut(g,f,q,d,t,y)) =l= pGenData(g,"Capacity")*sum(AT$mapTS(q,d,t,AT), isOn(g,q,d,t,AT,y));
Running dispatch mode#
Set
fDispatchMode=1and the ancillary switches (fRampConstraints,fApplyRampConstraint,fApplyMinGenerationConstraint,fApplyStartupCost,fApplyMUDT) inside yourpSettings.csvor via command-line overrides.epm/main.gmspulls these scalars before loadingbase.gms, so every dispatch equation sees the intended flags.Ensure the GDX input contains the hourly sets:
AT,pHours, and the mappingmapTS(q,d,t,AT)created by the reader scripts. If you regenerate settings (e.g., togglingfRampConstraintsorInitialSOCforBattery), rerun the Python input treatment so the new scalars persist ininput.gdx.Launch the usual solver command (
gams epm/main.gms lo=2or your wrapper). Do not skip thebase.gmsinclusion; it defines the dispatch equations, storage continuity logic, and startup-cost reporting (vYearlyStartupCost). Thegenerate_reportstep will now capture startup costs as part of the per-zone variable-cost breakdown.
Checklist before dispatch runs#
Confirm
fDispatchMode=1and any of the supporting toggles (fRampConstraints,fApplyRampConstraint,fApplyMinGenerationConstraint,fApplyStartupCost,fApplyMUDT) that you need are present in the chosenpSettingsfile.Validate that
input.gdxexposes the full chronology (AT,mapTS,pHours) and any storage initialization scalars (InitialSOCforBattery/pStorageInitShare) the dispatch equations depend on.Run the same base script (
gams epm/main.gmsor the Python wrapper) sobase.gmscan generate the dispatch-level variables/histories your analysis relies on.