LCOV - code coverage report
Current view: top level - src/meshgenerators - RenameBlockGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 122 124 98.4 %
Date: 2025-07-17 01:28:37 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       16027 : RenameBlockGenerator::validParams()
      21             : {
      22       16027 :   InputParameters params = MeshGenerator::validParams();
      23             : 
      24       16027 :   params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
      25             : 
      26       16027 :   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       16027 :   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       16027 :   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       16027 :   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       16027 :   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       16027 :   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       16027 :   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       16027 :   return params;
      67           0 : }
      68             : 
      69         882 : RenameBlockGenerator::RenameBlockGenerator(const InputParameters & parameters)
      70         882 :   : MeshGenerator(parameters), _input(getMesh("input"))
      71             : {
      72         878 :   if (isParamValid("old_block_id") && isParamValid("old_block_name"))
      73           4 :     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         874 :   if (isParamValid("new_block_id") && isParamValid("new_block_name"))
      77           4 :     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         870 :   if (isParamValid("old_block"))
      82             :   {
      83         838 :     if (isParamValid("old_block_id"))
      84           4 :       paramError("old_block_id",
      85             :                  "Cannot use with 'old_block'. Use only 'old_block'; 'old_block_id' is "
      86             :                  "deprecated.");
      87         834 :     if (isParamValid("old_block_name"))
      88           4 :       paramError("old_block_name",
      89             :                  "Cannot use with 'old_block'. Use only 'old_block'; 'old_block_name' is "
      90             :                  "deprecated.");
      91         830 :     _old_block = getParam<std::vector<SubdomainName>>("old_block");
      92         830 :     _old_block_param_name = "old_block";
      93             :   }
      94          32 :   else if (isParamValid("old_block_id"))
      95             :   {
      96          60 :     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          40 :     _old_block = isParamValid("old_block_name")
     103          40 :                      ? getParam<std::vector<SubdomainName>>("old_block_name")
     104          20 :                      : std::vector<SubdomainName>{};
     105          20 :     _old_block_param_name = "old_block_name";
     106             :   }
     107             : 
     108         862 :   std::string new_block_param_name;
     109         862 :   if (isParamValid("new_block"))
     110             :   {
     111         838 :     if (isParamValid("new_block_id"))
     112           4 :       paramError("new_block_id",
     113             :                  "Cannot use with 'new_block'. Use only 'new_block'; 'new_block_id' is "
     114             :                  "deprecated.");
     115         834 :     if (isParamValid("new_block_name"))
     116           4 :       paramError("new_block_name",
     117             :                  "Cannot use with 'new_block'. Use only 'new_block'; 'new_block_name' is "
     118             :                  "deprecated.");
     119         830 :     _new_block = getParam<std::vector<SubdomainName>>("new_block");
     120         830 :     new_block_param_name = "new_block";
     121             :   }
     122          24 :   else if (isParamValid("new_block_id"))
     123             :   {
     124          60 :     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          24 :                      ? getParam<std::vector<SubdomainName>>("new_block_name")
     132          12 :                      : std::vector<SubdomainName>{};
     133          12 :     new_block_param_name = "new_block_name";
     134             :   }
     135             : 
     136         854 :   if (_old_block.size() != _new_block.size())
     137           4 :     paramError(new_block_param_name, "Must be the same length as '", _old_block_param_name, "'");
     138         850 : }
     139             : 
     140             : std::unique_ptr<MeshBase>
     141         675 : RenameBlockGenerator::generate()
     142             : {
     143         675 :   std::unique_ptr<MeshBase> mesh = std::move(_input);
     144             : 
     145             :   // MeshBase::subdomain_name will insert, so we need a const ref
     146         675 :   const MeshBase & const_mesh = *mesh;
     147             : 
     148             :   // Get the subdomains in the mesh (this is global)
     149         675 :   std::set<subdomain_id_type> block_ids;
     150         675 :   mesh->subdomain_ids(block_ids);
     151             : 
     152             :   // Helper for getting an unused block ID, and keeping track of it
     153             :   // so that we can generate more later
     154         418 :   auto get_unused_block_id = [this, &block_ids, &const_mesh]()
     155             :   {
     156         286 :     for (const auto id : make_range(Moose::INVALID_BLOCK_ID))
     157         286 :       if (!block_ids.count(id) && !const_mesh.get_subdomain_name_map().count(id))
     158             :       {
     159          44 :         block_ids.insert(id);
     160          44 :         return id;
     161             :       }
     162             : 
     163           0 :     mooseError("Failed to find an unused ID!");
     164         675 :   };
     165             : 
     166         675 :   const auto num_blocks = _old_block.size();
     167             : 
     168             :   // Helper for checking whether or not a SubdomainName (which could be an ID or a name)
     169             :   // is really input as an ID
     170        4440 :   const auto is_subdomain_id = [](const SubdomainName & subdomain_name)
     171        4440 :   { return MooseUtils::isDigits(subdomain_name); };
     172             : 
     173             :   // Get the old block IDs and make sure they exist
     174         675 :   std::vector<SubdomainID> old_block_ids(num_blocks, Moose::INVALID_BLOCK_ID);
     175         675 :   std::vector<SubdomainName> old_block_names(num_blocks);
     176         675 :   std::stringstream missing_block;
     177        2901 :   for (const auto i : make_range(num_blocks))
     178             :   {
     179        2226 :     const SubdomainName & name = _old_block[i];
     180             : 
     181             :     // Convert the SubdomainName to an id and store
     182        2226 :     const auto id = MooseMeshUtils::getSubdomainID(name, *mesh);
     183        2226 :     old_block_ids[i] = id;
     184             : 
     185             :     // Block does not exist - store for a future error
     186        2226 :     if (!block_ids.count(id))
     187           8 :       missing_block << name << " ";
     188             : 
     189             :     // Keep track of the block names
     190             :     // If this SubdomainName is an ID, try to see if it has a name set
     191        2226 :     if (is_subdomain_id(name))
     192        2090 :       old_block_names[i] = const_mesh.subdomain_name(id);
     193             :     // If this SubdomainName is a name, use said name
     194             :     else
     195         136 :       old_block_names[i] = name;
     196             :   }
     197         675 :   if (missing_block.str().size())
     198           4 :     paramError(_old_block_param_name,
     199             :                "The following blocks were requested to be renamed, but do not exist: ",
     200           4 :                missing_block.str());
     201             : 
     202             :   // Get the block IDs that we're moving to
     203         671 :   std::vector<SubdomainID> new_block_ids(num_blocks, Moose::INVALID_BLOCK_ID);
     204         671 :   std::map<SubdomainID, std::string> new_names;
     205        2885 :   for (const auto i : make_range(num_blocks))
     206             :   {
     207        2214 :     const SubdomainName & name = _new_block[i];
     208             : 
     209             :     // If the user input an ID, we have the ID
     210        2214 :     if (is_subdomain_id(name))
     211             :     {
     212         309 :       const auto id = MooseMeshUtils::getSubdomainID(name, *mesh);
     213         309 :       new_block_ids[i] = id;
     214             : 
     215             :       // In the case that this is a new block ID, keep track of it so that we
     216             :       // don't reuse it if we have to create temporaries
     217         309 :       block_ids.insert(id);
     218             : 
     219             :       // Preserve the old block name if there was one
     220         309 :       if (old_block_names[i].size())
     221         154 :         new_names[id] = old_block_names[i];
     222             :     }
     223             :     // If the user input a name, we will use the ID that it is coming from for the
     224             :     // "new" name if the new name does not name a current block. If the name does
     225             :     // exist, we will merge with said block.
     226             :     else
     227             :     {
     228        1905 :       bool name_already_exists = false;
     229             : 
     230             :       // If the target block already exists, merge into that one
     231             :       // Check both the old maps and the new map
     232        5715 :       for (const auto map : {&const_mesh.get_subdomain_name_map(),
     233        7620 :                              const_cast<const std::map<SubdomainID, std::string> *>(&new_names)})
     234       53368 :         for (const auto & id_name_pair : *map)
     235       49558 :           if (!name_already_exists && id_name_pair.second == name)
     236             :           {
     237          11 :             new_block_ids[i] = id_name_pair.first;
     238          11 :             new_names[id_name_pair.first] = name;
     239          11 :             name_already_exists = true;
     240             :           }
     241             : 
     242             :       // Target name doesn't exist, so use the source id/name
     243        1905 :       if (!name_already_exists)
     244             :       {
     245        1894 :         new_block_ids[i] = old_block_ids[i];
     246        1894 :         new_names[new_block_ids[i]] = name;
     247             :       }
     248             :     }
     249             :   }
     250             : 
     251             :   // Create temporaries if needed; recall that this generator is independent
     252             :   // of input ordering and does _not_ merge subdomains.
     253             :   //
     254             :   // Take the example where we want to move 0 -> 1 and 1 -> 2. If we just
     255             :   // move them in order, we will actually end up with (0, 1) -> 2. This is
     256             :   // bad. In this case, we want to first make a temporary for 1 (call it 3).
     257             :   // We then do: 0 -> 3, 1 -> 2, 3 -> 1 in order to get the desired behavior.
     258             :   // We will accomplish this by creating temporaries as needed, modifying
     259             :   // the initial move to the temporaries as needed, and then moving the
     260             :   // temporaries back. temp_change_ids here are the (from -> to) pairs
     261             :   // that we will move at the end.
     262         671 :   auto temp_new_block_ids = new_block_ids;
     263         671 :   std::vector<std::pair<SubdomainID, SubdomainID>> temp_change_ids;
     264             :   // Loop through all new IDs
     265        2885 :   for (const auto new_i : make_range(num_blocks))
     266             :   {
     267             :     // Look at all of the old IDs that will be moved after the move to the new ID.
     268             :     // If any of the old IDs after are IDs that we are moving to, create a temporary
     269             :     // and keep track of it so we can move it back at the end.
     270       51387 :     for (const auto old_i : make_range(new_i + 1, num_blocks))
     271       49217 :       if (new_block_ids[new_i] == old_block_ids[old_i])
     272             :       {
     273          44 :         const auto temp_id = get_unused_block_id();
     274          44 :         temp_change_ids.emplace_back(temp_id, new_block_ids[new_i]);
     275          44 :         temp_new_block_ids[new_i] = temp_id;
     276          44 :         break;
     277             :       }
     278             :   }
     279             : 
     280             :   // First pass through changing the block ids
     281        2885 :   for (const auto i : make_range(num_blocks))
     282        2214 :     MeshTools::Modification::change_subdomain_id(*mesh, old_block_ids[i], temp_new_block_ids[i]);
     283             :   // Pass through moving the temporaries to the actual blocks, if necessary
     284         715 :   for (const auto & pair : temp_change_ids)
     285          44 :     MeshTools::Modification::change_subdomain_id(*mesh, pair.first, pair.second);
     286             : 
     287             :   // First go through and remove all of the old names
     288        2885 :   for (const auto i : make_range(num_blocks))
     289        2214 :     if (mesh->get_subdomain_name_map().count(old_block_ids[i]))
     290         286 :       mesh->set_subdomain_name_map().erase(old_block_ids[i]);
     291             :   // With the old names removed, add the new names if there are any to add
     292        2708 :   for (const auto & pair : new_names)
     293        2037 :     mesh->subdomain_name(pair.first) = pair.second;
     294             : 
     295         671 :   mesh->set_isnt_prepared();
     296        1342 :   return dynamic_pointer_cast<MeshBase>(mesh);
     297         671 : }

Generated by: LCOV version 1.14