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 : }