LCOV - code coverage report
Current view: top level - src/meshmodifiers - SidesetAroundSubdomainUpdater.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 104 116 89.7 %
Date: 2025-07-17 01:28:37 Functions: 11 11 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             : #include "SidesetAroundSubdomainUpdater.h"
      11             : #include "DisplacedProblem.h"
      12             : #include "Assembly.h"
      13             : 
      14             : #include "libmesh/parallel_algebra.h"
      15             : #include "libmesh/parallel_sync.h"
      16             : 
      17             : registerMooseObject("MooseApp", SidesetAroundSubdomainUpdater);
      18             : 
      19             : InputParameters
      20       14523 : SidesetAroundSubdomainUpdater::validParams()
      21             : {
      22       14523 :   InputParameters params = DomainUserObject::validParams();
      23       14523 :   params.addClassDescription("Sets up a boundary between inner_subdomains and outer_subdomains");
      24       14523 :   params.addParam<std::vector<SubdomainName>>("inner_subdomains",
      25             :                                               "Subdomains that own the boundary");
      26       14523 :   params.addParam<std::vector<SubdomainName>>("outer_subdomains",
      27             :                                               "Subdomains on the outside of the boundary");
      28       14523 :   params.addParam<BoundaryName>("mask_side",
      29             :                                 "If specified, only add sides where this sideset exists.");
      30       43569 :   params.addParam<bool>("assign_outer_surface_sides",
      31       29046 :                         true,
      32             :                         "Assign sides of elements im `inner_subdomains` that have no neighbor.");
      33       14523 :   params.addRequiredParam<BoundaryName>("update_sideset_name",
      34             :                                         "The name of the sideset to be updated. If the boundary "
      35             :                                         "does not exist it will be added to the system.");
      36       14523 :   params.renameParam(
      37             :       "update_sideset_name", "update_boundary_name", "The boundary name which is updated.");
      38       14523 :   params.addParam<BoundaryID>("update_sideset_id",
      39             :                               Moose::INVALID_BOUNDARY_ID,
      40             :                               "The ID of the sideset to be updated. If the boundary "
      41             :                               "does not exist it will be added to the system.");
      42       14523 :   params.renameParam(
      43             :       "update_sideset_id", "update_boundary_id", "The boundary id which is updated.");
      44       14523 :   params.registerBase("MeshModifier");
      45       14523 :   return params;
      46           0 : }
      47             : 
      48         134 : SidesetAroundSubdomainUpdater::SidesetAroundSubdomainUpdater(const InputParameters & parameters)
      49             :   : DomainUserObject(parameters),
      50         268 :     _pid(_communicator.rank()),
      51         134 :     _displaced_problem(_fe_problem.getDisplacedProblem().get()),
      52         134 :     _neighbor_side(_assembly.neighborSide()),
      53         134 :     _assign_outer_surface_sides(getParam<bool>("assign_outer_surface_sides")),
      54         134 :     _boundary_name(getParam<BoundaryName>("update_boundary_name")),
      55         134 :     _boundary_id(_mesh.getBoundaryID(_boundary_name)),
      56         134 :     _mask_side(isParamValid("mask_side") ? _mesh.getBoundaryID(getParam<BoundaryName>("mask_side"))
      57             :                                          : Moose::INVALID_BOUNDARY_ID),
      58         134 :     _boundary_info(_mesh.getMesh().get_boundary_info()),
      59         134 :     _displaced_boundary_info(
      60         402 :         _displaced_problem ? &_displaced_problem->mesh().getMesh().get_boundary_info() : nullptr)
      61             : {
      62             :   // subdomains
      63         134 :   const auto & inner_subdomains = getParam<std::vector<SubdomainName>>("inner_subdomains");
      64         134 :   const auto & outer_subdomains = getParam<std::vector<SubdomainName>>("outer_subdomains");
      65         268 :   for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), inner_subdomains))
      66         268 :     _inner_ids.insert(id);
      67         268 :   for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), outer_subdomains))
      68         268 :     _outer_ids.insert(id);
      69         134 :   std::set<SubdomainID> mesh_subdomains = _mesh.meshSubdomains();
      70             : 
      71         268 :   for (const auto & id : _inner_ids)
      72         134 :     if (mesh_subdomains.find(id) == mesh_subdomains.end())
      73           0 :       paramError("inner_subdomains", "The block '", id, "' was not found in the mesh");
      74         268 :   for (const auto & id : _outer_ids)
      75         134 :     if (mesh_subdomains.find(id) == mesh_subdomains.end())
      76           0 :       paramError("outer_subdomains", "The block '", id, "' was not found in the mesh");
      77             : 
      78             :   // save boundary name
      79         134 :   _boundary_info.sideset_name(_boundary_id) = _boundary_name;
      80         134 :   _boundary_info.nodeset_name(_boundary_id) = _boundary_name;
      81         134 :   if (_displaced_boundary_info)
      82             :   {
      83           0 :     _displaced_boundary_info->sideset_name(_boundary_id) = _boundary_name;
      84           0 :     _displaced_boundary_info->nodeset_name(_boundary_id) = _boundary_name;
      85             :   }
      86         134 :   if (!_mesh.getConstructNodeListFromSideList())
      87           4 :     mooseDoOnce(
      88             :         mooseWarning("The user has selected 'construct_node_list_from_side_list' as false, but "
      89             :                      "SidesetAroundSubdomainUpdate is building node lists from the side lists."));
      90         130 : }
      91             : 
      92             : void
      93        5472 : SidesetAroundSubdomainUpdater::executeOnExternalSide(const Elem * elem, unsigned int side)
      94             : {
      95             :   // we should add the sideset only of the current element is in the "inner" set _and_ the user set
      96             :   // assign_surface_sides
      97        5472 :   if (_inner_ids.count(elem->subdomain_id()))
      98             :   {
      99        7584 :     if (_assign_outer_surface_sides && !_boundary_info.has_boundary_id(elem, side, _boundary_id) &&
     100        3184 :         (_mask_side == Moose::INVALID_BOUNDARY_ID ||
     101        1792 :          _boundary_info.has_boundary_id(elem, side, _mask_side)))
     102        1456 :       _add[_pid].emplace_back(elem->id(), side);
     103             :   }
     104             :   else
     105             :   {
     106        1072 :     if (_boundary_info.has_boundary_id(elem, side, _boundary_id))
     107         208 :       _remove[_pid].emplace_back(elem->id(), side);
     108             :   }
     109        5472 : }
     110             : 
     111             : void
     112        9296 : SidesetAroundSubdomainUpdater::executeOnInternalSide()
     113             : {
     114        9296 :   processSide(_current_elem, _current_side, _neighbor_elem);
     115        9296 :   processSide(_neighbor_elem, _neighbor_side, _current_elem);
     116        9296 : }
     117             : 
     118             : void
     119       18592 : SidesetAroundSubdomainUpdater::processSide(const Elem * primary_elem,
     120             :                                            unsigned short int primary_side,
     121             :                                            const Elem * secondary_elem)
     122             : {
     123             :   // undisplaced mesh
     124       33136 :   if (_inner_ids.count(primary_elem->subdomain_id()) &&
     125       33136 :       _outer_ids.count(secondary_elem->subdomain_id()))
     126             :   {
     127             : 
     128             :     // we are on an inner element facing an outer element->add boundary
     129       19720 :     if ((!_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id)) &&
     130        9848 :         (_mask_side == Moose::INVALID_BOUNDARY_ID ||
     131        1024 :          _boundary_info.has_boundary_id(primary_elem, primary_side, _mask_side)))
     132        8824 :       _add[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
     133             :   }
     134             :   else
     135             :   {
     136             :     // we are on an outer, between inner elements, or other elements etc., delete
     137             :     // the boundary for sure
     138        8720 :     if (_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id))
     139         128 :       _remove[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
     140             :   }
     141       18592 : }
     142             : 
     143             : void
     144         492 : SidesetAroundSubdomainUpdater::initialize()
     145             : {
     146         492 :   _add.clear();
     147         492 :   _remove.clear();
     148         492 : }
     149             : 
     150             : void
     151          41 : SidesetAroundSubdomainUpdater::threadJoin(const UserObject & uo)
     152             : {
     153          41 :   const auto & sas = static_cast<const SidesetAroundSubdomainUpdater &>(uo);
     154             : 
     155          59 :   for (const auto & [pid, list] : sas._add)
     156          18 :     _add[pid].insert(_add[pid].end(), list.begin(), list.end());
     157             : 
     158          55 :   for (const auto & [pid, list] : sas._remove)
     159          14 :     _remove[pid].insert(_remove[pid].end(), list.begin(), list.end());
     160          41 : }
     161             : 
     162             : void
     163         451 : SidesetAroundSubdomainUpdater::finalize()
     164             : {
     165         451 :   const auto & mesh = _mesh.getMesh();
     166             :   const auto * displaced_mesh =
     167         451 :       _displaced_problem ? &_displaced_problem->mesh().getMesh() : nullptr;
     168             : 
     169       20741 :   auto add_functor = [this, &mesh, &displaced_mesh](const processor_id_type, const auto & sent_data)
     170             :   {
     171       10461 :     for (auto & [elem_id, side] : sent_data)
     172             :     {
     173       10280 :       _boundary_info.add_side(mesh.elem_ptr(elem_id), side, _boundary_id);
     174       10280 :       if (_displaced_boundary_info)
     175           0 :         _displaced_boundary_info->add_side(displaced_mesh->elem_ptr(elem_id), side, _boundary_id);
     176             :     }
     177         181 :   };
     178             : 
     179             :   auto remove_functor =
     180        1799 :       [this, &mesh, &displaced_mesh](const processor_id_type, const SideList & sent_data)
     181             :   {
     182         455 :     for (const auto & [elem_id, side] : sent_data)
     183             :     {
     184         336 :       const auto elem = mesh.elem_ptr(elem_id);
     185         336 :       _boundary_info.remove_side(elem, side, _boundary_id);
     186        1008 :       for (const auto local_node_id : elem->nodes_on_side(side))
     187        1008 :         _boundary_info.remove_node(elem->node_ptr(local_node_id), _boundary_id);
     188         336 :       if (_displaced_boundary_info)
     189             :       {
     190           0 :         const auto displaced_elem = displaced_mesh->elem_ptr(elem_id);
     191           0 :         _displaced_boundary_info->remove_side(displaced_elem, side, _boundary_id);
     192           0 :         for (const auto local_node_id : displaced_elem->nodes_on_side(side))
     193           0 :           _displaced_boundary_info->remove_node(displaced_elem->node_ptr(local_node_id),
     194           0 :                                                 _boundary_id);
     195             :       }
     196             :     }
     197         119 :   };
     198             : 
     199             :   // communicate and act on remote and local changes
     200         451 :   TIMPI::push_parallel_vector_data(_communicator, _remove, remove_functor);
     201         451 :   TIMPI::push_parallel_vector_data(_communicator, _add, add_functor);
     202             : 
     203         451 :   auto sync = [](auto & mesh)
     204             :   {
     205         451 :     mesh.getMesh().get_boundary_info().parallel_sync_side_ids();
     206         451 :     mesh.getMesh().get_boundary_info().parallel_sync_node_ids();
     207         451 :     mesh.getMesh().get_boundary_info().build_node_list_from_side_list();
     208         451 :     mesh.update();
     209         451 :   };
     210         451 :   sync(_mesh);
     211         451 :   if (_displaced_problem)
     212           0 :     sync(_displaced_problem->mesh());
     213             : 
     214             :   // Reinit equation systems
     215         451 :   _fe_problem.meshChanged(
     216             :       /*intermediate_change=*/false, /*contract_mesh=*/false, /*clean_refinement_flags=*/false);
     217         451 : }

Generated by: LCOV version 1.14