LCOV - code coverage report
Current view: top level - src/meshmodifiers - TimedSubdomainModifier.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 119 157 75.8 %
Date: 2025-07-17 01:28:37 Functions: 8 8 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 "TimedSubdomainModifier.h"
      11             : #include "TimedElementSubdomainModifier.h"
      12             : #include "DelimitedFileReader.h"
      13             : #include "MooseMesh.h"
      14             : 
      15             : registerMooseObject("MooseApp", TimedSubdomainModifier);
      16             : 
      17             : InputParameters
      18       14390 : TimedSubdomainModifier::validParams()
      19             : {
      20       14390 :   InputParameters params = TimedElementSubdomainModifier::validParams();
      21             : 
      22             :   // parameters for direct input
      23       14390 :   params.addParam<std::vector<Real>>("times", "The times of the subdomain modifications.");
      24       14390 :   params.addParam<std::vector<SubdomainName>>("blocks_from",
      25             :                                               "Names or ids of the 'old' block(s), to be renamed.");
      26       14390 :   params.addParam<std::vector<SubdomainName>>("blocks_to", "Names or ids of the 'new' block.");
      27       14390 :   params.addParamNamesToGroup("times blocks_from blocks_to", "Subdomain change data from input");
      28             : 
      29             :   // parameters for file-based data supply
      30       14390 :   params.addParam<FileName>("data_file", "File holding CSV data");
      31       14390 :   params.addParam<bool>("header",
      32             :                         "Indicates whether the file contains a header with the column names");
      33       14390 :   params.addParam<std::string>("delimiter", ",", "Delimiter used to parse the file");
      34       14390 :   params.addParam<std::string>("comment", ";", "Comment character used to parse the file");
      35       43170 :   params.addParam<std::size_t>(
      36       28780 :       "time_column_index", 0, "Zero-based index of the time column. Default is '0'.");
      37       43170 :   params.addParam<std::size_t>(
      38       28780 :       "blocks_from_column_index", 1, "Zero-based index of the blocks_from column. Default is '1'.");
      39       43170 :   params.addParam<std::size_t>(
      40       28780 :       "blocks_to_column_index", 2, "Zero-based index of the blocks_to column. Default is '2'.");
      41       14390 :   params.addParam<std::string>("time_column_text", "Header text of the time column.");
      42       14390 :   params.addParam<std::string>("blocks_from_column_text", "Header text of the blocks_from column.");
      43       14390 :   params.addParam<std::string>("blocks_to_column_text", "Header text of the blocks_to column.");
      44       14390 :   params.addParamNamesToGroup(
      45             :       "data_file header delimiter comment time_column_index blocks_from_column_index "
      46             :       "blocks_to_column_index time_column_text blocks_from_column_text blocks_to_column_text",
      47             :       "Subdomain change data from CSV file");
      48             : 
      49       14390 :   params.addClassDescription(
      50             :       "Modify element subdomain ID of entire subdomains for given points "
      51             :       "in time. This mesh modifier only runs on the undisplaced mesh, and it will "
      52             :       "modify both the undisplaced and the displaced mesh.");
      53             : 
      54       14390 :   return params;
      55           0 : }
      56             : 
      57          65 : TimedSubdomainModifier::TimedSubdomainModifier(const InputParameters & parameters)
      58          65 :   : TimedElementSubdomainModifier(parameters)
      59             : {
      60             :   // determine function arguments
      61             : 
      62             :   // helper variables for parameter consistency checks
      63             :   const auto from_data_file =
      64         130 :       isParamSetByUser("data_file") + isParamSetByUser("header") + isParamSetByUser("delimiter") +
      65         130 :       isParamSetByUser("comment") + isParamSetByUser("time_column_index") +
      66         130 :       isParamSetByUser("blocks_from_column_index") + isParamSetByUser("blocks_to_column_index") +
      67         130 :       isParamSetByUser("time_column_text") + isParamSetByUser("blocks_from_column_text") +
      68          65 :       isParamSetByUser("blocks_to_column_text");
      69             : 
      70         130 :   const auto from_data_File_needs_header = isParamSetByUser("time_column_text") +
      71         130 :                                            isParamSetByUser("blocks_from_column_text") +
      72          65 :                                            isParamSetByUser("blocks_to_column_text");
      73             : 
      74             :   const auto from_parameters =
      75          65 :       isParamSetByUser("times") + isParamSetByUser("blocks_from") + isParamSetByUser("blocks_to");
      76             : 
      77             :   // Check parameter set for inconsistencies
      78          65 :   const auto from_source_count = ((from_data_file > 0) + (from_parameters > 0));
      79          65 :   if (from_source_count != 1)
      80             :   {
      81           0 :     mooseError("Data on times and blocks must be provided either via a CSV file ('data_file' and "
      82             :                "corresponding blocks), or via direct parameter input ('times', 'blocks_from', and "
      83             :                "'blocks_to').");
      84             :   }
      85             : 
      86          65 :   if (from_parameters > 0)
      87             :   {
      88          52 :     if (from_parameters != 3)
      89           0 :       mooseError("All parameters 'times', and 'blocks_from', and 'blocks_to' must be specified.");
      90          52 :     buildFromParameters();
      91             :   }
      92          13 :   else if (from_data_file > 0)
      93             :   {
      94          13 :     if ((isParamSetByUser("time_column_index") + isParamSetByUser("time_column_text")) > 1)
      95           0 :       mooseError(
      96             :           "The parameters 'time_column_index', and 'time_column_text' are mutual exclusive.");
      97          26 :     if ((isParamSetByUser("blocks_from_column_index") +
      98          13 :          isParamSetByUser("blocks_from_column_text")) > 1)
      99           0 :       mooseError("The parameters 'blocks_from_column_index', and 'blocks_from_column_text' are "
     100             :                  "mutual exclusive.");
     101          13 :     if ((isParamSetByUser("blocks_to_column_index") + isParamSetByUser("blocks_to_column_text")) >
     102             :         1)
     103           0 :       mooseError("The parameters 'blocks_to_column_index', and 'blocks_to_column_text' are mutual "
     104             :                  "exclusive.");
     105          13 :     if ((from_data_File_needs_header > 0) && (isParamSetByUser("header") == 0))
     106           0 :       mooseError("Header flag must be active if columns are to be found via header.");
     107             : 
     108          13 :     buildFromFile();
     109             :   }
     110             :   else
     111           0 :     mooseError("Unknown data source. Are you missing a parameter? Did you misspell one?");
     112          65 : }
     113             : 
     114             : void
     115          52 : TimedSubdomainModifier::buildFromParameters()
     116             : {
     117          52 :   _times = getParam<std::vector<Real>>("times");
     118          52 :   const auto n = _times.size();
     119             : 
     120          52 :   const auto raw_from = getParam<std::vector<SubdomainName>>("blocks_from");
     121          52 :   const auto raw_to = getParam<std::vector<SubdomainName>>("blocks_to");
     122             : 
     123          52 :   if (raw_from.size() != n)
     124           0 :     mooseError(
     125             :         "Parameter 'blocks_from' must contain the same number of items as parameter 'times'.");
     126          52 :   if (raw_to.size() != n)
     127           0 :     mooseError("Parameter 'blocks_to' must contain the same number of items as parameter 'times'.");
     128             : 
     129          52 :   _blocks_from.resize(n);
     130          52 :   _blocks_to.resize(n);
     131             : 
     132         169 :   for (const auto i : index_range(raw_from))
     133             :   {
     134         117 :     _blocks_from[i] = getSubdomainIDAndCheck(raw_from[i]);
     135         117 :     _blocks_to[i] = getSubdomainIDAndCheck(raw_to[i]);
     136             :   }
     137          52 : }
     138             : 
     139             : void
     140          13 : TimedSubdomainModifier::buildFromFile()
     141             : {
     142          13 :   const auto _file_name = getParam<FileName>("data_file");
     143             : 
     144             :   /// Flag indicating if the file contains a header.
     145          13 :   auto _header_flag = MooseUtils::DelimitedFileOfStringReader::HeaderFlag::OFF;
     146          13 :   if (isParamValid("header"))
     147             :   {
     148          26 :     _header_flag = getParam<bool>("header")
     149          13 :                        ? MooseUtils::DelimitedFileOfStringReader::HeaderFlag::ON
     150             :                        : MooseUtils::DelimitedFileOfStringReader::HeaderFlag::OFF;
     151             :   }
     152             : 
     153          13 :   std::string _delimiter = ",";
     154          13 :   if (isParamValid("delimiter"))
     155             :   {
     156          13 :     _delimiter = getParam<std::string>("delimiter");
     157             :   }
     158             : 
     159          13 :   std::string _comment = "#";
     160          13 :   if (isParamValid("comment"))
     161             :   {
     162          13 :     _comment = getParam<std::string>("comment");
     163             :   }
     164             : 
     165          13 :   MooseUtils::DelimitedFileOfStringReader file(_file_name);
     166             : 
     167          13 :   file.setHeaderFlag(_header_flag);
     168          13 :   file.setDelimiter(_delimiter);
     169          13 :   file.setComment(_comment);
     170          13 :   file.read();
     171             : 
     172          13 :   std::size_t _time_column = 0;
     173          13 :   if (isParamValid("time_column_text"))
     174             :   {
     175           0 :     const auto s = getParam<std::string>("time_column_text");
     176           0 :     const auto _names = file.getNames();
     177           0 :     const auto it = find(_names.begin(), _names.end(), s);
     178           0 :     if (it == _names.end())
     179           0 :       mooseError("Could not find '", s, "' in header of file ", _file_name, ".");
     180           0 :     _time_column = std::distance(_names.begin(), it);
     181           0 :   }
     182          13 :   else if (isParamValid("time_column_index"))
     183             :   {
     184          13 :     _time_column = getParam<std::size_t>("time_column_index");
     185             :   }
     186             : 
     187          13 :   std::size_t _blocks_from_column = 1;
     188          13 :   if (isParamValid("blocks_from_column_text"))
     189             :   {
     190           0 :     const auto s = getParam<std::string>("blocks_from_column_text");
     191           0 :     const auto _names = file.getNames();
     192           0 :     const auto it = find(_names.begin(), _names.end(), s);
     193           0 :     if (it == _names.end())
     194           0 :       mooseError("Could not find '", s, "' in header of file ", _file_name, ".");
     195           0 :     _blocks_from_column = std::distance(_names.begin(), it);
     196           0 :   }
     197          13 :   else if (isParamValid("blocks_from_column_index"))
     198             :   {
     199          13 :     _blocks_from_column = getParam<std::size_t>("blocks_from_column_index");
     200             :   }
     201             : 
     202          13 :   std::size_t _blocks_to_column = 2;
     203          13 :   if (isParamValid("blocks_to_column_text"))
     204             :   {
     205           0 :     const auto s = getParam<std::string>("blocks_to_column_text");
     206           0 :     const auto _names = file.getNames();
     207           0 :     const auto it = find(_names.begin(), _names.end(), s);
     208           0 :     if (it == _names.end())
     209           0 :       mooseError("Could not find '", s, "' in header of file ", _file_name, ".");
     210           0 :     _blocks_to_column = std::distance(_names.begin(), it);
     211           0 :   }
     212          13 :   else if (isParamValid("blocks_to_column_index"))
     213          13 :     _blocks_to_column = getParam<std::size_t>("blocks_to_column_index");
     214             : 
     215             :   const auto max_needed_column_index =
     216          13 :       std::max({_time_column, _blocks_from_column, _blocks_to_column});
     217             : 
     218          13 :   const auto data = file.getData();
     219             : 
     220          13 :   if (data.size() < max_needed_column_index)
     221           0 :     mooseError("data must contain at least " + std::to_string(max_needed_column_index) +
     222             :                    " columns in file ",
     223             :                _file_name);
     224             : 
     225          13 :   const auto strTimes = data[_time_column];
     226          13 :   const auto strBlockFrom = data[_blocks_from_column];
     227          13 :   const auto strBlockTo = data[_blocks_to_column];
     228             : 
     229          13 :   const auto n_rows = strTimes.size();
     230             : 
     231             :   // some sanity checks
     232          13 :   if (n_rows == 0)
     233           0 :     mooseError("empty sequence in file ", _file_name);
     234          13 :   if (n_rows != strBlockFrom.size())
     235           0 :     mooseError("Inconsistent source block data size in ",
     236             :                _file_name,
     237             :                ". Expected ",
     238             :                n_rows,
     239             :                " and read ",
     240           0 :                strBlockFrom.size());
     241          13 :   if (n_rows != strBlockTo.size())
     242           0 :     mooseError("Inconsistent target block data size in ",
     243             :                _file_name,
     244             :                ". Expected ",
     245             :                n_rows,
     246             :                " and read ",
     247           0 :                strBlockTo.size());
     248             : 
     249             :   // resize variables to fit the data
     250          13 :   _blocks_from.resize(n_rows);
     251          13 :   _blocks_to.resize(n_rows);
     252             : 
     253             :   // fill the to and from blocks vectors
     254          39 :   for (const auto & time_str : strTimes)
     255          26 :     _times.push_back(std::stod(time_str));
     256          13 :   std::transform(strBlockFrom.begin(),
     257             :                  strBlockFrom.end(),
     258             :                  _blocks_from.begin(),
     259          26 :                  [this](const std::string & x) { return getSubdomainIDAndCheck(x); });
     260          13 :   std::transform(strBlockTo.begin(),
     261             :                  strBlockTo.end(),
     262             :                  _blocks_to.begin(),
     263          26 :                  [this](const std::string & x) { return getSubdomainIDAndCheck(x); });
     264          13 : }
     265             : 
     266             : SubdomainID
     267         286 : TimedSubdomainModifier::getSubdomainIDAndCheck(const std::string & subdomain_name)
     268             : {
     269         286 :   const auto id = _mesh.getSubdomainID(subdomain_name);
     270         286 :   if (id == Moose::INVALID_BLOCK_ID)
     271           0 :     mooseError("block", "Subdomain \"" + subdomain_name + "\" not found in mesh.");
     272         286 :   return id;
     273             : }
     274             : 
     275             : SubdomainID
     276      150016 : TimedSubdomainModifier::computeSubdomainID()
     277             : {
     278             :   // get the subdomain-id of the current element
     279      150016 :   SubdomainID resulting_subdomain_id = _current_elem->subdomain_id();
     280             : 
     281             :   // check for all the subdomain changes that can have been requested between the previous and the
     282             :   // current time
     283      528256 :   for (const auto & time_pair : _times_and_indices)
     284             :   {
     285             :     // time of the data point
     286      378240 :     const auto t = time_pair.time;
     287             : 
     288             :     // original data point index
     289      378240 :     const auto j = time_pair.index;
     290             : 
     291             :     // do we have to apply?
     292      378240 :     if (t > _t_old && t <= _t && resulting_subdomain_id == _blocks_from[j])
     293             :     {
     294             :       // we have to change the subdomain-id using the original index (stored in 'j')
     295        2256 :       resulting_subdomain_id = _blocks_to[j];
     296             :     }
     297             :   }
     298             : 
     299      150016 :   return resulting_subdomain_id;
     300             : }

Generated by: LCOV version 1.14