/home/runner/work/kynema/kynema/kynema/src/math/quaternion_operations.hpp Source File

Kynema API: /home/runner/work/kynema/kynema/kynema/src/math/quaternion_operations.hpp Source File
Kynema API
A flexible multibody structural dynamics code for wind turbines
Loading...
Searching...
No Matches
quaternion_operations.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <cmath>
5#include <numbers>
6
7#include <Eigen/Geometry>
8#include <Kokkos_Core.hpp>
9
10namespace kynema::math {
11
15template <typename Quaternion, typename RotationMatrix>
16KOKKOS_INLINE_FUNCTION void QuaternionToRotationMatrix(
17 const Quaternion& q, const RotationMatrix& R
18) {
19 R(0, 0) = q(0) * q(0) + q(1) * q(1) - q(2) * q(2) - q(3) * q(3);
20 R(0, 1) = 2. * (q(1) * q(2) - q(0) * q(3));
21 R(0, 2) = 2. * (q(1) * q(3) + q(0) * q(2));
22 R(1, 0) = 2. * (q(1) * q(2) + q(0) * q(3));
23 R(1, 1) = q(0) * q(0) - q(1) * q(1) + q(2) * q(2) - q(3) * q(3);
24 R(1, 2) = 2. * (q(2) * q(3) - q(0) * q(1));
25 R(2, 0) = 2. * (q(1) * q(3) - q(0) * q(2));
26 R(2, 1) = 2. * (q(2) * q(3) + q(0) * q(1));
27 R(2, 2) = q(0) * q(0) - q(1) * q(1) - q(2) * q(2) + q(3) * q(3);
28}
29
33template <typename Quaternion, typename View1, typename View2>
34KOKKOS_INLINE_FUNCTION void RotateVectorByQuaternion(
35 const Quaternion& q, const View1& v, const View2& v_rot
36) {
37 v_rot(0) = (q(0) * q(0) + q(1) * q(1) - q(2) * q(2) - q(3) * q(3)) * v(0) +
38 2. * (q(1) * q(2) - q(0) * q(3)) * v(1) + 2. * (q(1) * q(3) + q(0) * q(2)) * v(2);
39 v_rot(1) = 2. * (q(1) * q(2) + q(0) * q(3)) * v(0) +
40 (q(0) * q(0) - q(1) * q(1) + q(2) * q(2) - q(3) * q(3)) * v(1) +
41 2. * (q(2) * q(3) - q(0) * q(1)) * v(2);
42 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) +
43 (q(0) * q(0) - q(1) * q(1) - q(2) * q(2) + q(3) * q(3)) * v(2);
44}
45
49template <typename Quaternion, typename Matrix>
50KOKKOS_INLINE_FUNCTION void QuaternionDerivative(const Quaternion& q, const Matrix& m) {
51 m(0, 0) = -q(1);
52 m(0, 1) = q(0);
53 m(0, 2) = -q(3);
54 m(0, 3) = q(2);
55 m(1, 0) = -q(2);
56 m(1, 1) = q(3);
57 m(1, 2) = q(0);
58 m(1, 3) = -q(1);
59 m(2, 0) = -q(3);
60 m(2, 1) = -q(2);
61 m(2, 2) = q(1);
62 m(2, 3) = q(0);
63}
64
68template <typename QuaternionInput, typename QuaternionOutput>
69KOKKOS_INLINE_FUNCTION void QuaternionInverse(
70 const QuaternionInput& q_in, const QuaternionOutput& q_out
71) {
72 auto length = Kokkos::sqrt(
73 (q_in(0) * q_in(0)) + (q_in(1) * q_in(1)) + (q_in(2) * q_in(2)) + (q_in(3) * q_in(3))
74 );
75
76 // Inverse of a quaternion is the conjugate divided by the length
77 q_out(0) = q_in(0) / length;
78 for (auto i = 1; i < 4; ++i) {
79 q_out(i) = -q_in(i) / length;
80 }
81}
82
86template <typename Quaternion1, typename Quaternion2, typename QuaternionN>
87KOKKOS_INLINE_FUNCTION void QuaternionCompose(
88 const Quaternion1& q1, const Quaternion2& q2, QuaternionN& qn
89) {
90 qn(0) = q1(0) * q2(0) - q1(1) * q2(1) - q1(2) * q2(2) - q1(3) * q2(3);
91 qn(1) = q1(0) * q2(1) + q1(1) * q2(0) + q1(2) * q2(3) - q1(3) * q2(2);
92 qn(2) = q1(0) * q2(2) - q1(1) * q2(3) + q1(2) * q2(0) + q1(3) * q2(1);
93 qn(3) = q1(0) * q2(3) + q1(1) * q2(2) - q1(2) * q2(1) + q1(3) * q2(0);
94}
95
99template <typename Vector, typename Quaternion>
100KOKKOS_INLINE_FUNCTION void RotationVectorToQuaternion(
101 const Vector& phi, const Quaternion& quaternion
102) {
103 const auto angle = Kokkos::sqrt((phi(0) * phi(0)) + (phi(1) * phi(1)) + (phi(2) * phi(2)));
104 const auto cos_angle = Kokkos::cos(angle / 2.);
105 const auto factor = (Kokkos::abs(angle) < 1.e-12) ? 0. : Kokkos::sin(angle / 2.) / angle;
106
107 quaternion(0) = cos_angle;
108 for (auto i = 1; i < 4; ++i) {
109 quaternion(i) = phi(i - 1) * factor;
110 }
111}
112
116template <typename Quaternion, typename Vector>
117KOKKOS_INLINE_FUNCTION void QuaternionToRotationVector(
118 const Quaternion& quaternion, const Vector& phi
119) {
120 auto theta = 2. * Kokkos::acos(quaternion(0));
121 const auto sin_half_theta = std::sqrt(1. - (quaternion(0) * quaternion(0)));
122 if (sin_half_theta > 1e-12) {
123 phi(0) = theta * quaternion(1) / sin_half_theta;
124 phi(1) = theta * quaternion(2) / sin_half_theta;
125 phi(2) = theta * quaternion(3) / sin_half_theta;
126 } else {
127 phi(0) = 0.;
128 phi(1) = 0.;
129 phi(2) = 0.;
130 }
131}
132
142KOKKOS_INLINE_FUNCTION
143Kokkos::Array<double, 4> NormalizeQuaternion(const Kokkos::Array<double, 4>& q) {
144 const auto length_squared = (q[0] * q[0]) + (q[1] * q[1]) + (q[2] * q[2]) + (q[3] * q[3]);
145
146 // If the length is 1, our work is done
147 if (std::abs(length_squared - 1.) < 1.e-16) {
148 return q;
149 }
150
151 // If the length of the quaternion is zero, return a default unit quaternion
152 if (std::abs(length_squared) < 1.e-16) {
153 return Kokkos::Array<double, 4>{1., 0., 0., 0.};
154 }
155
156 // Normalize the quaternion
157 const auto length = std::sqrt(length_squared);
158 auto normalized_quaternion = Kokkos::Array<double, 4>{};
159 for (auto k = 0U; k < 4; ++k) {
160 normalized_quaternion[k] = q[k] / length;
161 }
162 return normalized_quaternion;
163}
164
168inline std::array<double, 4> TangentTwistToQuaternion(
169 const std::array<double, 3>& tangent, const double twist
170) {
171 const auto tan_vec = Eigen::Matrix<double, 3, 1>(tangent.data());
172 const auto e1 = tan_vec.normalized();
173
174 const auto temp = Eigen::Matrix<double, 3, 1>::Unit(1);
175 const auto plane_axis = (std::abs(e1.dot(temp)) > .9) ? Eigen::Matrix<double, 3, 1>::Unit(0)
176 : Eigen::Matrix<double, 3, 1>::Unit(1);
177 const auto a = e1.dot(plane_axis);
178
179 const auto e2 = (plane_axis - a * e1).normalized();
180 const auto e3 = e1.cross(e2);
181
182 const auto q_tan = Eigen::Quaternion<double>(Eigen::Matrix<double, 3, 3>(
183 {{e1(0), e2(0), e3(0)}, {e1(1), e2(1), e3(1)}, {e1(2), e2(2), e3(2)}}
184 ));
185 const auto q_twist = Eigen::Quaternion<double>(Eigen::AngleAxis<double>(twist, e1));
186 const auto q_final = q_twist * q_tan;
187 return std::array{q_final.w(), q_final.x(), q_final.y(), q_final.z()};
188}
189
197inline bool IsIdentityQuaternion(const std::array<double, 4>& q, double tolerance = 1e-12) {
198 return std::abs(q[0] - 1.) <= tolerance && std::abs(q[1]) <= tolerance &&
199 std::abs(q[2]) <= tolerance && std::abs(q[3]) <= tolerance;
200}
201
202} // namespace kynema::math
Definition gl_quadrature.hpp:8
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:117
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 (radians) about tangent.
Definition quaternion_operations.hpp:168
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:87
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:100
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:197
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:143
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:34
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:16
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:50
KOKKOS_INLINE_FUNCTION void QuaternionInverse(const QuaternionInput &q_in, const QuaternionOutput &q_out)
Computes the inverse of a quaternion.
Definition quaternion_operations.hpp:69