High Performance Plasticity  0.5.0
rotation.h
Go to the documentation of this file.
1 #ifndef HPP_ROTATION_H
5 #define HPP_ROTATION_H
6 
7 #include "mpi.h"
8 #include <hpp/config.h>
9 #include <hpp/tensor.h>
10 #include <hpp/mpiUtils.h>
11 #include <hpp/external/ISOI/grid_generation.h>
12 
13 namespace hpp
14 {
15 
16 // Types of symmetry in Schoenflies notation
20 };
21 
42 template <typename T>
43 struct EulerAngles {
44  T alpha = 0;
45  T beta = 0;
46  T gamma = 0;
47 
48  HPP_NVCC_ONLY(__host__ __device__) EulerAngles() {;}
49  HPP_NVCC_ONLY(__host__ __device__) EulerAngles(T alpha, T beta, T gamma) :
50  alpha(alpha), beta(beta), gamma(gamma) {;}
51 
52  // Getters/setters (mainly intended for Python interface)
53  T getAlpha() const {return alpha;}
54  T getBeta() const {return beta;}
55  T getGamma() const {return gamma;}
56  void setAlpha(const T& alpha) {this->alpha = alpha;}
57  void setBeta(const T& beta) {this->beta = beta;}
58  void setGamma(const T& gamma) {this->gamma = gamma;}
59 };
60 
61 template <typename T>
62 MPI_Datatype getEulerAnglesTypeMPI() {
63  MPI_Datatype dtype;
64  MPI_Type_contiguous(3, MPIType<T>(), &dtype);
65  MPI_Type_commit(&dtype);
66  return dtype;
67 }
68 
75 template <typename T>
76 EulerAngles<T> polarToEuler(T theta, T phi) {
77  EulerAngles<T> angles;
78  // Rotate about z axis until x axis is aligned with y axis
79  angles.gamma = M_PI/2;
80 
81  // Rotate about x axis to get the zenithal angle correct
82  angles.beta = M_PI/2-phi;
83 
84  // Rotate about z axis to get the azimuthal angle correct
85  angles.alpha = theta;
86 
87  // Return
88  return angles;
89 }
90 
91 template <typename T>
92 std::ostream& operator<<(std::ostream& out, const EulerAngles<T>& angles)
93 {
94  out << "[";
95  out << angles.alpha << ",";
96  out << angles.beta << ",";
97  out << angles.gamma;
98  out << "]";
99  return out;
100 }
101 
102 template <typename T>
103 bool operator==(const EulerAngles<T>& l, const EulerAngles<T>& r) {
104  if (l.alpha != r.alpha) return false;
105  if (l.beta != r.beta) return false;
106  if (l.gamma != r.gamma) return false;
107 
108  // All checks passed
109  return true;
110 }
111 
112 template <typename T>
113 bool operator!=(const EulerAngles<T>& l, const EulerAngles<T>& r) {
114  return !(l==r);
115 }
116 
117 template <typename T>
119  Tensor2<T> R(3,3);
120  T c1 = std::cos(alpha);
121  T c2 = std::cos(beta);
122  T c3 = std::cos(gamma);
123  T s1 = std::sin(alpha);
124  T s2 = std::sin(beta);
125  T s3 = std::sin(gamma);
126  R(0,0) = c1*c3 - c2*s1*s3;
127  R(0,1) = -c1*s3 - c2*c3*s1;
128  R(0,2) = s1*s2;
129  R(1,0) = c3*s1 + c1*c2*s3;
130  R(1,1) = c1*c2*c3 - s1*s3;
131  R(1,2) = -c1*s2;
132  R(2,0) = s2*s3;
133  R(2,1) = c3*s2;
134  R(2,2) = c2;
135  return R;
136 }
137 
138 template <typename T>
140  return EulerZXZRotationMatrix(angle.alpha, angle.beta, angle.gamma);
141 }
142 
148 template <typename T>
150 {
151  EulerAngles<T> angle;
152 
153  // Angle beta
154  angle.beta = std::acos(R(2,2));
155 
156  if (angle.beta > 1e3*std::numeric_limits<T>::epsilon()) {
157  // The other 2 angles
158  angle.alpha = std::atan2(R(0,2),-R(1,2));
159  angle.gamma = std::atan2(R(2,0),R(2,1));
160  }
161  else {
162  // Singular case
163  angle.beta = 0.0;
164  T alphaPlusGamma = std::atan2(-R(0,1), R(0,0));
165 
166  // Not uniquely determined, so just pick a combination
167  angle.alpha = alphaPlusGamma/2.0;
168  angle.gamma = alphaPlusGamma/2.0;
169  }
170 
171  // Correct the angle ranges if necessary
172  if (angle.alpha < 0) angle.alpha += 2*M_PI;
173  if (angle.gamma < 0) angle.gamma += 2*M_PI;
174 
175  // Return
176  return angle;
177 }
178 
180 // RANDOM ROTATIONS //
182 
183 // TRANSFORMATIONS
184 inline std::mt19937 makeMt19937(bool defaultSeed) {
185  if (defaultSeed) {
186  return std::mt19937();
187  }
188  else {
189  std::random_device rd;
190  return std::mt19937(rd());
191  }
192 }
193 
194 // Arvo 1992 method
195 template <typename T>
197  // Static to avoid expensive alloc/dealloc for the tens/hundreds of millions regime
198  static std::vector<T> v(3);
199  static Tensor2<T> R(3,3);
200  static Tensor2<T> H(3,3);
201 
202  // Random rotation about vertical axis
203  R(0,0) = std::cos(2*M_PI*x1);
204  R(1,1) = R(0,0);
205  R(0,1) = std::sin(2*M_PI*x1);
206  R(1,0) = -R(0,1);
207  R(2,2) = 1.0;
208 
209  // Random rotation of vertical axis
210  v[0] = std::cos(2*M_PI*x2)*std::sqrt(x3);
211  v[1] = std::sin(2*M_PI*x2)*std::sqrt(x3);
212  v[2] = std::sqrt(1-x3);
213 
214  // Householder reflection
215  outerInPlace(v, v, H);
216  H *= (T)2.0;
217  H(0,0) -= 1.0;
218  H(1,1) -= 1.0;
219  H(2,2) -= 1.0;
220 
221  // Final matrix
222  A = H*R;
223 }
224 
225 template <typename T>
226 void randomRotationTensorArvo1992(std::mt19937& gen, Tensor2<T>& A) {
227  // Static to avoid expensive alloc/dealloc for the tens/hundreds of millions regime
228  static std::vector<T> v(3);
229  static Tensor2<T> R(3,3);
230  static Tensor2<T> H(3,3);
231 
232  // double is specified here, as if it is not, the values out of the
233  // distribution are different for float and double, even with the same
234  // default seed
235  static std::uniform_real_distribution<double> dist(0.0,1.0);
236 
237  // Random samples
238  T x1 = (T)dist(gen);
239  T x2 = (T)dist(gen);
240  T x3 = (T)dist(gen);
241 
242  // Generate
244 }
245 
246 template <typename T>
247 void randomRotationTensorArvo1992(Tensor2<T>& A, bool defaultSeed=false) {
248  // Create generator once
249  static std::mt19937 gen = makeMt19937(defaultSeed);
250 
251  // Generate
253 }
254 
255 template <typename T>
256 void rotationTensorFrom3UniformRandoms(Tensor2<T>& A, T x1, T x2, T x3) {
258 }
259 
276 template <typename T>
277 Tensor2<T> randomRotationTensorStewart1980(unsigned int dim, bool defaultSeed=false) {
278  // Generator
279  static std::mt19937 gen = makeMt19937(defaultSeed);
280 
281  // Normal distribution to draw from
282  std::normal_distribution<T> dist(0.0,1.0);
283 
284  // Construction
285  Tensor2<T> H = identityTensor2<T>(dim);
286  std::vector<T> D = ones<T>(dim);
287  for (unsigned int n=1; n<dim; n++) {
288  std::valarray<T> x(dim-n+1);
289  for (unsigned int i=0; i<dim-n+1; i++) {
290  x[i] = dist(gen);
291  }
292  D[n-1] = std::copysign(1.0, x[0]);
293  x[0] -= D[n-1]*std::sqrt((x*x).sum());
294 
295  // Householder transformation
296  Tensor2<T> Hx = identityTensor2<T>(dim-n+1) - (T)2.0*outer(x, x)/(x*x).sum();
297  Tensor2<T> mat = identityTensor2<T>(dim);
298  for (unsigned int i=n-1; i<dim; i++) {
299  for (unsigned int j=n-1; j<dim; j++) {
300  mat(i,j) = Hx(i-n+1,j-n+1);
301  }
302  }
303  H = H*mat;
304  }
305 
306  // Fix the last sign such that the determinant is 1
307  D[dim-1] = -prod(D);
308  H = (D*H.trans()).trans();
309 
310  // Return
311  return H;
312 }
313 
320 template <typename T>
321 void randomRotationTensorInPlace(unsigned int dim, Tensor2<T>& A, bool defaultSeed=false) {
322  // Generate tensor
323  if (dim == 3) {
324  randomRotationTensorArvo1992<T>(A, defaultSeed);
325  }
326  else {
327  A = randomRotationTensorStewart1980<T>(dim, defaultSeed);
328  }
329 
330  // Check the tensor
331  #ifdef DEBUG_BUILD
332  if (!(A.isRotationMatrix())) {
333  std::cerr << "Warning: random rotation tensor didn't pass check. Re-generating." << std::endl;
334  randomRotationTensorInPlace<T>(dim, A, defaultSeed);
335  }
336  #endif
337 }
338 
339 template <typename T>
340 Tensor2<T> randomRotationTensor(unsigned int dim, bool defaultSeed=false) {
341  // Generate tensor
342  Tensor2<T> A(dim,dim);
343  randomRotationTensorInPlace<T>(dim, A, defaultSeed);
344  return A;
345 }
346 
348 // ROTATION SPACES //
350 
351 template <typename T>
353  EulerAngles<T> angles;
354  auto q0 = q.a;
355  auto q1 = q.b;
356  auto q2 = q.c;
357  auto q3 = q.d;
358  angles.alpha = std::atan2(2*(q0*q1+q2*q3), 1-2*(std::pow(q1,2.)+std::pow(q2,2.)));
359  angles.beta = std::asin(2*(q0*q2-q3*q1));
360  angles.gamma = std::atan2(2*(q0*q3+q1*q2), 1-2*(std::pow(q2,2.)+std::pow(q3,2.)));
361  return angles;
362 }
363 
375 template <typename T>
376 class SO3Discrete {
377 public:
379  SO3Discrete(unsigned int resolution, SymmetryType symmetryType = SYMMETRY_TYPE_NONE);
380  isoi::Quaternion getQuat(unsigned int i) {return quatList[i];}
381  EulerAngles<T> getEulerAngle(unsigned int i) {return eulerAngleList[i];}
382  unsigned int size() {return quatList.size();}
383 private:
385  std::vector<isoi::Quaternion> quatList;
386  std::vector<EulerAngles<T>> eulerAngleList;
387 };
388 
389 } //END NAMESPACE HPP
390 
391 #endif /* HPP_ROTATION_H */
void setBeta(const T &beta)
Definition: rotation.h:57
T alpha
Definition: rotation.h:44
Tensor2< T > outer(const std::vector< T > &A, const std::vector< T > &B)
Definition: tensor.h:640
T getBeta() const
Definition: rotation.h:54
EulerAngles< T > getEulerAngle(unsigned int i)
Definition: rotation.h:381
T beta
Definition: rotation.h:45
void rotationTensorFrom3UniformRandomsArvo1992(Tensor2< T > &A, T x1, T x2, T x3)
Definition: rotation.h:196
Definition: casesUtils.cpp:4
Tensor2< T > randomRotationTensorStewart1980(unsigned int dim, bool defaultSeed=false)
Generate a random rotation tensor.
Definition: rotation.h:277
std::vector< isoi::Quaternion > quatList
Definition: rotation.h:385
Definition: rotation.h:18
Tensor2< T > EulerZXZRotationMatrix(T alpha, T beta, T gamma)
Definition: rotation.h:118
Tensor2< T > randomRotationTensor(unsigned int dim, bool defaultSeed=false)
Definition: rotation.h:340
SymmetryType
Definition: rotation.h:17
HPP_NVCC_ONLY(__host__ __device__) EulerAngles()
Definition: rotation.h:48
Definition: rotation.h:376
void setAlpha(const T &alpha)
Definition: rotation.h:56
void rotationTensorFrom3UniformRandoms(Tensor2< T > &A, T x1, T x2, T x3)
Definition: rotation.h:256
SymmetryType symmetryType
Definition: rotation.h:384
Header file for tensor classes.
bool operator==(const SpectralDatasetID &l, const SpectralDatasetID &r)
Definition: spectralUtils.cpp:132
A class for second order tensors.
Definition: tensor.h:303
void setGamma(const T &gamma)
Definition: rotation.h:58
MPI_Datatype getEulerAnglesTypeMPI()
Definition: rotation.h:62
bool isRotationMatrix() const
Definition: tensor.cpp:342
void randomRotationTensorArvo1992(std::mt19937 &gen, Tensor2< T > &A)
Definition: rotation.h:226
EulerAngles< T > polarToEuler(T theta, T phi)
Convert polar angles to Euler angles.
Definition: rotation.h:76
std::mt19937 makeMt19937(bool defaultSeed)
Definition: rotation.h:184
std::vector< EulerAngles< T > > eulerAngleList
Definition: rotation.h:386
void outerInPlace(const std::vector< T > &A, const std::vector< T > &B, Tensor2< T > &C)
Definition: tensor.h:653
T gamma
Definition: rotation.h:46
bool operator!=(const EulerAngles< T > &l, const EulerAngles< T > &r)
Definition: rotation.h:113
Tensor2< T > trans() const
The transpose of the tensor.
Definition: tensor.cpp:536
SO3Discrete()
Definition: rotation.h:378
isoi::Quaternion getQuat(unsigned int i)
Definition: rotation.h:380
EulerAngles< T > getEulerZXZAngles(Tensor2< T > R)
Get Euler angles from rotation matrix.
Definition: rotation.h:149
T getAlpha() const
Definition: rotation.h:53
EulerAngles< T > quaternionToEulerAngles(isoi::Quaternion &q)
Definition: rotation.h:352
T prod(const std::vector< T > &vec)
Product of all the entries of a vector.
Definition: tensor.h:128
T getGamma() const
Definition: rotation.h:55
void randomRotationTensorInPlace(unsigned int dim, Tensor2< T > &A, bool defaultSeed=false)
Generate a random rotation tensor.
Definition: rotation.h:321
Definition: rotation.h:43
Definition: rotation.h:19
unsigned int size()
Definition: rotation.h:382