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 : #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 :
23 : /// Macro for registering a scalar parameter using the setScalarValue helper
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 : /// Macro for registering a vector parameter using the setVectorValue helper
30 : #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 : /// Macro for registering a double vector parameter using the setDoubleVectorValue helper
36 : #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 : /// Macro for registering a double vector parameter using the setTripleVectorValue helper
42 : #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 : /// Macro for registering a scalar, vector, double vector, and triple vector parameter
48 : #define registerParameter(type) \
49 : registerScalarParameter(type); \
50 : registerVectorParameter(type); \
51 : registerDoubleVectorParameter(type); \
52 : registerTripleVectorParameter(type)
53 : /// Macro for registering a map parameter of the given type using the setMapValue helper
54 : #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 :
60 : namespace Moose::ParameterRegistration
61 : {
62 :
63 : /**
64 : * Converts the given field node into a scalar of the given type.
65 : */
66 : template <class T>
67 : void setScalarValue(T & value, const hit::Field & field);
68 :
69 : /**
70 : * Converts the given field node into a vector of the given type.
71 : */
72 : template <class T>
73 : void setVectorValue(std::vector<T> & value, const hit::Field & field);
74 :
75 : /**
76 : * Converts the given field node into a vector-of-vectors of the given type.
77 : */
78 : template <class T>
79 : void setDoubleVectorValue(std::vector<std::vector<T>> & value, const hit::Field & field);
80 :
81 : /**
82 : * Converts the given field node into a triple-indexed vector of the given type.
83 : */
84 : template <class T>
85 : void setTripleVectorValue(std::vector<std::vector<std::vector<T>>> & value,
86 : const hit::Field & field);
87 :
88 : /**
89 : * Converts the given field node into a map with the given types.
90 : */
91 : template <class Key, class Value>
92 : void setMapValue(std::map<Key, Value> & value, const hit::Field & field);
93 :
94 : /// setScalarValue specialiation for bool
95 : template <>
96 : void setScalarValue(bool & value, const hit::Field & field);
97 :
98 : template <class T>
99 : void
100 1541307 : setScalarValue(T & value, const hit::Field & field)
101 : {
102 3082614 : const auto strval = field.param<std::string>();
103 : if constexpr (std::is_base_of_v<std::string, T>)
104 : {
105 1112733 : value = strval;
106 : }
107 : else
108 : {
109 428574 : if (!MooseUtils::convert<T>(strval, value, false))
110 5 : throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
111 : " parameter: " + field.fullpath() + "='" + strval + "'");
112 : }
113 1541307 : }
114 :
115 : template <class T>
116 : void
117 440408 : setVectorValue(std::vector<T> & value, const hit::Field & field)
118 : {
119 440408 : value.clear();
120 880816 : const auto base_values = field.param<std::vector<std::string>>();
121 : if constexpr (std::is_base_of_v<std::string, T>)
122 : {
123 371317 : std::copy(base_values.begin(), base_values.end(), std::back_inserter(value));
124 : }
125 : else
126 : {
127 69091 : value.resize(base_values.size());
128 215617 : for (const auto i : index_range(base_values))
129 : {
130 : if constexpr (std::is_same_v<bool, T>)
131 : {
132 2287 : if (base_values[i] == "1")
133 : {
134 20 : value[i] = true;
135 20 : continue;
136 : }
137 2267 : else if (base_values[i] == "0")
138 : {
139 20 : value[i] = false;
140 20 : continue;
141 : }
142 2247 : else if (bool bool_val; hit::toBool(base_values[i], &bool_val))
143 : {
144 2147 : value[i] = bool_val;
145 2147 : continue;
146 : }
147 : }
148 : else
149 : {
150 144340 : if (MooseUtils::convert<T>(base_values[i], value[i], false))
151 144339 : continue;
152 : }
153 :
154 202 : throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
155 : " vector parameter: " + field.fullpath() + "[" +
156 101 : std::to_string(i) + "]='" + base_values[i] + "'");
157 : }
158 : }
159 440408 : }
160 :
161 : template <class T>
162 : void
163 5693 : setDoubleVectorValue(std::vector<std::vector<T>> & value, const hit::Field & field)
164 : {
165 5693 : value.clear();
166 17079 : const auto strval = MooseUtils::trim(field.param<std::string>());
167 5693 : if (strval.empty())
168 29 : 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 11328 : const auto tokens = MooseUtils::split(strval, ";");
174 :
175 5664 : value.resize(tokens.size());
176 15746 : for (const auto i : index_range(tokens))
177 : {
178 20164 : const auto token = MooseUtils::trim(tokens[i]);
179 20164 : if (!MooseUtils::tokenizeAndConvert<T>(token, value[i]))
180 1 : throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
181 : " double vector parameter: " + field.fullpath() + "[" +
182 : std::to_string(i) + "]='" + token + "'");
183 : }
184 5694 : }
185 :
186 : template <class T>
187 : void
188 637 : setTripleVectorValue(std::vector<std::vector<std::vector<T>>> & value, const hit::Field & field)
189 : {
190 637 : value.clear();
191 1274 : const auto value_string = field.param<std::string>();
192 637 : if (value_string.find_first_not_of(' ', 0) == std::string::npos)
193 1 : 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 636 : std::string buffer;
198 636 : buffer.push_back(value_string[0]);
199 636 : if (buffer[0] == '|' || buffer[0] == ';')
200 39 : buffer = ' ' + buffer;
201 78623 : for (std::string::size_type i = 1; i < value_string.size(); i++)
202 : {
203 77987 : const auto val = value_string[i];
204 77987 : const auto last_val = value_string[i - 1];
205 77987 : if ((last_val == '|' || last_val == ';') && (val == '|' || val == ';'))
206 91 : buffer.push_back(' ');
207 77987 : buffer.push_back(val);
208 : }
209 636 : if (buffer.back() == '|' || buffer.back() == ';')
210 17 : buffer.push_back(' ');
211 :
212 : // split vector at delim | to get a series of 2D subvectors
213 636 : std::vector<std::string> outer_tokens;
214 636 : MooseUtils::tokenize(buffer, outer_tokens, 1, "|");
215 636 : value.resize(outer_tokens.size());
216 3501 : for (const auto i : index_range(outer_tokens))
217 : {
218 1474 : const auto & inner_token = outer_tokens[i];
219 1474 : auto & inner_value = value[i];
220 :
221 : // Identify empty subvector first
222 1474 : if (inner_token.find_first_not_of(' ', 0) == std::string::npos)
223 : {
224 : mooseAssert(inner_value.empty(), "Should be empty");
225 82 : 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 1392 : std::vector<std::string> inner_tokenized;
231 1392 : MooseUtils::tokenize(inner_token, inner_tokenized, 1, ";");
232 1392 : inner_value.resize(inner_tokenized.size());
233 4824 : for (const auto j : index_range(inner_tokenized))
234 : {
235 6864 : const auto token = MooseUtils::trim(inner_tokenized[j]);
236 6864 : if (!MooseUtils::tokenizeAndConvert<T>(token, inner_value[j]))
237 1 : 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 639 : }
244 :
245 : template <class Key, class Value>
246 : void
247 455 : setMapValue(std::map<Key, Value> & value, const hit::Field & field)
248 : {
249 455 : value.clear();
250 :
251 910 : const auto string_vec = field.param<std::vector<std::string>>();
252 455 : auto it = string_vec.begin();
253 2378 : while (it != string_vec.end())
254 : {
255 1006 : const auto & string_key = *(it++);
256 1006 : if (it == string_vec.end())
257 1 : 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 1005 : const auto & string_value = *(it++);
261 :
262 1005 : std::pair<Key, Value> pr;
263 :
264 : // convert key
265 1005 : if (!MooseUtils::convert<Key>(string_key, pr.first, false))
266 1 : throw std::invalid_argument("invalid " + MooseUtils::prettyCppType<Key>() +
267 : " syntax for map parameter '" + field.fullpath() + "' key: '" +
268 : string_key + "'");
269 :
270 : // convert value
271 1004 : if (!MooseUtils::convert<Value>(string_value, pr.second, false))
272 1 : throw std::invalid_argument("invalid " + MooseUtils::prettyCppType<Value>() +
273 : " syntax for map parameter '" + field.fullpath() + "' value: '" +
274 : string_value + "'");
275 : // attempt insert
276 1003 : if (!value.insert(std::move(pr)).second)
277 1 : throw std::invalid_argument("duplicate entry for map parameter: '" + field.fullpath() +
278 : "'; key '" + string_key + "' appears multiple times");
279 : }
280 455 : }
281 :
282 : } // end of namespace Moose::ParameterRegistration
|