2018-12-08 12:32:55 +05:30
|
|
|
! ###################################################################
|
|
|
|
! Copyright (c) 2013-2015, Marc De Graef/Carnegie Mellon University
|
2019-02-01 13:23:57 +05:30
|
|
|
! Modified 2017-2019, Martin Diehl/Max-Planck-Institut für Eisenforschung GmbH
|
2018-12-08 12:32:55 +05:30
|
|
|
! All rights reserved.
|
|
|
|
!
|
2019-05-28 12:57:52 +05:30
|
|
|
! Redistribution and use in source and binary forms, with or without modification, are
|
2018-12-08 12:32:55 +05:30
|
|
|
! permitted provided that the following conditions are met:
|
|
|
|
!
|
2019-05-28 12:57:52 +05:30
|
|
|
! - Redistributions of source code must retain the above copyright notice, this list
|
2018-12-08 12:32:55 +05:30
|
|
|
! of conditions and the following disclaimer.
|
2019-05-28 12:57:52 +05:30
|
|
|
! - Redistributions in binary form must reproduce the above copyright notice, this
|
|
|
|
! list of conditions and the following disclaimer in the documentation and/or
|
2018-12-08 12:32:55 +05:30
|
|
|
! other materials provided with the distribution.
|
2019-05-28 12:57:52 +05:30
|
|
|
! - Neither the names of Marc De Graef, Carnegie Mellon University nor the names
|
|
|
|
! of its contributors may be used to endorse or promote products derived from
|
2018-12-08 12:32:55 +05:30
|
|
|
! this software without specific prior written permission.
|
|
|
|
!
|
2019-05-28 12:57:52 +05:30
|
|
|
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
|
|
! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
|
|
! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
2018-12-08 12:32:55 +05:30
|
|
|
! USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
! ###################################################################
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
|
|
|
!> @author Marc De Graef, Carnegie Mellon University
|
|
|
|
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
|
|
|
|
!> @brief general quaternion math, not limited to unit quaternions
|
2020-01-11 07:38:39 +05:30
|
|
|
!> @details w is the real part, (x, y, z) are the imaginary parts.
|
|
|
|
!> @details https://users.aalto.fi/~ssarkka/pub/quat.pdf
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2018-12-08 12:32:55 +05:30
|
|
|
module quaternions
|
2019-05-28 12:57:52 +05:30
|
|
|
use prec
|
2019-09-23 12:41:45 +05:30
|
|
|
use IO
|
2019-05-28 12:57:52 +05:30
|
|
|
|
|
|
|
implicit none
|
|
|
|
public
|
|
|
|
|
|
|
|
real(pReal), parameter, public :: P = -1.0_pReal !< parameter for orientation conversion.
|
|
|
|
|
|
|
|
type, public :: quaternion
|
2019-09-20 21:06:16 +05:30
|
|
|
real(pReal), private :: w = 0.0_pReal
|
|
|
|
real(pReal), private :: x = 0.0_pReal
|
|
|
|
real(pReal), private :: y = 0.0_pReal
|
|
|
|
real(pReal), private :: z = 0.0_pReal
|
2019-05-28 12:57:52 +05:30
|
|
|
|
|
|
|
|
|
|
|
contains
|
|
|
|
procedure, private :: add__
|
|
|
|
procedure, private :: pos__
|
|
|
|
generic, public :: operator(+) => add__,pos__
|
|
|
|
|
|
|
|
procedure, private :: sub__
|
|
|
|
procedure, private :: neg__
|
|
|
|
generic, public :: operator(-) => sub__,neg__
|
|
|
|
|
|
|
|
procedure, private :: mul_quat__
|
|
|
|
procedure, private :: mul_scal__
|
|
|
|
generic, public :: operator(*) => mul_quat__, mul_scal__
|
|
|
|
|
|
|
|
procedure, private :: div_quat__
|
|
|
|
procedure, private :: div_scal__
|
|
|
|
generic, public :: operator(/) => div_quat__, div_scal__
|
|
|
|
|
|
|
|
procedure, private :: eq__
|
|
|
|
generic, public :: operator(==) => eq__
|
|
|
|
|
|
|
|
procedure, private :: neq__
|
|
|
|
generic, public :: operator(/=) => neq__
|
|
|
|
|
|
|
|
procedure, private :: pow_quat__
|
|
|
|
procedure, private :: pow_scal__
|
|
|
|
generic, public :: operator(**) => pow_quat__, pow_scal__
|
|
|
|
|
|
|
|
procedure, public :: abs__
|
|
|
|
procedure, public :: dot_product__
|
|
|
|
procedure, public :: conjg__
|
|
|
|
procedure, public :: exp__
|
|
|
|
procedure, public :: log__
|
|
|
|
|
|
|
|
procedure, public :: homomorphed => quat_homomorphed
|
2019-09-20 21:06:16 +05:30
|
|
|
procedure, public :: asArray
|
|
|
|
procedure, public :: real => real__
|
|
|
|
procedure, public :: aimag => aimag__
|
2019-05-28 12:57:52 +05:30
|
|
|
|
|
|
|
end type
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
interface assignment (=)
|
|
|
|
module procedure assign_quat__
|
|
|
|
module procedure assign_vec__
|
|
|
|
end interface assignment (=)
|
|
|
|
|
|
|
|
interface quaternion
|
|
|
|
module procedure init__
|
|
|
|
end interface quaternion
|
|
|
|
|
|
|
|
interface abs
|
|
|
|
procedure abs__
|
|
|
|
end interface abs
|
|
|
|
|
|
|
|
interface dot_product
|
|
|
|
procedure dot_product__
|
|
|
|
end interface dot_product
|
|
|
|
|
|
|
|
interface conjg
|
|
|
|
module procedure conjg__
|
|
|
|
end interface conjg
|
|
|
|
|
|
|
|
interface exp
|
|
|
|
module procedure exp__
|
|
|
|
end interface exp
|
|
|
|
|
|
|
|
interface log
|
|
|
|
module procedure log__
|
|
|
|
end interface log
|
2020-01-11 07:38:39 +05:30
|
|
|
|
|
|
|
interface real
|
|
|
|
module procedure real__
|
|
|
|
end interface real
|
|
|
|
|
|
|
|
interface aimag
|
|
|
|
module procedure aimag__
|
|
|
|
end interface aimag
|
2019-09-23 00:40:39 +05:30
|
|
|
|
|
|
|
private :: &
|
|
|
|
unitTest
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
contains
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
!--------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> @brief do self test
|
2019-09-23 00:40:39 +05:30
|
|
|
!--------------------------------------------------------------------------------------------------
|
2019-09-23 18:07:36 +05:30
|
|
|
subroutine quaternions_init
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2020-01-11 07:38:39 +05:30
|
|
|
write(6,'(/,a)') ' <<<+- quaternions init -+>>>'; flush(6)
|
2019-09-23 00:40:39 +05:30
|
|
|
call unitTest
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
end subroutine quaternions_init
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> construct a quaternion from a 4-vector
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2018-12-08 12:32:55 +05:30
|
|
|
type(quaternion) pure function init__(array)
|
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
real(pReal), intent(in), dimension(4) :: array
|
|
|
|
|
2020-01-10 22:37:30 +05:30
|
|
|
init__%w = array(1)
|
|
|
|
init__%x = array(2)
|
|
|
|
init__%y = array(3)
|
|
|
|
init__%z = array(4)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function init__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> assign a quaternion
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
elemental pure subroutine assign_quat__(self,other)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
type(quaternion), intent(out) :: self
|
|
|
|
type(quaternion), intent(in) :: other
|
|
|
|
|
2020-01-10 22:37:30 +05:30
|
|
|
self = [other%w,other%x,other%y,other%z]
|
|
|
|
|
2018-12-08 12:32:55 +05:30
|
|
|
end subroutine assign_quat__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> assign a 4-vector
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2018-12-08 12:32:55 +05:30
|
|
|
pure subroutine assign_vec__(self,other)
|
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
type(quaternion), intent(out) :: self
|
|
|
|
real(pReal), intent(in), dimension(4) :: other
|
|
|
|
|
|
|
|
self%w = other(1)
|
|
|
|
self%x = other(2)
|
|
|
|
self%y = other(3)
|
|
|
|
self%z = other(4)
|
|
|
|
|
2018-12-08 12:32:55 +05:30
|
|
|
end subroutine assign_vec__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> add a quaternion
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function add__(self,other)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self,other
|
|
|
|
|
2020-01-11 08:28:12 +05:30
|
|
|
add__ = [ self%w, self%x, self%y ,self%z] &
|
|
|
|
+ [other%w, other%x, other%y,other%z]
|
2020-01-10 22:37:30 +05:30
|
|
|
|
2018-12-08 12:32:55 +05:30
|
|
|
end function add__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> return (unary positive operator)
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function pos__(self)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
|
|
|
|
2020-01-11 08:28:12 +05:30
|
|
|
pos__ = self * (+1.0_pReal)
|
2020-01-10 22:37:30 +05:30
|
|
|
|
2018-12-08 12:32:55 +05:30
|
|
|
end function pos__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> subtract a quaternion
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function sub__(self,other)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self,other
|
|
|
|
|
2020-01-11 08:28:12 +05:30
|
|
|
sub__ = [ self%w, self%x, self%y ,self%z] &
|
|
|
|
- [other%w, other%x, other%y,other%z]
|
2020-01-10 22:37:30 +05:30
|
|
|
|
2018-12-08 12:32:55 +05:30
|
|
|
end function sub__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> negate (unary negative operator)
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function neg__(self)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
|
|
|
|
2020-01-11 08:28:12 +05:30
|
|
|
neg__ = self * (-1.0_pReal)
|
2020-01-10 22:37:30 +05:30
|
|
|
|
2018-12-08 12:32:55 +05:30
|
|
|
end function neg__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> multiply with a quaternion
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function mul_quat__(self,other)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self, other
|
|
|
|
|
|
|
|
mul_quat__%w = self%w*other%w - self%x*other%x - self%y*other%y - self%z*other%z
|
|
|
|
mul_quat__%x = self%w*other%x + self%x*other%w + P * (self%y*other%z - self%z*other%y)
|
|
|
|
mul_quat__%y = self%w*other%y + self%y*other%w + P * (self%z*other%x - self%x*other%z)
|
|
|
|
mul_quat__%z = self%w*other%z + self%z*other%w + P * (self%x*other%y - self%y*other%x)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function mul_quat__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> multiply with a scalar
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function mul_scal__(self,scal)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
|
|
|
real(pReal), intent(in) :: scal
|
|
|
|
|
2020-01-10 22:37:30 +05:30
|
|
|
mul_scal__ = [self%w,self%x,self%y,self%z]*scal
|
|
|
|
|
2018-12-08 12:32:55 +05:30
|
|
|
end function mul_scal__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> divide by a quaternion
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function div_quat__(self,other)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self, other
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
div_quat__ = self * (conjg(other)/(abs(other)**2.0_pReal))
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function div_quat__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> divide by a scalar
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function div_scal__(self,scal)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
|
|
|
real(pReal), intent(in) :: scal
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
div_scal__ = [self%w,self%x,self%y,self%z]/scal
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function div_scal__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> test equality
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
logical elemental pure function eq__(self,other)
|
2019-02-01 13:23:57 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self,other
|
|
|
|
|
|
|
|
eq__ = all(dEq([ self%w, self%x, self%y, self%z], &
|
|
|
|
[other%w,other%x,other%y,other%z]))
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function eq__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> test inequality
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
logical elemental pure function neq__(self,other)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self,other
|
|
|
|
|
|
|
|
neq__ = .not. self%eq__(other)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function neq__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> raise to the power of a quaternion
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
type(quaternion) elemental pure function pow_quat__(self,expon)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
2020-01-11 07:38:39 +05:30
|
|
|
type(quaternion), intent(in) :: expon
|
2019-05-28 12:57:52 +05:30
|
|
|
|
2020-01-11 07:38:39 +05:30
|
|
|
pow_quat__ = exp(log(self)*expon)
|
2019-05-28 12:57:52 +05:30
|
|
|
|
2020-01-11 07:38:39 +05:30
|
|
|
end function pow_quat__
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> raise to the power of a scalar
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
type(quaternion) elemental pure function pow_scal__(self,expon)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
2020-01-11 08:28:12 +05:30
|
|
|
real(pReal), intent(in) :: expon
|
2019-05-28 12:57:52 +05:30
|
|
|
|
2020-01-11 07:38:39 +05:30
|
|
|
pow_scal__ = exp(log(self)*expon)
|
2019-05-28 12:57:52 +05:30
|
|
|
|
2020-01-11 07:38:39 +05:30
|
|
|
end function pow_scal__
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> take exponential
|
2018-12-08 12:32:55 +05:30
|
|
|
!> ToDo: Lacks any check for invalid operations
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function exp__(self)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
|
|
|
real(pReal) :: absImag
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2020-01-11 07:38:39 +05:30
|
|
|
absImag = norm2(aimag(self))
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
exp__ = exp(self%w) * [ cos(absImag), &
|
|
|
|
self%x/absImag * sin(absImag), &
|
|
|
|
self%y/absImag * sin(absImag), &
|
|
|
|
self%z/absImag * sin(absImag)]
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function exp__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> take logarithm
|
2018-12-08 12:32:55 +05:30
|
|
|
!> ToDo: Lacks any check for invalid operations
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function log__(self)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
|
|
|
real(pReal) :: absImag
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2020-01-11 07:38:39 +05:30
|
|
|
absImag = norm2(aimag(self))
|
2019-05-28 12:57:52 +05:30
|
|
|
|
|
|
|
log__ = [log(abs(self)), &
|
|
|
|
self%x/absImag * acos(self%w/abs(self)), &
|
|
|
|
self%y/absImag * acos(self%w/abs(self)), &
|
|
|
|
self%z/absImag * acos(self%w/abs(self))]
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function log__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> return norm
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
real(pReal) elemental pure function abs__(a)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: a
|
|
|
|
|
|
|
|
abs__ = norm2([a%w,a%x,a%y,a%z])
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function abs__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> calculate dot product
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
real(pReal) elemental pure function dot_product__(a,b)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: a,b
|
|
|
|
|
|
|
|
dot_product__ = a%w*b%w + a%x*b%x + a%y*b%y + a%z*b%z
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function dot_product__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> take conjugate complex
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function conjg__(a)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-05-28 12:57:52 +05:30
|
|
|
class(quaternion), intent(in) :: a
|
|
|
|
|
2020-01-10 22:37:30 +05:30
|
|
|
conjg__ = [a%w, -a%x, -a%y, -a%z]
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function conjg__
|
|
|
|
|
|
|
|
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> homomorph
|
2019-02-01 14:31:54 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
2019-09-20 21:06:16 +05:30
|
|
|
type(quaternion) elemental pure function quat_homomorphed(self)
|
2018-12-08 12:32:55 +05:30
|
|
|
|
2019-09-20 21:06:16 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
2019-05-28 12:57:52 +05:30
|
|
|
|
2020-01-11 08:28:12 +05:30
|
|
|
quat_homomorphed = - self
|
2018-12-08 12:32:55 +05:30
|
|
|
|
|
|
|
end function quat_homomorphed
|
|
|
|
|
2019-09-20 21:06:16 +05:30
|
|
|
|
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> return as plain array
|
2019-09-20 21:06:16 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
|
|
|
pure function asArray(self)
|
|
|
|
|
|
|
|
real(pReal), dimension(4) :: asArray
|
|
|
|
class(quaternion), intent(in) :: self
|
|
|
|
|
|
|
|
asArray = [self%w,self%x,self%y,self%z]
|
|
|
|
|
|
|
|
end function asArray
|
|
|
|
|
|
|
|
|
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> real part (scalar)
|
2019-09-20 21:06:16 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
|
|
|
pure function real__(self)
|
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
real(pReal) :: real__
|
2019-09-20 21:06:16 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
real__ = self%w
|
2019-09-20 21:06:16 +05:30
|
|
|
|
|
|
|
end function real__
|
|
|
|
|
|
|
|
|
|
|
|
!---------------------------------------------------------------------------------------------------
|
2020-01-11 07:38:39 +05:30
|
|
|
!> imaginary part (3-vector)
|
2019-09-20 21:06:16 +05:30
|
|
|
!---------------------------------------------------------------------------------------------------
|
|
|
|
pure function aimag__(self)
|
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
real(pReal), dimension(3) :: aimag__
|
2019-09-20 21:06:16 +05:30
|
|
|
class(quaternion), intent(in) :: self
|
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
aimag__ = [self%x,self%y,self%z]
|
2019-09-20 21:06:16 +05:30
|
|
|
|
|
|
|
end function aimag__
|
|
|
|
|
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
!> @brief check correctness of (some) quaternions functions
|
|
|
|
!--------------------------------------------------------------------------------------------------
|
|
|
|
subroutine unitTest
|
|
|
|
|
|
|
|
real(pReal), dimension(4) :: qu
|
|
|
|
type(quaternion) :: q, q_2
|
2019-09-23 18:07:36 +05:30
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
call random_number(qu)
|
2020-01-11 07:41:45 +05:30
|
|
|
qu = (qu-0.5_pReal) * 2.0_pReal
|
2020-01-11 08:20:17 +05:30
|
|
|
q = quaternion(qu)
|
|
|
|
|
|
|
|
q_2= qu
|
|
|
|
if(any(dNeq(q%asArray(),q_2%asArray()))) call IO_error(401,ext_msg='assign_vec__')
|
2020-01-11 07:38:39 +05:30
|
|
|
|
2019-09-23 10:38:19 +05:30
|
|
|
q_2 = q + q
|
2019-09-23 18:07:36 +05:30
|
|
|
if(any(dNeq(q_2%asArray(),2.0_pReal*qu))) call IO_error(401,ext_msg='add__')
|
2020-01-11 07:38:39 +05:30
|
|
|
|
2019-09-23 10:38:19 +05:30
|
|
|
q_2 = q - q
|
2019-09-23 18:07:36 +05:30
|
|
|
if(any(dNeq0(q_2%asArray()))) call IO_error(401,ext_msg='sub__')
|
2020-01-11 07:38:39 +05:30
|
|
|
|
2020-01-10 22:37:30 +05:30
|
|
|
q_2 = q * 5.0_pReal
|
2019-09-23 18:07:36 +05:30
|
|
|
if(any(dNeq(q_2%asArray(),5.0_pReal*qu))) call IO_error(401,ext_msg='mul__')
|
2020-01-11 07:38:39 +05:30
|
|
|
|
2020-01-10 22:37:30 +05:30
|
|
|
q_2 = q / 0.5_pReal
|
2019-09-23 18:07:36 +05:30
|
|
|
if(any(dNeq(q_2%asArray(),2.0_pReal*qu))) call IO_error(401,ext_msg='div__')
|
2020-01-11 07:38:39 +05:30
|
|
|
|
2020-01-11 08:20:17 +05:30
|
|
|
q_2 = q * 0.3_pReal
|
|
|
|
if(dNeq0(abs(q)) .and. q_2 == q) call IO_error(401,ext_msg='eq__')
|
|
|
|
|
2019-09-23 10:38:19 +05:30
|
|
|
q_2 = q
|
2020-01-11 08:20:17 +05:30
|
|
|
if(q_2 /= q) call IO_error(401,ext_msg='neq__')
|
|
|
|
|
|
|
|
if(dNeq(abs(q),norm2(qu))) call IO_error(401,ext_msg='abs__')
|
2019-09-23 00:40:39 +05:30
|
|
|
|
2019-09-23 18:07:36 +05:30
|
|
|
if(any(dNeq(q%asArray(),qu))) call IO_error(401,ext_msg='eq__')
|
|
|
|
if(dNeq(q%real(), qu(1))) call IO_error(401,ext_msg='real()')
|
|
|
|
if(any(dNeq(q%aimag(), qu(2:4)))) call IO_error(401,ext_msg='aimag()')
|
2020-01-11 07:38:39 +05:30
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
q_2 = q%homomorphed()
|
2019-09-23 18:07:36 +05:30
|
|
|
if(q /= q_2* (-1.0_pReal)) call IO_error(401,ext_msg='homomorphed')
|
|
|
|
if(dNeq(q_2%real(), qu(1)* (-1.0_pReal))) call IO_error(401,ext_msg='homomorphed/real')
|
|
|
|
if(any(dNeq(q_2%aimag(),qu(2:4)*(-1.0_pReal)))) call IO_error(401,ext_msg='homomorphed/aimag')
|
2020-01-11 07:38:39 +05:30
|
|
|
|
2019-09-23 00:40:39 +05:30
|
|
|
q_2 = conjg(q)
|
2019-09-23 18:07:36 +05:30
|
|
|
if(dNeq(q_2%real(), q%real())) call IO_error(401,ext_msg='conjg/real')
|
|
|
|
if(any(dNeq(q_2%aimag(),q%aimag()*(-1.0_pReal)))) call IO_error(401,ext_msg='conjg/aimag')
|
2020-01-11 08:20:17 +05:30
|
|
|
|
|
|
|
if (norm2(aimag(q)) * abs(real(q)) > 0.0_pReal) then
|
|
|
|
if (dNeq0(abs(q-exp(log(q))),1.0e-12_pReal)) call IO_error(401,ext_msg='exp/log')
|
|
|
|
if (dNeq0(abs(q-log(exp(q))),1.0e-12_pReal)) call IO_error(401,ext_msg='log/exp')
|
|
|
|
endif
|
2019-09-23 00:40:39 +05:30
|
|
|
|
|
|
|
end subroutine unitTest
|
|
|
|
|
|
|
|
|
2018-12-08 12:32:55 +05:30
|
|
|
end module quaternions
|