rbmatlab 0.10.01
|
00001 classdef rectgrid < gridbase 00002 % A cartesian rectangular grid in two dimensions with axis parallel elements. 00003 % 00004 % General geometrical information is stored including neighbour information. 00005 % Therefore also boundary neighbour relations can be specified. The boundary 00006 % type is set to be symmetric by default. Additionally, "rectangles" can be 00007 % defined: the edges with midpoints within such a rectangle are marked 00008 % accordingly. By this, boundary edges can be marked for later special use 00009 % Much (partially redundant) information is stored in the grid, which might 00010 % be useful in simulations. 00011 % 00012 % - Sorting of vertices is always counterclockwise SE,NE,NW,SW 00013 % - A local edge `j \in \{1,\dots,4\}` is connecting points `j` and `(j+1) 00014 % \mod 4` 00015 00016 methods 00017 00018 function grid=rectgrid(varargin) 00019 %function rectgrid(varargin) 00020 % constructor of a cartesian rectangular grid in 2 dimensions with 00021 % axis parallel elements. 00022 % 00023 % The constructor has sthe following 00024 % Synopsis: 00025 % 00026 % - rectgrid() : construction of a default rectgrid (2d unit square, 00027 % 2x2 elements with -1 as outer neighbour indices) 00028 % - rectgrid(rgrid) : copy-constructor 00029 % - rectgrid(params) : generate rectgrid with certain options. In this 00030 % case either 00031 % -# the field grid_initfile is existent in params. Then the file is read 00032 % and a pointlist p and a triangle. Procedure is then executing the 00033 % following constructor 00034 % -# a structured equidistant triangle grid is generated 00035 % - 'params.xnumintervals' : number of elements along x directions 00036 % - 'params.ynumintervals' : number of elements along y directions 00037 % - 'params.xrange,yrange' : intervals covered along the axes 00038 % . 00039 % with the optional fields 00040 % - 'params.bnd_rect_corner1' : coordinates of lower corner of to 00041 % be marked boundaries 00042 % - 'params.bnd_rect_corner2' : coordinates of upper corner of to 00043 % be marked boundaries 00044 % - 'params.bnd_rect_index': integer index to be set on the edges 00045 % in the above defined rectangle. Should not be positive integer 00046 % in the range of the number of elements. use negative indices for 00047 % certain later discrimination. 00048 % . 00049 % For the last three optional boundary settings, also multiple 00050 % rectangles can be straightforwardly defined by accepting matrix 00051 % of columnwise corners1, corners2 and a vector of indices for the 00052 % different rectangles. 00053 % 00054 % perhaps later: constructor by duneDGF-file? 00055 % perhaps later: contructor-flag: full vs non-full 00056 % => only compute redundant information if required. 00057 % 00058 % Parameters: 00059 % 'varargin' : variable number of input arguments, see above for description 00060 % of possible configurations. 00061 % 00062 % Return values: 00063 % 'grid' : generated rectgrid 00064 % 00065 % generated fields of grid: 00066 % nelements: number of elements 00067 % nvertices: number of vertices 00068 % nneigh: 4 00069 % A : @copybrief gridbase.A 00070 % Ainv : vector of inverted element area 00071 % X : vector of vertex x-coordinates 00072 % Y : vector of vertex y-coordinates 00073 % VI : matrix of vertex indices: 'VI(i,j)' is the global index of j-th 00074 % vertex of element i 00075 % CX : vector of centroid x-values 00076 % CY : vector of centroid y-values 00077 % NBI : 'NBI(i,j) = ' element index of j-th neighbour of element i 00078 % boundary faces are set to -1 or negative values are requested by 00079 % 'params.boundary_type' 00080 % INB : 'INB(i,j) = ' local edge number in 'NBI(i,j)' leading from 00081 % element 'NBI(i,j)' to element 'i', i.e. satisfying 00082 % 'NBI(NBI(i,j), INB(i,j)) = i' 00083 % EL : 'EL(i,j) = ' length of edge from element 'i' to neighbour 'j' 00084 % DC : 'DC(i,j) = ' distance from centroid of element i to NB j 00085 % for boundary elements, this is the distance to the reflected 00086 % element (for use in boundary treatment) 00087 % NX : 'NX(i,j) = ' x-coordinate of unit outer normal of edge from el 00088 % 'i' to NB 'j' 00089 % NY : 'NY(i,j) = ' y-coordinate of unit outer normal of edge from el 00090 % 'i' to NB 'j' 00091 % ECX : 'ECX(i,j) = ' x-coordinate of midpoint of edge from el 'i' to NB 'j' 00092 % ECY : 'ECY(i,j) = ' y-coordinate of midpoint of edge from el 'i' to NB 'j' 00093 % SX : vector of x-coordinates of point `S_i` (for rect: identical to 00094 % centroids) 00095 % SY : vector of y-coordinate of point `S_j` (for rect: identical to 00096 % centroids) 00097 % ESX : 'ESX(i,j) = ' x-coordinate of point `S_{ij}` on edge el i to NB j 00098 % ESY : 'ESY(i,j) = ' y-coordinate of point `S_{ij}` on edge el i to NB j 00099 % DS : 'DS(i,j) = ' distance from `S_i` of element i to `S_j` of NB j 00100 % for boundary elements, this is the distance to the reflected 00101 % element (for use in boundary treatment) 00102 % hmin : minimal element-diameter 00103 % alpha: geometry bound (simultaneously satisfying `\alpha \cdot h_i^d 00104 % \leq A(T_i)`, `\alpha \cdot \mbox{diam}(T_i) \leq h_i^{d-1}` and 00105 % `\alpha \cdot h_i \leq `dist(midpoint `i` to any neigbour) ) 00106 % 00107 % \note for diffusion-discretization with FV-schemes, points `S_i` must exist, 00108 % such that `S_i S_j` is perpendicular to edge 'i j', the intersection points 00109 % are denoted `S_{ij}` 00110 % 00111 % Bernard Haasdonk 9.5.2007 00112 00113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00114 % copy constructor 00115 if (nargin==1) && ... 00116 isa(varargin{1},'rectgrid') 00117 grid = rectgrid; 00118 00119 fnames = fieldnames(varargin{1}); 00120 for i=1:length(fnames) 00121 grid.(fnames{i}) = varargin{1}.(fnames{i}); 00122 end 00123 else 00124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00125 % default constructor: unit square 00126 if (nargin==0) 00127 params.xnumintervals = 2; 00128 params.ynumintervals = 2; 00129 params.xrange = [0,1]; 00130 params.yrange = [0,1]; 00131 % mark element in rectangle from [-1,-1] to [+2,+2] with index -1 00132 params.bnd_rect_corner1 = [-1,-1]'; 00133 params.bnd_rect_corner2 = [2 2]'; 00134 params.bnd_rect_index = [-1]; 00135 params.verbose = 0; 00136 else 00137 params = varargin{1}; 00138 end; 00139 00140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00141 % construct from params 00142 00143 % if ~isfield(params,'verbose') 00144 % params.verbose = 0; 00145 % end; 00146 00147 nx = params.xnumintervals; 00148 ny = params.ynumintervals; 00149 00150 grid.nelements =nx*ny; 00151 grid.nvertices =(nx+1)*(ny+1); 00152 00153 % get areas of grid-cells 00154 dx = (params.xrange(2)-params.xrange(1))/nx; 00155 dy = (params.yrange(2)-params.yrange(1))/ny; 00156 grid.A = dx*dy*ones(nx*ny,1); 00157 grid.Ainv = grid.A.^(-1); 00158 00159 % set vertex coordinates 00160 vind = (1:(nx+1)*(ny+1))'; 00161 grid.X = mod(vind-1,nx+1) * dx + params.xrange(1); 00162 grid.Y = floor((vind-1)/(nx+1))*dy + params.yrange(1); 00163 00164 % set element vertex indices: numbering starting right lower corner 00165 % counterclockwise, i.e. edge j connects vertex j and j+1 00166 % nx+2--nx+3-- ... 00167 % | | 00168 % | 1 | 2 ... 00169 % | | 00170 % 1-----2---- ... 00171 % => grid.VI = [ 2 nx+3 nx+2 1]; 00172 00173 el_ind = 1:length(grid.A); 00174 col_ind = transpose(mod((el_ind-1),nx)+1); 00175 row_ind = transpose(floor((el_ind-1)/nx)+1); 00176 VI = zeros(length(grid.A),4); 00177 VI(:,1) = (row_ind-1)*(nx+1)+1 +col_ind; 00178 VI(:,2) = (row_ind )*(nx+1)+1 +col_ind; 00179 VI(:,3) = (row_ind )*(nx+1) +col_ind; 00180 VI(:,4) = (row_ind-1)*(nx+1) +col_ind; 00181 grid.VI = VI; 00182 00183 % midpoint coordinates of grid-cells 00184 CX = (0:(nx-1))*(params.xrange(2)-params.xrange(1))/ ... 00185 nx+dx/2+params.xrange(1); 00186 CX = CX(:); 00187 grid.CX = repmat(CX,ny,1); 00188 CY = (0:(ny-1))*(params.yrange(2)-params.yrange(1))/ ... 00189 ny+dy/2+ params.yrange(1); 00190 CY = repmat(CY,nx,1); 00191 grid.CY = CY(:); 00192 %disp('stopping after COG computation'); 00193 %keyboard; 00194 00195 % check consistency: grid-midpoints and vertices 00196 xdiff1 = max(abs(grid.CX + dx/2 -grid.X(grid.VI(:,1)))); 00197 xdiff2 = max(abs(grid.CX + dx/2 -grid.X(grid.VI(:,2)))); 00198 xdiff3 = max(abs(grid.CX - dx/2 -grid.X(grid.VI(:,3)))); 00199 xdiff4 = max(abs(grid.CX - dx/2 -grid.X(grid.VI(:,4)))); 00200 ydiff1 = max(abs(grid.CY - dy/2 -grid.Y(grid.VI(:,1)))); 00201 ydiff2 = max(abs(grid.CY + dy/2 -grid.Y(grid.VI(:,2)))); 00202 ydiff3 = max(abs(grid.CY + dy/2 -grid.Y(grid.VI(:,3)))); 00203 ydiff4 = max(abs(grid.CY - dy/2 -grid.Y(grid.VI(:,4)))); 00204 00205 if (isfield(params, 'verbose') || isprop(params, 'verbose')) && params.verbose>=10 00206 disp([xdiff1,xdiff2,xdiff3,xdiff4, ... 00207 ydiff1,ydiff2,ydiff3,ydiff4]); 00208 00209 if max([xdiff1,xdiff2,xdiff3,xdiff4, ... 00210 ydiff1,ydiff2,ydiff3,ydiff4] > eps) 00211 error('vertex coordinate and element midpoint consistency!!'); 00212 end; 00213 end; 00214 00215 % matrix with edge-lengths 00216 grid.EL = repmat([dy, dx, dy, dx ],size(grid.CX,1),1); 00217 00218 % matrix with midpoint-distances 00219 grid.DC = repmat([dx, dy, dx, dy],size(grid.CX,1),1); 00220 00221 % matrix with (unit) normal components 00222 grid.NX = repmat([1,0,-1,0],size(grid.CX,1),1); 00223 grid.NY = repmat([0,1,0,-1],size(grid.CX,1),1); 00224 00225 % matrix with edge-midpoint-coordinates 00226 % this computation yields epsilon-differing edge-midpoints on 00227 % neighbouring elements. This is adjusted at end of this routine 00228 grid.ECX = [grid.CX + dx/2,grid.CX,grid.CX-dx/2,grid.CX]; 00229 grid.ECY = [grid.CY, grid.CY + dy/2,grid.CY,grid.CY-dy/2]; 00230 00231 %%% determine indices of neighbouring elements, 00232 NBI = repmat((1:nx*ny)',1,4); 00233 % first column: +x direction: cyclical shift +1 of indices 00234 NBI(:,1) = NBI(:,1)+1; 00235 % second column: +y direction 00236 NBI(:,2) = NBI(:,2)+nx; 00237 % third column: -x direction 00238 NBI(:,3) = NBI(:,3)-1; 00239 % fourth column: -y direction 00240 NBI(:,4) = NBI(:,4)-nx; 00241 00242 % correct boundary elements neighbour-indices: 00243 bnd_i1 = (1:ny)*nx; % indices of right-column elements 00244 bnd_i2 = (1:nx)+ nx*(ny-1); % indices of upper el 00245 bnd_i3 = (1:ny)*nx-nx+1; % indices of left-column 00246 bnd_i4 = 1:nx; % indices of lower row elements 00247 SX = [grid.ECX(bnd_i1,1); grid.ECX(bnd_i2,2); grid.ECX(bnd_i3,3); grid.ECX(bnd_i4, 4)]; 00248 SY = [grid.ECY(bnd_i1,1); grid.ECY(bnd_i2,2); grid.ECY(bnd_i3,3); grid.ECY(bnd_i4, 4)]; 00249 00250 % formerly default: Dirichlet : 00251 % bnd_ind = -1 * ones(1,length(SX)); 00252 % now: set default to "symmetric", i.e. rectangle is a torus 00253 00254 bnd_ind = [NBI(bnd_i1,1)'-nx, NBI(bnd_i2,2)'-nx*ny, ... 00255 NBI(bnd_i3,3)'+nx, NBI(bnd_i4,4)'+nx*ny]; 00256 00257 % disp('halt 1'); 00258 % keyboard; 00259 00260 if ~isfield(params, 'bnd_rect_index') && ~isprop(params, 'bnd_rect_index') 00261 if isobject(params) 00262 addprop(params, 'bnd_rect_index'); 00263 end 00264 params.bnd_rect_index = []; 00265 end 00266 00267 if ~isempty(params.bnd_rect_index) 00268 % keyboard; 00269 if (max(params.bnd_rect_index)>0) 00270 error('boundary indices must be negative!'); 00271 end; 00272 if size(params.bnd_rect_corner1,1) == 1 00273 params.bnd_rect_corner1 = params.bnd_rect_corner1'; 00274 end; 00275 if size(params.bnd_rect_corner2,1) == 1 00276 params.bnd_rect_corner2 = params.bnd_rect_corner2'; 00277 end; 00278 for i = 1:length(params.bnd_rect_index) 00279 indx = (SX > params.bnd_rect_corner1(1,i)) & ... 00280 (SX < params.bnd_rect_corner2(1,i)) & ... 00281 (SY > params.bnd_rect_corner1(2,i)) & ... 00282 (SY < params.bnd_rect_corner2(2,i)); 00283 bnd_ind(indx) = params.bnd_rect_index(i); 00284 end; 00285 end; 00286 % disp('halt 2'); 00287 % keyboard; 00288 00289 iend1 = length(bnd_i1); 00290 iend2 = iend1 + length(bnd_i2); 00291 iend3 = iend2 + length(bnd_i3); 00292 iend4 = iend3 + length(bnd_i4); 00293 NBI(bnd_i1,1) = bnd_ind(1:iend1)'; % set right border-neigbours to boundary 00294 NBI(bnd_i2,2) = bnd_ind((iend1+1):iend2)'; % set neighbours to boundary 00295 NBI(bnd_i3,3) = bnd_ind((iend2+1):iend3)'; % set neigbours to boundary 00296 NBI(bnd_i4,4) = bnd_ind((iend3+1):iend4)'; % set neighbours to boundary 00297 00298 grid.NBI = NBI; 00299 00300 % INB: INB(i,j) = local edge number in NBI(i,j) leading from element 00301 % NBI(i,j) to element i, i.e. satisfying 00302 % NBI(NBI(i,j), INB(i,j)) = i 00303 INB = repmat([3 4 1 2],size(grid.NBI,1),1); 00304 grid.INB = INB; 00305 00306 % check grid consistency: 00307 nonzero = find(NBI>0); % vector with vector-indices 00308 [i,j] = ind2sub(size(NBI), nonzero); % vectors with matrix indices 00309 NBIind = NBI(nonzero); % vector with global neighbour indices 00310 INBind = INB(nonzero); 00311 i2 = sub2ind(size(NBI),NBIind, INBind); 00312 i3 = NBI(i2); 00313 if ~isequal(i3,i) 00314 % plot_element_data(grid,grid.NBI,params); 00315 disp('neighbour indices are not consistent!!'); 00316 keyboard; 00317 end; 00318 00319 grid.hmin = sqrt(dx^2+dy^2); % minimal diameter of elements 00320 % CAUTION: this geometry bound is 00321 % adapted to triangles, should be extended 00322 % properly to rectangles 00323 alpha1 = dx * dy/(dx^2+dy^2); % geometry bound 00324 alpha2 = sqrt(dx^2+dy^2)/(2*dx + 2*dy); 00325 alpha3 = dx / sqrt(dx^2+dy^2); 00326 grid.alpha = min([alpha1,alpha2,alpha3]); 00327 00328 % make entries of ECX, ECY exactly identical for neighbouring elements! 00329 % currently by construction a small eps deviation is possible. 00330 00331 %averaging over all pairs is required 00332 nonzero = find(grid.NBI>0); % vector with vector-indices 00333 [i,j] = ind2sub(size(grid.NBI), nonzero); % vectors with matrix indices 00334 NBIind = NBI(nonzero); % vector with global neighbour indices 00335 INBind = INB(nonzero); % vector with local edge indices 00336 i2 = sub2ind(size(NBI),NBIind, INBind); 00337 % determine maximum difference in edge-midpoints, but exclude 00338 % symmetry boundaries by relative error < 0.0001 00339 diffx = abs(grid.ECX(nonzero)-grid.ECX(i2)); 00340 diffy = abs(grid.ECY(nonzero)-grid.ECY(i2)); 00341 fi = find ( (diffx/(max(grid.X)-min(grid.X)) < 0.0001) & ... 00342 (diffy/(max(grid.Y)-min(grid.Y)) < 0.0001) ); 00343 00344 %disp(max(diffx)); 00345 %disp(max(diffy)); 00346 % => 0 ! :-) 00347 % keyboard; 00348 00349 grid.ECX(nonzero(fi)) = 0.5*(grid.ECX(nonzero(fi))+ grid.ECX(i2(fi))); 00350 grid.ECY(nonzero(fi)) = 0.5*(grid.ECY(nonzero(fi))+ grid.ECY(i2(fi))); 00351 00352 % for diffusion discretization: Assumption of points with 00353 % orthogonal connections to edges. Distances and intersections 00354 % determined here. In cartesian case identical to centroids 00355 grid.SX = grid.CX; 00356 grid.SY = grid.CY; 00357 grid.ESX = grid.ECX; 00358 grid.ESY = grid.ECY; 00359 grid.DS = grid.DC; 00360 grid.nneigh= 4; 00361 00362 end 00363 00364 end 00365 00366 % demo 00367 demo(dummy); 00368 00369 p=plot(grid, params); 00370 00371 res = isequal(grid,grid2); 00372 00373 grid=set_nbi(grid, nbind, values); 00374 00375 function gcopy = copy(grid) 00376 % @copybrief gridbase copy 00377 % 00378 % @copydoc gridbase copy 00379 00380 gcopy = rectgrid(grid); 00381 end 00382 00383 glob = local2global(grid, einds, loc, params); 00384 00385 end 00386 end 00387