LCOV - code coverage report
Current view: top level - src/meshmodifiers - SidesetAroundSubdomainUpdater.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: fef103 Lines: 106 130 81.5 %
Date: 2025-09-03 20:01:23 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       14537 : SidesetAroundSubdomainUpdater::validParams()
      21             : {
      22       14537 :   InputParameters params = DomainUserObject::validParams();
      23       29074 :   params.addClassDescription("Sets up a boundary between inner_subdomains and outer_subdomains");
      24       58148 :   params.addParam<std::vector<SubdomainName>>("inner_subdomains",
      25             :                                               "Subdomains that own the boundary");
      26       58148 :   params.addParam<std::vector<SubdomainName>>("outer_subdomains",
      27             :                                               "Subdomains on the outside of the boundary");
      28       58148 :   params.addParam<BoundaryName>("mask_side",
      29             :                                 "If specified, only add sides where this sideset exists.");
      30       43611 :   params.addParam<bool>("assign_outer_surface_sides",
      31       29074 :                         true,
      32             :                         "Assign sides of elements im `inner_subdomains` that have no neighbor.");
      33       58148 :   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       87222 :   params.renameParam(
      37             :       "update_sideset_name", "update_boundary_name", "The boundary name which is updated.");
      38       58148 :   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       87222 :   params.renameParam(
      43             :       "update_sideset_id", "update_boundary_id", "The boundary id which is updated.");
      44       29074 :   params.registerBase("MeshModifier");
      45       43611 :   params.addParam<bool>("verbose", false, "Whether to output some information during execution");
      46       14537 :   return params;
      47           0 : }
      48             : 
      49         141 : SidesetAroundSubdomainUpdater::SidesetAroundSubdomainUpdater(const InputParameters & parameters)
      50             :   : DomainUserObject(parameters),
      51         282 :     _pid(_communicator.rank()),
      52         141 :     _displaced_problem(_fe_problem.getDisplacedProblem().get()),
      53         141 :     _neighbor_side(_assembly.neighborSide()),
      54         282 :     _assign_outer_surface_sides(getParam<bool>("assign_outer_surface_sides")),
      55         282 :     _boundary_name(getParam<BoundaryName>("update_boundary_name")),
      56         141 :     _boundary_id(_mesh.getBoundaryID(_boundary_name)),
      57         346 :     _mask_side(isParamValid("mask_side") ? _mesh.getBoundaryID(getParam<BoundaryName>("mask_side"))
      58             :                                          : Moose::INVALID_BOUNDARY_ID),
      59         141 :     _boundary_info(_mesh.getMesh().get_boundary_info()),
      60         141 :     _displaced_boundary_info(
      61         423 :         _displaced_problem ? &_displaced_problem->mesh().getMesh().get_boundary_info() : nullptr)
      62             : {
      63             :   // subdomains
      64         282 :   const auto & inner_subdomains = getParam<std::vector<SubdomainName>>("inner_subdomains");
      65         282 :   const auto & outer_subdomains = getParam<std::vector<SubdomainName>>("outer_subdomains");
      66         282 :   for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), inner_subdomains))
      67         282 :     _inner_ids.insert(id);
      68         282 :   for (const auto id : MooseMeshUtils::getSubdomainIDs(_mesh.getMesh(), outer_subdomains))
      69         282 :     _outer_ids.insert(id);
      70         141 :   std::set<SubdomainID> mesh_subdomains = _mesh.meshSubdomains();
      71             : 
      72         282 :   for (const auto & id : _inner_ids)
      73         141 :     if (mesh_subdomains.find(id) == mesh_subdomains.end())
      74           0 :       paramError("inner_subdomains", "The block '", id, "' was not found in the mesh");
      75         282 :   for (const auto & id : _outer_ids)
      76         141 :     if (mesh_subdomains.find(id) == mesh_subdomains.end())
      77           0 :       paramError("outer_subdomains", "The block '", id, "' was not found in the mesh");
      78             : 
      79             :   // save boundary name
      80         141 :   _boundary_info.sideset_name(_boundary_id) = _boundary_name;
      81         141 :   _boundary_info.nodeset_name(_boundary_id) = _boundary_name;
      82         141 :   if (_displaced_boundary_info)
      83             :   {
      84           0 :     _displaced_boundary_info->sideset_name(_boundary_id) = _boundary_name;
      85           0 :     _displaced_boundary_info->nodeset_name(_boundary_id) = _boundary_name;
      86             :   }
      87         141 :   if (!_mesh.getConstructNodeListFromSideList())
      88           4 :     mooseDoOnce(
      89             :         mooseWarning("The user has selected 'construct_node_list_from_side_list' as false, but "
      90             :                      "SidesetAroundSubdomainUpdate is building node lists from the side lists."));
      91         137 : }
      92             : 
      93             : void
      94        6056 : SidesetAroundSubdomainUpdater::executeOnExternalSide(const Elem * elem, unsigned int side)
      95             : {
      96             :   // we should add the sideset only of the current element is in the "inner" set _and_ the user set
      97             :   // assign_surface_sides
      98        6056 :   if (_inner_ids.count(elem->subdomain_id()))
      99             :   {
     100        8437 :     if (_assign_outer_surface_sides && !_boundary_info.has_boundary_id(elem, side, _boundary_id) &&
     101        3565 :         (_mask_side == Moose::INVALID_BOUNDARY_ID ||
     102        2034 :          _boundary_info.has_boundary_id(elem, side, _mask_side)))
     103        1603 :       _add[_pid].emplace_back(elem->id(), side);
     104             :   }
     105             :   else
     106             :   {
     107        1184 :     if (_boundary_info.has_boundary_id(elem, side, _boundary_id))
     108         229 :       _remove[_pid].emplace_back(elem->id(), side);
     109             :   }
     110        6056 : }
     111             : 
     112             : void
     113       10452 : SidesetAroundSubdomainUpdater::executeOnInternalSide()
     114             : {
     115       10452 :   processSide(_current_elem, _current_side, _neighbor_elem);
     116       10452 :   processSide(_neighbor_elem, _neighbor_side, _current_elem);
     117       10452 : }
     118             : 
     119             : void
     120       20904 : SidesetAroundSubdomainUpdater::processSide(const Elem * primary_elem,
     121             :                                            unsigned short int primary_side,
     122             :                                            const Elem * secondary_elem)
     123             : {
     124             :   // undisplaced mesh
     125       37216 :   if (_inner_ids.count(primary_elem->subdomain_id()) &&
     126       37216 :       _outer_ids.count(secondary_elem->subdomain_id()))
     127             :   {
     128             : 
     129             :     // we are on an inner element facing an outer element->add boundary
     130       22208 :     if ((!_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id)) &&
     131       11092 :         (_mask_side == Moose::INVALID_BOUNDARY_ID ||
     132        1168 :          _boundary_info.has_boundary_id(primary_elem, primary_side, _mask_side)))
     133        9924 :       _add[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
     134             :   }
     135             :   else
     136             :   {
     137             :     // we are on an outer, between inner elements, or other elements etc., delete
     138             :     // the boundary for sure
     139        9788 :     if (_boundary_info.has_boundary_id(primary_elem, primary_side, _boundary_id))
     140         144 :       _remove[primary_elem->processor_id()].emplace_back(primary_elem->id(), primary_side);
     141             :   }
     142       20904 : }
     143             : 
     144             : void
     145         529 : SidesetAroundSubdomainUpdater::initialize()
     146             : {
     147         529 :   _add.clear();
     148         529 :   _remove.clear();
     149         529 : }
     150             : 
     151             : void
     152          41 : SidesetAroundSubdomainUpdater::threadJoin(const UserObject & uo)
     153             : {
     154          41 :   const auto & sas = static_cast<const SidesetAroundSubdomainUpdater &>(uo);
     155             : 
     156          59 :   for (const auto & [pid, list] : sas._add)
     157          18 :     _add[pid].insert(_add[pid].end(), list.begin(), list.end());
     158             : 
     159          55 :   for (const auto & [pid, list] : sas._remove)
     160          14 :     _remove[pid].insert(_remove[pid].end(), list.begin(), list.end());
     161          41 : }
     162             : 
     163             : void
     164         488 : SidesetAroundSubdomainUpdater::finalize()
     165             : {
     166         488 :   const auto & mesh = _mesh.getMesh();
     167             :   const auto * displaced_mesh =
     168         488 :       _displaced_problem ? &_displaced_problem->mesh().getMesh() : nullptr;
     169        1464 :   if (getParam<bool>("verbose"))
     170             :   {
     171           0 :     unsigned int total_remove = 0, total_add = 0;
     172           0 :     for (const auto & [pid, list] : _remove)
     173           0 :       total_remove += _remove[pid].size();
     174           0 :     for (const auto & [pid, list] : _add)
     175           0 :       total_add += _add[pid].size();
     176           0 :     comm().sum(total_remove);
     177           0 :     comm().sum(total_add);
     178             : 
     179           0 :     if (total_remove)
     180           0 :       _console << "Removing " << total_remove << " sides from sideset " << _boundary_id
     181           0 :                << std::endl;
     182           0 :     if (total_add)
     183           0 :       _console << "Adding " << total_add << " sides to sideset " << _boundary_id << std::endl;
     184             :   }
     185             : 
     186         196 :   auto add_functor = [this, &mesh, &displaced_mesh](const processor_id_type, const auto & sent_data)
     187             :   {
     188       11723 :     for (auto & [elem_id, side] : sent_data)
     189             :     {
     190       11527 :       _boundary_info.add_side(mesh.elem_ptr(elem_id), side, _boundary_id);
     191       11527 :       if (_displaced_boundary_info)
     192           0 :         _displaced_boundary_info->add_side(displaced_mesh->elem_ptr(elem_id), side, _boundary_id);
     193             :     }
     194         196 :   };
     195             : 
     196             :   auto remove_functor =
     197         130 :       [this, &mesh, &displaced_mesh](const processor_id_type, const SideList & sent_data)
     198             :   {
     199         503 :     for (const auto & [elem_id, side] : sent_data)
     200             :     {
     201         373 :       const auto elem = mesh.elem_ptr(elem_id);
     202         373 :       _boundary_info.remove_side(elem, side, _boundary_id);
     203        1119 :       for (const auto local_node_id : elem->nodes_on_side(side))
     204        1119 :         _boundary_info.remove_node(elem->node_ptr(local_node_id), _boundary_id);
     205         373 :       if (_displaced_boundary_info)
     206             :       {
     207           0 :         const auto displaced_elem = displaced_mesh->elem_ptr(elem_id);
     208           0 :         _displaced_boundary_info->remove_side(displaced_elem, side, _boundary_id);
     209           0 :         for (const auto local_node_id : displaced_elem->nodes_on_side(side))
     210           0 :           _displaced_boundary_info->remove_node(displaced_elem->node_ptr(local_node_id),
     211           0 :                                                 _boundary_id);
     212             :       }
     213             :     }
     214         130 :   };
     215             : 
     216             :   // communicate and act on remote and local changes
     217         488 :   TIMPI::push_parallel_vector_data(_communicator, _remove, remove_functor);
     218         488 :   TIMPI::push_parallel_vector_data(_communicator, _add, add_functor);
     219             : 
     220         488 :   auto sync = [](auto & mesh)
     221             :   {
     222         488 :     mesh.getMesh().get_boundary_info().parallel_sync_side_ids();
     223         488 :     mesh.getMesh().get_boundary_info().parallel_sync_node_ids();
     224         488 :     mesh.getMesh().get_boundary_info().build_node_list_from_side_list();
     225         488 :     mesh.update();
     226         488 :   };
     227         488 :   sync(_mesh);
     228         488 :   if (_displaced_problem)
     229           0 :     sync(_displaced_problem->mesh());
     230             : 
     231             :   // Reinit equation systems
     232         488 :   _fe_problem.meshChanged(
     233             :       /*intermediate_change=*/false, /*contract_mesh=*/false, /*clean_refinement_flags=*/false);
     234         488 : }

Generated by: LCOV version 1.14