OPALX (Object Oriented Parallel Accelerator Library for Exascal) MINIorX
OPALX
Quaternion.cpp
Go to the documentation of this file.
2#include <cmath>
3#include <iostream>
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 GeneralClassicException("normalize()", "length of vector less than 1e-12");
16#endif
17
18 return vec / length;
19 }
20} // namespace
21
22Quaternion::Quaternion(const matrix_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
87 double res = 0.0;
88 for (unsigned i = 0; i < 3; i++)
89 res += imagThis(i) * imagOther(i);
90 double dp = std::sqrt(res);
91
92 *this = Quaternion(
93 (*this)(0) * other(0) - dp,
94 (*this)(0) * imagOther + other(0) * imagThis + cross(imagThis, imagOther));
95 return *this;
96}
97
98Quaternion Quaternion::operator/(const double& d) const {
99 Quaternion result(this->real() / d, this->imag() / d);
100
101 return result;
102}
103
105#ifndef NOPAssert
106 if (this->Norm() < 1e-12)
108 "Quaternion::normalize()", "length of quaternion less than 1e-12");
109#endif
110
111 (*this) /= this->length();
112
113 return (*this);
114}
115
117 Quaternion returnValue = conjugate();
118
119 return returnValue.normalize();
120}
121
122ippl::Vector<double, 3> Quaternion::rotate(const ippl::Vector<double, 3>& vec) const {
123#ifndef NOPAssert
124 if (!this->isUnit())
126 "Quaternion::rotate()",
127 "quaternion isn't unit quaternion. Norm: " + std::to_string(this->Norm()));
128#endif
129
130 Quaternion quat(vec);
131
132 return ((*this) * (quat * (*this).conjugate())).imag();
133}
134
136 Quaternion rot(*this);
137 rot.normalize();
138
139 matrix_t mat(3, 3);
140 mat(0, 0) = 1 - 2 * (rot(2) * rot(2) + rot(3) * rot(3));
141 mat(0, 1) = 2 * (-rot(0) * rot(3) + rot(1) * rot(2));
142 mat(0, 2) = 2 * (rot(0) * rot(2) + rot(1) * rot(3));
143 mat(1, 0) = 2 * (rot(0) * rot(3) + rot(1) * rot(2));
144 mat(1, 1) = 1 - 2 * (rot(1) * rot(1) + rot(3) * rot(3));
145 mat(1, 2) = 2 * (-rot(0) * rot(1) + rot(2) * rot(3));
146 mat(2, 0) = 2 * (-rot(0) * rot(2) + rot(1) * rot(3));
147 mat(2, 1) = 2 * (rot(0) * rot(1) + rot(2) * rot(3));
148 mat(2, 2) = 1 - 2 * (rot(1) * rot(1) + rot(2) * rot(2));
149
150 return mat;
151}
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
Definition Vector3D.cpp:111
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition Vector3D.cpp:118
Quaternion getQuaternion(ippl::Vector< double, 3 > u, ippl::Vector< double, 3 > ref)
boost::numeric::ublas::matrix< double > matrix_t
Definition BoostMatrix.h:23
constexpr double pi
The value of.
Definition Physics.h:30
Quaternion & normalize()
double real() const
Quaternion conjugate() const
Quaternion inverse() const
ippl::Vector< double, 3 > rotate(const ippl::Vector< double, 3 > &) const
Quaternion & operator*=(const Quaternion &)
Quaternion operator/(const double &) const
bool isUnit() const
Quaternion operator*(const double &) const
matrix_t getRotationMatrix() const
double length() const
ippl::Vector< double, 3 > imag() const
double Norm() const