PRISMS-PF Manual
Loading...
Searching...
No Matches
user_constants.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: © 2025 PRISMS Center at the University of Michigan
2// SPDX-License-Identifier: GNU Lesser General Public Version 2.1
3
4#pragma once
5
6#include <deal.II/base/parameter_handler.h>
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
17
18#include <prismspf/config.h>
19
20#include <fstream>
21#include <map>
22
24
28template <unsigned int dim>
30{
31public:
32 using InputVariant = boost::variant<double,
33 int,
34 bool,
35 std::string,
36 dealii::Tensor<1, dim>,
37 dealii::Tensor<2, dim>,
38 dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>>;
39
44 construct_user_constant(std::vector<std::string> &model_constants_strings);
45
52 [[nodiscard]] double
53 get_double(const std::string &constant_name) const;
54
61 [[nodiscard]] int
62 get_int(const std::string &constant_name) const;
63
70 [[nodiscard]] bool
71 get_bool(const std::string &constant_name) const;
72
79 [[nodiscard]] std::string
80 get_string(const std::string &constant_name) const;
81
88 [[nodiscard]] dealii::Tensor<1, dim>
89 get_rank_1_tensor(const std::string &constant_name) const;
90
97 [[nodiscard]] dealii::Tensor<2, dim>
98 get_rank_2_tensor(const std::string &constant_name) const;
99
106 [[nodiscard]] dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
107 get_elasticity_tensor(const std::string &constant_name) const;
108
112 void
113 add_user_constant(const std::string &constant_name,
114 std::vector<std::string> &model_constants_strings)
115 {
116 model_constants[constant_name] = construct_user_constant(model_constants_strings);
117 };
118
122 void
123 print() const;
124
125 static void
126 strip_spaces(std::string &line);
127
128 static bool
129 check_keyword_match(const std::string &line, const std::string &keyword);
130
135 static bool
136 parse_line(std::string line,
137 const std::string &keyword,
138 const std::string &entry_name,
139 std::string &out_string,
140 bool expect_equals_sign);
141
145 static std::set<std::string>
146 get_names(const std::string &input_file_name);
147
152 void
153 declare_parameters(dealii::ParameterHandler &parameter_handler) const;
154
159 void
160 assign_parameters(dealii::ParameterHandler &parameter_handler);
161
165 std::string file_name;
166
167private:
171 unsigned int
172 compute_tensor_parentheses(const unsigned int &n_elements,
173 const std::vector<std::string> &tensor_elements);
174
178 void
179 remove_parentheses(std::vector<std::string> &tensor_elements);
180
184 dealii::Tensor<1, dim>
185 compute_rank_1_tensor_constant(const unsigned int &n_elements,
186 const std::vector<std::string> &tensor_elements);
187
191 dealii::Tensor<2, dim>
192 compute_rank_2_tensor_constant(const unsigned int &n_elements,
193 const std::vector<std::string> &tensor_elements);
194
199 primitive_model_constant(std::vector<std::string> &model_constants_strings);
200
201 [[nodiscard]] dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
202 get_cij_tensor(std::vector<double> elastic_constants,
203 const std::string &elastic_const_symmetry,
204 const StressState &stress_state) const;
205
206 [[nodiscard]] dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
207 get_cij_matrix(const ElasticityModel &model,
208 const std::vector<double> &constants,
209 const StressState &stress_state) const;
210
214 std::map<std::string, InputVariant> model_constants;
215
219 class VariantPrinter : public boost::static_visitor<>
220 {
221 public:
222 void
223 operator()(double value) const
224 {
226 }
227
228 void
229 operator()(int value) const
230 {
232 }
233
234 void
235 operator()(bool value) const
236 {
237 ConditionalOStreams::pout_summary() << std::boolalpha << value;
238 }
239
240 void
241 operator()(const std::string &value) const
242 {
244 }
245
246 void
247 operator()(const dealii::Tensor<1, dim> &value) const
248 {
249 ConditionalOStreams::pout_summary() << "Tensor<1, " << dim << ">: ";
250 for (unsigned int i = 0; i < dim; ++i)
251 {
252 ConditionalOStreams::pout_summary() << value[i] << ' ';
253 }
254 }
255
256 void
257 operator()(const dealii::Tensor<2, dim> &value) const
258 {
259 ConditionalOStreams::pout_summary() << "Tensor<2, " << dim << ">: ";
260 for (unsigned int i = 0; i < dim; ++i)
261 {
262 for (unsigned int j = 0; j < dim; ++j)
263 {
264 ConditionalOStreams::pout_summary() << value[i][j] << ' ';
265 }
266 }
267 }
268
269 template <unsigned int D = dim>
270 void
271 operator()(const dealii::Tensor<2, (2 * D) - 1 + (D / 3)> &value) const
272 requires((D != ((2 * D) - 1 + (D / 3))))
273 {
274 constexpr unsigned int dimension = (2 * D) - 1 + (D / 3);
275 ConditionalOStreams::pout_summary() << "Tensor<2, " << dimension << ">: ";
276 for (unsigned int i = 0; i < dimension; ++i)
277 {
278 for (unsigned int j = 0; j < dimension; ++j)
279 {
280 ConditionalOStreams::pout_summary() << value[i][j] << ' ';
281 }
282 }
283 }
284 };
285};
286
287template <unsigned int dim>
288inline double
289UserConstants<dim>::get_double(const std::string &constant_name) const
290{
291 Assert(model_constants.find(constant_name) != model_constants.end(),
292 dealii::ExcMessage(
293 "Mismatch between constants in parameters.prm and CustomPDE.h. The constant "
294 "that you attempted to access was " +
295 constant_name + "."));
296
297 return boost::get<double>(model_constants.at(constant_name));
298}
299
300template <unsigned int dim>
301inline int
302UserConstants<dim>::get_int(const std::string &constant_name) const
303{
304 Assert(model_constants.find(constant_name) != model_constants.end(),
305 dealii::ExcMessage(
306 "Mismatch between constants in parameters.prm and CustomPDE.h. The constant "
307 "that you attempted to access was " +
308 constant_name + "."));
309
310 return boost::get<int>(model_constants.at(constant_name));
311}
312
313template <unsigned int dim>
314inline bool
315UserConstants<dim>::get_bool(const std::string &constant_name) const
316{
317 Assert(model_constants.find(constant_name) != model_constants.end(),
318 dealii::ExcMessage(
319 "Mismatch between constants in parameters.prm and CustomPDE.h. The constant "
320 "that you attempted to access was " +
321 constant_name + "."));
322
323 return boost::get<bool>(model_constants.at(constant_name));
324}
325
326template <unsigned int dim>
327inline std::string
328UserConstants<dim>::get_string(const std::string &constant_name) const
329{
330 Assert(model_constants.find(constant_name) != model_constants.end(),
331 dealii::ExcMessage(
332 "Mismatch between constants in parameters.prm and CustomPDE.h. The constant "
333 "that you attempted to access was " +
334 constant_name + "."));
335
336 return boost::get<std::string>(model_constants.at(constant_name));
337}
338
339template <unsigned int dim>
340inline dealii::Tensor<1, dim>
341UserConstants<dim>::get_rank_1_tensor(const std::string &constant_name) const
342{
343 Assert(model_constants.find(constant_name) != model_constants.end(),
344 dealii::ExcMessage(
345 " Mismatch between constants in parameters.prm and "
346 "CustomPDE.h. The constant that you attempted to access was " +
347 constant_name + "."));
348
349 return boost::get<dealii::Tensor<1, dim>>(model_constants.at(constant_name));
350}
351
352template <unsigned int dim>
353inline dealii::Tensor<2, dim>
354UserConstants<dim>::get_rank_2_tensor(const std::string &constant_name) const
355{
356 Assert(model_constants.find(constant_name) != model_constants.end(),
357 dealii::ExcMessage(
358 "Mismatch between constants in parameters.prm and CustomPDE.h. The constant "
359 "that you attempted to access was " +
360 constant_name + "."));
361
362 return boost::get<dealii::Tensor<2, dim>>(model_constants.at(constant_name));
363}
364
365template <unsigned int dim>
366inline dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
367UserConstants<dim>::get_elasticity_tensor(const std::string &constant_name) const
368{
369 Assert(model_constants.find(constant_name) != model_constants.end(),
370 dealii::ExcMessage(
371 "Mismatch between constants in parameters.prm and CustomPDE.h. The constant "
372 "that you attempted to access was " +
373 constant_name + "."));
374
375 return boost::get<dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>>(
376 model_constants.at(constant_name));
377}
378
379template <unsigned int dim>
380inline unsigned int
382 const unsigned int &n_elements,
383 const std::vector<std::string> &tensor_elements)
384{
385 unsigned int open_parentheses = 0;
386 unsigned int close_parentheses = 0;
387
388 for (unsigned int element = 0; element < n_elements; element++)
389 {
390 for (const char character : tensor_elements.at(element))
391 {
392 if (character == '(')
393 {
394 ++open_parentheses;
395 }
396 else if (character == ')')
397 {
398 ++close_parentheses;
399 }
400 }
401 }
402
403 if (open_parentheses != close_parentheses)
404 {
405 AssertThrow(false,
406 dealii::ExcMessage("User-defined elastic constant list does not have "
407 "the same number of open and close parentheses."));
408 }
409
410 return open_parentheses;
411}
412
413template <unsigned int dim>
414inline void
415UserConstants<dim>::remove_parentheses(std::vector<std::string> &tensor_elements)
416{
417 for (std::string &element : tensor_elements)
418 {
419 boost::range::remove_erase(element, '(');
420 boost::range::remove_erase(element, ')');
421 }
422}
423
424template <unsigned int dim>
425inline dealii::Tensor<1, dim>
427 const unsigned int &n_elements,
428 const std::vector<std::string> &tensor_elements)
429{
430 AssertThrow(n_elements == 3,
431 dealii::ExcMessage("The columns in user-defined constant tensors must be "
432 "equal to the maximum number of dimensions."));
433
434 dealii::Tensor<1, dim> temp;
435 for (unsigned int i = 0; i < dim; i++)
436 {
437 temp[i] = dealii::Utilities::string_to_double(tensor_elements.at(i));
438 }
439
440 return temp;
441}
442
443template <unsigned int dim>
444inline dealii::Tensor<2, dim>
446 const unsigned int &n_elements,
447 const std::vector<std::string> &tensor_elements)
448{
449 AssertThrow(n_elements == 9,
450 dealii::ExcMessage("User-defined constant tensor does not have the "
451 "correct number of elements, matrices must be 3x3."));
452
453 const unsigned int row_length = 3;
454
455 dealii::Tensor<2, dim> temp;
456 for (unsigned int i = 0; i < dim; i++)
457 {
458 for (unsigned int j = 0; j < dim; j++)
459 {
460 temp[i][j] =
461 dealii::Utilities::string_to_double(tensor_elements.at((i * row_length) + j));
462 }
463 }
464
465 return temp;
466}
467
468template <unsigned int dim>
471 std::vector<std::string> &model_constants_strings)
472{
473 // Ensure that the input includes a value and a type
474 AssertThrow(
475 model_constants_strings.size() > 1,
476 dealii::ExcMessage(
477 "At least two fields are required for user-defined variables (value and type)."));
478
479 std::vector<std::string> model_constants_type_strings =
480 dealii::Utilities::split_string_list(model_constants_strings.at(
481 model_constants_strings.size() - 1),
482 ' ');
483
484 if (model_constants_strings.size() == 2)
485 {
486 return primitive_model_constant(model_constants_strings);
487 }
488
489 if (boost::iequals(model_constants_type_strings.at(0), "tensor"))
490 {
491 const unsigned int n_elements = model_constants_strings.size() - 1;
492
493 const unsigned int open_parentheses =
494 compute_tensor_parentheses(n_elements, model_constants_strings);
495
496 AssertThrow(open_parentheses <= 4,
497 FeatureNotImplemented("3rd rank tensors and above"));
498
499 remove_parentheses(model_constants_strings);
500
501 // Rank 1 tensor
502 if (open_parentheses == 1)
503 {
504 return compute_rank_1_tensor_constant(n_elements, model_constants_strings);
505 }
506 // Rank 2 tensor
507 return compute_rank_2_tensor_constant(n_elements, model_constants_strings);
508 }
509 if (boost::iequals(model_constants_type_strings.at(1), "elastic") &&
510 boost::iequals(model_constants_type_strings.at(2), "constants"))
511 {
512 const unsigned int n_elements = model_constants_strings.size() - 1;
513
514 remove_parentheses(model_constants_strings);
515
516 // Load in the elastic constants as a vector
517 std::vector<double> temp_elastic_constants(n_elements);
518 for (unsigned int i = 0; i < n_elements; i++)
519 {
520 temp_elastic_constants[i] =
521 dealii::Utilities::string_to_double(model_constants_strings.at(i));
522 }
523 const std::string &elastic_const_symmetry = model_constants_type_strings.at(0);
524
525 // get the stress state for the 2D case
527 if (dim == 2)
528 {
529 if (model_constants_type_strings.size() == 4)
530 {
531 if (boost::iequals(model_constants_type_strings.at(3), "planestress"))
532 {
533 stress_state = StressState::PlaneStress;
534 }
535 else if (boost::iequals(model_constants_type_strings.at(3), "planestrain"))
536 {
537 stress_state = StressState::PlaneStrain;
538 }
539 else
540 {
541 AssertThrow(
542 false,
543 dealii::ExcMessage(
544 "Wrong 2D stress state. Use planestress or planestrain."));
545 }
546 }
547 else if (model_constants_type_strings.size() == 3)
548 {
549 // Default to plane strain if nothing is specified
550 stress_state = StressState::PlaneStrain;
551 }
552 else
553 {
554 AssertThrow(false,
555 dealii::ExcMessage(
556 "Wrong format of user-defined elastic constants."));
557 }
558 }
559
560 dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)> temp =
561 get_cij_tensor(temp_elastic_constants, elastic_const_symmetry, stress_state);
562 return temp;
563 }
564
565 AssertThrow(false,
566 dealii::ExcMessage(
567 "Only user-defined constant tensors may have multiple elements."));
568 return 0;
569}
570
571template <unsigned int dim>
574 std::vector<std::string> &model_constants_strings)
575{
576 std::vector<std::string> model_constants_type_strings =
577 dealii::Utilities::split_string_list(model_constants_strings.at(
578 model_constants_strings.size() - 1),
579 ' ');
580
581 if (boost::iequals(model_constants_type_strings.at(0), "double"))
582 {
583 return dealii::Utilities::string_to_double(model_constants_strings.at(0));
584 }
585 if (boost::iequals(model_constants_type_strings.at(0), "int"))
586 {
587 return dealii::Utilities::string_to_int(model_constants_strings.at(0));
588 }
589 if (boost::iequals(model_constants_type_strings.at(0), "bool"))
590 {
591 return boost::iequals(model_constants_strings.at(0), "true");
592 }
593 if (boost::iequals(model_constants_type_strings.at(0), "string"))
594 {
595 return model_constants_strings.at(0);
596 }
597
598 AssertThrow(false,
599 dealii::ExcMessage(
600 "The type for user-defined variables must be `double`, `int`, "
601 "`bool`, `string`, `tensor`, or `elastic constants`."));
602 return 0;
603}
604
605template <unsigned int dim>
606inline dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
607UserConstants<dim>::get_cij_tensor(std::vector<double> elastic_constants,
608 const std::string &elastic_const_symmetry,
609 const StressState &stress_state) const
610{
611 // First set the material model
612 ElasticityModel mat_model = Isotropic;
613 if (elastic_const_symmetry == "isotropic")
614 {
615 mat_model = ElasticityModel::Isotropic;
616 }
617 else if (elastic_const_symmetry == "transverse")
618 {
619 mat_model = ElasticityModel::Transverse;
620 }
621 else if (elastic_const_symmetry == "orthotropic")
622 {
624 }
625 else if (elastic_const_symmetry == "anisotropic")
626 {
628 }
629 else
630 {
631 AssertThrow(false, dealii::ExcMessage("Invalid elasticity tensor type"));
632 }
633
634 // If the material model is anisotropic for a 2D calculation but the elastic
635 // constants are given for a 3D calculation, change the elastic constant
636 // vector to the 2D form
637 constexpr unsigned int max_number = 21;
638 if ((mat_model == Anisotropic) && (dim == 2) && elastic_constants.size() == max_number)
639 {
640 std::vector<double> elastic_constants_temp = elastic_constants;
641 elastic_constants.clear();
642 const std::vector<unsigned int> indices_2d = {0, 1, 5, 6, 10, 14};
643 std::transform(indices_2d.begin(),
644 indices_2d.end(),
645 std::back_inserter(elastic_constants),
646 [&elastic_constants_temp](unsigned int index)
647 {
648 return elastic_constants_temp.at(index);
649 });
650 }
651
652 return get_cij_matrix(mat_model, elastic_constants, stress_state);
653}
654
655template <unsigned int dim>
656inline dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)>
658 const std::vector<double> &constants,
659 const StressState &stress_state) const
660{
661 // Initialize stiffness tensor
662 dealii::Tensor<2, (2 * dim) - 1 + (dim / 3)> stiffness;
663
664 switch (dim)
665 {
666 case 1:
667 {
668 const int xx_dir = 0;
669
670 switch (model)
671 {
672 // For the 1D case, it make little sense to accept anything besides an
673 // isotropic elasticity tensor. One hiccup, is that if a user is debugging
674 // an application and switches to 1D, they will have to modify the
675 // elasticity constants to align with that. While more burdensome, there's
676 // less of a chance of producing spurious behavior.
677 case Isotropic:
678 {
679 const double modulus = constants.at(0);
680
681 stiffness[xx_dir][xx_dir] = modulus;
682 break;
683 }
684 default:
685 AssertThrow(false,
686 dealii::ExcMessage(
687 "Invalid elasticity model type for 1D. We only accept "
688 "isotropic elasticity tensors."));
689 }
690 break;
691 }
692 case 2:
693 {
694 // The voigt indexing scheme for 2 dimensions
695 const int xx_dir = 0;
696 const int yy_dir = 1;
697 const int xy_dir = 2;
698
699 switch (model)
700 {
701 // Like the 1D case, it is nonsensical to have transverse or orthotropic
702 // stiffness tensors, so we throw an error.
703 case Isotropic:
704 {
705 // For isotropic stiffness tensors, we can simplify the computation to
706 // two parameters: $\lambda$ and $\mu$, where $\mu$ is the shear
707 // modulus. In cartesian coordinates,
708 // $$$
709 // c_{ijkl} = \lambda \delta_{ij} \delta_{kl} + \mu (\delta_{ik}
710 // \delta_{jl} + \delta_{il} \delta_{kj})
711 // $$$
712 // In 2D, we distinguish between plane stress and plane strain
713 const double modulus = constants.at(0);
714 const double poisson = constants.at(1);
715
716 const double shear_modulus = modulus / (2 * (1 + poisson));
717 double lambda = 0.0;
718 switch (stress_state)
719 {
720 case PlaneStress:
721 {
722 lambda = poisson * modulus / ((1 - poisson * poisson));
723 break;
724 }
725 case PlaneStrain:
726 {
727 lambda =
728 poisson * modulus / ((1 + poisson) * (1 - 2 * poisson));
729 break;
730 }
731 default:
732 AssertThrow(false,
733 dealii::ExcMessage("Invalid stress state type"));
734 }
735
736 stiffness[xx_dir][xx_dir] = stiffness[yy_dir][yy_dir] =
737 lambda + 2 * shear_modulus;
738 stiffness[xy_dir][xy_dir] = shear_modulus;
739 stiffness[xx_dir][yy_dir] = stiffness[yy_dir][xx_dir] = lambda;
740 break;
741 }
742 case Orthotropic:
743 {
744 // In 2D, we distinguish between plane stress and plane strain
745 switch (stress_state)
746 {
747 case PlaneStress:
748 {
749 const double E1 = constants.at(0);
750 const double E2 = constants.at(1);
751 const double nu12 = constants.at(2);
752 const double G12 = constants.at(3);
753
754 const double nu21 = nu12 * (E2 / E1);
755 const double denom = 1.0 - (nu12 * nu21);
756
757 stiffness[xx_dir][xx_dir] = E1 / denom;
758 stiffness[yy_dir][yy_dir] = E2 / denom;
759 stiffness[xx_dir][yy_dir] = stiffness[yy_dir][xx_dir] =
760 (nu12 * E2) / denom;
761 stiffness[xy_dir][xy_dir] = G12;
762 break;
763 }
764 case PlaneStrain:
765 {
766 const double E1 = constants.at(0);
767 const double E2 = constants.at(1);
768 const double E3 = constants.at(2);
769 const double nu12 = constants.at(3);
770 const double nu13 = constants.at(4);
771 const double nu23 = constants.at(5);
772 const double G12 = constants.at(6);
773
774 const double nu21 = nu12 * (E2 / E1);
775 const double nu31 = nu13 * (E3 / E1);
776 const double nu32 = nu23 * (E3 / E2);
777
778 const double delta = 1.0 - (nu12 * nu21) - (nu23 * nu32) -
779 (nu13 * nu31) - (2.0 * nu12 * nu23 * nu31);
780
781 stiffness[xx_dir][xx_dir] =
782 (E1 * (1.0 - (nu23 * nu32))) / delta;
783 stiffness[yy_dir][yy_dir] =
784 (E2 * (1.0 - (nu13 * nu31))) / delta;
785 stiffness[xx_dir][yy_dir] = stiffness[yy_dir][xx_dir] =
786 (E1 * (nu21 + (nu31 * nu23))) / delta;
787 stiffness[xy_dir][xy_dir] = G12;
788 break;
789 }
790 default:
791 AssertThrow(false,
792 dealii::ExcMessage("Invalid stress state type"));
793 }
794 break;
795 }
796 case Anisotropic:
797 {
798 // In the anisotropic case, every entry is specified (given the symmetry
799 // constraints). Also, ignore magic numbers because it is simpler to
800 // hardcode this.
801
802 // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
803
804 stiffness[xx_dir][xx_dir] = constants.at(0);
805 stiffness[yy_dir][yy_dir] = constants.at(1);
806 stiffness[xy_dir][xy_dir] = constants.at(2);
807 stiffness[xx_dir][yy_dir] = stiffness[yy_dir][xx_dir] = constants.at(3);
808 stiffness[xx_dir][xy_dir] = stiffness[xy_dir][xx_dir] = constants.at(4);
809 stiffness[yy_dir][xy_dir] = stiffness[xy_dir][yy_dir] = constants.at(5);
810
811 // NOLINTEND(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
812 break;
813 }
814 default:
815 AssertThrow(false, dealii::ExcMessage("Invalid elasticity model type"));
816 }
817 break;
818 }
819 case 3:
820 {
821 const int xx_dir = 0;
822 const int yy_dir = 1;
823 const int zz_dir = 2;
824 const int yz_dir = 3;
825 const int xz_dir = 4;
826 const int xy_dir = 5;
827
828 switch (model)
829 {
830 case Isotropic:
831 {
832 // For isotropic stiffness tensors, we can simplify the computation to
833 // two parameters: $\lambda$ and $\mu$, where $\mu$ is the shear
834 // modulus. In cartesian coordinates,
835 // $$$
836 // c_{ijkl} = \lambda \delta_{ij} \delta_{kl} + \mu (\delta_{ik}
837 // \delta_{jl} + \delta_{il} \delta_{kj})
838 // $$$
839 const double modulus = constants.at(0);
840 const double poisson = constants.at(1);
841
842 const double shear_modulus = modulus / (2 * (1 + poisson));
843 const double lambda =
844 poisson * modulus / ((1 + poisson) * (1 - 2 * poisson));
845
846 stiffness[xx_dir][xx_dir] = stiffness[yy_dir][yy_dir] =
847 stiffness[zz_dir][zz_dir] = lambda + 2 * shear_modulus;
848 stiffness[yz_dir][yz_dir] = stiffness[xz_dir][xz_dir] =
849 stiffness[xy_dir][xy_dir] = shear_modulus;
850 stiffness[xx_dir][yy_dir] = stiffness[yy_dir][xx_dir] =
851 stiffness[xx_dir][zz_dir] = stiffness[zz_dir][xx_dir] =
852 stiffness[yy_dir][zz_dir] = stiffness[zz_dir][yy_dir] = lambda;
853 break;
854 }
855 case Anisotropic:
856 {
857 // In the anisotropic case, every entry is specified (given the symmetry
858 // constraints). Also, ignore magic numbers because it is simpler to
859 // hardcode this.
860
861 // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
862
863 stiffness[xx_dir][xx_dir] = constants[0];
864 stiffness[yy_dir][yy_dir] = constants[1];
865 stiffness[zz_dir][zz_dir] = constants[2];
866 stiffness[yz_dir][yz_dir] = constants[3];
867 stiffness[xz_dir][xz_dir] = constants[4];
868 stiffness[xy_dir][xy_dir] = constants[5];
869 stiffness[xx_dir][yy_dir] = stiffness[yy_dir][xx_dir] = constants[6];
870 stiffness[xx_dir][zz_dir] = stiffness[zz_dir][xx_dir] = constants[7];
871 stiffness[xx_dir][yz_dir] = stiffness[yz_dir][xx_dir] = constants[8];
872 stiffness[xx_dir][xz_dir] = stiffness[xz_dir][xx_dir] = constants[9];
873 stiffness[xx_dir][xy_dir] = stiffness[xy_dir][xx_dir] = constants[10];
874 stiffness[yy_dir][zz_dir] = stiffness[zz_dir][yy_dir] = constants[11];
875 stiffness[yy_dir][yz_dir] = stiffness[yz_dir][yy_dir] = constants[12];
876 stiffness[yy_dir][xz_dir] = stiffness[xz_dir][yy_dir] = constants[13];
877 stiffness[yy_dir][xy_dir] = stiffness[xy_dir][yy_dir] = constants[14];
878 stiffness[zz_dir][yz_dir] = stiffness[yz_dir][zz_dir] = constants[15];
879 stiffness[zz_dir][xz_dir] = stiffness[xz_dir][zz_dir] = constants[16];
880 stiffness[zz_dir][xy_dir] = stiffness[xy_dir][zz_dir] = constants[17];
881 stiffness[yz_dir][xz_dir] = stiffness[xz_dir][yz_dir] = constants[18];
882 stiffness[yz_dir][xy_dir] = stiffness[xy_dir][yz_dir] = constants[19];
883 stiffness[xz_dir][xy_dir] = stiffness[xy_dir][xz_dir] = constants[20];
884
885 // NOLINTEND(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
886 break;
887 }
888 case Transverse:
889 {
890 // TODO (landinjm): implement
891 AssertThrow(false, FeatureNotImplemented("Transverse material"));
892 break;
893 }
894 case Orthotropic:
895 {
896 const double E1 = constants.at(0);
897 const double E2 = constants.at(1);
898 const double E3 = constants.at(2);
899 const double nu12 = constants.at(3);
900 const double nu13 = constants.at(4);
901 const double nu23 = constants.at(5);
902 const double G12 = constants.at(6);
903 const double G13 = constants.at(7);
904 const double G23 = constants.at(8);
905
906 const double nu21 = nu12 * (E2 / E1);
907 const double nu31 = nu13 * (E3 / E1);
908 const double nu32 = nu23 * (E3 / E2);
909
910 const double delta = 1.0 - (nu12 * nu21) - (nu23 * nu32) -
911 (nu13 * nu31) - (2.0 * nu12 * nu23 * nu31);
912
913 stiffness[xx_dir][xx_dir] = (E1 * (1.0 - nu23 * nu32)) / delta;
914 stiffness[yy_dir][yy_dir] = (E2 * (1.0 - nu13 * nu31)) / delta;
915 stiffness[zz_dir][zz_dir] = (E3 * (1.0 - nu12 * nu21)) / delta;
916 stiffness[xx_dir][yy_dir] = stiffness[yy_dir][xx_dir] =
917 (E1 * (nu21 + nu31 * nu23)) / delta;
918 stiffness[xx_dir][zz_dir] = stiffness[zz_dir][xx_dir] =
919 (E1 * (nu31 + nu21 * nu32)) / delta;
920 stiffness[yy_dir][zz_dir] = stiffness[zz_dir][yy_dir] =
921 (E2 * (nu32 + nu12 * nu31)) / delta;
922 stiffness[yz_dir][yz_dir] = G23;
923 stiffness[xz_dir][xz_dir] = G13;
924 stiffness[xy_dir][xy_dir] = G12;
925 break;
926 }
927 default:
928 AssertThrow(false, dealii::ExcMessage("Invalid elasticity model type"));
929 }
930 break;
931 }
932 default:
933 {
934 Assert(false, UnreachableCode());
935 }
936 }
937
938 return stiffness;
939}
940
941template <unsigned int dim>
942void
944{
945 if (!model_constants.empty())
946 {
948 << "================================================\n"
949 << " User Constants\n"
950 << "================================================\n";
951
952 for (const auto &[constant_name, variant] : model_constants)
953 {
954 ConditionalOStreams::pout_summary() << constant_name << ": ";
955 boost::apply_visitor(VariantPrinter(), variant);
957 }
958 ConditionalOStreams::pout_summary() << "\n" << std::flush;
959 }
960}
961
962template <unsigned int dim>
963void
965{
966 while ((!line.empty()) && (line[0] == ' ' || line[0] == '\t'))
967 {
968 line.erase(0, 1);
969 }
970 while ((!line.empty()) &&
971 (line[line.size() - 1] == ' ' || line[line.size() - 1] == '\t'))
972 {
973 line.erase(line.size() - 1, std::string::npos);
974 }
975}
976
977template <unsigned int dim>
978bool
980 const std::string &keyword)
981{
982 // Early return if the line is less than the keyword size
983 if (line.size() < keyword.size())
984 {
985 return false;
986 }
987
988 // Check that the line begins with the keyword
989 for (unsigned int i = 0; i < keyword.size(); i++)
990 {
991 if (line[i] != keyword[i])
992 {
993 return false;
994 }
995 }
996
997 return true;
998}
999
1000template <unsigned int dim>
1001bool
1003 const std::string &keyword,
1004 const std::string &entry_name,
1005 std::string &out_string,
1006 bool expect_equals_sign)
1007{
1008 // Remove spaces from the front and back
1009 strip_spaces(line);
1010
1011 // Check whether the line starts with 'keyword'. If not, try next line (if the entry is
1012 // "", then zero spaces after the keyword is ok)
1013 if (!check_keyword_match(line, keyword))
1014 {
1015 return false;
1016 }
1017
1018 if (!entry_name.empty())
1019 {
1020 if (line[keyword.size()] != ' ' && line[keyword.size()] != '\t')
1021 {
1022 return false;
1023 }
1024 }
1025
1026 // Delete the "keyword" and any more spaces, if present
1027 line.erase(0, keyword.size());
1028 strip_spaces(line);
1029
1030 // now see whether the next word is the word we look for
1031 if (!line.starts_with(entry_name))
1032 {
1033 return false;
1034 }
1035
1036 line.erase(0, entry_name.size());
1037 strip_spaces(line);
1038
1039 // we'd expect an equals size here if expect_equals_sign is true
1040 if (expect_equals_sign)
1041 {
1042 if ((line.empty()) || (line[0] != '='))
1043 {
1044 return false;
1045 }
1046 }
1047
1048 // remove comment
1049 const std::string::size_type pos = line.find('#');
1050 if (pos != std::string::npos)
1051 {
1052 line.erase(pos);
1053 }
1054
1055 // trim the equals sign at the beginning and possibly following spaces
1056 // as well as spaces at the end
1057 if (expect_equals_sign)
1058 {
1059 line.erase(0, 1);
1060 }
1061 strip_spaces(line);
1062
1063 out_string = line;
1064 return true;
1065}
1066
1067template <unsigned int dim>
1068std::set<std::string>
1069UserConstants<dim>::get_names(const std::string &input_file_name)
1070{
1071 const std::string keyword = "set";
1072 const std::string entry_name_begining = "Model constant";
1073 std::ifstream input_file;
1074 input_file.open(input_file_name);
1075
1076 std::string line;
1077 std::string entry;
1078
1079 std::set<std::string> entry_name_end_list;
1080
1081 // Loop through each line
1082 while (std::getline(input_file, line))
1083 {
1084 if (parse_line(line, keyword, entry_name_begining, entry, false))
1085 {
1086 // Strip whitespace, the equals sign, and everything after the equals
1087 // sign
1088
1089 // Strip whitespace at the beginning
1090 while ((!entry.empty()) && (entry[0] == ' ' || entry[0] == '\t'))
1091 {
1092 entry.erase(0, 1);
1093 }
1094
1095 // Strip everything up to the equals sign
1096 while ((!entry.empty()) && (entry[entry.size() - 1] != '='))
1097 {
1098 entry.erase(entry.size() - 1, std::string::npos);
1099 }
1100
1101 // Strip the equals sign
1102 entry.erase(entry.size() - 1, std::string::npos);
1103
1104 // Strip whitespace between the entry name and the equals sign
1105 while ((!entry.empty()) &&
1106 (entry[entry.size() - 1] == ' ' || entry[entry.size() - 1] == '\t'))
1107 {
1108 entry.erase(entry.size() - 1, std::string::npos);
1109 }
1110
1111 // Add it to the list
1112 AssertThrow(entry_name_end_list.insert(entry).second,
1113 dealii::ExcMessage(
1114 "Non-unique constant name in parameters.prm. The constant that "
1115 "you attempted to create was \"" +
1116 entry + "\"."));
1117 }
1118 }
1119 return entry_name_end_list;
1120}
1121
1122template <unsigned int dim>
1123void
1124UserConstants<dim>::declare_parameters(dealii::ParameterHandler &parameter_handler) const
1125{
1126 if (file_name.empty())
1127 {
1128 return;
1129 }
1130 const std::set<std::string> model_constant_names = get_names(file_name);
1131 for (const std::string &constant_name : model_constant_names)
1132 {
1133 std::string constants_text = "Model constant ";
1134 constants_text.append(constant_name);
1135 parameter_handler.declare_entry(constants_text,
1136 "0",
1137 dealii::Patterns::Anything(),
1138 "The value of a user-defined constant.");
1139 }
1140}
1141
1142template <unsigned int dim>
1143void
1144UserConstants<dim>::assign_parameters(dealii::ParameterHandler &parameter_handler)
1145{
1146 if (file_name.empty())
1147 {
1148 return;
1149 }
1150 const std::set<std::string> model_constant_names = get_names(file_name);
1151 for (const std::string &constant_name : model_constant_names)
1152 {
1153 std::string constants_text = "Model constant ";
1154 constants_text.append(constant_name);
1155
1156 std::vector<std::string> model_constants_strings =
1157 dealii::Utilities::split_string_list(parameter_handler.get(constants_text));
1158 add_user_constant(constant_name, model_constants_strings);
1159 }
1160}
1161
1162PRISMS_PF_END_NAMESPACE
static dealii::ConditionalOStream & pout_summary()
Log output stream for writing a summary.log file.
Definition conditional_ostreams.cc:35
Class for printing of variant types. This is bad practice and should be fixed.
Definition user_constants.h:220
void operator()(bool value) const
Definition user_constants.h:235
void operator()(const std::string &value) const
Definition user_constants.h:241
void operator()(int value) const
Definition user_constants.h:229
void operator()(double value) const
Definition user_constants.h:223
void operator()(const dealii::Tensor< 2, dim > &value) const
Definition user_constants.h:257
void operator()(const dealii::Tensor< 2,(2 *D) - 1+(D/3)> &value) const
Definition user_constants.h:271
void operator()(const dealii::Tensor< 1, dim > &value) const
Definition user_constants.h:247
Class the stores and manages user-defined constants.
Definition user_constants.h:30
InputVariant construct_user_constant(std::vector< std::string > &model_constants_strings)
Assign the specified user constant to whatever type.
Definition user_constants.h:470
dealii::Tensor< 2,(2 *dim) - 1+(dim/3)> get_cij_matrix(const ElasticityModel &model, const std::vector< double > &constants, const StressState &stress_state) const
Definition user_constants.h:657
dealii::Tensor< 2,(2 *dim) - 1+(dim/3)> get_cij_tensor(std::vector< double > elastic_constants, const std::string &elastic_const_symmetry, const StressState &stress_state) const
Definition user_constants.h:607
int get_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:302
dealii::Tensor< 1, dim > get_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:341
void add_user_constant(const std::string &constant_name, std::vector< std::string > &model_constants_strings)
Add user-specified constants.
Definition user_constants.h:113
std::map< std::string, InputVariant > model_constants
List of user-defined constants.
Definition user_constants.h:214
InputVariant primitive_model_constant(std::vector< std::string > &model_constants_strings)
Assign the primitive user constants (e.g., int, double, bool).
Definition user_constants.h:573
static std::set< std::string > get_names(const std::string &input_file_name)
Get names of user-specified parameters from file.
Definition user_constants.h:1069
boost::variant< double, int, bool, std::string, dealii::Tensor< 1, dim >, dealii::Tensor< 2, dim >, dealii::Tensor< 2,(2 *dim) - 1+(dim/3)> > InputVariant
Definition user_constants.h:32
double get_double(const std::string &constant_name) const
Retrieve the double from the model_constants that are defined from the parameters....
Definition user_constants.h:289
static bool check_keyword_match(const std::string &line, const std::string &keyword)
Definition user_constants.h:979
dealii::Tensor< 2,(2 *dim) - 1+(dim/3)> get_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:367
dealii::Tensor< 2, dim > get_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:354
void declare_parameters(dealii::ParameterHandler &parameter_handler) const
Declare the parameters to be read from an input file.
Definition user_constants.h:1124
dealii::Tensor< 1, dim > compute_rank_1_tensor_constant(const unsigned int &n_elements, const std::vector< std::string > &tensor_elements)
Compute a 1st rank tensor from user inputs .
Definition user_constants.h:426
dealii::Tensor< 2, dim > compute_rank_2_tensor_constant(const unsigned int &n_elements, const std::vector< std::string > &tensor_elements)
Compute a 2nd rank tensor from user inputs .
Definition user_constants.h:445
std::string file_name
File to be parsed to extract the user-defined constants.
Definition user_constants.h:165
unsigned int compute_tensor_parentheses(const unsigned int &n_elements, const std::vector< std::string > &tensor_elements)
Compute the number of tensor rows.
Definition user_constants.h:381
static bool parse_line(std::string line, const std::string &keyword, const std::string &entry_name, std::string &out_string, bool expect_equals_sign)
Look for a keyword in a line and if it is found, extract the entry name and value....
Definition user_constants.h:1002
void print() const
Print all user-specified constants.
Definition user_constants.h:943
std::string get_string(const std::string &constant_name) const
Retrieve the string from the model_constants that are defined from the parameters....
Definition user_constants.h:328
static void strip_spaces(std::string &line)
Definition user_constants.h:964
bool get_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:315
void assign_parameters(dealii::ParameterHandler &parameter_handler)
Assign the parameters read from an input file to this object.
Definition user_constants.h:1144
void remove_parentheses(std::vector< std::string > &tensor_elements)
Remove and leading and trailing parentheses.
Definition user_constants.h:415
Definition conditional_ostreams.cc:20
ElasticityModel
Symmetry of elastic tensor.
Definition type_enums.h:62
@ Transverse
Definition type_enums.h:64
@ Anisotropic
Definition type_enums.h:66
@ Orthotropic
Definition type_enums.h:65
@ Isotropic
Definition type_enums.h:63
StressState
State of stress.
Definition type_enums.h:73
@ ThreeDimension
Definition type_enums.h:77
@ PlaneStress
Definition type_enums.h:87
@ PlaneStrain
Definition type_enums.h:82