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 "SideSetsFromBoundingBoxGenerator.h" 11 : #include "Conversion.h" 12 : #include "MooseTypes.h" 13 : #include "MooseMeshUtils.h" 14 : #include "CastUniquePointer.h" 15 : #include "MooseUtils.h" 16 : 17 : #include "libmesh/distributed_mesh.h" 18 : #include "libmesh/elem.h" 19 : 20 : #include <typeinfo> 21 : 22 : registerMooseObject("MooseApp", SideSetsFromBoundingBoxGenerator); 23 : 24 : InputParameters 25 14709 : SideSetsFromBoundingBoxGenerator::validParams() 26 : { 27 14709 : InputParameters params = SideSetsGeneratorBase::validParams(); 28 : 29 14709 : params.addClassDescription("Defines new sidesets using currently-defined sideset IDs inside or " 30 : "outside of a bounding box."); 31 : 32 14709 : MooseEnum location("INSIDE OUTSIDE", "INSIDE"); 33 : 34 14709 : params.addRequiredParam<RealVectorValue>( 35 : "bottom_left", "The bottom left point (in x,y,z with spaces in-between)."); 36 14709 : params.addRequiredParam<RealVectorValue>( 37 : "top_right", "The bottom left point (in x,y,z with spaces in-between)."); 38 14709 : params.addDeprecatedParam<subdomain_id_type>( 39 : "block_id", 40 : "Subdomain id to set for inside/outside the bounding box", 41 : "The parameter 'block_id' is not used."); 42 14709 : params.makeParamRequired<std::vector<BoundaryName>>("included_boundaries"); 43 14709 : params.addParam<std::vector<BoundaryName>>( 44 : "boundaries_old", 45 : "The list of boundaries on the specified block within the bounding box to be modified"); 46 14709 : params.deprecateParam("boundaries_old", "included_boundaries", "4/01/2025"); 47 14709 : params.addRequiredParam<BoundaryName>( 48 : "boundary_new", "Boundary on specified block within the bounding box to assign"); 49 44127 : params.addParam<bool>("boundary_id_overlap", 50 29418 : false, 51 : "Set to true if boundaries need to overlap on sideset to be detected."); 52 14709 : params.addParam<MooseEnum>( 53 : "location", location, "Control of where the subdomain id is to be set"); 54 : 55 : // TODO: Implement each of these in the generate() routine using utilities in SidesetGeneratorBase 56 14709 : params.suppressParameter<bool>("fixed_normal"); 57 14709 : params.suppressParameter<std::vector<BoundaryName>>("new_boundary"); 58 : 59 29418 : return params; 60 14709 : } 61 : 62 222 : SideSetsFromBoundingBoxGenerator::SideSetsFromBoundingBoxGenerator( 63 222 : const InputParameters & parameters) 64 : : SideSetsGeneratorBase(parameters), 65 222 : _location(parameters.get<MooseEnum>("location")), 66 222 : _bounding_box(MooseUtils::buildBoundingBox(parameters.get<RealVectorValue>("bottom_left"), 67 222 : parameters.get<RealVectorValue>("top_right"))), 68 666 : _boundary_id_overlap(parameters.get<bool>("boundary_id_overlap")) 69 : { 70 222 : if (_boundary_id_overlap) 71 : { 72 : const std::vector<std::string> incompatible_params = {"normal", 73 : "replace", 74 : "include_only_external_sides", 75 : "included_subdomains", 76 396 : "included_neighbors"}; 77 396 : for (const auto & param_name : incompatible_params) 78 330 : if (isParamSetByUser(param_name)) 79 0 : paramError(param_name, "Parameter should not be used with boundary_id_overlap = true."); 80 66 : } 81 : 82 222 : _boundary_names.push_back(parameters.get<BoundaryName>("boundary_new")); 83 354 : } 84 : 85 : std::unique_ptr<MeshBase> 86 219 : SideSetsFromBoundingBoxGenerator::generate() 87 : { 88 219 : std::unique_ptr<MeshBase> mesh = std::move(_input); 89 219 : if (!mesh->is_replicated()) 90 0 : mooseError("SideSetsFromBoundingBoxGenerator is not implemented for distributed meshes"); 91 : 92 : // construct the FE object so we can compute normals of faces 93 219 : setup(*mesh); 94 : 95 : // Get a reference to our BoundaryInfo object for later use 96 219 : BoundaryInfo & boundary_info = mesh->get_boundary_info(); 97 219 : boundary_info.build_node_list_from_side_list(); 98 : 99 219 : bool found_element = false; 100 219 : bool found_side_sets = false; 101 219 : const bool inside = (_location == "INSIDE"); 102 : 103 : // Attempt to get the new boundary id from the name 104 219 : auto boundary_id_new = MooseMeshUtils::getBoundaryID(_boundary_names[0], *mesh); 105 : 106 : // If the new boundary id is not valid, make it instead 107 219 : if (boundary_id_new == Moose::INVALID_BOUNDARY_ID) 108 : { 109 8 : boundary_id_new = MooseMeshUtils::getNextFreeBoundaryID(*mesh); 110 : 111 : // Write the name alias of the boundary id to the mesh boundary info 112 8 : boundary_info.sideset_name(boundary_id_new) = _boundary_names[0]; 113 8 : boundary_info.nodeset_name(boundary_id_new) = _boundary_names[0]; 114 : } 115 : 116 219 : if (!_boundary_id_overlap) 117 : { 118 : // Request to compute normal vectors 119 156 : const std::vector<Point> & face_normals = _fe_face->get_normals(); 120 : 121 : // Loop over the elements 122 79820 : for (const auto & elem : mesh->active_element_ptr_range()) 123 : { 124 : // boolean if element centroid is in bounding box 125 39832 : bool contains = _bounding_box.contains_point(elem->vertex_average()); 126 : 127 : // check if active elements are found either in or out of the bounding box, apropos "inside" 128 39832 : if (contains == inside) 129 : { 130 3364 : found_element = true; 131 : // loop over sides of elements within bounding box 132 19428 : for (const auto & side : make_range(elem->n_sides())) 133 : { 134 16064 : _fe_face->reinit(elem, side); 135 : // We'll just use the normal of the first qp 136 16064 : const Point face_normal = face_normals[0]; 137 : 138 16064 : if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal)) 139 : { 140 : // assign new boundary value to boundary which meets meshmodifier criteria 141 872 : if (_replace) 142 0 : boundary_info.remove_side(elem, side); 143 872 : boundary_info.add_side(elem, side, boundary_id_new); 144 872 : found_side_sets = true; 145 : } 146 : } 147 : } 148 156 : } 149 156 : if (!found_element && inside) 150 4 : mooseError("No elements found within the bounding box"); 151 : 152 152 : if (!found_element && !inside) 153 0 : mooseError("No elements found outside the bounding box"); 154 : 155 152 : if (!found_side_sets) 156 4 : mooseError("No side sets found on active elements within the bounding box"); 157 : } 158 : 159 63 : else if (_boundary_id_overlap) 160 : { 161 63 : if (_included_boundary_ids.size() < 2) 162 8 : mooseError("boundary_id_old out of bounds: ", 163 4 : _included_boundary_ids.size(), 164 : " Must be 2 boundary inputs or more."); 165 : 166 59 : bool found_node = false; 167 : 168 : // Loop over the elements and assign node set id to nodes within the bounding box 169 147437 : for (auto node = mesh->active_nodes_begin(); node != mesh->active_nodes_end(); ++node) 170 : { 171 : // check if nodes are inside of bounding box 172 73689 : if (_bounding_box.contains_point(**node) == inside) 173 : { 174 : // read out boundary ids for nodes 175 73333 : std::vector<boundary_id_type> node_boundary_ids; 176 73333 : boundary_info.boundary_ids(*node, node_boundary_ids); 177 : 178 : // sort boundary ids on node and sort boundary ids provided in input file 179 73333 : std::sort(node_boundary_ids.begin(), node_boundary_ids.end()); 180 73333 : std::sort(_included_boundary_ids.begin(), _included_boundary_ids.end()); 181 : 182 : // check if input boundary ids are all contained in the node 183 : // if true, write new boundary id on respective node 184 73333 : if (std::includes(node_boundary_ids.begin(), 185 : node_boundary_ids.end(), 186 : _included_boundary_ids.begin(), 187 : _included_boundary_ids.end())) 188 : { 189 391 : boundary_info.add_node(*node, boundary_id_new); 190 391 : found_node = true; 191 : } 192 73333 : } 193 59 : } 194 : 195 59 : if (!found_node) 196 8 : mooseError("No nodes found within the bounding box"); 197 : } 198 : 199 199 : mesh->set_isnt_prepared(); 200 398 : return dynamic_pointer_cast<MeshBase>(mesh); 201 199 : }