コード例 #1
0
ファイル: SplineField2D.C プロジェクト: OPM/IFEM
bool SplineField2D::gradFE (const FiniteElement& fe, Vector& grad) const
{
  if (!basis) return false;
  if (!surf)  return false;

  // Evaluate the basis functions at the given point
  Go::BasisDerivsSf spline;
#pragma omp critical
  surf->computeBasis(fe.u,fe.v,spline);

  const int uorder = surf->order_u();
  const int vorder = surf->order_v();
  const size_t nen = uorder*vorder;

  Matrix dNdu(nen,2), dNdX;
  for (size_t n = 1; n <= nen; n++)
  {
    dNdu(n,1) = spline.basisDerivs_u[n-1];
    dNdu(n,2) = spline.basisDerivs_v[n-1];
  }

  IntVec ip;
  ASMs2D::scatterInd(surf->numCoefs_u(),surf->numCoefs_v(),
		     uorder,vorder,spline.left_idx,ip);

  // Evaluate the Jacobian inverse
  Matrix Xnod, Jac;
  Vector Xctrl(&(*surf->coefs_begin()),surf->coefs_end()-surf->coefs_begin());
  utl::gather(ip,surf->dimension(),Xctrl,Xnod);
  utl::Jacobian(Jac,dNdX,Xnod,dNdu);

  // Evaluate the gradient of the solution field at the given point
  if (basis != surf)
  {
    // Mixed formulation, the solution uses a different basis than the geometry
#pragma omp critical
    basis->computeBasis(fe.u,fe.v,spline);

    const size_t nbf = basis->order_u()*basis->order_v();
    dNdu.resize(nbf,2);
    for (size_t n = 1; n <= nbf; n++)
    {
      dNdu(n,1) = spline.basisDerivs_u[n-1];
      dNdu(n,2) = spline.basisDerivs_v[n-1];
    }
    dNdX.multiply(dNdu,Jac); // dNdX = dNdu * Jac

    ip.clear();
    ASMs2D::scatterInd(basis->numCoefs_u(),basis->numCoefs_v(),
		       basis->order_u(),basis->order_v(),
		       spline.left_idx,ip);
  }

  Vector Vnod;
  utl::gather(ip,1,values,Vnod);
  return dNdX.multiply(Vnod,grad,true); // grad = dNdX * Vnod^t
}
コード例 #2
0
ファイル: ASMs2DSpec.C プロジェクト: kmokstad/IFEM-2
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;
}
コード例 #3
0
ファイル: ASMs1DSpec.C プロジェクト: OPM/IFEM
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;
}
コード例 #4
0
ファイル: ASMu3Dmxrecovery.C プロジェクト: kmokstad/IFEM-2
bool ASMu3Dmx::assembleL2matrices (SparseMatrix& A, StdVector& B,
                                   const IntegrandBase& integrand,
                                   bool continuous) const
{
  const int p1 = projBasis->order(0);
  const int p2 = projBasis->order(1);
  const int p3 = projBasis->order(2);

  // Get Gaussian quadrature points
  const int ng1 = continuous ? nGauss : p1 - 1;
  const int ng2 = continuous ? nGauss : p2 - 1;
  const int ng3 = continuous ? nGauss : p3 - 1;
  const double* xg = GaussQuadrature::getCoord(ng1);
  const double* yg = GaussQuadrature::getCoord(ng2);
  const double* zg = GaussQuadrature::getCoord(ng3);
  const double* wg = continuous ? GaussQuadrature::getWeight(nGauss) : nullptr;
  if (!xg || !yg || !zg) return false;
  if (continuous && !wg) return false;

  size_t nnod = this->getNoProjectionNodes();
  double dV = 0.0;
  Vectors phi(2);
  Matrices dNdu(2);
  Matrix sField, Xnod, Jac;
  std::vector<Go::BasisDerivs> spl1(2);
  std::vector<Go::BasisPts> spl0(2);


  // === Assembly loop over all elements in the patch ==========================
  LR::LRSplineVolume* geoVol;
  if (m_basis[geoBasis-1]->nBasisFunctions() == projBasis->nBasisFunctions())
    geoVol = m_basis[geoBasis-1].get();
  else
    geoVol = projBasis.get();

  for (const LR::Element* el1 : geoVol->getAllElements())
  {
    double uh = (el1->umin()+el1->umax())/2.0;
    double vh = (el1->vmin()+el1->vmax())/2.0;
    double wh = (el1->wmin()+el1->wmax())/2.0;
    std::vector<size_t> els;
    els.push_back(projBasis->getElementContaining(uh, vh, wh) + 1);
    els.push_back(m_basis[geoBasis-1]->getElementContaining(uh, vh, wh) + 1);

    if (continuous)
    {
      // Set up control point (nodal) coordinates for current element
      if (!this->getElementCoordinates(Xnod,els[1]))
        return false;
      else if ((dV = 0.25*this->getParametricVolume(els[1])) < 0.0)
        return false; // topology error (probably logic error)
    }

    // Compute parameter values of the Gauss points over this element
    RealArray gpar[3], unstrGpar[3];
    this->getGaussPointParameters(gpar[0],0,ng1,els[1],xg);
    this->getGaussPointParameters(gpar[1],1,ng2,els[1],yg);
    this->getGaussPointParameters(gpar[2],2,ng3,els[1],zg);

    // convert to unstructred mesh representation
    expandTensorGrid(gpar, unstrGpar);

    // Evaluate the secondary solution at all integration points
    if (!this->evalSolution(sField,integrand,unstrGpar))
      return false;

    // set up basis function size (for extractBasis subroutine)
    const LR::Element* elm = projBasis->getElement(els[0]-1);
    phi[0].resize(elm->nBasisFunctions());
    phi[1].resize(el1->nBasisFunctions());
    IntVec lmnpc;
    if (projBasis != m_basis[0]) {
      lmnpc.reserve(phi[0].size());
      for (const LR::Basisfunction* f : elm->support())
        lmnpc.push_back(f->getId());
    }
    const IntVec& mnpc = projBasis == m_basis[0] ? MNPC[els[1]-1] : lmnpc;

    // --- Integration loop over all Gauss points in each direction ----------
    Matrix eA(phi[0].size(), phi[0].size());
    Vectors eB(sField.rows(), Vector(phi[0].size()));
    int ip = 0;
    for (int k = 0; k < ng3; k++)
      for (int j = 0; j < ng2; j++)
        for (int i = 0; i < ng1; i++, ip++)
        {
          if (continuous)
          {
            projBasis->computeBasis(gpar[0][i], gpar[1][j], gpar[2][k],
                                    spl1[0], els[0]-1);
            SplineUtils::extractBasis(spl1[0],phi[0],dNdu[0]);
            m_basis[geoBasis-1]->computeBasis(gpar[0][i], gpar[1][j], gpar[2][k],
                                              spl1[1], els[1]-1);
            SplineUtils::extractBasis(spl1[1], phi[1], dNdu[1]);
          }
          else
          {
            projBasis->computeBasis(gpar[0][i], gpar[1][j], gpar[2][k],
                                    spl0[0], els[0]-1);
            phi[0] = spl0[0].basisValues;
          }

          // Compute the Jacobian inverse and derivatives
          double dJw = 1.0;
          if (continuous)
          {
            dJw = dV*wg[i]*wg[j]*wg[k]*utl::Jacobian(Jac,dNdu[1],Xnod,dNdu[1],false);
            if (dJw == 0.0) continue; // skip singular points
          }

          // Integrate the mass matrix
          eA.outer_product(phi[0], phi[0], true, dJw);

          // Integrate the rhs vector B
          for (size_t r = 1; r <= sField.rows(); r++)
            eB[r-1].add(phi[0],sField(r,ip+1)*dJw);
        }

    for (size_t i = 0; i < eA.rows(); ++i) {
      for (size_t j = 0; j < eA.cols(); ++j)
        A(mnpc[i]+1, mnpc[j]+1) += eA(i+1,j+1);

      int jp = mnpc[i]+1;
      for (size_t r = 0; r < sField.rows(); r++, jp += nnod)
        B(jp) += eB[r](1+i);
    }
  }

  return true;
}
コード例 #5
0
ファイル: SplineField2D.C プロジェクト: OPM/IFEM
bool SplineField2D::hessianFE(const FiniteElement& fe, Matrix& H) const
{
  if (!basis) return false;
  if (!surf)  return false;

  // Order of basis
  const int uorder = surf->order_u();
  const int vorder = surf->order_v();
  const size_t nen = uorder*vorder;

  // Evaluate the basis functions at the given point
  Go::BasisDerivsSf  spline;
  Go::BasisDerivsSf2 spline2;
  Matrix3D d2Ndu2;
  Matrix dNdu, dNdX;
  IntVec ip;
#pragma omp critical
  if (surf == basis) {
    surf->computeBasis(fe.u,fe.v,spline2);
    
    dNdu.resize(nen,2);
    d2Ndu2.resize(nen,2,2);
    for (size_t n = 1; n <= nen; n++) {
      dNdu(n,1) = spline2.basisDerivs_u[n-1];
      dNdu(n,2) = spline2.basisDerivs_v[n-1];
      d2Ndu2(n,1,1) = spline2.basisDerivs_uu[n-1];
      d2Ndu2(n,1,2) = d2Ndu2(n,2,1) = spline2.basisDerivs_uv[n-1];
      d2Ndu2(n,2,2) = spline2.basisDerivs_vv[n-1];
    }
    
    ASMs2D::scatterInd(surf->numCoefs_u(),surf->numCoefs_v(),
		       uorder,vorder,spline2.left_idx,ip);
  }
  else {
    surf->computeBasis(fe.u,fe.v,spline);
    
    dNdu.resize(nen,2);
    for (size_t n = 1; n <= nen; n++) {
      dNdu(n,1) = spline.basisDerivs_u[n-1];
      dNdu(n,2) = spline.basisDerivs_v[n-1];
    }
    
    ASMs2D::scatterInd(surf->numCoefs_u(),surf->numCoefs_v(),
		       uorder,vorder,spline.left_idx,ip);
  }
  
  // Evaluate the Jacobian inverse
  Matrix Xnod, Jac;
  Vector Xctrl(&(*surf->coefs_begin()),surf->coefs_end()-surf->coefs_begin());
  utl::gather(ip,surf->dimension(),Xctrl,Xnod);
  utl::Jacobian(Jac,dNdX,Xnod,dNdu);
  
  // Evaluate the gradient of the solution field at the given point
  if (basis != surf)
  {
    // Mixed formulation, the solution uses a different basis than the geometry
#pragma omp critical
    basis->computeBasis(fe.u,fe.v,spline2);

    const size_t nbf = basis->order_u()*basis->order_v();
    dNdu.resize(nbf,2);
    d2Ndu2.resize(nbf,2,2);
    for (size_t n = 1; n <= nbf; n++) {
      dNdu(n,1) = spline2.basisDerivs_u[n-1];
      dNdu(n,2) = spline2.basisDerivs_v[n-1];
      d2Ndu2(n,1,1) = spline2.basisDerivs_uu[n-1];
      d2Ndu2(n,1,2) = d2Ndu2(n,2,1) = spline2.basisDerivs_uv[n-1];
      d2Ndu2(n,2,2) = spline2.basisDerivs_vv[n-1];
    }

    ip.clear();
    ASMs2D::scatterInd(basis->numCoefs_u(),basis->numCoefs_v(),
		       basis->order_u(),basis->order_v(),
		       spline2.left_idx,ip);
  }

  Vector Vnod;
  utl::gather(ip,1,values,Vnod);
  return H.multiply(d2Ndu2,Vnod);
}
コード例 #6
0
ファイル: ASMs2DSpec.C プロジェクト: kmokstad/IFEM-2
bool ASMs2DSpec::integrate (Integrand& integrand,
			    GlobalIntegral& glInt,
			    const TimeDomain& time)
{
  if (this->empty()) return true; // silently ignore empty patches

  // Evaluate integration points (= nodal points) and weights
  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;


  // === 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++)
    {
      FiniteElement fe(p1*p2);
      Matrix dNdu(p1*p2,2), Xnod, Jac;
      Vec4   X;
      for (size_t e = 0; e < threadGroups[g][t].size(); e++)
      {
        int iel = threadGroups[g][t][e]+1;

        // 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(fe.N.size(),fe.iel);
        if (!integrand.initElement(MNPC[iel-1],*A))
        {
          A->destruct();
          ok = false;
          break;
        }


        // --- Integration loop over all Gauss points in each direction --------

        int count = 1;
        for (int j = 1; j <= p2; j++)
          for (int i = 1; i <= p1; i++, count++)
          {
            // Evaluate the basis functions and gradients using
            // tensor product of one-dimensional Lagrange polynomials
            evalBasis(i,j,p1,p2,D1,D2,fe.N,dNdu);

            // Compute Jacobian inverse of coordinate mapping and derivatives
            fe.detJxW = utl::Jacobian(Jac,fe.dNdX,Xnod,dNdu);
            if (fe.detJxW == 0.0) continue; // skip singular points

            // Cartesian coordinates of current integration point
            X.x = Xnod(1,count);
            X.y = Xnod(2,count);
            X.t = time.t;

            // Evaluate the integrand and accumulate element contributions
            fe.detJxW *= wg1(i)*wg2(j);
            if (!integrand.evalInt(*A,fe,time,X))
              ok = false;
          }

        // Assembly of global system integral
        if (ok && !glInt.assemble(A->ref(),fe.iel))
          ok = false;

        A->destruct();
      }
    }
  }

  return ok;
}
コード例 #7
0
ファイル: ASMs2DSpec.C プロジェクト: kmokstad/IFEM-2
bool ASMs2DSpec::integrate (Integrand& integrand, int lIndex,
			    GlobalIntegral& glInt,
			    const TimeDomain& time)
{
  if (this->empty()) return true; // silently ignore empty patches

  // Find the parametric direction of the edge normal {-2,-1, 1, 2}
  int edgeDir = lIndex = (lIndex+1)/((lIndex%2) ? -2 : 2);

  const int t1 = abs(edgeDir);   // Tangent direction normal to the patch edge
  const int t2 = 3-abs(edgeDir); // Tangent direction along the patch edge

  // Number of elements in each direction
  int n1, n2;
  this->getSize(n1,n2);
  const int nelx = (n1-1)/(p1-1);
  const int nely = (n2-1)/(p2-1);

  // Evaluate integration points and weights

  std::array<Vector,2> wg, xg;
  std::array<Matrix,2> D;
  std::array<int,2> p({{p1,p2}});
  for (int d = 0; d < 2; d++)
  {
    if (!Legendre::GLL(wg[d],xg[d],p[d])) return false;
    if (!Legendre::basisDerivatives(p[d],D[d])) return false;
  }
  int nen = p1*p2;

  FiniteElement fe(nen);
  Matrix dNdu(nen,2), Xnod, Jac;
  Vec4   X;
  Vec3   normal;
  int    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(nen,fe.iel,true);
      if (!integrand.initElementBou(MNPC[iel-1],*A)) return false;


      // --- Integration loop over all Gauss points along the edge -------------

      for (int i = 0; i < p[t2-1]; i++)
      {
	// "Coordinates" along the edge
	xi[t1-1] = edgeDir < 0 ? 1 : p[t1-1];
	xi[t2-1] = i+1;

	// Evaluate the basis functions and gradients using
	// tensor product of one-dimensional Lagrange polynomials
	evalBasis(xi[0],xi[1],p1,p2,D[0],D[1],fe.N,dNdu);

	// 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[t2-1][i];
        if (!integrand.evalBou(*A,fe,time,X,normal))
	  return false;
      }

      // Finalize the element quantities
      if (!integrand.finalizeElementBou(*A,fe,time))
        return false;

      // Assembly of global system integral
      if (!glInt.assemble(A->ref(),fe.iel))
	return false;

      A->destruct();
    }

  return true;
}
コード例 #8
0
ファイル: ASMs3DSpec.C プロジェクト: OPM/IFEM
bool ASMs3DSpec::integrateEdge (Integrand& integrand, int lEdge,
				GlobalIntegral& glInt,
				const TimeDomain& time)
{
  if (!svol) return true; // silently ignore empty patches

  // Parametric direction of the edge {0, 1, 2}
  const int lDir = (lEdge-1)/4;

  // Order of basis in the three parametric directions (order = degree + 1)
  const int p1 = svol->order(0);
  const int p2 = svol->order(1);
  const int p3 = svol->order(2);
  const int pe = svol->order(lDir);

  // Number of elements in each direction
  int n1, n2, n3;
  this->getSize(n1,n2,n3);
  const int nelx = (n1-1)/(p1-1);
  const int nely = (n2-1)/(p2-1);
  const int nelz = (n3-1)/(p3-1);

  // Evaluate integration points (=nodal points) and weights

  std::array<Vector,3> wg, xg;
  if (!Legendre::GLL(wg[0],xg[0],p1)) return false;
  if (!Legendre::GLL(wg[1],xg[1],p2)) return false;
  if (!Legendre::GLL(wg[2],xg[2],p3)) return false;

  Matrix D1, D2, D3;
  if (!Legendre::basisDerivatives(p1,D1)) return false;
  if (!Legendre::basisDerivatives(p2,D2)) return false;
  if (!Legendre::basisDerivatives(p3,D3)) return false;

  const int nen = p1*p2*p3;

  FiniteElement fe(nen);
  Matrix dNdu(nen,3), Xnod, Jac;
  Vec4   X;
  Vec3   tangent;
  int    xi[3];

  switch (lEdge)
    {
    case  1: xi[1] =  1; xi[2] =  1; break;
    case  2: xi[1] = p2; xi[2] =  1; break;
    case  3: xi[1] =  1; xi[2] = p3; break;
    case  4: xi[1] = p2; xi[2] = p3; break;
    case  5: xi[0] =  1; xi[2] =  1; break;
    case  6: xi[0] = p1; xi[2] =  1; break;
    case  7: xi[0] =  1; xi[2] = p3; break;
    case  8: xi[0] = p1; xi[2] = p3; break;
    case  9: xi[0] =  1; xi[1] =  1; break;
    case 10: xi[0] = p1; xi[1] =  1; break;
    case 11: xi[0] =  1; xi[1] = p2; break;
    case 12: xi[0] = p1; xi[1] = p2; break;
    }


  // === Assembly loop over all elements on the patch edge =====================

  int iel = 1;
  for (int i3 = 0; i3 < nelz; i3++)
    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 (lEdge)
	  {
	  case  1: if (i2 > 0      || i3 > 0)      skipMe = true; break;
	  case  2: if (i2 < nely-1 || i3 > 0)      skipMe = true; break;
	  case  3: if (i2 > 0      || i3 < nelz-1) skipMe = true; break;
	  case  4: if (i2 < nely-1 || i3 < nelz-1) skipMe = true; break;
	  case  5: if (i1 > 0      || i3 > 0)      skipMe = true; break;
	  case  6: if (i1 < nelx-1 || i3 > 0)      skipMe = true; break;
	  case  7: if (i1 > 0      || i3 < nelz-1) skipMe = true; break;
	  case  8: if (i1 < nelx-1 || i3 < nelz-1) skipMe = true; break;
	  case  9: if (i1 > 0      || i2 > 0)      skipMe = true; break;
	  case 10: if (i1 < nelx-1 || i2 > 0)      skipMe = true; break;
	  case 11: if (i1 > 0      || i2 < nely-1) skipMe = true; break;
	  case 12: if (i1 < nelx-1 || 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 = MLGE[iel-1];
        LocalIntegral* A = integrand.getLocalIntegral(nen,fe.iel,true);
        if (!integrand.initElementBou(MNPC[iel-1],*A)) return false;


	// --- Integration loop over all Gauss points along the edge -----------

	for (int i = 0; i < pe; i++)
	{
	  // "Coordinate" on the edge
	  xi[lDir] = i+1;

	  // Compute the basis functions and their derivatives, using
	  // tensor product of one-dimensional Lagrange polynomials
	  evalBasis(xi[0],xi[1],xi[2],p1,p2,p3,D1,D2,D3,fe.N,dNdu);

	  // Compute basis function derivatives and the edge tangent
	  fe.detJxW = utl::Jacobian(Jac,tangent,fe.dNdX,Xnod,dNdu,1+lDir);
	  if (fe.detJxW == 0.0) continue; // skip singular points

	  // Cartesian coordinates of current integration point
	  X = Xnod * fe.N;
	  X.t = time.t;

	  // Evaluate the integrand and accumulate element contributions
	  fe.detJxW *= wg[lDir][i];
          if (!integrand.evalBou(*A,fe,time,X,tangent))
	    return false;
	}

        // Finalize the element quantities
        if (!integrand.finalizeElementBou(*A,fe,time))
          return false;

	// Assembly of global system integral
	if (!glInt.assemble(A->ref(),fe.iel))
	  return false;
      }

  return true;
}
コード例 #9
0
ファイル: ASMs3DSpec.C プロジェクト: OPM/IFEM
bool ASMs3DSpec::integrate (Integrand& integrand, int lIndex,
			    GlobalIntegral& glInt,
			    const TimeDomain& time)
{
  if (!svol) return true; // silently ignore empty patches

  std::map<char,ThreadGroups>::const_iterator tit;
  if ((tit = threadGroupsFace.find(lIndex)) == threadGroupsFace.end())
  {
    std::cerr <<" *** ASMs3DSpec::integrate: No thread groups for face "<<lIndex
	      << std::endl;
    return false;
  }
  const ThreadGroups& threadGrp = tit->second;

  // Find the parametric direction of the face normal {-3,-2,-1, 1, 2, 3}
  const int faceDir = (lIndex+1)/(lIndex%2 ? -2 : 2);

  const int t0 = abs(faceDir); // unsigned normal direction of the face
  const int t1 = 1 + t0%3; // first tangent direction of the face
  const int t2 = 1 + t1%3; // second tangent direction of the face

  // Order of basis in the three parametric directions (order = degree + 1)
  int p[3];
  p[0] = svol->order(0);
  p[1] = svol->order(1);
  p[2] = svol->order(2);

  // Evaluate integration points (=nodal points) and weights

  std::array<Vector,3> xg, wg;
  std::array<Matrix,3> D;
  for (int d = 0; d < 3; d++)
  {
    if (!Legendre::GLL(wg[d],xg[d],p[d])) return false;
    if (!Legendre::basisDerivatives(p[d],D[d])) return false;
  }
  int nen = p[0]*p[1]*p[2];


  // === Assembly loop over all elements on the patch face =====================

  bool ok = true;
  for (size_t g = 0; g < threadGrp.size() && ok; g++)
  {
#pragma omp parallel for schedule(static)
    for (size_t t = 0; t < threadGrp[g].size(); t++)
    {
      FiniteElement fe(nen);
      Matrix dNdu(nen,3), Xnod, Jac;
      Vec4   X;
      Vec3   normal;
      int    xi[3];
      for (size_t l = 0; l < threadGrp[g][t].size(); l++)
      {
        int iel = threadGrp[g][t][l];

	// Set up nodal 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(nen,fe.iel,true);
        if (!integrand.initElementBou(MNPC[iel-1],*A))
        {
          A->destruct();
          ok = false;
          break;
        }


	// --- Integration loop over all Gauss points in each direction --------

	for (int j = 0; j < p[t2-1]; j++)
	  for (int i = 0; i < p[t1-1]; i++)
	  {
	    // "Coordinates" on the face
	    xi[t0-1] = faceDir < 0 ? 1 : p[t0-1];
	    xi[t1-1] = i+1;
	    xi[t2-1] = j+1;

	    // Compute the basis functions and their derivatives, using
	    // tensor product of one-dimensional Lagrange polynomials
	    evalBasis(xi[0],xi[1],xi[2],p[0],p[1],p[2],D[0],D[1],D[2],fe.N,dNdu);

	    // Compute basis function derivatives and the face normal
	    fe.detJxW = utl::Jacobian(Jac,normal,fe.dNdX,Xnod,dNdu,t1,t2);
	    if (fe.detJxW == 0.0) continue; // skip singular points

	    if (faceDir < 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[t1-1][i]*wg[t2-1][j];
            if (!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();
      }
    }
  }

  return ok;
}