rbmatlab 0.10.01
grid/@rectgrid/rectgrid.m
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 
All Classes Namespaces Files Functions Variables