https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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); })
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); })
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); })
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); })
48#define registerParameter(type) \
49 registerScalarParameter(type); \
50 registerVectorParameter(type); \
51 registerDoubleVectorParameter(type); \
52 registerTripleVectorParameter(type)
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
61{
62
66template <class T>
67void setScalarValue(T & value, const hit::Field & field);
68
72template <class T>
73void setVectorValue(std::vector<T> & value, const hit::Field & field);
74
78template <class T>
79void setDoubleVectorValue(std::vector<std::vector<T>> & value, const hit::Field & field);
80
84template <class T>
85void setTripleVectorValue(std::vector<std::vector<std::vector<T>>> & value,
86 const hit::Field & field);
87
91template <class Key, class Value>
92void setMapValue(std::map<Key, Value> & value, const hit::Field & field);
93
95template <>
96void setScalarValue(bool & value, const hit::Field & field);
97
98template <class T>
99void
100setScalarValue(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
115template <class T>
116void
117setVectorValue(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
161template <class T>
162void
163setDoubleVectorValue(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
186template <class T>
187void
188setTripleVectorValue(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
245template <class Key, class Value>
246void
247setMapValue(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
std::vector< std::string > split(const std::string &str, const std::string &delimiter, std::size_t max_count)
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 ...
std::string trim(const std::string &str, const std::string &white_space=" \t\n\v\f\r")
Standard scripting language trim function.
void setVectorValue(std::vector< T > &value, const hit::Field &field)
Converts the given field node into a vector of the given type.
void setMapValue(std::map< Key, Value > &value, const hit::Field &field)
Converts the given field node into a map with the given types.
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.
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 setScalarValue(T &value, const hit::Field &field)
Converts the given field node into a scalar of the given type.