diff --git a/CHANGELOG.md b/CHANGELOG.md index 8679544e4a..8b4478add3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 non-zero in multi-stage GenX (#666) - Added condition number scaling added to objective function (#667) - Added versioned doc-pages for v0.3.6 and v0.4.0 + +- Added a warning message in write_costs_multistage mentioning th approximate value of costs currently. + +### Fixed - Add constraint in mga to compute total capacity in each zone from a given technology type (#681) - New settings parameter MGAAnnualGeneration to switch between different MGA formulations (#681) - Add validation for `Can_Retire` column in multi-stage GenX since the current implementation @@ -51,8 +55,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add writing of multistage stats during optimization with foresight (#687) - Fix docstring in operational_reserves.jl (#690) - Fix docstring in energy_share_requirement.jl (#692) - -### Fixed - Set MUST_RUN=1 for RealSystemExample/small_hydro plants (#517). Previously these plants had no resource flag set, and so they did not contribute to the power balance. As these plants are now useful, the objective in these cases is slightly lower. @@ -73,6 +75,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed outputting capital recovery cost to 0 if the remaining number of years is 0 (#666) - Updated the docstring for the initialize_cost_to_go function and adjusted the formula for the discount factor to reflect the code implementation (#672). - Fix write_multi_stage_cost.jl: add discount with OPEX multipliers to cUnmetPolicyPenalty (#679) +- Fix DF calculation in DDP to make it more generic for variable length stages (#680) - Fix write_power_balance.jl: add additional two columns ("VRE_Storage_Discharge" and "VRE_Storage_Charge") for VRE_STOR ### Changed diff --git a/src/multi_stage/dual_dynamic_programming.jl b/src/multi_stage/dual_dynamic_programming.jl index 60de7822c8..c7f0dacab5 100644 --- a/src/multi_stage/dual_dynamic_programming.jl +++ b/src/multi_stage/dual_dynamic_programming.jl @@ -560,7 +560,7 @@ The updated objective function $OBJ^{*}$ returned by this method takes the form: where $OBJ$ is the original objective function. $OBJ$ is scaled by two terms. The first is a discount factor (applied only in the non-myopic case), which discounts costs associated with the model stage $p$ to year-0 dollars: ```math \begin{aligned} - DF = \frac{1}{(1+WACC)^{L_{p}*(p-1)}} + DF = \frac{1}{(1+WACC)^{\sum^{(p-1)}_{k=0}L_{k}}} \end{aligned} ``` where $WACC$ is the weighted average cost of capital, and $L_{p}$ is the length of each stage in years (both set in multi\_stage\_settings.yml) @@ -584,6 +584,10 @@ returns: JuMP model with updated objective function. """ function initialize_cost_to_go(settings_d::Dict, EP::Model, inputs::Dict) cur_stage = settings_d["CurStage"] # Current DDP Investment Planning Stage + cum_years = 0 + for stage_count in 1:(cur_stage-1) + cum_years += settings_d["StageLengths"][stage_count] + end stage_len = settings_d["StageLengths"][cur_stage] wacc = settings_d["WACC"] # Interest Rate and also the discount rate unless specified other wise myopic = settings_d["Myopic"] == 1 # 1 if myopic (only one forward pass), 0 if full DDP @@ -596,7 +600,7 @@ function initialize_cost_to_go(settings_d::Dict, EP::Model, inputs::Dict) ### No discount factor or OPEX multiplier applied in myopic case as costs are left annualized. @objective(EP, Min, EP[:eObj]) else - DF = 1 / (1 + wacc)^(stage_len * (cur_stage - 1)) # Discount factor applied all to costs in each stage ### + DF = 1 / (1 + wacc)^(cum_years) # Discount factor applied all to costs in each stage ### # Initialize the cost-to-go variable @variable(EP, vALPHA>=0) @objective(EP, Min, DF * OPEXMULT * EP[:eObj]+vALPHA) diff --git a/src/multi_stage/write_multi_stage_costs.jl b/src/multi_stage/write_multi_stage_costs.jl index 6e71c2b5c1..f508052e3b 100644 --- a/src/multi_stage/write_multi_stage_costs.jl +++ b/src/multi_stage/write_multi_stage_costs.jl @@ -30,7 +30,13 @@ function write_multi_stage_costs(outpath::String, settings_d::Dict, inputs_dict: if myopic DF = 1 # DF=1 because we do not apply discount factor in myopic case else - DF = 1 / (1 + wacc)^(stage_lens[p] * (p - 1)) # Discount factor applied to ALL costs in each stage + cum_stage_length = 0 + if p > 1 + for stage_counter in 1:(p - 1) + cum_stage_length += stage_lens[stage_counter] + end + end + DF = 1 / (1 + wacc)^(cum_stage_length) # Discount factor applied to ALL costs in each stage end df_costs[!, Symbol("TotalCosts_p$p")] = DF .* costs_d[p][!, Symbol("Total")] end @@ -45,6 +51,7 @@ function write_multi_stage_costs(outpath::String, settings_d::Dict, inputs_dict: # Remove "cTotal" from results (as this includes Cost-to-Go) df_costs = df_costs[df_costs[!, :Costs] .!= "cTotal", :] + @warn("The cost calculation of the multi-stage GenX is approximate currently, and we will be refining it more in one of the future releases.") CSV.write(joinpath(outpath, "costs_multi_stage.csv"), df_costs) end