dropped support for legacy table
This commit is contained in:
Martin Diehl 2021-03-27 10:10:35 +01:00
parent 111a1a76c6
commit be9e00347b
24 changed files with 98 additions and 96 deletions

View File

@ -1,7 +1,9 @@
SHELL = /bin/sh SHELL = /bin/sh
########################################################################################
# Makefile for the installation of DAMASK ###################################################################################################
######################################################################################## # One-command-build invoking CMake (meant for developers, should not be part of the distribution)
###################################################################################################
.PHONY: all .PHONY: all
all: grid mesh all: grid mesh

View File

@ -39,20 +39,20 @@ class Colormap(mpl.colors.ListedColormap):
""" """
def __add__(self,other): def __add__(self,other):
"""Concatenate colormaps.""" """Concatenate."""
return Colormap(np.vstack((self.colors,other.colors)), return Colormap(np.vstack((self.colors,other.colors)),
f'{self.name}+{other.name}') f'{self.name}+{other.name}')
def __iadd__(self,other): def __iadd__(self,other):
"""Concatenate colormaps.""" """Concatenate (in-place)."""
return self.__add__(other) return self.__add__(other)
def __invert__(self): def __invert__(self):
"""Return inverted colormap.""" """Reverse."""
return self.reversed() return self.reversed()
def __repr__(self): def __repr__(self):
"""Show colormap as matplotlib figure.""" """Show as matplotlib figure."""
fig = plt.figure(self.name,figsize=(5,.5)) fig = plt.figure(self.name,figsize=(5,.5))
ax1 = fig.add_axes([0, 0, 1, 1]) ax1 = fig.add_axes([0, 0, 1, 1])
ax1.set_axis_off() ax1.set_axis_off()
@ -207,7 +207,7 @@ class Colormap(mpl.colors.ListedColormap):
def reversed(self,name=None): def reversed(self,name=None):
""" """
Make a reversed instance of the colormap. Reverse.
Parameters Parameters
---------- ----------

View File

@ -31,7 +31,7 @@ class NiceDumper(yaml.SafeDumper):
return super().represent_data(data) return super().represent_data(data)
def ignore_aliases(self, data): def ignore_aliases(self, data):
"""No references.""" """Do not use references to existing objects."""
return True return True
class Config(dict): class Config(dict):

View File

@ -9,14 +9,29 @@ from . import Orientation
from . import util from . import util
class ConfigMaterial(Config): class ConfigMaterial(Config):
"""Material configuration.""" """
Material configuration.
Manipulate material configurations for storage in YAML format.
A complete material configuration file has the entries 'material',
'phase', and 'homogenization'. For use in DAMASK, it needs to be
stored as 'material.yaml'.
"""
_defaults = {'material': [], _defaults = {'material': [],
'homogenization': {}, 'homogenization': {},
'phase': {}} 'phase': {}}
def __init__(self,d=_defaults): def __init__(self,d=_defaults):
"""Initialize object with default dictionary keys.""" """
New material configuration.
Parameters
----------
d : dictionary, optional
Initial content. Defaults to empty material, homogenization, and phase entries.
"""
super().__init__(d) super().__init__(d)

View File

@ -17,11 +17,18 @@ from . import Rotation
class Grid: class Grid:
"""Geometry definition for grid solvers.""" """
Geometry definition for grid solvers.
Create and manipulate geometry definitions for storage as VTK
rectiliear grid files ('.vtr' extension). A grid contains the
material ID (referring to the entry in 'material.yaml') and
the physical size.
"""
def __init__(self,material,size,origin=[0.0,0.0,0.0],comments=[]): def __init__(self,material,size,origin=[0.0,0.0,0.0],comments=[]):
""" """
New grid definition from array of materials, size, and origin. New geometry definition for grid solvers.
Parameters Parameters
---------- ----------

View File

@ -47,19 +47,30 @@ class Orientation(Rotation):
The Bravais lattice is one of Orientation.lattice_symmetries: The Bravais lattice is one of Orientation.lattice_symmetries:
- aP : triclinic primitive - triclinic
- mP : monoclinic primitive - aP : primitive
- mS : ... base-centered
- oP : orthorhombic primitive - monoclininic
- oS : ... base-centered - mP : primitive
- oI : ... body-centered - mS : base-centered
- oF : ... face-centered
- tP : tetragonal primitive - orthorhombic
- tI : ... body-centered - oP : primitive
- hP : hexagonal primitive - oS : base-centered
- cP : cubic primitive - oI : body-centered
- cI : ... body-centered - oF : face-centered
- cF : ... face-centered
- tetragonal
- tP : primitive
- tI : body-centered
- hexagonal
- hP : primitive
- cubic
- cP : primitive
- cI : body-centered
- cF : face-centered
and inherits the corresponding crystal family. and inherits the corresponding crystal family.
Specifying a Bravais lattice, compared to just the crystal family, Specifying a Bravais lattice, compared to just the crystal family,
@ -111,7 +122,7 @@ class Orientation(Rotation):
alpha = None,beta = None,gamma = None, alpha = None,beta = None,gamma = None,
degrees = False): degrees = False):
""" """
Initialize orientation object. New orientation.
Parameters Parameters
---------- ----------

View File

@ -26,14 +26,14 @@ h5py3 = h5py.__version__[0] == '3'
class Result: class Result:
""" """
Read and write to DADF5 files. Manipulate and read DADF5 files.
DADF5 (DAMASK HDF5) files contain DAMASK results. DADF5 (DAMASK HDF5) files contain DAMASK results.
""" """
def __init__(self,fname): def __init__(self,fname):
""" """
Open an existing DADF5 file. New result view bound to a HDF5 file.
Parameters Parameters
---------- ----------

View File

@ -51,7 +51,7 @@ class Rotation:
def __init__(self,rotation = np.array([1.0,0.0,0.0,0.0])): def __init__(self,rotation = np.array([1.0,0.0,0.0,0.0])):
""" """
Initialize rotation object. New rotation.
Parameters Parameters
---------- ----------
@ -140,7 +140,7 @@ class Rotation:
def __len__(self): def __len__(self):
"""Length of leading/leftmost dimension of Rotation array.""" """Length of leading/leftmost dimension of array."""
return 0 if self.shape == () else self.shape[0] return 0 if self.shape == () else self.shape[0]
@ -180,7 +180,7 @@ class Rotation:
def __mul__(self,other): def __mul__(self,other):
""" """
Compose this rotation with other. Compose with other.
Parameters Parameters
---------- ----------
@ -206,7 +206,7 @@ class Rotation:
def __imul__(self,other): def __imul__(self,other):
""" """
Compose this rotation with other (in-place). Compose with other (in-place).
Parameters Parameters
---------- ----------
@ -219,7 +219,7 @@ class Rotation:
def __truediv__(self,other): def __truediv__(self,other):
""" """
Compose this rotation with inverse of other. Compose with inverse of other.
Parameters Parameters
---------- ----------
@ -239,7 +239,7 @@ class Rotation:
def __itruediv__(self,other): def __itruediv__(self,other):
""" """
Compose this rotation with inverse of other (in-place). Compose with inverse of other (in-place).
Parameters Parameters
---------- ----------
@ -252,7 +252,7 @@ class Rotation:
def __matmul__(self,other): def __matmul__(self,other):
""" """
Rotation of vector, second order tensor, or fourth order tensor. Rotate vector, second order tensor, or fourth order tensor.
Parameters Parameters
---------- ----------
@ -301,7 +301,7 @@ class Rotation:
def append(self,other): def append(self,other):
""" """
Extend rotation array along first dimension with other array(s). Extend array along first dimension with other array(s).
Parameters Parameters
---------- ----------
@ -313,19 +313,19 @@ class Rotation:
def flatten(self,order = 'C'): def flatten(self,order = 'C'):
"""Flatten quaternion array.""" """Flatten array."""
return self.copy(rotation=self.quaternion.reshape((-1,4),order=order)) return self.copy(rotation=self.quaternion.reshape((-1,4),order=order))
def reshape(self,shape,order = 'C'): def reshape(self,shape,order = 'C'):
"""Reshape quaternion array.""" """Reshape array."""
if isinstance(shape,(int,np.integer)): shape = (shape,) if isinstance(shape,(int,np.integer)): shape = (shape,)
return self.copy(rotation=self.quaternion.reshape(tuple(shape)+(4,),order=order)) return self.copy(rotation=self.quaternion.reshape(tuple(shape)+(4,),order=order))
def broadcast_to(self,shape,mode = 'right'): def broadcast_to(self,shape,mode = 'right'):
""" """
Broadcast quaternion array to shape. Broadcast array.
Parameters Parameters
---------- ----------
@ -343,7 +343,7 @@ class Rotation:
def average(self,weights = None): def average(self,weights = None):
""" """
Average rotations along last dimension. Average along last array dimension.
Parameters Parameters
---------- ----------
@ -382,7 +382,7 @@ class Rotation:
def misorientation(self,other): def misorientation(self,other):
""" """
Calculate misorientation from self to other Rotation. Calculate misorientation to other Rotation.
Parameters Parameters
---------- ----------

View File

@ -7,7 +7,7 @@ import numpy as np
from . import util from . import util
class Table: class Table:
"""Store spreadsheet-like data.""" """Manipulate multi-dimensional spreadsheet-like data."""
def __init__(self,data,shapes,comments=None): def __init__(self,data,shapes,comments=None):
""" """
@ -77,13 +77,11 @@ class Table:
""" """
Load from ASCII table file. Load from ASCII table file.
In legacy style, the first line indicates the number of Initial comments are marked by '#', the first non-comment line
subsequent header lines as "N header", with the last header line being
interpreted as column labels.
Alternatively, initial comments are marked by '#', with the first non-comment line
containing the column labels. containing the column labels.
Vector data column labels are indicated by '1_v, 2_v, ..., n_v'.
Tensor data column labels are indicated by '3x3:1_T, 3x3:2_T, ..., 3x3:9_T'. - Vector data column labels are indicated by '1_v, 2_v, ..., n_v'.
- Tensor data column labels are indicated by '3x3:1_T, 3x3:2_T, ..., 3x3:9_T'.
Parameters Parameters
---------- ----------
@ -97,21 +95,13 @@ class Table:
f = fname f = fname
f.seek(0) f.seek(0)
try: f.seek(0)
N_comment_lines,keyword = f.readline().strip().split(maxsplit=1) comments = []
if keyword != 'header': line = f.readline().strip()
raise ValueError while line.startswith('#'):
else: comments.append(line.lstrip('#').strip())
comments = [f.readline().strip() for i in range(1,int(N_comment_lines))]
labels = f.readline().split()
except ValueError:
f.seek(0)
comments = []
line = f.readline().strip() line = f.readline().strip()
while line.startswith('#'): labels = line.split()
comments.append(line.lstrip('#').strip())
line = f.readline().strip()
labels = line.split()
shapes = {} shapes = {}
for label in labels: for label in labels:
@ -391,7 +381,7 @@ class Table:
return dup return dup
def save(self,fname,legacy=False): def save(self,fname):
""" """
Save as plain text file. Save as plain text file.
@ -399,9 +389,6 @@ class Table:
---------- ----------
fname : file, str, or pathlib.Path fname : file, str, or pathlib.Path
Filename or file for writing. Filename or file for writing.
legacy : Boolean, optional
Write table in legacy style, indicating header lines by "N header"
in contrast to using comment sign ('#') at beginning of lines.
""" """
seen = set() seen = set()
@ -416,13 +403,10 @@ class Table:
labels += [f'{util.srepr(self.shapes[l],"x")}:{i+1}_{l}' \ labels += [f'{util.srepr(self.shapes[l],"x")}:{i+1}_{l}' \
for i in range(np.prod(self.shapes[l]))] for i in range(np.prod(self.shapes[l]))]
header = ([f'{len(self.comments)+1} header'] + self.comments) if legacy else \
[f'# {comment}' for comment in self.comments]
try: try:
fhandle = open(fname,'w',newline='\n') fhandle = open(fname,'w',newline='\n')
except TypeError: except TypeError:
fhandle = fname fhandle = fname
for line in header + [' '.join(labels)]: fhandle.write(line+'\n') fhandle.write('\n'.join([f'# {c}' for c in self.comments] + [' '.join(labels)])+'\n')
self.data.to_csv(fhandle,sep=' ',na_rep='nan',index=False,header=False) self.data.to_csv(fhandle,sep=' ',na_rep='nan',index=False,header=False)

View File

@ -22,7 +22,7 @@ class VTK:
def __init__(self,vtk_data): def __init__(self,vtk_data):
""" """
Initialize from vtk dataset. New spatial visualization.
Parameters Parameters
---------- ----------

View File

@ -153,10 +153,12 @@ def scale_to_coprime(v):
"""Denominator of the square of a number.""" """Denominator of the square of a number."""
return fractions.Fraction(x ** 2).limit_denominator(MAX_DENOMINATOR).denominator return fractions.Fraction(x ** 2).limit_denominator(MAX_DENOMINATOR).denominator
def lcm(a, b): def lcm(a,b):
"""Least common multiple.""" """Least common multiple."""
# Python 3.9 provides math.lcm, see https://stackoverflow.com/questions/51716916. try:
return a * b // np.gcd(a, b) return np.lcm(a,b) # numpy > 1.18
except AttributeError:
return a * b // np.gcd(a, b)
m = (np.array(v) * reduce(lcm, map(lambda x: int(get_square_denominator(x)),v)) ** 0.5).astype(int) m = (np.array(v) * reduce(lcm, map(lambda x: int(get_square_denominator(x)),v)) ** 0.5).astype(int)
m = m//reduce(np.gcd,m) m = m//reduce(np.gcd,m)
@ -405,7 +407,7 @@ class return_message:
def __init__(self,message): def __init__(self,message):
""" """
Sets return message. Set return message.
Parameters Parameters
---------- ----------
@ -429,7 +431,7 @@ class _ProgressBar:
def __init__(self,total,prefix,bar_length): def __init__(self,total,prefix,bar_length):
""" """
Inititalize a progress bar to current time as basis for ETA estimation. Set current time as basis for ETA estimation.
Parameters Parameters
---------- ----------

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
180.0 45.00000000000001 180.0 1 1 180.0 45.00000000000001 180.0 1 1
270.0 45.00000000000001 90.0 1 2 270.0 45.00000000000001 90.0 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
146.75362934444064 9.976439066337804 256.395594327347 1 1 146.75362934444064 9.976439066337804 256.395594327347 1 1
356.59977719102034 43.39784965440254 12.173896584899929 1 2 356.59977719102034 43.39784965440254 12.173896584899929 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
166.39559432734697 9.976439066337804 236.75362934444058 1 1 166.39559432734697 9.976439066337804 236.75362934444058 1 1
352.1156357053931 43.82007387041961 14.074783631236542 1 2 352.1156357053931 43.82007387041961 14.074783631236542 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
114.20342833932975 10.52877936550932 204.20342833932972 1 1 114.20342833932975 10.52877936550932 204.20342833932972 1 1
94.3573968784815 80.40593177313954 311.22729452432543 1 2 94.3573968784815 80.40593177313954 311.22729452432543 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
96.91733794010702 83.13253115922213 314.5844440567886 1 1 96.91733794010702 83.13253115922213 314.5844440567886 1 1
173.082662059893 83.13253115922211 45.41555594321143 1 2 173.082662059893 83.13253115922211 45.41555594321143 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
135.41555594321144 83.13253115922213 173.082662059893 1 1 135.41555594321144 83.13253115922213 173.082662059893 1 1
260.26438968275465 90.0 135.0 1 2 260.26438968275465 90.0 135.0 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
0.0 45.00000000000001 0.0 1 1 0.0 45.00000000000001 0.0 1 1
90.0 45.00000000000001 270.0 1 2 90.0 45.00000000000001 270.0 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
283.60440567265294 9.976439066337804 33.24637065555936 1 1 283.60440567265294 9.976439066337804 33.24637065555936 1 1
167.8261034151001 43.397849654402556 183.40022280897963 1 2 167.8261034151001 43.397849654402556 183.40022280897963 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
303.24637065555936 9.976439066337804 13.604405672652977 1 1 303.24637065555936 9.976439066337804 13.604405672652977 1 1
165.92521636876344 43.82007387041961 187.88436429460683 1 2 165.92521636876344 43.82007387041961 187.88436429460683 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
335.7965716606702 10.528779365509317 65.79657166067024 1 1 335.7965716606702 10.528779365509317 65.79657166067024 1 1
228.77270547567446 80.40593177313953 85.64260312151849 1 2 228.77270547567446 80.40593177313953 85.64260312151849 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
225.41555594321144 83.13253115922213 83.08266205989301 1 1 225.41555594321144 83.13253115922213 83.08266205989301 1 1
134.58444405678856 83.13253115922211 6.917337940107012 1 2 134.58444405678856 83.13253115922211 6.917337940107012 1 2

View File

@ -1,4 +1,3 @@
1 header
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos 1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
6.9173379401070045 83.13253115922213 44.58444405678856 1 1 6.9173379401070045 83.13253115922213 44.58444405678856 1 1
45.0 89.99999999999999 279.7356103172453 1 2 45.0 89.99999999999999 279.7356103172453 1 2

View File

@ -60,13 +60,6 @@ class TestTable:
new = Table.load(f) new = Table.load(f)
assert all(default.data==new.data) and default.shapes == new.shapes assert all(default.data==new.data) and default.shapes == new.shapes
def test_write_read_legacy_style(self,default,tmp_path):
with open(tmp_path/'legacy.txt','w') as f:
default.save(f,legacy=True)
with open(tmp_path/'legacy.txt') as f:
new = Table.load(f)
assert all(default.data==new.data) and default.shapes == new.shapes
def test_write_invalid_format(self,default,tmp_path): def test_write_invalid_format(self,default,tmp_path):
with pytest.raises(TypeError): with pytest.raises(TypeError):
default.save(tmp_path/'shouldnotbethere.txt',format='invalid') default.save(tmp_path/'shouldnotbethere.txt',format='invalid')