bool ASMs3DLag::evalSolution (Matrix& sField, const IntegrandBase& integrand, const RealArray*, bool) const { sField.resize(0,0); const int p1 = svol->order(0); const int p2 = svol->order(1); const int p3 = svol->order(2); double incx = 2.0/double(p1-1); double incy = 2.0/double(p2-1); double incz = 2.0/double(p3-1); size_t nPoints = coord.size(); IntVec check(nPoints,0); FiniteElement fe(p1*p2*p3); Vector solPt; Vectors globSolPt(nPoints); Matrix dNdu, Xnod, Jac; // Evaluate the secondary solution field at each point const int nel = this->getNoElms(true); for (int iel = 1; iel <= nel; iel++) { const IntVec& mnpc = MNPC[iel-1]; this->getElementCoordinates(Xnod,iel); int i, j, k, loc = 0; for (k = 0; k < p3; k++) for (j = 0; j < p2; j++) for (i = 0; i < p1; i++, loc++) { fe.xi = -1.0 + i*incx; fe.eta = -1.0 + j*incy; fe.zeta = -1.0 + k*incz; if (!Lagrange::computeBasis(fe.N,dNdu,p1,fe.xi,p2,fe.eta,p3,fe.zeta)) return false; // Compute the Jacobian inverse fe.detJxW = utl::Jacobian(Jac,fe.dNdX,Xnod,dNdu); // Now evaluate the solution field if (!integrand.evalSol(solPt,fe,Xnod*fe.N,mnpc)) return false; else if (sField.empty()) sField.resize(solPt.size(),nPoints,true); if (++check[mnpc[loc]] == 1) globSolPt[mnpc[loc]] = solPt; else globSolPt[mnpc[loc]] += solPt; } } for (size_t i = 0; i < nPoints; i++) sField.fillColumn(1+i,globSolPt[i] /= check[i]); return true; }
bool ASMs2DSpec::evalSolution (Matrix& sField, const IntegrandBase& integrand, const RealArray*, bool) const { sField.resize(0,0); Vector wg1,xg1,wg2,xg2; if (!Legendre::GLL(wg1,xg1,p1)) return false; if (!Legendre::GLL(wg2,xg2,p2)) return false; Matrix D1, D2; if (!Legendre::basisDerivatives(p1,D1)) return false; if (!Legendre::basisDerivatives(p2,D2)) return false; size_t nPoints = this->getNoNodes(); IntVec check(nPoints,0); FiniteElement fe(p1*p2); Vector solPt; Vectors globSolPt(nPoints); Matrix dNdu(p1*p2,2), Xnod, Jac; // Evaluate the secondary solution field at each point const int nel = this->getNoElms(); for (int iel = 1; iel <= nel; iel++) { const IntVec& mnpc = MNPC[iel-1]; this->getElementCoordinates(Xnod,iel); int i, j, loc = 0; for (j = 0; j < p2; j++) for (i = 0; i < p1; i++, loc++) { evalBasis(i+1,j+1,p1,p2,D1,D2,fe.N,dNdu); // Compute the Jacobian inverse fe.detJxW = utl::Jacobian(Jac,fe.dNdX,Xnod,dNdu); // Now evaluate the solution field if (!integrand.evalSol(solPt,fe,Xnod.getColumn(loc+1),mnpc)) return false; else if (sField.empty()) sField.resize(solPt.size(),nPoints,true); if (++check[mnpc[loc]] == 1) globSolPt[mnpc[loc]] = solPt; else globSolPt[mnpc[loc]] += solPt; } } for (size_t i = 0; i < nPoints; i++) sField.fillColumn(1+i,globSolPt[i] /= check[i]); return true; }
bool ASMs1DSpec::evalSolution (Matrix& sField, const IntegrandBase& integrand, const RealArray*, bool) const { sField.resize(0,0); if (!curv) return false; const int p1 = curv->order(); Matrix D1; if (!Legendre::basisDerivatives(p1,D1)) return false; size_t nPoints = this->getNoNodes(); IntVec check(nPoints,0); FiniteElement fe(p1); Vector solPt; Vectors globSolPt(nPoints); Matrix dNdu(p1,1), Xnod, Jac; // Evaluate the secondary solution field at each point const int nel = this->getNoElms(); for (int iel = 1; iel <= nel; iel++) { const IntVec& mnpc = MNPC[iel-1]; this->getElementCoordinates(Xnod,iel); for (int i = 0; i < p1; i++) { fe.N.fill(0.0); fe.N(i+1) = 1.0; dNdu.fillColumn(1,D1.getRow(i+1)); // Compute the Jacobian inverse fe.detJxW = utl::Jacobian(Jac,fe.dNdX,Xnod,dNdu); // Now evaluate the solution field if (!integrand.evalSol(solPt,fe,Xnod.getColumn(i+1),mnpc)) return false; else if (sField.empty()) sField.resize(solPt.size(),nPoints,true); if (++check[mnpc[i]] == 1) globSolPt[mnpc[i]] = solPt; else globSolPt[mnpc[i]] += solPt; } } for (size_t i = 0; i < nPoints; i++) sField.fillColumn(1+i,globSolPt[i] /= check[i]); return true; }
bool ASMs1D::evalSolution (Matrix& sField, const IntegrandBase& integrand, const RealArray* gpar, bool) const { sField.resize(0,0); const int p1 = curv->order(); // Fetch nodal (control point) coordinates FiniteElement fe(p1,firstIp); this->getNodalCoordinates(fe.Xn); Vector solPt; Matrix dNdu, Jac, Xtmp; Matrix3D d2Ndu2, Hess; if (nsd > 1 && (integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES)) fe.G.resize(nsd,2); // For storing d{X}/du and d2{X}/du2 // Evaluate the secondary solution field at each point const RealArray& upar = *gpar; size_t nPoints = upar.size(); for (size_t i = 0; i < nPoints; i++, fe.iGP++) { fe.u = upar[i]; // Fetch basis function derivatives at current integration point if (integrand.getIntegrandType() & Integrand::NO_DERIVATIVES) this->extractBasis(fe.u,fe.N); else if (integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES) this->extractBasis(fe.u,fe.N,dNdu,d2Ndu2); else this->extractBasis(fe.u,fe.N,dNdu); // Fetch indices of the non-zero basis functions at this point IntVec ip; scatterInd(p1,curv->basis().lastKnotInterval(),ip); // Fetch associated control point coordinates utl::gather(ip,nsd,fe.Xn,Xtmp); if (!dNdu.empty()) { // Compute the Jacobian inverse and derivatives fe.detJxW = utl::Jacobian(Jac,fe.dNdX,Xtmp,dNdu); // Compute Hessian of coordinate mapping and 2nd order derivatives if (integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES) { if (!utl::Hessian(Hess,fe.d2NdX2,Jac,Xtmp,d2Ndu2,fe.dNdX)) continue; else if (fe.G.cols() == 2) { // Store the first and second derivatives of {X} w.r.t. // the parametric coordinate (xi), in the G-matrix fe.G.fillColumn(1,Jac.ptr()); fe.G.fillColumn(2,Hess.ptr()); } } } // Now evaluate the solution field if (!integrand.evalSol(solPt,fe,Xtmp*fe.N,ip)) return false; else if (sField.empty()) sField.resize(solPt.size(),nPoints,true); sField.fillColumn(1+i,solPt); } return true; }
bool ASMs3Dmx::evalSolution (Matrix& sField, const IntegrandBase& integrand, const RealArray* gpar, bool regular) const { sField.resize(0,0); if (m_basis.empty()) return false; // Evaluate the basis functions and their derivatives at all points std::vector<std::vector<Go::BasisDerivs>> splinex(m_basis.size()); if (regular) { for (size_t b = 0; b < m_basis.size(); ++b) m_basis[b]->computeBasisGrid(gpar[0],gpar[1],gpar[2],splinex[b]); } else if (gpar[0].size() == gpar[1].size() && gpar[0].size() == gpar[2].size()) { for (size_t b = 0; b < m_basis.size(); ++b) { splinex[b].resize(gpar[0].size()); for (size_t i = 0; i < splinex[b].size(); i++) m_basis[b]->computeBasis(gpar[0][i],gpar[1][i],gpar[2][i],splinex[b][i]); } } std::vector<size_t> elem_sizes; for (auto& it : m_basis) elem_sizes.push_back(it->order(0)*it->order(1)*it->order(2)); // Fetch nodal (control point) coordinates Matrix Xnod, Xtmp; this->getNodalCoordinates(Xnod); MxFiniteElement fe(elem_sizes,firstIp); Vector solPt; std::vector<Matrix> dNxdu(m_basis.size()); Matrix Jac; Vec3 X; // Evaluate the secondary solution field at each point size_t nPoints = splinex[0].size(); for (size_t i = 0; i < nPoints; i++, fe.iGP++) { // Fetch indices of the non-zero basis functions at this point std::vector<IntVec> ip(m_basis.size()); IntVec ipa; size_t ofs = 0; for (size_t b = 0; b < m_basis.size(); ++b) { scatterInd(m_basis[b]->numCoefs(0),m_basis[b]->numCoefs(1),m_basis[b]->numCoefs(2), m_basis[b]->order(0),m_basis[b]->order(1),m_basis[b]->order(2), splinex[b][i].left_idx,ip[b]); // Fetch associated control point coordinates if (b == (size_t)geoBasis-1) utl::gather(ip[geoBasis-1], 3, Xnod, Xtmp); for (auto& it : ip[b]) it += ofs; ipa.insert(ipa.end(), ip[b].begin(), ip[b].end()); ofs += nb[b]; } fe.u = splinex[0][i].param[0]; fe.v = splinex[0][i].param[1]; fe.w = splinex[0][i].param[2]; // Fetch basis function derivatives at current integration point for (size_t b = 0; b < m_basis.size(); ++b) SplineUtils::extractBasis(splinex[b][i],fe.basis(b+1),dNxdu[b]); // Compute Jacobian inverse of the coordinate mapping and // basis function derivatives w.r.t. Cartesian coordinates fe.detJxW = utl::Jacobian(Jac,fe.grad(geoBasis),Xtmp,dNxdu[geoBasis-1]); for (size_t b = 1; b <= m_basis.size(); b++) if (b != (size_t)geoBasis) { if (fe.detJxW == 0.0) fe.grad(b).clear(); else fe.grad(b).multiply(dNxdu[b-1],Jac); } // Cartesian coordinates of current integration point X = Xtmp * fe.basis(geoBasis); // Now evaluate the solution field if (!integrand.evalSol(solPt,fe,X,ipa,elem_sizes,nb)) return false; else if (sField.empty()) sField.resize(solPt.size(),nPoints,true); sField.fillColumn(1+i,solPt); } return true; }
bool ASMu2D::globalL2projection (Matrix& sField, const IntegrandBase& integrand, bool continuous) const { if (!lrspline) return true; // silently ignore empty patches PROFILE2("ASMu2D::globalL2"); const int p1 = lrspline->order(0); const int p2 = lrspline->order(1); // Get Gaussian quadrature points const int ng1 = continuous ? nGauss : p1 - 1; const int ng2 = continuous ? nGauss : p2 - 1; const double* xg = GaussQuadrature::getCoord(ng1); const double* yg = GaussQuadrature::getCoord(ng2); const double* wg = continuous ? GaussQuadrature::getWeight(nGauss) : nullptr; if (!xg || !yg) return false; if (continuous && !wg) return false; // Set up the projection matrices const size_t nnod = this->getNoNodes(); const size_t ncomp = integrand.getNoFields(); SparseMatrix A(SparseMatrix::SUPERLU); StdVector B(nnod*ncomp); A.redim(nnod,nnod); double dA = 0.0; Vector phi; Matrix dNdu, Xnod, Jac; Go::BasisDerivsSf spl1; Go::BasisPtsSf spl0; // === Assembly loop over all elements in the patch ========================== std::vector<LR::Element*>::iterator el = lrspline->elementBegin(); for (int iel = 1; el != lrspline->elementEnd(); el++, iel++) { if (continuous) { // Set up control point (nodal) coordinates for current element if (!this->getElementCoordinates(Xnod,iel)) return false; else if ((dA = 0.25*this->getParametricArea(iel)) < 0.0) return false; // topology error (probably logic error) } // Compute parameter values of the Gauss points over this element std::array<RealArray,2> gpar, unstrGpar; this->getGaussPointParameters(gpar[0],0,ng1,iel,xg); this->getGaussPointParameters(gpar[1],1,ng2,iel,yg); // convert to unstructred mesh representation expandTensorGrid(gpar.data(),unstrGpar.data()); // Evaluate the secondary solution at all integration points if (!this->evalSolution(sField,integrand,unstrGpar.data())) return false; // set up basis function size (for extractBasis subroutine) phi.resize((**el).nBasisFunctions()); // --- Integration loop over all Gauss points in each direction ---------- int ip = 0; for (int j = 0; j < ng2; j++) for (int i = 0; i < ng1; i++, ip++) { if (continuous) { lrspline->computeBasis(gpar[0][i],gpar[1][j],spl1,iel-1); SplineUtils::extractBasis(spl1,phi,dNdu); } else { lrspline->computeBasis(gpar[0][i],gpar[1][j],spl0,iel-1); phi = spl0.basisValues; } // Compute the Jacobian inverse and derivatives double dJw = 1.0; if (continuous) { dJw = dA*wg[i]*wg[j]*utl::Jacobian(Jac,dNdu,Xnod,dNdu,false); if (dJw == 0.0) continue; // skip singular points } // Integrate the linear system A*x=B for (size_t ii = 0; ii < phi.size(); ii++) { int inod = MNPC[iel-1][ii]+1; for (size_t jj = 0; jj < phi.size(); jj++) { int jnod = MNPC[iel-1][jj]+1; A(inod,jnod) += phi[ii]*phi[jj]*dJw; } for (size_t r = 1; r <= ncomp; r++) B(inod+(r-1)*nnod) += phi[ii]*sField(r,ip+1)*dJw; } } } #if SP_DEBUG > 2 std::cout <<"---- Matrix A -----"<< A <<"-------------------"<< std::endl; std::cout <<"---- Vector B -----"<< B <<"-------------------"<< std::endl; #endif // Solve the patch-global equation system if (!A.solve(B)) return false; // Store the control-point values of the projected field sField.resize(ncomp,nnod); for (size_t i = 1; i <= nnod; i++) for (size_t j = 1; j <= ncomp; j++) sField(j,i) = B(i+(j-1)*nnod); return true; }
bool ASMs2DmxLag::evalSolution (Matrix& sField, const IntegrandBase& integrand, const RealArray*, bool) const { sField.resize(0,0); double incx = 2.0/double(p1-1); double incy = 2.0/double(p2-1); size_t nPoints = nb[0]; IntVec check(nPoints,0); MxFiniteElement fe(elem_size); Vector solPt; Vectors globSolPt(nPoints); Matrices dNxdu(nxx.size()); Matrix Xnod, Jac; // Evaluate the secondary solution field at each point for (size_t iel = 1; iel <= nel; iel++) { IntVec::const_iterator f2start = geoBasis == 1? MNPC[iel-1].begin() : MNPC[iel-1].begin() + std::accumulate(elem_size.begin()+geoBasis-2, elem_size.begin()+geoBasis-1, 0); IntVec::const_iterator f2end = f2start + elem_size[geoBasis-1]; IntVec mnpc1(f2start,f2end); this->getElementCoordinates(Xnod,iel); int i, j, loc = 0; for (j = 0; j < p2; j++) for (i = 0; i < p1; i++, loc++) { double xi = -1.0 + i*incx; double eta = -1.0 + j*incy; for (size_t b = 0; b < nxx.size(); ++b) if (!Lagrange::computeBasis(fe.basis(b+1),dNxdu[b],elem_sizes[b][0],xi, elem_sizes[b][1],eta)) return false; // Compute the Jacobian inverse fe.detJxW = utl::Jacobian(Jac,fe.grad(geoBasis),Xnod,dNxdu[geoBasis-1]); for (size_t b = 1; b <= nxx.size(); b++) if (b != (size_t)geoBasis) { if (fe.detJxW == 0.0) fe.grad(b).clear(); else fe.grad(b).multiply(dNxdu[b-1],Jac); } // Now evaluate the solution field if (!integrand.evalSol(solPt,fe,Xnod*fe.basis(geoBasis),MNPC[iel-1],elem_size,nb)) return false; else if (sField.empty()) sField.resize(solPt.size(),nPoints,true); if (++check[mnpc1[loc]] == 1) globSolPt[mnpc1[loc]] = solPt; else globSolPt[mnpc1[loc]] += solPt; } } for (size_t i = 0; i < nPoints; i++) sField.fillColumn(1+i,globSolPt[i] /= check[i]); return true; }