LCOV - code coverage report
Current view: top level - fem - fespace.hpp (source / functions) Coverage Total Hit
Test: Palace Coverage Report Lines: 66.7 % 57 38
Test Date: 2025-10-23 22:45:05 Functions: 73.3 % 15 11
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       2              : // SPDX-License-Identifier: Apache-2.0
       3              : 
       4              : #ifndef PALACE_FEM_FESPACE_HPP
       5              : #define PALACE_FEM_FESPACE_HPP
       6              : 
       7              : #include <memory>
       8              : #include <vector>
       9              : #include <mfem.hpp>
      10              : #include "fem/libceed/ceed.hpp"
      11              : #include "fem/mesh.hpp"
      12              : #include "linalg/operator.hpp"
      13              : #include "linalg/vector.hpp"
      14              : 
      15              : namespace palace
      16              : {
      17              : 
      18              : //
      19              : // Wrapper for MFEM's ParFiniteElementSpace class, with extensions for Palace.
      20              : //
      21              : class FiniteElementSpace
      22              : {
      23              : private:
      24              :   // Underlying MFEM object.
      25              :   mfem::ParFiniteElementSpace fespace;
      26              : 
      27              :   // Reference to the underlying mesh object (not owned).
      28              :   Mesh &mesh;
      29              : 
      30              :   // Members for constructing libCEED operators.
      31              :   mutable ceed::CeedObjectMap<CeedBasis> basis;
      32              :   mutable ceed::CeedObjectMap<CeedElemRestriction> restr, interp_restr, interp_range_restr;
      33              : 
      34              :   // Temporary storage for operator applications.
      35              :   mutable ComplexVector tx, lx, ly;
      36              : 
      37              :   // Members for discrete interpolators from an auxiliary space to a primal space.
      38              :   mutable const FiniteElementSpace *aux_fespace;
      39              :   mutable std::unique_ptr<Operator> G;
      40              : 
      41         2374 :   bool HasUniqueInterpRestriction(const mfem::FiniteElement &fe) const
      42              :   {
      43              :     // For interpolation operators and tensor-product elements, we need native (not
      44              :     // lexicographic) ordering.
      45              :     const mfem::TensorBasisElement *tfe =
      46         2374 :         dynamic_cast<const mfem::TensorBasisElement *>(&fe);
      47         2374 :     return (tfe && tfe->GetDofMap().Size() > 0 &&
      48         2374 :             fe.GetRangeType() != mfem::FiniteElement::VECTOR);
      49              :   }
      50              : 
      51         1254 :   bool HasUniqueInterpRangeRestriction(const mfem::FiniteElement &fe) const
      52              :   {
      53              :     // The range restriction for interpolation operators needs to use a special
      54              :     // DofTransformation (not equal to the transpose of the domain restriction).
      55         1254 :     if (mesh.Dimension() < 3)
      56              :     {
      57              :       return false;
      58              :     }
      59              :     const auto geom = fe.GetGeomType();
      60          681 :     const auto *dof_trans = fespace.FEColl()->DofTransformationForGeometry(geom);
      61          681 :     return (dof_trans && !dof_trans->IsIdentity());
      62              :   }
      63              : 
      64              :   const Operator &BuildDiscreteInterpolator() const;
      65              : 
      66              : public:
      67              :   template <typename... T>
      68        20638 :   FiniteElementSpace(Mesh &mesh, T &&...args)
      69        20638 :     : fespace(&mesh.Get(), std::forward<T>(args)...), mesh(mesh), aux_fespace(nullptr)
      70              :   {
      71        20638 :     ResetCeedObjects();
      72        20638 :     tx.UseDevice(true);
      73        20638 :     lx.UseDevice(true);
      74        20638 :     ly.UseDevice(true);
      75        20638 :   }
      76        41339 :   virtual ~FiniteElementSpace() { ResetCeedObjects(); }
      77              : 
      78           18 :   const auto &Get() const { return fespace; }
      79          189 :   auto &Get() { return fespace; }
      80              : 
      81              :   operator const mfem::ParFiniteElementSpace &() const { return Get(); }
      82              :   operator mfem::ParFiniteElementSpace &() { return Get(); }
      83              : 
      84              :   const auto &GetFEColl() const { return *Get().FEColl(); }
      85              :   auto &GetFEColl() { return *Get().FEColl(); }
      86              : 
      87        11366 :   const auto &GetMesh() const { return mesh; }
      88            0 :   auto &GetMesh() { return mesh; }
      89              : 
      90            0 :   const auto &GetParMesh() const { return mesh.Get(); }
      91           84 :   auto &GetParMesh() { return mesh.Get(); }
      92              : 
      93              :   auto GetVDim() const { return Get().GetVDim(); }
      94              :   auto GetVSize() const { return Get().GetVSize(); }
      95              :   auto GlobalVSize() const { return Get().GlobalVSize(); }
      96           54 :   auto GetTrueVSize() const { return Get().GetTrueVSize(); }
      97              :   auto GlobalTrueVSize() const { return Get().GlobalTrueVSize(); }
      98         5862 :   auto Dimension() const { return mesh.Get().Dimension(); }
      99            0 :   auto SpaceDimension() const { return mesh.Get().SpaceDimension(); }
     100            0 :   auto GetMaxElementOrder() const { return Get().GetMaxElementOrder(); }
     101              : 
     102           54 :   const auto *GetProlongationMatrix() const { return Get().GetProlongationMatrix(); }
     103            0 :   const auto *GetRestrictionMatrix() const { return Get().GetRestrictionMatrix(); }
     104              : 
     105              :   // Return the discrete gradient, curl, or divergence matrix interpolating from the
     106              :   // auxiliary to the primal space, constructing it on the fly as necessary.
     107            6 :   const auto &GetDiscreteInterpolator(const FiniteElementSpace &aux_fespace_) const
     108              :   {
     109            6 :     if (&aux_fespace_ != aux_fespace)
     110              :     {
     111              :       G.reset();
     112            6 :       aux_fespace = &aux_fespace_;
     113              :     }
     114            6 :     return G ? *G : BuildDiscreteInterpolator();
     115              :   }
     116              : 
     117              :   // Return the basis object for elements of the given element geometry type.
     118              :   CeedBasis GetCeedBasis(Ceed ceed, mfem::Geometry::Type geom) const;
     119              : 
     120              :   // Return the element restriction object for the given element set (all with the same
     121              :   // geometry type).
     122              :   CeedElemRestriction GetCeedElemRestriction(Ceed ceed, mfem::Geometry::Type geom,
     123              :                                              const std::vector<int> &indices) const;
     124              : 
     125              :   // If the space has a special element restriction for discrete interpolators, return that.
     126              :   // Otherwise return the same restriction as given by GetCeedElemRestriction.
     127              :   CeedElemRestriction GetInterpCeedElemRestriction(Ceed ceed, mfem::Geometry::Type geom,
     128              :                                                    const std::vector<int> &indices) const;
     129              : 
     130              :   // If the space has a special element restriction for the range space of discrete
     131              :   // interpolators, return that. Otherwise return the same restriction as given by
     132              :   // GetCeedElemRestriction.
     133              :   CeedElemRestriction
     134              :   GetInterpRangeCeedElemRestriction(Ceed ceed, mfem::Geometry::Type geom,
     135              :                                     const std::vector<int> &indices) const;
     136              : 
     137              :   // Clear the cached basis and element restriction objects owned by the finite element
     138              :   // space.
     139              :   void ResetCeedObjects();
     140              : 
     141              :   void Update() { ResetCeedObjects(); }
     142              : 
     143              :   static CeedBasis BuildCeedBasis(const mfem::FiniteElementSpace &fespace, Ceed ceed,
     144              :                                   mfem::Geometry::Type geom);
     145              :   static CeedElemRestriction
     146              :   BuildCeedElemRestriction(const mfem::FiniteElementSpace &fespace, Ceed ceed,
     147              :                            mfem::Geometry::Type geom, const std::vector<int> &indices,
     148              :                            bool is_interp = false, bool is_interp_range = false);
     149              : 
     150              :   template <typename VecType>
     151              :   auto &GetTVector() const
     152              :   {
     153           12 :     tx.SetSize(GetTrueVSize());
     154              :     if constexpr (std::is_same<VecType, ComplexVector>::value)
     155              :     {
     156              :       return tx;
     157              :     }
     158              :     else
     159              :     {
     160              :       return tx.Real();
     161              :     }
     162              :   }
     163              : 
     164              :   template <typename VecType>
     165              :   auto &GetLVector() const
     166              :   {
     167           18 :     lx.SetSize(GetVSize());
     168              :     if constexpr (std::is_same<VecType, ComplexVector>::value)
     169              :     {
     170              :       return lx;
     171              :     }
     172              :     else
     173              :     {
     174              :       return lx.Real();
     175              :     }
     176              :   }
     177              : 
     178              :   template <typename VecType>
     179              :   auto &GetLVector2() const
     180              :   {
     181           18 :     ly.SetSize(GetVSize());
     182              :     if constexpr (std::is_same<VecType, ComplexVector>::value)
     183              :     {
     184              :       return ly;
     185              :     }
     186              :     else
     187              :     {
     188              :       return ly.Real();
     189              :     }
     190              :   }
     191              : 
     192              :   // Get the associated MPI communicator.
     193              :   MPI_Comm GetComm() const { return fespace.GetComm(); }
     194              : };
     195              : 
     196              : //
     197              : // A collection of FiniteElementSpace objects constructed on the same mesh with the ability
     198              : // to construct the prolongation operators between them as needed.
     199              : //
     200            0 : class FiniteElementSpaceHierarchy
     201              : {
     202              : protected:
     203              :   std::vector<std::unique_ptr<FiniteElementSpace>> fespaces;
     204              :   mutable std::vector<std::unique_ptr<Operator>> P;
     205              : 
     206              :   const Operator &BuildProlongationAtLevel(std::size_t l) const;
     207              : 
     208              : public:
     209              :   FiniteElementSpaceHierarchy() = default;
     210           63 :   FiniteElementSpaceHierarchy(std::unique_ptr<FiniteElementSpace> &&fespace)
     211           63 :   {
     212           63 :     AddLevel(std::move(fespace));
     213           63 :   }
     214              : 
     215              :   auto GetNumLevels() const { return fespaces.size(); }
     216              : 
     217           63 :   void AddLevel(std::unique_ptr<FiniteElementSpace> &&fespace)
     218              :   {
     219           63 :     fespaces.push_back(std::move(fespace));
     220           63 :     P.push_back(nullptr);
     221           63 :   }
     222              : 
     223              :   auto &GetFESpaceAtLevel(std::size_t l)
     224              :   {
     225              :     MFEM_ASSERT(l < GetNumLevels(),
     226              :                 "Out of bounds request for finite element space at level " << l << "!");
     227              :     return *fespaces[l];
     228              :   }
     229              :   const auto &GetFESpaceAtLevel(std::size_t l) const
     230              :   {
     231              :     MFEM_ASSERT(l < GetNumLevels(),
     232              :                 "Out of bounds request for finite element space at level " << l << "!");
     233              :     return *fespaces[l];
     234              :   }
     235              : 
     236              :   auto &GetFinestFESpace()
     237              :   {
     238              :     MFEM_ASSERT(GetNumLevels() > 0,
     239              :                 "Out of bounds request for finite element space at level 0!");
     240              :     return *fespaces.back();
     241              :   }
     242              :   const auto &GetFinestFESpace() const
     243              :   {
     244              :     MFEM_ASSERT(GetNumLevels() > 0,
     245              :                 "Out of bounds request for finite element space at level 0!");
     246              :     return *fespaces.back();
     247              :   }
     248              : 
     249              :   const auto &GetProlongationAtLevel(std::size_t l) const
     250              :   {
     251              :     MFEM_ASSERT(l + 1 < GetNumLevels(),
     252              :                 "Out of bounds request for finite element space prolongation at level "
     253              :                     << l << "!");
     254            0 :     return P[l] ? *P[l] : BuildProlongationAtLevel(l);
     255              :   }
     256              : 
     257            0 :   std::vector<const Operator *> GetProlongationOperators() const
     258              :   {
     259              :     MFEM_ASSERT(GetNumLevels() > 1,
     260              :                 "Out of bounds request for finite element space prolongation at level 0!");
     261            0 :     std::vector<const Operator *> P_(GetNumLevels() - 1);
     262            0 :     for (std::size_t l = 0; l < P_.size(); l++)
     263              :     {
     264            0 :       P_[l] = &GetProlongationAtLevel(l);
     265              :     }
     266            0 :     return P_;
     267              :   }
     268              : 
     269              :   const auto &GetDiscreteInterpolatorAtLevel(std::size_t l,
     270              :                                              const FiniteElementSpace &aux_fespace) const
     271              :   {
     272            0 :     return GetFESpaceAtLevel(l).GetDiscreteInterpolator(aux_fespace);
     273              :   }
     274              : 
     275              :   std::vector<const Operator *>
     276            0 :   GetDiscreteInterpolators(const FiniteElementSpaceHierarchy &aux_fespaces) const
     277              :   {
     278            0 :     std::vector<const Operator *> G_(GetNumLevels());
     279            0 :     G_[0] = nullptr;  // No discrete interpolator for coarsest level
     280            0 :     for (std::size_t l = 1; l < G_.size(); l++)
     281              :     {
     282            0 :       G_[l] = &GetDiscreteInterpolatorAtLevel(l, aux_fespaces.GetFESpaceAtLevel(l));
     283              :     }
     284            0 :     return G_;
     285              :   }
     286              : };
     287              : 
     288              : }  // namespace palace
     289              : 
     290              : #endif  // PALACE_FEM_FESPACE_HPP
        

Generated by: LCOV version 2.0-1