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 }
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; }
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)); } }
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(); }
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; }
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); }
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; }
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; }
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; }