www.gusucode.com > 基于多边形网格的流动问题拓扑优化设计元代码 > PolyTop.m

    %------------------------------ PolyTop ----------------------------------%
% Ref: A Pereira, C Talischi, GH Paulino, IFM Menezes, MS Carvalho        %
%      "Fluid Flow Topology Optimization in PolyTop: Stability and        %
%      Computational Implementation", Struct Multidisc Optim,             %
%      DOI 10.1007/s00158-014-1182-z                                      %
%-------------------------------------------------------------------------%
function [z,V,fem] = PolyTop(fem,opt)
Iter=0; Tol=opt.Tol*(opt.zMax-opt.zMin); Change=2*Tol; z=opt.zIni; P=opt.P;
[E,dEdy,V,dVdy] = opt.MatIntFnc(P*z);
[FigHandle,FigData] = InitialPlot(fem,V);
while (Iter<opt.MaxIter) && (Change>Tol)  
  Iter = Iter + 1;
  %Compute cost functionals and analysis sensitivities
  [g,dgdE,dgdV,fem] = ConstraintFnc(fem,E,V,opt.VolFrac); 
  [f,dfdE,dfdV,fem] = ObjectiveFnc(fem,E,V);
  %Compute design sensitivities
  dfdz = P'*(dEdy.*dfdE + dVdy.*dfdV);
  dgdz = P'*(dEdy.*dgdE + dVdy.*dgdV);
  %Update design variable and analysis parameters
  [z,Change] = UpdateScheme(dfdz,g,dgdz,z,opt);
  [E,dEdy,V,dVdy] = opt.MatIntFnc(P*z);
  %Output results
  fprintf('It: %i \t Objective: %1.3f\tChange: %1.3f\n',Iter,f,Change);
  set(FigHandle,'FaceColor','flat','CData',V(FigData)); drawnow
end
%------------------------------------------------------- OBJECTIVE FUNCTION
function [f,dfdE,dfdV,fem] = ObjectiveFnc(fem,E,V)
[U,F,fem] = FEAnalysis(fem,E);
f = 1/2*dot(F,U);
temp = cumsum(U(fem.iA).*fem.kAalpha.*U(fem.jA));
temp = temp(cumsum(fem.ElemNDofA.^2));
dfdE = 1/2*[temp(1);temp(2:end)-temp(1:end-1)];
dfdV = zeros(size(V));
%------------------------------------------------------ CONSTRAINT FUNCTION
function [g,dgdE,dgdV,fem] = ConstraintFnc(fem,E,V,VolFrac)
if ~isfield(fem,'ElemArea')
  fem.ElemArea = zeros(fem.NElem,1);
  for el=1:fem.NElem
    vx = fem.Node(fem.Element{el},1); vy = fem.Node(fem.Element{el},2);
    fem.ElemArea(el) = 0.5*sum(vx.*vy([2:end 1])-vy.*vx([2:end 1]));
  end
end
g = sum(fem.ElemArea.*V)/sum(fem.ElemArea)-VolFrac;
dgdE = zeros(size(E));
dgdV = fem.ElemArea/sum(fem.ElemArea);
%----------------------------------------------- OPTIMALITY CRITERIA UPDATE
function [zNew,Change] = UpdateScheme(dfdz,g,dgdz,z0,opt)  
zMin=opt.zMin; zMax=opt.zMax;  
move=opt.OCMove*(zMax-zMin); eta=opt.OCEta;
l1=0; l2=1e6;  
while l2-l1 > 1e-4
  lmid = 0.5*(l1+l2);
  B = -(dfdz./dgdz)/lmid;
  zCnd = zMin+(z0-zMin).*B.^eta;
  zNew = max(max(min(min(zCnd,z0+move),zMax),z0-move),zMin);
  if (g+dgdz'*(zNew-z0)>0),  l1 = lmid;
  else                       l2 = lmid;  end
end
Change = max(abs(zNew-z0))/(zMax-zMin);
%-------------------------------------------------------------- FE-ANALYSIS
function [U,F,fem] = FEAnalysis(fem,E)
if ~isfield(fem,'kAmu')
  fem.ElemNDofA = 2*cellfun(@length,fem.Element);%% 形成每个单元的自由度索引
  fem.iA = zeros(sum(fem.ElemNDofA.^2),1);       %% A矩阵的单元组装索引 写成列向量
  fem.jA=fem.iA; fem.kAmu=fem.iA; fem.kAalpha=fem.iA; fem.e=fem.iA;   %% 类似
  fem.iB = zeros(sum(fem.ElemNDofA),1); fem.jB=fem.iB; fem.kB=fem.iB; %% 类似
  fem.NDof = 2*fem.NNode+fem.NElem+1;            %% 总刚度矩阵中的自由度
  indexA = 0; indexB = 0;               
  if ~isfield(fem,'ShapeFnc'), fem=TabShapeFnc(fem); end
  for el = 1:fem.NElem  
    eNode = fem.Element{el};
    eNDof = fem.ElemNDofA(el);
    if (el==1 || ~fem.Reg),  [Amu_e,Aalpha_e,Be]=LocalK(fem,eNode); end
    eDofA = reshape([2*eNode-1;2*eNode],eNDof,1); %% 单元节点对应自由度
    I=repmat(eDofA,1,eNDof); J=I';                %% A矩阵的自由度矩阵
    fem.iA(indexA+1:indexA+eNDof^2) = I(:);       %% 第indexA个单元的行自由度索引
    fem.jA(indexA+1:indexA+eNDof^2) = J(:);       %% 第indexA个单元的列自由度索引
    fem.kAmu(indexA+1:indexA+eNDof^2) = Amu_e(:); %% 第indexA个单元的行列对应Amu_e的值
    fem.kAalpha(indexA+1:indexA+eNDof^2) = Aalpha_e(:); %% 用sparse矩阵的命令,可实现自动对应叠加
    fem.e(indexA+1:indexA+eNDof^2) = el;
    fem.iB(indexB+1:indexB+eNDof) = eDofA(:);
    fem.jB(indexB+1:indexB+eNDof) = el;
    fem.kB(indexB+1:indexB+eNDof) = Be(:);
    indexA = indexA + eNDof^2;  
    indexB = indexB + eNDof;
  end
  fem.FixedDofs = zeros(1,size(fem.NodeBC,1));
  fem.G = zeros(size(fem.NodeBC,1),1);
  for i = 1:size(fem.NodeBC,1)
    fem.FixedDofs(i) = 2*(fem.NodeBC(i,1)-1) + fem.NodeBC(i,2);
    fem.G(i) = fem.NodeBC(i,3);
  end
  fem.FreeDofs = setdiff(1:fem.NDof,fem.FixedDofs);
end
A = sparse(fem.iA,fem.jA,fem.kAmu+E(fem.e).*fem.kAalpha);
B = sparse(fem.iB,fem.jB,fem.kB);
Z=zeros(2*fem.NNode,1); O=sparse(fem.NElem,fem.NElem);
K = [A B Z; B' O fem.ElemArea; Z' fem.ElemArea' 0];  
K = (K+K')/2;
S = zeros(fem.NDof,1); S(fem.FixedDofs,:)=fem.G;
S(fem.FreeDofs,:) = K(fem.FreeDofs,fem.FreeDofs)\...
                     (-K(fem.FreeDofs,fem.FixedDofs)*S(fem.FixedDofs,:));
U = S(1:2*fem.NNode);
F = A*U;
%----------------------------------------------- ELEMENT STIFFNESS MATRICES
function [Amu_e,Aalpha_e,Be] = LocalK(fem,eNode)
Cmu = fem.mu0*[2 0 0; 0 2 0; 0 0 1];
nn=length(eNode); Amu_e=zeros(2*nn,2*nn); Aalpha_e=Amu_e; Be=zeros(2*nn,1);
W = fem.ShapeFnc{nn}.W;
for q = 1:length(W)  %quadrature loop
 dNdxi = fem.ShapeFnc{nn}.dNdxi(:,:,q);    
  J0 = fem.Node(eNode,:)'*dNdxi; 
  dNdx = dNdxi/J0;            % N=(N1 0 N2 0 N3 0 ... Nnn 0;
                              %    0 N1 0 N2 0 N3 ... 0 Nnn)
                              % U=(u1 v1 u2 v2 u3 v3 ... unn vnn)^T
  B = zeros(3,2*nn);
  B(1,1:2:2*nn) = dNdx(:,1)'; 
  B(2,2:2:2*nn) = dNdx(:,2)'; 
  B(3,1:2:2*nn) = dNdx(:,2)'; 
  B(3,2:2:2*nn) = dNdx(:,1)';
  % B=(du/dx 0;0 dv/dy;du/dy+dv/dx)^T
  %  =(dN1/dx    0   dN2/dx    0   dN3/dx    0   ... dNnn/dx     0
  %       0   dN1/dy    0   dN2/dy    0   dN3/dy ...     0   dNnn/dy
  %    dN1/dy dN1/dx dN2/dy dN2/dx dN3/dy dN3/dx ... dNnn/dy dNnn/dx)
  Amu_e = Amu_e + B'*Cmu*B*W(q)*det(J0);
  N = fem.ShapeFnc{nn}.N(:,:,q);
  Nu = zeros(2,2*nn);
  Nu(1,1:2:2*nn) = N(:);
  Nu(2,2:2:2*nn) = N(:);
  Aalpha_e = Aalpha_e + Nu'*Nu*W(q)*det(J0);
  dNudx = reshape(dNdx',1,2*nn);
  Be = Be - dNudx'*W(q)*det(J0);
end
%------------------------------------------------- TABULATE SHAPE FUNCTIONS
function fem = TabShapeFnc(fem)
ElemNNode = cellfun(@length,fem.Element); % number of nodes per element
fem.ShapeFnc = cell(max(ElemNNode),1);
for nn = min(ElemNNode):max(ElemNNode)
  [W,Q] = PolyQuad(nn);
  fem.ShapeFnc{nn}.W = W;
  fem.ShapeFnc{nn}.N = zeros(nn,1,size(W,1));
  fem.ShapeFnc{nn}.dNdxi = zeros(nn,2,size(W,1));
  for q = 1:size(W,1)
    [N,dNdxi] = PolyShapeFnc(nn,Q(q,:));
    fem.ShapeFnc{nn}.N(:,:,q) = N;
    fem.ShapeFnc{nn}.dNdxi(:,:,q) = dNdxi;
  end
end
%------------------------------------------------ POLYGONAL SHAPE FUNCTIONS
function [N,dNdxi] = PolyShapeFnc(nn,xi)
N=zeros(nn,1); alpha=zeros(nn,1); dNdxi=zeros(nn,2); dalpha=zeros(nn,2);
sum_alpha=0.0; sum_dalpha=zeros(1,2); A=zeros(nn,1); dA=zeros(nn,2);
[p,Tri] = PolyTrnglt(nn,xi);
for i=1:nn
  sctr = Tri(i,:); pT = p(sctr,:);
  A(i) = 1/2*det([pT,ones(3,1)]);
  dA(i,1) = 1/2*(pT(3,2)-pT(2,2));
  dA(i,2) = 1/2*(pT(2,1)-pT(3,1));
end
A=[A(nn,:);A]; dA=[dA(nn,:);dA];
for i=1:nn
  alpha(i) = 1/(A(i)*A(i+1));
  dalpha(i,1) = -alpha(i)*(dA(i,1)/A(i)+dA(i+1,1)/A(i+1));
  dalpha(i,2) = -alpha(i)*(dA(i,2)/A(i)+dA(i+1,2)/A(i+1));
  sum_alpha = sum_alpha + alpha(i);
  sum_dalpha(1:2) = sum_dalpha(1:2)+dalpha(i,1:2);
end
for i=1:nn
  N(i) = alpha(i)/sum_alpha;
  dNdxi(i,1:2) = (dalpha(i,1:2)-N(i)*sum_dalpha(1:2))/sum_alpha;
end
%---------------------------------------------------- POLYGON TRIANGULATION
function [p,Tri] = PolyTrnglt(nn,xi)
p = [cos(2*pi*((1:nn))/nn); sin(2*pi*((1:nn))/nn)]';
p = [p; xi];
Tri = zeros(nn,3); Tri(1:nn,1)=nn+1;
Tri(1:nn,2)=1:nn; Tri(1:nn,3)=2:nn+1; Tri(nn,3)=1;
%----------------------------------------------------- POLYGONAL QUADRATURE
function [weight,point] = PolyQuad(nn)
[W,Q]= TriQuad;                  %integration pnts & wgts for ref. triangle
[p,Tri] = PolyTrnglt(nn,[0 0]);  %triangulate from origin
point=zeros(nn*length(W),2); weight=zeros(nn*length(W),1);
for k=1:nn
  sctr = Tri(k,:);
  for q=1:length(W)
    [N,dNds] = TriShapeFnc(Q(q,:));  %compute shape functions
    J0 = p(sctr,:)'*dNds;
    l = (k-1)*length(W) + q;
    point(l,:) = N'*p(sctr,:);
    weight(l) = det(J0)*W(q);
  end                                 
end
%---------------------------------------------------- TRIANGULAR QUADRATURE
function [weight,point] = TriQuad
point=[1/6,1/6;2/3,1/6;1/6,2/3]; weight=[1/6,1/6,1/6];   
%----------------------------------------------- TRIANGULAR SHAPE FUNCTIONS
function [N,dNds] = TriShapeFnc(s)
N=[1-s(1)-s(2);s(1);s(2)]; dNds=[-1,-1;1,0;0,1];
%------------------------------------------------------------- INITIAL PLOT
function [handle,map] = InitialPlot(fem,z0)
Tri = zeros(length([fem.Element{:}])-2*fem.NElem,3);
map = zeros(size(Tri,1),1); index=0;
for el = 1:fem.NElem
  for enode = 1:length(fem.Element{el})-2
    map(index+1) = el;
    Tri(index+1,:) = fem.Element{el}([1,enode+1,enode+2]);
    index = index + 1;
  end
end
handle = patch('Faces',Tri,'Vertices',fem.Node,'FaceVertexCData',...
               z0(map),'FaceColor','flat','EdgeColor','none');
axis equal; axis off; axis tight; colormap(gray); caxis([0 1]);
%-------------------------------------------------------------------------%