function C=ttdConvolveWithGv(time,Tdata,Cbdata,Pe,tau,epsilon,lambdaDecay,isSteady) % USAGE: C = ttdConvolveWithGv(time,Tdata,Cbdata,Pe,tau,[epsilon],[lambdaDecay],[isSteady]) % Returns the convolution of Gv with the tracer boundary condition % at time t with flow parameters Pe and tau. % INPUTS: % time = time (same units as Tdata and tau) % Tdata = vector of times at which boundary data are available % Cbdata = vector of boundary data (of length Tdata) % Pe = Peclet number % tau = mean age % epsilon = optional parameter used to split the convolution % integral. If omitted or is an empty array ([]) a default value % of 1 year is used. % lambdaDecay = optional decay constant [1/year] for a radioactive tracer. % If omitted or is an empty array ([]) a default value % of 0 is used. % isSteady = optional flag indicating whether the tracer is a steady state % tracer or not. If isSteady=1, the steady state concentration is % computed. The arguments 'time' and 'Tdata' are then ignored, and % Cbdata is assumed to be a scalar. % Compatibility note: % This function uses an adaptive quadrature routine to evaluate the convolution integral. % The builtin 'quad' function is not very robust and is also quite slow. Matlab 7.5 introduced % a vectorized quad ('quadgk.m') that is much much better. However, if you don't have version % 7.5, you can download an alternative called 'quadva.m' written by Lawrence Shampine of SMU. % You can download it from his website: http://faculty.smu.edu/shampine/quadva.m or email me % for a copy (spk@ldeo.columbia.edu). % This routine checks whether you are using version 7.5. If you are, then it will use quadgk.m. % Otherwise it will use quadva.m. % Notes: % C(t) = Integral[Gv(t')*Cb(t-t'),{t',0,t}] % C(t) = I1(eps) + I2(eps) % I1(eps) = Integral[Gv(t')*Cb(t-t'),{t',0,eps}] % ~ *Integral[Gv(t'),{t',0,eps}] % where, % = mean of Cb(t) in interval [0,eps] % I2(eps) = Integral[Gv(t')*Cb(t-t'),{t',eps,t}] % If lambdaDecay is specified, the integral is: % C(t) = Integral[Gv(t')*exp(-lambdaDecay*t')*Cb(t-t'),{t',0,t}] % If isSteady=1, the integral is: % C(t) = Cb*Integral[Gv(t')*exp(-lambdaDecay*t'),{t',0,Inf}] % Samar Khatiwala (spk@ldeo.columbia.edu) % Process arguments if nargin<6 epsilon=1; end if isempty(epsilon) epsilon=1; end if nargin<7 lambdaDecay=0; end if isempty(lambdaDecay) lambdaDecay=0; end if nargin<8 isSteady=0; end if isempty(isSteady) isSteady=0; end quadTol=1e-10; if ~isSteady % transient tracer if any(timeTdata(end)) error('ERROR: time must be bracketed by Tdata(1) and Tdata(end)') end if any(time= epsilon') end if length(Pe)~=1 | length(tau)~=1 error('ERROR: Pe and tau must be scalars') end % Assume that Cb = 0 for t < Tdata(1) so shift origin time=time-Tdata(1); Tdata=Tdata-Tdata(1); if ~verLessThan('matlab','7.5') Gv1=1-quadgk(@(tp)ttdGv(tp,Pe,tau),epsilon,Inf,'AbsTol',quadTol); else Gv1=1-quadva(@(tp)ttdGv(tp,Pe,tau),[epsilon Inf],[],quadTol); end C=repmat(0,size(time)); for it=1:length(time) t=time(it); Cbbar=mean(interp1(Tdata,Cbdata,[t-epsilon t]')); I1=Gv1*Cbbar; if ~verLessThan('matlab','7.5') I2=quadgk(@(tp)convolutionIntegrand(tp),epsilon,t,'AbsTol',quadTol); else I2=quadva(@(tp)convolutionIntegrand(tp),[epsilon t],[],quadTol); end C(it)=I1+I2; end else % steady state tracer if ~verLessThan('matlab','7.5') Gv1=1-quadgk(@(tp)ttdGv(tp,Pe,tau),epsilon,Inf,'AbsTol',quadTol); else Gv1=1-quadva(@(tp)ttdGv(tp,Pe,tau),[epsilon Inf],[],quadTol); end expbar=mean(exp(-lambdaDecay*linspace(0,epsilon,10))); I1=Gv1*expbar; if ~verLessThan('matlab','7.5') I2=quadgk(@(tp)steadyIntegrand(tp),epsilon,Inf,'AbsTol',quadTol); else I2=quadva(@(tp)steadyIntegrand(tp),[epsilon Inf],[],quadTol); end C=Cbdata*(I1+I2); end % private (nested) functions function GC=convolutionIntegrand(tp) GC=ttdGv(tp,Pe,tau).*exp(-lambdaDecay*tp).*interp1(Tdata,Cbdata,t-tp); end function GC=steadyIntegrand(tp) GC=ttdGv(tp,Pe,tau).*exp(-lambdaDecay*tp); end end