CFD Online Logo CFD Online URL
www.cfd-online.com
[Sponsors]
Home > Wiki > PFV get pressure

PFV get pressure

From CFD-Wiki

(Difference between revisions)
Jump to: navigation, search
(Created page with "Matlab function '''GetPresW.m''' to retrieve consistent pressure from velocity. <pre> function [P,Px,Py] = GetPresW(NumNod,NodNdx,Elcon,nn2nft,Xgrid,Ygrid,Q,EBCPr,nu) %GETPRESW...")
(Update to MatLab version R2012b and generalize to handle rectangular and triangular elements. This is a major revision.)
 
Line 2: Line 2:
<pre>
<pre>
-
function [P,Px,Py] = GetPresW(NumNod,NodNdx,Elcon,nn2nft,Xgrid,Ygrid,Q,EBCPr,nu)
+
function [P,Px,Py] = GetPres3W(eu,NodXY,Elcon,nn2nft,Q,EBCPr,~)  
-
%GETPRESW - Compute continuous simple cubic pressure and derivatives from (simple-cubic)
+
% GetPres3W - Compute continuous simple-cubic pressure from velocity
-
% velocity field on general quadrilateral grid (bilinear geometric mapping).  
+
%   field on general quadrilateral grid (bilinear geometric mapping) or
 +
%  quadratic pressure for triangular grid (linear mapping).
 +
% This version is restricted to 3-node triangles and 4-node quadrilaterals
 +
% P,Px,Py must be reshaped or restructured for use in calling program with
 +
%  P=reshape(P,NumNx,NumNy), etc. because it assumes that the grid may be
 +
%  unstructured.
 +
%
 +
% Usage
 +
%  P = GetPres3W(eu,NodXY,Elcon,nn2nft,Q,EBCPr);
 +
%  [P,Px,Py] = GetPres3W(eu,NodXY,Elcon,nn2nft,Q,EBCPr);
%
%
% Inputs
% Inputs
-
% NumNod - number of nodes
+
%   eu    - velocity class, (eg. ELS3412r, ELS4424r, ELS5424r, ELS2309t )
-
NodNdx - nodal index into Xgrid and Ygrid 
+
%   NodXY - coordinates of nodes
-
% Elcon  - element connectivity, nodes in element  
+
%   Elcon  - element connectivity, nodes in element  
-
% nn2nft - global number and type of (non-pressure) DOF at each node  
+
%   nn2nft - global number and type of (non-pressure) DOF at each node  
-
% Xgrid  - array of nodal x-coordinates
+
%   Q      - array of DOFs for velocity elements  
-
%  Ygrid  - array of nodal y-coordinates
+
%   EBCp  - essential pressure boundary condition structure
-
Q      - array of DOFs for cubic velocity elements  
+
%     EBCp.nodn - node number of fixed pressure node  
-
% EBCp  - essential pressure boundary condition structure
+
%     EBCp.val  - value of pressure  
-
%   EBCp.nodn - node number of fixed pressure node  
+
-
%   EBCp.val  - value of pressure  
+
-
%  nu - diffusion coefficient
+
% Outputs  
% Outputs  
-
% P  - pressure  
+
%   P,Px,Py - pressure degrees of freedom
-
%  Px - x-derivative of pressure
+
-
%  Py - y-derivative of pressure
+
% Uses  
% Uses  
-
% ilu_gmres_with_EBC - to solve the system with essential/Dirichlet BCs
+
%   ilu      - ilu preconditioner
-
% GQ3, GQ4, GQ5  - quadrature rules.
+
%  gmres    - to solve the system  
 +
% Indirectly may use (handle passed by eu):
 +
%  GQuad2  - function providing 2D rectangle quadrature rules.
 +
%  TQuad2  - function providing 2D triangle quadrature rules.
 +
%  ELG3412r - basis function class defining the cubic/pressure elements(Q)
 +
%  ELG2309t - basis function class defining the quadratic/pressure elements(T)
 +
%
 +
% Jonas Holdeman,  January 2007, revised March 2013 
-
% Jonas Holdeman,  January 2007, revised June 2011 
+
% ------------------- Constants and fixed data ---------------------------
-
% Constants and fixed data
+
nvn = eu.nnodes;       % Number of nodes in elements (4)
-
nn=[-1 -1; 1 -1; 1 1; -1 1];  % defines local nodal order
+
nvd = eu.nndofs;       % number of velocity DOFs at nodes (3|4|6);  
-
nnd = 4;                     % Number of nodes in elements
+
if nvn==4, ep = ELG3412r;   % simple cubic voricity class definition (Q)
-
nd = 3;  ND=1:nd;            % Number DOFs in velocity fns (bicubic-derived)
+
elseif nvn==3, ep=ELG2309t; % quadratic voricity class definition (T)
-
np = 3;                       % Number DOFs in pressure fns (simple cubic)
+
else error(['pressure: ' num2str(nvn) ' nodes not supported']);
-
% Parameters for GMRES solver
+
-
GMRES.Tolerance=1.e-9;
+
-
GMRES.MaxIterates=8;
+
-
GMRES.MaxRestarts=6;
+
-
DropTol = 1e-7;                 % Drop tolerence for ilu preconditioner
+
-
 
+
-
% Define 3-point quadrature data once, on first call (if needed).
+
-
% Gaussian weights and absissas to integrate 5th degree polynomials exactly.
+
-
global GQ3;
+
-
if (isempty(GQ3))      % Define 3-point quadrature data once, on first call.
+
-
  Aq=[-.774596669241483, .000000000000000,.774596669241483]; %Abs
+
-
  Hq=[ .555555555555556, .888888888888889,.555555555555556]; %Wts
+
-
  GQ3.size=9; GQ3.xa=[Aq;Aq;Aq]; GQ3.ya=GQ3.xa';
+
-
  wt=[Hq;Hq;Hq]; GQ3.wt=wt.*wt';
+
end
end
-
% Define 4-point quadrature data once, on first call (if needed).
+
npd = ep.nndofs;       % Number DOFs in pressure fns (3, simple cubic)
-
% Gaussian weights and absissas to integrate 7th degree polynomials exactly.
+
ND=1:nvd;               % Number DOFs in velocity fns (bicubic-derived)
-
global GQ4;
+
-
if (isempty(GQ4))      % Define 4-point quadrature data once, on first call.
+
-
  Aq=[-.861136311594053,-.339981043584856,.339981043584856, .861136311594053]; %Abs
+
-
  Hq=[ .347854845137454, .652145154862546,.652145154862546, .347854845137454]; %Wts
+
-
  GQ4.size=16; GQ4.xa=[Aq;Aq;Aq;Aq]; GQ4.ya=GQ4.xa';
+
-
  wt=[Hq;Hq;Hq;Hq]; GQ4.wt=wt.*wt';    % 4x4
+
-
end
+
-
% Define 5-point quadrature data once, on first call (if needed).
+
-
% Gaussian weights and absissas to integrate 9th degree polynomials exactly.
+
-
global GQ5;
+
-
if (isempty(GQ5))  % Has 5-point quadrature data been defined? If not, define arguments & weights.
+
-
  Aq=[-.906179845938664,-.538469310105683, .0,              .538469310105683, .906179845938664];
+
-
  Hq=[ .236926885056189, .478628670499366, .568888888888889, .478628670499366, .236926885056189];
+
-
  GQ5.size=25; GQ5.xa=[Aq;Aq;Aq;Aq;Aq]; GQ5.ya=GQ5.xa';
+
-
  wt=[Hq;Hq;Hq;Hq;Hq]; GQ5.wt=wt.*wt';    % 5x5
+
-
end
+
-
% -------------- end fixed data ------------------------
+
-
NumEl=size(Elcon,2);           % Number of elements  
+
NumEl=size(Elcon,1);   % Number of elements  
-
[NumNy,NumNx]=size(Xgrid);
+
NumNod=size(NodXY,1);   % Number of global nodes  
-
NumNod=NumNy*NumNx;            % Number of nodes  
+
NumPdof=npd*NumNod;     % Max number pressure DOFs  
-
MxVDof=nd*NumNod;               % Max number velocity DOFs  
+
 
-
MxPDof=np*NumNod;               % Max number pressure DOFs
+
% Parameters for GMRES solver
 +
GM.Tol=1.e-11;
 +
GM.MIter=30;
 +
GM.MRstrt=8;
 +
% parameters for ilu preconditioner
 +
% Decrease su.droptol if ilu preconditioner fails
 +
su.type='ilutp';
 +
su.droptol=1.e-5;
-
% We can use the same nodal connectivities (Elcon) for pressure elements,
+
nn2pft = zeros(NumNod,2);
-
%  but need new pointers from nodes to pressure DOFs
+
-
nn2nftp=zeros(2,NumNod); % node number -> pressure nf & nt
+
-
nf=-np+1;  nt=1;
+
for n=1:NumNod
for n=1:NumNod
-
  nf=nf+np;              % all nodes have 3 dofs
+
    nn2pft(n,:)=[(n-1)*npd+1,1];
-
  nn2nftp(:,n)=[nf;nt];  % dof number & type (all nodes type 1)
+
end
-
end;
+
% ---------------------- end fixed data ----------------------------------
-
 
+
-
% Allocate space for pressure matrix, velocity data 
+
-
pMat = spalloc(MxPDof,MxPDof,30*MxPDof);  % allocate P mass matrix
+
-
Vdata = zeros(MxPDof,1);       % allocate for velocity data (RHS)
+
-
Qp=zeros(MxPDof,1);      % Nodal pressure DOFs
+
% Begin essential boundary conditions, allocate space  
% Begin essential boundary conditions, allocate space  
-
MaxPBC = 1;
+
EBCp.Mxdof=NumPdof;
-
EBCp.Mxdof=MxPDof;
+
% Essential boundary condition for pressure  
% Essential boundary condition for pressure  
-
EBCp.dof = nn2nftp(1,EBCPr.nodn(1)); % Degree-of-freedom index
+
EBCp.dof = nn2pft(EBCPr.nodn(1),1);   % Degree-of-freedom index
-
EBCp.val = EBCPr.val;                         % Pressure Dof value  
+
EBCp.val = EBCPr.val;                 % Pressure Dof value  
% partion out essential (Dirichlet) dofs
% partion out essential (Dirichlet) dofs
-
p_vec = [1:EBCp.Mxdof]';        % List of all dofs
+
p_vec = (1:EBCp.Mxdof)';        % List of all dofs
EBCp.p_vec_undo = zeros(1,EBCp.Mxdof);
EBCp.p_vec_undo = zeros(1,EBCp.Mxdof);
% form a list of non-diri dofs
% form a list of non-diri dofs
EBCp.ndro = p_vec(~ismember(p_vec, EBCp.dof)); % list of non-diri dofs
EBCp.ndro = p_vec(~ismember(p_vec, EBCp.dof)); % list of non-diri dofs
% calculate p_vec_undo to restore Q to the original dof ordering
% calculate p_vec_undo to restore Q to the original dof ordering
-
EBCp.p_vec_undo([EBCp.ndro;EBCp.dof]) = [1:EBCp.Mxdof]; %p_vec';
+
EBCp.p_vec_undo([EBCp.ndro;EBCp.dof]) = (1:EBCp.Mxdof); %p_vec';
-
   Qp(EBCp.dof(1))=EBCp.val(1);
+
% Allocate space for pressure matrix, velocity data 
 +
pMat = spalloc(NumPdof,NumPdof,36*NumPdof);   % allocate P mass matrix
 +
Vdata = zeros(NumPdof,1);        % allocate velocity data
 +
Vdof = zeros(nvd,nvn);            % Nodal velocity DOFs
 +
Xe = zeros(2,nvn);
    
    
-
Vdof = zeros(nd,nnd);            % Nodal velocity DOFs
+
% BEGIN GLOBAL MATRIX ASSEMBLY
-
Xe = zeros(2,nnd);
+
for ne=1:NumEl
 +
   
 +
    Xe(1:2,1:nvn)=NodXY(Elcon(ne,1:nvn),1:2)';  
-
% BEGIN GLOBAL MATRIX ASSEMBLY
+
% Get stream function and velocities
-
for ne=1:NumEl 
+
   for n=1:nvn 
-
   for k=1:4
+
     Vdof(ND,n)=Q((nn2nft(Elcon(ne,n),1)-1)+ND); % Loop over local nodes
-
     ki=NodNdx(:,Elcon(k,ne));
+
-
    Xe(:,k)=[Xgrid(ki(2),ki(1));Ygrid(ki(2),ki(1))];  
+
   end
   end
-
% Get stream function and velocities
 
-
  for n=1:nnd 
 
-
    Vdof(ND,n)=Q((nn2nft(1,Elcon(n,ne))-1)+ND); % Loop over local nodes of element
 
-
  end
 
-
  [pMmat,Rndx,Cndx] = pMassMat(Xe,Elcon(:,ne),nn2nftp);    % Pressure "mass" matrix
 
-
  pMat=pMat+sparse(Rndx,Cndx,pMmat,MxPDof,MxPDof);  % Global mass assembly
 
-
 
 
-
  [CDat,RRndx] = PCDat(Xe,Elcon(:,ne),nn2nftp,Vdof);  % Convective data term
 
-
  Vdata([RRndx]) = Vdata([RRndx])-CDat(:);
 
    
    
-
   [DDat,RRndx] = PDDatL(Xe,Elcon(:,ne),nn2nftp,Vdof);   % Diffusive data term  
+
%      Pressure "mass" matrix
-
   Vdata([RRndx]) = Vdata([RRndx]) + nu*DDat(:); % +nu*DDat;
+
   [Emat,Rndx,Cndx] = pMassMat(Xe,Elcon(ne,:),nn2pft,ep)
 +
  pMat=pMat+sparse(Rndx,Cndx,Emat,NumPdof,NumPdof); % Global mass assembly
 +
%       Convective data term  
 +
   [CDat,RRndx] = PCDat(Xe,Elcon(ne,:),nn2pft,Vdof,ep,eu);
 +
  Vdata(RRndx) = Vdata(RRndx)-CDat(:);
end;  % Loop ne  
end;  % Loop ne  
% END GLOBAL MATRIX ASSEMBLY
% END GLOBAL MATRIX ASSEMBLY
Line 131: Line 108:
Vdatap=Vdata(EBCp.ndro)-pMat(EBCp.ndro,EBCp.dof)*EBCp.val;
Vdatap=Vdata(EBCp.ndro)-pMat(EBCp.ndro,EBCp.dof)*EBCp.val;
pMatr=pMat(EBCp.ndro,EBCp.ndro);
pMatr=pMat(EBCp.ndro,EBCp.ndro);
-
Qs=Qp(EBCp.ndro);            % Non-Dirichlet (active) dofs  
+
%Qs=Qp(EBCp.ndro);            % Non-Dirichlet (active) dofs  
-
Pr=ilu_gmres_with_EBC(pMatr,Vdatap,[],GMRES,Qs,DropTol);
+
[Lm,Um] = ilu(pMatr,su);      % incomplete LU
 +
Pr = gmres(pMatr,Vdatap,GM.MIter,GM.Tol,GM.MRstrt,Lm,Um,[]); % GMRES
-
Qp=[Pr;EBCp.val];         % Augment active dofs with esential (Dirichlet) dofs
+
Qp=[Pr;EBCp.val];     % Augment active dofs with esential (Dirichlet) dofs
-
Qp=Qp(EBCp.p_vec_undo);     % Restore natural order
+
Qp=Qp(EBCp.p_vec_undo);   % Restore natural order
-
Qp=reshape(Qp,np,NumNod);
+
if (nargout==3)
-
P= reshape(Qp(1,:),NumNy,NumNx);  
+
  Qp=reshape(Qp,npd,NumNod);
-
Px=reshape(Qp(2,:),NumNy,NumNx);  
+
  P = Qp(1,:);
-
Py=reshape(Qp(3,:),NumNy,NumNx);  
+
  Px = Qp(2,:);  
 +
  Py = Qp(3,:);  
 +
else
 +
    P = Qp;
 +
end
return;
return;
% >>>>>>>>>>>>> End pressure recovery <<<<<<<<<<<<<
% >>>>>>>>>>>>> End pressure recovery <<<<<<<<<<<<<
-
% -------------------- function pMassMat ----------------------------
+
% ********************* function pMassMat ********************************
-
function [MM,Rndx,Cndx]=pMassMat(Xe,Elcon,nn2nftp)
+
function [MM,Rndx,Cndx]=pMassMat(Xe,Elcon,nn2nftp,ep)
% Simple cubic gradient element "mass" matrix  
% Simple cubic gradient element "mass" matrix  
-
% -------------- Constants and fixed data -----------------
+
% ep = handle to class of definitions for cubic pressure functions:
-
global GQ4;
+
% ELG3412r (rectangle) or ELG2309t (triangle)
-
xa=GQ4.xa; ya=GQ4.ya; wt=GQ4.wt; Nq=GQ4.size;
+
-
nn=[-1 -1; 1 -1; 1 1; -1 1]; % defines local nodal order
+
-
nnd=4;
+
-
np=3; np4=nnd*np; NP=1:np;
+
%
%
-
global ZG3412pm;   
+
% -------------------- Constants and fixed data --------------------------
-
if (isempty(ZG3412pm)|size(ZG3412pm,2)~=Nq)
+
npn = ep.nnodes;       % number of velocity/vorticity element nodes (4)
 +
npd = ep.nndofs;        % number of vorticity DOFs at nodes (3);
 +
nn = ep.nn;          % defines local nodal order [-1 -1; 1 -1; 1 1; -1 1]
 +
npdf=npn*npd;
 +
NP=1:npd;
 +
% ------------------------------------------------------------------------
 +
 
 +
persistent QQ_prMMp;      % quadrature rules
 +
if isempty(QQ_prMMp)
 +
  QRord = (2*ep.mxpowr+1); % quadtature rule order
 +
  [QQ_prMMp.xa, QQ_prMMp.ya, QQ_prMMp.wt, QQ_prMMp.nq]=ep.hQuad(QRord);
 +
end % if isempty...
 +
xa = QQ_prMMp.xa; ya = QQ_prMMp.ya; wt = QQ_prMMp.wt; Nq = QQ_prMMp.nq;
 +
% ------------------------------------------------------------------------
 +
persistent ZZ_Gpmm;        % pressure functions
 +
if (isempty(ZZ_Gpmm)||size(ZZ_Gpmm,2)~=Nq)
% Evaluate and save/cache the set of shape functions at quadrature pts.  
% Evaluate and save/cache the set of shape functions at quadrature pts.  
-
   ZG3412pm=cell(nnd,Nq);  
+
   ZZ_Gpmm=cell(npn,Nq);  
   for k=1:Nq
   for k=1:Nq
-
     for m=1:nnd
+
     for m=1:npn
-
       ZG3412pm{m,k}=Gr(nn(m,:),xa(k),ya(k));
+
       ZZ_Gpmm{m,k}=ep.G(nn(m,:),xa(k),ya(k));
     end
     end
   end
   end
end  % if(isempty(*))
end  % if(isempty(*))
-
% --------------------- end fixed data -----------------
+
% ------------------------ end fixed data --------------------------------
-
TGi=cell(nnd);
+
TGi=cell(npn);
-
  for m=1:nnd   % Loop over corner nodes  
+
for m=1:npn   % Loop over corner nodes, GBL is gradient of bilinear fn
-
    J=(Xe*GBL(nn(:,:),nn(m,1),nn(m,2)))'; % GBL is gradient of bilinear function
+
  J=(Xe*ep.Gm(nn(:,:),nn(m,1),nn(m,2)))'; %
-
    TGi{m} = blkdiag(1,J);
+
  TGi{m} = blkdiag(1,J);
-
  end  % Loop m  
+
end  % Loop m  
-
MM=zeros(np4,np4);  G=zeros(2,np4);  % Preallocate arrays
+
MM=zeros(npdf,npdf);  G=zeros(2,npdf);  % Preallocate arrays
for k=1:Nq   
for k=1:Nq   
 +
   
% Initialize functions and derivatives at the quadrature point (xa,ya).
% Initialize functions and derivatives at the quadrature point (xa,ya).
-
   J=(Xe*GBL(nn(:,:),xa(k),ya(k)))';         % transpose of Jacobian J at (xa,ya)
+
   J=(Xe*ep.Gm(nn(:,:),xa(k),ya(k)))';   % Jacobian at (xa,ya)
-
   Det=J(1,1)*J(2,2)-J(1,2)*J(2,1);         % Determinant of J  
+
   Det=J(1,1)*J(2,2)-J(1,2)*J(2,1);       % Determinant of Jt & J  
-
   Ji=[J(2,2),-J(1,2); -J(2,1),J(1,1)]/Det;  % inverse of J
+
   Ji=[J(2,2),-J(1,2); -J(2,1),J(1,1)]/Det;
-
 
+
   for m=1:npn  
-
  mm = 0;
+
    mm=(m-1)*npd;
-
   for m=1:nnd  
+
     G(:,mm+NP)=Ji*ZZ_Gpmm{m,k}*TGi{m};
-
     G(:,mm+NP) = Ji*ZG3412pm{m,k}*TGi{m};
+
-
    mm = mm+np;
+
   end  % loop m
   end  % loop m
   MM = MM + G'*G*(wt(k)*Det);
   MM = MM + G'*G*(wt(k)*Det);
end        % end loop k (quadrature pts)
end        % end loop k (quadrature pts)
-
gf=zeros(np4,1);         % array of global freedoms  
+
gf=zeros(npdf,1);           % array of global freedoms  
-
m=0;
+
for n=1:npn            % Loop over element nodes  
-
for n=1:4                % Loop over element nodes  
+
  m=(n-1)*npd;
-
  gf(m+NP)=(nn2nftp(1,Elcon(n))-1)+NP; % Get global freedoms
+
  gf(m+NP)=(nn2nftp(Elcon(n),1)-1)+NP; % Get global freedoms
-
  m=m+np;
+
end
end
-
Rndx=repmat(gf,1,np4);    % Row indices
+
Rndx=repmat(gf,1,npdf);    % Row indices
Cndx=Rndx';                % Column indices
Cndx=Rndx';                % Column indices
   
   
-
MM = reshape(MM,1,np4*np4);
+
MM = reshape(MM,1,npdf*npdf);
-
Rndx=reshape(Rndx,1,np4*np4);
+
Rndx=reshape(Rndx,1,npdf*npdf);
-
Cndx=reshape(Cndx,1,np4*np4);   
+
Cndx=reshape(Cndx,1,npdf*npdf);   
 +
 
return;
return;
-
% --------------------- funnction PCDat -----------------------
+
% *********************** funnction PCDat ******************************
-
function [PC,Rndx]=PCDat(Xe,Elcon,nn2nftp,Vdof)
+
function [PC,Rndx]=PCDat(Xe,Elcon,nn2nftp,Vdof,ep,eu)
% Evaluate convective force data  
% Evaluate convective force data  
-
% ----------- Constants and fixed data ---------------
+
% ep = handle to class of definitions for cubic pressure functions:  
-
global GQ5;
+
% ELG3412r (rectangle) or ELG2309t (triangle)
-
xa=GQ5.xa; ya=GQ5.ya; wt=GQ5.wt; Nq=GQ5.size;
+
-
nn=[-1 -1; 1 -1; 1 1; -1 1]; % defines local nodal order
+
-
nnd=4;    % number of nodes
+
-
np = 3;  np4=4*np;  NP=1:np;
+
-
nd = 3; nd4=4*nd;  ND=1:nd;
+
%
%
-
global ZS3412pc; global ZSX3412pc; global ZSY3412pc; global ZG3412pc;   
+
% ----------- Constants and fixed data ---------------
-
if (isempty(ZS3412pc)|size(ZS3412pc,2)~=Nq)
+
 
 +
nvn = eu.nnodes;       % number of velocity element nodes  (4)
 +
nvd = eu.nndofs;       % number of velocity DOFs at nodes (3|4|6);  
 +
npd = ep.nndofs;        % number of vorticity DOFs at nodes (3); 
 +
nn = eu.nn;            % defines local nodal order [-1 -1; 1 -1; 1 1; -1 1]
 +
npdf=nvn*npd;   
 +
nvdf=nvn*nvd; 
 +
NP=1:npd;
 +
NV=1:nvd;
 +
% ------------------------------------------------------------------------
 +
persistent QQ_prPCp;      % quadrature rules
 +
if isempty(QQ_prPCp)
 +
  QRord = (eu.mxpowr+ep.mxpowr-1); % quadtature rule order
 +
  [QQ_prPCp.xa, QQ_prPCp.ya, QQ_prPCp.wt, QQ_prPCp.nq]=eu.hQuad(QRord);
 +
end  % if isempty...
 +
xa = QQ_prPCp.xa; ya = QQ_prPCp.ya; wt = QQ_prPCp.wt; Nq = QQ_prPCp.nq;
 +
% ------------------------------------------------------------------------
 +
persistent ZZ_Spcd; persistent ZZ_SXpcd; persistent ZZ_SYpcd;
 +
persistent ZZ_Gpcd; 
 +
if (isempty(ZZ_Spcd)||isempty(ZZ_Gpcd)||size(ZZ_Spcd,2)~=Nq)
% Evaluate and save/cache the set of shape functions at quadrature pts.  
% Evaluate and save/cache the set of shape functions at quadrature pts.  
-
   ZS3412pc=cell(nnd,Nq); ZSX3412pc=cell(nnd,Nq);  
+
   ZZ_Spcd=cell(nvn,Nq); ZZ_SXpcd=cell(nvn,Nq);  
-
   ZSY3412pc=cell(nnd,Nq); ZG3412pc=cell(nnd,Nq);   
+
   ZZ_SYpcd=cell(nvn,Nq); ZZ_Gpcd=cell(nvn,Nq);   
   for k=1:Nq
   for k=1:Nq
-
     for m=1:nnd
+
     for m=1:nvn
-
       ZS3412pc{m,k} =Sr(nn(m,:),xa(k),ya(k));
+
       ZZ_Spcd{m,k} =eu.S(nn(m,:),xa(k),ya(k));
-
       ZSX3412pc{m,k}=Sxr(nn(m,:),xa(k),ya(k));
+
       [ZZ_SXpcd{m,k},ZZ_SYpcd{m,k}]=eu.DS(nn(m,:),xa(k),ya(k));
-
      ZSY3412pc{m,k}=Syr(nn(m,:),xa(k),ya(k));
+
       ZZ_Gpcd{m,k}=ep.G(nn(m,:),xa(k),ya(k));
-
       ZG3412pc{m,k}=Gr(nn(m,:),xa(k),ya(k));
+
     end  % loop m over nodes   
     end  % loop m over nodes   
   end  % loop k over Nq
   end  % loop k over Nq
end  % if(isempty(*))
end  % if(isempty(*))
-
% ----------------- end fixed data ------------------
+
% ----------------------- end fixed data ---------------------------------
-
Ti=cell(nnd);  TGi=cell(nnd);
+
Ti=cell(nvn);  TGi=cell(nvn);
-
for m=1:nnd   % Loop over corner nodes  
+
for m=1:nvn   % Loop over corner nodes  
-
  J=(Xe*GBL(nn(:,:),nn(m,1),nn(m,2)))';  % Jacobian at (xa,ya)
+
    Jt=Xe*eu.Gm(nn(:,:),nn(m,1),nn(m,2));
-
   Det=J(1,1)*J(2,2)-J(1,2)*J(2,1);     % Determinant of J & Jt
+
    JtiD=[Jt(2,2),-Jt(1,2); -Jt(2,1),Jt(1,1)];  % det(J)*inv(J)
-
   JiD=[J(2,2),-J(1,2); -J(2,1),J(1,1)]; % inv(J)*det(J)
+
  if nvd==3,
-
   Ti{m} = blkdiag(1,JiD');
+
    TT=blkdiag(1,JtiD);
-
   TGi{m} = blkdiag(1,J);
+
   elseif nvd==4
 +
    TT=blkdiag(1,JtiD,(Jt(1,1)*Jt(2,2)+Jt(1,2)*Jt(2,1)) );
 +
   else
 +
    T2=[Jt(1,1)^2, 2*Jt(1,1)*Jt(2,1), Jt(2,1)^2; ...  % alt
 +
    Jt(1,1)*Jt(1,2), Jt(1,1)*Jt(2,2)+Jt(1,2)*Jt(2,1), Jt(2,1)*Jt(2,2); ...
 +
    Jt(1,2)^2, 2*Jt(1,2)*Jt(2,2), Jt(2,2)^2];
 +
    TT=blkdiag(1,JtiD,T2);
 +
    Bxy=Xe*eu.DGm(nn(:,:),nn(m,1),nn(m,2));  % Second cross derivatives
 +
    TT(5,2)= Bxy(2);
 +
    TT(5,3)=-Bxy(1);
 +
  end
 +
   Ti{m}=TT;
 +
%
 +
%  J=[Jt(1,1),Jt(2,1); Jt(1,2),Jt(2,2)];   % evaluate J from transpose
 +
  TGi{m} = blkdiag(1,Jt');
end  % Loop m over corner nodes
end  % Loop m over corner nodes
-
PC=zeros(np4,1);
+
PC=zeros(npdf,1);
-
S=zeros(2,nd4);  Sx=zeros(2,nd4);  Sy=zeros(2,nd4);  G=zeros(2,np4);
+
S=zeros(2,nvdf);  Sx=zeros(2,nvdf);  Sy=zeros(2,nvdf);  G=zeros(2,npdf);
for k=1:Nq      % Loop over quadrature points  
for k=1:Nq      % Loop over quadrature points  
-
   J=(Xe*GBL(nn(:,:),xa(k),ya(k)))';       % Jacobian at (xa,ya)
+
   Jt=Xe*eu.Gm(nn(:,:),xa(k),ya(k));   % transpose of Jacobian at (xa,ya)
-
   Det=J(1,1)*J(2,2)-J(1,2)*J(2,1);     % Determinant of J & Jt
+
   Det=Jt(1,1)*Jt(2,2)-Jt(1,2)*Jt(2,1); % Determinant of Jt & J  
-
   Jtbd=(J/Det)';                       % transpose(J/D)
+
   Jtd=Jt/Det;
-
   JiD=[J(2,2),-J(1,2); -J(2,1),J(1,1)]; % inv(J)*det(J)
+
   JtiD=[Jt(2,2),-Jt(1,2); -Jt(2,1),Jt(1,1)];
-
   Ji=JiD/Det;                           % inverse(J)
+
   Jti=JtiD/Det;
-
   for m=1:4         % Loop over element nodes  
+
  Ji=[Jti(1,1),Jti(2,1); Jti(1,2),Jti(2,2)];
-
     mm=nd*(m-1);
+
   for m=1:nvn         % Loop over element nodes  
-
     S(:,mm+ND) =Jtbd*ZS3412pc{m,k}*Ti{m};
+
     mm=nvd*(m-1);
-
     Sx(:,mm+ND)=Jtbd*(Ji(1,1)*ZSX3412pc{m,k}+Ji(1,2)*ZSY3412pc{m,k})*Ti{m};
+
     S(:,mm+NV) =Jtd*ZZ_Spcd{m,k}*Ti{m};
-
     Sy(:,mm+ND)=Jtbd*(Ji(2,1)*ZSX3412pc{m,k}+Ji(2,2)*ZSY3412pc{m,k})*Ti{m};
+
     Sx(:,mm+NV)=Jtd*(Jti(1,1)*ZZ_SXpcd{m,k}+Jti(2,1)*ZZ_SYpcd{m,k})*Ti{m};
-
     mm=np*(m-1);
+
     Sy(:,mm+NV)=Jtd*(Jti(1,2)*ZZ_SXpcd{m,k}+Jti(2,2)*ZZ_SYpcd{m,k})*Ti{m};
-
     G(:,mm+NP)=Ji*ZG3412pc{m,k}*TGi{m};
+
     mm=npd*(m-1);
 +
     G(:,mm+NP)=Ji*ZZ_Gpcd{m,k}*TGi{m};  
   end    % end loop over element nodes
   end    % end loop over element nodes
    
    
Line 262: Line 282:
   Ux = Sx*Vdof(:);
   Ux = Sx*Vdof(:);
   Uy = Sy*Vdof(:);
   Uy = Sy*Vdof(:);
-
   UgU = U(1)*Ux+U(2)*Uy;   % U dot grad U
+
   UgU = U(1)*Ux+U(2)*Uy; % U dot grad U  
 +
 
   PC = PC + G'*UgU*(wt(k)*Det);
   PC = PC + G'*UgU*(wt(k)*Det);
end    % end loop over Nq quadrature points
end    % end loop over Nq quadrature points
-
 
-
gf=zeros(1,np4);          % array of global freedoms
 
-
m=0;
 
-
for n=1:4                % Loop over element nodes
 
-
  gf(m+NP)=(nn2nftp(1,Elcon(n))-1)+NP; % Get global freedoms
 
-
  m=m+np;
 
-
end
 
-
Rndx=gf;
 
-
PC = reshape(PC,1,np4);
 
-
return;
 
-
 
-
% ----------------- function PDDatL -------------------------
 
-
 
-
function [PD,Rndx]=PDDatL(Xe,Elcon,nn2nftp,Vdof)
 
-
% Evaluate diffusive force data (Laplacian form) 
 
-
% --------------- Constants and fixed data -------------------
 
-
global GQ3;
 
-
xa=GQ3.xa; ya=GQ3.ya; wt=GQ3.wt; Nq=GQ3.size;
 
-
nnd=4;    % number of nodes
 
-
nn=[-1 -1; 1 -1; 1 1; -1 1]; % defines local nodal order
 
-
np = 3;  npdf=nnd*np;  NP=1:np;
 
-
nd = 3;  nd4=nnd*nd;  ND=1:nd;
 
-
global ZSXX3412pd; global ZSXY3412pd; global ZSYY3412pd; global ZG3412pd; 
 
-
if (isempty(ZSXX3412pd)|size(ZSXX3412pd,2)~=Nq)
 
-
% Evaluate and save/cache the set of shape functions at quadrature pts.
 
-
ZSXX3412pd=cell(nnd,Nq); ZSXY3412pd=cell(nnd,Nq);
 
-
ZSYY3412pd=cell(nnd,Nq);  ZG3412pd=cell(nnd,Nq);
 
-
global ZSYY3412pd;
 
-
  for k=1:Nq
 
-
    for m=1:nnd
 
-
      ZSXX3412pd{m,k}=Sxxr(nn(m,:),xa(k),ya(k));
 
-
      ZSXY3412pd{m,k}=Sxyr(nn(m,:),xa(k),ya(k));
 
-
      ZSYY3412pd{m,k}=Syyr(nn(m,:),xa(k),ya(k));
 
-
      ZG3412pd{m,k}=Gr(nn(m,:),xa(k),ya(k));
 
-
    end  % loop m over nodes 
 
-
  end  % loop k over Nq
 
-
end  % if(isempty(*))
 
-
% ------------ end fixed data -------------------
 
-
%
 
-
Ti=cell(nnd);  TGi=cell(nnd);
 
-
  for m=1:nnd  % Loop over corner nodes
 
-
  J=(Xe*GBL(nn(:,:),nn(m,1),nn(m,2)))';  % Jacobian at (xa,ya)
 
-
  Det=J(1,1)*J(2,2)-J(1,2)*J(2,1);      % Determinant of J & Jt
 
-
  JiD=[J(2,2),-J(1,2); -J(2,1),J(1,1)]; % inv(J)*det(J)
 
-
  Ti{m} = blkdiag(1,JiD');
 
-
  TGi{m} = blkdiag(1,J);
 
-
  end  % Loop m over corner nodes
 
-
 
-
PD=zeros(npdf,1);
 
-
Sxx=zeros(2,nd4);  Syy=zeros(2,nd4);  G=zeros(2,npdf);
 
-
for k=1:Nq          % Loop over quadrature points
 
-
  Jt=(Xe*GBL(nn(:,:),xa(k),ya(k)));      % transpose of Jacobian at (xa,ya)
 
-
  Det=Jt(1,1)*Jt(2,2)-Jt(1,2)*Jt(2,1);  % Determinant of Jt & J
 
-
  Jtd=Jt/Det;
 
-
  JiD=[Jt(2,2),-Jt(1,2); -Jt(2,1),Jt(1,1)];
 
-
  Ji=JiD/Det;
 
-
  for m=1:nnd        % Loop over element nodes
 
-
    mm=nd*(m-1);    % This transform is approximate !!
 
-
    Sxx(:,mm+ND)=Jtd*(Ji(1,1)^2*ZSXX3412pd{m,k}+2*Ji(1,1)*Ji(1,2)*ZSXY3412pd{m,k}+Ji(1,2)^2*ZSYY3412pd{m,k})*Ti{m};
 
-
    Syy(:,mm+ND)=Jtd*(Ji(2,1)^2*ZSXX3412pd{m,k}+2*Ji(2,1)*Ji(2,2)*ZSXY3412pd{m,k}+Ji(2,2)^2*ZSYY3412pd{m,k})*Ti{m};
 
-
    mm=np*(m-1);
 
-
    G(:,mm+NP) =Ji*ZG3412pd{m,k}*TGi{m};
 
-
  end    % end loop over element nodes
 
-
 
 
-
  LapU = (Sxx+Syy)*Vdof(:);
 
-
  PD = PD+G'*LapU*(wt(k)*Det);
 
-
end    % end loop over quadrature points
 
gf=zeros(1,npdf);          % array of global freedoms  
gf=zeros(1,npdf);          % array of global freedoms  
-
m=0;  K=1:np;
+
for n=1:nvn            % Loop over element nodes  
-
for n=1:nnd                % Loop over element nodes  
+
  m=(n-1)*npd;
-
  nfn=nn2nftp(1,Elcon(n))-1; % Get global freedom
+
  gf(m+NP)=(nn2nftp(Elcon(n),1)-1)+NP; % Get global freedoms
-
  gf(m+NP)=(nn2nftp(1,Elcon(n))-1)+NP;
+
-
  m=m+np;
+
end
end
Rndx=gf;
Rndx=gf;
-
PD = reshape(PD,1,npdf);
+
PC = reshape(PC,1,npdf);
-
return;
+
-
 
+
-
% ------------------------------------------------------------------------------
+
-
function gv=Gr(ni,q,r)
+
-
%GR  Cubic Hermite gradient basis functions for pressure gradient.
+
-
  qi=ni(1); q0=q*ni(1); 
+
-
  ri=ni(2); r0=r*ni(2);
+
-
% Cubic Hermite gradient 
+
-
gv=[1/8*qi*(1+r0)*(r0*(1-r0)+3*(1-q^2)), -1/8*(1+r0)*(1+q0)*(1-3*q0), ...
+
-
      -1/8*qi/ri*(1-r^2)*(1+r0); ...
+
-
    1/8*ri*(1+q0)*(q0*(1-q0)+3*(1-r^2)),  -1/8/qi*ri*(1-q^2)*(1+q0), ...
+
-
      -1/8*(1+q0)*(1+r0)*(1-3*r0)];
+
-
return;
+
-
 
+
-
function gx=Gxr(ni,q,r)
+
-
%GRX - Cubic Hermite gradient basis functions for pressure gradient.
+
-
  qi=ni(1); q0=q*ni(1); 
+
-
  ri=ni(2); r0=r*ni(2);
+
-
% x-derivative of irrotational vector
+
-
  gx=[-3/4*qi^2*q0*(1+r0), 1/4*qi*(1+r0)*(1+3*q0), 0; ...
+
-
      1/8*qi*ri*(4-3*q0^2-3*r0^2), -1/8*ri*(1+q0)*(1-3*q0), -1/8*qi*(1+r0)*(1-3*r0)];
+
-
return;
+
-
 
+
-
function gy=Gyr(ni,q,r)
+
-
%GRY - Cubic Hermite gradient basis functions for pressure gradient.
+
-
  qi=ni(1); q0=q*ni(1); 
+
-
  ri=ni(2); r0=r*ni(2);
+
-
% y-derivative of irrotational vector
+
-
  gy=[1/8*qi*ri*(4-3*q0^2-3*r0^2), -1/8*ri*(1+q0)*(1-3*q0), -1/8*qi*(1+r0)*(1-3*r0); ...
+
-
    -3/4*ri^2*r0*(1+q0), 0, 1/4*ri*(1+q0)*(1+3*r0)];
+
-
return;
+
-
 
+
-
% ------------------------------------------------------------------------------
+
-
function S=Sr(ni,q,r)
+
-
%SR  Array of solenoidal basis functions.
+
-
  qi=ni(1); q0=q*ni(1); q1=1+q0;
+
-
  ri=ni(2); r0=r*ni(2); r1=1+r0;
+
-
% array of solenoidal vectors
+
-
  S=[ .125*ri*q1*(q0*(1-q0)+3*(1-r^2)), .125*q1*r1*(3*r0-1),    .125*ri/qi*q1^2*(1-q0); ...
+
-
    -.125*qi*r1*(r0*(1-r0)+3*(1-q^2)), .125*qi/ri*r1^2*(1-r0), .125*q1*r1*(3*q0-1)];
+
-
return;
+
-
 
+
-
function S=Sxr(ni,q,r)
+
-
%SXR  Array of x-derivatives of solenoidal basis functions.
+
-
  qi=ni(1); q0=q*ni(1); q1=1+q0;
+
-
  ri=ni(2); r0=r*ni(2); r1=1+r0;
+
-
% array of solenoidal vectors
+
-
  S=[.125*qi*ri*(4-3*q^2-3*r^2), .125*qi*r1*(3*r0-1), -.125*ri*q1*(3*q0-1); ...
+
-
      .75*qi^2*r1*q0,              0,                  .25*qi*r1*(3*q0+1)];
+
-
return;
+
-
 
+
-
function s=Syr(ni,q,r)
+
-
%SYR  Array of y-derivatives of solenoidal basis functions.
+
-
  qi=ni(1); q0=q*ni(1); q1=1+q0;
+
-
  ri=ni(2); r0=r*ni(2); r1=1+r0;
+
-
% array of solenoidal vectors
+
-
  s=[-.75*ri^2*q1*r0,            .25*ri*q1*(3*r0+1),  0 ; ...
+
-
      -.125*qi*ri*(4-3*q^2-3*r^2), .125*qi*r1*(1-3*r0), .125*ri*q1*(3*q0-1)];
+
-
return;
+
-
 
+
-
function s=Sxxr(ni,q,r)
+
-
%SXXR  Array of second x-derivatives of solenoidal basis functions.
+
-
  qi=ni(1); q0=q*ni(1); q1=1+q0;
+
-
  ri=ni(2); r0=r*ni(2); r1=1+r0;
+
-
  % array of solenoidal vectors
+
-
  s=[-3/4*qi^2*ri*q0, 0, -1/4*ri*qi*(1+3*q0); 3/4*qi^3*r1, 0, 3/4*qi^2*r1 ];
+
-
return;
+
-
 
+
-
function s=Syyr(ni,q,r)
+
-
%SYYR  Array of second y-derivatives of solenoidal basis functions.
+
-
  qi=ni(1); q0=q*ni(1); q1=1+q0;
+
-
  ri=ni(2); r0=r*ni(2); r1=1+r0;
+
-
% array of solenoidal vectors
+
-
s=[-3/4*ri^3*q1, 3/4*ri^2*q1, 0; 3/4*qi*ri^2*r0, -1/4*qi*ri*(1+3*r0), 0 ];
+
-
return;
+
-
 
+
-
function s=Sxyr(ni,q,r)
+
-
%SXYR  Array of second (cross) xy-derivatives of solenoidal basis functions.
+
-
  qi=ni(1); q0=q*ni(1); q1=1+q0;
+
-
  ri=ni(2); r0=r*ni(2); r1=1+r0;
+
-
% array of solenoidal vectors
+
-
s=[-3/4*qi*ri^2*r0, 1/4*qi*ri*(1+3*r0), 0; 3/4*qi^2*ri*q0, 0, 1/4*qi*ri*(1+3*q0)];
+
-
return;
+
-
 
+
-
function G=GBL(ni,q,r)
+
-
% Transposed gradient (derivatives) of scalar bilinear mapping function.
+
-
% The parameter ni can be a vector of coordinate pairs.
+
-
  G=[.25*ni(:,1).*(1+ni(:,2).*r), .25*ni(:,2).*(1+ni(:,1).*q)];
+
return;
return;
</pre>
</pre>

Latest revision as of 16:10, 15 March 2013

Matlab function GetPresW.m to retrieve consistent pressure from velocity.

function [P,Px,Py] = GetPres3W(eu,NodXY,Elcon,nn2nft,Q,EBCPr,~) 
% GetPres3W - Compute continuous simple-cubic pressure from velocity
%   field on general quadrilateral grid (bilinear geometric mapping) or
%   quadratic pressure for triangular grid (linear mapping).
% This version is restricted to 3-node triangles and 4-node quadrilaterals
% P,Px,Py must be reshaped or restructured for use in calling program with
%   P=reshape(P,NumNx,NumNy), etc. because it assumes that the grid may be
%   unstructured. 
%
% Usage
%   P = GetPres3W(eu,NodXY,Elcon,nn2nft,Q,EBCPr);
%   [P,Px,Py] = GetPres3W(eu,NodXY,Elcon,nn2nft,Q,EBCPr);
%
% Inputs
%   eu     - velocity class, (eg. ELS3412r, ELS4424r, ELS5424r, ELS2309t )
%   NodXY  - coordinates of nodes 
%   Elcon  - element connectivity, nodes in element 
%   nn2nft - global number and type of (non-pressure) DOF at each node 
%   Q      - array of DOFs for velocity elements 
%   EBCp   - essential pressure boundary condition structure
%     EBCp.nodn - node number of fixed pressure node 
%     EBCp.val  - value of pressure 
% Outputs 
%   P,Px,Py  - pressure degrees of freedom
% Uses 
%   ilu      - ilu preconditioner
%   gmres    - to solve the system 
% Indirectly may use (handle passed by eu):
%   GQuad2   - function providing 2D rectangle quadrature rules.
%   TQuad2   - function providing 2D triangle quadrature rules.
%   ELG3412r - basis function class defining the cubic/pressure elements(Q)
%   ELG2309t - basis function class defining the quadratic/pressure elements(T)
%
% Jonas Holdeman,   January 2007, revised March 2013  

% ------------------- Constants and fixed data ---------------------------

nvn = eu.nnodes;        % Number of nodes in elements (4)
nvd = eu.nndofs;        % number of velocity DOFs at nodes (3|4|6); 
if nvn==4, ep = ELG3412r;    % simple cubic voricity class definition (Q)
elseif nvn==3, ep=ELG2309t;  % quadratic voricity class definition (T)
else error(['pressure: ' num2str(nvn) ' nodes not supported']);
end
npd = ep.nndofs;        % Number DOFs in pressure fns (3, simple cubic)
ND=1:nvd;               % Number DOFs in velocity fns (bicubic-derived)

NumEl=size(Elcon,1);    % Number of elements 
NumNod=size(NodXY,1);   % Number of global nodes 
NumPdof=npd*NumNod;     % Max number pressure DOFs 

% Parameters for GMRES solver 
GM.Tol=1.e-11;
GM.MIter=30; 
GM.MRstrt=8;
% parameters for ilu preconditioner
% Decrease su.droptol if ilu preconditioner fails
su.type='ilutp';
su.droptol=1.e-5;

nn2pft = zeros(NumNod,2);
for n=1:NumNod
    nn2pft(n,:)=[(n-1)*npd+1,1];
end
% ---------------------- end fixed data ----------------------------------

% Begin essential boundary conditions, allocate space 
EBCp.Mxdof=NumPdof;
% Essential boundary condition for pressure 
EBCp.dof = nn2pft(EBCPr.nodn(1),1);   % Degree-of-freedom index
EBCp.val = EBCPr.val;                  % Pressure Dof value 

% partion out essential (Dirichlet) dofs
p_vec = (1:EBCp.Mxdof)';         % List of all dofs
EBCp.p_vec_undo = zeros(1,EBCp.Mxdof);
% form a list of non-diri dofs
EBCp.ndro = p_vec(~ismember(p_vec, EBCp.dof));	% list of non-diri dofs
% calculate p_vec_undo to restore Q to the original dof ordering
EBCp.p_vec_undo([EBCp.ndro;EBCp.dof]) = (1:EBCp.Mxdof); %p_vec';

% Allocate space for pressure matrix, velocity data  
pMat = spalloc(NumPdof,NumPdof,36*NumPdof);   % allocate P mass matrix
Vdata = zeros(NumPdof,1);        % allocate velocity data 
Vdof = zeros(nvd,nvn);             % Nodal velocity DOFs 
Xe = zeros(2,nvn);
   
% BEGIN GLOBAL MATRIX ASSEMBLY
for ne=1:NumEl
    
     Xe(1:2,1:nvn)=NodXY(Elcon(ne,1:nvn),1:2)'; 

% Get stream function and velocities
   for n=1:nvn  
     Vdof(ND,n)=Q((nn2nft(Elcon(ne,n),1)-1)+ND); % Loop over local nodes
   end
   
%       Pressure "mass" matrix
   [Emat,Rndx,Cndx] = pMassMat(Xe,Elcon(ne,:),nn2pft,ep);  
   pMat=pMat+sparse(Rndx,Cndx,Emat,NumPdof,NumPdof);  % Global mass assembly 
%       Convective data term   
   [CDat,RRndx] = PCDat(Xe,Elcon(ne,:),nn2pft,Vdof,ep,eu); 
   Vdata(RRndx) = Vdata(RRndx)-CDat(:);
end;   % Loop ne 
% END GLOBAL MATRIX ASSEMBLY

Vdatap=Vdata(EBCp.ndro)-pMat(EBCp.ndro,EBCp.dof)*EBCp.val;
pMatr=pMat(EBCp.ndro,EBCp.ndro);
%Qs=Qp(EBCp.ndro);            % Non-Dirichlet (active) dofs 

[Lm,Um] = ilu(pMatr,su);      % incomplete LU
Pr = gmres(pMatr,Vdatap,GM.MIter,GM.Tol,GM.MRstrt,Lm,Um,[]);	% GMRES

Qp=[Pr;EBCp.val];      % Augment active dofs with esential (Dirichlet) dofs
Qp=Qp(EBCp.p_vec_undo);    % Restore natural order
if (nargout==3)
   Qp=reshape(Qp,npd,NumNod);
   P =  Qp(1,:);
   Px = Qp(2,:); 
   Py = Qp(3,:); 
else
    P = Qp;
end
return;
% >>>>>>>>>>>>> End pressure recovery <<<<<<<<<<<<<

% ********************* function pMassMat ********************************

function [MM,Rndx,Cndx]=pMassMat(Xe,Elcon,nn2nftp,ep)
% Simple cubic gradient element "mass" matrix 
% ep = handle to class of definitions for cubic pressure functions: 
% ELG3412r (rectangle) or ELG2309t (triangle)
%
% -------------------- Constants and fixed data --------------------------
npn = ep.nnodes;        % number of velocity/vorticity element nodes (4)
npd = ep.nndofs;        % number of vorticity DOFs at nodes (3); 
nn = ep.nn;           % defines local nodal order [-1 -1; 1 -1; 1 1; -1 1]
npdf=npn*npd; 
NP=1:npd; 
% ------------------------------------------------------------------------

persistent QQ_prMMp;       % quadrature rules
if isempty(QQ_prMMp) 
   QRord = (2*ep.mxpowr+1); % quadtature rule order 
  [QQ_prMMp.xa, QQ_prMMp.ya, QQ_prMMp.wt, QQ_prMMp.nq]=ep.hQuad(QRord);
end  % if isempty...
xa = QQ_prMMp.xa; ya = QQ_prMMp.ya; wt = QQ_prMMp.wt; Nq = QQ_prMMp.nq;
% ------------------------------------------------------------------------
persistent ZZ_Gpmm;        % pressure functions
if (isempty(ZZ_Gpmm)||size(ZZ_Gpmm,2)~=Nq)
% Evaluate and save/cache the set of shape functions at quadrature pts. 
  ZZ_Gpmm=cell(npn,Nq); 
  for k=1:Nq
    for m=1:npn
      ZZ_Gpmm{m,k}=ep.G(nn(m,:),xa(k),ya(k));
    end
  end
end  % if(isempty(*))
% ------------------------ end fixed data --------------------------------

TGi=cell(npn);
for m=1:npn   % Loop over corner nodes, GBL is gradient of bilinear fn
  J=(Xe*ep.Gm(nn(:,:),nn(m,1),nn(m,2)))'; %
  TGi{m} = blkdiag(1,J);
end  % Loop m 

MM=zeros(npdf,npdf);  G=zeros(2,npdf);   % Preallocate arrays
for k=1:Nq  
    
% Initialize functions and derivatives at the quadrature point (xa,ya).
  J=(Xe*ep.Gm(nn(:,:),xa(k),ya(k)))';    % Jacobian at (xa,ya)
  Det=J(1,1)*J(2,2)-J(1,2)*J(2,1);        % Determinant of Jt & J 
  Ji=[J(2,2),-J(1,2); -J(2,1),J(1,1)]/Det;
  for m=1:npn  
     mm=(m-1)*npd;
    G(:,mm+NP)=Ji*ZZ_Gpmm{m,k}*TGi{m};
  end  % loop m
  MM = MM + G'*G*(wt(k)*Det);
end        % end loop k (quadrature pts)

gf=zeros(npdf,1);           % array of global freedoms 
for n=1:npn             % Loop over element nodes 
   m=(n-1)*npd;
   gf(m+NP)=(nn2nftp(Elcon(n),1)-1)+NP; % Get global freedoms
end

Rndx=repmat(gf,1,npdf);     % Row indices
Cndx=Rndx';                % Column indices
 
MM = reshape(MM,1,npdf*npdf);
Rndx=reshape(Rndx,1,npdf*npdf);
Cndx=reshape(Cndx,1,npdf*npdf);   

return;

% *********************** funnction PCDat ******************************

function [PC,Rndx]=PCDat(Xe,Elcon,nn2nftp,Vdof,ep,eu)
% Evaluate convective force data 
% ep = handle to class of definitions for cubic pressure functions: 
%  ELG3412r (rectangle) or ELG2309t (triangle)
%
% ----------- Constants and fixed data ---------------

nvn = eu.nnodes;        % number of velocity element nodes   (4)
nvd = eu.nndofs;        % number of velocity DOFs at nodes (3|4|6); 
npd = ep.nndofs;        % number of vorticity DOFs at nodes (3);   
nn = eu.nn;            % defines local nodal order [-1 -1; 1 -1; 1 1; -1 1]
npdf=nvn*npd;  
nvdf=nvn*nvd;  
NP=1:npd;
NV=1:nvd;
% ------------------------------------------------------------------------
persistent QQ_prPCp;       % quadrature rules
if isempty(QQ_prPCp) 
   QRord = (eu.mxpowr+ep.mxpowr-1); % quadtature rule order 
  [QQ_prPCp.xa, QQ_prPCp.ya, QQ_prPCp.wt, QQ_prPCp.nq]=eu.hQuad(QRord);
end  % if isempty...
xa = QQ_prPCp.xa; ya = QQ_prPCp.ya; wt = QQ_prPCp.wt; Nq = QQ_prPCp.nq;
% ------------------------------------------------------------------------
persistent ZZ_Spcd; persistent ZZ_SXpcd; persistent ZZ_SYpcd; 
persistent ZZ_Gpcd;  
if (isempty(ZZ_Spcd)||isempty(ZZ_Gpcd)||size(ZZ_Spcd,2)~=Nq)
% Evaluate and save/cache the set of shape functions at quadrature pts. 
  ZZ_Spcd=cell(nvn,Nq); ZZ_SXpcd=cell(nvn,Nq); 
  ZZ_SYpcd=cell(nvn,Nq); ZZ_Gpcd=cell(nvn,Nq);  
  for k=1:Nq
    for m=1:nvn
      ZZ_Spcd{m,k} =eu.S(nn(m,:),xa(k),ya(k));
      [ZZ_SXpcd{m,k},ZZ_SYpcd{m,k}]=eu.DS(nn(m,:),xa(k),ya(k));
      ZZ_Gpcd{m,k}=ep.G(nn(m,:),xa(k),ya(k));
    end  % loop m over nodes  
  end  % loop k over Nq
end  % if(isempty(*))
% ----------------------- end fixed data ---------------------------------

Ti=cell(nvn);  TGi=cell(nvn);
for m=1:nvn   % Loop over corner nodes 
    Jt=Xe*eu.Gm(nn(:,:),nn(m,1),nn(m,2)); 
    JtiD=[Jt(2,2),-Jt(1,2); -Jt(2,1),Jt(1,1)];   % det(J)*inv(J)
  if nvd==3, 
    TT=blkdiag(1,JtiD);
  elseif nvd==4
    TT=blkdiag(1,JtiD,(Jt(1,1)*Jt(2,2)+Jt(1,2)*Jt(2,1)) );
  else
    T2=[Jt(1,1)^2, 2*Jt(1,1)*Jt(2,1), Jt(2,1)^2; ...  % alt
    Jt(1,1)*Jt(1,2), Jt(1,1)*Jt(2,2)+Jt(1,2)*Jt(2,1), Jt(2,1)*Jt(2,2); ...
    Jt(1,2)^2, 2*Jt(1,2)*Jt(2,2), Jt(2,2)^2];
    TT=blkdiag(1,JtiD,T2); 
    Bxy=Xe*eu.DGm(nn(:,:),nn(m,1),nn(m,2));  % Second cross derivatives
    TT(5,2)= Bxy(2);
    TT(5,3)=-Bxy(1);
  end
  Ti{m}=TT;
% 
%   J=[Jt(1,1),Jt(2,1); Jt(1,2),Jt(2,2)];   % evaluate J from transpose
   TGi{m} = blkdiag(1,Jt');
end  % Loop m over corner nodes

PC=zeros(npdf,1);
S=zeros(2,nvdf);  Sx=zeros(2,nvdf);  Sy=zeros(2,nvdf);  G=zeros(2,npdf);

for k=1:Nq      % Loop over quadrature points 
  Jt=Xe*eu.Gm(nn(:,:),xa(k),ya(k));    % transpose of Jacobian at (xa,ya)
  Det=Jt(1,1)*Jt(2,2)-Jt(1,2)*Jt(2,1);  % Determinant of Jt & J 
  Jtd=Jt/Det;
  JtiD=[Jt(2,2),-Jt(1,2); -Jt(2,1),Jt(1,1)];
  Jti=JtiD/Det;
  Ji=[Jti(1,1),Jti(2,1); Jti(1,2),Jti(2,2)]; 
  for m=1:nvn         % Loop over element nodes 
    mm=nvd*(m-1);
    S(:,mm+NV) =Jtd*ZZ_Spcd{m,k}*Ti{m};
    Sx(:,mm+NV)=Jtd*(Jti(1,1)*ZZ_SXpcd{m,k}+Jti(2,1)*ZZ_SYpcd{m,k})*Ti{m};
    Sy(:,mm+NV)=Jtd*(Jti(1,2)*ZZ_SXpcd{m,k}+Jti(2,2)*ZZ_SYpcd{m,k})*Ti{m};
     mm=npd*(m-1);
    G(:,mm+NP)=Ji*ZZ_Gpcd{m,k}*TGi{m}; 
  end    % end loop over element nodes
  
% Compute the fluid velocities at the quadrature point.
  U = S*Vdof(:);
  Ux = Sx*Vdof(:);
  Uy = Sy*Vdof(:);
  UgU = U(1)*Ux+U(2)*Uy;  % U dot grad U 
  
  PC = PC + G'*UgU*(wt(k)*Det);
end    % end loop over Nq quadrature points

gf=zeros(1,npdf);          % array of global freedoms 
for n=1:nvn            % Loop over element nodes 
   m=(n-1)*npd;
   gf(m+NP)=(nn2nftp(Elcon(n),1)-1)+NP; % Get global freedoms
end
Rndx=gf;
PC = reshape(PC,1,npdf);
return;
My wiki