Skip to content

Commit ebe821f

Browse files
sambuddhaccfe316Qingyu XuwrguntherGenXProject
authored
Feature updates and bug fixes for v0.3.2 patch release (#270)
* Remove extraneous 'param' files * Fix spelling of output file * Updated the Project.toml, README, and the doc pages to comment out and treat SCIP the same way as Gurobi and CPLEX, especially for Windows environment, until we have a stable SCIP deployment for Windows * Remove extraneous column Line_Min_Flow_MW * Fixed #222 by re-scaling network_expansion.csv Outputs are now in MW and $, not the internal units of GW and M$. * Use ModelScalingFactor, not two ad-hoc conversions * CRM: update the zone membership So that the zone is in the CRM as long as the dfCapRes is not zero. * Fix JuMP interface in DPP getdual and getvalue were deprecated. * Updated instructions for MUMPS_seq_jll error Auto-populated MUMPS_seq_jll v5.5.1 causes pre-compilation issues with solvers on Windows. Edited run instructions to downgrade MUMPS_seq_jll to v5.4.1 after instantiate. * Update versions of proprietary solver interfaces * Updated Project.toml To fix SCIP dependency issue breaking at CI * Add write capacity factor function * Move multi-stage write functions to their own files Moved write_capacities_dicharge(), write_costs(), and write_stats() to their own files and renamed multi-stage write files to include "multi_stage" to differentiate them from other write files. * Rename write_settings to write_multi_stage_settings To be consistent with other files and to differentiate multi-stage write files from single-stage write files. * New multi-stage write files Wrote analogous write files for charge capacity, energy capacity, and transmission capacity based on write_multi_stage_capacities_discharge(). Feel free to expand upon network expansion output writing later. * Update GenX.jl To incorporate write_multi_stage_settings.jl instead of write_settings.jl * Fixed Syntax error in GenX.jl Gotten rid of the extra "/" in include("multi_stage/write_multi_stage_settings.jl") Co-authored-by: Jacob Schwartz <jacob@jaschwartz.net> Co-authored-by: Qingyu Xu <qingyux@princeton.edu> Co-authored-by: wrgunther <112493531+wrgunther@users.noreply.github.com> Co-authored-by: GenXProject <84470580+GenXProject@users.noreply.github.com> Co-authored-by: jfmorris <jfmorris@mit.edu>
1 parent 004e6ec commit ebe821f

16 files changed

Lines changed: 380 additions & 148 deletions

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ Cbc = "1.0.1"
3535
Clp = "1.0.1"
3636
Clustering = "0.14.2"
3737
Combinatorics = "1.0.2"
38-
#CPLEX ="0.6.1"
38+
#CPLEX ="0.9.3"
3939
DataFrames = "1.3.4"
4040
DataStructures = "0.18.13"
4141
Distances = "0.10.7"
42-
#Gurobi ="0.9.14"
42+
#Gurobi ="0.11.3"
4343
HiGHS = "1.1.4"
4444
JuMP = "1.1.1"
4545
MathOptInterface = "1.6.1"

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,13 @@ For this tutorial it will be assumed to be within your home directory: `/home/yo
7878

7979
2. Start a terminal and navigate into the `GenX` folder.
8080
3. Type `julia --project=.` to start an instance of the `julia` kernel with the `project` set to the current folder.
81-
The `.` indicates the current folder.
81+
The `.` indicates the current folder. On Windows the location of Julia can also be specified as e.g., 'C:\julia-1.6.0\bin\julia.exe --project=.'
8282

8383
If it's your first time running GenX (or, if you have pulled after some major upgrades/release/version) execute steps 3-6.
8484

8585
4. Type `]` to bring up the package system `(GenX) pkg >` prompt. This indicates that the GenX project was detected. If you see `(@v1.6) pkg>` as the prompt, then the `project` was not successfully set.
8686
5. Type `instantiate` from the `(GenX) pkg` prompt.
87+
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.
8788
6. Type `st` to check that the dependecies have been installed. If there is no error, it has been successful.
8889
7. Type the back key to come back to the `julia>` prompt.
8990

docs/src/how_to_run_genx.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ For this tutorial it will be assumed to be within your home directory: `/home/yo
3636

3737
2. Start a terminal and navigate into the `GenX` folder.
3838
3. Type `julia --project=.` to start an instance of the `julia` kernel with the `project` set to the current folder.
39-
The `.` indicates the current folder.
39+
The `.` indicates the current folder. On Windows the location of Julia can also be specified as e.g., 'C:\julia-1.6.0\bin\julia.exe --project=.'
4040

4141
If it's your first time running GenX (or, if you have pulled after some major upgrades/release/version) execute steps 3-6.
4242

4343
4. Type `]` to bring up the package system `(GenX) pkg >` prompt. This indicates that the GenX project was detected. If you see `(@v1.6) pkg>` as the prompt, then the `project` was not successfully set.
4444
5. Type `instantiate` from the `(GenX) pkg` prompt.
45+
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.
4546
6. Type `st` to check that the dependecies have been installed. If there is no error, it has been successful.
4647
7. Type the back key to come back to the `julia>` prompt.
4748

@@ -106,7 +107,6 @@ julia> <press close-bracket ] to access the package manager>
106107
-or-
107108
(GenX) pkg> add CPLEX
108109
```
109-
110110
3. At the beginning of the `GenX/src/GenX.jl` file, uncomment `using Gurobi` and/or `using CPLEX`.
111111
4. Set the appropriate solver in the `genx_settings.yml` file of your case
112112

src/GenX.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ include("model/solve_model.jl")
147147

148148
include("write_outputs/dftranspose.jl")
149149
include("write_outputs/write_capacity.jl")
150+
include("write_outputs/write_capacityfactor.jl")
150151
include("write_outputs/write_charge.jl")
151152
include("write_outputs/write_charging_cost.jl")
152153
include("write_outputs/write_costs.jl")
@@ -197,7 +198,7 @@ include("simple_operation.jl")
197198
include("multi_stage/dual_dynamic_programming.jl")
198199
include("multi_stage/configure_multi_stage_inputs.jl")
199200
include("multi_stage/endogenous_retirement.jl")
200-
include("multi_stage//write_settings.jl")
201+
include("multi_stage/write_multi_stage_settings.jl")
201202

202203
include("additional_tools/modeling_to_generate_alternatives.jl")
203204
include("additional_tools/method_of_morris.jl")

src/model/core/non_served_energy.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ function non_served_energy!(EP::Model, inputs::Dict, setup::Dict)
8787
# Capacity Reserves Margin policy
8888
if setup["CapacityReserveMargin"] > 0
8989
if SEG >=2
90-
@expression(EP, eCapResMarBalanceNSE[res=1:inputs["NCapacityReserveMargin"], t=1:T], sum(EP[:vNSE][s,t,z] for s in 2:SEG, z in findall(x->x>0,inputs["dfCapRes"][:,res])))
90+
@expression(EP, eCapResMarBalanceNSE[res=1:inputs["NCapacityReserveMargin"], t=1:T], sum(EP[:vNSE][s,t,z] for s in 2:SEG, z in findall(x->x!=0,inputs["dfCapRes"][:,res])))
9191
EP[:eCapResMarBalance] += eCapResMarBalanceNSE
9292
end
9393
end

src/model/policies/cap_reserve_margin.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ function cap_reserve_margin!(EP::Model, inputs::Dict, setup::Dict)
3535

3636
@constraint(EP, cCapacityResMargin[res=1:inputs["NCapacityReserveMargin"], t=1:T], EP[:eCapResMarBalance][res, t]
3737
>= sum(inputs["pD"][t,z] * (1 + inputs["dfCapRes"][z,res])
38-
for z=findall(x->x>0,inputs["dfCapRes"][:,res])))
38+
for z=findall(x->x!=0,inputs["dfCapRes"][:,res])))
3939

4040
end

src/multi_stage/dual_dynamic_programming.jl

Lines changed: 10 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ end
6565
@doc raw"""
6666
function run_ddp(models_d::Dict, setup::Dict, inputs_d::Dict)
6767
68-
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.
68+
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.
6969
7070
inputs:
7171
@@ -276,141 +276,13 @@ function write_multi_stage_outputs(stats_d::Dict, outpath::String, settings_d::D
276276

277277
multi_stage_settings_d = settings_d["MultiStageSettingsDict"]
278278

279-
write_capacities_discharge(outpath, multi_stage_settings_d)
280-
#write_capacities_charge(outpath, multi_stage_settings_d)
281-
#write_capacities_energy(outpath, multi_stage_settings_d)
282-
#write_network_expansion(outpath, multi_stage_settings_d)
283-
write_costs(outpath, multi_stage_settings_d, inputs_dict)
284-
write_stats(outpath, stats_d)
285-
write_settings(outpath, settings_d)
286-
287-
end
288-
289-
@doc raw"""
290-
function write_capacities_discharge(outpath::String, settings_d::Dict)
291-
292-
This function writes the file capacities\_multi\_stage.csv to the Results directory. This file contains starting resource capcities from the first model stage and end resource capacities for the first and all subsequent model stages.
293-
294-
inputs:
295-
296-
* outpath – String which represents the path to the Results directory.
297-
* settings\_d - Dictionary containing settings dictionary configured in the multi-stage settings file multi\_stage\_settings.yml.
298-
"""
299-
function write_capacities_discharge(outpath::String, settings_d::Dict)
300-
# TO DO - DO THIS FOR ENERGY CAPACITY AS WELL
301-
302-
num_stages = settings_d["NumStages"] # Total number of investment planning stages
303-
capacities_d = Dict()
304-
305-
for p in 1:num_stages
306-
inpath = joinpath(outpath, "Results_p$p")
307-
capacities_d[p] = DataFrame(CSV.File(joinpath(inpath, "capacity.csv"), header=true), copycols=true)
308-
end
309-
310-
# Set first column of DataFrame as resource names from the first stage
311-
df_cap = DataFrame(Resource=capacities_d[1][!, :Resource], Zone=capacities_d[1][!, :Zone])
312-
313-
# Store starting capacities from the first stage
314-
df_cap[!, Symbol("StartCap_p1")] = capacities_d[1][!, :StartCap]
315-
316-
# Store end capacities for all stages
317-
for p in 1:num_stages
318-
df_cap[!, Symbol("EndCap_p$p")] = capacities_d[p][!, :EndCap]
319-
end
320-
321-
CSV.write(joinpath(outpath, "capacities_multi_stage.csv"), df_cap)
322-
323-
end
324-
325-
function write_capacities_charge(outpath::String, settings_d::Dict) end
326-
327-
function write_capacities_energy(outpath::String, settings_d::Dict) end
328-
329-
function write_network_expansion(outpath::String, settings_d::Dict)
330-
# Include discounted NE costs and capacities for each model period
331-
end
332-
333-
@doc raw"""
334-
function write_costs(outpath::String, settings_d::Dict)
335-
336-
This function writes the file costs\_multi\_stage.csv to the Results directory. This file contains variable, fixed, startup, network expansion, unmet reserve, and non-served energy costs discounted to year zero.
337-
338-
inputs:
339-
340-
* outpath – String which represents the path to the Results directory.
341-
* settings\_d - Dictionary containing settings dictionary configured in the multi-stage settings file multi\_stage\_settings.yml.
342-
"""
343-
function write_costs(outpath::String, settings_d::Dict, inputs_dict::Dict)
344-
345-
num_stages = settings_d["NumStages"] # Total number of DDP stages
346-
wacc = settings_d["WACC"] # Interest Rate and also the discount rate unless specified other wise
347-
stage_lens = settings_d["StageLengths"]
348-
myopic = settings_d["Myopic"] == 1 # 1 if myopic (only one forward pass), 0 if full DDP
349-
350-
costs_d = Dict()
351-
for p in 1:num_stages
352-
cur_path = joinpath(outpath, "Results_p$p")
353-
costs_d[p] = DataFrame(CSV.File(joinpath(cur_path, "costs.csv"), header=true), copycols=true)
354-
end
355-
356-
OPEXMULTS = [inputs_dict[j]["OPEXMULT"] for j in 1:num_stages] # Stage-wise OPEX multipliers to count multiple years between two model stages
357-
358-
# Set first column of DataFrame as resource names from the first stage
359-
df_costs = DataFrame(Costs=costs_d[1][!, :Costs])
360-
361-
# Store discounted total costs for each stage in a data frame
362-
for p in 1:num_stages
363-
if myopic
364-
DF = 1 # DF=1 because we do not apply discount factor in myopic case
365-
else
366-
DF = 1 / (1 + wacc)^(stage_lens[p] * (p - 1)) # Discount factor applied to ALL costs in each stage
367-
end
368-
df_costs[!, Symbol("TotalCosts_p$p")] = DF .* costs_d[p][!, Symbol("Total")]
369-
end
370-
371-
# For OPEX costs, apply additional discounting
372-
for cost in ["cVar", "cNSE", "cStart", "cUnmetRsv"]
373-
if cost in df_costs[!, :Costs]
374-
df_costs[df_costs[!, :Costs].==cost, 2:end] = transpose(OPEXMULTS) .* df_costs[df_costs[!, :Costs].==cost, 2:end]
375-
end
376-
end
377-
378-
# Remove "cTotal" from results (as this includes Cost-to-Go)
379-
df_costs = df_costs[df_costs[!, :Costs].!="cTotal", :]
380-
381-
CSV.write(joinpath(outpath, "costs_multi_stage.csv"), df_costs)
382-
383-
end
384-
385-
@doc raw"""
386-
function write_stats(outpath::String, stats_d::Dict)
387-
388-
This function writes the file stats\_multi\_stage.csv. to the Results directory. This file contains the runtime, upper bound, lower bound, and relative optimality gap for each iteration of the DDP algorithm.
389-
390-
inputs:
391-
392-
* outpath – String which represents the path to the Results directory.
393-
* stats\_d – Dictionary which contains the run time, upper bound, and lower bound of each DDP iteration.
394-
"""
395-
function write_stats(outpath::String, stats_d::Dict)
396-
397-
times_a = stats_d["TIMES"] # Time (seconds) of each iteration
398-
upper_bounds_a = stats_d["UPPER_BOUNDS"] # Upper bound of each iteration
399-
lower_bounds_a = stats_d["LOWER_BOUNDS"] # Lower bound of each iteration
400-
401-
# Create an array of numbers 1 through total number of iterations
402-
iteration_count_a = collect(1:length(times_a))
403-
404-
realtive_gap_a = (upper_bounds_a .- lower_bounds_a) ./ lower_bounds_a
405-
406-
# Construct dataframe where first column is iteration number, second is iteration time
407-
df_stats = DataFrame(Iteration_Number=iteration_count_a,
408-
Seconds=times_a,
409-
Upper_Bound=upper_bounds_a,
410-
Lower_Bound=lower_bounds_a,
411-
Relative_Gap=realtive_gap_a)
412-
413-
CSV.write(joinpath(outpath, "stats_multi_stage.csv"), df_stats)
279+
write_multi_stage_capacities_discharge(outpath, multi_stage_settings_d)
280+
write_multi_stage_capacities_charge(outpath, multi_stage_settings_d)
281+
write_multi_stage_capacities_energy(outpath, multi_stage_settings_d)
282+
write_multi_stage_network_expansion(outpath, multi_stage_settings_d)
283+
write_multi_stage_costs(outpath, multi_stage_settings_d, inputs_dict)
284+
write_multi_stage_stats(outpath, stats_d)
285+
write_multi_stage_settings(outpath, settings_d)
414286

415287
end
416288

@@ -582,8 +454,8 @@ function generate_cut_component_track(EP_cur::Model, EP_next::Model, var_name::S
582454
y = k[1] # Index representing resource
583455
p = k[2] # Index representing stage
584456

585-
push!(next_dual_value, getdual(EP_next[constr_name][y, p]))
586-
push!(cur_inv_value, getvalue(EP_cur[var_name][y, p]))
457+
push!(next_dual_value, dual(EP_next[constr_name][y, p]))
458+
push!(cur_inv_value, value(EP_cur[var_name][y, p]))
587459
push!(cur_inv_var, EP_cur[var_name][y, p])
588460
end
589461

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"""
2+
GenX: An Configurable Capacity Expansion Model
3+
Copyright (C) 2021, Massachusetts Institute of Technology
4+
This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
This program is distributed in the hope that it will be useful,
9+
but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
GNU General Public License for more details.
12+
A complete copy of the GNU General Public License v2 (GPLv2) is available
13+
in LICENSE.txt. Users uncompressing this from an archive may not have
14+
received this license file. If not, see <http://www.gnu.org/licenses/>.
15+
"""
16+
17+
@doc raw"""
18+
function write_multi_stage_capacities_charge(outpath::String, settings_d::Dict)
19+
20+
This function writes the file capacities\_charge\_multi\_stage.csv to the Results directory. This file contains starting resource charge capacities from the first model stage and end resource charge capacities for the first and all subsequent model stages.
21+
22+
inputs:
23+
24+
* outpath – String which represents the path to the Results directory.
25+
* settings\_d - Dictionary containing settings dictionary configured in the multi-stage settings file multi\_stage\_settings.yml.
26+
"""
27+
function write_multi_stage_capacities_charge(outpath::String, settings_d::Dict)
28+
29+
num_stages = settings_d["NumStages"] # Total number of investment planning stages
30+
capacities_d = Dict()
31+
32+
for p in 1:num_stages
33+
inpath = joinpath(outpath, "Results_p$p")
34+
capacities_d[p] = DataFrame(CSV.File(joinpath(inpath, "capacity.csv"), header=true), copycols=true)
35+
end
36+
37+
# Set first column of DataFrame as resource names from the first stage
38+
df_cap = DataFrame(Resource=capacities_d[1][!, :Resource], Zone=capacities_d[1][!, :Zone])
39+
40+
# Store starting capacities from the first stage
41+
df_cap[!, Symbol("StartChargeCap_p1")] = capacities_d[1][!, :StartChargeCap]
42+
43+
# Store end capacities for all stages
44+
for p in 1:num_stages
45+
df_cap[!, Symbol("EndChargeCap_p$p")] = capacities_d[p][!, :EndChargeCap]
46+
end
47+
48+
CSV.write(joinpath(outpath, "capacities_charge_multi_stage.csv"), df_cap)
49+
50+
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"""
2+
GenX: An Configurable Capacity Expansion Model
3+
Copyright (C) 2021, Massachusetts Institute of Technology
4+
This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
This program is distributed in the hope that it will be useful,
9+
but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
GNU General Public License for more details.
12+
A complete copy of the GNU General Public License v2 (GPLv2) is available
13+
in LICENSE.txt. Users uncompressing this from an archive may not have
14+
received this license file. If not, see <http://www.gnu.org/licenses/>.
15+
"""
16+
17+
@doc raw"""
18+
function write_multi_stage_capacities_discharge(outpath::String, settings_d::Dict)
19+
20+
This function writes the file capacities\_multi\_stage.csv to the Results directory. This file contains starting resource capacities from the first model stage and end resource capacities for the first and all subsequent model stages.
21+
22+
inputs:
23+
24+
* outpath – String which represents the path to the Results directory.
25+
* settings\_d - Dictionary containing settings dictionary configured in the multi-stage settings file multi\_stage\_settings.yml.
26+
"""
27+
function write_multi_stage_capacities_discharge(outpath::String, settings_d::Dict)
28+
29+
num_stages = settings_d["NumStages"] # Total number of investment planning stages
30+
capacities_d = Dict()
31+
32+
for p in 1:num_stages
33+
inpath = joinpath(outpath, "Results_p$p")
34+
capacities_d[p] = DataFrame(CSV.File(joinpath(inpath, "capacity.csv"), header=true), copycols=true)
35+
end
36+
37+
# Set first column of DataFrame as resource names from the first stage
38+
df_cap = DataFrame(Resource=capacities_d[1][!, :Resource], Zone=capacities_d[1][!, :Zone])
39+
40+
# Store starting capacities from the first stage
41+
df_cap[!, Symbol("StartCap_p1")] = capacities_d[1][!, :StartCap]
42+
43+
# Store end capacities for all stages
44+
for p in 1:num_stages
45+
df_cap[!, Symbol("EndCap_p$p")] = capacities_d[p][!, :EndCap]
46+
end
47+
48+
CSV.write(joinpath(outpath, "capacities_multi_stage.csv"), df_cap)
49+
50+
end

0 commit comments

Comments
 (0)