LCOV - code coverage report
Current view: top level - src/meshgenerators - RefineSidesetGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 79 80 98.8 %
Date: 2025-07-17 01:28:37 Functions: 4 4 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 "RefineSidesetGenerator.h"
      11             : #include "MooseMeshUtils.h"
      12             : 
      13             : #include "libmesh/elem.h"
      14             : #include "libmesh/mesh_refinement.h"
      15             : #include "CastUniquePointer.h"
      16             : 
      17             : registerMooseObject("MooseApp", RefineSidesetGenerator);
      18             : 
      19             : InputParameters
      20       14449 : RefineSidesetGenerator::validParams()
      21             : {
      22       14449 :   InputParameters params = MeshGenerator::validParams();
      23       14449 :   params.addClassDescription("Mesh generator which refines one or more sidesets");
      24       14449 :   params.addRequiredParam<MeshGeneratorName>("input", "Input mesh to modify");
      25       14449 :   params.addRequiredParam<std::vector<BoundaryName>>("boundaries",
      26             :                                                      "The list of boundaries to be modified");
      27       14449 :   params.addRequiredParam<std::vector<int>>(
      28             :       "refinement",
      29             :       "The amount of times to refine each sideset, corresponding to their index in 'boundaries'");
      30       43347 :   params.addParam<bool>(
      31             :       "enable_neighbor_refinement",
      32       28898 :       true,
      33             :       "Toggles whether neighboring level one elements should be refined or not. Defaults to true. "
      34             :       "False may lead to unsupported mesh non-conformality without great care.");
      35       14449 :   MultiMooseEnum boundary_side("primary secondary both", "both");
      36       14449 :   params.addParam<MultiMooseEnum>("boundary_side",
      37             :                                   boundary_side,
      38             :                                   "Whether the generator should refine itself(primary), its "
      39             :                                   "neighbors(secondary), or itself and its neighbors(both)");
      40             : 
      41       28898 :   return params;
      42       14449 : }
      43             : 
      44          94 : RefineSidesetGenerator::RefineSidesetGenerator(const InputParameters & parameters)
      45             :   : MeshGenerator(parameters),
      46          94 :     _input(getMesh("input")),
      47          94 :     _boundaries(getParam<std::vector<BoundaryName>>("boundaries")),
      48          94 :     _refinement(getParam<std::vector<int>>("refinement")),
      49          94 :     _enable_neighbor_refinement(getParam<bool>("enable_neighbor_refinement")),
      50         188 :     _boundary_side(getParam<MultiMooseEnum>("boundary_side"))
      51             : {
      52          94 :   if (_boundaries.size() != _refinement.size())
      53           4 :     paramError("refinement",
      54             :                "The boundaries and refinement parameter vectors should be the same size");
      55          90 :   if (_boundaries.size() != _boundary_side.size())
      56           0 :     paramError("boundary_side",
      57             :                "The boundaries and boundary_side parameter vectors should be the same size");
      58          90 : }
      59             : 
      60             : std::unique_ptr<MeshBase>
      61          89 : RefineSidesetGenerator::generate()
      62             : {
      63             :   // Get the list of boundary ids from the boundary names
      64             :   const auto boundary_ids = MooseMeshUtils::getBoundaryIDs(
      65          89 :       *_input, getParam<std::vector<BoundaryName>>("boundaries"), false);
      66             : 
      67             :   // Check that the boundary ids/names exist in the mesh
      68         185 :   for (std::size_t i = 0; i < boundary_ids.size(); ++i)
      69         100 :     if (boundary_ids[i] == Moose::INVALID_BOUNDARY_ID)
      70           4 :       paramError("boundaries",
      71             :                  "The boundary '",
      72           4 :                  getParam<std::vector<BoundaryName>>("boundaries")[i],
      73             :                  "' was not found within the mesh");
      74          85 :   std::unique_ptr<MeshBase> mesh = std::move(_input);
      75          85 :   int max = *std::max_element(_refinement.begin(), _refinement.end());
      76         170 :   return recursive_refine(boundary_ids, mesh, _refinement, max);
      77          85 : }
      78             : 
      79             : std::unique_ptr<MeshBase>
      80         210 : RefineSidesetGenerator::recursive_refine(std::vector<boundary_id_type> boundary_ids,
      81             :                                          std::unique_ptr<MeshBase> & mesh,
      82             :                                          std::vector<int> refinement,
      83             :                                          int max,
      84             :                                          int ref_step)
      85             : {
      86             :   // If the refinement step has reached the largest value in the _refinement array, return the mesh,
      87             :   // as we are done.
      88         210 :   if (ref_step == max)
      89          85 :     return dynamic_pointer_cast<MeshBase>(mesh);
      90             : 
      91         125 :   const bool old_allow_remote_element_removal = mesh->allow_remote_element_removal();
      92         125 :   if (mesh->is_serial())
      93             :     // If our mesh is already serial then we will keep it that way to avoid doing communication
      94         103 :     mesh->allow_remote_element_removal(false);
      95         125 :   if (!mesh->is_prepared())
      96          44 :     mesh->prepare_for_use();
      97             : 
      98             :   std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> sideList =
      99         125 :       mesh->get_boundary_info().build_active_side_list();
     100             : 
     101             :   // If on one process a sideset element is semilocal, then any semilocal active neighbors might be
     102             :   // marked for refinement. However, if on another process that sideset element is *not* semilocal,
     103             :   // then obviously no neighboring elements can be marked for refinement. With no communication this
     104             :   // can lead to elements on the former process being flagged for refinement while on the latter
     105             :   // they will be marked to do nothing. This is a violation of parallel consistency, so we make sure
     106             :   // to communicate neighbors that need to be refined
     107         125 :   std::vector<dof_id_type> neighbors_to_refine;
     108             : 
     109         261 :   for (std::size_t i = 0; i < boundary_ids.size(); i++)
     110             :   {
     111         136 :     if (refinement[i] > 0 && refinement[i] > ref_step)
     112             :     {
     113       20689 :       for (std::tuple<dof_id_type, unsigned short int, boundary_id_type> tuple : sideList)
     114             :       {
     115       20553 :         if (std::get<2>(tuple) == boundary_ids[i])
     116             :         {
     117        6334 :           Elem * elem = mesh->elem_ptr(std::get<0>(tuple));
     118        6334 :           if (_boundary_side[i] == "primary" || _boundary_side[i] == "both")
     119        5819 :             elem->set_refinement_flag(Elem::REFINE);
     120        6334 :           if (_boundary_side[i] == "secondary" || _boundary_side[i] == "both")
     121             :           {
     122        2266 :             auto neighbor = elem->neighbor_ptr(std::get<1>(tuple));
     123             :             // when we have multiple domains, domains will only refine the elements that they own
     124             :             // since there can be instances where there is no neighbor, this null_ptr check is
     125             :             // necessary
     126        2266 :             if (neighbor)
     127             :             {
     128        1998 :               if (neighbor->active())
     129             :               {
     130        1742 :                 neighbor->set_refinement_flag(Elem::REFINE);
     131        1742 :                 if (!mesh->is_serial())
     132         262 :                   neighbors_to_refine.push_back(neighbor->id());
     133             :               }
     134             :               else
     135             :               {
     136         256 :                 std::vector<Elem *> family_tree;
     137         256 :                 neighbor->active_family_tree_by_neighbor(family_tree, elem);
     138        1258 :                 for (auto child_elem : family_tree)
     139             :                 {
     140        1002 :                   child_elem->set_refinement_flag(Elem::REFINE);
     141        1002 :                   if (!mesh->is_serial())
     142         138 :                     neighbors_to_refine.push_back(child_elem->id());
     143             :                 }
     144         256 :               }
     145             :             }
     146             :           }
     147             :         }
     148             :       }
     149             :     }
     150             :   }
     151             : 
     152         125 :   if (!mesh->is_serial())
     153             :   {
     154          22 :     mesh->comm().allgather(neighbors_to_refine);
     155          22 :     std::sort(neighbors_to_refine.begin(), neighbors_to_refine.end());
     156          22 :     auto new_last = std::unique(neighbors_to_refine.begin(), neighbors_to_refine.end());
     157          22 :     neighbors_to_refine.erase(new_last, neighbors_to_refine.end());
     158         540 :     for (const auto id : neighbors_to_refine)
     159         518 :       if (Elem * const elem = mesh->query_elem_ptr(id))
     160         347 :         elem->set_refinement_flag(Elem::REFINE);
     161             :   }
     162             : 
     163         125 :   libMesh::MeshRefinement refinedmesh(*mesh);
     164         125 :   if (!_enable_neighbor_refinement)
     165          70 :     refinedmesh.face_level_mismatch_limit() = 0;
     166             : 
     167             :   // This calls prepare_for_use
     168         125 :   refinedmesh.refine_elements();
     169         125 :   mesh->allow_remote_element_removal(old_allow_remote_element_removal);
     170         125 :   ref_step++;
     171         125 :   return recursive_refine(boundary_ids, mesh, refinement, max, ref_step);
     172         125 : }

Generated by: LCOV version 1.14