https://mooseframework.inl.gov
ParameterRegistration.h
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 #pragma once
11 
12 #include <vector>
13 #include <map>
14 #include <string>
15 
16 #include "hit/hit.h"
17 
18 #include "MooseUtils.h"
19 
20 #define combineParamNames1(X, Y) X##Y
21 #define combineParamNames(X, Y) combineParamNames1(X, Y)
22 
24 #define registerScalarParameter(type) \
25  static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
26  Moose::ParameterRegistry::get().add<type>( \
27  [](type & value, const hit::Field & field) \
28  { Moose::ParameterRegistration::setScalarValue<type>(value, field); })
29 #define registerVectorParameter(type) \
31  static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
32  Moose::ParameterRegistry::get().add<std::vector<type>>( \
33  [](std::vector<type> & value, const hit::Field & field) \
34  { Moose::ParameterRegistration::setVectorValue<type>(value, field); })
35 #define registerDoubleVectorParameter(type) \
37  static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
38  Moose::ParameterRegistry::get().add<std::vector<std::vector<type>>>( \
39  [](std::vector<std::vector<type>> & value, const hit::Field & field) \
40  { Moose::ParameterRegistration::setDoubleVectorValue<type>(value, field); })
41 #define registerTripleVectorParameter(type) \
43  static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
44  Moose::ParameterRegistry::get().add<std::vector<std::vector<std::vector<type>>>>( \
45  [](std::vector<std::vector<std::vector<type>>> & value, const hit::Field & field) \
46  { Moose::ParameterRegistration::setTripleVectorValue<type>(value, field); })
47 #define registerParameter(type) \
49  registerScalarParameter(type); \
50  registerVectorParameter(type); \
51  registerDoubleVectorParameter(type); \
52  registerTripleVectorParameter(type)
53 #define registerMapParameter(key_type, value_type) \
55  static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
56  Moose::ParameterRegistry::get().add<std::map<key_type, value_type>>( \
57  [](std::map<key_type, value_type> & value, const hit::Field & field) \
58  { Moose::ParameterRegistration::setMapValue<key_type, value_type>(value, field); })
59 
61 {
62 
66 template <class T>
67 void setScalarValue(T & value, const hit::Field & field);
68 
72 template <class T>
73 void setVectorValue(std::vector<T> & value, const hit::Field & field);
74 
78 template <class T>
79 void setDoubleVectorValue(std::vector<std::vector<T>> & value, const hit::Field & field);
80 
84 template <class T>
85 void setTripleVectorValue(std::vector<std::vector<std::vector<T>>> & value,
86  const hit::Field & field);
87 
91 template <class Key, class Value>
92 void setMapValue(std::map<Key, Value> & value, const hit::Field & field);
93 
95 template <>
96 void setScalarValue(bool & value, const hit::Field & field);
97 
98 template <class T>
99 void
100 setScalarValue(T & value, const hit::Field & field)
101 {
102  const auto strval = field.param<std::string>();
103  if constexpr (std::is_base_of_v<std::string, T>)
104  {
105  value = strval;
106  }
107  else
108  {
109  if (!MooseUtils::convert<T>(strval, value, false))
110  throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
111  " parameter: " + field.fullpath() + "='" + strval + "'");
112  }
113 }
114 
115 template <class T>
116 void
117 setVectorValue(std::vector<T> & value, const hit::Field & field)
118 {
119  value.clear();
120  const auto base_values = field.param<std::vector<std::string>>();
121  if constexpr (std::is_base_of_v<std::string, T>)
122  {
123  std::copy(base_values.begin(), base_values.end(), std::back_inserter(value));
124  }
125  else
126  {
127  value.resize(base_values.size());
128  for (const auto i : index_range(base_values))
129  {
130  if constexpr (std::is_same_v<bool, T>)
131  {
132  if (base_values[i] == "1")
133  {
134  value[i] = true;
135  continue;
136  }
137  else if (base_values[i] == "0")
138  {
139  value[i] = false;
140  continue;
141  }
142  else if (bool bool_val; hit::toBool(base_values[i], &bool_val))
143  {
144  value[i] = bool_val;
145  continue;
146  }
147  }
148  else
149  {
150  if (MooseUtils::convert<T>(base_values[i], value[i], false))
151  continue;
152  }
153 
154  throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
155  " vector parameter: " + field.fullpath() + "[" +
156  std::to_string(i) + "]='" + base_values[i] + "'");
157  }
158  }
159 }
160 
161 template <class T>
162 void
163 setDoubleVectorValue(std::vector<std::vector<T>> & value, const hit::Field & field)
164 {
165  value.clear();
166  const auto strval = MooseUtils::trim(field.param<std::string>());
167  if (strval.empty())
168  return;
169 
170  // split vector on ";" (the substrings are _not_ of type T yet)
171  // The zero length here is intentional, as we want something like:
172  // "abc; 123;" -> ["abc", "123", ""]
173  const auto tokens = MooseUtils::split(strval, ";");
174 
175  value.resize(tokens.size());
176  for (const auto i : index_range(tokens))
177  {
178  const auto token = MooseUtils::trim(tokens[i]);
179  if (!MooseUtils::tokenizeAndConvert<T>(token, value[i]))
180  throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
181  " double vector parameter: " + field.fullpath() + "[" +
182  std::to_string(i) + "]='" + token + "'");
183  }
184 }
185 
186 template <class T>
187 void
188 setTripleVectorValue(std::vector<std::vector<std::vector<T>>> & value, const hit::Field & field)
189 {
190  value.clear();
191  const auto value_string = field.param<std::string>();
192  if (value_string.find_first_not_of(' ', 0) == std::string::npos)
193  return;
194 
195  // Add a space between neighboring delim's, before the first delim if nothing is ahead of it, and
196  // after the last delim if nothing is behind it.
197  std::string buffer;
198  buffer.push_back(value_string[0]);
199  if (buffer[0] == '|' || buffer[0] == ';')
200  buffer = ' ' + buffer;
201  for (std::string::size_type i = 1; i < value_string.size(); i++)
202  {
203  const auto val = value_string[i];
204  const auto last_val = value_string[i - 1];
205  if ((last_val == '|' || last_val == ';') && (val == '|' || val == ';'))
206  buffer.push_back(' ');
207  buffer.push_back(val);
208  }
209  if (buffer.back() == '|' || buffer.back() == ';')
210  buffer.push_back(' ');
211 
212  // split vector at delim | to get a series of 2D subvectors
213  std::vector<std::string> outer_tokens;
214  MooseUtils::tokenize(buffer, outer_tokens, 1, "|");
215  value.resize(outer_tokens.size());
216  for (const auto i : index_range(outer_tokens))
217  {
218  const auto & inner_token = outer_tokens[i];
219  auto & inner_value = value[i];
220 
221  // Identify empty subvector first
222  if (inner_token.find_first_not_of(' ', 0) == std::string::npos)
223  {
224  mooseAssert(inner_value.empty(), "Should be empty");
225  continue;
226  }
227 
228  // split each 2D subvector at delim ; to get 1D sub-subvectors
229  // NOTE: the 1D sub-subvectors are _not_ of type T yet
230  std::vector<std::string> inner_tokenized;
231  MooseUtils::tokenize(inner_token, inner_tokenized, 1, ";");
232  inner_value.resize(inner_tokenized.size());
233  for (const auto j : index_range(inner_tokenized))
234  {
235  const auto token = MooseUtils::trim(inner_tokenized[j]);
236  if (!MooseUtils::tokenizeAndConvert<T>(token, inner_value[j]))
237  throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
238  " triple vector parameter: " + field.fullpath() + "[" +
239  std::to_string(i) + "][" + std::to_string(j) + "]='" + token +
240  "'");
241  }
242  }
243 }
244 
245 template <class Key, class Value>
246 void
247 setMapValue(std::map<Key, Value> & value, const hit::Field & field)
248 {
249  value.clear();
250 
251  const auto string_vec = field.param<std::vector<std::string>>();
252  auto it = string_vec.begin();
253  while (it != string_vec.end())
254  {
255  const auto & string_key = *(it++);
256  if (it == string_vec.end())
257  throw std::invalid_argument(
258  "odd number of entries for map parameter '" + field.fullpath() +
259  "'; there must be an even number or else you will end up with a key without a value");
260  const auto & string_value = *(it++);
261 
262  std::pair<Key, Value> pr;
263 
264  // convert key
265  if (!MooseUtils::convert<Key>(string_key, pr.first, false))
266  throw std::invalid_argument("invalid " + MooseUtils::prettyCppType<Key>() +
267  " syntax for map parameter '" + field.fullpath() + "' key: '" +
268  string_key + "'");
269 
270  // convert value
271  if (!MooseUtils::convert<Value>(string_value, pr.second, false))
272  throw std::invalid_argument("invalid " + MooseUtils::prettyCppType<Value>() +
273  " syntax for map parameter '" + field.fullpath() + "' value: '" +
274  string_value + "'");
275  // attempt insert
276  if (!value.insert(std::move(pr)).second)
277  throw std::invalid_argument("duplicate entry for map parameter: '" + field.fullpath() +
278  "'; key '" + string_key + "' appears multiple times");
279  }
280 }
281 
282 } // end of namespace Moose::ParameterRegistration
void tokenize(const std::string &str, std::vector< T > &elements, unsigned int min_len=1, const std::string &delims="/")
This function will split the passed in string on a set of delimiters appending the substrings to the ...
void setScalarValue(T &value, const hit::Field &field)
Converts the given field node into a scalar of the given type.
void setDoubleVectorValue(std::vector< std::vector< T >> &value, const hit::Field &field)
Converts the given field node into a vector-of-vectors of the given type.
void setVectorValue(std::vector< T > &value, const hit::Field &field)
Converts the given field node into a vector of the given type.
std::vector< std::string > split(const std::string &str, const std::string &delimiter, std::size_t max_count=std::numeric_limits< std::size_t >::max())
Python like split functions for strings.
Definition: MooseUtils.C:1027
void setMapValue(std::map< Key, Value > &value, const hit::Field &field)
Converts the given field node into a map with the given types.
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
std::string trim(const std::string &str, const std::string &white_space=" \\\)
Standard scripting language trim function.
auto index_range(const T &sizable)
void setTripleVectorValue(std::vector< std::vector< std::vector< T >>> &value, const hit::Field &field)
Converts the given field node into a triple-indexed vector of the given type.