10#include <Kokkos_Core.hpp>
19template <
typename Quaternion,
typename RotationMatrix>
21 const Quaternion& q,
const RotationMatrix& R
23 R(0, 0) = q(0) * q(0) + q(1) * q(1) - q(2) * q(2) - q(3) * q(3);
24 R(0, 1) = 2. * (q(1) * q(2) - q(0) * q(3));
25 R(0, 2) = 2. * (q(1) * q(3) + q(0) * q(2));
26 R(1, 0) = 2. * (q(1) * q(2) + q(0) * q(3));
27 R(1, 1) = q(0) * q(0) - q(1) * q(1) + q(2) * q(2) - q(3) * q(3);
28 R(1, 2) = 2. * (q(2) * q(3) - q(0) * q(1));
29 R(2, 0) = 2. * (q(1) * q(3) - q(0) * q(2));
30 R(2, 1) = 2. * (q(2) * q(3) + q(0) * q(1));
31 R(2, 2) = q(0) * q(0) - q(1) * q(1) - q(2) * q(2) + q(3) * q(3);
39 return std::array<std::array<double, 3>, 3>{{
41 q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3],
42 2. * (q[1] * q[2] - q[0] * q[3]),
43 2. * (q[1] * q[3] + q[0] * q[2]),
46 2. * (q[1] * q[2] + q[0] * q[3]),
47 q[0] * q[0] - q[1] * q[1] + q[2] * q[2] - q[3] * q[3],
48 2. * (q[2] * q[3] - q[0] * q[1]),
51 2. * (q[1] * q[3] - q[0] * q[2]),
52 2. * (q[2] * q[3] + q[0] * q[1]),
53 q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3],
65 auto m22_p_m33 = m[1][1] + m[2][2];
66 auto m22_m_m33 = m[1][1] - m[2][2];
67 std::array<double, 4> vals{
75 const auto* max_num = std::max_element(vals.begin(), vals.end());
76 auto max_idx = std::distance(vals.cbegin(), max_num);
78 auto tmp = sqrt(*max_num + 1.);
82 return std::array<double, 4>{
84 (m[2][1] - m[1][2]) * c,
85 (m[0][2] - m[2][0]) * c,
86 (m[1][0] - m[0][1]) * c,
90 return std::array<double, 4>{
91 (m[2][1] - m[1][2]) * c,
93 (m[0][1] + m[1][0]) * c,
94 (m[0][2] + m[2][0]) * c,
98 return std::array<double, 4>{
99 (m[0][2] - m[2][0]) * c,
100 (m[0][1] + m[1][0]) * c,
102 (m[1][2] + m[2][1]) * c,
106 return std::array<double, 4>{
107 (m[1][0] - m[0][1]) * c,
108 (m[0][2] + m[2][0]) * c,
109 (m[1][2] + m[2][1]) * c,
113 return std::array<double, 4>{1., 0., 0., 0};
119template <
typename Quaternion,
typename View1,
typename View2>
121 const Quaternion& q,
const View1& v,
const View2& v_rot
123 v_rot(0) = (q(0) * q(0) + q(1) * q(1) - q(2) * q(2) - q(3) * q(3)) * v(0) +
124 2. * (q(1) * q(2) - q(0) * q(3)) * v(1) + 2. * (q(1) * q(3) + q(0) * q(2)) * v(2);
125 v_rot(1) = 2. * (q(1) * q(2) + q(0) * q(3)) * v(0) +
126 (q(0) * q(0) - q(1) * q(1) + q(2) * q(2) - q(3) * q(3)) * v(1) +
127 2. * (q(2) * q(3) - q(0) * q(1)) * v(2);
128 v_rot(2) = 2. * (q(1) * q(3) - q(0) * q(2)) * v(0) + 2. * (q(2) * q(3) + q(0) * q(1)) * v(1) +
129 (q(0) * q(0) - q(1) * q(1) - q(2) * q(2) + q(3) * q(3)) * v(2);
136 std::span<const double, 4> q, std::span<const double, 3> v
138 auto v_rot = std::array<double, 3>{};
139 v_rot[0] = (q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3]) * v[0] +
140 2. * (q[1] * q[2] - q[0] * q[3]) * v[1] + 2. * (q[1] * q[3] + q[0] * q[2]) * v[2];
141 v_rot[1] = 2. * (q[1] * q[2] + q[0] * q[3]) * v[0] +
142 (q[0] * q[0] - q[1] * q[1] + q[2] * q[2] - q[3] * q[3]) * v[1] +
143 2. * (q[2] * q[3] - q[0] * q[1]) * v[2];
144 v_rot[2] = 2. * (q[1] * q[3] - q[0] * q[2]) * v[0] + 2. * (q[2] * q[3] + q[0] * q[1]) * v[1] +
145 (q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3]) * v[2];
152template <
typename Quaternion,
typename Matrix>
171template <
typename QuaternionInput,
typename QuaternionOutput>
173 const QuaternionInput& q_in,
const QuaternionOutput& q_out
176 Kokkos::sqrt(q_in(0) * q_in(0) + q_in(1) * q_in(1) + q_in(2) * q_in(2) + q_in(3) * q_in(3));
179 q_out(0) = q_in(0) / length;
180 for (
auto i = 1; i < 4; ++i) {
181 q_out(i) = -q_in(i) / length;
189 const auto length = std::sqrt(
190 quaternion[0] * quaternion[0] + quaternion[1] * quaternion[1] +
191 quaternion[2] * quaternion[2] + quaternion[3] * quaternion[3]
195 quaternion[0] / length, -quaternion[1] / length, -quaternion[2] / length,
196 -quaternion[3] / length
203template <
typename Quaternion1,
typename Quaternion2,
typename QuaternionN>
205 const Quaternion1& q1,
const Quaternion2& q2, QuaternionN& qn
207 qn(0) = q1(0) * q2(0) - q1(1) * q2(1) - q1(2) * q2(2) - q1(3) * q2(3);
208 qn(1) = q1(0) * q2(1) + q1(1) * q2(0) + q1(2) * q2(3) - q1(3) * q2(2);
209 qn(2) = q1(0) * q2(2) - q1(1) * q2(3) + q1(2) * q2(0) + q1(3) * q2(1);
210 qn(3) = q1(0) * q2(3) + q1(1) * q2(2) - q1(2) * q2(1) + q1(3) * q2(0);
217 const std::array<double, 4>& q1,
const std::array<double, 4>& q2
219 auto qn = std::array<double, 4>{};
220 qn[0] = q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] - q1[3] * q2[3];
221 qn[1] = q1[0] * q2[1] + q1[1] * q2[0] + q1[2] * q2[3] - q1[3] * q2[2];
222 qn[2] = q1[0] * q2[2] - q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1];
223 qn[3] = q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0];
230template <
typename Vector,
typename Quaternion>
232 const Vector& phi,
const Quaternion& quaternion
234 const auto angle = Kokkos::sqrt(phi(0) * phi(0) + phi(1) * phi(1) + phi(2) * phi(2));
235 const auto cos_angle = Kokkos::cos(angle / 2.);
236 const auto factor = (Kokkos::abs(angle) < 1.e-12) ? 0. : Kokkos::sin(angle / 2.) / angle;
238 quaternion(0) = cos_angle;
239 for (
auto i = 1; i < 4; ++i) {
240 quaternion(i) = phi(i - 1) * factor;
247template <
typename Quaternion,
typename Vector>
249 const Quaternion& quaternion,
const Vector& phi
251 auto theta = 2. * Kokkos::acos(quaternion(0));
252 const auto sin_half_theta = std::sqrt(1. - quaternion(0) * quaternion(0));
253 if (sin_half_theta > 1e-12) {
254 phi(0) = theta * quaternion(1) / sin_half_theta;
255 phi(1) = theta * quaternion(2) / sin_half_theta;
256 phi(2) = theta * quaternion(3) / sin_half_theta;
268 auto theta = 2. * Kokkos::acos(quaternion[0]);
269 const auto sin_half_theta = std::sqrt(1. - quaternion[0] * quaternion[0]);
270 std::array<double, 3> phi{};
271 if (sin_half_theta > 1e-12) {
272 phi[0] = theta * quaternion[1] / sin_half_theta;
273 phi[1] = theta * quaternion[2] / sin_half_theta;
274 phi[2] = theta * quaternion[3] / sin_half_theta;
287 const auto angle = std::sqrt(phi[0] * phi[0] + phi[1] * phi[1] + phi[2] * phi[2]);
289 if (std::abs(angle) < 1e-12) {
290 return std::array<double, 4>{1., 0., 0., 0.};
293 const auto sin_angle = std::sin(angle / 2.);
294 const auto cos_angle = std::cos(angle / 2.);
295 const auto factor = sin_angle / angle;
296 return std::array<double, 4>{cos_angle, phi[0] * factor, phi[1] * factor, phi[2] * factor};
308KOKKOS_INLINE_FUNCTION
310 const auto length_squared = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
313 if (std::abs(length_squared - 1.) < 1.e-16) {
318 if (std::abs(length_squared) < 1.e-16) {
319 return Kokkos::Array<double, 4>{1., 0., 0., 0.};
323 const auto length = std::sqrt(length_squared);
324 auto normalized_quaternion = Kokkos::Array<double, 4>{};
325 for (
auto k = 0U; k < 4; ++k) {
326 normalized_quaternion[k] = q[k] / length;
328 return normalized_quaternion;
335 const std::array<double, 3>& tangent,
const double twist
338 std::array<double, 3> temp{0., 1., 0.};
345 std::array<double, 3> e2 =
346 UnitVector({temp[0] - e1[0] * a, temp[1] - e1[1] * a, temp[2] - e1[2] * a});
352 {e1[0], e2[0], e3[0]},
353 {e1[1], e2[1], e3[1]},
354 {e1[2], e2[2], e3[2]},
357 const auto twist_rad = twist * std::numbers::pi / 180.;
368 if (std::abs(angle) < 1.e-16) {
369 return {1., 0., 0., 0.};
371 const auto sin = std::sin(angle / 2.);
372 const auto cos = std::cos(angle / 2.);
373 return {cos, sin * axis[0], sin * axis[1], sin * axis[2]};
384 return std::abs(q[0] - 1.) <= tolerance && std::abs(q[1]) <= tolerance &&
385 std::abs(q[2]) <= tolerance && std::abs(q[3]) <= tolerance;
Definition gll_quadrature.hpp:7
KOKKOS_INLINE_FUNCTION void QuaternionToRotationVector(const Quaternion &quaternion, const Vector &phi)
Returns a 3-D rotation vector from provided 4-D quaternion, i.e. the logarithmic map.
Definition quaternion_operations.hpp:248
KOKKOS_INLINE_FUNCTION void CrossProduct(const VectorType &a, const VectorType &b, const VectorType &c)
Calculate the cross product between two vector views.
Definition vector_operations.hpp:40
std::array< double, 4 > TangentTwistToQuaternion(const std::array< double, 3 > &tangent, const double twist)
Returns a 4-D quaternion from provided tangent vector and twist (degrees) about tangent.
Definition quaternion_operations.hpp:334
KOKKOS_INLINE_FUNCTION void QuaternionCompose(const Quaternion1 &q1, const Quaternion2 &q2, QuaternionN &qn)
Composes (i.e. multiplies) two quaternions and stores the result in a third quaternion.
Definition quaternion_operations.hpp:204
std::array< double, 4 > RotationMatrixToQuaternion(const std::array< std::array< double, 3 >, 3 > &m)
Converts a 3x3 rotation matrix to a 4x1 quaternion and returns the result, see https://www....
Definition quaternion_operations.hpp:63
std::array< double, 4 > AxisAngleToQuaternion(const std::array< double, 3 > &axis, double angle)
Returns a quaternion from the axis vector and angle (radians)
Definition quaternion_operations.hpp:367
KOKKOS_INLINE_FUNCTION void RotationVectorToQuaternion(const Vector &phi, const Quaternion &quaternion)
Returns a 4-D quaternion from provided 3-D rotation vector, i.e. the exponential map.
Definition quaternion_operations.hpp:231
KOKKOS_INLINE_FUNCTION double DotProduct(const AVectorType &a, const BVectorType &b)
Calculate the dot product between two vector views.
Definition vector_operations.hpp:25
bool IsIdentityQuaternion(const std::array< double, 4 > &q, double tolerance=1e-12)
Checks if a quaternion is approximately the identity quaternion [1, 0, 0, 0].
Definition quaternion_operations.hpp:383
KOKKOS_INLINE_FUNCTION Kokkos::Array< double, 4 > NormalizeQuaternion(const Kokkos::Array< double, 4 > &q)
Normalizes a quaternion to ensure it is a unit quaternion.
Definition quaternion_operations.hpp:309
KOKKOS_INLINE_FUNCTION void RotateVectorByQuaternion(const Quaternion &q, const View1 &v, const View2 &v_rot)
Rotates provided vector by provided unit quaternion and returns the result.
Definition quaternion_operations.hpp:120
constexpr std::array< double, 3 > UnitVector(const std::array< double, 3 > &v)
UnitVector returns the unit vector of the given vector.
Definition vector_operations.hpp:65
KOKKOS_INLINE_FUNCTION void QuaternionToRotationMatrix(const Quaternion &q, const RotationMatrix &R)
Converts a 4x1 quaternion to a 3x3 rotation matrix and returns the result.
Definition quaternion_operations.hpp:20
KOKKOS_INLINE_FUNCTION void QuaternionDerivative(const Quaternion &q, const Matrix &m)
Computes the derivative of a quaternion and stores the result in a 3x4 matrix.
Definition quaternion_operations.hpp:153
KOKKOS_INLINE_FUNCTION void QuaternionInverse(const QuaternionInput &q_in, const QuaternionOutput &q_out)
Computes the inverse of a quaternion.
Definition quaternion_operations.hpp:172