LCOV - code coverage report
Current view: top level - src/mfem/equation_systems - ComplexEquationSystem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 142 161 88.2 %
Date: 2026-05-29 20:35:17 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #ifdef MOOSE_MFEM_ENABLED
       2             : 
       3             : #include "ComplexEquationSystem.h"
       4             : #include "libmesh/int_range.h"
       5             : 
       6             : namespace Moose::MFEM
       7             : {
       8             : 
       9             : void
      10          62 : ComplexEquationSystem::Init(GridFunctions & gridfunctions,
      11             :                             ComplexGridFunctions & cmplx_gridfunctions,
      12             :                             mfem::AssemblyLevel assembly_level)
      13             : {
      14          62 :   _assembly_level = assembly_level;
      15             : 
      16          62 :   if (gridfunctions.size())
      17           0 :     mooseError("Mixing real and complex variables is currently not supported.");
      18             : 
      19         103 :   for (auto & test_var_name : _test_var_names)
      20             :   {
      21          41 :     if (!cmplx_gridfunctions.Has(test_var_name))
      22             :     {
      23           0 :       mooseError("MFEM complex variable ",
      24             :                  test_var_name,
      25             :                  " requested by equation system during initialization was "
      26             :                  "not found in gridfunctions");
      27             :     }
      28             :     // Store pointers to test FESpaces
      29          41 :     _test_pfespaces.push_back(cmplx_gridfunctions.Get(test_var_name)->ParFESpace());
      30             :     // Create auxiliary gridfunctions for storing essential constraints from Dirichlet conditions
      31          41 :     _cmplx_var_ess_constraints.emplace_back(std::make_unique<mfem::ParComplexGridFunction>(
      32          82 :         cmplx_gridfunctions.Get(test_var_name)->ParFESpace()));
      33             :   }
      34             : 
      35             :   // Store pointers to FESpaces of all coupled variables
      36         103 :   for (auto & coupled_var_name : _coupled_var_names)
      37          41 :     _coupled_pfespaces.push_back(cmplx_gridfunctions.Get(coupled_var_name)->ParFESpace());
      38             : 
      39             :   // Extract which coupled variables are to be trivially eliminated and which are trial variables
      40          62 :   SetTrialVariableNames();
      41             : 
      42             :   // Store pointers to coupled variable ComplexGridFunctions that are to be eliminated prior to
      43             :   // forming the jacobian
      44          62 :   for (auto & eliminated_var_name : _eliminated_var_names)
      45           0 :     _cmplx_eliminated_variables.Register(eliminated_var_name,
      46           0 :                                          cmplx_gridfunctions.GetShared(eliminated_var_name));
      47             : 
      48             :   // Get a reference to the complex GridFunctions
      49          62 :   _complex_gfuncs = &cmplx_gridfunctions;
      50          62 : }
      51             : 
      52             : void
      53          41 : ComplexEquationSystem::BuildEquationSystem()
      54             : {
      55          41 :   BuildBilinearForms();
      56          41 :   BuildLinearForms();
      57          41 : }
      58             : 
      59             : void
      60          41 : ComplexEquationSystem::BuildLinearForms()
      61             : {
      62             :   // Register linear forms
      63          82 :   for (const auto i : index_range(_test_var_names))
      64             :   {
      65          41 :     auto test_var_name = _test_var_names.at(i);
      66          41 :     _clfs.Register(test_var_name,
      67          82 :                    std::make_shared<mfem::ParComplexLinearForm>(_test_pfespaces.at(i)));
      68          41 :     _clfs.GetRef(test_var_name) = 0.0;
      69          41 :   }
      70             :   // Apply boundary conditions
      71          41 :   ApplyEssentialBCs();
      72             : 
      73          82 :   for (auto & test_var_name : _test_var_names)
      74             :   {
      75             :     // Apply kernels
      76          41 :     auto clf = _clfs.GetShared(test_var_name);
      77          41 :     ApplyDomainLFIntegrators(test_var_name, clf, _cmplx_kernels_map);
      78          41 :     ApplyBoundaryLFIntegrators(test_var_name, clf, _cmplx_integrated_bc_map);
      79          41 :     clf->Assemble();
      80          41 :   }
      81          41 : }
      82             : 
      83             : void
      84          41 : ComplexEquationSystem::BuildBilinearForms()
      85             : {
      86             :   // Register bilinear forms
      87          82 :   for (const auto i : index_range(_test_var_names))
      88             :   {
      89          41 :     auto test_var_name = _test_var_names.at(i);
      90          41 :     _slfs.Register(test_var_name,
      91          82 :                    std::make_shared<mfem::ParSesquilinearForm>(_test_pfespaces.at(i)));
      92             : 
      93             :     // Apply kernels
      94          41 :     auto slf = _slfs.GetShared(test_var_name);
      95          41 :     slf->SetAssemblyLevel(_assembly_level);
      96          41 :     ApplyBoundaryBLFIntegrators<mfem::ParSesquilinearForm>(
      97          41 :         test_var_name, test_var_name, slf, _cmplx_integrated_bc_map);
      98          41 :     ApplyDomainBLFIntegrators<mfem::ParSesquilinearForm>(
      99          41 :         test_var_name, test_var_name, slf, _cmplx_kernels_map);
     100             :     // Assemble
     101          41 :     slf->Assemble();
     102          41 :   }
     103          41 : }
     104             : 
     105             : void
     106          41 : ComplexEquationSystem::ApplyComplexEssentialBC(const std::string & var_name,
     107             :                                                mfem::ParComplexGridFunction & trial_gf,
     108             :                                                mfem::Array<int> & global_ess_markers)
     109             : {
     110          41 :   if (_cmplx_essential_bc_map.Has(var_name))
     111             :   {
     112          41 :     auto & bcs = _cmplx_essential_bc_map.GetRef(var_name);
     113         103 :     for (auto & bc : bcs)
     114             :     {
     115             :       // Set constrained DoFs values on essential boundaries
     116          62 :       bc->ApplyBC(trial_gf);
     117             :       // Fetch marker array labelling essential boundaries of current BC
     118          62 :       mfem::Array<int> ess_bdrs(bc->getBoundaryMarkers());
     119             :       // Add these boundary markers to the set of markers labelling all essential boundaries
     120         385 :       for (const auto i : make_range(trial_gf.ParFESpace()->GetParMesh()->bdr_attributes.Max()))
     121         323 :         global_ess_markers[i] = std::max(global_ess_markers[i], ess_bdrs[i]);
     122          62 :     }
     123             :   }
     124          41 : }
     125             : 
     126             : void
     127          41 : ComplexEquationSystem::ApplyEssentialBCs()
     128             : {
     129          41 :   _ess_tdof_lists.resize(_trial_var_names.size());
     130          82 :   for (const auto i : index_range(_trial_var_names))
     131             :   {
     132          41 :     const auto & trial_var_name = _trial_var_names.at(i);
     133          41 :     mfem::ParComplexGridFunction & trial_gf = *_cmplx_var_ess_constraints.at(i);
     134             : 
     135             :     // Make sure we update the size, if this mesh has changed recently for instance
     136          41 :     trial_gf.Update();
     137             : 
     138             :     // Initial guess for non-linear problems (initial condition or the previous time step solution)
     139          41 :     static_cast<mfem::Vector &>(trial_gf) = _complex_gfuncs->GetRef(trial_var_name);
     140             : 
     141          41 :     mfem::Array<int> global_ess_markers(trial_gf.ParFESpace()->GetParMesh()->bdr_attributes.Max());
     142          41 :     global_ess_markers = 0;
     143             :     // Set strongly constrained DoFs of trial_gf on essential boundaries and add markers for all
     144             :     // essential boundaries to the global_ess_markers array
     145          41 :     ApplyComplexEssentialBC(trial_var_name, trial_gf, global_ess_markers);
     146          41 :     trial_gf.FESpace()->GetEssentialTrueDofs(global_ess_markers, _ess_tdof_lists.at(i));
     147          41 :   }
     148          41 : }
     149             : 
     150             : void
     151          61 : ComplexEquationSystem::AddComplexKernel(std::shared_ptr<MFEMComplexKernel> kernel)
     152             : {
     153          61 :   const auto & trial_var_name = kernel->getTrialVariableName();
     154          61 :   const auto & test_var_name = kernel->getTestVariableName();
     155          61 :   AddCoupledVariableNameIfMissing(trial_var_name);
     156          61 :   AddTestVariableNameIfMissing(test_var_name);
     157             :   // Register new complex kernels map if not present for the test variable
     158          61 :   if (!_cmplx_kernels_map.Has(test_var_name))
     159             :   {
     160             :     auto kernel_field_map =
     161          41 :         std::make_shared<NamedFieldsMap<std::vector<std::shared_ptr<MFEMComplexKernel>>>>();
     162          41 :     _cmplx_kernels_map.Register(test_var_name, std::move(kernel_field_map));
     163          41 :   }
     164             :   // Register new complex kernels map if not present for the test/trial variable pair
     165          61 :   if (!_cmplx_kernels_map.Get(test_var_name)->Has(trial_var_name))
     166             :   {
     167          41 :     auto kernels = std::make_shared<std::vector<std::shared_ptr<MFEMComplexKernel>>>();
     168          41 :     _cmplx_kernels_map.Get(test_var_name)->Register(trial_var_name, std::move(kernels));
     169          41 :   }
     170          61 :   _cmplx_kernels_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(kernel));
     171          61 : }
     172             : 
     173             : void
     174          12 : ComplexEquationSystem::AddComplexIntegratedBC(std::shared_ptr<MFEMComplexIntegratedBC> bc)
     175             : {
     176          12 :   const auto & trial_var_name = bc->getTrialVariableName();
     177          12 :   const auto & test_var_name = bc->getTestVariableName();
     178          12 :   AddCoupledVariableNameIfMissing(trial_var_name);
     179          12 :   AddTestVariableNameIfMissing(test_var_name);
     180             :   // Register new complex integrated bc map if not present for the test variable
     181          12 :   if (!_cmplx_integrated_bc_map.Has(test_var_name))
     182             :   {
     183             :     auto integrated_bc_field_map =
     184           6 :         std::make_shared<NamedFieldsMap<std::vector<std::shared_ptr<MFEMComplexIntegratedBC>>>>();
     185           6 :     _cmplx_integrated_bc_map.Register(test_var_name, std::move(integrated_bc_field_map));
     186           6 :   }
     187             :   // Register new complex integrated bc map if not present for the test/trial variable pair
     188          12 :   if (!_cmplx_integrated_bc_map.Get(test_var_name)->Has(trial_var_name))
     189             :   {
     190           6 :     auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMComplexIntegratedBC>>>();
     191           6 :     _cmplx_integrated_bc_map.Get(test_var_name)->Register(trial_var_name, std::move(bcs));
     192           6 :   }
     193          12 :   _cmplx_integrated_bc_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(bc));
     194          12 : }
     195             : 
     196             : void
     197          62 : ComplexEquationSystem::AddComplexEssentialBCs(std::shared_ptr<MFEMComplexEssentialBC> bc)
     198             : {
     199          62 :   const auto & test_var_name = bc->getTestVariableName();
     200          62 :   AddTestVariableNameIfMissing(test_var_name);
     201             :   // Register new complex essential bc map if not present for the test variable
     202          62 :   if (!_cmplx_essential_bc_map.Has(test_var_name))
     203             :   {
     204          41 :     auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMComplexEssentialBC>>>();
     205          41 :     _cmplx_essential_bc_map.Register(test_var_name, std::move(bcs));
     206          41 :   }
     207          62 :   _cmplx_essential_bc_map.GetRef(test_var_name).push_back(std::move(bc));
     208          62 : }
     209             : 
     210             : void
     211           0 : ComplexEquationSystem::FormSystemOperator(mfem::OperatorHandle & op,
     212             :                                           mfem::BlockVector & trueX,
     213             :                                           mfem::BlockVector & trueRHS)
     214             : {
     215           0 :   auto & test_var_name = _test_var_names.at(0);
     216           0 :   mfem::Vector aux_x, aux_rhs;
     217           0 :   mfem::OperatorPtr aux_a;
     218             : 
     219           0 :   auto slf = _slfs.Get(test_var_name);
     220           0 :   slf->FormLinearSystem(_ess_tdof_lists.at(0),
     221           0 :                         *_cmplx_var_ess_constraints.at(0),
     222           0 :                         *_clfs.Get(test_var_name),
     223             :                         aux_a,
     224             :                         aux_x,
     225             :                         aux_rhs,
     226             :                         /*copy_interior=*/true);
     227             : 
     228           0 :   trueX.GetBlock(0) = aux_x;
     229           0 :   trueRHS.GetBlock(0) = aux_rhs;
     230           0 :   trueX.SyncFromBlocks();
     231           0 :   trueRHS.SyncFromBlocks();
     232             : 
     233           0 :   op.Reset(aux_a.Ptr());
     234           0 :   aux_a.SetOperatorOwner(false);
     235           0 : }
     236             : 
     237             : void
     238          41 : ComplexEquationSystem::FormSystemMatrix(mfem::OperatorHandle & op,
     239             :                                         mfem::BlockVector & trueX,
     240             :                                         mfem::BlockVector & trueRHS)
     241             : {
     242             : 
     243             :   // Allocate block operator
     244          41 :   DeleteHBlocks();
     245          41 :   _h_blocks.SetSize(_test_var_names.size(), _trial_var_names.size());
     246          41 :   _h_blocks = nullptr;
     247             :   // Zero out RHS and sync memory
     248          41 :   trueRHS = 0.0;
     249          41 :   trueRHS.SyncToBlocks();
     250             : 
     251             :   // Form diagonal blocks.
     252          82 :   for (const auto i : index_range(_test_var_names))
     253             :   {
     254          41 :     auto & test_var_name = _test_var_names.at(i);
     255             : 
     256          41 :     mfem::Vector aux_x, aux_rhs;
     257          41 :     mfem::OperatorHandle aux_a;
     258             : 
     259          41 :     auto slf = _slfs.Get(test_var_name);
     260          41 :     slf->FormLinearSystem(_ess_tdof_lists.at(i),
     261          41 :                           *_cmplx_var_ess_constraints.at(i),
     262          41 :                           *_clfs.Get(test_var_name),
     263             :                           aux_a,
     264             :                           aux_x,
     265             :                           aux_rhs,
     266             :                           /*copy_interior=*/true);
     267          41 :     trueX.GetBlock(i) = aux_x;
     268          41 :     trueRHS.GetBlock(i) = aux_rhs;
     269          41 :     _h_blocks(i, i) = aux_a.As<mfem::ComplexHypreParMatrix>()->GetSystemMatrix();
     270          41 :   }
     271             :   // Sync memory
     272          41 :   trueX.SyncFromBlocks();
     273          41 :   trueRHS.SyncFromBlocks();
     274             : 
     275             :   // Create monolithic matrix
     276          41 :   op.Reset(mfem::HypreParMatrixFromBlocks(_h_blocks));
     277          41 : }
     278             : 
     279             : // Equation system Mult
     280             : void
     281          82 : ComplexEquationSystem::Mult(const mfem::Vector & x, mfem::Vector & residual) const
     282             : {
     283          82 :   _linear_operator->Mult(x, residual);
     284          82 :   x.HostRead();
     285          82 :   residual.HostRead();
     286          82 : }
     287             : 
     288             : void
     289          41 : ComplexEquationSystem::SetTrialVariablesFromTrueVectors(const mfem::BlockVector & trueX) const
     290             : {
     291          82 :   for (const auto i : index_range(_trial_var_names))
     292             :   {
     293          41 :     auto & trial_var_name = _trial_var_names.at(i);
     294          41 :     trueX.GetBlock(i).SyncAliasMemory(trueX);
     295          41 :     _complex_gfuncs->Get(trial_var_name)->Distribute(&(trueX.GetBlock(i)));
     296             :   }
     297          41 : }
     298             : 
     299             : }
     300             : 
     301             : #endif

Generated by: LCOV version 1.14