170 lines
4.9 KiB
Mathematica
170 lines
4.9 KiB
Mathematica
|
function [nodes, tets, faces, P] = meshStructTess(nodes, dx, dy, dz, check_mesh, plot_mesh)
|
||
|
%% [nodes, tets, faces] = meshStructTess(nodes, dx, dy, dz, check_mesh, plot_mesh)
|
||
|
% Generate a tessalation from a list of structured nodes.
|
||
|
% input: nodes: n times 3 matrix with on the rows the coordinates of
|
||
|
% the n points in the mesh
|
||
|
% dx, dy, dz: the mesh-size in the directions x, y and z
|
||
|
% check_mesh: if true, then it solves a Poisson problem
|
||
|
% plot_mesh: if true, then it plots the mesh
|
||
|
% output: nodes: m times 3 matrix with on the rows the coordinates of
|
||
|
% the m <= n points in the triangulationedi
|
||
|
% tets: l times 4 matrix with on the rows the tetrahedra
|
||
|
% faces: k times 3 matrix with on the rows the triangles of the
|
||
|
% boundary of the mesh
|
||
|
% P: Transformation matrix from input nodes to output nodes.
|
||
|
% Useful also for transforming node-valued functions on
|
||
|
% the input nodes to node-valued functions on the output
|
||
|
% nodes
|
||
|
%
|
||
|
% The triangulation can be plotted using tetramesh(tets,nodes)
|
||
|
|
||
|
|
||
|
% compute the minimum and number of points in each direction
|
||
|
if size(nodes,1) < 4
|
||
|
error('Triangulation needs at least 4 points')
|
||
|
end
|
||
|
mn = min(nodes);
|
||
|
xmin = mn(1);
|
||
|
ymin = mn(2);
|
||
|
zmin = mn(3);
|
||
|
|
||
|
mn = max(nodes);
|
||
|
xmax = mn(1);
|
||
|
ymax = mn(2);
|
||
|
zmax = mn(3);
|
||
|
|
||
|
nx = round((xmax-xmin)/dx +1);
|
||
|
ny = round((ymax-ymin)/dy +1);
|
||
|
nz = round((zmax-zmin)/dz +1);
|
||
|
|
||
|
Nnodes = size(nodes,1);
|
||
|
|
||
|
|
||
|
% Define tensor which consist of nodes indices, used for the creation of
|
||
|
% the tetrahedra
|
||
|
|
||
|
nodes3d = zeros(nx,ny,nz); % preallocate
|
||
|
for i=1:Nnodes
|
||
|
nodes3d(round((nodes(i,1)-xmin)/dx)+1,round((nodes(i,2)-ymin)/dy)+1,round((nodes(i,3)-zmin)/dz)+1)=i;
|
||
|
end
|
||
|
|
||
|
|
||
|
disp('Creating Tetrahedra')
|
||
|
|
||
|
% create tetrahedral mesh in cube, which we will reuse.
|
||
|
ii = 1;
|
||
|
X = zeros(8,3);
|
||
|
for i=0:1
|
||
|
for j=0:1
|
||
|
for k=0:1
|
||
|
X(ii,:) = [i,j,k];
|
||
|
ii = ii+1;
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
cubetet = delaunay(X);
|
||
|
|
||
|
% Run through the mesh
|
||
|
el = 1;
|
||
|
Tetrahedra = zeros(6*(nnz(nodes3d)),4); % preallocate
|
||
|
|
||
|
for i=1:nx-1
|
||
|
for j=1:ny-1
|
||
|
for k=1:nz-1
|
||
|
% take [i:i+1,j:j+1,k:k+1] as cube
|
||
|
nod = zeros(1,8); % perallocate
|
||
|
|
||
|
for l = 1:8
|
||
|
% nod is vector with node indices of cube
|
||
|
nod(l) = nodes3d(i + X(l,1), j + X(l,2), k + X(l,3));
|
||
|
end
|
||
|
|
||
|
if nnz(nod) == 8 % then the cube is inside the mesh
|
||
|
tet = nod(cubetet);
|
||
|
else % then there is at least one point of the cube outside the mesh
|
||
|
Xs = X(logical(nod),:); % take only nodes inside the mesh
|
||
|
nodx = nod(logical(nod));
|
||
|
if nnz(nod) == 4 % 4 nodes, check if points are coplanar
|
||
|
C = cross(Xs(2,:)-Xs(1,:), Xs(3,:)-Xs(1,:));
|
||
|
cop = logical(dot(C,Xs(4,:)-Xs(1,:)));
|
||
|
% if cop = 0, then points are coplanar end thus no
|
||
|
% tetrahedra exists.
|
||
|
end
|
||
|
if (nnz(nod)>4) || (nnz(nod) == 4 && cop)
|
||
|
% create tetrahedra
|
||
|
tet1 = delaunay(Xs);
|
||
|
tet = nodx(tet1);
|
||
|
else % no tetrahedra exists
|
||
|
tet = [];
|
||
|
end
|
||
|
end
|
||
|
|
||
|
% add new tetrahedra to list
|
||
|
Tetrahedra(el:el+size(tet,1)-1,:) = tet;
|
||
|
el = el+size(tet,1);
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
tets = Tetrahedra(1:el-1,:); % Delete extra preallocated rows.
|
||
|
clear Tetrahedra
|
||
|
|
||
|
disp([num2str(size(tets,1)), ' tetrahedra created'])
|
||
|
|
||
|
% Delete nodes which are not in any tetrahedra.
|
||
|
disp('Update mesh')
|
||
|
contr = zeros(size(nodes,1),1);
|
||
|
for i=1:size(tets,1)
|
||
|
for j=1:4
|
||
|
contr(tets(i,j))=1;
|
||
|
end
|
||
|
end
|
||
|
|
||
|
nodes = nodes(logical(contr),:);
|
||
|
|
||
|
% compute P
|
||
|
P = speye(Nnodes);
|
||
|
P = P(logical(contr),:);
|
||
|
|
||
|
disp([num2str(nnz(~contr)), ' unused nodes in triangulation deleted.'])
|
||
|
|
||
|
disp('Update tetrahedra')
|
||
|
|
||
|
% make tetrahedra compatible with new node indices
|
||
|
cumcon = cumsum(~contr)';
|
||
|
tets = tets - cumcon(tets);
|
||
|
|
||
|
% create triangles
|
||
|
if size(tets,1) == 0
|
||
|
warning('No tetrahedra created')
|
||
|
faces = zeros(0,3);
|
||
|
else
|
||
|
disp('Create Triangles')
|
||
|
faces = freeBoundary(triangulation(tets,nodes));
|
||
|
disp([num2str(size(faces,1)), ' triangles created'])
|
||
|
end
|
||
|
|
||
|
% checking the mesh by solving a Poisson problem
|
||
|
if check_mesh
|
||
|
% Builds the P1 stiffness matrix from tets and nodes
|
||
|
[A,volumes]=stifness_matrixP1_3D(tets,nodes);
|
||
|
% Check if element volumes may be negative
|
||
|
if any(volumes<=0)
|
||
|
warning('Some elements have zero or negative volume')
|
||
|
end
|
||
|
% solve the Poisson problem with Dirichlet BC
|
||
|
A(2:end,2:end)\ones(size(A(2:end,2:end),1),1);
|
||
|
disp('If there are no warnings, it probably means that the mesh is fine')
|
||
|
end
|
||
|
|
||
|
% Plots mesh
|
||
|
if plot_mesh
|
||
|
tetramesh(tets,nodes)
|
||
|
xlabel('x')
|
||
|
ylabel('y')
|
||
|
zlabel('z')
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|