LCOV - code coverage report
Current view: top level - src/meshgenerators - RenameBlockGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 124 126 98.4 %
Date: 2026-05-29 20:35:17 Functions: 5 5 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 "RenameBlockGenerator.h"
      11             : 
      12             : #include "CastUniquePointer.h"
      13             : #include "MooseMeshUtils.h"
      14             : 
      15             : #include "libmesh/mesh_modification.h"
      16             : 
      17             : registerMooseObject("MooseApp", RenameBlockGenerator);
      18             : 
      19             : InputParameters
      20        4888 : RenameBlockGenerator::validParams()
      21             : {
      22        4888 :   InputParameters params = MeshGenerator::validParams();
      23             : 
      24       19552 :   params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
      25             : 
      26       29328 :   params.addDeprecatedParam<std::vector<SubdomainID>>(
      27             :       "old_block_id",
      28             :       "Elements with this block number will be given the new_block_number or "
      29             :       "new_block_name.  You must supply either old_block_id or old_block_name.  "
      30             :       "You may supply a vector of old_block_id, in which case the new_block "
      31             :       "information must also be a vector.",
      32             :       "Use 'old_block' instead of 'old_block_id'.");
      33       29328 :   params.addDeprecatedParam<std::vector<SubdomainName>>(
      34             :       "old_block_name",
      35             :       "Elements with this block name will be given the new_block_number or "
      36             :       "new_block_name.  You must supply either old_block_id or old_block_name.  "
      37             :       "You may supply a vector of old_block_name, in which case the new_block "
      38             :       "information must also be a vector.",
      39             :       "Use 'old_block' instead of 'old_block_name'.");
      40       29328 :   params.addDeprecatedParam<std::vector<SubdomainID>>(
      41             :       "new_block_id",
      42             :       "Elements with the old block number (or name) will be given this block "
      43             :       "number.  If the old blocks are named, their names will be passed onto the "
      44             :       "newly numbered blocks.",
      45             :       "Use 'new_block' instead of 'new_block_id'.");
      46       29328 :   params.addDeprecatedParam<std::vector<SubdomainName>>(
      47             :       "new_block_name",
      48             :       "Elements with the old block number (or name) will be given this block "
      49             :       "name.  No change of block ID is performed, unless multiple old blocks are "
      50             :       "given the same name, in which case they are all given the first old block "
      51             :       "number.",
      52             :       "Use 'new_block' instead of 'new_block_name'.");
      53             : 
      54       19552 :   params.addParam<std::vector<SubdomainName>>(
      55             :       "old_block",
      56             :       "Elements with these block ID(s)/name(s) will be given the new block information specified "
      57             :       "in 'new_block'");
      58       19552 :   params.addParam<std::vector<SubdomainName>>(
      59             :       "new_block",
      60             :       "The new block ID(s)/name(s) to be given by the elements defined in 'old_block'.");
      61             : 
      62        4888 :   params.addClassDescription("Changes the block IDs and/or block names for a given set of blocks "
      63             :                              "defined by either block ID or block name. The changes are "
      64             :                              "independent of ordering. The merging of blocks is supported.");
      65             : 
      66        4888 :   return params;
      67           0 : }
      68             : 
      69         913 : RenameBlockGenerator::RenameBlockGenerator(const InputParameters & parameters)
      70        2736 :   : MeshGenerator(parameters), _input(getMesh("input"))
      71             : {
      72        2766 :   if (isParamValid("old_block_id") && isParamValid("old_block_name"))
      73           6 :     paramError("old_block_id",
      74             :                "Cannot use in combination with 'old_block_name'. Please use 'old_block' "
      75             :                "instead; 'old_block_id' and 'old_block_name' are deprecated.");
      76        2757 :   if (isParamValid("new_block_id") && isParamValid("new_block_name"))
      77           6 :     paramError("new_block_id",
      78             :                "Cannot use in combination with 'new_block_name'. Please use 'new_block' "
      79             :                "instead; 'new_block_id' and 'new_block_name' are deprecated.");
      80             : 
      81        2712 :   if (isParamValid("old_block"))
      82             :   {
      83        2622 :     if (isParamValid("old_block_id"))
      84           6 :       paramError("old_block_id",
      85             :                  "Cannot use with 'old_block'. Use only 'old_block'; 'old_block_id' is "
      86             :                  "deprecated.");
      87        2613 :     if (isParamValid("old_block_name"))
      88           9 :       paramError("old_block_name",
      89             :                  "Cannot use with 'old_block'. Use only 'old_block'; 'old_block_name' is "
      90             :                  "deprecated.");
      91        1736 :     _old_block = getParam<std::vector<SubdomainName>>("old_block");
      92         868 :     _old_block_param_name = "old_block";
      93             :   }
      94          90 :   else if (isParamValid("old_block_id"))
      95             :   {
      96          84 :     for (const auto id : getParam<std::vector<SubdomainID>>("old_block_id"))
      97          48 :       _old_block.push_back(std::to_string(id));
      98          12 :     _old_block_param_name = "old_block_id";
      99             :   }
     100             :   else
     101             :   {
     102          36 :     _old_block = isParamValid("old_block_name")
     103          60 :                      ? getParam<std::vector<SubdomainName>>("old_block_name")
     104          18 :                      : std::vector<SubdomainName>{};
     105          18 :     _old_block_param_name = "old_block_name";
     106             :   }
     107             : 
     108         898 :   std::string new_block_param_name;
     109        2694 :   if (isParamValid("new_block"))
     110             :   {
     111        2622 :     if (isParamValid("new_block_id"))
     112           6 :       paramError("new_block_id",
     113             :                  "Cannot use with 'new_block'. Use only 'new_block'; 'new_block_id' is "
     114             :                  "deprecated.");
     115        2613 :     if (isParamValid("new_block_name"))
     116           6 :       paramError("new_block_name",
     117             :                  "Cannot use with 'new_block'. Use only 'new_block'; 'new_block_name' is "
     118             :                  "deprecated.");
     119        1736 :     _new_block = getParam<std::vector<SubdomainName>>("new_block");
     120         868 :     new_block_param_name = "new_block";
     121             :   }
     122          72 :   else if (isParamValid("new_block_id"))
     123             :   {
     124          84 :     for (const auto id : getParam<std::vector<SubdomainID>>("new_block_id"))
     125          48 :       _new_block.push_back(std::to_string(id));
     126          12 :     new_block_param_name = "new_block_id";
     127             :   }
     128             :   else
     129             :   {
     130          24 :     _new_block = isParamValid("new_block_name")
     131          48 :                      ? getParam<std::vector<SubdomainName>>("new_block_name")
     132          12 :                      : std::vector<SubdomainName>{};
     133          12 :     new_block_param_name = "new_block_name";
     134             :   }
     135             : 
     136         892 :   if (_old_block.size() != _new_block.size())
     137           3 :     paramError(new_block_param_name, "Must be the same length as '", _old_block_param_name, "'");
     138         889 : }
     139             : 
     140             : std::unique_ptr<MeshBase>
     141         681 : RenameBlockGenerator::generate()
     142             : {
     143         681 :   std::unique_ptr<MeshBase> mesh = std::move(_input);
     144             : 
     145             :   // MeshBase::subdomain_name will insert, so we need a const ref
     146         681 :   const MeshBase & const_mesh = *mesh;
     147             : 
     148             :   // Get the subdomains in the mesh (this is global)
     149         681 :   if (!mesh->preparation().has_cached_elem_data)
     150         576 :     mesh->cache_elem_data();
     151         681 :   std::set<subdomain_id_type> block_ids;
     152         681 :   mesh->subdomain_ids(block_ids);
     153             : 
     154             :   // Helper for getting an unused block ID, and keeping track of it
     155             :   // so that we can generate more later
     156          44 :   auto get_unused_block_id = [this, &block_ids, &const_mesh]()
     157             :   {
     158         286 :     for (const auto id : make_range(Moose::INVALID_BLOCK_ID))
     159         286 :       if (!block_ids.count(id) && !const_mesh.get_subdomain_name_map().count(id))
     160             :       {
     161          44 :         block_ids.insert(id);
     162          44 :         return id;
     163             :       }
     164             : 
     165           0 :     mooseError("Failed to find an unused ID!");
     166         681 :   };
     167             : 
     168         681 :   const auto num_blocks = _old_block.size();
     169             : 
     170             :   // Helper for checking whether or not a SubdomainName (which could be an ID or a name)
     171             :   // is really input as an ID
     172        4333 :   const auto is_subdomain_id = [](const SubdomainName & subdomain_name)
     173        4333 :   { return MooseUtils::isDigits(subdomain_name); };
     174             : 
     175             :   // Get the old block IDs and make sure they exist
     176        1362 :   std::vector<SubdomainID> old_block_ids(num_blocks, Moose::INVALID_BLOCK_ID);
     177         681 :   std::vector<SubdomainName> old_block_names(num_blocks);
     178         681 :   std::stringstream missing_block;
     179        2852 :   for (const auto i : make_range(num_blocks))
     180             :   {
     181        2171 :     const SubdomainName & name = _old_block[i];
     182             : 
     183             :     // Convert the SubdomainName to an id and store
     184        2171 :     const auto id = MooseMeshUtils::getSubdomainID(name, *mesh);
     185        2171 :     old_block_ids[i] = id;
     186             : 
     187             :     // Block does not exist - store for a future error
     188        2171 :     if (!block_ids.count(id))
     189           6 :       missing_block << name << " ";
     190             : 
     191             :     // Keep track of the block names
     192             :     // If this SubdomainName is an ID, try to see if it has a name set
     193        2171 :     if (is_subdomain_id(name))
     194        2036 :       old_block_names[i] = const_mesh.subdomain_name(id);
     195             :     // If this SubdomainName is a name, use said name
     196             :     else
     197         135 :       old_block_names[i] = name;
     198             :   }
     199         681 :   if (missing_block.str().size())
     200           3 :     paramError(_old_block_param_name,
     201             :                "The following blocks were requested to be renamed, but do not exist: ",
     202           3 :                missing_block.str());
     203             : 
     204             :   // Get the block IDs that we're moving to
     205         678 :   std::vector<SubdomainID> new_block_ids(num_blocks, Moose::INVALID_BLOCK_ID);
     206         678 :   std::map<SubdomainID, std::string> new_names;
     207        2840 :   for (const auto i : make_range(num_blocks))
     208             :   {
     209        2162 :     const SubdomainName & name = _new_block[i];
     210             : 
     211             :     // If the user input an ID, we have the ID
     212        2162 :     if (is_subdomain_id(name))
     213             :     {
     214         352 :       const auto id = MooseMeshUtils::getSubdomainID(name, *mesh);
     215         352 :       new_block_ids[i] = id;
     216             : 
     217             :       // In the case that this is a new block ID, keep track of it so that we
     218             :       // don't reuse it if we have to create temporaries
     219         352 :       block_ids.insert(id);
     220             : 
     221             :       // Preserve the old block name if there was one
     222         352 :       if (old_block_names[i].size())
     223         154 :         new_names[id] = old_block_names[i];
     224             :     }
     225             :     // If the user input a name, we will use the ID that it is coming from for the
     226             :     // "new" name if the new name does not name a current block. If the name does
     227             :     // exist, we will merge with said block.
     228             :     else
     229             :     {
     230        1810 :       bool name_already_exists = false;
     231             : 
     232             :       // If the target block already exists, merge into that one
     233             :       // Check both the old maps and the new map
     234        5430 :       for (const auto map : {&const_mesh.get_subdomain_name_map(),
     235        7240 :                              const_cast<const std::map<SubdomainID, std::string> *>(&new_names)})
     236       47847 :         for (const auto & id_name_pair : *map)
     237       44227 :           if (!name_already_exists && id_name_pair.second == name)
     238             :           {
     239          11 :             new_block_ids[i] = id_name_pair.first;
     240          11 :             new_names[id_name_pair.first] = name;
     241          11 :             name_already_exists = true;
     242             :           }
     243             : 
     244             :       // Target name doesn't exist, so use the source id/name
     245        1810 :       if (!name_already_exists)
     246             :       {
     247        1799 :         new_block_ids[i] = old_block_ids[i];
     248        1799 :         new_names[new_block_ids[i]] = name;
     249             :       }
     250             :     }
     251             :   }
     252             : 
     253             :   // Create temporaries if needed; recall that this generator is independent
     254             :   // of input ordering and does _not_ merge subdomains.
     255             :   //
     256             :   // Take the example where we want to move 0 -> 1 and 1 -> 2. If we just
     257             :   // move them in order, we will actually end up with (0, 1) -> 2. This is
     258             :   // bad. In this case, we want to first make a temporary for 1 (call it 3).
     259             :   // We then do: 0 -> 3, 1 -> 2, 3 -> 1 in order to get the desired behavior.
     260             :   // We will accomplish this by creating temporaries as needed, modifying
     261             :   // the initial move to the temporaries as needed, and then moving the
     262             :   // temporaries back. temp_change_ids here are the (from -> to) pairs
     263             :   // that we will move at the end.
     264         678 :   auto temp_new_block_ids = new_block_ids;
     265         678 :   std::vector<std::pair<SubdomainID, SubdomainID>> temp_change_ids;
     266             :   // Loop through all new IDs
     267        2840 :   for (const auto new_i : make_range(num_blocks))
     268             :   {
     269             :     // Look at all of the old IDs that will be moved after the move to the new ID.
     270             :     // If any of the old IDs after are IDs that we are moving to, create a temporary
     271             :     // and keep track of it so we can move it back at the end.
     272       46124 :     for (const auto old_i : make_range(new_i + 1, num_blocks))
     273       44006 :       if (new_block_ids[new_i] == old_block_ids[old_i])
     274             :       {
     275          44 :         const auto temp_id = get_unused_block_id();
     276          44 :         temp_change_ids.emplace_back(temp_id, new_block_ids[new_i]);
     277          44 :         temp_new_block_ids[new_i] = temp_id;
     278          44 :         break;
     279             :       }
     280             :   }
     281             : 
     282             :   // First pass through changing the block ids
     283        2840 :   for (const auto i : make_range(num_blocks))
     284        2162 :     MeshTools::Modification::change_subdomain_id(*mesh, old_block_ids[i], temp_new_block_ids[i]);
     285             :   // Pass through moving the temporaries to the actual blocks, if necessary
     286         722 :   for (const auto & pair : temp_change_ids)
     287          44 :     MeshTools::Modification::change_subdomain_id(*mesh, pair.first, pair.second);
     288             : 
     289             :   // First go through and remove all of the old names
     290        2840 :   for (const auto i : make_range(num_blocks))
     291        2162 :     if (mesh->get_subdomain_name_map().count(old_block_ids[i]))
     292         334 :       mesh->set_subdomain_name_map().erase(old_block_ids[i]);
     293             :   // With the old names removed, add the new names if there are any to add
     294        2620 :   for (const auto & pair : new_names)
     295        1942 :     mesh->subdomain_name(pair.first) = pair.second;
     296             : 
     297         678 :   mesh->unset_is_prepared();
     298        1356 :   return dynamic_pointer_cast<MeshBase>(mesh);
     299         678 : }

Generated by: LCOV version 1.14