From cbb9217feb8cfab71d42fcbe30c79e90a85d464c Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Tue, 9 Apr 2024 14:13:01 -0400 Subject: [PATCH 01/16] Revised DF calculation in DDP initialize CTG --- src/multi_stage/dual_dynamic_programming.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/multi_stage/dual_dynamic_programming.jl b/src/multi_stage/dual_dynamic_programming.jl index 9703784473..25d7f0506b 100644 --- a/src/multi_stage/dual_dynamic_programming.jl +++ b/src/multi_stage/dual_dynamic_programming.jl @@ -617,6 +617,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 + stage_len_1 = 0 + for stage_count in 1:(cur_stage-1) + stage_len_1 += 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 @@ -629,7 +633,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)^(stage_len_1) # 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) From 72b253ddedf4af735b3f1b217bb6f13f4e9618d8 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Tue, 9 Apr 2024 14:44:56 -0400 Subject: [PATCH 02/16] Updated doc of DDP --- src/multi_stage/dual_dynamic_programming.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/multi_stage/dual_dynamic_programming.jl b/src/multi_stage/dual_dynamic_programming.jl index 25d7f0506b..7ae8e621ce 100644 --- a/src/multi_stage/dual_dynamic_programming.jl +++ b/src/multi_stage/dual_dynamic_programming.jl @@ -593,7 +593,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=0}^{(p-1)}L_{p}}} \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) @@ -621,6 +621,7 @@ function initialize_cost_to_go(settings_d::Dict, EP::Model, inputs::Dict) for stage_count in 1:(cur_stage-1) stage_len_1 += settings_d["StageLengths"][stage_count] end + println("Value of stage len_1 in stage ", cur_stage, " is ", stage_len_1) 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 From 9d465e79b2f3f6ed68b7b6e408cef36dff93444a Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Tue, 9 Apr 2024 14:47:36 -0400 Subject: [PATCH 03/16] minor doc fix --- src/multi_stage/dual_dynamic_programming.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multi_stage/dual_dynamic_programming.jl b/src/multi_stage/dual_dynamic_programming.jl index 7ae8e621ce..6baf43865e 100644 --- a/src/multi_stage/dual_dynamic_programming.jl +++ b/src/multi_stage/dual_dynamic_programming.jl @@ -593,7 +593,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)^{\Sum_{p=0}^{(p-1)}L_{p}}} + DF = \frac{1}{(1+WACC)^{\sum^{(p-1)}_{p=0}L_{p}}} \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) From 9d2949dc7e0c4b2aebeaf342861ee0e051542de8 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Tue, 9 Apr 2024 14:56:14 -0400 Subject: [PATCH 04/16] Update CHANGELOG.md Fix DF calculation in DDP to make it more generic for variable length stages --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18ea0f2e09..510d9e8ca1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,7 +65,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 ### Changed - Use add_to_expression! instead of the += and -= operators for memory performance improvements (#498). - Generally, 'demand' is now used where (electrical) 'load' was used previously (#397). From 0f7ae5469ce149d9c6c2f540b271e5d0920c88e3 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Tue, 9 Apr 2024 15:00:37 -0400 Subject: [PATCH 05/16] Update CHANGELOG.md Added PR # in CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 510d9e8ca1..b390d4790b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add check when capital recovery period is zero and investment costs are 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 versioned doc-pages for v0.3.6 and v0.4.0 (#680) ### Fixed - Set MUST_RUN=1 for RealSystemExample/small_hydro plants (#517). From afbda63263e979bd16deb98827eaeecdc63c7096 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Tue, 9 Apr 2024 15:01:23 -0400 Subject: [PATCH 06/16] Update CHANGELOG.md Fix --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b390d4790b..b667d35950 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add check when capital recovery period is zero and investment costs are 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 (#680) +- Added versioned doc-pages for v0.3.6 and v0.4.0 ### Fixed - Set MUST_RUN=1 for RealSystemExample/small_hydro plants (#517). @@ -65,7 +65,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 +- Fix DF calculation in DDP to make it more generic for variable length stages (#680) ### Changed - Use add_to_expression! instead of the += and -= operators for memory performance improvements (#498). - Generally, 'demand' is now used where (electrical) 'load' was used previously (#397). From 0cef5cd54595dfd2815186469b283fae2bb46a6a Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Tue, 9 Apr 2024 15:28:21 -0400 Subject: [PATCH 07/16] Update write_multi_stage_costs.jl Update write_multi_stage_costs.jl with refined DF --- src/multi_stage/write_multi_stage_costs.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/multi_stage/write_multi_stage_costs.jl b/src/multi_stage/write_multi_stage_costs.jl index 20bed3a9f7..9df028bd36 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 + stage_length_1 = 0 + if p > 1 + for stage_counter in 1:(p - 1) + stage_length_1 += stage_lens[stage_counter] + end + end + DF = 1 / (1 + wacc)^(stage_length_1) # Discount factor applied to ALL costs in each stage end df_costs[!, Symbol("TotalCosts_p$p")] = DF .* costs_d[p][!, Symbol("Total")] end From 199953007eb9c89a70d7f1ff91b0dbb436fe643e Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Tue, 9 Apr 2024 16:02:23 -0400 Subject: [PATCH 08/16] Minor doc fix; Changed counter of summation from p to k --- src/multi_stage/dual_dynamic_programming.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multi_stage/dual_dynamic_programming.jl b/src/multi_stage/dual_dynamic_programming.jl index 6baf43865e..ad1ba0f74d 100644 --- a/src/multi_stage/dual_dynamic_programming.jl +++ b/src/multi_stage/dual_dynamic_programming.jl @@ -593,7 +593,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)^{\sum^{(p-1)}_{p=0}L_{p}}} + 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) From 3df1aebf31986f9cba04a60cd0f3c01b1b8d0c97 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Fri, 3 May 2024 16:05:14 -0400 Subject: [PATCH 09/16] Update write_multi_stage_costs.jl Added a print statement reflecting the approximate value of costs for DDP --- src/multi_stage/write_multi_stage_costs.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/multi_stage/write_multi_stage_costs.jl b/src/multi_stage/write_multi_stage_costs.jl index 9df028bd36..72c30f2739 100644 --- a/src/multi_stage/write_multi_stage_costs.jl +++ b/src/multi_stage/write_multi_stage_costs.jl @@ -52,6 +52,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", :] + println("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 From 81e5c6e1ec3017fbd1499c961d8a6852fe8682f3 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Fri, 3 May 2024 16:05:55 -0400 Subject: [PATCH 10/16] Update write_multi_stage_costs.jl --- src/multi_stage/write_multi_stage_costs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multi_stage/write_multi_stage_costs.jl b/src/multi_stage/write_multi_stage_costs.jl index 72c30f2739..dc6d216215 100644 --- a/src/multi_stage/write_multi_stage_costs.jl +++ b/src/multi_stage/write_multi_stage_costs.jl @@ -52,7 +52,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", :] - println("The cost calculation of the multi-stage GenX is approximate currently, and we will be refining it more in one of the future releases.") + println("**WARNING** : 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 From b29701dca8f24c50b9cfa9912b42cbfcd406d0d0 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Fri, 3 May 2024 16:06:59 -0400 Subject: [PATCH 11/16] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b667d35950..985dfcbf99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ 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 - Set MUST_RUN=1 for RealSystemExample/small_hydro plants (#517). From bed9f76589795ffbeab03b8a2b1bb2381b43cbf4 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Sun, 5 May 2024 15:05:48 -0400 Subject: [PATCH 12/16] Update src/multi_stage/write_multi_stage_costs.jl Replaced println("**WARNING** : The cost calculation of the multi-stage GenX is approximate currently, and we will be refining it more in one of the future releases.") with @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.") Co-authored-by: Luca Bonaldo <39280783+lbonaldo@users.noreply.github.com> --- src/multi_stage/write_multi_stage_costs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multi_stage/write_multi_stage_costs.jl b/src/multi_stage/write_multi_stage_costs.jl index dc6d216215..510cd24cf3 100644 --- a/src/multi_stage/write_multi_stage_costs.jl +++ b/src/multi_stage/write_multi_stage_costs.jl @@ -52,7 +52,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", :] - println("**WARNING** : The cost calculation of the multi-stage GenX is approximate currently, and we will be refining it more in one of the future releases.") + @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 From 0b525a2e97b3a5bfd08ddf26e8842479921c1636 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Sun, 5 May 2024 15:06:43 -0400 Subject: [PATCH 13/16] Update src/multi_stage/dual_dynamic_programming.jl Removed print statement println("Value of stage len_1 in stage ", cur_stage, " is ", stage_len_1) Co-authored-by: Luca Bonaldo <39280783+lbonaldo@users.noreply.github.com> --- src/multi_stage/dual_dynamic_programming.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/multi_stage/dual_dynamic_programming.jl b/src/multi_stage/dual_dynamic_programming.jl index ad1ba0f74d..393034ba5f 100644 --- a/src/multi_stage/dual_dynamic_programming.jl +++ b/src/multi_stage/dual_dynamic_programming.jl @@ -621,7 +621,6 @@ function initialize_cost_to_go(settings_d::Dict, EP::Model, inputs::Dict) for stage_count in 1:(cur_stage-1) stage_len_1 += settings_d["StageLengths"][stage_count] end - println("Value of stage len_1 in stage ", cur_stage, " is ", stage_len_1) 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 From 1b0356da368d76d11ddf664e44e660c6c3461f1b Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Sun, 5 May 2024 15:07:27 -0400 Subject: [PATCH 14/16] Update src/multi_stage/dual_dynamic_programming.jl Replaced stage_len_1 with cum_years Co-authored-by: Luca Bonaldo <39280783+lbonaldo@users.noreply.github.com> --- src/multi_stage/dual_dynamic_programming.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multi_stage/dual_dynamic_programming.jl b/src/multi_stage/dual_dynamic_programming.jl index 393034ba5f..d45feaf667 100644 --- a/src/multi_stage/dual_dynamic_programming.jl +++ b/src/multi_stage/dual_dynamic_programming.jl @@ -617,7 +617,7 @@ 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 - stage_len_1 = 0 + cum_years = 0 for stage_count in 1:(cur_stage-1) stage_len_1 += settings_d["StageLengths"][stage_count] end From ffe95f4091e3b3c7856e8c635a3cc667c15d2fef Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Sun, 5 May 2024 15:30:02 -0400 Subject: [PATCH 15/16] Update dual_dynamic_programming.jl --- src/multi_stage/dual_dynamic_programming.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/multi_stage/dual_dynamic_programming.jl b/src/multi_stage/dual_dynamic_programming.jl index d45feaf667..1fac5e7c91 100644 --- a/src/multi_stage/dual_dynamic_programming.jl +++ b/src/multi_stage/dual_dynamic_programming.jl @@ -619,7 +619,7 @@ 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) - stage_len_1 += settings_d["StageLengths"][stage_count] + 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 @@ -633,7 +633,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_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) From dac2ec5b46f927ba071db51fc5ebf377392dbbc1 Mon Sep 17 00:00:00 2001 From: "Chakrabarti, Sambuddha (Sam)" Date: Sun, 5 May 2024 15:31:15 -0400 Subject: [PATCH 16/16] Update write_multi_stage_costs.jl --- src/multi_stage/write_multi_stage_costs.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/multi_stage/write_multi_stage_costs.jl b/src/multi_stage/write_multi_stage_costs.jl index 510cd24cf3..5c22703a4e 100644 --- a/src/multi_stage/write_multi_stage_costs.jl +++ b/src/multi_stage/write_multi_stage_costs.jl @@ -30,13 +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 - stage_length_1 = 0 + cum_stage_length = 0 if p > 1 for stage_counter in 1:(p - 1) - stage_length_1 += stage_lens[stage_counter] + cum_stage_length += stage_lens[stage_counter] end end - DF = 1 / (1 + wacc)^(stage_length_1) # Discount factor applied to ALL costs in each stage + 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