https://mooseframework.inl.gov
TimedSubdomainModifier.C
Go to the documentation of this file.
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"
12 #include "DelimitedFileReader.h"
13 #include "MooseMesh.h"
14 
16 
19 {
21 
22  // parameters for direct input
23  params.addParam<std::vector<Real>>("times", "The times of the subdomain modifications.");
24  params.addParam<std::vector<SubdomainName>>("blocks_from",
25  "Names or ids of the 'old' block(s), to be renamed.");
26  params.addParam<std::vector<SubdomainName>>("blocks_to", "Names or ids of the 'new' block.");
27  params.addParamNamesToGroup("times blocks_from blocks_to", "Subdomain change data from input");
28 
29  // parameters for file-based data supply
30  params.addParam<FileName>("data_file", "File holding CSV data");
31  params.addParam<bool>("header",
32  "Indicates whether the file contains a header with the column names");
33  params.addParam<std::string>("delimiter", ",", "Delimiter used to parse the file");
34  params.addParam<std::string>("comment", ";", "Comment character used to parse the file");
35  params.addParam<std::size_t>(
36  "time_column_index", 0, "Zero-based index of the time column. Default is '0'.");
37  params.addParam<std::size_t>(
38  "blocks_from_column_index", 1, "Zero-based index of the blocks_from column. Default is '1'.");
39  params.addParam<std::size_t>(
40  "blocks_to_column_index", 2, "Zero-based index of the blocks_to column. Default is '2'.");
41  params.addParam<std::string>("time_column_text", "Header text of the time column.");
42  params.addParam<std::string>("blocks_from_column_text", "Header text of the blocks_from column.");
43  params.addParam<std::string>("blocks_to_column_text", "Header text of the blocks_to column.");
44  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  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  return params;
55 }
56 
58  : TimedElementSubdomainModifier(parameters)
59 {
60  // determine function arguments
61 
62  // helper variables for parameter consistency checks
63  const auto from_data_file =
64  isParamSetByUser("data_file") + isParamSetByUser("header") + isParamSetByUser("delimiter") +
65  isParamSetByUser("comment") + isParamSetByUser("time_column_index") +
66  isParamSetByUser("blocks_from_column_index") + isParamSetByUser("blocks_to_column_index") +
67  isParamSetByUser("time_column_text") + isParamSetByUser("blocks_from_column_text") +
68  isParamSetByUser("blocks_to_column_text");
69 
70  const auto from_data_File_needs_header = isParamSetByUser("time_column_text") +
71  isParamSetByUser("blocks_from_column_text") +
72  isParamSetByUser("blocks_to_column_text");
73 
74  const auto from_parameters =
75  isParamSetByUser("times") + isParamSetByUser("blocks_from") + isParamSetByUser("blocks_to");
76 
77  // Check parameter set for inconsistencies
78  const auto from_source_count = ((from_data_file > 0) + (from_parameters > 0));
79  if (from_source_count != 1)
80  {
81  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  if (from_parameters > 0)
87  {
88  if (from_parameters != 3)
89  mooseError("All parameters 'times', and 'blocks_from', and 'blocks_to' must be specified.");
91  }
92  else if (from_data_file > 0)
93  {
94  if ((isParamSetByUser("time_column_index") + isParamSetByUser("time_column_text")) > 1)
95  mooseError(
96  "The parameters 'time_column_index', and 'time_column_text' are mutual exclusive.");
97  if ((isParamSetByUser("blocks_from_column_index") +
98  isParamSetByUser("blocks_from_column_text")) > 1)
99  mooseError("The parameters 'blocks_from_column_index', and 'blocks_from_column_text' are "
100  "mutual exclusive.");
101  if ((isParamSetByUser("blocks_to_column_index") + isParamSetByUser("blocks_to_column_text")) >
102  1)
103  mooseError("The parameters 'blocks_to_column_index', and 'blocks_to_column_text' are mutual "
104  "exclusive.");
105  if ((from_data_File_needs_header > 0) && (isParamSetByUser("header") == 0))
106  mooseError("Header flag must be active if columns are to be found via header.");
107 
108  buildFromFile();
109  }
110  else
111  mooseError("Unknown data source. Are you missing a parameter? Did you misspell one?");
112 }
113 
114 void
116 {
117  _times = getParam<std::vector<Real>>("times");
118  const auto n = _times.size();
119 
120  const auto raw_from = getParam<std::vector<SubdomainName>>("blocks_from");
121  const auto raw_to = getParam<std::vector<SubdomainName>>("blocks_to");
122 
123  if (raw_from.size() != n)
124  mooseError(
125  "Parameter 'blocks_from' must contain the same number of items as parameter 'times'.");
126  if (raw_to.size() != n)
127  mooseError("Parameter 'blocks_to' must contain the same number of items as parameter 'times'.");
128 
129  _blocks_from.resize(n);
130  _blocks_to.resize(n);
131 
132  for (const auto i : index_range(raw_from))
133  {
134  _blocks_from[i] = getSubdomainIDAndCheck(raw_from[i]);
135  _blocks_to[i] = getSubdomainIDAndCheck(raw_to[i]);
136  }
137 }
138 
139 void
141 {
142  const auto _file_name = getParam<FileName>("data_file");
143 
146  if (isParamValid("header"))
147  {
148  _header_flag = getParam<bool>("header")
151  }
152 
153  std::string _delimiter = ",";
154  if (isParamValid("delimiter"))
155  {
156  _delimiter = getParam<std::string>("delimiter");
157  }
158 
159  std::string _comment = "#";
160  if (isParamValid("comment"))
161  {
162  _comment = getParam<std::string>("comment");
163  }
164 
166 
167  file.setHeaderFlag(_header_flag);
168  file.setDelimiter(_delimiter);
169  file.setComment(_comment);
170  file.read();
171 
172  std::size_t _time_column = 0;
173  if (isParamValid("time_column_text"))
174  {
175  const auto s = getParam<std::string>("time_column_text");
176  const auto _names = file.getNames();
177  const auto it = find(_names.begin(), _names.end(), s);
178  if (it == _names.end())
179  mooseError("Could not find '", s, "' in header of file ", _file_name, ".");
180  _time_column = std::distance(_names.begin(), it);
181  }
182  else if (isParamValid("time_column_index"))
183  {
184  _time_column = getParam<std::size_t>("time_column_index");
185  }
186 
187  std::size_t _blocks_from_column = 1;
188  if (isParamValid("blocks_from_column_text"))
189  {
190  const auto s = getParam<std::string>("blocks_from_column_text");
191  const auto _names = file.getNames();
192  const auto it = find(_names.begin(), _names.end(), s);
193  if (it == _names.end())
194  mooseError("Could not find '", s, "' in header of file ", _file_name, ".");
195  _blocks_from_column = std::distance(_names.begin(), it);
196  }
197  else if (isParamValid("blocks_from_column_index"))
198  {
199  _blocks_from_column = getParam<std::size_t>("blocks_from_column_index");
200  }
201 
202  std::size_t _blocks_to_column = 2;
203  if (isParamValid("blocks_to_column_text"))
204  {
205  const auto s = getParam<std::string>("blocks_to_column_text");
206  const auto _names = file.getNames();
207  const auto it = find(_names.begin(), _names.end(), s);
208  if (it == _names.end())
209  mooseError("Could not find '", s, "' in header of file ", _file_name, ".");
210  _blocks_to_column = std::distance(_names.begin(), it);
211  }
212  else if (isParamValid("blocks_to_column_index"))
213  _blocks_to_column = getParam<std::size_t>("blocks_to_column_index");
214 
215  const auto max_needed_column_index =
216  std::max({_time_column, _blocks_from_column, _blocks_to_column});
217 
218  const auto data = file.getData();
219 
220  if (data.size() < max_needed_column_index)
221  mooseError("data must contain at least " + std::to_string(max_needed_column_index) +
222  " columns in file ",
223  _file_name);
224 
225  const auto strTimes = data[_time_column];
226  const auto strBlockFrom = data[_blocks_from_column];
227  const auto strBlockTo = data[_blocks_to_column];
228 
229  const auto n_rows = strTimes.size();
230 
231  // some sanity checks
232  if (n_rows == 0)
233  mooseError("empty sequence in file ", _file_name);
234  if (n_rows != strBlockFrom.size())
235  mooseError("Inconsistent source block data size in ",
236  _file_name,
237  ". Expected ",
238  n_rows,
239  " and read ",
240  strBlockFrom.size());
241  if (n_rows != strBlockTo.size())
242  mooseError("Inconsistent target block data size in ",
243  _file_name,
244  ". Expected ",
245  n_rows,
246  " and read ",
247  strBlockTo.size());
248 
249  // resize variables to fit the data
250  _blocks_from.resize(n_rows);
251  _blocks_to.resize(n_rows);
252 
253  // fill the to and from blocks vectors
254  for (const auto & time_str : strTimes)
255  _times.push_back(std::stod(time_str));
256  std::transform(strBlockFrom.begin(),
257  strBlockFrom.end(),
258  _blocks_from.begin(),
259  [this](const std::string & x) { return getSubdomainIDAndCheck(x); });
260  std::transform(strBlockTo.begin(),
261  strBlockTo.end(),
262  _blocks_to.begin(),
263  [this](const std::string & x) { return getSubdomainIDAndCheck(x); });
264 }
265 
267 TimedSubdomainModifier::getSubdomainIDAndCheck(const std::string & subdomain_name)
268 {
269  const auto id = _mesh.getSubdomainID(subdomain_name);
270  if (id == Moose::INVALID_BLOCK_ID)
271  mooseError("block", "Subdomain \"" + subdomain_name + "\" not found in mesh.");
272  return id;
273 }
274 
277 {
278  // get the subdomain-id of the current element
279  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  for (const auto & time_pair : _times_and_indices)
284  {
285  // time of the data point
286  const auto t = time_pair.time;
287 
288  // original data point index
289  const auto j = time_pair.index;
290 
291  // do we have to apply?
292  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  resulting_subdomain_id = _blocks_to[j];
296  }
297  }
298 
299  return resulting_subdomain_id;
300 }
void setComment(const std::string &value)
std::set< TimeIndexPair > _times_and_indices
Times and subdomain changes to make.
std::vector< Real > _times
Times to change the subdomains on.
std::vector< SubdomainID > _blocks_to
Target subdomains to change the source subdomains to.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
auto max(const L &left, const R &right)
registerMooseObject("MooseApp", TimedSubdomainModifier)
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
const SubdomainID INVALID_BLOCK_ID
Definition: MooseTypes.C:20
std::vector< SubdomainID > _blocks_from
Source subdomains to change from.
const Real & _t_old
Old time.
void read()
Perform the actual data reading.
const std::vector< std::vector< T > > & getData() const
Return the rows/columns of data.
static InputParameters validParams()
bool isParamSetByUser(const std::string &nm) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
virtual SubdomainID computeSubdomainID() override
Compute the subdomain ID of the current element.
const Elem *const & _current_elem
The current element pointer (available during execute())
Utility class for reading delimited data (e.g., CSV data).
SubdomainID getSubdomainIDAndCheck(const std::string &subdomain_name)
void setDelimiter(const std::string &value)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
const std::vector< std::string > & getNames() const
Return the column/row names.
Modifies element subdomains only at a given list of times.
auto index_range(const T &sizable)
TimedSubdomainModifier(const InputParameters &parameters)
Modifies elements from entire subdomains based on user input or file input.
SubdomainID getSubdomainID(const SubdomainName &subdomain_name) const
Get the associated subdomain ID for the subdomain name.
Definition: MooseMesh.C:1728
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...