Merge branch 'development' into python-vtk-improvements
This commit is contained in:
commit
0adc827278
|
@ -96,14 +96,14 @@ mesh_GNU:
|
|||
grid_GNU-64bit:
|
||||
stage: compile
|
||||
script:
|
||||
- module load Compiler/GNU/10 Libraries/PETSc/3.16.2/64bit
|
||||
- module load Compiler/GNU/10 Libraries/PETSc/3.16.4/64bit
|
||||
- cd PRIVATE/testing/pytest
|
||||
- pytest -k 'compile and grid' --basetemp ${TESTROOT}/compile_grid_GNU-64bit
|
||||
|
||||
mesh_GNU-64bit:
|
||||
stage: compile
|
||||
script:
|
||||
- module load Compiler/GNU/10 Libraries/PETSc/3.16.2/64bit
|
||||
- module load Compiler/GNU/10 Libraries/PETSc/3.16.4/64bit
|
||||
- cd PRIVATE/testing/pytest
|
||||
- pytest -k 'compile and mesh' --basetemp ${TESTROOT}/compile_mesh_GNU-64bit
|
||||
|
||||
|
|
2
PRIVATE
2
PRIVATE
|
@ -1 +1 @@
|
|||
Subproject commit 0d639a9ba41db279b0d2825c8e8eddf0ccd91326
|
||||
Subproject commit e663a548b10ee3f9ced35c5a5105bd6824d3eebf
|
|
@ -1,31 +1,62 @@
|
|||
type: dislotwin
|
||||
output: [rho_mob, rho_dip, gamma_sl, Lambda_sl, tau_pass, f_tw, Lambda_tw, tau_hat_tw, f_tr]
|
||||
D: 2.0e-5
|
||||
output: [rho_mob, rho_dip, gamma_sl, Lambda_sl, tau_pass, f_tw, Lambda_tw, f_tr]
|
||||
|
||||
# Slip
|
||||
N_sl: [12]
|
||||
b_sl: [2.56e-10]
|
||||
Q_sl: [3.5e-19]
|
||||
p_sl: [0.325]
|
||||
q_sl: [1.55]
|
||||
B: [0.001]
|
||||
i_sl: [30.0]
|
||||
|
||||
rho_mob_0: [1.0e+12]
|
||||
rho_dip_0: [1.0]
|
||||
|
||||
v_0: [1.0e+4]
|
||||
Q_sl: [3.7e-19]
|
||||
p_sl: [1.0]
|
||||
q_sl: [1.0]
|
||||
tau_0: [1.5e+8]
|
||||
i_sl: [10.0] # Adj. parameter controlling dislocation mean free path
|
||||
D_0: 4.0e-5 # Vacancy diffusion prefactor / m^2/s
|
||||
tau_0: [3.5e+8]
|
||||
D_a: 1.0 # minimum dipole distance / b
|
||||
Q_cl: 4.5e-19 # Activation energy for climb / J
|
||||
|
||||
h_sl-sl: [0.122, 0.122, 0.625, 0.07, 0.137, 0.137, 0.122] # Interaction coefficients (Kubin et al. 2008)
|
||||
# twinning parameters
|
||||
h_tw-sl: [0.0] # ToDo: values not known
|
||||
|
||||
# Twin
|
||||
N_tw: [12]
|
||||
b_tw: [1.47e-10] # Burgers vector length of twin system / b
|
||||
t_tw: [5.0e-8] # Twin stack mean thickness / m
|
||||
L_tw: 442.0 # Length of twin nuclei / b
|
||||
x_c_tw: 1.0e-9 # critical distance for formation of twin nucleus / m
|
||||
V_cs: 1.67e-29 # cross slip volume / m^3
|
||||
p_tw: [10.0] # r-exponent in twin formation probability
|
||||
i_tw: 1.0 # Adj. parameter controlling twin mean free path
|
||||
h_sl-tw: [0.0, 1.0, 1.0] # dislocation-twin interaction coefficients
|
||||
h_tw-tw: [0.0, 1.0] # twin-twin interaction coefficients
|
||||
T_ref: 0.0
|
||||
Gamma_sf: -0.0396 # stacking fault energy / J/m^2 at zero K; TWIP steel: -0.0526; Cu: -0.0396
|
||||
Gamma_sf,T: 0.0002 # temperature dependence / J/(m^2 K) of stacking fault energy
|
||||
b_tw: [1.40e-10]
|
||||
L_tw: 1.8e-7
|
||||
i_tw: 10.0
|
||||
t_tw: [5.0e-8]
|
||||
p_tw: [3.0] # A
|
||||
|
||||
h_tw-tw: [0.0, 1.0] # ToDo: values not known
|
||||
h_sl-tw: [0.0, 1.0, 1.0] # ToDo: values not known
|
||||
|
||||
# Transformation
|
||||
N_tr: [12]
|
||||
b_tr: [1.40e-10]
|
||||
L_tr: 1.8e-7
|
||||
i_tr: 3.0
|
||||
t_tr: [1.0e-7]
|
||||
p_tr: [3.0] # B
|
||||
V_mol: 7.09e-6
|
||||
Delta_G: 1.33343932e+02
|
||||
Delta_G,T: 2.56640412
|
||||
Delta_G,T^2: 1.49524179e-03
|
||||
|
||||
h_tr-tr: [1.0, 1.0] # guessing
|
||||
h_sl-tr: [0.0, 1.0, 1.0] # guessing
|
||||
|
||||
# Twin & Transformation
|
||||
T_ref: 298.15
|
||||
Gamma_sf: 2.89394017e-02
|
||||
Gamma_sf,T: 1.22823814e-04
|
||||
Gamma_sf,T^2: 1.47322968e-07
|
||||
x_c: 1.0e-9
|
||||
V_cs: 1.67e-29
|
||||
|
||||
a_cF: 3.62e-10
|
||||
c/a_hP: 1.633
|
||||
|
||||
# Slip & Twin & Transformation
|
||||
D: 2.0e-5
|
||||
|
|
|
@ -1 +1 @@
|
|||
v3.0.0-alpha5-651-gd4f711416
|
||||
v3.0.0-alpha6
|
||||
|
|
|
@ -144,10 +144,9 @@ class Config(dict):
|
|||
Configuration from file.
|
||||
|
||||
"""
|
||||
if isinstance(fname, (str, Path)):
|
||||
fhandle = open(fname)
|
||||
else:
|
||||
fhandle = fname
|
||||
fhandle = open(fname) if isinstance(fname, (str, Path)) else \
|
||||
fname
|
||||
|
||||
return cls(yaml.safe_load(fhandle))
|
||||
|
||||
def save(self,
|
||||
|
@ -164,10 +163,8 @@ class Config(dict):
|
|||
Keyword arguments parsed to yaml.dump.
|
||||
|
||||
"""
|
||||
if isinstance(fname, (str, Path)):
|
||||
fhandle = open(fname,'w',newline='\n')
|
||||
else:
|
||||
fhandle = fname
|
||||
fhandle = open(fname,'w',newline='\n') if isinstance(fname, (str, Path)) else \
|
||||
fname
|
||||
|
||||
if 'width' not in kwargs:
|
||||
kwargs['width'] = 256
|
||||
|
|
|
@ -2,10 +2,11 @@ from typing import Union, Dict, List, Tuple
|
|||
|
||||
import numpy as np
|
||||
|
||||
from ._typehints import FloatSequence, CrystalFamily, CrystalLattice, CrystalKinematics
|
||||
from . import util
|
||||
from . import Rotation
|
||||
|
||||
lattice_symmetries = {
|
||||
lattice_symmetries: Dict[CrystalLattice, CrystalFamily] = {
|
||||
'aP': 'triclinic',
|
||||
|
||||
'mP': 'monoclinic',
|
||||
|
@ -30,9 +31,9 @@ lattice_symmetries = {
|
|||
class Crystal():
|
||||
"""Crystal lattice."""
|
||||
|
||||
def __init__(self,*,
|
||||
family = None,
|
||||
lattice = None,
|
||||
def __init__(self, *,
|
||||
family: CrystalFamily = None,
|
||||
lattice: CrystalLattice = None,
|
||||
a: float = None, b: float = None, c: float = None,
|
||||
alpha: float = None, beta: float = None, gamma: float = None,
|
||||
degrees: bool = False):
|
||||
|
@ -130,9 +131,8 @@ class Crystal():
|
|||
Crystal to check for equality.
|
||||
|
||||
"""
|
||||
if not isinstance(other, Crystal):
|
||||
return NotImplemented
|
||||
return self.lattice == other.lattice and \
|
||||
return NotImplemented if not isinstance(other, Crystal) else \
|
||||
self.lattice == other.lattice and \
|
||||
self.parameters == other.parameters and \
|
||||
self.family == other.family
|
||||
|
||||
|
@ -208,7 +208,7 @@ class Crystal():
|
|||
... }
|
||||
|
||||
"""
|
||||
_basis = {
|
||||
_basis: Dict[CrystalFamily, Dict[str, np.ndarray]] = {
|
||||
'cubic': {'improper':np.array([ [-1. , 0. , 1. ],
|
||||
[ np.sqrt(2.) , -np.sqrt(2.) , 0. ],
|
||||
[ 0. , np.sqrt(3.) , 0. ] ]),
|
||||
|
@ -315,58 +315,58 @@ class Crystal():
|
|||
self.lattice[-1],None),dtype=float)
|
||||
|
||||
def to_lattice(self, *,
|
||||
direction: np.ndarray = None,
|
||||
plane: np.ndarray = None) -> np.ndarray:
|
||||
direction: FloatSequence = None,
|
||||
plane: FloatSequence = None) -> np.ndarray:
|
||||
"""
|
||||
Calculate lattice vector corresponding to crystal frame direction or plane normal.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
direction|plane : numpy.ndarray of shape (...,3)
|
||||
direction|plane : numpy.ndarray, shape (...,3)
|
||||
Vector along direction or plane normal.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Miller : numpy.ndarray of shape (...,3)
|
||||
Miller : numpy.ndarray, shape (...,3)
|
||||
Lattice vector of direction or plane.
|
||||
Use util.scale_to_coprime to convert to (integer) Miller indices.
|
||||
|
||||
"""
|
||||
if (direction is not None) ^ (plane is None):
|
||||
raise KeyError('specify either "direction" or "plane"')
|
||||
axis,basis = (np.array(direction),self.basis_reciprocal.T) \
|
||||
if plane is None else \
|
||||
(np.array(plane),self.basis_real.T)
|
||||
return np.einsum('il,...l',basis,axis)
|
||||
basis,axis = (self.basis_reciprocal,np.array(direction)) \
|
||||
if plane is None else \
|
||||
(self.basis_real,np.array(plane))
|
||||
return np.einsum('li,...l',basis,axis)
|
||||
|
||||
|
||||
def to_frame(self, *,
|
||||
uvw: np.ndarray = None,
|
||||
hkl: np.ndarray = None) -> np.ndarray:
|
||||
uvw: FloatSequence = None,
|
||||
hkl: FloatSequence = None) -> np.ndarray:
|
||||
"""
|
||||
Calculate crystal frame vector along lattice direction [uvw] or plane normal (hkl).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
uvw|hkl : numpy.ndarray of shape (...,3)
|
||||
uvw|hkl : numpy.ndarray, shape (...,3)
|
||||
Miller indices of crystallographic direction or plane normal.
|
||||
|
||||
Returns
|
||||
-------
|
||||
vector : numpy.ndarray of shape (...,3)
|
||||
vector : numpy.ndarray, shape (...,3)
|
||||
Crystal frame vector along [uvw] direction or (hkl) plane normal.
|
||||
|
||||
"""
|
||||
if (uvw is not None) ^ (hkl is None):
|
||||
raise KeyError('specify either "uvw" or "hkl"')
|
||||
axis,basis = (np.array(uvw),self.basis_real) \
|
||||
if hkl is None else \
|
||||
(np.array(hkl),self.basis_reciprocal)
|
||||
basis,axis = (self.basis_real,np.array(uvw)) \
|
||||
if hkl is None else \
|
||||
(self.basis_reciprocal,np.array(hkl))
|
||||
return np.einsum('il,...l',basis,axis)
|
||||
|
||||
|
||||
def kinematics(self,
|
||||
mode: str) -> Dict[str, List[np.ndarray]]:
|
||||
mode: CrystalKinematics) -> Dict[str, List[np.ndarray]]:
|
||||
"""
|
||||
Return crystal kinematics systems.
|
||||
|
||||
|
@ -381,7 +381,7 @@ class Crystal():
|
|||
Directions and planes of deformation mode families.
|
||||
|
||||
"""
|
||||
_kinematics = {
|
||||
_kinematics: Dict[CrystalLattice, Dict[CrystalKinematics, List[np.ndarray]]] = {
|
||||
'cF': {
|
||||
'slip': [np.array([
|
||||
[+0,+1,-1, +1,+1,+1],
|
||||
|
@ -626,7 +626,7 @@ class Crystal():
|
|||
|
||||
|
||||
def relation_operations(self,
|
||||
model: str) -> Tuple[str, Rotation]:
|
||||
model: str) -> Tuple[CrystalLattice, Rotation]:
|
||||
"""
|
||||
Crystallographic orientation relationships for phase transformations.
|
||||
|
||||
|
@ -658,7 +658,7 @@ class Crystal():
|
|||
https://doi.org/10.1016/j.actamat.2004.11.021
|
||||
|
||||
"""
|
||||
_orientation_relationships = {
|
||||
_orientation_relationships: Dict[str, Dict[CrystalLattice,np.ndarray]] = {
|
||||
'KS': {
|
||||
'cF' : np.array([
|
||||
[[-1, 0, 1],[ 1, 1, 1]],
|
||||
|
|
|
@ -63,8 +63,8 @@ class Grid:
|
|||
mat_N = self.N_materials
|
||||
return util.srepr([
|
||||
f'cells: {util.srepr(self.cells, " × ")}',
|
||||
f'size: {util.srepr(self.size, " × ")} / m³',
|
||||
f'origin: {util.srepr(self.origin," ")} / m',
|
||||
f'size: {util.srepr(self.size, " × ")} m³',
|
||||
f'origin: {util.srepr(self.origin," ")} m',
|
||||
f'# materials: {mat_N}' + ('' if mat_min == 0 and mat_max+1 == mat_N else
|
||||
f' (min: {mat_min}, max: {mat_max})')
|
||||
])
|
||||
|
@ -182,7 +182,7 @@ class Grid:
|
|||
Grid-based geometry from file.
|
||||
|
||||
"""
|
||||
v = VTK.load(fname if str(fname).endswith(('.vti','.vtr')) else str(fname)+'.vti') # compatibility hack
|
||||
v = VTK.load(fname if str(fname).endswith('.vti') else str(fname)+'.vti')
|
||||
cells = np.array(v.vtk_data.GetDimensions())-1
|
||||
bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
|
||||
comments = v.comments
|
||||
|
@ -603,8 +603,8 @@ class Grid:
|
|||
>>> import damask
|
||||
>>> damask.Grid.from_minimal_surface([64]*3,np.ones(3)*1.e-4,'Gyroid')
|
||||
cells : 64 x 64 x 64
|
||||
size : 0.0001 x 0.0001 x 0.0001 / m³
|
||||
origin: 0.0 0.0 0.0 / m
|
||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
||||
origin: 0.0 0.0 0.0 m
|
||||
# materials: 2
|
||||
|
||||
Minimal surface of 'Neovius' type. non-default material IDs.
|
||||
|
@ -614,8 +614,8 @@ class Grid:
|
|||
>>> damask.Grid.from_minimal_surface([80]*3,np.ones(3)*5.e-4,
|
||||
... 'Neovius',materials=(1,5))
|
||||
cells : 80 x 80 x 80
|
||||
size : 0.0005 x 0.0005 x 0.0005 / m³
|
||||
origin: 0.0 0.0 0.0 / m
|
||||
size : 0.0005 x 0.0005 x 0.0005 m³
|
||||
origin: 0.0 0.0 0.0 m
|
||||
# materials: 2 (min: 1, max: 5)
|
||||
|
||||
"""
|
||||
|
@ -735,8 +735,8 @@ class Grid:
|
|||
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
||||
>>> g.add_primitive(np.ones(3)*5e-5,np.ones(3)*5e-5,1)
|
||||
cells : 64 x 64 x 64
|
||||
size : 0.0001 x 0.0001 x 0.0001 / m³
|
||||
origin: 0.0 0.0 0.0 / m
|
||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
||||
origin: 0.0 0.0 0.0 m
|
||||
# materials: 2
|
||||
|
||||
Add a cube at the origin.
|
||||
|
@ -746,8 +746,8 @@ class Grid:
|
|||
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
||||
>>> g.add_primitive(np.ones(3,int)*32,np.zeros(3),np.inf)
|
||||
cells : 64 x 64 x 64
|
||||
size : 0.0001 x 0.0001 x 0.0001 / m³
|
||||
origin: 0.0 0.0 0.0 / m
|
||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
||||
origin: 0.0 0.0 0.0 m
|
||||
# materials: 2
|
||||
|
||||
"""
|
||||
|
@ -805,8 +805,8 @@ class Grid:
|
|||
>>> g = damask.Grid(np.zeros([32]*3,int), np.ones(3)*1e-4)
|
||||
>>> g.mirror('xy',True)
|
||||
cells : 64 x 64 x 32
|
||||
size : 0.0002 x 0.0002 x 0.0001 / m³
|
||||
origin: 0.0 0.0 0.0 / m
|
||||
size : 0.0002 x 0.0002 x 0.0001 m³
|
||||
origin: 0.0 0.0 0.0 m
|
||||
# materials: 1
|
||||
|
||||
"""
|
||||
|
@ -886,8 +886,8 @@ class Grid:
|
|||
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4)
|
||||
>>> g.scale(g.cells*2)
|
||||
cells : 64 x 64 x 64
|
||||
size : 0.0001 x 0.0001 x 0.0001 / m³
|
||||
origin: 0.0 0.0 0.0 / m
|
||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
||||
origin: 0.0 0.0 0.0 m
|
||||
# materials: 1
|
||||
|
||||
"""
|
||||
|
@ -1036,8 +1036,8 @@ class Grid:
|
|||
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4)
|
||||
>>> g.canvas([32,32,16])
|
||||
cells : 33 x 32 x 16
|
||||
size : 0.0001 x 0.0001 x 5e-05 / m³
|
||||
origin: 0.0 0.0 0.0 / m
|
||||
size : 0.0001 x 0.0001 x 5e-05 m³
|
||||
origin: 0.0 0.0 0.0 m
|
||||
# materials: 1
|
||||
|
||||
"""
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import inspect
|
||||
import copy
|
||||
from typing import Union, Callable, List, Dict, Any, Tuple, TypeVar
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ._typehints import FloatSequence, IntSequence, CrystalFamily, CrystalLattice
|
||||
from . import Rotation
|
||||
from . import Crystal
|
||||
from . import util
|
||||
|
@ -33,6 +35,7 @@ _parameter_doc = \
|
|||
|
||||
"""
|
||||
|
||||
MyType = TypeVar('MyType', bound='Orientation')
|
||||
|
||||
class Orientation(Rotation,Crystal):
|
||||
"""
|
||||
|
@ -93,12 +96,13 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
@util.extend_docstring(_parameter_doc)
|
||||
def __init__(self,
|
||||
rotation = np.array([1.0,0.0,0.0,0.0]), *,
|
||||
family = None,
|
||||
lattice = None,
|
||||
a = None,b = None,c = None,
|
||||
alpha = None,beta = None,gamma = None,
|
||||
degrees = False):
|
||||
rotation: Union[FloatSequence, Rotation] = np.array([1.,0.,0.,0.]),
|
||||
*,
|
||||
family: CrystalFamily = None,
|
||||
lattice: CrystalLattice = None,
|
||||
a: float = None, b: float = None, c: float = None,
|
||||
alpha: float = None, beta: float = None, gamma: float = None,
|
||||
degrees: bool = False):
|
||||
"""
|
||||
New orientation.
|
||||
|
||||
|
@ -115,13 +119,13 @@ class Orientation(Rotation,Crystal):
|
|||
a=a,b=b,c=c, alpha=alpha,beta=beta,gamma=gamma, degrees=degrees)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
"""Represent."""
|
||||
return '\n'.join([Crystal.__repr__(self),
|
||||
Rotation.__repr__(self)])
|
||||
|
||||
|
||||
def __copy__(self,rotation=None):
|
||||
def __copy__(self: MyType,
|
||||
rotation: Union[FloatSequence, Rotation] = None) -> MyType:
|
||||
"""Create deep copy."""
|
||||
dup = copy.deepcopy(self)
|
||||
if rotation is not None:
|
||||
|
@ -131,7 +135,9 @@ class Orientation(Rotation,Crystal):
|
|||
copy = __copy__
|
||||
|
||||
|
||||
def __eq__(self,other):
|
||||
|
||||
def __eq__(self,
|
||||
other: object) -> bool:
|
||||
"""
|
||||
Equal to other.
|
||||
|
||||
|
@ -141,12 +147,15 @@ class Orientation(Rotation,Crystal):
|
|||
Orientation to check for equality.
|
||||
|
||||
"""
|
||||
if not isinstance(other, Orientation):
|
||||
return NotImplemented
|
||||
matching_type = self.family == other.family and \
|
||||
self.lattice == other.lattice and \
|
||||
self.parameters == other.parameters
|
||||
return np.logical_and(matching_type,super(self.__class__,self.reduced).__eq__(other.reduced))
|
||||
|
||||
def __ne__(self,other):
|
||||
def __ne__(self,
|
||||
other: object) -> bool:
|
||||
"""
|
||||
Not equal to other.
|
||||
|
||||
|
@ -156,10 +165,14 @@ class Orientation(Rotation,Crystal):
|
|||
Orientation to check for equality.
|
||||
|
||||
"""
|
||||
return np.logical_not(self==other)
|
||||
return np.logical_not(self==other) if isinstance(other, Orientation) else NotImplemented
|
||||
|
||||
|
||||
def isclose(self,other,rtol=1e-5,atol=1e-8,equal_nan=True):
|
||||
def isclose(self: MyType,
|
||||
other: MyType,
|
||||
rtol: float = 1e-5,
|
||||
atol: float = 1e-8,
|
||||
equal_nan: bool = True) -> bool:
|
||||
"""
|
||||
Report where values are approximately equal to corresponding ones of other Orientation.
|
||||
|
||||
|
@ -176,7 +189,7 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
Returns
|
||||
-------
|
||||
mask : numpy.ndarray bool
|
||||
mask : numpy.ndarray of bool, shape (self.shape)
|
||||
Mask indicating where corresponding orientations are close.
|
||||
|
||||
"""
|
||||
|
@ -187,7 +200,11 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
|
||||
|
||||
def allclose(self,other,rtol=1e-5,atol=1e-8,equal_nan=True):
|
||||
def allclose(self: MyType,
|
||||
other: MyType,
|
||||
rtol: float = 1e-5,
|
||||
atol: float = 1e-8,
|
||||
equal_nan: bool = True) -> bool:
|
||||
"""
|
||||
Test whether all values are approximately equal to corresponding ones of other Orientation.
|
||||
|
||||
|
@ -208,10 +225,11 @@ class Orientation(Rotation,Crystal):
|
|||
Whether all values are close between both orientations.
|
||||
|
||||
"""
|
||||
return np.all(self.isclose(other,rtol,atol,equal_nan))
|
||||
return bool(np.all(self.isclose(other,rtol,atol,equal_nan)))
|
||||
|
||||
|
||||
def __mul__(self,other):
|
||||
def __mul__(self: MyType,
|
||||
other: Union[Rotation, 'Orientation']) -> MyType:
|
||||
"""
|
||||
Compose this orientation with other.
|
||||
|
||||
|
@ -226,14 +244,15 @@ class Orientation(Rotation,Crystal):
|
|||
Compound rotation self*other, i.e. first other then self rotation.
|
||||
|
||||
"""
|
||||
if isinstance(other,Orientation) or isinstance(other,Rotation):
|
||||
return self.copy(rotation=Rotation.__mul__(self,Rotation(other.quaternion)))
|
||||
if isinstance(other, (Orientation,Rotation)):
|
||||
return self.copy(Rotation(self.quaternion)*Rotation(other.quaternion))
|
||||
else:
|
||||
raise TypeError('use "O@b", i.e. matmul, to apply Orientation "O" to object "b"')
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _split_kwargs(kwargs,target):
|
||||
def _split_kwargs(kwargs: Dict[str, Any],
|
||||
target: Callable) -> Tuple[Dict[str, Any], ...]:
|
||||
"""
|
||||
Separate keyword arguments in 'kwargs' targeted at 'target' from general keyword arguments of Orientation objects.
|
||||
|
||||
|
@ -252,7 +271,7 @@ class Orientation(Rotation,Crystal):
|
|||
Valid keyword arguments of Orientation object.
|
||||
|
||||
"""
|
||||
kws = ()
|
||||
kws: Tuple[Dict[str, Any], ...] = ()
|
||||
for t in (target,Orientation.__init__):
|
||||
kws += ({key: kwargs[key] for key in set(inspect.signature(t).parameters) & set(kwargs)},)
|
||||
|
||||
|
@ -264,105 +283,108 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_random,_parameter_doc)
|
||||
def from_random(cls,**kwargs):
|
||||
@util.extended_docstring(Rotation.from_random, _parameter_doc)
|
||||
def from_random(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_random)
|
||||
return cls(rotation=Rotation.from_random(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_quaternion,_parameter_doc)
|
||||
def from_quaternion(cls,**kwargs):
|
||||
def from_quaternion(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_quaternion)
|
||||
return cls(rotation=Rotation.from_quaternion(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_Euler_angles,_parameter_doc)
|
||||
def from_Euler_angles(cls,**kwargs):
|
||||
def from_Euler_angles(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Euler_angles)
|
||||
return cls(rotation=Rotation.from_Euler_angles(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_axis_angle,_parameter_doc)
|
||||
def from_axis_angle(cls,**kwargs):
|
||||
def from_axis_angle(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_axis_angle)
|
||||
return cls(rotation=Rotation.from_axis_angle(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_basis,_parameter_doc)
|
||||
def from_basis(cls,**kwargs):
|
||||
def from_basis(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_basis)
|
||||
return cls(rotation=Rotation.from_basis(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_matrix,_parameter_doc)
|
||||
def from_matrix(cls,**kwargs):
|
||||
def from_matrix(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_matrix)
|
||||
return cls(rotation=Rotation.from_matrix(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_Rodrigues_vector,_parameter_doc)
|
||||
def from_Rodrigues_vector(cls,**kwargs):
|
||||
def from_Rodrigues_vector(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Rodrigues_vector)
|
||||
return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_homochoric,_parameter_doc)
|
||||
def from_homochoric(cls,**kwargs):
|
||||
def from_homochoric(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_homochoric)
|
||||
return cls(rotation=Rotation.from_homochoric(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_cubochoric,_parameter_doc)
|
||||
def from_cubochoric(cls,**kwargs):
|
||||
def from_cubochoric(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_cubochoric)
|
||||
return cls(rotation=Rotation.from_cubochoric(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_spherical_component,_parameter_doc)
|
||||
def from_spherical_component(cls,**kwargs):
|
||||
def from_spherical_component(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_spherical_component)
|
||||
return cls(rotation=Rotation.from_spherical_component(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extended_docstring(Rotation.from_fiber_component,_parameter_doc)
|
||||
def from_fiber_component(cls,**kwargs):
|
||||
def from_fiber_component(cls, **kwargs) -> 'Orientation':
|
||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_fiber_component)
|
||||
return cls(rotation=Rotation.from_fiber_component(**kwargs_rot),**kwargs_ori)
|
||||
|
||||
|
||||
@classmethod
|
||||
@util.extend_docstring(_parameter_doc)
|
||||
def from_directions(cls,uvw,hkl,**kwargs):
|
||||
def from_directions(cls,
|
||||
uvw: FloatSequence,
|
||||
hkl: FloatSequence,
|
||||
**kwargs) -> 'Orientation':
|
||||
"""
|
||||
Initialize orientation object from two crystallographic directions.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
uvw : list, numpy.ndarray of shape (...,3)
|
||||
lattice direction aligned with lab frame x-direction.
|
||||
hkl : list, numpy.ndarray of shape (...,3)
|
||||
lattice plane normal aligned with lab frame z-direction.
|
||||
uvw : numpy.ndarray, shape (...,3)
|
||||
Lattice direction aligned with lab frame x-direction.
|
||||
hkl : numpy.ndarray, shape (...,3)
|
||||
Lattice plane normal aligned with lab frame z-direction.
|
||||
|
||||
"""
|
||||
o = cls(**kwargs)
|
||||
x = o.to_frame(uvw=uvw)
|
||||
z = o.to_frame(hkl=hkl)
|
||||
om = np.stack([x,np.cross(z,x),z],axis=-2)
|
||||
return o.copy(rotation=Rotation.from_matrix(tensor.transpose(om/np.linalg.norm(om,axis=-1,keepdims=True))))
|
||||
return o.copy(Rotation.from_matrix(tensor.transpose(om/np.linalg.norm(om,axis=-1,keepdims=True))))
|
||||
|
||||
|
||||
@property
|
||||
def equivalent(self):
|
||||
def equivalent(self: MyType) -> MyType:
|
||||
"""
|
||||
Orientations that are symmetrically equivalent.
|
||||
|
||||
|
@ -372,11 +394,11 @@ class Orientation(Rotation,Crystal):
|
|||
"""
|
||||
sym_ops = self.symmetry_operations
|
||||
o = sym_ops.broadcast_to(sym_ops.shape+self.shape,mode='right')
|
||||
return self.copy(rotation=o*Rotation(self.quaternion).broadcast_to(o.shape,mode='left'))
|
||||
return self.copy(o*Rotation(self.quaternion).broadcast_to(o.shape,mode='left'))
|
||||
|
||||
|
||||
@property
|
||||
def reduced(self):
|
||||
def reduced(self: MyType) -> MyType:
|
||||
"""Select symmetrically equivalent orientation that falls into fundamental zone according to symmetry."""
|
||||
eq = self.equivalent
|
||||
ok = eq.in_FZ
|
||||
|
@ -387,13 +409,13 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
|
||||
@property
|
||||
def in_FZ(self):
|
||||
def in_FZ(self) -> Union[np.bool_, np.ndarray]:
|
||||
"""
|
||||
Check whether orientation falls into fundamental zone of own symmetry.
|
||||
|
||||
Returns
|
||||
-------
|
||||
in : numpy.ndarray of bool, quaternion.shape
|
||||
in : numpy.ndarray of bool, shape (self.shape)
|
||||
Whether Rodrigues-Frank vector falls into fundamental zone.
|
||||
|
||||
Notes
|
||||
|
@ -431,13 +453,13 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
|
||||
@property
|
||||
def in_disorientation_FZ(self):
|
||||
def in_disorientation_FZ(self) -> np.ndarray:
|
||||
"""
|
||||
Check whether orientation falls into fundamental zone of disorientations.
|
||||
|
||||
Returns
|
||||
-------
|
||||
in : numpy.ndarray of bool, quaternion.shape
|
||||
in : numpy.ndarray of bool, shape (self.shape)
|
||||
Whether Rodrigues-Frank vector falls into disorientation FZ.
|
||||
|
||||
References
|
||||
|
@ -471,8 +493,9 @@ class Orientation(Rotation,Crystal):
|
|||
else:
|
||||
return np.ones_like(rho[...,0],dtype=bool)
|
||||
|
||||
|
||||
def disorientation(self,other,return_operators=False):
|
||||
def disorientation(self,
|
||||
other: 'Orientation',
|
||||
return_operators: bool = False) -> object:
|
||||
"""
|
||||
Calculate disorientation between myself and given other orientation.
|
||||
|
||||
|
@ -490,7 +513,7 @@ class Orientation(Rotation,Crystal):
|
|||
-------
|
||||
disorientation : Orientation
|
||||
Disorientation between self and other.
|
||||
operators : numpy.ndarray int of shape (...,2), conditional
|
||||
operators : numpy.ndarray of int, shape (...,2), conditional
|
||||
Index of symmetrically equivalent orientation that rotated vector to the SST.
|
||||
|
||||
Notes
|
||||
|
@ -530,7 +553,7 @@ class Orientation(Rotation,Crystal):
|
|||
raise NotImplementedError('disorientation between different crystal families')
|
||||
|
||||
blend = util.shapeblender(self.shape,other.shape)
|
||||
s = self.equivalent
|
||||
s = self.equivalent
|
||||
o = other.equivalent
|
||||
|
||||
s_ = s.reshape((s.shape[0],1)+ self.shape).broadcast_to((s.shape[0],o.shape[0])+blend,mode='right')
|
||||
|
@ -557,13 +580,15 @@ class Orientation(Rotation,Crystal):
|
|||
)
|
||||
|
||||
|
||||
def average(self,weights=None,return_cloud=False):
|
||||
def average(self,
|
||||
weights: FloatSequence = None,
|
||||
return_cloud: bool = False):
|
||||
"""
|
||||
Return orientation average over last dimension.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
weights : numpy.ndarray, optional
|
||||
weights : numpy.ndarray, shape (self.shape), optional
|
||||
Relative weights of orientations.
|
||||
return_cloud : bool, optional
|
||||
Return the set of symmetrically equivalent orientations that was used in averaging.
|
||||
|
@ -583,31 +608,30 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
"""
|
||||
eq = self.equivalent
|
||||
m = eq.misorientation(self[...,0].reshape((1,)+self.shape[:-1]+(1,))
|
||||
.broadcast_to(eq.shape))\
|
||||
.as_axis_angle()[...,3]
|
||||
m = eq.misorientation(self[...,0].reshape((1,)+self.shape[:-1]+(1,)) # type: ignore
|
||||
.broadcast_to(eq.shape)).as_axis_angle()[...,3] # type: ignore
|
||||
r = Rotation(np.squeeze(np.take_along_axis(eq.quaternion,
|
||||
np.argmin(m,axis=0)[np.newaxis,...,np.newaxis],
|
||||
axis=0),
|
||||
axis=0))
|
||||
return (
|
||||
(self.copy(rotation=Rotation(r).average(weights)),
|
||||
self.copy(rotation=Rotation(r)))
|
||||
if return_cloud else
|
||||
self.copy(rotation=Rotation(r).average(weights))
|
||||
return ((self.copy(Rotation(r).average(weights)),self.copy(Rotation(r))) if return_cloud else
|
||||
self.copy(Rotation(r).average(weights))
|
||||
)
|
||||
|
||||
|
||||
def to_SST(self,vector,proper=False,return_operators=False):
|
||||
def to_SST(self,
|
||||
vector: FloatSequence,
|
||||
proper: bool = False,
|
||||
return_operators: bool = False) -> np.ndarray:
|
||||
"""
|
||||
Rotate vector to ensure it falls into (improper or proper) standard stereographic triangle of crystal symmetry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
vector : numpy.ndarray of shape (...,3)
|
||||
vector : numpy.ndarray, shape (...,3)
|
||||
Lab frame vector to align with crystal frame direction.
|
||||
Shape of vector blends with shape of own rotation array.
|
||||
For example, a rotation array of shape (3,2) and a (2,4) vector array result in (3,2,4) outputs.
|
||||
For example, a rotation array of shape (3,2) and a vector array of shape (2,4) result in (3,2,4) outputs.
|
||||
proper : bool, optional
|
||||
Consider only vectors with z >= 0, hence combine two neighboring SSTs.
|
||||
Defaults to False.
|
||||
|
@ -617,15 +641,18 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
Returns
|
||||
-------
|
||||
vector_SST : numpy.ndarray of shape (...,3)
|
||||
vector_SST : numpy.ndarray, shape (...,3)
|
||||
Rotated vector falling into SST.
|
||||
operators : numpy.ndarray int of shape (...), conditional
|
||||
operators : numpy.ndarray of int, shape (...), conditional
|
||||
Index of symmetrically equivalent orientation that rotated vector to SST.
|
||||
|
||||
"""
|
||||
vector_ = np.array(vector,float)
|
||||
if vector_.shape[-1] != 3:
|
||||
raise ValueError('input is not a field of three-dimensional vectors')
|
||||
eq = self.equivalent
|
||||
blend = util.shapeblender(eq.shape,np.array(vector).shape[:-1])
|
||||
poles = eq.broadcast_to(blend,mode='right') @ np.broadcast_to(np.array(vector),blend+(3,))
|
||||
blend = util.shapeblender(eq.shape,vector_.shape[:-1])
|
||||
poles = eq.broadcast_to(blend,mode='right') @ np.broadcast_to(vector_,blend+(3,))
|
||||
ok = self.in_SST(poles,proper=proper)
|
||||
ok &= np.cumsum(ok,axis=0) == 1
|
||||
loc = np.where(ok)
|
||||
|
@ -637,13 +664,15 @@ class Orientation(Rotation,Crystal):
|
|||
)
|
||||
|
||||
|
||||
def in_SST(self,vector,proper=False):
|
||||
def in_SST(self,
|
||||
vector: FloatSequence,
|
||||
proper: bool = False) -> Union[np.bool_, np.ndarray]:
|
||||
"""
|
||||
Check whether given crystal frame vector falls into standard stereographic triangle of own symmetry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
vector : numpy.ndarray of shape (...,3)
|
||||
vector : numpy.ndarray, shape (...,3)
|
||||
Vector to check.
|
||||
proper : bool, optional
|
||||
Consider only vectors with z >= 0, hence combine two neighboring SSTs.
|
||||
|
@ -655,39 +684,43 @@ class Orientation(Rotation,Crystal):
|
|||
Whether vector falls into SST.
|
||||
|
||||
"""
|
||||
if not isinstance(vector,np.ndarray) or vector.shape[-1] != 3:
|
||||
vector_ = np.array(vector,float)
|
||||
if vector_.shape[-1] != 3:
|
||||
raise ValueError('input is not a field of three-dimensional vectors')
|
||||
|
||||
if self.standard_triangle is None: # direct exit for no symmetry
|
||||
return np.ones_like(vector[...,0],bool)
|
||||
return np.ones_like(vector_[...,0],bool)
|
||||
|
||||
if proper:
|
||||
components_proper = np.around(np.einsum('...ji,...i',
|
||||
np.broadcast_to(self.standard_triangle['proper'], vector.shape+(3,)),
|
||||
vector), 12)
|
||||
np.broadcast_to(self.standard_triangle['proper'], vector_.shape+(3,)),
|
||||
vector_), 12)
|
||||
components_improper = np.around(np.einsum('...ji,...i',
|
||||
np.broadcast_to(self.standard_triangle['improper'], vector.shape+(3,)),
|
||||
vector), 12)
|
||||
np.broadcast_to(self.standard_triangle['improper'], vector_.shape+(3,)),
|
||||
vector_), 12)
|
||||
return np.all(components_proper >= 0.0,axis=-1) \
|
||||
| np.all(components_improper >= 0.0,axis=-1)
|
||||
else:
|
||||
components = np.around(np.einsum('...ji,...i',
|
||||
np.broadcast_to(self.standard_triangle['improper'], vector.shape+(3,)),
|
||||
np.block([vector[...,:2],np.abs(vector[...,2:3])])), 12)
|
||||
np.broadcast_to(self.standard_triangle['improper'], vector_.shape+(3,)),
|
||||
np.block([vector_[...,:2],np.abs(vector_[...,2:3])])), 12)
|
||||
|
||||
return np.all(components >= 0.0,axis=-1)
|
||||
|
||||
|
||||
def IPF_color(self,vector,in_SST=True,proper=False):
|
||||
def IPF_color(self,
|
||||
vector: FloatSequence,
|
||||
in_SST: bool = True,
|
||||
proper: bool = False) -> np.ndarray:
|
||||
"""
|
||||
Map vector to RGB color within standard stereographic triangle of own symmetry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
vector : numpy.ndarray of shape (...,3)
|
||||
vector : numpy.ndarray, shape (...,3)
|
||||
Vector to colorize.
|
||||
Shape of vector blends with shape of own rotation array.
|
||||
For example, a rotation array of shape (3,2) and a (2,4) vector array result in (3,2,4) outputs.
|
||||
For example, a rotation array of shape (3,2) and a vector array of shape (2,4) result in (3,2,4) outputs.
|
||||
in_SST : bool, optional
|
||||
Consider symmetrically equivalent orientations such that poles are located in SST.
|
||||
Defaults to True.
|
||||
|
@ -697,7 +730,7 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
Returns
|
||||
-------
|
||||
rgb : numpy.ndarray of shape (...,3)
|
||||
rgb : numpy.ndarray, shape (...,3)
|
||||
RGB array of IPF colors.
|
||||
|
||||
Examples
|
||||
|
@ -721,35 +754,35 @@ class Orientation(Rotation,Crystal):
|
|||
|
||||
if proper:
|
||||
components_proper = np.around(np.einsum('...ji,...i',
|
||||
np.broadcast_to(self.standard_triangle['proper'], vector_.shape+(3,)),
|
||||
np.broadcast_to(self.standard_triangle['proper'], vector_.shape+(3,)),
|
||||
vector_), 12)
|
||||
components_improper = np.around(np.einsum('...ji,...i',
|
||||
np.broadcast_to(self.standard_triangle['improper'], vector_.shape+(3,)),
|
||||
vector_), 12)
|
||||
in_SST = np.all(components_proper >= 0.0,axis=-1) \
|
||||
| np.all(components_improper >= 0.0,axis=-1)
|
||||
components = np.where((in_SST & np.all(components_proper >= 0.0,axis=-1))[...,np.newaxis],
|
||||
in_SST_ = np.all(components_proper >= 0.0,axis=-1) \
|
||||
| np.all(components_improper >= 0.0,axis=-1)
|
||||
components = np.where((in_SST_ & np.all(components_proper >= 0.0,axis=-1))[...,np.newaxis],
|
||||
components_proper,components_improper)
|
||||
else:
|
||||
components = np.around(np.einsum('...ji,...i',
|
||||
np.broadcast_to(self .standard_triangle['improper'], vector_.shape+(3,)),
|
||||
np.block([vector_[...,:2],np.abs(vector_[...,2:3])])), 12)
|
||||
|
||||
in_SST = np.all(components >= 0.0,axis=-1)
|
||||
in_SST_ = np.all(components >= 0.0,axis=-1)
|
||||
|
||||
with np.errstate(invalid='ignore',divide='ignore'):
|
||||
rgb = (components/np.linalg.norm(components,axis=-1,keepdims=True))**0.5 # smoothen color ramps
|
||||
rgb = np.clip(rgb,0.,1.) # clip intensity
|
||||
rgb /= np.max(rgb,axis=-1,keepdims=True) # normalize to (HS)V = 1
|
||||
rgb[np.broadcast_to(~in_SST[...,np.newaxis],rgb.shape)] = 0.0
|
||||
rgb[np.broadcast_to(~in_SST_[...,np.newaxis],rgb.shape)] = 0.0
|
||||
|
||||
return rgb
|
||||
|
||||
|
||||
@property
|
||||
def symmetry_operations(self):
|
||||
def symmetry_operations(self) -> Rotation:
|
||||
"""Symmetry operations as Rotations."""
|
||||
_symmetry_operations = {
|
||||
_symmetry_operations: Dict[CrystalFamily, List] = {
|
||||
'cubic': [
|
||||
[ 1.0, 0.0, 0.0, 0.0 ],
|
||||
[ 0.0, 1.0, 0.0, 0.0 ],
|
||||
|
@ -819,22 +852,25 @@ class Orientation(Rotation,Crystal):
|
|||
####################################################################################################
|
||||
# functions that require lattice, not just family
|
||||
|
||||
def to_pole(self,*,uvw=None,hkl=None,with_symmetry=False):
|
||||
def to_pole(self, *,
|
||||
uvw: FloatSequence = None,
|
||||
hkl: FloatSequence = None,
|
||||
with_symmetry: bool = False) -> np.ndarray:
|
||||
"""
|
||||
Calculate lab frame vector along lattice direction [uvw] or plane normal (hkl).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
uvw|hkl : numpy.ndarray of shape (...,3)
|
||||
uvw|hkl : numpy.ndarray, shape (...,3)
|
||||
Miller indices of crystallographic direction or plane normal.
|
||||
Shape of vector blends with shape of own rotation array.
|
||||
For example, a rotation array of shape (3,2) and a (2,4) vector array result in (3,2,4) outputs.
|
||||
For example, a rotation array, shape (3,2) and a vector array of shape (2,4) result in (3,2,4) outputs.
|
||||
with_symmetry : bool, optional
|
||||
Calculate all N symmetrically equivalent vectors.
|
||||
|
||||
Returns
|
||||
-------
|
||||
vector : numpy.ndarray of shape (...,3) or (...,N,3)
|
||||
vector : numpy.ndarray, shape (...,3) or (...,N,3)
|
||||
Lab frame vector (or vectors if with_symmetry) along [uvw] direction or (hkl) plane normal.
|
||||
|
||||
"""
|
||||
|
@ -846,23 +882,24 @@ class Orientation(Rotation,Crystal):
|
|||
blend += sym_ops.shape
|
||||
v = sym_ops.broadcast_to(shape) \
|
||||
@ np.broadcast_to(v.reshape(util.shapeshifter(v.shape,shape+(3,))),shape+(3,))
|
||||
return ~(self.broadcast_to(blend)) \
|
||||
@ np.broadcast_to(v,blend+(3,))
|
||||
return ~(self.broadcast_to(blend))@ np.broadcast_to(v,blend+(3,))
|
||||
|
||||
|
||||
def Schmid(self,*,N_slip=None,N_twin=None):
|
||||
def Schmid(self, *,
|
||||
N_slip: IntSequence = None,
|
||||
N_twin: IntSequence = None) -> np.ndarray:
|
||||
u"""
|
||||
Calculate Schmid matrix P = d ⨂ n in the lab frame for selected deformation systems.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
N_slip|N_twin : iterable of int
|
||||
N_slip|N_twin : '*' or iterable of int
|
||||
Number of deformation systems per family of the deformation system.
|
||||
Use '*' to select all.
|
||||
|
||||
Returns
|
||||
-------
|
||||
P : numpy.ndarray of shape (N,...,3,3)
|
||||
P : numpy.ndarray, shape (N,...,3,3)
|
||||
Schmid matrix for each of the N deformation systems.
|
||||
|
||||
Examples
|
||||
|
@ -887,6 +924,8 @@ class Orientation(Rotation,Crystal):
|
|||
(self.kinematics('twin'),N_twin)
|
||||
if active == '*': active = [len(a) for a in kinematics['direction']]
|
||||
|
||||
if not active:
|
||||
raise ValueError('Schmid matrix not defined')
|
||||
d = self.to_frame(uvw=np.vstack([kinematics['direction'][i][:n] for i,n in enumerate(active)]))
|
||||
p = self.to_frame(hkl=np.vstack([kinematics['plane'][i][:n] for i,n in enumerate(active)]))
|
||||
P = np.einsum('...i,...j',d/np.linalg.norm(d,axis=1,keepdims=True),
|
||||
|
@ -897,7 +936,8 @@ class Orientation(Rotation,Crystal):
|
|||
@ np.broadcast_to(P.reshape(util.shapeshifter(P.shape,shape)),shape)
|
||||
|
||||
|
||||
def related(self,model):
|
||||
def related(self: MyType,
|
||||
model: str) -> MyType:
|
||||
"""
|
||||
Orientations derived from the given relationship.
|
||||
|
||||
|
|
|
@ -168,17 +168,21 @@ class Result:
|
|||
|
||||
def __repr__(self):
|
||||
"""Show summary of file content."""
|
||||
with h5py.File(self.fname,'r') as f:
|
||||
header = [f'Created by {f.attrs["creator"]}',
|
||||
f' on {f.attrs["created"]}',
|
||||
f' executing "{f.attrs["call"]}"']
|
||||
visible_increments = self.visible['increments']
|
||||
|
||||
first = self.view(increments=visible_increments[0:1]).list_data()
|
||||
|
||||
last = '' if len(visible_increments) < 2 else \
|
||||
last = [] if len(visible_increments) < 2 else \
|
||||
self.view(increments=visible_increments[-1:]).list_data()
|
||||
|
||||
in_between = '' if len(visible_increments) < 3 else \
|
||||
''.join([f'\n{inc}\n ...\n' for inc in visible_increments[1:-1]])
|
||||
in_between = [] if len(visible_increments) < 3 else \
|
||||
[f'\n{inc}\n ...' for inc in visible_increments[1:-1]]
|
||||
|
||||
return util.srepr(first + in_between + last)
|
||||
return util.srepr([util.deemph(header)] + first + in_between + last)
|
||||
|
||||
|
||||
def _manage_view(self,action,what,datasets):
|
||||
|
@ -537,24 +541,32 @@ class Result:
|
|||
|
||||
|
||||
def list_data(self):
|
||||
"""Return information on all active datasets in the file."""
|
||||
msg = ''
|
||||
"""
|
||||
Collect information on all active datasets in the file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
data : list of str
|
||||
Line-formatted information about active datasets.
|
||||
|
||||
"""
|
||||
msg = []
|
||||
with h5py.File(self.fname,'r') as f:
|
||||
for inc in self.visible['increments']:
|
||||
msg = ''.join([msg,f'\n{inc} ({self.times[self.increments.index(inc)]}s)\n'])
|
||||
msg += [f'\n{inc} ({self.times[self.increments.index(inc)]} s)']
|
||||
for ty in ['phase','homogenization']:
|
||||
msg = ' '.join([msg,f'{ty}\n'])
|
||||
msg += [f' {ty}']
|
||||
for label in self.visible[ty+'s']:
|
||||
msg = ' '.join([msg,f'{label}\n'])
|
||||
msg += [f' {label}']
|
||||
for field in _match(self.visible['fields'],f['/'.join([inc,ty,label])].keys()):
|
||||
msg = ' '.join([msg,f'{field}\n'])
|
||||
msg += [f' {field}']
|
||||
for d in f['/'.join([inc,ty,label,field])].keys():
|
||||
dataset = f['/'.join([inc,ty,label,field,d])]
|
||||
unit = f' / {dataset.attrs["unit"]}' if h5py3 else \
|
||||
f' / {dataset.attrs["unit"].decode()}'
|
||||
unit = dataset.attrs["unit"] if h5py3 else \
|
||||
dataset.attrs["unit"].decode()
|
||||
description = dataset.attrs['description'] if h5py3 else \
|
||||
dataset.attrs['description'].decode()
|
||||
msg = ' '.join([msg,f'{d}{unit}: {description}\n'])
|
||||
msg += [f' {d} / {unit}: {description}']
|
||||
|
||||
return msg
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -194,7 +194,7 @@ class Table:
|
|||
|
||||
Returns
|
||||
-------
|
||||
mask : numpy.ndarray bool
|
||||
mask : numpy.ndarray of bool
|
||||
Mask indicating where corresponding table values are close.
|
||||
|
||||
"""
|
||||
|
@ -263,10 +263,8 @@ class Table:
|
|||
f.seek(0)
|
||||
|
||||
comments = []
|
||||
line = f.readline().strip()
|
||||
while line.startswith('#'):
|
||||
while (line := f.readline().strip()).startswith('#'):
|
||||
comments.append(line.lstrip('#').strip())
|
||||
line = f.readline().strip()
|
||||
labels = line.split()
|
||||
|
||||
shapes = {}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Functionality for typehints."""
|
||||
|
||||
from typing import Sequence, Union, TextIO
|
||||
from typing import Sequence, Union, Literal, TextIO
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
@ -9,6 +9,9 @@ import numpy as np
|
|||
FloatSequence = Union[np.ndarray,Sequence[float]]
|
||||
IntSequence = Union[np.ndarray,Sequence[int]]
|
||||
FileHandle = Union[TextIO, str, Path]
|
||||
CrystalFamily = Union[None,Literal['triclinic', 'monoclinic', 'orthorhombic', 'tetragonal', 'hexagonal', 'cubic']]
|
||||
CrystalLattice = Union[None,Literal['aP', 'mP', 'mS', 'oP', 'oS', 'oI', 'oF', 'tP', 'tI', 'hP', 'cP', 'cI', 'cF']]
|
||||
CrystalKinematics = Literal['slip', 'twin']
|
||||
NumpyRngSeed = Union[int, IntSequence, np.random.SeedSequence, np.random.Generator]
|
||||
# BitGenerator does not exists in older numpy versions
|
||||
#NumpyRngSeed = Union[int, IntSequence, np.random.SeedSequence, np.random.BitGenerator, np.random.Generator]
|
||||
|
|
|
@ -9,7 +9,7 @@ import re
|
|||
import fractions
|
||||
from collections import abc
|
||||
from functools import reduce
|
||||
from typing import Union, Tuple, Iterable, Callable, Dict, List, Any, Literal, SupportsIndex, Sequence
|
||||
from typing import Union, Tuple, Iterable, Callable, Dict, List, Any, Literal
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
@ -428,7 +428,7 @@ def hybrid_IA(dist: np.ndarray,
|
|||
def shapeshifter(fro: Tuple[int, ...],
|
||||
to: Tuple[int, ...],
|
||||
mode: Literal['left','right'] = 'left',
|
||||
keep_ones: bool = False) -> Sequence[SupportsIndex]:
|
||||
keep_ones: bool = False) -> Tuple[int, ...]:
|
||||
"""
|
||||
Return dimensions that reshape 'fro' to become broadcastable to 'to'.
|
||||
|
||||
|
@ -491,7 +491,7 @@ def shapeshifter(fro: Tuple[int, ...],
|
|||
|
||||
|
||||
def shapeblender(a: Tuple[int, ...],
|
||||
b: Tuple[int, ...]) -> Sequence[SupportsIndex]:
|
||||
b: Tuple[int, ...]) -> Tuple[int, ...]:
|
||||
"""
|
||||
Return a shape that overlaps the rightmost entries of 'a' with the leftmost of 'b'.
|
||||
|
||||
|
@ -794,7 +794,7 @@ class ProgressBar:
|
|||
|
||||
fraction = (iteration+1) / self.total
|
||||
|
||||
if filled_length := int(self.bar_length * fraction) > int(self.bar_length * self.fraction_last) or \
|
||||
if (filled_length := int(self.bar_length * fraction)) > int(self.bar_length * self.fraction_last) or \
|
||||
datetime.datetime.now() - self.time_last_update > datetime.timedelta(seconds=10):
|
||||
self.time_last_update = datetime.datetime.now()
|
||||
bar = '█' * filled_length + '░' * (self.bar_length - filled_length)
|
||||
|
|
|
@ -313,13 +313,13 @@ def ho2ax(ho):
|
|||
if iszero(hmag_squared):
|
||||
ax = np.array([ 0.0, 0.0, 1.0, 0.0 ])
|
||||
else:
|
||||
hm = hmag_squared
|
||||
hm = np.ones_like(hmag_squared)
|
||||
|
||||
# convert the magnitude to the rotation angle
|
||||
s = tfit[0] + tfit[1] * hmag_squared
|
||||
for i in range(2,16):
|
||||
s = 0.0
|
||||
for t in tfit:
|
||||
s += t * hm
|
||||
hm *= hmag_squared
|
||||
s += tfit[i] * hm
|
||||
ax = np.append(ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0)))
|
||||
return ax
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ module discretization
|
|||
|
||||
integer, public, protected :: &
|
||||
discretization_nIPs, &
|
||||
discretization_Nelems
|
||||
discretization_Nelems, &
|
||||
discretization_Ncells
|
||||
|
||||
integer, public, protected, dimension(:), allocatable :: &
|
||||
discretization_materialAt !ToDo: discretization_ID_material
|
||||
|
@ -53,6 +54,7 @@ subroutine discretization_init(materialAt,&
|
|||
|
||||
discretization_Nelems = size(materialAt,1)
|
||||
discretization_nIPs = size(IPcoords0,2)/discretization_Nelems
|
||||
discretization_Ncells = discretization_Nelems*discretization_nIPs
|
||||
|
||||
discretization_materialAt = materialAt
|
||||
|
||||
|
|
|
@ -97,8 +97,8 @@ subroutine discretization_grid_init(restart)
|
|||
if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error'
|
||||
|
||||
print'(/,1x,a,i0,a,i0,a,i0)', 'cells: ', cells(1), ' × ', cells(2), ' × ', cells(3)
|
||||
print '(1x,a,es8.2,a,es8.2,a,es8.2,a)', 'size: ', geomSize(1), ' × ', geomSize(2), ' × ', geomSize(3), ' / m³'
|
||||
print '(1x,a,es8.2,a,es8.2,a,es8.2,a)', 'origin: ', origin(1), ' ', origin(2), ' ', origin(3), ' / m'
|
||||
print '(1x,a,es8.2,a,es8.2,a,es8.2,a)', 'size: ', geomSize(1), ' × ', geomSize(2), ' × ', geomSize(3), ' m³'
|
||||
print '(1x,a,es8.2,a,es8.2,a,es8.2,a)', 'origin: ', origin(1), ' ', origin(2), ' ', origin(3), ' m'
|
||||
|
||||
if (worldsize>cells(3)) call IO_error(894, ext_msg='number of processes exceeds cells(3)')
|
||||
|
||||
|
|
|
@ -131,20 +131,15 @@ module subroutine mechanical_homogenize(Delta_t,ce)
|
|||
integer :: co
|
||||
|
||||
|
||||
homogenization_P(1:3,1:3,ce) = phase_P(1,ce)
|
||||
homogenization_dPdF(1:3,1:3,1:3,1:3,ce) = phase_mechanical_dPdF(Delta_t,1,ce)
|
||||
homogenization_P(1:3,1:3,ce) = phase_P(1,ce)*material_v(1,ce)
|
||||
homogenization_dPdF(1:3,1:3,1:3,1:3,ce) = phase_mechanical_dPdF(Delta_t,1,ce)*material_v(1,ce)
|
||||
do co = 2, homogenization_Nconstituents(material_homogenizationID(ce))
|
||||
homogenization_P(1:3,1:3,ce) = homogenization_P(1:3,1:3,ce) &
|
||||
+ phase_P(co,ce)
|
||||
+ phase_P(co,ce)*material_v(co,ce)
|
||||
homogenization_dPdF(1:3,1:3,1:3,1:3,ce) = homogenization_dPdF(1:3,1:3,1:3,1:3,ce) &
|
||||
+ phase_mechanical_dPdF(Delta_t,co,ce)
|
||||
+ phase_mechanical_dPdF(Delta_t,co,ce)*material_v(co,ce)
|
||||
end do
|
||||
|
||||
homogenization_P(1:3,1:3,ce) = homogenization_P(1:3,1:3,ce) &
|
||||
/ real(homogenization_Nconstituents(material_homogenizationID(ce)),pReal)
|
||||
homogenization_dPdF(1:3,1:3,1:3,1:3,ce) = homogenization_dPdF(1:3,1:3,1:3,1:3,ce) &
|
||||
/ real(homogenization_Nconstituents(material_homogenizationID(ce)),pReal)
|
||||
|
||||
end subroutine mechanical_homogenize
|
||||
|
||||
|
||||
|
|
|
@ -105,13 +105,11 @@ module function homogenization_mu_T(ce) result(mu)
|
|||
integer :: co
|
||||
|
||||
|
||||
mu = phase_mu_T(1,ce)
|
||||
mu = phase_mu_T(1,ce)*material_v(1,ce)
|
||||
do co = 2, homogenization_Nconstituents(material_homogenizationID(ce))
|
||||
mu = mu + phase_mu_T(co,ce)
|
||||
mu = mu + phase_mu_T(co,ce)*material_v(co,ce)
|
||||
end do
|
||||
|
||||
mu = mu / real(homogenization_Nconstituents(material_homogenizationID(ce)),pReal)
|
||||
|
||||
end function homogenization_mu_T
|
||||
|
||||
|
||||
|
@ -126,13 +124,11 @@ module function homogenization_K_T(ce) result(K)
|
|||
integer :: co
|
||||
|
||||
|
||||
K = phase_K_T(1,ce)
|
||||
K = phase_K_T(1,ce)*material_v(1,ce)
|
||||
do co = 2, homogenization_Nconstituents(material_homogenizationID(ce))
|
||||
K = K + phase_K_T(co,ce)
|
||||
K = K + phase_K_T(co,ce)*material_v(co,ce)
|
||||
end do
|
||||
|
||||
K = K / real(homogenization_Nconstituents(material_homogenizationID(ce)),pReal)
|
||||
|
||||
end function homogenization_K_T
|
||||
|
||||
|
||||
|
@ -147,13 +143,11 @@ module function homogenization_f_T(ce) result(f)
|
|||
integer :: co
|
||||
|
||||
|
||||
f = phase_f_T(material_phaseID(1,ce),material_phaseEntry(1,ce))
|
||||
f = phase_f_T(material_phaseID(1,ce),material_phaseEntry(1,ce))*material_v(1,ce)
|
||||
do co = 2, homogenization_Nconstituents(material_homogenizationID(ce))
|
||||
f = f + phase_f_T(material_phaseID(co,ce),material_phaseEntry(co,ce))
|
||||
f = f + phase_f_T(material_phaseID(co,ce),material_phaseEntry(co,ce))*material_v(co,ce)
|
||||
end do
|
||||
|
||||
f = f/real(homogenization_Nconstituents(material_homogenizationID(ce)),pReal)
|
||||
|
||||
end function homogenization_f_T
|
||||
|
||||
|
||||
|
|
|
@ -528,22 +528,22 @@ end function lattice_C66_twin
|
|||
!> @brief Rotated elasticity matrices for transformation in 6x6-matrix notation
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
function lattice_C66_trans(Ntrans,C_parent66,lattice_target, &
|
||||
cOverA_trans,a_bcc,a_fcc)
|
||||
cOverA_trans,a_fcc,a_bcc)
|
||||
|
||||
integer, dimension(:), intent(in) :: Ntrans !< number of active twin systems per family
|
||||
character(len=2), intent(in) :: lattice_target !< Bravais lattice (Pearson symbol)
|
||||
real(pReal), dimension(6,6), intent(in) :: C_parent66
|
||||
real(pReal), optional, intent(in) :: cOverA_trans, a_fcc, a_bcc
|
||||
real(pReal), dimension(6,6,sum(Ntrans)) :: lattice_C66_trans
|
||||
|
||||
real(pReal), dimension(6,6) :: C_bar66, C_target_unrotated66
|
||||
real(pReal), dimension(3,3,sum(Ntrans)) :: Q,S
|
||||
type(tRotation) :: R
|
||||
real(pReal) :: a_bcc, a_fcc, cOverA_trans
|
||||
integer :: i
|
||||
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
! elasticity matrix of the target phase in cube orientation
|
||||
if (lattice_target == 'hP') then
|
||||
if (lattice_target == 'hP' .and. present(cOverA_trans)) then
|
||||
! https://doi.org/10.1063/1.1663858 eq. (16), eq. (18), eq. (19)
|
||||
! https://doi.org/10.1016/j.actamat.2016.07.032 eq. (47), eq. (48)
|
||||
if (cOverA_trans < 1.0_pReal .or. cOverA_trans > 2.0_pReal) &
|
||||
|
@ -562,7 +562,7 @@ function lattice_C66_trans(Ntrans,C_parent66,lattice_target, &
|
|||
C_target_unrotated66(3,3) = C_bar66(3,3)
|
||||
C_target_unrotated66(4,4) = C_bar66(4,4) - C_bar66(1,4)**2/(0.5_pReal*(C_bar66(1,1) - C_bar66(1,2)))
|
||||
C_target_unrotated66 = lattice_symmetrize_C66(C_target_unrotated66,'hP')
|
||||
elseif (lattice_target == 'cI') then
|
||||
elseif (lattice_target == 'cI' .and. present(a_fcc) .and. present(a_bcc)) then
|
||||
if (a_bcc <= 0.0_pReal .or. a_fcc <= 0.0_pReal) &
|
||||
call IO_error(134,ext_msg='lattice_C66_trans: '//trim(lattice_target))
|
||||
C_target_unrotated66 = C_parent66
|
||||
|
@ -1484,26 +1484,27 @@ end function lattice_SchmidMatrix_twin
|
|||
!> @brief Schmid matrix for transformation
|
||||
!> details only active twin systems are considered
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
function lattice_SchmidMatrix_trans(Ntrans,lattice_target,cOverA,a_bcc,a_fcc) result(SchmidMatrix)
|
||||
function lattice_SchmidMatrix_trans(Ntrans,lattice_target,cOverA,a_fcc,a_bcc) result(SchmidMatrix)
|
||||
|
||||
integer, dimension(:), intent(in) :: Ntrans !< number of active twin systems per family
|
||||
character(len=2), intent(in) :: lattice_target !< Bravais lattice (Pearson symbol)
|
||||
real(pReal), intent(in) :: cOverA !< c/a ratio
|
||||
real(pReal), optional, intent(in) :: cOverA, a_bcc, a_fcc
|
||||
real(pReal), dimension(3,3,sum(Ntrans)) :: SchmidMatrix
|
||||
|
||||
real(pReal), dimension(3,3,sum(Ntrans)) :: devNull
|
||||
real(pReal) :: a_bcc, a_fcc
|
||||
|
||||
if (lattice_target /= 'cI' .and. lattice_target /= 'hP') &
|
||||
call IO_error(137,ext_msg='lattice_SchmidMatrix_trans: '//trim(lattice_target))
|
||||
|
||||
if (lattice_target == 'hP' .and. (cOverA < 1.0_pReal .or. cOverA > 2.0_pReal)) &
|
||||
if (lattice_target == 'hP' .and. present(cOverA)) then
|
||||
if (cOverA < 1.0_pReal .or. cOverA > 2.0_pReal) &
|
||||
call IO_error(131,ext_msg='lattice_SchmidMatrix_trans: '//trim(lattice_target))
|
||||
|
||||
if (lattice_target == 'cI' .and. (a_bcc <= 0.0_pReal .or. a_fcc <= 0.0_pReal)) &
|
||||
call buildTransformationSystem(devNull,SchmidMatrix,Ntrans,cOverA=cOverA)
|
||||
else if (lattice_target == 'cI' .and. present(a_fcc) .and. present(a_bcc)) then
|
||||
if (a_bcc <= 0.0_pReal .or. a_fcc <= 0.0_pReal) &
|
||||
call IO_error(134,ext_msg='lattice_SchmidMatrix_trans: '//trim(lattice_target))
|
||||
|
||||
call buildTransformationSystem(devNull,SchmidMatrix,Ntrans,cOverA,a_fcc,a_bcc)
|
||||
call buildTransformationSystem(devNull,SchmidMatrix,Ntrans,a_fcc=a_fcc,a_bcc=a_bcc)
|
||||
else
|
||||
call IO_error(131,ext_msg='lattice_SchmidMatrix_trans: '//trim(lattice_target))
|
||||
end if
|
||||
|
||||
end function lattice_SchmidMatrix_trans
|
||||
|
||||
|
@ -1971,7 +1972,7 @@ subroutine buildTransformationSystem(Q,S,Ntrans,cOverA,a_fcc,a_bcc)
|
|||
real(pReal), dimension(3,3,sum(Ntrans)), intent(out) :: &
|
||||
Q, & !< Total rotation: Q = R*B
|
||||
S !< Eigendeformation tensor for phase transformation
|
||||
real(pReal), intent(in) :: &
|
||||
real(pReal), optional, intent(in) :: &
|
||||
cOverA, & !< c/a for target hex lattice
|
||||
a_bcc, & !< lattice parameter a for bcc target lattice
|
||||
a_fcc !< lattice parameter a for fcc parent lattice
|
||||
|
@ -2050,7 +2051,7 @@ subroutine buildTransformationSystem(Q,S,Ntrans,cOverA,a_fcc,a_bcc)
|
|||
0.0, 0.0, 1.0, 45.0 &
|
||||
],shape(FCCTOBCC_BAINROT))
|
||||
|
||||
if (a_bcc > 0.0_pReal .and. a_fcc > 0.0_pReal .and. dEq0(cOverA)) then ! fcc -> bcc
|
||||
if (present(a_bcc) .and. present(a_fcc)) then
|
||||
do i = 1,sum(Ntrans)
|
||||
call R%fromAxisAngle(FCCTOBCC_SYSTEMTRANS(:,i),degrees=.true.,P=1)
|
||||
call B%fromAxisAngle(FCCTOBCC_BAINROT(:,i), degrees=.true.,P=1)
|
||||
|
@ -2064,7 +2065,7 @@ subroutine buildTransformationSystem(Q,S,Ntrans,cOverA,a_fcc,a_bcc)
|
|||
Q(1:3,1:3,i) = matmul(R%asMatrix(),B%asMatrix())
|
||||
S(1:3,1:3,i) = matmul(R%asMatrix(),U) - MATH_I3
|
||||
enddo
|
||||
elseif (cOverA > 0.0_pReal .and. dEq0(a_bcc)) then ! fcc -> hex
|
||||
else if (present(cOverA)) then
|
||||
ss = MATH_I3
|
||||
sd = MATH_I3
|
||||
ss(1,3) = sqrt(2.0_pReal)/4.0_pReal
|
||||
|
@ -2078,10 +2079,10 @@ subroutine buildTransformationSystem(Q,S,Ntrans,cOverA,a_fcc,a_bcc)
|
|||
Q(1:3,2,i) = y
|
||||
Q(1:3,3,i) = z
|
||||
S(1:3,1:3,i) = matmul(Q(1:3,1:3,i), matmul(matmul(sd,ss), transpose(Q(1:3,1:3,i)))) - MATH_I3 ! ToDo: This is of interest for the Schmid matrix only
|
||||
enddo
|
||||
end do
|
||||
else
|
||||
call IO_error(132,ext_msg='buildTransformationSystem')
|
||||
endif
|
||||
end if
|
||||
|
||||
end subroutine buildTransformationSystem
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@ module material
|
|||
material_phaseID, & ! TODO: rename to material_ID_phase
|
||||
material_phaseEntry ! TODO: rename to material_entry_phase
|
||||
|
||||
real(pReal), dimension(:,:), allocatable, public, protected :: &
|
||||
material_v ! fraction
|
||||
|
||||
public :: &
|
||||
material_init
|
||||
|
||||
|
@ -123,11 +126,13 @@ subroutine parse()
|
|||
allocate(counterPhase(phases%length),source=0)
|
||||
allocate(counterHomogenization(homogenizations%length),source=0)
|
||||
|
||||
allocate(material_homogenizationID(discretization_nIPs*discretization_Nelems),source=0)
|
||||
allocate(material_homogenizationEntry(discretization_nIPs*discretization_Nelems),source=0)
|
||||
allocate(material_homogenizationID(discretization_Ncells),source=0)
|
||||
allocate(material_homogenizationEntry(discretization_Ncells),source=0)
|
||||
|
||||
allocate(material_phaseID(homogenization_maxNconstituents,discretization_nIPs*discretization_Nelems),source=0)
|
||||
allocate(material_phaseEntry(homogenization_maxNconstituents,discretization_nIPs*discretization_Nelems),source=0)
|
||||
allocate(material_phaseID(homogenization_maxNconstituents,discretization_Ncells),source=0)
|
||||
allocate(material_phaseEntry(homogenization_maxNconstituents,discretization_Ncells),source=0)
|
||||
|
||||
allocate(material_v(homogenization_maxNconstituents,discretization_Ncells),source=0.0_pReal)
|
||||
|
||||
do el = 1, discretization_Nelems
|
||||
material => materials%get(discretization_materialAt(el))
|
||||
|
@ -140,11 +145,11 @@ subroutine parse()
|
|||
material_homogenizationEntry(ce) = counterHomogenization(ho)
|
||||
end do
|
||||
|
||||
v = 0.0_pReal
|
||||
constituents => material%get('constituents')
|
||||
do co = 1, constituents%length
|
||||
constituent => constituents%get(co)
|
||||
v = v + constituent%get_asFloat('v')
|
||||
|
||||
v = constituent%get_asFloat('v')
|
||||
|
||||
ph = phases%getIndex(constituent%get_asString('phase'))
|
||||
do ip = 1, discretization_nIPs
|
||||
|
@ -152,10 +157,12 @@ subroutine parse()
|
|||
material_phaseID(co,ce) = ph
|
||||
counterPhase(ph) = counterPhase(ph) + 1
|
||||
material_phaseEntry(co,ce) = counterPhase(ph)
|
||||
material_v(co,ce) = v
|
||||
end do
|
||||
|
||||
end do
|
||||
if (dNeq(v,1.0_pReal,1.e-12_pReal)) call IO_error(153,ext_msg='constituent')
|
||||
if (dNeq(sum(material_v(1:constituents%length,ce)),1.0_pReal,1.e-9_pReal)) &
|
||||
call IO_error(153,ext_msg='constituent')
|
||||
|
||||
end do
|
||||
|
||||
|
|
|
@ -49,9 +49,6 @@ module discretization_mesh
|
|||
mesh_ipVolume, & !< volume associated with IP (initially!)
|
||||
mesh_node0 !< node x,y,z coordinates (initially!)
|
||||
|
||||
real(pReal), pointer, dimension(:) :: &
|
||||
mesh_node0_temp
|
||||
|
||||
real(pReal), dimension(:,:,:), allocatable :: &
|
||||
mesh_ipCoordinates !< IP x,y,z coordinates (after deformation!)
|
||||
|
||||
|
@ -88,6 +85,8 @@ subroutine discretization_mesh_init(restart)
|
|||
num_mesh
|
||||
integer :: p_i, dim !< integration order (quadrature rule)
|
||||
type(tvec) :: coords_node0
|
||||
real(pReal), pointer, dimension(:) :: &
|
||||
mesh_node0_temp
|
||||
|
||||
print'(/,1x,a)', '<<<+- discretization_mesh init -+>>>'
|
||||
|
||||
|
@ -124,7 +123,7 @@ subroutine discretization_mesh_init(restart)
|
|||
dimPlex = int(dim,pPETSCINT)
|
||||
if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error'
|
||||
|
||||
if (worldrank == 0) then
|
||||
if (worldsize == 1) then
|
||||
call DMClone(globalMesh,geomMesh,err_PETSc)
|
||||
else
|
||||
call DMPlexDistribute(globalMesh,0_pPETSCINT,sf,geomMesh,err_PETSc)
|
||||
|
@ -155,7 +154,7 @@ subroutine discretization_mesh_init(restart)
|
|||
CHKERRQ(err_PETSc)
|
||||
|
||||
! Get initial nodal coordinates
|
||||
call DMGetCoordinates(geomMesh,coords_node0,err_PETSc)
|
||||
call DMGetCoordinatesLocal(geomMesh,coords_node0,err_PETSc)
|
||||
CHKERRQ(err_PETSc)
|
||||
call VecGetArrayF90(coords_node0, mesh_node0_temp,err_PETSc)
|
||||
CHKERRQ(err_PETSc)
|
||||
|
|
|
@ -140,15 +140,15 @@ submodule(phase:mechanical) plastic
|
|||
dotState
|
||||
end function plastic_kinehardening_dotState
|
||||
|
||||
module subroutine dislotwin_dotState(Mp,T,ph,en)
|
||||
module function dislotwin_dotState(Mp,ph,en) result(dotState)
|
||||
real(pReal), dimension(3,3), intent(in) :: &
|
||||
Mp !< Mandel stress
|
||||
real(pReal), intent(in) :: &
|
||||
T
|
||||
integer, intent(in) :: &
|
||||
ph, &
|
||||
en
|
||||
end subroutine dislotwin_dotState
|
||||
real(pReal), dimension(plasticState(ph)%sizeDotState) :: &
|
||||
dotState
|
||||
end function dislotwin_dotState
|
||||
|
||||
module function dislotungsten_dotState(Mp,ph,en) result(dotState)
|
||||
real(pReal), dimension(3,3), intent(in) :: &
|
||||
|
@ -170,12 +170,10 @@ submodule(phase:mechanical) plastic
|
|||
en
|
||||
end subroutine nonlocal_dotState
|
||||
|
||||
module subroutine dislotwin_dependentState(T,ph,en)
|
||||
module subroutine dislotwin_dependentState(ph,en)
|
||||
integer, intent(in) :: &
|
||||
ph, &
|
||||
en
|
||||
real(pReal), intent(in) :: &
|
||||
T
|
||||
end subroutine dislotwin_dependentState
|
||||
|
||||
module subroutine dislotungsten_dependentState(ph,en)
|
||||
|
@ -326,8 +324,7 @@ module function plastic_dotState(subdt,ph,en) result(dotState)
|
|||
dotState = plastic_kinehardening_dotState(Mp,ph,en)
|
||||
|
||||
case (PLASTIC_DISLOTWIN_ID) plasticType
|
||||
call dislotwin_dotState(Mp,thermal_T(ph,en),ph,en)
|
||||
dotState = plasticState(ph)%dotState(:,en)
|
||||
dotState = dislotwin_dotState(Mp,ph,en)
|
||||
|
||||
case (PLASTIC_DISLOTUNGSTEN_ID) plasticType
|
||||
dotState = dislotungsten_dotState(Mp,ph,en)
|
||||
|
@ -355,7 +352,7 @@ module subroutine plastic_dependentState(ph,en)
|
|||
plasticType: select case (phase_plasticity(ph))
|
||||
|
||||
case (PLASTIC_DISLOTWIN_ID) plasticType
|
||||
call dislotwin_dependentState(thermal_T(ph,en),ph,en)
|
||||
call dislotwin_dependentState(ph,en)
|
||||
|
||||
case (PLASTIC_DISLOTUNGSTEN_ID) plasticType
|
||||
call dislotungsten_dependentState(ph,en)
|
||||
|
|
|
@ -17,22 +17,23 @@ submodule(phase:plastic) dislotwin
|
|||
p_sb = 1.0_pReal, & !< p-exponent in shear band velocity
|
||||
q_sb = 1.0_pReal, & !< q-exponent in shear band velocity
|
||||
i_tw = 1.0_pReal, & !< adjustment parameter to calculate MFP for twinning
|
||||
L_tw = 1.0_pReal, & !< length of twin nuclei in Burgers vectors: TODO unit should be meters
|
||||
L_tr = 1.0_pReal, & !< length of trans nuclei in Burgers vectors: TODO unit should be meters
|
||||
x_c_tw = 1.0_pReal, & !< critical distance for formation of twin nucleus
|
||||
x_c_tr = 1.0_pReal, & !< critical distance for formation of trans nucleus
|
||||
i_tr = 1.0_pReal, & !< adjustment parameter to calculate MFP for transformation
|
||||
L_tw = 1.0_pReal, & !< length of twin nuclei
|
||||
L_tr = 1.0_pReal, & !< length of trans nuclei
|
||||
x_c = 1.0_pReal, & !< critical distance for formation of twin/trans nucleus
|
||||
V_cs = 1.0_pReal, & !< cross slip volume
|
||||
xi_sb = 1.0_pReal, & !< value for shearband resistance
|
||||
v_sb = 1.0_pReal, & !< value for shearband velocity_0
|
||||
E_sb = 1.0_pReal, & !< activation energy for shear bands
|
||||
delta_G = 1.0_pReal, & !< free energy difference between austensite and martensite
|
||||
i_tr = 1.0_pReal, & !< adjustment parameter to calculate MFP for transformation
|
||||
h = 1.0_pReal, & !< stack height of hex nucleus
|
||||
T_ref = T_ROOM, &
|
||||
a_cI = 1.0_pReal, &
|
||||
a_cF = 1.0_pReal
|
||||
real(pReal), dimension(2) :: &
|
||||
Gamma_sf = 0.0_pReal
|
||||
gamma_char_tr = sqrt(0.125_pReal), & !< Characteristic shear for transformation
|
||||
a_cF = 1.0_pReal, &
|
||||
cOverA_hP = 1.0_pReal, &
|
||||
V_mol = 1.0_pReal, &
|
||||
rho = 1.0_pReal
|
||||
type(tPolynomial) :: &
|
||||
Gamma_sf, & !< stacking fault energy
|
||||
Delta_G !< free energy difference between austensite and martensite
|
||||
real(pReal), allocatable, dimension(:) :: &
|
||||
b_sl, & !< absolute length of Burgers vector [m] for each slip system
|
||||
b_tw, & !< absolute length of Burgers vector [m] for each twin system
|
||||
|
@ -48,7 +49,7 @@ submodule(phase:plastic) dislotwin
|
|||
r, & !< exponent in twin nucleation rate
|
||||
s, & !< exponent in trans nucleation rate
|
||||
tau_0, & !< strength due to elements in solid solution
|
||||
gamma_char, & !< characteristic shear for twins
|
||||
gamma_char_tw, & !< characteristic shear for twins
|
||||
B, & !< drag coefficient
|
||||
d_caron !< distance of spontaneous annhihilation
|
||||
real(pReal), allocatable, dimension(:,:) :: &
|
||||
|
@ -77,13 +78,22 @@ submodule(phase:plastic) dislotwin
|
|||
character(len=pStringLen), allocatable, dimension(:) :: &
|
||||
output
|
||||
logical :: &
|
||||
ExtendedDislocations, & !< consider split into partials for climb calculation
|
||||
extendedDislocations, & !< consider split into partials for climb calculation
|
||||
fccTwinTransNucleation, & !< twinning and transformation models are for fcc
|
||||
omitDipoles !< flag controlling consideration of dipole formation
|
||||
character(len=:), allocatable, dimension(:) :: &
|
||||
systems_sl, &
|
||||
systems_tw
|
||||
end type !< container type for internal constitutive parameters
|
||||
end type tParameters !< container type for internal constitutive parameters
|
||||
|
||||
type :: tIndexDotState
|
||||
integer, dimension(2) :: &
|
||||
rho_mob, &
|
||||
rho_dip, &
|
||||
gamma_sl, &
|
||||
f_tw, &
|
||||
f_tr
|
||||
end type tIndexDotState
|
||||
|
||||
type :: tDislotwinState
|
||||
real(pReal), dimension(:,:), pointer :: &
|
||||
|
@ -99,17 +109,14 @@ submodule(phase:plastic) dislotwin
|
|||
Lambda_sl, & !< mean free path between 2 obstacles seen by a moving dislocation
|
||||
Lambda_tw, & !< mean free path between 2 obstacles seen by a growing twin
|
||||
Lambda_tr, & !< mean free path between 2 obstacles seen by a growing martensite
|
||||
tau_pass, & !< threshold stress for slip
|
||||
tau_hat_tw, & !< threshold stress for twinning
|
||||
tau_hat_tr !< threshold stress for transformation
|
||||
tau_pass !< threshold stress for slip
|
||||
end type tDislotwinDependentState
|
||||
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
! containers for parameters and state
|
||||
type(tParameters), allocatable, dimension(:) :: param
|
||||
type(tDislotwinState), allocatable, dimension(:) :: &
|
||||
dotState, &
|
||||
state
|
||||
type(tIndexDotState), allocatable, dimension(:) :: indexDotState
|
||||
type(tDislotwinState), allocatable, dimension(:) :: state
|
||||
type(tDislotwinDependentState), allocatable, dimension(:) :: dependentState
|
||||
|
||||
contains
|
||||
|
@ -129,6 +136,7 @@ module function plastic_dislotwin_init() result(myPlasticity)
|
|||
startIndex, endIndex
|
||||
integer, dimension(:), allocatable :: &
|
||||
N_sl
|
||||
real(pReal) :: a_cF
|
||||
real(pReal), allocatable, dimension(:) :: &
|
||||
rho_mob_0, & !< initial unipolar dislocation density per slip system
|
||||
rho_dip_0 !< initial dipole dislocation density per slip system
|
||||
|
@ -159,15 +167,15 @@ module function plastic_dislotwin_init() result(myPlasticity)
|
|||
|
||||
phases => config_material%get('phase')
|
||||
allocate(param(phases%length))
|
||||
allocate(indexDotState(phases%length))
|
||||
allocate(state(phases%length))
|
||||
allocate(dotState(phases%length))
|
||||
allocate(dependentState(phases%length))
|
||||
|
||||
|
||||
do ph = 1, phases%length
|
||||
if (.not. myPlasticity(ph)) cycle
|
||||
|
||||
associate(prm => param(ph), dot => dotState(ph), stt => state(ph), dst => dependentState(ph))
|
||||
associate(prm => param(ph), stt => state(ph), dst => dependentState(ph), &
|
||||
idx_dot => indexDotState(ph))
|
||||
|
||||
phase => phases%get(ph)
|
||||
mech => phase%get('mechanical')
|
||||
|
@ -179,7 +187,6 @@ module function plastic_dislotwin_init() result(myPlasticity)
|
|||
prm%output = pl%get_as1dString('output',defaultVal=emptyStringArray)
|
||||
#endif
|
||||
|
||||
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
! slip related parameters
|
||||
N_sl = pl%get_as1dInt('N_sl',defaultVal=emptyIntArray)
|
||||
|
@ -209,7 +216,7 @@ module function plastic_dislotwin_init() result(myPlasticity)
|
|||
|
||||
prm%Q_cl = pl%get_asFloat('Q_cl')
|
||||
|
||||
prm%ExtendedDislocations = pl%get_asBool('extend_dislocations',defaultVal = .false.)
|
||||
prm%extendedDislocations = pl%get_asBool('extend_dislocations',defaultVal = .false.)
|
||||
prm%omitDipoles = pl%get_asBool('omit_dipoles',defaultVal = .false.)
|
||||
|
||||
! multiplication factor according to crystal structure (nearest neighbors bcc vs fcc/hex)
|
||||
|
@ -250,7 +257,7 @@ module function plastic_dislotwin_init() result(myPlasticity)
|
|||
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
! twin related parameters
|
||||
prm%N_tw = pl%get_as1dInt('N_tw', defaultVal=emptyIntArray)
|
||||
prm%N_tw = pl%get_as1dInt('N_tw', defaultVal=emptyIntArray)
|
||||
prm%sum_N_tw = sum(abs(prm%N_tw))
|
||||
twinActive: if (prm%sum_N_tw > 0) then
|
||||
prm%systems_tw = lattice_labels_twin(prm%N_tw,phase_lattice(ph))
|
||||
|
@ -262,16 +269,10 @@ module function plastic_dislotwin_init() result(myPlasticity)
|
|||
prm%t_tw = pl%get_as1dFloat('t_tw', requiredSize=size(prm%N_tw))
|
||||
prm%r = pl%get_as1dFloat('p_tw', requiredSize=size(prm%N_tw))
|
||||
|
||||
prm%x_c_tw = pl%get_asFloat('x_c_tw')
|
||||
prm%L_tw = pl%get_asFloat('L_tw')
|
||||
prm%i_tw = pl%get_asFloat('i_tw')
|
||||
|
||||
prm%gamma_char= lattice_characteristicShear_Twin(prm%N_tw,phase_lattice(ph),phase_cOverA(ph))
|
||||
|
||||
if (.not. prm%fccTwinTransNucleation) then
|
||||
prm%dot_N_0_tw = pl%get_as1dFloat('dot_N_0_tw')
|
||||
prm%dot_N_0_tw = math_expand(prm%dot_N_0_tw,prm%N_tw)
|
||||
endif
|
||||
prm%gamma_char_tw = lattice_characteristicShear_Twin(prm%N_tw,phase_lattice(ph),phase_cOverA(ph))
|
||||
|
||||
! expand: family => system
|
||||
prm%b_tw = math_expand(prm%b_tw,prm%N_tw)
|
||||
|
@ -279,54 +280,47 @@ module function plastic_dislotwin_init() result(myPlasticity)
|
|||
prm%r = math_expand(prm%r,prm%N_tw)
|
||||
|
||||
! sanity checks
|
||||
if ( prm%x_c_tw < 0.0_pReal) extmsg = trim(extmsg)//' x_c_tw'
|
||||
if (.not. prm%fccTwinTransNucleation) extmsg = trim(extmsg)//' TWIP for non-fcc'
|
||||
if ( prm%L_tw < 0.0_pReal) extmsg = trim(extmsg)//' L_tw'
|
||||
if ( prm%i_tw < 0.0_pReal) extmsg = trim(extmsg)//' i_tw'
|
||||
if (any(prm%b_tw < 0.0_pReal)) extmsg = trim(extmsg)//' b_tw'
|
||||
if (any(prm%t_tw < 0.0_pReal)) extmsg = trim(extmsg)//' t_tw'
|
||||
if (any(prm%r < 0.0_pReal)) extmsg = trim(extmsg)//' p_tw'
|
||||
if (.not. prm%fccTwinTransNucleation) then
|
||||
if (any(prm%dot_N_0_tw < 0.0_pReal)) extmsg = trim(extmsg)//' dot_N_0_tw'
|
||||
end if
|
||||
else twinActive
|
||||
allocate(prm%gamma_char,prm%b_tw,prm%dot_N_0_tw,prm%t_tw,prm%r,source=emptyRealArray)
|
||||
allocate(prm%gamma_char_tw,prm%b_tw,prm%t_tw,prm%r,source=emptyRealArray)
|
||||
allocate(prm%h_tw_tw(0,0))
|
||||
end if twinActive
|
||||
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
! transformation related parameters
|
||||
prm%N_tr = pl%get_as1dInt('N_tr', defaultVal=emptyIntArray)
|
||||
prm%N_tr = pl%get_as1dInt('N_tr', defaultVal=emptyIntArray)
|
||||
prm%sum_N_tr = sum(abs(prm%N_tr))
|
||||
transActive: if (prm%sum_N_tr > 0) then
|
||||
prm%b_tr = pl%get_as1dFloat('b_tr')
|
||||
prm%b_tr = math_expand(prm%b_tr,prm%N_tr)
|
||||
|
||||
prm%h = pl%get_asFloat('h', defaultVal=0.0_pReal) ! ToDo: This is not optional!
|
||||
prm%i_tr = pl%get_asFloat('i_tr', defaultVal=0.0_pReal) ! ToDo: This is not optional!
|
||||
prm%delta_G = pl%get_asFloat('delta_G')
|
||||
prm%x_c_tr = pl%get_asFloat('x_c_tr', defaultVal=0.0_pReal) ! ToDo: This is not optional!
|
||||
prm%L_tr = pl%get_asFloat('L_tr')
|
||||
prm%a_cI = pl%get_asFloat('a_cI', defaultVal=0.0_pReal)
|
||||
prm%a_cF = pl%get_asFloat('a_cF', defaultVal=0.0_pReal)
|
||||
|
||||
prm%lattice_tr = pl%get_asString('lattice_tr')
|
||||
|
||||
prm%i_tr = pl%get_asFloat('i_tr')
|
||||
prm%Delta_G = polynomial(pl%asDict(),'Delta_G','T')
|
||||
prm%L_tr = pl%get_asFloat('L_tr')
|
||||
a_cF = pl%get_asFloat('a_cF')
|
||||
prm%h = 5.0_pReal * a_cF/sqrt(3.0_pReal)
|
||||
prm%cOverA_hP = pl%get_asFloat('c/a_hP')
|
||||
prm%rho = 4.0_pReal/(sqrt(3.0_pReal)*a_cF**2)/N_A
|
||||
prm%V_mol = pl%get_asFloat('V_mol')
|
||||
prm%h_tr_tr = lattice_interaction_TransByTrans(prm%N_tr,pl%get_as1dFloat('h_tr-tr'),&
|
||||
phase_lattice(ph))
|
||||
|
||||
prm%P_tr = lattice_SchmidMatrix_trans(prm%N_tr,prm%lattice_tr, &
|
||||
0.0_pReal, &
|
||||
prm%a_cI, &
|
||||
prm%a_cF)
|
||||
prm%P_tr = lattice_SchmidMatrix_trans(prm%N_tr,'hP',prm%cOverA_hP)
|
||||
|
||||
prm%t_tr = pl%get_as1dFloat('t_tr')
|
||||
prm%t_tr = math_expand(prm%t_tr,prm%N_tr)
|
||||
prm%s = pl%get_as1dFloat('p_tr',defaultVal=[0.0_pReal])
|
||||
prm%s = pl%get_as1dFloat('p_tr')
|
||||
prm%s = math_expand(prm%s,prm%N_tr)
|
||||
|
||||
! sanity checks
|
||||
if ( prm%x_c_tr < 0.0_pReal) extmsg = trim(extmsg)//' x_c_tr'
|
||||
if (.not. prm%fccTwinTransNucleation) extmsg = trim(extmsg)//' TRIP for non-fcc'
|
||||
if ( prm%L_tr < 0.0_pReal) extmsg = trim(extmsg)//' L_tr'
|
||||
if ( prm%V_mol < 0.0_pReal) extmsg = trim(extmsg)//' V_mol'
|
||||
if ( prm%i_tr < 0.0_pReal) extmsg = trim(extmsg)//' i_tr'
|
||||
if (any(prm%t_tr < 0.0_pReal)) extmsg = trim(extmsg)//' t_tr'
|
||||
if (any(prm%s < 0.0_pReal)) extmsg = trim(extmsg)//' p_tr'
|
||||
|
@ -356,15 +350,16 @@ module function plastic_dislotwin_init() result(myPlasticity)
|
|||
if (prm%sum_N_sl + prm%sum_N_tw + prm%sum_N_tw > 0) &
|
||||
prm%D = pl%get_asFloat('D')
|
||||
|
||||
if (prm%sum_N_tw + prm%sum_N_tr > 0) &
|
||||
if (prm%sum_N_tw + prm%sum_N_tr > 0) then
|
||||
prm%x_c = pl%get_asFloat('x_c')
|
||||
prm%V_cs = pl%get_asFloat('V_cs')
|
||||
|
||||
if (prm%sum_N_tw + prm%sum_N_tr > 0 .or. prm%ExtendedDislocations) then
|
||||
prm%T_ref = pl%get_asFloat('T_ref')
|
||||
prm%Gamma_sf(1) = pl%get_asFloat('Gamma_sf')
|
||||
prm%Gamma_sf(2) = pl%get_asFloat('Gamma_sf,T',defaultVal=0.0_pReal)
|
||||
if (prm%x_c < 0.0_pReal) extmsg = trim(extmsg)//' x_c'
|
||||
if (prm%V_cs < 0.0_pReal) extmsg = trim(extmsg)//' V_cs'
|
||||
end if
|
||||
|
||||
if (prm%sum_N_tw + prm%sum_N_tr > 0 .or. prm%extendedDislocations) &
|
||||
prm%Gamma_sf = polynomial(pl%asDict(),'Gamma_sf','T')
|
||||
|
||||
slipAndTwinActive: if (prm%sum_N_sl * prm%sum_N_tw > 0) then
|
||||
prm%h_sl_tw = lattice_interaction_SlipByTwin(N_sl,prm%N_tw,pl%get_as1dFloat('h_sl-tw'), &
|
||||
phase_lattice(ph))
|
||||
|
@ -385,55 +380,51 @@ module function plastic_dislotwin_init() result(myPlasticity)
|
|||
+ size(['f_tr']) * prm%sum_N_tr
|
||||
sizeState = sizeDotState
|
||||
|
||||
|
||||
call phase_allocateState(plasticState(ph),Nmembers,sizeState,sizeDotState,0)
|
||||
deallocate(plasticState(ph)%dotState) ! ToDo: remove dotState completely
|
||||
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
! locally defined state aliases and initialization of state0 and atol
|
||||
! state aliases and initialization
|
||||
startIndex = 1
|
||||
endIndex = prm%sum_N_sl
|
||||
idx_dot%rho_mob = [startIndex,endIndex]
|
||||
stt%rho_mob=>plasticState(ph)%state(startIndex:endIndex,:)
|
||||
stt%rho_mob= spread(rho_mob_0,2,Nmembers)
|
||||
dot%rho_mob=>plasticState(ph)%dotState(startIndex:endIndex,:)
|
||||
plasticState(ph)%atol(startIndex:endIndex) = pl%get_asFloat('atol_rho',defaultVal=1.0_pReal)
|
||||
if (any(plasticState(ph)%atol(startIndex:endIndex) < 0.0_pReal)) extmsg = trim(extmsg)//' atol_rho'
|
||||
|
||||
startIndex = endIndex + 1
|
||||
endIndex = endIndex + prm%sum_N_sl
|
||||
idx_dot%rho_dip = [startIndex,endIndex]
|
||||
stt%rho_dip=>plasticState(ph)%state(startIndex:endIndex,:)
|
||||
stt%rho_dip= spread(rho_dip_0,2,Nmembers)
|
||||
dot%rho_dip=>plasticState(ph)%dotState(startIndex:endIndex,:)
|
||||
plasticState(ph)%atol(startIndex:endIndex) = pl%get_asFloat('atol_rho',defaultVal=1.0_pReal)
|
||||
|
||||
startIndex = endIndex + 1
|
||||
endIndex = endIndex + prm%sum_N_sl
|
||||
idx_dot%gamma_sl = [startIndex,endIndex]
|
||||
stt%gamma_sl=>plasticState(ph)%state(startIndex:endIndex,:)
|
||||
dot%gamma_sl=>plasticState(ph)%dotState(startIndex:endIndex,:)
|
||||
plasticState(ph)%atol(startIndex:endIndex) = pl%get_asFloat('atol_gamma',defaultVal=1.0e-6_pReal)
|
||||
if (any(plasticState(ph)%atol(startIndex:endIndex) < 0.0_pReal)) extmsg = trim(extmsg)//' atol_gamma'
|
||||
|
||||
startIndex = endIndex + 1
|
||||
endIndex = endIndex + prm%sum_N_tw
|
||||
idx_dot%f_tw = [startIndex,endIndex]
|
||||
stt%f_tw=>plasticState(ph)%state(startIndex:endIndex,:)
|
||||
dot%f_tw=>plasticState(ph)%dotState(startIndex:endIndex,:)
|
||||
plasticState(ph)%atol(startIndex:endIndex) = pl%get_asFloat('atol_f_tw',defaultVal=1.0e-6_pReal)
|
||||
if (any(plasticState(ph)%atol(startIndex:endIndex) < 0.0_pReal)) extmsg = trim(extmsg)//' atol_f_tw'
|
||||
|
||||
startIndex = endIndex + 1
|
||||
endIndex = endIndex + prm%sum_N_tr
|
||||
idx_dot%f_tr = [startIndex,endIndex]
|
||||
stt%f_tr=>plasticState(ph)%state(startIndex:endIndex,:)
|
||||
dot%f_tr=>plasticState(ph)%dotState(startIndex:endIndex,:)
|
||||
plasticState(ph)%atol(startIndex:endIndex) = pl%get_asFloat('atol_f_tr',defaultVal=1.0e-6_pReal)
|
||||
if (any(plasticState(ph)%atol(startIndex:endIndex) < 0.0_pReal)) extmsg = trim(extmsg)//' atol_f_tr'
|
||||
|
||||
allocate(dst%Lambda_sl (prm%sum_N_sl,Nmembers),source=0.0_pReal)
|
||||
allocate(dst%tau_pass (prm%sum_N_sl,Nmembers),source=0.0_pReal)
|
||||
|
||||
allocate(dst%Lambda_tw (prm%sum_N_tw,Nmembers),source=0.0_pReal)
|
||||
allocate(dst%tau_hat_tw (prm%sum_N_tw,Nmembers),source=0.0_pReal)
|
||||
|
||||
allocate(dst%Lambda_tr (prm%sum_N_tr,Nmembers),source=0.0_pReal)
|
||||
allocate(dst%tau_hat_tr (prm%sum_N_tr,Nmembers),source=0.0_pReal)
|
||||
allocate(dst%tau_pass (prm%sum_N_sl,Nmembers),source=0.0_pReal)
|
||||
allocate(dst%Lambda_sl(prm%sum_N_sl,Nmembers),source=0.0_pReal)
|
||||
allocate(dst%Lambda_tw(prm%sum_N_tw,Nmembers),source=0.0_pReal)
|
||||
allocate(dst%Lambda_tr(prm%sum_N_tr,Nmembers),source=0.0_pReal)
|
||||
|
||||
end associate
|
||||
|
||||
|
@ -482,7 +473,7 @@ module function plastic_dislotwin_homogenizedC(ph,en) result(homogenizedC)
|
|||
end if twinActive
|
||||
|
||||
transActive: if (prm%sum_N_tr > 0) then
|
||||
C66_tr = lattice_C66_trans(prm%N_tr,C,prm%lattice_tr,0.0_pReal,prm%a_cI,prm%a_cF)
|
||||
C66_tr = lattice_C66_trans(prm%N_tr,C,'hP',prm%cOverA_hP)
|
||||
do i=1,prm%sum_N_tr
|
||||
homogenizedC = homogenizedC &
|
||||
+ stt%f_tr(i,en)*C66_tr(1:6,1:6,i)
|
||||
|
@ -559,7 +550,7 @@ module subroutine dislotwin_LpAndItsTangent(Lp,dLp_dMp,Mp,ph,en)
|
|||
+ ddot_gamma_dtau_sl(i) * prm%P_sl(k,l,i) * prm%P_sl(m,n,i)
|
||||
end do slipContribution
|
||||
|
||||
call kinetics_tw(Mp,T,dot_gamma_sl,ph,en,dot_gamma_tw,ddot_gamma_dtau_tw)
|
||||
if (prm%sum_N_tw > 0) call kinetics_tw(Mp,T,dot_gamma_sl,ph,en,dot_gamma_tw,ddot_gamma_dtau_tw)
|
||||
twinContibution: do i = 1, prm%sum_N_tw
|
||||
Lp = Lp + dot_gamma_tw(i)*prm%P_tw(1:3,1:3,i)
|
||||
forall (k=1:3,l=1:3,m=1:3,n=1:3) &
|
||||
|
@ -567,7 +558,7 @@ module subroutine dislotwin_LpAndItsTangent(Lp,dLp_dMp,Mp,ph,en)
|
|||
+ ddot_gamma_dtau_tw(i)* prm%P_tw(k,l,i)*prm%P_tw(m,n,i)
|
||||
end do twinContibution
|
||||
|
||||
call kinetics_tr(Mp,T,dot_gamma_sl,ph,en,dot_gamma_tr,ddot_gamma_dtau_tr)
|
||||
if (prm%sum_N_tr > 0) call kinetics_tr(Mp,T,dot_gamma_sl,ph,en,dot_gamma_tr,ddot_gamma_dtau_tr)
|
||||
transContibution: do i = 1, prm%sum_N_tr
|
||||
Lp = Lp + dot_gamma_tr(i)*prm%P_tr(1:3,1:3,i)
|
||||
forall (k=1:3,l=1:3,m=1:3,n=1:3) &
|
||||
|
@ -581,7 +572,7 @@ module subroutine dislotwin_LpAndItsTangent(Lp,dLp_dMp,Mp,ph,en)
|
|||
shearBandingContribution: if (dNeq0(prm%v_sb)) then
|
||||
|
||||
E_kB_T = prm%E_sb/(K_B*T)
|
||||
call math_eigh33(eigValues,eigVectors,Mp) ! is Mp symmetric by design?
|
||||
call math_eigh33(eigValues,eigVectors,Mp) ! is Mp symmetric by design?
|
||||
|
||||
do i = 1,6
|
||||
P_sb = 0.5_pReal * math_outer(matmul(eigVectors,sb_sComposition(1:3,i)),&
|
||||
|
@ -612,15 +603,15 @@ end subroutine dislotwin_LpAndItsTangent
|
|||
!--------------------------------------------------------------------------------------------------
|
||||
!> @brief Calculate the rate of change of microstructure.
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
module subroutine dislotwin_dotState(Mp,T,ph,en)
|
||||
module function dislotwin_dotState(Mp,ph,en) result(dotState)
|
||||
|
||||
real(pReal), dimension(3,3), intent(in):: &
|
||||
Mp !< Mandel stress
|
||||
real(pReal), intent(in) :: &
|
||||
T !< temperature at integration point
|
||||
integer, intent(in) :: &
|
||||
ph, &
|
||||
en
|
||||
real(pReal), dimension(plasticState(ph)%sizeDotState) :: &
|
||||
dotState
|
||||
|
||||
integer :: i
|
||||
real(pReal) :: &
|
||||
|
@ -639,22 +630,27 @@ module subroutine dislotwin_dotState(Mp,T,ph,en)
|
|||
real(pReal), dimension(param(ph)%sum_N_tr) :: &
|
||||
dot_gamma_tr
|
||||
real(pReal) :: &
|
||||
mu, &
|
||||
nu, &
|
||||
Gamma
|
||||
mu, nu, &
|
||||
T
|
||||
|
||||
associate(prm => param(ph), stt => state(ph), dot => dotState(ph), dst => dependentState(ph))
|
||||
|
||||
associate(prm => param(ph), stt => state(ph), dst => dependentState(ph), &
|
||||
dot_rho_mob => dotState(indexDotState(ph)%rho_mob(1):indexDotState(ph)%rho_mob(2)), &
|
||||
dot_rho_dip => dotState(indexDotState(ph)%rho_dip(1):indexDotState(ph)%rho_dip(2)), &
|
||||
abs_dot_gamma_sl => dotState(indexDotState(ph)%gamma_sl(1):indexDotState(ph)%gamma_sl(2)), &
|
||||
dot_f_tw => dotState(indexDotState(ph)%f_tw(1):indexDotState(ph)%f_tw(2)), &
|
||||
dot_f_tr => dotState(indexDotState(ph)%f_tr(1):indexDotState(ph)%f_tr(2)))
|
||||
|
||||
mu = elastic_mu(ph,en)
|
||||
nu = elastic_nu(ph,en)
|
||||
Gamma = prm%Gamma_sf(1) + prm%Gamma_sf(2) * (T-prm%T_ref)
|
||||
T = thermal_T(ph,en)
|
||||
|
||||
f_matrix = 1.0_pReal &
|
||||
- sum(stt%f_tw(1:prm%sum_N_tw,en)) &
|
||||
- sum(stt%f_tr(1:prm%sum_N_tr,en))
|
||||
|
||||
call kinetics_sl(Mp,T,ph,en,dot_gamma_sl)
|
||||
dot%gamma_sl(:,en) = abs(dot_gamma_sl)
|
||||
abs_dot_gamma_sl = abs(dot_gamma_sl)
|
||||
|
||||
slipState: do i = 1, prm%sum_N_sl
|
||||
tau = math_tensordot(Mp,prm%P_sl(1:3,1:3,i))
|
||||
|
@ -668,16 +664,18 @@ module subroutine dislotwin_dotState(Mp,T,ph,en)
|
|||
d_hat = math_clip(d_hat, left = prm%d_caron(i))
|
||||
|
||||
dot_rho_dip_formation(i) = 2.0_pReal*(d_hat-prm%d_caron(i))/prm%b_sl(i) &
|
||||
* stt%rho_mob(i,en)*abs(dot_gamma_sl(i))
|
||||
* stt%rho_mob(i,en)*abs_dot_gamma_sl(i)
|
||||
|
||||
if (dEq(d_hat,prm%d_caron(i))) then
|
||||
dot_rho_dip_climb(i) = 0.0_pReal
|
||||
else
|
||||
! Argon & Moffat, Acta Metallurgica, Vol. 29, pg 293 to 299, 1981
|
||||
sigma_cl = dot_product(prm%n0_sl(1:3,i),matmul(Mp,prm%n0_sl(1:3,i)))
|
||||
b_d = merge(24.0_pReal*PI*(1.0_pReal - nu)/(2.0_pReal + nu) * Gamma / (mu*prm%b_sl(i)), &
|
||||
1.0_pReal, &
|
||||
prm%ExtendedDislocations)
|
||||
if (prm%extendedDislocations) then
|
||||
b_d = 24.0_pReal*PI*(1.0_pReal - nu)/(2.0_pReal + nu) * prm%Gamma_sf%at(T) / (mu*prm%b_sl(i))
|
||||
else
|
||||
b_d = 1.0_pReal
|
||||
end if
|
||||
v_cl = 2.0_pReal*prm%omega*b_d**2*exp(-prm%Q_cl/(K_B*T)) &
|
||||
* (exp(abs(sigma_cl)*prm%b_sl(i)**3/(K_B*T)) - 1.0_pReal)
|
||||
|
||||
|
@ -687,38 +685,36 @@ module subroutine dislotwin_dotState(Mp,T,ph,en)
|
|||
end if significantSlipStress
|
||||
end do slipState
|
||||
|
||||
dot%rho_mob(:,en) = abs(dot_gamma_sl)/(prm%b_sl*dst%Lambda_sl(:,en)) &
|
||||
- dot_rho_dip_formation &
|
||||
- 2.0_pReal*prm%d_caron/prm%b_sl * stt%rho_mob(:,en)*abs(dot_gamma_sl)
|
||||
dot_rho_mob = abs_dot_gamma_sl/(prm%b_sl*dst%Lambda_sl(:,en)) &
|
||||
- dot_rho_dip_formation &
|
||||
- 2.0_pReal*prm%d_caron/prm%b_sl * stt%rho_mob(:,en)*abs_dot_gamma_sl
|
||||
|
||||
dot%rho_dip(:,en) = dot_rho_dip_formation &
|
||||
- 2.0_pReal*prm%d_caron/prm%b_sl * stt%rho_dip(:,en)*abs(dot_gamma_sl) &
|
||||
- dot_rho_dip_climb
|
||||
dot_rho_dip = dot_rho_dip_formation &
|
||||
- 2.0_pReal*prm%d_caron/prm%b_sl * stt%rho_dip(:,en)*abs_dot_gamma_sl &
|
||||
- dot_rho_dip_climb
|
||||
|
||||
call kinetics_tw(Mp,T,dot_gamma_sl,ph,en,dot_gamma_tw)
|
||||
dot%f_tw(:,en) = f_matrix*dot_gamma_tw/prm%gamma_char
|
||||
if (prm%sum_N_tw > 0) call kinetics_tw(Mp,T,abs_dot_gamma_sl,ph,en,dot_gamma_tw)
|
||||
dot_f_tw = f_matrix*dot_gamma_tw/prm%gamma_char_tw
|
||||
|
||||
call kinetics_tr(Mp,T,dot_gamma_sl,ph,en,dot_gamma_tr)
|
||||
dot%f_tr(:,en) = f_matrix*dot_gamma_tr
|
||||
if (prm%sum_N_tr > 0) call kinetics_tr(Mp,T,abs_dot_gamma_sl,ph,en,dot_gamma_tr)
|
||||
dot_f_tr = f_matrix*dot_gamma_tr/prm%gamma_char_tr
|
||||
|
||||
end associate
|
||||
|
||||
end subroutine dislotwin_dotState
|
||||
end function dislotwin_dotState
|
||||
|
||||
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
!> @brief Calculate derived quantities from state.
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
module subroutine dislotwin_dependentState(T,ph,en)
|
||||
module subroutine dislotwin_dependentState(ph,en)
|
||||
|
||||
integer, intent(in) :: &
|
||||
ph, &
|
||||
en
|
||||
real(pReal), intent(in) :: &
|
||||
T
|
||||
|
||||
real(pReal) :: &
|
||||
sumf_tw,Gamma,sumf_tr
|
||||
sumf_tw, sumf_tr
|
||||
real(pReal), dimension(param(ph)%sum_N_sl) :: &
|
||||
inv_lambda_sl
|
||||
real(pReal), dimension(param(ph)%sum_N_tw) :: &
|
||||
|
@ -728,19 +724,15 @@ module subroutine dislotwin_dependentState(T,ph,en)
|
|||
inv_lambda_tr_tr, & !< 1/mean free distance between 2 martensite stacks from different systems seen by a growing martensite
|
||||
f_over_t_tr
|
||||
real(pReal) :: &
|
||||
mu, &
|
||||
nu
|
||||
mu
|
||||
|
||||
|
||||
associate(prm => param(ph), stt => state(ph), dst => dependentState(ph))
|
||||
|
||||
mu = elastic_mu(ph,en)
|
||||
nu = elastic_nu(ph,en)
|
||||
|
||||
sumf_tw = sum(stt%f_tw(1:prm%sum_N_tw,en))
|
||||
sumf_tr = sum(stt%f_tr(1:prm%sum_N_tr,en))
|
||||
|
||||
Gamma = prm%Gamma_sf(1) + prm%Gamma_sf(2) * (T-prm%T_ref)
|
||||
|
||||
!* rescaled volume fraction for topology
|
||||
f_over_t_tw = stt%f_tw(1:prm%sum_N_tw,en)/prm%t_tw ! this is per system ...
|
||||
f_over_t_tr = sumf_tr/prm%t_tr ! but this not
|
||||
|
@ -762,13 +754,6 @@ module subroutine dislotwin_dependentState(T,ph,en)
|
|||
!* threshold stress for dislocation motion
|
||||
dst%tau_pass(:,en) = mu*prm%b_sl* sqrt(matmul(prm%h_sl_sl,stt%rho_mob(:,en)+stt%rho_dip(:,en)))
|
||||
|
||||
!* threshold stress for growing twin/martensite
|
||||
dst%tau_hat_tw(:,en) = Gamma/(3.0_pReal*prm%b_tw) &
|
||||
+ 3.0_pReal*prm%b_tw*mu/(prm%L_tw*prm%b_tw)
|
||||
dst%tau_hat_tr(:,en) = Gamma/(3.0_pReal*prm%b_tr) &
|
||||
+ 3.0_pReal*prm%b_tr*mu/(prm%L_tr*prm%b_tr) &
|
||||
+ prm%h*prm%delta_G/(3.0_pReal*prm%b_tr)
|
||||
|
||||
end associate
|
||||
|
||||
end subroutine dislotwin_dependentState
|
||||
|
@ -813,9 +798,6 @@ module subroutine plastic_dislotwin_results(ph,group)
|
|||
case('Lambda_tw')
|
||||
call results_writeDataset(dst%Lambda_tw,group,trim(prm%output(ou)), &
|
||||
'mean free path for twinning','m',prm%systems_tw)
|
||||
case('tau_hat_tw')
|
||||
call results_writeDataset(dst%tau_hat_tw,group,trim(prm%output(ou)), &
|
||||
'threshold stress for twinning','Pa',prm%systems_tw)
|
||||
|
||||
case('f_tr')
|
||||
if (prm%sum_N_tr>0) call results_writeDataset(stt%f_tr,group,trim(prm%output(ou)), &
|
||||
|
@ -847,15 +829,14 @@ pure subroutine kinetics_sl(Mp,T,ph,en, &
|
|||
integer, intent(in) :: &
|
||||
ph, &
|
||||
en
|
||||
|
||||
real(pReal), dimension(param(ph)%sum_N_sl), intent(out) :: &
|
||||
dot_gamma_sl
|
||||
real(pReal), dimension(param(ph)%sum_N_sl), optional, intent(out) :: &
|
||||
ddot_gamma_dtau_sl, &
|
||||
tau_sl
|
||||
|
||||
real(pReal), dimension(param(ph)%sum_N_sl) :: &
|
||||
ddot_gamma_dtau
|
||||
|
||||
real(pReal), dimension(param(ph)%sum_N_sl) :: &
|
||||
tau, &
|
||||
stressRatio, &
|
||||
|
@ -914,7 +895,7 @@ end subroutine kinetics_sl
|
|||
! NOTE: Against the common convention, the result (i.e. intent(out)) variables are the last to
|
||||
! have the optional arguments at the end.
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
pure subroutine kinetics_tw(Mp,T,dot_gamma_sl,ph,en,&
|
||||
pure subroutine kinetics_tw(Mp,T,abs_dot_gamma_sl,ph,en,&
|
||||
dot_gamma_tw,ddot_gamma_dtau_tw)
|
||||
|
||||
real(pReal), dimension(3,3), intent(in) :: &
|
||||
|
@ -925,18 +906,17 @@ pure subroutine kinetics_tw(Mp,T,dot_gamma_sl,ph,en,&
|
|||
ph, &
|
||||
en
|
||||
real(pReal), dimension(param(ph)%sum_N_sl), intent(in) :: &
|
||||
dot_gamma_sl
|
||||
|
||||
abs_dot_gamma_sl
|
||||
real(pReal), dimension(param(ph)%sum_N_tw), intent(out) :: &
|
||||
dot_gamma_tw
|
||||
real(pReal), dimension(param(ph)%sum_N_tw), optional, intent(out) :: &
|
||||
ddot_gamma_dtau_tw
|
||||
|
||||
real :: &
|
||||
tau, tau_r, &
|
||||
tau, tau_r, tau_hat, &
|
||||
dot_N_0, &
|
||||
x0, V, &
|
||||
Gamma, &
|
||||
Gamma_sf, &
|
||||
mu, nu, &
|
||||
P_ncs, dP_ncs_dtau, &
|
||||
P, dP_dtau
|
||||
|
@ -947,50 +927,37 @@ pure subroutine kinetics_tw(Mp,T,dot_gamma_sl,ph,en,&
|
|||
|
||||
associate(prm => param(ph), stt => state(ph), dst => dependentState(ph))
|
||||
|
||||
isFCC: if (prm%fccTwinTransNucleation) then
|
||||
mu = elastic_mu(ph,en)
|
||||
nu = elastic_nu(ph,en)
|
||||
Gamma = prm%Gamma_sf(1) + prm%Gamma_sf(2) * (T-prm%T_ref)
|
||||
mu = elastic_mu(ph,en)
|
||||
nu = elastic_nu(ph,en)
|
||||
Gamma_sf = prm%Gamma_sf%at(T)
|
||||
|
||||
do i = 1, prm%sum_N_tw
|
||||
tau = math_tensordot(Mp,prm%P_tw(1:3,1:3,i))
|
||||
x0 = mu*prm%b_tw(i)**2*(2.0_pReal+nu)/(Gamma*8.0_pReal*PI*(1.0_pReal-nu)) ! ToDo: In the paper, the Burgers vector for slip is used
|
||||
tau_r = mu*prm%b_tw(i)/(2.0_pReal*PI)*(1.0_pReal/(x0+prm%x_c_tw)+cos(PI/3.0_pReal)/x0) ! ToDo: In the paper, the Burgers vector for slip is used
|
||||
tau_hat = 3.0_pReal*prm%b_tw(1)*mu/prm%L_tw &
|
||||
+ Gamma_sf/(3.0_pReal*prm%b_tw(1))
|
||||
x0 = mu*prm%b_sl(1)**2*(2.0_pReal+nu)/(Gamma_sf*8.0_pReal*PI*(1.0_pReal-nu))
|
||||
tau_r = mu*prm%b_sl(1)/(2.0_pReal*PI)*(1.0_pReal/(x0+prm%x_c)+cos(PI/3.0_pReal)/x0)
|
||||
|
||||
if (tau > tol_math_check .and. tau < tau_r) then
|
||||
P = exp(-(dst%tau_hat_tw(i,en)/tau)**prm%r(i))
|
||||
dP_dTau = prm%r(i) * (dst%tau_hat_tw(i,en)/tau)**prm%r(i)/tau * P
|
||||
do i = 1, prm%sum_N_tw
|
||||
tau = math_tensordot(Mp,prm%P_tw(1:3,1:3,i))
|
||||
|
||||
s = prm%fcc_twinNucleationSlipPair(1:2,i)
|
||||
dot_N_0 = sum(abs(dot_gamma_sl(s(2:1:-1)))*(stt%rho_mob(s,en)+stt%rho_dip(s,en))) &
|
||||
/ (prm%L_tw*prm%b_sl(i))
|
||||
if (tau > tol_math_check .and. tau < tau_r) then
|
||||
P = exp(-(tau_hat/tau)**prm%r(i))
|
||||
dP_dTau = prm%r(i) * (tau_hat/tau)**prm%r(i)/tau * P
|
||||
|
||||
P_ncs = 1.0_pReal-exp(-prm%V_cs/(K_B*T)*(tau_r-tau))
|
||||
dP_ncs_dtau = prm%V_cs / (K_B * T) * (P_ncs - 1.0_pReal)
|
||||
s = prm%fcc_twinNucleationSlipPair(1:2,i)
|
||||
dot_N_0 = sum(abs_dot_gamma_sl(s(2:1:-1))*(stt%rho_mob(s,en)+stt%rho_dip(s,en)))/(prm%L_tw*3.0_pReal)
|
||||
|
||||
V = PI/4.0_pReal*dst%Lambda_tw(i,en)**2*prm%t_tw(i)
|
||||
dot_gamma_tw(i) = V*dot_N_0*P_ncs*P
|
||||
if (present(ddot_gamma_dtau_tw)) &
|
||||
ddot_gamma_dtau_tw(i) = V*dot_N_0*(P*dP_ncs_dtau + P_ncs*dP_dtau)
|
||||
else
|
||||
dot_gamma_tw(i) = 0.0_pReal
|
||||
if (present(ddot_gamma_dtau_tw)) ddot_gamma_dtau_tw(i) = 0.0_pReal
|
||||
end if
|
||||
end do
|
||||
P_ncs = 1.0_pReal-exp(-prm%V_cs/(K_B*T)*(tau_r-tau))
|
||||
dP_ncs_dtau = prm%V_cs / (K_B * T) * (P_ncs - 1.0_pReal)
|
||||
|
||||
else isFCC
|
||||
do i = 1, prm%sum_N_tw
|
||||
error stop 'not implemented'
|
||||
tau = math_tensordot(Mp,prm%P_tw(1:3,1:3,i))
|
||||
if (tau > tol_math_check) then
|
||||
dot_gamma_tw(i) = 0.0_pReal
|
||||
if (present(ddot_gamma_dtau_tw)) ddot_gamma_dtau_tw(i) = 0.0_pReal
|
||||
else
|
||||
dot_gamma_tw(i) = 0.0_pReal
|
||||
if (present(ddot_gamma_dtau_tw)) ddot_gamma_dtau_tw(i) = 0.0_pReal
|
||||
end if
|
||||
end do
|
||||
end if isFCC
|
||||
V = PI/4.0_pReal*dst%Lambda_tw(i,en)**2*prm%t_tw(i)
|
||||
dot_gamma_tw(i) = V*dot_N_0*P_ncs*P*prm%gamma_char_tw(i)
|
||||
if (present(ddot_gamma_dtau_tw)) &
|
||||
ddot_gamma_dtau_tw(i) = V*dot_N_0*(P*dP_ncs_dtau + P_ncs*dP_dtau)*prm%gamma_char_tw(i)
|
||||
else
|
||||
dot_gamma_tw(i) = 0.0_pReal
|
||||
if (present(ddot_gamma_dtau_tw)) ddot_gamma_dtau_tw(i) = 0.0_pReal
|
||||
end if
|
||||
end do
|
||||
|
||||
end associate
|
||||
|
||||
|
@ -1004,7 +971,7 @@ end subroutine kinetics_tw
|
|||
! NOTE: Against the common convention, the result (i.e. intent(out)) variables are the last to
|
||||
! have the optional arguments at the end.
|
||||
!--------------------------------------------------------------------------------------------------
|
||||
pure subroutine kinetics_tr(Mp,T,dot_gamma_sl,ph,en,&
|
||||
pure subroutine kinetics_tr(Mp,T,abs_dot_gamma_sl,ph,en,&
|
||||
dot_gamma_tr,ddot_gamma_dtau_tr)
|
||||
|
||||
real(pReal), dimension(3,3), intent(in) :: &
|
||||
|
@ -1015,18 +982,17 @@ pure subroutine kinetics_tr(Mp,T,dot_gamma_sl,ph,en,&
|
|||
ph, &
|
||||
en
|
||||
real(pReal), dimension(param(ph)%sum_N_sl), intent(in) :: &
|
||||
dot_gamma_sl
|
||||
|
||||
abs_dot_gamma_sl
|
||||
real(pReal), dimension(param(ph)%sum_N_tr), intent(out) :: &
|
||||
dot_gamma_tr
|
||||
real(pReal), dimension(param(ph)%sum_N_tr), optional, intent(out) :: &
|
||||
ddot_gamma_dtau_tr
|
||||
|
||||
real :: &
|
||||
tau, tau_r, &
|
||||
tau, tau_r, tau_hat, &
|
||||
dot_N_0, &
|
||||
x0, V, &
|
||||
Gamma, &
|
||||
Gamma_sf, &
|
||||
mu, nu, &
|
||||
P_ncs, dP_ncs_dtau, &
|
||||
P, dP_dtau
|
||||
|
@ -1039,28 +1005,30 @@ pure subroutine kinetics_tr(Mp,T,dot_gamma_sl,ph,en,&
|
|||
|
||||
mu = elastic_mu(ph,en)
|
||||
nu = elastic_nu(ph,en)
|
||||
Gamma = prm%Gamma_sf(1) + prm%Gamma_sf(2) * (T-prm%T_ref)
|
||||
Gamma_sf = prm%Gamma_sf%at(T)
|
||||
|
||||
tau_hat = 3.0_pReal*prm%b_tr(1)*mu/prm%L_tr &
|
||||
+ (Gamma_sf + (prm%h/prm%V_mol - 2.0_pReal*prm%rho)*prm%Delta_G%at(T))/(3.0_pReal*prm%b_tr(1))
|
||||
x0 = mu*prm%b_sl(1)**2*(2.0_pReal+nu)/(Gamma_sf*8.0_pReal*PI*(1.0_pReal-nu))
|
||||
tau_r = mu*prm%b_sl(1)/(2.0_pReal*PI)*(1.0_pReal/(x0+prm%x_c)+cos(PI/3.0_pReal)/x0)
|
||||
|
||||
do i = 1, prm%sum_N_tr
|
||||
tau = math_tensordot(Mp,prm%P_tr(1:3,1:3,i))
|
||||
x0 = mu*prm%b_tr(i)**2*(2.0_pReal+nu)/(Gamma*8.0_pReal*PI*(1.0_pReal-nu)) ! ToDo: In the paper, the Burgers vector for slip is used
|
||||
tau_r = mu*prm%b_tr(i)/(2.0_pReal*PI)*(1.0_pReal/(x0+prm%x_c_tr)+cos(PI/3.0_pReal)/x0) ! ToDo: In the paper, the Burgers vector for slip is used
|
||||
|
||||
if (tau > tol_math_check .and. tau < tau_r) then
|
||||
P = exp(-(dst%tau_hat_tr(i,en)/tau)**prm%s(i))
|
||||
dP_dTau = prm%s(i) * (dst%tau_hat_tr(i,en)/tau)**prm%s(i)/tau * P
|
||||
P = exp(-(tau_hat/tau)**prm%s(i))
|
||||
dP_dTau = prm%s(i) * (tau_hat/tau)**prm%s(i)/tau * P
|
||||
|
||||
s = prm%fcc_twinNucleationSlipPair(1:2,i)
|
||||
dot_N_0 = sum(abs(dot_gamma_sl(s(2:1:-1)))*(stt%rho_mob(s,en)+stt%rho_dip(s,en))) &
|
||||
/ (prm%L_tr*prm%b_sl(i))
|
||||
dot_N_0 = sum(abs_dot_gamma_sl(s(2:1:-1))*(stt%rho_mob(s,en)+stt%rho_dip(s,en)))/(prm%L_tr*3.0_pReal)
|
||||
|
||||
P_ncs = 1.0_pReal-exp(-prm%V_cs/(K_B*T)*(tau_r-tau))
|
||||
dP_ncs_dtau = prm%V_cs / (K_B * T) * (P_ncs - 1.0_pReal)
|
||||
|
||||
|
||||
V = PI/4.0_pReal*dst%Lambda_tr(i,en)**2*prm%t_tr(i)
|
||||
dot_gamma_tr(i) = V*dot_N_0*P_ncs*P
|
||||
dot_gamma_tr(i) = V*dot_N_0*P_ncs*P*prm%gamma_char_tr
|
||||
if (present(ddot_gamma_dtau_tr)) &
|
||||
ddot_gamma_dtau_tr(i) = V*dot_N_0*(P*dP_ncs_dtau + P_ncs*dP_dtau)
|
||||
ddot_gamma_dtau_tr(i) = V*dot_N_0*(P*dP_ncs_dtau + P_ncs*dP_dtau)*prm%gamma_char_tr
|
||||
else
|
||||
dot_gamma_tr(i) = 0.0_pReal
|
||||
if (present(ddot_gamma_dtau_tr)) ddot_gamma_dtau_tr(i) = 0.0_pReal
|
||||
|
|
Loading…
Reference in New Issue