Merge branch 'python-improvements' into 'development'
Python improvements See merge request damask/DAMASK!279
This commit is contained in:
commit
a13a9d0e9e
|
@ -136,7 +136,7 @@ def shapeMismatch(size,F,nodes,centres):
|
|||
# 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.
|
||||
Operates on periodic three-dimensional x,y,z-ordered data sets.
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ scriptID = ' '.join([scriptName,damask.version])
|
|||
# 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.
|
||||
Operates on periodic three-dimensional x,y,z-ordered data sets.
|
||||
Outputs at cell centers or cell nodes (into separate file).
|
||||
|
|
|
@ -98,7 +98,7 @@ slipSystems = {
|
|||
# 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.
|
||||
|
||||
""", version = scriptID)
|
||||
|
|
|
@ -14,7 +14,7 @@ scriptID = ' '.join([scriptName,damask.version])
|
|||
# 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
|
||||
grains are segmented). Requires orientation data as quaternion.
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ scriptID = ' '.join([scriptName,damask.version])
|
|||
# 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.
|
||||
The osteon phase is lamellar with a twisted plywood structure.
|
||||
Its fiber orientation is oscillating by +/- amplitude within one period.
|
||||
|
|
|
@ -208,7 +208,7 @@ def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to
|
|||
# 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.
|
||||
Use *py_connection to operate on model presently opened in MSC.Mentat.
|
||||
""", version = scriptID)
|
||||
|
|
|
@ -168,7 +168,7 @@ def initial_conditions(material):
|
|||
# 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.
|
||||
|
||||
""", version = scriptID)
|
||||
|
|
|
@ -164,7 +164,7 @@ class myThread (threading.Thread):
|
|||
# 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.
|
||||
|
||||
""", version = scriptID)
|
||||
|
|
|
@ -16,7 +16,7 @@ scriptID = ' '.join([scriptName,damask.version])
|
|||
# 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.
|
||||
Mimics APS Beamline 34-ID-E DAXM poking.
|
||||
|
||||
|
|
|
@ -22,6 +22,19 @@ _ref_white = np.array([.95047, 1.00000, 1.08883])
|
|||
# - support NaN color (paraview)
|
||||
|
||||
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):
|
||||
"""Concatenate colormaps."""
|
||||
|
@ -36,6 +49,17 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
"""Return inverted colormap."""
|
||||
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
|
||||
def from_range(low,high,name='DAMASK colormap',N=256,model='rgb'):
|
||||
"""
|
||||
|
@ -126,40 +150,16 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
"""
|
||||
# matplotlib presets
|
||||
for cat in Colormap._predefined_mpl:
|
||||
for n in cat[1]:
|
||||
if n == name:
|
||||
colormap = cm.__dict__[name]
|
||||
if isinstance(colormap,mpl.colors.LinearSegmentedColormap):
|
||||
return Colormap(np.array(list(map(colormap,np.linspace(0,1,N)))),name=name)
|
||||
else:
|
||||
return Colormap(np.array(colormap.colors),name=name)
|
||||
|
||||
# DAMASK presets
|
||||
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]))
|
||||
try:
|
||||
colormap = cm.__dict__[name]
|
||||
return Colormap(np.array(list(map(colormap,np.linspace(0,1,N)))
|
||||
if isinstance(colormap,mpl.colors.LinearSegmentedColormap) else
|
||||
colormap.colors),
|
||||
name=name)
|
||||
except KeyError:
|
||||
# DAMASK presets
|
||||
definition = Colormap._predefined_DAMASK[name]
|
||||
return Colormap.from_range(definition['low'],definition['high'],name,N)
|
||||
|
||||
|
||||
def shade(self,field,bounds=None,gap=None):
|
||||
|
@ -168,9 +168,9 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
field : numpy.array of shape(:,:)
|
||||
field : numpy.array of shape (:,:)
|
||||
Data to be shaded.
|
||||
bounds : iterable of len(2), optional
|
||||
bounds : iterable of len (2), optional
|
||||
Colormap value range (low,high).
|
||||
gap : field.dtype, optional
|
||||
Transparent value. NaN will always be rendered transparent.
|
||||
|
@ -203,18 +203,6 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
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):
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
|
||||
def save_paraview(self,fname=None):
|
||||
"""
|
||||
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'.
|
||||
|
||||
"""
|
||||
if fname is not None:
|
||||
if fname is None:
|
||||
fhandle = None
|
||||
else:
|
||||
try:
|
||||
fhandle = open(fname,'w')
|
||||
except TypeError:
|
||||
fhandle = fname
|
||||
else:
|
||||
fhandle = None
|
||||
|
||||
colors = []
|
||||
for i,c in enumerate(np.round(self.colors,6).tolist()):
|
||||
|
@ -266,11 +253,9 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
'DefaultMap':True,
|
||||
'RGBPoints':colors
|
||||
}]
|
||||
if fhandle is None:
|
||||
with open(self.name.replace(' ','_')+'.json', 'w') as f:
|
||||
json.dump(out, f,indent=4)
|
||||
else:
|
||||
json.dump(out,fhandle,indent=4)
|
||||
|
||||
with open(self.name.replace(' ','_')+'.json', 'w') if fhandle is None else fhandle as f:
|
||||
json.dump(out, f,indent=4)
|
||||
|
||||
|
||||
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'.
|
||||
|
||||
"""
|
||||
if fname is not None:
|
||||
if fname is None:
|
||||
fhandle = None
|
||||
else:
|
||||
try:
|
||||
fhandle = open(fname,'w')
|
||||
except TypeError:
|
||||
fhandle = fname
|
||||
else:
|
||||
fhandle = None
|
||||
|
||||
labels = {'RGBA':4} if self.colors.shape[1] == 4 else {'RGB': 3}
|
||||
t = Table(self.colors,labels,f'Creator: {util.execution_stamp("Colormap")}')
|
||||
|
||||
if fhandle is None:
|
||||
with open(self.name.replace(' ','_')+'.txt', 'w') as f:
|
||||
t.save(f)
|
||||
else:
|
||||
t.save(fhandle)
|
||||
with open(self.name.replace(' ','_')+'.txt', 'w') if fhandle is None else fhandle as f:
|
||||
t.save(f)
|
||||
|
||||
|
||||
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'.
|
||||
|
||||
"""
|
||||
if fname is not None:
|
||||
if fname is None:
|
||||
fhandle = None
|
||||
else:
|
||||
try:
|
||||
fhandle = open(fname,'w')
|
||||
except TypeError:
|
||||
fhandle = fname
|
||||
else:
|
||||
fhandle = None
|
||||
# ToDo: test in GOM
|
||||
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 ' \
|
||||
+ 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))]) \
|
||||
+ '\n'
|
||||
if fhandle is None:
|
||||
with open(self.name.replace(' ','_')+'.legend', 'w') as f:
|
||||
f.write(GOM_str)
|
||||
else:
|
||||
fhandle.write(GOM_str)
|
||||
with open(self.name.replace(' ','_')+'.legend', 'w') if fhandle is None else fhandle as f:
|
||||
f.write(GOM_str)
|
||||
|
||||
|
||||
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'.
|
||||
|
||||
"""
|
||||
if fname is not None:
|
||||
if fname is None:
|
||||
fhandle = None
|
||||
else:
|
||||
try:
|
||||
fhandle = open(fname,'w')
|
||||
except TypeError:
|
||||
fhandle = fname
|
||||
else:
|
||||
fhandle = None
|
||||
# ToDo: test in gmsh
|
||||
gmsh_str = 'View.ColorTable = {\n' \
|
||||
+'\n'.join([f'{c[0]},{c[1]},{c[2]},' for c in self.colors[:,:3]*255]) \
|
||||
+'\n}\n'
|
||||
if fhandle is None:
|
||||
with open(self.name.replace(' ','_')+'.msh', 'w') as f:
|
||||
f.write(gmsh_str)
|
||||
else:
|
||||
fhandle.write(gmsh_str)
|
||||
with open(self.name.replace(' ','_')+'.msh', 'w') if fhandle is None else fhandle as f:
|
||||
f.write(gmsh_str)
|
||||
|
||||
|
||||
@staticmethod
|
||||
|
@ -387,7 +363,6 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
if msh_sat[2] < - np.pi/3.0: hSpin *= -1.0
|
||||
return msh_sat[2] + hSpin
|
||||
|
||||
|
||||
lo = np.array(low)
|
||||
hi = np.array(high)
|
||||
|
||||
|
@ -407,28 +382,28 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
return (1.0 - frac) * lo + frac * hi
|
||||
|
||||
|
||||
_predefined_mpl= [('Perceptually Uniform Sequential', [
|
||||
'viridis', 'plasma', 'inferno', 'magma', 'cividis']),
|
||||
('Sequential', [
|
||||
_predefined_mpl= {'Perceptually Uniform Sequential': [
|
||||
'viridis', 'plasma', 'inferno', 'magma', 'cividis'],
|
||||
'Sequential': [
|
||||
'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
|
||||
'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
|
||||
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn']),
|
||||
('Sequential (2)', [
|
||||
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'],
|
||||
'Sequential (2)': [
|
||||
'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',
|
||||
'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia',
|
||||
'hot', 'afmhot', 'gist_heat', 'copper']),
|
||||
('Diverging', [
|
||||
'hot', 'afmhot', 'gist_heat', 'copper'],
|
||||
'Diverging': [
|
||||
'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu',
|
||||
'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic']),
|
||||
('Cyclic', ['twilight', 'twilight_shifted', 'hsv']),
|
||||
('Qualitative', [
|
||||
'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'],
|
||||
'Cyclic': ['twilight', 'twilight_shifted', 'hsv'],
|
||||
'Qualitative': [
|
||||
'Pastel1', 'Pastel2', 'Paired', 'Accent',
|
||||
'Dark2', 'Set1', 'Set2', 'Set3',
|
||||
'tab10', 'tab20', 'tab20b', 'tab20c']),
|
||||
('Miscellaneous', [
|
||||
'tab10', 'tab20', 'tab20b', 'tab20c'],
|
||||
'Miscellaneous': [
|
||||
'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern',
|
||||
'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],
|
||||
'high': [0.250980,0.007843,0.000000]},
|
||||
|
@ -437,6 +412,9 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
'stress': {'low': [0.878432,0.874511,0.949019],
|
||||
'high': [0.000002,0.000000,0.286275]}}
|
||||
|
||||
predefined = dict(**{'DAMASK':list(_predefined_DAMASK)},**_predefined_mpl)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _hsv2rgb(hsv):
|
||||
"""
|
||||
|
|
|
@ -226,13 +226,13 @@ class ConfigMaterial(Config):
|
|||
return dup
|
||||
|
||||
|
||||
def material_add(self,constituents,**kwargs):
|
||||
def material_add(self,constituents=None,**kwargs):
|
||||
"""
|
||||
Add material entries.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
constituents : dict
|
||||
constituents : dict, optional
|
||||
Entries for 'constituents' as key-value pair.
|
||||
**kwargs
|
||||
Key-value pairs.
|
||||
|
@ -263,13 +263,26 @@ class ConfigMaterial(Config):
|
|||
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():
|
||||
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):
|
||||
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:
|
||||
for i in range(len(c)):
|
||||
c[i][k] = v
|
||||
|
@ -293,7 +306,7 @@ class ConfigMaterial(Config):
|
|||
if len(v) != N_material:
|
||||
raise ValueError('Cannot add entries of different length')
|
||||
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:
|
||||
for i in range(N_material):
|
||||
m[i][0][k] = v
|
||||
|
|
|
@ -5,8 +5,6 @@ class Environment:
|
|||
|
||||
@property
|
||||
def screen_size(self):
|
||||
width = 1024
|
||||
height = 768
|
||||
try:
|
||||
import wx
|
||||
_ = wx.App(False) # noqa
|
||||
|
@ -19,7 +17,9 @@ class Environment:
|
|||
height = tk.winfo_screenheight()
|
||||
tk.destroy()
|
||||
except Exception as e:
|
||||
pass
|
||||
width = 1024
|
||||
height = 768
|
||||
|
||||
return (width,height)
|
||||
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import copy
|
|||
import multiprocessing as mp
|
||||
from functools import partial
|
||||
from os import path
|
||||
import warnings
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
@ -73,23 +74,23 @@ class Geom:
|
|||
"""
|
||||
message = []
|
||||
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 ")}'))
|
||||
|
||||
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 ")}'))
|
||||
|
||||
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," ")}'))
|
||||
|
||||
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}'))
|
||||
|
||||
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)}'))
|
||||
|
||||
return util.return_message(message)
|
||||
|
@ -188,12 +189,16 @@ class Geom:
|
|||
"""
|
||||
Read a geom file.
|
||||
|
||||
Storing geometry files in ASCII format is deprecated.
|
||||
This function will be removed in a future version of DAMASK.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str, pathlib.Path, or file handle
|
||||
Geometry file to read.
|
||||
|
||||
"""
|
||||
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.1.0', DeprecationWarning)
|
||||
try:
|
||||
f = open(fname)
|
||||
except TypeError:
|
||||
|
@ -247,7 +252,6 @@ class Geom:
|
|||
return Geom(material.reshape(grid,order='F'),size,origin,comments)
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def load_DREAM3D(fname,base_group,point_data=None,material='FeatureIds'):
|
||||
"""
|
||||
|
@ -523,6 +527,9 @@ class Geom:
|
|||
"""
|
||||
Write a geom file.
|
||||
|
||||
Storing geometry files in ASCII format is deprecated.
|
||||
This function will be removed in a future version of DAMASK.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str or file handle
|
||||
|
@ -531,6 +538,7 @@ class Geom:
|
|||
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 \
|
||||
+ ['grid a {} b {} c {}'.format(*self.grid),
|
||||
'size x {} y {} z {}'.format(*self.size),
|
||||
|
@ -547,8 +555,7 @@ class Geom:
|
|||
|
||||
def show(self):
|
||||
"""Show on screen."""
|
||||
v = VTK.from_rectilinear_grid(self.grid,self.size,self.origin)
|
||||
v.show()
|
||||
VTK.from_rectilinear_grid(self.grid,self.size,self.origin).show()
|
||||
|
||||
|
||||
def add_primitive(self,dimension,center,exponent,
|
||||
|
|
|
@ -4,7 +4,7 @@ from . import Rotation
|
|||
from . import util
|
||||
from . import mechanics
|
||||
|
||||
__parameter_doc__ = \
|
||||
_parameter_doc = \
|
||||
"""lattice : str
|
||||
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].
|
||||
|
@ -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):
|
||||
"""
|
||||
Representation of crystallographic orientation as combination of rotation and either crystal family or Bravais lattice.
|
||||
|
@ -85,18 +69,6 @@ class Orientation(Rotation):
|
|||
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
|
||||
|
||||
Disorientation between two specific orientations of hexagonal symmetry:
|
||||
>>> 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)
|
||||
|
||||
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_Eulers(phi=[0,45,0],degrees=True,lattice='cF').Schmid('slip')
|
||||
|
||||
"""
|
||||
|
||||
crystal_families = ['triclinic',
|
||||
|
@ -128,7 +100,7 @@ class Orientation(Rotation):
|
|||
}
|
||||
|
||||
|
||||
@extend_docstring()
|
||||
@util.extend_docstring(_parameter_doc)
|
||||
def __init__(self,
|
||||
rotation = None,
|
||||
lattice = None,
|
||||
|
@ -279,73 +251,73 @@ class Orientation(Rotation):
|
|||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_random)
|
||||
@util.extended_docstring(Rotation.from_random,_parameter_doc)
|
||||
def from_random(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_random(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_quaternion)
|
||||
@util.extended_docstring(Rotation.from_quaternion,_parameter_doc)
|
||||
def from_quaternion(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_quaternion(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_Eulers)
|
||||
@util.extended_docstring(Rotation.from_Eulers,_parameter_doc)
|
||||
def from_Eulers(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_Eulers(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_axis_angle)
|
||||
@util.extended_docstring(Rotation.from_axis_angle,_parameter_doc)
|
||||
def from_axis_angle(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_axis_angle(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_basis)
|
||||
@util.extended_docstring(Rotation.from_basis,_parameter_doc)
|
||||
def from_basis(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_basis(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_matrix)
|
||||
@util.extended_docstring(Rotation.from_matrix,_parameter_doc)
|
||||
def from_matrix(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_matrix(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_Rodrigues)
|
||||
@util.extended_docstring(Rotation.from_Rodrigues,_parameter_doc)
|
||||
def from_Rodrigues(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_Rodrigues(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_homochoric)
|
||||
@util.extended_docstring(Rotation.from_homochoric,_parameter_doc)
|
||||
def from_homochoric(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_homochoric(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_cubochoric)
|
||||
@util.extended_docstring(Rotation.from_cubochoric,_parameter_doc)
|
||||
def from_cubochoric(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_cubochoric(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_spherical_component)
|
||||
@util.extended_docstring(Rotation.from_spherical_component,_parameter_doc)
|
||||
def from_spherical_component(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_spherical_component(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extended_docstring(Rotation.from_fiber_component)
|
||||
@util.extended_docstring(Rotation.from_fiber_component,_parameter_doc)
|
||||
def from_fiber_component(cls,**kwargs):
|
||||
return cls(rotation=Rotation.from_fiber_component(**kwargs),**kwargs)
|
||||
|
||||
|
||||
@classmethod
|
||||
@extend_docstring()
|
||||
@util.extend_docstring(_parameter_doc)
|
||||
def from_directions(cls,uvw,hkl,**kwargs):
|
||||
"""
|
||||
Initialize orientation object from two crystallographic directions.
|
||||
|
@ -847,6 +819,14 @@ class Orientation(Rotation):
|
|||
rgb : numpy.ndarray of shape (...,3)
|
||||
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
|
||||
----------
|
||||
Bases are computed from
|
||||
|
@ -867,7 +847,8 @@ class Orientation(Rotation):
|
|||
... }
|
||||
|
||||
"""
|
||||
if vector.shape[-1] != 3:
|
||||
vector_ = np.array(vector)
|
||||
if vector_.shape[-1] != 3:
|
||||
raise ValueError('Input is not a field of three-dimensional vectors.')
|
||||
|
||||
if self.family == 'cubic':
|
||||
|
@ -903,23 +884,23 @@ class Orientation(Rotation):
|
|||
[ 0., 1., 0.] ]),
|
||||
}
|
||||
else: # direct exit for unspecified symmetry
|
||||
return np.zeros_like(vector)
|
||||
return np.zeros_like(vector_)
|
||||
|
||||
if proper:
|
||||
components_proper = np.around(np.einsum('...ji,...i',
|
||||
np.broadcast_to(basis['proper'], vector.shape+(3,)),
|
||||
vector), 12)
|
||||
np.broadcast_to(basis['proper'], vector_.shape+(3,)),
|
||||
vector_), 12)
|
||||
components_improper = np.around(np.einsum('...ji,...i',
|
||||
np.broadcast_to(basis['improper'], vector.shape+(3,)),
|
||||
vector), 12)
|
||||
np.broadcast_to(basis['improper'], vector_.shape+(3,)),
|
||||
vector_), 12)
|
||||
in_SST = np.all(components_proper >= 0.0,axis=-1) \
|
||||
| np.all(components_improper >= 0.0,axis=-1)
|
||||
components = np.where((in_SST & np.all(components_proper >= 0.0,axis=-1))[...,np.newaxis],
|
||||
components_proper,components_improper)
|
||||
else:
|
||||
components = np.around(np.einsum('...ji,...i',
|
||||
np.broadcast_to(basis['improper'], vector.shape+(3,)),
|
||||
np.block([vector[...,:2],np.abs(vector[...,2:3])])), 12)
|
||||
np.broadcast_to(basis['improper'], vector_.shape+(3,)),
|
||||
np.block([vector_[...,:2],np.abs(vector_[...,2:3])])), 12)
|
||||
|
||||
in_SST = np.all(components >= 0.0,axis=-1)
|
||||
|
||||
|
@ -957,6 +938,22 @@ class Orientation(Rotation):
|
|||
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.
|
||||
|
||||
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:
|
||||
raise ValueError('Missing crystal symmetry')
|
||||
|
@ -1065,8 +1062,8 @@ class Orientation(Rotation):
|
|||
raise ValueError('Missing crystal symmetry')
|
||||
|
||||
eq = self.equivalent
|
||||
blend = util.shapeblender(eq.shape,vector.shape[:-1])
|
||||
poles = eq.broadcast_to(blend,mode='right') @ np.broadcast_to(vector,blend+(3,))
|
||||
blend = util.shapeblender(eq.shape,np.array(vector).shape[:-1])
|
||||
poles = eq.broadcast_to(blend,mode='right') @ np.broadcast_to(np.array(vector),blend+(3,))
|
||||
ok = self.in_SST(poles,proper=proper)
|
||||
ok &= np.cumsum(ok,axis=0) == 1
|
||||
loc = np.where(ok)
|
||||
|
@ -1085,12 +1082,12 @@ class Orientation(Rotation):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
uvtw | hkil : numpy.ndarray of shape (...,4)
|
||||
uvtw|hkil : numpy.ndarray of shape (...,4)
|
||||
Miller–Bravais indices of crystallographic direction [uvtw] or plane normal (hkil).
|
||||
|
||||
Returns
|
||||
-------
|
||||
uvw | hkl : numpy.ndarray of shape (...,3)
|
||||
uvw|hkl : numpy.ndarray of shape (...,3)
|
||||
Miller indices of [uvw] direction or (hkl) plane normal.
|
||||
|
||||
"""
|
||||
|
@ -1113,12 +1110,12 @@ class Orientation(Rotation):
|
|||
|
||||
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).
|
||||
|
||||
Returns
|
||||
-------
|
||||
uvtw | hkil : numpy.ndarray of shape (...,4)
|
||||
uvtw|hkil : numpy.ndarray of shape (...,4)
|
||||
Miller–Bravais indices of [uvtw] direction or (hkil) plane normal.
|
||||
|
||||
"""
|
||||
|
@ -1142,7 +1139,7 @@ class Orientation(Rotation):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
direction | normal : numpy.ndarray of shape (...,3)
|
||||
direction|normal : numpy.ndarray of shape (...,3)
|
||||
Vector along direction or plane normal.
|
||||
|
||||
Returns
|
||||
|
@ -1166,7 +1163,7 @@ class Orientation(Rotation):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
uvw | hkl : numpy.ndarray of shape (...,3)
|
||||
uvw|hkl : numpy.ndarray of shape (...,3)
|
||||
Miller indices of crystallographic direction or plane normal.
|
||||
with_symmetry : bool, optional
|
||||
Calculate all N symmetrically equivalent vectors.
|
||||
|
@ -1194,7 +1191,7 @@ class Orientation(Rotation):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
uvw | hkl : numpy.ndarray of shape (...,3)
|
||||
uvw|hkl : numpy.ndarray of shape (...,3)
|
||||
Miller indices of crystallographic direction or plane normal.
|
||||
with_symmetry : bool, optional
|
||||
Calculate all N symmetrically equivalent vectors.
|
||||
|
@ -1217,13 +1214,26 @@ class Orientation(Rotation):
|
|||
Parameters
|
||||
----------
|
||||
mode : str
|
||||
Type of kinematics, e.g. 'slip' or 'twin'.
|
||||
Type of kinematics, i.e. 'slip' or 'twin'.
|
||||
|
||||
Returns
|
||||
-------
|
||||
P : numpy.ndarray of shape (...,N,3,3)
|
||||
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)
|
||||
p = self.to_frame(hkl=self.kinematics[mode]['plane'] ,with_symmetry=False)
|
||||
|
|
|
@ -167,9 +167,7 @@ class Result:
|
|||
|
||||
|
||||
def allow_modification(self):
|
||||
print(util.bcolors().WARNING+util.bcolors().BOLD+
|
||||
'Warning: Modification of existing datasets allowed!'+
|
||||
util.bcolors().ENDC)
|
||||
print(util.warn('Warning: Modification of existing datasets allowed!'))
|
||||
self._allow_modification = True
|
||||
|
||||
def disallow_modification(self):
|
||||
|
|
|
@ -107,22 +107,6 @@ class Rotation:
|
|||
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
|
||||
def shape(self):
|
||||
return self.quaternion.shape[:-1]
|
||||
|
@ -404,7 +388,7 @@ class Rotation:
|
|||
Returns
|
||||
-------
|
||||
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)
|
||||
|
@ -698,7 +682,7 @@ class Rotation:
|
|||
|
||||
@staticmethod
|
||||
def from_random(shape = None,
|
||||
seed = None,
|
||||
rng_seed = None,
|
||||
**kwargs):
|
||||
"""
|
||||
Draw random rotation.
|
||||
|
@ -710,12 +694,12 @@ class Rotation:
|
|||
shape : tuple of ints, optional
|
||||
Shape of the sample. Defaults to None which gives a
|
||||
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.
|
||||
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))
|
||||
|
||||
A = np.sqrt(r[...,2])
|
||||
|
@ -734,7 +718,7 @@ class Rotation:
|
|||
N = 500,
|
||||
degrees = True,
|
||||
fractions = True,
|
||||
seed = None,
|
||||
rng_seed = None,
|
||||
**kwargs):
|
||||
"""
|
||||
Sample discrete values from a binned ODF.
|
||||
|
@ -753,7 +737,7 @@ class Rotation:
|
|||
fractions : boolean, optional
|
||||
ODF values correspond to volume fractions, not probability density.
|
||||
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
|
||||
will be pulled from the OS.
|
||||
|
||||
|
@ -784,7 +768,7 @@ class Rotation:
|
|||
dg = 1.0 if fractions else _dg(Eulers,degrees)
|
||||
dV_V = dg * np.maximum(0.0,weights.squeeze())
|
||||
|
||||
return Rotation.from_Eulers(Eulers[util.hybrid_IA(dV_V,N,seed)],degrees)
|
||||
return Rotation.from_Eulers(Eulers[util.hybrid_IA(dV_V,N,rng_seed)],degrees)
|
||||
|
||||
|
||||
@staticmethod
|
||||
|
@ -792,7 +776,7 @@ class Rotation:
|
|||
sigma,
|
||||
N = 500,
|
||||
degrees = True,
|
||||
seed = None,
|
||||
rng_seed = None,
|
||||
**kwargs):
|
||||
"""
|
||||
Calculate set of rotations with Gaussian distribution around center.
|
||||
|
@ -807,12 +791,12 @@ class Rotation:
|
|||
Number of samples, defaults to 500.
|
||||
degrees : boolean, optional
|
||||
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
|
||||
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
|
||||
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))
|
||||
|
@ -829,7 +813,7 @@ class Rotation:
|
|||
sigma = 0.0,
|
||||
N = 500,
|
||||
degrees = True,
|
||||
seed = None,
|
||||
rng_seed = None,
|
||||
**kwargs):
|
||||
"""
|
||||
Calculate set of rotations with Gaussian distribution around direction.
|
||||
|
@ -847,12 +831,12 @@ class Rotation:
|
|||
Number of samples, defaults to 500.
|
||||
degrees : boolean, optional
|
||||
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
|
||||
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)
|
||||
|
||||
d_cr = np.array([np.sin(alpha_[0])*np.cos(alpha_[1]), np.sin(alpha_[0])*np.sin(alpha_[1]), np.cos(alpha_[0])])
|
||||
|
|
|
@ -5,7 +5,7 @@ from . import util
|
|||
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.
|
||||
|
||||
|
@ -18,12 +18,12 @@ def from_random(size,N_seeds,grid=None,seed=None):
|
|||
grid : numpy.ndarray of shape (3), optional.
|
||||
If given, ensures that all seeds initiate one grain if using a
|
||||
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.
|
||||
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:
|
||||
coords = rng.random((N_seeds,3)) * size
|
||||
else:
|
||||
|
@ -34,7 +34,7 @@ def from_random(size,N_seeds,grid=None,seed=None):
|
|||
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.
|
||||
|
||||
|
@ -50,12 +50,12 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,seed=None
|
|||
Minimum acceptable distance to other seeds.
|
||||
periodic : boolean, optional
|
||||
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.
|
||||
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[0] = rng.random(3) * size
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ __all__=[
|
|||
'srepr',
|
||||
'croak',
|
||||
'report',
|
||||
'emph','deemph','delete','strikeout',
|
||||
'emph','deemph','warn','strikeout',
|
||||
'execute',
|
||||
'show_progress',
|
||||
'scale_to_coprime',
|
||||
|
@ -26,8 +26,8 @@ __all__=[
|
|||
'return_message',
|
||||
'extendableOption',
|
||||
'execution_stamp',
|
||||
'shapeshifter',
|
||||
'shapeblender',
|
||||
'shapeshifter', 'shapeblender',
|
||||
'extend_docstring', 'extended_docstring'
|
||||
]
|
||||
|
||||
####################################################################################################
|
||||
|
@ -42,7 +42,7 @@ def srepr(arg,glue = '\n'):
|
|||
arg : iterable
|
||||
Items to join.
|
||||
glue : str, optional
|
||||
Defaults to \n.
|
||||
Glue used for joining operation. Defaults to \n.
|
||||
|
||||
"""
|
||||
if (not hasattr(arg, "strip") and
|
||||
|
@ -56,6 +56,8 @@ def croak(what, newline = True):
|
|||
"""
|
||||
Write formated to stderr.
|
||||
|
||||
DEPRECATED
|
||||
|
||||
Parameters
|
||||
----------
|
||||
what : str or iterable
|
||||
|
@ -72,7 +74,7 @@ def croak(what, newline = True):
|
|||
def report(who = None,
|
||||
what = None):
|
||||
"""
|
||||
Reports script and file name.
|
||||
Report script and file name.
|
||||
|
||||
DEPRECATED
|
||||
|
||||
|
@ -84,16 +86,13 @@ def emph(what):
|
|||
"""Formats string with emphasis."""
|
||||
return bcolors.BOLD+srepr(what)+bcolors.ENDC
|
||||
|
||||
|
||||
def deemph(what):
|
||||
"""Formats string with deemphasis."""
|
||||
return bcolors.DIM+srepr(what)+bcolors.ENDC
|
||||
|
||||
|
||||
def delete(what):
|
||||
"""Formats string as deleted."""
|
||||
return bcolors.DIM+srepr(what)+bcolors.ENDC
|
||||
|
||||
def warn(what):
|
||||
"""Formats string for warning."""
|
||||
return bcolors.WARNING+emph(what)+bcolors.ENDC
|
||||
|
||||
def strikeout(what):
|
||||
"""Formats string as strikeout."""
|
||||
|
@ -164,7 +163,15 @@ def show_progress(iterable,N_iter=None,prefix='',bar_length=50):
|
|||
|
||||
|
||||
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
|
||||
|
||||
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})'
|
||||
|
||||
|
||||
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
|
||||
|
||||
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 \
|
||||
(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):
|
||||
|
@ -300,6 +321,40 @@ def shapeblender(a,b):
|
|||
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
|
||||
####################################################################################################
|
||||
|
@ -393,17 +448,6 @@ class bcolors:
|
|||
UNDERLINE = '\033[4m'
|
||||
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:
|
||||
"""Object with formatted return message."""
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
from pathlib import Path
|
||||
import datetime
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
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
|
||||
|
||||
|
@ -25,8 +30,9 @@ def patch_datetime_now(monkeypatch):
|
|||
|
||||
monkeypatch.setattr(datetime, 'datetime', mydatetime)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def execution_stamp(monkeypatch):
|
||||
def patch_execution_stamp(monkeypatch):
|
||||
"""Set damask.util.execution_stamp for reproducible tests results."""
|
||||
def execution_stamp(class_name,function_name=None):
|
||||
_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)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patch_plt_show(monkeypatch):
|
||||
def _None(block=None):
|
||||
pass
|
||||
monkeypatch.setattr(plt, 'show', _None, raising=True)
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--update",
|
||||
action="store_true",
|
||||
default=False)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def update(request):
|
||||
"""Store current results as new reference results."""
|
||||
return request.config.getoption("--update")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def reference_dir_base():
|
||||
"""Directory containing reference results."""
|
||||
return Path(__file__).parent/'reference'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def set_of_quaternions():
|
||||
"""A set of n random rotations."""
|
||||
|
|
|
@ -17,9 +17,12 @@ def reference_dir(reference_dir_base):
|
|||
class TestColormap:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _execution_stamp(self, execution_stamp):
|
||||
def _patch_execution_stamp(self, patch_execution_stamp):
|
||||
print('patched damask.util.execution_stamp')
|
||||
|
||||
def test_repr(self,patch_plt_show):
|
||||
print(Colormap.from_predefined('stress'))
|
||||
|
||||
def test_conversion(self):
|
||||
specials = np.array([[0.,0.,0.],
|
||||
[1.,0.,0.],
|
||||
|
@ -138,8 +141,8 @@ class TestColormap:
|
|||
diff = ImageChops.difference(img_reference.convert('RGB'),img_current.convert('RGB'))
|
||||
assert not diff.getbbox()
|
||||
|
||||
def test_list(self):
|
||||
Colormap.list_predefined()
|
||||
def test_predefined(self):
|
||||
assert (isinstance(Colormap.predefined,dict))
|
||||
|
||||
@pytest.mark.parametrize('format,ext',[('ASCII','.txt'),
|
||||
('paraview','.json'),
|
||||
|
|
|
@ -62,6 +62,12 @@ class TestConfigMaterial:
|
|||
del material_config['material'][0]['homogenization']
|
||||
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):
|
||||
material_config = ConfigMaterial.load(reference_dir/'material.yaml')
|
||||
del material_config['phase']['Aluminum']['lattice']
|
||||
|
@ -85,9 +91,36 @@ class TestConfigMaterial:
|
|||
assert len(c['material']) == N
|
||||
for i,m in enumerate(c['material']):
|
||||
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])
|
||||
assert c[0][0]['c'] == c[1][0]['c'] == 1
|
||||
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)
|
||||
|
|
|
@ -34,7 +34,7 @@ def reference_dir(reference_dir_base):
|
|||
class TestGeom:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _execution_stamp(self, execution_stamp):
|
||||
def _patch_execution_stamp(self, patch_execution_stamp):
|
||||
print('patched damask.util.execution_stamp')
|
||||
|
||||
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'])
|
||||
assert str(default.diff(new)) != ''
|
||||
|
||||
def test_repr(self,default):
|
||||
print(default)
|
||||
|
||||
def test_read_write_vtr(self,default,tmp_path):
|
||||
default.save(tmp_path/'default')
|
||||
|
@ -70,6 +72,9 @@ class TestGeom:
|
|||
Geom(default.material[1:,1:,1:],
|
||||
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):
|
||||
with pytest.raises(ValueError):
|
||||
|
|
|
@ -125,9 +125,9 @@ class TestOrientation:
|
|||
|
||||
def test_from_fiber_component(self):
|
||||
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),
|
||||
sigma=0.0,N=1,seed=0,lattice='triclinic').quaternion
|
||||
sigma=0.0,N=1,rng_seed=0,lattice='triclinic').quaternion
|
||||
== r.quaternion)
|
||||
|
||||
@pytest.mark.parametrize('kwargs',[
|
||||
|
@ -175,8 +175,8 @@ class TestOrientation:
|
|||
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||
@pytest.mark.parametrize('N',[1,8,32])
|
||||
def test_disorientation(self,lattice,N):
|
||||
o = Orientation.from_random(lattice=lattice,shape=N,seed=0)
|
||||
p = Orientation.from_random(lattice=lattice,shape=N,seed=1)
|
||||
o = Orientation.from_random(lattice=lattice,shape=N)
|
||||
p = Orientation.from_random(lattice=lattice,shape=N)
|
||||
|
||||
d,ops = o.disorientation(p,return_operators=True)
|
||||
|
||||
|
@ -198,8 +198,8 @@ class TestOrientation:
|
|||
(None,None),
|
||||
])
|
||||
def test_disorientation_blending(self,lattice,a,b):
|
||||
o = Orientation.from_random(lattice=lattice,shape=a,seed=0)
|
||||
p = Orientation.from_random(lattice=lattice,shape=b,seed=1)
|
||||
o = Orientation.from_random(lattice=lattice,shape=a)
|
||||
p = Orientation.from_random(lattice=lattice,shape=b)
|
||||
blend = util.shapeblender(o.shape,p.shape)
|
||||
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):])]) \
|
||||
|
@ -214,7 +214,7 @@ class TestOrientation:
|
|||
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
|
||||
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()):
|
||||
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('proper',[True,False])
|
||||
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()):
|
||||
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('proper',[True,False])
|
||||
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)
|
||||
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))
|
||||
|
@ -245,7 +245,7 @@ class TestOrientation:
|
|||
(None,(3,)),
|
||||
])
|
||||
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,))
|
||||
blend = util.shapeblender(o.shape,b)
|
||||
for loc in np.random.randint(0,blend,(10,len(blend))):
|
||||
|
|
|
@ -769,18 +769,19 @@ class TestRotation:
|
|||
|
||||
@pytest.mark.parametrize('shape',[None,1,(4,4)])
|
||||
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):
|
||||
r = Rotation.from_random(seed=0)
|
||||
assert r == r
|
||||
|
||||
def test_unequal(self):
|
||||
r = Rotation.from_random(seed=0)
|
||||
assert not (r != r)
|
||||
assert Rotation.from_random(rng_seed=1) == Rotation.from_random(rng_seed=1)
|
||||
|
||||
def test_inversion(self):
|
||||
r = Rotation.from_random(seed=0)
|
||||
r = Rotation.from_random()
|
||||
assert r == ~~r
|
||||
|
||||
@pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(1,1,1)])
|
||||
|
|
|
@ -17,6 +17,12 @@ def reference_dir(reference_dir_base):
|
|||
|
||||
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):
|
||||
d = default.get('s')
|
||||
assert np.allclose(d,1.0) and d.shape[1:] == (1,)
|
||||
|
|
|
@ -23,7 +23,7 @@ def default():
|
|||
class TestVTK:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _execution_stamp(self, execution_stamp):
|
||||
def _patch_execution_stamp(self, patch_execution_stamp):
|
||||
print('patched damask.util.execution_stamp')
|
||||
|
||||
def test_rectilinearGrid(self,tmp_path):
|
||||
|
@ -84,6 +84,15 @@ class TestVTK:
|
|||
time.sleep(.5)
|
||||
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'])
|
||||
def test_filename_variations(self,tmp_path,fname):
|
||||
|
|
|
@ -15,6 +15,10 @@ class TestUtil:
|
|||
out,err = util.execute('sh -c "echo $test_for_execute"',env={'test_for_execute':'test'})
|
||||
assert out=='test\n' and err==''
|
||||
|
||||
def test_execute_invalid(self):
|
||||
with pytest.raises(RuntimeError):
|
||||
util.execute('/bin/false')
|
||||
|
||||
def test_croak(self):
|
||||
util.croak('Burp!')
|
||||
|
||||
|
@ -93,3 +97,7 @@ class TestUtil:
|
|||
])
|
||||
def test_shapeblender(self,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')
|
||||
|
|
Loading…
Reference in New Issue