OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
Quaternion.cpp
Go to the documentation of this file.
2#include <cmath>
3#include <iostream>
4#include "Algorithms/Matrix.h"
5#include "OPALTypes.h"
6#include "Physics/Physics.h"
8
9namespace {
10 ippl::Vector<double, 3> normalize(const ippl::Vector<double, 3>& vec) {
11 double length = std::sqrt(dot(vec, vec));
12
13#ifndef NOPAssert
14 if (length < 1e-12)
15 throw GeneralOpalException("normalize()", "length of vector less than 1e-12");
16#endif
17
18 return vec / length;
19 }
20} // namespace
21
22Quaternion::Quaternion(const matrix3x3_t& M) : ippl::Vector<double, 4>(0.0) {
23 (*this)(0) = std::sqrt(std::max(0.0, 1 + M(0, 0) + M(1, 1) + M(2, 2))) / 2;
24 (*this)(1) = std::sqrt(std::max(0.0, 1 + M(0, 0) - M(1, 1) - M(2, 2))) / 2;
25 (*this)(2) = std::sqrt(std::max(0.0, 1 - M(0, 0) + M(1, 1) - M(2, 2))) / 2;
26 (*this)(3) = std::sqrt(std::max(0.0, 1 - M(0, 0) - M(1, 1) + M(2, 2))) / 2;
27 (*this)(1) =
28 std::abs(M(2, 1) - M(1, 2)) > 0 ? std::copysign((*this)(1), M(2, 1) - M(1, 2)) : 0.0;
29 (*this)(2) =
30 std::abs(M(0, 2) - M(2, 0)) > 0 ? std::copysign((*this)(2), M(0, 2) - M(2, 0)) : 0.0;
31 (*this)(3) =
32 std::abs(M(1, 0) - M(0, 1)) > 0 ? std::copysign((*this)(3), M(1, 0) - M(0, 1)) : 0.0;
33}
34
35Quaternion getQuaternion(ippl::Vector<double, 3> u, ippl::Vector<double, 3> ref) {
36 const double tol = 1e-12;
37
38 u = normalize(u);
39 ref = normalize(ref);
40
41 ippl::Vector<double, 3> axis = cross(u, ref);
42 double normAxis = std::sqrt(dot(axis, axis));
43
44 if (normAxis < tol) {
45 if (std::abs(dot(u, ref) - 1.0) < tol) {
46 return Quaternion(1.0, ippl::Vector<double, 3>(0.0));
47 }
48 // vectors are parallel or antiparallel
49 do { // find any vector in plane with ref as normal
50 double u = rand() / RAND_MAX;
51 double v = 2 * Physics::pi * rand() / RAND_MAX;
52 axis(0) = std::sqrt(1 - u * u) * std::cos(v);
53 axis(1) = std::sqrt(1 - u * u) * std::sin(v);
54 axis(2) = u;
55 } while (std::abs(dot(axis, ref)) > 0.9);
56
57 axis -= dot(axis, ref) * ref;
58 axis = normalize(axis);
59
60 return Quaternion(0, axis);
61 }
62
63 axis /= normAxis;
64
65 double cosAngle = sqrt(0.5 * (1 + dot(u, ref)));
66 double sinAngle = sqrt(1 - cosAngle * cosAngle);
67
68 return Quaternion(cosAngle, sinAngle * axis);
69}
70
71Quaternion Quaternion::operator*(const double& d) const {
72 Quaternion result(d * this->real(), d * this->imag());
73
74 return result;
75}
76
78 Quaternion result(*this);
79 return result *= other;
80}
81
83 ippl::Vector<double, 3> imagThis = this->imag();
84 ippl::Vector<double, 3> imagOther = other.imag();
85
86 double res = imagThis.dot(imagOther);
87
88 *this = Quaternion(
89 (*this)(0) * other(0) - res,
90 (*this)(0) * imagOther + other(0) * imagThis + cross(imagThis, imagOther));
91 return *this;
92}
93
94Quaternion Quaternion::operator/(const double& d) const {
95 Quaternion result(this->real() / d, this->imag() / d);
96
97 return result;
98}
99
101#ifndef NOPAssert
102 if (this->Norm() < 1e-12)
104 "Quaternion::normalize()", "length of quaternion less than 1e-12");
105#endif
106
107 (*this) /= this->length();
108
109 return (*this);
110}
111
113 Quaternion returnValue = conjugate();
114
115#ifndef NOPAssert
116 if (this->Norm() < 1e-12)
117 throw GeneralOpalException("Quaternion::inverse()", "length of quaternion less than 1e-12");
118#endif
119
120 returnValue /= returnValue.Norm();
121
122 return returnValue;
123}
124
125ippl::Vector<double, 3> Quaternion::rotate(const ippl::Vector<double, 3>& vec) const {
126#ifndef NOPAssert
127 if (!this->isUnit())
129 "Quaternion::rotate()",
130 "quaternion isn't unit quaternion. Norm: " + std::to_string(this->Norm()));
131#endif
132
133 Quaternion quat(vec);
134
135 return ((*this) * (quat * (*this).conjugate())).imag();
136}
137
139 Quaternion rot(*this);
140 rot.normalize();
141
142 matrix3x3_t mat(0.0);
143 mat(0, 0) = 1 - 2 * (rot(2) * rot(2) + rot(3) * rot(3));
144 mat(0, 1) = 2 * (-rot(0) * rot(3) + rot(1) * rot(2));
145 mat(0, 2) = 2 * (rot(0) * rot(2) + rot(1) * rot(3));
146 mat(1, 0) = 2 * (rot(0) * rot(3) + rot(1) * rot(2));
147 mat(1, 1) = 1 - 2 * (rot(1) * rot(1) + rot(3) * rot(3));
148 mat(1, 2) = 2 * (-rot(0) * rot(1) + rot(2) * rot(3));
149 mat(2, 0) = 2 * (-rot(0) * rot(2) + rot(1) * rot(3));
150 mat(2, 1) = 2 * (rot(0) * rot(1) + rot(2) * rot(3));
151 mat(2, 2) = 1 - 2 * (rot(1) * rot(1) + rot(2) * rot(2));
152
153 return mat;
154}
Quaternion getQuaternion(ippl::Vector< double, 3 > u, ippl::Vector< double, 3 > ref)
Return a unit quaternion that rotates vec onto reference.
ippl::Vector< T, Dim > Vector
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
Definition Vector3D.cpp:89
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition Vector3D.cpp:95
Quaternion storage and rotation algebra used by OPALX geometry code.
Quaternion & normalize()
Normalize the quaternion in place.
double real() const
Return the scalar part .
Quaternion conjugate() const
Return the quaternion conjugate .
matrix3x3_t getRotationMatrix() const
Convert the quaternion to a 3x3 rotation matrix.
Quaternion inverse() const
Return the multiplicative inverse.
ippl::Vector< double, 3 > rotate(const ippl::Vector< double, 3 > &) const
Rotate a spatial vector by a unit quaternion.
Quaternion & operator*=(const Quaternion &)
Quaternion operator/(const double &) const
bool isUnit() const
Return true if within a fixed tolerance.
Quaternion operator*(const double &) const
Quaternion()
Construct the identity rotation quaternion .
double length() const
Return the Euclidean norm .
ippl::Vector< double, 3 > imag() const
Return the vector part .
double Norm() const
Return .
constexpr double pi
The value of.
Definition Physics.h:36