LCOV - code coverage report
Current view: top level - linalg - divfree.cpp (source / functions) Coverage Total Hit
Test: Palace Coverage Report Lines: 0.0 % 62 0
Test Date: 2025-10-23 22:45:05 Functions: 0.0 % 4 0
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              : #include "divfree.hpp"
       5              : 
       6              : #include <limits>
       7              : #include <mfem.hpp>
       8              : #include "fem/bilinearform.hpp"
       9              : #include "fem/fespace.hpp"
      10              : #include "fem/integrator.hpp"
      11              : #include "linalg/amg.hpp"
      12              : #include "linalg/gmg.hpp"
      13              : #include "linalg/iterative.hpp"
      14              : #include "linalg/rap.hpp"
      15              : #include "models/materialoperator.hpp"
      16              : #include "utils/timer.hpp"
      17              : 
      18              : namespace palace
      19              : {
      20              : 
      21              : namespace
      22              : {
      23              : 
      24              : template <typename OperType>
      25              : auto BuildLevelParOperator(std::unique_ptr<Operator> &&a,
      26              :                            const FiniteElementSpace &fespace);
      27              : 
      28              : template <>
      29              : auto BuildLevelParOperator<Operator>(std::unique_ptr<Operator> &&a,
      30              :                                      const FiniteElementSpace &fespace)
      31              : {
      32            0 :   return std::make_unique<ParOperator>(std::move(a), fespace);
      33              : }
      34              : 
      35              : template <>
      36              : auto BuildLevelParOperator<ComplexOperator>(std::unique_ptr<Operator> &&a,
      37              :                                             const FiniteElementSpace &fespace)
      38              : {
      39            0 :   return std::make_unique<ComplexParOperator>(std::move(a), nullptr, fespace);
      40              : }
      41              : 
      42              : }  // namespace
      43              : 
      44              : template <typename VecType>
      45            0 : DivFreeSolver<VecType>::DivFreeSolver(
      46              :     const MaterialOperator &mat_op, FiniteElementSpace &nd_fespace,
      47              :     FiniteElementSpaceHierarchy &h1_fespaces,
      48              :     const std::vector<mfem::Array<int>> &h1_bdr_tdof_lists, double tol, int max_it,
      49            0 :     int print)
      50              : {
      51            0 :   BlockTimer bt(Timer::DIV_FREE);
      52              : 
      53              :   // If no boundaries on the mesh have been marked, add a single degree of freedom
      54              :   // constraint so the system for the projection is not singular. This amounts to enforcing
      55              :   // a scalar potential of 0 at a point in space if it is otherwise completely
      56              :   // unconstrained.
      57              :   const auto *ptr_h1_bdr_tdof_lists = &h1_bdr_tdof_lists;
      58              :   {
      59            0 :     MFEM_VERIFY(
      60              :         !h1_bdr_tdof_lists.empty(),
      61              :         "Unexpected empty list of boundary true dofs for finite element space hierarchy!");
      62            0 :     HYPRE_BigInt coarse_bdr_tdofs = h1_bdr_tdof_lists[0].Size();
      63              :     MPI_Comm comm = h1_fespaces.GetFESpaceAtLevel(0).GetComm();
      64              :     Mpi::GlobalSum(1, &coarse_bdr_tdofs, comm);
      65            0 :     if (coarse_bdr_tdofs == 0)
      66              :     {
      67            0 :       int root = (h1_fespaces.GetFESpaceAtLevel(0).GetTrueVSize() == 0) ? Mpi::Size(comm)
      68              :                                                                         : Mpi::Rank(comm);
      69              :       Mpi::GlobalMin(1, &root, comm);
      70            0 :       MFEM_VERIFY(root < Mpi::Size(comm),
      71              :                   "No root process found for single true dof constraint!");
      72            0 :       if (root == Mpi::Rank(comm))
      73              :       {
      74            0 :         aux_tdof_lists.reserve(h1_fespaces.GetNumLevels());
      75            0 :         for (std::size_t l = 0; l < h1_fespaces.GetNumLevels(); l++)
      76              :         {
      77            0 :           auto &tdof_list = aux_tdof_lists.emplace_back(1);
      78            0 :           tdof_list[0] = 0;
      79              :         }
      80              :         ptr_h1_bdr_tdof_lists = &aux_tdof_lists;
      81              :       }
      82              :     }
      83              :   }
      84              : 
      85              :   // Create the mass and weak divergence operators for divergence-free projection.
      86            0 :   MaterialPropertyCoefficient epsilon_func(mat_op.GetAttributeToMaterial(),
      87              :                                            mat_op.GetPermittivityReal());
      88              :   {
      89              :     constexpr bool skip_zeros = false;
      90              :     BilinearForm m(h1_fespaces.GetFinestFESpace());
      91            0 :     m.AddDomainIntegrator<DiffusionIntegrator>(epsilon_func);
      92              :     // m.AssembleQuadratureData();
      93            0 :     auto m_vec = m.Assemble(h1_fespaces, skip_zeros);
      94            0 :     auto M_mg =
      95            0 :         std::make_unique<BaseMultigridOperator<OperType>>(h1_fespaces.GetNumLevels());
      96            0 :     for (std::size_t l = 0; l < h1_fespaces.GetNumLevels(); l++)
      97              :     {
      98              :       const auto &h1_fespace_l = h1_fespaces.GetFESpaceAtLevel(l);
      99              :       auto M_l = BuildLevelParOperator<OperType>(std::move(m_vec[l]), h1_fespace_l);
     100            0 :       M_l->SetEssentialTrueDofs((*ptr_h1_bdr_tdof_lists)[l],
     101              :                                 Operator::DiagonalPolicy::DIAG_ONE);
     102            0 :       if (l == h1_fespaces.GetNumLevels() - 1)
     103              :       {
     104            0 :         bdr_tdof_list_M = M_l->GetEssentialTrueDofs();
     105              :       }
     106            0 :       M_mg->AddOperator(std::move(M_l));
     107              :     }
     108              :     M = std::move(M_mg);
     109            0 :   }
     110              :   {
     111              :     // Weak divergence operator is always partially assembled.
     112              :     BilinearForm weakdiv(nd_fespace, h1_fespaces.GetFinestFESpace());
     113            0 :     weakdiv.AddDomainIntegrator<MixedVectorWeakDivergenceIntegrator>(epsilon_func);
     114            0 :     WeakDiv = std::make_unique<ParOperator>(weakdiv.PartialAssemble(), nd_fespace,
     115            0 :                                             h1_fespaces.GetFinestFESpace(), false);
     116              :   }
     117            0 :   Grad = &nd_fespace.GetDiscreteInterpolator(h1_fespaces.GetFinestFESpace());
     118              : 
     119              :   // The system matrix for the projection is real and SPD.
     120            0 :   auto amg = std::make_unique<MfemWrapperSolver<OperType>>(
     121            0 :       std::make_unique<BoomerAmgSolver>(1, 1, true, 0));
     122            0 :   std::unique_ptr<Solver<OperType>> pc;
     123            0 :   if (h1_fespaces.GetNumLevels() > 1)
     124              :   {
     125            0 :     const int mg_smooth_order =
     126            0 :         std::max(h1_fespaces.GetFinestFESpace().GetMaxElementOrder(), 2);
     127            0 :     pc = std::make_unique<GeometricMultigridSolver<OperType>>(
     128            0 :         h1_fespaces.GetFinestFESpace().GetComm(), std::move(amg),
     129            0 :         h1_fespaces.GetProlongationOperators(), nullptr, 1, 1, mg_smooth_order, 1.0, 0.0,
     130            0 :         true);
     131              :   }
     132              :   else
     133              :   {
     134              :     pc = std::move(amg);
     135              :   }
     136              : 
     137            0 :   auto pcg =
     138            0 :       std::make_unique<CgSolver<OperType>>(h1_fespaces.GetFinestFESpace().GetComm(), print);
     139            0 :   pcg->SetInitialGuess(false);
     140              :   pcg->SetRelTol(tol);
     141              :   pcg->SetAbsTol(std::numeric_limits<double>::epsilon());
     142              :   pcg->SetMaxIter(max_it);
     143              : 
     144            0 :   ksp = std::make_unique<BaseKspSolver<OperType>>(std::move(pcg), std::move(pc));
     145            0 :   ksp->SetOperators(*M, *M);
     146              : 
     147            0 :   psi.SetSize(h1_fespaces.GetFinestFESpace().GetTrueVSize());
     148            0 :   rhs.SetSize(h1_fespaces.GetFinestFESpace().GetTrueVSize());
     149            0 :   psi.UseDevice(true);
     150            0 :   rhs.UseDevice(true);
     151            0 : }
     152              : 
     153              : template <typename VecType>
     154            0 : void DivFreeSolver<VecType>::Mult(VecType &y) const
     155              : {
     156            0 :   BlockTimer bt(Timer::DIV_FREE);
     157              : 
     158              :   // Compute the divergence of y.
     159              :   if constexpr (std::is_same<VecType, ComplexVector>::value)
     160              :   {
     161            0 :     WeakDiv->Mult(y.Real(), rhs.Real());
     162            0 :     WeakDiv->Mult(y.Imag(), rhs.Imag());
     163              :   }
     164              :   else
     165              :   {
     166            0 :     WeakDiv->Mult(y, rhs);
     167              :   }
     168              : 
     169              :   // Apply essential BC and solve the linear system.
     170            0 :   if (bdr_tdof_list_M)
     171              :   {
     172            0 :     linalg::SetSubVector(rhs, *bdr_tdof_list_M, 0.0);
     173              :   }
     174            0 :   ksp->Mult(rhs, psi);
     175              : 
     176              :   // Compute the irrotational portion of y and subtract.
     177              :   if constexpr (std::is_same<VecType, ComplexVector>::value)
     178              :   {
     179            0 :     Grad->AddMult(psi.Real(), y.Real(), 1.0);
     180            0 :     Grad->AddMult(psi.Imag(), y.Imag(), 1.0);
     181              :   }
     182              :   else
     183              :   {
     184            0 :     Grad->AddMult(psi, y, 1.0);
     185              :   }
     186            0 : }
     187              : 
     188              : template class DivFreeSolver<Vector>;
     189              : template class DivFreeSolver<ComplexVector>;
     190              : 
     191              : }  // namespace palace
        

Generated by: LCOV version 2.0-1