// ATC header files #include "ATC_Error.h" #include "FE_Element.h" #include "FE_Mesh.h" // Other headers #include "math.h" namespace ATC { // ------------------------------------------------------------- // ------------------------------------------------------------- // class FE_Element // ------------------------------------------------------------- // ------------------------------------------------------------- FE_Element::FE_Element(FE_Mesh * feMesh, int nSD, int numEltNodes, int numIPs, int numFaces, int numFaceNodes, int numFaceIPs) : feMesh_(feMesh), nSD_(nSD), numEltNodes_(numEltNodes), numIPs_(numIPs), numFaces_(numFaces), numFaceNodes_(numFaceNodes), numFaceIPs_(numFaceIPs), localCoords_(nSD,numEltNodes), ipCoords_(nSD,numIPs), N_(numIPs,numEltNodes), ipWeights_(numIPs), localFaceConn_(numFaces,numFaceNodes), ipFace2DCoords_(nSD-1,numFaceIPs), ipFaceCoords_(numFaces), // localFaceCoords_(nSD-1,numFaceNodes), NFace_(numFaces), ipFaceWeights_(numFaceIPs) { for (int f = 0; f < numFaces; f++) { ipFaceCoords_[f].reset(nSD,numFaceIPs); NFace_[f].reset(numFaceIPs,numEltNodes); } } FE_Element::~FE_Element() { // Nothing else to do } // ------------------------------------------------------------- // ------------------------------------------------------------- // class FE_ElementHex // ------------------------------------------------------------- // ------------------------------------------------------------- FE_ElementHex::FE_ElementHex(FE_Mesh * feMesh) : FE_Element(feMesh, 3, 8, 8, 6, 4, 4) { // Matrix of local nodal coordinates localCoords_(0,0) = -1; localCoords_(1,0) = -1; localCoords_(2,0) = -1; localCoords_(0,1) = +1; localCoords_(1,1) = -1; localCoords_(2,1) = -1; localCoords_(0,2) = +1; localCoords_(1,2) = +1; localCoords_(2,2) = -1; localCoords_(0,3) = -1; localCoords_(1,3) = +1; localCoords_(2,3) = -1; localCoords_(0,4) = -1; localCoords_(1,4) = -1; localCoords_(2,4) = +1; localCoords_(0,5) = +1; localCoords_(1,5) = -1; localCoords_(2,5) = +1; localCoords_(0,6) = +1; localCoords_(1,6) = +1; localCoords_(2,6) = +1; localCoords_(0,7) = -1; localCoords_(1,7) = +1; localCoords_(2,7) = +1; // 3 --- 2 // /| /| // / 0 --/ 1 y // 7 --- 6 / | // | |/ | // 4 --- 5 ---> x // / // / // z // Matrix of local face connectivity // -x localFaceConn_(0,0) = 0; localFaceConn_(0,1) = 4; localFaceConn_(0,2) = 7; localFaceConn_(0,3) = 3; // +x localFaceConn_(1,0) = 1; localFaceConn_(1,1) = 2; localFaceConn_(1,2) = 6; localFaceConn_(1,3) = 5; // -y localFaceConn_(2,0) = 0; localFaceConn_(2,1) = 1; localFaceConn_(2,2) = 5; localFaceConn_(2,3) = 4; // +y localFaceConn_(3,0) = 2; localFaceConn_(3,1) = 3; localFaceConn_(3,2) = 7; localFaceConn_(3,3) = 6; // -z localFaceConn_(4,0) = 0; localFaceConn_(4,1) = 3; localFaceConn_(4,2) = 2; localFaceConn_(4,3) = 1; // +z localFaceConn_(5,0) = 4; localFaceConn_(5,1) = 5; localFaceConn_(5,2) = 6; localFaceConn_(5,3) = 7; /* localFaceCoords_(0,0) = -1; localFaceCoords_(1,0) = -1; localFaceCoords_(0,1) = +1; localFaceCoords_(1,1) = -1; localFaceCoords_(0,2) = +1; localFaceCoords_(1,2) = +1; localFaceCoords_(0,3) = -1; localFaceCoords_(1,3) = +1; */ set_quadrature(GAUSSIAN_QUADRATURE); } //----------------------------------------------------------------- void FE_ElementHex::set_quadrature(int quadrature) { double a = 1./sqrt(3.); if (quadrature == NODAL_QUADRATURE) { a = 1.0; } // Matrix of integration point locations (Gaussian) & follows local conn ipCoords_(0,0) = -a; ipCoords_(1,0) = -a; ipCoords_(2,0) = -a; ipCoords_(0,1) = +a; ipCoords_(1,1) = -a; ipCoords_(2,1) = -a; ipCoords_(0,2) = +a; ipCoords_(1,2) = +a; ipCoords_(2,2) = -a; ipCoords_(0,3) = -a; ipCoords_(1,3) = +a; ipCoords_(2,3) = -a; ipCoords_(0,4) = -a; ipCoords_(1,4) = -a; ipCoords_(2,4) = +a; ipCoords_(0,5) = +a; ipCoords_(1,5) = -a; ipCoords_(2,5) = +a; ipCoords_(0,6) = +a; ipCoords_(1,6) = +a; ipCoords_(2,6) = +a; ipCoords_(0,7) = -a; ipCoords_(1,7) = +a; ipCoords_(2,7) = +a; // Compute shape functions at ip's for (int ip = 0; ip < numIPs_; ip++) { double r = ipCoords_(0, ip); double s = ipCoords_(1, ip); double t = ipCoords_(2, ip); for (int iNode = 0; iNode < numEltNodes_; iNode++) { double rI = localCoords_(0, iNode); double sI = localCoords_(1, iNode); double tI = localCoords_(2, iNode); N_(ip, iNode) = 0.125 * (1 + r*rI) * (1 + s*sI) * (1 + t*tI); } } // Integration point weights ipWeights_ = 1.0; // integration points by face ipFace2DCoords_(0,0)=-a; ipFace2DCoords_(1,0)=-a; ipFace2DCoords_(0,1)= a; ipFace2DCoords_(1,1)=-a; ipFace2DCoords_(0,2)= a; ipFace2DCoords_(1,2)= a; ipFace2DCoords_(0,3)=-a; ipFace2DCoords_(1,3)= a; ipFaceCoords_[0](0,0)=-1;ipFaceCoords_[0](1,0)=-a;ipFaceCoords_[0](2,0)=-a; ipFaceCoords_[0](0,1)=-1;ipFaceCoords_[0](1,1)= a;ipFaceCoords_[0](2,1)=-a; ipFaceCoords_[0](0,2)=-1;ipFaceCoords_[0](1,2)= a;ipFaceCoords_[0](2,2)= a; ipFaceCoords_[0](0,3)=-1;ipFaceCoords_[0](1,3)=-a;ipFaceCoords_[0](2,3)= a; ipFaceCoords_[1](0,0)= 1;ipFaceCoords_[1](1,0)=-a;ipFaceCoords_[1](2,0)=-a; ipFaceCoords_[1](0,1)= 1;ipFaceCoords_[1](1,1)= a;ipFaceCoords_[1](2,1)=-a; ipFaceCoords_[1](0,2)= 1;ipFaceCoords_[1](1,2)= a;ipFaceCoords_[1](2,2)= a; ipFaceCoords_[1](0,3)= 1;ipFaceCoords_[1](1,3)=-a;ipFaceCoords_[1](2,3)= a; ipFaceCoords_[2](0,0)=-a;ipFaceCoords_[2](1,0)=-1;ipFaceCoords_[2](2,0)=-a; ipFaceCoords_[2](0,1)=-a;ipFaceCoords_[2](1,1)=-1;ipFaceCoords_[2](2,1)= a; ipFaceCoords_[2](0,2)= a;ipFaceCoords_[2](1,2)=-1;ipFaceCoords_[2](2,2)= a; ipFaceCoords_[2](0,3)= a;ipFaceCoords_[2](1,3)=-1;ipFaceCoords_[2](2,3)=-a; ipFaceCoords_[3](0,0)=-a;ipFaceCoords_[3](1,0)= 1;ipFaceCoords_[3](2,0)=-a; ipFaceCoords_[3](0,1)=-a;ipFaceCoords_[3](1,1)= 1;ipFaceCoords_[3](2,1)= a; ipFaceCoords_[3](0,2)= a;ipFaceCoords_[3](1,2)= 1;ipFaceCoords_[3](2,2)= a; ipFaceCoords_[3](0,3)= a;ipFaceCoords_[3](1,3)= 1;ipFaceCoords_[2](2,3)=-a; ipFaceCoords_[4](0,0)=-a;ipFaceCoords_[4](1,0)=-a;ipFaceCoords_[4](2,0)=-1; ipFaceCoords_[4](0,1)= a;ipFaceCoords_[4](1,1)=-a;ipFaceCoords_[4](2,1)=-1; ipFaceCoords_[4](0,2)= a;ipFaceCoords_[4](1,2)= a;ipFaceCoords_[4](2,2)=-1; ipFaceCoords_[4](0,3)=-a;ipFaceCoords_[4](1,3)= a;ipFaceCoords_[4](2,3)=-1; ipFaceCoords_[5](0,0)=-a;ipFaceCoords_[5](1,0)=-a;ipFaceCoords_[5](2,0)= 1; ipFaceCoords_[5](0,1)= a;ipFaceCoords_[5](1,1)=-a;ipFaceCoords_[5](2,1)= 1; ipFaceCoords_[5](0,2)= a;ipFaceCoords_[5](1,2)= a;ipFaceCoords_[5](2,2)= 1; ipFaceCoords_[5](0,3)=-a;ipFaceCoords_[5](1,3)= a;ipFaceCoords_[5](2,3)= 1; // Compute shape functions at ip's for (int f = 0; f < numFaces_; f++) { for (int ip = 0; ip < numFaceIPs_; ip++) { double r = ipFaceCoords_[f](0, ip); double s = ipFaceCoords_[f](1, ip); double t = ipFaceCoords_[f](2, ip); for (int iNode = 0; iNode < numEltNodes_; iNode++) { double rI = localCoords_(0, iNode); double sI = localCoords_(1, iNode); double tI = localCoords_(2, iNode); NFace_[f](ip, iNode) = 0.125 * (1 + r*rI) * (1 + s*sI) * (1 + t*tI); } } } // integration points ipFaceWeights_ = 1.0; } FE_ElementHex::~FE_ElementHex() { // Nothing to do here } // ------------------------------------------------------------- // shape_function // ------------------------------------------------------------- void FE_ElementHex::shape_function(const int eltID, DENS_MAT &N, vector &dN, DIAG_MAT &weights) { // Get element node coordinates from mesh DENS_MAT xCoords; feMesh_->element_coordinates(eltID, xCoords); // Transpose xCoords DENS_MAT xCoordsT(transpose(xCoords)); // Shape functions are simply the canonical element values N = N_; // Set sizes of matrices and vectors if ((int)dN.size() != nSD_) dN.resize(nSD_); for (int isd = 0; isd < nSD_; isd++) dN[isd].resize(numIPs_, numEltNodes_); weights.resize(numIPs_,numIPs_); // Create some temporary matrices: // Shape function deriv.'s w.r.t. element coords DENS_MAT dNdr(nSD_, numEltNodes_, false); // Jacobian matrix: [dx/dr dy/ds dz/dt | dx/ds ... ] DENS_MAT dxdr, drdx, dNdx; // Loop over integration points for (int ip = 0; ip < numIPs_; ip++) { const double &r = ipCoords_(0,ip); const double &s = ipCoords_(1,ip); const double &t = ipCoords_(2,ip); // Fill dNdr for (int inode = 0; inode < numEltNodes_; inode++) { const double &rI = localCoords_(0,inode); const double &sI = localCoords_(1,inode); const double &tI = localCoords_(2,inode); dNdr(0,inode) = 0.125 * rI * (1 + s*sI) * (1 + t*tI); dNdr(1,inode) = 0.125 * sI * (1 + r*rI) * (1 + t*tI); dNdr(2,inode) = 0.125 * tI * (1 + r*rI) * (1 + s*sI); } // Compute dx/dxi matrix dxdr = dNdr * xCoordsT; drdx = inv(dxdr); // Compute dNdx and fill dN matrix dNdx = drdx*dNdr; for (int isd = 0; isd < nSD_; isd++) for (int inode = 0; inode < numEltNodes_; inode++) dN[isd](ip,inode) = dNdx(isd,inode); // Compute jacobian determinant of dxdr at this ip double J = dxdr(0,0) * ( dxdr(1,1)*dxdr(2,2) - dxdr(2,1)*dxdr(1,2) ) - dxdr(0,1) * ( dxdr(1,0)*dxdr(2,2) - dxdr(1,2)*dxdr(2,0) ) + dxdr(0,2) * ( dxdr(1,0)*dxdr(2,1) - dxdr(1,1)*dxdr(2,0) ); // Compute ip weight weights(ip,ip) = ipWeights_(ip)*J; } } //----------------------------------------------------------------- void FE_ElementHex::shape_function(const int eltID, const VECTOR &xi, DENS_VEC &N) { N.resize(numEltNodes_); for (int inode = 0; inode < numEltNodes_; ++inode) { double shp = 0.125; for (int i = 0; i < nSD_; ++i) shp *= (1 + xi(i)*localCoords_(i, inode)); N(inode) = shp; } } //----------------------------------------------------------------- void FE_ElementHex::shape_function(const int eltID, const VECTOR &xi, DENS_VEC &N, DENS_MAT &dNdx) { N.resize(numEltNodes_); // Get element node coordinates from mesh DENS_MAT xCoords; feMesh_->element_coordinates(eltID, xCoords); DENS_MAT xCoordsT = transpose(xCoords); DENS_MAT dNdr(3,8,false), dxdr(3,3,false), drdx; double r = xi(0); double s = xi(1); double t = xi(2); for (int inode = 0; inode < numEltNodes_; ++inode) { double rI = localCoords_(0,inode); double sI = localCoords_(1,inode); double tI = localCoords_(2,inode); // Shape function N(inode) = 0.125 * (1.0 + r*rI) * (1.0 + s*sI) * (1.0 + t*tI); // Shape function derivative wrt (r,s,t) dNdr(0,inode) = 0.125 * rI * (1.0 + s*sI) * (1.0 + t*tI); dNdr(1,inode) = 0.125 * sI * (1.0 + r*rI) * (1.0 + t*tI); dNdr(2,inode) = 0.125 * tI * (1.0 + r*rI) * (1.0 + s*sI); } // Derivatives wrt (x,y,z) dxdr = dNdr * xCoordsT; drdx = inv(dxdr); dNdx = drdx*dNdr; } //----------------------------------------------------------------- void FE_ElementHex::face_shape_function(const PAIR & face, DENS_MAT &N, vector &dN, vector &Nn, DIAG_MAT &weights) { int eltID = face.first; int local_faceID = face.second; // const double * face_normal = face.normal(); // double * normal = face_normal; DENS_VEC normal(nSD_); // Get element node coordinates from mesh DENS_MAT xCoords; feMesh_->element_coordinates(eltID, xCoords); // Transpose xCoords DENS_MAT xCoordsT = transpose(xCoords); // Shape functions are simply the canonical element values N.reset(numFaceIPs_, numEltNodes_); N = NFace_[local_faceID]; // Set sizes of matrices and vectors if ((int)dN.size() != nSD_) dN.resize(nSD_); for (int isd = 0; isd < nSD_; isd++) dN[isd].reset(numFaceIPs_, numEltNodes_); weights.reset(numFaceIPs_,numFaceIPs_); // Create some temporary matrices: // Shape function deriv.'s w.r.t. element coords DENS_MAT dNdr(nSD_, numEltNodes_); // Jacobian matrix: [dx/dr dy/ds dz/dt | dx/ds ... ] DENS_MAT dxdr, drdx, dNdx; // Loop over integration points for (int ip = 0; ip < numFaceIPs_; ip++) { double r = ipFaceCoords_[local_faceID](0,ip); double s = ipFaceCoords_[local_faceID](1,ip); double t = ipFaceCoords_[local_faceID](2,ip); // Fill dNdr for (int inode = 0; inode < numEltNodes_; inode++) { double rI = localCoords_(0,inode); double sI = localCoords_(1,inode); double tI = localCoords_(2,inode); dNdr(0,inode) = 0.125 * rI * (1 + s*sI) * (1 + t*tI); dNdr(1,inode) = 0.125 * sI * (1 + r*rI) * (1 + t*tI); dNdr(2,inode) = 0.125 * tI * (1 + r*rI) * (1 + s*sI); } // Compute dx/dxi matrix dxdr = dNdr * xCoordsT; drdx = inv(dxdr); // Compute 2d jacobian determinant of dxdr at this ip double J = face_normal(face, ip, normal); // Compute dNdx and fill dN matrix dNdx = drdx*dNdr; for (int isd = 0; isd < nSD_; isd++) { for (int inode = 0; inode < numEltNodes_; inode++) { dN[isd](ip,inode) = dNdx(isd,inode); Nn[isd](ip,inode) = N(ip,inode)*normal(isd); } } // Compute ip weight weights(ip,ip) = ipFaceWeights_(ip)*J; } } //----------------------------------------------------------------- void FE_ElementHex::face_shape_function(const PAIR & face, DENS_MAT &N, DENS_MAT &n, DIAG_MAT &weights) { int eltID = face.first; int local_faceID = face.second; // const double * face_normal = face.normal(); // double * normal = face_normal; DENS_VEC normal(nSD_); // Get element node coordinates from mesh DENS_MAT xCoords; feMesh_->element_coordinates(eltID, xCoords); // Transpose xCoords DENS_MAT xCoordsT = transpose(xCoords); // Shape functions are simply the canonical element values N.reset(numFaceIPs_, numEltNodes_); N = NFace_[local_faceID]; weights.reset(numFaceIPs_,numFaceIPs_); // Create some temporary matrices: // Shape function deriv.'s w.r.t. element coords DENS_MAT dNdr(nSD_, numEltNodes_); // Jacobian matrix: [dx/dr dy/ds dz/dt | dx/ds ... ] DENS_MAT dxdr, drdx, dNdx; // Loop over integration points for (int ip = 0; ip < numFaceIPs_; ip++) { double r = ipFaceCoords_[local_faceID](0,ip); double s = ipFaceCoords_[local_faceID](1,ip); double t = ipFaceCoords_[local_faceID](2,ip); // Compute 2d jacobian determinant of dxdr at this ip double J = face_normal(face, ip, normal); // Copy normal at integration point for (int isd = 0; isd < nSD_; isd++) { n(isd,ip) = normal(isd); } // Compute ip weight weights(ip,ip) = ipFaceWeights_(ip)*J; } } // ------------------------------------------------------------- // face_normal // ------------------------------------------------------------- double FE_ElementHex::face_normal(const PAIR & face, int ip, DENS_VEC &normal) { // Get element node coordinates from mesh DENS_MAT xCoords; feMesh_->face_coordinates(face, xCoords); // Transpose xCoords DENS_MAT xCoordsT = transpose(xCoords); double r = ipFace2DCoords_(0,ip); double s = ipFace2DCoords_(1,ip); DENS_MAT dNdr(nSD_-1, numFaceNodes_); for (int inode = 0; inode < numFaceNodes_; inode++) { double rI = localCoords_(0,inode); // NOTE a little dangerous double sI = localCoords_(1,inode); dNdr(0,inode) = 0.25 * rI * (1 + s*sI); dNdr(1,inode) = 0.25 * sI * (1 + r*rI); } DENS_MAT dxdr(2,3); // Compute dx/dxi matrix dxdr = dNdr * xCoordsT; normal(0) = dxdr(0,1)*dxdr(1,2) - dxdr(0,2)*dxdr(1,1) ; normal(1) = dxdr(0,2)*dxdr(1,0) - dxdr(0,0)*dxdr(1,2) ; normal(2) = dxdr(0,0)*dxdr(1,1) - dxdr(0,1)*dxdr(1,0) ; double J = sqrt(normal(0)*normal(0)+normal(1)*normal(1)+normal(2)*normal(2)); // double inv_J = normal_sense(face)/J; double inv_J = 1.0/J; normal(0) *= inv_J; normal(1) *= inv_J; normal(2) *= inv_J; return J; } }; // namespace ATC_Transfer