NCCOOS Trac Projects: Top | Web | Platforms | Processing | Viz | Sprints | Sandbox | (Wind)

root/gliderproc/trunk/MATLAB/opnml/drog2ddt.m

Revision 495 (checked in by cbc, 12 years ago)

Initial import of Stark code.

Line 
1 function [xx,yy,j]=drog2ddt(fem_grid_struct,t1,t2,dt,xi,yi,V)
2 %DROG2DDT - Track drogues in a 2-D flow-field
3 % DROG2DDT tracks passive particles in a 2-D flow-field defined
4 % on a FEM domain.  The integrator is 4th-order Runge-Kutta.
5 %
6 %   Input: fem_grid_struct - fem grid structure (see LOADGRID)
7 %          t1,t2           - integration interval (in hours)
8 %          dt              - integration timestep (in hours)
9 %          xi,yi           - arrays of drogue starting positions
10 %          V               - array of structures containing velocity slices
11 %                            Type
12 %
13 %  Output: xx,yy           - arrays of particle trajectories
14 %          j               - elements containing final drogue positions
15 %
16 % Note: unless the first (and only) argument is a help string ('mainhelp',
17 % 'velhelp',...), all arguments are required.
18 %
19 % Call as:[xx,yy,j]=drog2ddt(fem_grid_struct,t1,t2,dt,xi,yi,V)
20
21 % Check first argument
22 if nargin==1
23    drog2ddthelp(fem_grid_struct);
24    return
25 elseif nargin>7
26    error('Too many arguments to DROG2DDT')
27 elseif nargin==0
28    error('DROG2DDT must be called with 1|7 input arguments')
29 end
30
31 if ~isstruct(fem_grid_struct)
32    disp('    First argument to DROG2DDT must be a structure.');return
33 elseif ~is_valid_struct(fem_grid_struct)
34    error('    fem_grid_struct to DROG2DDT invalid.')
35 end
36
37
38 % Error-check the input times relative to the timestamps
39 % in the velocity cell array V.  It is ASSUMED that the
40 % velocity slices are in temporal order within the cells
41 timemin=V(1).time;
42 timemax=V(length(V)).time;
43 if t1 < timemin
44    error('T1 less than minimum time in velocity cells.')
45 elseif t2 > timemax
46    error('T2 exceeds maximum time in velocity cells.')
47 end
48
49 xi=xi(:);yi=yi(:);
50 if length(xi)~=length(yi)
51    error('Lengths of xi,yi must be equal')
52 end
53
54 % Extract a time vector for the times at which the velocity
55 % slices are available.
56 timevec=[V.time];
57
58 % Attach element finding arrays to fem_grid_struct
59 if ~isfield(fem_grid_struct,'A')|~isfield(fem_grid_struct,'B')|...
60     ~isfield(fem_grid_struct,'A0')| ~isfield(fem_grid_struct,'T')
61    fem_grid_struct=belint(fem_grid_struct);
62    disp('   BELINT info added to fem_grid_struct')
63 end
64 if ~isfield(fem_grid_struct,'ar')
65    disp('   EL_AREAS info added to fem_grid_struct')
66    fem_grid_struct=el_areas(fem_grid_struct);
67 end
68
69 % Locate initial positions in grid
70 % j will be the array that keeps track of the
71 % current element number of each drog.  A NaN will
72 % be used to indicate drog in-activity, either because
73 % the drog is initially out-of-bounds, or because the
74 % drogue has left the domain during tracking.
75 j=findelem(fem_grid_struct,[xi yi]);
76
77 % Allocate space for time history of positions
78 xx=NaN*(ones(size(t1:dt:t2))'*ones(size(xi')))';
79 yy=xx;
80
81 %
82 xx(:,1)=xi;
83 yy(:,1)=yi;
84
85 % Loop over time;  for development purposes, the integration will
86 % be forward Euler.
87 time=t1;
88 iter=1;
89 dtsecs=dt*3600;
90 disp(['Starting: [' int2str(iter) ' ' num2str(time) ']'])
91
92 while time<t2
93    %
94 %   if iter==3,keyboard,end;
95    xnow=xx(:,iter);
96    ynow=yy(:,iter);
97    xnew=xnow;   % Propagate previously known positions, in case a
98    ynew=ynow;   % drogue is eliminated.
99 %   line(xnow,ynow,'Color','r','Marker','+')
100
101    igood=find(~isnan(j));
102    % If j contains NaN's, these drogues are have exited the
103    % domain at some previous timestep.
104    
105    if isempty(igood)
106       disp('All drogues eliminated')
107       disp(['Ending:   [' int2str(iter) ' ' num2str(time) ']'])
108       return
109    end
110    
111    % Extract drogues currently in domain
112    jgood=j(igood);xgood=xnow(igood);ygood=ynow(igood);
113    
114    [xnext,ynext,jnext]=track(fem_grid_struct,jgood,xgood,ygood,V,timevec,time,dtsecs);
115    j(igood)=jnext;
116    xnew(igood)=xnext;
117    ynew(igood)=ynext;
118
119    time=time+dt;
120    iter=iter+1;   
121
122    xx(:,iter)=xnew;
123    yy(:,iter)=ynew;
124    
125 end
126
127 % Prepare for return
128 disp(['Ending:   [' int2str(iter) ' ' num2str(time) ']'])
129 return
130
131
132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133 %  PRIVATE FUNCTIONS                                %
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135
136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
137 % locate_drog                                       %
138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139 function jnew=locate_drog(fem_grid_struct,x,y,j)
140
141 jnew=j;
142    
143 % See if drogs are still in Previously known element
144 idx=belel(fem_grid_struct,j,[x y]);
145 inotfound=find(idx==0);
146
147 % Get new elements, if not in previously known element
148 if ~isempty(inotfound)
149    idx=inotfound;
150    jnew(idx)=findelem(fem_grid_struct,[x(idx) y(idx)]);
151 end
152
153 function [xnew,ynew,jnew]=track(fem_grid_struct,j,x,y,V,timevec,t,dt)
154
155 jnew=j;
156    
157 % Runge-Kutta 4
158 tt1=t+.5*dt/3600;
159
160 [u,v]=vel_interp(fem_grid_struct,x,y,j,V,timevec,t);
161 k1u=dt*u;
162 k1v=dt*v;
163 xinter1=x+.5*k1u;
164 yinter1=y+.5*k1v;
165 jinter=locate_drog(fem_grid_struct,xinter1,yinter1,j);
166 if all(isnan(jinter))
167    xnew=x;
168    ynew=y;
169    jnew=jinter;
170    return
171 end
172
173 [uinter,vinter]=vel_interp(fem_grid_struct,xinter1,yinter1,jinter,V,timevec,tt1);
174 k2u=dt*uinter;
175 k2v=dt*vinter;
176 xinter2=x+.5*k2u;
177 yinter2=y+.5*k2v;
178 jinter=locate_drog(fem_grid_struct,xinter2,yinter2,j);
179 if all(isnan(jinter))
180    xnew=xinter1;
181    ynew=yinter1;
182    jnew=jinter;
183    return
184 end
185
186 [uinter,vinter]=vel_interp(fem_grid_struct,xinter2,yinter2,jinter,V,timevec,tt1);
187 k3u=dt*uinter;
188 k3v=dt*vinter;
189 xinter3=x+k3u;
190 yinter3=y+k3v;
191 jinter=locate_drog(fem_grid_struct,xinter3,yinter3,j);
192 if all(isnan(jinter))
193    xnew=xinter2;
194    ynew=yinter2;
195    jnew=jinter;
196    return
197 end
198
199 [uinter,vinter]=vel_interp(fem_grid_struct,xinter3,yinter3,jinter,V,timevec,t+dt/3600);
200 k4u=dt*uinter;
201 k4v=dt*vinter;
202
203
204 xnew=x+k1u/6+k2u/3+k3u/3+k4u/6;
205 ynew=y+k1v/6+k2v/3+k3v/3+k4v/6;
206
207 jnew=locate_drog(fem_grid_struct,xnew,ynew,j);
208          
209 % If NaN is in j, then drog has left domain. 
210 % insert last known location into arrays
211 inan=find(isnan(jnew));;
212 if ~isempty(inan)
213    xnew(inan)=x(inan);
214    ynew(inan)=y(inan);
215 end
216
217
218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219 % belel                                            %
220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221 function retval=belel(fem_grid_struct,j,xylist)
222 %BELEL - determine if points are in elements
223 % BELEL
224 tol=eps*10000000;
225 phi=basis2d(fem_grid_struct,xylist,j);
226 test=phi>=-tol & phi<=1+tol;
227 retval=all(test'==1);
228
229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230 % vel_interp                                        %
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232 function [u,v]=vel_interp(fem_grid_struct,x,y,j,V,timevec,t)
233 % Get the velocities at this time
234 % Temporal interpolation of velocity slices to this time.
235 it1=find(t<=timevec);it1=it1(1);
236 it2=find(t>=timevec);it2=it2(length(it2));
237 if it1==it2
238    tfac1=1;tfac2=0;
239 else
240    tfac1=(timevec(it1)-t)/(timevec(it1)-timevec(it2));
241    tfac2=1-tfac1;
242 end
243 u1=V(it1).u;
244 u2=V(it2).u;
245 v1=V(it1).v;
246 v2=V(it2).v;
247
248 % Depending on the number of particles to track, the
249 % interpolation to (x,y,t) is done one of two ways.
250 % it is not ovvious, but the flop savings can be huge.
251 if length(j)>150
252    % Interpolate in time first,...
253    uu=tfac1*u2 + tfac2*u1;
254    vv=tfac1*v2 + tfac2*v1;
255    % ... then, space
256    u=interp_scalar(fem_grid_struct,uu,x,y,j);
257    v=interp_scalar(fem_grid_struct,vv,x,y,j);
258 else
259    % Interpolate in space first, at the 2 time levels
260    uu1=interp_scalar(fem_grid_struct,u1(:),x,y,j);
261    vv1=interp_scalar(fem_grid_struct,v1(:),x,y,j);
262    uu2=interp_scalar(fem_grid_struct,u2(:),x,y,j);
263    vv2=interp_scalar(fem_grid_struct,v2(:),x,y,j);
264    % Then, interpolate BETWEEN time levels
265    u=tfac1*uu2 + tfac2*uu1;
266    v=tfac1*vv2 + tfac2*vv1;
267 end
268
269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270 % drog2ddthelp                                      %
271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272 function drog2ddthelp(option)
273
274 if ~isstr(option)
275    error('Invalid help string to DROG2DDT')
276 end
277
278 switch lower(option)
279    case 'mainhelp'
280       str=[sprintf('DROG2DDT HELP: mainhelp\n')];
281    case 'velhelp'
282       str=[sprintf('\nDROG2DDT HELP: velhelp\n')];
283       str=[str sprintf('\nDROG2DDT needs a series of 2-D velocity fields.  This\n')];
284       str=[str sprintf('information is passed into DROG2DDT in an array of structures.  \n')];
285       str=[str sprintf('Each structure has fields named ''u'',''v'', and ''time''.  The first\n')];
286       str=[str sprintf('two structures thus look like:\n')];
287       str=[str sprintf('\n   V(1).u;        %%  u-velocity for time 1\n')];
288       str=[str sprintf('   V(1).v;        %%  v-velocity for time 1\n')];
289       str=[str sprintf('   V(1).time;     %%  actual time in hours!! for time 1\n')];
290       str=[str sprintf('   V(2).u;        %%  u-velocity for time 2\n')];
291       str=[str sprintf('   V(2).v;        %%  u-velocity for time 2\n')];
292       str=[str sprintf('   V(2).time;     %%  actual time in hours!! for time 2\n')];
293       str=[str sprintf('\nand so on...\n')];
294       str=[str sprintf('DROG2DDT makes sure that each structure is identical in fields, \n')];
295       str=[str sprintf('and that the integration times are within the initial and final\n')];
296       str=[str sprintf('times specified in the velocity array V.  The sizes of the ''u'' and \n')];
297       str=[str sprintf('''v'' fields must match the nuber of nodes in the fem_grid_struct.\n')];
298  
299
300
301    otherwise
302       disp('DROG2DDT must be called with a valid help string.')
303       disp('Try: ''mainhelp'',''velhelp''')
304 end
305
306 if ~isempty(str)
307    disp(str)
308 end
309 return
Note: See TracBrowser for help on using the browser.