LCOV - code coverage report
Current view: top level - src/mfem/equation_systems - PatchedMixedBilinearForm.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32463 (9b8a52) with base a052fd Lines: 50 201 24.9 %
Date: 2026-05-26 14:49:46 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #ifdef MOOSE_MFEM_ENABLED
      11             : 
      12             : #include "PatchedMixedBilinearForm.h"
      13             : 
      14             : namespace Moose::MFEM
      15             : {
      16             : 
      17             : void
      18         173 : ParMixedBilinearForm::Assemble(int skip_zeros)
      19             : {
      20         173 :   if (interior_face_integs.Size())
      21             :   {
      22           0 :     trial_pfes->ExchangeFaceNbrData();
      23           0 :     test_pfes->ExchangeFaceNbrData();
      24           0 :     if (!ext && mat == NULL)
      25             :     {
      26           0 :       pAllocMat();
      27             :     }
      28             :   }
      29             : 
      30             :   // Call SubMeshTolerantAssemble if trial_pfes is defined on a submesh of the mesh
      31             :   // on which test_pfes is defined, else default to MixedBilinearForm::Assemble
      32             :   // as usual
      33         184 :   if ((trial_pfes->GetParMesh() != test_pfes->GetParMesh()) &&
      34          11 :       mfem::ParSubMesh::IsParSubMesh(trial_pfes->GetParMesh(), test_pfes->GetParMesh()))
      35          11 :     SubMeshTolerantAssemble(skip_zeros);
      36             :   else
      37         162 :     MixedBilinearForm::Assemble(skip_zeros);
      38             : 
      39         173 :   if (!ext && interior_face_integs.Size() > 0)
      40             :   {
      41           0 :     AssembleSharedFaces(skip_zeros);
      42             :   }
      43         173 : }
      44             : 
      45             : void
      46          11 : ParMixedBilinearForm::SubMeshTolerantAssemble(int skip_zeros)
      47             : {
      48          11 :   if (ext)
      49             :   {
      50           0 :     ext->Assemble();
      51           0 :     return;
      52             :   }
      53             : 
      54             :   mfem::ElementTransformation * eltrans;
      55          11 :   mfem::DenseMatrix elmat;
      56             : 
      57             :   // For usual mfem::MixedBilinearFormAssemble, the iterated FESpace is test_fes
      58          11 :   mfem::FiniteElementSpace & iterated_fes = *trial_fes;
      59          11 :   mfem::Mesh * mesh = iterated_fes.GetMesh();
      60          11 :   const auto * trial_submesh = static_cast<const mfem::ParSubMesh *>(trial_pfes->GetParMesh());
      61          11 :   const auto * trial_parent_mesh = trial_submesh->GetParent();
      62          11 :   const auto & test_element_ids = trial_submesh->GetParentElementIDMap();
      63          11 :   const auto & test_face_ids = trial_submesh->GetParentFaceIDMap();
      64          11 :   const auto & test_edge_ids = trial_submesh->GetParentEdgeIDMap();
      65          11 :   const auto & test_vertex_ids = trial_submesh->GetParentVertexIDMap();
      66          11 :   const auto & test_face_to_be = trial_parent_mesh->GetFaceToBdrElMap();
      67          11 :   const int num_elem = iterated_fes.GetNE();
      68          11 :   const int num_boundary_elem = iterated_fes.GetNBE();
      69             : 
      70          11 :   if (mat == NULL)
      71             :   {
      72          11 :     mat = new mfem::SparseMatrix(height, width);
      73             :   }
      74             : 
      75          11 :   if (domain_integs.Size())
      76             :   {
      77          22 :     for (int k = 0; k < domain_integs.Size(); k++)
      78             :     {
      79          11 :       if (domain_integs_marker[k] != NULL)
      80             :       {
      81           0 :         MFEM_VERIFY(domain_integs_marker[k]->Size() ==
      82             :                         (mesh->attributes.Size() ? mesh->attributes.Max() : 0),
      83             :                     "invalid element marker for domain integrator #" << k
      84             :                                                                      << ", counting from zero");
      85             :       }
      86             :     }
      87             : 
      88          11 :     mfem::DofTransformation dom_dof_trans, ran_dof_trans;
      89        1019 :     for (int i = 0; i < num_elem; i++)
      90             :     {
      91        1008 :       const int test_elem_id = test_element_ids[i];
      92        1008 :       const int elem_attr = mesh->GetAttribute(i);
      93        1008 :       trial_fes->GetElementVDofs(i, trial_vdofs, dom_dof_trans);
      94        1008 :       test_fes->GetElementVDofs(test_elem_id, test_vdofs, ran_dof_trans);
      95        1008 :       eltrans = iterated_fes.GetElementTransformation(i);
      96             : 
      97        1008 :       elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
      98        1008 :       elmat = 0.0;
      99        2016 :       for (int k = 0; k < domain_integs.Size(); k++)
     100             :       {
     101        1008 :         if (domain_integs_marker[k] == NULL || (*(domain_integs_marker[k]))[elem_attr - 1] == 1)
     102             :         {
     103        1008 :           domain_integs[k]->AssembleElementMatrix2(
     104        1008 :               *trial_fes->GetFE(i), *test_fes->GetFE(test_elem_id), *eltrans, elemmat);
     105        1008 :           elmat += elemmat;
     106             :         }
     107             :       }
     108        1008 :       TransformDual(ran_dof_trans, dom_dof_trans, elmat);
     109        1008 :       mat->AddSubMatrix(test_vdofs, trial_vdofs, elmat, skip_zeros);
     110             :     }
     111          11 :   }
     112             : 
     113          11 :   if (boundary_integs.Size())
     114             :   {
     115             :     // Which boundary attributes need to be processed?
     116           0 :     mfem::Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ? mesh->bdr_attributes.Max() : 0);
     117           0 :     bdr_attr_marker = 0;
     118           0 :     for (int k = 0; k < boundary_integs.Size(); k++)
     119             :     {
     120           0 :       if (boundary_integs_marker[k] == NULL)
     121             :       {
     122           0 :         bdr_attr_marker = 1;
     123           0 :         break;
     124             :       }
     125           0 :       mfem::Array<int> & bdr_marker = *boundary_integs_marker[k];
     126             :       MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
     127             :                   "invalid boundary marker for boundary integrator #" << k
     128             :                                                                       << ", counting from zero");
     129           0 :       for (int i = 0; i < bdr_attr_marker.Size(); i++)
     130             :       {
     131           0 :         bdr_attr_marker[i] |= bdr_marker[i];
     132             :       }
     133             :     }
     134             : 
     135           0 :     mfem::DofTransformation dom_dof_trans, ran_dof_trans;
     136           0 :     for (int i = 0; i < num_boundary_elem; i++)
     137             :     {
     138           0 :       const int iface = mesh->GetBdrElementFaceIndex(i);
     139           0 :       const int test_face_id = mesh->Dimension() == 3   ? test_face_ids[iface]
     140           0 :                                : mesh->Dimension() == 2 ? test_edge_ids[iface]
     141           0 :                                                         : test_vertex_ids[iface];
     142           0 :       const int test_bdr_elem_id = test_face_to_be[test_face_id];
     143           0 :       const int bdr_attr = mesh->GetBdrAttribute(i);
     144           0 :       if (bdr_attr_marker[bdr_attr - 1] == 0)
     145             :       {
     146           0 :         continue;
     147             :       }
     148           0 :       MFEM_VERIFY(test_bdr_elem_id != -1,
     149             :                   "Cannot assemble a mixed boundary integrator from submesh boundary element "
     150             :                       << i << " because it does not correspond to a parent boundary element.");
     151             : 
     152           0 :       trial_fes->GetBdrElementVDofs(i, trial_vdofs, dom_dof_trans);
     153           0 :       test_fes->GetBdrElementVDofs(test_bdr_elem_id, test_vdofs, ran_dof_trans);
     154           0 :       eltrans = iterated_fes.GetBdrElementTransformation(i);
     155             : 
     156           0 :       elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
     157           0 :       elmat = 0.0;
     158           0 :       for (int k = 0; k < boundary_integs.Size(); k++)
     159             :       {
     160           0 :         if (boundary_integs_marker[k] && (*boundary_integs_marker[k])[bdr_attr - 1] == 0)
     161             :         {
     162           0 :           continue;
     163             :         }
     164             : 
     165           0 :         boundary_integs[k]->AssembleElementMatrix2(
     166           0 :             *trial_fes->GetBE(i), *test_fes->GetBE(test_bdr_elem_id), *eltrans, elemmat);
     167           0 :         elmat += elemmat;
     168             :       }
     169           0 :       TransformDual(ran_dof_trans, dom_dof_trans, elmat);
     170           0 :       mat->AddSubMatrix(test_vdofs, trial_vdofs, elmat, skip_zeros);
     171             :     }
     172           0 :   }
     173             : 
     174          11 :   if (interior_face_integs.Size())
     175             :   {
     176             :     mfem::FaceElementTransformations * ftr;
     177           0 :     mfem::Array<int> trial_vdofs2, test_vdofs2;
     178             :     const mfem::FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
     179             : 
     180           0 :     int nfaces = mesh->GetNumFaces();
     181           0 :     for (int i = 0; i < nfaces; i++)
     182             :     {
     183           0 :       ftr = mesh->GetInteriorFaceTransformations(i);
     184           0 :       if (ftr != NULL)
     185             :       {
     186           0 :         const int test_elem_1 = test_element_ids[ftr->Elem1No];
     187           0 :         trial_fes->GetElementVDofs(ftr->Elem1No, trial_vdofs);
     188           0 :         test_fes->GetElementVDofs(test_elem_1, test_vdofs);
     189           0 :         trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
     190           0 :         test_fe1 = test_fes->GetFE(test_elem_1);
     191           0 :         if (ftr->Elem2No >= 0)
     192             :         {
     193           0 :           const int test_elem_2 = test_element_ids[ftr->Elem2No];
     194           0 :           trial_fes->GetElementVDofs(ftr->Elem2No, trial_vdofs2);
     195           0 :           test_fes->GetElementVDofs(test_elem_2, test_vdofs2);
     196           0 :           trial_vdofs.Append(trial_vdofs2);
     197           0 :           test_vdofs.Append(test_vdofs2);
     198           0 :           trial_fe2 = trial_fes->GetFE(ftr->Elem2No);
     199           0 :           test_fe2 = test_fes->GetFE(test_elem_2);
     200             :         }
     201             :         else
     202             :         {
     203             :           // The test_fe2 object is really a dummy and not used on the
     204             :           // boundaries, but we can't dereference a NULL pointer, and we don't
     205             :           // want to actually make a fake element.
     206           0 :           trial_fe2 = trial_fe1;
     207           0 :           test_fe2 = test_fe1;
     208             :         }
     209           0 :         for (int k = 0; k < interior_face_integs.Size(); k++)
     210             :         {
     211           0 :           interior_face_integs[k]->AssembleFaceMatrix(
     212           0 :               *trial_fe1, *test_fe1, *trial_fe2, *test_fe2, *ftr, elemmat);
     213           0 :           mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
     214             :         }
     215             :       }
     216             :     }
     217           0 :   }
     218             : 
     219          11 :   if (boundary_face_integs.Size())
     220             :   {
     221             :     mfem::FaceElementTransformations * ftr;
     222           0 :     mfem::Array<int> tr_vdofs2, te_vdofs2;
     223             :     const mfem::FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
     224             : 
     225             :     // Which boundary attributes need to be processed?
     226           0 :     mfem::Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ? mesh->bdr_attributes.Max() : 0);
     227           0 :     bdr_attr_marker = 0;
     228           0 :     for (int k = 0; k < boundary_face_integs.Size(); k++)
     229             :     {
     230           0 :       if (boundary_face_integs_marker[k] == NULL)
     231             :       {
     232           0 :         bdr_attr_marker = 1;
     233           0 :         break;
     234             :       }
     235           0 :       mfem::Array<int> & bdr_marker = *boundary_face_integs_marker[k];
     236             :       MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
     237             :                   "invalid boundary marker for boundary face integrator #"
     238             :                       << k << ", counting from zero");
     239           0 :       for (int i = 0; i < bdr_attr_marker.Size(); i++)
     240             :       {
     241           0 :         bdr_attr_marker[i] |= bdr_marker[i];
     242             :       }
     243             :     }
     244             : 
     245           0 :     mfem::DofTransformation dom_dof_trans, ran_dof_trans;
     246           0 :     for (int i = 0; i < trial_fes->GetNBE(); i++)
     247             :     {
     248           0 :       const int bdr_attr = mesh->GetBdrAttribute(i);
     249           0 :       if (bdr_attr_marker[bdr_attr - 1] == 0)
     250             :       {
     251           0 :         continue;
     252             :       }
     253             : 
     254           0 :       ftr = mesh->GetBdrFaceTransformations(i);
     255           0 :       if (ftr != NULL)
     256             :       {
     257           0 :         const int test_elem_1 = test_element_ids[ftr->Elem1No];
     258           0 :         trial_fes->GetElementVDofs(ftr->Elem1No, trial_vdofs, dom_dof_trans);
     259           0 :         test_fes->GetElementVDofs(test_elem_1, test_vdofs, ran_dof_trans);
     260           0 :         trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
     261           0 :         test_fe1 = test_fes->GetFE(test_elem_1);
     262             :         // The test_fe2 object is really a dummy and not used on the
     263             :         // boundaries, but we can't dereference a NULL pointer, and we don't
     264             :         // want to actually make a fake element.
     265           0 :         trial_fe2 = trial_fe1;
     266           0 :         test_fe2 = test_fe1;
     267           0 :         for (int k = 0; k < boundary_face_integs.Size(); k++)
     268             :         {
     269           0 :           if (boundary_face_integs_marker[k] &&
     270           0 :               (*boundary_face_integs_marker[k])[bdr_attr - 1] == 0)
     271             :           {
     272           0 :             continue;
     273             :           }
     274             : 
     275           0 :           boundary_face_integs[k]->AssembleFaceMatrix(
     276           0 :               *trial_fe1, *test_fe1, *trial_fe2, *test_fe2, *ftr, elemmat);
     277           0 :           TransformDual(ran_dof_trans, dom_dof_trans, elemmat);
     278           0 :           mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
     279             :         }
     280             :       }
     281             :     }
     282           0 :   }
     283             : 
     284          11 :   if (trace_face_integs.Size())
     285             :   {
     286             :     mfem::FaceElementTransformations * ftr;
     287           0 :     mfem::Array<int> test_vdofs2;
     288             :     const mfem::FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
     289             : 
     290           0 :     int nfaces = mesh->GetNumFaces();
     291           0 :     for (int i = 0; i < nfaces; i++)
     292             :     {
     293           0 :       ftr = mesh->GetFaceElementTransformations(i);
     294           0 :       const int test_elem_1 = test_element_ids[ftr->Elem1No];
     295           0 :       trial_fes->GetFaceVDofs(i, trial_vdofs);
     296           0 :       test_fes->GetElementVDofs(test_elem_1, test_vdofs);
     297           0 :       trial_face_fe = trial_fes->GetFaceElement(i);
     298           0 :       test_fe1 = test_fes->GetFE(test_elem_1);
     299           0 :       if (ftr->Elem2No >= 0)
     300             :       {
     301           0 :         const int test_elem_2 = test_element_ids[ftr->Elem2No];
     302           0 :         test_fes->GetElementVDofs(test_elem_2, test_vdofs2);
     303           0 :         test_vdofs.Append(test_vdofs2);
     304           0 :         test_fe2 = test_fes->GetFE(test_elem_2);
     305             :       }
     306             :       else
     307             :       {
     308             :         // The test_fe2 object is really a dummy and not used on the
     309             :         // boundaries, but we can't dereference a NULL pointer, and we don't
     310             :         // want to actually make a fake element.
     311           0 :         test_fe2 = test_fe1;
     312             :       }
     313           0 :       for (int k = 0; k < trace_face_integs.Size(); k++)
     314             :       {
     315           0 :         trace_face_integs[k]->AssembleFaceMatrix(
     316           0 :             *trial_face_fe, *test_fe1, *test_fe2, *ftr, elemmat);
     317           0 :         mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
     318             :       }
     319             :     }
     320           0 :   }
     321             : 
     322          11 :   if (boundary_trace_face_integs.Size())
     323             :   {
     324             :     mfem::FaceElementTransformations * ftr;
     325           0 :     mfem::Array<int> te_vdofs2;
     326             :     const mfem::FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
     327             : 
     328             :     // Which boundary attributes need to be processed?
     329           0 :     mfem::Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ? mesh->bdr_attributes.Max() : 0);
     330           0 :     bdr_attr_marker = 0;
     331           0 :     for (int k = 0; k < boundary_trace_face_integs.Size(); k++)
     332             :     {
     333           0 :       if (boundary_trace_face_integs_marker[k] == NULL)
     334             :       {
     335           0 :         bdr_attr_marker = 1;
     336           0 :         break;
     337             :       }
     338           0 :       mfem::Array<int> & bdr_marker = *boundary_trace_face_integs_marker[k];
     339             :       MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
     340             :                   "invalid boundary marker for boundary trace face"
     341             :                   "integrator #"
     342             :                       << k << ", counting from zero");
     343           0 :       for (int i = 0; i < bdr_attr_marker.Size(); i++)
     344             :       {
     345           0 :         bdr_attr_marker[i] |= bdr_marker[i];
     346             :       }
     347             :     }
     348             : 
     349           0 :     for (int i = 0; i < trial_fes->GetNBE(); i++)
     350             :     {
     351           0 :       const int bdr_attr = mesh->GetBdrAttribute(i);
     352           0 :       if (bdr_attr_marker[bdr_attr - 1] == 0)
     353             :       {
     354           0 :         continue;
     355             :       }
     356             : 
     357           0 :       ftr = mesh->GetBdrFaceTransformations(i);
     358           0 :       if (ftr)
     359             :       {
     360           0 :         const int iface = mesh->GetBdrElementFaceIndex(i);
     361           0 :         const int test_elem_1 = test_element_ids[ftr->Elem1No];
     362           0 :         trial_fes->GetFaceVDofs(iface, trial_vdofs);
     363           0 :         test_fes->GetElementVDofs(test_elem_1, test_vdofs);
     364           0 :         trial_face_fe = trial_fes->GetFaceElement(iface);
     365           0 :         test_fe1 = test_fes->GetFE(test_elem_1);
     366             :         // The test_fe2 object is really a dummy and not used on the
     367             :         // boundaries, but we can't dereference a NULL pointer, and we don't
     368             :         // want to actually make a fake element.
     369           0 :         test_fe2 = test_fe1;
     370           0 :         for (int k = 0; k < boundary_trace_face_integs.Size(); k++)
     371             :         {
     372           0 :           if (boundary_trace_face_integs_marker[k] &&
     373           0 :               (*boundary_trace_face_integs_marker[k])[bdr_attr - 1] == 0)
     374             :           {
     375           0 :             continue;
     376             :           }
     377             : 
     378           0 :           boundary_trace_face_integs[k]->AssembleFaceMatrix(
     379           0 :               *trial_face_fe, *test_fe1, *test_fe2, *ftr, elemmat);
     380           0 :           mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
     381             :         }
     382             :       }
     383             :     }
     384           0 :   }
     385          11 : }
     386             : 
     387             : } // namespace Moose::MFEM
     388             : 
     389             : #endif

Generated by: LCOV version 1.14