-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathThermal_Generation_Dispatch_Example.jl
More file actions
203 lines (166 loc) · 5.87 KB
/
Copy pathThermal_Generation_Dispatch_Example.jl
File metadata and controls
203 lines (166 loc) · 5.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# # Thermal Generation Dispatch Example
#md # [](@__REPO_ROOT_URL__/examples/Thermal_Generation_Dispatch_Example.jl)
# This example illustrates the sensitivity analysis of thermal generation dispatch problem.
# This problem can be described as the choice of thermal generation `g` given a demand `d`, a price for thermal generation `c` and a penalty price `c_{ϕ}` for any demand not attended ϕ.
# ```math
# \begin{split}
# \begin{array} {ll}
# \mbox{minimize} & \sum_{i=1}^{N} c_{i} g_{i} + c_{\phi} \phi \\
# \mbox{s.t.} & g_{i} \ge 0 \quad i=1..N \\
# & g_{i} \le G_{i} \quad i=1..N \\
# & \sum_{i=1}^{N} g_{i} + \phi = d\\
# \end{array}
# \end{split}
# ```
# where
# - `G_{i}` is the maximum possible generation for a thermal generator `i`
# ## Define and solve the Thermal Dispatch Problem
# First, import the libraries.
using Test
using JuMP
import DiffOpt
import LinearAlgebra: dot
import HiGHS
import MathOptInterface as MOI
import Plots
# Define the model that will be construct given a set of parameters.
function generate_model(
d::Float64;
g_sup::Vector{Float64},
c_g::Vector{Float64},
c_ϕ::Float64,
)
## Creation of the Model and Parameters
model = Model(() -> DiffOpt.diff_optimizer(HiGHS.Optimizer))
set_silent(model)
I = length(g_sup)
## Variables
@variable(model, g[i in 1:I] >= 0.0)
@variable(model, ϕ >= 0.0)
## Constraints
@constraint(model, limit_constraints_sup[i in 1:I], g[i] <= g_sup[i])
@constraint(model, demand_constraint, sum(g) + ϕ == d)
## Objectives
@objective(model, Min, dot(c_g, g) + c_ϕ * ϕ)
## Solve the model
optimize!(model)
## Return the solved model
return model
end
# Define the functions that will get the primal values `g` and `\phi` and sensitivity analysis of the demand `dg/dd` and `d\phi/dd` from a optimized model.
function diff_forward(model::Model, ϵ::Float64 = 1.0)
## Initialization of parameters and references to simplify the notation
vect_ref = [model[:g]; model[:ϕ]]
I = length(model[:g])
## Get the primal solution of the model
vect = MOI.get.(model, MOI.VariablePrimal(), vect_ref)
## Pass the perturbation to the DiffOpt Framework and set the context to Forward
constraint_equation = convert(MOI.ScalarAffineFunction{Float64}, ϵ)
MOI.set(
model,
DiffOpt.ForwardConstraintFunction(),
model[:demand_constraint],
constraint_equation,
)
DiffOpt.forward_differentiate!(model)
## Get the derivative of the model
dvect = MOI.get.(model, DiffOpt.ForwardVariablePrimal(), vect_ref)
## Return the values as a vector
return [vect; dvect]
end
function diff_reverse(model::Model, ϵ::Float64 = 1.0)
## Initialization of parameters and references to simplify the notation
vect_ref = [model[:g]; model[:ϕ]]
I = length(model[:g])
## Get the primal solution of the model
vect = MOI.get.(model, MOI.VariablePrimal(), vect_ref)
## Set variables needed for the DiffOpt Backward Framework
dvect = Array{Float64,1}(undef, I + 1)
perturbation = zeros(I + 1)
## Loop for each primal variable
for i in 1:(I+1)
## Set the perturbation in the Primal Variables and set the context to Backward
perturbation[i] = ϵ
MOI.set.(model, DiffOpt.ReverseVariablePrimal(), vect_ref, perturbation)
DiffOpt.reverse_differentiate!(model)
## Get the value of the derivative of the model
dvect[i] = JuMP.constant(
MOI.get(
model,
DiffOpt.ReverseConstraintFunction(),
model[:demand_constraint],
),
)
perturbation[i] = 0.0
end
## Return the values as a vector
return [vect; dvect]
end
# Initialize of Parameters
g_sup = [10.0, 20.0, 30.0]
I = length(g_sup)
d = 0.0:0.1:80
d_size = length(d)
c_g = [1.0, 3.0, 5.0]
c_ϕ = 10.0;
# Generate models for each demand `d`
models = generate_model.(d; g_sup = g_sup, c_g = c_g, c_ϕ = c_ϕ);
# Get the results of models with the DiffOpt Forward and Backward context
result_forward = diff_forward.(models)
optimize!.(models)
result_reverse = diff_reverse.(models);
# Organization of results to plot
# Initialize data_results that will contain every result
data_results = Array{Float64,3}(undef, 2, d_size, 2 * (I + 1));
# Populate the data_results array
for k in 1:d_size
data_results[1, k, :] = result_forward[k]
data_results[2, k, :] = result_reverse[k]
end
# ## Results with Plot graphs
# ### Results for the forward context
# Result Primal Values:
Plots.plot(
d,
data_results[1, :, 1:(I+1)];
title = "Generation by Demand",
label = [
"Thermal Generation 1" "Thermal Generation 2" "Thermal Generation 3" "Generation Deficit"
],
xlabel = "Demand [unit]",
ylabel = "Generation [unit]",
)
# Result Sensitivity Analysis:
Plots.plot(
d,
data_results[1, :, (I+2):(2*(I+1))];
title = "Sensitivity of Generation by Demand",
label = [
"T. Gen. 1 Sensitivity" "T. Gen. 2 Sensitivity" "T. Gen. 3 Sensitivity" "Gen. Deficit Sensitivity"
],
xlabel = "Demand [unit]",
ylabel = "Sensitivity [-]",
)
# ### Results for the reverse context
# Result Primal Values:
Plots.plot(
d,
data_results[2, :, 1:(I+1)];
title = "Generation by Demand",
label = [
"Thermal Generation 1" "Thermal Generation 2" "Thermal Generation 3" "Generation Deficit"
],
xlabel = "Demand [unit]",
ylabel = "Generation [unit]",
)
# Result Sensitivity Analysis:
Plots.plot(
d,
data_results[2, :, (I+2):(2*(I+1))];
title = "Sensitivity of Generation by Demand",
label = [
"T. Gen. 1 Sensitivity" "T. Gen. 2 Sensitivity" "T. Gen. 3 Sensitivity" "Gen. Deficit Sensitivity"
],
xlabel = "Demand [unit]",
ylabel = "Sensitivity [-]",
)