Line data Source code
1 : // Copyright 2024, UChicago Argonne, LLC
2 : // All Rights Reserved
3 : // Software Name: NEML2 -- the New Engineering material Model Library, version 2
4 : // By: Argonne National Laboratory
5 : // OPEN SOURCE LICENSE (MIT)
6 : //
7 : // Permission is hereby granted, free of charge, to any person obtaining a copy
8 : // of this software and associated documentation files (the "Software"), to deal
9 : // in the Software without restriction, including without limitation the rights
10 : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 : // copies of the Software, and to permit persons to whom the Software is
12 : // furnished to do so, subject to the following conditions:
13 : //
14 : // The above copyright notice and this permission notice shall be included in
15 : // all copies or substantial portions of the Software.
16 : //
17 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 : // THE SOFTWARE.
24 :
25 : #include "neml2/user_tensors/Orientation.h"
26 :
27 : #include "neml2/tensors/Quaternion.h"
28 : #include "neml2/tensors/Rot.h"
29 : #include "neml2/tensors/Vec.h"
30 : #include "neml2/tensors/functions/where.h"
31 :
32 : namespace neml2
33 : {
34 : register_NEML2_object(Orientation);
35 :
36 : OptionSet
37 2 : Orientation::expected_options()
38 : {
39 2 : OptionSet options = UserTensorBase::expected_options();
40 :
41 2 : options.doc() = "An orientation, internally defined as a set of Modified Rodrigues parameters "
42 : "given by \\f$ r = n \\tan{\\frac{\\theta}{4}} \\f$ with \\f$ n \\f$ the axis of "
43 : "rotation and \\f$ \\theta \\f$ the rotation angle about that axis. However, "
44 : "this class provides a variety of ways to define the orientation in terms of "
45 2 : "other, more common representations.";
46 :
47 4 : options.set<std::string>("input_type") = "euler_angles";
48 6 : options.set("input_type").doc() =
49 2 : "The method used to define the angles, 'euler_angles' or 'random'";
50 :
51 4 : options.set<std::string>("angle_convention") = "kocks";
52 4 : options.set("angle_convention").doc() = "Euler angle convention, 'Kocks', 'Roe', or 'Bunge'";
53 :
54 4 : options.set<std::string>("angle_type") = "degrees";
55 2 : options.set("angle_type").doc() = "Type of angles, either 'degrees' or 'radians'";
56 :
57 6 : options.set<std::vector<double>>("values") = {};
58 4 : options.set("values").doc() = "Input Euler angles, as a flattened n-by-3 matrix";
59 :
60 4 : options.set<bool>("normalize") = false;
61 6 : options.set("normalize").doc() =
62 : "If true do a shadow parameter replacement of the underlying MRP representation to move the "
63 2 : "inputs farther away from the singularity";
64 :
65 4 : options.set<unsigned int>("quantity") = 1;
66 2 : options.set("quantity").doc() = "Number (batch size) of random orientations";
67 :
68 2 : return options;
69 0 : }
70 :
71 6 : Orientation::Orientation(const OptionSet & options)
72 : : Rot(fill(options)),
73 6 : UserTensorBase(options)
74 : {
75 6 : }
76 :
77 : Rot
78 6 : Orientation::fill(const OptionSet & options) const
79 : {
80 6 : std::string input_type = options.get<std::string>("input_type");
81 :
82 6 : Rot R;
83 6 : if (input_type == "euler_angles")
84 : {
85 6 : auto vals = options.get<std::vector<double>>("values");
86 6 : auto t = neml2::Tensor::create(vals);
87 6 : auto v = Vec(t.reshape({-1, 3}));
88 18 : R = expand_as_needed(Rot::fill_euler_angles(v,
89 12 : options.get<std::string>("angle_convention"),
90 18 : options.get<std::string>("angle_type")),
91 6 : options.get<unsigned int>("quantity"));
92 6 : }
93 0 : else if (input_type == "random")
94 : {
95 0 : R = Rot::fill_random(options.get<unsigned int>("quantity"));
96 : }
97 : else
98 0 : throw NEMLException("Unknown Orientation input_type " + input_type);
99 :
100 12 : if (options.get<bool>("normalize"))
101 0 : return neml2::where((R.norm_sq() < 1.0).unsqueeze(-1), R, R.shadow());
102 :
103 6 : return R;
104 6 : }
105 :
106 : Rot
107 6 : Orientation::expand_as_needed(const Rot & input, unsigned int inp_size) const
108 : {
109 6 : if (inp_size > 1)
110 0 : return input.batch_expand({inp_size});
111 :
112 6 : return input;
113 0 : }
114 :
115 : } // namespace neml2
|