Merge branch 'development' into no-crystallite_subF
This commit is contained in:
commit
2cbcbf6552
|
@ -21,6 +21,9 @@ class NiceDumper(yaml.SafeDumper):
|
||||||
return self.represent_data(dict(data)) if isinstance(data, dict) and type(data) != dict else \
|
return self.represent_data(dict(data)) if isinstance(data, dict) and type(data) != dict else \
|
||||||
super().represent_data(data)
|
super().represent_data(data)
|
||||||
|
|
||||||
|
def ignore_aliases(self, data):
|
||||||
|
"""No references."""
|
||||||
|
return True
|
||||||
|
|
||||||
class Config(dict):
|
class Config(dict):
|
||||||
"""YAML-based configuration."""
|
"""YAML-based configuration."""
|
||||||
|
|
|
@ -9,6 +9,16 @@ from . import Orientation
|
||||||
class ConfigMaterial(Config):
|
class ConfigMaterial(Config):
|
||||||
"""Material configuration."""
|
"""Material configuration."""
|
||||||
|
|
||||||
|
_defaults = {'material': [],
|
||||||
|
'homogenization': {},
|
||||||
|
'phase': {}}
|
||||||
|
|
||||||
|
def __init__(self,d={}):
|
||||||
|
"""Initialize object with default dictionary keys."""
|
||||||
|
super().__init__(d)
|
||||||
|
for k,v in self._defaults.items():
|
||||||
|
if k not in self: self[k] = v
|
||||||
|
|
||||||
def save(self,fname='material.yaml',**kwargs):
|
def save(self,fname='material.yaml',**kwargs):
|
||||||
"""
|
"""
|
||||||
Save to yaml file.
|
Save to yaml file.
|
||||||
|
@ -75,6 +85,8 @@ class ConfigMaterial(Config):
|
||||||
fraction: 1.0
|
fraction: 1.0
|
||||||
phase: Steel
|
phase: Steel
|
||||||
homogenization: SX
|
homogenization: SX
|
||||||
|
homogenization: {}
|
||||||
|
phase: {}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
constituents_ = {k:table.get(v) for k,v in constituents.items()}
|
constituents_ = {k:table.get(v) for k,v in constituents.items()}
|
||||||
|
@ -261,6 +273,8 @@ class ConfigMaterial(Config):
|
||||||
fraction: 1.0
|
fraction: 1.0
|
||||||
phase: Aluminum
|
phase: Aluminum
|
||||||
homogenization: SX
|
homogenization: SX
|
||||||
|
homogenization: {}
|
||||||
|
phase: {}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
length = -1
|
length = -1
|
||||||
|
@ -274,6 +288,7 @@ class ConfigMaterial(Config):
|
||||||
|
|
||||||
c = [{} for _ in range(length)] if constituents is None else \
|
c = [{} for _ in range(length)] if constituents is None else \
|
||||||
[{'constituents':u} for u in ConfigMaterial._constituents(**constituents)]
|
[{'constituents':u} for u in ConfigMaterial._constituents(**constituents)]
|
||||||
|
|
||||||
if len(c) == 1: c = [copy.deepcopy(c[0]) for _ in range(length)]
|
if len(c) == 1: c = [copy.deepcopy(c[0]) for _ in range(length)]
|
||||||
|
|
||||||
if length != 1 and length != len(c):
|
if length != 1 and length != len(c):
|
||||||
|
|
|
@ -226,9 +226,9 @@ class Orientation(Rotation):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return super().__eq__(other) \
|
return super().__eq__(other) \
|
||||||
and self.family == other.family \
|
and hasattr(other, 'family') and self.family == other.family \
|
||||||
and self.lattice == other.lattice \
|
and hasattr(other, 'lattice') and self.lattice == other.lattice \
|
||||||
and self.parameters == other.parameters
|
and hasattr(other, 'parameters') and self.parameters == other.parameters
|
||||||
|
|
||||||
|
|
||||||
def __matmul__(self,other):
|
def __matmul__(self,other):
|
||||||
|
|
|
@ -144,6 +144,11 @@ class Rotation:
|
||||||
return self.copy(rotation=Rotation(np.block([np.cos(pwr*phi),np.sin(pwr*phi)*p]))._standardize())
|
return self.copy(rotation=Rotation(np.block([np.cos(pwr*phi),np.sin(pwr*phi)*p]))._standardize())
|
||||||
|
|
||||||
|
|
||||||
|
def __mul__(self,other):
|
||||||
|
"""Standard multiplication is not implemented."""
|
||||||
|
raise NotImplementedError('Use "R@b", i.e. matmul, to apply rotation "R" to object "b"')
|
||||||
|
|
||||||
|
|
||||||
def __matmul__(self,other):
|
def __matmul__(self,other):
|
||||||
"""
|
"""
|
||||||
Rotation of vector, second or fourth order tensor, or rotation object.
|
Rotation of vector, second or fourth order tensor, or rotation object.
|
||||||
|
@ -199,8 +204,16 @@ class Rotation:
|
||||||
|
|
||||||
|
|
||||||
def append(self,other):
|
def append(self,other):
|
||||||
"""Extend rotation array along first dimension with other array."""
|
"""
|
||||||
return self.copy(rotation=np.vstack((self.quaternion,other.quaternion)))
|
Extend rotation array along first dimension with other array(s).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
other : Rotation or list of Rotations.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return self.copy(rotation=np.vstack(tuple(map(lambda x:x.quaternion,
|
||||||
|
[self]+other if isinstance(other,list) else [self,other]))))
|
||||||
|
|
||||||
|
|
||||||
def flatten(self,order = 'C'):
|
def flatten(self,order = 'C'):
|
||||||
|
@ -258,7 +271,7 @@ class Rotation:
|
||||||
"""Intermediate representation supporting quaternion averaging."""
|
"""Intermediate representation supporting quaternion averaging."""
|
||||||
return np.einsum('...i,...j',quat,quat)
|
return np.einsum('...i,...j',quat,quat)
|
||||||
|
|
||||||
if not weights:
|
if weights is None:
|
||||||
weights = np.ones(self.shape,dtype=float)
|
weights = np.ones(self.shape,dtype=float)
|
||||||
|
|
||||||
eig, vec = np.linalg.eig(np.sum(_M(self.quaternion) * weights[...,np.newaxis,np.newaxis],axis=-3) \
|
eig, vec = np.linalg.eig(np.sum(_M(self.quaternion) * weights[...,np.newaxis,np.newaxis],axis=-3) \
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
homogenization:
|
homogenization:
|
||||||
SX:
|
SX:
|
||||||
N_constituents: 2
|
N_constituents: 1
|
||||||
mech: {type: none}
|
mechanics: {type: none}
|
||||||
Taylor:
|
Taylor:
|
||||||
N_constituents: 2
|
N_constituents: 2
|
||||||
mech: {type: isostrain}
|
mechanics: {type: isostrain}
|
||||||
|
|
||||||
material:
|
material:
|
||||||
- constituents:
|
- constituents:
|
||||||
|
@ -34,11 +34,11 @@ material:
|
||||||
phase:
|
phase:
|
||||||
Aluminum:
|
Aluminum:
|
||||||
lattice: cF
|
lattice: cF
|
||||||
mech:
|
mechanics:
|
||||||
output: [F, P, F_e, F_p, L_p]
|
output: [F, P, F_e, F_p, L_p]
|
||||||
elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke}
|
elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke}
|
||||||
Steel:
|
Steel:
|
||||||
lattice: cI
|
lattice: cI
|
||||||
mech:
|
mechanics:
|
||||||
output: [F, P, F_e, F_p, L_p]
|
output: [F, P, F_e, F_p, L_p]
|
||||||
elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke}
|
elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke}
|
||||||
|
|
|
@ -800,6 +800,14 @@ class TestRotation:
|
||||||
print(f'append 2x {shape} --> {s.shape}')
|
print(f'append 2x {shape} --> {s.shape}')
|
||||||
assert s[0,...] == r[0,...] and s[-1,...] == p[-1,...]
|
assert s[0,...] == r[0,...] and s[-1,...] == p[-1,...]
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(3,3,2)])
|
||||||
|
def test_append_list(self,shape):
|
||||||
|
r = Rotation.from_random(shape=shape)
|
||||||
|
p = Rotation.from_random(shape=shape)
|
||||||
|
s = r.append([r,p])
|
||||||
|
print(f'append 3x {shape} --> {s.shape}')
|
||||||
|
assert s[0,...] == r[0,...] and s[-1,...] == p[-1,...]
|
||||||
|
|
||||||
@pytest.mark.parametrize('quat,standardized',[
|
@pytest.mark.parametrize('quat,standardized',[
|
||||||
([-1,0,0,0],[1,0,0,0]),
|
([-1,0,0,0],[1,0,0,0]),
|
||||||
([-0.5,-0.5,-0.5,-0.5],[0.5,0.5,0.5,0.5]),
|
([-0.5,-0.5,-0.5,-0.5],[0.5,0.5,0.5,0.5]),
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include "config.f90"
|
#include "config.f90"
|
||||||
#include "LAPACK_interface.f90"
|
#include "LAPACK_interface.f90"
|
||||||
#include "math.f90"
|
#include "math.f90"
|
||||||
#include "quaternions.f90"
|
|
||||||
#include "rotations.f90"
|
#include "rotations.f90"
|
||||||
#include "element.f90"
|
#include "element.f90"
|
||||||
#include "HDF5_utilities.f90"
|
#include "HDF5_utilities.f90"
|
||||||
|
|
|
@ -846,8 +846,8 @@ subroutine crystallite_init
|
||||||
el, & !< counter in element loop
|
el, & !< counter in element loop
|
||||||
cMax, & !< maximum number of integration point components
|
cMax, & !< maximum number of integration point components
|
||||||
iMax, & !< maximum number of integration points
|
iMax, & !< maximum number of integration points
|
||||||
eMax, & !< maximum number of elements
|
eMax !< maximum number of elements
|
||||||
so
|
|
||||||
|
|
||||||
class(tNode), pointer :: &
|
class(tNode), pointer :: &
|
||||||
num_crystallite, &
|
num_crystallite, &
|
||||||
|
@ -881,7 +881,6 @@ subroutine crystallite_init
|
||||||
allocate(crystallite_subdt(cMax,iMax,eMax),source=0.0_pReal)
|
allocate(crystallite_subdt(cMax,iMax,eMax),source=0.0_pReal)
|
||||||
allocate(crystallite_orientation(cMax,iMax,eMax))
|
allocate(crystallite_orientation(cMax,iMax,eMax))
|
||||||
|
|
||||||
|
|
||||||
num_crystallite => config_numerics%get('crystallite',defaultVal=emptyDict)
|
num_crystallite => config_numerics%get('crystallite',defaultVal=emptyDict)
|
||||||
|
|
||||||
num%subStepMinCryst = num_crystallite%get_asFloat ('subStepMin', defaultVal=1.0e-3_pReal)
|
num%subStepMinCryst = num_crystallite%get_asFloat ('subStepMin', defaultVal=1.0e-3_pReal)
|
||||||
|
|
|
@ -1014,6 +1014,7 @@ function integrateStateFPI(F_0,F,Delta_t,co,ip,el) result(broken)
|
||||||
|
|
||||||
enddo iteration
|
enddo iteration
|
||||||
|
|
||||||
|
|
||||||
contains
|
contains
|
||||||
|
|
||||||
!--------------------------------------------------------------------------------------------------
|
!--------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -1,534 +0,0 @@
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
|
|
||||||
!> @author Philip Eisenlohr, Michigan State University
|
|
||||||
!> @brief general quaternion math, not limited to unit quaternions
|
|
||||||
!> @details w is the real part, (x, y, z) are the imaginary parts.
|
|
||||||
!> @details https://en.wikipedia.org/wiki/Quaternion
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
module quaternions
|
|
||||||
use prec
|
|
||||||
|
|
||||||
implicit none
|
|
||||||
private
|
|
||||||
|
|
||||||
real(pReal), parameter, public :: P = -1.0_pReal !< parameter for orientation conversion.
|
|
||||||
|
|
||||||
type, public :: quaternion
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
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 => abs__
|
|
||||||
procedure, public :: conjg => conjg__
|
|
||||||
procedure, public :: real => real__
|
|
||||||
procedure, public :: aimag => aimag__
|
|
||||||
|
|
||||||
procedure, public :: homomorphed
|
|
||||||
procedure, public :: asArray
|
|
||||||
procedure, public :: inverse
|
|
||||||
|
|
||||||
end type
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
interface real
|
|
||||||
module procedure real__
|
|
||||||
end interface real
|
|
||||||
|
|
||||||
interface aimag
|
|
||||||
module procedure aimag__
|
|
||||||
end interface aimag
|
|
||||||
|
|
||||||
public :: &
|
|
||||||
quaternions_init, &
|
|
||||||
assignment(=), &
|
|
||||||
conjg, aimag, &
|
|
||||||
log, exp, &
|
|
||||||
abs, dot_product, &
|
|
||||||
inverse, &
|
|
||||||
real
|
|
||||||
|
|
||||||
contains
|
|
||||||
|
|
||||||
|
|
||||||
!--------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief Do self test.
|
|
||||||
!--------------------------------------------------------------------------------------------------
|
|
||||||
subroutine quaternions_init
|
|
||||||
|
|
||||||
print'(/,a)', ' <<<+- quaternions init -+>>>'; flush(6)
|
|
||||||
|
|
||||||
call selfTest
|
|
||||||
|
|
||||||
end subroutine quaternions_init
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief construct a quaternion from a 4-vector
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) pure function init__(array)
|
|
||||||
|
|
||||||
real(pReal), intent(in), dimension(4) :: array
|
|
||||||
|
|
||||||
init__%w = array(1)
|
|
||||||
init__%x = array(2)
|
|
||||||
init__%y = array(3)
|
|
||||||
init__%z = array(4)
|
|
||||||
|
|
||||||
end function init__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief assign a quaternion
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
elemental pure subroutine assign_quat__(self,other)
|
|
||||||
|
|
||||||
type(quaternion), intent(out) :: self
|
|
||||||
type(quaternion), intent(in) :: other
|
|
||||||
|
|
||||||
self = [other%w,other%x,other%y,other%z]
|
|
||||||
|
|
||||||
end subroutine assign_quat__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief assign a 4-vector
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
pure subroutine assign_vec__(self,other)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
end subroutine assign_vec__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief add a quaternion
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function add__(self,other)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self,other
|
|
||||||
|
|
||||||
add__ = [ self%w, self%x, self%y ,self%z] &
|
|
||||||
+ [other%w, other%x, other%y,other%z]
|
|
||||||
|
|
||||||
end function add__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief return (unary positive operator)
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function pos__(self)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
|
|
||||||
pos__ = self * (+1.0_pReal)
|
|
||||||
|
|
||||||
end function pos__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief subtract a quaternion
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function sub__(self,other)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self,other
|
|
||||||
|
|
||||||
sub__ = [ self%w, self%x, self%y ,self%z] &
|
|
||||||
- [other%w, other%x, other%y,other%z]
|
|
||||||
|
|
||||||
end function sub__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief negate (unary negative operator)
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function neg__(self)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
|
|
||||||
neg__ = self * (-1.0_pReal)
|
|
||||||
|
|
||||||
end function neg__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief multiply with a quaternion
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function mul_quat__(self,other)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
end function mul_quat__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief multiply with a scalar
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function mul_scal__(self,scal)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
real(pReal), intent(in) :: scal
|
|
||||||
|
|
||||||
mul_scal__ = [self%w,self%x,self%y,self%z]*scal
|
|
||||||
|
|
||||||
end function mul_scal__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief divide by a quaternion
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function div_quat__(self,other)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self, other
|
|
||||||
|
|
||||||
div_quat__ = self * (conjg(other)/(abs(other)**2.0_pReal))
|
|
||||||
|
|
||||||
end function div_quat__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief divide by a scalar
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function div_scal__(self,scal)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
real(pReal), intent(in) :: scal
|
|
||||||
|
|
||||||
div_scal__ = [self%w,self%x,self%y,self%z]/scal
|
|
||||||
|
|
||||||
end function div_scal__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief test equality
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
logical elemental pure function eq__(self,other)
|
|
||||||
|
|
||||||
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]))
|
|
||||||
|
|
||||||
end function eq__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief test inequality
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
logical elemental pure function neq__(self,other)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self,other
|
|
||||||
|
|
||||||
neq__ = .not. self%eq__(other)
|
|
||||||
|
|
||||||
end function neq__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief raise to the power of a quaternion
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function pow_quat__(self,expon)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
type(quaternion), intent(in) :: expon
|
|
||||||
|
|
||||||
pow_quat__ = exp(log(self)*expon)
|
|
||||||
|
|
||||||
end function pow_quat__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief raise to the power of a scalar
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function pow_scal__(self,expon)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
real(pReal), intent(in) :: expon
|
|
||||||
|
|
||||||
pow_scal__ = exp(log(self)*expon)
|
|
||||||
|
|
||||||
end function pow_scal__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief take exponential
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function exp__(a)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: a
|
|
||||||
real(pReal) :: absImag
|
|
||||||
|
|
||||||
absImag = norm2(aimag(a))
|
|
||||||
|
|
||||||
exp__ = merge(exp(a%w) * [ cos(absImag), &
|
|
||||||
a%x/absImag * sin(absImag), &
|
|
||||||
a%y/absImag * sin(absImag), &
|
|
||||||
a%z/absImag * sin(absImag)], &
|
|
||||||
IEEE_value(1.0_pReal,IEEE_SIGNALING_NAN), &
|
|
||||||
dNeq0(absImag))
|
|
||||||
|
|
||||||
end function exp__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief take logarithm
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function log__(a)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: a
|
|
||||||
real(pReal) :: absImag
|
|
||||||
|
|
||||||
absImag = norm2(aimag(a))
|
|
||||||
|
|
||||||
log__ = merge([log(abs(a)), &
|
|
||||||
a%x/absImag * acos(a%w/abs(a)), &
|
|
||||||
a%y/absImag * acos(a%w/abs(a)), &
|
|
||||||
a%z/absImag * acos(a%w/abs(a))], &
|
|
||||||
IEEE_value(1.0_pReal,IEEE_SIGNALING_NAN), &
|
|
||||||
dNeq0(absImag))
|
|
||||||
|
|
||||||
end function log__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief return norm
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
real(pReal) elemental pure function abs__(self)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
|
|
||||||
abs__ = norm2([self%w,self%x,self%y,self%z])
|
|
||||||
|
|
||||||
end function abs__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief calculate dot product
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
real(pReal) elemental pure function dot_product__(a,b)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: a,b
|
|
||||||
|
|
||||||
dot_product__ = a%w*b%w + a%x*b%x + a%y*b%y + a%z*b%z
|
|
||||||
|
|
||||||
end function dot_product__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief take conjugate complex
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function conjg__(self)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
|
|
||||||
conjg__ = [self%w,-self%x,-self%y,-self%z]
|
|
||||||
|
|
||||||
end function conjg__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief homomorph
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function homomorphed(self)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
|
|
||||||
homomorphed = - self
|
|
||||||
|
|
||||||
end function homomorphed
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief return as plain array
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief real part (scalar)
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
pure function real__(self)
|
|
||||||
|
|
||||||
real(pReal) :: real__
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
|
|
||||||
real__ = self%w
|
|
||||||
|
|
||||||
end function real__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief imaginary part (3-vector)
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
pure function aimag__(self)
|
|
||||||
|
|
||||||
real(pReal), dimension(3) :: aimag__
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
|
|
||||||
aimag__ = [self%x,self%y,self%z]
|
|
||||||
|
|
||||||
end function aimag__
|
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief inverse
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
|
||||||
type(quaternion) elemental pure function inverse(self)
|
|
||||||
|
|
||||||
class(quaternion), intent(in) :: self
|
|
||||||
|
|
||||||
inverse = conjg(self)/abs(self)**2.0_pReal
|
|
||||||
|
|
||||||
end function inverse
|
|
||||||
|
|
||||||
|
|
||||||
!--------------------------------------------------------------------------------------------------
|
|
||||||
!> @brief check correctness of some quaternions functions
|
|
||||||
!--------------------------------------------------------------------------------------------------
|
|
||||||
subroutine selfTest
|
|
||||||
|
|
||||||
real(pReal), dimension(4) :: qu
|
|
||||||
type(quaternion) :: q, q_2
|
|
||||||
|
|
||||||
if(dNeq(abs(P),1.0_pReal)) error stop 'P not in {-1,+1}'
|
|
||||||
|
|
||||||
call random_number(qu)
|
|
||||||
qu = (qu-0.5_pReal) * 2.0_pReal
|
|
||||||
q = quaternion(qu)
|
|
||||||
|
|
||||||
q_2= qu
|
|
||||||
if(any(dNeq(q%asArray(),q_2%asArray()))) error stop 'assign_vec__'
|
|
||||||
|
|
||||||
q_2 = q + q
|
|
||||||
if(any(dNeq(q_2%asArray(),2.0_pReal*qu))) error stop 'add__'
|
|
||||||
|
|
||||||
q_2 = q - q
|
|
||||||
if(any(dNeq0(q_2%asArray()))) error stop 'sub__'
|
|
||||||
|
|
||||||
q_2 = q * 5.0_pReal
|
|
||||||
if(any(dNeq(q_2%asArray(),5.0_pReal*qu))) error stop 'mul__'
|
|
||||||
|
|
||||||
q_2 = q / 0.5_pReal
|
|
||||||
if(any(dNeq(q_2%asArray(),2.0_pReal*qu))) error stop 'div__'
|
|
||||||
|
|
||||||
q_2 = q * 0.3_pReal
|
|
||||||
if(dNeq0(abs(q)) .and. q_2 == q) error stop 'eq__'
|
|
||||||
|
|
||||||
q_2 = q
|
|
||||||
if(q_2 /= q) error stop 'neq__'
|
|
||||||
|
|
||||||
if(dNeq(abs(q),norm2(qu))) error stop 'abs__'
|
|
||||||
if(dNeq(abs(q)**2.0_pReal, real(q*q%conjg()),1.0e-14_pReal)) &
|
|
||||||
error stop 'abs__/*conjg'
|
|
||||||
|
|
||||||
if(any(dNeq(q%asArray(),qu))) error stop 'eq__'
|
|
||||||
if(dNeq(q%real(), qu(1))) error stop 'real()'
|
|
||||||
if(any(dNeq(q%aimag(), qu(2:4)))) error stop 'aimag()'
|
|
||||||
|
|
||||||
q_2 = q%homomorphed()
|
|
||||||
if(q /= q_2* (-1.0_pReal)) error stop 'homomorphed'
|
|
||||||
if(dNeq(q_2%real(), qu(1)* (-1.0_pReal))) error stop 'homomorphed/real'
|
|
||||||
if(any(dNeq(q_2%aimag(),qu(2:4)*(-1.0_pReal)))) error stop 'homomorphed/aimag'
|
|
||||||
|
|
||||||
q_2 = conjg(q)
|
|
||||||
if(dNeq(abs(q),abs(q_2))) error stop 'conjg/abs'
|
|
||||||
if(q /= conjg(q_2)) error stop 'conjg/involution'
|
|
||||||
if(dNeq(q_2%real(), q%real())) error stop 'conjg/real'
|
|
||||||
if(any(dNeq(q_2%aimag(),q%aimag()*(-1.0_pReal)))) error stop 'conjg/aimag'
|
|
||||||
|
|
||||||
if(abs(q) > 0.0_pReal) then
|
|
||||||
q_2 = q * q%inverse()
|
|
||||||
if( dNeq(real(q_2), 1.0_pReal,1.0e-15_pReal)) error stop 'inverse/real'
|
|
||||||
if(any(dNeq0(aimag(q_2), 1.0e-15_pReal))) error stop 'inverse/aimag'
|
|
||||||
|
|
||||||
q_2 = q/abs(q)
|
|
||||||
q_2 = conjg(q_2) - inverse(q_2)
|
|
||||||
if(any(dNeq0(q_2%asArray(),1.0e-15_pReal))) error stop 'inverse/conjg'
|
|
||||||
endif
|
|
||||||
if(dNeq(dot_product(qu,qu),dot_product(q,q))) error stop 'dot_product'
|
|
||||||
|
|
||||||
#if !(defined(__GFORTRAN__) && __GNUC__ < 9)
|
|
||||||
if (norm2(aimag(q)) > 0.0_pReal) then
|
|
||||||
if (dNeq0(abs(q-exp(log(q))),1.0e-13_pReal)) error stop 'exp/log'
|
|
||||||
if (dNeq0(abs(q-log(exp(q))),1.0e-13_pReal)) error stop 'log/exp'
|
|
||||||
endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
end subroutine selfTest
|
|
||||||
|
|
||||||
|
|
||||||
end module quaternions
|
|
|
@ -47,16 +47,16 @@
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
module rotations
|
module rotations
|
||||||
use prec
|
|
||||||
use IO
|
use IO
|
||||||
use math
|
use math
|
||||||
use quaternions
|
|
||||||
|
|
||||||
implicit none
|
implicit none
|
||||||
private
|
private
|
||||||
|
|
||||||
|
real(pReal), parameter :: P = -1.0_pReal !< parameter for orientation conversion.
|
||||||
|
|
||||||
type, public :: rotation
|
type, public :: rotation
|
||||||
type(quaternion) :: q
|
real(pReal), dimension(4) :: q
|
||||||
contains
|
contains
|
||||||
procedure, public :: asQuaternion
|
procedure, public :: asQuaternion
|
||||||
procedure, public :: asEulers
|
procedure, public :: asEulers
|
||||||
|
@ -103,7 +103,6 @@ contains
|
||||||
!--------------------------------------------------------------------------------------------------
|
!--------------------------------------------------------------------------------------------------
|
||||||
subroutine rotations_init
|
subroutine rotations_init
|
||||||
|
|
||||||
call quaternions_init
|
|
||||||
print'(/,a)', ' <<<+- rotations init -+>>>'; flush(IO_STDOUT)
|
print'(/,a)', ' <<<+- rotations init -+>>>'; flush(IO_STDOUT)
|
||||||
|
|
||||||
print*, 'Rowenhorst et al., Modelling and Simulation in Materials Science and Engineering 23:083501, 2015'
|
print*, 'Rowenhorst et al., Modelling and Simulation in Materials Science and Engineering 23:083501, 2015'
|
||||||
|
@ -122,7 +121,7 @@ pure function asQuaternion(self)
|
||||||
class(rotation), intent(in) :: self
|
class(rotation), intent(in) :: self
|
||||||
real(pReal), dimension(4) :: asQuaternion
|
real(pReal), dimension(4) :: asQuaternion
|
||||||
|
|
||||||
asQuaternion = self%q%asArray()
|
asQuaternion = self%q
|
||||||
|
|
||||||
end function asQuaternion
|
end function asQuaternion
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
|
@ -131,7 +130,7 @@ pure function asEulers(self)
|
||||||
class(rotation), intent(in) :: self
|
class(rotation), intent(in) :: self
|
||||||
real(pReal), dimension(3) :: asEulers
|
real(pReal), dimension(3) :: asEulers
|
||||||
|
|
||||||
asEulers = qu2eu(self%q%asArray())
|
asEulers = qu2eu(self%q)
|
||||||
|
|
||||||
end function asEulers
|
end function asEulers
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
|
@ -140,7 +139,7 @@ pure function asAxisAngle(self)
|
||||||
class(rotation), intent(in) :: self
|
class(rotation), intent(in) :: self
|
||||||
real(pReal), dimension(4) :: asAxisAngle
|
real(pReal), dimension(4) :: asAxisAngle
|
||||||
|
|
||||||
asAxisAngle = qu2ax(self%q%asArray())
|
asAxisAngle = qu2ax(self%q)
|
||||||
|
|
||||||
end function asAxisAngle
|
end function asAxisAngle
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
|
@ -149,7 +148,7 @@ pure function asMatrix(self)
|
||||||
class(rotation), intent(in) :: self
|
class(rotation), intent(in) :: self
|
||||||
real(pReal), dimension(3,3) :: asMatrix
|
real(pReal), dimension(3,3) :: asMatrix
|
||||||
|
|
||||||
asMatrix = qu2om(self%q%asArray())
|
asMatrix = qu2om(self%q)
|
||||||
|
|
||||||
end function asMatrix
|
end function asMatrix
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
|
@ -158,7 +157,7 @@ pure function asRodrigues(self)
|
||||||
class(rotation), intent(in) :: self
|
class(rotation), intent(in) :: self
|
||||||
real(pReal), dimension(4) :: asRodrigues
|
real(pReal), dimension(4) :: asRodrigues
|
||||||
|
|
||||||
asRodrigues = qu2ro(self%q%asArray())
|
asRodrigues = qu2ro(self%q)
|
||||||
|
|
||||||
end function asRodrigues
|
end function asRodrigues
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
|
@ -167,7 +166,7 @@ pure function asHomochoric(self)
|
||||||
class(rotation), intent(in) :: self
|
class(rotation), intent(in) :: self
|
||||||
real(pReal), dimension(3) :: asHomochoric
|
real(pReal), dimension(3) :: asHomochoric
|
||||||
|
|
||||||
asHomochoric = qu2ho(self%q%asArray())
|
asHomochoric = qu2ho(self%q)
|
||||||
|
|
||||||
end function asHomochoric
|
end function asHomochoric
|
||||||
|
|
||||||
|
@ -259,7 +258,7 @@ pure elemental function rotRot__(self,R) result(rRot)
|
||||||
type(rotation) :: rRot
|
type(rotation) :: rRot
|
||||||
class(rotation), intent(in) :: self,R
|
class(rotation), intent(in) :: self,R
|
||||||
|
|
||||||
rRot = rotation(self%q*R%q)
|
rRot = rotation(multiply_quaternion(self%q,R%q))
|
||||||
call rRot%standardize()
|
call rRot%standardize()
|
||||||
|
|
||||||
end function rotRot__
|
end function rotRot__
|
||||||
|
@ -272,14 +271,14 @@ pure elemental subroutine standardize(self)
|
||||||
|
|
||||||
class(rotation), intent(inout) :: self
|
class(rotation), intent(inout) :: self
|
||||||
|
|
||||||
if (real(self%q) < 0.0_pReal) self%q = self%q%homomorphed()
|
if (self%q(1) < 0.0_pReal) self%q = - self%q
|
||||||
|
|
||||||
end subroutine standardize
|
end subroutine standardize
|
||||||
|
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
!> @author Marc De Graef, Carnegie Mellon University
|
!> @author Marc De Graef, Carnegie Mellon University
|
||||||
!> @brief rotate a vector passively (default) or actively
|
!> @brief Rotate a vector passively (default) or actively.
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
pure function rotVector(self,v,active) result(vRot)
|
pure function rotVector(self,v,active) result(vRot)
|
||||||
|
|
||||||
|
@ -288,8 +287,7 @@ pure function rotVector(self,v,active) result(vRot)
|
||||||
real(pReal), intent(in), dimension(3) :: v
|
real(pReal), intent(in), dimension(3) :: v
|
||||||
logical, intent(in), optional :: active
|
logical, intent(in), optional :: active
|
||||||
|
|
||||||
real(pReal), dimension(3) :: v_normed
|
real(pReal), dimension(4) :: v_normed, q
|
||||||
type(quaternion) :: q
|
|
||||||
logical :: passive
|
logical :: passive
|
||||||
|
|
||||||
if (present(active)) then
|
if (present(active)) then
|
||||||
|
@ -301,13 +299,13 @@ pure function rotVector(self,v,active) result(vRot)
|
||||||
if (dEq0(norm2(v))) then
|
if (dEq0(norm2(v))) then
|
||||||
vRot = v
|
vRot = v
|
||||||
else
|
else
|
||||||
v_normed = v/norm2(v)
|
v_normed = [0.0_pReal,v]/norm2(v)
|
||||||
if (passive) then
|
if (passive) then
|
||||||
q = self%q * (quaternion([0.0_pReal, v_normed(1), v_normed(2), v_normed(3)]) * conjg(self%q) )
|
q = multiply_quaternion(self%q, multiply_quaternion(v_normed, conjugate_quaternion(self%q)))
|
||||||
else
|
else
|
||||||
q = conjg(self%q) * (quaternion([0.0_pReal, v_normed(1), v_normed(2), v_normed(3)]) * self%q )
|
q = multiply_quaternion(conjugate_quaternion(self%q), multiply_quaternion(v_normed, self%q))
|
||||||
endif
|
endif
|
||||||
vRot = q%aimag()*norm2(v)
|
vRot = q(2:4)*norm2(v)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
end function rotVector
|
end function rotVector
|
||||||
|
@ -315,8 +313,8 @@ end function rotVector
|
||||||
|
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
!> @author Marc De Graef, Carnegie Mellon University
|
!> @author Marc De Graef, Carnegie Mellon University
|
||||||
!> @brief rotate a rank-2 tensor passively (default) or actively
|
!> @brief Rotate a rank-2 tensor passively (default) or actively.
|
||||||
!> @details: rotation is based on rotation matrix
|
!> @details: Rotation is based on rotation matrix
|
||||||
!---------------------------------------------------------------------------------------------------
|
!---------------------------------------------------------------------------------------------------
|
||||||
pure function rotTensor2(self,T,active) result(tRot)
|
pure function rotTensor2(self,T,active) result(tRot)
|
||||||
|
|
||||||
|
@ -403,7 +401,7 @@ pure elemental function misorientation(self,other)
|
||||||
type(rotation) :: misorientation
|
type(rotation) :: misorientation
|
||||||
class(rotation), intent(in) :: self, other
|
class(rotation), intent(in) :: self, other
|
||||||
|
|
||||||
misorientation%q = other%q * conjg(self%q)
|
misorientation%q = multiply_quaternion(other%q, conjugate_quaternion(self%q))
|
||||||
|
|
||||||
end function misorientation
|
end function misorientation
|
||||||
|
|
||||||
|
@ -1338,7 +1336,7 @@ end function cu2ho
|
||||||
!--------------------------------------------------------------------------
|
!--------------------------------------------------------------------------
|
||||||
!> @author Marc De Graef, Carnegie Mellon University
|
!> @author Marc De Graef, Carnegie Mellon University
|
||||||
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
|
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
|
||||||
!> @brief determine to which pyramid a point in a cubic grid belongs
|
!> @brief Determine to which pyramid a point in a cubic grid belongs.
|
||||||
!--------------------------------------------------------------------------
|
!--------------------------------------------------------------------------
|
||||||
pure function GetPyramidOrder(xyz)
|
pure function GetPyramidOrder(xyz)
|
||||||
|
|
||||||
|
@ -1362,7 +1360,39 @@ end function GetPyramidOrder
|
||||||
|
|
||||||
|
|
||||||
!--------------------------------------------------------------------------------------------------
|
!--------------------------------------------------------------------------------------------------
|
||||||
!> @brief check correctness of some rotations functions
|
!> @brief Multiply two quaternions.
|
||||||
|
!--------------------------------------------------------------------------------------------------
|
||||||
|
pure function multiply_quaternion(qu1,qu2)
|
||||||
|
|
||||||
|
real(pReal), dimension(4), intent(in) :: qu1, qu2
|
||||||
|
real(pReal), dimension(4) :: multiply_quaternion
|
||||||
|
|
||||||
|
|
||||||
|
multiply_quaternion(1) = qu1(1)*qu2(1) - qu1(2)*qu2(2) - qu1(3)*qu2(3) - qu1(4)*qu2(4)
|
||||||
|
multiply_quaternion(2) = qu1(1)*qu2(2) + qu1(2)*qu2(1) + P * (qu1(3)*qu2(4) - qu1(4)*qu2(3))
|
||||||
|
multiply_quaternion(3) = qu1(1)*qu2(3) + qu1(3)*qu2(1) + P * (qu1(4)*qu2(2) - qu1(2)*qu2(4))
|
||||||
|
multiply_quaternion(4) = qu1(1)*qu2(4) + qu1(4)*qu2(1) + P * (qu1(2)*qu2(3) - qu1(3)*qu2(2))
|
||||||
|
|
||||||
|
end function multiply_quaternion
|
||||||
|
|
||||||
|
|
||||||
|
!--------------------------------------------------------------------------------------------------
|
||||||
|
!> @brief Calculate conjugate complex of a quaternion.
|
||||||
|
!--------------------------------------------------------------------------------------------------
|
||||||
|
pure function conjugate_quaternion(qu)
|
||||||
|
|
||||||
|
real(pReal), dimension(4), intent(in) :: qu
|
||||||
|
real(pReal), dimension(4) :: conjugate_quaternion
|
||||||
|
|
||||||
|
|
||||||
|
conjugate_quaternion = [qu(1), -qu(2), -qu(3), -qu(4)]
|
||||||
|
|
||||||
|
|
||||||
|
end function conjugate_quaternion
|
||||||
|
|
||||||
|
|
||||||
|
!--------------------------------------------------------------------------------------------------
|
||||||
|
!> @brief Check correctness of some rotations functions.
|
||||||
!--------------------------------------------------------------------------------------------------
|
!--------------------------------------------------------------------------------------------------
|
||||||
subroutine selfTest
|
subroutine selfTest
|
||||||
|
|
||||||
|
@ -1374,7 +1404,8 @@ subroutine selfTest
|
||||||
real :: A,B
|
real :: A,B
|
||||||
integer :: i
|
integer :: i
|
||||||
|
|
||||||
do i=1,10
|
|
||||||
|
do i = 1, 10
|
||||||
|
|
||||||
#if defined(__GFORTRAN__) && __GNUC__<9
|
#if defined(__GFORTRAN__) && __GNUC__<9
|
||||||
if(i<7) cycle
|
if(i<7) cycle
|
||||||
|
|
Loading…
Reference in New Issue