1 |
function bfd=genbfd(fem_grid_struct,xylist,outflag,bfdfilename,refl) |
---|
2 |
%GENBFD generate a "basis function data" file for FD contouring |
---|
3 |
% GENBFD computes an information file for contouring FEM |
---|
4 |
% node-based data using FD sampled points and MATLAB's |
---|
5 |
% contourf routine. The FD-based plotting tools are part |
---|
6 |
% of the FDCONT toolkit. |
---|
7 |
% |
---|
8 |
% Input: fem_grid_struct - FEM domain |
---|
9 |
% xylist - FD point list (n X 2) or a 1x2 vector |
---|
10 |
% containing [nx ny], the number of FD |
---|
11 |
% points in (x,y) to discretize the area. |
---|
12 |
% See below. |
---|
13 |
% outflag - flag to output .bfd file to disk |
---|
14 |
% if outflag==1, the bfd matrix is output to |
---|
15 |
% the current directory with the name |
---|
16 |
% <gridname>.bfd. |
---|
17 |
% if outflag==0, the bfd matrix is returned |
---|
18 |
% workspace. |
---|
19 |
% bfdfilename - optional filename to write bfd matrix to. |
---|
20 |
% refl - Reference lon/lat for CPP transformation |
---|
21 |
% 1x2 vector [reflon reflat] |
---|
22 |
% (optional: output will be in input coordinates) |
---|
23 |
% |
---|
24 |
% Arguments 1-3 are required. |
---|
25 |
% |
---|
26 |
% If xylist is passed in as [nx ny], GENBFD generates |
---|
27 |
% the FD points convering an area equal to the |
---|
28 |
% total extent of the FEM domain. If only 1 integer |
---|
29 |
% is passed in, then nx=ny, GENBFD takes the smaller |
---|
30 |
% of [(xmax-xmin),(ymax-ymin)] for equal spacing. |
---|
31 |
% |
---|
32 |
% Output: The result of GENBFD is a matrix |
---|
33 |
% containing the following information. |
---|
34 |
% |
---|
35 |
% For each FD point: |
---|
36 |
% x y elem n1 n2 n3 b1 b2 b3 depth |
---|
37 |
% |
---|
38 |
% where x,y = FD point coordinate |
---|
39 |
% elem = FE element containing x y (==0 if outside FE mesh) |
---|
40 |
% n1,n2,n3 = node numbers of containing element (or closest) |
---|
41 |
% b1,b2,b3 = basis function values (or 1 0 0 if outside FEM) |
---|
42 |
% depth = depth at xy (or depth of closest node) |
---|
43 |
% |
---|
44 |
% For any given FD discretization, the bfd matrix need only be |
---|
45 |
% computed once. The bfd matrix is passed to FE2FD to perform |
---|
46 |
% the actual FE to FD interpolation. |
---|
47 |
% |
---|
48 |
% Call: bfd=genbfd(fem_grid_struct,xylist,outflag) |
---|
49 |
% OR bfd=genbfd(fem_grid_struct,xylist,outflag,bfdfilename) |
---|
50 |
% OR bfd=genbfd(fem_grid_struct,[nx ny],outflag,bfdfilename) |
---|
51 |
% OR bfd=genbfd(fem_grid_struct,[nx ny],outflag,refl) |
---|
52 |
% OR bfd=genbfd(fem_grid_struct,[nx ny],outflag,bfdfilename,refl) |
---|
53 |
% |
---|
54 |
% Written by: Brian Blanton (Spring 99) to implement |
---|
55 |
% Chris Naimie's "bfd" file in MATLAB. |
---|
56 |
% |
---|
57 |
% CPP transformation added 07/08/2003 (CRE) |
---|
58 |
% |
---|
59 |
|
---|
60 |
if nargin<3 | nargin>5 |
---|
61 |
error('Incorrect number of arguments to GENBFD.') |
---|
62 |
end |
---|
63 |
|
---|
64 |
if outflag~=0 & outflag~=1 |
---|
65 |
error('outflag to GENBFD must be 0|1.') |
---|
66 |
end |
---|
67 |
|
---|
68 |
grid=fem_grid_struct; grid=el_areas(grid); |
---|
69 |
if ~is_valid_struct(fem_grid_struct) |
---|
70 |
error(' Argument to GENBFD must be a valid fem_grid_struct.') |
---|
71 |
end |
---|
72 |
if ~is_valid_struct2(fem_grid_struct) |
---|
73 |
disp('Adding Grid Components') |
---|
74 |
grid=belint(grid); |
---|
75 |
grid=el_areas(grid); |
---|
76 |
end |
---|
77 |
|
---|
78 |
if nargin==3 |
---|
79 |
bfdfilename=fem_grid_struct.name; |
---|
80 |
end |
---|
81 |
if nargin==4 |
---|
82 |
if ~isstr(bfdfilename) |
---|
83 |
if(isa(bfdfilename,'double')&(size(bfdfilename)==[1 2])) |
---|
84 |
refl=bfdfilename; |
---|
85 |
bfdfilename=fem_grid_struct.name; |
---|
86 |
if outflag==0 |
---|
87 |
disp('Outflag==0, ignoring bfdfilename input.') |
---|
88 |
end |
---|
89 |
else |
---|
90 |
error('bfdfilename to GENBFD must be a string.') |
---|
91 |
end |
---|
92 |
end |
---|
93 |
end |
---|
94 |
|
---|
95 |
if nargin==5 |
---|
96 |
if ~isstr(bfdfilename) |
---|
97 |
error('bfdfilename to GENBFD must be a string.') |
---|
98 |
end |
---|
99 |
if outflag==0 |
---|
100 |
disp('Outflag=0, ignoring bfdfilename input.') |
---|
101 |
end |
---|
102 |
end |
---|
103 |
|
---|
104 |
% Check size of xylist; if it is 1x1|1x2|2x1, assume this is |
---|
105 |
% the [nx ny] case and generate the FD points |
---|
106 |
[m,n]=size(xylist); |
---|
107 |
if m*n==1 | m*n==2 |
---|
108 |
if m*n==1 |
---|
109 |
nx=xylist;ny=[]; |
---|
110 |
else |
---|
111 |
nx=xylist(1);ny=xylist(2); |
---|
112 |
end |
---|
113 |
|
---|
114 |
if nx<3 | ny < 3 |
---|
115 |
error('[nx,ny] to genbfd must be larger than 3x2 or 2x3') |
---|
116 |
end |
---|
117 |
disp(... |
---|
118 |
['Generating FD points as [' int2str(nx) ' ' int2str(ny) '] array...']) |
---|
119 |
[xylist,nnx,nny]=gen_fd_points(nx,ny,fem_grid_struct); |
---|
120 |
nx=nnx;ny=nny; |
---|
121 |
else |
---|
122 |
if (n==1 | m==1)&m*n>2 |
---|
123 |
error('xylist to BASIS1D must be Nx2') |
---|
124 |
end |
---|
125 |
end |
---|
126 |
|
---|
127 |
% allow for possible 2 x N shape |
---|
128 |
if n>2 |
---|
129 |
xylist=xylist'; |
---|
130 |
end |
---|
131 |
|
---|
132 |
[m,n]=size(xylist); |
---|
133 |
|
---|
134 |
bfd=NaN*ones(m,10); |
---|
135 |
|
---|
136 |
xfd=xylist(:,1); |
---|
137 |
yfd=xylist(:,2); |
---|
138 |
if(exist('refl','var')) |
---|
139 |
[xfd,yfd]=ll2xy(xylist(:,2),xylist(:,1),refl(2),refl(1)); |
---|
140 |
[xgrd,ygrd]=ll2xy(grid.y,grid.x,refl(2),refl(1)); |
---|
141 |
grid.x=xgrd; grid.y=ygrd; grid=el_areas(grid); grid=belint(grid); |
---|
142 |
end |
---|
143 |
bfd(:,1)=xfd; |
---|
144 |
bfd(:,2)=yfd; |
---|
145 |
|
---|
146 |
% Locate elements for xylist |
---|
147 |
disp('Finding elements...') |
---|
148 |
j=findelem(grid,[xfd yfd]); |
---|
149 |
|
---|
150 |
% which points are in.out of the FEM domain |
---|
151 |
idx_in_fem=find(~isnan(j)); |
---|
152 |
idx_out_fem=find(isnan(j)); |
---|
153 |
|
---|
154 |
% Fill element column of bfd |
---|
155 |
bfd(idx_in_fem,3)=j(idx_in_fem); |
---|
156 |
bfd(idx_out_fem,3)=zeros(size(idx_out_fem)); |
---|
157 |
|
---|
158 |
% NODE COLUMNS of bfd |
---|
159 |
bfd(idx_in_fem,4:6)=grid.e(j(idx_in_fem),:); |
---|
160 |
% Find nearest nodes for fd points outside FEM |
---|
161 |
% Only need to search boundary nodes for closest |
---|
162 |
disp('Minimizing distances...') |
---|
163 |
[bnd,cbnd] = count(grid.bnd); |
---|
164 |
xbnd=grid.x(bnd); |
---|
165 |
ybnd=grid.y(bnd); |
---|
166 |
xout=xfd(idx_out_fem); |
---|
167 |
yout=yfd(idx_out_fem); |
---|
168 |
XOUT=xout*ones(size(xbnd')); |
---|
169 |
XBND=ones(size(xout))*xbnd'; |
---|
170 |
YOUT=yout*ones(size(ybnd')); |
---|
171 |
YBND=ones(size(yout))*ybnd'; |
---|
172 |
XDIF=XOUT-XBND;YDIF=YOUT-YBND; |
---|
173 |
DIST=sqrt(XDIF.*XDIF + YDIF.*YDIF); |
---|
174 |
[min_dist,imin] = min(DIST'); |
---|
175 |
nearest_nodes=bnd(imin); |
---|
176 |
nearest_nodes=nearest_nodes(:); |
---|
177 |
bfd(idx_out_fem,4:6)=[nearest_nodes nearest_nodes nearest_nodes]; |
---|
178 |
|
---|
179 |
% BASIS |
---|
180 |
disp('Computing interp basis...') |
---|
181 |
%size([xfd(idx_in_fem) yfd(idx_in_fem)]) |
---|
182 |
phi=basis2d(grid,[xfd(idx_in_fem) yfd(idx_in_fem)],j(idx_in_fem)); |
---|
183 |
bfd(idx_in_fem,7:9)=phi; |
---|
184 |
|
---|
185 |
% |
---|
186 |
% Check sum of basis; |
---|
187 |
bsum=sum(phi'); |
---|
188 |
tol=1e-8; |
---|
189 |
idx=find(bsum>1+tol | bsum<0-tol); |
---|
190 |
if ~isempty(idx) |
---|
191 |
error('Sum of FE basis ~=1.') |
---|
192 |
end |
---|
193 |
|
---|
194 |
% |
---|
195 |
bfd(idx_out_fem,7:9)=... |
---|
196 |
[ones(size(nearest_nodes)) zeros(size(nearest_nodes)) zeros(size(nearest_nodes))]; |
---|
197 |
|
---|
198 |
% DEPTHS |
---|
199 |
disp('Interpolating depths...') |
---|
200 |
bfd(idx_out_fem,10)=grid.z(nearest_nodes); |
---|
201 |
bfd(idx_in_fem,10)=interp_scalar(grid,grid.z,xfd(idx_in_fem),yfd(idx_in_fem),... |
---|
202 |
j(idx_in_fem)); |
---|
203 |
|
---|
204 |
if ~isempty(find(isnan(bfd(:)))) |
---|
205 |
disp('Still NaNs in bfd array') |
---|
206 |
end |
---|
207 |
|
---|
208 |
if(exist('refl','var')) |
---|
209 |
bfd(:,1:2)=xylist; |
---|
210 |
end |
---|
211 |
|
---|
212 |
delete(findobj(0,'Tag','GENBFD fig')) |
---|
213 |
figure('MenuBar','none','Name','GENBFD Output') |
---|
214 |
line(bfd(:,1),bfd(:,2),'LineStyle','none','Marker','.','Color','r') |
---|
215 |
set(gcf,'Tag','GENBFD fig') |
---|
216 |
title_string=['GENBFD disc. [' int2str(nx) ' ' int2str(ny) '] on ' fem_grid_struct.name]; |
---|
217 |
title(title_string) |
---|
218 |
hb=plotbnd(fem_grid_struct);set(hb,'LineWidth',2) |
---|
219 |
axis('tight') |
---|
220 |
drawnow |
---|
221 |
|
---|
222 |
|
---|
223 |
% Check for output file flag |
---|
224 |
if outflag==1 |
---|
225 |
filename=[bfdfilename '.bfd']; |
---|
226 |
disp(['Writing BFD matrix to ' filename]) |
---|
227 |
fid=fopen(filename,'w'); |
---|
228 |
fprintf(fid,'%.3f %.3f %d %d %d %d %f %f %f %.2f\n',bfd'); |
---|
229 |
end |
---|
230 |
if nargout==0 |
---|
231 |
bfd=[]; |
---|
232 |
end |
---|
233 |
|
---|
234 |
% |
---|
235 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
236 |
%%%%% PRIVATE FUNCTION FOR GENBFD %%%%%%%%%%%%%%%%%%%%% |
---|
237 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
---|
238 |
function [xy,nnx,nny]=gen_fd_points(nx,ny,fem_grid_struct) |
---|
239 |
x=fem_grid_struct.x; |
---|
240 |
y=fem_grid_struct.y; |
---|
241 |
|
---|
242 |
xmin=min(x); |
---|
243 |
xmax=max(x); |
---|
244 |
ymin=min(y); |
---|
245 |
ymax=max(y); |
---|
246 |
xrange=xmax-xmin; |
---|
247 |
yrange=ymax-ymin; |
---|
248 |
|
---|
249 |
if isempty(ny) |
---|
250 |
minrange=min(xrange,yrange); |
---|
251 |
nnx=nx; |
---|
252 |
else |
---|
253 |
nnx=nx; |
---|
254 |
nny=ny; |
---|
255 |
end |
---|
256 |
|
---|
257 |
if isempty(ny) |
---|
258 |
dx=((xmax-xmin)/(nnx-1)); |
---|
259 |
xx=xmin:dx:xmax; |
---|
260 |
yy=ymin:dx:ymax; |
---|
261 |
nny=length(yy); |
---|
262 |
else |
---|
263 |
xx=linspace(xmin,xmax,nnx); |
---|
264 |
yy=linspace(ymin,ymax,nny); |
---|
265 |
end |
---|
266 |
[XX,YY]=meshgrid(xx,yy); |
---|
267 |
XX=XX';YY=YY'; % to get x-coord to vary fastest. |
---|
268 |
xy=[XX(:) YY(:)]; |
---|
269 |
|
---|
270 |
disp(['DX = ' num2str(xx(2)-xx(1))]) |
---|
271 |
disp(['DY = ' num2str(yy(2)-yy(1))]) |
---|
272 |
|
---|
273 |
|
---|
274 |
% |
---|
275 |
% Brian O. Blanton |
---|
276 |
% Department of Marine Sciences |
---|
277 |
% 15-1A Venable Hall |
---|
278 |
% CB# 3300 |
---|
279 |
% Uni. of North Carolina |
---|
280 |
% Chapel Hill, NC |
---|
281 |
% 27599-3300 |
---|
282 |
% |
---|
283 |
% 919-962-4466 |
---|
284 |
% blanton@marine.unc.edu |
---|
285 |
% |
---|
286 |
% Spring 1999 |
---|
287 |
|
---|
288 |
|
---|
289 |
|
---|
290 |
|
---|
291 |
|
---|
292 |
|
---|
293 |
|
---|
294 |
|
---|
295 |
|
---|