@@ -35,8 +35,11 @@ function unit_commitment(load1_demand, load2_demand, gen_costs, noload_costs; mo
3535 Cnl = Dict (1 => noload_costs[1 ], 2 => noload_costs[2 ]) # No-load cost ($)
3636
3737 # # Variables
38+ # Note: u represents the activation of generation units.
39+ # Would be binary in the typical UC problem, relaxed here to u ∈ [0,1]
40+ # for a linear relaxation.
3841 @variable (model, 0 <= u[g in unit_codes, t in 1 : n_periods] <= 1 ) # Commitment
39- @variable (model, p[g in unit_codes, t in 1 : n_periods] >= 0 ) # Power output
42+ @variable (model, p[g in unit_codes, t in 1 : n_periods] >= 0 ) # Power output (pu)
4043
4144 # # Constraints
4245
7578# Forward differentiation rule for the solution map of the unit commitment problem
7679# taking in input perturbations on the input parameters and returning perturbations propagated to the result
7780function ChainRulesCore. frule ((_, Δload1_demand, Δload2_demand, Δgen_costs, Δnoload_costs), :: typeof (unit_commitment), load1_demand, load2_demand, gen_costs, noload_costs)
81+ # creating the UC model with a DiffOpt optimizer wrapper around Clp
7882 model = Model (() -> diff_optimizer (Clp. Optimizer))
83+ # building and solving the main model
7984 pv = unit_commitment (load1_demand, load2_demand, gen_costs, noload_costs, model= model)
8085 energy_balance_cons = model[:energy_balance_cons ]
81- MOI. set .(model, DiffOpt. ForwardIn {DiffOpt.ConstraintConstant} (), energy_balance_cons, [d1 + d2 for (d1, d2) in zip (Δload1_demand, Δload1_demand)])
86+
87+ # Setting some perturbation of the right-hand side of the energy balance constraints
88+ # the RHS is equal to the sum of load demands at each period.
89+ # the corresponding perturbation are set accordingly as the set of perturbations of the two loads
90+ MOI. set .(
91+ model,
92+ DiffOpt. ForwardIn {DiffOpt.ConstraintConstant} (), energy_balance_cons,
93+ [d1 + d2 for (d1, d2) in zip (Δload1_demand, Δload1_demand)],
94+ )
8295
8396 p = model[:p ]
8497 u = model[:u ]
8598
99+ # setting the perturbation of the linear objective
86100 for t in size (p, 2 )
87101 MOI. set (model, DiffOpt. ForwardIn {DiffOpt.LinearObjective} (), p[1 ,t], Δgen_costs[1 ])
88102 MOI. set (model, DiffOpt. ForwardIn {DiffOpt.LinearObjective} (), p[2 ,t], Δgen_costs[2 ])
89103 MOI. set (model, DiffOpt. ForwardIn {DiffOpt.LinearObjective} (), u[1 ,t], Δnoload_costs[1 ])
90104 MOI. set (model, DiffOpt. ForwardIn {DiffOpt.LinearObjective} (), u[2 ,t], Δnoload_costs[2 ])
91105 end
92106 DiffOpt. forward (JuMP. backend (model))
107+ # querying the corresponding perturbation of the decision
93108 Δp = MOI. get .(model, DiffOpt. ForwardOut {MOI.VariablePrimal} (), p)
94109 return (pv, Δp. data)
95110end
@@ -110,6 +125,7 @@ noload_costs = [500.0, 1000.0]
110125# The computed pullback takes a seed for the optimal solution `̄p` and returns
111126# derivatives wrt each input parameter.
112127function ChainRulesCore. rrule (:: typeof (unit_commitment), load1_demand, load2_demand, gen_costs, noload_costs; model = Model (() -> diff_optimizer (Clp. Optimizer)))
128+ # solve the forward UC problem
113129 pv = unit_commitment (load1_demand, load2_demand, gen_costs, noload_costs, model= model)
114130 function pullback_unit_commitment (pb)
115131 p = model[:p ]
@@ -119,6 +135,7 @@ function ChainRulesCore.rrule(::typeof(unit_commitment), load1_demand, load2_dem
119135 MOI. set .(model, DiffOpt. BackwardIn {MOI.VariablePrimal} (), p, pb)
120136 DiffOpt. backward (JuMP. backend (model))
121137
138+ # computing derivative wrt linear objective costs
122139 dgen_costs = similar (gen_costs)
123140 dgen_costs[1 ] = sum (MOI. get .(model, DiffOpt. BackwardOut {DiffOpt.LinearObjective} (), p[1 ,:]))
124141 dgen_costs[2 ] = sum (MOI. get .(model, DiffOpt. BackwardOut {DiffOpt.LinearObjective} (), p[2 ,:]))
@@ -127,6 +144,7 @@ function ChainRulesCore.rrule(::typeof(unit_commitment), load1_demand, load2_dem
127144 dnoload_costs[1 ] = sum (MOI. get .(model, DiffOpt. BackwardOut {DiffOpt.LinearObjective} (), u[1 ,:]))
128145 dnoload_costs[2 ] = sum (MOI. get .(model, DiffOpt. BackwardOut {DiffOpt.LinearObjective} (), u[2 ,:]))
129146
147+ # computing derivative wrt constraint constant
130148 dload1_demand = MOI. get .(model, DiffOpt. BackwardOut {DiffOpt.ConstraintConstant} (), energy_balance_cons)
131149 dload2_demand = copy (dload1_demand)
132150 return (dload1_demand, dload2_demand, dgen_costs, dnoload_costs)
0 commit comments