|
65 | 65 | @doc raw""" |
66 | 66 | function run_ddp(models_d::Dict, setup::Dict, inputs_d::Dict) |
67 | 67 |
|
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. |
69 | 69 |
|
70 | 70 | inputs: |
71 | 71 |
|
@@ -276,141 +276,13 @@ function write_multi_stage_outputs(stats_d::Dict, outpath::String, settings_d::D |
276 | 276 |
|
277 | 277 | multi_stage_settings_d = settings_d["MultiStageSettingsDict"] |
278 | 278 |
|
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) |
414 | 286 |
|
415 | 287 | end |
416 | 288 |
|
@@ -582,8 +454,8 @@ function generate_cut_component_track(EP_cur::Model, EP_next::Model, var_name::S |
582 | 454 | y = k[1] # Index representing resource |
583 | 455 | p = k[2] # Index representing stage |
584 | 456 |
|
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])) |
587 | 459 | push!(cur_inv_var, EP_cur[var_name][y, p]) |
588 | 460 | end |
589 | 461 |
|
|
0 commit comments