TP1
#Install package
import sys
!{sys.executable} -m pip install numpy
!{sys.executable} -m pip install matplotlib
# import packages
import numpy as np
import scipy
from scipy import optimize
from scipy.optimize import minimize
Deterministic model
-
Time scale: the decisions are taken every hour during the day.
-
Optimization variables (at each time step) :
- the amount of energy to be stored or withdrawn from the battery
- the amount of energy bought or sold to the network.
-
Contraints:
- nonnegativity of variables
- evolution of the battery
- storage capacity of the battery.
-
Cost function:
- Cost of the energy bought on the network…
- minus the cost of the energy sold on the network.
The problem is modeled by:
-
Horizon: 24 hours, stepsize: 1 hour.
-
Optimization over $T= 24$ intervals.
-
Optimisation variable :
- $x(s)$ : state of charge of the battery at time $s$, $s= 0,…,T$
- $a(s)$: amount of electricity bought on the network ($s= 0,…,T-1$).
- $v(s)$: amount of energy sold on the network ($s= 0,…,T-1$).
-
Parameters:
- $d(s)$: net demand of energy (load minus solar production) at time $s$, $s= 0,…,T-1$.
- $P_a(s)$ : unitary buying price of energy at time $s$, $s= 0,…,T-1$
- $P_v(s)$ : unitary selling price of energy at time $s$, $s= 0,…,T-1$
- $x_{\max}$: storage capacity of the battery.
-
Contraints:
- $x(s+1)= x(s) - d(s) + a(s) - v(s)$, $\forall s= 0,…,T-1$
- $x(0)= 0$
- $a(s) \geq 0$, $\forall s=0,…,T-1$
- $v(s) \geq 0$, $\forall s=0,…,T-1$
- $0 \leq x(s) \leq x_{\max}$, $\forall s=0,…T$.
-
Cost function to be minimized: $$J(x,a,v)= \sum_{s=0}^{T-1} \Big( P_a(s) a(s) - P_v(s) v(s) \Big).$$
Exercice 1
Write the optimization problem in a form that is compatible with the function linprog
% Exercise 1: Indication: you should find optimal value= 124
T= 24; # Time
x_max= 5; # battery maximum storage
P_a= np.array([2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 3, 3, 2]); # unitary buying price of energy at time s
P_v= np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1]); # unitary selling price of energy at time s
d =np.array([-1, -1, -1, -1, -1, -2, 2 ,6, 8, 4, 2, 0, 0, -1, -2, -1, 0, 1, 3, 7, 9, 3, 2, 0]); # net demand of energy (already known)
#d =np.array([-2, -2, -2, -2, -2, -3, 1 ,4 ,6 ,3 ,1, -1, -1, -2, -3, -2, -1, 0, 2 ,5 ,5, 2, 1, -1]);
#d =np.array([-3 ,-3 ,-3 ,-3 ,-3 ,-4 ,0 ,2 ,4, 2, 0 ,-2 ,-2 ,-3 ,-4 ,-3 ,-2 ,-1 ,1 ,3 ,5 ,1 ,0 ,-2]);
d=d.reshape((T,1))
P_a=P_a.reshape(T,1)
P_v=P_v.reshape(T,1)
# with T=2 (for testing purposes ...)
# T = 2;
#x_max= 5;
#P_a=np.array([-1, -1])
#P_v=P_a
#d =np.array([-1, -1])
#d=d.reshape(T,1)
#P_a=P_a.reshape(T,1)
#P_v=P_v.reshape(T,1)
def solve_deterministic_pb():
global d, P_a,P_v
""" print x,a,v and J(x,a,v) """
"""
####### Inequality constraints: #######
xi<=xmax for i = 0.. T: concatenate A1=Identity matrix & A2 & A2
---------------
-x<=0 (size T+1 ! )
-a<=0 (size T)
-v<=0 (size T) : identity matrix A3 (size 3T+1)
---------------
#A X <= B
Indications: with A of shape((len(x)+1 + len(a)+1 + len(v)+1 , len(x) + len (a) + len(v))) #e.g. (10, 7) for T=2
with B= [x_max*np.ones(T+1,1)],
np.zeros((3*T+1,1))];
"""
# xi<=xmax for i = 0.. T: concatenate A1=Identity matrix & A2 & A2
A1=...
A2=...
A=np.concatenate((A1,A2,A2), axis=1)
# -x, -a, -v <= 0,0,0
A3=...
A=...
#print(np.shape(A))
# xi<=xmax for i = 0.. T
B1=...
# -x, -a, -v <= 0,0,0
B3=...
B=np.concatenate((B1.transpose(),B3), axis=0);
#print(B)
"""
####### Equality constraints: #######
---------------
Aeq1:
x(s+1)-x(s)-a(s)+v(s)=-d(s) for all s=0...T-1
-1. 1. on the diagonal (-x(s)+x(s+1))
-1 for a(s)
1 for v(s)
---------------
Aeq2
x(0)=0
---------------
# Aeq X = Beq
with Beq= [-d,0] # -d for Aeq1 and 0 for Aeq2
"""
# Aeq1:
M1=... #-x(s) and x(s+1) s=0, T-1
M2=... #
M=np.concatenate((-M1,M2), axis=1)+np.concatenate((M2,M1),axis=1)
Aeq1=... # M & -a(s) & v(s) s=0, T-1
Aeq2=... # #x(0)=0, (with concatenate, don't use axis=1 for only one line, use double parentheses)
#print(Aeq2)
Aeq=np.concatenate((Aeq1,Aeq2.transpose()),axis=0)
#print(Aeq)
Beq=np.concatenate((-d,np.zeros((1,1))))
#print(Beq)
"""
solving min c^T * X s.t. A X <= B and Aeq X= Beq
no x in min: 0;
a P_a -v P_v
"""
# min c^T [x,a,v]
c=...#cost function: sum_s P_a a(s) - P_v(v)
#print(c) #columns of A must be equal to size of c
X=optimize.linprog(...)
print("x:", X.x[:T+1])
print(np.shape(X.x[:T+1]))
print("a:", X.x[T+1:2*T+1])
print(np.shape(X.x[T+1:2*T+1]))
print("v:", X.x[2*T+1:])
print(np.shape(X.x[2*T+1:]))
print("Optimal cost", X.fun)
solve_deterministic_pb()
x: [-0. 0. 0. 1. 2. 3. 5. 5. 0. 0. 0. 0. 0. 0. 1. 3. 5. 5.
5. 5. 0. 0. 0. 0. 0.]
(25,)
a: [ 0. 0. 0. 0. 0. 0. 2. 1. 8. 4. 2. -0. -0. 0. 0. 1. -0. 1.
3. 2. 9. 3. 2. 0.]
(24,)
v: [ 1. 1. -0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. -0.]
(24,)
Optimal cost 124.0
Exercice 2
interpolation d’ordre 2
% with y=[0 1 2] and val=[1 3 7], the solution is alpha= [1 1 1]
from scipy.optimize import minimize
def interpolate_2(y,val):
def objective(alpha):
return ...
# initial guess
n = 3
alpha0 = np.zeros(n)
# show initial objective
#print('Initial SSE Objective: ' + str(objective(alpha0)))
# optimize
solution = minimize(...)
#print('Output SSE Objective: ' + str((solution.fun)))
#print('Optimal minimizers: ' + str((solution.x)))
return solution.x
#% Exercise 2: with y=[0 1 2] and z=[1 3 7], the solution is alpha= [1 1 1]
y=np.array([0,1,2])
val=np.array([1,3,7])
interpolate_2(y,val)
array([0.99999997, 1.00000017, 0.99999991])
Exercice 3
DP_solve
def DP_solve(t,y,alpha):
def cost(X):
# X[0]=y X[1]=a, X[2]= v
# inf P_a*a -Pv*v + V(t+1,z) (V(t+1, z) en fonction de plusieurs valeurs de z
return ...
# x,a,v>=0, x<=xmax -> bounds
# z -a +v = y -d[t] -> contraints
#print(d[t])
cons = ({'type': 'eq', 'fun': lambda x: ...})
bnds = (...)
res = minimize(...);
X=res.x
#print("objective solution: ",res.fun)
#print("min solution: ",res.x)
z= X[0];
a= X[1];
v= X[2];
return z,a,v,res.fun
t=0,
y=0,
alpha=np.array([ 1, -2, 1])
DP_solve(t,y,alpha)
# the solution is z= 0.5, a= 0, v= 0.5, the optimal value is -0.25.
(0.49999999068677436, 0.0, 0.5000000093132256, -0.24999999999999992)
Exercice 4
J=10
def DP_backward():
global T;
global J;
global x_max;
alpha= np.zeros((3,T+1));#V(T+1,z)=0
y_grid= np.zeros(J)
for j in range(J):
y_grid[j]=... #yj={0,...,x_max}, j=0...J-1
for t in reversed(range(T)): # Backward in time
Val_update=np.zeros(J) #V(t+1,z)
for j in range(J): # for all value y_j, we evaluate V(t,y_j) (first with alpha=0 )
_,_,_,val= DP_solve(...)
Val_update[j]= val;
#print(y_grid,"z",z)
alpha[:,t]= interpolate_2(...); # (then with alpha = interpolation of V(t,y_j) and so on...)
return alpha
DP_backward()
array([[ 1.23631437e+02, 1.24791155e+02, 1.26095882e+02,
1.27656100e+02, 1.29587347e+02, 1.31916134e+02,
1.40773709e+02, 1.34773709e+02, 1.16773710e+02,
9.30031462e+01, 8.08861154e+01, 7.68542717e+01,
7.68635386e+01, 7.68814136e+01, 7.88586402e+01,
8.30747352e+01, 8.49474625e+01, 9.49474620e+01,
9.09474628e+01, 7.89474634e+01, 5.09474632e+01,
1.49474628e+01, 5.94545415e+00, 1.67766160e-07,
0.00000000e+00],
[-1.08846000e+00, -1.17081109e+00, -1.32595089e+00,
-1.59971656e+00, -2.00087060e+00, -2.43166594e+00,
-2.99999953e+00, -2.99999935e+00, -2.99999937e+00,
-3.26596357e+00, -2.19027431e+00, -1.61937311e+00,
-1.63962941e+00, -1.67967549e+00, -2.05487349e+00,
-2.29060523e+00, -1.99999953e+00, -3.99999898e+00,
-3.99999937e+00, -4.00000031e+00, -4.00000033e+00,
-3.19803556e+00, -3.32757498e+00, -1.00000005e+00,
0.00000000e+00],
[ 1.24663331e-02, 2.40182821e-02, 4.55023072e-02,
8.18284764e-02, 1.27903185e-01, 1.59545303e-01,
-4.14799962e-08, -1.31699557e-07, -1.29224448e-07,
7.70765417e-02, 1.09805403e-01, 7.34671183e-02,
7.91449183e-02, 9.06201514e-02, 1.27500734e-01,
8.45452442e-02, -1.10380417e-07, -1.77990387e-07,
-1.35081699e-07, 5.36456687e-08, 5.07712857e-08,
5.81728157e-02, 3.19090748e-01, 1.73503868e-09,
0.00000000e+00]])
Exercice 5
alpha= DP_backward(); # for any z, interpolation of V(t+1,z)
def DP_forward():
global T;
global P_a;
global P_v;
x= np.zeros(T+1); #initialization
a= np.zeros(T);
v= np.zeros(T);
for t in range(0,T):
z,a0,v0,_= ... # solve
x[t+1]= ...;# update
a[t]= ... ;
v[t]= ... ;
val= ... #cost
return x, a, v, val
x,a,v,val=DP_forward()
print("X",x,"a",a,"v",v)
print("val",val)
X [0.00000000e+00 1.00000000e+00 2.00000000e+00 3.00000000e+00
3.91260913e+00 4.48671136e+00 5.00000000e+00 3.00000000e+00
0.00000000e+00 1.72531780e+00 0.00000000e+00 1.11022302e-15
0.00000000e+00 0.00000000e+00 1.00000000e+00 3.00000000e+00
4.00000000e+00 5.00000000e+00 4.00000000e+00 1.00000000e+00
4.44089210e-16 0.00000000e+00 5.13294201e-01 0.00000000e+00
0.00000000e+00] a [2.28983499e-16 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 2.22044605e-16 3.00000000e+00
9.72531780e+00 2.27468220e+00 2.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
9.99999970e-01 0.00000000e+00 2.22044605e-16 6.00000000e+00
9.00000000e+00 3.51329420e+00 1.48670580e+00 0.00000000e+00] v [1.11022302e-16 1.77635684e-15 0.00000000e+00 8.73908685e-02
4.25897770e-01 1.48671136e+00 6.66133815e-16 0.00000000e+00
0.00000000e+00 0.00000000e+00 1.44328993e-15 0.00000000e+00
0.00000000e+00 1.11022302e-16 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 0.00000000e+00 1.55431223e-15
0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
val [123.99999994]