-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a feature to enable thermal power plants to burn multiple fuels #586
Conversation
1. In load_fuels_data.jl, there is no need to scale fuel_co2 as it will cause scaling issues when the parameter scale is on. 2. In load_generator_data.jl, remove the start up fuel costs as all the costs associated with fuel consumption will be accounted in fuel.jl. 3. In discharge.jl, remove the fuel costs as they will be separately accounted in fuel.jl 4. In Generate_model.jl, remove emissions!(EP, inputs) as emissions.jl will be replaced by CO2.jl. include fuel.jl. 5. Fuel.jl is a module that tracks the consumption (MMBTU or billion BTU scaled) and costs ($ or million $) of fuels used in generators (startup fuels included as well). It also includes a piecewise fuel consumption option if you want to represent the fuel consumption during different load factor. 6. CO2.jl is an updated version of emissios.jl, and we don’t need emissions.jl when we have co2.jl. Also added BECCS options in CO2.jl, line 29 and line 39. Basically, when BECCS plants are included, “Generator_data.csv” should have a column named “BECCS”, and the values under “BECCS” column should be 1 for BECCS facilities and 0 for non-BECCS facilities. The amount of CO2 captured and stored for BECCS generators are accounted in the same way as other thermal generators, but its corresponding emissions should be negative. 7. Modified write_costs such that fuel costs are appropriately included. 8. Include write_co2.jl and write_fuel_consumption.jl, which give co2 emissions and fuel consumption for each generator. Co-Authored-By: Qingyu Xu <[email protected]>
accidently deleted eEmissionsByZone... added them in this version. Co-Authored-By: Qingyu Xu <[email protected]>
1. Reduce the number of variables by removing P1 and P2 2. Add a placeholder for possible different heat rates when cofiring 3. Change column name "Fuel1" back to "Fuel"
…a loading script to use defaults if second fuel is not in input file
Add constraints related to EPA new rules: capacity factor, emission rate, ...
Add varialbes "THERM_DUAL" and "THERM_SING" Apply maximum co-fire level constraints to THERM_DUAL \
allow users to specify "Fuel1", "Fuel2", ..., "FuelN" enable resources to use multi fuels for both startup and operations remove codes related to "fuel2" create a new example case "ThreeZones_Multi_Fuel"
include multiple fuels in write_fuel_consumption separate consumption and costs of fuels during startup and normal operations when writing outputs
add descriptions and math for multi fuels
make heat rates 0 for non-thermal resources add conditional evaluation to fuel.jl and write_fueL_consumption so that the model can run when multi_fuel does not exist.
Separate startup and generation fuels when writing outputs Add blending level constraints during startup processes and corresponding new columns in Generators_data.jl Fix bugs for blending constraints
1. add fuel cost for multi-fuel resources (ePlantCFuelOut_multi, ePlantCFuelOut_multi_start); 2. make eCFuel_out only consider fuel costs during generation; 3. change *_startup to _start to be consistent with other files; 4. delete the column for start fuel costs when writing costs and combine it with generation fuel cost 5. add error message when both "PieceWiseHeatRate" and "MULTI_FUELS" exist; 6. fix some typos when calculating fuel costs.
1. enable RETROFIT by commenting out the error message in load_generators_data.jl 2. add the variable "MULTI_FUELS" to indicate whether a resource uses multi fuels when writing fuel consumption 3. bug fix
1. Fix eFuelConsumption and fuel costs for MULTI_FUELS resources; 2. Fix bugs in writing out retrofitted capacity; 3. Disable writing some CO2 emission outputs when only unit-level CO2 emission constraints are used
1. Remove constraints on capacity factors 2. Remove constraints on unit-level emission rates 3. Change a column name in Fuel_cost_plant.csv (from "AnnualSum" to "AnnualSumCosts) 4. Remove EPA example system
Add an optional formulation for scheduled maintenance. Plants with this formulation active (so far, limited to thermal-commit plants, THERM=1) need to undergo a certain number of contiguous hours of maintenance every y >= 1 years. During this time they produce no power. This may be particularly useful in modeling fission plants, which need roughly 4 weeks of maintenance every 18 or 24 months. (Here, 18 would need to be rounded up to 24, as only maintenance cycles which are an integer number of years work with this formulation.)
Change the New_Build column to accept only {0, 1}; add a new required column Can_Retire which handles that feature separately (also {0, 1}). The change is backward-compatible, with a warning to update. --------- Co-authored-by: Gabe Mantegna <[email protected]>
Fixed computation of cumulative minimum retirements in multistage code. Previously, minimum capacity retirement parameters were not added up and this resulted in the minimum retirement constraints enforcing wrong lower bounds (#542)
undo changes to files which are comment-only or whitespace-only
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, @qluo0320github; this is an excellent contribution! I added a few comments with suggestions for minor changes, but overall, this PR is already in great shape.
inputs_gen["RETRO"] = gen_in[gen_in.RETRO.==1,:R_ID] | ||
# Disable Retrofit while it's under development | ||
if !(isempty(inputs_gen["RETRO"])) | ||
error("The Retrofits feature, which is activated by nonzero data in a 'RETRO' column in Generators_data.csv, is under development and is not ready for public use. Disable this message to enable this *experimental* feature.") | ||
end | ||
|
||
# Set of multi-fuel resources | ||
if "MULTI_FUELS" ∉ names(gen_in) | ||
gen_in[!, "MULTI_FUELS"] = zero(gen_in[!, "R_ID"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use zeros(G)
to create a vector of zero elements of length G
(it should be faster because it doesn't read the data frame)
gen_in[!, "MULTI_FUELS"] = zero(gen_in[!, "R_ID"]) | |
gen_in[!, "MULTI_FUELS"] = zeros(G) |
@@ -219,7 +223,7 @@ function load_generators_data!(setup::Dict, path::AbstractString, inputs_gen::Di | |||
end | |||
|
|||
load_vre_stor_data!(inputs_gen, setup, path) | |||
|
|||
load_multi_fuels_data!(inputs_gen, setup, path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest defining here the two entries inputs_gen["SINGLE_FUEL"]
and inputs_gen["MULTI_FUELS"]
instead of inside the load_multi_fuels_data!
, and adding the function call inside a if !isempty(inputs_gen["MULTI_FUELS"]) end
block. Something like:
# Single-fuel resources
inputs_gen["SINGLE_FUEL"] = gen_in[gen_in.MULTI_FUELS.!=1,:R_ID]
# Multi-fuel resources
inputs_gen["MULTI_FUELS"] = gen_in[gen_in.MULTI_FUELS.==1,:R_ID]
if !isempty(inputs_gen["MULTI_FUELS"]) # If there are any resources using multi fuels, read relevant data
load_multi_fuels_data!(inputs_gen, setup, path)
end
inputs_gen["NUM_FUELS"] = gen_in[!,:Num_Fuels] # Number of fuels that this resource can use | ||
max_fuels = maximum(inputs_gen["NUM_FUELS"]) | ||
fuel_cols = [ Symbol(string("Fuel",i)) for i in 1:max_fuels ] | ||
heat_rate_cols = [ Symbol(string("Heat_Rate",i, "_MMBTU_per_MWh")) for i in 1:max_fuels ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for f in 1:max_fuels
might be more readable than for i in 1:max_fuels
src/model/core/fuel.jl
Outdated
else | ||
error("Multi-fuel option is not available when piece-wise heat rates are used. Please remove multi fuels to avoid this error.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'd also suggest moving this check in load_generators_data
(for example, inside process_piecewisefuelusage!
or load_multi_fuels_data!
)
@@ -169,7 +178,7 @@ function write_net_revenue(path::AbstractString, inputs::Dict, setup::Dict, EP:: | |||
end | |||
|
|||
dfNetRevenue.Revenue = dfNetRevenue.EnergyRevenue .+ dfNetRevenue.SubsidyRevenue .+ dfNetRevenue.ReserveMarginRevenue .+ dfNetRevenue.ESRRevenue .+ dfNetRevenue.RegSubsidyRevenue | |||
dfNetRevenue.Cost = dfNetRevenue.Inv_cost_MW .+ dfNetRevenue.Inv_cost_MWh .+ dfNetRevenue.Fixed_OM_cost_MW .+ dfNetRevenue.Fixed_OM_cost_MWh .+ dfNetRevenue.Var_OM_cost_out .+ dfNetRevenue.Var_OM_cost_in .+ dfNetRevenue.Fuel_cost .+ dfNetRevenue.Charge_cost .+ dfNetRevenue.EmissionsCost .+ dfNetRevenue.StartCost | |||
dfNetRevenue.Cost = dfNetRevenue.Inv_cost_MW .+ dfNetRevenue.Inv_cost_MWh .+ dfNetRevenue.Fixed_OM_cost_MW .+ dfNetRevenue.Fixed_OM_cost_MWh .+ dfNetRevenue.Var_OM_cost_out .+ dfNetRevenue.Var_OM_cost_in .+ dfNetRevenue.Fuel_cost .+ dfNetRevenue.Charge_cost .+ dfNetRevenue.EmissionsCost .+ dfNetRevenue.StartCost +dfNetRevenue.CO2SequestrationCost |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formally, it's identical, but for consistency, you could do the following:
dfNetRevenue.Cost = dfNetRevenue.Inv_cost_MW .+ dfNetRevenue.Inv_cost_MWh .+ dfNetRevenue.Fixed_OM_cost_MW .+ dfNetRevenue.Fixed_OM_cost_MWh .+ dfNetRevenue.Var_OM_cost_out .+ dfNetRevenue.Var_OM_cost_in .+ dfNetRevenue.Fuel_cost .+ dfNetRevenue.Charge_cost .+ dfNetRevenue.EmissionsCost .+ dfNetRevenue.StartCost +dfNetRevenue.CO2SequestrationCost | |
dfNetRevenue.Cost = dfNetRevenue.Inv_cost_MW .+ dfNetRevenue.Inv_cost_MWh .+ dfNetRevenue.Fixed_OM_cost_MW .+ dfNetRevenue.Fixed_OM_cost_MWh .+ dfNetRevenue.Var_OM_cost_out .+ dfNetRevenue.Var_OM_cost_in .+ dfNetRevenue.Fuel_cost .+ dfNetRevenue.Charge_cost .+ dfNetRevenue.EmissionsCost .+ dfNetRevenue.StartCost .+ dfNetRevenue.CO2SequestrationCost |
…es when reading generators_data.csv; 2. change i into f in load_generators_data.jl in "for i in 1:max_fuels"
…in function load_multi_fuels_data
…y when UCommit > 1
…y when THERM_COMMIT_PWFU exists but is not empty
Needs to check the write time performance once again by allocating more memory. @qluo0320github @filippopecci |
I ran multiple times with different memory and it did not change writing time significantly. @sambuddhac |
Description
This PR adds the feature that enables thermal power plants to burn multiple fuels.
Cofiring relatively cleaner energy is one of the carbon mitigation options, such cofiring H2 in natural gas turbines. This feature enables thermal generators ("THERM" in GenX) to burn multiple fuels at the same time and also allows the user to specify the cofiring level during both startup and generation processes to meet potential regulations. (e.g., H2 blending requirements in combustion turbines proposed by EPA). This feature also allows users to specify heat rates for different fuels in case there is any efficiency penalty due to cofiring.
Variables in
Generators_data.csv
required to use this feature: "MULTI_FUELS", "Num_Fuels", "Fuel1", "Heat_Rate1_MMBTU_per_MWh", "Fuel1_Min_Cofire_Level", "Fuel1_Min_Cofire_Level_Start", , "Fuel1_Max_Cofire_Level", "Fuel1_Max_Cofire_Level_Start", "Fuel2", "Heat_Rate2_MMBTU_per_MWh", "Fuel2_Min_Cofire_Level", "Fuel2_Min_Cofire_Level_Start", , "Fuel2_Max_Cofire_Level", "Fuel2_Max_Cofire_Level_Start" (assuming "MULTI_FUELS" = 1 and "Num_Fuels" = 2).What type of PR is this? (check all applicable)
Checklist
git merge develop
) or by rebasing on top of the target branch (e.g.git rebase develop
). Please do not hesitate to reach out to the GenX development team if you need help with this.How this can be tested
An example case is add to /Example_Systems/SmallNewEngland/ThreeZones_Multi_Fuel.
For any other cases without multi fuels, this feature should not change the results.
Post-approval checklist for GenX core developers
After the PR is approved