function [pts,tri] = xmesh2dlin(filename,varargin) %-------------------------------------------------------------------------% % XMESH2D stands for EXACT MESHER 2d. Given an arbitrary collection of % NURBS curves up through polynomial degree 3 in 2D, XMESH2d will generate % a higher order triangular mesh that exactly matches the input geometry. % % INPUT: % filename: The filename of a .spline file containing the curves that % define the problem geometry. % % Output: % NODE: A nNodesx3 array containing the coordinates and weights of the % nodes that make up the mesh. % % IEN: a 10xnel array containing the mesh connectivity information. % % filename.neu: xmesh2d also writes out the mesh information int he % standard gambit neu trail fil e format to the file .neu %-------------------------------------------------------------------------% if nargin == 1 options.output = false; options.debug = false; options.smoothWeights = true; options.smoothNodes = false; options.thresh=1.1; options.hmax=.3; elseif nargin == 2 options = varargin{1}; if ~exist('options.output') %#ok<*EXIST> options.output = false; end if ~exist('options.debug') options.debug = false; end if ~isfield(options,'smoothWeights') options.smoothWeights = true; end if ~exist('options.smoothNodes') options.smoothNodes = false; end if ~isfield(options,'thresh') options.thresh= 1.1; end if ~isfield(options,'hmax') options.hmax=.3; end end % Input Parser [P,KV,~,~,~,face] = splineFileIn(filename); % Normalize the knot vectors to span [0 1] for kk = 1:numel(KV) KV{kk} = KV{kk}/KV{kk}(end); end % Subdividing the inputted NURBS curves into polygons [node,edge,kvloc] = NURBS2poly(P,KV,options.thresh); hdata.hmax=options.hmax*(max(node(:,1))-min(node(:,1))); % Feeding the polygons into mesh2d [pts,tri,~] = xmeshfaces(node,edge,P,KV,kvloc,face,hdata,options); return function [node,linnode,BFLAG,CFLAG]= elevateMesh(pts,tri,bNode,bflag,bc,p) side = [1 2; 2 3; 3 1]; side10 = [1 4 5 2; 2 6 7 3; 3 8 9 1]; node = cell(length(tri),1); linnode = cell(length(tri),1); BFLAG = zeros(numel(bNode),4); ctr = 1; d = 14; % Define CFLAG as a flag if the current element is curved. CFLAG = false(length(tri),1); cctr=0; for ee = 1:length(tri) vert = pts(tri(ee,:),:); linnode{ee} = round(gen_net(vert)*10^d)/10^d; node{ee} = round(gen_net(vert)*10^d)/10^d; %Check to see if the current triangle is a boundary triangle. for bb = 1:numel(bNode) % Check to see if the triangle has a side on the boundary. for ss = 1:3 if all(single(node{ee}(side(ss,1),1:2)) == single(bNode{bb}(1,1:2))) && ... all(single(node{ee}(side(ss,2),1:2)) == single(bNode{bb}(4,1:2))); node{ee}(side10(ss,:),:) = bNode{bb}; linnode{ee}(side10(ss,:),3) = bNode{bb}(:,3); BFLAG(ctr,1) = ee; BFLAG(ctr,2) = ss; BFLAG(ctr,3) = bflag(bb,1); BFLAG(ctr,4) = bc(bflag(bb,1),2); if p(bflag(bb,2))>1 CFLAG(ee) = true; ss=evalNURBS(node{ee}(side10(ss,:),:),[0 0 0 0 1 1 1 1],0:.1:1); if abs(ss(:,1).^2+ss(:,2).^2-1)>1e-10 cctr=cctr+1; end end ctr=ctr+1; elseif all(single(node{ee}(side(ss,2),1:2)) == single(bNode{bb}(1,1:2))) && ... all(single(node{ee}(side(ss,1),1:2)) == single(bNode{bb}(4,1:2))); node{ee}(side10(ss,:),:) = flipud(bNode{bb}); linnode{ee}(side10(ss,:),3) = flipud(bNode{bb}(:,3)); BFLAG(ctr,1) = ee; BFLAG(ctr,2) = ss; BFLAG(ctr,3) = bflag(bb,1); BFLAG(ctr,4) = bc(bflag(bb,1),2); if p(bflag(bb,2))>1 CFLAG(ee) = true; ss=evalNURBS(node{ee}(side10(ss,:),:),[0 0 0 0 1 1 1 1],0:.1:1); if abs(ss(:,1).^2+ss(:,2).^2-1)>1e-10 cctr=cctr+1; end end ctr=ctr+1; end end % Also check to see if the triangle has a vertex on the boundary. % If it does, it is part of the blending layer, so it needs to be % flagged. % for vv = 1:3 % if single(node{ee}(vv,1:2)) == single(bNode{bb}(1,1:2)) || ... % single(node{ee}(vv,1:2)) == single(bNode{bb}(4,1:2)); % if p(bflag(bb,2))>1 % CFLAG(ee) = true; % end % ctr=ctr+1; % end % end end end return function [node] = gen_net(vert) % ----------------------------------gen_net------------------------------------% % Generates the control net for the current triangular Bezier patch. Reads in % the verticies of a triangle, and linearly interpolates the triangle to make a % 10 control point bezier element. % INPUT: % vert: a matrix in the form [x1 y1; x2 y2; x3 y3] containing the verticies of a % linear triangle, ordered counter clockwise from the bottom left vertex. % v3 % | \ % | \ % | \ % | \ % v1----v2 % OUTPUT: % node: a 10x3 array containing the control point coordinates and weights. % The standard node ordering is shown below. % % 3 % |\ % | \ % 8 7 % | \ % | \ % 9 10 6 % | \ % | \ % 1--4--5--2 % %------------------------------------------------------------------------------% node(:,1:2) = [ vert(1,1:2);... vert(2,1:2);... vert(3,1:2);... vert(1,1:2) + (vert(2,1:2)-vert(1,1:2))/3;... vert(1,1:2) + (vert(2,1:2)-vert(1,1:2))*2/3;... vert(2,1:2) + (vert(3,1:2)-vert(2,1:2))/3;... vert(2,1:2) + (vert(3,1:2)-vert(2,1:2))*2/3;... vert(3,1:2) + (vert(1,1:2)-vert(3,1:2))/3;... vert(3,1:2) + (vert(1,1:2)-vert(3,1:2))*2/3]; node(10,1:2) = node(9,1:2) + (node(6,1:2)-node(9,1:2))/2; if size(vert,2) ==3 node(4:10,3) = ones(7,1); node(1:3,3) = vert(1:3,3); else node(:,3) = ones(10,1); end return function [P,KV,p,BFLAG,BC,FACE] = splineFileIn(filename) filename = [filename,'.spline']; fileID = fopen(filename,'r'); % Read in the file header for i=1:2 line = fgetl(fileID); end % Find the total number of curves line = fgetl(fileID); dims = sscanf(line, '%f'); nCurves = dims(1); KV = cell(1,nCurves); P = cell(1,nCurves); BFLAG = cell(1,nCurves); p = zeros(1,nCurves); for cc = 1:nCurves line = fgetl(fileID); %#ok<*NASGU> dims = fscanf(fileID,'%u'); nCP = dims(1); lKV = dims(2); p(cc) = dims(3); line=fgetl(fileID); for ii = 1:nCP line = fgetl(fileID); tmpx = sscanf(line, '%lf'); P{cc}(ii,1) = tmpx(1); P{cc}(ii,2) = tmpx(2); P{cc}(ii,3) = tmpx(3); end line = fgetl(fileID); line = fgetl(fileID); KV{cc} = sscanf(line, '%lf'); KV{cc} = KV{cc}'; line = fgetl(fileID); nKspan = length(unique(KV{cc}))-1; for bb = 1:nKspan line = fgetl(fileID); BFLAG{cc}(bb,:) = sscanf(line, '%u'); end end line = fgetl(fileID);line = fgetl(fileID);line = fgetl(fileID); NBC = sscanf(line, '%u'); BC = zeros(NBC,2); for bb = 1:NBC line = fgetl(fileID); BC(bb,:) = sscanf(line,'%u'); end line = fgetl(fileID); if line ~= -1 fgetl(fileID); line = fgetl(fileID); nFace = sscanf(line,'%u'); FACE = cell(1,nFace); for ff = 1:nFace fgetl(fileID); line = fgetl(fileID); nCurve = sscanf(line,'%u'); for cc = 1:nCurve line = fgetl(fileID); FACE{ff}(cc) = sscanf(line,'%u'); end end else FACE{1} = 1:nCurves; end fclose(fileID); return function [NODE, IEN,BFLAG,CFLAG]= elevateMeshAndSmooth(pts,tri,bNode) side = [1 2; 2 3; 3 1]; side10 = [1 4 5 2; 2 6 7 3; 3 8 9 1]; node = cell(length(tri),1); ctr = 1; d = 14; % Loop through elements in the mesh and elevate locally. for ee = 1:length(tri) vert = pts(tri(ee,:),:); node{ee} = round(gen_net(vert)*10^d)/10^d; end % Create the global NODE and IEN arrays from the local arrays. addpath('~/TriGA/') addpath('~/TriGA/xmesh') [NODE, IEN] = gen_arrays(node); bNodeList = []; g = zeros(2,max(IEN(:))); % Find the displacement boundary conditions. for ee = 1:length(IEN) node = NODE(IEN(:,ee),:); %Check to see if the current triangle is a boundary triangle. for bb = 1:numel(bNode) % Check to see if the triangle has a side on the boundary. for ss = 1:3 if all(single(node(side(ss,1),1:2)) == single(bNode{bb}(1,1:2))) && ... all(single(node(side(ss,2),1:2)) == single(bNode{bb}(4,1:2))); ctr=ctr+1; bNodeList = [bNodeList;IEN(side10(ss,:),ee)]; gloc = bNode{bb}(:,1:2) - node(side10(ss,:),1:2); g(:,IEN(side10(ss,:),ee)) = gloc'; elseif all(single(node(side(ss,2),1:2)) == single(bNode{bb}(1,1:2))) && ... all(single(node(side(ss,1),1:2)) == single(bNode{bb}(4,1:2))); bNodeList = [bNodeList;IEN(side10(ss,:),ee)]; gloc = flipud(bNode{bb}(:,1:2)) - node(side10(ss,:),1:2); g(:,IEN(side10(ss,:),ee)) = gloc'; ctr=ctr+1; end end end end % Linear elasticty smoothing to make the curvilinear mesh. bNodes = unique(bNodeList); NODE = LE2d(NODE,IEN,bNodes,g); NODE(:,3) = 1; NODE(:,1:2) = NODE(:,1:2)+g'; % Defining dummy BFLAG and CFLAG variables so this function will play nice % in the TriGA environment. These will need to actaully be computed if this % is found to be worthwhile. BFLAG =[]; CFLAG =[]; return function [newNode] = LE2d(NODE, IEN, bNodes,g) % LE2d solves the 2D linear elasticity equations for the express purpose of % calculating mesh deformation. Because of this, it does not account for % traction and free boundary conditions. It simply claculates the global % stiffness matrix, sets the forcing matric to zero and applies diriclet % boundary conditions based on the geometry of the new mesh. % Quadrature rules [qPts, ~, w, ~] = quadData(16); nq = length(w); % Stiffness Properties E = 100*10^9; nu = .3; lambda = nu*E/((1+nu)*(1-2*nu)); mu = E/(2*(1+nu)); D = [lambda + 2*mu, lambda, 0; lambda, lambda + 2*mu, 0; 0 0 mu]; % Mesh/ Geometry information nel = length(IEN); nen = 10; nNodes = max(IEN(:)); nsd = 2; ndof = nsd*(nNodes-length(bNodes)); nedof = nen*nsd; %Initialize the global K and F matrices. K = zeros(ndof); F = zeros(ndof,1); % Construct the ID array. P = 1; ID = zeros(nsd,nNodes); for a = 1:nNodes if find(a==bNodes) ID(1,a) = 0; ID(2,a) = 0; else ID(1,a) = P; ID(2,a) = P+1; P = P+2; end end % Generate a lookup table for the basis. [N,dN_du] = evaluateBasis(qPts); % Loop over elements. for ee = 1:nel node = NODE(IEN(:,ee),:); % Set the local stiffness matrix to zero. k = zeros(nedof); % Loop over quadrature points to construct k. for qq = 1:nq % Construct the B matrix B = zeros(3,nedof); [~, dR_dx,~, J_det] = tri10fast(node,N(:,qq),dN_du(:,:,qq)); for a = 1:nen B(:,nsd*(a-1)+(1:2)) = [dR_dx(a,1), 0; ... 0, dR_dx(a,2);... dR_dx(a,2), dR_dx(a,1)]; end % Add the contributions of the current quad point to the local % stiffness matrix. J_det = abs(J_det); k = k + w(qq)*B'*D*B*J_det; end % Assemble the local element stiffness matrix to the global stiffness % matrix. for a = 1:nen for b = 1:nen for i = 1:nsd for j = 1:nsd p = (a-1)*nsd+i; q = (b-1)*nsd+j; Pa = ID(i,IEN(a,ee)); Pb = ID(j,IEN(b,ee)); if Pa ~= 0 && Pb ~= 0 K(Pa,Pb) = K(Pa,Pb) + k(p,q); elseif Pa~=0 && Pb ==0 F(Pa) = F(Pa) - k(p,q)*g(j,IEN(b,ee)); end end end end end end % Solve the system d = K\F; newNode = zeros(size(NODE)); for i = 1:nNodes xidx = ID(1,i); yidx = ID(2,i); if xidx~=0 newNode(i,1:2) = NODE(i,1:2) + [d(xidx), d(yidx)]; else newNode(i,1:2) = NODE(i,1:2); end end return