rbmatlab 0.10.01
|
00001 classdef triagrid < gridbase 00002 % A triangular conforming grid in two dimensions. 00003 % 00004 % General geometrical information is stored including neighbour 00005 % information. Therefore also boundary neighbour relations can be 00006 % specified. Boundary edges can be marked by "painting rectangles": the 00007 % edges with midpoints within such a rectangle are marked accordingly. 00008 % By this boundary edges can be marked for later special use. Much 00009 % (partially redundant) information is stored in the grid, which might be 00010 % useful in simulations. 00011 00012 properties 00013 % number of interior edges 00014 nedges_interior; 00015 00016 % number of boundary edges 00017 nedges_boundary; 00018 end; 00019 00020 methods 00021 00022 function grid= triagrid(varargin) 00023 %function triagrid(varargin) 00024 % constructor of a triangular conform grid in 2 dimensions with following 00025 % Synopsis: 00026 % 00027 % - triagrid() : construction of a default triagrid (2d unit square, 00028 % loaded from file, -1 as outer neighbour indices) 00029 % - @link triagrid() triagrid(tgrid) @endlink : copy-constructor 00030 % - @link triagrid() triagrid(params) @endlink : in this 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 % - @link triagrid() triagrid(p,t,params) @endlink : generate triagrid from 00054 % triangle-data with certain options. 00055 % - p is assumed to be a 2 x npoints matrix with coordinates 00056 % - t is assumed to be a XX x ntriangles matrix, but only first three 00057 % rows are used == vertex indices, in clockwise order as default, all 00058 % nondefined edges are set to -1, then the following "rectangles" are 00059 % set as specified in params 00060 % 00061 % Using this class, grids from PDETOOLS can be used: 00062 % 00063 % pdetools 00064 % %%% => generate your grid and export 'p' and 't' to MATLAB workspace 00065 % @code 00066 % save('mygrid','p','t') 00067 % grid = triagrid(struct('grid_initfile','mygrid')); 00068 % @endcode 00069 % 00070 % perhaps later: constructor by duneDGF-file? 00071 % perhaps later: contructor-flag: full vs non-full 00072 % => only compute redundant information if required. 00073 % 00074 % Parameters: 00075 % 'varargin' : variable number of input arguments, see above for description 00076 % of possible configurations. 00077 % 00078 % Return values: 00079 % 'grid' : generated triagrid 00080 % 00081 % generated fields of grid: 00082 % nelements: number of elements 00083 % nvertices: number of vertices 00084 % nneigh: 3 00085 % A : vector of element area 00086 % Ainv : vector of inverted element area 00087 % X : vector of vertex x-coordinates 00088 % Y : vector of vertex y-coordinates 00089 % VI : matrix of vertex indices: 'VI(i,j)' is the global index of j-th 00090 % vertex of element i 00091 % CX : vector of centroid x-values 00092 % CY : vector of centroid y-values 00093 % NBI : 'NBI(i,j) = ' element index of j-th neighbour of element i 00094 % boundary faces are set to -1 or negative values are requested by 00095 % 'params.boundary_type' 00096 % INB : 'INB(i,j) = ' local edge number in 'NBI(i,j)' leading from 00097 % element 'NBI(i,j)' to element 'i', i.e. satisfying 00098 % 'NBI(NBI(i,j), INB(i,j)) = i' 00099 % EL : 'EL(i,j) = ' length of edge from element 'i' to neighbour 'j' 00100 % DC : 'DC(i,j) = ' distance from centroid of element i to NB j 00101 % for boundary elements, this is the distance to the reflected 00102 % element (for use in boundary treatment) 00103 % NX : 'NX(i,j) = ' x-coordinate of unit outer normal of edge from el 00104 % 'i' to NB 'j' 00105 % NY : 'NY(i,j) = ' y-coordinate of unit outer normal of edge from el 00106 % 'i' to NB 'j' 00107 % ECX : 'ECX(i,j) = ' x-coordinate of midpoint of edge from el 'i' to NB 'j' 00108 % ECY : 'ECY(i,j) = ' y-coordinate of midpoint of edge from el 'i' to NB 'j' 00109 % SX : vector of x-coordinates of point `S_i` (for rect: identical to 00110 % centroids) 00111 % SY : vector of y-coordinate of point `S_j` (for rect: identical to 00112 % centroids) 00113 % ESX : 'ESX(i,j) = ' x-coordinate of point `S_{ij}` on edge el i to NB j 00114 % ESY : 'ESY(i,j) = ' y-coordinate of point `S_{ij}` on edge el i to NB j 00115 % DS : 'DS(i,j) = ' distance from `S_i` of element i to `S_j` of NB j 00116 % for boundary elements, this is the distance to the reflected 00117 % element (for use in boundary treatment) 00118 % hmin : minimal element-diameter 00119 % alpha: geometry bound (simultaneously satisfying `\alpha \cdot h_i^d 00120 % \leq A(T_i)`, `\alpha \cdot \mbox{diam}(T_i) \leq h_i^{d-1}` and 00121 % `\alpha \cdot h_i \leq `dist(midpoint `i` to any neigbour) ) 00122 % JIT : Jacobian inverse transposed 'JIT(i,:,:)' is a 2x2-matrix of the Jac. 00123 % Inv. Tr. on element 'i' 00124 % 00125 % \note for diffusion-discretization with FV-schemes, points `S_i` must exist, 00126 % such that `S_i S_j` is perpendicular to edge 'i j', the intersection points 00127 % are denoted `S_{ij}` 00128 % 00129 00130 % Bernard Haasdonk 9.5.2007 00131 00132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00133 % copy constructor 00134 if (nargin==1) & isa(varargin{1},'triagrid') 00135 grid = triagrid; % create default triagrid 00136 00137 fnames = fieldnames(varargin{1}); 00138 for i=1:length(fnames) 00139 grid.(fnames{i}) = varargin{1}.(fnames{i}); 00140 end 00141 00142 else 00143 00144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00145 % default constructor: unit square 00146 if (nargin==0) 00147 % p = [0.0 0.5 1.0 0.0 0.5 1.0 0.0 0.5 1.0; ... 00148 % 0.0 0.0 0.0 0.5 0.5 0.5 1.0 1.0 1.0 ]; 00149 % t = [1 2 2 3 4 5 5 6; ... 00150 % 2 5 3 6 5 8 6 9; ... 00151 % 4 4 5 5 7 7 8 8] ; 00152 params = []; 00153 load 2dsquaretriang; 00154 00155 % mark boundary in rectangle from [-1,-1] to [+2,+2] with index -1 00156 params.bnd_rect_corner1 = [-1,-1]'; 00157 params.bnd_rect_corner2 = [2 2]'; 00158 params.bnd_rect_index = [-1]; 00159 elseif nargin==1 00160 params = varargin{1}; 00161 if isfield(params,'grid_initfile') || isprop(params, 'grid_initfile') 00162 tmp = load(params.grid_initfile); 00163 t = tmp.t(1:3,:); 00164 p = tmp.p; 00165 else 00166 nx = params.xnumintervals; 00167 ny = params.ynumintervals; 00168 nvertices =(nx+1)*(ny+1); 00169 00170 dx = (params.xrange(2)-params.xrange(1))/nx; 00171 dy = (params.yrange(2)-params.yrange(1))/ny; 00172 00173 % set vertex coordinates 00174 vind = (1:(nx+1)*(ny+1)); 00175 X = mod(vind-1,nx+1) * dx + params.xrange(1); 00176 Y = floor((vind-1)/(nx+1))*dy + params.yrange(1); 00177 p = [X(:)'; Y(:)']; 00178 00179 % identify triangles: 00180 % ---- 00181 % | /| 00182 % |/ | 00183 % ---- 00184 00185 all_ind = 1:(nx+1)*(ny+1); 00186 % index vector of lower left corners, i.e. not last col/row 00187 lc_ind = find((mod(all_ind,nx+1)~=0) & (all_ind < (nx+1)*ny)); 00188 t1 = [lc_ind;lc_ind+1;lc_ind+2+nx]; % lower triangles 00189 t2 = [lc_ind;lc_ind+nx+2;lc_ind+nx+1]; % upper triangles 00190 t = [t1,t2]; 00191 end; 00192 else % read p-e-t information from varargin 00193 p =varargin{1}; 00194 t =varargin{2}; 00195 if size(t,1)>3 00196 t = t(1:3,:); 00197 end; 00198 params = varargin{3}; 00199 end; 00200 00201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00202 % construct from p,t and params 00203 00204 if ~isfield(params,'verbose') && ~isprop(params, 'verbose') 00205 params.verbose = 0; 00206 end; 00207 00208 % nx = params.xnumintervals; 00209 % ny = params.ynumintervals; 00210 00211 grid.nelements = size(t,2); 00212 grid.nvertices = size(p,2); 00213 grid.nneigh= 3; 00214 00215 % set vertex coordinates 00216 grid.X = p(1,:)'; 00217 grid.Y = p(2,:)'; 00218 00219 % set element vertex indices: numbering counterclockwise 00220 % counterclockwise, edge j connects vertex j and j+1 00221 00222 grid.VI = t'; 00223 00224 % get areas of grid-cells after VI and X,Y are available 00225 % 00226 % A(a b c) = 0.5 |Det ((b-a) (c-a)) | 00227 grid.A = abs(area_triangle(... 00228 [grid.X(grid.VI(:,1)), ... 00229 grid.Y(grid.VI(:,1))], ... 00230 [grid.X(grid.VI(:,2)), ... 00231 grid.Y(grid.VI(:,2))], ... 00232 [grid.X(grid.VI(:,3)), ... 00233 grid.Y(grid.VI(:,3))])); 00234 grid.A = grid.A(:); 00235 % a11 = grid.X(grid.VI(:,2))-grid.X(grid.VI(:,1)); 00236 % a21 = grid.Y(grid.VI(:,2))-grid.Y(grid.VI(:,1)); 00237 % a12 = grid.X(grid.VI(:,3))-grid.X(grid.VI(:,1)); 00238 % a22 = grid.Y(grid.VI(:,3))-grid.Y(grid.VI(:,1)); 00239 % grid.A = 0.5 * (a11.*a22 - a21.*a12); 00240 grid.Ainv = grid.A.^(-1); 00241 00242 % midpoint coordinates of grid-cells 00243 % equals cog of corners 00244 00245 % coordinates of vertices: XX(elnum, vnum) 00246 XX = reshape(grid.X(grid.VI(:)),size(grid.VI)); 00247 YY = reshape(grid.Y(grid.VI(:)),size(grid.VI)); 00248 grid.CX = mean(XX,2); 00249 grid.CY = mean(YY,2); 00250 00251 % edge-vectors: [DX(el,edge) DX (el,edge)] 00252 DX = [XX(:,2:3), XX(:,1)] - XX; 00253 DY = [YY(:,2:3), YY(:,1)] - YY; 00254 00255 % matrix with edge-lengths 00256 grid.EL = sqrt(DX.^2 + DY.^2); 00257 00258 % matrix with (unit) normal components 00259 grid.NX = grid.EL.^(-1) .* DY; 00260 grid.NY = - grid.EL.^(-1) .* DX; 00261 00262 % matrix with edge-midpoint-coordinates 00263 % this computation yields epsilon-differing edge-midpoints on 00264 % neighbouring elements, perhaps solve later. 00265 grid.ECX = XX + DX * 0.5; 00266 grid.ECY = YY + DY * 0.5; 00267 00268 %%% determine indices of neighbouring elements, default: -1 00269 NBI = -1 * ones(grid.nelements, grid.nneigh); 00270 INB = zeros(grid.nelements, grid.nneigh); 00271 % and now it gets complicated... 00272 00273 % setup edge list e(1,i), e(2,i) are the point indices of the i-th edge 00274 % eid(i) is the element number, which has the edge 00275 % led(i) : local edge number, which is the edge 00276 % e(:,i) in eid(i) 00277 ee = zeros(2,grid.nelements*3); 00278 % li = [1 2 2 3 3 1 4 5 5 6 6 4 ... ] 00279 li = 1:grid.nelements*3; 00280 li = [li;li]; 00281 li = reshape(li,6,grid.nelements); 00282 li = [li(2:end,:); li(1,:)]; 00283 li = reshape(li,2,grid.nelements*3); 00284 ee = t(li); 00285 ee = sort(ee); % now smallest vindex above 00286 elid = repmat(1:grid.nelements,3,1); 00287 elid = elid(:)'; 00288 led = repmat((1:3)',1,grid.nelements); 00289 led = led(:)'; 00290 00291 % generate sort key from both indices 00292 key = ee(1,:) + grid.nvertices * ee(2,:); 00293 [keysort, ind] = sort(key); 00294 ee_sort = ee(:,ind); 00295 elid_sort = elid(ind); 00296 led_sort = led(ind); 00297 00298 % find indices of duplicates by simple forward difference 00299 % => these are inner edges! 00300 00301 diff = keysort(1:end-1) - [keysort(2:end)]; 00302 inner_edges = find(diff==0); 00303 00304 % prepare entries in NBI: for all i in inner_edges 00305 % NBI(elid_sort(i),led_sort(i)) = elid_sort(i+1); 00306 % INB(elid_sort(i),led_sort(i)) = led_sort(i+1); 00307 % und umgekehrt! 00308 00309 li = sub2ind(size(NBI),... 00310 elid_sort(inner_edges),... 00311 led_sort(inner_edges)); 00312 NBI(li) = elid_sort(inner_edges+1); 00313 INB(li) = led_sort(inner_edges+1); 00314 li = sub2ind(size(NBI),... 00315 elid_sort(inner_edges+1),... 00316 led_sort(inner_edges+1)); 00317 NBI(li) = elid_sort(inner_edges); 00318 INB(li) = led_sort(inner_edges); 00319 00320 % % find all element-pairs, which have a common edge 00321 % % i.e. neighs(i,1) and neighs(i,2) are two elements, which 00322 % % have the same edge i, where this edge is the 00323 % % eind(i,1)-th edge (1..3) in the first element 00324 % % eind(i,2)-th edge (1..3) in the first element 00325 % 00326 % nedges = max(t(:)); 00327 % ehist = hist(t(:),1:nedges); 00328 % if max(ehist)>3 00329 % error('edge occuring in more than 2 triangles!!'); 00330 % end; 00331 % inner_edges = find(ehist==2); 00332 % neighs = zeros(length(inner_edges),2); 00333 % eind = zeros(length(inner_edges),2); 00334 % 00335 % % somehow map edge-numbers => triangle numbers 00336 % % need two of them, as occasionally global and local edge numbers 00337 % % can coincide: 00338 % % edgemap1(i,locedgenum) = elementno if edge i is local edge in elementno 00339 % % edgemap2(i,locedgenum) = elementno if edge i is local edge in elementno 00340 % 00341 % edgemap1 = nan * ones(nedges,grid.nneigh);% 00342 % 00343 % [locedgenum,triangnum] = ind2sub(size(t),1:length(t(:))); 00344 % li = sub2ind(size(edgemap1),t(:),locedgenum(:)); 00345 % edgemap1(li) = triangnum; % here due to duplicates, only the last 00346 % % entry is taken 00347 % 00348 % % remove these entries from t and repeat for 2nd edgemap 00349 % t2 = t; 00350 % [edgenum,locedgenum] = find(~isnan(edgemap1)); 00351 % li = sub2ind(size(edgemap1),edgenum(:),locedgenum(:)); 00352 % 00353 % li2 = sub2ind(size(t2),locedgenum(:),edgemap1(li)); 00354 % t2(li2) = 0; 00355 % 00356 % 00357 % edgemap2 = nan * ones(nedges,grid.nneigh); 00358 % nonzeros = find(t2~=0); 00359 % 00360 % [locedgenum,triangnum] = ind2sub(size(t2),1:length(nonzeros)); 00361 % li = sub2ind(size(edgemap2),t2(nonzeros),locedgenum(:)); 00362 % edgemap2(li) = triangnum; 00363 % % now together edgemap1 and edgemap 2 represent the edge information. 00364 % 00365 % % extract inner edges 00366 % edgemap = [edgemap1(inner_edges,:), edgemap2(inner_edges,:)]; 00367 % % check, that exactly two entries per row are non-nan 00368 % entries = sum(~isnan(edgemap),2); 00369 % if (min(entries)~=2) | max(entries)~=2 00370 % disp('error in neighbour detection, please check'); 00371 % keyboard; 00372 % end; 00373 % 00374 % [mi, imi] = min(edgemap,[],2); 00375 % [ma, ima] = max(edgemap,[],2); 00376 % neighs = [mi, ma]; 00377 % eind = [imi, ima]; 00378 % 00379 % % then fill NBI and INB in a vectorized way, i.e. 00380 % % for all edges: 00381 % % NBI(neighs(i,1), eind(i,1)) = neighs(i,2); 00382 % % NBI(neighs(i,2), eind(i,2)) = neighs(i,1); 00383 % % INB(neighs(i,1), eind(i,1)) = eind(i,2); 00384 % % INB(neighs(i,2), eind(i,2)) = eind(i,1); 00385 % 00386 % l1 = sub2ind( size(NBI), neighs(:,1) , eind(:,1)); 00387 % l2 = sub2ind( size(NBI), neighs(:,2) , eind(:,2)); 00388 % NBI(l1) = neighs(:,2); 00389 % NBI(l2) = neighs(:,1); 00390 % INB(l1) = eind(:,2); 00391 % INB(l2) = eind(:,1); 00392 00393 % search non-inner boundaries and their midpoints 00394 00395 li = find(NBI==-1); 00396 SX = grid.ECX(li(:)); 00397 SY = grid.ECY(li(:)); 00398 00399 % default-boundary = -1 00400 bnd_ind = -1 * ones(length(li),1); 00401 00402 if isfield(params,'bnd_rect_index') || isprop(params, 'bnd_rect_index') 00403 if isfield(params,'boundary_type') || isprop(params, 'boundary_type') 00404 error(['Do not specify both bnd_rect_index and boundary_type', ... 00405 '�in triagrid construction!']); 00406 end; 00407 if (max(params.bnd_rect_index)>0) 00408 error('boundary indices must be negative!'); 00409 end; 00410 if size(params.bnd_rect_corner1,1) == 1 00411 params.bnd_rect_corner1 = params.bnd_rect_corner1'; 00412 end; 00413 if size(params.bnd_rect_corner2,1) == 1 00414 params.bnd_rect_corner2 = params.bnd_rect_corner2'; 00415 end; 00416 for i = 1:length(params.bnd_rect_index) 00417 indx = (SX > params.bnd_rect_corner1(1,i)) & ... 00418 (SX < params.bnd_rect_corner2(1,i)) & ... 00419 (SY > params.bnd_rect_corner1(2,i)) & ... 00420 (SY < params.bnd_rect_corner2(2,i)); 00421 bnd_ind(indx) = params.bnd_rect_index(i); 00422 end; 00423 else 00424 if isfield(params,'boundary_type') || isprop(params, 'boundary_type') 00425 bnd_ind = params.boundary_type([SX(:),SY(:)],params); 00426 end; 00427 end; 00428 00429 NBI(li) = bnd_ind'; % set neighbours to boundary 00430 00431 grid.NBI = NBI; 00432 grid.INB = INB; 00433 00434 % check grid consistency: 00435 nonzero = find(NBI>0); % vector with vector-indices 00436 [i,j] = ind2sub(size(NBI), nonzero); % vectors with matrix indices 00437 NBIind = NBI(nonzero); % vector with global neighbour indices 00438 INBind = INB(nonzero); 00439 i2 = sub2ind(size(NBI),NBIind, INBind); 00440 i3 = NBI(i2); 00441 if ~isequal(i3,i) 00442 % plot_element_data(grid,grid.NBI,params); 00443 disp('neighbour indices are not consistent!!'); 00444 keyboard; 00445 end; 00446 00447 % matrix with centroid-distances 00448 grid.DC = nan * ones(size(grid.CX,1),grid.nneigh); 00449 nonzero = find(grid.NBI>0); 00450 [elind, nbind] = ind2sub(size(grid.NBI),nonzero); 00451 00452 CXX = repmat(grid.CX(:),1,grid.nneigh); 00453 CYY = repmat(grid.CY(:),1,grid.nneigh); 00454 00455 CXN = CXX; 00456 CXN(nonzero) = grid.CX(grid.NBI(nonzero)); 00457 00458 CYN = CYY; 00459 CYN(nonzero) = grid.CY(grid.NBI(nonzero)); 00460 00461 DC = sqrt((CXX-CXN).^2 + (CYY - CYN).^2); 00462 00463 grid.DC(nonzero) = DC(nonzero); 00464 00465 % computation of boundary distances: twice the distance to the border 00466 00467 nondef = find(isnan(grid.DC)); 00468 nondef = nondef(:)'; 00469 [elind, nind] = ind2sub(size(grid.DC),nondef); 00470 nind_plus_one = nind + 1; 00471 i = find(nind_plus_one > grid.nneigh); 00472 nind_plus_one(i) = 1; 00473 nondef_plus_one = sub2ind(size(grid.DC),elind,nind_plus_one); 00474 nondef_plus_one = nondef_plus_one(:)'; 00475 00476 d = zeros(length(nondef),1); 00477 00478 q = [grid.CX(elind)'; grid.CY(elind)']; 00479 p1 = [grid.X(grid.VI(nondef)), ... 00480 grid.Y(grid.VI(nondef))]; 00481 p2 = [grid.X(grid.VI(nondef_plus_one)), ... 00482 grid.Y(grid.VI(nondef_plus_one))]; 00483 00484 grid.DC(nondef) = 2 * dist_point_line(q,p1,p2); 00485 00486 % make entries of ECX, ECY exactly identical for neighbouring elements! 00487 % currently by construction a small eps deviation is possible. 00488 %averaging over all pairs is required 00489 nonzero = find(grid.NBI>0); % vector with vector-indices 00490 [i,j] = ind2sub(size(grid.NBI), nonzero); % vectors with matrix indices 00491 NBIind = NBI(nonzero); % vector with global neighbour indices 00492 INBind = INB(nonzero); % vector with local edge indices 00493 i2 = sub2ind(size(NBI),NBIind, INBind); 00494 % determine maximum difference in edge-midpoints, but exclude 00495 % symmetry boundaries by relative error < 0.0001 00496 diffx = abs(grid.ECX(nonzero)-grid.ECX(i2)); 00497 diffy = abs(grid.ECY(nonzero)-grid.ECY(i2)); 00498 fi = find ( (diffx/(max(grid.X)-min(grid.X)) < 0.0001) & ... 00499 (diffy/(max(grid.Y)-min(grid.Y)) < 0.0001) ); 00500 00501 %disp(max(diffx)); 00502 %disp(max(diffy)); 00503 % => 0 ! :-) 00504 % keyboard; 00505 00506 grid.ECX(nonzero(fi)) = 0.5*(grid.ECX(nonzero(fi))+ grid.ECX(i2(fi))); 00507 grid.ECY(nonzero(fi)) = 0.5*(grid.ECY(nonzero(fi))+ grid.ECY(i2(fi))); 00508 00509 % for diffusion discretization: Assumption of points with 00510 % orthogonal connections to edges. Distances and intersections 00511 % determined here. For triangles, this can simply be the 00512 % circumcenters and the corresponding intersections 00513 00514 q = [grid.X(grid.VI(:,1)), ... 00515 grid.Y(grid.VI(:,1))]; 00516 p1 = [grid.X(grid.VI(:,2)), ... 00517 grid.Y(grid.VI(:,2))]; 00518 p2 = [grid.X(grid.VI(:,3)), ... 00519 grid.Y(grid.VI(:,3))]; 00520 S = circumcenter_triangle(q,p1,p2); 00521 grid.SX = S(:,1); 00522 grid.SY = S(:,2); 00523 00524 % compute DS for inner edges (identical as DC computation!) 00525 grid.DS = nan * ones(size(grid.CX,1),grid.nneigh); 00526 nonzero = find(grid.NBI>0); 00527 [elind, nbind] = ind2sub(size(grid.NBI),nonzero); 00528 00529 SXX = repmat(grid.SX(:),1,grid.nneigh); 00530 SYY = repmat(grid.SY(:),1,grid.nneigh); 00531 00532 SXN = SXX; 00533 SXN(nonzero) = grid.SX(grid.NBI(nonzero)); 00534 00535 SYN = SYY; 00536 SYN(nonzero) = grid.SY(grid.NBI(nonzero)); 00537 00538 DS = sqrt((SXX-SXN).^2 + (SYY - SYN).^2); 00539 00540 grid.DS(nonzero) = DS(nonzero); 00541 00542 % computation of boundary distances: twice the distance to the border 00543 00544 nondef = find(isnan(grid.DS)); 00545 nondef = nondef(:)'; 00546 [elind, nind] = ind2sub(size(grid.DS),nondef); 00547 nind_plus_one = nind + 1; 00548 i = find(nind_plus_one > grid.nneigh); 00549 nind_plus_one(i) = 1; 00550 nondef_plus_one = sub2ind(size(grid.DS),elind,nind_plus_one); 00551 nondef_plus_one = nondef_plus_one(:)'; 00552 00553 d = zeros(length(nondef),1); 00554 00555 q = [grid.SX(elind)'; grid.SY(elind)']; 00556 p1 = [grid.X(grid.VI(nondef)), ... 00557 grid.Y(grid.VI(nondef))]; 00558 p2 = [grid.X(grid.VI(nondef_plus_one)), ... 00559 grid.Y(grid.VI(nondef_plus_one))]; 00560 00561 % keyboard; 00562 00563 grid.DS(nondef) = 2 * dist_point_line(q,p1,p2); 00564 00565 if ~isempty(find(isnan(grid.DS))) 00566 error('nans produced in grid generation!'); 00567 end; 00568 00569 % intersections of S_i are the centroids of edges 00570 grid.ESX = grid.ECX; 00571 grid.ESY = grid.ECY; 00572 00573 % compute geometry constants for CFL-condition 00574 h = max(grid.EL,[],2); % elementwise maximum edgelength 00575 grid.hmin = min(h); 00576 % alpha1 * h_j^2 <= |T_j| 00577 alpha1 = min(grid.A .* h.^(-2)); 00578 % alpha2 * |boundary T_j| <= h_j 00579 b = sum(grid.EL,2); 00580 alpha2 = min(h .* b.^(-1)); 00581 % alpha3 h_j <= d_jl, d_jl distance of circumcenters 00582 alpha3 = min(min(grid.DS,[],2) .* h.^(-1)); 00583 grid.alpha = min([alpha1,alpha2,alpha3]); 00584 00585 % if grid.alpha<=0 00586 % disp(['Caution: Grid-geometry constant alpha less/equal zero', ... 00587 % ' problematic ' ... 00588 % ' in automatic CFL-conditions!']); 00589 % end; 00590 00591 % DF = [(p2-p1) (p3-p1)] a 2x2 matrix 00592 DF = zeros(grid.nelements,2,2); % jacobian 00593 DF(:,1,1) = XX(:,2)-XX(:,1); 00594 DF(:,2,1) = YY(:,2)-YY(:,1); 00595 DF(:,1,2) = XX(:,3)-XX(:,1); 00596 DF(:,2,2) = YY(:,3)-YY(:,1); 00597 DetDF = DF(:,1,1).*DF(:,2,2)- DF(:,2,1).*DF(:,1,2); % determinant 00598 DetDFinv = DetDF.^(-1); 00599 JIT = zeros(grid.nelements,2,2); 00600 % inversetransposed of A = (a,b; c,d) is A^-1 = 1/det A (d,-c; -b,a); 00601 JIT(:,1,1)=DF(:,2,2).*DetDFinv; 00602 JIT(:,1,2)=-DF(:,2,1).*DetDFinv; 00603 JIT(:,2,1)=-DF(:,1,2).*DetDFinv; 00604 JIT(:,2,2)=DF(:,1,1).*DetDFinv; 00605 00606 % test: 00607 if (size(JIT,1)>=5) &(max(max(abs(... 00608 transpose(reshape(JIT(5,:,:),2,2))*... 00609 reshape(DF(5,:,:),2,2)-eye(2)... 00610 )))>1e-5) 00611 error('error in JIT computation!'); 00612 end; 00613 00614 % JIT: 00615 grid.JIT = JIT; % perhaps later also store area, etc. 00616 00617 grid.nedges_boundary = length(find(grid.NBI<0)); 00618 00619 grid.nedges_interior = 0.5*(3*grid.nelements - grid.nedges_boundary); 00620 if ~isequal(ceil(grid.nedges_interior), ... 00621 grid.nedges_interior); 00622 error('number of inner edges odd!!!'); 00623 end; 00624 00625 end 00626 end 00627 00628 demo(dummy); 00629 00630 display(grid); 00631 00632 gridp = gridpart(grid,eind); 00633 00634 lcoord = llocal2local(grid, faceinds, llcoord); 00635 00636 glob = local2global(grid, einds, loc, params); 00637 00638 p = plot(gird, params); 00639 00640 grid = set_nbi(grid, nbind, values); 00641 00642 function gcopy = copy(grid) 00643 % @copybrief gridbase copy 00644 % 00645 % Return values: 00646 % gcopy: object of type triagrid. This is a deep copy of the current instance. 00647 % 00648 00649 gcopy = triagrid(grid); 00650 end 00651 00652 end 00653 00654 methods(Static) 00655 00656 [C, G] = aff_trafo_glob2loc(x0, y0); 00657 00658 [C, G] = aff_trafo_loc2glob(x0, y0); 00659 00660 [C, G] = aff_trafo_orig2ref(x0, y0, varargin); 00661 00662 loc = global2local(grid, elementid, glob); 00663 00664 micro2macro = micro2macro_map(microgrid, macrogrid); 00665 end 00666 end 00667