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 "ExtraNodesetGenerator.h" 11 : #include "MooseMesh.h" 12 : #include "Conversion.h" 13 : #include "MooseMeshUtils.h" 14 : #include "CastUniquePointer.h" 15 : 16 : #include "libmesh/elem.h" 17 : 18 : registerMooseObject("MooseApp", ExtraNodesetGenerator); 19 : 20 : InputParameters 21 14753 : ExtraNodesetGenerator::validParams() 22 : { 23 14753 : InputParameters params = MeshGenerator::validParams(); 24 : 25 14753 : params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify"); 26 14753 : params.addRequiredParam<std::vector<BoundaryName>>("new_boundary", 27 : "The names of the boundaries to create"); 28 : 29 14753 : params.addParam<std::vector<unsigned int>>("nodes", 30 : "The nodes you want to be in the nodeset " 31 : "(Either this parameter or \"coord\" must be " 32 : "supplied)."); 33 14753 : params.addParam<std::vector<std::vector<Real>>>( 34 : "coord", 35 : {}, 36 : "The nodes with coordinates you want to be in the " 37 : "nodeset. Separate multple coords with ';' (Either this parameter or \"nodes\" must be " 38 : "supplied)."); 39 14753 : params.addParam<Real>( 40 : "tolerance", TOLERANCE, "The tolerance in which two nodes are considered identical"); 41 14753 : params.addParam<bool>("use_closest_node", false, "Use the node closest to the coordinate."); 42 14753 : params.addClassDescription( 43 : "Creates a new node set and a new boundary made with the nodes the user provides."); 44 : 45 14753 : return params; 46 0 : } 47 : 48 244 : ExtraNodesetGenerator::ExtraNodesetGenerator(const InputParameters & parameters) 49 244 : : MeshGenerator(parameters), _input(getMesh("input")) 50 : { 51 244 : } 52 : 53 : std::unique_ptr<MeshBase> 54 232 : ExtraNodesetGenerator::generate() 55 : { 56 232 : std::unique_ptr<MeshBase> mesh = std::move(_input); 57 : 58 : // Get the BoundaryIDs from the mesh 59 232 : std::vector<BoundaryName> boundary_names = getParam<std::vector<BoundaryName>>("new_boundary"); 60 : std::vector<boundary_id_type> boundary_ids = 61 232 : MooseMeshUtils::getBoundaryIDs(*mesh, boundary_names, true); 62 : 63 : // Get a reference to our BoundaryInfo object 64 232 : BoundaryInfo & boundary_info = mesh->get_boundary_info(); 65 : 66 : // add nodes with their ids 67 232 : if (isParamValid("nodes")) 68 294 : for (const auto & node_id : getParam<std::vector<unsigned int>>("nodes")) 69 : { 70 : // Our mesh may be distributed and this node may not exist on this process 71 147 : if (!mesh->query_node_ptr(node_id)) 72 0 : continue; 73 : 74 294 : for (const auto & boundary_id : boundary_ids) 75 147 : boundary_info.add_node(node_id, boundary_id); 76 : } 77 : 78 : // add nodes with their coordinates 79 232 : const auto dim = mesh->mesh_dimension(); 80 : 81 232 : std::unique_ptr<libMesh::PointLocatorBase> locator = mesh->sub_point_locator(); 82 232 : locator->enable_out_of_mesh_mode(); 83 : 84 232 : const auto tolerance = getParam<Real>("tolerance"); 85 232 : const bool use_closest_node = getParam<bool>("use_closest_node"); 86 232 : const auto coords = getParam<std::vector<std::vector<Real>>>("coord"); 87 232 : if (use_closest_node && coords.empty()) 88 0 : paramError("coord", "A coordinate should be specified to use 'use_closest_node'"); 89 353 : for (const auto & c : coords) 90 : { 91 125 : Point p; 92 125 : if (c.size() < dim) 93 0 : paramError("coord", 94 : "Coordinate ", 95 0 : Moose::stringify(c), 96 : " does not have enough components for a ", 97 : dim, 98 : "D mesh."); 99 : 100 125 : if (c.size() > 3) 101 0 : paramError("coord", 102 : "Coordinate ", 103 0 : Moose::stringify(c), 104 : " has too many components. Did you maybe forget to separate multiple coordinates " 105 : "with a ';'?"); 106 : 107 375 : for (unsigned int j = 0; j < c.size(); ++j) 108 250 : p(j) = c[j]; 109 : 110 : // locate candidate element 111 125 : bool on_node = false; 112 125 : bool found_elem = false; 113 125 : const Elem * elem = (*locator)(p); 114 125 : if (elem) 115 : { 116 98 : found_elem = true; 117 282 : for (unsigned int j = 0; j < elem->n_nodes(); ++j) 118 : { 119 275 : const Node * node = elem->node_ptr(j); 120 275 : if (p.absolute_fuzzy_equals(*node, tolerance)) 121 : { 122 182 : for (const auto & boundary_id : boundary_ids) 123 91 : boundary_info.add_node(node, boundary_id); 124 : 125 91 : on_node = true; 126 91 : break; 127 : } 128 : } 129 : } 130 : 131 : // If we are on a distributed mesh, then any particular processor 132 : // may be unable to find any particular node, but *some* processor 133 : // should have found it. 134 125 : if (!mesh->is_replicated()) 135 : { 136 46 : this->comm().max(found_elem); 137 46 : this->comm().max(on_node); 138 : } 139 : 140 : // only search for closest node if it is not found on a node 141 125 : if (use_closest_node && !on_node) 142 : { 143 : // these are always true when using closest node 144 30 : found_elem = true; 145 30 : on_node = true; 146 30 : Real dmin(std::numeric_limits<Real>::max()); 147 30 : dof_id_type dmin_id(std::numeric_limits<dof_id_type>::max()); 148 : // find this processors closest node and save distance and the node id 149 5112 : for (const auto & node_iter : as_range(mesh->local_nodes_begin(), mesh->local_nodes_end())) 150 : { 151 2541 : Real dist = (*node_iter - p).norm_sq(); 152 2541 : if (dist < dmin) 153 : { 154 451 : dmin = dist; 155 451 : dmin_id = node_iter->id(); 156 : } 157 30 : } 158 : 159 : // get proc id with the global closest node and then communicate that procs closest node_id 160 : processor_id_type dmin_proc_id; 161 30 : this->comm().minloc(dmin, dmin_proc_id); 162 30 : this->comm().broadcast(dmin_id, dmin_proc_id); 163 : 164 30 : const Node * node = mesh->query_node_ptr(dmin_id); 165 30 : if (node) 166 42 : for (const auto & boundary_id : boundary_ids) 167 21 : boundary_info.add_node(node, boundary_id); 168 : } 169 : 170 125 : if (!found_elem) 171 4 : mooseError("Unable to locate the following point within the domain, please check its " 172 : "coordinates:\n", 173 : p); 174 : 175 121 : if (!on_node) 176 0 : mooseError("No node found at point:\n", 177 : p, 178 : "\nSet use_closest_node=true if you want to find the closest node."); 179 : } 180 : 181 456 : for (unsigned int i = 0; i < boundary_ids.size(); ++i) 182 228 : boundary_info.nodeset_name(boundary_ids[i]) = boundary_names[i]; 183 : 184 : // This is a terrible hack that we'll want to remove once BMBBG isn't terrible 185 228 : if (!_app.getMeshGeneratorSystem().hasBreakMeshByBlockGenerator()) 186 228 : mesh->set_isnt_prepared(); 187 456 : return dynamic_pointer_cast<MeshBase>(mesh); 188 228 : }