MiniTensor Version of the Day
Loading...
Searching...
No Matches
MiniTensor_Rotations.h
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MiniTensor Package
4//
5// Copyright 2016 NTESS and the MiniTensor contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#if !defined(MiniTensor_Rotations_h)
11#define MiniTensor_Rotations_h
12
13// Rotation algebra: SO(N) log and exp maps.
15#include "MiniTensor_Norms.h"
16
17namespace minitensor {
18
21
27template<typename T, Index N>
29Tensor<T, N>
30log_rotation(Tensor<T, N> const & R);
31
37template<typename T, Index N>
39Tensor<T, N>
40log_rotation_pi(Tensor<T, N> const & R);
41
47template<typename T, Index N>
49Tensor<T, N>
50exp_skew_symmetric(Tensor<T, N> const & r);
51
58template<typename T, Index N>
60Vector<T, N>
61vee(Tensor<T, N> const & W);
62
63//
64// R^N logarithmic map of a rotation.
65// \param R with \f$ R \in SO(N) \f$
66// \return \f$ r = \log R \f$ with \f$ r \in so(N) \f$
67//
68template<typename T, Index N>
70Tensor<T, N>
72{
73 Index const
74 dimension = R.get_dimension();
75
76 //firewalls, make sure R \in SO(N)
77 assert(norm(dot_t(R,R) - eye<T, N>(dimension)) <
78 std::max(1.0e-12 * norm(R), 1.0e-12));
79 assert(std::abs(det(R) - 1.0) <
80 std::max(1.0e-12 * norm(R), 1.0e-12));
81 // acos requires input between -1 and +1
82 T
83 cosine = 0.5 * (trace(R) - 1.0);
84
85 if (cosine < -1.0) {
86 cosine = -1.0;
87 } else if(cosine > 1.0) {
88 cosine = 1.0;
89 }
90 T
91 theta = std::acos(cosine);
92
94 r(dimension);
95
96 switch (dimension) {
97
98 default:
99 MT_ERROR_EXIT("Logarithm of SO(N) N != 2,3 not implemented.");
100 break;
101
102 case 3:
103 if (theta == 0.0) {
104
105 r = zero<T, N>(3);
106
107 } else if (std::abs(cosine + 1.0) < 10.0 * machine_epsilon<T>()) {
108
109 r = log_rotation_pi(R);
110
111 } else {
112
113 r = theta / std::sin(theta) * skew(R);
114
115 }
116 break;
117
118 case 2:
119 r(0,0) = 0.0;
120 r(0,1) = -theta;
121 r(1,0) = theta;
122 r(1,1) = 0.0;
123 break;
124
125 case 1:
126 r(0,0) = 0.0;
127 break;
128
129 }
130
131 return r;
132}
133
134// R^N Logarithmic map of a 180-degree rotation.
135// \param R with \f$ R \in SO(N) \f$
136// \return \f$ r = \log R \f$ with \f$ r \in so(N) \f$
137//
138template<typename T, Index N>
140Tensor<T, N>
142{
143 Index const
144 dimension = R.get_dimension();
145
146 // set firewall to make sure the rotation is indeed 180 degrees
147 assert(std::abs(trace(R) + 1.0) < 10.0 * machine_epsilon<T>());
148
150 r(dimension);
151
152 switch (dimension) {
153
154 default:
155 MT_ERROR_EXIT("Logarithm of SO(N) N != 2,3 not implemented.");
156 break;
157
158 case 3:
159 {
161 normal(3);
162
163 Tensor<T, N> const
164 B = R - identity<T, N>(3);
165
166 Vector<T, N> const
167 u = row(B, 0);
168
169 Vector<T, N> const
170 v = row(B, 1);
171
172 normal = cross(u, v);
173
174 if (norm(normal) < machine_epsilon<T>()) {
175
176 Vector<T, N> const
177 w = row(B, 2);
178
179 normal = cross(u, w);
180
181 if (norm(normal) < machine_epsilon<T>()) {
182 MT_ERROR_EXIT("Cannot determine rotation vector of rotation.");
183 }
184
185 }
186
187 normal = unit(normal);
188
190 r(0,1) = -normal(2);
191 r(0,2) = normal(1);
192 r(1,0) = normal(2);
193 r(1,2) = -normal(0);
194 r(2,0) = -normal(1);
195 r(2,1) = normal(0);
196
197 T const
198 pi = std::acos(-1.0);
199
200 r = pi * r;
201 }
202 break;
203
204 case 2:
205 {
206 T theta = std::acos(-1.0);
207 if (R(0,0) > 0.0) {
208 theta = -theta;
209 }
210
211 r(0,0) = 0.0;
212 r(0,1) = -theta;
213 r(1,0) = theta;
214 r(1,1) = 0.0;
215 }
216 break;
217
218 }
219
220 return r;
221}
222
223//
224// R^N exponential map of a skew-symmetric tensor.
225//
226template<typename T, Index N>
228Tensor<T, N>
230{
231 // Check whether skew-symmetry holds
232 assert(norm(sym(r)) < std::max(1.0e-12 * norm(r), 1.0e-12));
233
234 Index const
235 dimension = r.get_dimension();
236
238 R = identity<T, N>(dimension);
239
240 T
241 theta = 0.0;
242
243 switch (dimension) {
244
245 default:
246 R = exp(r);
247 break;
248
249 case 3:
250 theta = std::sqrt(r(2,1)*r(2,1)+r(0,2)*r(0,2)+r(1,0)*r(1,0));
251
252 //Check whether norm == 0. If so, return identity.
253 if (theta >= machine_epsilon<T>()) {
254 R += sin(theta) / theta * r +
255 (1.0 - cos(theta)) / (theta * theta) * r * r;
256 }
257 break;
258
259 case 2:
260 theta = r(1,0);
261
262 {
263 T const
264 c = std::cos(theta);
265
266 T const
267 s = std::sin(theta);
268
269 R(0,0) = c;
270 R(0,1) = -s;
271 R(1,0) = s;
272 R(1,1) = c;
273 }
274
275 break;
276
277 case 1:
278 R(0,0) = 1.0;
279 break;
280
281 }
282
283 return R;
284}
285
286//
287// R^N axial vector of a skew-symmetric tensor, undefined for N != 3.
288//
289template<typename T, Index N>
291Vector<T, N>
293{
294 // Check whether skew-symmetry holds
295 assert(norm(sym(W)) < std::max(1.0e-12 * norm(W), 1.0e-12));
296
297 Index const
298 dimension = W.get_dimension();
299
301 w(dimension);
302
303 switch (dimension) {
304
305 case 3:
306 w(0) = W(2, 1);
307 w(1) = W(0, 2);
308 w(2) = W(1, 0);
309 break;
310
311 default:
312 MT_ERROR_EXIT("Axial vector from tensor defined for 3D only");
313 break;
314
315 }
316
317 return w;
318}
319
321} // namespace minitensor
322
323#endif // MiniTensor_Rotations_h
#define KOKKOS_INLINE_FUNCTION
#define MT_ERROR_EXIT(...)
KOKKOS_INLINE_FUNCTION Vector< typename Promote< S, T >::type, N > cross(Vector< S, N > const &u, Vector< T, N > const &v)
KOKKOS_INLINE_FUNCTION Index get_dimension() const
KOKKOS_INLINE_FUNCTION Matrix< typename Promote< S, T >::type, M, N > dot_t(Matrix< S, M, P > const &A, Matrix< T, N, P > const &B)
KOKKOS_INLINE_FUNCTION void fill(Filler const value)
KOKKOS_INLINE_FUNCTION Tensor< T, N > sym(Tensor< T, N > const &A)
KOKKOS_INLINE_FUNCTION Tensor< T, N > skew(Tensor< T, N > const &A)
KOKKOS_INLINE_FUNCTION Vector< T, N > row(Matrix< T, M, N > const &A, Index const i)
KOKKOS_INLINE_FUNCTION Vector< T, N > normal(Vector< T, N > const &p0, Vector< T, N > const &p1, Vector< T, N > const &p2)
Tensor< T, N > exp(Tensor< T, N > const &A)
KOKKOS_INLINE_FUNCTION T norm(Tensor< T, N > const &A)
KOKKOS_INLINE_FUNCTION T det(Tensor< T, N > const &A)
KOKKOS_INLINE_FUNCTION T trace(Tensor< T, N > const &A)
KOKKOS_INLINE_FUNCTION Tensor< T, N > log_rotation_pi(Tensor< T, N > const &R)
KOKKOS_INLINE_FUNCTION Vector< T, N > vee(Tensor< T, N > const &W)
KOKKOS_INLINE_FUNCTION Tensor< T, N > log_rotation(Tensor< T, N > const &R)
KOKKOS_INLINE_FUNCTION Tensor< T, N > exp_skew_symmetric(Tensor< T, N > const &r)
KOKKOS_INLINE_FUNCTION Quaternion< T > unit(Quaternion< T > const &q)
uint32_t Index
Indexing type.