bool ASMs2DLag::integrate (Integrand& integrand, int lIndex, GlobalIntegral& glInt, const TimeDomain& time) { if (this->empty()) return true; // silently ignore empty patches // Get Gaussian quadrature points and weights int nG1 = this->getNoGaussPt(lIndex%10 < 3 ? p1 : p2, true); int nGP = integrand.getBouIntegrationPoints(nG1); const double* xg = GaussQuadrature::getCoord(nGP); const double* wg = GaussQuadrature::getWeight(nGP); if (!xg || !wg) return false; // Find the parametric direction of the edge normal {-2,-1, 1, 2} const int edgeDir = (lIndex%10+1)/((lIndex%2) ? -2 : 2); const int t1 = abs(edgeDir); // tangent direction normal to the patch edge const int t2 = 3-t1; // tangent direction along the patch edge // Number of elements in each direction const int nelx = (nx-1)/(p1-1); const int nely = (ny-1)/(p2-1); // Get parametric coordinates of the elements FiniteElement fe(p1*p2); RealArray upar, vpar; if (t1 == 1) { fe.u = edgeDir < 0 ? surf->startparam_u() : surf->endparam_u(); this->getGridParameters(vpar,1,1); } else if (t1 == 2) { this->getGridParameters(upar,0,1); fe.v = edgeDir < 0 ? surf->startparam_v() : surf->endparam_v(); } // Extract the Neumann order flag (1 or higher) for the integrand integrand.setNeumannOrder(1 + lIndex/10); // Integrate the extraordinary elements? size_t doXelms = 0; if (integrand.getIntegrandType() & Integrand::XO_ELEMENTS) if ((doXelms = nelx*nely)*2 > MNPC.size()) { std::cerr <<" *** ASMs2DLag::integrate: Too few XO-elements " << MNPC.size() - doXelms << std::endl; return false; } std::map<char,size_t>::const_iterator iit = firstBp.find(lIndex%10); size_t firstp = iit == firstBp.end() ? 0 : iit->second; Matrix dNdu, Xnod, Jac; Vec4 X; Vec3 normal; double xi[2]; // === Assembly loop over all elements on the patch edge ===================== int iel = 1; for (int i2 = 0; i2 < nely; i2++) for (int i1 = 0; i1 < nelx; i1++, iel++) { // Skip elements that are not on current boundary edge bool skipMe = false; switch (edgeDir) { case -1: if (i1 > 0) skipMe = true; break; case 1: if (i1 < nelx-1) skipMe = true; break; case -2: if (i2 > 0) skipMe = true; break; case 2: if (i2 < nely-1) skipMe = true; break; } if (skipMe) continue; // Set up nodal point coordinates for current element if (!this->getElementCoordinates(Xnod,iel)) return false; // Initialize element quantities fe.iel = abs(MLGE[doXelms+iel-1]); LocalIntegral* A = integrand.getLocalIntegral(fe.N.size(),fe.iel,true); bool ok = integrand.initElementBou(MNPC[doXelms+iel-1],*A); // --- Integration loop over all Gauss points along the edge ------------- int jp = (t1 == 1 ? i2 : i1)*nGP; fe.iGP = firstp + jp; // Global integration point counter for (int i = 0; i < nGP && ok; i++, fe.iGP++) { // Local element coordinates of current integration point xi[t1-1] = edgeDir < 0 ? -1.0 : 1.0; xi[t2-1] = xg[i]; fe.xi = xi[0]; fe.eta = xi[1]; // Parameter values of current integration point if (upar.size() > 1) fe.u = 0.5*(upar[i1]*(1.0-xg[i]) + upar[i1+1]*(1.0+xg[i])); if (vpar.size() > 1) fe.v = 0.5*(vpar[i2]*(1.0-xg[i]) + vpar[i2+1]*(1.0+xg[i])); // Compute the basis functions and their derivatives, using // tensor product of one-dimensional Lagrange polynomials if (!Lagrange::computeBasis(fe.N,dNdu,p1,xi[0],p2,xi[1])) ok = false; // Compute basis function derivatives and the edge normal fe.detJxW = utl::Jacobian(Jac,normal,fe.dNdX,Xnod,dNdu,t1,t2); if (fe.detJxW == 0.0) continue; // skip singular points if (edgeDir < 0) normal *= -1.0; // Cartesian coordinates of current integration point X = Xnod * fe.N; X.t = time.t; // Evaluate the integrand and accumulate element contributions fe.detJxW *= wg[i]; if (ok && !integrand.evalBou(*A,fe,time,X,normal)) ok = false; } // Finalize the element quantities if (ok && !integrand.finalizeElementBou(*A,fe,time)) ok = false; // Assembly of global system integral if (ok && !glInt.assemble(A->ref(),fe.iel)) ok = false; A->destruct(); if (!ok) return false; } return true; }
bool ASMs2DmxLag::integrate (Integrand& integrand, int lIndex, 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; // Find the parametric direction of the edge normal {-2,-1, 1, 2} const int edgeDir = (lIndex%10+1)/((lIndex%2) ? -2 : 2); const int t1 = abs(edgeDir); // tangent direction normal to the patch edge const int t2 = 3-t1; // tangent direction along the patch edge // Extract the Neumann order flag (1 or higher) for the integrand integrand.setNeumannOrder(1 + lIndex/10); // Number of elements in each direction const int nelx = (nxx[geoBasis-1]-1)/(elem_sizes[geoBasis-1][0]-1); const int nely = (nyx[geoBasis-1]-1)/(elem_sizes[geoBasis-1][1]-1); std::map<char,size_t>::const_iterator iit = firstBp.find(lIndex%10); size_t firstp = iit == firstBp.end() ? 0 : iit->second; MxFiniteElement fe(elem_size); Matrices dNxdu(nxx.size()); Matrix Xnod, Jac; Vec4 X; Vec3 normal; double xi[2]; // === Assembly loop over all elements on the patch edge ===================== int iel = 1; for (int i2 = 0; i2 < nely; i2++) for (int i1 = 0; i1 < nelx; i1++, iel++) { // Skip elements that are not on current boundary edge bool skipMe = false; switch (edgeDir) { case -1: if (i1 > 0) skipMe = true; break; case 1: if (i1 < nelx-1) skipMe = true; break; case -2: if (i2 > 0) skipMe = true; break; case 2: if (i2 < nely-1) skipMe = true; break; } if (skipMe) continue; // Set up control point coordinates for current element if (!this->getElementCoordinates(Xnod,iel)) return false; // Initialize element quantities fe.iel = MLGE[iel-1]; LocalIntegral* A = integrand.getLocalIntegral(elem_size,fe.iel,true); bool ok = integrand.initElementBou(MNPC[iel-1],elem_size,nb,*A); // --- Integration loop over all Gauss points along the edge ------------- int jp = (t1 == 1 ? i2 : i1)*nGauss; fe.iGP = firstp + jp; // Global integration point counter for (int i = 0; i < nGauss && ok; i++, fe.iGP++) { // Gauss point coordinates along the edge xi[t1-1] = edgeDir < 0 ? -1.0 : 1.0; xi[t2-1] = xg[i]; // Compute the basis functions and their derivatives, 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],xi[0], elem_sizes[b][1],xi[1])) ok = false; // Compute basis function derivatives and the edge normal fe.detJxW = utl::Jacobian(Jac,normal,fe.grad(geoBasis),Xnod,dNxdu[geoBasis-1],t1,t2); 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); if (edgeDir < 0) normal *= -1.0; // 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]; if (ok && !integrand.evalBouMx(*A,fe,time,X,normal)) ok = false; } // Finalize the element quantities if (ok && !integrand.finalizeElementBou(*A,fe,time)) ok = false; // Assembly of global system integral if (ok && !glInt.assemble(A->ref(),fe.iel)) ok = false; A->destruct(); if (!ok) return false; } return true; }