Merge remote-tracking branch 'origin/development' into vector-mechanics

This commit is contained in:
Martin Diehl 2020-11-18 13:46:48 +01:00
commit 89c748fdf1
60 changed files with 615 additions and 587 deletions

View File

@ -187,8 +187,6 @@ grid_mech_compile_Intel:
stage: compilePETSc stage: compilePETSc
script: script:
- module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel
- cp -r grid_mech_compile grid_mech_compile_Intel
- grid_mech_compile_Intel/test.py
- cd pytest - cd pytest
- pytest -k 'compile and grid' --basetemp=${TESTROOT}/compile_grid_Intel - pytest -k 'compile and grid' --basetemp=${TESTROOT}/compile_grid_Intel
except: except:
@ -199,8 +197,6 @@ Compile_FEM_Intel:
stage: compilePETSc stage: compilePETSc
script: script:
- module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel
- cp -r FEM_compile FEM_compile_Intel
- FEM_compile_Intel/test.py
- cd pytest - cd pytest
- pytest -k 'compile and mesh' --basetemp=${TESTROOT}/compile_mesh_Intel - pytest -k 'compile and mesh' --basetemp=${TESTROOT}/compile_mesh_Intel
except: except:
@ -211,8 +207,6 @@ grid_mech_compile_GNU:
stage: compilePETSc stage: compilePETSc
script: script:
- module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU - module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU
- cp -r grid_mech_compile grid_mech_compile_GNU
- grid_mech_compile_GNU/test.py
- cd pytest - cd pytest
- pytest -k 'compile and grid' --basetemp=${TESTROOT}/compile_grid_GNU - pytest -k 'compile and grid' --basetemp=${TESTROOT}/compile_grid_GNU
except: except:
@ -223,8 +217,6 @@ Compile_FEM_GNU:
stage: compilePETSc stage: compilePETSc
script: script:
- module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU - module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU
- cp -r FEM_compile FEM_compile_GNU
- FEM_compile_GNU/test.py
- cd pytest - cd pytest
- pytest -k 'compile and mesh' --basetemp=${TESTROOT}/compile_mesh_GNU - pytest -k 'compile and mesh' --basetemp=${TESTROOT}/compile_mesh_GNU
except: except:
@ -274,22 +266,6 @@ Nonlocal_Damage_DetectChanges:
- master - master
- release - release
grid_all_restart:
stage: grid
script: grid_all_restart/test.py
except:
- master
- release
grid_all_restartMPI:
stage: grid
script:
- module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel
- grid_all_restartMPI/test.py
except:
- master
- release
Plasticity_DetectChanges: Plasticity_DetectChanges:
stage: grid stage: grid
script: Plasticity_DetectChanges/test.py script: Plasticity_DetectChanges/test.py

@ -1 +1 @@
Subproject commit 281e7eb84f76a2974a50eb54faf35ea25ec89b20 Subproject commit 2d00aa541f071dbfc200f32e358d324995a061f5

View File

@ -1 +1 @@
v3.0.0-alpha-726-g1f59f6301 v3.0.0-alpha-777-g523a0979e

View File

@ -2,7 +2,7 @@
homogenization: homogenization:
SX: SX:
N_constituents: 1 N_constituents: 1
mech: {type: none} mechanics: {type: none}
material: material:
- homogenization: SX - homogenization: SX
@ -109,7 +109,7 @@ material:
phase: phase:
Aluminum: Aluminum:
lattice: fcc lattice: fcc
mech: mechanics:
output: [F, P, F_e, F_p, L_p, O] output: [F, P, F_e, F_p, L_p, O]
elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke} elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke}
plasticity: plasticity:

View File

@ -1,5 +1,5 @@
step: step:
- mech: - mechanics:
dot_F: [0, 0, 0, dot_F: [0, 0, 0,
1e-3, 0, 0, 1e-3, 0, 0,
0, 0, 0] 0, 0, 0]

View File

@ -1,6 +1,6 @@
--- ---
step: step:
- mech: - mechanics:
dot_F: [0, 0, 1e-3, dot_F: [0, 0, 1e-3,
0, 0, 0, 0, 0, 0,
0, 0, 0] 0, 0, 0]

View File

@ -1,7 +1,7 @@
--- ---
step: step:
- mech: - mechanics:
dot_F: [1.0e-3, 0, 0, dot_F: [1.0e-3, 0, 0,
0, x, 0, 0, x, 0,
0, 0, x] 0, 0, x]
@ -12,7 +12,7 @@ step:
t: 10 t: 10
N: 40 N: 40
f_out: 4 f_out: 4
- mech: - mechanics:
dot_F: [1.0e-3, 0, 0, dot_F: [1.0e-3, 0, 0,
0, x, 0, 0, x, 0,
0, 0, x] 0, 0, x]

View File

@ -136,7 +136,7 @@ def shapeMismatch(size,F,nodes,centres):
# MAIN # MAIN
# -------------------------------------------------------------------- # --------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ parser = OptionParser(usage='%prog options [ASCIItable(s)]', description = """
Add column(s) containing the shape and volume mismatch resulting from given deformation gradient. Add column(s) containing the shape and volume mismatch resulting from given deformation gradient.
Operates on periodic three-dimensional x,y,z-ordered data sets. Operates on periodic three-dimensional x,y,z-ordered data sets.

View File

@ -16,7 +16,7 @@ scriptID = ' '.join([scriptName,damask.version])
# MAIN # MAIN
# -------------------------------------------------------------------- # --------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ parser = OptionParser(usage='%prog options [ASCIItable(s)]', description = """
Add displacments resulting from deformation gradient field. Add displacments resulting from deformation gradient field.
Operates on periodic three-dimensional x,y,z-ordered data sets. Operates on periodic three-dimensional x,y,z-ordered data sets.
Outputs at cell centers or cell nodes (into separate file). Outputs at cell centers or cell nodes (into separate file).

View File

@ -98,7 +98,7 @@ slipSystems = {
# MAIN # MAIN
# -------------------------------------------------------------------- # --------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [ASCIItable(s)]', description = """ parser = OptionParser(usage='%prog options [ASCIItable(s)]', description = """
Add columns listing Schmid factors (and optional trace vector of selected system) for given Euler angles. Add columns listing Schmid factors (and optional trace vector of selected system) for given Euler angles.
""", version = scriptID) """, version = scriptID)

View File

@ -14,7 +14,7 @@ scriptID = ' '.join([scriptName,damask.version])
# MAIN # MAIN
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [DREAM.3Dfile(s)]', description = """ parser = OptionParser(usage='%prog options [DREAM.3Dfile(s)]', description = """
Converts DREAM.3D file. Input can be cell data (direct pointwise takeover) or grain data (individual Converts DREAM.3D file. Input can be cell data (direct pointwise takeover) or grain data (individual
grains are segmented). Requires orientation data as quaternion. grains are segmented). Requires orientation data as quaternion.

View File

@ -1,69 +0,0 @@
#!/usr/bin/env python3
import os
import sys
from optparse import OptionParser
import damask
scriptName = os.path.splitext(os.path.basename(__file__))[0]
scriptID = ' '.join([scriptName,damask.version])
minimal_surfaces = list(damask.Geom._minimal_surface.keys())
# --------------------------------------------------------------------
# MAIN
# --------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [geomfile]', description = """
Generate a bicontinuous structure of given type.
""", version = scriptID)
parser.add_option('-t','--type',
dest = 'type',
choices = minimal_surfaces, metavar = 'string',
help = 'type of minimal surface [primitive] {%s}' %(','.join(minimal_surfaces)))
parser.add_option('-f','--threshold',
dest = 'threshold',
type = 'float', metavar = 'float',
help = 'threshold value defining minimal surface [%default]')
parser.add_option('-g', '--grid',
dest = 'grid',
type = 'int', nargs = 3, metavar = 'int int int',
help = 'a,b,c grid of hexahedral box [%default]')
parser.add_option('-s', '--size',
dest = 'size',
type = 'float', nargs = 3, metavar = 'float float float',
help = 'x,y,z size of hexahedral box [%default]')
parser.add_option('-p', '--periods',
dest = 'periods',
type = 'int', metavar = 'int',
help = 'number of repetitions of unit cell [%default]')
parser.add_option('--m',
dest = 'microstructure',
type = 'int', nargs = 2, metavar = 'int int',
help = 'two microstructure indices to be used [%default]')
parser.set_defaults(type = minimal_surfaces[0],
threshold = 0.0,
periods = 1,
grid = (16,16,16),
size = (1.0,1.0,1.0),
microstructure = (1,2),
)
(options,filename) = parser.parse_args()
name = None if filename == [] else filename[0]
damask.util.report(scriptName,name)
geom=damask.Geom.from_minimal_surface(options.grid,options.size,options.type,options.threshold,
options.periods,options.microstructure)
damask.util.croak(geom)
geom.save_ASCII(sys.stdout if name is None else name)

View File

@ -17,7 +17,7 @@ scriptID = ' '.join([scriptName,damask.version])
# MAIN # MAIN
# -------------------------------------------------------------------- # --------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [geomfile]', description = """ parser = OptionParser(usage='%prog options [geomfile]', description = """
Generate description of an osteon enclosing the Harvesian canal and separated by interstitial tissue. Generate description of an osteon enclosing the Harvesian canal and separated by interstitial tissue.
The osteon phase is lamellar with a twisted plywood structure. The osteon phase is lamellar with a twisted plywood structure.
Its fiber orientation is oscillating by +/- amplitude within one period. Its fiber orientation is oscillating by +/- amplitude within one period.

View File

@ -30,11 +30,11 @@ def parseMFD(dat):
# lines that start with a space are numerical data # lines that start with a space are numerical data
if line[0] == ' ': if line[0] == ' ':
formatted[section]['els'].append([]) formatted[section]['els'].append([])
# grab numbers # grab numbers
nums = re.split(r'\s+', line.strip()) nums = re.split(r'\s+', line.strip())
for num in nums: for num in nums:
# floating point has format ' -x.xxxxxxxxxxxxe+yy' # floating point has format ' -x.xxxxxxxxxxxxe+yy'
# scientific notation is used for float # scientific notation is used for float
if (len(num) >= 4) and (num[-4] == 'e'): if (len(num) >= 4) and (num[-4] == 'e'):
@ -47,7 +47,7 @@ def parseMFD(dat):
else: else:
formatted[section]['els'].append([]) formatted[section]['els'].append([])
formatted[section]['els'][-1] = line formatted[section]['els'][-1] = line
else: # Not in a section, we are looking for a =beg= now else: # Not in a section, we are looking for a =beg= now
search = re.search(r'=beg=\s+(\d+)\s\((.*?)\)', line) search = re.search(r'=beg=\s+(\d+)\s\((.*?)\)', line)
if search is not None: # found start of a new section if search is not None: # found start of a new section
@ -60,7 +60,7 @@ def parseMFD(dat):
section += 1 section += 1
formatted.append({'label': '', 'uid': -2, 'els': []}) # make dummy section to store unrecognized data formatted.append({'label': '', 'uid': -2, 'els': []}) # make dummy section to store unrecognized data
formatted[section]['els'].append(line) formatted[section]['els'].append(line)
return formatted return formatted
def asMFD(mfd_data): def asMFD(mfd_data):
@ -93,14 +93,14 @@ def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to
'max': np.zeros(3,dtype='d'), 'max': np.zeros(3,dtype='d'),
'delta': np.zeros(3,dtype='d'), 'delta': np.zeros(3,dtype='d'),
} }
mfd_dict = {} mfd_dict = {}
for i in range(len(mfd_data)): for i in range(len(mfd_data)):
mfd_dict[mfd_data[i]['label']] = i mfd_dict[mfd_data[i]['label']] = i
NodeCoords = np.array(mfd_data[mfd_dict['nodes']]['els'][1::4])[:,1:4] NodeCoords = np.array(mfd_data[mfd_dict['nodes']]['els'][1::4])[:,1:4]
Nnodes = NodeCoords.shape[0] Nnodes = NodeCoords.shape[0]
box['min'] = NodeCoords.min(axis=0) # find the bounding box box['min'] = NodeCoords.min(axis=0) # find the bounding box
box['max'] = NodeCoords.max(axis=0) box['max'] = NodeCoords.max(axis=0)
box['delta'] = box['max']-box['min'] box['delta'] = box['max']-box['min']
@ -131,7 +131,7 @@ def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to
elif (key[base[coord]] == "%.8e"%box['max'][coord]): # compare to max of bounding box (i.e. is on outer face?) elif (key[base[coord]] == "%.8e"%box['max'][coord]): # compare to max of bounding box (i.e. is on outer face?)
Nmax += 1 # count outer (front) face membership Nmax += 1 # count outer (front) face membership
maxFlag[coord] = True # remember face membership (for linked nodes) maxFlag[coord] = True # remember face membership (for linked nodes)
if Nmin > 0: # node is on a back face if Nmin > 0: # node is on a back face
# prepare for any non-existing entries in the data structure # prepare for any non-existing entries in the data structure
if key['x'] not in baseNode.keys(): if key['x'] not in baseNode.keys():
@ -140,17 +140,17 @@ def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to
baseNode[key['x']][key['y']] = {} baseNode[key['x']][key['y']] = {}
if key['z'] not in baseNode[key['x']][key['y']].keys(): if key['z'] not in baseNode[key['x']][key['y']].keys():
baseNode[key['x']][key['y']][key['z']] = 0 baseNode[key['x']][key['y']][key['z']] = 0
baseNode[key['x']][key['y']][key['z']] = node+1 # remember the base node id baseNode[key['x']][key['y']][key['z']] = node+1 # remember the base node id
if Nmax > 0 and Nmax >= Nmin: # node is on at least as many front than back faces if Nmax > 0 and Nmax >= Nmin: # node is on at least as many front than back faces
if any([maxFlag[i] and active[i] for i in range(3)]): if any([maxFlag[i] and active[i] for i in range(3)]):
linkNodes.append({'id': node+1,'coord': NodeCoords[node], 'faceMember': [maxFlag[i] and active[i] for i in range(3)]}) linkNodes.append({'id': node+1,'coord': NodeCoords[node], 'faceMember': [maxFlag[i] and active[i] for i in range(3)]})
mfd_data[mfd_dict['entities']]['els'][0][0] += len(linkNodes) * 3 mfd_data[mfd_dict['entities']]['els'][0][0] += len(linkNodes) * 3
baseCorner = baseNode["%.8e"%box['min'][0]]["%.8e"%box['min'][1]]["%.8e"%box['min'][2]] # detect ultimate base node baseCorner = baseNode["%.8e"%box['min'][0]]["%.8e"%box['min'][1]]["%.8e"%box['min'][2]] # detect ultimate base node
links = {'uid': 1705, 'label': 'links', 'els': [[7,0],[9,0]]} links = {'uid': 1705, 'label': 'links', 'els': [[7,0],[9,0]]}
linkID = 0 linkID = 0
for node in linkNodes: # loop over all linked nodes for node in linkNodes: # loop over all linked nodes
@ -165,7 +165,7 @@ def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to
for dof in [1,2,3]: for dof in [1,2,3]:
tied_node = node['id'] tied_node = node['id']
nterms = 1 + nLinks nterms = 1 + nLinks
linkID += 1 linkID += 1
# Link header # Link header
links['els'].append('link{0}\n'.format(linkID)) links['els'].append('link{0}\n'.format(linkID))
@ -173,10 +173,10 @@ def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to
links['els'].append([0]) links['els'].append([0])
links['els'].append([0]) links['els'].append([0])
links['els'].append([0, 0, 0, tied_node]) links['els'].append([0, 0, 0, tied_node])
# these need to be put in groups of four # these need to be put in groups of four
link_payload = [dof, 0, nterms] link_payload = [dof, 0, nterms]
# Individual node contributions (node, dof, coef.) # Individual node contributions (node, dof, coef.)
for i in range(nterms): for i in range(nterms):
if i == nLinks: if i == nLinks:
@ -190,7 +190,7 @@ def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to
link_payload.append(1.0 - nLinks) link_payload.append(1.0 - nLinks)
else: else:
link_payload.append(1.0) link_payload.append(1.0)
# Needs to be formatted 4 data points per row, character width of 20, so 80 total # Needs to be formatted 4 data points per row, character width of 20, so 80 total
for j in range(0, len(link_payload), 4): for j in range(0, len(link_payload), 4):
links['els'].append(link_payload[j:j+4]) links['els'].append(link_payload[j:j+4])
@ -206,9 +206,9 @@ def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
# MAIN # MAIN
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [file[s]]', description = """ parser = OptionParser(usage='%prog options [file[s]]', description = """
Set up servo linking to achieve periodic boundary conditions for a regular hexahedral mesh. Set up servo linking to achieve periodic boundary conditions for a regular hexahedral mesh.
Use *py_connection to operate on model presently opened in MSC.Mentat. Use *py_connection to operate on model presently opened in MSC.Mentat.
""", version = scriptID) """, version = scriptID)

View File

@ -168,7 +168,7 @@ def initial_conditions(material):
# MAIN # MAIN
#-------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [file[s]]', description = """ parser = OptionParser(usage='%prog options [file[s]]', description = """
Generate MSC.Marc FE hexahedral mesh from geom file. Generate MSC.Marc FE hexahedral mesh from geom file.
""", version = scriptID) """, version = scriptID)

View File

@ -164,7 +164,7 @@ class myThread (threading.Thread):
# MAIN # MAIN
# -------------------------------------------------------------------- # --------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [file[s]]', description = """ parser = OptionParser(usage='%prog options [file[s]]', description = """
Monte Carlo simulation to produce seed file that gives same size distribution like given geometry file. Monte Carlo simulation to produce seed file that gives same size distribution like given geometry file.
""", version = scriptID) """, version = scriptID)

View File

@ -16,7 +16,7 @@ scriptID = ' '.join([scriptName,damask.version])
# MAIN # MAIN
# -------------------------------------------------------------------- # --------------------------------------------------------------------
parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [file[s]]', description = """ parser = OptionParser(usage='%prog options [file[s]]', description = """
Create seeds file by poking at 45 degree through given geom file. Create seeds file by poking at 45 degree through given geom file.
Mimics APS Beamline 34-ID-E DAXM poking. Mimics APS Beamline 34-ID-E DAXM poking.

View File

@ -22,6 +22,19 @@ _ref_white = np.array([.95047, 1.00000, 1.08883])
# - support NaN color (paraview) # - support NaN color (paraview)
class Colormap(mpl.colors.ListedColormap): class Colormap(mpl.colors.ListedColormap):
"""
Enhance matplotlib colormap functionality to be used within DAMASK.
References
----------
[1] DAMASK colormap theory
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
[2] DAMASK colormaps first use
https://doi.org/10.1016/j.ijplas.2012.09.012
[3] Matplotlib colormaps overview
https://matplotlib.org/tutorials/colors/colormaps.html
"""
def __add__(self,other): def __add__(self,other):
"""Concatenate colormaps.""" """Concatenate colormaps."""
@ -36,6 +49,17 @@ class Colormap(mpl.colors.ListedColormap):
"""Return inverted colormap.""" """Return inverted colormap."""
return self.reversed() return self.reversed()
def __repr__(self):
"""Show colormap as matplotlib figure."""
fig = plt.figure(self.name,figsize=(5,.5))
ax1 = fig.add_axes([0, 0, 1, 1])
ax1.set_axis_off()
ax1.imshow(np.linspace(0,1,self.N).reshape(1,-1),
aspect='auto', cmap=self, interpolation='nearest')
plt.show(block = False)
return self.name
@staticmethod @staticmethod
def from_range(low,high,name='DAMASK colormap',N=256,model='rgb'): def from_range(low,high,name='DAMASK colormap',N=256,model='rgb'):
""" """
@ -126,40 +150,16 @@ class Colormap(mpl.colors.ListedColormap):
""" """
# matplotlib presets # matplotlib presets
for cat in Colormap._predefined_mpl: try:
for n in cat[1]: colormap = cm.__dict__[name]
if n == name: return Colormap(np.array(list(map(colormap,np.linspace(0,1,N)))
colormap = cm.__dict__[name] if isinstance(colormap,mpl.colors.LinearSegmentedColormap) else
if isinstance(colormap,mpl.colors.LinearSegmentedColormap): colormap.colors),
return Colormap(np.array(list(map(colormap,np.linspace(0,1,N)))),name=name) name=name)
else: except KeyError:
return Colormap(np.array(colormap.colors),name=name) # DAMASK presets
definition = Colormap._predefined_DAMASK[name]
# DAMASK presets return Colormap.from_range(definition['low'],definition['high'],name,N)
definition = Colormap._predefined_DAMASK[name]
return Colormap.from_range(definition['low'],definition['high'],name,N)
@staticmethod
def list_predefined():
"""
List predefined colormaps by category.
References
----------
[1] DAMASK colormap theory
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
[2] DAMASK colormaps first use
https://doi.org/10.1016/j.ijplas.2012.09.012
[3] Matplotlib colormaps overview
https://matplotlib.org/tutorials/colors/colormaps.html
"""
print('DAMASK colormaps')
print(' '+', '.join(Colormap._predefined_DAMASK.keys()))
for cat in Colormap._predefined_mpl:
print(f'{cat[0]}')
print(' '+', '.join(cat[1]))
def shade(self,field,bounds=None,gap=None): def shade(self,field,bounds=None,gap=None):
@ -168,9 +168,9 @@ class Colormap(mpl.colors.ListedColormap):
Parameters Parameters
---------- ----------
field : numpy.array of shape(:,:) field : numpy.array of shape (:,:)
Data to be shaded. Data to be shaded.
bounds : iterable of len(2), optional bounds : iterable of len (2), optional
Colormap value range (low,high). Colormap value range (low,high).
gap : field.dtype, optional gap : field.dtype, optional
Transparent value. NaN will always be rendered transparent. Transparent value. NaN will always be rendered transparent.
@ -203,18 +203,6 @@ class Colormap(mpl.colors.ListedColormap):
mode='RGBA') mode='RGBA')
def show(self,aspect=10,vertical=False):
"""Show colormap as matplotlib figure."""
fig = plt.figure(figsize=(5/aspect,5) if vertical else (5,5/aspect))
ax1 = fig.add_axes([0, 0, 1, 1])
ax1.set_axis_off()
ax1.imshow(np.linspace(1 if vertical else 0,
0 if vertical else 1,
self.N).reshape((-1,1) if vertical else (1,-1)),
aspect='auto', cmap=self, interpolation='nearest')
plt.show()
def reversed(self,name=None): def reversed(self,name=None):
""" """
Make a reversed instance of the colormap. Make a reversed instance of the colormap.
@ -235,7 +223,6 @@ class Colormap(mpl.colors.ListedColormap):
return Colormap(np.array(rev.colors),rev.name[:-4] if rev.name.endswith('_r_r') else rev.name) return Colormap(np.array(rev.colors),rev.name[:-4] if rev.name.endswith('_r_r') else rev.name)
def save_paraview(self,fname=None): def save_paraview(self,fname=None):
""" """
Write colormap to JSON file for Paraview. Write colormap to JSON file for Paraview.
@ -247,13 +234,13 @@ class Colormap(mpl.colors.ListedColormap):
consist of the name of the colormap and extension '.json'. consist of the name of the colormap and extension '.json'.
""" """
if fname is not None: if fname is None:
fhandle = None
else:
try: try:
fhandle = open(fname,'w') fhandle = open(fname,'w')
except TypeError: except TypeError:
fhandle = fname fhandle = fname
else:
fhandle = None
colors = [] colors = []
for i,c in enumerate(np.round(self.colors,6).tolist()): for i,c in enumerate(np.round(self.colors,6).tolist()):
@ -266,11 +253,9 @@ class Colormap(mpl.colors.ListedColormap):
'DefaultMap':True, 'DefaultMap':True,
'RGBPoints':colors 'RGBPoints':colors
}] }]
if fhandle is None:
with open(self.name.replace(' ','_')+'.json', 'w') as f: with open(self.name.replace(' ','_')+'.json', 'w') if fhandle is None else fhandle as f:
json.dump(out, f,indent=4) json.dump(out, f,indent=4)
else:
json.dump(out,fhandle,indent=4)
def save_ASCII(self,fname=None): def save_ASCII(self,fname=None):
@ -284,22 +269,19 @@ class Colormap(mpl.colors.ListedColormap):
consist of the name of the colormap and extension '.txt'. consist of the name of the colormap and extension '.txt'.
""" """
if fname is not None: if fname is None:
fhandle = None
else:
try: try:
fhandle = open(fname,'w') fhandle = open(fname,'w')
except TypeError: except TypeError:
fhandle = fname fhandle = fname
else:
fhandle = None
labels = {'RGBA':4} if self.colors.shape[1] == 4 else {'RGB': 3} labels = {'RGBA':4} if self.colors.shape[1] == 4 else {'RGB': 3}
t = Table(self.colors,labels,f'Creator: {util.execution_stamp("Colormap")}') t = Table(self.colors,labels,f'Creator: {util.execution_stamp("Colormap")}')
if fhandle is None: with open(self.name.replace(' ','_')+'.txt', 'w') if fhandle is None else fhandle as f:
with open(self.name.replace(' ','_')+'.txt', 'w') as f: t.save(f)
t.save(f)
else:
t.save(fhandle)
def save_GOM(self,fname=None): def save_GOM(self,fname=None):
@ -313,24 +295,21 @@ class Colormap(mpl.colors.ListedColormap):
consist of the name of the colormap and extension '.legend'. consist of the name of the colormap and extension '.legend'.
""" """
if fname is not None: if fname is None:
fhandle = None
else:
try: try:
fhandle = open(fname,'w') fhandle = open(fname,'w')
except TypeError: except TypeError:
fhandle = fname fhandle = fname
else:
fhandle = None
# ToDo: test in GOM # ToDo: test in GOM
GOM_str = '1 1 {name} 9 {name} '.format(name=self.name.replace(" ","_")) \ GOM_str = '1 1 {name} 9 {name} '.format(name=self.name.replace(" ","_")) \
+ '0 1 0 3 0 0 -1 9 \\ 0 0 0 255 255 255 0 0 255 ' \ + '0 1 0 3 0 0 -1 9 \\ 0 0 0 255 255 255 0 0 255 ' \
+ f'30 NO_UNIT 1 1 64 64 64 255 1 0 0 0 0 0 0 3 0 {len(self.colors)}' \ + f'30 NO_UNIT 1 1 64 64 64 255 1 0 0 0 0 0 0 3 0 {len(self.colors)}' \
+ ' '.join([f' 0 {c[0]} {c[1]} {c[2]} 255 1' for c in reversed((self.colors*255).astype(int))]) \ + ' '.join([f' 0 {c[0]} {c[1]} {c[2]} 255 1' for c in reversed((self.colors*255).astype(int))]) \
+ '\n' + '\n'
if fhandle is None: with open(self.name.replace(' ','_')+'.legend', 'w') if fhandle is None else fhandle as f:
with open(self.name.replace(' ','_')+'.legend', 'w') as f: f.write(GOM_str)
f.write(GOM_str)
else:
fhandle.write(GOM_str)
def save_gmsh(self,fname=None): def save_gmsh(self,fname=None):
@ -344,22 +323,19 @@ class Colormap(mpl.colors.ListedColormap):
consist of the name of the colormap and extension '.msh'. consist of the name of the colormap and extension '.msh'.
""" """
if fname is not None: if fname is None:
fhandle = None
else:
try: try:
fhandle = open(fname,'w') fhandle = open(fname,'w')
except TypeError: except TypeError:
fhandle = fname fhandle = fname
else:
fhandle = None
# ToDo: test in gmsh # ToDo: test in gmsh
gmsh_str = 'View.ColorTable = {\n' \ gmsh_str = 'View.ColorTable = {\n' \
+'\n'.join([f'{c[0]},{c[1]},{c[2]},' for c in self.colors[:,:3]*255]) \ +'\n'.join([f'{c[0]},{c[1]},{c[2]},' for c in self.colors[:,:3]*255]) \
+'\n}\n' +'\n}\n'
if fhandle is None: with open(self.name.replace(' ','_')+'.msh', 'w') if fhandle is None else fhandle as f:
with open(self.name.replace(' ','_')+'.msh', 'w') as f: f.write(gmsh_str)
f.write(gmsh_str)
else:
fhandle.write(gmsh_str)
@staticmethod @staticmethod
@ -387,7 +363,6 @@ class Colormap(mpl.colors.ListedColormap):
if msh_sat[2] < - np.pi/3.0: hSpin *= -1.0 if msh_sat[2] < - np.pi/3.0: hSpin *= -1.0
return msh_sat[2] + hSpin return msh_sat[2] + hSpin
lo = np.array(low) lo = np.array(low)
hi = np.array(high) hi = np.array(high)
@ -407,28 +382,28 @@ class Colormap(mpl.colors.ListedColormap):
return (1.0 - frac) * lo + frac * hi return (1.0 - frac) * lo + frac * hi
_predefined_mpl= [('Perceptually Uniform Sequential', [ _predefined_mpl= {'Perceptually Uniform Sequential': [
'viridis', 'plasma', 'inferno', 'magma', 'cividis']), 'viridis', 'plasma', 'inferno', 'magma', 'cividis'],
('Sequential', [ 'Sequential': [
'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn']), 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'],
('Sequential (2)', [ 'Sequential (2)': [
'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink', 'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',
'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia', 'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia',
'hot', 'afmhot', 'gist_heat', 'copper']), 'hot', 'afmhot', 'gist_heat', 'copper'],
('Diverging', [ 'Diverging': [
'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', 'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu',
'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic']), 'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'],
('Cyclic', ['twilight', 'twilight_shifted', 'hsv']), 'Cyclic': ['twilight', 'twilight_shifted', 'hsv'],
('Qualitative', [ 'Qualitative': [
'Pastel1', 'Pastel2', 'Paired', 'Accent', 'Pastel1', 'Pastel2', 'Paired', 'Accent',
'Dark2', 'Set1', 'Set2', 'Set3', 'Dark2', 'Set1', 'Set2', 'Set3',
'tab10', 'tab20', 'tab20b', 'tab20c']), 'tab10', 'tab20', 'tab20b', 'tab20c'],
('Miscellaneous', [ 'Miscellaneous': [
'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern', 'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern',
'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg', 'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg',
'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar'])] 'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar']}
_predefined_DAMASK = {'orientation': {'low': [0.933334,0.878432,0.878431], _predefined_DAMASK = {'orientation': {'low': [0.933334,0.878432,0.878431],
'high': [0.250980,0.007843,0.000000]}, 'high': [0.250980,0.007843,0.000000]},
@ -437,6 +412,9 @@ class Colormap(mpl.colors.ListedColormap):
'stress': {'low': [0.878432,0.874511,0.949019], 'stress': {'low': [0.878432,0.874511,0.949019],
'high': [0.000002,0.000000,0.286275]}} 'high': [0.000002,0.000000,0.286275]}}
predefined = dict(**{'DAMASK':list(_predefined_DAMASK)},**_predefined_mpl)
@staticmethod @staticmethod
def _hsv2rgb(hsv): def _hsv2rgb(hsv):
""" """

View File

@ -226,13 +226,13 @@ class ConfigMaterial(Config):
return dup return dup
def material_add(self,constituents,**kwargs): def material_add(self,constituents=None,**kwargs):
""" """
Add material entries. Add material entries.
Parameters Parameters
---------- ----------
constituents : dict constituents : dict, optional
Entries for 'constituents' as key-value pair. Entries for 'constituents' as key-value pair.
**kwargs **kwargs
Key-value pairs. Key-value pairs.
@ -263,13 +263,26 @@ class ConfigMaterial(Config):
homogenization: SX homogenization: SX
""" """
c = [{'constituents':u} for u in ConfigMaterial._constituents(**constituents)] length = -1
for v in kwargs.values():
if hasattr(v,'__len__') and not isinstance(v,str):
if length != -1 and len(v) != length:
raise ValueError('Cannot add entries of different length')
else:
length = len(v)
length = max(1,length)
c = [{} for _ in range(length)] if constituents is None else \
[{'constituents':u} for u in ConfigMaterial._constituents(**constituents)]
if len(c) == 1: c = [copy.deepcopy(c[0]) for _ in range(length)]
if length != 1 and length != len(c):
raise ValueError('Cannot add entries of different length')
for k,v in kwargs.items(): for k,v in kwargs.items():
if hasattr(v,'__len__') and not isinstance(v,str): if hasattr(v,'__len__') and not isinstance(v,str):
if len(v) != len(c):
raise ValueError('Cannot add entries of different length')
for i,vv in enumerate(v): for i,vv in enumerate(v):
c[i][k] = [w.item() for w in vv] if isinstance(vv,np.ndarray) else vv.item() c[i][k] = vv.item() if isinstance(vv,np.generic) else vv
else: else:
for i in range(len(c)): for i in range(len(c)):
c[i][k] = v c[i][k] = v
@ -293,7 +306,7 @@ class ConfigMaterial(Config):
if len(v) != N_material: if len(v) != N_material:
raise ValueError('Cannot add entries of different length') raise ValueError('Cannot add entries of different length')
for i,vv in enumerate(np.array(v)): for i,vv in enumerate(np.array(v)):
m[i][0][k] = [w.item() for w in vv] if isinstance(vv,np.ndarray) else vv.item() m[i][0][k] = vv.item() if isinstance(vv,np.generic) else vv
else: else:
for i in range(N_material): for i in range(N_material):
m[i][0][k] = v m[i][0][k] = v

View File

@ -3,14 +3,8 @@ from pathlib import Path
class Environment: class Environment:
def __init__(self):
"""Do Nothing."""
pass
@property @property
def screen_size(self): def screen_size(self):
width = 1024
height = 768
try: try:
import wx import wx
_ = wx.App(False) # noqa _ = wx.App(False) # noqa
@ -23,7 +17,9 @@ class Environment:
height = tk.winfo_screenheight() height = tk.winfo_screenheight()
tk.destroy() tk.destroy()
except Exception as e: except Exception as e:
pass width = 1024
height = 768
return (width,height) return (width,height)
@ -43,8 +39,3 @@ class Environment:
def root_dir(self): def root_dir(self):
"""Return DAMASK root path.""" """Return DAMASK root path."""
return Path(__file__).parents[2] return Path(__file__).parents[2]
# for compatibility
def rootDir(self):
return str(self.root_dir)

View File

@ -2,6 +2,7 @@ import copy
import multiprocessing as mp import multiprocessing as mp
from functools import partial from functools import partial
from os import path from os import path
import warnings
import numpy as np import numpy as np
import pandas as pd import pandas as pd
@ -73,23 +74,23 @@ class Geom:
""" """
message = [] message = []
if np.any(other.grid != self.grid): if np.any(other.grid != self.grid):
message.append(util.delete(f'grid a b c: {util.srepr(other.grid," x ")}')) message.append(util.deemph(f'grid a b c: {util.srepr(other.grid," x ")}'))
message.append(util.emph( f'grid a b c: {util.srepr( self.grid," x ")}')) message.append(util.emph( f'grid a b c: {util.srepr( self.grid," x ")}'))
if not np.allclose(other.size,self.size): if not np.allclose(other.size,self.size):
message.append(util.delete(f'size x y z: {util.srepr(other.size," x ")}')) message.append(util.deemph(f'size x y z: {util.srepr(other.size," x ")}'))
message.append(util.emph( f'size x y z: {util.srepr( self.size," x ")}')) message.append(util.emph( f'size x y z: {util.srepr( self.size," x ")}'))
if not np.allclose(other.origin,self.origin): if not np.allclose(other.origin,self.origin):
message.append(util.delete(f'origin x y z: {util.srepr(other.origin," ")}')) message.append(util.deemph(f'origin x y z: {util.srepr(other.origin," ")}'))
message.append(util.emph( f'origin x y z: {util.srepr( self.origin," ")}')) message.append(util.emph( f'origin x y z: {util.srepr( self.origin," ")}'))
if other.N_materials != self.N_materials: if other.N_materials != self.N_materials:
message.append(util.delete(f'# materials: {other.N_materials}')) message.append(util.deemph(f'# materials: {other.N_materials}'))
message.append(util.emph( f'# materials: { self.N_materials}')) message.append(util.emph( f'# materials: { self.N_materials}'))
if np.nanmax(other.material) != np.nanmax(self.material): if np.nanmax(other.material) != np.nanmax(self.material):
message.append(util.delete(f'max material: {np.nanmax(other.material)}')) message.append(util.deemph(f'max material: {np.nanmax(other.material)}'))
message.append(util.emph( f'max material: {np.nanmax( self.material)}')) message.append(util.emph( f'max material: {np.nanmax( self.material)}'))
return util.return_message(message) return util.return_message(message)
@ -188,12 +189,16 @@ class Geom:
""" """
Read a geom file. Read a geom file.
Storing geometry files in ASCII format is deprecated.
This function will be removed in a future version of DAMASK.
Parameters Parameters
---------- ----------
fname : str, pathlib.Path, or file handle fname : str, pathlib.Path, or file handle
Geometry file to read. Geometry file to read.
""" """
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.1.0', DeprecationWarning)
try: try:
f = open(fname) f = open(fname)
except TypeError: except TypeError:
@ -247,7 +252,6 @@ class Geom:
return Geom(material.reshape(grid,order='F'),size,origin,comments) return Geom(material.reshape(grid,order='F'),size,origin,comments)
@staticmethod @staticmethod
def load_DREAM3D(fname,base_group,point_data=None,material='FeatureIds'): def load_DREAM3D(fname,base_group,point_data=None,material='FeatureIds'):
""" """
@ -523,6 +527,9 @@ class Geom:
""" """
Write a geom file. Write a geom file.
Storing geometry files in ASCII format is deprecated.
This function will be removed in a future version of DAMASK.
Parameters Parameters
---------- ----------
fname : str or file handle fname : str or file handle
@ -531,6 +538,7 @@ class Geom:
Compress geometry with 'x of y' and 'a to b'. Compress geometry with 'x of y' and 'a to b'.
""" """
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.1.0', DeprecationWarning)
header = [f'{len(self.comments)+4} header'] + self.comments \ header = [f'{len(self.comments)+4} header'] + self.comments \
+ ['grid a {} b {} c {}'.format(*self.grid), + ['grid a {} b {} c {}'.format(*self.grid),
'size x {} y {} z {}'.format(*self.size), 'size x {} y {} z {}'.format(*self.size),
@ -547,8 +555,7 @@ class Geom:
def show(self): def show(self):
"""Show on screen.""" """Show on screen."""
v = VTK.from_rectilinear_grid(self.grid,self.size,self.origin) VTK.from_rectilinear_grid(self.grid,self.size,self.origin).show()
v.show()
def add_primitive(self,dimension,center,exponent, def add_primitive(self,dimension,center,exponent,

View File

@ -4,7 +4,7 @@ from . import Rotation
from . import util from . import util
from . import tensor from . import tensor
__parameter_doc__ = \ _parameter_doc = \
"""lattice : str """lattice : str
Either a crystal family out of [triclinic, monoclinic, orthorhombic, tetragonal, hexagonal, cubic] Either a crystal family out of [triclinic, monoclinic, orthorhombic, tetragonal, hexagonal, cubic]
or a Bravais lattice out of [aP, mP, mS, oP, oS, oI, oF, tP, tI, hP, cP, cI, cF]. or a Bravais lattice out of [aP, mP, mS, oP, oS, oI, oF, tP, tI, hP, cP, cI, cF].
@ -27,22 +27,6 @@ __parameter_doc__ = \
""" """
def extend_docstring():
"""Decorator: Append Orientation parameter documentation to function's docstring."""
def _decorator(func):
func.__doc__ += __parameter_doc__
return func
return _decorator
def extended_docstring(f):
"""Decorator: Combine Orientation parameter documentation with another function's docstring."""
def _decorator(func):
func.__doc__ = f.__doc__ + __parameter_doc__
return func
return _decorator
class Orientation(Rotation): class Orientation(Rotation):
""" """
Representation of crystallographic orientation as combination of rotation and either crystal family or Bravais lattice. Representation of crystallographic orientation as combination of rotation and either crystal family or Bravais lattice.
@ -83,20 +67,9 @@ class Orientation(Rotation):
Examples Examples
-------- --------
An array of 3 x 5 random orientations reduced to the fundamental zone of tetragonal symmetry: An array of 3 x 5 random orientations reduced to the fundamental zone of tetragonal symmetry:
>>> damask.Orientation.from_random(shape=(3,5),lattice='tetragonal').reduced >>> damask.Orientation.from_random(shape=(3,5),lattice='tetragonal').reduced
Disorientation between two specific orientations of hexagonal symmetry:
>>> a = damask.Orientation.from_Euler_angles(phi=[123,32,21],degrees=True,lattice='hexagonal')
>>> b = damask.Orientation.from_Euler_angles(phi=[104,11,87],degrees=True,lattice='hexagonal')
>>> a.disorientation(b)
Inverse pole figure color of the e_3 direction for a crystal in "Cube" orientation with cubic symmetry:
>>> o = damask.Orientation(lattice='cubic')
>>> o.IPF_color(o.to_SST(np.array([0,0,1])))
Schmid matrix (in lab frame) of slip systems of a face-centered cubic crystal in "Goss" orientation:
>>> damask.Orientation.from_Euler_angles(phi=[0,45,0],degrees=True,lattice='cF').Schmid('slip')
""" """
crystal_families = ['triclinic', crystal_families = ['triclinic',
@ -128,7 +101,7 @@ class Orientation(Rotation):
} }
@extend_docstring() @util.extend_docstring(_parameter_doc)
def __init__(self, def __init__(self,
rotation = None, rotation = None,
lattice = None, lattice = None,
@ -279,73 +252,73 @@ class Orientation(Rotation):
@classmethod @classmethod
@extended_docstring(Rotation.from_random) @util.extended_docstring(Rotation.from_random,_parameter_doc)
def from_random(cls,**kwargs): def from_random(cls,**kwargs):
return cls(rotation=Rotation.from_random(**kwargs),**kwargs) return cls(rotation=Rotation.from_random(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_quaternion) @util.extended_docstring(Rotation.from_quaternion,_parameter_doc)
def from_quaternion(cls,**kwargs): def from_quaternion(cls,**kwargs):
return cls(rotation=Rotation.from_quaternion(**kwargs),**kwargs) return cls(rotation=Rotation.from_quaternion(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_Euler_angles) @util.extended_docstring(Rotation.from_Euler_angles,_parameter_doc)
def from_Euler_angles(cls,**kwargs): def from_Euler_angles(cls,**kwargs):
return cls(rotation=Rotation.from_Euler_angles(**kwargs),**kwargs) return cls(rotation=Rotation.from_Euler_angles(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_axis_angle) @util.extended_docstring(Rotation.from_axis_angle,_parameter_doc)
def from_axis_angle(cls,**kwargs): def from_axis_angle(cls,**kwargs):
return cls(rotation=Rotation.from_axis_angle(**kwargs),**kwargs) return cls(rotation=Rotation.from_axis_angle(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_basis) @util.extended_docstring(Rotation.from_basis,_parameter_doc)
def from_basis(cls,**kwargs): def from_basis(cls,**kwargs):
return cls(rotation=Rotation.from_basis(**kwargs),**kwargs) return cls(rotation=Rotation.from_basis(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_matrix) @util.extended_docstring(Rotation.from_matrix,_parameter_doc)
def from_matrix(cls,**kwargs): def from_matrix(cls,**kwargs):
return cls(rotation=Rotation.from_matrix(**kwargs),**kwargs) return cls(rotation=Rotation.from_matrix(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_Rodrigues_vector) @util.extended_docstring(Rotation.from_Rodrigues_vector,_parameter_doc)
def from_Rodrigues_vector(cls,**kwargs): def from_Rodrigues_vector(cls,**kwargs):
return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs),**kwargs) return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_homochoric) @util.extended_docstring(Rotation.from_homochoric,_parameter_doc)
def from_homochoric(cls,**kwargs): def from_homochoric(cls,**kwargs):
return cls(rotation=Rotation.from_homochoric(**kwargs),**kwargs) return cls(rotation=Rotation.from_homochoric(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_cubochoric) @util.extended_docstring(Rotation.from_cubochoric,_parameter_doc)
def from_cubochoric(cls,**kwargs): def from_cubochoric(cls,**kwargs):
return cls(rotation=Rotation.from_cubochoric(**kwargs),**kwargs) return cls(rotation=Rotation.from_cubochoric(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_spherical_component) @util.extended_docstring(Rotation.from_spherical_component,_parameter_doc)
def from_spherical_component(cls,**kwargs): def from_spherical_component(cls,**kwargs):
return cls(rotation=Rotation.from_spherical_component(**kwargs),**kwargs) return cls(rotation=Rotation.from_spherical_component(**kwargs),**kwargs)
@classmethod @classmethod
@extended_docstring(Rotation.from_fiber_component) @util.extended_docstring(Rotation.from_fiber_component,_parameter_doc)
def from_fiber_component(cls,**kwargs): def from_fiber_component(cls,**kwargs):
return cls(rotation=Rotation.from_fiber_component(**kwargs),**kwargs) return cls(rotation=Rotation.from_fiber_component(**kwargs),**kwargs)
@classmethod @classmethod
@extend_docstring() @util.extend_docstring(_parameter_doc)
def from_directions(cls,uvw,hkl,**kwargs): def from_directions(cls,uvw,hkl,**kwargs):
""" """
Initialize orientation object from two crystallographic directions. Initialize orientation object from two crystallographic directions.
@ -847,6 +820,14 @@ class Orientation(Rotation):
rgb : numpy.ndarray of shape (...,3) rgb : numpy.ndarray of shape (...,3)
RGB array of IPF colors. RGB array of IPF colors.
Examples
--------
Inverse pole figure color of the e_3 direction for a crystal in "Cube" orientation with cubic symmetry:
>>> o = damask.Orientation(lattice='cubic')
>>> o.IPF_color(o.to_SST([0,0,1]))
array([1., 0., 0.])
References References
---------- ----------
Bases are computed from Bases are computed from
@ -957,6 +938,22 @@ class Orientation(Rotation):
Currently requires same crystal family for both orientations. Currently requires same crystal family for both orientations.
For extension to cases with differing symmetry see A. Heinz and P. Neumann 1991 and 10.1107/S0021889808016373. For extension to cases with differing symmetry see A. Heinz and P. Neumann 1991 and 10.1107/S0021889808016373.
Examples
--------
Disorientation between two specific orientations of hexagonal symmetry:
>>> import damask
>>> a = damask.Orientation.from_Eulers(phi=[123,32,21],degrees=True,lattice='hexagonal')
>>> b = damask.Orientation.from_Eulers(phi=[104,11,87],degrees=True,lattice='hexagonal')
>>> a.disorientation(b)
Crystal family hexagonal
Quaternion: (real=0.976, imag=<+0.189, +0.018, +0.103>)
Matrix:
[[ 0.97831006 0.20710935 0.00389135]
[-0.19363288 0.90765544 0.37238141]
[ 0.07359167 -0.36505797 0.92807163]]
Bunge Eulers / deg: (11.40, 21.86, 0.60)
""" """
if self.family is None or other.family is None: if self.family is None or other.family is None:
raise ValueError('Missing crystal symmetry') raise ValueError('Missing crystal symmetry')
@ -1065,8 +1062,8 @@ class Orientation(Rotation):
raise ValueError('Missing crystal symmetry') raise ValueError('Missing crystal symmetry')
eq = self.equivalent eq = self.equivalent
blend = util.shapeblender(eq.shape,vector.shape[:-1]) blend = util.shapeblender(eq.shape,np.array(vector).shape[:-1])
poles = eq.broadcast_to(blend,mode='right') @ np.broadcast_to(vector,blend+(3,)) poles = eq.broadcast_to(blend,mode='right') @ np.broadcast_to(np.array(vector),blend+(3,))
ok = self.in_SST(poles,proper=proper) ok = self.in_SST(poles,proper=proper)
ok &= np.cumsum(ok,axis=0) == 1 ok &= np.cumsum(ok,axis=0) == 1
loc = np.where(ok) loc = np.where(ok)
@ -1085,12 +1082,12 @@ class Orientation(Rotation):
Parameters Parameters
---------- ----------
uvtw | hkil : numpy.ndarray of shape (...,4) uvtw|hkil : numpy.ndarray of shape (...,4)
MillerBravais indices of crystallographic direction [uvtw] or plane normal (hkil). MillerBravais indices of crystallographic direction [uvtw] or plane normal (hkil).
Returns Returns
------- -------
uvw | hkl : numpy.ndarray of shape (...,3) uvw|hkl : numpy.ndarray of shape (...,3)
Miller indices of [uvw] direction or (hkl) plane normal. Miller indices of [uvw] direction or (hkl) plane normal.
""" """
@ -1113,12 +1110,12 @@ class Orientation(Rotation):
Parameters Parameters
---------- ----------
uvw | hkl : numpy.ndarray of shape (...,3) uvw|hkl : numpy.ndarray of shape (...,3)
Miller indices of crystallographic direction [uvw] or plane normal (hkl). Miller indices of crystallographic direction [uvw] or plane normal (hkl).
Returns Returns
------- -------
uvtw | hkil : numpy.ndarray of shape (...,4) uvtw|hkil : numpy.ndarray of shape (...,4)
MillerBravais indices of [uvtw] direction or (hkil) plane normal. MillerBravais indices of [uvtw] direction or (hkil) plane normal.
""" """
@ -1142,7 +1139,7 @@ class Orientation(Rotation):
Parameters Parameters
---------- ----------
direction | normal : numpy.ndarray of shape (...,3) direction|normal : numpy.ndarray of shape (...,3)
Vector along direction or plane normal. Vector along direction or plane normal.
Returns Returns
@ -1166,7 +1163,7 @@ class Orientation(Rotation):
Parameters Parameters
---------- ----------
uvw | hkl : numpy.ndarray of shape (...,3) uvw|hkl : numpy.ndarray of shape (...,3)
Miller indices of crystallographic direction or plane normal. Miller indices of crystallographic direction or plane normal.
with_symmetry : bool, optional with_symmetry : bool, optional
Calculate all N symmetrically equivalent vectors. Calculate all N symmetrically equivalent vectors.
@ -1194,7 +1191,7 @@ class Orientation(Rotation):
Parameters Parameters
---------- ----------
uvw | hkl : numpy.ndarray of shape (...,3) uvw|hkl : numpy.ndarray of shape (...,3)
Miller indices of crystallographic direction or plane normal. Miller indices of crystallographic direction or plane normal.
with_symmetry : bool, optional with_symmetry : bool, optional
Calculate all N symmetrically equivalent vectors. Calculate all N symmetrically equivalent vectors.
@ -1217,13 +1214,26 @@ class Orientation(Rotation):
Parameters Parameters
---------- ----------
mode : str mode : str
Type of kinematics, e.g. 'slip' or 'twin'. Type of kinematics, i.e. 'slip' or 'twin'.
Returns Returns
------- -------
P : numpy.ndarray of shape (...,N,3,3) P : numpy.ndarray of shape (...,N,3,3)
Schmid matrix for each of the N deformation systems. Schmid matrix for each of the N deformation systems.
Examples
--------
Schmid matrix (in lab frame) of slip systems of a face-centered
cubic crystal in "Goss" orientation.
>>> import damask
>>> import numpy as np
>>> np.set_printoptions(3,suppress=True,floatmode='fixed')
>>> damask.Orientation.from_Eulers(phi=[0,45,0],degrees=True,lattice='cF').Schmid('slip')[0]
array([[ 0.000, 0.000, 0.000],
[ 0.577, -0.000, 0.816],
[ 0.000, 0.000, 0.000]])
""" """
d = self.to_frame(uvw=self.kinematics[mode]['direction'],with_symmetry=False) d = self.to_frame(uvw=self.kinematics[mode]['direction'],with_symmetry=False)
p = self.to_frame(hkl=self.kinematics[mode]['plane'] ,with_symmetry=False) p = self.to_frame(hkl=self.kinematics[mode]['plane'] ,with_symmetry=False)

View File

@ -168,9 +168,7 @@ class Result:
def allow_modification(self): def allow_modification(self):
print(util.bcolors().WARNING+util.bcolors().BOLD+ print(util.warn('Warning: Modification of existing datasets allowed!'))
'Warning: Modification of existing datasets allowed!'+
util.bcolors().ENDC)
self._allow_modification = True self._allow_modification = True
def disallow_modification(self): def disallow_modification(self):

View File

@ -107,22 +107,6 @@ class Rotation:
and np.allclose(self.quaternion,other.quaternion) and np.allclose(self.quaternion,other.quaternion)
def __neq__(self,other):
"""
Not Equal to other.
Equality is determined taking limited floating point precision into
account. See numpy.allclose for details.
Parameters
----------
other : Rotation
Rotation to check for inequality.
"""
return not self.__eq__(other)
@property @property
def shape(self): def shape(self):
return self.quaternion.shape[:-1] return self.quaternion.shape[:-1]
@ -315,7 +299,7 @@ class Rotation:
return self.quaternion.copy() return self.quaternion.copy()
def as_Euler_angles(self, def as_Euler_angles(self,
degrees = False): degrees = False):
""" """
Represent as Bunge-Euler angles. Represent as Bunge-Euler angles.
@ -373,7 +357,7 @@ class Rotation:
return Rotation._qu2om(self.quaternion) return Rotation._qu2om(self.quaternion)
def as_Rodrigues_vector(self, def as_Rodrigues_vector(self,
vector = False): vector = False):
""" """
Represent as Rodrigues-Frank vector with separated axis and angle argument. Represent as Rodrigues-Frank vector with separated axis and angle argument.
@ -404,7 +388,7 @@ class Rotation:
Returns Returns
------- -------
h : numpy.ndarray of shape (...,3) h : numpy.ndarray of shape (...,3)
Homochoric vector: (h_1, h_2, h_3), ǀhǀ < 1/2*π^(2/3). Homochoric vector: (h_1, h_2, h_3), ǀhǀ < (3/4*π)^(1/3).
""" """
return Rotation._qu2ho(self.quaternion) return Rotation._qu2ho(self.quaternion)
@ -698,7 +682,7 @@ class Rotation:
@staticmethod @staticmethod
def from_random(shape = None, def from_random(shape = None,
seed = None, rng_seed = None,
**kwargs): **kwargs):
""" """
Draw random rotation. Draw random rotation.
@ -710,12 +694,12 @@ class Rotation:
shape : tuple of ints, optional shape : tuple of ints, optional
Shape of the sample. Defaults to None which gives a Shape of the sample. Defaults to None which gives a
single rotation single rotation
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None. A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS. If None, then fresh, unpredictable entropy will be pulled from the OS.
""" """
rng = np.random.default_rng(seed) rng = np.random.default_rng(rng_seed)
r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3)) r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3))
A = np.sqrt(r[...,2]) A = np.sqrt(r[...,2])
@ -730,11 +714,11 @@ class Rotation:
@staticmethod @staticmethod
def from_ODF(weights, def from_ODF(weights,
Eulers, phi,
N = 500, N = 500,
degrees = True, degrees = True,
fractions = True, fractions = True,
seed = None, rng_seed = None,
**kwargs): **kwargs):
""" """
Sample discrete values from a binned ODF. Sample discrete values from a binned ODF.
@ -743,7 +727,7 @@ class Rotation:
---------- ----------
weights : numpy.ndarray of shape (n) weights : numpy.ndarray of shape (n)
Texture intensity values (probability density or volume fraction) at Euler grid points. Texture intensity values (probability density or volume fraction) at Euler grid points.
Eulers : numpy.ndarray of shape (n,3) phi : numpy.ndarray of shape (n,3)
Grid coordinates in Euler space at which weights are defined. Grid coordinates in Euler space at which weights are defined.
N : integer, optional N : integer, optional
Number of discrete orientations to be sampled from the given ODF. Number of discrete orientations to be sampled from the given ODF.
@ -753,7 +737,7 @@ class Rotation:
fractions : boolean, optional fractions : boolean, optional
ODF values correspond to volume fractions, not probability density. ODF values correspond to volume fractions, not probability density.
Defaults to True. Defaults to True.
seed: {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed: {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy
will be pulled from the OS. will be pulled from the OS.
@ -776,15 +760,15 @@ class Rotation:
""" """
def _dg(eu,deg): def _dg(eu,deg):
"""Return infinitesimal Euler space volume of bin(s).""" """Return infinitesimal Euler space volume of bin(s)."""
Eulers_sorted = eu[np.lexsort((eu[:,0],eu[:,1],eu[:,2]))] phi_sorted = eu[np.lexsort((eu[:,0],eu[:,1],eu[:,2]))]
steps,size,_ = grid_filters.cell_coord0_gridSizeOrigin(Eulers_sorted) steps,size,_ = grid_filters.cell_coord0_gridSizeOrigin(phi_sorted)
delta = np.radians(size/steps) if deg else size/steps delta = np.radians(size/steps) if deg else size/steps
return delta[0]*2.0*np.sin(delta[1]/2.0)*delta[2] / 8.0 / np.pi**2 * np.sin(np.radians(eu[:,1]) if deg else eu[:,1]) return delta[0]*2.0*np.sin(delta[1]/2.0)*delta[2] / 8.0 / np.pi**2 * np.sin(np.radians(eu[:,1]) if deg else eu[:,1])
dg = 1.0 if fractions else _dg(Eulers,degrees) dg = 1.0 if fractions else _dg(phi,degrees)
dV_V = dg * np.maximum(0.0,weights.squeeze()) dV_V = dg * np.maximum(0.0,weights.squeeze())
return Rotation.from_Euler_angles(Eulers[util.hybrid_IA(dV_V,N,seed)],degrees) return Rotation.from_Euler_angles(phi[util.hybrid_IA(dV_V,N,rng_seed)],degrees)
@staticmethod @staticmethod
@ -792,7 +776,7 @@ class Rotation:
sigma, sigma,
N = 500, N = 500,
degrees = True, degrees = True,
seed = None, rng_seed = None,
**kwargs): **kwargs):
""" """
Calculate set of rotations with Gaussian distribution around center. Calculate set of rotations with Gaussian distribution around center.
@ -807,12 +791,12 @@ class Rotation:
Number of samples, defaults to 500. Number of samples, defaults to 500.
degrees : boolean, optional degrees : boolean, optional
sigma is given in degrees. sigma is given in degrees.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy
will be pulled from the OS. will be pulled from the OS.
""" """
rng = np.random.default_rng(seed) rng = np.random.default_rng(rng_seed)
sigma = np.radians(sigma) if degrees else sigma sigma = np.radians(sigma) if degrees else sigma
u,Theta = (rng.random((N,2)) * 2.0 * np.array([1,np.pi]) - np.array([1.0, 0])).T u,Theta = (rng.random((N,2)) * 2.0 * np.array([1,np.pi]) - np.array([1.0, 0])).T
omega = abs(rng.normal(scale=sigma,size=N)) omega = abs(rng.normal(scale=sigma,size=N))
@ -829,7 +813,7 @@ class Rotation:
sigma = 0.0, sigma = 0.0,
N = 500, N = 500,
degrees = True, degrees = True,
seed = None, rng_seed = None,
**kwargs): **kwargs):
""" """
Calculate set of rotations with Gaussian distribution around direction. Calculate set of rotations with Gaussian distribution around direction.
@ -847,12 +831,12 @@ class Rotation:
Number of samples, defaults to 500. Number of samples, defaults to 500.
degrees : boolean, optional degrees : boolean, optional
sigma, alpha, and beta are given in degrees. sigma, alpha, and beta are given in degrees.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy
will be pulled from the OS. will be pulled from the OS.
""" """
rng = np.random.default_rng(seed) rng = np.random.default_rng(rng_seed)
sigma_,alpha_,beta_ = map(np.radians,(sigma,alpha,beta)) if degrees else (sigma,alpha,beta) sigma_,alpha_,beta_ = map(np.radians,(sigma,alpha,beta)) if degrees else (sigma,alpha,beta)
d_cr = np.array([np.sin(alpha_[0])*np.cos(alpha_[1]), np.sin(alpha_[0])*np.sin(alpha_[1]), np.cos(alpha_[0])]) d_cr = np.array([np.sin(alpha_[0])*np.cos(alpha_[1]), np.sin(alpha_[0])*np.sin(alpha_[1]), np.cos(alpha_[0])])
@ -1440,9 +1424,3 @@ class Rotation:
np.where(np.maximum(np.abs(xyz[...,1]),np.abs(xyz[...,2])) <= np.abs(xyz[...,0]),1,2)) np.where(np.maximum(np.abs(xyz[...,1]),np.abs(xyz[...,2])) <= np.abs(xyz[...,0]),1,2))
return order[direction][p] return order[direction][p]
# for compatibility with deprecated tests
Rotation.from_Eulers = Rotation.from_Euler_angles
Rotation.as_Eulers = Rotation.as_Euler_angles
Rotation.from_Rodrigues = Rotation.from_Rodrigues_vector

View File

@ -31,7 +31,7 @@ class Table:
def __repr__(self): def __repr__(self):
"""Brief overview.""" """Brief overview."""
return util.srepr(self.comments)+'\n'+self.data.__repr__() return '\n'.join(['# '+c for c in self.comments])+'\n'+self.data.__repr__()
def __len__(self): def __len__(self):
"""Number of rows.""" """Number of rows."""
@ -159,7 +159,7 @@ class Table:
comments = [util.execution_stamp('Table','from_ang')] comments = [util.execution_stamp('Table','from_ang')]
for line in content: for line in content:
if line.startswith('#'): if line.startswith('#'):
comments.append(line.strip()) comments.append(line.split('#',1)[1].strip())
else: else:
break break
@ -222,6 +222,7 @@ class Table:
dup.data[label] = data.reshape(dup.data[label].shape) dup.data[label] = data.reshape(dup.data[label].shape)
return dup return dup
def add(self,label,data,info=None): def add(self,label,data,info=None):
""" """
Add column data. Add column data.

View File

@ -7,7 +7,7 @@ from . import util
from . import grid_filters from . import grid_filters
def from_random(size,N_seeds,grid=None,seed=None): def from_random(size,N_seeds,grid=None,rng_seed=None):
""" """
Random seeding in space. Random seeding in space.
@ -20,12 +20,12 @@ def from_random(size,N_seeds,grid=None,seed=None):
grid : numpy.ndarray of shape (3), optional. grid : numpy.ndarray of shape (3), optional.
If given, ensures that all seeds initiate one grain if using a If given, ensures that all seeds initiate one grain if using a
standard Voronoi tessellation. standard Voronoi tessellation.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None. A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS. If None, then fresh, unpredictable entropy will be pulled from the OS.
""" """
rng = _np.random.default_rng(seed) rng = _np.random.default_rng(rng_seed)
if grid is None: if grid is None:
coords = rng.random((N_seeds,3)) * size coords = rng.random((N_seeds,3)) * size
else: else:
@ -36,7 +36,7 @@ def from_random(size,N_seeds,grid=None,seed=None):
return coords return coords
def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,seed=None): def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,rng_seed=None):
""" """
Seeding in space according to a Poisson disc distribution. Seeding in space according to a Poisson disc distribution.
@ -52,12 +52,12 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,seed=None
Minimum acceptable distance to other seeds. Minimum acceptable distance to other seeds.
periodic : boolean, optional periodic : boolean, optional
Calculate minimum distance for periodically repeated grid. Calculate minimum distance for periodically repeated grid.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None. A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS. If None, then fresh, unpredictable entropy will be pulled from the OS.
""" """
rng = _np.random.default_rng(seed) rng = _np.random.default_rng(rng_seed)
coords = _np.empty((N_seeds,3)) coords = _np.empty((N_seeds,3))
coords[0] = rng.random(3) * size coords[0] = rng.random(3) * size

View File

@ -17,7 +17,7 @@ __all__=[
'srepr', 'srepr',
'croak', 'croak',
'report', 'report',
'emph','deemph','delete','strikeout', 'emph','deemph','warn','strikeout',
'execute', 'execute',
'show_progress', 'show_progress',
'scale_to_coprime', 'scale_to_coprime',
@ -26,8 +26,8 @@ __all__=[
'return_message', 'return_message',
'extendableOption', 'extendableOption',
'execution_stamp', 'execution_stamp',
'shapeshifter', 'shapeshifter', 'shapeblender',
'shapeblender', 'extend_docstring', 'extended_docstring'
] ]
#################################################################################################### ####################################################################################################
@ -42,7 +42,7 @@ def srepr(arg,glue = '\n'):
arg : iterable arg : iterable
Items to join. Items to join.
glue : str, optional glue : str, optional
Defaults to \n. Glue used for joining operation. Defaults to \n.
""" """
if (not hasattr(arg, "strip") and if (not hasattr(arg, "strip") and
@ -56,6 +56,8 @@ def croak(what, newline = True):
""" """
Write formated to stderr. Write formated to stderr.
DEPRECATED
Parameters Parameters
---------- ----------
what : str or iterable what : str or iterable
@ -72,7 +74,7 @@ def croak(what, newline = True):
def report(who = None, def report(who = None,
what = None): what = None):
""" """
Reports script and file name. Report script and file name.
DEPRECATED DEPRECATED
@ -84,16 +86,13 @@ def emph(what):
"""Formats string with emphasis.""" """Formats string with emphasis."""
return bcolors.BOLD+srepr(what)+bcolors.ENDC return bcolors.BOLD+srepr(what)+bcolors.ENDC
def deemph(what): def deemph(what):
"""Formats string with deemphasis.""" """Formats string with deemphasis."""
return bcolors.DIM+srepr(what)+bcolors.ENDC return bcolors.DIM+srepr(what)+bcolors.ENDC
def warn(what):
def delete(what): """Formats string for warning."""
"""Formats string as deleted.""" return bcolors.WARNING+emph(what)+bcolors.ENDC
return bcolors.DIM+srepr(what)+bcolors.ENDC
def strikeout(what): def strikeout(what):
"""Formats string as strikeout.""" """Formats string as strikeout."""
@ -164,7 +163,15 @@ def show_progress(iterable,N_iter=None,prefix='',bar_length=50):
def scale_to_coprime(v): def scale_to_coprime(v):
"""Scale vector to co-prime (relatively prime) integers.""" """
Scale vector to co-prime (relatively prime) integers.
Parameters
----------
v : numpy.ndarray of shape (:)
Vector to scale.
"""
MAX_DENOMINATOR = 1000000 MAX_DENOMINATOR = 1000000
def get_square_denominator(x): def get_square_denominator(x):
@ -215,7 +222,21 @@ def execution_stamp(class_name,function_name=None):
return f'damask.{class_name}{_function_name} v{version} ({now})' return f'damask.{class_name}{_function_name} v{version} ({now})'
def hybrid_IA(dist,N,seed=None): def hybrid_IA(dist,N,rng_seed=None):
"""
Hybrid integer approximation.
Parameters
----------
dist : numpy.ndarray
Distribution to be approximated
N : int
Number of samples to draw.
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS.
"""
N_opt_samples,N_inv_samples = (max(np.count_nonzero(dist),N),0) # random subsampling if too little samples requested N_opt_samples,N_inv_samples = (max(np.count_nonzero(dist),N),0) # random subsampling if too little samples requested
scale_,scale,inc_factor = (0.0,float(N_opt_samples),1.0) scale_,scale,inc_factor = (0.0,float(N_opt_samples),1.0)
@ -226,7 +247,7 @@ def hybrid_IA(dist,N,seed=None):
if N_inv_samples < N_opt_samples else \ if N_inv_samples < N_opt_samples else \
(scale_,0.5*(scale_ + scale), 1.0) (scale_,0.5*(scale_ + scale), 1.0)
return np.repeat(np.arange(len(dist)),repeats)[np.random.default_rng(seed).permutation(N_inv_samples)[:N]] return np.repeat(np.arange(len(dist)),repeats)[np.random.default_rng(rng_seed).permutation(N_inv_samples)[:N]]
def shapeshifter(fro,to,mode='left',keep_ones=False): def shapeshifter(fro,to,mode='left',keep_ones=False):
@ -300,6 +321,40 @@ def shapeblender(a,b):
return a + b[i:] return a + b[i:]
def extend_docstring(extra_docstring):
"""
Decorator: Append to function's docstring.
Parameters
----------
extra_docstring : str
Docstring to append.
"""
def _decorator(func):
func.__doc__ += extra_docstring
return func
return _decorator
def extended_docstring(f,extra_docstring):
"""
Decorator: Combine another function's docstring with a given docstring.
Parameters
----------
f : function
Function of which the docstring is taken.
extra_docstring : str
Docstring to append.
"""
def _decorator(func):
func.__doc__ = f.__doc__ + extra_docstring
return func
return _decorator
#################################################################################################### ####################################################################################################
# Classes # Classes
#################################################################################################### ####################################################################################################
@ -393,17 +448,6 @@ class bcolors:
UNDERLINE = '\033[4m' UNDERLINE = '\033[4m'
CROSSOUT = '\033[9m' CROSSOUT = '\033[9m'
def disable(self):
self.HEADER = ''
self.OKBLUE = ''
self.OKGREEN = ''
self.WARNING = ''
self.FAIL = ''
self.ENDC = ''
self.BOLD = ''
self.UNDERLINE = ''
self.CROSSOUT = ''
class return_message: class return_message:
"""Object with formatted return message.""" """Object with formatted return message."""

View File

@ -1,8 +1,13 @@
from pathlib import Path from pathlib import Path
import datetime import datetime
import os
import numpy as np import numpy as np
import pytest import pytest
import matplotlib as mpl
if os.name == 'posix' and 'DISPLAY' not in os.environ:
mpl.use('Agg')
import matplotlib.pyplot as plt
import damask import damask
@ -25,8 +30,9 @@ def patch_datetime_now(monkeypatch):
monkeypatch.setattr(datetime, 'datetime', mydatetime) monkeypatch.setattr(datetime, 'datetime', mydatetime)
@pytest.fixture @pytest.fixture
def execution_stamp(monkeypatch): def patch_execution_stamp(monkeypatch):
"""Set damask.util.execution_stamp for reproducible tests results.""" """Set damask.util.execution_stamp for reproducible tests results."""
def execution_stamp(class_name,function_name=None): def execution_stamp(class_name,function_name=None):
_function_name = '' if function_name is None else f'.{function_name}' _function_name = '' if function_name is None else f'.{function_name}'
@ -35,21 +41,31 @@ def execution_stamp(monkeypatch):
monkeypatch.setattr(damask.util, 'execution_stamp', execution_stamp) monkeypatch.setattr(damask.util, 'execution_stamp', execution_stamp)
@pytest.fixture
def patch_plt_show(monkeypatch):
def _None(block=None):
pass
monkeypatch.setattr(plt, 'show', _None, raising=True)
def pytest_addoption(parser): def pytest_addoption(parser):
parser.addoption("--update", parser.addoption("--update",
action="store_true", action="store_true",
default=False) default=False)
@pytest.fixture @pytest.fixture
def update(request): def update(request):
"""Store current results as new reference results.""" """Store current results as new reference results."""
return request.config.getoption("--update") return request.config.getoption("--update")
@pytest.fixture @pytest.fixture
def reference_dir_base(): def reference_dir_base():
"""Directory containing reference results.""" """Directory containing reference results."""
return Path(__file__).parent/'reference' return Path(__file__).parent/'reference'
@pytest.fixture @pytest.fixture
def set_of_quaternions(): def set_of_quaternions():
"""A set of n random rotations.""" """A set of n random rotations."""

View File

@ -17,9 +17,12 @@ def reference_dir(reference_dir_base):
class TestColormap: class TestColormap:
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def _execution_stamp(self, execution_stamp): def _patch_execution_stamp(self, patch_execution_stamp):
print('patched damask.util.execution_stamp') print('patched damask.util.execution_stamp')
def test_repr(self,patch_plt_show):
print(Colormap.from_predefined('stress'))
def test_conversion(self): def test_conversion(self):
specials = np.array([[0.,0.,0.], specials = np.array([[0.,0.,0.],
[1.,0.,0.], [1.,0.,0.],
@ -138,8 +141,8 @@ class TestColormap:
diff = ImageChops.difference(img_reference.convert('RGB'),img_current.convert('RGB')) diff = ImageChops.difference(img_reference.convert('RGB'),img_current.convert('RGB'))
assert not diff.getbbox() assert not diff.getbbox()
def test_list(self): def test_predefined(self):
Colormap.list_predefined() assert (isinstance(Colormap.predefined,dict))
@pytest.mark.parametrize('format,ext',[('ASCII','.txt'), @pytest.mark.parametrize('format,ext',[('ASCII','.txt'),
('paraview','.json'), ('paraview','.json'),

View File

@ -62,6 +62,12 @@ class TestConfigMaterial:
del material_config['material'][0]['homogenization'] del material_config['material'][0]['homogenization']
assert not material_config.is_complete assert not material_config.is_complete
def test_incomplete_homogenization_N_constituents(self,reference_dir):
material_config = ConfigMaterial.load(reference_dir/'material.yaml')
for h in material_config['homogenization'].keys():
del material_config['homogenization'][h]['N_constituents']
assert not material_config.is_complete
def test_incomplete_phase_lattice(self,reference_dir): def test_incomplete_phase_lattice(self,reference_dir):
material_config = ConfigMaterial.load(reference_dir/'material.yaml') material_config = ConfigMaterial.load(reference_dir/'material.yaml')
del material_config['phase']['Aluminum']['lattice'] del material_config['phase']['Aluminum']['lattice']
@ -85,9 +91,36 @@ class TestConfigMaterial:
assert len(c['material']) == N assert len(c['material']) == N
for i,m in enumerate(c['material']): for i,m in enumerate(c['material']):
c = m['constituents'][0] c = m['constituents'][0]
assert m['c'] == 1 and c['b'] == 0 and c['a'] == [i,1] assert m['c'] == 1 and c['b'] == 0 and (c['a'] == [i,1]).all()
def test__constituents(self): def test_constituents(self):
c = ConfigMaterial._constituents(c=1,v=[2,3]) c = ConfigMaterial._constituents(c=1,v=[2,3])
assert c[0][0]['c'] == c[1][0]['c'] == 1 assert c[0][0]['c'] == c[1][0]['c'] == 1
assert c[0][0]['v'] == c[1][0]['v'] -1 ==2 assert c[0][0]['v'] == c[1][0]['v'] -1 ==2
@pytest.mark.parametrize('constituents',[{'W':1,'X':[2,3]},{'Y':4},{'Z':[5,6]}])
@pytest.mark.parametrize('a',[[7.,8.],9.])
@pytest.mark.parametrize('b',['bd',['efg','hi']])
def test_material_add(self,tmp_path,constituents,a,b):
len_c = len(ConfigMaterial()._constituents(1,**constituents))
len_a = len(a) if isinstance(a,list) else 1
len_b = len(b) if isinstance(b,list) else 1
m = ConfigMaterial().material_add(constituents,a=a,b=b)
m.save()
assert len(m['material']) == np.max([len_a,len_b,len_c])
@pytest.mark.parametrize('constituents',[{'W':1,'X':np.array([2,3])},{'Y':4},{'Z':np.array([5,6])}])
@pytest.mark.parametrize('a',[np.array([7,8]),9])
def test_material_add_np(self,tmp_path,constituents,a):
len_c = len(ConfigMaterial()._constituents(1,**constituents))
len_a = len(a) if isinstance(a,np.ndarray) else 1
m = ConfigMaterial().material_add(constituents,ld=a)
m.save()
assert len(m['material']) == np.max([len_a,len_c])
@pytest.mark.parametrize('constituents',[{'X':np.array([2,3,4,5])},{'Y':4}])
@pytest.mark.parametrize('a',[np.array([1,2,3]),[4,5,6]])
@pytest.mark.parametrize('b',[np.array([6.,7.]),[8.,9.]])
def test_material_add_invalid(self,constituents,a,b):
with pytest.raises(ValueError):
ConfigMaterial().material_add(constituents,a=a,u=b)

View File

@ -34,7 +34,7 @@ def reference_dir(reference_dir_base):
class TestGeom: class TestGeom:
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def _execution_stamp(self, execution_stamp): def _patch_execution_stamp(self, patch_execution_stamp):
print('patched damask.util.execution_stamp') print('patched damask.util.execution_stamp')
def test_diff_equal(self,default): def test_diff_equal(self,default):
@ -45,6 +45,8 @@ class TestGeom:
new = Geom(default.material[1:,1:,1:]+1,default.size*.9,np.ones(3)-default.origin,comments=['modified']) new = Geom(default.material[1:,1:,1:]+1,default.size*.9,np.ones(3)-default.origin,comments=['modified'])
assert str(default.diff(new)) != '' assert str(default.diff(new)) != ''
def test_repr(self,default):
print(default)
def test_read_write_vtr(self,default,tmp_path): def test_read_write_vtr(self,default,tmp_path):
default.save(tmp_path/'default') default.save(tmp_path/'default')
@ -70,6 +72,9 @@ class TestGeom:
Geom(default.material[1:,1:,1:], Geom(default.material[1:,1:,1:],
size=np.ones(2)) size=np.ones(2))
def test_save_load_ASCII(self,default,tmp_path):
default.save_ASCII(tmp_path/'ASCII')
assert geom_equal(Geom.load_ASCII(tmp_path/'ASCII'),default)
def test_invalid_origin(self,default): def test_invalid_origin(self,default):
with pytest.raises(ValueError): with pytest.raises(ValueError):

View File

@ -125,9 +125,9 @@ class TestOrientation:
def test_from_fiber_component(self): def test_from_fiber_component(self):
r = Rotation.from_fiber_component(alpha=np.zeros(2),beta=np.zeros(2), r = Rotation.from_fiber_component(alpha=np.zeros(2),beta=np.zeros(2),
sigma=0.0,N=1,seed=0) sigma=0.0,N=1,rng_seed=0)
assert np.all(Orientation.from_fiber_component(alpha=np.zeros(2),beta=np.zeros(2), assert np.all(Orientation.from_fiber_component(alpha=np.zeros(2),beta=np.zeros(2),
sigma=0.0,N=1,seed=0,lattice='triclinic').quaternion sigma=0.0,N=1,rng_seed=0,lattice='triclinic').quaternion
== r.quaternion) == r.quaternion)
@pytest.mark.parametrize('kwargs',[ @pytest.mark.parametrize('kwargs',[
@ -175,8 +175,8 @@ class TestOrientation:
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',Orientation.crystal_families)
@pytest.mark.parametrize('N',[1,8,32]) @pytest.mark.parametrize('N',[1,8,32])
def test_disorientation(self,lattice,N): def test_disorientation(self,lattice,N):
o = Orientation.from_random(lattice=lattice,shape=N,seed=0) o = Orientation.from_random(lattice=lattice,shape=N)
p = Orientation.from_random(lattice=lattice,shape=N,seed=1) p = Orientation.from_random(lattice=lattice,shape=N)
d,ops = o.disorientation(p,return_operators=True) d,ops = o.disorientation(p,return_operators=True)
@ -198,8 +198,8 @@ class TestOrientation:
(None,None), (None,None),
]) ])
def test_disorientation_blending(self,lattice,a,b): def test_disorientation_blending(self,lattice,a,b):
o = Orientation.from_random(lattice=lattice,shape=a,seed=0) o = Orientation.from_random(lattice=lattice,shape=a)
p = Orientation.from_random(lattice=lattice,shape=b,seed=1) p = Orientation.from_random(lattice=lattice,shape=b)
blend = util.shapeblender(o.shape,p.shape) blend = util.shapeblender(o.shape,p.shape)
for loc in np.random.randint(0,blend,(10,len(blend))): for loc in np.random.randint(0,blend,(10,len(blend))):
assert o[tuple(loc[:len(o.shape)])].disorientation(p[tuple(loc[-len(p.shape):])]) \ assert o[tuple(loc[:len(o.shape)])].disorientation(p[tuple(loc[-len(p.shape):])]) \
@ -214,7 +214,7 @@ class TestOrientation:
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',Orientation.crystal_families)
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)]) @pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
def test_reduced_vectorization(self,lattice,shape): def test_reduced_vectorization(self,lattice,shape):
o = Orientation.from_random(lattice=lattice,shape=shape,seed=0) o = Orientation.from_random(lattice=lattice,shape=shape)
for r, theO in zip(o.reduced.flatten(),o.flatten()): for r, theO in zip(o.reduced.flatten(),o.flatten()):
assert r == theO.reduced assert r == theO.reduced
@ -223,7 +223,7 @@ class TestOrientation:
@pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]])) @pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]]))
@pytest.mark.parametrize('proper',[True,False]) @pytest.mark.parametrize('proper',[True,False])
def test_to_SST_vectorization(self,lattice,shape,vector,proper): def test_to_SST_vectorization(self,lattice,shape,vector,proper):
o = Orientation.from_random(lattice=lattice,shape=shape,seed=0) o = Orientation.from_random(lattice=lattice,shape=shape)
for r, theO in zip(o.to_SST(vector=vector,proper=proper).reshape((-1,3)),o.flatten()): for r, theO in zip(o.to_SST(vector=vector,proper=proper).reshape((-1,3)),o.flatten()):
assert np.allclose(r,theO.to_SST(vector=vector,proper=proper)) assert np.allclose(r,theO.to_SST(vector=vector,proper=proper))
@ -232,7 +232,7 @@ class TestOrientation:
@pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]])) @pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]]))
@pytest.mark.parametrize('proper',[True,False]) @pytest.mark.parametrize('proper',[True,False])
def test_IPF_color_vectorization(self,lattice,shape,vector,proper): def test_IPF_color_vectorization(self,lattice,shape,vector,proper):
o = Orientation.from_random(lattice=lattice,shape=shape,seed=0) o = Orientation.from_random(lattice=lattice,shape=shape)
poles = o.to_SST(vector=vector,proper=proper) poles = o.to_SST(vector=vector,proper=proper)
for r, theO in zip(o.IPF_color(poles,proper=proper).reshape((-1,3)),o.flatten()): for r, theO in zip(o.IPF_color(poles,proper=proper).reshape((-1,3)),o.flatten()):
assert np.allclose(r,theO.IPF_color(theO.to_SST(vector=vector,proper=proper),proper=proper)) assert np.allclose(r,theO.IPF_color(theO.to_SST(vector=vector,proper=proper),proper=proper))
@ -245,7 +245,7 @@ class TestOrientation:
(None,(3,)), (None,(3,)),
]) ])
def test_to_SST_blending(self,lattice,a,b): def test_to_SST_blending(self,lattice,a,b):
o = Orientation.from_random(lattice=lattice,shape=a,seed=0) o = Orientation.from_random(lattice=lattice,shape=a)
v = np.random.random(b+(3,)) v = np.random.random(b+(3,))
blend = util.shapeblender(o.shape,b) blend = util.shapeblender(o.shape,b)
for loc in np.random.randint(0,blend,(10,len(blend))): for loc in np.random.randint(0,blend,(10,len(blend))):

View File

@ -769,18 +769,19 @@ class TestRotation:
@pytest.mark.parametrize('shape',[None,1,(4,4)]) @pytest.mark.parametrize('shape',[None,1,(4,4)])
def test_random(self,shape): def test_random(self,shape):
Rotation.from_random(shape) r = Rotation.from_random(shape)
if shape is None:
assert r.shape == ()
elif shape == 1:
assert r.shape == (1,)
else:
assert r.shape == shape
def test_equal(self): def test_equal(self):
r = Rotation.from_random(seed=0) assert Rotation.from_random(rng_seed=1) == Rotation.from_random(rng_seed=1)
assert r == r
def test_unequal(self):
r = Rotation.from_random(seed=0)
assert not (r != r)
def test_inversion(self): def test_inversion(self):
r = Rotation.from_random(seed=0) r = Rotation.from_random()
assert r == ~~r assert r == ~~r
@pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(1,1,1)]) @pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(1,1,1)])

View File

@ -17,6 +17,12 @@ def reference_dir(reference_dir_base):
class TestTable: class TestTable:
def test_repr(self,default):
print(default)
def test_len(self):
len(Table(np.random.rand(7,3),{'X':3})) == 7
def test_get_scalar(self,default): def test_get_scalar(self,default):
d = default.get('s') d = default.get('s')
assert np.allclose(d,1.0) and d.shape[1:] == (1,) assert np.allclose(d,1.0) and d.shape[1:] == (1,)

View File

@ -23,7 +23,7 @@ def default():
class TestVTK: class TestVTK:
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def _execution_stamp(self, execution_stamp): def _patch_execution_stamp(self, patch_execution_stamp):
print('patched damask.util.execution_stamp') print('patched damask.util.execution_stamp')
def test_rectilinearGrid(self,tmp_path): def test_rectilinearGrid(self,tmp_path):
@ -84,6 +84,15 @@ class TestVTK:
time.sleep(.5) time.sleep(.5)
assert(False) assert(False)
def test_compress(self,tmp_path):
points = np.random.rand(102,3)
v = VTK.from_poly_data(points)
fname_c = tmp_path/'compressed.vtp'
fname_p = tmp_path/'plain.vtp'
v.save(fname_c,parallel=False,compress=False)
v.save(fname_p,parallel=False,compress=True)
assert(VTK.load(fname_c).__repr__() == VTK.load(fname_p).__repr__())
@pytest.mark.parametrize('fname',['a','a.vtp','a.b','a.b.vtp']) @pytest.mark.parametrize('fname',['a','a.vtp','a.b','a.b.vtp'])
def test_filename_variations(self,tmp_path,fname): def test_filename_variations(self,tmp_path,fname):

View File

@ -15,6 +15,10 @@ class TestUtil:
out,err = util.execute('sh -c "echo $test_for_execute"',env={'test_for_execute':'test'}) out,err = util.execute('sh -c "echo $test_for_execute"',env={'test_for_execute':'test'})
assert out=='test\n' and err=='' assert out=='test\n' and err==''
def test_execute_invalid(self):
with pytest.raises(RuntimeError):
util.execute('/bin/false')
def test_croak(self): def test_croak(self):
util.croak('Burp!') util.croak('Burp!')
@ -93,3 +97,7 @@ class TestUtil:
]) ])
def test_shapeblender(self,a,b,answer): def test_shapeblender(self,a,b,answer):
assert util.shapeblender(a,b) == answer assert util.shapeblender(a,b) == answer
@pytest.mark.parametrize('style',[util.emph,util.deemph,util.warn,util.strikeout])
def test_decorate(self,style):
assert 'DAMASK' in style('DAMASK')

View File

@ -4,25 +4,24 @@
#include <dirent.h> #include <dirent.h>
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
#include <pwd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "zlib.h" #include "zlib.h"
/* http://stackoverflow.com/questions/30279228/is-there-an-alternative-to-getcwd-in-fortran-2003-2008 */ #define PATHLEN 4096
#define STRLEN 256
int isdirectory_c(const char *dir){ int setcwd_c(const char *cwd){
struct stat statbuf; return chdir(cwd);
if(stat(dir, &statbuf) != 0) /* error */
return 0; /* return "NO, this is not a directory" */
return S_ISDIR(statbuf.st_mode); /* 1 => is directory, 0 => this is NOT a directory */
} }
void getcurrentworkdir_c(char cwd[], int *stat ){ void getcwd_c(char cwd[], int *stat ){
char cwd_tmp[4096]; char cwd_tmp[PATHLEN+1];
if(getcwd(cwd_tmp, sizeof(cwd_tmp)) == cwd_tmp){ if(getcwd(cwd_tmp, sizeof(cwd_tmp))){
strcpy(cwd,cwd_tmp); strcpy(cwd,cwd_tmp); // getcwd guarantees a NULL-terminated string
*stat = 0; *stat = 0;
} }
else{ else{
@ -32,9 +31,9 @@ void getcurrentworkdir_c(char cwd[], int *stat ){
void gethostname_c(char hostname[], int *stat){ void gethostname_c(char hostname[], int *stat){
char hostname_tmp[4096]; char hostname_tmp[STRLEN];
if(gethostname(hostname_tmp, sizeof(hostname_tmp)) == 0){ if(gethostname(hostname_tmp, sizeof(hostname_tmp)) == 0){
strcpy(hostname,hostname_tmp); strncpy(hostname,hostname_tmp,sizeof(hostname_tmp)+1); // gethostname does not guarantee a NULL-terminated string
*stat = 0; *stat = 0;
} }
else{ else{
@ -43,10 +42,18 @@ void gethostname_c(char hostname[], int *stat){
} }
int chdir_c(const char *dir){ void getusername_c(char username[], int *stat){
return chdir(dir); struct passwd *pw = getpwuid(geteuid());
if(pw && strlen(pw->pw_name) <= STRLEN){
strncpy(username,pw->pw_name,STRLEN+1);
*stat = 0;
}
else{
*stat = 1;
}
} }
void signalterm_c(void (*handler)(int)){ void signalterm_c(void (*handler)(int)){
signal(SIGTERM, handler); signal(SIGTERM, handler);
} }
@ -59,6 +66,7 @@ void signalusr2_c(void (*handler)(int)){
signal(SIGUSR2, handler); signal(SIGUSR2, handler);
} }
void inflate_c(const uLong *s_deflated, const uLong *s_inflated, const Byte deflated[], Byte inflated[]){ void inflate_c(const uLong *s_deflated, const uLong *s_inflated, const Byte deflated[], Byte inflated[]){
/* make writable copy, uncompress will write to it */ /* make writable copy, uncompress will write to it */
uLong s_inflated_,i; uLong s_inflated_,i;

View File

@ -69,8 +69,6 @@ subroutine DAMASK_interface_init
loadCaseArg = '', & !< -l argument given to the executable loadCaseArg = '', & !< -l argument given to the executable
geometryArg = '', & !< -g argument given to the executable geometryArg = '', & !< -g argument given to the executable
workingDirArg = '' !< -w argument given to the executable workingDirArg = '' !< -w argument given to the executable
character(len=pStringLen) :: &
userName !< name of user calling the executable
integer :: & integer :: &
stat, & stat, &
i i
@ -117,6 +115,9 @@ subroutine DAMASK_interface_init
print'(/,a)', ' Compiled on: '//__DATE__//' at '//__TIME__ print'(/,a)', ' Compiled on: '//__DATE__//' at '//__TIME__
print'(/,a,i0,a,i0,a,i0)', &
' PETSc version: ',PETSC_VERSION_MAJOR,'.',PETSC_VERSION_MINOR,'.',PETSC_VERSION_SUBMINOR
call date_and_time(values = dateAndTime) call date_and_time(values = dateAndTime)
print'(/,a,2(i2.2,a),i4.4)', ' Date: ',dateAndTime(3),'/',dateAndTime(2),'/', dateAndTime(1) print'(/,a,2(i2.2,a),i4.4)', ' Date: ',dateAndTime(3),'/',dateAndTime(2),'/', dateAndTime(1)
print'(a,2(i2.2,a),i2.2)', ' Time: ',dateAndTime(5),':', dateAndTime(6),':', dateAndTime(7) print'(a,2(i2.2,a),i2.2)', ' Time: ',dateAndTime(5),':', dateAndTime(6),':', dateAndTime(7)
@ -126,9 +127,9 @@ subroutine DAMASK_interface_init
if (err /= 0) call quit(1) if (err /= 0) call quit(1)
select case(trim(arg)) ! extract key select case(trim(arg)) ! extract key
case ('-h','--help') case ('-h','--help')
print'(a)', ' #######################################################################' print'(/,a)',' #######################################################################'
print'(a)', ' DAMASK Command Line Interface:' print'(a)', ' DAMASK Command Line Interface:'
print'(a)', ' For PETSc-based solvers for the Düsseldorf Advanced Material Simulation Kit' print'(a)', ' Düsseldorf Advanced Material Simulation Kit with PETSc-based solvers'
print'(a,/)',' #######################################################################' print'(a,/)',' #######################################################################'
print'(a,/)',' Valid command line switches:' print'(a,/)',' Valid command line switches:'
print'(a)', ' --geom (-g, --geometry)' print'(a)', ' --geom (-g, --geometry)'
@ -189,17 +190,15 @@ subroutine DAMASK_interface_init
interface_loadFile = getLoadCaseFile(loadCaseArg) interface_loadFile = getLoadCaseFile(loadCaseArg)
call get_command(commandLine) call get_command(commandLine)
call get_environment_variable('USER',userName) print'(/,a)', ' Host name: '//getHostName()
! ToDo: https://stackoverflow.com/questions/8953424/how-to-get-the-username-in-c-c-in-linux print'(a)', ' User name: '//getUserName()
print'(a)', ' Host name: '//trim(getHostName())
print'(a)', ' User name: '//trim(userName)
print'(/a)', ' Command line call: '//trim(commandLine) print'(/a)', ' Command line call: '//trim(commandLine)
if (len_trim(workingDirArg) > 0) & if (len_trim(workingDirArg) > 0) &
print'(a)', ' Working dir argument: '//trim(workingDirArg) print'(a)', ' Working dir argument: '//trim(workingDirArg)
print'(a)', ' Geometry argument: '//trim(geometryArg) print'(a)', ' Geometry argument: '//trim(geometryArg)
print'(a)', ' Load case argument: '//trim(loadcaseArg) print'(a)', ' Loadcase argument: '//trim(loadcaseArg)
print'(a)', ' Working directory: '//getCWD() print'(/,a)', ' Working directory: '//getCWD()
print'(a)', ' Geometry file: '//interface_geomFile print'(a)', ' Geometry file: '//interface_geomFile
print'(a)', ' Loadcase file: '//interface_loadFile print'(a)', ' Loadcase file: '//interface_loadFile
print'(a)', ' Solver job name: '//getSolverJobName() print'(a)', ' Solver job name: '//getSolverJobName()
@ -222,8 +221,8 @@ end subroutine DAMASK_interface_init
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
subroutine setWorkingDirectory(workingDirectoryArg) subroutine setWorkingDirectory(workingDirectoryArg)
character(len=*), intent(in) :: workingDirectoryArg !< working directory argument character(len=*), intent(in) :: workingDirectoryArg !< working directory argument
character(len=pPathLen) :: workingDirectory character(len=:), allocatable :: workingDirectory
logical :: error logical :: error
external :: quit external :: quit
@ -359,12 +358,12 @@ end function rectifyPath
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief relative path from absolute a to absolute b !> @brief Determine relative path from absolute a to absolute b
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
function makeRelativePath(a,b) function makeRelativePath(a,b)
character (len=*), intent(in) :: a,b character(len=*), intent(in) :: a,b
character (len=pPathLen) :: a_cleaned,b_cleaned character(len=pPathLen) :: a_cleaned,b_cleaned
character(len=:), allocatable :: makeRelativePath character(len=:), allocatable :: makeRelativePath
integer :: i,posLastCommonSlash,remainingSlashes integer :: i,posLastCommonSlash,remainingSlashes

View File

@ -217,7 +217,7 @@ module subroutine mech_init
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
elastic => mech%get('elasticity') elastic => mech%get('elasticity')
if(elastic%get_asString('type') == 'hooke') then if(elastic%get_asString('type') == 'hooke') then
phase_elasticity(p) = ELASTICITY_HOOKE_ID phase_elasticity(p) = ELASTICITY_HOOKE_ID
@ -234,7 +234,7 @@ module subroutine mech_init
if(maxVal(phase_NstiffnessDegradations)/=0) then if(maxVal(phase_NstiffnessDegradations)/=0) then
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
stiffDegradation => mech%get('stiffness_degradation',defaultVal=emptyList) stiffDegradation => mech%get('stiffness_degradation',defaultVal=emptyList)
do stiffDegradationCtr = 1, stiffDegradation%length do stiffDegradationCtr = 1, stiffDegradation%length
if(stiffDegradation%get_asString(stiffDegradationCtr) == 'damage') & if(stiffDegradation%get_asString(stiffDegradationCtr) == 'damage') &
@ -285,7 +285,7 @@ module function plastic_active(plastic_label) result(active_plastic)
allocate(active_plastic(phases%length), source = .false. ) allocate(active_plastic(phases%length), source = .false. )
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
pl => mech%get('plasticity') pl => mech%get('plasticity')
if(pl%get_asString('type') == plastic_label) active_plastic(p) = .true. if(pl%get_asString('type') == plastic_label) active_plastic(p) = .true.
enddo enddo

View File

@ -116,7 +116,7 @@ module function plastic_disloTungsten_init() result(myPlasticity)
i = 0 i = 0
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
if(.not. myPlasticity(p)) cycle if(.not. myPlasticity(p)) cycle
i = i + 1 i = i + 1
associate(prm => param(i), & associate(prm => param(i), &

View File

@ -169,7 +169,7 @@ module function plastic_dislotwin_init() result(myPlasticity)
i = 0 i = 0
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
if(.not. myPlasticity(p)) cycle if(.not. myPlasticity(p)) cycle
i = i + 1 i = i + 1
associate(prm => param(i), & associate(prm => param(i), &

View File

@ -86,7 +86,7 @@ module function plastic_isotropic_init() result(myPlasticity)
i = 0 i = 0
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
if(.not. myPlasticity(p)) cycle if(.not. myPlasticity(p)) cycle
i = i + 1 i = i + 1
associate(prm => param(i), & associate(prm => param(i), &

View File

@ -96,7 +96,7 @@ module function plastic_kinehardening_init() result(myPlasticity)
i = 0 i = 0
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
if(.not. myPlasticity(p)) cycle if(.not. myPlasticity(p)) cycle
i = i + 1 i = i + 1
associate(prm => param(i), & associate(prm => param(i), &

View File

@ -31,7 +31,7 @@ module function plastic_none_init() result(myPlasticity)
allocate(myPlasticity(phases%length), source = .false.) allocate(myPlasticity(phases%length), source = .false.)
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
pl => mech%get ('plasticity') pl => mech%get ('plasticity')
if(pl%get_asString('type') == 'none') myPlasticity(p) = .true. if(pl%get_asString('type') == 'none') myPlasticity(p) = .true.
enddo enddo

View File

@ -213,7 +213,7 @@ module function plastic_nonlocal_init() result(myPlasticity)
i = 0 i = 0
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
if(.not. myPlasticity(p)) cycle if(.not. myPlasticity(p)) cycle
i = i + 1 i = i + 1
associate(prm => param(i), & associate(prm => param(i), &

View File

@ -104,7 +104,7 @@ module function plastic_phenopowerlaw_init() result(myPlasticity)
i = 0 i = 0
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
if(.not. myPlasticity(p)) cycle if(.not. myPlasticity(p)) cycle
i = i + 1 i = i + 1
associate(prm => param(i), & associate(prm => param(i), &

View File

@ -240,7 +240,7 @@ subroutine crystallite_init
allocate(output_constituent(phases%length)) allocate(output_constituent(phases%length))
do c = 1, phases%length do c = 1, phases%length
phase => phases%get(c) phase => phases%get(c)
mech => phase%get('mech',defaultVal = emptyDict) mech => phase%get('mechanics',defaultVal = emptyDict)
#if defined(__GFORTRAN__) #if defined(__GFORTRAN__)
output_constituent(c)%label = output_asStrings(mech) output_constituent(c)%label = output_asStrings(mech)
#else #else
@ -739,7 +739,7 @@ subroutine crystallite_results
character(len=:), allocatable :: group,structureLabel character(len=:), allocatable :: group,structureLabel
do p=1,size(material_name_phase) do p=1,size(material_name_phase)
group = trim('current/constituent')//'/'//trim(material_name_phase(p))//'/generic' group = trim('current/constituent')//'/'//trim(material_name_phase(p))//'/mechanics'
call results_closeGroup(results_addGroup(group)) call results_closeGroup(results_addGroup(group))

View File

@ -176,7 +176,7 @@ program DAMASK_grid
load_step => load_steps%get(l) load_step => load_steps%get(l)
step_mech => load_step%get('mech') step_mech => load_step%get('mechanics')
loadCases(l)%stress%myType='P' loadCases(l)%stress%myType='P'
readMech: do m = 1, step_mech%length readMech: do m = 1, step_mech%length
select case (step_mech%getKey(m)) select case (step_mech%getKey(m))

View File

@ -56,25 +56,33 @@ subroutine discretization_grid_init(restart)
myGrid !< domain grid of this process myGrid !< domain grid of this process
integer, dimension(:), allocatable :: & integer, dimension(:), allocatable :: &
materialAt materialAt, materialAt_global
integer :: & integer :: &
j, & j, &
debug_element, & debug_element, debug_ip, &
debug_ip ierr
integer(C_INTPTR_T) :: & integer(C_INTPTR_T) :: &
devNull, z, z_offset devNull, z, z_offset
integer, dimension(worldsize) :: &
displs, sendcounts
print'(/,a)', ' <<<+- discretization_grid init -+>>>'; flush(IO_STDOUT) print'(/,a)', ' <<<+- discretization_grid init -+>>>'; flush(IO_STDOUT)
call readVTR(grid,geomSize,origin,materialAt) if(worldrank == 0) call readVTR(grid,geomSize,origin,materialAt_global)
call MPI_Bcast(grid,3,MPI_INTEGER,0,PETSC_COMM_WORLD, ierr)
if (ierr /= 0) error stop 'MPI error'
call MPI_Bcast(geomSize,3,MPI_DOUBLE,0,PETSC_COMM_WORLD, ierr)
if (ierr /= 0) error stop 'MPI error'
call MPI_Bcast(origin,3,MPI_DOUBLE,0,PETSC_COMM_WORLD, ierr)
if (ierr /= 0) error stop 'MPI error'
print'(/,a,3(i12 ))', ' grid a b c: ', grid print'(/,a,3(i12 ))', ' grid a b c: ', grid
print'(a,3(es12.5))', ' size x y z: ', geomSize print'(a,3(es12.5))', ' size x y z: ', geomSize
print'(a,3(es12.5))', ' origin x y z: ', origin print'(a,3(es12.5))', ' origin x y z: ', origin
!--------------------------------------------------------------------------------------------------
! grid solver specific quantities
if(worldsize>grid(3)) call IO_error(894, ext_msg='number of processes exceeds grid(3)') if(worldsize>grid(3)) call IO_error(894, ext_msg='number of processes exceeds grid(3)')
call fftw_mpi_init call fftw_mpi_init
@ -93,14 +101,14 @@ subroutine discretization_grid_init(restart)
myGrid = [grid(1:2),grid3] myGrid = [grid(1:2),grid3]
mySize = [geomSize(1:2),size3] mySize = [geomSize(1:2),size3]
!------------------------------------------------------------------------------------------------- call MPI_Gather(product(grid(1:2))*grid3Offset,1,MPI_INTEGER,displs, 1,MPI_INTEGER,0,PETSC_COMM_WORLD,ierr)
! debug parameters if (ierr /= 0) error stop 'MPI error'
debug_element = config_debug%get_asInt('element',defaultVal=1) call MPI_Gather(product(myGrid), 1,MPI_INTEGER,sendcounts,1,MPI_INTEGER,0,PETSC_COMM_WORLD,ierr)
debug_ip = config_debug%get_asInt('integrationpoint',defaultVal=1) if (ierr /= 0) error stop 'MPI error'
!-------------------------------------------------------------------------------------------------- allocate(materialAt(product(myGrid)))
! general discretization call MPI_scatterv(materialAt_global,sendcounts,displs,MPI_INTEGER,materialAt,size(materialAt),MPI_INTEGER,0,PETSC_COMM_WORLD,ierr)
materialAt = materialAt(product(grid(1:2))*grid3Offset+1:product(grid(1:2))*(grid3Offset+grid3)) ! reallocate/shrink in case of MPI if (ierr /= 0) error stop 'MPI error'
call discretization_init(materialAt, & call discretization_init(materialAt, &
IPcoordinates0(myGrid,mySize,grid3Offset), & IPcoordinates0(myGrid,mySize,grid3Offset), &
@ -131,10 +139,12 @@ subroutine discretization_grid_init(restart)
call geometry_plastic_nonlocal_setIPareaNormal (cellSurfaceNormal(product(myGrid))) call geometry_plastic_nonlocal_setIPareaNormal (cellSurfaceNormal(product(myGrid)))
call geometry_plastic_nonlocal_setIPneighborhood(IPneighborhood(myGrid)) call geometry_plastic_nonlocal_setIPneighborhood(IPneighborhood(myGrid))
!-------------------------------------------------------------------------------------------------- !-------------------------------------------------------------------------------------------------
! sanity checks for debugging ! debug parameters
if (debug_element < 1 .or. debug_element > product(myGrid)) call IO_error(602,ext_msg='element') ! selected element does not exist debug_element = config_debug%get_asInt('element',defaultVal=1)
if (debug_ip /= 1) call IO_error(602,ext_msg='IP') ! selected IP does not exist if (debug_element < 1 .or. debug_element > product(myGrid)) call IO_error(602,ext_msg='element')
debug_ip = config_debug%get_asInt('integrationpoint',defaultVal=1)
if (debug_ip /= 1) call IO_error(602,ext_msg='IP')
end subroutine discretization_grid_init end subroutine discretization_grid_init

View File

@ -498,7 +498,7 @@ subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dumm
err_div/divTol, ' (',err_div, ' / m, tol = ',divTol,')' err_div/divTol, ' (',err_div, ' / m, tol = ',divTol,')'
print '(a,f12.2,a,es8.2,a,es9.2,a)', ' error curl = ', & print '(a,f12.2,a,es8.2,a,es9.2,a)', ' error curl = ', &
err_curl/curlTol,' (',err_curl,' -, tol = ',curlTol,')' err_curl/curlTol,' (',err_curl,' -, tol = ',curlTol,')'
print '(a,f12.2,a,es8.2,a,es9.2,a)', ' error stress BC = ', & print '(a,f12.2,a,es8.2,a,es9.2,a)', ' error stress BC = ', &
err_BC/BCTol, ' (',err_BC, ' Pa, tol = ',BCTol,')' err_BC/BCTol, ' (',err_BC, ' Pa, tol = ',BCTol,')'
print'(/,a)', ' ===========================================================================' print'(/,a)', ' ==========================================================================='
flush(IO_STDOUT) flush(IO_STDOUT)

View File

@ -993,12 +993,11 @@ subroutine utilities_updateCoords(F)
real(pReal), dimension(3, grid(1)+1,grid(2)+1,grid3+1) :: nodeCoords real(pReal), dimension(3, grid(1)+1,grid(2)+1,grid3+1) :: nodeCoords
integer :: & integer :: &
i,j,k,n, & i,j,k,n, &
rank_t, & rank_t, rank_b, &
rank_b, & c, &
c, r, &
ierr ierr
integer, dimension(MPI_STATUS_SIZE) :: & integer, dimension(4) :: request
s integer, dimension(MPI_STATUS_SIZE,4) :: status
real(pReal), dimension(3) :: step real(pReal), dimension(3) :: step
real(pReal), dimension(3,3) :: Favg real(pReal), dimension(3,3) :: Favg
integer, dimension(3) :: me integer, dimension(3) :: me
@ -1044,20 +1043,20 @@ subroutine utilities_updateCoords(F)
rank_b = modulo(worldrank-1,worldsize) rank_b = modulo(worldrank-1,worldsize)
! send bottom layer to process below ! send bottom layer to process below
call MPI_Isend(IPfluct_padded(:,:,:,2), c,MPI_DOUBLE,rank_b,0,PETSC_COMM_WORLD,r,ierr) call MPI_Isend(IPfluct_padded(:,:,:,2), c,MPI_DOUBLE,rank_b,0,PETSC_COMM_WORLD,request(1),ierr)
if(ierr /=0) error stop 'MPI error' if(ierr /=0) error stop 'MPI error'
call MPI_Irecv(IPfluct_padded(:,:,:,grid3+2),c,MPI_DOUBLE,rank_t,0,PETSC_COMM_WORLD,r,ierr) call MPI_Irecv(IPfluct_padded(:,:,:,grid3+2),c,MPI_DOUBLE,rank_t,0,PETSC_COMM_WORLD,request(2),ierr)
if(ierr /=0) error stop 'MPI error'
call MPI_Wait(r,s,ierr)
if(ierr /=0) error stop 'MPI error' if(ierr /=0) error stop 'MPI error'
! send top layer to process above ! send top layer to process above
call MPI_Isend(IPfluct_padded(:,:,:,grid3+1),c,MPI_DOUBLE,rank_t,0,PETSC_COMM_WORLD,r,ierr) call MPI_Isend(IPfluct_padded(:,:,:,grid3+1),c,MPI_DOUBLE,rank_t,1,PETSC_COMM_WORLD,request(3),ierr)
if(ierr /=0) error stop 'MPI error' if(ierr /=0) error stop 'MPI error'
call MPI_Irecv(IPfluct_padded(:,:,:,1), c,MPI_DOUBLE,rank_b,0,PETSC_COMM_WORLD,r,ierr) call MPI_Irecv(IPfluct_padded(:,:,:,1), c,MPI_DOUBLE,rank_b,1,PETSC_COMM_WORLD,request(4),ierr)
if(ierr /=0) error stop 'MPI error' if(ierr /=0) error stop 'MPI error'
call MPI_Wait(r,s,ierr)
call MPI_Waitall(4,request,status,ierr)
if(ierr /=0) error stop 'MPI error' if(ierr /=0) error stop 'MPI error'
if(any(status(MPI_ERROR,:) /= 0)) error stop 'MPI error'
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! calculate nodal displacements ! calculate nodal displacements

View File

@ -145,7 +145,7 @@ module subroutine mech_RGC_init(num_homogMech)
do h = 1, size(homogenization_type) do h = 1, size(homogenization_type)
if (homogenization_type(h) /= HOMOGENIZATION_RGC_ID) cycle if (homogenization_type(h) /= HOMOGENIZATION_RGC_ID) cycle
homog => material_homogenization%get(h) homog => material_homogenization%get(h)
homogMech => homog%get('mech') homogMech => homog%get('mechanics')
associate(prm => param(homogenization_typeInstance(h)), & associate(prm => param(homogenization_typeInstance(h)), &
stt => state(homogenization_typeInstance(h)), & stt => state(homogenization_typeInstance(h)), &
st0 => state0(homogenization_typeInstance(h)), & st0 => state0(homogenization_typeInstance(h)), &

View File

@ -48,7 +48,7 @@ module subroutine mech_isostrain_init
do h = 1, size(homogenization_type) do h = 1, size(homogenization_type)
if (homogenization_type(h) /= HOMOGENIZATION_ISOSTRAIN_ID) cycle if (homogenization_type(h) /= HOMOGENIZATION_ISOSTRAIN_ID) cycle
homog => material_homogenization%get(h) homog => material_homogenization%get(h)
homogMech => homog%get('mech') homogMech => homog%get('mechanics')
associate(prm => param(homogenization_typeInstance(h))) associate(prm => param(homogenization_typeInstance(h)))
prm%N_constituents = homogenization_Nconstituents(h) prm%N_constituents = homogenization_Nconstituents(h)

View File

@ -63,7 +63,7 @@ module function kinematics_slipplane_opening_init(kinematics_length) result(myKi
do p = 1, phases%length do p = 1, phases%length
if(any(myKinematics(:,p))) kinematics_slipplane_opening_instance(p) = count(myKinematics(:,1:p)) if(any(myKinematics(:,p))) kinematics_slipplane_opening_instance(p) = count(myKinematics(:,1:p))
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
pl => mech%get('plasticity') pl => mech%get('plasticity')
if(count(myKinematics(:,p)) == 0) cycle if(count(myKinematics(:,p)) == 0) cycle
kinematics => phase%get('kinematics') kinematics => phase%get('kinematics')

View File

@ -476,7 +476,7 @@ subroutine lattice_init
do p = 1, phases%length do p = 1, phases%length
phase => phases%get(p) phase => phases%get(p)
mech => phase%get('mech') mech => phase%get('mechanics')
elasticity => mech%get('elasticity') elasticity => mech%get('elasticity')
lattice_C66(1,1,p) = elasticity%get_asFloat('C_11') lattice_C66(1,1,p) = elasticity%get_asFloat('C_11')
lattice_C66(1,2,p) = elasticity%get_asFloat('C_12') lattice_C66(1,2,p) = elasticity%get_asFloat('C_12')

View File

@ -226,7 +226,7 @@ subroutine material_parseHomogenization
do h=1, size(material_name_homogenization) do h=1, size(material_name_homogenization)
homog => material_homogenization%get(h) homog => material_homogenization%get(h)
homogMech => homog%get('mech') homogMech => homog%get('mechanics')
select case (homogMech%get_asString('type')) select case (homogMech%get_asString('type'))
case('none') case('none')
homogenization_type(h) = HOMOGENIZATION_NONE_ID homogenization_type(h) = HOMOGENIZATION_NONE_ID

View File

@ -20,7 +20,7 @@ program DAMASK_mesh
use discretization_mesh use discretization_mesh
use FEM_Utilities use FEM_Utilities
use mesh_mech_FEM use mesh_mech_FEM
implicit none implicit none
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
@ -56,7 +56,7 @@ program DAMASK_mesh
totalIncsCounter = 0, & !< total # of increments totalIncsCounter = 0, & !< total # of increments
statUnit = 0, & !< file unit for statistics output statUnit = 0, & !< file unit for statistics output
stagIter, & stagIter, &
component component
class(tNode), pointer :: & class(tNode), pointer :: &
num_mesh num_mesh
character(len=pStringLen), dimension(:), allocatable :: fileContent character(len=pStringLen), dimension(:), allocatable :: fileContent
@ -80,7 +80,7 @@ program DAMASK_mesh
call CPFEM_initAll call CPFEM_initAll
print'(/,a)', ' <<<+- DAMASK_mesh init -+>>>'; flush(IO_STDOUT) print'(/,a)', ' <<<+- DAMASK_mesh init -+>>>'; flush(IO_STDOUT)
!--------------------------------------------------------------------- !---------------------------------------------------------------------
! reading field information from numerics file and do sanity checks ! reading field information from numerics file and do sanity checks
num_mesh => config_numerics%get('mesh', defaultVal=emptyDict) num_mesh => config_numerics%get('mesh', defaultVal=emptyDict)
stagItMax = num_mesh%get_asInt('maxStaggeredIter',defaultVal=10) stagItMax = num_mesh%get_asInt('maxStaggeredIter',defaultVal=10)
@ -100,7 +100,7 @@ program DAMASK_mesh
do l = 1, size(fileContent) do l = 1, size(fileContent)
line = fileContent(l) line = fileContent(l)
if (IO_isBlank(line)) cycle ! skip empty lines if (IO_isBlank(line)) cycle ! skip empty lines
chunkPos = IO_stringPos(line) chunkPos = IO_stringPos(line)
do i = 1, chunkPos(1) ! reading compulsory parameters for loadcase do i = 1, chunkPos(1) ! reading compulsory parameters for loadcase
select case (IO_lc(IO_stringValue(line,chunkPos,i))) select case (IO_lc(IO_stringValue(line,chunkPos,i)))
@ -109,15 +109,16 @@ program DAMASK_mesh
end select end select
enddo ! count all identifiers to allocate memory and do sanity check enddo ! count all identifiers to allocate memory and do sanity check
enddo enddo
allocate (loadCases(N_def)) if(N_def < 1) call IO_error(error_ID = 837)
allocate(loadCases(N_def))
do i = 1, size(loadCases) do i = 1, size(loadCases)
allocate(loadCases(i)%fieldBC(nActiveFields)) allocate(loadCases(i)%fieldBC(nActiveFields))
field = 1 field = 1
loadCases(i)%fieldBC(field)%ID = FIELD_MECH_ID loadCases(i)%fieldBC(field)%ID = FIELD_MECH_ID
enddo enddo
do i = 1, size(loadCases) do i = 1, size(loadCases)
do field = 1, nActiveFields do field = 1, nActiveFields
select case (loadCases(i)%fieldBC(field)%ID) select case (loadCases(i)%fieldBC(field)%ID)
@ -133,21 +134,21 @@ program DAMASK_mesh
case (3) case (3)
loadCases(i)%fieldBC(field)%componentBC(component)%ID = COMPONENT_MECH_Z_ID loadCases(i)%fieldBC(field)%componentBC(component)%ID = COMPONENT_MECH_Z_ID
end select end select
enddo enddo
end select end select
do component = 1, loadCases(i)%fieldBC(field)%nComponents do component = 1, loadCases(i)%fieldBC(field)%nComponents
allocate(loadCases(i)%fieldBC(field)%componentBC(component)%Value(mesh_Nboundaries), source = 0.0_pReal) allocate(loadCases(i)%fieldBC(field)%componentBC(component)%Value(mesh_Nboundaries), source = 0.0_pReal)
allocate(loadCases(i)%fieldBC(field)%componentBC(component)%Mask (mesh_Nboundaries), source = .false.) allocate(loadCases(i)%fieldBC(field)%componentBC(component)%Mask (mesh_Nboundaries), source = .false.)
enddo enddo
enddo enddo
enddo enddo
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! reading the load case and assign values to the allocated data structure ! reading the load case and assign values to the allocated data structure
do l = 1, size(fileContent) do l = 1, size(fileContent)
line = fileContent(l) line = fileContent(l)
if (IO_isBlank(line)) cycle ! skip empty lines if (IO_isBlank(line)) cycle ! skip empty lines
chunkPos = IO_stringPos(line) chunkPos = IO_stringPos(line)
do i = 1, chunkPos(1) do i = 1, chunkPos(1)
select case (IO_lc(IO_stringValue(line,chunkPos,i))) select case (IO_lc(IO_stringValue(line,chunkPos,i)))
@ -161,7 +162,7 @@ program DAMASK_mesh
do faceSet = 1, mesh_Nboundaries do faceSet = 1, mesh_Nboundaries
if (mesh_boundaries(faceSet) == currentFace) currentFaceSet = faceSet if (mesh_boundaries(faceSet) == currentFace) currentFaceSet = faceSet
enddo enddo
if (currentFaceSet < 0) call IO_error(error_ID = errorID, ext_msg = 'invalid BC') if (currentFaceSet < 0) call IO_error(error_ID = 837, ext_msg = 'invalid BC')
case('t','time','delta') ! increment time case('t','time','delta') ! increment time
loadCases(currentLoadCase)%time = IO_floatValue(line,chunkPos,i+1) loadCases(currentLoadCase)%time = IO_floatValue(line,chunkPos,i+1)
case('n','incs','increments','steps') ! number of increments case('n','incs','increments','steps') ! number of increments
@ -170,7 +171,7 @@ program DAMASK_mesh
loadCases(currentLoadCase)%incs = IO_intValue(line,chunkPos,i+1) loadCases(currentLoadCase)%incs = IO_intValue(line,chunkPos,i+1)
loadCases(currentLoadCase)%logscale = 1 loadCases(currentLoadCase)%logscale = 1
case('freq','frequency','outputfreq') ! frequency of result writings case('freq','frequency','outputfreq') ! frequency of result writings
loadCases(currentLoadCase)%outputfrequency = IO_intValue(line,chunkPos,i+1) loadCases(currentLoadCase)%outputfrequency = IO_intValue(line,chunkPos,i+1)
case('guessreset','dropguessing') case('guessreset','dropguessing')
loadCases(currentLoadCase)%followFormerTrajectory = .false. ! do not continue to predict deformation along former trajectory loadCases(currentLoadCase)%followFormerTrajectory = .false. ! do not continue to predict deformation along former trajectory
@ -185,7 +186,7 @@ program DAMASK_mesh
case('z') case('z')
ID = COMPONENT_MECH_Z_ID ID = COMPONENT_MECH_Z_ID
end select end select
do field = 1, nActiveFields do field = 1, nActiveFields
if (loadCases(currentLoadCase)%fieldBC(field)%ID == FIELD_MECH_ID) then if (loadCases(currentLoadCase)%fieldBC(field)%ID == FIELD_MECH_ID) then
do component = 1, loadcases(currentLoadCase)%fieldBC(field)%nComponents do component = 1, loadcases(currentLoadCase)%fieldBC(field)%nComponents
@ -197,11 +198,11 @@ program DAMASK_mesh
endif endif
enddo enddo
endif endif
enddo enddo
end select end select
enddo enddo
enddo enddo
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! consistency checks and output of load case ! consistency checks and output of load case
loadCases(1)%followFormerTrajectory = .false. ! cannot guess along trajectory for first inc of first currentLoadCase loadCases(1)%followFormerTrajectory = .false. ! cannot guess along trajectory for first inc of first currentLoadCase
@ -215,17 +216,17 @@ program DAMASK_mesh
select case (loadCases(currentLoadCase)%fieldBC(field)%ID) select case (loadCases(currentLoadCase)%fieldBC(field)%ID)
case(FIELD_MECH_ID) case(FIELD_MECH_ID)
print'(a)', ' Field '//trim(FIELD_MECH_label) print'(a)', ' Field '//trim(FIELD_MECH_label)
end select end select
do faceSet = 1, mesh_Nboundaries do faceSet = 1, mesh_Nboundaries
do component = 1, loadCases(currentLoadCase)%fieldBC(field)%nComponents do component = 1, loadCases(currentLoadCase)%fieldBC(field)%nComponents
if (loadCases(currentLoadCase)%fieldBC(field)%componentBC(component)%Mask(faceSet)) & if (loadCases(currentLoadCase)%fieldBC(field)%componentBC(component)%Mask(faceSet)) &
print'(a,i2,a,i2,a,f12.7)', ' Face ', mesh_boundaries(faceSet), & print'(a,i2,a,i2,a,f12.7)', ' Face ', mesh_boundaries(faceSet), &
' Component ', component, & ' Component ', component, &
' Value ', loadCases(currentLoadCase)%fieldBC(field)% & ' Value ', loadCases(currentLoadCase)%fieldBC(field)% &
componentBC(component)%Value(faceSet) componentBC(component)%Value(faceSet)
enddo enddo
enddo enddo
enddo enddo
print'(a,f12.6)', ' time: ', loadCases(currentLoadCase)%time print'(a,f12.6)', ' time: ', loadCases(currentLoadCase)%time
if (loadCases(currentLoadCase)%incs < 1) errorID = 835 ! non-positive incs count if (loadCases(currentLoadCase)%incs < 1) errorID = 835 ! non-positive incs count
@ -244,7 +245,7 @@ program DAMASK_mesh
case(FIELD_MECH_ID) case(FIELD_MECH_ID)
call FEM_mech_init(loadCases(1)%fieldBC(field)) call FEM_mech_init(loadCases(1)%fieldBC(field))
end select end select
enddo enddo
if (worldrank == 0) then if (worldrank == 0) then
open(newunit=statUnit,file=trim(getSolverJobName())//'.sta',form='FORMATTED',status='REPLACE') open(newunit=statUnit,file=trim(getSolverJobName())//'.sta',form='FORMATTED',status='REPLACE')
@ -254,9 +255,9 @@ program DAMASK_mesh
loadCaseLooping: do currentLoadCase = 1, size(loadCases) loadCaseLooping: do currentLoadCase = 1, size(loadCases)
time0 = time ! load case start time time0 = time ! load case start time
guess = loadCases(currentLoadCase)%followFormerTrajectory ! change of load case? homogeneous guess for the first inc guess = loadCases(currentLoadCase)%followFormerTrajectory ! change of load case? homogeneous guess for the first inc
incLooping: do inc = 1, loadCases(currentLoadCase)%incs incLooping: do inc = 1, loadCases(currentLoadCase)%incs
totalIncsCounter = totalIncsCounter + 1 totalIncsCounter = totalIncsCounter + 1
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! forwarding time ! forwarding time
@ -266,7 +267,7 @@ program DAMASK_mesh
else else
if (currentLoadCase == 1) then ! 1st load case of logarithmic scale if (currentLoadCase == 1) then ! 1st load case of logarithmic scale
if (inc == 1) then ! 1st inc of 1st load case of logarithmic scale if (inc == 1) then ! 1st inc of 1st load case of logarithmic scale
timeinc = loadCases(1)%time*(2.0_pReal**real( 1-loadCases(1)%incs ,pReal)) ! assume 1st inc is equal to 2nd timeinc = loadCases(1)%time*(2.0_pReal**real( 1-loadCases(1)%incs ,pReal)) ! assume 1st inc is equal to 2nd
else ! not-1st inc of 1st load case of logarithmic scale else ! not-1st inc of 1st load case of logarithmic scale
timeinc = loadCases(1)%time*(2.0_pReal**real(inc-1-loadCases(1)%incs ,pReal)) timeinc = loadCases(1)%time*(2.0_pReal**real(inc-1-loadCases(1)%incs ,pReal))
endif endif
@ -287,7 +288,7 @@ program DAMASK_mesh
remainingLoadCaseTime = loadCases(currentLoadCase)%time+time0 - time remainingLoadCaseTime = loadCases(currentLoadCase)%time+time0 - time
time = time + timeinc ! forward target time time = time + timeinc ! forward target time
stepFraction = stepFraction + 1 ! count step stepFraction = stepFraction + 1 ! count step
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! report begin of new step ! report begin of new step
print'(/,a)', ' ###########################################################################' print'(/,a)', ' ###########################################################################'
@ -310,8 +311,8 @@ program DAMASK_mesh
guess,timeinc,timeIncOld,loadCases(currentLoadCase)%fieldBC(field)) guess,timeinc,timeIncOld,loadCases(currentLoadCase)%fieldBC(field))
end select end select
enddo enddo
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! solve fields ! solve fields
stagIter = 0 stagIter = 0
@ -332,10 +333,10 @@ program DAMASK_mesh
stagIterate = stagIter < stagItMax & stagIterate = stagIter < stagItMax &
.and. all(solres(:)%converged) & .and. all(solres(:)%converged) &
.and. .not. all(solres(:)%stagConverged) ! stationary with respect to staggered iteration .and. .not. all(solres(:)%stagConverged) ! stationary with respect to staggered iteration
enddo enddo
! check solution ! check solution
cutBack = .False. cutBack = .False.
if(.not. all(solres(:)%converged .and. solres(:)%stagConverged)) then ! no solution found if(.not. all(solres(:)%converged .and. solres(:)%stagConverged)) then ! no solution found
if (cutBackLevel < maxCutBack) then ! do cut back if (cutBackLevel < maxCutBack) then ! do cut back
print'(/,a)', ' cut back detected' print'(/,a)', ' cut back detected'
@ -344,7 +345,7 @@ program DAMASK_mesh
cutBackLevel = cutBackLevel + 1 cutBackLevel = cutBackLevel + 1
time = time - timeinc ! rewind time time = time - timeinc ! rewind time
timeinc = timeinc/2.0_pReal timeinc = timeinc/2.0_pReal
else ! default behavior, exit if spectral solver does not converge else ! default behavior, exit if spectral solver does not converge
call IO_warning(850) call IO_warning(850)
call quit(1) ! quit call quit(1) ! quit
endif endif
@ -374,8 +375,8 @@ program DAMASK_mesh
enddo incLooping enddo incLooping
enddo loadCaseLooping enddo loadCaseLooping
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! report summary of whole calculation ! report summary of whole calculation
print'(/,a)', ' ###########################################################################' print'(/,a)', ' ###########################################################################'

View File

@ -17,6 +17,7 @@ module discretization_mesh
use IO use IO
use config use config
use discretization use discretization
use results
use FEsolving use FEsolving
use FEM_quadrature use FEM_quadrature
use YAML_types use YAML_types
@ -182,6 +183,10 @@ subroutine discretization_mesh_init(restart)
reshape(mesh_ipCoordinates,[3,mesh_maxNips*mesh_NcpElems]), & reshape(mesh_ipCoordinates,[3,mesh_maxNips*mesh_NcpElems]), &
mesh_node0) mesh_node0)
call results_openJobFile
call results_closeGroup(results_addGroup('geometry'))
call results_closeJobFile
end subroutine discretization_mesh_init end subroutine discretization_mesh_init

View File

@ -60,7 +60,7 @@ module function source_damage_anisoDuctile_init(source_length) result(mySources)
phase => phases%get(p) phase => phases%get(p)
if(any(mySources(:,p))) source_damage_anisoDuctile_instance(p) = count(mySources(:,1:p)) if(any(mySources(:,p))) source_damage_anisoDuctile_instance(p) = count(mySources(:,1:p))
if(count(mySources(:,p)) == 0) cycle if(count(mySources(:,p)) == 0) cycle
mech => phase%get('mech') mech => phase%get('mechanics')
pl => mech%get('plasticity') pl => mech%get('plasticity')
sources => phase%get('source') sources => phase%get('source')
do sourceOffset = 1, sources%length do sourceOffset = 1, sources%length

View File

@ -8,79 +8,65 @@ module system_routines
use prec use prec
implicit none implicit none
private
public :: & public :: &
signalterm_C, & setCWD, &
signalusr1_C, &
signalusr2_C, &
isDirectory, &
getCWD, & getCWD, &
getHostName, & getHostName, &
setCWD getUserName, &
signalterm_C, &
signalusr1_C, &
signalusr2_C
interface interface
function isDirectory_C(path) bind(C) function setCWD_C(cwd) bind(C)
use, intrinsic :: ISO_C_Binding, only: & use, intrinsic :: ISO_C_Binding, only: C_INT, C_CHAR
C_INT, &
C_CHAR integer(C_INT) :: setCWD_C
character(kind=C_CHAR), dimension(*), intent(in) :: cwd
end function setCWD_C
subroutine getCWD_C(cwd, stat) bind(C)
use, intrinsic :: ISO_C_Binding, only: C_INT, C_CHAR
use prec use prec
integer(C_INT) :: isDirectory_C character(kind=C_CHAR), dimension(pPathLen+1), intent(out) :: cwd ! NULL-terminated array
character(kind=C_CHAR), dimension(pPathLen), intent(in) :: path ! C string is an array
end function isDirectory_C
subroutine getCurrentWorkDir_C(path, stat) bind(C)
use, intrinsic :: ISO_C_Binding, only: &
C_INT, &
C_CHAR
use prec
character(kind=C_CHAR), dimension(pPathLen), intent(out) :: path ! C string is an array
integer(C_INT), intent(out) :: stat
end subroutine getCurrentWorkDir_C
subroutine getHostName_C(str, stat) bind(C)
use, intrinsic :: ISO_C_Binding, only: &
C_INT, &
C_CHAR
use prec
character(kind=C_CHAR), dimension(pStringLen), intent(out) :: str ! C string is an array
integer(C_INT), intent(out) :: stat integer(C_INT), intent(out) :: stat
end subroutine getCWD_C
subroutine getHostName_C(hostname, stat) bind(C)
use, intrinsic :: ISO_C_Binding, only: C_INT, C_CHAR
use prec
character(kind=C_CHAR), dimension(pStringLen+1), intent(out) :: hostname ! NULL-terminated array
integer(C_INT), intent(out) :: stat
end subroutine getHostName_C end subroutine getHostName_C
function chdir_C(path) bind(C) subroutine getUserName_C(username, stat) bind(C)
use, intrinsic :: ISO_C_Binding, only: & use, intrinsic :: ISO_C_Binding, only: C_INT, C_CHAR
C_INT, &
C_CHAR
use prec use prec
integer(C_INT) :: chdir_C character(kind=C_CHAR), dimension(pStringLen+1), intent(out) :: username ! NULL-terminated array
character(kind=C_CHAR), dimension(pPathLen), intent(in) :: path ! C string is an array integer(C_INT), intent(out) :: stat
end function chdir_C end subroutine getUserName_C
subroutine signalterm_C(handler) bind(C) subroutine signalterm_C(handler) bind(C)
use, intrinsic :: ISO_C_Binding, only: & use, intrinsic :: ISO_C_Binding, only: C_FUNPTR
C_FUNPTR
type(C_FUNPTR), intent(in), value :: handler type(C_FUNPTR), intent(in), value :: handler
end subroutine signalterm_C end subroutine signalterm_C
subroutine signalusr1_C(handler) bind(C) subroutine signalusr1_C(handler) bind(C)
use, intrinsic :: ISO_C_Binding, only: & use, intrinsic :: ISO_C_Binding, only: C_FUNPTR
C_FUNPTR
type(C_FUNPTR), intent(in), value :: handler type(C_FUNPTR), intent(in), value :: handler
end subroutine signalusr1_C end subroutine signalusr1_C
subroutine signalusr2_C(handler) bind(C) subroutine signalusr2_C(handler) bind(C)
use, intrinsic :: ISO_C_Binding, only: & use, intrinsic :: ISO_C_Binding, only: C_FUNPTR
C_FUNPTR
type(C_FUNPTR), intent(in), value :: handler type(C_FUNPTR), intent(in), value :: handler
end subroutine signalusr2_C end subroutine signalusr2_C
@ -89,45 +75,48 @@ module system_routines
contains contains
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief figures out if a given path is a directory (and not an ordinary file) !> @brief set the current working directory
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
logical function isDirectory(path) logical function setCWD(path)
character(len=*), intent(in) :: path character(len=*), intent(in) :: path
isDirectory=merge(.True.,.False.,isDirectory_C(f_c_string(path)) /= 0_C_INT)
end function isDirectory setCWD=merge(.True.,.False.,setCWD_C(f_c_string(path)) /= 0_C_INT)
end function setCWD
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief gets the current working directory !> @brief get the current working directory
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
function getCWD() function getCWD()
character(kind=C_CHAR), dimension(pPathLen) :: getCWD_Cstring character(len=:), allocatable :: getCWD
character(len=:), allocatable :: getCWD
character(kind=C_CHAR), dimension(pPathLen+1) :: getCWD_Cstring
integer(C_INT) :: stat integer(C_INT) :: stat
call getCurrentWorkDir_C(getCWD_Cstring,stat) call getCWD_C(getCWD_Cstring,stat)
if(stat == 0) then if(stat == 0) then
getCWD = c_f_string(getCWD_Cstring) getCWD = c_f_string(getCWD_Cstring)
else else
getCWD = 'Error occured when getting currend working directory' error stop 'invalid working directory'
endif endif
end function getCWD end function getCWD
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief gets the current host name !> @brief get the host name
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
function getHostName() function getHostName()
character(kind=C_CHAR), dimension(pPathLen) :: getHostName_Cstring character(len=:), allocatable :: getHostName
character(len=:), allocatable :: getHostName
character(kind=C_CHAR), dimension(pStringLen+1) :: getHostName_Cstring
integer(C_INT) :: stat integer(C_INT) :: stat
call getHostName_C(getHostName_Cstring,stat) call getHostName_C(getHostName_Cstring,stat)
@ -135,22 +124,31 @@ function getHostName()
if(stat == 0) then if(stat == 0) then
getHostName = c_f_string(getHostName_Cstring) getHostName = c_f_string(getHostName_Cstring)
else else
getHostName = 'Error occured when getting host name' getHostName = 'n/a (Error!)'
endif endif
end function getHostName end function getHostName
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
!> @brief changes the current working directory !> @brief get the user name
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
logical function setCWD(path) function getUserName()
character(len=*), intent(in) :: path character(len=:), allocatable :: getUserName
setCWD=merge(.True.,.False.,chdir_C(f_c_string(path)) /= 0_C_INT) character(kind=C_CHAR), dimension(pStringLen+1) :: getUserName_Cstring
integer(C_INT) :: stat
end function setCWD call getUserName_C(getUserName_Cstring,stat)
if(stat == 0) then
getUserName = c_f_string(getUserName_Cstring)
else
getUserName = 'n/a (Error!)'
endif
end function getUserName
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
@ -182,14 +180,14 @@ end function c_f_string
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
pure function f_c_string(f_string) result(c_string) pure function f_c_string(f_string) result(c_string)
character(len=*), intent(in) :: f_string character(len=*), intent(in) :: f_string
character(kind=C_CHAR), dimension(len(f_string)+1) :: c_string character(kind=C_CHAR), dimension(len_trim(f_string)+1) :: c_string
integer :: i integer :: i
do i=1,len(f_string) do i=1,len_trim(f_string)
c_string(i)=f_string(i:i) c_string(i)=f_string(i:i)
enddo enddo
c_string(i) = C_NULL_CHAR c_string(len_trim(f_string)+1) = C_NULL_CHAR
end function f_c_string end function f_c_string