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 "RenumberBySubdomainGenerator.h" 11 : #include "CastUniquePointer.h" 12 : #include "MooseMeshUtils.h" 13 : 14 : registerMooseObject("MooseApp", RenumberBySubdomainGenerator); 15 : 16 : InputParameters 17 3077 : RenumberBySubdomainGenerator::validParams() 18 : { 19 3077 : InputParameters params = MeshGenerator::validParams(); 20 : 21 12308 : params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify"); 22 12308 : params.addParam<std::vector<SubdomainName>>( 23 : "blocks_to_renumber", 24 : "Elements and nodes within these blocks will be renumbered. If none are specified, all " 25 : "subdomains are affected by the renumbering"); 26 : 27 3077 : params.addClassDescription("Changes the element and node IDs so that elements and nodes are " 28 : "contiguous within a subdomain. Note that DoF ordering may be " 29 : "affected as well, and that the mesh renumbering will be turned off."); 30 : 31 3077 : return params; 32 0 : } 33 : 34 8 : RenumberBySubdomainGenerator::RenumberBySubdomainGenerator(const InputParameters & parameters) 35 16 : : MeshGenerator(parameters), _input(getMesh("input")) 36 : { 37 8 : } 38 : 39 : std::unique_ptr<MeshBase> 40 8 : RenumberBySubdomainGenerator::generate() 41 : { 42 8 : std::unique_ptr<MeshBase> mesh = std::move(_input); 43 : 44 : // Not impossible to do. 45 8 : if (!mesh->is_serial()) 46 0 : mooseError("Not implemented for non-serialized distributed meshes"); 47 : 48 : // Orphaned nodes would cause problems on renumbering, we are looping on the nodes attached 49 : // to elements 50 8 : mesh->remove_orphaned_nodes(); 51 8 : mesh->renumber_nodes_and_elements(); 52 : 53 : // Get the blocks provided by the user 54 : std::optional<std::vector<SubdomainName>> blocks = 55 16 : isParamValid("blocks_to_renumber") 56 40 : ? getParam<std::vector<SubdomainName>>("blocks_to_renumber") 57 8 : : std::vector<SubdomainName>(); 58 8 : std::vector<SubdomainID> block_ids(blocks->size()); 59 8 : std::stringstream missing_block; 60 : 61 40 : for (const auto i : index_range(block_ids)) 62 : { 63 32 : const SubdomainName & name = blocks.value()[i]; 64 : 65 : // Convert the SubdomainName to an id and store 66 32 : const auto id = MooseMeshUtils::getSubdomainID(name, *mesh); 67 32 : block_ids[i] = id; 68 : 69 : // Block does not exist - store for a future error 70 32 : if (id == Moose::INVALID_BLOCK_ID) 71 0 : missing_block << name << " "; 72 : } 73 8 : if (missing_block.str().size()) 74 0 : paramError("blocks_to_renumber", 75 : "The following blocks were requested to be renumbered, but do not exist: ", 76 0 : missing_block.str()); 77 : 78 : // User did not specify blocks, just get them all 79 8 : if (blocks->empty()) 80 : { 81 0 : std::set<subdomain_id_type> block_ids_set; 82 0 : mesh->subdomain_ids(block_ids_set); 83 0 : block_ids.reserve(block_ids_set.size()); 84 0 : block_ids.assign(block_ids_set.begin(), block_ids_set.end()); 85 : 86 : // Does not have useful data 87 0 : blocks.reset(); 88 0 : } 89 : 90 : // Renumber all elements with an ID we can recognize (so we can tell an already renumbered elem) 91 8 : const auto max_elem_id = mesh->max_elem_id(); 92 8 : const auto max_node_id = mesh->max_node_id(); 93 8 : std::unordered_map<dof_id_type, dof_id_type> new_elem_ids; 94 8 : new_elem_ids.reserve(max_elem_id); 95 8 : std::unordered_set<dof_id_type> renumbered_nodes; 96 8 : renumbered_nodes.reserve(max_node_id); 97 : 98 : // Renumber block IDs one at a time 99 : // We have to move them out of range, then back to range 100 8 : dof_id_type elem_count = 0; 101 8 : dof_id_type node_count = 0; 102 40 : for (const auto i : index_range(block_ids)) 103 : { 104 272 : for (auto elem : mesh->active_subdomain_elements_ptr_range(block_ids[i])) 105 : { 106 : // If we didn't specify all the subdomains, we might have to skip elem ids that are still 107 : // taken 108 480 : while (mesh->query_elem_ptr(elem_count)) 109 : { 110 240 : elem_count++; 111 : } 112 : // We can't mess with the range while looping in them 113 240 : new_elem_ids[elem->id()] = elem_count++; 114 : 115 1200 : for (auto & node : elem->node_ref_range()) 116 : // prevent re-renumbering 117 960 : if (!renumbered_nodes.count(node.id())) 118 : { 119 : // If we didn't specify all the subdomains, we might have to skip node ids that are still 120 : // taken 121 1296 : while (mesh->query_node_ptr(node_count)) 122 : { 123 336 : node_count++; 124 : } 125 960 : renumbered_nodes.insert(node.id()); 126 960 : mesh->renumber_node(node.id(), node_count++); 127 : } 128 32 : } 129 : } 130 : 131 : // Now change the IDs 132 248 : for (const auto [key, value] : new_elem_ids) 133 240 : mesh->renumber_elem(key, value); 134 : 135 : // Update the max ids 136 8 : mesh->contract(); 137 : 138 : // Try to disallow renumbering from now on since we just renumbered 139 8 : mesh->allow_renumbering(false); 140 : // No gain if exodus just renumbers this. Better to tell the user 141 8 : if (mesh->n_nodes() != mesh->max_node_id() || mesh->n_elem() != mesh->max_elem_id()) 142 0 : mooseWarning("Mesh is not contiguously numbered after renumbering. The numbering may be erased " 143 0 : "by outputs that require contiguous numbering such as Exodus.\nNumber of nodes: " + 144 0 : std::to_string(mesh->n_nodes()) + 145 0 : "\nMax node ID: " + std::to_string(mesh->max_node_id() - 1) + 146 0 : "\nNumber of elements: " + std::to_string(mesh->n_elem()) + 147 0 : "\nMax elem ID: " + std::to_string(mesh->max_elem_id() - 1)); 148 : 149 8 : mesh->unset_is_prepared(); 150 16 : return dynamic_pointer_cast<MeshBase>(mesh); 151 8 : }