diff --git a/.github/workflows/typos_on_pr.yaml b/.github/workflows/typos_on_pr.yaml new file mode 100644 index 0000000000..86fc79dc01 --- /dev/null +++ b/.github/workflows/typos_on_pr.yaml @@ -0,0 +1,35 @@ +name: Typo Check + +on: + pull_request: + branches: [ main ] + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install dependencies + run: | + sudo apt-get update && sudo apt-get install --no-install-recommends -y wget hunspell hunspell-en-us + - name: Install typos + id: typo-install + run: | + pwd + mkdir ~/typos + cd ~/typos + wget -O typos.tar.gz https://github.com/crate-ci/typos/releases/download/v1.29.5/typos-v1.29.5-x86_64-unknown-linux-musl.tar.gz + tar xavf typos.tar.gz + - name: Run typo check + id: typo-check + run: | + set -e + touch tmpfile + ~/typos/typos --words --config=docs/typos.toml | sort -u | hunspell -l -p docs/hunspell_whitelist - > tmpfile + if [ -s tmpfile ]; then + echo "*Typos found:*" + echo " (Can fix, modify docs/hunspell_whitelist, or add file type exception to docs/typos.toml)" + cat tmpfile + exit 1 + fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 4db6ad4dd6..0a8f778238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -193,7 +193,7 @@ to the constraint (#725). - The above `load` keys, which generally refer to electrical demand, are being deprecated. Users should update their case files. For now this is done in a backward-compatible manner, and @info reminders are written to the log to prompt the user to update. - "Load" now typically refers only to the transferrence of data from files to memory, + "Load" now typically refers only to the transference of data from files to memory, except for a few places such as the common term "value of lost load" which refers to non-served demand (#397). - `New_Build = -1` in `Generators_data.csv`: instead, use `New_Build = 0` and `Can_Retire = 0`. - The matrix-style input of the grid for Network.csv is deprecated in favor a column-style input. @@ -281,7 +281,7 @@ to the constraint (#725). ### Changed - Simplified the `Simple_Test_Case` example (#414). -- SmallNewEngland/Onezone example now uses linearized unit committment by default (#404). +- SmallNewEngland/Onezone example now uses linearized unit commitment by default (#404). - Removed the unused dependency BenchmarkTools (#381). ### Removed diff --git a/docs/hunspell_whitelist b/docs/hunspell_whitelist new file mode 100644 index 0000000000..45eb35ebb3 --- /dev/null +++ b/docs/hunspell_whitelist @@ -0,0 +1,782 @@ +AGGFILL +AIC +Acknowledgement +Agg +Aneesha +BAREPCOMP +BAROBJRNG +Bal +Berntsen +Bff +Blanford +Bonaldo +Bool +CAPCONTRSTOR +CAPTRACK +CAPTRACKCHARGE +CAPTRACKCHARGEAC +CAPTRACKCHARGEDC +CAPTRACKDC +CAPTRACKDISCHARGEAC +CAPTRACKDISCHARGEDC +CAPTRACKELEC +CAPTRACKENERGY +CAPTRACKSOLAR +CAPTRACKWIND +CCO +CES +CESR +CNSE +CNSET +CNSETS +CONSTRAINTSET +CPX +Capacitated +Carolia +Chakrabarti +Chargingcost +Cheng +Coef +Combinatorics +Concat +Confl +Conv +Cormick +DCCAP +De +aff +al +allequal +annualsum +annuitized +api +argmax +argmin +args +ascii +aspell +asym +atleast +atol +attr +autodocs +baseloaded +basename +basenames +behaviour +bene +bilinear +bioenergy +br +buildable +buildout +capacityfactor +capcharge +capchargeac +capchargedc +capdc +capdischarge +capdischargeac +capdischargedc +capelec +capenergy +capgrid +capres +capresfactor +capresvrestor +capsolar +capvalue +capwind +carveout +casestudies +cbc +ccs +cd +cff +cgdf +cha +changelog +chargecost +chopprefix +clp +cmap +cmp +codecov +coeff +cofire +cofiring +cogeneration +collapselevel +colname +colnames +colocated +columnnumbers +columnprefix +combin +compat +congestions +const +constr +consumptions +countmap +cplex +crm +crp +csm +css +csv +curtailable +dashdot +dataframe +dataframerow +dataframes +datetime +dcopf +ddp +Deduplicated +deepskyblue +deleteat +demandcol +deploydoc +deploydocs +deps +depwarn +derate +derated +derating +desol +dev +devbranch +devnull +devurl +df +dfd +dflex +dfr +dftranspose +denseaxisarray +Dharik +dicts +dirname +dirs +disch +Disp +dispatchable +Dispverblevel +dists +dn +docstring +doesn +DOI +DOLPHYN +downvars +dropmissing +Ds +dsoc +dstor +dualise +dualization +Dualized +dur +dw +eachcol +eachindex +eachrow +ecap +ef +EKK +ELC +elec +ELECCAP +electrolyzer +electrolyzers +ELOSS +elseif +eltype +emm +emms +endogenize +endswith +energyrevenue +england +env +EPGAP +EPOPT +EPRHS +Eqs +esc +España +esr +ESRVRE +estart +etainverter +eval +Evol +exe +EXISTINGCAP +existingcapcharge +existingcapchargeac +existingcapchargedc +existingcapdc +existingcapdischargeac +existingcapdischargedc +existingcapelec +existingcapenergy +existingcapgrid +existingcapsolar +existingcapwind +EXISTINGDCCAP +EXISTINGELECCAP +EXISTINGSOLARCAP +EXISTINGWINDCAP +Expl +expr +exprname +exprs +extr +Fangwei +Feasib +feebate +filefullpath +filenotfound +filenotfoundconstant +filepath +Filesystem +Filippo +findall +findfirst +findlast +findmax +findmin +firstrow +Fitiwi +fnetavgcap +FOM +forcepush +forecasted +fpy +frac +Fram +Frist +Fs +fullpath +fulltimeseries +ga +Gabe +GDF +genvar +genx +genxoutput +genxsettings +geo +geospatial +getdual +getfield +getproperty +gh +GHS +github +GPL +GPT +groupby +groupedbar +Grp +gsa +gurobi +gv +GW +hardcoded +haskey +hasmethod +hcat +heatmap +heatrate +Helion +HH +HHV +Hirth +hoursafter +hoursbefore +Hs +html +https +hunspell +HYDR +ic +idx +idxs +ILR +img +Importcost +infeasibilities +inpath +insertcols +intra +io +ipm +ipx +isa +isapprox +isdefined +isdir +isempty +isequal +isfile +isnan +isnothing +ISONE +iter +Iters +ith +JIT +jl +jld +jldoctest +jll +joinpath +JS +Ju +julia +jupyter +kilotonnes +kmcen +kmeans +kmedoids +kton +ktons +kwarg +lajolla +LDA +LDES +lds +len +lhs +LHV +licence +licensor +lightrainbow +limitsgap +Linearization +linewidth +LMP +loadgen +lp +LPMETHOD +lps +LTS +Luca +Luo +maint +makedocs +Mallapragada +Manocha +mapslices +maxcap +maxcaptagsolar +maxcaptagstor +maxcaptagwind +MAXCO +maxlog +maxpower +Mc +mcr +md +MDOWN +medoids +Methodof +methodofmorris +mga +mgaoutpath +MILP +mincap +mincaptag +mincaptagsolar +mincaptagstor +mincaptagwind +minmax +MINRET +mins +mip +Missings +missingstring +mkdir +mkpath +MMBT +mmbtu +Modelingto +modelled +modeloutput +mse +msg +MSHUT +Mtons +Mul +mulit +multiday +multifuels +multioutput +multitage +mults +MUSD +mustrun +Mutic +mutli +mutualinfo +mw +mwh +mwhyr +mwyr +myinputs +myscheme +mysetup +mystats +mytab +NACC +Nahmmacher +nameof +ncapres +ncol +Ncols +NCRM +Ndisp +Neha +netavgcap +netrev +netrevenue +NG +Nhours +nocap +noex +nokmeans +NONFLEX +nonfuel +NONLDS +nonneg +Nonserved +nonzeros +Nota +nrow +nse +num +NUMERICALEMPHASIS +nw +NYU +Objbound +Objval +occ +occursin +ok +ol +onwards +opennotebook +oper +OPEX +OPEXMULT +OPEXMULTS +OPF +opwrap +outerright +Outfile +Outfiles +outpath +OV +Palmintier +param +parameterscale +params +parentmodule +Parolin +Patankar +pathinit +pathof +Pecci +Pereira +piecewisefuel +piecewisefuelusage +pkgdir +pkgversion +plotly +plotlyjs +png +policyfile +Poncelet +popfirst +powerbalance +powerflow +powerplants +Prac +pre +precluster +precompilation +precompile +precompiled +Precompiles +precompiling +PREDUAL +prefixseparator +PREIND +prepopulated +Preprocessing +presolve +presolved +presolver +Presolving +prettyurls +prev +println +priori +pulsestart +pv +pwd +pwfu +px +pygenx +Qian +Qingyu +ra +rampdown +rampup +randindex +rc +readdir +readline +readme +Reframing +regrevenue +renewables +REPL +repo +reqs +ret +rsv +runcase +runtests +scip +src +storagedual +svg +TDR +threezones +tols +toml +ucommit +vals +vre +yml +postsolve +RETCAP +retcapcharge +retcapchargeac +retcapchargedc +retcapdc +retcapdischarge +retcapdischargeac +retcapdischargedc +retcapelec +retcapenergy +retcapgrid +retcapsolar +RETCAPTRACK +RETCAPTRACKCHARGE +RETCAPTRACKCHARGEAC +RETCAPTRACKCHARGEDC +RETCAPTRACKDC +RETCAPTRACKDISCHARGEAC +RETCAPTRACKDISCHARGEDC +RETCAPTRACKELEC +RETCAPTRACKENERGY +RETCAPTRACKSOLAR +RETCAPTRACKWIND +retcapwind +RETDCCAP +RETELECCAP +rethrow +retirable +retrocapdischarge +RETROFITCAP +retrofittable +RETSOLARCAP +RETWINDCAP +rhs +riskyhour +rmse +rng +ro +Roadmap +rp +Rpath +Rsetup +rsvrevenue +Ruaridh +rv +rvs +Sambuddha +sametype +scalings +Schivley +sciform +scikit +sclope +SDS +seg +segs +Sepulveda +setdiff +setdocmeta +setindex +setproperty +sevaral +shiftable +showerror +singlefuel +singlestage +Sisternes +sitename +sk +skipmissing +SNE +socinreserve +socw +SOLARCAP +SOLUTIONTYPE +sortperm +splitpath +sqrt +startswith +Stasify +stderr +STDLIB +stdout +storagebal +stordual +streamflow +struct +structs +subheader +sublicense +subperiod +subperiods +subtyped +syms +Sys +systemfiles +systemwide +tagnum +TAUX +tbody +TCAP +td +tdr +tdrpath +telectrolyzers +tempannualsum +tempresrev +testlog +testset +th +thead +TILIM +timedomainreduction +timelimit +timeseries +timestep +timesteps +titlefontsize +TLOSS +tlosses +tmp +TODO +tokamak +tokamaks +tol +topleft +totalcost +Totale +tradeoffs +transcap +TRANSMAX +Trutnevyte +tryparse +tstart +tt +TTFX +tw +twinx +twotypes +typeof +TZ +ub +UC +Uncomment +undef +uniques +unitless +unregister +unserved +unsets +Uper +uptime +USD +uuid +validatetimebasis +variabilities +varphi +vcat +vcommit +vd +ve +vec +vellip +verblevel +violetred +vlplot +Voll +vom +vp +VR +vrestor +vslack +VSO +wacc +walkdir +walkthrough +warnerror +warntype +Wh +Whs +WINDCAP +withhead +Wks +writeheader +writeoutput +ws +wth +www +Wyr +xlabel +xlabelfontsize +xnames +xrotation +xticks +yaml +yaxis +yformatter +ygrid +Yifu +ylabel +ylabelfontsize +ylims +yticks +yy +yyyy +Zhang +Zhou +zonests +Zwanziger +η +σ +τdw +τpu +ω +auxilary +tmpfile \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index a7cfa663a7..e95dcadb93 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -15,7 +15,7 @@ pages = OrderedDict( ], "Getting Started" => [ "Running GenX" => "Getting_Started/examples_casestudies.md", - "Commertial solvers" => "Getting_Started/commercial_solvers.md" + "Commercial solvers" => "Getting_Started/commercial_solvers.md" ], "Tutorials" => [ "Tutorials Overview" => "Tutorials/Tutorials_intro.md", diff --git a/docs/src/Getting_Started/examples_casestudies.md b/docs/src/Getting_Started/examples_casestudies.md index 9f4f5a04ed..b5d9945ee2 100644 --- a/docs/src/Getting_Started/examples_casestudies.md +++ b/docs/src/Getting_Started/examples_casestudies.md @@ -100,7 +100,7 @@ MyCase └── Run.jl ``` -In this example, `MyCase` will define a case with `Themal`, `Storage`, `Vre`, and `Hydro` resources, the `system` folder will provide the data for the demand, fuel, generators' variability, and network, the `policies` folder will include a CO2 cap, a minimum capacity requirement, and an energy share requirement, and the `settings` folder will contain the configuration files for the model. +In this example, `MyCase` will define a case with `Thermal`, `Storage`, `Vre`, and `Hydro` resources, the `system` folder will provide the data for the demand, fuel, generators' variability, and network, the `policies` folder will include a CO2 cap, a minimum capacity requirement, and an energy share requirement, and the `settings` folder will contain the configuration files for the model. The `Run.jl` file should contain the following code: ```julia diff --git a/docs/src/Model_Concept_Overview/model_notation.md b/docs/src/Model_Concept_Overview/model_notation.md index a805fd96cd..8568b8b77f 100644 --- a/docs/src/Model_Concept_Overview/model_notation.md +++ b/docs/src/Model_Concept_Overview/model_notation.md @@ -9,7 +9,7 @@ |$\mathcal{T}^{start} \subseteq \mathcal{T}$ | where $\mathcal{T}^{start}$ is the set of initial timesteps in the data series. $\mathcal{T}^{start}={1}$ when representing entire year as a single contiguous period; $\mathcal{T}^{start}=\{\left(m-1\right) \times \tau^{period}+1 \| m \in \mathcal{M}\}$, which corresponds to the first time step of each representative period $m \in \mathcal{M}$| |$n \in \mathcal{N}$ | where $n$ corresponds to a contiguous time period and $\mathcal{N}$ corresponds to the set of contiguous periods of length $\tau^{period}$ that make up the input time series (e.g. demand, variable renewable energy availability) to the model| |$\mathcal{N}^{rep} \subseteq \mathcal{N}$ | where $\mathcal{N}^{rep}$ corresponds to the set of representative time periods that are selected from the set of contiguous periods, $\mathcal{M}$| -|$m \in \mathcal{M}$ | where $m$ corresponds to a representative time period and $\mathcal{M}$ corresponds to the set of representative time periods indexed as per their chronological ocurrence in the set of contiguous periods spanning the input time series data, i.e. $\mathcal{N}$| +|$m \in \mathcal{M}$ | where $m$ corresponds to a representative time period and $\mathcal{M}$ corresponds to the set of representative time periods indexed as per their chronological occurrence in the set of contiguous periods spanning the input time series data, i.e. $\mathcal{N}$| $z \in \mathcal{Z}$ | where $z$ denotes a zone and $\mathcal{Z}$ is the set of zones in the network| |$l \in \mathcal{L}$ | where $l$ denotes a line and $\mathcal{L}$ is the set of transmission lines in the network| |$y \in \mathcal{G}$ | where $y$ denotes a technology and $\mathcal{G}$ is the set of available technologies | @@ -172,7 +172,7 @@ $\mathcal{W} \subseteq \mathcal{G}$ | where $\mathcal{W}$ set of hydroelectric g |$\underline{\Omega}^{pv}_{y,z}$ | Minimum solar PV capacity of technology $y$ in zone $z$ - only applicable for co-located VRE and storage resources with a solar PV component, $y \in \mathcal{VS}^{pv}$ \[MW DC\]| |$\overline{\Omega}^{wind}_{y,z}$ | Maximum wind capacity of technology $y$ in zone $z$ - only applicable for co-located VRE and storage resources with a wind component, $y \in \mathcal{VS}^{wind}$ \[MW AC\]| |$\underline{\Omega}^{wind}_{y,z}$ | Minimum wind capacity of technology $y$ in zone $z$ - only applicable for co-located VRE and storage resources with a wind component, $y \in \mathcal{VS}^{wind}$ \[MW AC\]| -|$\overline{\Omega}^{elec}_{y,z}$ | Maximum electrolyzer capacity of technology $y$ in zone $z$ - only applicable for co-located VRE and storage resources with an electrolzyer component, $y \in \mathcal{VS}^{elec}$ \[MW AC\]| +|$\overline{\Omega}^{elec}_{y,z}$ | Maximum electrolyzer capacity of technology $y$ in zone $z$ - only applicable for co-located VRE and storage resources with an electrolyzer component, $y \in \mathcal{VS}^{elec}$ \[MW AC\]| |$\underline{\Omega}^{elec}_{y,z}$ | Minimum electrolyzer capacity of technology $y$ in zone $z$ - only applicable for co-located VRE and storage resources with an electrolyzer component, $y \in \mathcal{VS}^{elec}$ \[MW AC\]| |$\overline{\Omega}^{inv}_{y,z}$ | Maximum inverter capacity of technology $y$ in zone $z$ - only applicable for co-located VRE and storage resources with an inverter component, $y \in \mathcal{VS}^{inv}$ \[MW AC\]| |$\underline{\Omega}^{inv}_{y,z}$ | Minimum inverter capacity of technology $y$ in zone $z$ - only applicable for co-located VRE and storage resources with an inverter component, $y \in \mathcal{VS}^{inv}$ \[MW AC\]| diff --git a/docs/src/Model_Concept_Overview/objective_function.md b/docs/src/Model_Concept_Overview/objective_function.md index db857cd340..f725ff456f 100644 --- a/docs/src/Model_Concept_Overview/objective_function.md +++ b/docs/src/Model_Concept_Overview/objective_function.md @@ -63,7 +63,7 @@ The tenth term represents the fixed cost of installed inverter capacity and is s This term includes the sum of the annualized inverter capital cost, $\pi^{INVEST,inv}_{y,z}$, times the total new inverter capacity added (if any), plus the Fixed O&M cost, $\pi^{FOM, inv}_{y,z}$, times the net installed inverter capacity, $\Delta^{total,inv}_{y,z}$ (e.g., existing capacity less retirements plus additions). The eleventh term represents the fixed cost of installed solar PV capacity and is summed over only the co-located resources with a solar PV component ($y \in \mathcal{VS}^{pv}$). This term includes the sum of the annualized solar PV capital cost, $\pi^{INVEST,pv}_{y,z}$, times the total new solar PV capacity added (if any), plus the Fixed O&M cost, $\pi^{FOM, pv}_{y,z}$, times the net installed solar PV capacity, $\Delta^{total,pv}_{y,z}$ (e.g., existing capacity less retirements plus additions). -The twelveth term represents the fixed cost of installed wind capacity and is summed over only the co-located resources with a wind component ($y \in \mathcal{VS}^{wind}$). +The twelfth term represents the fixed cost of installed wind capacity and is summed over only the co-located resources with a wind component ($y \in \mathcal{VS}^{wind}$). This term includes the sum of the annualized wind capital cost, $\pi^{INVEST,wind}_{y,z}$, times the total new wind capacity added (if any), plus the Fixed O&M cost, $\pi^{FOM, wind}_{y,z}$, times the net installed wind capacity, $\Delta^{total,wind}_{y,z}$ (e.g., existing capacity less retirements plus additions). The thirteenth term represents the fixed cost of installed storage DC discharge capacity and is summed over only the co-located resources with an asymmetric storage DC discharge component ($y \in \mathcal{VS}^{asym,dc,dis}$). This term includes the sum of the annualized storage DC discharge capital cost, $\pi^{INVEST,dc,dis}_{y,z}$, times the total new storage DC discharge capacity added (if any), plus the Fixed O&M cost, $\pi^{FOM, dc, dis}_{y,z}$, times the net installed storage DC discharge capacity, $\Delta^{total,dc,dis}_{y,z}$ (e.g., existing capacity less retirements plus additions). @@ -74,7 +74,7 @@ This term includes the sum of the annualized storage AC discharge capital cost, The sixteenth term represents to the fixed cost of installed storage AC charge capacity and is summed over only the co-located resources with an asymmetric storage AC charge component ($y \in \mathcal{VS}^{asym,ac,cha}$). This term includes the sum of the annualized storage AC charge capital cost, $\pi^{INVEST,ac,cha}_{y,z}$, times the total new storage AC charge capacity added (if any), plus the Fixed O&M cost, $\pi^{FOM, ac, cha}_{y,z}$, times the net installed storage AC charge capacity, $\Delta^{total,ac,cha}_{y,z}$ (e.g., existing capacity less retirements plus additions). -The seventeeth term onwards corresponds to the operational cost across all zones, technologies, and time steps for co-located VRE and storage resources. +The seventeenth term onwards corresponds to the operational cost across all zones, technologies, and time steps for co-located VRE and storage resources. The seventeenth summation represents the variable O&M cost, $\pi^{VOM,pv}_{y,z}$, times the energy generation by solar PV resources ($y\in\mathcal{VS}^{pv}$) in time step $t$, $\Theta^{pv}_{y,z,t}$, the inverter efficiency, $\eta^{inverter}_{y,z}$, and the weight of each time step $t$, $\omega_t$. The eighteenth summation represents the variable O&M cost, $\pi^{VOM,wind}_{y,z}$, times the energy generation by wind resources ($y\in\mathcal{VS}^{wind}$) in time step $t$, $\Theta^{wind}_{y,z,t}$, and the weight of each time step $t$, $\omega_t$. The nineteenth summation represents the variable O&M cost, $\pi^{VOM,dc,dis}_{y,z}$, times the energy discharge by storage DC components ($y\in\mathcal{VS}^{sym,dc} \cup \mathcal{VS}^{asym,dc,dis}$) in time step $t$, $\Theta^{dc}_{y,z,t}$, the inverter efficiency, $\eta^{inverter}_{y,z}$, and the weight of each time step $t$, $\omega_t$. diff --git a/docs/src/Model_Reference/Resources/fusion.md b/docs/src/Model_Reference/Resources/fusion.md index 31e09e0a96..da47357685 100644 --- a/docs/src/Model_Reference/Resources/fusion.md +++ b/docs/src/Model_Reference/Resources/fusion.md @@ -23,7 +23,7 @@ There are nine optional parameters for fusion in this model; all can be mixed an Some of the properties span more than one of these domains. ### Parasitic power -Fusion plant designs often require significant amounts of electrical energy (and instantenous power) +Fusion plant designs often require significant amounts of electrical energy (and instantaneous power) 1. to maintain the vacuum pumps, cryogenic systems, tritium plants, 2. for heating systems, control magnet systems, target manufacturing, or lasers, @@ -40,7 +40,7 @@ The pulse start _power_ is used as part of the capacity reserve margin formulati Pulsed tokamaks (as opposed to steady-state tokamaks) often call for an operational cycle where the plasma is on for 30 minutes to a few hours before carefully being drawn down. The _maximum pulse length_ is typically limited by the engineering of the "central solenoid", one of the large magnets. -A _dwell time_ of a few minutes to 30 minutes is taken to allow various systems to be reset and readied for the next plasma pulse; during this time there is no plasma and no fusion occuring. +A _dwell time_ of a few minutes to 30 minutes is taken to allow various systems to be reset and readied for the next plasma pulse; during this time there is no plasma and no fusion occurring. Restarting the plasma may require a significant amount of parasitic power draw, described above. #### Pulses are stressful @@ -84,7 +84,7 @@ By default these four parasitic load parameters are $0$. The `parasitic_start_energy` and `parasitic_start_power` are related, as described above. If starting a plasma pulse in a 1000-MW-gross plant requires a draw of 500 MW for 3 minutes, then `parasitic_start_power` would be $0.5$ and `parasitic_start_energy` would be $(500/1000) * (3/60) = 0.025$, where 60 is the number of minutes in an hour. -The plasma startup sequence is assumed to be shorter than an hour: while this is not checked programatically, the `parasitic_start_power` should, logically, always be equal to or larger than the `parasitic_start_energy`. +The plasma startup sequence is assumed to be shorter than an hour: while this is not checked programmatically, the `parasitic_start_power` should, logically, always be equal to or larger than the `parasitic_start_energy`. #### Dwell time The `dwell_time` parameter is expressed in fractions of an hour. @@ -94,7 +94,7 @@ The default is $0$. The dwell time is counted in the same hour as the start of a plasma pulse. Therefore the pulse start hour may have less net generation due to the `parasitic_start_energy` as well as the dwell time. -_Nota bene_: while at first blush the dwell time and `parastic_start_energy` might seem interchangeable as ways to reduce the net power output during the start hour, a dwell time does not contribute to the accumulated gross power generation as is constrained by `max_fpy_per_year`. +_Nota bene_: while at first blush the dwell time and `parasitic_start_energy` might seem interchangeable as ways to reduce the net power output during the start hour, a dwell time does not contribute to the accumulated gross power generation as is constrained by `max_fpy_per_year`. #### Operational constraints The `max_up_time` constraint is activated by entering an integer denoting the length of the pulse in hours. @@ -126,7 +126,7 @@ With a value of $0.5$ it is reduced by half, and so on. Use of the fusion module leads to two new outputs files, and changes to existing output files. -- `fusion_pulse_starts`. This file is similar to `start/commit/shutdown.csv` for unit committment. +- `fusion_pulse_starts`. This file is similar to `start/commit/shutdown.csv` for unit commitment. There is a column for each fusion resource component and a row for each timestep. Values are number of plant units (of a given resource component) starting a fusion pulse in each timestep. diff --git a/docs/src/Model_Reference/Resources/maintenance.md b/docs/src/Model_Reference/Resources/maintenance.md index 415318c913..2cf41bf70f 100644 --- a/docs/src/Model_Reference/Resources/maintenance.md +++ b/docs/src/Model_Reference/Resources/maintenance.md @@ -11,7 +11,7 @@ Scheduled maintenance is implemented **only** for thermal plants with unit commi A plant requires a single contiguous period of $h \ge 1$ hours of maintenance, every $y \ge 1$ years. For each plant, the best time to start the maintenance period is determined by the optimizer. -During maintenance, the plant cannot be "commited", and therefore +During maintenance, the plant cannot be "committed", and therefore * uses no fuel, * produces no power, @@ -105,4 +105,4 @@ GenX.controlling_maintenance_start_hours GenX.ensure_maintenance_variable_records! GenX.has_maintenance GenX.maintenance_down_variables -``` \ No newline at end of file +``` diff --git a/docs/src/Tutorials/Tutorial_1_configuring_settings.md b/docs/src/Tutorials/Tutorial_1_configuring_settings.md index c7d8c7f08c..3a53078fc6 100644 --- a/docs/src/Tutorials/Tutorial_1_configuring_settings.md +++ b/docs/src/Tutorials/Tutorial_1_configuring_settings.md @@ -335,7 +335,7 @@ results = CSV.read(open("example_systems/1_three_zones/Results/capacity.csv"),Da As you can see, this runs without a problem! To try with your own parameters, edit the `new_params` dictionary with whatever parameters you'd like to try and run the cells again.Note: to output the results, you'll have to either delete the previous `results` folder, or input the name of the new results folder (e.g. `results_1`) when calling `CSV.read` as above. -Finally, let's rewite `genx_settings.yml` to put the original settings in the example back: +Finally, let's rewrite `genx_settings.yml` to put the original settings in the example back: ```julia diff --git a/docs/src/Tutorials/Tutorial_2_network_visualization.md b/docs/src/Tutorials/Tutorial_2_network_visualization.md index 6556e5da7c..e6559864ca 100644 --- a/docs/src/Tutorials/Tutorial_2_network_visualization.md +++ b/docs/src/Tutorials/Tutorial_2_network_visualization.md @@ -25,7 +25,7 @@ network = CSV.read("example_systems/1_three_zones/system/Network.csv",DataFrame, MA, CT, and ME are the abbreviations for states Massachusetts, Connecticut, and Maine. However, since the US region of New England contains other states as well, MA in this case is also used to refer to those states. -Columns `Start_Zone` and `End_Zone` specify the network of the three regions. In this case, there are only two network lines, specified in the `Network_Lines` columns. The `Start_Zone` column indicates that the first node, MA, is the source of both lines as both rows have value 1. Rows `z1` and `z2` have values of 2 and 3 in `End_Zone`, which means both nodes CT and ME recieve energy from node MA. This is also indicated in the column `transmission path name'. +Columns `Start_Zone` and `End_Zone` specify the network of the three regions. In this case, there are only two network lines, specified in the `Network_Lines` columns. The `Start_Zone` column indicates that the first node, MA, is the source of both lines as both rows have value 1. Rows `z1` and `z2` have values of 2 and 3 in `End_Zone`, which means both nodes CT and ME receive energy from node MA. This is also indicated in the column `transmission path name'. Below is a visualization of the network: diff --git a/docs/src/Tutorials/Tutorial_3_K-means_time_domain_reduction.md b/docs/src/Tutorials/Tutorial_3_K-means_time_domain_reduction.md index 5d56315d4c..7ce1b41758 100644 --- a/docs/src/Tutorials/Tutorial_3_K-means_time_domain_reduction.md +++ b/docs/src/Tutorials/Tutorial_3_K-means_time_domain_reduction.md @@ -320,7 +320,7 @@ demands_with_TDR[!,:MW] = convert.(Float64,demands_with_TDR[!,:MW]); demands_with_TDR |> @vlplot(mark={:line}, x={:hour,title="Time Step (hours)",labels="Week:n"}, y={:MW,title="Demand (MW)"}, - color={"Week:n", scale={scheme="paired"},sort="decsending"}, title="MW Demand per hour with TDR Representative Weeks", + color={"Week:n", scale={scheme="paired"},sort="descending"}, title="MW Demand per hour with TDR Representative Weeks", width=845,height=400) ``` ![svg](./files/t3_TDR_demand.svg) @@ -379,13 +379,13 @@ demands_with_TDR2[!,:MW] = convert.(Float64,demands_with_TDR2[!,:MW]); ```julia -# Define a new color scheme to accomodate more periods +# Define a new color scheme to accommodate more periods myscheme = ["#a6cee3","#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00", "#cab2d6","#6a3d9a","#ffff99","#b15928","#b1ff00","#095768","#ce7e00","#b4a7d6"]; [demands_with_TDR; demands_with_TDR2] |> @vlplot(mark={:line}, row="Extreme_Periods:n", x={:hour,title="Time Step (hours)",labels="Week:n"}, y={:MW,title="Demand (MW)"}, - color={"Week:n", scale={scheme="paired"},sort="decsending"}, + color={"Week:n", scale={scheme="paired"},sort="descending"}, title="MW Demand per hour with TDR Representative Weeks, Extreme Periods Off", width=845,height=300) ``` @@ -549,14 +549,14 @@ for i in range(1,6) end println(" ") YAML.write_file(joinpath(case,"settings/time_domain_reduction_settings.yml"), time_domain_reduction_settings) - time = @elapsed include("example_systmes/1_three_zones/Run.jl") + time = @elapsed include("example_systems/1_three_zones/Run.jl") times[i] = time end ``` Note that as the number of periods increases, so does the time it takes to run. -Now, let's check that we have the correct Results folders and process the objecive values to plot. There should be seven results folders, including the original `results`. +Now, let's check that we have the correct Results folders and process the objective values to plot. There should be seven results folders, including the original `results`. ```julia @@ -627,10 +627,10 @@ ygrid!(:on, :dashdot, 0.1) ![svg](./files/t3_obj_vals.svg) -Here, we can see that while having very few representative periods produces an objective value that differs greatly from the orignal, once we reach around 12 representative periods the difference begins to taper out. Therefore, the original choice of 11 maximum periods in `1_three_zones` decreases the run time of GenX significantly while while maintaining an objective value close to the original. +Here, we can see that while having very few representative periods produces an objective value that differs greatly from the original, once we reach around 12 representative periods the difference begins to taper out. Therefore, the original choice of 11 maximum periods in `1_three_zones` decreases the run time of GenX significantly while while maintaining an objective value close to the original. -It's important to note, however, that the difference does not always taper out, and for some systems you'll find that the error in objective value continues to decrease as the number of representative periods increases. There also is no way to know apriori what number of periods works. +It's important to note, however, that the difference does not always taper out, and for some systems you'll find that the error in objective value continues to decrease as the number of representative periods increases. There also is no way to know a priori what number of periods works. Finally, let's set TDR to have 8 and 11 min/max periods again, and delete the TDR Results folder. diff --git a/docs/src/Tutorials/Tutorial_4_model_generation.md b/docs/src/Tutorials/Tutorial_4_model_generation.md index 0d50bab766..a6f105a9d1 100644 --- a/docs/src/Tutorials/Tutorial_4_model_generation.md +++ b/docs/src/Tutorials/Tutorial_4_model_generation.md @@ -2,7 +2,7 @@ [Interactive Notebook of the tutorial](https://github.com/GenXProject/GenX-Tutorials/blob/main/Tutorials/Tutorial_4_Model_Generation.ipynb) -To run GenX, we use the file `Run.jl`. This file will solve the optimization problem and generate the output files as described in the documentation and previous tutorial. It does so by first generating the model, then solving the model, both according to settings described in `genx_settings.yml`. However, `Run.jl` only contains one commmand, `run_genx_case!(dirname(@__FILE__))`. This can be confusing for users viewing the files for the first time. In reality, this function signals many more functions to run, generating and solving the model. This tutorial explains how the model in GenX is generated. The next tutorial will then describe how it is solved. +To run GenX, we use the file `Run.jl`. This file will solve the optimization problem and generate the output files as described in the documentation and previous tutorial. It does so by first generating the model, then solving the model, both according to settings described in `genx_settings.yml`. However, `Run.jl` only contains one command, `run_genx_case!(dirname(@__FILE__))`. This can be confusing for users viewing the files for the first time. In reality, this function signals many more functions to run, generating and solving the model. This tutorial explains how the model in GenX is generated. The next tutorial will then describe how it is solved. We'll start by explaining JuMP, the optimization package that GenX uses to generate and solve the model. @@ -68,7 +68,7 @@ Using the JuMP function `@constraint`, we can add the constraints of the model: @constraint(power, non_neg_x, x >= 0) # Non-negativity constraint (can't have negative power plants!) @constraint(power, non_neg_y, y >= 0) # Non-negativity constraint -@constraint(power, emissions, 40x + 5y <= 200) # Emisisons constraint +@constraint(power, emissions, 40x + 5y <= 200) # Emissions constraint @constraint(power, construction_costs, 55x + 70y <= 1000) # Cost of constructing a new plant @constraint(power, demand, x + y >= 10) # Grid demand diff --git a/docs/src/Tutorials/Tutorial_5_solve_model.md b/docs/src/Tutorials/Tutorial_5_solve_model.md index d1a8327604..45789cc8f1 100644 --- a/docs/src/Tutorials/Tutorial_5_solve_model.md +++ b/docs/src/Tutorials/Tutorial_5_solve_model.md @@ -44,7 +44,7 @@ power = Model(HiGHS.Optimizer) @constraint(power, non_neg_x, x >= 0) # Non-negativity constraint (can't have negative power plants!) @constraint(power, non_neg_y, y >= 0) # Non-negativity constraint -@constraint(power, emissions, 40x + 5y <= 200) # Emisisons constraint +@constraint(power, emissions, 40x + 5y <= 200) # Emissions constraint @constraint(power, construction_costs, 55x + 70y <= 1000) # Cost of constructing a new plant @constraint(power, demand, x + y >= 10) # Grid demand @@ -305,7 +305,7 @@ optimize!(power) 0 (heuristics) ``` -In this case, the infeasibility was detected on the presovle since it's clear no solution would fit within all constraints. For information on how to debug an infeasible solution, see the [JuMP documentaion](https://jump.dev/JuMP.jl/stable/manual/solutions/#Conflicts). Some solvers, such as Gurobi, will compute what is causing the conflict, e.g. which constraints are infeasible with one another (HiGHS does not do this). +In this case, the infeasibility was detected on the presolve since it's clear no solution would fit within all constraints. For information on how to debug an infeasible solution, see the [JuMP documentation](https://jump.dev/JuMP.jl/stable/manual/solutions/#Conflicts). Some solvers, such as Gurobi, will compute what is causing the conflict, e.g. which constraints are infeasible with one another (HiGHS does not do this). GenX version 0.4 has the feature `ComputeConflict` in settings. If the model does not work, try setting `ComputeConflict = 1`, and the conflicting constraints will be returned. diff --git a/docs/src/Tutorials/Tutorial_6_solver_settings.md b/docs/src/Tutorials/Tutorial_6_solver_settings.md index a50f4b048b..ca2dd79563 100644 --- a/docs/src/Tutorials/Tutorial_6_solver_settings.md +++ b/docs/src/Tutorials/Tutorial_6_solver_settings.md @@ -102,7 +102,7 @@ The default settings are combined with the settings you specify in `highs_settin ### Feasibility Tolerance -The parameters `Feasib_Tol` and `Optimal_Tol` represent the feasibility of the primal and dual functions respectively. Without going into too much detail, a [__dual function__](https://en.wikipedia.org/wiki/Duality_(optimization)) is an analagous formulation of the original ("primal") function whose objective value acts as a lower bound to the primal function. The objective value of the primal function is then the upper bound of the dual function. HiGHS will solve the dual and primal at each time step, then terminate when the solutions of the two are within a certain tolerance range. For more information on how this works specifically in HiGHS, see the [HiGHS documentaion](https://ergo-code.github.io/HiGHS/dev/terminology). +The parameters `Feasib_Tol` and `Optimal_Tol` represent the feasibility of the primal and dual functions respectively. Without going into too much detail, a [__dual function__](https://en.wikipedia.org/wiki/Duality_(optimization)) is an analogous formulation of the original ("primal") function whose objective value acts as a lower bound to the primal function. The objective value of the primal function is then the upper bound of the dual function. HiGHS will solve the dual and primal at each time step, then terminate when the solutions of the two are within a certain tolerance range. For more information on how this works specifically in HiGHS, see the [HiGHS documentation](https://ergo-code.github.io/HiGHS/dev/terminology). If we decrease the tolerance parameters, the objective value becomes closer to the "true" optimal value. @@ -160,7 +160,7 @@ ygrid!(:on, :dashdot, 0.1) ### PreSolve -In optimization, presolve is a stage at the beginning of the solver in which the problem is simplified to remove redunant constraints and otherwise simplify the problem before the optimization itself begins. The default for presolve in GenX is "choose", allowing the solver to use presolve only if it will reduce computation time. +In optimization, presolve is a stage at the beginning of the solver in which the problem is simplified to remove redundant constraints and otherwise simplify the problem before the optimization itself begins. The default for presolve in GenX is "choose", allowing the solver to use presolve only if it will reduce computation time. Let's try setting presolve to off and on, then compare computation times. @@ -495,4 +495,4 @@ solution5 = @elapsed GenX.solve_model(EP5,setup) LP solved for primal 140.74829025 -``` \ No newline at end of file +``` diff --git a/docs/src/Tutorials/Tutorial_7_setup.md b/docs/src/Tutorials/Tutorial_7_setup.md index 53dfe6ea68..17d698c968 100644 --- a/docs/src/Tutorials/Tutorial_7_setup.md +++ b/docs/src/Tutorials/Tutorial_7_setup.md @@ -106,7 +106,7 @@ Now, we'll generate and solve the model using these results: ```julia -## Delte Previous TDR Results +## Delete Previous TDR Results if "TDR_results" in cd(readdir,case) rm(joinpath(case,"TDR_results"), recursive=true) end @@ -473,7 +473,7 @@ DataFrame([RT totCap_base],["Resource","Total Capacity"]) ``` -To visualize the impact of the emmissions policies, let's group the nodes together by type and plot the data. +To visualize the impact of the emissions policies, let's group the nodes together by type and plot the data. ```julia @@ -509,11 +509,11 @@ As you can see, with no limit on emissions, GenX goes straight to using natural ## CO2 Cap -The setting `CO2Cap` specifies if the model should have a constraint on CO$_2$ emmissions, and, if so, what that constraint should look like. There are three types, mass, load-based, and generator-based. +The setting `CO2Cap` specifies if the model should have a constraint on CO$_2$ emissions, and, if so, what that constraint should look like. There are three types, mass, load-based, and generator-based. ### Mass Cap -The first type of constraint, done by setting `CO2Cap` to "1", is a mass based constraint, which simply puts a limit on the total tons of CO$_2$ able to be produced per megawatt of electricty. +The first type of constraint, done by setting `CO2Cap` to "1", is a mass based constraint, which simply puts a limit on the total tons of CO$_2$ able to be produced per megawatt of electricity. ```julia @@ -1019,11 +1019,11 @@ plot(G3,G2,size=(800,450),titlefontsize=8) ![svg](./files/t7_2p_mass_zero.svg) -As you can see, the use of natural gas has been eliminated compeltely. Note that the objective value increases here as well as renewable energy tends to cost more than natural gas. +As you can see, the use of natural gas has been eliminated completely. Note that the objective value increases here as well as renewable energy tends to cost more than natural gas. #### CO2 Slack -Another thing we can do is, instead of demanding that the model 100% meet the CO$_2$ cap, we can add a penalty for if it violates the cap. This lets the system allow some CO$_2$ emmissions if it's determined the cost of the grid with some emmissions is low enough that it will offset the cost from the penalty variable. GenX will automatically incorporate this feature if a file by the name "CO2_cap_slack.csv" is in the policies folder of the directory. For more information on other types of policy slack variables in GenX, see the documentation on [Policy Slack Variables]. +Another thing we can do is, instead of demanding that the model 100% meet the CO$_2$ cap, we can add a penalty for if it violates the cap. This lets the system allow some CO$_2$ emissions if it's determined the cost of the grid with some emissions is low enough that it will offset the cost from the penalty variable. GenX will automatically incorporate this feature if a file by the name "CO2_cap_slack.csv" is in the policies folder of the directory. For more information on other types of policy slack variables in GenX, see the documentation on [Policy Slack Variables]. Here, the CO$_2$ slack cap models a [carbon tax](https://en.wikipedia.org/wiki/Carbon_tax#:~:text=A%20carbon%20tax%20is%20a,like%20more%20severe%20weather%20events.of) of \$250 per ton of emissions. @@ -2077,7 +2077,7 @@ plot(G7,G2,G5,G6,size=(900,900), titlefontsize=8,layout=(2,2)) ![svg](./files/t7_4p_esr_mass_load_gen.svg) -The Energy Share Requriement policy also has the possibiliy to be run with slack variables +The Energy Share Requirement policy also has the possibility to be run with slack variables ## Capacity Reserve Margin @@ -2342,7 +2342,7 @@ plot(G8,G7,G2,size=(900,450), titlefontsize=8,layout=(1,3)) -Capacity Reserve Margin also has the possibiliy to be run with slack variables. +Capacity Reserve Margin also has the possibility to be run with slack variables. ## Minimum Capacity Requirement diff --git a/docs/src/Tutorials/Tutorial_8_outputs.md b/docs/src/Tutorials/Tutorial_8_outputs.md index e6b9f130f5..c7a54aff95 100644 --- a/docs/src/Tutorials/Tutorial_8_outputs.md +++ b/docs/src/Tutorials/Tutorial_8_outputs.md @@ -7,7 +7,7 @@ Once an instance of GenX is run, a series of csv files describing the outputs ar ### Table of Contents * [Power](#power) * [Cost and Revenue](#cost) -* [Emmissions](#emms) +* [Emissions](#emms) Let's get things started by running an instance of GenX using `Run.jl`. You can skip this step if you already have a results folder you would like to analyze. @@ -393,7 +393,7 @@ power_plot |> @vlplot(mark={:area}, x={:Hour,title="Time Step (hours)",labels="Resource_Type:n",axis={values=0:12:168}}, y={:MW,title="Demand (MW)",type="quantitative"}, color={"Resource_Type:n",scale={scheme="accent"},sort="descending"},order={field="Resource_Type:n"},width=845,height=400)+ -@vlplot(mark=:line,x=:Hour,y=:Demand_Total,lables="Demand",color={datum="Demand",legend={title=nothing}},title="Resource Capacity per Hour with Demand Curve, all Zones") +@vlplot(mark=:line,x=:Hour,y=:Demand_Total,labels="Demand",color={datum="Demand",legend={title=nothing}},title="Resource Capacity per Hour with Demand Curve, all Zones") ``` ![svg](./files/t8_cap.svg) @@ -414,7 +414,7 @@ groupedbar(["Zone 1", "Zone 2", "Zone 3"],[Zone1; Zone2; Zone3], bar_position = ![svg](./files/t8_resource_allocation.svg) -Below is a heatmap for the natural gas plant in Massachusetts. It is normalized by the end capacity in `capcity.csv`. To change which plant the heat map plots, change the DataFrame column in `power` when defining `power_cap` below, and the corresponding capacity. +Below is a heatmap for the natural gas plant in Massachusetts. It is normalized by the end capacity in `capacity.csv`. To change which plant the heat map plots, change the DataFrame column in `power` when defining `power_cap` below, and the corresponding capacity. ```julia @@ -480,7 +480,7 @@ StatsPlots.scatter!(xnames,netrevenue[!,"Revenue"],label="Revenue",color="black" ### Emissions -The file `emmissions.csv` gives the total CO2 emmissions per zone for each hour GenX runs. The first three rows give the marginal CO2 abatement cost in $/ton CO2. +The file `emissions.csv` gives the total CO2 emissions per zone for each hour GenX runs. The first three rows give the marginal CO2 abatement cost in $/ton CO2. ```julia @@ -513,14 +513,14 @@ end ```julia emm_plot |> @vlplot(mark={:line}, - x={:Hour,title="Time Step (hours)",labels="Zone:n",axis={values=tstart:24:tend}}, y={:MW,title="Emmissions (Tons)",type="quantitative"}, - color={"Zone:n"},width=845,height=400,title="Emmissions per Time Step by Zone") + x={:Hour,title="Time Step (hours)",labels="Zone:n",axis={values=tstart:24:tend}}, y={:MW,title="Emissions (Tons)",type="quantitative"}, + color={"Zone:n"},width=845,height=400,title="Emissions per Time Step by Zone") ``` ![svg](./files/t8_emm1.svg) -Let's try changing the CO2 cap, as in Tutorial 7, and plotting the resulting emmissions. +Let's try changing the CO2 cap, as in Tutorial 7, and plotting the resulting emissions. ```julia genx_settings_TZ = YAML.load(open((joinpath(case,"settings/genx_settings.yml")))) @@ -802,8 +802,8 @@ end ```julia emm_plot2 |> @vlplot(mark={:line}, - x={:Hour,title="Time Step (hours)",labels="Zone:n",axis={values=tstart:24:tend}}, y={:MW,title="Emmissions (Tons)",type="quantitative"}, - color={"Zone:n"},width=845,height=400,title="Emmissions per Time Step by Zone") + x={:Hour,title="Time Step (hours)",labels="Zone:n",axis={values=tstart:24:tend}}, y={:MW,title="Emissions (Tons)",type="quantitative"}, + color={"Zone:n"},width=845,height=400,title="Emissions per Time Step by Zone") ``` ![svg](./files/t8_emm2.svg) @@ -811,7 +811,7 @@ emm_plot2 |> -We can see how the emmissions, summed over all zones, compare in the following plot: +We can see how the emissions, summed over all zones, compare in the following plot: ```julia @@ -819,8 +819,8 @@ emm1sum = sum(eachcol(emm_tot)); emm2sum = sum(eachcol(emm_tot2)); Plots.plot(collect((tstart-3):(tend-3)),emm1sum[tstart:tend],size=(800,400),label="Demand Based CO2 Cap", - xlabel="Time Step (Hours)",ylabel="Emmissions (Tons)",thickness_scaling = 1.1,linewidth = 1.5, - title="Emmisions per Time Step",xticks=tstart:72:tend) + xlabel="Time Step (Hours)",ylabel="Emissions (Tons)",thickness_scaling = 1.1,linewidth = 1.5, + title="Emissions per Time Step",xticks=tstart:72:tend) Plots.plot!(collect((tstart-3):(tend-3)),emm2sum[tstart:tend],label="No CO2 Cap",linewidth = 1.5) ``` ![svg](./files/t8_emm_comp.svg) diff --git a/docs/src/Tutorials/files/t8_emm1.svg b/docs/src/Tutorials/files/t8_emm1.svg index 55cbae0e1d..f3fc9c7e48 100644 --- a/docs/src/Tutorials/files/t8_emm1.svg +++ b/docs/src/Tutorials/files/t8_emm1.svg @@ -1 +1 @@ -47049451854256659061463866268671073475878280683085487890292695097499810221046107010941118114211661190121412381262128613101334135813821406143014541478Time Step (hours)05001,0001,5002,0002,5003,0003,5004,000Emmissions (Tons)Zone 1Zone 2Zone 3ZoneEmmissions per Time Step by Zone \ No newline at end of file +47049451854256659061463866268671073475878280683085487890292695097499810221046107010941118114211661190121412381262128613101334135813821406143014541478Time Step (hours)05001,0001,5002,0002,5003,0003,5004,000Emissions (Tons)Zone 1Zone 2Zone 3ZoneEmissions per Time Step by Zone \ No newline at end of file diff --git a/docs/src/Tutorials/files/t8_emm2.svg b/docs/src/Tutorials/files/t8_emm2.svg index 025757e6c3..922e325430 100644 --- a/docs/src/Tutorials/files/t8_emm2.svg +++ b/docs/src/Tutorials/files/t8_emm2.svg @@ -1 +1 @@ -47049451854256659061463866268671073475878280683085487890292695097499810221046107010941118114211661190121412381262128613101334135813821406143014541478Time Step (hours)05001,0001,5002,0002,5003,0003,5004,0004,500Emmissions (Tons)Zone 1Zone 2Zone 3ZoneEmmissions per Time Step by Zone \ No newline at end of file +47049451854256659061463866268671073475878280683085487890292695097499810221046107010941118114211661190121412381262128613101334135813821406143014541478Time Step (hours)05001,0001,5002,0002,5003,0003,5004,0004,500Emissions (Tons)Zone 1Zone 2Zone 3ZoneEmissions per Time Step by Zone \ No newline at end of file diff --git a/docs/src/User_Guide/methodofmorris_input.md b/docs/src/User_Guide/methodofmorris_input.md index f643bb1182..184c476ced 100644 --- a/docs/src/User_Guide/methodofmorris_input.md +++ b/docs/src/User_Guide/methodofmorris_input.md @@ -14,8 +14,8 @@ This file contains the settings parameters required to run the Method of Morris |Parameter| Column from the `Generators_data.csv` file containing uncertain parameters| |Group| Group the uncertain parameters that will be changed all at once while performing the sensitivity analysis. For example, if the fuel price of natural gas is uncertain, all generators consuming natural gas should be in the same group. Group name is user defined| |p_steps| Number of steps between upper and lower bound| -|total\_num\_trajectory| Total number of trakectories through the design matrix| -|num\_trajectory| Selected number of trajectories throigh the design matrix| +|total\_num\_trajectory| Total number of trajectories through the design matrix| +|num\_trajectory| Selected number of trajectories through the design matrix| |len\_design\_mat| Length of the design matrix| |policy| Name of the policy| @@ -28,4 +28,4 @@ Notes: 6. `num_trajectory` should be approximately equal to the total number of uncertain parameters 7. `len_design_mat` should be 1.5 to 2 times the total number of uncertain parameters 8. Higher number of `num_trajectory` and `len_design_mat` would lead to higher accuracy -9. Upper and lower bounds should be specified for all the resources included in the `Generators_data.csv` file. If a parameter related to a particular resource is not uncertain, specify upper bound = lower bound = 0. \ No newline at end of file +9. Upper and lower bounds should be specified for all the resources included in the `Generators_data.csv` file. If a parameter related to a particular resource is not uncertain, specify upper bound = lower bound = 0. diff --git a/docs/src/User_Guide/model_configuration.md b/docs/src/User_Guide/model_configuration.md index 3713227099..ccb9ff6bf5 100644 --- a/docs/src/User_Guide/model_configuration.md +++ b/docs/src/User_Guide/model_configuration.md @@ -7,7 +7,7 @@ The first step in configuring a GenX model is to specify the model settings para - Network related parameters specify settings related to transmission network expansion and losses. Note that all settings parameters are case sensitive. -(Optional) The user can also select the output files that they want to export using the `output_settings.yml` file. This file containes a list of `yes/no` options for each output file, and should be located in the `settings` folder. By default, if `output_settings.yml` is not included, GenX will export all output files. +(Optional) The user can also select the output files that they want to export using the `output_settings.yml` file. This file contains a list of `yes/no` options for each output file, and should be located in the `settings` folder. By default, if `output_settings.yml` is not included, GenX will export all output files. The following tables summarize the model settings parameters and their default/possible values. diff --git a/docs/src/User_Guide/model_input.md b/docs/src/User_Guide/model_input.md index ea3c86d24a..64cf11cd05 100644 --- a/docs/src/User_Guide/model_input.md +++ b/docs/src/User_Guide/model_input.md @@ -96,7 +96,7 @@ Network_Lines, Start_Zone, End_Zone, ``` The matrix interface requires N columns labeled `z1, z2, z3 ... zN`, -and L rows, one for each network line (or interregional path), with a `1` in the column corresponding to the 'start' zone +and L rows, one for each network line (or inter-regional path), with a `1` in the column corresponding to the 'start' zone and a `-1` in the column corresponding to the 'end' zone for each line. Here is the same network map implemented as a matrix: ``` @@ -119,7 +119,7 @@ This file includes parameters to characterize model temporal resolution to appro | :------------ | :-----------| |**Mandatory Columns**| |Voll |Value of lost load (also referred to as non-served energy) in $/MWh.| -|Demand\_Segment |Number of demand curtailment/unserved demand segments with different cost and capacity of curtailable demand for each segment. User-specified demand segments. Integer values starting with 1 in the first row. Additional segements added in subsequent rows.| +|Demand\_Segment |Number of demand curtailment/unserved demand segments with different cost and capacity of curtailable demand for each segment. User-specified demand segments. Integer values starting with 1 in the first row. Additional segments added in subsequent rows.| |Cost\_of\_Demand\_Curtailment\_per\_MW |Cost of non-served energy/demand curtailment (for each segment), reported as a fraction of value of the lost load (non-served demand). If *Demand\_Segment = 1*, then this parameter is a scalar and equal to one. In general this parameter is a vector of length equal to the length of Demand\_Segment.| |Max\_Demand\_Curtailment| Maximum time-dependent demand curtailable in each segment, reported as % of the demand in each zone and each period. *If Demand\_Segment = 1*, then this parameter is a scalar and equal to one. In general this parameter is a vector of length given by length of Demand\_segment.| |Time\_Index |Index defining time step in the model.| @@ -216,7 +216,7 @@ Each file contains cost and performance parameters for various generators and ot |Ramp\_Up\_Percentage |[0,1], Maximum increase in power output from between two periods (typically hours), reported as a fraction of nameplate capacity.| |Ramp\_Dn\_Percentage |[0,1], Maximum decrease in power output from between two periods (typically hours), reported as a fraction of nameplate capacity.| |**PiecewiseFuelUsage-related parameters**| -|PWFU\_Fuel\_Usage\_Zero\_Load\_MMBTU\_per\_h|The fuel usage (MMBTU/h) for the first PWFU segemnt (y-intercept) at zero load.| +|PWFU\_Fuel\_Usage\_Zero\_Load\_MMBTU\_per\_h|The fuel usage (MMBTU/h) for the first PWFU segment (y-intercept) at zero load.| |PWFU\_Heat\_Rate\_MMBTU\_per\_MWh\_*i| The slope of fuel usage function of the segment i.| |PWFU\_Load\_Point\_MW\_*i| The end of segment i (MW).| |**Multi-fuel parameters**| @@ -228,14 +228,14 @@ Each file contains cost and performance parameters for various generators and ot |Fuel2 |Second fuel needed for a mulit-fuel generator (MULTI_FUELS = 1). The names should match with the ones in the `Fuels_data.csv`. | |Heat1\_Rate\_MMBTU\_per\_MWh |Heat rate of a multi-fuel generator (MULTI_FUELS = 1) for Fuel1. | |Heat2\_Rate\_MMBTU\_per\_MWh |Heat rate of a multi-fuel generator (MULTI_FUELS = 1) for Fuel2. | -|Fuel1\_Min\_Cofire\_Level |The minimum blendng level of 'Fuel1' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the normal generation process. | -|Fuel1\_Min\_Cofire_Level\_Start |The minimum blendng level of 'Fuel1' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the start-up process. | -|Fuel1\_Max\_Cofire\_Level |The maximum blendng level of 'Fuel1' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the normal generation process. | -|Fuel1\_Max\_Cofire_Level\_Start |The maximum blendng level of 'Fuel1' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the start-up process. | -|Fuel2\_Min\_Cofire\_Level |The minimum blendng level of 'Fuel2' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the normal generation process. | -|Fuel2\_Min\_Cofire_Level\_Start |The minimum blendng level of 'Fuel2' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the start-up process. | -|Fuel2\_Max\_Cofire\_Level |The maximum blendng level of 'Fuel2' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the normal generation process. | -|Fuel2\_Max\_Cofire_Level\_Start |The maximum blendng level of 'Fuel2' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the start-up process. | +|Fuel1\_Min\_Cofire\_Level |The minimum blending level of 'Fuel1' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the normal generation process. | +|Fuel1\_Min\_Cofire_Level\_Start |The minimum blending level of 'Fuel1' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the start-up process. | +|Fuel1\_Max\_Cofire\_Level |The maximum blending level of 'Fuel1' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the normal generation process. | +|Fuel1\_Max\_Cofire_Level\_Start |The maximum blending level of 'Fuel1' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the start-up process. | +|Fuel2\_Min\_Cofire\_Level |The minimum blending level of 'Fuel2' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the normal generation process. | +|Fuel2\_Min\_Cofire_Level\_Start |The minimum blending level of 'Fuel2' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the start-up process. | +|Fuel2\_Max\_Cofire\_Level |The maximum blending level of 'Fuel2' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the normal generation process. | +|Fuel2\_Max\_Cofire_Level\_Start |The maximum blending level of 'Fuel2' in total heat inputs of a mulit-fuel generator (MULTI_FUELS = 1) during the start-up process. | ##### Table 6b: Settings-specific columns in the Thermal.csv file --- @@ -356,8 +356,10 @@ Each file contains cost and performance parameters for various generators and ot !!! note Check `Qualified_Hydrogen_Supply` column in table 5a if electrolyzers are included in the model. This column is used to indicate which resources are eligible to supply electrolyzers in the same zone (used for hourly clean supply constraint). -Each co-located VRE, electrolyzer, and storage resource can be easily configured to contain either a co-located VRE-ELEC-storage resource, standalone VRE resource (either wind, solar PV, or both), standalone eletrolyzers, or standalone storage resource. + +Each co-located VRE, electrolyzer, and storage resource can be easily configured to contain either a co-located VRE-ELEC-storage resource, standalone VRE resource (either wind, solar PV, or both), standalone electrolyzers, or standalone storage resource. ##### Table 12a: Additional columns in the Vre_stor.csv file + --- |**Column Name** | **Description**| | :------------ | :-----------| @@ -478,7 +480,7 @@ Each co-located VRE, electrolyzer, and storage resource can be easily configured --- |**Column Name** | **Description**| | :------------ | :-----------| -|With_LOX | {0, 1}, Flag to indicate the availabity of liquid oxygen storage (LOX) for Allam Cycle.| +|With_LOX | {0, 1}, Flag to indicate the availability of liquid oxygen storage (LOX) for Allam Cycle.| ||With_LOX = 0: LOX is not available.| ||With_LOX = 1: LOX is available.| |**Existing technology capacity**| @@ -505,7 +507,7 @@ Each co-located VRE, electrolyzer, and storage resource can be easily configured |HeatRate\_sCO2|Heat rate of sCO2 turbines in an Allam Cycle power plant (MMBtu/MWh).| |LOX\_PowerUseRate\_O2|Power consumption by ASU to produce liquid oxygen (MWh/ton).| |GOX\_PowerUseRate\_O2|Power consumption by ASU to produce gaseous oxygen (MWh/ton).| -|PowerUseRate\_other|Power consumption by anxilary processes in an Allam Cycle plant (MWh/MWh electricity generated from sCO2 turbines).| +|PowerUseRate\_other|Power consumption by ancillary processes in an Allam Cycle plant (MWh/MWh electricity generated from sCO2 turbines).| |O2UseRate|Oxygen consumption by sCO2 turbines to produce electricity (ton/MWh).| |LOX_duration| Duration of LOX (Hour).| ##### Table 13b: Settings-specific columns in the Allam_Cycle_LOX.csv file @@ -814,8 +816,8 @@ This file contains the settings parameters required to run the Method of Morris |Parameter| Column from the resource `.csv` file (inside the `Resource`) containing uncertain parameters| |Group| Group the uncertain parameters that will be changed all at once while performing the sensitivity analysis. For example, if the fuel price of natural gas is uncertain, all generators consuming natural gas should be in the same group. Group name is user defined| |p_steps| Number of steps between upper and lower bound| -|total\_num\_trajectory| Total number of trakectories through the design matrix| -|num\_trajectory| Selected number of trajectories throigh the design matrix| +|total\_num\_trajectory| Total number of trajectories through the design matrix| +|num\_trajectory| Selected number of trajectories through the design matrix| |len\_design\_mat| Length of the design matrix| |policy| Name of the policy| @@ -841,4 +843,4 @@ This file contains inputs specifying regional hydrogen production requirements. |H2DemandConstraint| Index of the hydrogen demand constraint.| |Constraint\_Description| Names of hydrogen demand constraints; not to be read by model, but used as a helpful notation to the model user. | |Hydrogen\_Demand\_kt| Hydrogen production requirements in 1,000 tons| -|PriceCap| Price of hydrogen per metric ton ($/t)| \ No newline at end of file +|PriceCap| Price of hydrogen per metric ton ($/t)| diff --git a/docs/src/User_Guide/model_output.md b/docs/src/User_Guide/model_output.md index ced87befd1..ab327cd778 100644 --- a/docs/src/User_Guide/model_output.md +++ b/docs/src/User_Guide/model_output.md @@ -38,7 +38,7 @@ Reports optimal objective function value and contribution of each term by zone. |**Output** |**Description** |**Units** | | :------------ | :-----------|:-----------| | cTotal |Total objective function value |$ | -| cFix |Total annualized investment and fixed operating & maintainenance (FOM) costs associated with all resources |$ | +| cFix |Total annualized investment and fixed operating & maintenance (FOM) costs associated with all resources |$ | | cVar |Total annual variable cost associated with all resources; includes fuel costs for thermal plants |$| | cNSE |Total annual cost of non-served energy |$| | cStart |Total annual cost of start-up of thermal power plants| $| @@ -49,7 +49,7 @@ Reports optimal objective function value and contribution of each term by zone. ### 1.3 emissions.csv -Reports CO2 emissions by zone at each hour; an annual sum row will be provided. If any emission cap is present, emission prices each zone faced by each cap will be copied on top of this table with the following strucutre. +Reports CO2 emissions by zone at each hour; an annual sum row will be provided. If any emission cap is present, emission prices each zone faced by each cap will be copied on top of this table with the following structure. ###### Table 17: Structure of emission prices in the emissions.csv file --- @@ -91,7 +91,7 @@ Reports computational performance of the model and objective function related in This file summarizes the cost, revenue and profit for each generation technology for each region. -###### Table 19: Stucture of the NetRevenue.csv file +###### Table 19: Structure of the NetRevenue.csv file --- |**Output** |**Description** |**Units** | | :------------ | :-----------|:-----------| @@ -152,7 +152,7 @@ This file includes the renewable/clean energy credit price of each modeled RPS/C ### 2.7 ESR\_Revenue.csv -This file includes the renewable/clean credit revenue earned by each generator listed in the input file. GenX will print this file only when RPS/CES is modeled and the shadow price can be obtained form the solver. Each row corresponds to a generator, and each column starting from the 6th to the second last is the total revenue earned from each RPS constraint. The revenue is calculated as the total annual generation (if elgible for the corresponding constraint) multiplied by the RPS/CES price. The last column is the total revenue received from all constraint. The unit is $. +This file includes the renewable/clean credit revenue earned by each generator listed in the input file. GenX will print this file only when RPS/CES is modeled and the shadow price can be obtained form the solver. Each row corresponds to a generator, and each column starting from the 6th to the second last is the total revenue earned from each RPS constraint. The revenue is calculated as the total annual generation (if eligible for the corresponding constraint) multiplied by the RPS/CES price. The last column is the total revenue received from all constraint. The unit is $. ### 2.8 SubsidyRevenue.csv diff --git a/docs/src/User_Guide/multi_stage_input.md b/docs/src/User_Guide/multi_stage_input.md index 7ddb2318fd..6455435d9e 100644 --- a/docs/src/User_Guide/multi_stage_input.md +++ b/docs/src/User_Guide/multi_stage_input.md @@ -31,9 +31,9 @@ Instead of one set of input files, there is one directory of input files that ne | | **co-located VRE-STOR resources only** | |:------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------| -|Min\_Retired\_Cap\_Inverter\_MW |Minimum inverter capacity in MW AC that must retire in this plannig stage. | -|Min\_Retired\_Cap\_Solar\_MW |Minimum solar PV capacity in MW DC that must retire in this plannig stage. | -|Min\_Retired\_Cap\_Wind\_MW |Minimum wind capacity in MW AC that must retire in this plannig stage. | +|Min\_Retired\_Cap\_Inverter\_MW |Minimum inverter capacity in MW AC that must retire in this planning stage. | +|Min\_Retired\_Cap\_Solar\_MW |Minimum solar PV capacity in MW DC that must retire in this planning stage. | +|Min\_Retired\_Cap\_Wind\_MW |Minimum wind capacity in MW AC that must retire in this planning stage. | |Min\_Retired\_Cap\_Discharge_DC\_MW |Minimum storage DC discharge capacity that must retire in this planning stage with `STOR_DC_DISCHARGE = 2`. | |Min\_Retired\_Cap\_Charge_DC\_MW |Minimum storage DC charge capacity that must retire in this planning stage with `STOR_DC_CHARGE = 2`. | |Min\_Retired\_Cap\_Discharge_AC\_MW |Minimum storage AC discharge capacity that must retire in this planning stage with `STOR_AC_DISCHARGE = 2`. | diff --git a/docs/src/User_Guide/workflow.md b/docs/src/User_Guide/workflow.md index 96844500c1..10309249e3 100644 --- a/docs/src/User_Guide/workflow.md +++ b/docs/src/User_Guide/workflow.md @@ -27,7 +27,7 @@ The next sections in this guide provide more details on how to perform all the s 7. [GenX Outputs](@ref) ## Details of running a GenX case -This section details as to what happens in the process of running a GenX case. As a first step, the GenX package and the desired solver (is it's anyting other than the default solver, HiGHS; for instance, Gurobi) are loaded +This section details as to what happens in the process of running a GenX case. As a first step, the GenX package and the desired solver (is it's anything other than the default solver, HiGHS; for instance, Gurobi) are loaded ```julia using GenX @@ -39,7 +39,7 @@ The next command the user needs to run is the following: ```julia run_genx_case!("", optimizer) ``` -Contingent upon whether a single stage model or a multi-stage model is intended to be run, the above function, inturn makes calls to either of these two functions: +Contingent upon whether a single stage model or a multi-stage model is intended to be run, the above function, in turn makes calls to either of these two functions: For single-stage case: ```julia run_genx_case_simple!(case, mysetup, optimizer) @@ -63,7 +63,7 @@ For multi-stage case: ```julia run_genx_case_multistage!(case, mysetup, optimizer) ``` -In this case also, the TDR clustering is done in a similar way, exxcept for the fact that if TDRSettingsDict["MultiStageConcatenate"] is set to 0, the TDR clustering is done individually for each stage. Otherwise, the clustering is done for all the stages together. The next step is configuring the solver, which is done by +In this case also, the TDR clustering is done in a similar way, except for the fact that if TDRSettingsDict["MultiStageConcatenate"] is set to 0, the TDR clustering is done individually for each stage. Otherwise, the clustering is done for all the stages together. The next step is configuring the solver, which is done by ```julia OPTIMIZER = configure_solver(settings_path, optimizer) ``` @@ -79,7 +79,7 @@ time_elapsed = @elapsed EP = generate_model(mysetup, myinputs, OPTIMIZER) println("Time elapsed for model building is") println(time_elapsed) ``` -The above function call instantiates the different decision variables, constraints, and objective function expressions from the input data. It can be seen that we also keep track of the time required to build the model. Follwoing this, the solve_model function makes the call to the solver and return the results as well as the solve time. +The above function call instantiates the different decision variables, constraints, and objective function expressions from the input data. It can be seen that we also keep track of the time required to build the model. Following this, the solve_model function makes the call to the solver and return the results as well as the solve time. ```julia EP, solve_time = solve_model(EP, mysetup) myinputs["solve_time"] = solve_time # Store the model solve time in myinputs @@ -89,7 +89,7 @@ For writing the results, we invoke the following function: outputs_path = get_default_output_folder(case) elapsed_time = @elapsed outputs_path = write_outputs(EP, outputs_path, mysetup, myinputs) ``` -The call to the write_outputs() function in turn calls a series of functions (write_capacity, write_power etc.) each of which querries the respective decision variables and creates dataframes, eventually outputting the results to separate CSV files. +The call to the write_outputs() function in turn calls a series of functions (write_capacity, write_power etc.) each of which queries the respective decision variables and creates dataframes, eventually outputting the results to separate CSV files. ## Single and Multi-stage investment planning diff --git a/docs/src/developer_guide.md b/docs/src/developer_guide.md index bca5d37293..bbeaaac33e 100644 --- a/docs/src/developer_guide.md +++ b/docs/src/developer_guide.md @@ -275,7 +275,7 @@ const resource_types = (:Thermal, ``` We encourage you to use `CamelCase` for the name of the new resource type. -The lines right after the `resource_types` list automatically create a new `struct` (composite type) for the new resource type. More importantly, the new resource type will be defined as a subtype of the GenX `AbstractResource` type. This is important because it allows the code to use multiple dispach and define a common interface (behavior) for all resources in GenX. For instance, the `resource_id()` function will return the `id` of any resource in GenX, regardless of its type (and therefore will automatically work for the newly created `new_resource`). +The lines right after the `resource_types` list automatically create a new `struct` (composite type) for the new resource type. More importantly, the new resource type will be defined as a subtype of the GenX `AbstractResource` type. This is important because it allows the code to use multiple dispatch and define a common interface (behavior) for all resources in GenX. For instance, the `resource_id()` function will return the `id` of any resource in GenX, regardless of its type (and therefore will automatically work for the newly created `new_resource`). ### Step 2: Add the filename of the new resource type to GenX @@ -316,7 +316,7 @@ For example, if the input data file `New_resource.csv` contains the following da ``` New_resource.csv - Resource │ Zone | Exisiting_capacity | attribute_1 | attribute_2 + Resource │ Zone | Existing_capacity | attribute_1 | attribute_2 String │ Int64 | Float64 | Float64 | Float64 ──────────┼───────┼────────────────────┼─────────────┼──────────── new_res1 │ 1 │ 100.0 │ 6.2 │ 0.4 @@ -364,4 +364,4 @@ DocTestSetup = nothing ```@autodocs Modules = [GenX] Pages = ["model/expression_manipulation.jl"] -``` \ No newline at end of file +``` diff --git a/docs/src/index.md b/docs/src/index.md index 91dfc7bafe..ebdf5894c5 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -27,7 +27,7 @@ This page serves as a gentle introduction to what GenX is meant for and what it The next subsection, [Installation Guide](@ref) goes over how to download and install GenX and also how to download and install the Julia programming language (in which GenX is written) and the different open-source non-commercial freely available solvers, as well as the commercial solvers and the respective JuMP interfaces. This subsection also goes over installing the environment dependencies and instantiating a virtual environment. -We also mention the shortcomings of GenX and some third party extentions in the next couple subsections +We also mention the shortcomings of GenX and some third party extensions in the next couple subsections The next section is **Getting Started** goes over [Running GenX](@ref) and has two subsections. The first subsection, [Example cases](@ref), gives a walkthrough through some predefined example systems and how to run GenX for those and interpret the results. It also tells how to run GenX for a user-defined case. The subsection [Using commercial solvers: Gurobi or CPLEX](@ref) talks specifically about how to run GenX with commercial solvers like Gurobi and CPLEX that are absolutely indispensable for solving large cases. @@ -37,7 +37,7 @@ The **User Guide**, which the fourth section ([User Guide](@ref)) goes into the The **Model Concept and Overview** section first introduces the GenX model in [GenX Model Introduction](@ref) and talks about its scope. It also introduces the notations, the objective function, and the power balance constraints. This is the first section which delves into the theoretical and mathematical details of the model, which is the most important one for model developers. -The **Model Reference**, which is the sixth section delves deep into the GenX model and introduces the mathematical formulation, while discussing the physical interpretations of all the different parts of the GenX model. This section starts off with discussing the [Core](@ref) of the model, which models the Discharge, Non-Served Energy, Operational Reserves, Transmission, Unit Commitment, CO2, and Fuel. The different parts of the model consists of the different tyoe of generating resources (thermal, hydro, VRE, storage etc.), transmission network (modeling of flows as well as losses), demand modeling, operating reserves, unit commitment, different policies (such as CO2 constraint, capacity reserve margin, energy share requirement, min and max cap requirement etc.). This section also mentions about the different Julia functions (or methods) used for loading the input files, building the model, solving it, and generating the output files. Also, this is the section that explains the internal details of the Julia functions used for TDR, MGA, Method of Morris, Multi-stage modeling, and the several utility functions used throughout the GenX code-base. +The **Model Reference**, which is the sixth section delves deep into the GenX model and introduces the mathematical formulation, while discussing the physical interpretations of all the different parts of the GenX model. This section starts off with discussing the [Core](@ref) of the model, which models the Discharge, Non-Served Energy, Operational Reserves, Transmission, Unit Commitment, CO2, and Fuel. The different parts of the model consists of the different type of generating resources (thermal, hydro, VRE, storage etc.), transmission network (modeling of flows as well as losses), demand modeling, operating reserves, unit commitment, different policies (such as CO2 constraint, capacity reserve margin, energy share requirement, min and max cap requirement etc.). This section also mentions about the different Julia functions (or methods) used for loading the input files, building the model, solving it, and generating the output files. Also, this is the section that explains the internal details of the Julia functions used for TDR, MGA, Method of Morris, Multi-stage modeling, and the several utility functions used throughout the GenX code-base. The seventh section, **Public API Reference** [Public Documentation](@ref) is for describing the functions that are directly accessible to an external program from GenX (like loading inputs, generating output, running TDR script etc.) and how an external "client" code can access the GenX features, if the user desires to run his/her own code instead of the Run.jl provided by us. @@ -94,4 +94,4 @@ Pages = ["Model_Reference/core.md", "Public_API/mga.md", "Public_API/methodofmorris.md", "Public_API/write_outputs.md"] -``` \ No newline at end of file +``` diff --git a/docs/src/installation.md b/docs/src/installation.md index c2a7f3d73f..78a60a619b 100644 --- a/docs/src/installation.md +++ b/docs/src/installation.md @@ -16,7 +16,7 @@ Once you have downloaded GenX, you can install the dependencies by following the 2\. Type `julia --project=.` to start an instance of the `julia` kernel with the `project` set to the current folder. The flag `--project=.` indicates that Julia will activate the project environment using the `Project.toml` present in the current folder, `.`. If running on Windows, the location of Julia can also be specified as e.g., `C:\julia-1.6.0\bin\julia.exe --project=.`. !!! tip "Tip" - The file `Project.toml` in the parent directory lists all of the dependencies and their versions needed to run GenX. You can see all of the packages installed in your Julia environment and their version numbers by running `pkg> status` or `pkg> st` on the package manager command line in the Jula REPL (for more information on the Julia package manager, read the documentation for the [Pkg.jl](https://pkgdocs.julialang.org/v1/environments/) or for the [Julia standard library](https://docs.julialang.org/en/v1/stdlib/Pkg/)). + The file `Project.toml` in the parent directory lists all of the dependencies and their versions needed to run GenX. You can see all of the packages installed in your Julia environment and their version numbers by running `pkg> status` or `pkg> st` on the package manager command line in the Julia REPL (for more information on the Julia package manager, read the documentation for the [Pkg.jl](https://pkgdocs.julialang.org/v1/environments/) or for the [Julia standard library](https://docs.julialang.org/en/v1/stdlib/Pkg/)). !!! tip "Tip" `julia --project` is a shortcut for `julia --project=.` @@ -31,7 +31,7 @@ Once you have downloaded GenX, you can install the dependencies by following the !!! note "Note for Windows users" On Windows there is an issue with the prepopulated `MUMPS_seq_jll v5.5.1` that prevents compilation of the solvers. To avoid this issue type `add MUMPS_seq_jll@5.4.1` after running instantiate. -5\. Type `st` to check that the dependecies have been installed. If there is no error, it has been successful. +5\. Type `st` to check that the dependencies have been installed. If there is no error, it has been successful. !!! tip "Tip" Type the back key to come back to the `julia>` prompt from the package manager. diff --git a/docs/typos.toml b/docs/typos.toml new file mode 100644 index 0000000000..639425ff3b --- /dev/null +++ b/docs/typos.toml @@ -0,0 +1,12 @@ +[type.csv] +extend-glob = ["*.csv"] +check-file = false +[type.svg] +extend-glob = ["*.svg"] +check-file = false +[type.cff] +extend-glob = ["*.cff"] +check-file = false +[type.hunspellWhitelist] +extend-glob = ["hunspell_whitelist"] +check-file = false \ No newline at end of file diff --git a/example_systems/10_IEEE_9_bus_DC_OPF/settings/genx_settings.yml b/example_systems/10_IEEE_9_bus_DC_OPF/settings/genx_settings.yml index 36fbafbfe6..2e4cdf28cc 100644 --- a/example_systems/10_IEEE_9_bus_DC_OPF/settings/genx_settings.yml +++ b/example_systems/10_IEEE_9_bus_DC_OPF/settings/genx_settings.yml @@ -1,5 +1,5 @@ PrintModel: 1 # Write the model formulation as an output; 0 = active; 1 = not active -NetworkExpansion: 0 # Transmission network expansionl; 0 = not active; 1 = active systemwide +NetworkExpansion: 0 # Transmission network expansion; 0 = not active; 1 = active systemwide Trans_Loss_Segments: 0 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic EnergyShareRequirement: 0 # Minimum qualifying renewables penetration; 0 = not active; 1 = active systemwide CapacityReserveMargin: 0 # Number of capacity reserve margin constraints; 0 = not active; 1 = active systemwide diff --git a/example_systems/10_IEEE_9_bus_DC_OPF/settings/gurobi_settings.yml b/example_systems/10_IEEE_9_bus_DC_OPF/settings/gurobi_settings.yml index fd38fb298e..1949cf6fe1 100644 --- a/example_systems/10_IEEE_9_bus_DC_OPF/settings/gurobi_settings.yml +++ b/example_systems/10_IEEE_9_bus_DC_OPF/settings/gurobi_settings.yml @@ -10,6 +10,6 @@ Method: 2 # Algorithm used to solve continuous models (includ MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-06 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: 0 # Barrier crossver strategy. +Crossover: 0 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. diff --git a/example_systems/11_three_zones_w_allam_cycle_lox/settings/genx_settings.yml b/example_systems/11_three_zones_w_allam_cycle_lox/settings/genx_settings.yml index 91148ed002..885ba9e20f 100644 --- a/example_systems/11_three_zones_w_allam_cycle_lox/settings/genx_settings.yml +++ b/example_systems/11_three_zones_w_allam_cycle_lox/settings/genx_settings.yml @@ -1,4 +1,4 @@ -NetworkExpansion: 0 # Transmission network expansionl; 0 = not active; 1 = active systemwide +NetworkExpansion: 0 # Transmission network expansion; 0 = not active; 1 = active systemwide Trans_Loss_Segments: 1 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic EnergyShareRequirement: 0 # Minimum qualifying renewables penetration; 0 = not active; 1 = active systemwide CapacityReserveMargin: 0 # Number of capacity reserve margin constraints; 0 = not active; 1 = active systemwide @@ -8,6 +8,6 @@ MinCapReq: 0 # Activate minimum technology carveout constraints; 0 = not active MaxCapReq: 0 # Activate maximum technology carveout constraints; 0 = not active; 1 = active ParameterScale: 0 # Turn on parameter scaling wherein demand, capacity and power variables are defined in GW rather than MW. 0 = not active; 1 = active systemwide WriteShadowPrices: 1 # Write shadow prices of LP or relaxed MILP; 0 = not active; 1 = active -UCommit: 2 # Unit committment of thermal power plants; 0 = not active; 1 = active using integer clestering; 2 = active using linearized clustering +UCommit: 2 # Unit commitment of thermal power plants; 0 = not active; 1 = active using integer clustering; 2 = active using linearized clustering TimeDomainReduction: 1 # Time domain reduce (i.e. cluster) inputs based on Demand_data.csv, Generators_variability.csv, and Fuels_data.csv; 0 = not active (use input data as provided); 0 = active (cluster input data, or use data that has already been clustered) -EnableJuMPStringNames: true \ No newline at end of file +EnableJuMPStringNames: true diff --git a/example_systems/11_three_zones_w_allam_cycle_lox/settings/gurobi_settings.yml b/example_systems/11_three_zones_w_allam_cycle_lox/settings/gurobi_settings.yml index fd4d9b8a83..e338be4afc 100644 --- a/example_systems/11_three_zones_w_allam_cycle_lox/settings/gurobi_settings.yml +++ b/example_systems/11_three_zones_w_allam_cycle_lox/settings/gurobi_settings.yml @@ -10,6 +10,6 @@ Method: 4 # Algorithm used to solve continuous models (inclu MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-08 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: -1 # Barrier crossver strategy. +Crossover: -1 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. diff --git a/example_systems/1_three_zones/settings/genx_settings.yml b/example_systems/1_three_zones/settings/genx_settings.yml index d48032b1d1..76e26f89c8 100644 --- a/example_systems/1_three_zones/settings/genx_settings.yml +++ b/example_systems/1_three_zones/settings/genx_settings.yml @@ -1,4 +1,4 @@ -NetworkExpansion: 1 # Transmission network expansionl; 0 = not active; 1 = active systemwide +NetworkExpansion: 1 # Transmission network expansion; 0 = not active; 1 = active systemwide Trans_Loss_Segments: 1 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic EnergyShareRequirement: 0 # Minimum qualifying renewables penetration; 0 = not active; 1 = active systemwide CapacityReserveMargin: 0 # Number of capacity reserve margin constraints; 0 = not active; 1 = active systemwide @@ -8,6 +8,6 @@ MinCapReq: 1 # Activate minimum technology carveout constraints; 0 = not active MaxCapReq: 0 # Activate maximum technology carveout constraints; 0 = not active; 1 = active ParameterScale: 1 # Turn on parameter scaling wherein demand, capacity and power variables are defined in GW rather than MW. 0 = not active; 1 = active systemwide WriteShadowPrices: 1 # Write shadow prices of LP or relaxed MILP; 0 = not active; 1 = active -UCommit: 2 # Unit committment of thermal power plants; 0 = not active; 1 = active using integer clestering; 2 = active using linearized clustering +UCommit: 2 # Unit commitment of thermal power plants; 0 = not active; 1 = active using integer clustering; 2 = active using linearized clustering TimeDomainReduction: 1 # Time domain reduce (i.e. cluster) inputs based on Demand_data.csv, Generators_variability.csv, and Fuels_data.csv; 0 = not active (use input data as provided); 0 = active (cluster input data, or use data that has already been clustered) OutputFullTimeSeries: 1 \ No newline at end of file diff --git a/example_systems/1_three_zones/settings/gurobi_settings.yml b/example_systems/1_three_zones/settings/gurobi_settings.yml index fd4d9b8a83..e338be4afc 100644 --- a/example_systems/1_three_zones/settings/gurobi_settings.yml +++ b/example_systems/1_three_zones/settings/gurobi_settings.yml @@ -10,6 +10,6 @@ Method: 4 # Algorithm used to solve continuous models (inclu MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-08 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: -1 # Barrier crossver strategy. +Crossover: -1 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. diff --git a/example_systems/2_three_zones_w_electrolyzer/settings/genx_settings.yml b/example_systems/2_three_zones_w_electrolyzer/settings/genx_settings.yml index 3c3f4d572e..4ff3e3a35f 100644 --- a/example_systems/2_three_zones_w_electrolyzer/settings/genx_settings.yml +++ b/example_systems/2_three_zones_w_electrolyzer/settings/genx_settings.yml @@ -1,5 +1,5 @@ Trans_Loss_Segments: 1 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic -UCommit: 2 # Unit committment of thermal power plants; 0 = not active; 1 = active using integer clestering; 2 = active using linearized clustering +UCommit: 2 # Unit commitment of thermal power plants; 0 = not active; 1 = active using integer clustering; 2 = active using linearized clustering StorageLosses: 1 # Energy Share Requirement and CO2 constraints account for energy lost; 0 = not active (DO NOT account for energy lost); 1 = active systemwide (DO account for energy lost) HydrogenHourlyMatching: 1 # Hydrogen electrolyzer contribution to hourly supply matching required ParameterScale: 1 # Turn on parameter scaling wherein demand, capacity and power variables are defined in GW rather than MW. 0 = not active; 1 = active systemwide diff --git a/example_systems/2_three_zones_w_electrolyzer/settings/gurobi_settings.yml b/example_systems/2_three_zones_w_electrolyzer/settings/gurobi_settings.yml index 0aa53a56d3..2ee76a163d 100644 --- a/example_systems/2_three_zones_w_electrolyzer/settings/gurobi_settings.yml +++ b/example_systems/2_three_zones_w_electrolyzer/settings/gurobi_settings.yml @@ -10,6 +10,6 @@ Method: 2 # Algorithm used to solve continuous models (includin MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-08 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: 0 # Barrier crossver strategy. +Crossover: 0 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. diff --git a/example_systems/3_three_zones_w_co2_capture/settings/genx_settings.yml b/example_systems/3_three_zones_w_co2_capture/settings/genx_settings.yml index 27f3eef52f..e7b61221d6 100644 --- a/example_systems/3_three_zones_w_co2_capture/settings/genx_settings.yml +++ b/example_systems/3_three_zones_w_co2_capture/settings/genx_settings.yml @@ -1,4 +1,4 @@ -NetworkExpansion: 1 # Transmission network expansionl; 0 = not active; 1 = active systemwide +NetworkExpansion: 1 # Transmission network expansion; 0 = not active; 1 = active systemwide Trans_Loss_Segments: 1 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic EnergyShareRequirement: 0 # Minimum qualifying renewables penetration; 0 = not active; 1 = active systemwide CapacityReserveMargin: 0 # Number of capacity reserve margin constraints; 0 = not active; 1 = active systemwide @@ -8,6 +8,6 @@ MinCapReq: 1 # Activate minimum technology carveout constraints; 0 = not active MaxCapReq: 0 # Activate maximum technology carveout constraints; 0 = not active; 1 = active ParameterScale: 1 # Turn on parameter scaling wherein demand, capacity and power variables are defined in GW rather than MW. 0 = not active; 1 = active systemwide WriteShadowPrices: 1 # Write shadow prices of LP or relaxed MILP; 0 = not active; 1 = active -UCommit: 2 # Unit committment of thermal power plants; 0 = not active; 1 = active using integer clestering; 2 = active using linearized clustering +UCommit: 2 # Unit commitment of thermal power plants; 0 = not active; 1 = active using integer clustering; 2 = active using linearized clustering TimeDomainReduction: 1 # Time domain reduce (i.e. cluster) inputs based on Demand_data.csv, Generators_variability.csv, and Fuels_data.csv; 0 = not active (use input data as provided); 0 = active (cluster input data, or use data that has already been clustered) LDSAdditionalConstraints: 1 # Activate additional constraints to prevent violation of SoC limits in non-representative periods; 0 = not active; 1 = active \ No newline at end of file diff --git a/example_systems/3_three_zones_w_co2_capture/settings/gurobi_settings.yml b/example_systems/3_three_zones_w_co2_capture/settings/gurobi_settings.yml index fd4d9b8a83..e338be4afc 100644 --- a/example_systems/3_three_zones_w_co2_capture/settings/gurobi_settings.yml +++ b/example_systems/3_three_zones_w_co2_capture/settings/gurobi_settings.yml @@ -10,6 +10,6 @@ Method: 4 # Algorithm used to solve continuous models (inclu MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-08 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: -1 # Barrier crossver strategy. +Crossover: -1 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. diff --git a/example_systems/4_three_zones_w_policies_slack/settings/genx_settings.yml b/example_systems/4_three_zones_w_policies_slack/settings/genx_settings.yml index 2aeabd9a67..4f2f9eac8c 100644 --- a/example_systems/4_three_zones_w_policies_slack/settings/genx_settings.yml +++ b/example_systems/4_three_zones_w_policies_slack/settings/genx_settings.yml @@ -1,4 +1,4 @@ -NetworkExpansion: 1 # Transmission network expansionl; 0 = not active; 1 = active systemwide +NetworkExpansion: 1 # Transmission network expansion; 0 = not active; 1 = active systemwide Trans_Loss_Segments: 1 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic EnergyShareRequirement: 1 # Minimum qualifying renewables penetration; 0 = not active; 1 = active systemwide CapacityReserveMargin: 1 # Number of capacity reserve margin constraints; 0 = not active; 1 = active systemwide @@ -8,5 +8,5 @@ MinCapReq: 1 # Activate minimum technology carveout constraints; 0 = not active MaxCapReq: 1 # Activate maximum technology carveout constraints; 0 = not active; 1 = active ParameterScale: 1 # Turn on parameter scaling wherein demand, capacity and power variables are defined in GW rather than MW. 0 = not active; 1 = active systemwide WriteShadowPrices: 1 # Write shadow prices of LP or relaxed MILP; 0 = not active; 1 = active -UCommit: 2 # Unit committment of thermal power plants; 0 = not active; 1 = active using integer clestering; 2 = active using linearized clustering +UCommit: 2 # Unit commitment of thermal power plants; 0 = not active; 1 = active using integer clustering; 2 = active using linearized clustering TimeDomainReduction: 1 # Time domain reduce (i.e. cluster) inputs based on Demand_data.csv, Generators_variability.csv, and Fuels_data.csv; 0 = not active (use input data as provided); 0 = active (cluster input data, or use data that has already been clustered) diff --git a/example_systems/4_three_zones_w_policies_slack/settings/gurobi_settings.yml b/example_systems/4_three_zones_w_policies_slack/settings/gurobi_settings.yml index fd4d9b8a83..e338be4afc 100644 --- a/example_systems/4_three_zones_w_policies_slack/settings/gurobi_settings.yml +++ b/example_systems/4_three_zones_w_policies_slack/settings/gurobi_settings.yml @@ -10,6 +10,6 @@ Method: 4 # Algorithm used to solve continuous models (inclu MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-08 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: -1 # Barrier crossver strategy. +Crossover: -1 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. diff --git a/example_systems/5_three_zones_w_piecewise_fuel/README.md b/example_systems/5_three_zones_w_piecewise_fuel/README.md index c84543c957..b2c363b9d6 100644 --- a/example_systems/5_three_zones_w_piecewise_fuel/README.md +++ b/example_systems/5_three_zones_w_piecewise_fuel/README.md @@ -1,7 +1,7 @@ # Small New England: Three Zones with piecewise fuel consumption This is a one-year example with hourly resolution which contains zones representing Massachusetts, Connecticut, and Maine. The ten represented resources include natural gas, solar PV, wind, and lithium-ion battery storage and biomass with carbon capture and storage. -For natural gas ccs generator, we provide picewise fuel usage (PWFU) parameters to represent the fuel consumption at differernt load point. Please refer to the documentation for more details on PWFU parameters and corresponding data requirements. When settings["UCommit"] >= 1 and PWFU parameters are provided in `Thermal.csv`, the standard heat rate (i.e., Heat_Rate_MMBTU_per_MWh) will not be used. Instead, the heat rate will be calculated based on the PWFU parameters. +For natural gas ccs generator, we provide piecewise fuel usage (PWFU) parameters to represent the fuel consumption at different load point. Please refer to the documentation for more details on PWFU parameters and corresponding data requirements. When settings["UCommit"] >= 1 and PWFU parameters are provided in `Thermal.csv`, the standard heat rate (i.e., Heat_Rate_MMBTU_per_MWh) will not be used. Instead, the heat rate will be calculated based on the PWFU parameters. To run the model, first navigate to the example directory: diff --git a/example_systems/5_three_zones_w_piecewise_fuel/settings/genx_settings.yml b/example_systems/5_three_zones_w_piecewise_fuel/settings/genx_settings.yml index fdd18b2300..1cb9ec4862 100644 --- a/example_systems/5_three_zones_w_piecewise_fuel/settings/genx_settings.yml +++ b/example_systems/5_three_zones_w_piecewise_fuel/settings/genx_settings.yml @@ -1,4 +1,4 @@ -NetworkExpansion: 1 # Transmission network expansionl; 0 = not active; 1 = active systemwide +NetworkExpansion: 1 # Transmission network expansion; 0 = not active; 1 = active systemwide Trans_Loss_Segments: 1 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic EnergyShareRequirement: 0 # Minimum qualifying renewables penetration; 0 = not active; 1 = active systemwide CapacityReserveMargin: 0 # Number of capacity reserve margin constraints; 0 = not active; 1 = active systemwide @@ -9,5 +9,5 @@ MinCapReq: 1 # Activate minimum technology carveout constraints; 0 = not active MaxCapReq: 0 # Activate maximum technology carveout constraints; 0 = not active; 1 = active ParameterScale: 1 # Turn on parameter scaling wherein demand, capacity and power variables are defined in GW rather than MW. 0 = not active; 1 = active systemwide WriteShadowPrices: 1 # Write shadow prices of LP or relaxed MILP; 0 = not active; 1 = active -UCommit: 2 # Unit committment of thermal power plants; 0 = not active; 1 = active using integer clestering; 2 = active using linearized clustering +UCommit: 2 # Unit commitment of thermal power plants; 0 = not active; 1 = active using integer clustering; 2 = active using linearized clustering TimeDomainReduction: 1 # Time domain reduce (i.e. cluster) inputs based on Demand_data.csv, Generators_variability.csv, and Fuels_data.csv; 0 = not active (use input data as provided); 0 = active (cluster input data, or use data that has already been clustered) diff --git a/example_systems/5_three_zones_w_piecewise_fuel/settings/gurobi_settings.yml b/example_systems/5_three_zones_w_piecewise_fuel/settings/gurobi_settings.yml index fd4d9b8a83..e338be4afc 100644 --- a/example_systems/5_three_zones_w_piecewise_fuel/settings/gurobi_settings.yml +++ b/example_systems/5_three_zones_w_piecewise_fuel/settings/gurobi_settings.yml @@ -10,6 +10,6 @@ Method: 4 # Algorithm used to solve continuous models (inclu MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-08 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: -1 # Barrier crossver strategy. +Crossover: -1 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. diff --git a/example_systems/6_three_zones_w_multistage/settings/genx_settings.yml b/example_systems/6_three_zones_w_multistage/settings/genx_settings.yml index e9599523c4..ac770a360e 100644 --- a/example_systems/6_three_zones_w_multistage/settings/genx_settings.yml +++ b/example_systems/6_three_zones_w_multistage/settings/genx_settings.yml @@ -1,4 +1,4 @@ -NetworkExpansion: 1 # Transmission network expansionl; 0 = not active; 1 = active systemwide +NetworkExpansion: 1 # Transmission network expansion; 0 = not active; 1 = active systemwide Trans_Loss_Segments: 1 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic EnergyShareRequirement: 0 # Minimum qualifying renewables penetration; 0 = not active; 1 = active systemwide CapacityReserveMargin: 0 # Number of capacity reserve margin constraints; 0 = not active; 1 = active systemwide @@ -7,6 +7,6 @@ StorageLosses: 1 # Energy Share Requirement and CO2 constraints account for ener MinCapReq: 0 # Activate minimum technology carveout constraints; 0 = not active; 1 = active MaxCapReq: 0 # Activate maximum technology carveout constraints; 0 = not active; 1 = active ParameterScale: 1 # Turn on parameter scaling wherein demand, capacity and power variables are defined in GW rather than MW. 0 = not active; 1 = active systemwide -UCommit: 2 # Unit committment of thermal power plants; 0 = not active; 1 = active using integer clestering; 2 = active using linearized clustering +UCommit: 2 # Unit commitment of thermal power plants; 0 = not active; 1 = active using integer clustering; 2 = active using linearized clustering TimeDomainReduction: 1 # Time domain reduce (i.e. cluster) inputs based on Demand_data.csv, Generators_variability.csv, and Fuels_data.csv; 0 = not active (use input data as provided); 0 = active (cluster input data, or use data that has already been clustered) MultiStage: 1 # 0 = Single-stage GenX, 1 = Multi-stage GenX diff --git a/example_systems/6_three_zones_w_multistage/settings/gurobi_settings.yml b/example_systems/6_three_zones_w_multistage/settings/gurobi_settings.yml index 6593f70370..fca3461a15 100644 --- a/example_systems/6_three_zones_w_multistage/settings/gurobi_settings.yml +++ b/example_systems/6_three_zones_w_multistage/settings/gurobi_settings.yml @@ -10,7 +10,7 @@ Method: 4 # Algorithm used to solve continuous models (inclu MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-08 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: -1 # Barrier crossver strategy. +Crossover: -1 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. OutputFlag: 0 # Controls Gurobi output.s diff --git a/example_systems/7_three_zones_w_colocated_VRE_storage/settings/gurobi_settings.yml b/example_systems/7_three_zones_w_colocated_VRE_storage/settings/gurobi_settings.yml index d1f8d45b21..f8f916377c 100644 --- a/example_systems/7_three_zones_w_colocated_VRE_storage/settings/gurobi_settings.yml +++ b/example_systems/7_three_zones_w_colocated_VRE_storage/settings/gurobi_settings.yml @@ -10,7 +10,7 @@ Method: 2 # Algorithm used to solve continuous models (inclu MIPGap: 1e-4 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-04 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: 0 # Barrier crossver strategy. +Crossover: 0 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. BarHomogeneous: 1 diff --git a/example_systems/8_three_zones_w_colocated_VRE_storage_electrolyzers/settings/genx_settings.yml b/example_systems/8_three_zones_w_colocated_VRE_storage_electrolyzers/settings/genx_settings.yml index c53bd4b62b..9c06988c7f 100644 --- a/example_systems/8_three_zones_w_colocated_VRE_storage_electrolyzers/settings/genx_settings.yml +++ b/example_systems/8_three_zones_w_colocated_VRE_storage_electrolyzers/settings/genx_settings.yml @@ -1,5 +1,5 @@ Trans_Loss_Segments: 1 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic -UCommit: 2 # Unit committment of thermal power plants; 0 = not active; 1 = active using integer clestering; 2 = active using linearized clustering +UCommit: 2 # Unit commitment of thermal power plants; 0 = not active; 1 = active using integer clustering; 2 = active using linearized clustering StorageLosses: 1 # Energy Share Requirement and CO2 constraints account for energy lost; 0 = not active (DO NOT account for energy lost); 1 = active systemwide (DO account for energy lost) HydrogenHourlyMatching: 0 # Hydrogen electrolyzer hourly supply matching required ParameterScale: 0 # Turn on parameter scaling wherein demand, capacity and power variables are defined in GW rather than MW. 0 = not active; 1 = active systemwide diff --git a/example_systems/8_three_zones_w_colocated_VRE_storage_electrolyzers/settings/gurobi_settings.yml b/example_systems/8_three_zones_w_colocated_VRE_storage_electrolyzers/settings/gurobi_settings.yml index 0aa53a56d3..2ee76a163d 100644 --- a/example_systems/8_three_zones_w_colocated_VRE_storage_electrolyzers/settings/gurobi_settings.yml +++ b/example_systems/8_three_zones_w_colocated_VRE_storage_electrolyzers/settings/gurobi_settings.yml @@ -10,6 +10,6 @@ Method: 2 # Algorithm used to solve continuous models (includin MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-08 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: 0 # Barrier crossver strategy. +Crossover: 0 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. diff --git a/example_systems/9_three_zones_w_retrofit/settings/genx_settings.yml b/example_systems/9_three_zones_w_retrofit/settings/genx_settings.yml index 96854d0222..f581992115 100644 --- a/example_systems/9_three_zones_w_retrofit/settings/genx_settings.yml +++ b/example_systems/9_three_zones_w_retrofit/settings/genx_settings.yml @@ -1,4 +1,4 @@ -NetworkExpansion: 1 # Transmission network expansionl; 0 = not active; 1 = active systemwide +NetworkExpansion: 1 # Transmission network expansion; 0 = not active; 1 = active systemwide Trans_Loss_Segments: 1 # Number of segments used in piecewise linear approximation of transmission losses; 1 = linear, >2 = piecewise quadratic EnergyShareRequirement: 0 # Minimum qualifying renewables penetration; 0 = not active; 1 = active systemwide CapacityReserveMargin: 0 # Number of capacity reserve margin constraints; 0 = not active; 1 = active systemwide @@ -8,5 +8,5 @@ MinCapReq: 1 # Activate minimum technology carveout constraints; 0 = not active MaxCapReq: 0 # Activate maximum technology carveout constraints; 0 = not active; 1 = active ParameterScale: 1 # Turn on parameter scaling wherein demand, capacity and power variables are defined in GW rather than MW. 0 = not active; 1 = active systemwide WriteShadowPrices: 1 # Write shadow prices of LP or relaxed MILP; 0 = not active; 1 = active -UCommit: 2 # Unit committment of thermal power plants; 0 = not active; 1 = active using integer clestering; 2 = active using linearized clustering +UCommit: 2 # Unit commitment of thermal power plants; 0 = not active; 1 = active using integer clustering; 2 = active using linearized clustering TimeDomainReduction: 1 # Time domain reduce (i.e. cluster) inputs based on Demand_data.csv, Generators_variability.csv, and Fuels_data.csv; 0 = not active (use input data as provided); 0 = active (cluster input data, or use data that has already been clustered) \ No newline at end of file diff --git a/example_systems/9_three_zones_w_retrofit/settings/gurobi_settings.yml b/example_systems/9_three_zones_w_retrofit/settings/gurobi_settings.yml index fd4d9b8a83..e338be4afc 100644 --- a/example_systems/9_three_zones_w_retrofit/settings/gurobi_settings.yml +++ b/example_systems/9_three_zones_w_retrofit/settings/gurobi_settings.yml @@ -10,6 +10,6 @@ Method: 4 # Algorithm used to solve continuous models (inclu MIPGap: 1e-3 # Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). BarConvTol: 1.0e-08 # Barrier convergence tolerance (determines when barrier terminates). NumericFocus: 0 # Numerical precision emphasis. -Crossover: -1 # Barrier crossver strategy. +Crossover: -1 # Barrier crossover strategy. PreDual: 0 # Decides whether presolve should pass the primal or dual linear programming problem to the LP optimization algorithm. AggFill: 10 # Allowed fill during presolve aggregation. diff --git a/src/additional_tools/method_of_morris.jl b/src/additional_tools/method_of_morris.jl index ed5cd5ddfa..b05a3f9ea3 100644 --- a/src/additional_tools/method_of_morris.jl +++ b/src/additional_tools/method_of_morris.jl @@ -256,7 +256,7 @@ function morris(EP::Model, random) println(m.means) println(DataFrame(m.means', :auto)) - #save the mean effect of each uncertain variable on the objective fucntion + #save the mean effect of each uncertain variable on the objective function Morris_range[!, :mean] = DataFrame(m.means', :auto)[!, :x1] println(DataFrame(m.variances', :auto)) #save the variance of effect of each uncertain variable on the objective function diff --git a/src/additional_tools/modeling_to_generate_alternatives.jl b/src/additional_tools/modeling_to_generate_alternatives.jl index 0fe990c7be..55a69b6566 100644 --- a/src/additional_tools/modeling_to_generate_alternatives.jl +++ b/src/additional_tools/modeling_to_generate_alternatives.jl @@ -16,7 +16,7 @@ To create the MGA formulation, we replace the cost-minimizing objective function \end{aligned} ``` -where, $\beta_{z,r}$ is a random objective function coefficient betwen $[0,1]$ for MGA iteration $k$. We aggregate capacity into a new variable $P_{z,r}$ that represents total capacity from technology type $r$ in a zone $z$. +where, $\beta_{z,r}$ is a random objective function coefficient between $[0,1]$ for MGA iteration $k$. We aggregate capacity into a new variable $P_{z,r}$ that represents total capacity from technology type $r$ in a zone $z$. If the users set `MGAAnnualGeneration = 1` in the genx_settings.yml file, the MGA formulation is given as: ```math @@ -29,7 +29,7 @@ If the users set `MGAAnnualGeneration = 1` in the genx_settings.yml file, the MG &Ax = b \end{aligned} ``` -where, $\beta_{z,r}$ is a random objective function coefficient betwen $[0,1]$ for MGA iteration $k$. $\Theta_{y,t,z,r}$ is a generation of technology $y$ in zone $z$ in time period $t$ that belongs to a resource type $r$. We aggregate $\Theta_{y,t,z,r}$ into a new variable $P_{z,r}$ that represents total generation from technology type $r$ in a zone $z$. +where, $\beta_{z,r}$ is a random objective function coefficient between $[0,1]$ for MGA iteration $k$. $\Theta_{y,t,z,r}$ is a generation of technology $y$ in zone $z$ in time period $t$ that belongs to a resource type $r$. We aggregate $\Theta_{y,t,z,r}$ into a new variable $P_{z,r}$ that represents total generation from technology type $r$ in a zone $z$. In the second constraint in both the above formulations, $\delta$ denote the increase in budget from the least-cost solution and $f$ represents the expression for the total system cost. The constraint $Ax = b$ represents all other constraints in the power system model. We then solve the formulation with minimization and maximization objective function to explore near optimal solution space. """ diff --git a/src/case_runners/case_runner.jl b/src/case_runners/case_runner.jl index afea227f29..b7cdf4cfdd 100644 --- a/src/case_runners/case_runner.jl +++ b/src/case_runners/case_runner.jl @@ -180,7 +180,7 @@ function run_genx_case_multistage!(case::AbstractString, mysetup::Dict, optimize mkdir(outpath) end else - # Find closest unused ouput directory name and create it + # Find closest unused output directory name and create it outpath = choose_output_dir(outpath) mkdir(outpath) end diff --git a/src/configure_solver/configure_gurobi.jl b/src/configure_solver/configure_gurobi.jl index 00f132f34f..a235a02e27 100644 --- a/src/configure_solver/configure_gurobi.jl +++ b/src/configure_solver/configure_gurobi.jl @@ -14,7 +14,7 @@ The Gurobi optimizer instance is configured with the following default parameter - PreDual = -1 (Presolve dualization. See https://www.gurobi.com/documentation/8.1/refman/predual.html#parameter:PreDual) - TimeLimit = Inf (Limits total time solver. See https://www.gurobi.com/documentation/8.1/refman/timelimit.html) - MIPGap = 1e-4 (Relative (p.u. of optimal) mixed integer optimality tolerance for MIP problems (ignored otherwise). See https://www.gurobi.com/documentation/8.1/refman/mipgap2.html) - - Crossover = -1 (Barrier crossver strategy. See https://www.gurobi.com/documentation/8.1/refman/crossover.html#parameter:Crossover) + - Crossover = -1 (Barrier crossover strategy. See https://www.gurobi.com/documentation/8.1/refman/crossover.html#parameter:Crossover) - Method = -1 (Algorithm used to solve continuous models (including MIP root relaxation). See https://www.gurobi.com/documentation/8.1/refman/method.html) - BarConvTol = 1e-8 (Barrier convergence tolerance (determines when barrier terminates). See https://www.gurobi.com/documentation/8.1/refman/barconvtol.html) - NumericFocus = 0 (Numerical precision emphasis. See https://www.gurobi.com/documentation/8.1/refman/numericfocus.html) diff --git a/src/load_inputs/load_demand_data.jl b/src/load_inputs/load_demand_data.jl index 52c5bd7bf2..67e7336e11 100644 --- a/src/load_inputs/load_demand_data.jl +++ b/src/load_inputs/load_demand_data.jl @@ -64,7 +64,7 @@ function load_demand_data!(setup::Dict, path::AbstractString, inputs::Dict) end end - # Create time set steps indicies + # Create time set steps indices inputs["hours_per_subperiod"] = div.(T, inputs["REP_PERIOD"]) # total number of hours per subperiod hours_per_subperiod = inputs["hours_per_subperiod"] # set value for internal use diff --git a/src/load_inputs/load_fuels_data.jl b/src/load_inputs/load_fuels_data.jl index 61b0ff2f0f..cd935fc6ae 100644 --- a/src/load_inputs/load_fuels_data.jl +++ b/src/load_inputs/load_fuels_data.jl @@ -27,7 +27,7 @@ function load_fuels_data!(setup::Dict, path::AbstractString, inputs::Dict) scale_factor = setup["ParameterScale"] == 1 ? ModelScalingFactor : 1 for i in 1:length(fuels) - # fuel cost is in $/MMBTU w/o scaling, $/Billon BTU w/ scaling + # fuel cost is in $/MMBTU w/o scaling, $/Billion BTU w/ scaling fuel_costs[fuels[i]] = costs[:, i] / scale_factor # No need to scale fuel_CO2, fuel_CO2 is ton/MMBTU or kton/Billion BTU fuel_CO2[fuels[i]] = CO2_content[i] diff --git a/src/load_inputs/load_inputs.jl b/src/load_inputs/load_inputs.jl index aa1ee28a0e..f91f90acd4 100644 --- a/src/load_inputs/load_inputs.jl +++ b/src/load_inputs/load_inputs.jl @@ -70,7 +70,7 @@ function load_inputs(setup::Dict, path::AbstractString) load_vre_stor_variability!(setup, path, inputs) end - # Read in hydrogen damand data + # Read in hydrogen demand data if setup["HydrogenMinimumProduction"] == 1 load_hydrogen_demand!(setup, policies_path, inputs) end diff --git a/src/load_inputs/load_network_data.jl b/src/load_inputs/load_network_data.jl index ac7f2b1c8c..2907c9e787 100644 --- a/src/load_inputs/load_network_data.jl +++ b/src/load_inputs/load_network_data.jl @@ -38,7 +38,7 @@ function load_network_data!(setup::Dict, path::AbstractString, inputs_nw::Dict) ## Inputs for the DC-OPF if setup["DC_OPF"] == 1 if setup["NetworkExpansion"] == 1 - @warn("Because the DC_OPF flag is active, GenX will not allow any transmission capacity expansion. Set the DC_OPF flag to 0 if you want to optimize tranmission capacity expansion.") + @warn("Because the DC_OPF flag is active, GenX will not allow any transmission capacity expansion. Set the DC_OPF flag to 0 if you want to optimize transmission capacity expansion.") setup["NetworkExpansion"] = 0 end println("Reading DC-OPF values...") diff --git a/src/load_inputs/load_resources_data.jl b/src/load_inputs/load_resources_data.jl index 22d52f9258..66c1d793af 100644 --- a/src/load_inputs/load_resources_data.jl +++ b/src/load_inputs/load_resources_data.jl @@ -687,7 +687,7 @@ Validate the policy files by checking if they exist in the specified folder and - `setup::Dict`: Dictionary containing GenX settings. # Returns -- warning messages if the polcies are set to 1 in settings but the files are not found in the resource_policies_path. +- warning messages if the polices are set to 1 in settings but the files are not found in the resource_policies_path. !isfile(joinpath(resource_policies_path, filename)) """ function validate_policy_files(resource_policies_path::AbstractString, setup::Dict) @@ -897,7 +897,7 @@ end function validate_piecewisefuelusage(heat_rate_mat, load_point_mat) # it's possible to construct piecewise fuel consumption with n of heat rate and n-1 of load point. # if a user feed n of heat rate and more than n of load point, throw a error message, and then use - # n of heat rate and n-1 load point to construct the piecewise fuel usage fuction + # n of heat rate and n-1 load point to construct the piecewise fuel usage function if size(heat_rate_mat)[2] < size(load_point_mat)[2] @error """ The numbers of heatrate data are less than load points, we found $(size(heat_rate_mat)[2]) of heat rate, and $(size(load_point_mat)[2]) of load points. We will just use $(size(heat_rate_mat)[2]) of heat rate, and $(size(heat_rate_mat)[2]-1) @@ -966,7 +966,7 @@ function process_piecewisefuelusage!(setup::Dict, nonzero_rows = any(heat_rate_mat .!= 0, dims = 2)[:] HAS_PWFU = resource_id.(gen[nonzero_rows]) - # translate the inital fuel usage, heat rate, and load points into intercept for each segment + # translate the initial fuel usage, heat rate, and load points into intercept for each segment fuel_usage_zero_load = zeros(length(gen)) fuel_usage_zero_load[THERM] = pwfu_fuel_usage_zero_load_mmbtu_per_h.(thermal_gen) # construct a matrix for intercept @@ -1152,12 +1152,12 @@ function add_resources_to_input_data!(inputs::Dict, ## STORAGE # Set of storage resources with symmetric charge/discharge capacity inputs["STOR_SYMMETRIC"] = symmetric_storage(gen) - # Set of storage resources with asymmetric (separte) charge/discharge capacity components + # Set of storage resources with asymmetric (separate) charge/discharge capacity components inputs["STOR_ASYMMETRIC"] = asymmetric_storage(gen) # Set of all storage resources inputs["STOR_ALL"] = union(inputs["STOR_SYMMETRIC"], inputs["STOR_ASYMMETRIC"]) - # Set of storage resources with long duration storage capabilitites + # Set of storage resources with long duration storage capabilities inputs["STOR_HYDRO_LONG_DURATION"] = intersect(inputs["HYDRO_RES"], is_LDS(gen)) inputs["STOR_HYDRO_SHORT_DURATION"] = intersect(inputs["HYDRO_RES"], is_SDS(gen)) inputs["STOR_LONG_DURATION"] = intersect(inputs["STOR_ALL"], is_LDS(gen)) @@ -1176,7 +1176,7 @@ function add_resources_to_input_data!(inputs::Dict, inputs["MUST_RUN"] = must_run(gen) ## ELECTROLYZER - # Set of hydrogen electolyzer resources: + # Set of hydrogen electrolyzer resources: inputs["ELECTROLYZER"] = electrolyzer(gen) ## Operational Reserves @@ -1210,7 +1210,7 @@ function add_resources_to_input_data!(inputs::Dict, # Set of thermal resources without unit commitment inputs["THERM_NO_COMMIT"] = inputs["THERM_ALL"] end - # For now, the only resources eligible for UC are themal resources + # For now, the only resources eligible for UC are thermal resources inputs["COMMIT"] = inputs["THERM_COMMIT"] # Set of CCS resources (optional set): diff --git a/src/model/core/co2.jl b/src/model/core/co2.jl index 64e05e2714..bb2268bcaf 100644 --- a/src/model/core/co2.jl +++ b/src/model/core/co2.jl @@ -20,7 +20,7 @@ The CO2 emissions from such a generator will be assumed to be zero without CCS a The CO2 emissions from generator $y$ at time $t$ are determined by total fuel consumption (MMBTU) multiplied by the CO2 content of the fuel (tCO2/MMBTU), and by (1 - Biomass [0 or 1] - CO2 capture fraction [a fraction, between 0 - 1]). -The CO2 capture fraction could be differernt during the steady-state and startup events +The CO2 capture fraction could be different during the steady-state and startup events (generally startup events have a lower CO2 capture fraction), so we use distinct CO2 capture fractions to determine the emissions. In short, the CO2 emissions for a generator depend on the CO2 emission factor from fuel combustion, @@ -83,8 +83,8 @@ function co2!(EP::Model, inputs::Dict) end) else @info "Using the CO2 module to determine the CO2 emissions of CCS-equipped plants" - # CO2_Capture_Fraction refers to the CO2 capture rate of CCS equiped power plants at a steady state - # CO2_Capture_Fraction_Startup refers to the CO2 capture rate of CCS equiped power plants during startup events + # CO2_Capture_Fraction refers to the CO2 capture rate of CCS equipped power plants at a steady state + # CO2_Capture_Fraction_Startup refers to the CO2 capture rate of CCS equipped power plants during startup events @expression(EP, eEmissionsByPlant[y = 1:G, t = 1:T], if y in SINGLE_FUEL diff --git a/src/model/core/discharge/investment_discharge.jl b/src/model/core/discharge/investment_discharge.jl index e0b07120b1..3aa28f5948 100755 --- a/src/model/core/discharge/investment_discharge.jl +++ b/src/model/core/discharge/investment_discharge.jl @@ -111,7 +111,7 @@ function investment_discharge!(EP::Model, inputs::Dict, setup::Dict) eExistingCap[y] end) - ### Need editting ## + ### Need editing ## @expression(EP, eCFix[y in 1:G], if y in NEW_CAP # Resources eligible for new capacity (Non-Retrofit) if y in COMMIT @@ -137,7 +137,7 @@ function investment_discharge!(EP::Model, inputs::Dict, setup::Dict) add_to_expression!(EP[:eObj], eTotalCFix) end - ### Constratints ### + ### Constraints ### if MultiStage == 1 # Existing capacity variable is equal to existing capacity specified in the input file @@ -163,12 +163,12 @@ function investment_discharge!(EP::Model, inputs::Dict, setup::Dict) ## Constraints on new built capacity # Constraint on maximum capacity (if applicable) [set input to -1 if no constraint on maximum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasibility MAX_CAP = ids_with_positive(gen, max_cap_mw) @constraint(EP, cMaxCap[y in MAX_CAP], eTotalCap[y]<=max_cap_mw(gen[y])) # Constraint on minimum capacity (if applicable) [set input to -1 if no constraint on minimum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasibility MIN_CAP = ids_with_positive(gen, min_cap_mw) @constraint(EP, cMinCap[y in MIN_CAP], eTotalCap[y]>=min_cap_mw(gen[y])) diff --git a/src/model/core/fuel.jl b/src/model/core/fuel.jl index cc80e2c6c3..a0d7632ee9 100644 --- a/src/model/core/fuel.jl +++ b/src/model/core/fuel.jl @@ -17,7 +17,7 @@ the fact that most generators have a decreasing heat rate as a function of load. (1). Constant heat rate: The fuel consumption for power generation $vFuel_{y,t}$ is determined by power generation -($vP_{y,t}$) mutiplied by the corresponding heat rate ($Heat\_Rate_y$). +($vP_{y,t}$) multiplied by the corresponding heat rate ($Heat\_Rate_y$). The fuel costs for power generation and start fuel for a plant $y$ at time $t$, denoted by $eCFuelOut_{y,t}$ and $eFuelStart$, are determined by fuel consumption ($vFuel_{y,t}$ and $eStartFuel$) multiplied by the fuel costs (\$/MMBTU) @@ -45,7 +45,7 @@ For example, when a plant is operating at the full load (i.e., power output equa the fuel usage determined by the effective segment divided by Cap\_Size should be equal to the heat rate at full-load. -Since fuel consumption and fuel costs are postive, the optimization will force the fuel usage +Since fuel consumption and fuel costs are positive, the optimization will force the fuel usage to be equal to the highest fuel usage segment for any given value of vP. When the power output is zero, the commitment variable $U_{g,t}$ will bring the intercept to be zero such that the fuel consumption is zero when thermal units are offline. @@ -67,7 +67,7 @@ During startup, heat input from multiple startup fuels are equal to startup fuel \sum_{i \in \mathcal{I} } vMulStartFuels_{y, i, t}= CapSize_{y} \times StartFuelMMBTUperMW_{y} \times vSTART_{y,t} \end{aligned} ``` -During normal operation, the sum of fuel consumptions from multiple fuels dividing by the correspnding heat rates, respectively, is equal to $vPower$ in plant $y$ at time $t$. +During normal operation, the sum of fuel consumptions from multiple fuels dividing by the corresponding heat rates, respectively, is equal to $vPower$ in plant $y$ at time $t$. ```math \begin{aligned} \sum_{i \in \mathcal{I} } \frac{vMulFuels_{y, i, t}} {HeatRate_{i,y} } = vPower_{y,t} @@ -281,7 +281,7 @@ function fuel!(EP::Model, inputs::Dict, setup::Dict) if !isempty(THERM_COMMIT) # Only apply piecewise fuel consumption to thermal generators in THERM_COMMIT_PWFU set THERM_COMMIT_PWFU = inputs["THERM_COMMIT_PWFU"] - # segemnt for piecewise fuel usage + # segment for piecewise fuel usage if !isempty(THERM_COMMIT_PWFU) segs = 1:inputs["PWFU_Num_Segments"] PWFU_data = inputs["PWFU_data"] diff --git a/src/model/core/non_served_energy.jl b/src/model/core/non_served_energy.jl index 458ac6348a..64667a6144 100644 --- a/src/model/core/non_served_energy.jl +++ b/src/model/core/non_served_energy.jl @@ -98,7 +98,7 @@ function non_served_energy!(EP::Model, inputs::Dict, setup::Dict) end end - ### Constratints ### + ### Constraints ### # Demand curtailed in each segment of curtailable demands cannot exceed maximum allowable share of demand @constraint(EP, diff --git a/src/model/core/operational_reserves.jl b/src/model/core/operational_reserves.jl index 1790db3bb1..77118edee5 100644 --- a/src/model/core/operational_reserves.jl +++ b/src/model/core/operational_reserves.jl @@ -31,7 +31,7 @@ There are three options for the $Contingency$ expression, depending on user sett 2. a dynamic contingency based on installed capacity decisions, in which the largest 'installed' generator is used to determine the contingency requirement for all time periods; and 3. dynamic unit commitment based contingency, in which the largest 'committed' generator in any time period is used to determine the contingency requirement in that time period. -Note that the two dynamic contigencies are only available if unit commitment is being modeled. +Note that the two dynamic contingencies are only available if unit commitment is being modeled. **Static contingency** Option 1 (static contingency) is expressed by the following constraint: @@ -104,8 +104,8 @@ function operational_reserves_contingency!(EP::Model, inputs::Dict, setup::Dict) println("Dynamic Contingency Type 2: Modeling the largest contingency as the largest largest committed generator") @expression(EP, eContingencyReq[t = 1:T], vLARGEST_CONTINGENCY[t]) else - # Largest contingency defined fixed as user-specifed static contingency in MW - println("Static Contingency: Modeling the largest contingency as user-specifed static contingency") + # Largest contingency defined fixed as user-specified static contingency in MW + println("Static Contingency: Modeling the largest contingency as user-specified static contingency") @expression(EP, eContingencyReq[t = 1:T], inputs["pStatic_Contingency"]) end @@ -124,7 +124,7 @@ function operational_reserves_contingency!(EP::Model, inputs::Dict, setup::Dict) cContAux2[y in COMMIT], EP[:eTotalCap][y]<=inputs["pContingency_BigM"][y] * vCONTINGENCY_AUX[y]) - # option 2: ensures vLARGEST_CONTINGENCY is greater than the capacity of the largest commited generator in each hour + # option 2: ensures vLARGEST_CONTINGENCY is greater than the capacity of the largest committed generator in each hour elseif UCommit == 1 && pDynamic_Contingency == 2 @constraint(EP, cContingency[y in COMMIT, t = 1:T], @@ -170,7 +170,7 @@ There is a penalty $C^{rsv}$ added to the objective function to penalize reserve **Frequency regulation requirements** -Total requirements for frequency regulation (aka primary reserves) in each time step $t$ are specified as fractions of hourly demand (to reflect demand forecast errors) and variable renewable avaialblity in the time step (to reflect wind and solar forecast errors). +Total requirements for frequency regulation (aka primary reserves) in each time step $t$ are specified as fractions of hourly demand (to reflect demand forecast errors) and variable renewable availability in the time step (to reflect wind and solar forecast errors). ```math \begin{aligned} @@ -188,7 +188,7 @@ and $\epsilon^{demand}_{reg}$ and $\epsilon^{vre}_{reg}$ are parameters specifyi **Operating reserve requirements** -Total requirements for operating reserves in the upward direction (aka spinning reserves or contingency reserces or secondary reserves) in each time step $t$ are specified as fractions of time step's demand (to reflect demand forecast errors) and variable renewable avaialblity in the time step (to reflect wind and solar forecast errors) plus the largest planning contingency (e.g. potential forced generation outage). +Total requirements for operating reserves in the upward direction (aka spinning reserves or contingency reserves or secondary reserves) in each time step $t$ are specified as fractions of time step's demand (to reflect demand forecast errors) and variable renewable availability in the time step (to reflect wind and solar forecast errors) plus the largest planning contingency (e.g. potential forced generation outage). ```math \begin{aligned} diff --git a/src/model/core/transmission/dcopf_transmission.jl b/src/model/core/transmission/dcopf_transmission.jl index ab2537ca01..3995a9e00d 100644 --- a/src/model/core/transmission/dcopf_transmission.jl +++ b/src/model/core/transmission/dcopf_transmission.jl @@ -1,6 +1,6 @@ @doc raw""" dcopf_transmission!(EP::Model, inputs::Dict, setup::Dict) -The addtional constraints imposed upon the line flows in the case of DC-OPF are as follows: +The additional constraints imposed upon the line flows in the case of DC-OPF are as follows: For the definition of the line flows, in terms of the voltage phase angles: ```math \begin{aligned} diff --git a/src/model/core/transmission/investment_transmission.jl b/src/model/core/transmission/investment_transmission.jl index f80b898e9a..5d6b2bf790 100644 --- a/src/model/core/transmission/investment_transmission.jl +++ b/src/model/core/transmission/investment_transmission.jl @@ -14,7 +14,7 @@ Available transmission capacity between zones is set equal to the existing line' ```math \begin{aligned} &\varphi^{cap}_{l} = \overline{\varphi^{cap}_{l}} , &\quad \forall l \in (\mathcal{L} \setminus \mathcal{E} ),\forall t \in \mathcal{T}\\ - % trasmission expansion + % transmission expansion &\varphi^{cap}_{l} = \overline{\varphi^{cap}_{l}} + \bigtriangleup\varphi^{cap}_{l} , &\quad \forall l \in \mathcal{E},\forall t \in \mathcal{T} \end{aligned} ``` @@ -57,7 +57,7 @@ function investment_transmission!(EP::Model, inputs::Dict, setup::Dict) end ## Transmission power flow and loss related expressions: - # Total availabile maximum transmission capacity is the sum of existing maximum transmission capacity plus new transmission capacity + # Total available maximum transmission capacity is the sum of existing maximum transmission capacity plus new transmission capacity if NetworkExpansion == 1 @expression(EP, eAvail_Trans_Cap[l = 1:L], if l in EXPANSION_LINES @@ -110,6 +110,6 @@ function investment_transmission!(EP::Model, inputs::Dict, setup::Dict) cMaxLineReinforcement[l in EXPANSION_LINES], vNEW_TRANS_CAP[l]<=inputs["pMax_Line_Reinforcement"][l]) end - #END network expansion contraints + #END network expansion constraints end diff --git a/src/model/core/transmission/transmission.jl b/src/model/core/transmission/transmission.jl index 4020c8ea2e..4b6290b963 100644 --- a/src/model/core/transmission/transmission.jl +++ b/src/model/core/transmission/transmission.jl @@ -13,7 +13,7 @@ Power flows, $\Phi_{l,t}$, on each line $l$ into or out of a zone (defined by th Power flow, $\Phi_{l,t}$, on each line (or more likely a `path' aggregating flows across multiple parallel lines) is constrained to be less than or equal to the line's power transfer capacity, $\varphi^{cap}_{l}$, plus any transmission capacity added on that line (for lines eligible for expansion in the set $\mathcal{E}$). The additional transmission capacity, $\bigtriangleup\varphi^{cap}_{l} $, is constrained by a maximum allowed reinforcement, $\overline{\bigtriangleup\varphi^{cap}_{l}}$, for each line $l \in \mathcal{E}$. ```math \begin{aligned} - % trasmission constraints + % transmission constraints &-\varphi^{cap}_{l} \leq \Phi_{l,t} \leq \varphi^{cap}_{l} , &\quad \forall l \in \mathcal{L},\forall t \in \mathcal{T}\\ \end{aligned} ``` @@ -28,7 +28,7 @@ Transmission losses due to power flows can be accounted for in three different w For the second option, an absolute value approximation is utilized to calculate the magnitude of the power flow on each line (reflecting the fact that negative power flows for a line linking nodes $i$ and $j$ represents flows from node $j$ to $i$ and causes the same magnitude of losses as an equal power flow from $i$ to $j$). This absolute value function is linearized such that the flow in the line must be equal to the subtraction of the auxiliary variable for flow in the positive direction, $\Phi^{+}_{l,t}$, and the auxiliary variable for flow in the negative direction, $\Phi^{-}_{l,t}$, of the line. Then, the magnitude of the flow is calculated as the sum of the two auxiliary variables. The sum of positive and negative directional flows are also constrained by the line flow capacity. ```math \begin{aligned} -% trasmission losses simple +% transmission losses simple &\Phi_{l,t} = \Phi^{+}_{l,t} - \Phi^{-}_{l,t}, &\quad \forall l \in \mathcal{L}, \forall t \in \mathcal{T}\\ &\mid \Phi_{l,t} \mid = \Phi^{+}_{l,t} + \Phi^{-}_{l,t}, &\quad \forall l \in \mathcal{L}, \forall t \in \mathcal{T}\\ &\Phi^{+}_{l,t} + \Phi^{-}_{l,t} \leq \varphi^{cap}_{l}, &\quad \forall l \in \mathcal{L}, \forall t \in \mathcal{T} @@ -50,7 +50,7 @@ where $TransON^{+}_{l,t}$ is a continuous variable, representing the product of \end{aligned} ``` These constraints permit only the positive or negative auxiliary flow variables to be non-zero at a given time period, not both. -For the third option, losses are calculated as a piecewise-linear approximation of a quadratic function of power flows. In order to do this, we represent the absolute value of the line flow variable by the sum of positive stepwise flow variables $(\mathcal{S}^{+}_{m,l,t}, \mathcal{S}^{-}_{m,l,t})$, associated with each partition of line losses computed using the corresponding linear expressions. This can be understood as a segmentwise linear fitting (or first order approximation) of the quadratic losses function. The first constraint below computes the losses a the accumulated sum of losses for each linear stepwise segment of the approximated quadratic function, including both positive domain and negative domain segments. A second constraint ensures that the stepwise variables do not exceed the maximum size per segment. The slope and maximum size for each segment are calculated as per the method in \cite{Zhang2013}. +For the third option, losses are calculated as a piecewise-linear approximation of a quadratic function of power flows. In order to do this, we represent the absolute value of the line flow variable by the sum of positive stepwise flow variables $(\mathcal{S}^{+}_{m,l,t}, \mathcal{S}^{-}_{m,l,t})$, associated with each partition of line losses computed using the corresponding linear expressions. This can be understood as a segment-wise linear fitting (or first order approximation) of the quadratic losses function. The first constraint below computes the losses a the accumulated sum of losses for each linear stepwise segment of the approximated quadratic function, including both positive domain and negative domain segments. A second constraint ensures that the stepwise variables do not exceed the maximum size per segment. The slope and maximum size for each segment are calculated as per the method in \cite{Zhang2013}. ```math \begin{aligned} & \ell_{l,t} = \frac{\varphi^{ohm}_{l}}{(\varphi^{volt}_{l})^2}\bigg( \sum_{m \in \mathcal{M}}( S^{+}_{m,l}\times \mathcal{S}^{+}_{m,l,t} + S^{-}_{m,l}\times \mathcal{S}^{-}_{m,l,t}) \bigg), &\quad \forall l \in \mathcal{L}, \forall t \in \mathcal{T} \\ @@ -71,7 +71,7 @@ Next, a constraint ensures that the sum of auxiliary segment variables ($m \geq &\sum_{m \in [1:M]} (\mathcal{S}^{-}_{m,l,t}) - \mathcal{S}^{-}_{0,l,t} = - \Phi_{l,t} \end{aligned} ``` -As with losses option 2, this segment-wise approximation of a quadratic loss function also permits 'phantom losses' to avoid cycling thermal units when discrete unit commitment decisions are modeled. In this case, the additional constraints below are also added to ensure that auxiliary segments variables do not exceed maximum value per segment and that they are filled in order; i.e., one segment cannot be non-zero unless prior segment is at its maximum value. Binary constraints deal with absolute value of power flow on each line. If the flow is positive, $\mathcal{S}^{+}_{0,l,t}$ must be zero; if flow is negative, $\mathcal{S}^{+}_{0,l,t}$ must be positive and takes on value of the full negative flow, forcing all $\mathcal{S}^{+}_{m,l,t}$ other segments ($m \geq 1$) to be zero. Conversely, if the flow is negative, $\mathcal{S}^{-}_{0,l,t}$ must be zero; if flow is positive, $\mathcal{S}^{-}_{0,l,t}$ must be positive and takes on value of the full positive flow, forcing all $\mathcal{S}^{-}_{m,l,t}$ other segments ($m \geq 1$) to be zero. Requiring segments to fill in sequential order and binary variables to ensure variables reflect the actual direction of power flows are both necessary to eliminate ``phantom losses'' from the solution. These constraints and binary decisions are ommited if the model is fully linear. +As with losses option 2, this segment-wise approximation of a quadratic loss function also permits 'phantom losses' to avoid cycling thermal units when discrete unit commitment decisions are modeled. In this case, the additional constraints below are also added to ensure that auxiliary segments variables do not exceed maximum value per segment and that they are filled in order; i.e., one segment cannot be non-zero unless prior segment is at its maximum value. Binary constraints deal with absolute value of power flow on each line. If the flow is positive, $\mathcal{S}^{+}_{0,l,t}$ must be zero; if flow is negative, $\mathcal{S}^{+}_{0,l,t}$ must be positive and takes on value of the full negative flow, forcing all $\mathcal{S}^{+}_{m,l,t}$ other segments ($m \geq 1$) to be zero. Conversely, if the flow is negative, $\mathcal{S}^{-}_{0,l,t}$ must be zero; if flow is positive, $\mathcal{S}^{-}_{0,l,t}$ must be positive and takes on value of the full positive flow, forcing all $\mathcal{S}^{-}_{m,l,t}$ other segments ($m \geq 1$) to be zero. Requiring segments to fill in sequential order and binary variables to ensure variables reflect the actual direction of power flows are both necessary to eliminate ``phantom losses'' from the solution. These constraints and binary decisions are omitted if the model is fully linear. ```math \begin{aligned} &\mathcal{S}^{+}_{m,l,t} <= \overline{\mathcal{S}_{m,l}} \times ON^{+}_{m,l,t}, &\quad \forall m \in [1:M], \forall l \in \mathcal{L}, \forall t \in \mathcal{T}\\ @@ -265,7 +265,7 @@ function transmission!(EP::Model, inputs::Dict, setup::Dict) vTAUX_NEG[l, s, t] <= (inputs["pTrans_Max_Possible"][l] / TRANS_LOSS_SEGS) end) - else # Constraints that can be ommitted if problem is convex (i.e. if not using MILP unit commitment constraints) + else # Constraints that can be omitted if problem is convex (i.e. if not using MILP unit commitment constraints) # Eqs 3-4: Ensure that auxilary segment variables do not exceed maximum value per segment and that they # "fill" in order: i.e. one segment cannot be non-zero unless prior segment is at it's maximum value # (These constraints are necessary to prevents phantom losses in MILP problems) @@ -307,7 +307,7 @@ function transmission!(EP::Model, inputs::Dict, setup::Dict) end end # End if(TRANS_LOSS_SEGS > 0) block - # ESR Lossses + # ESR Losses if EnergyShareRequirement >= 1 && IncludeLossesInESR == 1 @expression(EP, eESRTran[ESR = 1:inputs["nESR"]], sum(inputs["dfESR"][z, ESR] * diff --git a/src/model/core/ucommit.jl b/src/model/core/ucommit.jl index 5db836a24b..557014ad5b 100644 --- a/src/model/core/ucommit.jl +++ b/src/model/core/ucommit.jl @@ -26,7 +26,7 @@ function ucommit!(EP::Model, inputs::Dict, setup::Dict) println("Unit Commitment Module") T = inputs["T"] # Number of time steps (hours) - COMMIT = inputs["COMMIT"] # For not, thermal resources are the only ones eligible for Unit Committment + COMMIT = inputs["COMMIT"] # For not, thermal resources are the only ones eligible for Unit Commitment ### Variables ### @@ -53,7 +53,7 @@ function ucommit!(EP::Model, inputs::Dict, setup::Dict) add_to_expression!(EP[:eObj], eTotalCStart) - ### Constratints ### + ### Constraints ### ## Declaration of integer/binary variables if setup["UCommit"] == 1 # Integer UC constraints for y in COMMIT diff --git a/src/model/generate_model.jl b/src/model/generate_model.jl index 35db927611..bb6733263a 100644 --- a/src/model/generate_model.jl +++ b/src/model/generate_model.jl @@ -27,7 +27,7 @@ The objective function of GenX minimizes total annual electricity system costs o \end{aligned} ``` -The first summation represents the fixed costs of generation/discharge over all zones and technologies, which refects the sum of the annualized capital cost, $\pi^{INVEST}_{y,z}$, times the total new capacity added (if any), plus the Fixed O&M cost, $\pi^{FOM}_{y,z}$, times the net installed generation capacity, $\overline{\Omega}^{size}_{y,z} \times \Delta^{total}_{y,z}$ (e.g., existing capacity less retirements plus additions). +The first summation represents the fixed costs of generation/discharge over all zones and technologies, which reflects the sum of the annualized capital cost, $\pi^{INVEST}_{y,z}$, times the total new capacity added (if any), plus the Fixed O&M cost, $\pi^{FOM}_{y,z}$, times the net installed generation capacity, $\overline{\Omega}^{size}_{y,z} \times \Delta^{total}_{y,z}$ (e.g., existing capacity less retirements plus additions). The second summation corresponds to the fixed cost of installed energy storage capacity and is summed over only the storage resources. This term includes the sum of the annualized energy capital cost, $\pi^{INVEST,energy}_{y,z}$, times the total new energy capacity added (if any), plus the Fixed O&M cost, $\pi^{FOM, energy}_{y,z}$, times the net installed energy storage capacity, $\Delta^{total}_{y,z}$ (e.g., existing capacity less retirements plus additions). diff --git a/src/model/policies/energy_share_requirement.jl b/src/model/policies/energy_share_requirement.jl index 4ed3728777..81113c1f54 100644 --- a/src/model/policies/energy_share_requirement.jl +++ b/src/model/policies/energy_share_requirement.jl @@ -1,6 +1,6 @@ @doc raw""" energy_share_requirement!(EP::Model, inputs::Dict, setup::Dict) -This function establishes constraints that can be flexibily applied to define alternative forms of policies that require generation of a minimum quantity of megawatt-hours from a set of qualifying resources, such as renewable portfolio standard (RPS) or clean electricity standard (CES) policies prevalent in different jurisdictions. +This function establishes constraints that can be flexibly applied to define alternative forms of policies that require generation of a minimum quantity of megawatt-hours from a set of qualifying resources, such as renewable portfolio standard (RPS) or clean electricity standard (CES) policies prevalent in different jurisdictions. These policies usually require that the annual MWh generation from a subset of qualifying generators has to be higher than a pre-specified percentage of demand from qualifying zones. The implementation allows for user to define one or multiple RPS/CES style minimum energy share constraints, where each constraint can cover different combination of model zones to mimic real-world policy implementation (e.g. multiple state policies, multiple RPS tiers or overlapping RPS and CES policies). diff --git a/src/model/policies/hydrogen_demand.jl b/src/model/policies/hydrogen_demand.jl index 27efc42e36..a6c567c6c6 100644 --- a/src/model/policies/hydrogen_demand.jl +++ b/src/model/policies/hydrogen_demand.jl @@ -1,7 +1,7 @@ @doc raw""" hydrogen_demand!(EP::Model, inputs::Dict, setup::Dict) -This policy constraints add hydrogen prodcution demand requirement for electrolyzers. +This policy constraints add hydrogen production demand requirement for electrolyzers. The hydrogen demand requirement can be defined as a zonal limit defined in terms of annual hydrogen production (in 1,000 tonnes of hydrogen). diff --git a/src/model/policies/maximum_capacity_requirement.jl b/src/model/policies/maximum_capacity_requirement.jl index 4f92aa4017..a1f139173f 100644 --- a/src/model/policies/maximum_capacity_requirement.jl +++ b/src/model/policies/maximum_capacity_requirement.jl @@ -6,7 +6,7 @@ The maximum capacity requirement constraint allows for modeling maximum deployme \sum_{y \in \mathcal{G} } \sum_{z \in \mathcal{Z} } \left( \epsilon_{y,z,p}^{MaxCapReq} \times \Delta^{\text{total}}_{y,z} \right) \leq REQ_{p}^{MaxCapReq} \hspace{1 cm} \forall p \in \mathcal{P}^{MaxCapReq} \end{aligned} ``` -Note that $\epsilon_{y,z,p}^{MaxCapReq}$ is the eligiblity of a generator of technology $y$ in zone $z$ of requirement $p$ and will be equal to $1$ for eligible generators and will be zero for ineligible resources. The dual value of each maximum capacity constraint can be interpreted as the required payment (e.g. subsidy) per MW per year required to ensure adequate revenue for the qualifying resources. +Note that $\epsilon_{y,z,p}^{MaxCapReq}$ is the eligibility of a generator of technology $y$ in zone $z$ of requirement $p$ and will be equal to $1$ for eligible generators and will be zero for ineligible resources. The dual value of each maximum capacity constraint can be interpreted as the required payment (e.g. subsidy) per MW per year required to ensure adequate revenue for the qualifying resources. """ function maximum_capacity_requirement!(EP::Model, inputs::Dict, setup::Dict) println("Maximum Capacity Requirement Module") diff --git a/src/model/policies/minimum_capacity_requirement.jl b/src/model/policies/minimum_capacity_requirement.jl index 333c6b551d..e23e76ec59 100644 --- a/src/model/policies/minimum_capacity_requirement.jl +++ b/src/model/policies/minimum_capacity_requirement.jl @@ -6,7 +6,7 @@ The minimum capacity requirement constraint allows for modeling minimum deployme \sum_{y \in \mathcal{G} } \sum_{z \in \mathcal{Z} } \left( \epsilon_{y,z,p}^{MinCapReq} \times \Delta^{\text{total}}_{y,z} \right) \geq REQ_{p}^{MinCapReq} \hspace{1 cm} \forall p \in \mathcal{P}^{MinCapReq} \end{aligned} ``` -Note that $\epsilon_{y,z,p}^{MinCapReq}$ is the eligiblity of a generator of technology $y$ in zone $z$ of requirement $p$ and will be equal to $1$ for eligible generators and will be zero for ineligible resources. The dual value of each minimum capacity constraint can be interpreted as the required payment (e.g. subsidy) per MW per year required to ensure adequate revenue for the qualifying resources. +Note that $\epsilon_{y,z,p}^{MinCapReq}$ is the eligibility of a generator of technology $y$ in zone $z$ of requirement $p$ and will be equal to $1$ for eligible generators and will be zero for ineligible resources. The dual value of each minimum capacity constraint can be interpreted as the required payment (e.g. subsidy) per MW per year required to ensure adequate revenue for the qualifying resources. Also note that co-located VRE and storage resources, there are three different components that minimum capacity requirements can be created for. The capacity of solar PV (in AC terms diff --git a/src/model/resources/curtailable_variable_renewable/curtailable_variable_renewable.jl b/src/model/resources/curtailable_variable_renewable/curtailable_variable_renewable.jl index ad367beb8c..e077296469 100644 --- a/src/model/resources/curtailable_variable_renewable/curtailable_variable_renewable.jl +++ b/src/model/resources/curtailable_variable_renewable/curtailable_variable_renewable.jl @@ -62,7 +62,7 @@ function curtailable_variable_renewable!(EP::Model, inputs::Dict, setup::Dict) # For resource for which we are modeling hourly power output for y in VRE_POWER_OUT # Define the set of generator indices corresponding to the different sites (or bins) of a particular VRE technology (E.g. wind or solar) in a particular zone. - # For example the wind resource in a particular region could be include three types of bins corresponding to different sites with unique interconnection, hourly capacity factor and maximim available capacity limits. + # For example the wind resource in a particular region could be include three types of bins corresponding to different sites with unique interconnection, hourly capacity factor and maximum available capacity limits. VRE_BINS = intersect(resource_id.(gen[resource_id.(gen) .>= y]), resource_id.(gen[resource_id.(gen) .<= y + num_vre_bins(gen[y]) - 1])) @@ -80,7 +80,8 @@ function curtailable_variable_renewable!(EP::Model, inputs::Dict, setup::Dict) for y in VRE_NO_POWER_OUT fix.(EP[:vP][y, :], 0.0, force = true) end - ##CO2 Polcy Module VRE Generation by zone + + ##CO2 Policy Module VRE Generation by zone # We use the transpose here because eGenerationByZone is [1:Z, 1:T] and # ePowerBalanceDisp is [1:T, 1:Z]. add_similar_to_expression!(EP[:eGenerationByZone], ePowerBalanceDisp') diff --git a/src/model/resources/flexible_ccs/allamcycle_commit.jl b/src/model/resources/flexible_ccs/allamcycle_commit.jl index 1aa26bc74d..07926923fc 100644 --- a/src/model/resources/flexible_ccs/allamcycle_commit.jl +++ b/src/model/resources/flexible_ccs/allamcycle_commit.jl @@ -3,7 +3,7 @@ This function defines the operating constraints for allam cycle power plants subject to unit commitment constraints on power plant start-ups and shut-down decision ($y \in UC$). The capacity investment decisions and commitment and cycling (start-up, shut-down) of ASU and sCO2 turbine in allam cycle power systems are similar to constraints defined in thermal_commit.jl -Operaional constraints include start-up, max ramping up/donw, max up/down time, min power level, and operational reserves. +Operational constraints include start-up, max ramping up/donw, max up/down time, min power level, and operational reserves. """ function allamcycle_commit!(EP::Model, inputs::Dict, setup::Dict) # Load generators dataframe, sets, and time periods @@ -124,11 +124,11 @@ function allamcycle_commit!(EP::Model, inputs::Dict, setup::Dict) [t in setdiff(INTERIOR_SUBPERIODS,Up_Time_HOURS)], vCOMMIT_Allam[y,i,t] >= sum(vSTART_Allam[y,i,e] for e=(t-allam_dict[y, "up_time"][i]):t) # cUpTimeWrap: If n is greater than the number of subperiods left in the period, constraint wraps around to first hour of time series - # cUpTimeWrap constraint equivalant to: sum(vSTART_Allam[y,e] for e=(t-((t%p)-1):t))+sum(vSTART_Allam[y,e] for e=(p_max-(allam_dict[y, "up_time"][i])-(t%p))):p_max) + # cUpTimeWrap constraint equivalent to: sum(vSTART_Allam[y,e] for e=(t-((t%p)-1):t))+sum(vSTART_Allam[y,e] for e=(p_max-(allam_dict[y, "up_time"][i])-(t%p))):p_max) [t in Up_Time_HOURS], vCOMMIT_Allam[y,i,t] >= sum(vSTART_Allam[y,i,e] for e=(t-((t%p)-1):t))+sum(vSTART_Allam[y,i,e] for e=((t+p-(t%p))-(allam_dict[y, "up_time"][i]-(t%p))):(t+p-(t%p))) # cUpTimeStart: - # NOTE: Expression t+p-(t%p) is equivalant to "p_max" + # NOTE: Expression t+p-(t%p) is equivalent to "p_max" [t in START_SUBPERIODS], vCOMMIT_Allam[y,i,t] >= vSTART_Allam[y,i,t]+sum(vSTART_Allam[y,i,e] for e=(hoursbefore(p, t, 1)-(allam_dict[y, "up_time"][i]-1)):hoursbefore(p, t, 1)) end) @@ -146,11 +146,11 @@ function allamcycle_commit!(EP::Model, inputs::Dict, setup::Dict) [t in setdiff(INTERIOR_SUBPERIODS,Down_Time_HOURS)], EP[:eTotalCap_AllamcycleLOX][y,i]/allam_dict[y, "cap_size"][i]-vCOMMIT_Allam[y,i,t] >= sum(vSHUT_Allam[y,i,e] for e=(t-allam_dict[y, "down_time"][i]):t) # cDownTimeWrap: If n is greater than the number of subperiods left in the period, constraint wraps around to first hour of time series - # cDownTimeWrap constraint equivalant to: eTotalCap_AllamcycleLOX[y,i]/allam_dict[y, "cap_size"][i]-vCOMMIT_Allam[y,t] >= sum(vSHUT_Allam[y,e] for e=(t-((t%p)-1):t))+sum(vSHUT_Allam[y,e] for e=(p_max-(allam_dict[y, "down_time"][i]-(t%p))):p_max) + # cDownTimeWrap constraint equivalent to: eTotalCap_AllamcycleLOX[y,i]/allam_dict[y, "cap_size"][i]-vCOMMIT_Allam[y,t] >= sum(vSHUT_Allam[y,e] for e=(t-((t%p)-1):t))+sum(vSHUT_Allam[y,e] for e=(p_max-(allam_dict[y, "down_time"][i]-(t%p))):p_max) [t in Down_Time_HOURS], EP[:eTotalCap_AllamcycleLOX][y,i]/allam_dict[y, "cap_size"][i]-vCOMMIT_Allam[y,i,t] >= sum(vSHUT_Allam[y,i,e] for e=(t-((t%p)-1):t))+sum(vSHUT_Allam[y,i,e] for e=((t+p-(t%p))-(allam_dict[y, "down_time"][i]-(t%p))):(t+p-(t%p))) # cDownTimeStart: - # NOTE: Expression t+p-(t%p) is equivalant to "p_max" + # NOTE: Expression t+p-(t%p) is equivalent to "p_max" [t in START_SUBPERIODS], EP[:eTotalCap_AllamcycleLOX][y,i]/allam_dict[y, "cap_size"][i]-vCOMMIT_Allam[y,i,t] >= vSHUT_Allam[y,i,t]+sum(vSHUT_Allam[y,i,e] for e=(hoursbefore(p, t, 1)-(allam_dict[y, "down_time"][i]-1)):hoursbefore(p, t, 1)) end) end @@ -190,4 +190,4 @@ function allamcycle_commit!(EP::Model, inputs::Dict, setup::Dict) [y in ALLAM_CYCLE_LOX, t in 1:T], expr[y, t]<=max_power(y, t) * commit(y, t)) end -end \ No newline at end of file +end diff --git a/src/model/resources/flexible_ccs/allamcycle_no_commit.jl b/src/model/resources/flexible_ccs/allamcycle_no_commit.jl index 7e2e7b5106..8ebf9abb11 100644 --- a/src/model/resources/flexible_ccs/allamcycle_no_commit.jl +++ b/src/model/resources/flexible_ccs/allamcycle_no_commit.jl @@ -2,7 +2,7 @@ allamcycle_no_commit!(EP::Model, inputs::Dict, setup::Dict) This function defines the operating constraints for allam cycle power plants subject to unit commitment constraints on power plant start-ups and shut-down decision ($y \in UC$). The capacity investment decisions and commitment and cycling (start-up, shut-down) of ASU and sCO2 turbine in allam cycle power systems are similar to constraints defined in thermal_no_commit.jl -Operaional constraints include max ramping up/donw, min power level, and operational reserves. +Operational constraints include max ramping up/donw, min power level, and operational reserves. """ function allamcycle_no_commit!(EP::Model, inputs::Dict, setup::Dict) # Load generators dataframe, sets, and time periods @@ -79,4 +79,4 @@ function allamcycle_no_commit!(EP::Model, inputs::Dict, setup::Dict) [y in ALLAM_CYCLE_LOX, t in 1:T], expr[y, t]<=max_power(y, t) * eTotalCap[y,sco2turbine]) end -end \ No newline at end of file +end diff --git a/src/model/resources/flexible_ccs/allamcyclelox.jl b/src/model/resources/flexible_ccs/allamcyclelox.jl index 49f8efb6fb..26964fff82 100644 --- a/src/model/resources/flexible_ccs/allamcyclelox.jl +++ b/src/model/resources/flexible_ccs/allamcyclelox.jl @@ -1,13 +1,13 @@ @doc raw""" allamcyclelox!(EP::Model, inputs::Dict, setup::Dict) This module models the Allam cycle with or without liquid oxygen storage (LOX) tank. -In this module, the key components of Allam cycle w/ LOX are break down into mutiple components with independent capacity decisions. +In this module, the key components of Allam cycle w/ LOX are break down into multiple components with independent capacity decisions. ## Important expressions **Power balance within an Allam Cycle resource** -Consumption of electricity by Air Seperation Unit (ASU) $y, asu$ in time $t$, denoted by $\Pi_{y,asu,t}$, and auxiliary load, denoted by $\Pi_{y,aux,t}$, is subtracted from power generation from the sCO2 turbines, denoted by $\Pi_{y,sco2turbine,t}$ +Consumption of electricity by Air Separation Unit (ASU) $y, asu$ in time $t$, denoted by $\Pi_{y,asu,t}$, and auxiliary load, denoted by $\Pi_{y,aux,t}$, is subtracted from power generation from the sCO2 turbines, denoted by $\Pi_{y,sco2turbine,t}$ **Power balance between an Allam Cycle resource and the grid** @@ -79,7 +79,7 @@ function allamcyclelox!(EP::Model, inputs::Dict, setup::Dict) NEW_CAP_Allam = intersect(inputs["NEW_CAP"], ALLAM_CYCLE_LOX) RET_CAP_Allam = intersect(inputs["RET_CAP"], ALLAM_CYCLE_LOX) COMMIT_Allam = setup["UCommit"] > 0 ? ALLAM_CYCLE_LOX : Int[] # If UCommit is on, then all Allam Cycle resources are subject to unit commitment - WITH_LOX = inputs["WITH_LOX"] # Set of Allam Cycel generators that can use liquid oxygen storage + WITH_LOX = inputs["WITH_LOX"] # Set of Allam Cycle generators that can use liquid oxygen storage # time related p = inputs["hours_per_subperiod"] @@ -98,8 +98,8 @@ function allamcyclelox!(EP::Model, inputs::Dict, setup::Dict) @variable(EP, vCAP_AllamCycleLOX[y in ALLAM_CYCLE_LOX, i = 1:3] >= 0) # construct a matrix represent the main output of each component (e.g., sCO2 Turbine, air separation unit (ASU), and liquid oxygen storage tank (LOX)) - # y represents the plant, i represents the specfic subcomponents, and t represents the time - # The main output from sCO2Turbine/ASU/LOX is the gross power output from sCO2 cycle (MWh), power consumption associated with ASU (MWh), and the amout of LOX (tonne) stored in the LOX tank + # y represents the plant, i represents the specific subcomponents, and t represents the time + # The main output from sCO2Turbine/ASU/LOX is the gross power output from sCO2 cycle (MWh), power consumption associated with ASU (MWh), and the amount of LOX (tonne) stored in the LOX tank @variable(EP, vOutput_AllamcycleLOX[y in ALLAM_CYCLE_LOX, i = 1:3, t = 1:T] >= 0) # Grid export to the system to support ASU @@ -116,14 +116,14 @@ function allamcyclelox!(EP::Model, inputs::Dict, setup::Dict) @expression(EP, eFuel_Allam[y in ALLAM_CYCLE_LOX ,t=1:T], gen[y].heatrate_sco2 * vOutput_AllamcycleLOX[y, sco2turbine, t]) - # Power consumption assumed by ASU is a function of gnerated LOX - # Note: it should be noticed that the poweruserate to generate GOX and LOX are differernt. + # Power consumption assumed by ASU is a function of generated LOX + # Note: it should be noticed that the poweruserate to generate GOX and LOX are different. @constraint(EP, [y in ALLAM_CYCLE_LOX, t = 1:T], vOutput_AllamcycleLOX[y, asu, t] == gen[y].lox_poweruserate_o2 * vLOX_in[y,t] + gen[y].gox_poweruserate_o2 * vGOX[y,t]) # Auxiliary load @expression(EP, ePower_other[y in ALLAM_CYCLE_LOX,t=1:T], gen[y].poweruserate_other * vOutput_AllamcycleLOX[y, sco2turbine, t]) - # The amount of LOX feed into oxyfuel cycle should be propotional to the power generated by oxyfuel cycle + # The amount of LOX feed into oxyfuel cycle should be proportional to the power generated by oxyfuel cycle @expression(EP, eLOX_out[y in ALLAM_CYCLE_LOX,t=1:T], gen[y].o2userate * vOutput_AllamcycleLOX[y, sco2turbine, t] - vGOX[y,t]) @constraint(EP, cLOX_out[y in ALLAM_CYCLE_LOX,t=1:T], eLOX_out[y ,t]>=0) @@ -145,7 +145,7 @@ function allamcyclelox!(EP::Model, inputs::Dict, setup::Dict) # Expressions and constraints related to Allam Cycle costs @expression(EP, eExistingCap_AllamCycleLOX[y in ALLAM_CYCLE_LOX, i = 1:3], allam_dict[y, "existing_cap"][i]) - # Note: Allam Cycle is not compatiable with RETRO for now. + # Note: Allam Cycle is not compatible with RETRO for now. @expression(EP, eTotalCap_AllamcycleLOX[y in ALLAM_CYCLE_LOX, i in 1:3], if y in intersect(NEW_CAP_Allam, RET_CAP_Allam) # Resources eligible for new capacity and retirements if y in COMMIT_Allam @@ -205,13 +205,13 @@ function allamcyclelox!(EP::Model, inputs::Dict, setup::Dict) @constraint(EP, cMinLoxDuration_out[y in intersect(ids_with_positive(gen, lox_duration), WITH_LOX), t in 1:T], eTotalCap_AllamcycleLOX[y,lox]/lox_duration(gen[y]) >= vLOX_in[y,t]) # connect eFuel_Allam to vFuel so the fuel cost will be determined in fuel.jl. We don't need to double account - # Allam cycle is exluded from the constraint on vFuel in fuel.jl + # Allam cycle is excluded from the constraint on vFuel in fuel.jl @constraint(EP, [y in ALLAM_CYCLE_LOX, t in 1:T], EP[:vFuel][y,t] == eFuel_Allam[y,t]) # add vom - # variale costs are related to the main output, e.g., gross power output frmo sCO2 turbine + # variable costs are related to the main output, e.g., gross power output from sCO2 turbine # power consumption associated with the ASU, and CO2 sequestration costs - # variable costs will be mutiplied by inputs["omega"] to be compatiable with time domain reduction + # variable costs will be multiplied by inputs["omega"] to be compatible with time domain reduction # variable OM @expression(EP, eCVar_component[y in ALLAM_CYCLE_LOX, i = 1:3, t = 1:T], omega[t] * vOutput_AllamcycleLOX[y,i,t] * allam_dict[y,"vom_cost"][i]) @@ -230,7 +230,7 @@ function allamcyclelox!(EP::Model, inputs::Dict, setup::Dict) if setup["UCommit"] > 0 allamcycle_commit!(EP, inputs, setup) else - @warn("Warning: it is not recommended to run Allam Cycele wihtout unit commit. Please set UCommit to 1 in the setting file.") + @warn("Warning: it is not recommended to run Allam Cycle without unit commit. Please set UCommit to 1 in the setting file.") allamcycle_no_commit!(EP, inputs, setup) end @@ -286,4 +286,4 @@ function allamcyclelox!(EP::Model, inputs::Dict, setup::Dict) for y in intersect(resources_in_zone_by_rid(gen,z), QUALIFIED_SUPPLY, ALLAM_CYCLE_LOX))) add_similar_to_expression!(EP[:eHM], eHMAllam) end -end \ No newline at end of file +end diff --git a/src/model/resources/hydro/hydro_inter_period_linkage.jl b/src/model/resources/hydro/hydro_inter_period_linkage.jl index 19761d07ea..277511d097 100644 --- a/src/model/resources/hydro/hydro_inter_period_linkage.jl +++ b/src/model/resources/hydro/hydro_inter_period_linkage.jl @@ -13,10 +13,10 @@ The constraints in this section are used to approximate the behavior of long-dur By definition $\mathcal{T}^{start}=\{\left(m-1\right) \times \tau^{period}+1 | m \in \mathcal{M}\}$, which implies that this constraint is defined for all values of $t \in T^{start}$. **Storage inventory change input periods** -We need additional variables and constraints to approximate energy exchange between representative periods, while accounting for their chronological occurence in the original input time series data and the possibility that two representative periods may not be adjacent to each other (see Figure below). To implement this, we introduce a new variable $Q_{o,z, n}$ that models inventory of storage technology $o \in O$ in zone $z$ in each input period $n \in \mathcal{N}$. Additionally we define a function mapping, $f: n \rightarrow m$, that uniquely maps each input period $n$ to its corresponding representative period $m$. This mapping is available as an output of the process used to identify representative periods (E.g. k-means clustering [Mallapragada et al., 2018](https://www.sciencedirect.com/science/article/pii/S0360544218315238?casa_token=I-6GVNMtAVIAAAAA:G8LFXFqXxRGrXHtrzmiIGm02BusIUmm83zKh8xf1BXY81-dTnA9p2YI1NnGuzlYBXsxK12by)). +We need additional variables and constraints to approximate energy exchange between representative periods, while accounting for their chronological occurrence in the original input time series data and the possibility that two representative periods may not be adjacent to each other (see Figure below). To implement this, we introduce a new variable $Q_{o,z, n}$ that models inventory of storage technology $o \in O$ in zone $z$ in each input period $n \in \mathcal{N}$. Additionally we define a function mapping, $f: n \rightarrow m$, that uniquely maps each input period $n$ to its corresponding representative period $m$. This mapping is available as an output of the process used to identify representative periods (E.g. k-means clustering [Mallapragada et al., 2018](https://www.sciencedirect.com/science/article/pii/S0360544218315238?casa_token=I-6GVNMtAVIAAAAA:G8LFXFqXxRGrXHtrzmiIGm02BusIUmm83zKh8xf1BXY81-dTnA9p2YI1NnGuzlYBXsxK12by)). ![Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations](../../assets/LDES_approach.png) *Figure. Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations* -The following two equations define the storage inventory at the beginning of each input period $n+1$ as the sum of storage inventory at begining of previous input period $n$ plus change in storage inventory for that period. The latter is approximated by the change in storage inventory in the corresponding representative period, identified per the mapping $f(n)$. The second constraint relates the storage level of the last input period, $|N|$, with the storage level at the beginning of the first input period. Finally, if the input period is also a representative period, then a third constraint enforces that initial storage level estimated by the intra-period storage balance constraint should equal the initial storage level estimated from the inter-period storage balance constraints. Note that $|N|$ refers to the last modeled period. +The following two equations define the storage inventory at the beginning of each input period $n+1$ as the sum of storage inventory at beginning of previous input period $n$ plus change in storage inventory for that period. The latter is approximated by the change in storage inventory in the corresponding representative period, identified per the mapping $f(n)$. The second constraint relates the storage level of the last input period, $|N|$, with the storage level at the beginning of the first input period. Finally, if the input period is also a representative period, then a third constraint enforces that initial storage level estimated by the intra-period storage balance constraint should equal the initial storage level estimated from the inter-period storage balance constraints. Note that $|N|$ refers to the last modeled period. ```math \begin{aligned} & Q_{o,z,n+1} = Q_{o,z,n} + \Delta Q_{o,z,f(n)} diff --git a/src/model/resources/hydro/hydro_res.jl b/src/model/resources/hydro/hydro_res.jl index 6de6f44093..14a973b498 100644 --- a/src/model/resources/hydro/hydro_res.jl +++ b/src/model/resources/hydro/hydro_res.jl @@ -11,7 +11,7 @@ Reservoir hydro systems are governed by the storage inventory balance constraint &\Gamma_{y,z,t} = \Gamma_{y,z,t+\tau^{period}-1} -\frac{1}{\eta_{y,z}^{down}}\Theta_{y,z,t} - \varrho_{y,z,t} + \rho^{max}_{y,z,t} \times \Delta^{total}_{y,z} \hspace{.1 cm} \forall y \in \mathcal{W}, z \in \mathcal{Z}, t \in \mathcal{T}^{start} \end{aligned} ``` -We implement time-wrapping to endogenize the definition of the intial state prior to the first period with the following assumption. If time step $t$ is the first time step of the year then storage inventory at $t$ is defined based on last time step of the year. Alternatively, if time step $t$ is the first time step of a representative period, then storage inventory at $t$ is defined based on the last time step of the representative period. Thus, when using representative periods, the storage balance constraint for hydro resources does not allow for energy exchange between representative periods. +We implement time-wrapping to endogenize the definition of the initial state prior to the first period with the following assumption. If time step $t$ is the first time step of the year then storage inventory at $t$ is defined based on last time step of the year. Alternatively, if time step $t$ is the first time step of a representative period, then storage inventory at $t$ is defined based on the last time step of the representative period. Thus, when using representative periods, the storage balance constraint for hydro resources does not allow for energy exchange between representative periods. Note: in future updates, an option to model hydro resources with large reservoirs that can transfer energy across sample periods will be implemented, similar to the functions for modeling long duration energy storage in ```long_duration_storage.jl```. **Ramping Limits** @@ -120,7 +120,7 @@ function hydro_res!(EP::Model, inputs::Dict, setup::Dict) add_similar_to_expression!(EP[:eCapResMarBalance], eCapResMarBalanceHydro) end - ### Constratints ### + ### Constraints ### if representative_periods > 1 && !isempty(inputs["STOR_HYDRO_LONG_DURATION"]) CONSTRAINTSET = STOR_HYDRO_SHORT_DURATION @@ -135,7 +135,7 @@ function hydro_res!(EP::Model, inputs::Dict, setup::Dict) (1 / efficiency_down(gen[y]) * EP[:vP][y, t]) - vSPILL[y, t] + inputs["pP_Max"][y, t] * EP[:eTotalCap][y]) - ### Constraints commmon to all reservoir hydro (y in set HYDRO_RES) ### + ### Constraints common to all reservoir hydro (y in set HYDRO_RES) ### @constraints(EP, begin ### NOTE: time coupling constraints in this block do not apply to first hour in each sample period; @@ -165,7 +165,7 @@ function hydro_res!(EP::Model, inputs::Dict, setup::Dict) # Maximum discharging rate must be less than power rating OR available stored energy at start of hour, whichever is less # DEV NOTE: We do not currently account for hydro power plant outages - leave it for later to figure out if we should. - # DEV NOTE (CONTD): If we defin pPMax as hourly availability of the plant and define inflows as a separate parameter, then notation will be consistent with its use for other resources + # DEV NOTE (CONTD): If we define pPMax as hourly availability of the plant and define inflows as a separate parameter, then notation will be consistent with its use for other resources cHydroMaxPower[y in HYDRO_RES, t in 1:T], EP[:vP][y, t] <= EP[:eTotalCap][y] cHydroMaxOutflow[y in HYDRO_RES, t in 1:T], EP[:vP][y, t] <= EP[:vS_HYDRO][y, hoursbefore(p, t, 1)] @@ -181,7 +181,7 @@ function hydro_res!(EP::Model, inputs::Dict, setup::Dict) ### Reserve related constraints for reservoir hydro resources (y in HYDRO_RES), if used hydro_res_operational_reserves!(EP, inputs) end - ##CO2 Polcy Module Hydro Res Generation by zone + ##CO2 Policy Module Hydro Res Generation by zone @expression(EP, eGenerationByHydroRes[z = 1:Z, t = 1:T], # the unit is GW sum(EP[:vP][y, t] for y in HYDRO_RES_BY_ZONE[z])) add_similar_to_expression!(EP[:eGenerationByZone], eGenerationByHydroRes) @@ -192,7 +192,7 @@ end This module defines the modified constraints and additional constraints needed when modeling operating reserves **Modifications when operating reserves are modeled** -When modeling operating reserves, the constraints regarding maximum power flow limits are modified to account for procuring some of the available capacity for frequency regulation ($f_{y,z,t}$) and "updward" operating (or spinning) reserves ($r_{y,z,t}$). +When modeling operating reserves, the constraints regarding maximum power flow limits are modified to account for procuring some of the available capacity for frequency regulation ($f_{y,z,t}$) and "upward" operating (or spinning) reserves ($r_{y,z,t}$). ```math \begin{aligned} \Theta_{y,z,t} + f_{y,z,t} +r_{y,z,t} \leq \times \Delta^{total}_{y,z} diff --git a/src/model/resources/maintenance.jl b/src/model/resources/maintenance.jl index 1a9bda5f04..8bad93895e 100644 --- a/src/model/resources/maintenance.jl +++ b/src/model/resources/maintenance.jl @@ -90,7 +90,7 @@ end to begin at any time step during the simulation. Instead this integer describes the cadence of timesteps in which maintenance can begin. Must be at least 1. maint_dur: Number of timesteps that maintenance takes. Must be at least 1. - maint_freq_years: 1 is maintenannce every year, + maint_freq_years: 1 is maintenance every year, 2 is maintenance every other year, etc. Must be at least 1. cap: Plant electrical capacity. vcommit: Symbol of vCOMMIT-like variable. diff --git a/src/model/resources/must_run/must_run.jl b/src/model/resources/must_run/must_run.jl index fd436ec92c..4ef8b68af9 100644 --- a/src/model/resources/must_run/must_run.jl +++ b/src/model/resources/must_run/must_run.jl @@ -45,12 +45,12 @@ function must_run!(EP::Model, inputs::Dict, setup::Dict) add_similar_to_expression!(EP[:eCapResMarBalance], eCapResMarBalanceMustRun) end - ### Constratints ### + ### Constraints ### @constraint(EP, [y in MUST_RUN, t = 1:T], EP[:vP][y, t]==inputs["pP_Max"][y, t] * EP[:eTotalCap][y]) - ##CO2 Polcy Module Must Run Generation by zone + ##CO2 Policy Module Must Run Generation by zone @expression(EP, eGenerationByMustRun[z = 1:Z, t = 1:T], # the unit is GW sum(EP[:vP][y, t] for y in MUST_RUN_BY_ZONE[z])) add_similar_to_expression!(EP[:eGenerationByZone], eGenerationByMustRun) diff --git a/src/model/resources/storage/investment_charge.jl b/src/model/resources/storage/investment_charge.jl index cb14122840..87e7307d53 100644 --- a/src/model/resources/storage/investment_charge.jl +++ b/src/model/resources/storage/investment_charge.jl @@ -45,7 +45,7 @@ function investment_charge!(EP::Model, inputs::Dict, setup::Dict) MultiStage = setup["MultiStage"] - STOR_ASYMMETRIC = inputs["STOR_ASYMMETRIC"] # Set of storage resources with asymmetric (separte) charge/discharge capacity components + STOR_ASYMMETRIC = inputs["STOR_ASYMMETRIC"] # Set of storage resources with asymmetric (separate) charge/discharge capacity components NEW_CAP_CHARGE = inputs["NEW_CAP_CHARGE"] # Set of asymmetric charge/discharge storage resources eligible for new charge capacity RET_CAP_CHARGE = inputs["RET_CAP_CHARGE"] # Set of asymmetric charge/discharge storage resources eligible for charge capacity retirements @@ -113,7 +113,7 @@ function investment_charge!(EP::Model, inputs::Dict, setup::Dict) add_to_expression!(EP[:eObj], eTotalCFixCharge) end - ### Constratints ### + ### Constraints ### if MultiStage == 1 # Existing capacity variable is equal to existing capacity specified in the input file @@ -131,14 +131,14 @@ function investment_charge!(EP::Model, inputs::Dict, setup::Dict) #Constraints on new built capacity # Constraint on maximum charge capacity (if applicable) [set input to -1 if no constraint on maximum charge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cMaxCapCharge[y in intersect(ids_with_positive(gen, max_charge_cap_mw), STOR_ASYMMETRIC)], eTotalCapCharge[y]<=max_charge_cap_mw(gen[y])) # Constraint on minimum charge capacity (if applicable) [set input to -1 if no constraint on minimum charge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cMinCapCharge[y in intersect(ids_with_positive(gen, min_charge_cap_mw), STOR_ASYMMETRIC)], diff --git a/src/model/resources/storage/investment_energy.jl b/src/model/resources/storage/investment_energy.jl index 24078b62d7..49361e5d92 100644 --- a/src/model/resources/storage/investment_energy.jl +++ b/src/model/resources/storage/investment_energy.jl @@ -130,13 +130,13 @@ function investment_energy!(EP::Model, inputs::Dict, setup::Dict) ## Constraints on new built energy capacity # Constraint on maximum energy capacity (if applicable) [set input to -1 if no constraint on maximum energy capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MWh is >= Max_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MWh is >= Max_Cap_MWh and lead to infeasibility @constraint(EP, cMaxCapEnergy[y in intersect(ids_with_positive(gen, max_cap_mwh), STOR_ALL)], eTotalCapEnergy[y]<=max_cap_mwh(gen[y])) - # Constraint on minimum energy capacity (if applicable) [set input to -1 if no constraint on minimum energy apacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MWh is <= Min_Cap_MWh and lead to infeasabilty + # Constraint on minimum energy capacity (if applicable) [set input to -1 if no constraint on minimum energy capacity] + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MWh is <= Min_Cap_MWh and lead to infeasibility @constraint(EP, cMinCapEnergy[y in intersect(ids_with_positive(gen, min_cap_mwh), STOR_ALL)], eTotalCapEnergy[y]>=min_cap_mwh(gen[y])) diff --git a/src/model/resources/storage/long_duration_storage.jl b/src/model/resources/storage/long_duration_storage.jl index 98ddc7d819..7685c79bd3 100644 --- a/src/model/resources/storage/long_duration_storage.jl +++ b/src/model/resources/storage/long_duration_storage.jl @@ -13,13 +13,13 @@ The constraints in this section are used to approximate the behavior of long-dur ``` By definition $\mathcal{T}^{start}=\{\left(m-1\right) \times \tau^{period}+1 | m \in \mathcal{M}\}$, which implies that this constraint is defined for all values of $t \in T^{start}$. \ **Storage inventory change input periods** -We need additional variables and constraints to approximate energy exchange between representative periods, while accounting for their chronological occurence in the original input time series data and the possibility that two representative periods may not be adjacent to each other (see Figure below). To implement this, we introduce a new variable $Q_{o,z, n}$ that models inventory of storage technology $o \in O$ in zone $z$ in each input period $n \in \mathcal{N}$. Additionally we define a function mapping, $f: n \rightarrow m$, that uniquely maps each input period $n$ to its corresponding representative period $m$. This mapping is available as an output of the process used to identify representative periods (E.g. k-means clustering [Mallapragada et al., 2018](https://www.sciencedirect.com/science/article/pii/S0360544218315238?casa_token=I-6GVNMtAVIAAAAA:G8LFXFqXxRGrXHtrzmiIGm02BusIUmm83zKh8xf1BXY81-dTnA9p2YI1NnGuzlYBXsxK12by)). +We need additional variables and constraints to approximate energy exchange between representative periods, while accounting for their chronological occurrence in the original input time series data and the possibility that two representative periods may not be adjacent to each other (see Figure below). To implement this, we introduce a new variable $Q_{o,z, n}$ that models inventory of storage technology $o \in O$ in zone $z$ in each input period $n \in \mathcal{N}$. Additionally we define a function mapping, $f: n \rightarrow m$, that uniquely maps each input period $n$ to its corresponding representative period $m$. This mapping is available as an output of the process used to identify representative periods (E.g. k-means clustering [Mallapragada et al., 2018](https://www.sciencedirect.com/science/article/pii/S0360544218315238?casa_token=I-6GVNMtAVIAAAAA:G8LFXFqXxRGrXHtrzmiIGm02BusIUmm83zKh8xf1BXY81-dTnA9p2YI1NnGuzlYBXsxK12by)). ![Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations](../../assets/LDES_approach.png) *Figure. Modeling inter-period energy exchange via long-duration storage when using representative period temporal resolution to approximate annual grid operations* The following two equations define the storage inventory at the beginning of each input period $n+1$ as -the sum of storage inventory at begining of previous input period $n$ plus change in storage inventory for that period. +the sum of storage inventory at beginning of previous input period $n$ plus change in storage inventory for that period. The latter is approximated by the change in storage inventory in the corresponding representative period, identified per the mapping $f(n)$. If the input period is also a representative period, diff --git a/src/model/resources/storage/storage.jl b/src/model/resources/storage/storage.jl index 78c9acd170..837a155a0c 100644 --- a/src/model/resources/storage/storage.jl +++ b/src/model/resources/storage/storage.jl @@ -17,7 +17,7 @@ If a capacity reserve margin is modeled, variables for virtual charge, $\Pi^{CRM ``` **Storage with symmetric charge and discharge capacity** -For storage technologies with symmetric charge and discharge capacity (all $o \in \mathcal{O}^{sym}$), charge rate, $\Pi_{o,z,t}$, and virtual charge rate, $\Pi^{CRM}_{o,z,t}$, are jointly constrained by the total installed power capacity, $\Omega_{o,z}$. Since storage resources generally represent a `cluster' of multiple similar storage devices of the same type/cost in the same zone, GenX permits storage resources to simultaneously charge and discharge (as some units could be charging while others discharge), with the simultaenous sum of charge, $\Pi_{o,z,t}$, discharge, $\Theta_{o,z,t}$, virtual charge, $\Pi^{CRM}_{o,z,t}$, and virtual discharge, $\Theta^{CRM}_{o,z,t}$, also limited by the total installed power capacity, $\Delta^{total}_{o,z}$. These two constraints are as follows: +For storage technologies with symmetric charge and discharge capacity (all $o \in \mathcal{O}^{sym}$), charge rate, $\Pi_{o,z,t}$, and virtual charge rate, $\Pi^{CRM}_{o,z,t}$, are jointly constrained by the total installed power capacity, $\Omega_{o,z}$. Since storage resources generally represent a `cluster' of multiple similar storage devices of the same type/cost in the same zone, GenX permits storage resources to simultaneously charge and discharge (as some units could be charging while others discharge), with the simultaneous sum of charge, $\Pi_{o,z,t}$, discharge, $\Theta_{o,z,t}$, virtual charge, $\Pi^{CRM}_{o,z,t}$, and virtual discharge, $\Theta^{CRM}_{o,z,t}$, also limited by the total installed power capacity, $\Delta^{total}_{o,z}$. These two constraints are as follows: ```math \begin{aligned} & \Pi_{o,z,t} + \Pi^{CRM}_{o,z,t} \leq \Delta^{total}_{o,z} & \quad \forall o \in \mathcal{O}^{sym}, z \in \mathcal{Z}, t \in \mathcal{T}\\ @@ -91,8 +91,8 @@ The above constraints are established in [`storage_all!()`](@ref) in ```storage_ If reserves are modeled, two pairs of proxy variables $f^{charge}_{o,z,t}, f^{discharge}_{o,z,t}$ and $r^{charge}_{o,z,t}, r^{discharge}_{o,z,t}$ are created for storage resources, to denote the contribution of storage resources to regulation or reserves while charging or discharging, respectively. The total contribution to regulation and reserves, $f_{o,z,t}, r_{o,z,t}$ is then the sum of the proxy variables: ```math \begin{aligned} - & f_{o,z,t} = f^{charge}_{o,z,t} + f^{dicharge}_{o,z,t} & \quad \forall o \in \mathcal{O}, z \in \mathcal{Z}, t \in \mathcal{T}\\ - & r_{o,z,t} = r^{charge}_{o,z,t} + r^{dicharge}_{o,z,t} & \quad \forall o \in \mathcal{O}, z \in \mathcal{Z}, t \in \mathcal{T} + & f_{o,z,t} = f^{charge}_{o,z,t} + f^{discharge}_{o,z,t} & \quad \forall o \in \mathcal{O}, z \in \mathcal{Z}, t \in \mathcal{T}\\ + & r_{o,z,t} = r^{charge}_{o,z,t} + r^{discharge}_{o,z,t} & \quad \forall o \in \mathcal{O}, z \in \mathcal{Z}, t \in \mathcal{T} \end{aligned} ``` The total storage contribution to frequency regulation ($f_{o,z,t}$) and reserves ($r_{o,z,t}$) are each limited specified fraction of installed discharge power capacity ($\upsilon^{reg}_{y,z}, \upsilon^{rsv}_{y,z}$), reflecting the maximum ramp rate for the storage resource in whatever time interval defines the requisite response time for the regulation or reserve products (e.g., 5 mins or 15 mins or 30 mins). These response times differ by system operator and reserve product, and so the user should define these parameters in a self-consistent way for whatever system context they are modeling. @@ -161,7 +161,7 @@ function storage!(EP::Model, inputs::Dict, setup::Dict) storage_symmetric!(EP, inputs, setup) end - # ESR Lossses + # ESR Losses if EnergyShareRequirement >= 1 nESR = inputs["nESR"] dfESR = inputs["dfESR"] diff --git a/src/model/resources/storage/storage_asymmetric.jl b/src/model/resources/storage/storage_asymmetric.jl index 44ae5b11be..f3dbb65ff6 100644 --- a/src/model/resources/storage/storage_asymmetric.jl +++ b/src/model/resources/storage/storage_asymmetric.jl @@ -8,7 +8,7 @@ function storage_asymmetric!(EP::Model, inputs::Dict, setup::Dict) # (e.g. most chemical, thermal, and mechanical storage options with distinct charge & discharge components/processes) # STOR = 2 corresponds to storage with distinct power and energy capacity decisions and distinct charge and discharge power capacity decisions/ratings - println("Storage Resources with Asmymetric Charge/Discharge Capacity Module") + println("Storage Resources with Asymmetric Charge/Discharge Capacity Module") OperationalReserves = setup["OperationalReserves"] == 1 CapacityReserveMargin = setup["CapacityReserveMargin"] > 0 diff --git a/src/model/resources/thermal/thermal.jl b/src/model/resources/thermal/thermal.jl index f16abe3ee9..2e1b8bf07e 100644 --- a/src/model/resources/thermal/thermal.jl +++ b/src/model/resources/thermal/thermal.jl @@ -23,10 +23,12 @@ function thermal!(EP::Model, inputs::Dict, setup::Dict) if !isempty(THERM_NO_COMMIT) thermal_no_commit!(EP, inputs, setup) end - ##CO2 Polcy Module Thermal Generation by zone + + ##CO2 Policy Module Thermal Generation by zone THERM_ALL_BY_ZONE = map(1:Z) do z return intersect(THERM_ALL, resources_in_zone_by_rid(gen, z)) end + @expression(EP, eGenerationByThermAll[z = 1:Z, t = 1:T], # the unit is GW sum(EP[:vP][y, t] for y in THERM_ALL_BY_ZONE[z])) diff --git a/src/model/resources/thermal/thermal_commit.jl b/src/model/resources/thermal/thermal_commit.jl index e7aa0e732c..dbf03672b3 100644 --- a/src/model/resources/thermal/thermal_commit.jl +++ b/src/model/resources/thermal/thermal_commit.jl @@ -41,7 +41,7 @@ where decision $\nu_{y,z,t}$ designates the commitment state of generator cluste *Commitment state constraint linking start-up and shut-down decisions* -Additionally, the following constarint maintains the commitment state variable across time, $\nu_{y,z,t}$, as the sum of the commitment state in the prior, $\nu_{y,z,t-1}$, period plus the number of units started in the current period, $\chi_{y,z,t}$, less the number of units shut down in the current period, $\zeta_{y,z,t}$: +Additionally, the following constraint maintains the commitment state variable across time, $\nu_{y,z,t}$, as the sum of the commitment state in the prior, $\nu_{y,z,t-1}$, period plus the number of units started in the current period, $\chi_{y,z,t}$, less the number of units shut down in the current period, $\zeta_{y,z,t}$: ```math \begin{aligned} diff --git a/src/model/resources/thermal/thermal_no_commit.jl b/src/model/resources/thermal/thermal_no_commit.jl index 9468138746..61052f3c02 100644 --- a/src/model/resources/thermal/thermal_no_commit.jl +++ b/src/model/resources/thermal/thermal_no_commit.jl @@ -141,7 +141,7 @@ When modeling regulation and spinning reserves, thermal units not subject to uni \end{aligned} ``` -Note there are multiple versions of these constraints in the code in order to avoid creation of unecessary constraints and decision variables for thermal units unable to provide regulation and/or reserves contributions due to input parameters (e.g. ```Reg_Max=0``` and/or ```RSV_Max=0```). +Note there are multiple versions of these constraints in the code in order to avoid creation of unnecessary constraints and decision variables for thermal units unable to provide regulation and/or reserves contributions due to input parameters (e.g. ```Reg_Max=0``` and/or ```RSV_Max=0```). """ function thermal_no_commit_operational_reserves!(EP::Model, inputs::Dict) println("Thermal No Commit Reserves Module") diff --git a/src/model/resources/vre_stor/vre_stor.jl b/src/model/resources/vre_stor/vre_stor.jl index 6a36395b93..f82d19f49c 100644 --- a/src/model/resources/vre_stor/vre_stor.jl +++ b/src/model/resources/vre_stor/vre_stor.jl @@ -511,11 +511,11 @@ function inverter_vre_stor!(EP::Model, inputs::Dict, setup::Dict) # Cannot retire more capacity than existing capacity for VRE-STOR technologies @constraint(EP, cMaxRet_DC[y = RET_CAP_DC], vRETDCCAP[y]<=eExistingCapDC[y]) # Constraint on maximum capacity (if applicable) [set input to -1 if no constraint on maximum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasibility @constraint(EP, cMaxCap_DC[y in ids_with_nonneg(gen_VRE_STOR, max_cap_inverter_mw)], eTotalCap_DC[y]<=by_rid(y, :max_cap_inverter_mw)) # Constraint on Minimum capacity (if applicable) [set input to -1 if no constraint on minimum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasibility @constraint(EP, cMinCap_DC[y in ids_with_positive(gen_VRE_STOR, min_cap_inverter_mw)], eTotalCap_DC[y]>=by_rid(y, :min_cap_inverter_mw)) @@ -686,11 +686,11 @@ function solar_vre_stor!(EP::Model, inputs::Dict, setup::Dict) # Cannot retire more capacity than existing capacity for VRE-STOR technologies @constraint(EP, cMaxRet_Solar[y = RET_CAP_SOLAR], vRETSOLARCAP[y]<=eExistingCapSolar[y]) # Constraint on maximum capacity (if applicable) [set input to -1 if no constraint on maximum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasibility @constraint(EP, cMaxCap_Solar[y in ids_with_nonneg(gen_VRE_STOR, max_cap_solar_mw)], eTotalCap_SOLAR[y]<=by_rid(y, :max_cap_solar_mw)) # Constraint on Minimum capacity (if applicable) [set input to -1 if no constraint on minimum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasibility @constraint(EP, cMinCap_Solar[y in ids_with_positive(gen_VRE_STOR, min_cap_solar_mw)], eTotalCap_SOLAR[y]>=by_rid(y, :min_cap_solar_mw)) @@ -865,11 +865,11 @@ function wind_vre_stor!(EP::Model, inputs::Dict, setup::Dict) # Cannot retire more capacity than existing capacity for VRE-STOR technologies @constraint(EP, cMaxRet_Wind[y = RET_CAP_WIND], vRETWINDCAP[y]<=eExistingCapWind[y]) # Constraint on maximum capacity (if applicable) [set input to -1 if no constraint on maximum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasibility @constraint(EP, cMaxCap_Wind[y in ids_with_nonneg(gen_VRE_STOR, max_cap_wind_mw)], eTotalCap_WIND[y]<=by_rid(y, :max_cap_wind_mw)) # Constraint on Minimum capacity (if applicable) [set input to -1 if no constraint on minimum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasibility @constraint(EP, cMinCap_Wind[y in ids_with_positive(gen_VRE_STOR, min_cap_wind_mw)], eTotalCap_WIND[y]>=by_rid(y, :min_cap_wind_mw)) @@ -1280,11 +1280,11 @@ function stor_vre_stor!(EP::Model, inputs::Dict, setup::Dict) cMaxRet_Stor[y = RET_CAP_STOR], vRETCAPENERGY_VS[y]<=eExistingCapEnergy_VS[y]) # Constraint on maximum capacity (if applicable) [set input to -1 if no constraint on maximum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasibility @constraint(EP, cMaxCap_Stor[y in intersect(ids_with_nonneg(gen, max_cap_mwh), STOR)], eTotalCap_STOR[y]<=max_cap_mwh(gen[y])) # Constraint on minimum capacity (if applicable) [set input to -1 if no constraint on minimum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasibility @constraint(EP, cMinCap_Stor[y in intersect(ids_with_positive(gen, min_cap_mwh), STOR)], eTotalCap_STOR[y]>=min_cap_mwh(gen[y])) @@ -1353,7 +1353,7 @@ For resources where $\overline{\Omega_{y,z}^{elec}}$ and $\underline{\Omega_{y,z \hspace{4 cm} \forall y \in \mathcal{VS}^{elec}, z \in \mathcal{Z} \end{aligned} ``` -Constraint 2 applies ramping constraints on electrolyzers where consumption of electricity by electrolyzer $y$ in time $t$ is denoted by $\Pi_{y,z}$ and the rampping constraints are denoated by $\kappa_{y}$. +Constraint 2 applies ramping constraints on electrolyzers where consumption of electricity by electrolyzer $y$ in time $t$ is denoted by $\Pi_{y,z}$ and the ramping constraints are denoted by $\kappa_{y}$. ```math \begin{aligned} \Pi_{y,t-1} - \Pi_{y,t} \leq \kappa_{y}^{down} \Delta^{\text{total}}_{y}, \hspace{1cm} \forall y \in \mathcal{EL}, \forall t \in \mathcal{T} @@ -1477,11 +1477,11 @@ function elec_vre_stor!(EP::Model, inputs::Dict, setup::Dict) # Cannot retire more capacity than existing capacity for VRE-STOR technologies @constraint(EP, cMaxRet_Elec[y = RET_CAP_ELEC], vRETELECCAP[y]<=eExistingCapElec[y]) # Constraint on maximum capacity (if applicable) [set input to -1 if no constraint on maximum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is >= Max_Cap_MW and lead to infeasibility @constraint(EP, cMaxCap_Elec[y in ids_with_nonneg(gen_VRE_STOR, max_cap_elec_mw)], eTotalCap_ELEC[y]<=by_rid(y, :max_cap_elec_mw)) # Constraint on Minimum capacity (if applicable) [set input to -1 if no constraint on minimum capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Cap_MW is <= Min_Cap_MW and lead to infeasibility @constraint(EP, cMinCap_Elec[y in ids_with_positive(gen_VRE_STOR, min_cap_elec_mw)], eTotalCap_ELEC[y]>=by_rid(y, :min_cap_elec_mw)) @@ -1869,12 +1869,12 @@ function investment_charge_vre_stor!(EP::Model, inputs::Dict, setup::Dict) cVreStorMaxRetDischargeDC[y in RET_CAP_DISCHARGE_DC], vRETCAPDISCHARGE_DC[y]<=eExistingCapDischargeDC[y]) # Constraint on maximum discharge DC capacity (if applicable) [set input to -1 if no constraint on maximum discharge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cVreStorMaxCapDischargeDC[y in MAX_DC_DISCHARGE], eTotalCapDischarge_DC[y]<=by_rid(y, :Max_Cap_Discharge_DC_MW)) # Constraint on minimum discharge DC capacity (if applicable) [set input to -1 if no constraint on minimum discharge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cVreStorMinCapDischargeDC[y in MIN_DC_DISCHARGE], eTotalCapDischarge_DC[y]>=by_rid(y, :Min_Cap_Discharge_DC_MW)) @@ -1969,12 +1969,12 @@ function investment_charge_vre_stor!(EP::Model, inputs::Dict, setup::Dict) cVreStorMaxRetChargeDC[y in RET_CAP_CHARGE_DC], vRETCAPCHARGE_DC[y]<=eExistingCapChargeDC[y]) # Constraint on maximum charge DC capacity (if applicable) [set input to -1 if no constraint on maximum charge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cVreStorMaxCapChargeDC[y in MAX_DC_CHARGE], eTotalCapCharge_DC[y]<=by_rid(y, :max_cap_charge_dc_mw)) # Constraint on minimum charge DC capacity (if applicable) [set input to -1 if no constraint on minimum charge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cVreStorMinCapChargeDC[y in MIN_DC_CHARGE], eTotalCapCharge_DC[y]>=by_rid(y, :min_cap_charge_dc_mw)) @@ -2073,12 +2073,12 @@ function investment_charge_vre_stor!(EP::Model, inputs::Dict, setup::Dict) cVreStorMaxRetDischargeAC[y in RET_CAP_DISCHARGE_AC], vRETCAPDISCHARGE_AC[y]<=eExistingCapDischargeAC[y]) # Constraint on maximum discharge AC capacity (if applicable) [set input to -1 if no constraint on maximum charge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cVreStorMaxCapDischargeAC[y in MAX_AC_DISCHARGE], eTotalCapDischarge_AC[y]<=by_rid(y, :max_cap_discharge_ac_mw)) # Constraint on minimum discharge AC capacity (if applicable) [set input to -1 if no constraint on minimum charge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cVreStorMinCapDischargeAC[y in MIN_AC_DISCHARGE], eTotalCapDischarge_AC[y]>=by_rid(y, :min_cap_discharge_ac_mw)) @@ -2173,12 +2173,12 @@ function investment_charge_vre_stor!(EP::Model, inputs::Dict, setup::Dict) cVreStorMaxRetChargeAC[y in RET_CAP_CHARGE_AC], vRETCAPCHARGE_AC[y]<=eExistingCapChargeAC[y]) # Constraint on maximum charge AC capacity (if applicable) [set input to -1 if no constraint on maximum charge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is >= Max_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cVreStorMaxCapChargeAC[y in MAX_AC_CHARGE], eTotalCapCharge_AC[y]<=by_rid(y, :max_cap_charge_ac_mw)) # Constraint on minimum charge AC capacity (if applicable) [set input to -1 if no constraint on minimum charge capacity] - # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasabilty + # DEV NOTE: This constraint may be violated in some cases where Existing_Charge_Cap_MW is <= Min_Charge_Cap_MWh and lead to infeasibility @constraint(EP, cVreStorMinCapChargeAC[y in MIN_AC_CHARGE], eTotalCapCharge_AC[y]>=by_rid(y, :min_cap_charge_ac_mw)) diff --git a/src/model/solve_model.jl b/src/model/solve_model.jl index e3713bc67b..d916e127fc 100644 --- a/src/model/solve_model.jl +++ b/src/model/solve_model.jl @@ -1,13 +1,13 @@ @doc raw""" fix_integers(jump_model::Model) -This function fixes the iteger variables ones the model has been solved in order to calculate approximations of dual variables. +This function fixes the integer variables ones the model has been solved in order to calculate approximations of dual variables. # Arguments - `jump_model::Model`: a model object containing that has been previously solved. # Returns -nothing (modifies an existing-solved model in the memory). `solve()` must be run again to solve and getdual veriables +nothing (modifies an existing-solved model in the memory). `solve()` must be run again to solve and getdual variables """ function fix_integers(jump_model::Model) @@ -16,11 +16,11 @@ function fix_integers(jump_model::Model) ## ## inputs: jump_model - a model object containing that has been previously solved. ## - ## description: fixes the iteger variables ones the model has been solved in order + ## description: fixes the integer variables ones the model has been solved in order ## to calculate approximations of dual variables ## ## returns: no result since it modifies an existing-solved model in the memory. - ## solve() must be run again to solve and getdual veriables + ## solve() must be run again to solve and getdual variables ## ################################################################################ values = Dict(v => value(v) for v in all_variables(jump_model)) @@ -68,7 +68,7 @@ function solve_model(EP::Model, setup::Dict) @info "No model solution. You can try to set ComputeConflicts to 1 in the genx_settings.yml file to compute conflicting constraints." elseif setup["ComputeConflicts"] == 1 - @info "No model solution. Trying to identify conflicting constriants..." + @info "No model solution. Trying to identify conflicting constraints..." try compute_conflict!(EP) diff --git a/src/multi_stage/configure_multi_stage_inputs.jl b/src/multi_stage/configure_multi_stage_inputs.jl index a1c887e02a..252f15bc10 100644 --- a/src/multi_stage/configure_multi_stage_inputs.jl +++ b/src/multi_stage/configure_multi_stage_inputs.jl @@ -1,7 +1,7 @@ @doc raw""" function compute_overnight_capital_cost(settings_d::Dict,inv_costs_yr::Array,crp::Array,tech_wacc::Array) -This function computes overnight capital costs incured within the model horizon, assuming that annualized costs to be paid after the model horizon are fully recoverable, and so are not included in the cost computation. +This function computes overnight capital costs incurred within the model horizon, assuming that annualized costs to be paid after the model horizon are fully recoverable, and so are not included in the cost computation. For each resource $y \in \mathcal{G}$ with annualized investment cost $AIC_{y}$ and capital recovery period $CRP_{y}$, overnight capital costs $OCC_{y}$ are computed as follows: ```math @@ -19,7 +19,7 @@ inputs: * tech_wacc - array object containing technology-specific weighted costs of capital. NOTE: The inv\_costs\_yr and crp arrays must be the same length; values with the same index in each array correspond to the same resource $y \in \mathcal{G}$. -returns: array object containing overnight capital costs, the discounted sum of annual investment costs incured within the model horizon. +returns: array object containing overnight capital costs, the discounted sum of annual investment costs incurred within the model horizon. """ function compute_overnight_capital_cost(settings_d::Dict, inv_costs_yr::Array, @@ -55,7 +55,7 @@ function compute_overnight_capital_cost(settings_d::Dict, init = 0) end - # 3) Return the overnight capital cost (discounted sum of annual investment costs incured within the model horizon) + # 3) Return the overnight capital cost (discounted sum of annual investment costs incurred within the model horizon) return occ end @@ -66,9 +66,9 @@ This function overwrites input parameters read in via the load\_inputs() method 1) Overnight capital costs are computed via the compute\_overnight\_capital\_cost() method and overwrite internal model representations of annualized investment costs. -2) Annualized fixed O&M costs are scaled up to represent total fixed O&M incured over the length of each model stage (specified by "StageLength" field in multi\_stage\_settings.yml). +2) Annualized fixed O&M costs are scaled up to represent total fixed O&M incurred over the length of each model stage (specified by "StageLength" field in multi\_stage\_settings.yml). -3) Internal set representations of resources eligible for capacity retirements are overwritten to ensure compatability with multi-stage modeling. +3) Internal set representations of resources eligible for capacity retirements are overwritten to ensure compatibility with multi-stage modeling. 4) When NetworkExpansion is active and there are multiple model zones, parameters related to transmission and network expansion are updated. First, annualized transmission reinforcement costs are converted into overnight capital costs. Next, the maximum allowable transmission line reinforcement parameter is overwritten by the model stage-specific value specified in the "Line\_Max\_Flow\_Possible\_MW" fields in the network\_multi\_stage.csv file. Finally, internal representations of lines eligible or not eligible for transmission expansion are overwritten based on the updated maximum allowable transmission line reinforcement parameters. @@ -97,7 +97,7 @@ function configure_multi_stage_inputs(inputs_d::Dict, inputs_d["OPEXMULT"] = OPEXMULT if !myopic ### Leave myopic costs in annualized form and do not scale OPEX costs - # 1. Convert annualized investment costs incured within the model horizon into overnight capital costs + # 1. Convert annualized investment costs incurred within the model horizon into overnight capital costs # NOTE: Although the "yr" suffix is still in use in these parameter names, they no longer represent annualized costs but rather truncated overnight capital costs gen.inv_cost_per_mwyr = compute_overnight_capital_cost(settings_d, inv_cost_per_mwyr.(gen), @@ -113,7 +113,7 @@ function configure_multi_stage_inputs(inputs_d::Dict, tech_wacc.(gen)) # 2. Update fixed O&M costs to account for the possibility of more than 1 year between two model stages - # NOTE: Although the "yr" suffix is still in use in these parameter names, they now represent total costs incured in each stage, which may be multiple years + # NOTE: Although the "yr" suffix is still in use in these parameter names, they now represent total costs incurred in each stage, which may be multiple years gen.fixed_om_cost_per_mwyr = fixed_om_cost_per_mwyr.(gen) .* OPEXMULT gen.fixed_om_cost_per_mwhyr = fixed_om_cost_per_mwhyr.(gen) .* OPEXMULT gen.fixed_om_cost_charge_per_mwyr = fixed_om_cost_charge_per_mwyr.(gen) .* OPEXMULT @@ -207,7 +207,7 @@ function configure_multi_stage_inputs(inputs_d::Dict, # Transmission if NetworkExpansion == 1 && inputs_d["Z"] > 1 if !myopic ### Leave myopic costs in annualized form - # 1. Convert annualized tramsmission investment costs incured within the model horizon into overnight capital costs + # 1. Convert annualized transmission investment costs incurred within the model horizon into overnight capital costs inputs_d["pC_Line_Reinforcement"] = compute_overnight_capital_cost(settings_d, inputs_d["pC_Line_Reinforcement"], inputs_d["Capital_Recovery_Period_Trans"], @@ -226,7 +226,7 @@ function configure_multi_stage_inputs(inputs_d::Dict, (inputs_d["pMax_Line_Reinforcement"] .<= 0)) # To-Do: Error Handling - # 1.) Enforce that pLine_Max_Flow_Possible_MW for the first model stage be equal to (for transmission expansion to be disalowed) or greater (to allow transmission expansion) than pTrans_Max in inputs/inputs_p1 + # 1.) Enforce that pLine_Max_Flow_Possible_MW for the first model stage be equal to (for transmission expansion to be disallowed) or greater (to allow transmission expansion) than pTrans_Max in inputs/inputs_p1 end return inputs_d @@ -235,7 +235,7 @@ end @doc raw""" validate_can_retire_multistage(inputs_dict::Dict, num_stages::Int) -This function validates that all the resources do not switch from havig `can_retire = 0` to `can_retire = 1` during the multi-stage optimization. +This function validates that all the resources do not switch from having `can_retire = 0` to `can_retire = 1` during the multi-stage optimization. # Arguments - `inputs_dict::Dict`: A dictionary containing the inputs for each stage. diff --git a/src/multi_stage/dual_dynamic_programming.jl b/src/multi_stage/dual_dynamic_programming.jl index f4feea9f86..30be55a221 100644 --- a/src/multi_stage/dual_dynamic_programming.jl +++ b/src/multi_stage/dual_dynamic_programming.jl @@ -125,7 +125,7 @@ end @doc raw""" run_ddp(models_d::Dict, setup::Dict, inputs_d::Dict) -This function run the dual dynamic programming (DDP) algorithm, as described in [Pereira and Pinto (1991)](https://doi.org/10.1007/BF01582895), and more recently, [Lara et al. (2018)](https://doi.org/10.1016/j.ejor.2018.05.039). Note that if the algorithm does not converge within 10,000 (currently hardcoded) iterations, this function will return models with sub-optimal solutions. However, results will still be printed as if the model is finished solving. This sub-optimal termination is noted in the output with the 'Exiting Without Covergence!' message. +This function run the dual dynamic programming (DDP) algorithm, as described in [Pereira and Pinto (1991)](https://doi.org/10.1007/BF01582895), and more recently, [Lara et al. (2018)](https://doi.org/10.1016/j.ejor.2018.05.039). Note that if the algorithm does not converge within 10,000 (currently hardcoded) iterations, this function will return models with sub-optimal solutions. However, results will still be printed as if the model is finished solving. This sub-optimal termination is noted in the output with the 'Exiting Without Convergence!' message. inputs: @@ -193,7 +193,7 @@ function run_ddp(outpath::AbstractString, models_d::Dict, setup::Dict, inputs_d: if (ic > 10000) println("***********") - println("Exiting Without Covergence!") + println("Exiting Without Convergence!") println(string("Upper Bound = ", z_upper)) println(string("Lower Bound = ", z_lower)) println("***********") @@ -208,7 +208,7 @@ function run_ddp(outpath::AbstractString, models_d::Dict, setup::Dict, inputs_d: println("***********") # Step d) Forward pass for t = 1:num_stages - ## For first iteration we dont need to solve forward pass for first stage (we did that already above), + ## For first iteration we don't need to solve forward pass for first stage (we did that already above), ## but we need to update forward pass solution for the first stage for subsequent iterations if ic > 1 t = 1 # update forward pass solution for the first stage @@ -395,8 +395,8 @@ function fix_capacity_tracking(EP_prev::Model, # and the associated linking constraint name (c) as a value for (v, c) in cap_track_d - # Tracking variables and constraints for retired capacity are named identicaly to those for newly - # built capacity, except have the prefex "vRET" and "cRet", accordingly + # Tracking variables and constraints for retired capacity are named identically to those for newly + # built capacity, except have the prefix "vRET" and "cRet", accordingly rv = Symbol("vRET", string(v)[2:end]) # Retired capacity tracking variable name (rv) rc = Symbol("cRet", string(c)[2:end]) # Retired capacity tracking constraint name (rc) @@ -406,7 +406,7 @@ function fix_capacity_tracking(EP_prev::Model, # For all previous stages, set the right hand side value of the tracking constraint in the current # stage to the value of the tracking constraint observed in the previous stage for p in 1:(cur_stage - 1) - # Tracking newly buily capacity over all previous stages + # Tracking newly built capacity over all previous stages JuMP.set_normalized_rhs(EP_cur[c][i, p], value(EP_prev[v][i, p])) # Tracking retired capacity over all previous stages JuMP.set_normalized_rhs(EP_cur[rc][i, p], value(EP_prev[rv][i, p])) diff --git a/src/multi_stage/endogenous_retirement.jl b/src/multi_stage/endogenous_retirement.jl index aa13805b3c..da7265cea2 100644 --- a/src/multi_stage/endogenous_retirement.jl +++ b/src/multi_stage/endogenous_retirement.jl @@ -307,7 +307,7 @@ function endogenous_retirement_charge!(EP::Model, eMinRetCapTrackCharge[y in RET_CAP_CHARGE], cum_min_retired_charge_cap_mw(gen[y])) - ### Constratints ### + ### Constraints ### # Keep track of newly built capacity from previous stages @constraint(EP, @@ -373,7 +373,7 @@ function endogenous_retirement_energy!(EP::Model, eMinRetCapTrackEnergy[y in RET_CAP_ENERGY], cum_min_retired_energy_cap_mw(gen[y])) - ### Constratints ### + ### Constraints ### # Keep track of newly built capacity from previous stages @constraint(EP, @@ -692,7 +692,7 @@ function endogenous_retirement_vre_stor_stor!( eMinRetCapTrackEnergy_VS[y in RET_CAP_STOR], cum_min_retired_energy_cap_mw(gen[y])) - ### Constratints ### + ### Constraints ### # Keep track of newly built capacity from previous stages @constraint(EP, diff --git a/src/multi_stage/write_multi_stage_stats.jl b/src/multi_stage/write_multi_stage_stats.jl index 7f37b04043..47de7ed6e5 100644 --- a/src/multi_stage/write_multi_stage_stats.jl +++ b/src/multi_stage/write_multi_stage_stats.jl @@ -26,12 +26,12 @@ function write_multi_stage_stats(outpath::String, stats_d::Dict) # Create an array of numbers 1 through total number of iterations iteration_count_a = collect(1:length(times_a)) - realtive_gap_a = (upper_bounds_a .- lower_bounds_a) ./ lower_bounds_a + relative_gap_a = (upper_bounds_a .- lower_bounds_a) ./ lower_bounds_a # Construct dataframe where first column is iteration number, second is iteration time header = _get_multi_stage_stats_header() df_stats = DataFrame(header .=> - [iteration_count_a, times_a, upper_bounds_a, lower_bounds_a, realtive_gap_a]) + [iteration_count_a, times_a, upper_bounds_a, lower_bounds_a, relative_gap_a]) CSV.write(joinpath(outpath, filename), df_stats) return nothing diff --git a/src/time_domain_reduction/time_domain_reduction.jl b/src/time_domain_reduction/time_domain_reduction.jl index 36aa7ecb6d..4491ae626d 100644 --- a/src/time_domain_reduction/time_domain_reduction.jl +++ b/src/time_domain_reduction/time_domain_reduction.jl @@ -630,7 +630,7 @@ In Demand_data.csv, include the following: If 1, this designates that the model should time domain reduce the input data of all model stages together. Else if 0, [still in development] the model will time domain reduce only the first stage and will apply the periods of each other model stage to this set - of representative periods by closest Eucliden distance. + of representative periods by closest Euclidean distance. For co-located VRE-STOR resources, all capacity factors must be in the Generators_variability.csv file in addition to separate Vre_and_stor_solar_variability.csv and Vre_and_stor_wind_variability.csv files. The co-located solar PV @@ -688,7 +688,7 @@ function cluster_inputs(inpath, # If ParameterScale =1 then make it zero, since clustered inputs will be scaled prior to generating model mysetup_local["ParameterScale"] = 0 # Performing cluster and report outputs in user-provided units - # Define another local version of setup such that Multi-Stage Non-Concatentation TDR can iteratively read in the raw data + # Define another local version of setup such that Multi-Stage Non-Concatenation TDR can iteratively read in the raw data mysetup_MS = copy(mysetup) mysetup_MS["TimeDomainReduction"] = 0 mysetup_MS["DoNotReadPeriodMap"] = 1 @@ -818,7 +818,7 @@ function cluster_inputs(inpath, AnnualTSeriesNormalized = DataFrame(Dict(OldColNames[c] => normProfiles[c] for c in 1:length(OldColNames))) - # Optional pre-scaling of demand in order to give it more preference in clutering algorithm + # Optional pre-scaling of demand in order to give it more preference in clustering algorithm if DemandWeight != 1 # If we want to value demand more/less than capacity factors. Assume nonnegative. LW=1 means no scaling. for c in demand_col_names AnnualTSeriesNormalized[!, Symbol(c)] .= AnnualTSeriesNormalized[!, @@ -1065,7 +1065,7 @@ function cluster_inputs(inpath, M_Dict[parse(Int64, string(names(ClusteringInputDF)[i]))] = M[A[i]] end - # Add extreme periods into the clustering result with # of occurences = 1 for each + # Add extreme periods into the clustering result with # of occurrences = 1 for each ExtremeWksList = sort(ExtremeWksList) if UseExtremePeriods == 1 if v @@ -1079,7 +1079,7 @@ function cluster_inputs(inpath, push!(W, 1) A_idx += 1 end - NClusters += length(ExtremeWksList) #NClusers from this point forward is the ending number of periods + NClusters += length(ExtremeWksList) #NClusters from this point forward is the ending number of periods end # Recreate A in numeric order (as opposed to ClusterInputDF order) @@ -1113,7 +1113,7 @@ function cluster_inputs(inpath, FuelCols = [Symbol(fuel_col_names[i]) for i in 1:length(fuel_col_names)] ConstCol_Syms = [Symbol(ConstCols[i]) for i in 1:length(ConstCols)] - # Cluster Ouput: The original data at the medoids/centers + # Cluster Output: The original data at the medoids/centers ClusterOutputData = ModifiedData[:, Symbol.(M)] # Get zone-wise demand multipliers for later scaling in order for weighted-representative-total-zonal demand to equal original total-zonal demand diff --git a/src/write_outputs/dftranspose.jl b/src/write_outputs/dftranspose.jl index ec9d1a5f39..409ade071f 100644 --- a/src/write_outputs/dftranspose.jl +++ b/src/write_outputs/dftranspose.jl @@ -23,4 +23,4 @@ function dftranspose(df::DataFrame, withhead::Bool) return DataFrame([[names(df)]; collect.(eachrow(df))], [:Row; Symbol.("x", axes(df, 1))]) end -end # End dftranpose() +end # End dftranspose() diff --git a/src/write_outputs/energy_share_requirement/write_esr_revenue.jl b/src/write_outputs/energy_share_requirement/write_esr_revenue.jl index 580ee45837..6588184516 100644 --- a/src/write_outputs/energy_share_requirement/write_esr_revenue.jl +++ b/src/write_outputs/energy_share_requirement/write_esr_revenue.jl @@ -1,7 +1,7 @@ @doc raw""" write_esr_revenue(path::AbstractString, inputs::Dict, setup::Dict, dfPower::DataFrame, dfESR::DataFrame, EP::Model) -Function for reporting the renewable/clean credit revenue earned by each generator listed in the input file. GenX will print this file only when RPS/CES is modeled and the shadow price can be obtained form the solver. Each row corresponds to a generator, and each column starting from the 6th to the second last is the total revenue earned from each RPS constraint. The revenue is calculated as the total annual generation (if elgible for the corresponding constraint) multiplied by the RPS/CES price. The last column is the total revenue received from all constraint. The unit is \$. +Function for reporting the renewable/clean credit revenue earned by each generator listed in the input file. GenX will print this file only when RPS/CES is modeled and the shadow price can be obtained form the solver. Each row corresponds to a generator, and each column starting from the 6th to the second last is the total revenue earned from each RPS constraint. The revenue is calculated as the total annual generation (if eligible for the corresponding constraint) multiplied by the RPS/CES price. The last column is the total revenue received from all constraint. The unit is \$. """ function write_esr_revenue(path::AbstractString, inputs::Dict, diff --git a/src/write_outputs/write_capacity.jl b/src/write_outputs/write_capacity.jl index 9a52bb6351..08a41f1d88 100755 --- a/src/write_outputs/write_capacity.jl +++ b/src/write_outputs/write_capacity.jl @@ -1,7 +1,7 @@ @doc raw""" write_capacity(path::AbstractString, inputs::Dict, setup::Dict, EP::Model)) -Function for writing the diferent capacities for the different generation technologies (starting capacities or, existing capacities, retired capacities, and new-built capacities). +Function for writing the different capacities for the different generation technologies (starting capacities or, existing capacities, retired capacities, and new-built capacities). """ function write_capacity(path::AbstractString, inputs::Dict, setup::Dict, EP::Model) gen = inputs["RESOURCES"] diff --git a/src/write_outputs/write_capacityfactor.jl b/src/write_outputs/write_capacityfactor.jl index c6f5352bf8..e061c513b4 100644 --- a/src/write_outputs/write_capacityfactor.jl +++ b/src/write_outputs/write_capacityfactor.jl @@ -125,7 +125,7 @@ function write_fusion_net_capacity_factor(path::AbstractString, inputs::Dict, se df.NetOutput .= gross_power - parasitic_power df.NetCapacity .= value.(EP[:eTotalCap][FUSION]) * scale_factor .* avg_power_factor - # We only calcualte the resulted capacity factor with total capacity > 1MW and total generation > 1MWh + # We only calculate the resulted capacity factor with total capacity > 1MW and total generation > 1MWh enough_power = findall(x -> x >= 1, df.NetOutput) enough_capacity = findall(x -> x >= 1, df.NetCapacity) CF_GEN = intersect(enough_power, enough_capacity) diff --git a/src/write_outputs/write_net_revenue.jl b/src/write_outputs/write_net_revenue.jl index 55f9a16b99..681fba71fc 100644 --- a/src/write_outputs/write_net_revenue.jl +++ b/src/write_outputs/write_net_revenue.jl @@ -185,7 +185,7 @@ function write_net_revenue(path::AbstractString, dfNetRevenue.Charge_cost = dfChargingcost[1:G, :AnnualSum] # Unit is confirmed to be US$ end - # Add CO2 releated sequestration cost or credit (e.g. 45 Q) to the dataframe + # Add CO2 related sequestration cost or credit (e.g. 45 Q) to the dataframe dfNetRevenue.CO2SequestrationCost = zeros(nrow(dfNetRevenue)) if any(co2_capture_fraction.(gen) .!= 0) dfNetRevenue.CO2SequestrationCost = zeros(G) diff --git a/src/write_outputs/write_outputs.jl b/src/write_outputs/write_outputs.jl index e8ce378e71..473a5a43f2 100644 --- a/src/write_outputs/write_outputs.jl +++ b/src/write_outputs/write_outputs.jl @@ -18,7 +18,7 @@ function write_outputs(EP::Model, path::AbstractString, setup::Dict, inputs::Dic mkpath(path) end else - # Find closest unused ouput directory name and create it + # Find closest unused output directory name and create it path = choose_output_dir(path) mkpath(path) end @@ -30,7 +30,7 @@ function write_outputs(EP::Model, path::AbstractString, setup::Dict, inputs::Dic # https://jump.dev/MathOptInterface.jl/v0.9.10/apireference/#MathOptInterface.TerminationStatusCode status = termination_status(EP) - ## Check if solved sucessfully - time out is included + ## Check if solved successfully - time out is included if status != MOI.OPTIMAL && status != MOI.LOCALLY_SOLVED if status != MOI.TIME_LIMIT # Model failed to solve, so record solver status and exit write_status(path, inputs, setup, EP) @@ -270,7 +270,7 @@ function write_outputs(EP::Model, path::AbstractString, setup::Dict, inputs::Dic println(elapsed_time_angles) end - # Temporary! Suppress these outputs until we know that they are compatable with multi-stage modeling + # Temporary! Suppress these outputs until we know that they are compatible with multi-stage modeling if setup["MultiStage"] == 0 dfEnergyRevenue = DataFrame() dfChargingcost = DataFrame() @@ -413,7 +413,7 @@ function write_outputs(EP::Model, path::AbstractString, setup::Dict, inputs::Dic inputs, setup, EP) - println("Time elapsed for writing oerating reserve and regulation revenue is") + println("Time elapsed for writing operating reserve and regulation revenue is") println(elapsed_time_op_res_rev) end