DAMASK with grid solvers  Revision: v2.0.3-2204-gdb1f2151
The Düsseldorf Advanced Material Simulation Kit with Grid Solvers
quaternions.f90
Go to the documentation of this file.
1 # 1 "/home/damask_user/GitLabCI_Pipeline_4301/DAMASK/src/quaternions.f90"
2 # 1 "<built-in>"
3 # 1 "<command-line>"
4 # 1 "/home/damask_user/GitLabCI_Pipeline_4301/DAMASK/src/quaternions.f90"
5 !---------------------------------------------------------------------------------------------------
11 !---------------------------------------------------------------------------------------------------
13  use prec
14  use io
15 
16  implicit none
17  private
18 
19  real(preal), parameter, public :: p = -1.0_preal
20 
21  type, public :: quaternion
22  real(preal), private :: w = 0.0_preal
23  real(preal), private :: x = 0.0_preal
24  real(preal), private :: y = 0.0_preal
25  real(preal), private :: z = 0.0_preal
26 
27 
28  contains
29  procedure, private :: add__
30  procedure, private :: pos__
31  generic, public :: operator(+) => add__,pos__
32 
33  procedure, private :: sub__
34  procedure, private :: neg__
35  generic, public :: operator(-) => sub__,neg__
36 
37  procedure, private :: mul_quat__
38  procedure, private :: mul_scal__
39  generic, public :: operator(*) => mul_quat__, mul_scal__
40 
41  procedure, private :: div_quat__
42  procedure, private :: div_scal__
43  generic, public :: operator(/) => div_quat__, div_scal__
44 
45  procedure, private :: eq__
46  generic, public :: operator(==) => eq__
47 
48  procedure, private :: neq__
49  generic, public :: operator(/=) => neq__
50 
51  procedure, private :: pow_quat__
52  procedure, private :: pow_scal__
53  generic, public :: operator(**) => pow_quat__, pow_scal__
54 
55  procedure, public :: abs => abs__
56  procedure, public :: conjg => conjg__
57  procedure, public :: real => real__
58  procedure, public :: aimag => aimag__
59 
60  procedure, public :: homomorphed
61  procedure, public :: asarray
62  procedure, public :: inverse
63 
64  end type
65 
66  interface assignment (=)
67  module procedure assign_quat__
68  module procedure assign_vec__
69  end interface assignment (=)
70 
71  interface quaternion
72  module procedure init__
73  end interface quaternion
74 
75  interface abs
76  procedure abs__
77  end interface abs
78 
79  interface dot_product
80  procedure dot_product__
81  end interface dot_product
82 
83  interface conjg
84  module procedure conjg__
85  end interface conjg
86 
87  interface exp
88  module procedure exp__
89  end interface exp
90 
91  interface log
92  module procedure log__
93  end interface log
94 
95  interface real
96  module procedure real__
97  end interface real
98 
99  interface aimag
100  module procedure aimag__
101  end interface aimag
102 
103  public :: &
105  assignment(=), &
106  conjg, aimag, &
107  log, exp, &
108  real
109 
110 contains
111 
112 
113 !--------------------------------------------------------------------------------------------------
115 !--------------------------------------------------------------------------------------------------
116 subroutine quaternions_init
117 
118  write(6,'(/,a)') ' <<<+- quaternions init -+>>>'; flush(6)
119  call unittest
120 
121 end subroutine quaternions_init
122 
123 
124 !---------------------------------------------------------------------------------------------------
126 !---------------------------------------------------------------------------------------------------
127 type(quaternion) pure function init__(array)
128 
129  real(preal), intent(in), dimension(4) :: array
130 
131  init__%w = array(1)
132  init__%x = array(2)
133  init__%y = array(3)
134  init__%z = array(4)
135 
136 end function init__
137 
138 
139 !---------------------------------------------------------------------------------------------------
141 !---------------------------------------------------------------------------------------------------
142 elemental pure subroutine assign_quat__(self,other)
143 
144  type(quaternion), intent(out) :: self
145  type(quaternion), intent(in) :: other
146 
147  self = [other%w,other%x,other%y,other%z]
148 
149 end subroutine assign_quat__
150 
151 
152 !---------------------------------------------------------------------------------------------------
154 !---------------------------------------------------------------------------------------------------
155 pure subroutine assign_vec__(self,other)
156 
157  type(quaternion), intent(out) :: self
158  real(preal), intent(in), dimension(4) :: other
159 
160  self%w = other(1)
161  self%x = other(2)
162  self%y = other(3)
163  self%z = other(4)
164 
165 end subroutine assign_vec__
166 
167 
168 !---------------------------------------------------------------------------------------------------
170 !---------------------------------------------------------------------------------------------------
171 type(quaternion) elemental pure function add__(self,other)
172 
173  class(quaternion), intent(in) :: self,other
174 
175  add__ = [ self%w, self%x, self%y ,self%z] &
176  + [other%w, other%x, other%y,other%z]
177 
178 end function add__
179 
180 
181 !---------------------------------------------------------------------------------------------------
183 !---------------------------------------------------------------------------------------------------
184 type(quaternion) elemental pure function pos__(self)
185 
186  class(quaternion), intent(in) :: self
187 
188  pos__ = self * (+1.0_preal)
189 
190 end function pos__
191 
192 
193 !---------------------------------------------------------------------------------------------------
195 !---------------------------------------------------------------------------------------------------
196 type(quaternion) elemental pure function sub__(self,other)
197 
198  class(quaternion), intent(in) :: self,other
199 
200  sub__ = [ self%w, self%x, self%y ,self%z] &
201  - [other%w, other%x, other%y,other%z]
202 
203 end function sub__
204 
205 
206 !---------------------------------------------------------------------------------------------------
208 !---------------------------------------------------------------------------------------------------
209 type(quaternion) elemental pure function neg__(self)
210 
211  class(quaternion), intent(in) :: self
212 
213  neg__ = self * (-1.0_preal)
214 
215 end function neg__
216 
217 
218 !---------------------------------------------------------------------------------------------------
220 !---------------------------------------------------------------------------------------------------
221 type(quaternion) elemental pure function mul_quat__(self,other)
222 
223  class(quaternion), intent(in) :: self, other
224 
225  mul_quat__%w = self%w*other%w - self%x*other%x - self%y*other%y - self%z*other%z
226  mul_quat__%x = self%w*other%x + self%x*other%w + p * (self%y*other%z - self%z*other%y)
227  mul_quat__%y = self%w*other%y + self%y*other%w + p * (self%z*other%x - self%x*other%z)
228  mul_quat__%z = self%w*other%z + self%z*other%w + p * (self%x*other%y - self%y*other%x)
229 
230 end function mul_quat__
231 
232 
233 !---------------------------------------------------------------------------------------------------
235 !---------------------------------------------------------------------------------------------------
236 type(quaternion) elemental pure function mul_scal__(self,scal)
237 
238  class(quaternion), intent(in) :: self
239  real(preal), intent(in) :: scal
240 
241  mul_scal__ = [self%w,self%x,self%y,self%z]*scal
242 
243 end function mul_scal__
244 
245 
246 !---------------------------------------------------------------------------------------------------
248 !---------------------------------------------------------------------------------------------------
249 type(quaternion) elemental pure function div_quat__(self,other)
250 
251  class(quaternion), intent(in) :: self, other
252 
253  div_quat__ = self * (conjg(other)/(abs(other)**2.0_preal))
254 
255 end function div_quat__
256 
257 
258 !---------------------------------------------------------------------------------------------------
260 !---------------------------------------------------------------------------------------------------
261 type(quaternion) elemental pure function div_scal__(self,scal)
262 
263  class(quaternion), intent(in) :: self
264  real(preal), intent(in) :: scal
265 
266  div_scal__ = [self%w,self%x,self%y,self%z]/scal
267 
268 end function div_scal__
269 
270 
271 !---------------------------------------------------------------------------------------------------
273 !---------------------------------------------------------------------------------------------------
274 logical elemental pure function eq__(self,other)
275 
276  class(quaternion), intent(in) :: self,other
277 
278  eq__ = all(deq([ self%w, self%x, self%y, self%z], &
279  [other%w,other%x,other%y,other%z]))
280 
281 end function eq__
282 
283 
284 !---------------------------------------------------------------------------------------------------
286 !---------------------------------------------------------------------------------------------------
287 logical elemental pure function neq__(self,other)
288 
289  class(quaternion), intent(in) :: self,other
290 
291  neq__ = .not. self%eq__(other)
292 
293 end function neq__
294 
295 
296 !---------------------------------------------------------------------------------------------------
298 !---------------------------------------------------------------------------------------------------
299 type(quaternion) elemental pure function pow_quat__(self,expon)
300 
301  class(quaternion), intent(in) :: self
302  type(quaternion), intent(in) :: expon
303 
304  pow_quat__ = exp(log(self)*expon)
305 
306 end function pow_quat__
307 
308 
309 !---------------------------------------------------------------------------------------------------
311 !---------------------------------------------------------------------------------------------------
312 type(quaternion) elemental pure function pow_scal__(self,expon)
313 
314  class(quaternion), intent(in) :: self
315  real(preal), intent(in) :: expon
316 
317  pow_scal__ = exp(log(self)*expon)
318 
319 end function pow_scal__
320 
321 
322 !---------------------------------------------------------------------------------------------------
324 !---------------------------------------------------------------------------------------------------
325 type(quaternion) elemental pure function exp__(a)
326 
327  class(quaternion), intent(in) :: a
328  real(preal) :: absimag
329 
330  absimag = norm2(aimag(a))
331 
332  exp__ = merge(exp(a%w) * [ cos(absimag), &
333  a%x/absimag * sin(absimag), &
334  a%y/absimag * sin(absimag), &
335  a%z/absimag * sin(absimag)], &
336  ieee_value(1.0_preal,ieee_signaling_nan), &
337  dneq0(absimag))
338 
339 end function exp__
340 
341 
342 !---------------------------------------------------------------------------------------------------
344 !---------------------------------------------------------------------------------------------------
345 type(quaternion) elemental pure function log__(a)
346 
347  class(quaternion), intent(in) :: a
348  real(preal) :: absimag
349 
350  absimag = norm2(aimag(a))
351 
352  log__ = merge([log(abs(a)), &
353  a%x/absimag * acos(a%w/abs(a)), &
354  a%y/absimag * acos(a%w/abs(a)), &
355  a%z/absimag * acos(a%w/abs(a))], &
356  ieee_value(1.0_preal,ieee_signaling_nan), &
357  dneq0(absimag))
358 
359 end function log__
360 
361 
362 !---------------------------------------------------------------------------------------------------
364 !---------------------------------------------------------------------------------------------------
365 real(preal) elemental pure function abs__(self)
366 
367  class(quaternion), intent(in) :: self
368 
369  abs__ = norm2([self%w,self%x,self%y,self%z])
370 
371 end function abs__
372 
373 
374 !---------------------------------------------------------------------------------------------------
376 !---------------------------------------------------------------------------------------------------
377 real(preal) elemental pure function dot_product__(a,b)
378 
379  class(quaternion), intent(in) :: a,b
380 
381  dot_product__ = a%w*b%w + a%x*b%x + a%y*b%y + a%z*b%z
382 
383 end function dot_product__
384 
385 
386 !---------------------------------------------------------------------------------------------------
388 !---------------------------------------------------------------------------------------------------
389 type(quaternion) elemental pure function conjg__(self)
390 
391  class(quaternion), intent(in) :: self
392 
393  conjg__ = [self%w,-self%x,-self%y,-self%z]
394 
395 end function conjg__
396 
397 
398 !---------------------------------------------------------------------------------------------------
400 !---------------------------------------------------------------------------------------------------
401 type(quaternion) elemental pure function homomorphed(self)
402 
403  class(quaternion), intent(in) :: self
404 
405  homomorphed = - self
406 
407 end function homomorphed
408 
409 
410 !---------------------------------------------------------------------------------------------------
412 !---------------------------------------------------------------------------------------------------
413 pure function asarray(self)
414 
415  real(preal), dimension(4) :: asarray
416  class(quaternion), intent(in) :: self
417 
418  asarray = [self%w,self%x,self%y,self%z]
419 
420 end function asarray
421 
422 
423 !---------------------------------------------------------------------------------------------------
425 !---------------------------------------------------------------------------------------------------
426 pure function real__(self)
427 
428  real(preal) :: real__
429  class(quaternion), intent(in) :: self
430 
431  real__ = self%w
432 
433 end function real__
434 
435 
436 !---------------------------------------------------------------------------------------------------
438 !---------------------------------------------------------------------------------------------------
439 pure function aimag__(self)
440 
441  real(preal), dimension(3) :: aimag__
442  class(quaternion), intent(in) :: self
443 
444  aimag__ = [self%x,self%y,self%z]
445 
446 end function aimag__
447 
448 
449 !---------------------------------------------------------------------------------------------------
451 !---------------------------------------------------------------------------------------------------
452 type(quaternion) elemental pure function inverse(self)
453 
454  class(quaternion), intent(in) :: self
455 
456  inverse = conjg(self)/abs(self)**2.0_preal
457 
458 end function inverse
459 
460 
461 !--------------------------------------------------------------------------------------------------
463 !--------------------------------------------------------------------------------------------------
464 subroutine unittest
465 
466  real(pReal), dimension(4) :: qu
467  type(quaternion) :: q, q_2
468 
469  call random_number(qu)
470  qu = (qu-0.5_preal) * 2.0_preal
471  q = quaternion(qu)
472 
473  q_2= qu
474  if(any(dneq(q%asArray(),q_2%asArray()))) call io_error(0,ext_msg='assign_vec__')
475 
476  q_2 = q + q
477  if(any(dneq(q_2%asArray(),2.0_preal*qu))) call io_error(0,ext_msg='add__')
478 
479  q_2 = q - q
480  if(any(dneq0(q_2%asArray()))) call io_error(0,ext_msg='sub__')
481 
482  q_2 = q * 5.0_preal
483  if(any(dneq(q_2%asArray(),5.0_preal*qu))) call io_error(0,ext_msg='mul__')
484 
485  q_2 = q / 0.5_preal
486  if(any(dneq(q_2%asArray(),2.0_preal*qu))) call io_error(0,ext_msg='div__')
487 
488  q_2 = q * 0.3_preal
489  if(dneq0(abs(q)) .and. q_2 == q) call io_error(0,ext_msg='eq__')
490 
491  q_2 = q
492  if(q_2 /= q) call io_error(0,ext_msg='neq__')
493 
494  if(dneq(abs(q),norm2(qu))) call io_error(0,ext_msg='abs__')
495  if(dneq(abs(q)**2.0_preal, real(q*q%conjg()),1.0e-14_preal)) &
496  call io_error(0,ext_msg='abs__/*conjg')
497 
498  if(any(dneq(q%asArray(),qu))) call io_error(0,ext_msg='eq__')
499  if(dneq(q%real(), qu(1))) call io_error(0,ext_msg='real()')
500  if(any(dneq(q%aimag(), qu(2:4)))) call io_error(0,ext_msg='aimag()')
501 
502  q_2 = q%homomorphed()
503  if(q /= q_2* (-1.0_preal)) call io_error(0,ext_msg='homomorphed')
504  if(dneq(q_2%real(), qu(1)* (-1.0_preal))) call io_error(0,ext_msg='homomorphed/real')
505  if(any(dneq(q_2%aimag(),qu(2:4)*(-1.0_preal)))) call io_error(0,ext_msg='homomorphed/aimag')
506 
507  q_2 = conjg(q)
508  if(dneq(abs(q),abs(q_2))) call io_error(0,ext_msg='conjg/abs')
509  if(q /= conjg(q_2)) call io_error(0,ext_msg='conjg/involution')
510  if(dneq(q_2%real(), q%real())) call io_error(0,ext_msg='conjg/real')
511  if(any(dneq(q_2%aimag(),q%aimag()*(-1.0_preal)))) call io_error(0,ext_msg='conjg/aimag')
512 
513  if(abs(q) > 0.0_preal) then
514  q_2 = q * q%inverse()
515  if( dneq(real(q_2), 1.0_preal,1.0e-15_preal)) call io_error(0,ext_msg='inverse/real')
516  if(any(dneq0(aimag(q_2), 1.0e-15_preal))) call io_error(0,ext_msg='inverse/aimag')
517 
518  q_2 = q/abs(q)
519  q_2 = conjg(q_2) - inverse(q_2)
520  if(any(dneq0(q_2%asArray(),1.0e-15_preal))) call io_error(0,ext_msg='inverse/conjg')
521  endif
522  if(dneq(dot_product(qu,qu),dot_product(q,q))) call io_error(0,ext_msg='dot_product')
523 
524 
525 
526 
527 
528 
529 
530 
531 end subroutine unittest
532 
533 
534 end module quaternions
quaternions::dot_product
Definition: quaternions.f90:79
quaternions::p
real(preal), parameter, public p
parameter for orientation conversion.
Definition: quaternions.f90:19
quaternions::mul_scal__
type(quaternion) elemental pure function mul_scal__(self, scal)
multiply with a scalar
Definition: quaternions.f90:237
quaternions::exp
Definition: quaternions.f90:87
quaternions::eq__
logical elemental pure function eq__(self, other)
test equality
Definition: quaternions.f90:275
quaternions::abs__
real(preal) elemental pure function abs__(self)
return norm
Definition: quaternions.f90:366
quaternions::log__
type(quaternion) elemental pure function log__(a)
take logarithm
Definition: quaternions.f90:346
quaternions::pos__
type(quaternion) elemental pure function pos__(self)
return (unary positive operator)
Definition: quaternions.f90:185
quaternions::unittest
subroutine unittest
check correctness of some quaternions functions
Definition: quaternions.f90:465
quaternions::div_scal__
type(quaternion) elemental pure function div_scal__(self, scal)
divide by a scalar
Definition: quaternions.f90:262
quaternions::mul_quat__
type(quaternion) elemental pure function mul_quat__(self, other)
multiply with a quaternion
Definition: quaternions.f90:222
quaternions::inverse
type(quaternion) elemental pure function inverse(self)
inverse
Definition: quaternions.f90:453
quaternions::homomorphed
type(quaternion) elemental pure function homomorphed(self)
homomorph
Definition: quaternions.f90:402
prec
setting precision for real and int type
Definition: prec.f90:13
quaternions::quaternion
Definition: quaternions.f90:21
quaternions::conjg__
type(quaternion) elemental pure function conjg__(self)
take conjugate complex
Definition: quaternions.f90:390
quaternions::quaternions_init
subroutine, public quaternions_init
do self test
Definition: quaternions.f90:117
quaternions::add__
type(quaternion) elemental pure function add__(self, other)
add a quaternion
Definition: quaternions.f90:172
quaternions::sub__
type(quaternion) elemental pure function sub__(self, other)
subtract a quaternion
Definition: quaternions.f90:197
quaternions::conjg
Definition: quaternions.f90:83
quaternions::aimag
Definition: quaternions.f90:99
quaternions::abs
Definition: quaternions.f90:75
io
input/output functions, partly depending on chosen solver
Definition: IO.f90:12
quaternions::assign_quat__
elemental pure subroutine assign_quat__(self, other)
assign a quaternion
Definition: quaternions.f90:143
quaternions::aimag__
pure real(preal) function, dimension(3) aimag__(self)
imaginary part (3-vector)
Definition: quaternions.f90:440
prec::preal
integer, parameter preal
number with 15 significant digits, up to 1e+-307 (typically 64 bit)
Definition: prec.f90:20
quaternions::neq__
logical elemental pure function neq__(self, other)
test inequality
Definition: quaternions.f90:288
quaternions::exp__
type(quaternion) elemental pure function exp__(a)
take exponential
Definition: quaternions.f90:326
quaternions
general quaternion math, not limited to unit quaternions
Definition: quaternions.f90:12
quaternions::real
Definition: quaternions.f90:95
quaternions::pow_quat__
type(quaternion) elemental pure function pow_quat__(self, expon)
raise to the power of a quaternion
Definition: quaternions.f90:300
quaternions::real__
pure real(preal) function real__(self)
real part (scalar)
Definition: quaternions.f90:427
quaternions::asarray
pure real(preal) function, dimension(4) asarray(self)
return as plain array
Definition: quaternions.f90:414
io::unittest
subroutine unittest
check correctness of some IO functions
Definition: IO.f90:662
quaternions::log
Definition: quaternions.f90:91
quaternions::init__
type(quaternion) pure function init__(array)
construct a quaternion from a 4-vector
Definition: quaternions.f90:128
quaternions::assign_vec__
pure subroutine assign_vec__(self, other)
assign a 4-vector
Definition: quaternions.f90:156
quaternions::neg__
type(quaternion) elemental pure function neg__(self)
negate (unary negative operator)
Definition: quaternions.f90:210
quaternions::dot_product__
real(preal) elemental pure function dot_product__(a, b)
calculate dot product
Definition: quaternions.f90:378
quaternions::pow_scal__
type(quaternion) elemental pure function pow_scal__(self, expon)
raise to the power of a scalar
Definition: quaternions.f90:313
quaternions::div_quat__
type(quaternion) elemental pure function div_quat__(self, other)
divide by a quaternion
Definition: quaternions.f90:250