Пример #1
0
bool ASMs3DLag::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 <<" *** ASMs3DLag::integrate: No thread groups for face "<< lIndex
	      << std::endl;
    return false;
  }
  const ThreadGroups& threadGrp = tit->second;

  // Get Gaussian quadrature points and weights
  int nGP = integrand.getBouIntegrationPoints(nGauss);
  const double* xg = GaussQuadrature::getCoord(nGP);
  const double* wg = GaussQuadrature::getWeight(nGP);
  if (!xg || !wg) return false;

  // 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)
  const int p1 = svol->order(0);
  const int p2 = svol->order(1);
  const int p3 = svol->order(2);

  // Number of elements in each direction
  const int nel1 = (nx-1)/(p1-1);
  const int nel2 = (ny-1)/(p2-1);
  const int nel3 = (nz-1)/(p3-1);

  // Get parametric coordinates of the elements
  RealArray upar, vpar, wpar;
  if (t0 == 1)
    upar.resize(1,faceDir < 0 ? svol->startparam(0) : svol->endparam(0));
  else if (t0 == 2)
    vpar.resize(1,faceDir < 0 ? svol->startparam(1) : svol->endparam(1));
  else if (t0 == 3)
    wpar.resize(1,faceDir < 0 ? svol->startparam(2) : svol->endparam(2));

  if (upar.empty()) this->getGridParameters(upar,0,1);
  if (vpar.empty()) this->getGridParameters(vpar,1,1);
  if (wpar.empty()) this->getGridParameters(wpar,2,1);

  // Integrate the extraordinary elements?
  size_t doXelms = 0;
  if (integrand.getIntegrandType() & Integrand::XO_ELEMENTS)
    if ((doXelms = nel1*nel2*nel3)*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);
  size_t firstp = iit == firstBp.end() ? 0 : iit->second;


  // === 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(p1*p2*p3);
      fe.u = upar.front();
      fe.v = vpar.front();
      fe.w = wpar.front();

      Matrix dNdu, Xnod, Jac;
      Vec4   X;
      Vec3   normal;
      double xi[3];

      for (size_t l = 0; l < threadGrp[g][t].size() && ok; l++)
      {
        int iel = threadGrp[g][t][l];
        int i1  =  iel % nel1;
        int i2  = (iel / nel1) % nel2;
        int i3  =  iel / (nel1*nel2);

        // Set up nodal point coordinates for current element
        if (!this->getElementCoordinates(Xnod,++iel))
        {
          ok = false;
          break;
        }

        // Initialize element quantities
        fe.iel = abs(MLGE[doXelms+iel-1]);
        LocalIntegral* A = integrand.getLocalIntegral(fe.N.size(),fe.iel,true);
        if (!integrand.initElementBou(MNPC[doXelms+iel-1],*A))
        {
          A->destruct();
          ok = false;
          break;
        }

        // Define some loop control variables depending on which face we are on
        int nf1, j1, j2;
        switch (abs(faceDir))
        {
          case 1: nf1 = nel2; j2 = i3; j1 = i2; break;
          case 2: nf1 = nel1; j2 = i3; j1 = i1; break;
          case 3: nf1 = nel1; j2 = i2; j1 = i1; break;
          default: nf1 = j1 = j2 = 0;
        }


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

        int k1, k2, k3;
        int jp = (j2*nf1 + j1)*nGP*nGP;
        fe.iGP = firstp + jp; // Global integration point counter

	for (int j = 0; j < nGP; j++)
	  for (int i = 0; i < nGP; i++, fe.iGP++)
	  {
	    // Local element coordinates of current integration point
	    xi[t0-1] = faceDir < 0 ? -1.0 : 1.0;
	    xi[t1-1] = xg[i];
	    xi[t2-1] = xg[j];
	    fe.xi   = xi[0];
	    fe.eta  = xi[1];
	    fe.zeta = xi[2];

	    // Local element coordinates and parameter values
	    // of current integration point
	    switch (abs(faceDir))
	    {
	      case 1: k2 = i; k3 = j; k1 = -1; break;
	      case 2: k1 = i; k3 = j; k2 = -1; break;
	      case 3: k1 = i; k2 = j; k3 = -1; break;
	      default: k1 = k2 = k3 = -1;
	    }
	    if (upar.size() > 1)
	      fe.u = 0.5*(upar[i1]*(1.0-xg[k1]) + upar[i1+1]*(1.0+xg[k1]));
	    if (vpar.size() > 1)
	      fe.v = 0.5*(vpar[i2]*(1.0-xg[k2]) + vpar[i2+1]*(1.0+xg[k2]));
	    if (wpar.size() > 1)
	      fe.w = 0.5*(wpar[i3]*(1.0-xg[k3]) + wpar[i3+1]*(1.0+xg[k3]));

	    // 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],p3,xi[2]))
              ok = false;

	    // 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[i]*wg[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;
}
Пример #2
0
bool ASMs3DLag::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;

  // Get Gaussian quadrature points and weights
  const double* xg = GaussQuadrature::getCoord(nGauss);
  const double* wg = GaussQuadrature::getWeight(nGauss);
  if (!xg || !wg) return false;

  // 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);

  // Number of elements in each direction
  const int nelx = (nx-1)/(p1-1);
  const int nely = (ny-1)/(p2-1);
  const int nelz = (nz-1)/(p3-1);

  FiniteElement fe(p1*p2*p3);
  Matrix dNdu, Xnod, Jac;
  Vec4   X;
  Vec3   tangent;
  double xi[3];

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

  std::map<char,size_t>::const_iterator iit = firstBp.find(lEdge);
  size_t firstp = iit == firstBp.end() ? 0 : iit->second;


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

  int ip, 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;

	if (lEdge < 5)
	  ip = i1*nGauss;
	else if (lEdge < 9)
	  ip = i2*nGauss;
	else
	  ip = i3*nGauss;

	// 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(fe.N.size(),fe.iel,true);
        bool ok = integrand.initElementBou(MNPC[iel-1],*A);


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

	fe.iGP = firstp + ip; // Global integration point counter

	for (int i = 0; i < nGauss && ok; i++, fe.iGP++)
	{
	  // Gauss point coordinates on the edge
	  xi[lDir] = 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],p3,xi[2]))
	    ok = false;

	  // 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
          if (!integrand.evalBou(*A,fe,time,X,tangent))
	    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;
}
Пример #3
0
Файл: ASMs1D.C Проект: OPM/IFEM
bool ASMs1D::integrate (Integrand& integrand, int lIndex,
			GlobalIntegral& glInt,
			const TimeDomain& time)
{
  if (!curv) return true; // silently ignore empty patches

  // Integration of boundary point

  FiniteElement fe(curv->order());
  size_t iel = 0;
  switch (lIndex)
    {
    case 1:
      fe.xi = -1.0;
      fe.u = curv->startparam();
      break;

    case 2:
      fe.xi = 1.0;
      fe.u = curv->endparam();
      iel = nel-1;
      break;

    default:
      return false;
    }

  std::map<char,size_t>::const_iterator iit = firstBp.find(lIndex);
  fe.iGP = iit == firstBp.end() ? 0 : iit->second;
  fe.iel = MLGE[iel];
  if (fe.iel < 1) return true; // zero-length element

  // Set up control point coordinates for current element
  if (!this->getElementCoordinates(fe.Xn,1+iel)) return false;

  if (integrand.getIntegrandType() & Integrand::ELEMENT_CORNERS)
    this->getElementEnds(iel+curv->order(),fe.XC);

  if (integrand.getIntegrandType() & Integrand::NODAL_ROTATIONS)
  {
    this->getElementNodalRotations(fe.Tn,iel);
    if (!elmCS.empty()) fe.Te = elmCS[iel];
  }

  // Initialize element matrices
  LocalIntegral* A = integrand.getLocalIntegral(fe.N.size(),fe.iel,true);
  bool ok = integrand.initElementBou(MNPC[iel],*A);

  Vec3 normal;

  // Evaluate basis functions and corresponding derivatives
  if (integrand.getIntegrandType() & Integrand::NO_DERIVATIVES)
    this->extractBasis(fe.u,fe.N);
  else
  {
    // Compute basis function derivatives
    Matrix dNdu, Jac;
    this->extractBasis(fe.u,fe.N,dNdu);
    utl::Jacobian(Jac,fe.dNdX,fe.Xn,dNdu);

    // Set up the normal vector
    if (lIndex == 1)
      normal.x = -copysign(1.0,Jac(1,1));
    else
      normal.x = copysign(1.0,Jac(1,1));
  }

  // Cartesian coordinates of current integration point
  Vec4 X(fe.Xn*fe.N,time.t);

  // Evaluate the integrand and accumulate element contributions
  if (ok && !integrand.evalBou(*A,fe,time,X,normal))
    ok = false;

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

  A->destruct();
  return ok;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}