# Objective function value for all the points in the feasible region

How can we find out the objective function value for all the points in the feasible region for a complex optimization problem using JuMP?

Is there a built-in method for doing so? If yes, then please specify the same.
If not, then please tell a way to do this.

There might be infinitely many points in the feasible region, how do you intend to “figure out the objection-function value” for such a large number of points?

I want to generate some random points let’s say 1000 or so.
I want to get a picture of how the objective function varies. Is there any extreme value?

The objective function now includes a weighted sum of the expected cost and the CVaR. For the input data set that I am using, I found that for only expected cost minimization the CVaR comes out to be very large, while is around the expected value for all other values between 0 and 1. So, I want to know is there a point in the feasible region which is resulting in such an extreme result.

For a problem, the feasible solutions can be infinite, If you want to get the extreme objective function values, you can just set the optimization aims to minimize the objective function or maximize it to get the corresponding solutions.

I want to visualize the objective function value for several random feasible points.

I assume that this just means your variable which represents CVaR is not “tight” and that it can take any value. This can happen because it is not in the objective function, and so there is no incentive for the solver to pick a small value.

If you have a reproducible example, we might be able to say more.

I want to visualize the objective function value for several random feasible points.

You can evaluate the objective function at a point as follows:

``````obj_f = objective_function(model)
point = Dict(
x => rand() # replace here with a feasible primal solution
for x in all_variables(model)
)
value(x -> point[x], obj_f)
``````

It’s a lot harder to find a set of random feasible points.

This will also only be useful if your problem has two dimensions. What do you hope to visualize?

``````using JuMP, Gurobi, Plots

function CVaR_3bus(CUD, M, α, β)
# Sets
w = ["w1", "w2", "w3", "w4", "w5", "w6"]                 # scenarios
d = ["d1"]                                               # representative
t = ["t1", "t2", "t3"]                                   # time periods in each representative
k = ["k1", "k2"]                                         # groups for EV
g = ["g1", "g2", "g3"]                                   # generators
s = ["s1", "s2", "s3"]                                   # storage
b = ["b1", "b2", "b3"]                                   # buses
l = ["l1", "l2", "l3", "l4", "l5", "l6"]                 # lines
T = collect(1:length(t))                                 # time periods in integer

#Lᴱ = filter(x -> parse(Int, x[2:end]) ≤ 3, l)            # gives the existing lines [l1, l2, l3]
#Lᶜ = filter(x -> parse(Int, x[2:end]) > 3, l)            # gives the candidate lines [l4, l5, l6]
Lᴱ = Dict("l1" => true,"l2" => true, "l3" => true,"l4" => false,"l5" => false, "l6" => false )
Lᶜ = Dict("l1" => false,"l2" => false, "l3" => false,"l4" => true,"l5" => true, "l6" => true )
Gᴰ = Dict("g1" => true, "g2" => true, "g3" => false)     # Set of Dispatchable Units
Gᴵ = Dict("g1" => false, "g2" => false, "g3" => true)    # Set of Intermittent Units

Gᵇ = Dict(
"b1"=>["g1"],
"b2"=>["g2"],
"b3"=>["g3"])
Sᵇ = Dict(
"b1"=>["s1"],
"b2"=>["s2"],
"b3"=>["s3"])

#=***********************************************************************************
Origin and Desitination Bus for Each Line
Lines Originating from bus and lines meeting to a destination bus
************************************************************************************=#
OL = Dict(
"l1" => "b1",
"l2" => "b2",
"l3" => "b3",
"l4" => "b1",
"l5" => "b2",
"l6" => "b3"
)
# Destination of Line 1
FL = Dict(
"l1" => "b2",
"l2" => "b3",
"l3" => "b1",
"l4" => "b2",
"l5" => "b3",
"l6" => "b1"
)

# Initialize an empty dictionary to store the result
L_OB = Dict{String, Vector{String}}()

# Iterate through the OL dictionary
for (lo, bo) in OL
# If the b key doesn't exist in the L_OB, create a new entry with an empty vector
L_OB[bo] = []
end

# Add the l key to the corresponding b entry
push!(L_OB[bo], lo)
end

# Initialize an empty dictionary to store the result
L_DB = Dict{String, Vector{String}}()

# Iterate through the OL dictionary
for (ld, bd) in FL
# If the b key doesn't exist in the L_DB, create a new entry with an empty vector
L_DB[bd] = []
end

# Add the l key to the corresponding b entry
push!(L_DB[bd], ld)
end

#=*****************************************************************************
Scalars
*****************************************************************************=#
#ηEV = 0.98                 # Chargin and discharging efficiency of EV
#Eₑᴮm = 0.04                # Battery Capacity of EV
#γₑm = 0.05                 # Minimum energy stored in EV
θᴰm = 1.5707963            # Maximum voltage angle deviation
#=*****************************************************************************
Parameters
*****************************************************************************=#
WD = Dict("d1" => 365*8)                                         # Weight for each time period
γˢm = Dict("s1" => 0.1, "s2" => 0.1, "s3" => 0.1)                # per unit energy that must remain in the storage
γₛ⁰ = Dict(
("s1","d1") => 0.7,
("s2","d1") => 0.7,
("s3","d1") => 0.7,)                                         # Per unit energy in the first period(storage)
γₛEP = Dict("s1" => 6, "s2" => 6, "s3" => 6)                      # 6 hr discharge duration
ηS = Dict("s1" => 0.98, "s2" => 0.98, "s3" => 0.98)              # Storage efficiency

# Define the table for Number of Electric Vehicles
EVₙ = Dict(
("k1", "b1") => Dict("w1" => 550, "w2" => 550, "w3" => 750,  "w4" => 450,  "w5" => 950,  "w6" => 950),
("k1", "b2") => Dict("w1" => 800, "w2" => 800, "w3" => 1000, "w4" => 1000, "w5" => 1200, "w6" => 1200),
("k1", "b3") => Dict("w1" => 400, "w2" => 400, "w3" => 600,  "w4" => 600,  "w5" => 800,  "w6" => 800),
("k2", "b1") => Dict("w1" => 300, "w2" => 300, "w3" => 500,  "w4" => 500,  "w5" => 700,  "w6" => 750),
("k2", "b2") => Dict("w1" => 400, "w2" => 400, "w3" => 600,  "w4" => 600,  "w5" => 800,  "w6" => 850),
("k2", "b3") => Dict("w1" => 150, "w2" => 150, "w3" => 350,  "w4" => 350,  "w5" => 550,  "w6" => 550)
)

pi = Dict("w1" => 1/length(w), "w2" => 1/length(w), "w3" => 1/length(w), "w4" => 1/length(w), "w5" => 1/length(w), "w6" => 1/length(w))

Pᵢᴳm = Dict("g1" => 400, "g2" => 400, "g3" => 600)          # Maximum Capacity of generting units
Eₛm = Dict("s1" => 100, "s2" => 100, "s3" => 100)           # Maximum possible Energy capacity of the candidate storage
Pₛm = Dict("s1" => 100, "s2" => 100, "s3" => 100)           # Maximum possible Power capacity of the candidate storage
PGᵁ = Dict("g1" => 0.25, "g2" => 0.25)                     # Per unit ramp up limit for the generating unit
PGᴰ = Dict("g1" => 0.25, "g2" => 0.25)                      # Per unit ramp down limit for the generating unit
Pₗm = Dict("l1" => 70, "l2" => 70, "l3" => 70, "l4" => 70, "l5" => 70, "l6" => 70)              # Line Capacity
X = Dict("l1" => 0.01, "l2" => 0.01, "l3" => 0.01, "l4" => 0.01, "l5" => 0.01, "l6" => 0.01)   # Line reactance
CIL = Dict("l4" => 200000, "l5" => 200000, "l6" => 200000)                                     # Transmission Line Cost
#
# Table AD availability of intermittnet power units
("g3", "d1") => Dict("t1" => 0.4, "t2" => 0.9, "t3" => 0.6)
)

# Table Generation Investment Plan for Renewables
Pᵢᴳ = Dict(
("g1") => Dict("w1" => 300, "w2" => 150, "w3" => 300, "w4" => 150, "w5" => 300, "w6" => 150),
("g2") => Dict("w1" => 90,  "w2" =>  90, "w3" =>  90, "w4" =>  90, "w5" =>  90, "w6" =>  90),
("g3") => Dict("w1" => 100, "w2" => 300, "w3" => 100, "w4" => 300, "w5" => 100, "w6" => 300),
)

# Table Demand (MWh)
Pᴰ = Dict(
("b1","d1","t1") => Dict("w1" =>  80,  "w2" => 80,  "w3" => 80, "w4" => 80,  "w5" => 80,  "w6" => 80),
("b1","d1","t2") => Dict("w1" =>  100, "w2" => 100, "w3" => 100,"w4" => 100, "w5" => 100, "w6" => 100),
("b1","d1","t3") => Dict("w1" =>  90,  "w2" => 90,  "w3" => 90, "w4" => 90,  "w5" => 90,  "w6" => 90),
("b2","d1","t1") => Dict("w1" =>  220, "w2" => 220, "w3" => 220,"w4" => 220, "w5" => 220, "w6" => 220),
("b2","d1","t2") => Dict("w1" =>  250, "w2" => 250, "w3" => 250,"w4" => 250, "w5" => 250, "w6" => 250),
("b2","d1","t3") => Dict("w1" =>  230, "w2" => 230, "w3" => 230,"w4" => 230, "w5" => 230, "w6" => 230),
("b3","d1","t1") => Dict("w1" =>  35,  "w2" => 35,  "w3" => 35, "w4" => 35,  "w5" => 35,  "w6" => 35),
("b3","d1","t2") => Dict("w1" =>  50,  "w2" => 50,  "w3" => 50, "w4" => 50,  "w5" => 50,  "w6" => 50),
("b3","d1","t3") => Dict("w1" =>  40,  "w2" => 40,  "w3" => 40, "w4" => 40,  "w5" => 40,  "w6" => 40)
)

# Table PD
PEV_pu = Dict(
("k1","b1","d1","t1") => Dict("w1" => 0,     "w2" => 0,     "w3" => 0,     "w4" => 0,     "w5" => 0,     "w6" => 0),
("k1","b1","d1","t2") => Dict("w1" => 15.00, "w2" => 15.00, "w3" => 15.00, "w4" => 15.00, "w5" => 15.00, "w6" => 15.00),
("k1","b1","d1","t3") => Dict("w1" => 5.408, "w2" => 5.408, "w3" => 5.408, "w4" => 5.408, "w5" => 5.408, "w6" => 5.408),
("k1","b2","d1","t1") => Dict("w1" => 0,     "w2" => 0,     "w3" => 0,     "w4" => 0,     "w5" => 0,     "w6" => 0),
("k1","b2","d1","t2") => Dict("w1" => 15.00, "w2" => 15.00, "w3" => 15.00, "w4" => 15.00, "w5" => 15.00, "w6" => 15.00),
("k1","b2","d1","t3") => Dict("w1" => 5.408, "w2" => 5.408, "w3" => 5.408, "w4" => 5.408, "w5" => 5.408, "w6" => 5.408),
("k1","b3","d1","t1") => Dict("w1" => 0,     "w2" => 0,     "w3" => 0,     "w4" => 0,     "w5" => 0,     "w6" => 0),
("k1","b3","d1","t2") => Dict("w1" => 15.00, "w2" => 15.00, "w3" => 15.00, "w4" => 15.00, "w5" => 15.00, "w6" => 15.00),
("k1","b3","d1","t3") => Dict("w1" => 5.408, "w2" => 5.408, "w3" => 5.408, "w4" => 5.408, "w5" => 5.408, "w6" => 5.408),
("k2","b1","d1","t1") => Dict("w1" => 15.00, "w2" => 15.00, "w3" => 15.00, "w4" => 15.00, "w5" => 15.00, "w6" => 15.00),
("k2","b1","d1","t2") => Dict("w1" => 5.408, "w2" => 5.408, "w3" => 5.408, "w4" => 5.408, "w5" => 5.408, "w6" => 5.408),
("k2","b1","d1","t3") => Dict("w1" => 0,     "w2" => 0,     "w3" => 0,     "w4" => 0,     "w5" => 0,     "w6" => 0),
("k2","b2","d1","t1") => Dict("w1" => 15.00, "w2" => 15.00, "w3" => 15.00, "w4" => 15.00, "w5" => 15.00, "w6" => 15.00),
("k2","b2","d1","t2") => Dict("w1" => 5.408, "w2" => 5.408, "w3" => 5.408, "w4" => 5.408, "w5" => 5.408, "w6" => 5.408),
("k2","b2","d1","t3") => Dict("w1" => 0,     "w2" => 0,     "w3" => 0,     "w4" => 0,     "w5" => 0,     "w6" => 0),
("k2","b3","d1","t1") => Dict("w1" => 15.00, "w2" => 15.00, "w3" => 15.00, "w4" => 15.00, "w5" => 15.00, "w6" => 15.00),
("k2","b3","d1","t2") => Dict("w1" => 5.408, "w2" => 5.408, "w3" => 5.408, "w4" => 5.408, "w5" => 5.408, "w6" => 5.408),
("k2","b3","d1","t3") => Dict("w1" => 0,     "w2" => 0,     "w3" => 0,     "w4" => 0,     "w5" => 0,     "w6" => 0)
)

# Initialize a new dictionary to store the multiplied values
PEV = Dict{Tuple, Dict}()

# Iterate through the keys of EVₙ
for (EV_key, EV_value) in EVₙ
# Extract "k" and "b" values from the EV_key
kEV, bEV = EV_key

# Iterate through the keys of PD
for (PEV_pu_key, PEV_pu_value) in PEV_pu
# Check if the "k" and "b" values match
if (kEV, bEV) == (PEV_pu_key, PEV_pu_key)
# Multiply the corresponding values
multiplied_dict = Dict{String, Float64}()
for (wEV, EV_val) in EV_value
multiplied_dict[wEV] = EV_val * PEV_pu_value[wEV]/1000
end

# Store the result in the result_dict
PEV[PEV_pu_key] = multiplied_dict
end
end
end

# Table Annualized Energy Investment Cost
CEᵢˢ = Dict(
("s1") => Dict("w1" => 500, "w2" => 500, "w3" => 500, "w4" => 500, "w5" => 500, "w6" => 500),
("s2") => Dict("w1" => 500, "w2" => 500, "w3" => 500, "w4" => 500, "w5" => 500, "w6" => 500),
("s3") => Dict("w1" => 500, "w2" => 500, "w3" => 500, "w4" => 500, "w5" => 500, "w6" => 500),
)

# Table  Annualized Power Investment Cost
CPᵢˢ = Dict(
("s1") => Dict("w1" => 3000, "w2" => 3000, "w3" => 3000, "w4" =>3000, "w5" =>3000, "w6" =>3000),
("s2") => Dict("w1" => 3000, "w2" => 3000, "w3" => 3000, "w4" =>3000, "w5" =>3000, "w6" =>3000),
("s3") => Dict("w1" => 3000, "w2" => 3000, "w3" => 3000, "w4" =>3000, "w5" =>3000, "w6" =>3000)
)

# Table 'Operating Cost (generating Units)'
CᴳD = Dict(
("g1") => Dict("w1" => 0.250, "w2" => 0.250, "w3" => 0.250, "w4" => 0.250, "w5" => 0.250, "w6" => 0.250),
("g2") => Dict("w1" => 0.400, "w2" => 0.400, "w3" => 0.400, "w4" => 0.400, "w5" => 0.400, "w6" => 0.400),
("g3") => Dict("w1" => 0.000, "w2" => 0.000, "w3" => 0.000, "w4" => 0.000, "w5" => 0.000, "w6" => 0.000)
)

# Table Discharge Cost(Storage)
CˢD = Dict(
("s1") => Dict("w1" => 0, "w2" => 0, "w3" => 0, "w4" => 0, "w5" => 0, "w6" => 0),
("s2") => Dict("w1" => 0, "w2" => 0, "w3" => 0, "w4" => 0, "w5" => 0, "w6" => 0),
("s3") => Dict("w1" => 0, "w2" => 0, "w3" => 0, "w4" => 0, "w5" => 0, "w6" => 0)
)

# Table CSC
CˢC = Dict(
("s1") => Dict("w1" => 0, "w2" => 0, "w3" => 0, "w4" => 0, "w5" => 0, "w6" => 0),
("s2") => Dict("w1" => 0, "w2" => 0, "w3" => 0, "w4" => 0, "w5" => 0, "w6" => 0),
("s3") => Dict("w1" => 0, "w2" => 0, "w3" => 0, "w4" => 0, "w5" => 0, "w6" => 0)
)

#=***********************************************************************************
Decalaration of Variables and Mathematical Characterization
*************************************************************************************=#
# Create a JuMP model with Gurobi solver
model = Model(Gurobi.Optimizer)
set_attribute(model, "OutputFlag", 1)
set_attribute(model, "FeasibilityTol", 1e-8)
set_attribute(model, "MIPGap", 1e-8)
set_attribute(model, "MIPGapAbs", 0)

# Variables
@variables(model, begin
# First stage variables
eᵢˢ[s in s] ≥ 0   # Storage energy capacity installed
pᵢˢ[s in s] ≥ 0  # Storage power capacity installed
yᴸ[l[4:end]], Bin   # Binary variable that is equal to 1 if line l is built

# Second Stage Variable
pᴳD[g in g, d in d, t in t, w in w] ≥ 0
pᴳDS[g in g, d in d, t in t, w in w] ≥ 0  # Intermittent power spillage
pˢC[s in s, d in d, t in t, w in w] ≥ 0  # Power charged from storages
pˢD[s in s, d in d, t in t, w in w] ≥ 0  # Power discharged from storages
eˢ[s in s, d in d, t in t, w in w] ≥ 0  # Energy stored in storages
pᴸD[l in l, d in d, t in t, w in w]  # Power flows
θᴰ[b in b, d in d, t in t, w in w]  # Voltage angles
pᵁD[b in b, d in d, t in t, w in w] ≥ 0  # Unserved demand

# CVaR Formulation Variables
η[w in w] ≥0
ζ
end)
#=***********************************************************************************
Constraints and Equations
*************************************************************************************=#

@expressions(model,begin
# Expressions for the Energy Balance Cosntraints
Gen[b in b, d in d, t in t, w in w], sum(pᴳD[gb, d, t, w] for gb in Gᵇ[b])                            # Sum of all generation at a bus
ESSgen[b in b, d in d, t in t, w in w], sum(pˢD[sb, d, t, w] - pˢC[sb, d, t, w] for sb in Sᵇ[b])      # Sum of difference of discharge and cahrge power for all storages at a bus
PF_final_bus[b in b, d in d, t in t, w in w], sum(pᴸD[lfb, d, t, w] for lfb in L_DB[b])               # sum of power flows for lines originating from each bus
PF_origin_bus[b in b, d in d, t in t, w in w], sum(pᴸD[lob, d, t, w] for lob in L_OB[b])              # sum of power flows for lines meeting to each bus
Demand[b in b, d in d, t in t, w in w], Pᴰ[b, d, t][w]                                                # Demand at each bus
EVdemand[b in b, d in d, t in t, w in w], sum(PEV[k, b, d, t][w] for k in k)                          # sum of EV demand for each group at each bus
DUnserved[b in b, d in d, t in t, w in w], pᵁD[b, d, t, w]                                            # load curtailed for each bus, dat, time, scenario
# Expressions for the Objective Function
#Cost_Lᶜ, sum(pi[w]*sum([yᴸ[l[i]] * CIL[l[i]] for i in collect(1:length(l)) if i>3]) for w in w)                            # Annualized Cost of Candidate Transmission Lines
Cost_Lᶜ, sum([yᴸ[l[i]] * CIL[l[i]] for i in collect(1:length(l)) if i>3])
CapCost_ESS, sum(pi[w]*sum([CEᵢˢ[es][w] * eᵢˢ[es]+ CPᵢˢ[es][w]*pᵢˢ[es] for es in s]) for w in w)                     # Annualized Energy and Power cost of Energ Storage
OpCost_Gen, sum(pi[w]*sum(sum(WD[d]*sum(CᴳD[gd][w]*pᴳD[gd, d, t, w] for gd in g) for t in t) for d in d) for w in w)
OpCost_ESS, sum(pi[w]*sum(sum(WD[d]*sum(CˢD[sb][w]*pˢD[sb, d, t, w] + CˢC[sb][w]*pˢC[sb, d, t, w] for sb in s) for t in t) for d in d) for w in w)
Cost_DUnserved, sum(pi[w]*sum(sum(WD[d]*sum(CUD*pᵁD[b, d, t, w] for b in b) for t in t) for d in d) for w in w)
#=
OpCost_Gen, sum(pi[w]*sum(sum(WD[d]*sum(CᴳD[gd]["w1"]*pᴳD[gd, d, t, w] for gd in g)+
sum(CˢD[sb][w]*pˢD[sb, d, t, w] + CˢC[sb][w]*pˢC[sb, d, t, w] for sb in s)+
sum(CUD*pᵁD[b, d, t, w] for b in b) for t in t) for d in d) for w in w)
OpCost_Gen, sum(pi[w]*sum(sum(WD[d]*sum(CᴳD[gd]["w1"]*pᴳD[gd, d, t, w] for gd in g)+
sum(CˢD[sb][w]*pˢD[sb, d, t, w] + CˢC[sb][w]*pˢC[sb, d, t, w] for sb in s)+
sum(CUD*pᵁD[b, d, t, w] for b in b) for t in t) for d in d) for w in w)
=#
CVaR_Total_Cost, ζ + (1/(1-α))*(pi[w]*sum(η[w] for w in w))
end)

@constraints(model, begin
# Investment Constraints
InvestESS_01[s in s], eᵢˢ[s] ≤ Eₛm[s]               # Energy capcaity ≤ max possible value
InvestESS_02[s in s], pᵢˢ[s] ≤ Pₛm[s]               # Power capcaity ≤ max possible value
InvestESS_03[s in s], eᵢˢ[s] ≥ γₛEP[s] * pᵢˢ[s]   # defining discharge duration for the BESS

# Generating Units Constraints
Gen_01[g in g, d in d, t in t, w in w; Gᴰ[g]], pᴳD[g, d, t, w] ≤ Pᵢᴳ[g][w]                                              # Dispatchable gen ≤ Capacity
Gen_02[g in g, d in d, t in t, w in w; Gᴵ[g]], pᴳD[g, d, t, w] + pᴳDS[g, d, t, w] ≤ AD[g, d][t] * Pᵢᴳ[g][w]             # RES Gen + RES Spillage ≤ AF*Capacity
Gen_03[g in g, d in d, i in T, w in w; Gᴰ[g] && i!=1], pᴳD[g, d, t[i], w] - pᴳD[g, d, t[i-1], w] ≤ PGᵁ[g] * Pᵢᴳ[g][w]   # Ramp up Constraints
Gen_04[g in g, d in d, i in T, w in w; Gᴰ[g] && i!=1], pᴳD[g, d, t[i-1], w] - pᴳD[g, d, t[i], w] ≤ PGᴰ[g] * Pᵢᴳ[g][w]   # Remap Down Constraints

# Storage Unit Constraints
ESS_01[s in s, d in d, t in t, w in w], pˢD[s, d, t, w] ≤ pᵢˢ[s]                                                        # discharging power ≤ Power capacity
ESS_02[s in s, d in d, t in t, w in w], pˢC[s, d, t, w] ≤ pᵢˢ[s]                                                        # charging power ≤ Power capacity
ESS_03[s in s, d in d, i in T, w in w; i!=1], eˢ[s, d, t[i], w] == eˢ[s, d, t[i-1], w] + ηS[s] * pˢC[s, d, t[i], w] - (1 / ηS[s]) * pˢD[s, d, t[i], w] # Energy balance for time period greater than 1
ESS_04[s in s, d in d, i in T, w in w; i==1], eˢ[s, d, t[i], w] == γₛ⁰[s, d] * eᵢˢ[s]+ ηS[s] * pˢC[s, d, t[i], w] - (1 / ηS[s]) * pˢD[s, d, t[i], w]   # Energy balance for first time period

ESS_05[s in s, d in d, t in t, w in w], eˢ[s, d, t, w] >= γˢm[s] * eᵢˢ[s]               # energy at any time ≥ min value possible
ESS_06[s in s, d in d, t in t, w in w], eˢ[s, d, t, w] <= eᵢˢ[s]                        # energy at any time ≤ max value possible
ESS_07[s in s, d in d, t in t, w in w; t == "t3"], eˢ[s, d, t, w] ≥ γₛ⁰[s, d] * eᵢˢ[s]   # SOC at the end of the day must be greater than a specified value

# Transmission Constraints
TL_01[l in l, d in d, t in t, w in w; Lᴱ[l]], pᴸD[l, d, t, w] == 1 / X[l] * (θᴰ[OL[l], d, t, w] - θᴰ[FL[l], d, t, w] )
TL_02[l in l, d in d, t in t, w in w; Lᶜ[l]], pᴸD[l, d, t, w] ≥ 1 / X[l] * (θᴰ[OL[l], d, t, w] - θᴰ[FL[l], d, t, w] )-(1-yᴸ[l])*M
TL_03[l in l, d in d, t in t, w in w; Lᶜ[l]], pᴸD[l, d, t, w] ≤ 1 / X[l] * (θᴰ[OL[l], d, t, w] - θᴰ[FL[l], d, t, w] )+(1-yᴸ[l])*M
TL_04[l in l, d in d, t in t, w in w; Lᴱ[l]], pᴸD[l, d, t, w] ≤ Pₗm[l]
TL_05[l in l, d in d, t in t, w in w; Lᴱ[l]], pᴸD[l, d, t, w] ≥ -Pₗm[l]
TL_06[l in l, d in d, t in t, w in w; Lᶜ[l]], pᴸD[l, d, t, w] ≤ Pₗm[l] * yᴸ[l]
TL_07[l in l, d in d, t in t, w in w; Lᶜ[l]], pᴸD[l, d, t, w] ≥ -Pₗm[l] * yᴸ[l]
TL_08[b in b, d in d, t in t, w in w], θᴰ[b, d, t, w] ≥ -θᴰm
TL_09[b in b, d in d, t in t, w in w], θᴰ[b, d, t, w] ≤ θᴰm

# Energy Balance Constraints
EnergyBalance01[b in b, d in d, t in t, w in w],
Gen[b,d,t,w] + ESSgen[b,d,t,w] - PF_origin_bus[b,d,t,w] + PF_final_bus[b,d,t,w] == Demand[b,d,t,w] + EVdemand[b,d,t,w] - DUnserved[b,d,t,w]

EnergyBalance02[b in b, d in d, t in t, w in w], DUnserved[b,d,t,w] ≤ Demand[b,d,t,w] + EVdemand[b,d,t,w] # unserved demand ≤ the inflexible demand

# Constraints Related to CVaR for each scenario
CVaR[w in w], (sum([yᴸ[l[i]] * CIL[l[i]] for i in collect(1:length(l)) if i>3]) +
sum([CEᵢˢ[es][w] * eᵢˢ[es]+ CPᵢˢ[es][w]*pᵢˢ[es] for es in s])+
sum(sum(WD[d]*sum(CᴳD[gd][w]*pᴳD[gd, d, t, w] for gd in g) for t in t) for d in d)+
sum(sum(WD[d]*sum(CˢD[sb][w]*pˢD[sb, d, t, w] + CˢC[sb][w]*pˢC[sb, d, t, w] for sb in s) for t in t) for d in d)+
sum(sum(WD[d]*sum(CUD*pᵁD[b, d, t, w] for b in b) for t in t) for d in d)) -ζ ≤ η[w]
end)

# Objective function
#z= @objective(model, Min, 0.001*(Cost_Lᶜ + CapCost_ESS + OpCost_Gen))        # 0.0001 to convert € to k€

z= @objective(model, Min, 0.001*(β*(Cost_Lᶜ + CapCost_ESS + OpCost_Gen + OpCost_ESS + Cost_DUnserved)+(1-β)*CVaR_Total_Cost))

# Solve the model
optimize!(model)

#=****************************************************************************************************
Results
****************************************************************************************************=#
#=
println("Investment Cost ")
println("Storage Investment Cost: ", 0.001*value(CapCost_ESS), " k€")
println("Transmission Line Investment Cost: ",  0.001*value(Cost_Lᶜ), " k€")
println("Generation Operational Cost: ", 0.001*(value(OpCost_Gen)), " k€" )
println("Cost of Demand Unserved: ", 0.001*(value(Cost_DUnserved)), " k€" )
println("Candidate Transmission Lines:", value.(yᴸ))
println("Storage Requirement in MWh and MW ")
println([value.(eᵢˢ) value.(pᵢˢ)])
println(value.(pᴸD))
println(value.(pˢC))
println(value.(pˢD))
println(0.001*value(CVaR_Total_Cost))
println("Total Cost: ", (0.001*(value(Cost_Lᶜ + CapCost_ESS + OpCost_Gen + OpCost_ESS + Cost_DUnserved))), " k€" )
=#
Inv_Cost = value(Cost_Lᶜ + CapCost_ESS)*0.001
Ex_Op_Cost = value(OpCost_Gen )*0.001
Ex_DUnserved = value(Cost_DUnserved)*0.001
Ex_Tot_Cost = value(Cost_Lᶜ + CapCost_ESS + OpCost_Gen + OpCost_ESS + Cost_DUnserved).*0.001
CVaR_Cost = value(CVaR_Total_Cost)*0.001
#=
println("Invextment Cost(k€): ", )
println("Expected Operation Cost(k€): ", )
println("Expected Demand Unserved Cost(k€): ", )
println("Expected Total Cost: ", )
println("CVaR :", )
=#
return Inv_Cost, Ex_Op_Cost, Ex_DUnserved, Ex_Tot_Cost, CVaR_Cost
end

CUD = 1000                 # Unreserves Demand Cost
M = 1000                   # Big M
α = 0.90                   # confidence Level for CVaR formulation
β = 0:0.01:1               # Weighting Factor for Expected Cost and Risk associated with it

Tot_Cost = Vector{Float64}(undef, length(β))
CVaR_Cost = Vector{Float64}(undef, length(β))

for i = 1:length(β)
IV, OC, DC, TC, CC = CVaR_3bus(CUD, M, α, β[i])
Tot_Cost[i] = TC
CVaR_Cost[i] = CC
end

scatter(CVaR_Cost, Tot_Cost, zcolor=β, color=:blues, xlabel="CVaR (k€)", ylabel="Expected Cost (k€)", legend=false, title="Efficient Frontier for α=0.9")

``````

When beta=1 the CVaR term does not appear in the objective, and therefore `CVaR_Total_Cost` can take any value. It is only guaranteed to be equal to CVaR of the distribution if it attains a minimum.

Just use a value of beta just less than 1, or manually compute the CVaR based on the solution of the costs.

Yes, that is true. CVaR can take any value for beta=1.

The value of CVaR for beta =1 is also obtained from the optimal solution. How do I manually compute the CVaR based on the solution of the costs?

If I want to limit its value then I have to add an upper bound on CVaR.

Perhaps to clarify in case it wasn’t clear, its not that the true CVaR of the distribution can take any value (although it can, provided the rest of the objective stays minimized), but that ζ and η can take any values, and so your expression for CVaR will not equal what you would get if you solved the problem without CVaR and then computed it based on the solution values.

It just doesn’t make sense to use this formulation of CVaR if it does not appear in the objective.

1 Like