Additional Supporting Material for paper: *Optimizing wellfield

advertisement
Additional Supporting Material for paper: “Optimizing wellfield operation
in a variable power price regime” by Peter Bauer-Gottwein, Raphael
Schneider and Claus Davidsen
Abstract:
Wellfield management is a multi-objective optimization problem. One important objective has been energy
efficiency in terms of minimizing the Energy Footprint (EFP) of delivered water (MWh/m3). However, power
systems in most countries are moving in the direction of deregulated markets and price variability is increasing
in many markets because of increased penetration of intermittent renewable power sources. In this context
the relevant management objective becomes minimizing the cost of electric energy used for pumping and
distribution of groundwater from wells rather than minimizing energy use itself.
We estimated energy footprint of pumped water as a function of wellfield pumping rate (EFP-Q relationship)
for a wellfield in Denmark using a coupled well and pipe network model. This EFP-Q relationship was
subsequently used in a Stochastic Dynamic Programming (SDP) framework to minimize total cost of operating
the combined wellfield-storage-demand system over the course of a 2-year planning period based on a time
series of observed price on the Danish power market and a deterministic, time-varying hourly water demand.
In the SDP setup, hourly pumping rates are the decision variables. Constraints include storage capacity and
hourly water demand fulfilment. The SDP was solved for a baseline situation and for five scenario runs
representing different EFP-Q relationships and different maximum wellfield pumping rates.
Savings were quantified as differences in total cost between the scenario and a constant-rate pumping
benchmark. Minor savings up to 10% were found in the baseline scenario, while the scenario with constant EFP
and unlimited pumping rate resulted in savings up to 40%. Key factors determining potential cost savings
obtained by flexible wellfield operation under a variable power price regime are the shape of the EFP-Q
relationship, the maximum feasible pumping rate and the capacity of available storage facilities.
MATLAB code listing for the water value method
%% Inputs
avdemand = 588; % average water demand, m3/hour
wtcap = 47173*1.5; % storage capacity of the water tower, m3. Share of Tinghøj according to inflow
sdisc = 500/2; %storage discretization (m^3)
wdhourfactors = [2.4865313e-02
1.4504766e-02
1.0360547e-02
8.2884376e-03
1.0360547e-02
2.0721094e-02
3.9370079e-02
6.1334438e-02
7.0451720e-02
6.4235392e-02
6.0091173e-02
4.9730626e-02
4.7658516e-02
4.5586407e-02
4.3514298e-02
4.5586407e-02
4.7658516e-02
5.3874845e-02
6.0091173e-02
5.8019063e-02
4.7658516e-02
4.1442188e-02
3.9370079e-02
3.5225860e-02];
% from http://www2.mst.dk/common/Udgivramme/Frame.asp?http://www2.mst.dk/Udgiv/publikationer/2005/87-7614-5921/html/sum.htm
wdhour = 24*wdhourfactors*avdemand; % hourly water demand, m3/hour
nscen = 5; %Number of price classes
%% Getting electricity price info
elprice=xlsread('Elprice_2012_13.xlsx','Elprice','D4:D17547');
% from http://www.energinet.dk/DA/El/Engrosmarked/Udtraek-af-markedsdata/Sider/default.aspx
% in DKK/MWh
time1=datenum('01-01-2012 00:00:00');
time=time1+([1:1:17544]-1)/24;
timevec = datevec(time);
hour = timevec(:,4)+1;
for i=1:1:24
pphour(i) = nanmean(elprice(find(hour==i)));
stdhour(i) = nanstd(elprice(find(hour==i)));
elpriceav(hour==i) = pphour(i);
elpricestd(hour==i) = stdhour(i);
end
elprice(find(isnan(elprice)))=elprice(find(isnan(elprice))-1); %Filling in the few NaNs that there are
elpricenorm = (elprice-elpriceav')./elpricestd'; %Normalizing
qbreaks = [1:1:nscen-1]/nscen;
breaks = quantile(elpricenorm,qbreaks);
nclasses = length(breaks) +1;
% Classifying price time series
elpriceclass (elpricenorm<breaks(1))=1;
nsamples(1) = sum(elpricenorm<breaks(1));
for i=2:1:nclasses-1
elpriceclass (elpricenorm>=breaks(i-1) & elpricenorm<breaks(i))=i;
nsamples(i) = sum(elpricenorm>=breaks(i-1) & elpricenorm<breaks(i));
end
elpriceclass (elpricenorm>breaks(end))=nclasses;
nsamples(nclasses) = sum(elpricenorm>breaks(end));
% Finding mean price for each class and each hour
for i=1:1:24
for j=1:1:nclasses
pphourscen(j,i) = nanmean(elprice(find(hour==i & elpriceclass'==j)));
end
end
% Finding transition probability matrices for each class and each hour
for i = 1:1:24
for j = 1:1:nclasses
for k = 1:1:nclasses
count1 = sum(hour==i & elpriceclass' ==j);
nextstep = find(elpriceclass' == j & hour == i) ;
nextstep = nextstep(1:end-1) + 1;
count2 = sum(elpriceclass(nextstep)==k);
TP(j,k,i) = count2/(count1-1);
end
end
end
%% Energy footprint.
% assumed to be a polynomial. Gives the energy footprint (kWh/m3) for given
% pumping rate in m3/hour. This is the result of the Søndersø wellfield
% model
load('maxrate.mat'); %maximum abstraction rate for the wellfield in m3/hour
maxrate = max(wdhour)+1;
load('WFCHARpoly3.mat'); %Coefficients of the polynomial as produced by polyfit
WFCHAR = WFCHARpoly3/3.6/1000; %Conversion from MJ/m3 to MWh/m3
qplot = linspace(0,maxrate,20);
efpplot = polyval(WFCHAR,qplot);
plotcc = 1;
if plotcc
plot(qplot,efpplot);
xlabel('pumping rate, m^3/hour')
ylabel('energy footprint, MWh/m^3')
end
%% Initializing
S=[0:sdisc:wtcap];
maxS = max(S);
expfutcost = 0*ones(nclasses,1)*S;
expfutlambda = 0*ones(nclasses,1)*S;
tcost = 0*ones(nclasses,1)*S;
arlambda = 0*ones(nclasses,1)*S;
%% Loop backwards
figure;hold on;
poolobj=parpool('Peter');
poolobj.NumWorkers
for l=1:1:100 % This is typically enough to reach steady-state water values
for j=24:-1:1
display(j);
for k = 1:1:nclasses
expfutcostscen = S*0;
expfutlambdascen = S*0;
for m = 1:1:nclasses
expfutcostscen = expfutcostscen + TP(k,m,j) * expfutcost(m,:);
expfutlambdascen = expfutlambdascen + TP(k,m,j) * expfutlambda(m,:);
end
parfor i=1:1:length(S)
[ic(i) fc(i) tc(i) lambda(i)] =
TC_function(S(i),maxS,wdhour(j),pphourscen(k,j),S,expfutcostscen,expfutlambdascen, maxrate, WFCHAR);
end
intermediatecost(k,:)=tc;
intermediatelambda(k,:)=lambda;
subplot(nclasses,1,k);
hold on;
plot(tc,S,'c','LineWidth',2)
xlabel('total cost in DKK','FontSize',14)
ylabel('Storage in m^3','FontSize',14)
set(gca,'fontsize',14)
end
expfutcost = intermediatecost;
expfutlambda = intermediatelambda;
tcost = cat(3,intermediatecost,tcost);
arlambda = cat(3,intermediatelambda,arlambda);
end
end
delete(poolobj);
plotvv = 1
if plotvv
figure
for i=1:1:nclasses
subplot(nclasses,1,i)
big = size(arlambda);
wv = reshape(arlambda(i,:,1:end-1),big(2),big(3)-1);
imagesc(flipud(wv));
set(gca,'YTick',[1:10:big(2)],'YTickLabel',fliplr(S(1:10:length(S))));
xlabel('Time, hours')
ylabel('Storage volume, m^3');
hh=colorbar
ylabel(hh,'water value, DKK/m^3');
end
end
%% Saving equilibrium water values and future costs for simulation phase
clear wv expfutcost
for i=1:1:nclasses
big = size(arlambda);
wv(:,:,i) = reshape(arlambda(i,:,2:25),big(2),24);
expfutcost(:,:,i) = reshape(tcost(i,:,2:25),big(2),24);
end
save wvsdp.mat wv expfutcost arlambda tcost
% shadow prices are for total cost from beginning of t to end of period.
% However, we need end to t to end of period for simulation phase.
%% Simulation phase real prices
elprice(find(isnan(elprice)))=elprice(find(isnan(elprice))-1); %replacing the very few NaN's that there are in the
elprice time series
efpav = polyval(WFCHAR,avdemand);
totcostconst = nansum(elprice*efpav*avdemand); %This is the cost when pumping at a constant rate
Scurrent = wtcap/2;
clear ic fc tc lambda x
for i=1:1:length(elprice)
class = elpriceclass(i);
expfutcostscen = S*0;
expfutlambdascen = S*0;
for m = 1:1:nclasses
expfutcostscen = expfutcostscen + TP(class,m,hour(i)) * expfutcost(:,hour(i),m)';
expfutlambdascen = expfutlambdascen + TP(class,m,hour(i)) * wv(:,hour(i),m)';
end
[ic(i) fc(i) tc(i) lambda(i) x(:,i)] =
TC_function(Scurrent,maxS,wdhour(hour(i)),elprice(i),S,expfutcostscen,expfutlambdascen, maxrate, WFCHAR);
display(i)
Scurrent = x(2,i);
end
totcostvar = sum(ic);
qvar = x(1,:);
svar = x(2,:);
save policysdp.mat totcostconst totcostvar qvar svar
function [ic,fc,tc,lambda,x] = TC_function(S,maxS,wdhour,pphour,Sf,FC,lambda,upperq, polycoeff)
%Define objective function:
function obj = ofunction(x)
obj=pphour*x(1)*polyval(polycoeff,x(1))+x(3);
end
% Constraints on future cost
alpha = -lambda;
beta=Sf;
gamma=FC;
ncuts = length(alpha);
A = [zeros(ncuts,1) alpha' -ones(ncuts,1)];
b = alpha'.*beta' - gamma';
%Define water balance equality constraint:
Aeq = [-1 1 0];
beq = S - wdhour;
%Define lb:
lb=[0;0;0];
ub = [upperq;maxS;Inf];
%Run constrained optimization
options = optimset('Algorithm','interior-point','TolX',1E-12,'TolCon',1E-8,'TolFun',1E8,'Diagnostics','off','Display','off');
[x,fval,exitflag,output,lambda] = fmincon(@ofunction,[0;S;FC(find(abs(Sf-S)==min(abs(SfS))))],A,b,Aeq,beq,lb,ub,[],options);
if ~(exitflag==1 | exitflag==2) % catching non-convergence
exitflag
keyboard
end
%Compute immediate, future and total cost in optimal solution
ic = fval - x(3);
fc = x(3);
tc = fval;
lambda=lambda.eqlin;
end
Download