From 3050471a2d95e4d036918ba5e3480426b617f4f3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 8 Oct 2020 18:05:03 +0200 Subject: [PATCH 1/9] avoid circular inclusion --- python/damask/__init__.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/python/damask/__init__.py b/python/damask/__init__.py index 955993607..600f64138 100644 --- a/python/damask/__init__.py +++ b/python/damask/__init__.py @@ -10,21 +10,21 @@ with open(_Path(__file__).parent/_Path('VERSION')) as _f: # make classes directly accessible as damask.Class from ._environment import Environment as _ # noqa environment = _() -from ._table import Table # noqa -from ._vtk import VTK # noqa -from ._colormap import Colormap # noqa -from ._rotation import Rotation # noqa -from ._lattice import Symmetry, Lattice# noqa -from ._orientation import Orientation # noqa -from ._result import Result # noqa -from ._geom import Geom # noqa -from ._config import Config # noqa -from ._configmaterial import ConfigMaterial # noqa -from . import solver # noqa from . import util # noqa from . import seeds # noqa -from . import grid_filters # noqa from . import mechanics # noqa +from . import solver # noqa +from . import grid_filters # noqa +from ._lattice import Symmetry, Lattice# noqa +from ._table import Table # noqa +from ._rotation import Rotation # noqa +from ._vtk import VTK # noqa +from ._colormap import Colormap # noqa +from ._orientation import Orientation # noqa +from ._config import Config # noqa +from ._configmaterial import ConfigMaterial # noqa +from ._geom import Geom # noqa +from ._result import Result # noqa From bdfbd2c62ea468f5a896a0c8dd7483b5de3f8d29 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 8 Oct 2020 18:05:15 +0200 Subject: [PATCH 2/9] dream3d file in an HDF5 file --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index b096658f8..c2785cf15 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,6 +8,7 @@ *.jpg binary *.hdf5 binary *.pdf binary +*.dream3d binary # ignore files from MSC.Marc in language statistics installation/mods_MarcMentat/20*/* linguist-vendored From 952ad4f8fec00552c2f100151b88e145368c7fd2 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 8 Oct 2020 18:33:40 +0200 Subject: [PATCH 3/9] functionality for geom generation in python lib --- processing/pre/geom_fromDREAM3D.py | 88 ++---------------------------- processing/pre/geom_fromTable.py | 57 ++----------------- python/damask/_geom.py | 38 ++++++++++++- 3 files changed, 44 insertions(+), 139 deletions(-) diff --git a/processing/pre/geom_fromDREAM3D.py b/processing/pre/geom_fromDREAM3D.py index daf7d2ab9..54ed4ca0a 100755 --- a/processing/pre/geom_fromDREAM3D.py +++ b/processing/pre/geom_fromDREAM3D.py @@ -1,12 +1,8 @@ #!/usr/bin/env python3 import os -import sys from optparse import OptionParser -import h5py -import numpy as np - import damask @@ -64,88 +60,12 @@ parser.set_defaults(pointwise = 'CellData', if options.basegroup is None: parser.error('No base group selected') -rootDir ='DataContainers' - - if filenames == []: parser.error('no input file specified.') for name in filenames: - damask.util.report(scriptName,name) + damask.util.report(scriptName,name) - errors = [] + geom = damask.Geom.load_DREAM3D(name,options.basegroup,options.pointwise) + damask.util.croak(geom) - inFile = h5py.File(name, 'r') - group_geom = os.path.join(rootDir,options.basegroup,'_SIMPL_GEOMETRY') - try: - size = inFile[os.path.join(group_geom,'DIMENSIONS')][...] \ - * inFile[os.path.join(group_geom,'SPACING')][...] - grid = inFile[os.path.join(group_geom,'DIMENSIONS')][...] - origin = inFile[os.path.join(group_geom,'ORIGIN')][...] - except KeyError: - errors.append('Geometry data ({}) not found'.format(group_geom)) - - - group_pointwise = os.path.join(rootDir,options.basegroup,options.pointwise) - if options.average is None: - label = 'Point' - - dataset = os.path.join(group_pointwise,options.quaternion) - try: - quats = np.reshape(inFile[dataset][...],(np.product(grid),4)) - rot = [damask.Rotation.from_quaternion(q,True,P=+1) for q in quats] - except KeyError: - errors.append('Pointwise orientation (quaternion) data ({}) not readable'.format(dataset)) - - dataset = os.path.join(group_pointwise,options.phase) - try: - phase = np.reshape(inFile[dataset][...],(np.product(grid))) - except KeyError: - errors.append('Pointwise phase data ({}) not readable'.format(dataset)) - - microstructure = np.arange(1,np.product(grid)+1,dtype=int).reshape(grid,order='F') - - - else: - label = 'Grain' - - dataset = os.path.join(group_pointwise,options.microstructure) - try: - microstructure = np.transpose(inFile[dataset][...].reshape(grid[::-1]),(2,1,0)) # convert from C ordering - except KeyError: - errors.append('Link between pointwise and grain average data ({}) not readable'.format(dataset)) - - group_average = os.path.join(rootDir,options.basegroup,options.average) - - dataset = os.path.join(group_average,options.quaternion) - try: - rot = [damask.Rotation.from_quaternion(q,True,P=+1) for q in inFile[dataset][...][1:]] # skip first entry (unindexed) - except KeyError: - errors.append('Average orientation data ({}) not readable'.format(dataset)) - - dataset = os.path.join(group_average,options.phase) - try: - phase = [i[0] for i in inFile[dataset][...]][1:] # skip first entry (unindexed) - except KeyError: - errors.append('Average phase data ({}) not readable'.format(dataset)) - - if errors != []: - damask.util.croak(errors) - continue - - config_header = [''] - for i in range(np.nanmax(microstructure)): - config_header += ['[{}{}]'.format(label,i+1), - '(gauss)\tphi1 {:.2f}\tPhi {:.2f}\tphi2 {:.2f}'.format(*rot[i].as_Eulers(degrees = True)), - ] - config_header += [''] - for i in range(np.nanmax(microstructure)): - config_header += ['[{}{}]'.format(label,i+1), - '(constituent)\tphase {}\ttexture {}\tfraction 1.0'.format(phase[i],i+1), - ] - - header = [scriptID + ' ' + ' '.join(sys.argv[1:])]\ - + config_header - geom = damask.Geom(microstructure,size,origin,comments=header) - damask.util.croak(geom) - - geom.save_ASCII(os.path.splitext(name)[0]+'.geom',compress=False) + geom.save_ASCII(os.path.splitext(name)[0]+'.geom',compress=False) diff --git a/processing/pre/geom_fromTable.py b/processing/pre/geom_fromTable.py index a0de6a4c5..d3cb2d50d 100755 --- a/processing/pre/geom_fromTable.py +++ b/processing/pre/geom_fromTable.py @@ -2,11 +2,8 @@ import os import sys -from io import StringIO from optparse import OptionParser -import numpy as np - import damask @@ -40,64 +37,20 @@ parser.add_option('-q', '--quaternion', dest = 'quaternion', type = 'string', metavar='string', help = 'quaternion label') -parser.add_option('--axes', - dest = 'axes', - type = 'string', nargs = 3, metavar = ' '.join(['string']*3), - help = 'orientation coordinate frame in terms of position coordinate frame [+x +y +z]') - -parser.set_defaults(pos = 'pos', - ) +parser.set_defaults(pos= 'pos') (options,filenames) = parser.parse_args() if filenames == []: filenames = [None] -if np.sum([options.quaternion is not None, - options.microstructure is not None]) != 1: - parser.error('need either microstructure or quaternion (and optionally phase) as input.') -if options.microstructure is not None and options.phase is not None: - parser.error('need either microstructure or phase (and mandatory quaternion) as input.') -if options.axes is not None and not set(options.axes).issubset(set(['x','+x','-x','y','+y','-y','z','+z','-z'])): - parser.error('invalid axes {} {} {}.'.format(*options.axes)) - for name in filenames: damask.util.report(scriptName,name) - table = damask.Table.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - table.sort_by(['{}_{}'.format(i,options.pos) for i in range(3,0,-1)]) # x fast, y slow - grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) + labels = [] + for l in [options.quaternion,options.phase,options.microstructure]: + if l is not None: labels.append(l) - config_header = table.comments - - if options.microstructure: - microstructure = table.get(options.microstructure).reshape(grid,order='F') - - elif options.quaternion: - q = table.get(options.quaternion) - phase = table.get(options.phase).astype(int) if options.phase else \ - np.ones((table.data.shape[0],1),dtype=int) - - unique,unique_inverse = np.unique(np.hstack((q,phase)),return_inverse=True,axis=0) - microstructure = unique_inverse.reshape(grid,order='F') + 1 - - config_header = [''] - for i,data in enumerate(unique): - ori = damask.Rotation(data[0:4]) - config_header += ['[Grain{}]'.format(i+1), - '(gauss)\tphi1 {:.2f}\tPhi {:.2f}\tphi2 {:.2f}'.format(*ori.as_Eulers(degrees = True)), - ] - if options.axes is not None: config_header += ['axes\t{} {} {}'.format(*options.axes)] - - config_header += [''] - for i,data in enumerate(unique): - config_header += ['[Grain{}]'.format(i+1), - '(constituent)\tphase {}\ttexture {}\tfraction 1.0'.format(int(data[4]),i+1), - ] - - header = [scriptID + ' ' + ' '.join(sys.argv[1:])]\ - + config_header - geom = damask.Geom(microstructure,size,origin, - comments=header) + geom = damask.Geom.load_table(name,options.pos,labels) damask.util.croak(geom) geom.save_ASCII(sys.stdout if name is None else os.path.splitext(name)[0]+'.geom',compress=False) diff --git a/python/damask/_geom.py b/python/damask/_geom.py index 2ccbb1988..ec65154bb 100644 --- a/python/damask/_geom.py +++ b/python/damask/_geom.py @@ -1,15 +1,18 @@ import copy import multiprocessing as mp from functools import partial +from os import path import numpy as np +import h5py from scipy import ndimage,spatial from . import environment -from . import Rotation from . import VTK from . import util from . import grid_filters +from . import Table +from . import Rotation class Geom: @@ -353,7 +356,7 @@ class Geom: Number of periods per unit cell. Defaults to 1. materials : (int, int), optional Material IDs. Defaults to (1,2). - + Notes ----- The following triply-periodic minimal surfaces are implemented: @@ -397,6 +400,35 @@ class Geom: ) + @staticmethod + def load_DREAM3D(fname,base_group,point_data=None,material='FeatureIds'): + root_dir ='DataContainers' + f = h5py.File(fname, 'r') + g = path.join(root_dir,base_group,'_SIMPL_GEOMETRY') + size = f[path.join(g,'DIMENSIONS')][()] * f[path.join(g,'SPACING')][()] + grid = f[path.join(g,'DIMENSIONS')][()] + origin = f[path.join(g,'ORIGIN')][()] + group_pointwise = path.join(root_dir,base_group,point_data) + + ma = np.arange(1,np.product(grid)+1,dtype=int) if point_data is None else \ + np.reshape(f[path.join(group_pointwise,material)],grid.prod()) + + return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','from_DREAM3D')) + + + @staticmethod + def load_table(fname,coordinates,labels): + table = Table.load(fname).sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) + + grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(table.get(coordinates)) + + labels_ = [labels] if isinstance(labels,str) else labels + _,unique_inverse = np.unique(np.hstack([table.get(l) for l in labels_]),return_inverse=True,axis=0) + ma = unique_inverse.reshape(grid,order='F') + 1 + + return Geom(ma,size,origin,util.execution_stamp('Geom','from_table')) + + def save(self,fname,compress=True): """ Generates vtk rectilinear grid. @@ -536,7 +568,7 @@ class Geom: coords_rot = R.broadcast_to(tuple(self.grid))@coords with np.errstate(all='ignore'): - mask = np.where(np.sum(np.power(coords_rot/r,2.0**exponent),axis=-1) > 1.0,True,False) + mask = np.sum(np.power(coords_rot/r,2.0**np.array(exponent)),axis=-1) > 1.0 if periodic: # translate back to center mask = np.roll(mask,((c-np.ones(3)*.5)*self.grid).astype(int),(0,1,2)) From 6ecaaa31c93ad9d41524f1abe8b93c6aafff1a32 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 8 Oct 2020 21:29:58 +0200 Subject: [PATCH 4/9] fairly general function to generate material configuration --- python/damask/_configmaterial.py | 62 +++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 26006fef7..dacc0d080 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -62,10 +62,10 @@ class ConfigMaterial(Config): print(f'No lattice specified in phase {k}') ok = False - #for k,v in self['homogenization'].items(): - # if 'N_constituents' not in v: - # print(f'No. of constituents not specified in homogenization {k}'} - # ok = False + for k,v in self['homogenization'].items(): + if 'N_constituents' not in v: + print(f'No. of constituents not specified in homogenization {k}') + ok = False if phase - set(self['phase']): print(f'Phase(s) {phase-set(self["phase"])} missing') @@ -158,3 +158,57 @@ class ConfigMaterial(Config): except KeyError: continue return dup + + + def material_add(self,constituents,**kwargs): + """ + Add material entries. + + Parameters + ---------- + constituents: scalar or numpy.ndarray + **kwargs: tbd + + Examples + -------- + m = damask.ConfigMaterial() + O = damask.Rotation.from_random(3).as_quaternion() + phase = ['Aluminum','Steel','Aluminum'] + + m.material_add(constituents={'phase':phase,'O':O},homogenization='SX') + + """ + c = [{'constituents':u} for u in ConfigMaterial._constituents(**constituents)] + for k,v in kwargs.items(): + if isinstance(v,np.ndarray): + for i,vv in enumerate(v): + c[i][k] = [w.item() for w in vv] if isinstance(vv,np.ndarray) else vv.item() + else: + for i in range(len(c)): + c[i][k] = v + dup = copy.deepcopy(self) + if 'material' not in dup: dup['material'] = [] + dup['material'] +=c + + return dup + + + @staticmethod + def _constituents(N=1,**kwargs): + for v in kwargs.values(): + if hasattr(v,'__len__') and not isinstance(v,str): N_material = len(v) + + if N == 1: + m = [[{'fraction':1.0}] for _ in range(N_material)] + for k,v in kwargs.items(): + if hasattr(v,'__len__') and not isinstance(v,str): + if len(v) != N_material: + raise ValueError + 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() + else: + for i in range(N_material): + m[i][0][k] = v + return m + else: + raise NotImplementedError From 0c68d293b643005b9fef3f1dbf9f8bdef4f27989 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 9 Oct 2020 07:44:05 +0200 Subject: [PATCH 5/9] N_constituents is now a general homog property --- python/tests/reference/ConfigMaterial/material.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/tests/reference/ConfigMaterial/material.yaml b/python/tests/reference/ConfigMaterial/material.yaml index 5c006c99c..97c6504bb 100644 --- a/python/tests/reference/ConfigMaterial/material.yaml +++ b/python/tests/reference/ConfigMaterial/material.yaml @@ -1,8 +1,10 @@ homogenization: SX: + N_constituents: 2 mech: {type: none} Taylor: - mech: {N_constituents: 2, type: isostrain} + N_constituents: 2 + mech: {type: isostrain} material: - constituents: From 75401dd280ea9f86074652b049a0247c7a5cad53 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 9 Oct 2020 07:45:20 +0200 Subject: [PATCH 6/9] generate configuration from table --- python/damask/_configmaterial.py | 24 ++++++++++++++++++++++-- python/damask/_table.py | 4 ++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index dacc0d080..0ad76d99c 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -5,6 +5,7 @@ import numpy as np from . import Config from . import Lattice from . import Rotation +from . import Table class ConfigMaterial(Config): """Material configuration.""" @@ -23,6 +24,22 @@ class ConfigMaterial(Config): """ super().save(fname,**kwargs) + + @staticmethod + def load_table(fname,coordinates=None,constituents={},**kwargs): + t = Table.load(fname) + if coordinates is not None: t = t.sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) + constituents_ = {k:t.get(v) for k,v in constituents.items()} + kwargs_ = {k:t.get(v) for k,v in kwargs.items()} + + _,idx = np.unique(np.hstack(list({**constituents_,**kwargs_}.values())),return_index=True,axis=0) + + constituents_ = {k:v[idx].squeeze() for k,v in constituents_.items()} + kwargs_ = {k:v[idx].squeeze() for k,v in kwargs_.items()} + + return ConfigMaterial().material_add(constituents_,**kwargs_) + + @property def is_complete(self): """Check for completeness.""" @@ -180,7 +197,9 @@ class ConfigMaterial(Config): """ c = [{'constituents':u} for u in ConfigMaterial._constituents(**constituents)] for k,v in kwargs.items(): - if isinstance(v,np.ndarray): + if hasattr(v,'__len__') and not isinstance(v,str): + if len(v) != len(c): + raise ValueError('len mismatch 1') for i,vv in enumerate(v): c[i][k] = [w.item() for w in vv] if isinstance(vv,np.ndarray) else vv.item() else: @@ -195,6 +214,7 @@ class ConfigMaterial(Config): @staticmethod def _constituents(N=1,**kwargs): + """Construct list of constituents.""" for v in kwargs.values(): if hasattr(v,'__len__') and not isinstance(v,str): N_material = len(v) @@ -203,7 +223,7 @@ class ConfigMaterial(Config): for k,v in kwargs.items(): if hasattr(v,'__len__') and not isinstance(v,str): if len(v) != N_material: - raise ValueError + raise ValueError('len mismatch 2') 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() else: diff --git a/python/damask/_table.py b/python/damask/_table.py index 431cf1886..dd8df97b0 100644 --- a/python/damask/_table.py +++ b/python/damask/_table.py @@ -33,6 +33,10 @@ class Table: """Brief overview.""" return util.srepr(self.comments)+'\n'+self.data.__repr__() + def __len__(self): + """Number of rows.""" + return len(self.data) + def __copy__(self): """Copy Table.""" return copy.deepcopy(self) From 347c88cbb66afae7e24764e814ade89aad19b2ed Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 9 Oct 2020 14:19:19 +0200 Subject: [PATCH 7/9] documented --- python/damask/_configmaterial.py | 83 ++++++++++++++++++++++++---- python/damask/_geom.py | 94 ++++++++++++++++++++++---------- 2 files changed, 137 insertions(+), 40 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 0ad76d99c..3b3d22a0e 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -2,6 +2,7 @@ import copy import numpy as np +from . import grid_filters from . import Config from . import Lattice from . import Rotation @@ -18,7 +19,7 @@ class ConfigMaterial(Config): ---------- fname : file, str, or pathlib.Path, optional Filename or file for writing. Defaults to 'material.yaml'. - **kwargs : dict + **kwargs Keyword arguments parsed to yaml.dump. """ @@ -27,8 +28,50 @@ class ConfigMaterial(Config): @staticmethod def load_table(fname,coordinates=None,constituents={},**kwargs): + """ + Load from an ASCII table. + + Parameters + ---------- + fname : str, file handle, or damask.Table + Table that contains material information. + coordinates : str, optional + Label of spatial coordiates. Used for sorting and performing a + sanity check. Default to None, in which case no sorting or checking is + peformed. + constituents : dict, optional + Entries for 'constituents'. The key is the name and the value specifies + the label of the data column in the table + **kwargs + Keyword arguments where the key is the name and the value specifies + the label of the data column in the table + + Examples + -------- + >>> import damask + >>> import damask.ConfigMaterial as cm + >>> damask.Table.load('small.txt') + pos pos pos qu qu qu qu phase homog + 0 0 0 0 0.19 0.8 0.24 -0.51 Aluminum SX + 1 1 0 0 0.8 0.19 0.24 -0.51 Steel SX + >>> cm.load_table('small.txt','pos',{'O':'qu','phase':'phase'},homogenization='h') + material: + - constituents: + - O: [0.19, 0.8, 0.24, -0.51] + fraction: 1.0 + phase: Aluminum + homogenization: SX + - constituents: + - O: [0.8, 0.19, 0.24, -0.51] + fraction: 1.0 + phase: Steel + homogenization: SX + + """ t = Table.load(fname) - if coordinates is not None: t = t.sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) + if coordinates is not None: + t = t.sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) + grid_filters.coord0_check(t.get(coordinates)) constituents_ = {k:t.get(v) for k,v in constituents.items()} kwargs_ = {k:t.get(v) for k,v in kwargs.items()} @@ -183,17 +226,37 @@ class ConfigMaterial(Config): Parameters ---------- - constituents: scalar or numpy.ndarray - **kwargs: tbd + constituents : dict + Entries for 'constituents'. The key is the name and the value specifies + the label of the data column in the table + **kwargs + Keyword arguments where the key is the name and the value specifies + the label of the data column in the table Examples -------- - m = damask.ConfigMaterial() - O = damask.Rotation.from_random(3).as_quaternion() - phase = ['Aluminum','Steel','Aluminum'] - - m.material_add(constituents={'phase':phase,'O':O},homogenization='SX') - + >>> import damask + >>> m = damask.ConfigMaterial() + >>> O = damask.Rotation.from_random(3).as_quaternion() + >>> phase = ['Aluminum','Steel','Aluminum'] + >>> m.material_add(constituents={'phase':phase,'O':O},homogenization='SX') + material: + - constituents: + - O: [0.577764, -0.146299, -0.617669, 0.513010] + fraction: 1.0 + phase: Aluminum + homogenization: SX + - constituents: + - O: [0.184176, 0.340305, 0.737247, 0.553840] + fraction: 1.0 + phase: Steel + homogenization: SX + - constituents: + - O: [0.0886257, -0.144848, 0.615674, -0.769487] + fraction: 1.0 + phase: Aluminum + homogenization: SX + """ c = [{'constituents':u} for u in ConfigMaterial._constituents(**constituents)] for k,v in kwargs.items(): diff --git a/python/damask/_geom.py b/python/damask/_geom.py index ec65154bb..7a5b20fcc 100644 --- a/python/damask/_geom.py +++ b/python/damask/_geom.py @@ -210,6 +210,69 @@ class Geom: return Geom(material.reshape(grid,order='F'),size,origin,comments) + + @staticmethod + def load_DREAM3D(fname,base_group,point_data=None,material='FeatureIds'): + """ + Load a DREAM.3D file. + + Parameters + ---------- + fname : str + Filename of the DREAM.3D file + base_group : str + Name of the group (folder) below 'DataContainers'. For example + 'SyntheticVolumeDataContainer'. + point_data : str, optional + Name of the group (folder) containing the point wise material data, + for example 'CellData'. Defaults to None, in which case points consecutively numbered. + material : str, optional + Name of the dataset containing the material ID. Defaults to + 'FeatureIds'. + + """ + root_dir ='DataContainers' + f = h5py.File(fname, 'r') + g = path.join(root_dir,base_group,'_SIMPL_GEOMETRY') + size = f[path.join(g,'DIMENSIONS')][()] * f[path.join(g,'SPACING')][()] + grid = f[path.join(g,'DIMENSIONS')][()] + origin = f[path.join(g,'ORIGIN')][()] + group_pointwise = path.join(root_dir,base_group,point_data) + + ma = np.arange(1,np.product(grid)+1,dtype=int) if point_data is None else \ + np.reshape(f[path.join(group_pointwise,material)],grid.prod()) + + return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','load_DREAM3D')) + + + @staticmethod + def load_table(fname,coordinates,labels): + """ + Load an ASCII table. + + Parameters + ---------- + fname : str, file handle, or damask.Table + Table that contains geometry information. + coordinates : str + Label of the column containing the spatial coordinates. + labels : str or list of str + Label(s) of the columns containing the material definition. + Each unique combintation of values results in a material. + + """ + table = (fname if isinstance(fname,Table) else Table.load(fname)). \ + sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) + + grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(table.get(coordinates)) + + labels_ = [labels] if isinstance(labels,str) else labels + _,unique_inverse = np.unique(np.hstack([table.get(l) for l in labels_]),return_inverse=True,axis=0) + ma = unique_inverse.reshape(grid,order='F') + 1 + + return Geom(ma,size,origin,util.execution_stamp('Geom','load_table')) + + @staticmethod def _find_closest_seed(seeds, weights, point): return np.argmin(np.sum((np.broadcast_to(point,(len(seeds),3))-seeds)**2,axis=1) - weights) @@ -400,38 +463,9 @@ class Geom: ) - @staticmethod - def load_DREAM3D(fname,base_group,point_data=None,material='FeatureIds'): - root_dir ='DataContainers' - f = h5py.File(fname, 'r') - g = path.join(root_dir,base_group,'_SIMPL_GEOMETRY') - size = f[path.join(g,'DIMENSIONS')][()] * f[path.join(g,'SPACING')][()] - grid = f[path.join(g,'DIMENSIONS')][()] - origin = f[path.join(g,'ORIGIN')][()] - group_pointwise = path.join(root_dir,base_group,point_data) - - ma = np.arange(1,np.product(grid)+1,dtype=int) if point_data is None else \ - np.reshape(f[path.join(group_pointwise,material)],grid.prod()) - - return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','from_DREAM3D')) - - - @staticmethod - def load_table(fname,coordinates,labels): - table = Table.load(fname).sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) - - grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(table.get(coordinates)) - - labels_ = [labels] if isinstance(labels,str) else labels - _,unique_inverse = np.unique(np.hstack([table.get(l) for l in labels_]),return_inverse=True,axis=0) - ma = unique_inverse.reshape(grid,order='F') + 1 - - return Geom(ma,size,origin,util.execution_stamp('Geom','from_table')) - - def save(self,fname,compress=True): """ - Generates vtk rectilinear grid. + Store as vtk rectilinear grid. Parameters ---------- From 57180952ecc3a2d8b36c7c26f2aa993bebb67a75 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 9 Oct 2020 19:05:05 +0200 Subject: [PATCH 8/9] typo --- python/damask/_configmaterial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 3b3d22a0e..2d897e79f 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -54,7 +54,7 @@ class ConfigMaterial(Config): pos pos pos qu qu qu qu phase homog 0 0 0 0 0.19 0.8 0.24 -0.51 Aluminum SX 1 1 0 0 0.8 0.19 0.24 -0.51 Steel SX - >>> cm.load_table('small.txt','pos',{'O':'qu','phase':'phase'},homogenization='h') + >>> cm.load_table('small.txt','pos',{'O':'qu','phase':'phase'},homogenization='homog') material: - constituents: - O: [0.19, 0.8, 0.24, -0.51] From 06d11a72da97f25b6c6c82f9b2a75998915bd089 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 9 Oct 2020 19:19:05 +0200 Subject: [PATCH 9/9] better fitting name load implies a more direct takeover. --- processing/pre/geom_fromTable.py | 3 ++- python/damask/_configmaterial.py | 18 ++++++++++-------- python/damask/_geom.py | 16 +++++++--------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/processing/pre/geom_fromTable.py b/processing/pre/geom_fromTable.py index d3cb2d50d..29a8b8852 100755 --- a/processing/pre/geom_fromTable.py +++ b/processing/pre/geom_fromTable.py @@ -50,7 +50,8 @@ for name in filenames: for l in [options.quaternion,options.phase,options.microstructure]: if l is not None: labels.append(l) - geom = damask.Geom.load_table(name,options.pos,labels) + t = damask.Table.load(name) + geom = damask.Geom.from_table(t,options.pos,labels) damask.util.croak(geom) geom.save_ASCII(sys.stdout if name is None else os.path.splitext(name)[0]+'.geom',compress=False) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 2d897e79f..a7ecec108 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -6,7 +6,6 @@ from . import grid_filters from . import Config from . import Lattice from . import Rotation -from . import Table class ConfigMaterial(Config): """Material configuration.""" @@ -27,13 +26,13 @@ class ConfigMaterial(Config): @staticmethod - def load_table(fname,coordinates=None,constituents={},**kwargs): + def from_table(table,coordinates=None,constituents={},**kwargs): """ Load from an ASCII table. Parameters ---------- - fname : str, file handle, or damask.Table + table : damask.Table Table that contains material information. coordinates : str, optional Label of spatial coordiates. Used for sorting and performing a @@ -50,11 +49,12 @@ class ConfigMaterial(Config): -------- >>> import damask >>> import damask.ConfigMaterial as cm - >>> damask.Table.load('small.txt') + >>> t = damask.Table.load('small.txt') + >>> t pos pos pos qu qu qu qu phase homog 0 0 0 0 0.19 0.8 0.24 -0.51 Aluminum SX 1 1 0 0 0.8 0.19 0.24 -0.51 Steel SX - >>> cm.load_table('small.txt','pos',{'O':'qu','phase':'phase'},homogenization='homog') + >>> cm.from_table(t,'pos',{'O':'qu','phase':'phase'},homogenization='homog') material: - constituents: - O: [0.19, 0.8, 0.24, -0.51] @@ -68,10 +68,12 @@ class ConfigMaterial(Config): homogenization: SX """ - t = Table.load(fname) if coordinates is not None: - t = t.sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) + t = table.sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) grid_filters.coord0_check(t.get(coordinates)) + else: + t = table + constituents_ = {k:t.get(v) for k,v in constituents.items()} kwargs_ = {k:t.get(v) for k,v in kwargs.items()} @@ -256,7 +258,7 @@ class ConfigMaterial(Config): fraction: 1.0 phase: Aluminum homogenization: SX - + """ c = [{'constituents':u} for u in ConfigMaterial._constituents(**constituents)] for k,v in kwargs.items(): diff --git a/python/damask/_geom.py b/python/damask/_geom.py index 7a5b20fcc..eb4dd055e 100644 --- a/python/damask/_geom.py +++ b/python/damask/_geom.py @@ -11,7 +11,6 @@ from . import environment from . import VTK from . import util from . import grid_filters -from . import Table from . import Rotation @@ -246,14 +245,14 @@ class Geom: @staticmethod - def load_table(fname,coordinates,labels): + def from_table(table,coordinates,labels): """ Load an ASCII table. Parameters ---------- - fname : str, file handle, or damask.Table - Table that contains geometry information. + table : damask.Table + Table that contains material information. coordinates : str Label of the column containing the spatial coordinates. labels : str or list of str @@ -261,16 +260,15 @@ class Geom: Each unique combintation of values results in a material. """ - table = (fname if isinstance(fname,Table) else Table.load(fname)). \ - sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) + t = table.sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) - grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(table.get(coordinates)) + grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(t.get(coordinates)) labels_ = [labels] if isinstance(labels,str) else labels - _,unique_inverse = np.unique(np.hstack([table.get(l) for l in labels_]),return_inverse=True,axis=0) + _,unique_inverse = np.unique(np.hstack([t.get(l) for l in labels_]),return_inverse=True,axis=0) ma = unique_inverse.reshape(grid,order='F') + 1 - return Geom(ma,size,origin,util.execution_stamp('Geom','load_table')) + return Geom(ma,size,origin,util.execution_stamp('Geom','from_table')) @staticmethod