PRISMS-PF Manual v3.0-pre
All Classes Functions Variables Enumerations Pages
user_constants.h
1// SPDX-FileCopyrightText: © 2025 PRISMS Center at the University of Michigan
2// SPDX-License-Identifier: GNU Lesser General Public Version 2.1
3
4#ifndef user_constants_h
5#define user_constants_h
6
7#include <deal.II/base/tensor.h>
8#include <deal.II/base/utilities.h>
9
10#include <boost/algorithm/string/predicate.hpp>
11#include <boost/range/algorithm_ext/erase.hpp>
12#include <boost/variant.hpp>
13
14#include <prismspf/config.h>
15#include <prismspf/core/conditional_ostreams.h>
16#include <prismspf/core/exceptions.h>
17#include <prismspf/core/type_enums.h>
18
19#include <iomanip>
20#include <map>
21
22PRISMS_PF_BEGIN_NAMESPACE
23
27template <int dim>
29{
30public:
31 using InputVariant = boost::variant<double,
32 int,
33 bool,
34 dealii::Tensor<1, dim>,
35 dealii::Tensor<2, dim>,
36 dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>>;
37
41 InputVariant
42 construct_user_constant(std::vector<std::string> &model_constants_strings);
43
50 [[nodiscard]] double
51 get_model_constant_double(const std::string &constant_name) const;
52
59 [[nodiscard]] int
60 get_model_constant_int(const std::string &constant_name) const;
61
68 [[nodiscard]] bool
69 get_model_constant_bool(const std::string &constant_name) const;
70
77 [[nodiscard]] dealii::Tensor<1, dim>
78 get_model_constant_rank_1_tensor(const std::string &constant_name) const;
79
86 [[nodiscard]] dealii::Tensor<2, dim>
87 get_model_constant_rank_2_tensor(const std::string &constant_name) const;
88
95 [[nodiscard]] dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
96 get_model_constant_elasticity_tensor(const std::string &constant_name) const;
97
98 // List of user-defined constants
99 std::map<std::string, InputVariant> model_constants;
100
101private:
105 unsigned int
106 compute_tensor_parentheses(const unsigned int &n_elements,
107 const std::vector<std::string> &tensor_elements);
108
112 void
113 remove_parentheses(std::vector<std::string> &tensor_elements);
114
118 dealii::Tensor<1, dim>
119 compute_rank_1_tensor_constant(const unsigned int &n_elements,
120 const std::vector<std::string> &tensor_elements);
121
125 dealii::Tensor<2, dim>
126 compute_rank_2_tensor_constant(const unsigned int &n_elements,
127 const std::vector<std::string> &tensor_elements);
128
132 InputVariant
133 primitive_model_constant(std::vector<std::string> &model_constants_strings);
134
135 [[nodiscard]] dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
136 get_Cij_tensor(std::vector<double> elastic_constants,
137 const std::string &elastic_const_symmetry) const;
138
139 dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
140 getCIJMatrix(const elasticityModel &model, const std::vector<double> &constants) const;
141};
142
143template <int dim>
144inline double
145userConstants<dim>::get_model_constant_double(const std::string &constant_name) const
146{
147 Assert(model_constants.find(constant_name) != model_constants.end(),
148 dealii::ExcMessage(
149 "Mismatch between constants in parameters.prm and customPDE.h. The constant "
150 "that you attempted to access was " +
151 constant_name + "."));
152
153 return boost::get<double>(model_constants.at(constant_name));
154}
155
156template <int dim>
157inline int
158userConstants<dim>::get_model_constant_int(const std::string &constant_name) const
159{
160 Assert(model_constants.find(constant_name) != model_constants.end(),
161 dealii::ExcMessage(
162 "Mismatch between constants in parameters.prm and customPDE.h. The constant "
163 "that you attempted to access was " +
164 constant_name + "."));
165
166 return boost::get<int>(model_constants.at(constant_name));
167}
168
169template <int dim>
170inline bool
171userConstants<dim>::get_model_constant_bool(const std::string &constant_name) const
172{
173 Assert(model_constants.find(constant_name) != model_constants.end(),
174 dealii::ExcMessage(
175 "Mismatch between constants in parameters.prm and customPDE.h. The constant "
176 "that you attempted to access was " +
177 constant_name + "."));
178
179 return boost::get<bool>(model_constants.at(constant_name));
180}
181
182template <int dim>
183inline dealii::Tensor<1, dim>
185 const std::string &constant_name) const
186{
187 Assert(model_constants.find(constant_name) != model_constants.end(),
188 dealii::ExcMessage(
189 " Mismatch between constants in parameters.prm and "
190 "customPDE.h. The constant that you attempted to access was " +
191 constant_name + "."));
192
193 return boost::get<dealii::Tensor<1, dim>>(model_constants.at(constant_name));
194}
195
196template <int dim>
197inline dealii::Tensor<2, dim>
199 const std::string &constant_name) const
200{
201 Assert(model_constants.find(constant_name) != model_constants.end(),
202 dealii::ExcMessage(
203 "Mismatch between constants in parameters.prm and customPDE.h. The constant "
204 "that you attempted to access was " +
205 constant_name + "."));
206
207 return boost::get<dealii::Tensor<2, dim>>(model_constants.at(constant_name));
208}
209
210template <int dim>
211inline dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
213 const std::string &constant_name) const
214{
215 Assert(model_constants.find(constant_name) != model_constants.end(),
216 dealii::ExcMessage(
217 "Mismatch between constants in parameters.prm and customPDE.h. The constant "
218 "that you attempted to access was " +
219 constant_name + "."));
220
221 return boost::get<dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>>(
222 model_constants.at(constant_name));
223}
224
225template <int dim>
226inline unsigned int
228 const unsigned int &n_elements,
229 const std::vector<std::string> &tensor_elements)
230{
231 unsigned int open_parentheses = 0;
232 unsigned int close_parentheses = 0;
233
234 for (unsigned int element = 0; element < n_elements; element++)
235 {
236 for (const char character : tensor_elements.at(element))
237 {
238 if (character == '(')
239 {
240 ++open_parentheses;
241 }
242 else if (character == ')')
243 {
244 ++close_parentheses;
245 }
246 }
247 }
248
249 if (open_parentheses != close_parentheses)
250 {
251 AssertThrow(false,
252 dealii::ExcMessage("User-defined elastic constant list does not have "
253 "the same number of open and close parentheses."));
254 }
255
256 return open_parentheses;
257}
258
259template <int dim>
260inline void
261userConstants<dim>::remove_parentheses(std::vector<std::string> &tensor_elements)
262{
263 for (std::string &element : tensor_elements)
264 {
265 boost::range::remove_erase(element, '(');
266 boost::range::remove_erase(element, '(');
267 }
268}
269
270template <int dim>
271inline dealii::Tensor<1, dim>
273 const unsigned int &n_elements,
274 const std::vector<std::string> &tensor_elements)
275{
276 AssertThrow(n_elements == dim,
277 dealii::ExcMessage("The columns in user-defined constant tensors must be "
278 "equal to the number of dimensions."));
279
280 dealii::Tensor<1, dim> temp;
281 for (unsigned int i = 0; i < dim; i++)
282 {
283 temp[i] = dealii::Utilities::string_to_double(tensor_elements.at(i));
284 }
285
286 return temp;
287}
288
289template <int dim>
290inline dealii::Tensor<2, dim>
292 const unsigned int &n_elements,
293 const std::vector<std::string> &tensor_elements)
294{
295 AssertThrow(n_elements == (dim * dim),
296 dealii::ExcMessage(
297 "User-defined constant tensor does not have the "
298 "correct number of elements, matrices must be 2x2 or 3x3."));
299
300 const unsigned int row_length = dim;
301
302 dealii::Tensor<2, dim> temp;
303 for (unsigned int i = 0; i < dim; i++)
304 {
305 for (unsigned int j = 0; j < dim; j++)
306 {
307 temp[i][j] =
308 dealii::Utilities::string_to_double(tensor_elements.at((i * row_length) + j));
309 }
310 }
311
312 return temp;
313}
314
315template <int dim>
316inline typename userConstants<dim>::InputVariant
318 std::vector<std::string> &model_constants_strings)
319{
320 // Ensure that the input includes a value and a type
321 AssertThrow(
322 model_constants_strings.size() > 1,
323 dealii::ExcMessage(
324 "At least two fields are required for user-defined variables (value and type)."));
325
326 std::vector<std::string> model_constants_type_strings =
327 dealii::Utilities::split_string_list(model_constants_strings.at(
328 model_constants_strings.size() - 1),
329 ' ');
330
331 if (model_constants_strings.size() == 2)
332 {
333 return primitive_model_constant(model_constants_strings);
334 }
335
336 if (boost::iequals(model_constants_type_strings.at(0), "tensor"))
337 {
338 const unsigned int n_elements = model_constants_strings.size() - 1;
339
340 const unsigned int open_parentheses =
341 compute_tensor_parentheses(n_elements, model_constants_strings);
342
343 AssertThrow(open_parentheses < 4,
344 FeatureNotImplemented("3rd rank tensors and above"));
345
346 remove_parentheses(model_constants_strings);
347
348 // Rank 1 tensor
349 if (open_parentheses == 1)
350 {
351 return compute_rank_1_tensor_constant(n_elements, model_constants_strings);
352 }
353 // Rank 2 tensor
354 return compute_rank_2_tensor_constant(n_elements, model_constants_strings);
355 }
356 if (boost::iequals(model_constants_type_strings.at(1), "elastic") &&
357 boost::iequals(model_constants_type_strings.at(2), "constants"))
358 {
359 const unsigned int n_elements = model_constants_strings.size() - 1;
360
361 remove_parentheses(model_constants_strings);
362
363 // Load in the elastic constants as a vector
364 std::vector<double> temp_elastic_constants;
365 for (unsigned int i = 0; i < n_elements; i++)
366 {
367 temp_elastic_constants.push_back(
368 dealii::Utilities::string_to_double(model_constants_strings.at(i)));
369 }
370
371 const std::string &elastic_const_symmetry = model_constants_type_strings.at(0);
372 dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)> temp =
373 get_Cij_tensor(temp_elastic_constants, elastic_const_symmetry);
374 return temp;
375 }
376
377 AssertThrow(false,
378 dealii::ExcMessage(
379 "Only user-defined constant tensors may have multiple elements."));
380 return 0;
381}
382
383template <int dim>
384inline typename userConstants<dim>::InputVariant
386 std::vector<std::string> &model_constants_strings)
387{
388 std::vector<std::string> model_constants_type_strings =
389 dealii::Utilities::split_string_list(model_constants_strings.at(
390 model_constants_strings.size() - 1),
391 ' ');
392
393 if (boost::iequals(model_constants_type_strings.at(0), "double"))
394 {
395 return dealii::Utilities::string_to_double(model_constants_strings.at(0));
396 }
397 if (boost::iequals(model_constants_type_strings.at(0), "int"))
398 {
399 return dealii::Utilities::string_to_int(model_constants_strings.at(0));
400 }
401 if (boost::iequals(model_constants_type_strings.at(0), "bool"))
402 {
403 return boost::iequals(model_constants_strings.at(0), "true");
404 }
405
406 AssertThrow(false,
407 dealii::ExcMessage(
408 "The type for user-defined variables must be `double`, `int`, "
409 "`bool`, `tensor`, or `elastic constants`."));
410 return 0;
411}
412
413template <int dim>
414inline dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
415userConstants<dim>::get_Cij_tensor(std::vector<double> elastic_constants,
416 const std::string &elastic_const_symmetry) const
417{
418 // First set the material model
419 elasticityModel mat_model = ISOTROPIC;
420 if (elastic_const_symmetry == "isotropic")
421 {
422 mat_model = elasticityModel::ISOTROPIC;
423 }
424 else if (elastic_const_symmetry == "transverse")
425 {
426 mat_model = elasticityModel::TRANSVERSE;
427 }
428 else if (elastic_const_symmetry == "orthotropic")
429 {
430 mat_model = elasticityModel::ORTHOTROPIC;
431 }
432 else if (elastic_const_symmetry == "anisotropic")
433 {
434 mat_model = elasticityModel::ANISOTROPIC;
435 }
436 else
437 {
438 AssertThrow(false, dealii::ExcMessage("Invalid elasticity tensor type"));
439 }
440
441 // If the material model is anisotropic for a 2D calculation but the elastic
442 // constants are given for a 3D calculation, change the elastic constant
443 // vector to the 2D form
444 constexpr unsigned int max_number = 21;
445 if ((mat_model == ANISOTROPIC) && (dim == 2) && elastic_constants.size() == max_number)
446 {
447 std::vector<double> elastic_constants_temp = elastic_constants;
448 elastic_constants.clear();
449 const std::vector<unsigned int> indices_2D = {0, 1, 5, 6, 10, 14};
450 for (const auto &index : indices_2D)
451 {
452 elastic_constants.push_back(elastic_constants_temp.at(index));
453 }
454 }
455
456 return getCIJMatrix(mat_model, elastic_constants);
457}
458
459template <int dim>
460inline dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
461userConstants<dim>::getCIJMatrix(const elasticityModel &model,
462 const std::vector<double> &constants) const
463{
464 dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)> CIJ;
465
466 (void) constants; // TODO (landinjm): Implement this function
467
468 switch (dim)
469 {
470 case 1:
471 {
472 switch (model)
473 {
474 // TODO (landinjm): Should we both fixing this for the other cases and just
475 // selecting the x index. It would allow the user to switch from 2D to 1D to
476 // 3D, but would produce unexpected behavior.
477 case ISOTROPIC:
478 default:
479 {
480 AssertThrow(false, dealii::ExcMessage("Invalid elasticity model type"));
481 }
482 }
483 break;
484 }
485 case 2:
486 {
487 switch (model)
488 {
489 case ISOTROPIC:
490 case ANISOTROPIC:
491 default:
492 {
493 AssertThrow(false, dealii::ExcMessage("Invalid elasticity model type"));
494 }
495 }
496 break;
497 }
498 case 3:
499 {
500 switch (model)
501 {
502 case ISOTROPIC:
503 case TRANSVERSE:
504 case ORTHOTROPIC:
505 case ANISOTROPIC:
506 default:
507 {
508 AssertThrow(false, dealii::ExcMessage("Invalid elasticity model type"));
509 }
510 }
511 break;
512 }
513 default:
514 {
515 Assert(false, UnreachableCode());
516 }
517 }
518
519 return CIJ;
520}
521
522PRISMS_PF_END_NAMESPACE
523
524#endif
Class the stores and manages user-defined constants.
Definition user_constants.h:29
int get_model_constant_int(const std::string &constant_name) const
Retrieve the int from the model_constants that are defined from the parameters.prm parser....
Definition user_constants.h:158
dealii::Tensor< 1, dim > get_model_constant_rank_1_tensor(const std::string &constant_name) const
Retrieve the rank 1 tensor from the model_constants that are defined from the parameters....
Definition user_constants.h:184
dealii::Tensor< 2, dim > get_model_constant_rank_2_tensor(const std::string &constant_name) const
Retrieve the rank 2 tensor from the model_constants that are defined from the parameters....
Definition user_constants.h:198
InputVariant construct_user_constant(std::vector< std::string > &model_constants_strings)
Assign the specified user constant to whatever type.
Definition user_constants.h:317
bool get_model_constant_bool(const std::string &constant_name) const
Retrieve the bool from the model_constants that are defined from the parameters.prm parser....
Definition user_constants.h:171
double get_model_constant_double(const std::string &constant_name) const
Retrieve the double from the model_constants that are defined from the parameters....
Definition user_constants.h:145
dealii::Tensor< 2,(2 *dim) - 1+(dim/3)> get_model_constant_elasticity_tensor(const std::string &constant_name) const
Retrieve the elasticity tensor from the model_constants that are defined from the parameters....
Definition user_constants.h:212