Merge branch 'development' into New-Thermal

This commit is contained in:
Martin Diehl 2019-02-26 07:54:03 +01:00
commit 56e2c1264b
41 changed files with 5026 additions and 5098 deletions

View File

@ -207,7 +207,9 @@ Post_ParaviewRelated:
Post_OrientationConversion:
stage: postprocessing
script: OrientationConversion/test.py
script:
- OrientationConversion/test.py
- OrientationConversion/test2.py
except:
- master
- release
@ -508,7 +510,7 @@ Processing:
stage: createDocumentation
script:
- cd $DAMASKROOT/processing/pre
- rm 3DRVEfrom2Dang.py abq_addUserOutput.py marc_addUserOutput.py
- rm abq_addUserOutput.py marc_addUserOutput.py
- $DAMASKROOT/PRIVATE/documenting/scriptHelpToWiki.py --debug *.py
- cd $DAMASKROOT/processing/post
- rm marc_to_vtk.py vtk2ang.py

@ -1 +1 @@
Subproject commit 75fbf8c1d9eb9b08fa15b55b7caaa4c4f7c167e0
Subproject commit def4081e837539dba7c4760abbb340553be66d3c

View File

@ -1 +1 @@
v2.0.2-1837-g3bec76e7
v2.0.2-1937-ge401c212

View File

@ -3,7 +3,6 @@
(output) texture
(output) volume
(output) orientation # quaternion
(output) eulerangles # orientation as Bunge triple in degree
(output) grainrotation # deviation from initial orientation as axis (1-3) and angle in degree (4) in crystal reference coordinates
(output) f # deformation gradient tensor
(output) fe # elastic deformation gradient tensor

View File

@ -13,7 +13,6 @@ mech none
(output) texture
(output) volume
(output) orientation # quaternion
(output) eulerangles # orientation as Bunge triple
(output) grainrotation # deviation from initial orientation as axis (1-3) and angle in degree (4)
(output) f # deformation gradient tensor; synonyms: "defgrad"
(output) fe # elastic deformation gradient tensor

View File

@ -1,84 +0,0 @@
#!/usr/bin/env python2.7
# -*- coding: UTF-8 no BOM -*-
import os,h5py
import numpy as np
from optparse import OptionParser
import damask
scriptName = os.path.splitext(os.path.basename(__file__))[0]
scriptID = ' '.join([scriptName,damask.version])
#--------------------------------------------------------------------------------------------------
# MAIN
#--------------------------------------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog [dream3dfile[s]]', description = """
Convert DREAM3D file to ASCIItable. Works for 3D datasets, but, hey, its not called DREAM2D ;)
""", version = scriptID)
parser.add_option('-d','--data',
dest = 'data',
action = 'extend', metavar = '<string LIST>',
help = 'data to extract from DREAM3D file')
parser.add_option('-c','--container',
dest = 'container', metavar = 'string',
help = 'root container(group) in which data is stored [%default]')
parser.set_defaults(container="ImageDataContainer",
)
(options, filenames) = parser.parse_args()
if options.data is None:
parser.error('No data selected')
rootDir ='DataContainers/'+options.container
# --- loop over input files -------------------------------------------------------------------------
if filenames == []: parser.error('no input file specified.')
for name in filenames:
try:
table = damask.ASCIItable(outname = os.path.splitext(name)[0]+'.txt',
buffered = False
)
except: continue
damask.util.report(scriptName,name)
inFile = h5py.File(name, 'r')
try:
grid = inFile[rootDir+'/_SIMPL_GEOMETRY/DIMENSIONS'][...]
except:
damask.util.croak('Group {} not found'.format(options.container))
table.close(dismiss = True)
continue
# --- read comments --------------------------------------------------------------------------------
coords = (np.mgrid[0:grid[2], 0:grid[1], 0: grid[0]]).reshape(3, -1).T
table.data = (np.fliplr(coords)*inFile[rootDir+'/_SIMPL_GEOMETRY/SPACING'][...] \
+ inFile[rootDir+'/_SIMPL_GEOMETRY/ORIGIN'][...] \
+ inFile[rootDir+'/_SIMPL_GEOMETRY/SPACING'][...]*0.5)
labels = ['1_pos','2_pos','3_pos']
for data in options.data:
try:
l = np.prod(inFile[rootDir+'/CellData/'+data].shape[3:])
labels+=['{}_{}'.format(i+1,data.replace(' ','')) for i in range(l)] if l >1 else [data.replace(' ','')]
except KeyError:
damask.util.croak('Data {} not found'.format(data))
pass
table.data = np.hstack((table.data,
inFile[rootDir+'/CellData/'+data][...].reshape(grid.prod(),l)))
# ------------------------------------------ assemble header ---------------------------------------
table.labels_clear()
table.labels_append(labels,reset = True)
table.head_write()
# ------------------------------------------ finalize output ---------------------------------------
table.data_writeArray()
table.close()

View File

@ -1,48 +0,0 @@
#!/usr/bin/env python2.7
# -*- coding: UTF-8 no BOM -*-
import os,sys
from optparse import OptionParser
import damask
scriptName = os.path.splitext(os.path.basename(__file__))[0]
scriptID = ' '.join([scriptName,damask.version])
#--------------------------------------------------------------------------------------------------
# MAIN
#--------------------------------------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog [file[s]]', description = """
Adds header to OIM grain file type 1 to make it accesible as ASCII table
""", version = scriptID)
(options, filenames) = parser.parse_args()
# --- loop over input files -------------------------------------------------------------------------
if filenames == []: filenames = [None]
for name in filenames:
try:
table = damask.ASCIItable(name = name,
buffered = False,
labeled = False)
except: continue
damask.util.report(scriptName,name)
table.head_read()
data = []
while table.data_read():
data.append(table.data[0:9])
table.info_append(scriptID + '\t' + ' '.join(sys.argv[1:]))
table.labels_append(['1_euler','2_euler','3_euler','1_pos','2_pos','IQ','CI','Fit','GrainID'])
table.head_write()
for i in data:
table.data = i
table.data_write()
# --- output finalization --------------------------------------------------------------------------
table.close() # close ASCII table

View File

@ -1,176 +0,0 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 no BOM -*-
import os,sys,copy
import numpy as np
import damask
from optparse import OptionParser
from scipy import spatial
scriptName = os.path.splitext(os.path.basename(__file__))[0]
scriptID = ' '.join([scriptName,damask.version])
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """
Add grain index based on similiarity of crystal lattice orientation.
""", version = scriptID)
parser.add_option('-r',
'--radius',
dest = 'radius',
type = 'float', metavar = 'float',
help = 'search radius')
parser.add_option('-d',
'--disorientation',
dest = 'disorientation',
type = 'float', metavar = 'float',
help = 'disorientation threshold in degrees [%default]')
parser.add_option('-s',
'--symmetry',
dest = 'symmetry', type = 'choice', choices = damask.Symmetry.lattices[1:],
metavar = 'string',
help = 'crystal symmetry [%default] {{{}}} '.format(', '.join(damask.Symmetry.lattices[1:])))
parser.add_option('-o',
'--orientation',
dest = 'quaternion',
metavar = 'string',
help = 'label of crystal orientation given as unit quaternion [%default]')
parser.add_option('-p',
'--pos', '--position',
dest = 'pos',
metavar = 'string',
help = 'label of coordinates [%default]')
parser.add_option('--quiet',
dest='verbose',
action = 'store_false',
help = 'hide status bar (useful when piping to file)')
parser.set_defaults(disorientation = 5,
verbose = True,
quaternion = 'orientation',
symmetry = damask.Symmetry.lattices[-1],
pos = 'pos',
)
(options, filenames) = parser.parse_args()
if options.radius is None:
parser.error('no radius specified.')
cos_disorientation = np.cos(np.radians(options.disorientation/2.)) # cos of half the disorientation angle
# --- loop over input files -------------------------------------------------------------------------
if filenames == []: filenames = [None]
for name in filenames:
try: table = damask.ASCIItable(name = name,
buffered = False)
except: continue
damask.util.report(scriptName,name)
# ------------------------------------------ read header -------------------------------------------
table.head_read()
# ------------------------------------------ sanity checks -----------------------------------------
errors = []
remarks = []
if not 3 >= table.label_dimension(options.pos) >= 1:
errors.append('coordinates "{}" need to have one, two, or three dimensions.'.format(options.pos))
if not np.all(table.label_dimension(options.quaternion) == 4):
errors.append('input "{}" does not have dimension 4.'.format(options.quaternion))
else: column = table.label_index(options.quaternion)
if remarks != []: damask.util.croak(remarks)
if errors != []:
damask.util.croak(errors)
table.close(dismiss = True)
continue
# ------------------------------------------ assemble header ---------------------------------------
table.info_append(scriptID + '\t' + ' '.join(sys.argv[1:]))
table.labels_append('grainID_{}@{:g}'.format(options.quaternion,options.disorientation)) # report orientation source and disorientation
table.head_write()
# ------------------------------------------ build KD tree -----------------------------------------
table.data_readArray(options.pos) # read position vectors
grainID = -np.ones(len(table.data),dtype=int)
Npoints = table.data.shape[0]
kdtree = spatial.KDTree(copy.deepcopy(table.data))
# ------------------------------------------ assign grain IDs --------------------------------------
orientations = [] # quaternions found for grain
memberCounts = [] # number of voxels in grain
p = 0 # point counter
g = 0 # grain counter
matchedID = -1
lastDistance = np.dot(kdtree.data[-1]-kdtree.data[0],kdtree.data[-1]-kdtree.data[0]) # (arbitrarily) use diagonal of cloud
table.data_rewind()
while table.data_read(): # read next data line of ASCII table
if options.verbose and Npoints > 100 and p%(Npoints//100) == 0: # report in 1% steps if possible and avoid modulo by zero
damask.util.progressBar(iteration=p,total=Npoints)
o = damask.Orientation(quaternion = np.array(list(map(float,table.data[column:column+4]))),
symmetry = options.symmetry).reduced()
matched = False
alreadyChecked = {}
candidates = []
bestDisorientation = damask.Quaternion([0,0,0,1]) # initialize to 180 deg rotation as worst case
for i in kdtree.query_ball_point(kdtree.data[p],options.radius): # check all neighboring points
gID = grainID[i]
if gID != -1 and gID not in alreadyChecked: # indexed point belonging to a grain not yet tested?
alreadyChecked[gID] = True # remember not to check again
disorientation = o.disorientation(orientations[gID],SST = False)[0] # compare against other orientation
if disorientation.quaternion.q > cos_disorientation: # within threshold ...
candidates.append(gID) # remember as potential candidate
if disorientation.quaternion.q >= bestDisorientation.q: # ... and better than current best?
matched = True
matchedID = gID # remember that grain
bestDisorientation = disorientation.quaternion
if matched: # did match existing grain
memberCounts[matchedID] += 1
if len(candidates) > 1: # ambiguity in grain identification?
largestGrain = sorted(candidates,key=lambda x:memberCounts[x])[-1] # find largest among potential candidate grains
matchedID = largestGrain
for c in [c for c in candidates if c != largestGrain]: # loop over smaller candidates
memberCounts[largestGrain] += memberCounts[c] # reassign member count of smaller to largest
memberCounts[c] = 0
grainID = np.where(np.in1d(grainID,candidates), largestGrain, grainID) # relabel grid points of smaller candidates as largest one
else: # no match -> new grain found
orientations += [o] # initialize with current orientation
memberCounts += [1] # start new membership counter
matchedID = g
g += 1 # increment grain counter
grainID[p] = matchedID # remember grain index assigned to point
p += 1 # increment point
grainIDs = np.where(np.array(memberCounts) > 0)[0] # identify "live" grain identifiers
packingMap = dict(zip(list(grainIDs),range(len(grainIDs)))) # map to condense into consecutive IDs
table.data_rewind()
outputAlive = True
p = 0
damask.util.progressBar(iteration=1,total=1)
while outputAlive and table.data_read(): # read next data line of ASCII table
table.data_append(1+packingMap[grainID[p]]) # add (condensed) grain ID
outputAlive = table.data_write() # output processed line
p += 1
# ------------------------------------------ output finalization -----------------------------------
table.close() # close ASCII tables

View File

@ -41,6 +41,10 @@ parser.set_defaults(pole = (0.0,0.0,1.0),
(options, filenames) = parser.parse_args()
# damask.Orientation requires Bravais lattice, but we are only interested in symmetry
symmetry2lattice={'cubic':'bcc','hexagonal':'hex','tetragonal':'bct'}
lattice = symmetry2lattice[options.symmetry]
pole = np.array(options.pole)
pole /= np.linalg.norm(pole)
@ -78,8 +82,8 @@ for name in filenames:
outputAlive = True
while outputAlive and table.data_read(): # read next data line of ASCII table
o = damask.Orientation(quaternion = np.array(list(map(float,table.data[column:column+4]))),
symmetry = options.symmetry).reduced()
o = damask.Orientation(np.array(list(map(float,table.data[column:column+4]))),
lattice = lattice).reduced()
table.data_append(o.IPFcolor(pole))
outputAlive = table.data_write() # output processed line

View File

@ -38,9 +38,12 @@ parser.add_option('-s','--stress',
action = 'extend', metavar = '<string LIST>',
help = 'heading(s) of columns containing stress tensors')
parser.set_defaults(strain = [],
stress = [],
)
(options,filenames) = parser.parse_args()
if options.stress is None and options.strain is None:
if options.stress is [] and options.strain is []:
parser.error('no data column specified...')
# --- loop over input files -------------------------------------------------------------------------

View File

@ -9,31 +9,6 @@ import damask
scriptName = os.path.splitext(os.path.basename(__file__))[0]
scriptID = ' '.join([scriptName,damask.version])
# --------------------------------------------------------------------
# convention conformity checks
# --------------------------------------------------------------------
def check_Eulers(eulers):
if np.any(eulers < 0.0) or np.any(eulers > 2.0*np.pi) or eulers[1] > np.pi: # Euler angles within valid range?
raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π].\n{} {} {}.'.format(*eulers))
return eulers
def check_quaternion(q):
if q[0] < 0.0: # positive first quaternion component?
raise ValueError('quaternion has negative first component.\n{}'.format(q[0]))
if not np.isclose(np.linalg.norm(q), 1.0): # unit quaternion?
raise ValueError('quaternion is not of unit length.\n{} {} {} {}'.format(*q))
return q
def check_matrix(M):
if not np.isclose(np.linalg.det(M),1.0): # proper rotation?
raise ValueError('matrix is not a proper rotation.\n{}'.format(M))
if not np.isclose(np.dot(M[0],M[1]), 0.0) \
or not np.isclose(np.dot(M[1],M[2]), 0.0) \
or not np.isclose(np.dot(M[2],M[0]), 0.0): # all orthogonal?
raise ValueError('matrix is not orthogonal.\n{}'.format(M))
return M
# --------------------------------------------------------------------
# MAIN
# --------------------------------------------------------------------
@ -46,19 +21,19 @@ Additional (globally fixed) rotations of the lab frame and/or crystal frame can
""", version = scriptID)
outputChoices = {
'quaternion': ['quat',4],
'rodrigues': ['rodr',3],
representations = {
'quaternion': ['quat',4], #ToDo: Use here Rowenhorst names (qu/ro/om/ax?)
'rodrigues': ['rodr',4],
'eulers': ['eulr',3],
'matrix': ['mtrx',9],
'angleaxis': ['aaxs',4],
}
}
parser.add_option('-o',
'--output',
dest = 'output',
action = 'extend', metavar = '<string LIST>',
help = 'output orientation formats {{{}}}'.format(', '.join(outputChoices)))
help = 'output orientation formats {{{}}}'.format(', '.join(representations)))
parser.add_option('-d',
'--degrees',
dest = 'degrees',
@ -104,15 +79,15 @@ parser.add_option('-z',
help = 'label of lab z vector (expressed in crystal coords)')
parser.set_defaults(output = [],
labrotation = (0.,1.,1.,1.), # no rotation about 1,1,1
crystalrotation = (0.,1.,1.,1.), # no rotation about 1,1,1
labrotation = (0.,1.,0.,0.), # no rotation about 1,0,0
crystalrotation = (0.,1.,0.,0.), # no rotation about 1,0,0
)
(options, filenames) = parser.parse_args()
options.output = list(map(lambda x: x.lower(), options.output))
if options.output == [] or (not set(options.output).issubset(set(outputChoices))):
parser.error('output must be chosen from {}.'.format(', '.join(outputChoices)))
if options.output == [] or (not set(options.output).issubset(set(representations))):
parser.error('output must be chosen from {}.'.format(', '.join(representations)))
input = [options.eulers is not None,
options.rodrigues is not None,
@ -125,16 +100,18 @@ input = [options.eulers is not None,
if np.sum(input) != 1: parser.error('needs exactly one input format.')
(label,dim,inputtype) = [(options.eulers,3,'eulers'),
(options.rodrigues,3,'rodrigues'),
(label,dim,inputtype) = [(options.eulers,representations['eulers'][1],'eulers'),
(options.rodrigues,representations['rodrigues'][1],'rodrigues'),
([options.x,options.y,options.z],[3,3,3],'frame'),
(options.matrix,9,'matrix'),
(options.quaternion,4,'quaternion'),
(options.matrix,representations['matrix'][1],'matrix'),
(options.quaternion,representations['quaternion'][1],'quaternion'),
][np.where(input)[0][0]] # select input label that was requested
toRadians = np.pi/180.0 if options.degrees else 1.0 # rescale degrees to radians
r = damask.Quaternion.fromAngleAxis(toRadians*options.crystalrotation[0],options.crystalrotation[1:]) # crystal frame rotation
R = damask.Quaternion.fromAngleAxis(toRadians*options. labrotation[0],options. labrotation[1:]) # lab frame rotation
crystalrotation = np.array(options.crystalrotation[1:4] + (options.crystalrotation[0],)) # Compatibility hack
labrotation = np.array(options.labrotation[1:4] + (options.labrotation[0],)) # Compatibility hack
r = damask.Rotation.fromAxisAngle(crystalrotation,options.degrees) # crystal frame rotation
R = damask.Rotation.fromAxisAngle(labrotation,options.degrees) # lab frame rotation
# --- loop over input files ------------------------------------------------------------------------
@ -168,9 +145,9 @@ for name in filenames:
table.info_append(scriptID + '\t' + ' '.join(sys.argv[1:]))
for output in options.output:
if output in outputChoices:
table.labels_append(['{}_{}({})'.format(i+1,outputChoices[output][0],label) \
for i in range(outputChoices[output][1])])
if output in representations:
table.labels_append(['{}_{}({})'.format(i+1,representations[output][0],label) \
for i in range(representations[output][1])])
table.head_write()
# ------------------------------------------ process data ------------------------------------------
@ -178,30 +155,35 @@ for name in filenames:
outputAlive = True
while outputAlive and table.data_read(): # read next data line of ASCII table
if inputtype == 'eulers':
l = representations['eulers'][1]
o = damask.Rotation.fromEulers(list(map(float,table.data[column:column+l])),options.degrees)
o = damask.Orientation(Eulers = check_Eulers(np.array(list(map(float,table.data[column:column+3])))*toRadians))
elif inputtype == 'rodrigues':
o = damask.Orientation(Rodrigues = np.array(list(map(float,table.data[column:column+3]))))
elif inputtype == 'matrix':
l = representations['rodrigues'][1]
o = damask.Rotation.fromRodrigues(list(map(float,table.data[column:column+l])))
o = damask.Orientation(matrix = check_matrix(np.array(list(map(float,table.data[column:column+9]))).reshape(3,3)))
elif inputtype == 'matrix':
l = representations['matrix'][1]
o = damask.Rotation.fromMatrix(list(map(float,table.data[column:column+l])))
elif inputtype == 'frame':
M = np.array(list(map(float,table.data[column[0]:column[0]+3] + \
table.data[column[1]:column[1]+3] + \
table.data[column[2]:column[2]+3]))).reshape(3,3).T
o = damask.Orientation(matrix = check_matrix(M/np.linalg.norm(M,axis=0)))
elif inputtype == 'quaternion':
o = damask.Rotation.fromMatrix(M/np.linalg.norm(M,axis=0))
o = damask.Orientation(quaternion = check_quaternion(np.array(list(map(float,table.data[column:column+4])))))
elif inputtype == 'quaternion':
l = representations['quaternion'][1]
o = damask.Rotation.fromQuaternion(list(map(float,table.data[column:column+l])))
o.quaternion = r*o.quaternion*R # apply additional lab and crystal frame rotations
o= r*o*R # apply additional lab and crystal frame rotations
for output in options.output:
if output == 'quaternion': table.data_append(o.asQuaternion())
elif output == 'rodrigues': table.data_append(o.asRodrigues())
elif output == 'eulers': table.data_append(o.asEulers(degrees=options.degrees))
elif output == 'matrix': table.data_append(o.asMatrix())
elif output == 'angleaxis': table.data_append(o.asAngleAxis(degrees=options.degrees,flat=True))
elif output == 'angleaxis': table.data_append(o.asAxisAngle(degrees=options.degrees))
outputAlive = table.data_write() # output processed line
# ------------------------------------------ output finalization -----------------------------------

View File

@ -75,9 +75,9 @@ for name in filenames:
# ------------------------------------------ process data ------------------------------------------
outputAlive = True
while outputAlive and table.data_read(): # read next data line of ASCII table
o = damask.Orientation(quaternion = np.array(list(map(float,table.data[column:column+4]))))
o = damask.Rotation(np.array(list(map(float,table.data[column:column+4]))))
rotatedPole = o.quaternion*pole # rotate pole according to crystal orientation
rotatedPole = o*pole # rotate pole according to crystal orientation
(x,y) = rotatedPole[0:2]/(1.+abs(pole[2])) # stereographic projection
table.data_append([np.sqrt(x*x+y*y),np.arctan2(y,x)] if options.polar else [x,y]) # cartesian coordinates

View File

@ -212,10 +212,10 @@ for name in filenames:
outputAlive = True
while outputAlive and table.data_read(): # read next data line of ASCII table
o = damask.Orientation(quaternion = np.array(list(map(float,table.data[column:column+4]))))
o = damask.Rotation(list(map(float,table.data[column:column+4])))
table.data_append( np.abs( np.sum(slip_direction * (o.quaternion * force) ,axis=1) \
* np.sum(slip_normal * (o.quaternion * normal),axis=1)))
table.data_append( np.abs( np.sum(slip_direction * (o * force) ,axis=1) \
* np.sum(slip_normal * (o * normal),axis=1)))
outputAlive = table.data_write() # output processed line
# ------------------------------------------ output finalization -----------------------------------

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 no BOM -*-
import os,sys,math
import os,sys
import numpy as np
from optparse import OptionParser
import damask
@ -40,9 +40,8 @@ parser.set_defaults(rotation = (0.,1.,1.,1.),
if options.data is None:
parser.error('no data column specified.')
toRadians = math.pi/180.0 if options.degrees else 1.0 # rescale degrees to radians
q = damask.Quaternion().fromAngleAxis(toRadians*options.rotation[0],options.rotation[1:])
R = q.asMatrix()
rotation = np.array(options.rotation[1:4]+(options.rotation[0],)) # Compatibility hack
r = damask.Rotation.fromAxisAngle(rotation,options.degrees,normalise=True)
# --- loop over input files -------------------------------------------------------------------------
@ -90,12 +89,11 @@ for name in filenames:
while outputAlive and table.data_read(): # read next data line of ASCII table
for v in active['vector']:
column = table.label_index(v)
table.data[column:column+3] = q * np.array(list(map(float,table.data[column:column+3])))
table.data[column:column+3] = r * np.array(list(map(float,table.data[column:column+3])))
for t in active['tensor']:
column = table.label_index(t)
table.data[column:column+9] = \
np.dot(R,np.dot(np.array(list(map(float,table.data[column:column+9]))).reshape((3,3)),
R.transpose())).reshape((9))
table.data[column:column+9] = (r * np.array(list(map(float,table.data[column:column+9]))).reshape((3,3))).reshape(9)
outputAlive = table.data_write() # output processed line
# ------------------------------------------ output finalization -----------------------------------

View File

@ -53,19 +53,22 @@ parser.set_defaults(data = [],
if not options.vtk: parser.error('No VTK file specified.')
if not os.path.exists(options.vtk): parser.error('VTK file does not exist.')
if os.path.splitext(options.vtk)[1] == '.vtr':
vtk_file,vtk_ext = os.path.splitext(options.vtk)
if vtk_ext == '.vtr':
reader = vtk.vtkXMLRectilinearGridReader()
reader.SetFileName(options.vtk)
reader.Update()
rGrid = reader.GetOutput()
writer = vtk.vtkXMLRectilinearGridWriter()
elif os.path.splitext(options.vtk)[1] == '.vtk':
elif vtk_ext == '.vtk':
reader = vtk.vtkGenericDataObjectReader()
reader.SetFileName(options.vtk)
reader.Update()
rGrid = reader.GetRectilinearGridOutput()
writer = vtk.vtkXMLRectilinearGridWriter()
elif os.path.splitext(options.vtk)[1] == '.vtu':
vtk_ext = '.vtr'
elif vtk_ext == '.vtu':
reader = vtk.vtkXMLUnstructuredGridReader()
reader.SetFileName(options.vtk)
reader.Update()
@ -74,7 +77,7 @@ elif os.path.splitext(options.vtk)[1] == '.vtu':
else:
parser.error('Unsupported VTK file type extension.')
writer.SetFileName(options.vtk)
writer.SetFileName(vtk_file+vtk_ext)
Npoints = rGrid.GetNumberOfPoints()
Ncells = rGrid.GetNumberOfCells()

View File

@ -49,16 +49,19 @@ parser.set_defaults(data = [],
if not options.vtk: parser.error('no VTK file specified.')
if not os.path.exists(options.vtk): parser.error('VTK file does not exist.')
if os.path.splitext(options.vtk)[1] == '.vtp':
vtk_file,vtk_ext = os.path.splitext(options.vtk)
if vtk_ext == '.vtp':
reader = vtk.vtkXMLPolyDataReader()
reader.SetFileName(options.vtk)
reader.Update()
Polydata = reader.GetOutput()
elif os.path.splitext(options.vtk)[1] == '.vtk':
elif vtk_ext == '.vtk':
reader = vtk.vtkGenericDataObjectReader()
reader.SetFileName(options.vtk)
reader.Update()
Polydata = reader.GetPolyDataOutput()
vtk_ext = '.vtp'
else:
parser.error('unsupported VTK file type extension.')
@ -149,7 +152,7 @@ for name in filenames:
writer = vtk.vtkXMLPolyDataWriter()
writer.SetDataModeToBinary()
writer.SetCompressorTypeToZLib()
writer.SetFileName(options.vtk)
writer.SetFileName(vtk_file+vtk_ext)
writer.SetInputData(Polydata)
writer.Write()

View File

@ -53,16 +53,18 @@ parser.set_defaults(data = [],
if not options.vtk: parser.error('no VTK file specified.')
if not os.path.exists(options.vtk): parser.error('VTK file does not exist.')
if os.path.splitext(options.vtk)[1] == '.vtr':
vtk_file,vtk_ext = os.path.splitext(options.vtk)
if vtk_ext == '.vtr':
reader = vtk.vtkXMLRectilinearGridReader()
reader.SetFileName(options.vtk)
reader.Update()
rGrid = reader.GetOutput()
elif os.path.splitext(options.vtk)[1] == '.vtk':
elif vtk_ext == '.vtk':
reader = vtk.vtkGenericDataObjectReader()
reader.SetFileName(options.vtk)
reader.Update()
rGrid = reader.GetRectilinearGridOutput()
vtk_ext = '.vtr'
else:
parser.error('unsupported VTK file type extension.')
@ -159,7 +161,7 @@ for name in filenames:
writer = vtk.vtkXMLRectilinearGridWriter()
writer.SetDataModeToBinary()
writer.SetCompressorTypeToZLib()
writer.SetFileName(options.vtk)
writer.SetFileName(vtk_file+vtk_ext)
writer.SetInputData(rGrid)
writer.Write()

View File

@ -1,119 +0,0 @@
#!/usr/bin/env python2.7
# -*- coding: UTF-8 no BOM -*-
import os,sys,math
from optparse import OptionParser
import damask
import pipes
scriptName = os.path.splitext(os.path.basename(__file__))[0]
scriptID = ' '.join([scriptName,damask.version])
# --------------------------------------------------------------------
# MAIN
# --------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [file[s]]',
description ='generate 3D RVE from .ang files of EBSD slices .',
version = scriptID)
parser.add_option('--offset',
dest='offset',
type='float',
help='offset of EBSD slices [%default]',
metavar='float')
parser.add_option('--outname',
dest='outName',
type='string',
help='output file name [%default]', metavar='string')
parser.add_option('--vtr',
action="store_true",
dest='vtr')
parser.add_option('--geom',
action="store_true",
dest='geom')
parser.set_defaults(offset = 1.0,
outName = 'RVE3D')
(options,filenames) = parser.parse_args()
numFiles = len(filenames)
formatwidth = 1+int(math.log10(numFiles))
# copy original files to tmp files to not alter originals
for i in range(numFiles):
sliceID = 'slice' + str(i).zfill(formatwidth) + '.tmp'
strCommand = 'cp ' + pipes.quote(filenames[i]) + ' ' + sliceID
os.system(strCommand)
# modify tmp files
print('Add z-coordinates')
for i in range(numFiles):
sliceID = 'slice' + str(i).zfill(formatwidth) + '.tmp'
strCommand = 'OIMgrainFile_toTable ' + sliceID
os.system(strCommand)
strCommand = 'addCalculation --label 3Dpos --formula "np.array(#pos#.tolist()+[' + str(i*options.offset) + '])" ' + sliceID
os.system(strCommand)
# join temp files into one
print('\n Colocate files')
fileOut = open(options.outName + '.ang','w')
# take header information from 1st file
sliceID = 'slice' + str(0).zfill(formatwidth) + '.tmp'
fileRead = open(sliceID)
data = fileRead.readlines()
fileRead.close()
headerLines = int(data[0].split()[0])
fileOut.write(str(headerLines+1) + '\t header\n')
for line in data[1:headerLines]:
fileOut.write(line)
fileOut.write(scriptID + '\t' + ' '.join(sys.argv[1:]) + '\n')
for line in data[headerLines:]:
fileOut.write(line)
# append other files content without header
for i in range(numFiles-1):
sliceID = 'slice' + str(i+1).zfill(formatwidth) + '.tmp'
fileRead = open(sliceID)
data = fileRead.readlines()
fileRead.close()
headerLines = int(data[0].split()[0])
for line in data[headerLines+1:]:
fileOut.write(line)
fileOut.close()
# tidy up and add phase column
print('\n Remove temp data and add phase info')
strCommand = 'filterTable --black pos ' + options.outName + '.ang'
os.system(strCommand)
strCommand = 'reLabel --label 3Dpos --substitute pos ' + options.outName + '.ang'
os.system(strCommand)
strCommand = 'addCalculation -l phase -f 1 ' + options.outName + '.ang'
os.system(strCommand)
# create geom file when asked for
if options.geom:
print('\n Build geometry file')
strCommand = 'geom_fromTable --phase phase --eulers euler --coordinates pos ' + pipes.quote(options.outName) + '.ang'
os.system(strCommand)
# create paraview file when asked for
if options.vtr:
print('\n Build Paraview file')
strCommand = 'addIPFcolor --eulers euler --pole 0.0 0.0 1.0 ' + options.outName + '.ang'
os.system(strCommand)
strCommand = 'vtk_rectilinearGrid ' + pipes.quote(options.outName) + '.ang'
os.system(strCommand)
os.rename(pipes.quote(options.outName) + '_pos(cell)'+'.vtr', pipes.quote(options.outName) + '.vtr')
strCommand = 'vtk_addRectilinearGridData --vtk '+ pipes.quote(options.outName) + '.vtr --color IPF_001_cubic '\
+ pipes.quote(options.outName) + '.ang'
os.system(strCommand)
# delete tmp files
for i in range(numFiles):
sliceID = 'slice' + str(i).zfill(formatwidth) + '.tmp'
os.remove(sliceID)

View File

@ -43,7 +43,7 @@ parser.add_option('-f', '--fill', dest='fill', type='int', metavar = 'int'
help='grain index to fill primitive. "0" selects maximum microstructure index + 1 [%default]')
parser.add_option('-q', '--quaternion', dest='quaternion', type='float', nargs = 4, metavar=' '.join(['float']*4),
help = 'rotation of primitive as quaternion')
parser.add_option('-a', '--angleaxis', dest='angleaxis', nargs = 4, metavar=' '.join(['float']*4),
parser.add_option('-a', '--angleaxis', dest='angleaxis', nargs = 4, metavar=' '.join(['float']*4), type=float,
help = 'angle,x,y,z clockwise rotation of primitive about axis by angle')
parser.add_option( '--degrees', dest='degrees', action='store_true',
help = 'angle is given in degrees [%default]')
@ -63,14 +63,12 @@ parser.set_defaults(center = (.0,.0,.0),
if options.dimension is None:
parser.error('no dimension specified.')
if options.angleaxis is not None:
options.angleaxis = list(map(float,options.angleaxis))
rotation = damask.Quaternion.fromAngleAxis(np.radians(options.angleaxis[0]) if options.degrees else options.angleaxis[0],
options.angleaxis[1:4])
ax = np.array(options.angleaxis[1:4] + (options.angleaxis[0],)) # Compatibility hack
rotation = damask.Rotation.fromAxisAngle(ax,options.degrees,normalise=True)
elif options.quaternion is not None:
options.quaternion = list(map(float,options.quaternion))
rotation = damask.Quaternion(quat=options.quaternion)
rotation = damask.Rotation.fromQuaternion(options.quaternion)
else:
rotation = damask.Quaternion()
rotation = damask.Rotation()
options.center = np.array(options.center)
options.dimension = np.array(options.dimension)
@ -159,8 +157,7 @@ for name in filenames:
X -= options.center[0] - 0.5
Y -= options.center[1] - 0.5
Z -= options.center[2] - 0.5
# and then by applying the quaternion
# this should be rotation.conjugate() * (X,Y,Z), but it is this way for backwards compatibility with the older version of this script
# and then by applying the rotation
(X, Y, Z) = rotation * (X, Y, Z)
# and finally by scaling (we don't worry about options.dimension being negative, np.abs occurs on the microstructure = np.where... line)
X /= options.dimension[0] * 0.5

View File

@ -18,8 +18,8 @@ do
< $geom \
| \
vtk_addRectilinearGridData \
--vtk ${geom%.*}.vtk \
--data microstructure \
--inplace \
--vtk ${geom%.*}.vtk
rm ${geom%.*}.vtk
done

View File

@ -0,0 +1,189 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 no BOM -*-
import os,sys,h5py
import numpy as np
from optparse import OptionParser
import damask
scriptName = os.path.splitext(os.path.basename(__file__))[0]
scriptID = ' '.join([scriptName,damask.version])
#--------------------------------------------------------------------------------------------------
# MAIN
#--------------------------------------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog [dream3dfile[s]]', description = """
Convert DREAM3D file to geometry file. This can be done from cell data (direct pointwise takeover) or
from grain data (individual grains are segmented). Requires orientation data as quaternion.
""", version = scriptID)
parser.add_option('-b','--basegroup',
dest = 'basegroup', metavar = 'string',
help = 'name of the group in "DataContainers" that contains all the data')
parser.add_option('-p','--pointwise',
dest = 'pointwise', metavar = 'string',
help = 'name of the group in "DataContainers/<basegroup>" that contains pointwise data [%default]')
parser.add_option('-a','--average',
dest = 'average', metavar = 'string',
help = 'name of the group in "DataContainers</basegroup>" that contains grain average data. '\
+ 'Leave empty for pointwise data')
parser.add_option('--phase',
dest = 'phase',
type = 'string', metavar = 'string',
help = 'name of the dataset containing pointwise/average phase IDs [%default]')
parser.add_option('--microstructure',
dest = 'microstructure',
type = 'string', metavar = 'string',
help = 'name of the dataset connecting pointwise and average data [%default]')
parser.add_option('-q', '--quaternion',
dest = 'quaternion',
type = 'string', metavar='string',
help = 'name of the dataset containing pointwise/average orientation as quaternion [%default]')
parser.set_defaults(pointwise = 'CellData',
quaternion = 'Quats',
phase = 'Phases',
microstructure = 'FeatureIds',
crystallite = 1,
)
(options, filenames) = parser.parse_args()
if options.basegroup is None:
parser.error('No base group selected')
rootDir ='DataContainers'
# --- loop over input files -------------------------------------------------------------------------
if filenames == []: parser.error('no input file specified.')
for name in filenames:
try:
table = damask.ASCIItable(outname = os.path.splitext(name)[0]+'.geom',
buffered = False, labeled=False,
)
except: continue
damask.util.report(scriptName,name)
errors = []
info = {}
ori = []
inFile = h5py.File(name, 'r')
group_geom = os.path.join(rootDir,options.basegroup,'_SIMPL_GEOMETRY')
try:
info['size'] = inFile[os.path.join(group_geom,'DIMENSIONS')][...] \
* inFile[os.path.join(group_geom,'SPACING')][...]
info['grid'] = inFile[os.path.join(group_geom,'DIMENSIONS')][...]
info['origin'] = inFile[os.path.join(group_geom,'ORIGIN')][...]
except:
errors.append('Geometry data ({}) not found'.format(group_geom))
group_pointwise = os.path.join(rootDir,options.basegroup,options.pointwise)
if options.average is None:
label = 'point'
N_microstructure = np.product(info['grid'])
dataset = os.path.join(group_pointwise,options.quaternion)
try:
quats = np.reshape(inFile[dataset][...],(N_microstructure,3))
except:
errors.append('Pointwise orientation data ({}) not found'.format(dataset))
texture = [damask.Rotation.fromQuaternion(q,True,P=+1) for q in quats]
dataset = os.path.join(group_pointwise,options.phase)
try:
phase = np.reshape(inFile[dataset][...],(N_microstructure))
except:
errors.append('Pointwise phase data ({}) not found'.format(dataset))
else:
label = 'grain'
dataset = os.path.join(group_pointwise,options.microstructure)
try:
microstructure = np.reshape(inFile[dataset][...],(np.product(info['grid'])))
N_microstructure = np.max(microstructure)
except:
errors.append('Link between pointwise and grain average data ({}) not found'.format(dataset))
group_average = os.path.join(rootDir,options.basegroup,options.average)
dataset = os.path.join(group_average,options.quaternion)
try:
texture = [damask.Rotation.fromQuaternion(q,True,P=+1) for q in inFile[dataset][...][1:]] # skip first entry (unindexed)
except:
errors.append('Average orientation data ({}) not found'.format(dataset))
dataset = os.path.join(group_average,options.phase)
try:
phase = [i[0] for i in inFile[dataset][...]][1:] # skip first entry (unindexed)
except:
errors.append('Average phase data ({}) not found'.format(dataset))
if errors != []:
damask.util.croak(errors)
table.close(dismiss = True)
continue
mat = damask.Material()
mat.verbose = False
# dummy <homogenization>
h = damask.config.material.Homogenization()
mat.add_section('Homogenization','none',h)
info['homogenization'] = 1
# <crystallite> placeholder (same for all microstructures at the moment)
c = damask.config.material.Crystallite()
mat.add_section('Crystallite','tbd',c)
# <phase> placeholders
for i in range(np.max(phase)):
p = damask.config.material.Phase()
mat.add_section('phase','phase{}-tbd'.format(i+1),p)
# <texture>
for i,o in enumerate(texture):
t = damask.config.material.Texture()
t.add_component('gauss',{'eulers':o.asEulers(degrees=True)})
mat.add_section(part='texture', section='{}{}'.format(label,i+1),initialData=t)
# <microstructure>
for i in range(N_microstructure):
m = damask.config.material.Microstructure()
mat.add_section('microstructure','{}{}'.format(label,i+1),m)
mat.add_microstructure('{}{}'.format(label,i+1),
{'phase': 'phase{}-tbd'.format(phase[i]),
'texture':'{}{}'.format(label,i+1),
'crystallite':'tbd',
'fraction':1
})
table.info_append([
scriptID + ' ' + ' '.join(sys.argv[1:]),
"grid\ta {}\tb {}\tc {}".format(*info['grid']),
"size\tx {}\ty {}\tz {}".format(*info['size']),
"origin\tx {}\ty {}\tz {}".format(*info['origin']),
"homogenization\t{}".format(info['homogenization']),
str(mat).split('\n')
])
table.head_write()
if options.average is None:
table.data = [1, 'to', format(N_microstructure)]
table.data_write()
else:
table.data = microstructure.reshape(info['grid'][1]*info['grid'][2],info['grid'][0])
table.data_writeArray()
table.close()

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 no BOM -*-
import os,sys,math,time
import scipy.spatial, numpy as np
import os,sys,math
import numpy as np
from optparse import OptionParser
import damask
@ -32,34 +32,6 @@ parser.add_option('--microstructure',
dest = 'microstructure',
type = 'string', metavar = 'string',
help = 'microstructure label')
parser.add_option('-t', '--tolerance',
dest = 'tolerance',
type = 'float', metavar = 'float',
help = 'angular tolerance for orientation squashing [%default]')
parser.add_option('-e', '--eulers',
dest = 'eulers',
type = 'string', metavar = 'string',
help = 'Euler angles label')
parser.add_option('-d', '--degrees',
dest = 'degrees',
action = 'store_true',
help = 'all angles are in degrees')
parser.add_option('-m', '--matrix',
dest = 'matrix',
type = 'string', metavar = 'string',
help = 'orientation matrix label')
parser.add_option('-a',
dest='a',
type = 'string', metavar = 'string',
help = 'crystal frame a vector label')
parser.add_option('-b',
dest='b',
type = 'string', metavar = 'string',
help = 'crystal frame b vector label')
parser.add_option('-c',
dest = 'c',
type = 'string', metavar='string',
help = 'crystal frame c vector label')
parser.add_option('-q', '--quaternion',
dest = 'quaternion',
type = 'string', metavar='string',
@ -67,11 +39,8 @@ parser.add_option('-q', '--quaternion',
parser.add_option('--axes',
dest = 'axes',
type = 'string', nargs = 3, metavar = ' '.join(['string']*3),
help = 'orientation coordinate frame in terms of position coordinate frame [same]')
parser.add_option('-s', '--symmetry',
dest = 'symmetry',
action = 'extend', metavar = '<string LIST>',
help = 'crystal symmetry of each phase %default {{{}}} '.format(', '.join(damask.Symmetry.lattices[1:])))
help = 'orientation coordinate frame in terms of position coordinate frame [+x +y +z]')
parser.add_option('--homogenization',
dest = 'homogenization',
type = 'int', metavar = 'int',
@ -80,27 +49,16 @@ parser.add_option('--crystallite',
dest = 'crystallite',
type = 'int', metavar = 'int',
help = 'crystallite index to be used [%default]')
parser.add_option('--verbose',
dest = 'verbose', action = 'store_true',
help = 'output extra info')
parser.set_defaults(symmetry = [damask.Symmetry.lattices[-1]],
tolerance = 0.0,
degrees = False,
homogenization = 1,
parser.set_defaults(homogenization = 1,
crystallite = 1,
verbose = False,
pos = 'pos',
)
(options,filenames) = parser.parse_args()
input = [options.eulers is not None,
options.a is not None and \
options.b is not None and \
options.c is not None,
options.matrix is not None,
options.quaternion is not None,
input = [ options.quaternion is not None,
options.microstructure is not None,
]
@ -109,14 +67,9 @@ if np.sum(input) != 1:
if options.axes is not None and not set(options.axes).issubset(set(['x','+x','-x','y','+y','-y','z','+z','-z'])):
parser.error('invalid axes {} {} {}.'.format(*options.axes))
(label,dim,inputtype) = [(options.eulers,3,'eulers'),
([options.a,options.b,options.c],[3,3,3],'frame'),
(options.matrix,9,'matrix'),
(options.quaternion,4,'quaternion'),
(label,dim,inputtype) = [(options.quaternion,4,'quaternion'),
(options.microstructure,1,'microstructure'),
][np.where(input)[0][0]] # select input label that was requested
toRadians = math.pi/180.0 if options.degrees else 1.0 # rescale all angles to radians
threshold = np.cos(options.tolerance/2.*toRadians) # cosine of (half of) tolerance angle
# --- loop over input files -------------------------------------------------------------------------
@ -146,7 +99,7 @@ for name in filenames:
if options.phase and table.label_dimension(options.phase) != 1:
errors.append('phase column "{}" is not scalar.'.format(options.phase))
if errors != []:
if errors != []:
damask.util.croak(errors)
table.close(dismiss = True)
continue
@ -157,10 +110,8 @@ for name in filenames:
if coordDim == 2:
table.data = np.insert(table.data,2,np.zeros(len(table.data)),axis=1) # add zero z coordinate for two-dimensional input
if options.verbose: damask.util.croak('extending to 3D...')
if options.phase is None:
table.data = np.column_stack((table.data,np.ones(len(table.data)))) # add single phase if no phase column given
if options.verbose: damask.util.croak('adding dummy phase info...')
# --------------- figure out size and grid ---------------------------------------------------------
@ -196,17 +147,10 @@ for name in filenames:
grain = table.data[:,colOri]
nGrains = len(np.unique(grain))
else:
if options.verbose: bg = damask.util.backgroundMessage(); bg.start() # start background messaging
elif inputtype == 'quaternion':
colPhase = -1 # column of phase data comes last
if options.verbose: bg.set_message('sorting positions...')
index = np.lexsort((table.data[:,0],table.data[:,1],table.data[:,2])) # index of position when sorting x fast, z slow
if options.verbose: bg.set_message('building KD tree...')
KDTree = scipy.spatial.KDTree((table.data[index,:3]-mincorner) / delta) # build KDTree with dX = dY = dZ = 1 and origin 0,0,0
statistics = {'global': 0, 'local': 0}
grain = -np.ones(N,dtype = 'int32') # initialize empty microstructure
orientations = [] # orientations
multiplicity = [] # orientation multiplicity (number of group members)
@ -215,87 +159,26 @@ for name in filenames:
existingGrains = np.arange(nGrains)
myPos = 0 # position (in list) of current grid point
tick = time.clock()
if options.verbose: bg.set_message('assigning grain IDs...')
for z in range(grid[2]):
for y in range(grid[1]):
for x in range(grid[0]):
if (myPos+1)%(N/500.) < 1:
time_delta = (time.clock()-tick) * (N - myPos) / myPos
if options.verbose: bg.set_message('(%02i:%02i:%02i) processing point %i of %i (grain count %i)...'
%(time_delta//3600,time_delta%3600//60,time_delta%60,myPos,N,nGrains))
myData = table.data[index[myPos]] # read data for current grid point
myPhase = int(myData[colPhase])
mySym = options.symmetry[min(myPhase,len(options.symmetry))-1] # take last specified option for all with higher index
if inputtype == 'eulers':
o = damask.Orientation(Eulers = myData[colOri:colOri+3]*toRadians,
symmetry = mySym)
elif inputtype == 'matrix':
o = damask.Orientation(matrix = myData[colOri:colOri+9].reshape(3,3),
symmetry = mySym)
elif inputtype == 'frame':
o = damask.Orientation(matrix = np.hstack((myData[colOri[0]:colOri[0]+3],
myData[colOri[1]:colOri[1]+3],
myData[colOri[2]:colOri[2]+3],
)).reshape(3,3),
symmetry = mySym)
elif inputtype == 'quaternion':
o = damask.Orientation(quaternion = myData[colOri:colOri+4],
symmetry = mySym)
o = damask.Rotation(myData[colOri:colOri+4])
cos_disorientations = -np.ones(1,dtype=float) # largest possible disorientation
closest_grain = -1 # invalid neighbor
if options.tolerance > 0.0: # only try to compress orientations if asked to
neighbors = np.array(KDTree.query_ball_point([x,y,z], 3)) # point indices within radius
# filter neighbors: skip myself, anyone further ahead (cannot yet have a grain ID), and other phases
neighbors = neighbors[(neighbors < myPos) & \
(table.data[index[neighbors],colPhase] == myPhase)]
grains = np.unique(grain[neighbors]) # unique grain IDs among valid neighbors
if len(grains) > 0: # check immediate neighborhood first
cos_disorientations = np.array([o.disorientation(orientations[grainID],
SST = False)[0].quaternion.q \
for grainID in grains]) # store disorientation per grainID
closest_grain = np.argmax(cos_disorientations) # grain among grains with closest orientation to myself
match = 'local'
if cos_disorientations[closest_grain] < threshold: # orientation not close enough?
grains = existingGrains[np.atleast_1d( (np.array(phases) == myPhase ) & \
(np.in1d(existingGrains,grains,invert=True)))] # other already identified grains (of my phase)
if len(grains) > 0:
cos_disorientations = np.array([o.disorientation(orientations[grainID],
SST = False)[0].quaternion.q \
for grainID in grains]) # store disorientation per grainID
closest_grain = np.argmax(cos_disorientations) # grain among grains with closest orientation to myself
match = 'global'
if cos_disorientations[closest_grain] >= threshold: # orientation now close enough?
grainID = grains[closest_grain]
grain[myPos] = grainID # assign myself to that grain ...
orientations[grainID] = damask.Orientation.average([orientations[grainID],o],
[multiplicity[grainID],1]) # update average orientation of best matching grain
multiplicity[grainID] += 1
statistics[match] += 1
else:
grain[myPos] = nGrains # assign new grain to me ...
nGrains += 1 # ... and update counter
orientations.append(o) # store new orientation for future comparison
multiplicity.append(1) # having single occurrence so far
phases.append(myPhase) # store phase info for future reporting
existingGrains = np.arange(nGrains) # update list of existing grains
grain[myPos] = nGrains # assign new grain to me ...
nGrains += 1 # ... and update counter
orientations.append(o) # store new orientation for future comparison
multiplicity.append(1) # having single occurrence so far
phases.append(myPhase) # store phase info for future reporting
existingGrains = np.arange(nGrains) # update list of existing grains
myPos += 1
if options.verbose:
bg.stop()
bg.join()
damask.util.croak("{} seconds total.\n{} local and {} global matches.".\
format(time.clock()-tick,statistics['local'],statistics['global']))
grain += 1 # offset from starting index 0 to 1

View File

@ -52,13 +52,14 @@ parser.set_defaults(degrees = False,
if sum(x is not None for x in [options.rotation,options.eulers,options.matrix,options.quaternion]) != 1:
parser.error('not exactly one rotation specified...')
eulers = np.array(damask.orientation.Orientation(
quaternion = np.array(options.quaternion) if options.quaternion else None,
angleAxis = np.array(options.rotation) if options.rotation else None,
matrix = np.array(options.matrix) if options.matrix else None,
Eulers = np.array(options.eulers) if options.eulers else None,
degrees = options.degrees,
).asEulers(degrees=True))
if options.quaternion is not None:
eulers = damask.Rotation.fromQuaternion(np.array(options.quaternion)).asEulers(degrees=True)
if options.rotation is not None:
eulers = damask.Rotation.fromAxisAngle(np.array(options.rotation,degrees=True)).asEulers(degrees=True)
if options.matrix is not None:
eulers = damask.Rotation.fromMatrix(np.array(options.Matrix)).asEulers(degrees=True)
if options.eulers is not None:
eulers = damask.Rotation.fromEulers(np.array(options.eulers),degrees=True).asEulers(degrees=True)
# --- loop over input files -------------------------------------------------------------------------

View File

@ -90,11 +90,7 @@ group.add_option( '-s',
'--selective',
action = 'store_true',
dest = 'selective',
help = 'selective picking of seed points from random seed points [%default]')
group.add_option( '--force',
action = 'store_true',
dest = 'force',
help = 'try selective picking despite large seed point number [%default]')
help = 'selective picking of seed points from random seed points')
group.add_option( '--distance',
dest = 'distance',
type = 'float', metavar = 'float',
@ -115,7 +111,6 @@ parser.set_defaults(randomSeed = None,
sigma = 0.05,
microstructure = 1,
selective = False,
force = False,
distance = 0.2,
numCandidates = 10,
format = None,
@ -148,10 +143,11 @@ for name in filenames:
errors = []
if gridSize == 0:
errors.append('zero grid dimension for {}.'.format(', '.join([['a','b','c'][x] for x in np.where(options.grid == 0)[0]])))
if options.N > gridSize/10.: errors.append('seed count exceeds 0.1 of grid points.')
if options.N > gridSize/10.:
remarks.append('seed count exceeds 0.1 of grid points.')
if options.selective and 4./3.*math.pi*(options.distance/2.)**3*options.N > 0.5:
(remarks if options.force else errors).append('maximum recommended seed point count for given distance is {}.{}'.
format(int(3./8./math.pi/(options.distance/2.)**3),'..'*options.force))
remarks.append('maximum recommended seed point count for given distance is {}.{}'.
format(int(3./8./math.pi/(options.distance/2.)**3)))
if remarks != []: damask.util.croak(remarks)
if errors != []:

125
python/damask/Lambert.py Normal file
View File

@ -0,0 +1,125 @@
# -*- coding: UTF-8 no BOM -*-
####################################################################################################
# Code below available according to the followin conditions on https://github.com/MarDiehl/3Drotations
####################################################################################################
# Copyright (c) 2017-2019, Martin Diehl/Max-Planck-Institut für Eisenforschung GmbH
# Copyright (c) 2013-2014, Marc De Graef/Carnegie Mellon University
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this list
# of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
# - Neither the names of Marc De Graef, Carnegie Mellon University nor the names
# of its contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
####################################################################################################
import numpy as np
sc = np.pi**(1./6.)/6.**(1./6.)
beta = np.pi**(5./6.)/6.**(1./6.)/2.
R1 = (3.*np.pi/4.)**(1./3.)
def CubeToBall(cube):
if np.abs(np.max(cube))>np.pi**(2./3.) * 0.5:
raise ValueError
# transform to the sphere grid via the curved square, and intercept the zero point
if np.allclose(cube,0.0,rtol=0.0,atol=1.0e-300):
ball = np.zeros(3)
else:
# get pyramide and scale by grid parameter ratio
p = GetPyramidOrder(cube)
XYZ = cube[p] * sc
# intercept all the points along the z-axis
if np.allclose(XYZ[0:2],0.0,rtol=0.0,atol=1.0e-300):
ball = np.array([0.0, 0.0, np.sqrt(6.0/np.pi) * XYZ[2]])
else:
order = [1,0] if np.abs(XYZ[1]) <= np.abs(XYZ[0]) else [0,1]
q = np.pi/12.0 * XYZ[order[0]]/XYZ[order[1]]
c = np.cos(q)
s = np.sin(q)
q = R1*2.0**0.25/beta * XYZ[order[1]] / np.sqrt(np.sqrt(2.0)-c)
T = np.array([ (np.sqrt(2.0)*c - 1.0), np.sqrt(2.0) * s]) * q
# transform to sphere grid (inverse Lambert)
# note that there is no need to worry about dividing by zero, since XYZ[2] can not become zero
c = np.sum(T**2)
s = c * np.pi/24.0 /XYZ[2]**2
c = c * np.sqrt(np.pi/24.0)/XYZ[2]
q = np.sqrt( 1.0 - s )
ball = np.array([ T[order[1]] * q, T[order[0]] * q, np.sqrt(6.0/np.pi) * XYZ[2] - c ])
# reverse the coordinates back to the regular order according to the original pyramid number
ball = ball[p]
return ball
def BallToCube(ball):
rs = np.linalg.norm(ball)
if rs > R1:
raise ValueError
if np.allclose(ball,0.0,rtol=0.0,atol=1.0e-300):
cube = np.zeros(3)
else:
p = GetPyramidOrder(ball)
xyz3 = ball[p]
# inverse M_3
xyz2 = xyz3[0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[2])) )
# inverse M_2
qxy = np.sum(xyz2**2)
if np.isclose(qxy,0.0,rtol=0.0,atol=1.0e-300):
Tinv = np.zeros(2)
else:
q2 = qxy + np.max(np.abs(xyz2))**2
sq2 = np.sqrt(q2)
q = (beta/np.sqrt(2.0)/R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2))*sq2))
tt = np.clip((np.min(np.abs(xyz2))**2+np.max(np.abs(xyz2))*sq2)/np.sqrt(2.0)/qxy,-1.0,1.0)
Tinv = np.array([1.0,np.arccos(tt)/np.pi*12.0]) if np.abs(xyz2[1]) <= np.abs(xyz2[0]) else \
np.array([np.arccos(tt)/np.pi*12.0,1.0])
Tinv = q * np.where(xyz2<0.0,-Tinv,Tinv)
# inverse M_1
cube = np.array([ Tinv[0], Tinv[1], (-1.0 if xyz3[2] < 0.0 else 1.0) * rs / np.sqrt(6.0/np.pi) ]) /sc
# reverse the coordinates back to the regular order according to the original pyramid number
cube = cube[p]
return cube
def GetPyramidOrder(xyz):
if (abs(xyz[0])<= xyz[2]) and (abs(xyz[1])<= xyz[2]) or \
(abs(xyz[0])<=-xyz[2]) and (abs(xyz[1])<=-xyz[2]):
return [0,1,2]
elif (abs(xyz[2])<= xyz[0]) and (abs(xyz[1])<= xyz[0]) or \
(abs(xyz[2])<=-xyz[0]) and (abs(xyz[1])<=-xyz[0]):
return [1,2,0]
elif (abs(xyz[0])<= xyz[1]) and (abs(xyz[2])<= xyz[1]) or \
(abs(xyz[0])<=-xyz[1]) and (abs(xyz[2])<=-xyz[1]):
return [2,0,1]

View File

@ -13,7 +13,7 @@ from .asciitable import ASCIItable # noqa
from .config import Material # noqa
from .colormaps import Colormap, Color # noqa
from .orientation import Quaternion, Symmetry, Orientation # noqa
from .orientation import Symmetry, Lattice, Rotation, Orientation # noqa
#from .block import Block # only one class
from .result import Result # noqa

View File

@ -77,18 +77,6 @@ class Texture(Section):
)
)
if multiKey == 'fiber':
self.add_multiKey(multiKey,'alpha1 %g\talpha2 %g\tbeta1 %g\tbeta2 %g\tscatter %g\tfraction %g'%(
properties['eulers'][0],
properties['eulers'][1],
properties['eulers'][2],
properties['eulers'][3],
scatter,
fraction,
)
)
class Material():
"""Reads, manipulates and writes material.config files"""
@ -97,10 +85,10 @@ class Material():
"""Generates ordered list of parts"""
self.parts = [
'homogenization',
'microstructure',
'crystallite',
'phase',
'texture',
'microstructure',
]
self.data = {\
'homogenization': {'__order__': []},
@ -117,15 +105,12 @@ class Material():
for part in self.parts:
if self.verbose: print('processing <{}>'.format(part))
me += ['',
'#-----------------------------#',
'#'*100,
'<{}>'.format(part),
'#-----------------------------#',
'#'*100,
]
for section in self.data[part]['__order__']:
me += ['',
'[{}] {}'.format(section,'#'*max(0,27-len(section))),
'',
]
me += ['[{}] {}'.format(section,'#'+'-'*max(0,96-len(section)))]
for key in self.data[part][section]['__order__']:
if key.startswith('(') and key.endswith(')'): # multiple (key)
me += ['{}\t{}'.format(key,' '.join(values)) for values in self.data[part][section][key]]

File diff suppressed because it is too large Load Diff

View File

@ -62,6 +62,18 @@ add_library(MATH OBJECT "math.f90")
add_dependencies(MATH NUMERICS)
list(APPEND OBJECTFILES $<TARGET_OBJECTS:MATH>)
add_library(QUATERNIONS OBJECT "quaternions.f90")
add_dependencies(QUATERNIONS MATH)
list(APPEND OBJECTFILES $<TARGET_OBJECTS:QUATERNIONS>)
add_library(LAMBERT OBJECT "Lambert.f90")
add_dependencies(LAMBERT MATH)
list(APPEND OBJECTFILES $<TARGET_OBJECTS:LAMBERT>)
add_library(ROTATIONS OBJECT "rotations.f90")
add_dependencies(ROTATIONS LAMBERT QUATERNIONS)
list(APPEND OBJECTFILES $<TARGET_OBJECTS:ROTATIONS>)
add_library(MESH_BASE OBJECT "mesh_base.f90")
add_dependencies(MESH_BASE ELEMENT)
list(APPEND OBJECTFILES $<TARGET_OBJECTS:MESH_BASE>)
@ -75,13 +87,13 @@ elseif (PROJECT_NAME STREQUAL "DAMASK_FEM")
add_library(FEZoo OBJECT "FEM_zoo.f90")
add_dependencies(FEZoo IO)
list(APPEND OBJECTFILES $<TARGET_OBJECTS:FEZoo>)
add_library(MESH OBJECT "mesh_FEM.f90")
add_library(MESH OBJECT "mesh_FEM.f90")
add_dependencies(MESH FEZoo MESH_BASE MATH FEsolving)
list(APPEND OBJECTFILES $<TARGET_OBJECTS:MESH>)
endif()
add_library(MATERIAL OBJECT "material.f90")
add_dependencies(MATERIAL MESH DAMASK_CONFIG)
add_dependencies(MATERIAL MESH DAMASK_CONFIG ROTATIONS)
list(APPEND OBJECTFILES $<TARGET_OBJECTS:MATERIAL>)
add_library(LATTICE OBJECT "lattice.f90")

217
src/Lambert.f90 Normal file
View File

@ -0,0 +1,217 @@
! ###################################################################
! Copyright (c) 2013-2015, Marc De Graef/Carnegie Mellon University
! Modified 2017-2019, Martin Diehl/Max-Planck-Institut für Eisenforschung GmbH
! All rights reserved.
!
! Redistribution and use in source and binary forms, with or without modification, are
! permitted provided that the following conditions are met:
!
! - Redistributions of source code must retain the above copyright notice, this list
! of conditions and the following disclaimer.
! - Redistributions in binary form must reproduce the above copyright notice, this
! list of conditions and the following disclaimer in the documentation and/or
! other materials provided with the distribution.
! - Neither the names of Marc De Graef, Carnegie Mellon University nor the names
! of its contributors may be used to endorse or promote products derived from
! this software without specific prior written permission.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
! USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! ###################################################################
!--------------------------------------------------------------------------
!> @author Marc De Graef, Carnegie Mellon University
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
!> @brief Mapping homochoric <-> cubochoric
!
!> @details
!> D. Rosca, A. Morawiec, and M. De Graef. A new method of constructing a grid
!> in the space of 3D rotations and its applications to texture analysis.
!> Modeling and Simulations in Materials Science and Engineering 22, 075013 (2014).
!--------------------------------------------------------------------------
module Lambert
use math
use prec, only: &
pReal
implicit none
private
real(pReal), parameter, private :: &
SPI = sqrt(PI), &
PREF = sqrt(6.0_pReal/PI), &
A = PI**(5.0_pReal/6.0_pReal)/6.0_pReal**(1.0_pReal/6.0_pReal), &
AP = PI**(2.0_pReal/3.0_pReal), &
SC = A/AP, &
BETA = A/2.0_pReal, &
R1 = (3.0_pReal*PI/4.0_pReal)**(1.0_pReal/3.0_pReal), &
R2 = sqrt(2.0_pReal), &
PI12 = PI/12.0_pReal, &
PREK = R1 * 2.0_pReal**(1.0_pReal/4.0_pReal)/BETA
public :: &
LambertCubeToBall, &
LambertBallToCube
private :: &
GetPyramidOrder
contains
!--------------------------------------------------------------------------
!> @author Marc De Graef, Carnegie Mellon University
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
!> @brief map from 3D cubic grid to 3D ball
!--------------------------------------------------------------------------
function LambertCubeToBall(cube) result(ball)
use, intrinsic :: IEEE_ARITHMETIC
use prec, only: &
pInt, &
dEq0
implicit none
real(pReal), intent(in), dimension(3) :: cube
real(pReal), dimension(3) :: ball, LamXYZ, XYZ
real(pReal) :: T(2), c, s, q
real(pReal), parameter :: eps = 1.0e-8_pReal
integer(pInt), dimension(3) :: p
integer(pInt), dimension(2) :: order
if (maxval(abs(cube)) > AP/2.0+eps) then
ball = IEEE_value(cube,IEEE_positive_inf)
return
end if
! transform to the sphere grid via the curved square, and intercept the zero point
center: if (all(dEq0(cube))) then
ball = 0.0_pReal
else center
! get pyramide and scale by grid parameter ratio
p = GetPyramidOrder(cube)
XYZ = cube(p) * sc
! intercept all the points along the z-axis
special: if (all(dEq0(XYZ(1:2)))) then
LamXYZ = [ 0.0_pReal, 0.0_pReal, pref * XYZ(3) ]
else special
order = merge( [2,1], [1,2], abs(XYZ(2)) <= abs(XYZ(1))) ! order of absolute values of XYZ
q = PI12 * XYZ(order(1))/XYZ(order(2)) ! smaller by larger
c = cos(q)
s = sin(q)
q = prek * XYZ(order(2))/ sqrt(R2-c)
T = [ (R2*c - 1.0), R2 * s] * q
! transform to sphere grid (inverse Lambert)
! [note that there is no need to worry about dividing by zero, since XYZ(3) can not become zero]
c = sum(T**2)
s = Pi * c/(24.0*XYZ(3)**2)
c = sPi * c / sqrt(24.0_pReal) / XYZ(3)
q = sqrt( 1.0 - s )
LamXYZ = [ T(order(2)) * q, T(order(1)) * q, pref * XYZ(3) - c ]
endif special
! reverse the coordinates back to the regular order according to the original pyramid number
ball = LamXYZ(p)
endif center
end function LambertCubeToBall
!--------------------------------------------------------------------------
!> @author Marc De Graef, Carnegie Mellon University
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
!> @brief map from 3D ball to 3D cubic grid
!--------------------------------------------------------------------------
pure function LambertBallToCube(xyz) result(cube)
use, intrinsic :: IEEE_ARITHMETIC, only:&
IEEE_positive_inf, &
IEEE_value
use prec, only: &
pInt, &
dEq0
implicit none
real(pReal), intent(in), dimension(3) :: xyz
real(pReal), dimension(3) :: cube, xyz1, xyz3
real(pReal), dimension(2) :: Tinv, xyz2
real(pReal) :: rs, qxy, q2, sq2, q, tt
integer(pInt), dimension(3) :: p
rs = norm2(xyz)
if (rs > R1) then
cube = IEEE_value(cube,IEEE_positive_inf)
return
endif
center: if (all(dEq0(xyz))) then
cube = 0.0_pReal
else center
p = GetPyramidOrder(xyz)
xyz3 = xyz(p)
! inverse M_3
xyz2 = xyz3(1:2) * sqrt( 2.0*rs/(rs+abs(xyz3(3))) )
! inverse M_2
qxy = sum(xyz2**2)
special: if (dEq0(qxy)) then
Tinv = 0.0
else special
q2 = qxy + maxval(abs(xyz2))**2
sq2 = sqrt(q2)
q = (beta/R2/R1) * sqrt(q2*qxy/(q2-maxval(abs(xyz2))*sq2))
tt = (minval(abs(xyz2))**2+maxval(abs(xyz2))*sq2)/R2/qxy
Tinv = q * sign(1.0,xyz2) * merge([ 1.0_pReal, acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12], &
[ acos(math_clip(tt,-1.0_pReal,1.0_pReal))/PI12, 1.0_pReal], &
abs(xyz2(2)) <= abs(xyz2(1)))
endif special
! inverse M_1
xyz1 = [ Tinv(1), Tinv(2), sign(1.0,xyz3(3)) * rs / pref ] /sc
! reverst the coordinates back to the regular order according to the original pyramid number
cube = xyz1(p)
endif center
end function LambertBallToCube
!--------------------------------------------------------------------------
!> @author Marc De Graef, Carnegie Mellon University
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
!> @brief determine to which pyramid a point in a cubic grid belongs
!--------------------------------------------------------------------------
pure function GetPyramidOrder(xyz)
use prec, only: &
pInt
implicit none
real(pReal),intent(in),dimension(3) :: xyz
integer(pInt), dimension(3) :: GetPyramidOrder
if (((abs(xyz(1)) <= xyz(3)).and.(abs(xyz(2)) <= xyz(3))) .or. &
((abs(xyz(1)) <= -xyz(3)).and.(abs(xyz(2)) <= -xyz(3)))) then
GetPyramidOrder = [1,2,3]
else if (((abs(xyz(3)) <= xyz(1)).and.(abs(xyz(2)) <= xyz(1))) .or. &
((abs(xyz(3)) <= -xyz(1)).and.(abs(xyz(2)) <= -xyz(1)))) then
GetPyramidOrder = [2,3,1]
else if (((abs(xyz(1)) <= xyz(2)).and.(abs(xyz(3)) <= xyz(2))) .or. &
((abs(xyz(1)) <= -xyz(2)).and.(abs(xyz(3)) <= -xyz(2)))) then
GetPyramidOrder = [3,1,2]
else
GetPyramidOrder = -1 ! should be impossible, but might simplify debugging
end if
end function GetPyramidOrder
end module Lambert

View File

@ -11,6 +11,9 @@
#include "HDF5_utilities.f90"
#endif
#include "math.f90"
#include "quaternions.f90"
#include "Lambert.f90"
#include "rotations.f90"
#include "FEsolving.f90"
#include "element.f90"
#include "mesh_base.f90"

View File

@ -48,11 +48,8 @@ subroutine constitutive_init()
use IO, only: &
IO_error, &
IO_open_file, &
IO_checkAndRewind, &
IO_open_jobFile_stat, &
IO_write_jobFile
use config, only: &
config_phase
use config, only: &
material_Nphase, &
material_localFileExt, &
@ -132,40 +129,29 @@ subroutine constitutive_init()
nonlocalConstitutionPresent = .false.
!--------------------------------------------------------------------------------------------------
! open material.config
if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present...
call IO_open_file(FILEUNIT,material_configFile) ! ... open material.config file
!--------------------------------------------------------------------------------------------------
! parse plasticities from config file
! initialized plasticity
if (any(phase_plasticity == PLASTICITY_NONE_ID)) call plastic_none_init
if (any(phase_plasticity == PLASTICITY_ISOTROPIC_ID)) call plastic_isotropic_init
if (any(phase_plasticity == PLASTICITY_PHENOPOWERLAW_ID)) call plastic_phenopowerlaw_init
if (any(phase_plasticity == PLASTICITY_KINEHARDENING_ID)) call plastic_kinehardening_init
if (any(phase_plasticity == PLASTICITY_DISLOTWIN_ID)) call plastic_dislotwin_init
if (any(phase_plasticity == PLASTICITY_DISLOUCLA_ID)) call plastic_disloucla_init
if (any(phase_plasticity == PLASTICITY_NONLOCAL_ID)) then
call plastic_nonlocal_init(FILEUNIT)
call plastic_nonlocal_stateInit()
endif
if (any(phase_plasticity == PLASTICITY_NONLOCAL_ID)) call plastic_nonlocal_init
!--------------------------------------------------------------------------------------------------
! parse source mechanisms from config file
call IO_checkAndRewind(FILEUNIT)
! initialize source mechanisms
if (any(phase_source == SOURCE_thermal_dissipation_ID)) call source_thermal_dissipation_init
if (any(phase_source == SOURCE_thermal_externalheat_ID)) call source_thermal_externalheat_init
if (any(phase_source == SOURCE_damage_isoBrittle_ID)) call source_damage_isoBrittle_init
if (any(phase_source == SOURCE_damage_isoDuctile_ID)) call source_damage_isoDuctile_init
if (any(phase_source == SOURCE_damage_anisoBrittle_ID)) call source_damage_anisoBrittle_init
if (any(phase_source == SOURCE_damage_anisoDuctile_ID)) call source_damage_anisoDuctile_init
!--------------------------------------------------------------------------------------------------
! parse kinematic mechanisms from config file
call IO_checkAndRewind(FILEUNIT)
! initialize kinematic mechanisms
if (any(phase_kinematics == KINEMATICS_cleavage_opening_ID)) call kinematics_cleavage_opening_init
if (any(phase_kinematics == KINEMATICS_slipplane_opening_ID)) call kinematics_slipplane_opening_init
if (any(phase_kinematics == KINEMATICS_thermal_expansion_ID)) call kinematics_thermal_expansion_init
close(FILEUNIT)
call config_deallocate('material.config/phase')
@ -337,7 +323,7 @@ end function constitutive_homogenizedC
!--------------------------------------------------------------------------------------------------
!> @brief calls microstructure function of the different constitutive models
!--------------------------------------------------------------------------------------------------
subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el)
subroutine constitutive_microstructure(Fe, Fp, ipc, ip, el)
use prec, only: &
pReal
use material, only: &
@ -352,7 +338,7 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el)
PLASTICITY_disloucla_ID, &
PLASTICITY_nonlocal_ID
use plastic_nonlocal, only: &
plastic_nonlocal_microstructure
plastic_nonlocal_dependentState
use plastic_dislotwin, only: &
plastic_dislotwin_dependentState
use plastic_disloUCLA, only: &
@ -370,8 +356,6 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el)
ho, & !< homogenization
tme, & !< thermal member position
instance, of
real(pReal), intent(in), dimension(:,:,:,:) :: &
orientations !< crystal orientations as quaternions
ho = material_homogenizationAt(el)
tme = thermalMapping(ho)%p(ip,el)
@ -386,7 +370,7 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el)
instance = phase_plasticityInstance(material_phase(ipc,ip,el))
call plastic_disloUCLA_dependentState(instance,of)
case (PLASTICITY_NONLOCAL_ID) plasticityType
call plastic_nonlocal_microstructure (Fe,Fp,ip,el)
call plastic_nonlocal_dependentState (Fe,Fp,ip,el)
end select plasticityType
end subroutine constitutive_microstructure
@ -394,15 +378,15 @@ end subroutine constitutive_microstructure
!--------------------------------------------------------------------------------------------------
!> @brief contains the constitutive equation for calculating the velocity gradient
! ToDo: Discuss wheter it makes sense if crystallite handles the configuration conversion, i.e.
! Mp in, dLp_dMp out
!--------------------------------------------------------------------------------------------------
subroutine constitutive_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, S6, Fi, ipc, ip, el)
subroutine constitutive_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, &
S, Fi, ipc, ip, el)
use prec, only: &
pReal
use math, only: &
math_mul33x33, &
math_6toSym33, &
math_sym33to6, &
math_99to3333
math_mul33x33
use material, only: &
phasememberAt, &
phase_plasticity, &
@ -418,6 +402,8 @@ subroutine constitutive_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, S6, Fi, ipc, ip, e
PLASTICITY_DISLOTWIN_ID, &
PLASTICITY_DISLOUCLA_ID, &
PLASTICITY_NONLOCAL_ID
use mesh, only: &
mesh_ipVolume
use plastic_isotropic, only: &
plastic_isotropic_LpAndItsTangent
use plastic_phenopowerlaw, only: &
@ -436,9 +422,8 @@ subroutine constitutive_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, S6, Fi, ipc, ip, e
ipc, & !< component-ID of integration point
ip, & !< integration point
el !< element
real(pReal), intent(in), dimension(6) :: &
S6 !< 2nd Piola-Kirchhoff stress (vector notation)
real(pReal), intent(in), dimension(3,3) :: &
S, & !< 2nd Piola-Kirchhoff stress
Fi !< intermediate deformation gradient
real(pReal), intent(out), dimension(3,3) :: &
Lp !< plastic velocity gradient
@ -447,11 +432,8 @@ subroutine constitutive_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, S6, Fi, ipc, ip, e
dLp_dFi !< derivative of Lp with respect to Fi
real(pReal), dimension(3,3,3,3) :: &
dLp_dMp !< derivative of Lp with respect to Mandel stress
real(pReal), dimension(9,9) :: &
dLp_dMp99 !< derivative of Lp with respect to Mstar (matrix notation)
real(pReal), dimension(3,3) :: &
Mp, & !< Mandel stress work conjugate with Lp
S !< 2nd Piola-Kirchhoff stress
Mp !< Mandel stress work conjugate with Lp
integer(pInt) :: &
ho, & !< homogenization
tme !< thermal member position
@ -461,7 +443,6 @@ subroutine constitutive_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, S6, Fi, ipc, ip, e
ho = material_homogenizationAt(el)
tme = thermalMapping(ho)%p(ip,el)
S = math_6toSym33(S6)
Mp = math_mul33x33(math_mul33x33(transpose(Fi),Fi),S)
plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el)))
@ -486,9 +467,8 @@ subroutine constitutive_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, S6, Fi, ipc, ip, e
call plastic_kinehardening_LpAndItsTangent (Lp,dLp_dMp, Mp,instance,of)
case (PLASTICITY_NONLOCAL_ID) plasticityType
call plastic_nonlocal_LpAndItsTangent (Lp,dLp_dMp99, math_sym33to6(Mp), &
temperature(ho)%p(tme),ip,el)
dLp_dMp = math_99to3333(dLp_dMp99) ! ToDo: We revert here the last statement in plastic_xx_LpAndItsTanget
call plastic_nonlocal_LpAndItsTangent (Lp,dLp_dMp,Mp, &
temperature(ho)%p(tme),mesh_ipVolume(ip,el),ip,el)
case (PLASTICITY_DISLOTWIN_ID) plasticityType
of = phasememberAt(ipc,ip,el)
@ -523,15 +503,15 @@ end subroutine constitutive_LpAndItsTangents
!> @brief contains the constitutive equation for calculating the velocity gradient
! ToDo: MD: S is Mi?
!--------------------------------------------------------------------------------------------------
subroutine constitutive_LiAndItsTangents(Li, dLi_dS, dLi_dFi, S6, Fi, ipc, ip, el)
subroutine constitutive_LiAndItsTangents(Li, dLi_dS, dLi_dFi, &
S, Fi, ipc, ip, el)
use prec, only: &
pReal
use math, only: &
math_I3, &
math_inv33, &
math_det33, &
math_mul33x33, &
math_6toSym33
math_mul33x33
use material, only: &
phasememberAt, &
phase_plasticity, &
@ -558,8 +538,8 @@ subroutine constitutive_LiAndItsTangents(Li, dLi_dS, dLi_dFi, S6, Fi, ipc, ip, e
ipc, & !< component-ID of integration point
ip, & !< integration point
el !< element
real(pReal), intent(in), dimension(6) :: &
S6 !< 2nd Piola-Kirchhoff stress (vector notation)
real(pReal), intent(in), dimension(3,3) :: &
S !< 2nd Piola-Kirchhoff stress
real(pReal), intent(in), dimension(3,3) :: &
Fi !< intermediate deformation gradient
real(pReal), intent(out), dimension(3,3) :: &
@ -588,7 +568,7 @@ subroutine constitutive_LiAndItsTangents(Li, dLi_dS, dLi_dFi, S6, Fi, ipc, ip, e
case (PLASTICITY_isotropic_ID) plasticityType
of = phasememberAt(ipc,ip,el)
instance = phase_plasticityInstance(material_phase(ipc,ip,el))
call plastic_isotropic_LiAndItsTangent(my_Li, my_dLi_dS, math_6toSym33(S6),instance,of)
call plastic_isotropic_LiAndItsTangent(my_Li, my_dLi_dS, S ,instance,of)
case default plasticityType
my_Li = 0.0_pReal
my_dLi_dS = 0.0_pReal
@ -600,9 +580,9 @@ subroutine constitutive_LiAndItsTangents(Li, dLi_dS, dLi_dFi, S6, Fi, ipc, ip, e
KinematicsLoop: do k = 1_pInt, phase_Nkinematics(material_phase(ipc,ip,el))
kinematicsType: select case (phase_kinematics(k,material_phase(ipc,ip,el)))
case (KINEMATICS_cleavage_opening_ID) kinematicsType
call kinematics_cleavage_opening_LiAndItsTangent(my_Li, my_dLi_dS, math_6toSym33(S6), ipc, ip, el)
call kinematics_cleavage_opening_LiAndItsTangent(my_Li, my_dLi_dS, S, ipc, ip, el)
case (KINEMATICS_slipplane_opening_ID) kinematicsType
call kinematics_slipplane_opening_LiAndItsTangent(my_Li, my_dLi_dS, math_6toSym33(S6), ipc, ip, el)
call kinematics_slipplane_opening_LiAndItsTangent(my_Li, my_dLi_dS, S, ipc, ip, el)
case (KINEMATICS_thermal_expansion_ID) kinematicsType
call kinematics_thermal_expansion_LiAndItsTangent(my_Li, my_dLi_dS, ipc, ip, el)
case default kinematicsType
@ -634,9 +614,7 @@ pure function constitutive_initialFi(ipc, ip, el)
use prec, only: &
pReal
use math, only: &
math_I3, &
math_inv33, &
math_mul33x33
math_I3
use material, only: &
material_phase, &
material_homog, &
@ -710,7 +688,8 @@ end subroutine constitutive_SandItsTangents
!> @brief returns the 2nd Piola-Kirchhoff stress tensor and its tangent with respect to
!> the elastic and intermeidate deformation gradients using Hookes law
!--------------------------------------------------------------------------------------------------
subroutine constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, Fe, Fi, ipc, ip, el)
subroutine constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, &
Fe, Fi, ipc, ip, el)
use prec, only: &
pReal
use math, only : &
@ -774,7 +753,7 @@ end subroutine constitutive_hooke_SandItsTangents
!--------------------------------------------------------------------------------------------------
!> @brief contains the constitutive equation for calculating the rate of change of microstructure
!--------------------------------------------------------------------------------------------------
subroutine constitutive_collectDotState(S6, FeArray, Fi, FpArray, subdt, subfracArray,ipc, ip, el)
subroutine constitutive_collectDotState(S, FeArray, Fi, FpArray, subdt, ipc, ip, el)
use prec, only: &
pReal, &
pLongInt
@ -784,8 +763,6 @@ subroutine constitutive_collectDotState(S6, FeArray, Fi, FpArray, subdt, subfrac
debug_levelBasic
use math, only: &
math_mul33x33, &
math_6toSym33, &
math_sym33to6, &
math_mul33x33
use mesh, only: &
theMesh
@ -839,27 +816,25 @@ subroutine constitutive_collectDotState(S6, FeArray, Fi, FpArray, subdt, subfrac
el !< element
real(pReal), intent(in) :: &
subdt !< timestep
real(pReal), intent(in), dimension(homogenization_maxNgrains,theMesh%elem%nIPs,theMesh%Nelems) :: &
subfracArray !< subfraction of timestep
real(pReal), intent(in), dimension(3,3,homogenization_maxNgrains,theMesh%elem%nIPs,theMesh%Nelems) :: &
FeArray, & !< elastic deformation gradient
FpArray !< plastic deformation gradient
real(pReal), intent(in), dimension(3,3) :: &
Fi !< intermediate deformation gradient
real(pReal), intent(in), dimension(6) :: &
S6 !< 2nd Piola Kirchhoff stress (vector notation)
real(pReal), intent(in), dimension(3,3) :: &
S !< 2nd Piola Kirchhoff stress (vector notation)
real(pReal), dimension(3,3) :: &
Mp
integer(pInt) :: &
ho, & !< homogenization
tme, & !< thermal member position
s, & !< counter in source loop
i, & !< counter in source loop
instance, of
ho = material_homogenizationAt(el)
tme = thermalMapping(ho)%p(ip,el)
Mp = math_mul33x33(math_mul33x33(transpose(Fi),Fi),math_6toSym33(S6))
Mp = math_mul33x33(math_mul33x33(transpose(Fi),Fi),S)
plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el)))
@ -889,16 +864,16 @@ subroutine constitutive_collectDotState(S6, FeArray, Fi, FpArray, subdt, subfrac
call plastic_disloucla_dotState (Mp,temperature(ho)%p(tme),instance,of)
case (PLASTICITY_NONLOCAL_ID) plasticityType
call plastic_nonlocal_dotState (math_sym33to6(Mp),FeArray,FpArray,temperature(ho)%p(tme), &
subdt,subfracArray,ip,el)
call plastic_nonlocal_dotState (Mp,FeArray,FpArray,temperature(ho)%p(tme), &
subdt,ip,el)
end select plasticityType
SourceLoop: do s = 1_pInt, phase_Nsources(material_phase(ipc,ip,el))
SourceLoop: do i = 1_pInt, phase_Nsources(material_phase(ipc,ip,el))
sourceType: select case (phase_source(s,material_phase(ipc,ip,el)))
sourceType: select case (phase_source(i,material_phase(ipc,ip,el)))
case (SOURCE_damage_anisoBrittle_ID) sourceType
call source_damage_anisoBrittle_dotState (math_6toSym33(S6), ipc, ip, el) !< correct stress?
call source_damage_anisoBrittle_dotState (S, ipc, ip, el) !< correct stress?
case (SOURCE_damage_isoDuctile_ID) sourceType
call source_damage_isoDuctile_dotState ( ipc, ip, el)
@ -928,7 +903,6 @@ subroutine constitutive_collectDeltaState(S, Fe, Fi, ipc, ip, el)
debug_constitutive, &
debug_levelBasic
use math, only: &
math_sym33to6, &
math_mul33x33
use material, only: &
phasememberAt, &
@ -972,7 +946,7 @@ subroutine constitutive_collectDeltaState(S, Fe, Fi, ipc, ip, el)
call plastic_kinehardening_deltaState(Mp,instance,of)
case (PLASTICITY_NONLOCAL_ID) plasticityType
call plastic_nonlocal_deltaState(math_sym33to6(Mp),ip,el)
call plastic_nonlocal_deltaState(Mp,ip,el)
end select plasticityType
@ -994,14 +968,11 @@ end subroutine constitutive_collectDeltaState
!--------------------------------------------------------------------------------------------------
!> @brief returns array of constitutive results
!--------------------------------------------------------------------------------------------------
function constitutive_postResults(S6, Fi, FeArray, ipc, ip, el)
function constitutive_postResults(S, Fi, ipc, ip, el)
use prec, only: &
pReal
use math, only: &
math_6toSym33, &
math_mul33x33
use mesh, only: &
theMesh
use material, only: &
phasememberAt, &
phase_plasticityInstance, &
@ -1014,7 +985,6 @@ function constitutive_postResults(S6, Fi, FeArray, ipc, ip, el)
material_homogenizationAt, &
temperature, &
thermalMapping, &
homogenization_maxNgrains, &
PLASTICITY_NONE_ID, &
PLASTICITY_ISOTROPIC_ID, &
PLASTICITY_PHENOPOWERLAW_ID, &
@ -1057,10 +1027,8 @@ function constitutive_postResults(S6, Fi, FeArray, ipc, ip, el)
constitutive_postResults
real(pReal), intent(in), dimension(3,3) :: &
Fi !< intermediate deformation gradient
real(pReal), intent(in), dimension(3,3,homogenization_maxNgrains,theMesh%elem%nIPs,theMesh%Nelems) :: &
FeArray !< elastic deformation gradient
real(pReal), intent(in), dimension(6) :: &
S6 !< 2nd Piola Kirchhoff stress (vector notation)
real(pReal), intent(in), dimension(3,3) :: &
S !< 2nd Piola Kirchhoff stress
real(pReal), dimension(3,3) :: &
Mp !< Mandel stress
integer(pInt) :: &
@ -1068,11 +1036,11 @@ function constitutive_postResults(S6, Fi, FeArray, ipc, ip, el)
integer(pInt) :: &
ho, & !< homogenization
tme, & !< thermal member position
s, of, instance !< counter in source loop
i, of, instance !< counter in source loop
constitutive_postResults = 0.0_pReal
Mp = math_mul33x33(math_mul33x33(transpose(Fi),Fi),math_6toSym33(S6))
Mp = math_mul33x33(math_mul33x33(transpose(Fi),Fi),S)
ho = material_homogenizationAt(el)
tme = thermalMapping(ho)%p(ip,el)
@ -1113,14 +1081,14 @@ function constitutive_postResults(S6, Fi, FeArray, ipc, ip, el)
case (PLASTICITY_NONLOCAL_ID) plasticityType
constitutive_postResults(startPos:endPos) = &
plastic_nonlocal_postResults (S6,FeArray,ip,el)
plastic_nonlocal_postResults (Mp,ip,el)
end select plasticityType
SourceLoop: do s = 1_pInt, phase_Nsources(material_phase(ipc,ip,el))
SourceLoop: do i = 1_pInt, phase_Nsources(material_phase(ipc,ip,el))
startPos = endPos + 1_pInt
endPos = endPos + sourceState(material_phase(ipc,ip,el))%p(s)%sizePostResults
endPos = endPos + sourceState(material_phase(ipc,ip,el))%p(i)%sizePostResults
of = phasememberAt(ipc,ip,el)
sourceType: select case (phase_source(s,material_phase(ipc,ip,el)))
sourceType: select case (phase_source(i,material_phase(ipc,ip,el)))
case (SOURCE_damage_isoBrittle_ID) sourceType
constitutive_postResults(startPos:endPos) = source_damage_isoBrittle_postResults(material_phase(ipc,ip,el),of)
case (SOURCE_damage_isoDuctile_ID) sourceType

File diff suppressed because it is too large Load Diff

View File

@ -9,14 +9,16 @@
!--------------------------------------------------------------------------------------------------
module crystallite
use prec, only: &
pReal, &
pInt
use rotations, only: &
rotation
use FEsolving, only: &
FEsolving_execElem, &
FEsolving_execIP
use material, only: &
homogenization_Ngrains
use prec, only: &
pReal, &
pInt
implicit none
@ -40,10 +42,9 @@ module crystallite
crystallite_Tstar_v, & !< current 2nd Piola-Kirchhoff stress vector (end of converged time step) ToDo: Should be called S, 3x3
crystallite_Tstar0_v, & !< 2nd Piola-Kirchhoff stress vector at start of FE inc ToDo: Should be called S, 3x3
crystallite_partionedTstar0_v !< 2nd Piola-Kirchhoff stress vector at start of homog inc ToDo: Should be called S, 3x3
real(pReal), dimension(:,:,:,:), allocatable, private :: &
crystallite_orientation, & !< orientation as quaternion
crystallite_orientation0, & !< initial orientation as quaternion
crystallite_rotation !< grain rotation away from initial orientation as axis-angle (in degrees) in crystal reference frame
type(rotation), dimension(:,:,:), allocatable, private :: &
crystallite_orientation, & !< orientation
crystallite_orientation0 !< initial orientation
real(pReal), dimension(:,:,:,:,:), allocatable, public, protected :: &
crystallite_Fe, & !< current "elastic" def grad (end of converged time step)
crystallite_P !< 1st Piola-Kirchhoff stress per grain
@ -89,7 +90,6 @@ module crystallite
volume_ID, &
orientation_ID, &
grainrotation_ID, &
eulerangles_ID, &
defgrad_ID, &
fe_ID, &
fp_ID, &
@ -233,9 +233,8 @@ subroutine crystallite_init
allocate(crystallite_subdt(cMax,iMax,eMax), source=0.0_pReal)
allocate(crystallite_subFrac(cMax,iMax,eMax), source=0.0_pReal)
allocate(crystallite_subStep(cMax,iMax,eMax), source=0.0_pReal)
allocate(crystallite_orientation(4,cMax,iMax,eMax), source=0.0_pReal)
allocate(crystallite_orientation0(4,cMax,iMax,eMax), source=0.0_pReal)
allocate(crystallite_rotation(4,cMax,iMax,eMax), source=0.0_pReal)
allocate(crystallite_orientation(cMax,iMax,eMax))
allocate(crystallite_orientation0(cMax,iMax,eMax))
allocate(crystallite_localPlasticity(cMax,iMax,eMax), source=.true.)
allocate(crystallite_requested(cMax,iMax,eMax), source=.false.)
allocate(crystallite_todo(cMax,iMax,eMax), source=.false.)
@ -284,9 +283,7 @@ subroutine crystallite_init
crystallite_outputID(o,c) = orientation_ID
case ('grainrotation') outputName
crystallite_outputID(o,c) = grainrotation_ID
case ('eulerangles') outputName
crystallite_outputID(o,c) = eulerangles_ID
case ('defgrad','f') outputName
case ('defgrad','f') outputName ! ToDo: no alias (f only)
crystallite_outputID(o,c) = defgrad_ID
case ('fe') outputName
crystallite_outputID(o,c) = fe_ID
@ -300,13 +297,13 @@ subroutine crystallite_init
crystallite_outputID(o,c) = li_ID
case ('p','firstpiola','1stpiola') outputName
crystallite_outputID(o,c) = p_ID
case ('s','tstar','secondpiola','2ndpiola') outputName
case ('s','tstar','secondpiola','2ndpiola') outputName ! ToDo: no alias (s only)
crystallite_outputID(o,c) = s_ID
case ('elasmatrix') outputName
crystallite_outputID(o,c) = elasmatrix_ID
case ('neighboringip') outputName
case ('neighboringip') outputName ! ToDo: this is not a result, it is static. Should be written out by mesh
crystallite_outputID(o,c) = neighboringip_ID
case ('neighboringelement') outputName
case ('neighboringelement') outputName ! ToDo: this is not a result, it is static. Should be written out by mesh
crystallite_outputID(o,c) = neighboringelement_ID
case default outputName
call IO_error(105_pInt,ext_msg=trim(str(o))//' (Crystallite)')
@ -322,8 +319,6 @@ subroutine crystallite_init
mySize = 1_pInt
case(orientation_ID,grainrotation_ID)
mySize = 4_pInt
case(eulerangles_ID)
mySize = 3_pInt
case(defgrad_ID,fe_ID,fp_ID,fi_ID,lp_ID,li_ID,p_ID,s_ID)
mySize = 9_pInt
case(elasmatrix_ID)
@ -394,8 +389,7 @@ subroutine crystallite_init
do e = FEsolving_execElem(1),FEsolving_execElem(2)
do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e)
do c = 1_pInt,homogenization_Ngrains(mesh_element(3,e))
call constitutive_microstructure(crystallite_orientation, &
crystallite_Fe(1:3,1:3,c,i,e), &
call constitutive_microstructure(crystallite_Fe(1:3,1:3,c,i,e), &
crystallite_Fp(1:3,1:3,c,i,e), &
c,i,e) ! update dependent state variables to be consistent with basic states
enddo
@ -426,7 +420,7 @@ end subroutine crystallite_init
!--------------------------------------------------------------------------------------------------
!> @brief calculate stress (P)
!--------------------------------------------------------------------------------------------------
function crystallite_stress(a)
function crystallite_stress(dummyArgumentToPreventInternalCompilerErrorWithGCC)
use prec, only: &
tol_math_check, &
dNeq0
@ -462,14 +456,11 @@ function crystallite_stress(a)
sourceState, &
phase_Nsources, &
phaseAt, phasememberAt
use constitutive, only: &
constitutive_SandItsTangents, &
constitutive_LpAndItsTangents, &
constitutive_LiAndItsTangents
implicit none
logical, dimension(theMesh%elem%nIPs,theMesh%Nelems) :: crystallite_stress
real(pReal), intent(in), optional :: a !ToDo: for some reason this prevents an internal compiler error in GNU. Very strange
real(pReal), intent(in), optional :: &
dummyArgumentToPreventInternalCompilerErrorWithGCC
real(pReal) :: &
formerSubStep
integer(pInt) :: &
@ -764,7 +755,7 @@ subroutine crystallite_stressTangent()
crystallite_Fe(1:3,1:3,c,i,e), &
crystallite_Fi(1:3,1:3,c,i,e),c,i,e) ! call constitutive law to calculate elastic stress tangent
call constitutive_LiAndItsTangents(devNull,dLidS,dLidFi, &
crystallite_Tstar_v(1:6,c,i,e), &
math_6toSym33(crystallite_Tstar_v(1:6,c,i,e)), &
crystallite_Fi(1:3,1:3,c,i,e), &
c,i,e) ! call constitutive law to calculate Li tangent in lattice configuration
@ -793,7 +784,7 @@ subroutine crystallite_stressTangent()
endif
call constitutive_LpAndItsTangents(devNull,dLpdS,dLpdFi, &
crystallite_Tstar_v(1:6,c,i,e), &
math_6toSym33(crystallite_Tstar_v(1:6,c,i,e)), &
crystallite_Fi(1:3,1:3,c,i,e),c,i,e) ! call constitutive law to calculate Lp tangent in lattice configuration
dLpdS = math_mul3333xx3333(dLpdFi,dFidS) + dLpdS
@ -894,9 +885,7 @@ subroutine crystallite_orientations
do e = FEsolving_execElem(1),FEsolving_execElem(2)
do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e)
do c = 1_pInt,homogenization_Ngrains(mesh_element(3,e))
crystallite_orientation(1:4,c,i,e) = math_RtoQ(transpose(math_rotationalPart33(crystallite_Fe(1:3,1:3,c,i,e))))
crystallite_rotation(1:4,c,i,e) = lattice_qDisorientation(crystallite_orientation0(1:4,c,i,e), &! active rotation from initial
crystallite_orientation(1:4,c,i,e)) ! to current orientation (with no symmetry)
call crystallite_orientation(c,i,e)%fromRotationMatrix(transpose(math_rotationalPart33(crystallite_Fe(1:3,1:3,c,i,e))))
enddo; enddo; enddo
!$OMP END PARALLEL DO
@ -969,6 +958,8 @@ function crystallite_postResults(ipc, ip, el)
use constitutive, only: &
constitutive_homogenizedC, &
constitutive_postResults
use rotations, only: &
rotation
implicit none
integer(pInt), intent(in):: &
@ -988,6 +979,7 @@ function crystallite_postResults(ipc, ip, el)
crystID, &
mySize, &
n
type(rotation) :: rot
crystID = microstructure_crystallite(mesh_element(4,el))
@ -1011,15 +1003,12 @@ function crystallite_postResults(ipc, ip, el)
/ real(homogenization_Ngrains(mesh_element(3,el)),pReal) ! grain volume (not fraction but absolute)
case (orientation_ID)
mySize = 4_pInt
crystallite_postResults(c+1:c+mySize) = crystallite_orientation(1:4,ipc,ip,el) ! grain orientation as quaternion
case (eulerangles_ID)
mySize = 3_pInt
crystallite_postResults(c+1:c+mySize) = inDeg &
* math_qToEuler(crystallite_orientation(1:4,ipc,ip,el)) ! grain orientation as Euler angles in degree
crystallite_postResults(c+1:c+mySize) = crystallite_orientation(ipc,ip,el)%asQuaternion()
case (grainrotation_ID)
rot = crystallite_orientation0(ipc,ip,el)%misorientation(crystallite_orientation(ipc,ip,el))
mySize = 4_pInt
crystallite_postResults(c+1:c+mySize) = &
math_qToEulerAxisAngle(crystallite_rotation(1:4,ipc,ip,el)) ! grain rotation away from initial orientation as axis-angle in sample reference coordinates
crystallite_postResults(c+1:c+mySize) = rot%asAxisAnglePair()
crystallite_postResults(c+4) = inDeg * crystallite_postResults(c+4) ! angle in degree
! remark: tensor output is of the form 11,12,13, 21,22,23, 31,32,33
@ -1078,8 +1067,8 @@ function crystallite_postResults(ipc, ip, el)
c = c + 1_pInt
if (size(crystallite_postResults)-c > 0_pInt) &
crystallite_postResults(c+1:size(crystallite_postResults)) = &
constitutive_postResults(crystallite_Tstar_v(1:6,ipc,ip,el), crystallite_Fi(1:3,1:3,ipc,ip,el), &
crystallite_Fe, ipc, ip, el)
constitutive_postResults(math_6toSym33(crystallite_Tstar_v(1:6,ipc,ip,el)), crystallite_Fi(1:3,1:3,ipc,ip,el), &
ipc, ip, el)
end function crystallite_postResults
@ -1289,7 +1278,7 @@ logical function integrateStress(&
!* calculate plastic velocity gradient and its tangent from constitutive law
call constitutive_LpAndItsTangents(Lp_constitutive, dLp_dS, dLp_dFi, &
math_sym33to6(S), Fi_new, ipc, ip, el)
S, Fi_new, ipc, ip, el)
#ifdef DEBUG
if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt &
@ -1390,7 +1379,7 @@ logical function integrateStress(&
!* calculate intermediate velocity gradient and its tangent from constitutive law
call constitutive_LiAndItsTangents(Li_constitutive, dLi_dS, dLi_dFi, &
math_sym33to6(S), Fi_new, ipc, ip, el)
S, Fi_new, ipc, ip, el)
#ifdef DEBUG
if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt &
@ -2206,8 +2195,7 @@ subroutine update_dependentState()
do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e)
do g = 1,homogenization_Ngrains(mesh_element(3,e))
if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) &
call constitutive_dependentState(crystallite_orientation, &
crystallite_Fe(1:3,1:3,g,i,e), &
call constitutive_dependentState(crystallite_Fe(1:3,1:3,g,i,e), &
crystallite_Fp(1:3,1:3,g,i,e), &
g, i, e)
enddo; enddo; enddo
@ -2271,6 +2259,8 @@ end subroutine update_state
subroutine update_dotState(timeFraction)
use, intrinsic :: &
IEEE_arithmetic
use math, only: &
math_6toSym33 !ToDo: Temporarly needed until T_star_v is called S and stored as matrix
use material, only: &
plasticState, &
sourceState, &
@ -2303,11 +2293,11 @@ subroutine update_dotState(timeFraction)
do g = 1,homogenization_Ngrains(mesh_element(3,e))
!$OMP FLUSH(nonlocalStop)
if ((crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) .and. .not. nonlocalStop) then
call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), &
call constitutive_collectDotState(math_6toSym33(crystallite_Tstar_v(1:6,g,i,e)), &
crystallite_Fe, &
crystallite_Fi(1:3,1:3,g,i,e), &
crystallite_Fp, &
crystallite_subdt(g,i,e)*timeFraction, crystallite_subFrac, g,i,e)
crystallite_subdt(g,i,e)*timeFraction, g,i,e)
p = phaseAt(g,i,e); c = phasememberAt(g,i,e)
NaN = any(IEEE_is_NaN(plasticState(p)%dotState(:,c)))
do s = 1_pInt, phase_Nsources(p)

View File

@ -1,169 +0,0 @@
!--------------------------------------------------------------------------------------------------
!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH
!> @brief material subroutine incorporating kinematics resulting from thermal expansion
!> @details to be done
!--------------------------------------------------------------------------------------------------
module kinematics_thermal_expansion
use prec, only: &
pReal, &
pInt
implicit none
private
<<<<<<< HEAD
!type, private :: tParameters
! real(pReal), allocatable, dimension(:) :: &
!end type tParameters
=======
integer(pInt), dimension(:), allocatable, public, protected :: &
kinematics_thermal_expansion_sizePostResults, & !< cumulative size of post results
kinematics_thermal_expansion_offset, & !< which kinematics is my current damage mechanism?
kinematics_thermal_expansion_instance !< instance of damage kinematics mechanism
integer(pInt), dimension(:,:), allocatable, target, public :: &
kinematics_thermal_expansion_sizePostResult !< size of each post result output
character(len=64), dimension(:,:), allocatable, target, public :: &
kinematics_thermal_expansion_output !< name of each post result output
integer(pInt), dimension(:), allocatable, target, public :: &
kinematics_thermal_expansion_Noutput !< number of outputs per instance of this damage
enum, bind(c) ! ToDo kinematics need state machinery to deal with sizePostResult
enumerator :: undefined_ID, & ! possible remedy is to decouple having state vars from having output
thermalexpansionrate_ID ! which means to separate user-defined types tState + tOutput...
end enum
>>>>>>> development
public :: &
kinematics_thermal_expansion_init, &
kinematics_thermal_expansion_initialStrain, &
kinematics_thermal_expansion_LiAndItsTangent
contains
!--------------------------------------------------------------------------------------------------
!> @brief module initialization
!> @details reads in material parameters, allocates arrays, and does sanity checks
!--------------------------------------------------------------------------------------------------
subroutine kinematics_thermal_expansion_init()
#if defined(__GFORTRAN__) || __INTEL_COMPILER >= 1800
use, intrinsic :: iso_fortran_env, only: &
compiler_version, &
compiler_options
#endif
use debug, only: &
debug_level,&
debug_constitutive,&
debug_levelBasic
use IO, only: &
IO_timeStamp
use material, only: &
phase_kinematics, &
KINEMATICS_thermal_expansion_label, &
KINEMATICS_thermal_expansion_ID
use config, only: &
config_phase
implicit none
integer(pInt) :: &
Ninstance, &
p
write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_thermal_expansion_LABEL//' init -+>>>'
write(6,'(a15,a)') ' Current time: ',IO_timeStamp()
#include "compilation_info.f90"
Ninstance = int(count(phase_kinematics == KINEMATICS_thermal_expansion_ID),pInt)
if (Ninstance == 0_pInt) return
if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) &
write(6,'(a16,1x,i5,/)') '# instances:',Ninstance
do p = 1_pInt, size(phase_kinematics)
if (all(phase_kinematics(:,p) /= KINEMATICS_thermal_expansion_ID)) cycle
enddo
end subroutine kinematics_thermal_expansion_init
!--------------------------------------------------------------------------------------------------
!> @brief report initial thermal strain based on current temperature deviation from reference
!--------------------------------------------------------------------------------------------------
pure function kinematics_thermal_expansion_initialStrain(homog,phase,offset)
use material, only: &
temperature
use lattice, only: &
lattice_thermalExpansion33, &
lattice_referenceTemperature
implicit none
integer(pInt), intent(in) :: &
phase, &
homog, offset
real(pReal), dimension(3,3) :: &
kinematics_thermal_expansion_initialStrain !< initial thermal strain (should be small strain, though)
kinematics_thermal_expansion_initialStrain = &
(temperature(homog)%p(offset) - lattice_referenceTemperature(phase))**1 / 1. * &
lattice_thermalExpansion33(1:3,1:3,1,phase) + & ! constant coefficient
(temperature(homog)%p(offset) - lattice_referenceTemperature(phase))**2 / 2. * &
lattice_thermalExpansion33(1:3,1:3,2,phase) + & ! linear coefficient
(temperature(homog)%p(offset) - lattice_referenceTemperature(phase))**3 / 3. * &
lattice_thermalExpansion33(1:3,1:3,3,phase) ! quadratic coefficient
end function kinematics_thermal_expansion_initialStrain
!--------------------------------------------------------------------------------------------------
!> @brief contains the constitutive equation for calculating the velocity gradient
!--------------------------------------------------------------------------------------------------
subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar, ipc, ip, el)
use material, only: &
material_phase, &
material_homog, &
temperature, &
temperatureRate, &
thermalMapping
use lattice, only: &
lattice_thermalExpansion33, &
lattice_referenceTemperature
implicit none
integer(pInt), intent(in) :: &
ipc, & !< grain number
ip, & !< integration point number
el !< element number
real(pReal), intent(out), dimension(3,3) :: &
Li !< thermal velocity gradient
real(pReal), intent(out), dimension(3,3,3,3) :: &
dLi_dTstar !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero)
integer(pInt) :: &
phase, &
homog, offset
real(pReal) :: &
T, TRef, TDot
phase = material_phase(ipc,ip,el)
homog = material_homog(ip,el)
offset = thermalMapping(homog)%p(ip,el)
T = temperature(homog)%p(offset)
TDot = temperatureRate(homog)%p(offset)
TRef = lattice_referenceTemperature(phase)
Li = TDot * ( &
lattice_thermalExpansion33(1:3,1:3,1,phase)*(T - TRef)**0 & ! constant coefficient
+ lattice_thermalExpansion33(1:3,1:3,2,phase)*(T - TRef)**1 & ! linear coefficient
+ lattice_thermalExpansion33(1:3,1:3,3,phase)*(T - TRef)**2 & ! quadratic coefficient
) / &
(1.0_pReal &
+ lattice_thermalExpansion33(1:3,1:3,1,phase)*(T - TRef)**1 / 1. &
+ lattice_thermalExpansion33(1:3,1:3,2,phase)*(T - TRef)**2 / 2. &
+ lattice_thermalExpansion33(1:3,1:3,3,phase)*(T - TRef)**3 / 3. &
)
dLi_dTstar = 0.0_pReal
end subroutine kinematics_thermal_expansion_LiAndItsTangent
end module kinematics_thermal_expansion

File diff suppressed because it is too large Load Diff

View File

@ -70,6 +70,10 @@ module math
!--------------------------------------------------------------------------------------------------
! Provide deprecated names for compatibility
interface math_cross
module procedure math_crossproduct
end interface math_cross
! ToDo MD: Our naming scheme was a little bit odd: We use essentially the re-ordering according to Nye
! (convenient because Abaqus and Marc want to have 12 on position 4)
! but weight the shear components according to Mandel (convenient for matrix multiplications)
@ -98,23 +102,13 @@ module math
module procedure math_99to3333
end interface math_Plain99to3333
interface math_Mandel3333to66
module procedure math_sym3333to66
end interface math_Mandel3333to66
interface math_Mandel66to3333
module procedure math_66toSym3333
end interface math_Mandel66to3333
public :: &
math_Plain33to9, &
math_Plain9to33, &
math_Mandel33to6, &
math_Mandel6to33, &
math_Plain3333to99, &
math_Plain99to3333, &
math_Mandel3333to66, &
math_Mandel66to3333
math_Plain99to3333
!---------------------------------------------------------------------------------------------------
public :: &
@ -129,6 +123,7 @@ module math
math_identity4th, &
math_civita, &
math_delta, &
math_cross, &
math_crossproduct, &
math_tensorproduct33, &
math_mul3x3, &
@ -1887,7 +1882,6 @@ function math_sampleGaussOri(center,FWHM)
math_sampleGaussOri = math_RtoEuler(math_mul33x33(R,math_EulerToR(center)))
endif
end function math_sampleGaussOri
@ -1960,11 +1954,11 @@ real(pReal) function math_sampleGaussVar(meanvalue, stddev, width)
tol_math_check
implicit none
real(pReal), intent(in) :: meanvalue, & ! meanvalue of gauss distribution
stddev ! standard deviation of gauss distribution
real(pReal), intent(in), optional :: width ! width of considered values as multiples of standard deviation
real(pReal), dimension(2) :: rnd ! random numbers
real(pReal) :: scatter, & ! normalized scatter around meanvalue
real(pReal), intent(in) :: meanvalue, & ! meanvalue of gauss distribution
stddev ! standard deviation of gauss distribution
real(pReal), intent(in), optional :: width ! width of considered values as multiples of standard deviation
real(pReal), dimension(2) :: rnd ! random numbers
real(pReal) :: scatter, & ! normalized scatter around meanvalue
myWidth
if (abs(stddev) < tol_math_check) then

File diff suppressed because it is too large Load Diff

View File

@ -29,8 +29,8 @@ module prec
real(pReal), parameter, public :: tol_math_check = 1.0e-8_pReal !< tolerance for internal math self-checks (rotation)
integer(pInt), allocatable, dimension(:) :: realloc_lhs_test
type, public :: group_float !< variable length datatype used for storage of state
type, public :: group_float !< variable length datatype used for storage of state
real(pReal), dimension(:), pointer :: p
end type group_float

443
src/quaternions.f90 Normal file
View File

@ -0,0 +1,443 @@
! ###################################################################
! Copyright (c) 2013-2015, Marc De Graef/Carnegie Mellon University
! Modified 2017-2019, Martin Diehl/Max-Planck-Institut für Eisenforschung GmbH
! All rights reserved.
!
! Redistribution and use in source and binary forms, with or without modification, are
! permitted provided that the following conditions are met:
!
! - Redistributions of source code must retain the above copyright notice, this list
! of conditions and the following disclaimer.
! - Redistributions in binary form must reproduce the above copyright notice, this
! list of conditions and the following disclaimer in the documentation and/or
! other materials provided with the distribution.
! - Neither the names of Marc De Graef, Carnegie Mellon University nor the names
! of its contributors may be used to endorse or promote products derived from
! this software without specific prior written permission.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
! USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! ###################################################################
!---------------------------------------------------------------------------------------------------
!> @author Marc De Graef, Carnegie Mellon University
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
!> @brief general quaternion math, not limited to unit quaternions
!> @details w is the real part, (x, y, z) are the imaginary parts.
!---------------------------------------------------------------------------------------------------
module quaternions
use prec, only: &
pReal
implicit none
public
real(pReal), parameter, public :: P = -1.0_pReal !< parameter for orientation conversion.
type, public :: quaternion
real(pReal) :: w = 0.0_pReal
real(pReal) :: x = 0.0_pReal
real(pReal) :: y = 0.0_pReal
real(pReal) :: z = 0.0_pReal
contains
procedure, private :: add__
procedure, private :: pos__
generic, public :: operator(+) => add__,pos__
procedure, private :: sub__
procedure, private :: neg__
generic, public :: operator(-) => sub__,neg__
procedure, private :: mul_quat__
procedure, private :: mul_scal__
generic, public :: operator(*) => mul_quat__, mul_scal__
procedure, private :: div_quat__
procedure, private :: div_scal__
generic, public :: operator(/) => div_quat__, div_scal__
procedure, private :: eq__
generic, public :: operator(==) => eq__
procedure, private :: neq__
generic, public :: operator(/=) => neq__
procedure, private :: pow_quat__
procedure, private :: pow_scal__
generic, public :: operator(**) => pow_quat__, pow_scal__
procedure, private :: abs__
procedure, private :: dot_product__
procedure, private :: conjg__
procedure, private :: exp__
procedure, private :: log__
procedure, public :: homomorphed => quat_homomorphed
end type
interface assignment (=)
module procedure assign_quat__
module procedure assign_vec__
end interface assignment (=)
interface quaternion
module procedure init__
end interface quaternion
interface abs
procedure abs__
end interface abs
interface dot_product
procedure dot_product__
end interface dot_product
interface conjg
module procedure conjg__
end interface conjg
interface exp
module procedure exp__
end interface exp
interface log
module procedure log__
end interface log
contains
!---------------------------------------------------------------------------------------------------
!> constructor for a quaternion from a 4-vector
!---------------------------------------------------------------------------------------------------
type(quaternion) pure function init__(array)
implicit none
real(pReal), intent(in), dimension(4) :: array
init__%w=array(1)
init__%x=array(2)
init__%y=array(3)
init__%z=array(4)
end function init__
!---------------------------------------------------------------------------------------------------
!> assing a quaternion
!---------------------------------------------------------------------------------------------------
elemental subroutine assign_quat__(self,other)
implicit none
type(quaternion), intent(out) :: self
type(quaternion), intent(in) :: other
self%w = other%w
self%x = other%x
self%y = other%y
self%z = other%z
end subroutine assign_quat__
!---------------------------------------------------------------------------------------------------
!> assing a 4-vector
!---------------------------------------------------------------------------------------------------
pure subroutine assign_vec__(self,other)
implicit none
type(quaternion), intent(out) :: self
real(pReal), intent(in), dimension(4) :: other
self%w = other(1)
self%x = other(2)
self%y = other(3)
self%z = other(4)
end subroutine assign_vec__
!---------------------------------------------------------------------------------------------------
!> addition of two quaternions
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function add__(self,other)
implicit none
class(quaternion), intent(in) :: self,other
add__%w = self%w + other%w
add__%x = self%x + other%x
add__%y = self%y + other%y
add__%z = self%z + other%z
end function add__
!---------------------------------------------------------------------------------------------------
!> unary positive operator
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function pos__(self)
implicit none
class(quaternion), intent(in) :: self
pos__%w = self%w
pos__%x = self%x
pos__%y = self%y
pos__%z = self%z
end function pos__
!---------------------------------------------------------------------------------------------------
!> subtraction of two quaternions
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function sub__(self,other)
implicit none
class(quaternion), intent(in) :: self,other
sub__%w = self%w - other%w
sub__%x = self%x - other%x
sub__%y = self%y - other%y
sub__%z = self%z - other%z
end function sub__
!---------------------------------------------------------------------------------------------------
!> unary positive operator
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function neg__(self)
implicit none
class(quaternion), intent(in) :: self
neg__%w = -self%w
neg__%x = -self%x
neg__%y = -self%y
neg__%z = -self%z
end function neg__
!---------------------------------------------------------------------------------------------------
!> multiplication of two quaternions
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function mul_quat__(self,other)
implicit none
class(quaternion), intent(in) :: self, other
mul_quat__%w = self%w*other%w - self%x*other%x - self%y*other%y - self%z*other%z
mul_quat__%x = self%w*other%x + self%x*other%w + P * (self%y*other%z - self%z*other%y)
mul_quat__%y = self%w*other%y + self%y*other%w + P * (self%z*other%x - self%x*other%z)
mul_quat__%z = self%w*other%z + self%z*other%w + P * (self%x*other%y - self%y*other%x)
end function mul_quat__
!---------------------------------------------------------------------------------------------------
!> multiplication of quaternions with scalar
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function mul_scal__(self,scal)
implicit none
class(quaternion), intent(in) :: self
real(pReal), intent(in) :: scal
mul_scal__%w = self%w*scal
mul_scal__%x = self%x*scal
mul_scal__%y = self%y*scal
mul_scal__%z = self%z*scal
end function mul_scal__
!---------------------------------------------------------------------------------------------------
!> division of two quaternions
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function div_quat__(self,other)
implicit none
class(quaternion), intent(in) :: self, other
div_quat__ = self * (conjg(other)/(abs(other)**2.0_pReal))
end function div_quat__
!---------------------------------------------------------------------------------------------------
!> divisiont of quaternions by scalar
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function div_scal__(self,scal)
implicit none
class(quaternion), intent(in) :: self
real(pReal), intent(in) :: scal
div_scal__ = [self%w,self%x,self%y,self%z]/scal
end function div_scal__
!---------------------------------------------------------------------------------------------------
!> equality of two quaternions
!---------------------------------------------------------------------------------------------------
logical elemental function eq__(self,other)
use prec, only: &
dEq
implicit none
class(quaternion), intent(in) :: self,other
eq__ = all(dEq([ self%w, self%x, self%y, self%z], &
[other%w,other%x,other%y,other%z]))
end function eq__
!---------------------------------------------------------------------------------------------------
!> inequality of two quaternions
!---------------------------------------------------------------------------------------------------
logical elemental function neq__(self,other)
implicit none
class(quaternion), intent(in) :: self,other
neq__ = .not. self%eq__(other)
end function neq__
!---------------------------------------------------------------------------------------------------
!> quaternion to the power of a scalar
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function pow_scal__(self,expon)
implicit none
class(quaternion), intent(in) :: self
real(pReal), intent(in) :: expon
pow_scal__ = exp(log(self)*expon)
end function pow_scal__
!---------------------------------------------------------------------------------------------------
!> quaternion to the power of a quaternion
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function pow_quat__(self,expon)
implicit none
class(quaternion), intent(in) :: self
type(quaternion), intent(in) :: expon
pow_quat__ = exp(log(self)*expon)
end function pow_quat__
!---------------------------------------------------------------------------------------------------
!> exponential of a quaternion
!> ToDo: Lacks any check for invalid operations
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function exp__(self)
implicit none
class(quaternion), intent(in) :: self
real(pReal) :: absImag
absImag = norm2([self%x, self%y, self%z])
exp__ = exp(self%w) * [ cos(absImag), &
self%x/absImag * sin(absImag), &
self%y/absImag * sin(absImag), &
self%z/absImag * sin(absImag)]
end function exp__
!---------------------------------------------------------------------------------------------------
!> logarithm of a quaternion
!> ToDo: Lacks any check for invalid operations
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function log__(self)
implicit none
class(quaternion), intent(in) :: self
real(pReal) :: absImag
absImag = norm2([self%x, self%y, self%z])
log__ = [log(abs(self)), &
self%x/absImag * acos(self%w/abs(self)), &
self%y/absImag * acos(self%w/abs(self)), &
self%z/absImag * acos(self%w/abs(self))]
end function log__
!---------------------------------------------------------------------------------------------------
!> norm of a quaternion
!---------------------------------------------------------------------------------------------------
real(pReal) elemental function abs__(a)
implicit none
class(quaternion), intent(in) :: a
abs__ = norm2([a%w,a%x,a%y,a%z])
end function abs__
!---------------------------------------------------------------------------------------------------
!> dot product of two quaternions
!---------------------------------------------------------------------------------------------------
real(pReal) elemental function dot_product__(a,b)
implicit none
class(quaternion), intent(in) :: a,b
dot_product__ = a%w*b%w + a%x*b%x + a%y*b%y + a%z*b%z
end function dot_product__
!---------------------------------------------------------------------------------------------------
!> conjugate complex of a quaternion
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function conjg__(a)
implicit none
class(quaternion), intent(in) :: a
conjg__ = quaternion([a%w, -a%x, -a%y, -a%z])
end function conjg__
!---------------------------------------------------------------------------------------------------
!> homomorphed quaternion of a quaternion
!---------------------------------------------------------------------------------------------------
type(quaternion) elemental function quat_homomorphed(a)
implicit none
class(quaternion), intent(in) :: a
quat_homomorphed = quaternion(-[a%w,a%x,a%y,a%z])
end function quat_homomorphed
end module quaternions

1198
src/rotations.f90 Normal file

File diff suppressed because it is too large Load Diff