bool ASMs3Dmx::integrate (Integrand& integrand, GlobalIntegral& glInt, const TimeDomain& time) { if (!svol) return true; // silently ignore empty patches if (m_basis.empty()) return false; PROFILE2("ASMs3Dmx::integrate(I)"); bool use2ndDer = integrand.getIntegrandType() & Integrand::SECOND_DERIVATIVES; bool useElmVtx = integrand.getIntegrandType() & Integrand::ELEMENT_CORNERS; // Get Gaussian quadrature points and weights const double* xg = GaussQuadrature::getCoord(nGauss); const double* wg = GaussQuadrature::getWeight(nGauss); if (!xg || !wg) return false; // Compute parameter values of the Gauss points over the whole patch std::array<Matrix,3> gpar; for (int d = 0; d < 3; d++) this->getGaussPointParameters(gpar[d],d,nGauss,xg); // Evaluate basis function derivatives at all integration points std::vector<std::vector<Go::BasisDerivs>> splinex(m_basis.size()); std::vector<std::vector<Go::BasisDerivs2>> splinex2(m_basis.size()); if (use2ndDer) { #pragma omp parallel for schedule(static) for (size_t i=0;i<m_basis.size();++i) m_basis[i]->computeBasisGrid(gpar[0],gpar[1],gpar[2],splinex2[i]); } else { #pragma omp parallel for schedule(static) for (size_t i=0;i<m_basis.size();++i) m_basis[i]->computeBasisGrid(gpar[0],gpar[1],gpar[2],splinex[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)); const int p1 = svol->order(0); const int p2 = svol->order(1); const int p3 = svol->order(2); const int n1 = svol->numCoefs(0); const int n2 = svol->numCoefs(1); const int n3 = svol->numCoefs(2); const int nel1 = n1 - p1 + 1; const int nel2 = n2 - p2 + 1; const int nel3 = n3 - p3 + 1; // === Assembly loop over all elements in the patch ========================== bool ok=true; for (size_t g=0;g<threadGroupsVol.size() && ok;++g) { #pragma omp parallel for schedule(static) for (size_t t=0;t<threadGroupsVol[g].size();++t) { MxFiniteElement fe(elem_sizes); std::vector<Matrix> dNxdu(m_basis.size()); std::vector<Matrix3D> d2Nxdu2(m_basis.size()); Matrix3D Hess; double dXidu[3]; Matrix Xnod, Jac; Vec4 X; for (size_t l = 0; l < threadGroupsVol[g][t].size() && ok; ++l) { int iel = threadGroupsVol[g][t][l]; fe.iel = MLGE[iel]; if (fe.iel < 1) continue; // zero-volume element int i1 = p1 + iel % nel1; int i2 = p2 + (iel / nel1) % nel3; int i3 = p3 + iel / (nel1*nel2); // Get element volume in the parameter space double dV = this->getParametricVolume(++iel); if (dV < 0.0) // topology error (probably logic error) { ok = false; break; } // Set up control point (nodal) coordinates for current element if (!this->getElementCoordinates(Xnod,iel)) { ok = false; break; } if (useElmVtx) this->getElementCorners(i1-1,i2-1,i3-1,fe.XC); if (integrand.getIntegrandType() & Integrand::G_MATRIX) { // Element size in parametric space dXidu[0] = svol->knotSpan(0,i1-1); dXidu[1] = svol->knotSpan(1,i2-1); dXidu[2] = svol->knotSpan(2,i3-1); } // Initialize element quantities LocalIntegral* A = integrand.getLocalIntegral(elem_sizes,fe.iel,false); if (!integrand.initElement(MNPC[iel-1],elem_sizes,nb,*A)) { A->destruct(); ok = false; break; } // --- Integration loop over all Gauss points in each direction -------- int ip = (((i3-p3)*nGauss*nel2 + i2-p2)*nGauss*nel1 + i1-p1)*nGauss; int jp = (((i3-p3)*nel2 + i2-p2*nel1 + i1-p1))*nGauss*nGauss*nGauss; fe.iGP = firstIp + jp; // Global integration point counter for (int k = 0; k < nGauss; k++, ip += nGauss*(nel2-1)*nGauss*nel1) for (int j = 0; j < nGauss; j++, ip += nGauss*(nel1-1)) for (int i = 0; i < nGauss; i++, ip++, fe.iGP++) { // Local element coordinates of current integration point fe.xi = xg[i]; fe.eta = xg[j]; fe.zeta = xg[k]; // Parameter values of current integration point fe.u = gpar[0](i+1,i1-p1+1); fe.v = gpar[1](j+1,i2-p2+1); fe.w = gpar[2](k+1,i3-p3+1); // Fetch basis function derivatives at current integration point if (use2ndDer) { for (size_t b = 0; b < m_basis.size(); ++b) SplineUtils::extractBasis(splinex2[b][ip],fe.basis(b+1),dNxdu[b], d2Nxdu2[b]); } else { for (size_t b = 0; b < m_basis.size(); ++b) SplineUtils::extractBasis(splinex[b][ip],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),Xnod, dNxdu[geoBasis-1]); if (fe.detJxW == 0.0) continue; // skip singular points for (size_t b = 0; b < m_basis.size(); ++b) if (b != (size_t)geoBasis-1) fe.grad(b+1).multiply(dNxdu[b],Jac); // Compute Hessian of coordinate mapping and 2nd order derivatives if (use2ndDer) { if (!utl::Hessian(Hess,fe.hess(geoBasis),Jac,Xnod, d2Nxdu2[geoBasis-1],fe.grad(geoBasis),true)) ok = false; for (size_t b = 0; b < m_basis.size() && ok; ++b) if ((int)b != geoBasis) if (!utl::Hessian(Hess,fe.hess(b+1),Jac,Xnod, d2Nxdu2[b],fe.grad(b+1),false)) ok = false; } // Compute G-matrix if (integrand.getIntegrandType() & Integrand::G_MATRIX) utl::getGmat(Jac,dXidu,fe.G); // Cartesian coordinates of current integration point X = Xnod * fe.basis(geoBasis); X.t = time.t; // Evaluate the integrand and accumulate element contributions fe.detJxW *= 0.125*dV*wg[i]*wg[j]*wg[k]; if (!integrand.evalIntMx(*A,fe,time,X)) ok = false; } // Finalize the element quantities if (ok && !integrand.finalizeElement(*A,time,firstIp+jp)) ok = false; // Assembly of global system integral if (ok && !glInt.assemble(A->ref(),fe.iel)) ok = false; A->destruct(); } } } return ok; }
bool ASMs2DmxLag::integrate (Integrand& integrand, GlobalIntegral& glInt, const TimeDomain& time) { if (this->empty()) return true; // silently ignore empty patches // Get Gaussian quadrature points and weights const double* xg = GaussQuadrature::getCoord(nGauss); const double* wg = GaussQuadrature::getWeight(nGauss); if (!xg || !wg) return false; // Get parametric coordinates of the elements RealArray upar, vpar; this->getGridParameters(upar,0,1); this->getGridParameters(vpar,1,1); const int nelx = upar.size() - 1; // === Assembly loop over all elements in the patch ========================== bool ok = true; for (size_t g = 0; g < threadGroups.size() && ok; g++) { #pragma omp parallel for schedule(static) for (size_t t = 0; t < threadGroups[g].size(); t++) { MxFiniteElement fe(elem_size); Matrices dNxdu(nxx.size()); Matrix Xnod, Jac; Vec4 X; for (size_t i = 0; i < threadGroups[g][t].size() && ok; ++i) { int iel = threadGroups[g][t][i]; int i1 = iel % nelx; int i2 = iel / nelx; // Set up control point coordinates for current element if (!this->getElementCoordinates(Xnod,++iel)) { ok = false; break; } // Initialize element quantities fe.iel = MLGE[iel-1]; LocalIntegral* A = integrand.getLocalIntegral(elem_size,fe.iel,false); if (!integrand.initElement(MNPC[iel-1],elem_size,nb,*A)) { A->destruct(); ok = false; break; } // --- Integration loop over all Gauss points in each direction -------- int jp = (i2*nelx + i1)*nGauss*nGauss; fe.iGP = firstIp + jp; // Global integration point counter for (int j = 0; j < nGauss; j++) for (int i = 0; i < nGauss; i++, fe.iGP++) { // Parameter value of current integration point fe.u = 0.5*(upar[i1]*(1.0-xg[i]) + upar[i1+1]*(1.0+xg[i])); fe.v = 0.5*(vpar[i2]*(1.0-xg[j]) + vpar[i2+1]*(1.0+xg[j])); // Local coordinates of current integration point fe.xi = xg[i]; fe.eta = xg[j]; // Compute basis function derivatives at current integration point // using tensor product of one-dimensional Lagrange polynomials for (size_t b = 0; b < nxx.size(); ++b) if (!Lagrange::computeBasis(fe.basis(b+1),dNxdu[b],elem_sizes[b][0],xg[i], elem_sizes[b][1],xg[j])) ok = false; // Compute Jacobian inverse of coordinate mapping and derivatives fe.detJxW = utl::Jacobian(Jac,fe.grad(geoBasis),Xnod,dNxdu[geoBasis-1]); if (fe.detJxW == 0.0) continue; // skip singular points for (size_t b = 0; b < nxx.size(); ++b) if (b != (size_t)geoBasis-1) fe.grad(b+1).multiply(dNxdu[b],Jac); // Cartesian coordinates of current integration point X = Xnod * fe.basis(geoBasis); X.t = time.t; // Evaluate the integrand and accumulate element contributions fe.detJxW *= wg[i]*wg[j]; if (!integrand.evalIntMx(*A,fe,time,X)) ok = false; } // Finalize the element quantities if (ok && !integrand.finalizeElement(*A,time,firstIp+jp)) ok = false; // Assembly of global system integral if (ok && !glInt.assemble(A->ref(),fe.iel)) ok = false; A->destruct(); } } } return ok; }