Example #1
0
File: device.cpp Project: LLNL/mfem
static void OccaDeviceSetup(const int dev)
{
#ifdef MFEM_USE_OCCA
   const int cpu  = Device::Allows(Backend::OCCA_CPU);
   const int omp  = Device::Allows(Backend::OCCA_OMP);
   const int cuda = Device::Allows(Backend::OCCA_CUDA);
   if (cpu + omp + cuda > 1)
   {
      MFEM_ABORT("Only one OCCA backend can be configured at a time!");
   }
   if (cuda)
   {
#if OCCA_CUDA_ENABLED
      std::string mode("mode: 'CUDA', device_id : ");
      internal::occaDevice.setup(mode.append(1,'0'+dev));
#else
      MFEM_ABORT("the OCCA CUDA backend requires OCCA built with CUDA!");
#endif
   }
   else if (omp)
   {
#if OCCA_OPENMP_ENABLED
      internal::occaDevice.setup("mode: 'OpenMP'");
#else
      MFEM_ABORT("the OCCA OpenMP backend requires OCCA built with OpenMP!");
#endif
   }
   else
   {
      internal::occaDevice.setup("mode: 'Serial'");
   }

   std::string mfemDir;
   if (occa::io::exists(MFEM_INSTALL_DIR "/include/mfem/"))
   {
      mfemDir = MFEM_INSTALL_DIR "/include/mfem/";
   }
   else if (occa::io::exists(MFEM_SOURCE_DIR))
   {
      mfemDir = MFEM_SOURCE_DIR;
   }
   else
   {
      MFEM_ABORT("Cannot find OCCA kernels in MFEM_INSTALL_DIR or MFEM_SOURCE_DIR");
   }

   occa::io::addLibraryPath("mfem", mfemDir);
   occa::loadKernels("mfem");
#else
   MFEM_ABORT("the OCCA backends require MFEM built with MFEM_USE_OCCA=YES");
#endif
}
Example #2
0
void IsoparametricTransformation::SetIdentityTransformation(
   Geometry::Type GeomType)
{
   switch (GeomType)
   {
      case Geometry::POINT :       FElem = &PointFE; break;
      case Geometry::SEGMENT :     FElem = &SegmentFE; break;
      case Geometry::TRIANGLE :    FElem = &TriangleFE; break;
      case Geometry::SQUARE :      FElem = &QuadrilateralFE; break;
      case Geometry::TETRAHEDRON : FElem = &TetrahedronFE; break;
      case Geometry::CUBE :        FElem = &HexahedronFE; break;
      case Geometry::PRISM :       FElem = &WedgeFE; break;
      default:
         MFEM_ABORT("unknown Geometry::Type!");
   }
   int dim = FElem->GetDim();
   int dof = FElem->GetDof();
   const IntegrationRule &nodes = FElem->GetNodes();
   PointMat.SetSize(dim, dof);
   for (int j = 0; j < dof; j++)
   {
      nodes.IntPoint(j).Get(&PointMat(0,j), dim);
   }
   geom = GeomType;
   space_dim = dim;
}
Example #3
0
void ParBlockNonlinearForm::Mult(const Vector &x, Vector &y) const
{
   xs_true.Update(x.GetData(), block_trueOffsets);
   ys_true.Update(y.GetData(), block_trueOffsets);
   xs.Update(block_offsets);
   ys.Update(block_offsets);

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->Mult(
         xs_true.GetBlock(s), xs.GetBlock(s));
   }

   BlockNonlinearForm::MultBlocked(xs, ys);

   if (fnfi.Size() > 0)
   {
      MFEM_ABORT("TODO: assemble contributions from shared face terms");
   }

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->MultTranspose(
         ys.GetBlock(s), ys_true.GetBlock(s));
   }
}
Example #4
0
Operator &ParNonlinearForm::GetGradient(const Vector &x) const
{
   ParFiniteElementSpace *pfes = ParFESpace();

   pGrad.Clear();

   NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.

   OperatorHandle dA(pGrad.Type()), Ph(pGrad.Type());

   if (fnfi.Size() == 0)
   {
      dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
                             pfes->GetDofOffsets(), Grad);
   }
   else
   {
      MFEM_ABORT("TODO: assemble contributions from shared face terms");
   }

   // TODO - construct Dof_TrueDof_Matrix directly in the pGrad format
   Ph.ConvertFrom(pfes->Dof_TrueDof_Matrix());
   pGrad.MakePtAP(dA, Ph);

   // Impose b.c. on pGrad
   OperatorHandle pGrad_e;
   pGrad_e.EliminateRowsCols(pGrad, ess_tdof_list);

   return *pGrad.Ptr();
}
Example #5
0
double ParNonlinearForm::GetParGridFunctionEnergy(const Vector &x) const
{
   double loc_energy, glob_energy;

   loc_energy = GetGridFunctionEnergy(x);

   if (fnfi.Size())
   {
      MFEM_ABORT("TODO: add energy contribution from shared faces");
   }

   MPI_Allreduce(&loc_energy, &glob_energy, 1, MPI_DOUBLE, MPI_SUM,
                 ParFESpace()->GetComm());

   return glob_energy;
}
Example #6
0
int InverseElementTransformation::Transform(const Vector &pt,
                                            IntegrationPoint &ip)
{
   MFEM_VERIFY(T != NULL, "invalid ElementTransformation");

   // Select initial guess ...
   switch (init_guess_type)
   {
      case Center:
         ip0 = &Geometries.GetCenter(T->GetGeometryType());
         break;

      case ClosestPhysNode:
      case ClosestRefNode:
      {
         const int order = std::max(T->Order()+rel_qpts_order, 0);
         if (order == 0)
         {
            ip0 = &Geometries.GetCenter(T->GetGeometryType());
         }
         else
         {
            const int old_type = GlobGeometryRefiner.GetType();
            GlobGeometryRefiner.SetType(qpts_type);
            RefinedGeometry &RefG =
               *GlobGeometryRefiner.Refine(T->GetGeometryType(), order);
            int closest_idx = (init_guess_type == ClosestPhysNode) ?
                              FindClosestPhysPoint(pt, RefG.RefPts) :
                              FindClosestRefPoint(pt, RefG.RefPts);
            ip0 = &RefG.RefPts.IntPoint(closest_idx);
            GlobGeometryRefiner.SetType(old_type);
         }
         break;
      }

      case GivenPoint:
         break;

      default:
         MFEM_ABORT("invalid initial guess type");
   }

   // Call the solver ...
   return NewtonSolve(pt, ip);
}
Example #7
0
int STable3D::operator() (int r, int c, int f) const
{
   STable3DNode *node;

   Sort3 (r, c, f);

   for (node = Rows[r]; node != NULL; node = node->Prev)
   {
      if (node->Column == c)
         if (node->Floor == f)
         {
            return node->Number;
         }
   }

   MFEM_ABORT("(r,c,f) = (" << r << "," << c << "," << f << ")");

   return 0;
}
Example #8
0
int InverseElementTransformation::NewtonSolve(const Vector &pt,
                                              IntegrationPoint &ip)
{
   MFEM_ASSERT(pt.Size() == T->GetSpaceDim(), "invalid point");

   const double phys_tol = phys_rtol*pt.Normlinf();

   const int geom = T->GetGeometryType();
   const int dim = T->GetDimension();
   const int sdim = T->GetSpaceDim();
   IntegrationPoint xip, prev_xip;
   double xd[3], yd[3], dxd[3], dx_norm = -1.0, err_phys, real_dx_norm = -1.0;
   Vector x(xd, dim), y(yd, sdim), dx(dxd, dim);
   bool hit_bdr = false, prev_hit_bdr = false;

   // Use ip0 as initial guess:
   xip = *ip0;
   xip.Get(xd, dim); // xip -> x
   if (print_level >= 3)
   {
      NewtonPrint(1, 0.); // iter 0
      NewtonPrintPoint(",    ref_pt", x, "\n");
   }

   for (int it = 0; true; )
   {
      // Remarks:
      // If f(x) := 1/2 |pt-F(x)|^2, then grad(f)(x) = -J^t(x) [pt-F(x)].
      // Linearize F(y) at y=x: F(y) ~ L[x](y) := F(x) + J(x) [y-x].
      // Newton iteration for F(y)=b is given by L[x_old](x_new) = b, i.e.
      // F(x_old) + J(x_old) [x_new-x_old] = b.
      //
      // To minimize: 1/2 |F(y)-b|^2, subject to: l(y) >= 0, we may consider the
      // iteration: minimize: |L[x_old](x_new)-b|^2, subject to l(x_new) >= 0,
      // i.e. minimize: |F(x_old) + J(x_old) [x_new-x_old] - b|^2.

      // This method uses:
      // Newton iteration:    x := x + J(x)^{-1} [pt-F(x)]
      // or when dim != sdim: x := x + [J^t.J]^{-1}.J^t [pt-F(x)]

      // Compute the physical coordinates of the current point:
      T->Transform(xip, y);
      if (print_level >= 3)
      {
         NewtonPrint(11, 0.); // continuation line
         NewtonPrintPoint("approx_pt", y, ", ");
         NewtonPrintPoint("exact_pt", pt, "\n");
      }
      subtract(pt, y, y); // y = pt-y

      // Check for convergence in physical coordinates:
      err_phys = y.Normlinf();
      if (err_phys < phys_tol)
      {
         if (print_level >= 1)
         {
            NewtonPrint(1, (double)it);
            NewtonPrint(3, dx_norm);
            NewtonPrint(30, err_phys);
         }
         ip = xip;
         if (solver_type != Newton) { return Inside; }
         return Geometry::CheckPoint(geom, ip, ip_tol) ? Inside : Outside;
      }
      if (print_level >= 1)
      {
         if (it == 0 || print_level >= 2)
         {
            NewtonPrint(1, (double)it);
            NewtonPrint(3, dx_norm);
            NewtonPrint(18, err_phys);
         }
      }

      if (hit_bdr)
      {
         xip.Get(xd, dim); // xip -> x
         if (prev_hit_bdr || it == max_iter || print_level >= 2)
         {
            prev_xip.Get(dxd, dim); // prev_xip -> dx
            subtract(x, dx, dx);    // dx = xip - prev_xip
            real_dx_norm = dx.Normlinf();
            if (print_level >= 2)
            {
               NewtonPrint(41, real_dx_norm);
            }
            if (prev_hit_bdr && real_dx_norm < ref_tol)
            {
               if (print_level >= 0)
               {
                  if (print_level <= 1)
                  {
                     NewtonPrint(1, (double)it);
                     NewtonPrint(3, dx_norm);
                     NewtonPrint(18, err_phys);
                     NewtonPrint(41, real_dx_norm);
                  }
                  mfem::out << "Newton: *** stuck on boundary!\n";
               }
               return Outside;
            }
         }
      }

      if (it == max_iter) { break; }

      // Perform a Newton step:
      T->SetIntPoint(&xip);
      T->InverseJacobian().Mult(y, dx);
      x += dx;
      it++;
      if (solver_type != Newton)
      {
         prev_xip = xip;
         prev_hit_bdr = hit_bdr;
      }
      xip.Set(xd, dim); // x -> xip

      // Perform projection based on solver_type:
      switch (solver_type)
      {
         case Newton: break;
         case NewtonSegmentProject:
            hit_bdr = !Geometry::ProjectPoint(geom, prev_xip, xip); break;
         case NewtonElementProject:
            hit_bdr = !Geometry::ProjectPoint(geom, xip); break;
         default: MFEM_ABORT("invalid solver type");
      }
      if (print_level >= 3)
      {
         NewtonPrint(1, double(it));
         xip.Get(xd, dim); // xip -> x
         NewtonPrintPoint(",    ref_pt", x, "\n");
      }

      // Check for convergence in reference coordinates:
      dx_norm = dx.Normlinf();
      if (dx_norm < ref_tol)
      {
         if (print_level >= 1)
         {
            NewtonPrint(1, (double)it);
            NewtonPrint(27, dx_norm);
         }
         ip = xip;
         if (solver_type != Newton) { return Inside; }
         return Geometry::CheckPoint(geom, ip, ip_tol) ? Inside : Outside;
      }
   }
   if (print_level >= 0)
   {
      if (print_level <= 1)
      {
         NewtonPrint(1, (double)max_iter);
         NewtonPrint(3, dx_norm);
         NewtonPrint(18, err_phys);
         if (hit_bdr) { NewtonPrint(41, real_dx_norm); }
      }
      mfem::out << "Newton: *** iteration did not converge!\n";
   }
   ip = xip;
   return Unknown;
}
Example #9
0
BlockOperator & ParBlockNonlinearForm::GetGradient(const Vector &x) const
{
   if (pBlockGrad == NULL)
   {
      pBlockGrad = new BlockOperator(block_trueOffsets);
   }

   Array<const ParFiniteElementSpace *> pfes(fes.Size());

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      pfes[s1] = ParFESpace(s1);

      for (int s2=0; s2<fes.Size(); ++s2)
      {
         phBlockGrad(s1,s2)->Clear();
      }
   }

   GetLocalGradient(x); // gradients are stored in 'Grads'

   if (fnfi.Size() > 0)
   {
      MFEM_ABORT("TODO: assemble contributions from shared face terms");
   }

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         OperatorHandle dA(phBlockGrad(s1,s2)->Type()),
                        Ph(phBlockGrad(s1,s2)->Type()),
                        Rh(phBlockGrad(s1,s2)->Type());

         if (s1 == s2)
         {
            dA.MakeSquareBlockDiag(pfes[s1]->GetComm(), pfes[s1]->GlobalVSize(),
                                   pfes[s1]->GetDofOffsets(), Grads(s1,s1));
            Ph.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
            phBlockGrad(s1,s1)->MakePtAP(dA, Ph);
         }
         else
         {
            dA.MakeRectangularBlockDiag(pfes[s1]->GetComm(),
                                        pfes[s1]->GlobalVSize(),
                                        pfes[s2]->GlobalVSize(),
                                        pfes[s1]->GetDofOffsets(),
                                        pfes[s2]->GetDofOffsets(),
                                        Grads(s1,s2));
            Rh.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
            Ph.ConvertFrom(pfes[s2]->Dof_TrueDof_Matrix());

            phBlockGrad(s1,s2)->MakeRAP(Rh, dA, Ph);
         }

         pBlockGrad->SetBlock(s1, s2, phBlockGrad(s1,s2)->Ptr());
      }
   }

   return *pBlockGrad;
}