rename: grid -> cells
This commit is contained in:
parent
676840ae1b
commit
ac0a20696c
2
PRIVATE
2
PRIVATE
|
@ -1 +1 @@
|
|||
Subproject commit 68cde52291ebb683ca6f610879f2ae28372597a7
|
||||
Subproject commit fc27bbd6e028aa73545327aebdb206840063e135
|
|
@ -64,7 +64,7 @@ for name in filenames:
|
|||
|
||||
geom = damask.Geom.load(StringIO(''.join(sys.stdin.read())) if name is None else name)
|
||||
|
||||
grid_original = geom.grid
|
||||
grid_original = geom.cells
|
||||
damask.util.croak(geom)
|
||||
material = np.tile(geom.material,np.where(grid_original == 1, 2,1)) # make one copy along dimensions with grid == 1
|
||||
grid = np.array(material.shape)
|
||||
|
|
|
@ -201,7 +201,7 @@ for name in filenames:
|
|||
|
||||
cmds = [\
|
||||
init(),
|
||||
mesh(geom.grid,geom.size),
|
||||
mesh(geom.cells,geom.size),
|
||||
materials(),
|
||||
geometry(),
|
||||
initial_conditions(material),
|
||||
|
|
|
@ -212,7 +212,7 @@ points = np.array(options.grid).prod().astype('float')
|
|||
# ----------- calculate target distribution and bin edges
|
||||
targetGeom = damask.Geom.load_ASCII(os.path.splitext(os.path.basename(options.target))[0]+'.geom')
|
||||
nMaterials = len(np.unique(targetGeom.material))
|
||||
targetVolFrac = np.bincount(targetGeom.material.flatten())/targetGeom.grid.prod().astype(np.float)
|
||||
targetVolFrac = np.bincount(targetGeom.material.flatten())/targetGeom.cells.prod().astype(np.float)
|
||||
target = []
|
||||
for i in range(1,nMaterials+1):
|
||||
targetHist,targetBins = np.histogram(targetVolFrac,bins=i) #bin boundaries
|
||||
|
|
|
@ -54,13 +54,13 @@ for name in filenames:
|
|||
damask.util.report(scriptName,name)
|
||||
geom = damask.Geom.load_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name)
|
||||
|
||||
offset =(np.amin(options.box, axis=1)*geom.grid/geom.size).astype(int)
|
||||
offset =(np.amin(options.box, axis=1)*geom.cells/geom.size).astype(int)
|
||||
box = np.amax(options.box, axis=1) \
|
||||
- np.amin(options.box, axis=1)
|
||||
|
||||
Nx = int(options.N/np.sqrt(options.N*geom.size[1]*box[1]/geom.size[0]/box[0]))
|
||||
Ny = int(options.N/np.sqrt(options.N*geom.size[0]*box[0]/geom.size[1]/box[1]))
|
||||
Nz = int(box[2]*geom.grid[2])
|
||||
Nz = int(box[2]*geom.cells[2])
|
||||
|
||||
damask.util.croak('poking {} x {} x {} in box {} {} {}...'.format(Nx,Ny,Nz,*box))
|
||||
|
||||
|
@ -70,12 +70,12 @@ for name in filenames:
|
|||
n = 0
|
||||
for i in range(Nx):
|
||||
for j in range(Ny):
|
||||
g[0] = round((i+0.5)*box[0]*geom.grid[0]/Nx-0.5)+offset[0]
|
||||
g[1] = round((j+0.5)*box[1]*geom.grid[1]/Ny-0.5)+offset[1]
|
||||
g[0] = round((i+0.5)*box[0]*geom.cells[0]/Nx-0.5)+offset[0]
|
||||
g[1] = round((j+0.5)*box[1]*geom.cells[1]/Ny-0.5)+offset[1]
|
||||
for k in range(Nz):
|
||||
g[2] = k + offset[2]
|
||||
g %= geom.grid
|
||||
seeds[n,0:3] = (g+0.5)/geom.grid # normalize coordinates to box
|
||||
g %= geom.cells
|
||||
seeds[n,0:3] = (g+0.5)/geom.cells # normalize coordinates to box
|
||||
seeds[n, 3] = geom.material[g[0],g[1],g[2]]
|
||||
if options.x: g[0] += 1
|
||||
if options.y: g[1] += 1
|
||||
|
@ -85,7 +85,7 @@ for name in filenames:
|
|||
comments = geom.comments \
|
||||
+ [scriptID + ' ' + ' '.join(sys.argv[1:]),
|
||||
'poking\ta {}\tb {}\tc {}'.format(Nx,Ny,Nz),
|
||||
'grid\ta {}\tb {}\tc {}'.format(*geom.grid),
|
||||
'grid\ta {}\tb {}\tc {}'.format(*geom.cells),
|
||||
'size\tx {}\ty {}\tz {}'.format(*geom.size),
|
||||
'origin\tx {}\ty {}\tz {}'.format(*geom.origin),
|
||||
]
|
||||
|
|
|
@ -225,7 +225,7 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
def save_paraview(self,fname=None):
|
||||
"""
|
||||
Write colormap to JSON file for Paraview.
|
||||
Save as JSON file for use in Paraview.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -260,7 +260,7 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
def save_ASCII(self,fname=None):
|
||||
"""
|
||||
Write colormap to ASCII table.
|
||||
Save as ASCII file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -286,7 +286,7 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
def save_GOM(self,fname=None):
|
||||
"""
|
||||
Write colormap to GOM Aramis compatible format.
|
||||
Save as ASCII file for use in GOM Aramis.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -314,7 +314,7 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
def save_gmsh(self,fname=None):
|
||||
"""
|
||||
Write colormap to Gmsh compatible format.
|
||||
Save as ASCII file for use in gmsh.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
|
@ -44,7 +44,7 @@ class Geom:
|
|||
def __repr__(self):
|
||||
"""Basic information on geometry definition."""
|
||||
return util.srepr([
|
||||
f'grid a b c: {util.srepr(self.grid, " x ")}',
|
||||
f'cells a b c: {util.srepr(self.cells, " x ")}',
|
||||
f'size x y z: {util.srepr(self.size, " x ")}',
|
||||
f'origin x y z: {util.srepr(self.origin," ")}',
|
||||
f'# materials: {self.N_materials}',
|
||||
|
@ -73,9 +73,9 @@ class Geom:
|
|||
|
||||
"""
|
||||
message = []
|
||||
if np.any(other.grid != self.grid):
|
||||
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 np.any(other.cells != self.cells):
|
||||
message.append(util.deemph(f'cells a b c: {util.srepr(other.cells," x ")}'))
|
||||
message.append(util.emph( f'cells a b c: {util.srepr( self.cells," x ")}'))
|
||||
|
||||
if not np.allclose(other.size,self.size):
|
||||
message.append(util.deemph(f'size x y z: {util.srepr(other.size," x ")}'))
|
||||
|
@ -150,8 +150,8 @@ class Geom:
|
|||
|
||||
|
||||
@property
|
||||
def grid(self):
|
||||
"""Grid dimension of geometry."""
|
||||
def cells(self):
|
||||
"""Number of cells in x,y,z direction."""
|
||||
return np.asarray(self.material.shape)
|
||||
|
||||
|
||||
|
@ -164,7 +164,7 @@ class Geom:
|
|||
@staticmethod
|
||||
def load(fname):
|
||||
"""
|
||||
Read a VTK rectilinear grid.
|
||||
Load from VTK rectilinear grid file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -175,10 +175,10 @@ class Geom:
|
|||
"""
|
||||
v = VTK.load(fname if str(fname).endswith('.vtr') else str(fname)+'.vtr')
|
||||
comments = v.get_comments()
|
||||
grid = np.array(v.vtk_data.GetDimensions())-1
|
||||
bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
|
||||
cells = np.array(v.vtk_data.GetDimensions())-1
|
||||
bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
|
||||
|
||||
return Geom(material = v.get('material').reshape(grid,order='F'),
|
||||
return Geom(material = v.get('material').reshape(cells,order='F'),
|
||||
size = bbox[1] - bbox[0],
|
||||
origin = bbox[0],
|
||||
comments=comments)
|
||||
|
@ -187,7 +187,7 @@ class Geom:
|
|||
@staticmethod
|
||||
def load_ASCII(fname):
|
||||
"""
|
||||
Read a geom file.
|
||||
Load from geom file.
|
||||
|
||||
Storing geometry files in ASCII format is deprecated.
|
||||
This function will be removed in a future version of DAMASK.
|
||||
|
@ -219,7 +219,7 @@ class Geom:
|
|||
items = line.split('#')[0].lower().strip().split()
|
||||
key = items[0] if items else ''
|
||||
if key == 'grid':
|
||||
grid = np.array([ int(dict(zip(items[1::2],items[2::2]))[i]) for i in ['a','b','c']])
|
||||
cells = np.array([ int(dict(zip(items[1::2],items[2::2]))[i]) for i in ['a','b','c']])
|
||||
elif key == 'size':
|
||||
size = np.array([float(dict(zip(items[1::2],items[2::2]))[i]) for i in ['x','y','z']])
|
||||
elif key == 'origin':
|
||||
|
@ -227,7 +227,7 @@ class Geom:
|
|||
else:
|
||||
comments.append(line.strip())
|
||||
|
||||
material = np.empty(grid.prod()) # initialize as flat array
|
||||
material = np.empty(cells.prod()) # initialize as flat array
|
||||
i = 0
|
||||
for line in content[header_length:]:
|
||||
items = line.split('#')[0].split()
|
||||
|
@ -242,19 +242,19 @@ class Geom:
|
|||
material[i:i+len(items)] = items
|
||||
i += len(items)
|
||||
|
||||
if i != grid.prod():
|
||||
raise TypeError(f'Invalid file: expected {grid.prod()} entries, found {i}')
|
||||
if i != cells.prod():
|
||||
raise TypeError(f'Invalid file: expected {cells.prod()} entries, found {i}')
|
||||
|
||||
if not np.any(np.mod(material,1) != 0.0): # no float present
|
||||
material = material.astype('int') - (1 if material.min() > 0 else 0)
|
||||
|
||||
return Geom(material.reshape(grid,order='F'),size,origin,comments)
|
||||
return Geom(material.reshape(cells,order='F'),size,origin,comments)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def load_DREAM3D(fname,base_group,point_data=None,material='FeatureIds'):
|
||||
"""
|
||||
Load a DREAM.3D file.
|
||||
Load from DREAM.3D file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -274,21 +274,21 @@ class Geom:
|
|||
root_dir ='DataContainers'
|
||||
f = h5py.File(fname, 'r')
|
||||
g = path.join(root_dir,base_group,'_SIMPL_GEOMETRY')
|
||||
grid = f[path.join(g,'DIMENSIONS')][()]
|
||||
size = f[path.join(g,'SPACING')][()] * grid
|
||||
cells = f[path.join(g,'DIMENSIONS')][()]
|
||||
size = f[path.join(g,'SPACING')][()] * cells
|
||||
origin = f[path.join(g,'ORIGIN')][()]
|
||||
|
||||
ma = np.arange(grid.prod(),dtype=int) \
|
||||
ma = np.arange(cells.prod(),dtype=int) \
|
||||
if point_data is None else \
|
||||
np.reshape(f[path.join(root_dir,base_group,point_data,material)],grid.prod())
|
||||
np.reshape(f[path.join(root_dir,base_group,point_data,material)],cells.prod())
|
||||
|
||||
return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','load_DREAM3D'))
|
||||
return Geom(ma.reshape(cells,order='F'),size,origin,util.execution_stamp('Geom','load_DREAM3D'))
|
||||
|
||||
|
||||
@staticmethod
|
||||
def from_table(table,coordinates,labels):
|
||||
"""
|
||||
Derive geometry from an ASCII table.
|
||||
Generate grid from ASCII table.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -302,15 +302,15 @@ class Geom:
|
|||
Each unique combintation of values results in one material ID.
|
||||
|
||||
"""
|
||||
grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(table.get(coordinates))
|
||||
cells,size,origin = grid_filters.cell_coord0_gridSizeOrigin(table.get(coordinates))
|
||||
|
||||
labels_ = [labels] if isinstance(labels,str) else labels
|
||||
unique,unique_inverse = np.unique(np.hstack([table.get(l) for l in labels_]),return_inverse=True,axis=0)
|
||||
|
||||
ma = np.arange(grid.prod()) if len(unique) == grid.prod() else \
|
||||
ma = np.arange(cells.prod()) if len(unique) == cells.prod() else \
|
||||
np.arange(unique.size)[np.argsort(pd.unique(unique_inverse))][unique_inverse]
|
||||
|
||||
return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','from_table'))
|
||||
return Geom(ma.reshape(cells,order='F'),size,origin,util.execution_stamp('Geom','from_table'))
|
||||
|
||||
|
||||
@staticmethod
|
||||
|
@ -318,14 +318,14 @@ class Geom:
|
|||
return np.argmin(np.sum((np.broadcast_to(point,(len(seeds),3))-seeds)**2,axis=1) - weights)
|
||||
|
||||
@staticmethod
|
||||
def from_Laguerre_tessellation(grid,size,seeds,weights,material=None,periodic=True):
|
||||
def from_Laguerre_tessellation(cells,size,seeds,weights,material=None,periodic=True):
|
||||
"""
|
||||
Generate geometry from Laguerre tessellation.
|
||||
Generate grid from Laguerre tessellation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid : int numpy.ndarray of shape (3)
|
||||
Number of grid points in x,y,z direction.
|
||||
cells : int numpy.ndarray of shape (3)
|
||||
Number of cells in x,y,z direction.
|
||||
size : list or numpy.ndarray of shape (3)
|
||||
Physical size of the geometry in meter.
|
||||
seeds : numpy.ndarray of shape (:,3)
|
||||
|
@ -344,11 +344,11 @@ class Geom:
|
|||
seeds_p = np.vstack((seeds -np.array([size[0],0.,0.]),seeds, seeds +np.array([size[0],0.,0.])))
|
||||
seeds_p = np.vstack((seeds_p-np.array([0.,size[1],0.]),seeds_p,seeds_p+np.array([0.,size[1],0.])))
|
||||
seeds_p = np.vstack((seeds_p-np.array([0.,0.,size[2]]),seeds_p,seeds_p+np.array([0.,0.,size[2]])))
|
||||
coords = grid_filters.cell_coord0(grid*3,size*3,-size).reshape(-1,3)
|
||||
coords = grid_filters.cell_coord0(cells*3,size*3,-size).reshape(-1,3)
|
||||
else:
|
||||
weights_p = weights
|
||||
seeds_p = seeds
|
||||
coords = grid_filters.cell_coord0(grid,size).reshape(-1,3)
|
||||
coords = grid_filters.cell_coord0(cells,size).reshape(-1,3)
|
||||
|
||||
pool = mp.Pool(processes = int(environment.options['DAMASK_NUM_THREADS']))
|
||||
result = pool.map_async(partial(Geom._find_closest_seed,seeds_p,weights_p), [coord for coord in coords])
|
||||
|
@ -357,10 +357,10 @@ class Geom:
|
|||
material_ = np.array(result.get())
|
||||
|
||||
if periodic:
|
||||
material_ = material_.reshape(grid*3)
|
||||
material_ = material_[grid[0]:grid[0]*2,grid[1]:grid[1]*2,grid[2]:grid[2]*2]%seeds.shape[0]
|
||||
material_ = material_.reshape(cells*3)
|
||||
material_ = material_[cells[0]:cells[0]*2,cells[1]:cells[1]*2,cells[2]:cells[2]*2]%seeds.shape[0]
|
||||
else:
|
||||
material_ = material_.reshape(grid)
|
||||
material_ = material_.reshape(cells)
|
||||
|
||||
return Geom(material = material_ if material is None else material[material_],
|
||||
size = size,
|
||||
|
@ -369,14 +369,14 @@ class Geom:
|
|||
|
||||
|
||||
@staticmethod
|
||||
def from_Voronoi_tessellation(grid,size,seeds,material=None,periodic=True):
|
||||
def from_Voronoi_tessellation(cells,size,seeds,material=None,periodic=True):
|
||||
"""
|
||||
Generate geometry from Voronoi tessellation.
|
||||
Generate grid from Voronoi tessellation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid : int numpy.ndarray of shape (3)
|
||||
Number of grid points in x,y,z direction.
|
||||
cells : int numpy.ndarray of shape (3)
|
||||
Number of cells in x,y,z direction.
|
||||
size : list or numpy.ndarray of shape (3)
|
||||
Physical size of the geometry in meter.
|
||||
seeds : numpy.ndarray of shape (:,3)
|
||||
|
@ -388,11 +388,11 @@ class Geom:
|
|||
Perform a periodic tessellation. Defaults to True.
|
||||
|
||||
"""
|
||||
coords = grid_filters.cell_coord0(grid,size).reshape(-1,3)
|
||||
coords = grid_filters.cell_coord0(cells,size).reshape(-1,3)
|
||||
KDTree = spatial.cKDTree(seeds,boxsize=size) if periodic else spatial.cKDTree(seeds)
|
||||
devNull,material_ = KDTree.query(coords)
|
||||
|
||||
return Geom(material = (material_ if material is None else material[material_]).reshape(grid),
|
||||
return Geom(material = (material_ if material is None else material[material_]).reshape(cells),
|
||||
size = size,
|
||||
comments = util.execution_stamp('Geom','from_Voronoi_tessellation'),
|
||||
)
|
||||
|
@ -441,14 +441,14 @@ class Geom:
|
|||
|
||||
|
||||
@staticmethod
|
||||
def from_minimal_surface(grid,size,surface,threshold=0.0,periods=1,materials=(0,1)):
|
||||
def from_minimal_surface(cells,size,surface,threshold=0.0,periods=1,materials=(0,1)):
|
||||
"""
|
||||
Generate geometry from definition of triply periodic minimal surface.
|
||||
Generate grid from definition of triply periodic minimal surface.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid : int numpy.ndarray of shape (3)
|
||||
Number of grid points in x,y,z direction.
|
||||
cells : int numpy.ndarray of shape (3)
|
||||
Number of cells in x,y,z direction.
|
||||
size : list or numpy.ndarray of shape (3)
|
||||
Physical size of the geometry in meter.
|
||||
surface : str
|
||||
|
@ -493,9 +493,9 @@ class Geom:
|
|||
https://doi.org/10.1016/j.simpa.2020.100026
|
||||
|
||||
"""
|
||||
x,y,z = np.meshgrid(periods*2.0*np.pi*(np.arange(grid[0])+0.5)/grid[0],
|
||||
periods*2.0*np.pi*(np.arange(grid[1])+0.5)/grid[1],
|
||||
periods*2.0*np.pi*(np.arange(grid[2])+0.5)/grid[2],
|
||||
x,y,z = np.meshgrid(periods*2.0*np.pi*(np.arange(cells[0])+0.5)/cells[0],
|
||||
periods*2.0*np.pi*(np.arange(cells[1])+0.5)/cells[1],
|
||||
periods*2.0*np.pi*(np.arange(cells[2])+0.5)/cells[2],
|
||||
indexing='ij',sparse=True)
|
||||
return Geom(material = np.where(threshold < Geom._minimal_surface[surface](x,y,z),materials[1],materials[0]),
|
||||
size = size,
|
||||
|
@ -505,7 +505,7 @@ class Geom:
|
|||
|
||||
def save(self,fname,compress=True):
|
||||
"""
|
||||
Store as VTK rectilinear grid.
|
||||
Save as VTK rectilinear grid file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -515,7 +515,7 @@ class Geom:
|
|||
Compress with zlib algorithm. Defaults to True.
|
||||
|
||||
"""
|
||||
v = VTK.from_rectilinear_grid(self.grid,self.size,self.origin)
|
||||
v = VTK.from_rectilinear_grid(self.cells,self.size,self.origin)
|
||||
v.add(self.material.flatten(order='F'),'material')
|
||||
v.add_comments(self.comments)
|
||||
|
||||
|
@ -524,7 +524,7 @@ class Geom:
|
|||
|
||||
def save_ASCII(self,fname):
|
||||
"""
|
||||
Write a geom file.
|
||||
Save as geom file.
|
||||
|
||||
Storing geometry files in ASCII format is deprecated.
|
||||
This function will be removed in a future version of DAMASK.
|
||||
|
@ -539,7 +539,7 @@ class Geom:
|
|||
"""
|
||||
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),
|
||||
+ ['grid a {} b {} c {}'.format(*self.cells),
|
||||
'size x {} y {} z {}'.format(*self.size),
|
||||
'origin x {} y {} z {}'.format(*self.origin),
|
||||
'homogenization 1',
|
||||
|
@ -548,13 +548,13 @@ class Geom:
|
|||
format_string = '%g' if self.material.dtype in np.sctypes['float'] else \
|
||||
'%{}i'.format(1+int(np.floor(np.log10(np.nanmax(self.material)))))
|
||||
np.savetxt(fname,
|
||||
self.material.reshape([self.grid[0],np.prod(self.grid[1:])],order='F').T,
|
||||
self.material.reshape([self.cells[0],np.prod(self.cells[1:])],order='F').T,
|
||||
header='\n'.join(header), fmt=format_string, comments='')
|
||||
|
||||
|
||||
def show(self):
|
||||
"""Show on screen."""
|
||||
VTK.from_rectilinear_grid(self.grid,self.size,self.origin).show()
|
||||
VTK.from_rectilinear_grid(self.cells,self.size,self.origin).show()
|
||||
|
||||
|
||||
def add_primitive(self,dimension,center,exponent,
|
||||
|
@ -566,11 +566,10 @@ class Geom:
|
|||
----------
|
||||
dimension : int or float numpy.ndarray of shape (3)
|
||||
Dimension (diameter/side length) of the primitive. If given as
|
||||
integers, grid point locations (cell centers) are addressed.
|
||||
integers, cell centers are addressed.
|
||||
If given as floats, coordinates are addressed.
|
||||
center : int or float numpy.ndarray of shape (3)
|
||||
Center of the primitive. If given as integers, grid point
|
||||
coordinates (cell centers) are addressed.
|
||||
Center of the primitive. If given as integers, cell centers are addressed.
|
||||
If given as floats, coordinates in space are addressed.
|
||||
exponent : numpy.ndarray of shape (3) or float
|
||||
Exponents for the three axes.
|
||||
|
@ -588,22 +587,22 @@ class Geom:
|
|||
|
||||
"""
|
||||
# radius and center
|
||||
r = np.array(dimension)/2.0*self.size/self.grid if np.array(dimension).dtype in np.sctypes['int'] else \
|
||||
r = np.array(dimension)/2.0*self.size/self.cells if np.array(dimension).dtype in np.sctypes['int'] else \
|
||||
np.array(dimension)/2.0
|
||||
c = (np.array(center) + .5)*self.size/self.grid if np.array(center).dtype in np.sctypes['int'] else \
|
||||
c = (np.array(center) + .5)*self.size/self.cells if np.array(center).dtype in np.sctypes['int'] else \
|
||||
(np.array(center) - self.origin)
|
||||
|
||||
coords = grid_filters.cell_coord0(self.grid,self.size,
|
||||
-(0.5*(self.size + (self.size/self.grid
|
||||
coords = grid_filters.cell_coord0(self.cells,self.size,
|
||||
-(0.5*(self.size + (self.size/self.cells
|
||||
if np.array(center).dtype in np.sctypes['int'] else
|
||||
0)) if periodic else c))
|
||||
coords_rot = R.broadcast_to(tuple(self.grid))@coords
|
||||
coords_rot = R.broadcast_to(tuple(self.cells))@coords
|
||||
|
||||
with np.errstate(all='ignore'):
|
||||
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/self.size-0.5)*self.grid).round().astype(int),(0,1,2))
|
||||
mask = np.roll(mask,((c/self.size-0.5)*self.cells).round().astype(int),(0,1,2))
|
||||
|
||||
return Geom(material = np.where(np.logical_not(mask) if inverse else mask,
|
||||
self.material,
|
||||
|
@ -642,7 +641,7 @@ class Geom:
|
|||
mat = np.concatenate([mat,mat[:,:,limits[0]:limits[1]:-1]],2)
|
||||
|
||||
return Geom(material = mat,
|
||||
size = self.size/self.grid*np.asarray(mat.shape),
|
||||
size = self.size/self.cells*np.asarray(mat.shape),
|
||||
origin = self.origin,
|
||||
comments = self.comments+[util.execution_stamp('Geom','mirror')],
|
||||
)
|
||||
|
@ -672,21 +671,21 @@ class Geom:
|
|||
)
|
||||
|
||||
|
||||
def scale(self,grid,periodic=True):
|
||||
def scale(self,cells,periodic=True):
|
||||
"""
|
||||
Scale geometry to new grid.
|
||||
Scale geometry to new cells.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid : numpy.ndarray of shape (3)
|
||||
Number of grid points in x,y,z direction.
|
||||
cells : numpy.ndarray of shape (3)
|
||||
Number of cells in x,y,z direction.
|
||||
periodic : Boolean, optional
|
||||
Assume geometry to be periodic. Defaults to True.
|
||||
|
||||
"""
|
||||
return Geom(material = ndimage.interpolation.zoom(
|
||||
self.material,
|
||||
grid/self.grid,
|
||||
cells/self.cells,
|
||||
output=self.material.dtype,
|
||||
order=0,
|
||||
mode=('wrap' if periodic else 'nearest'),
|
||||
|
@ -737,7 +736,7 @@ class Geom:
|
|||
"""Renumber sorted material indices as 0,...,N-1."""
|
||||
_,renumbered = np.unique(self.material,return_inverse=True)
|
||||
|
||||
return Geom(material = renumbered.reshape(self.grid),
|
||||
return Geom(material = renumbered.reshape(self.cells),
|
||||
size = self.size,
|
||||
origin = self.origin,
|
||||
comments = self.comments+[util.execution_stamp('Geom','renumber')],
|
||||
|
@ -773,25 +772,25 @@ class Geom:
|
|||
else:
|
||||
material_in = material_out
|
||||
|
||||
origin = self.origin-(np.asarray(material_in.shape)-self.grid)*.5 * self.size/self.grid
|
||||
origin = self.origin-(np.asarray(material_in.shape)-self.cells)*.5 * self.size/self.cells
|
||||
|
||||
return Geom(material = material_in,
|
||||
size = self.size/self.grid*np.asarray(material_in.shape),
|
||||
size = self.size/self.cells*np.asarray(material_in.shape),
|
||||
origin = origin,
|
||||
comments = self.comments+[util.execution_stamp('Geom','rotate')],
|
||||
)
|
||||
|
||||
|
||||
def canvas(self,grid=None,offset=None,fill=None):
|
||||
def canvas(self,cells=None,offset=None,fill=None):
|
||||
"""
|
||||
Crop or enlarge/pad geometry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid : numpy.ndarray of shape (3)
|
||||
Number of grid points in x,y,z direction.
|
||||
cells : numpy.ndarray of shape (3)
|
||||
Number of cells x,y,z direction.
|
||||
offset : numpy.ndarray of shape (3)
|
||||
Offset (measured in grid points) from old to new geometry [0,0,0].
|
||||
Offset (measured in cells) from old to new geometry [0,0,0].
|
||||
fill : int or float, optional
|
||||
Material index to fill the background. Defaults to material.max() + 1.
|
||||
|
||||
|
@ -800,18 +799,18 @@ class Geom:
|
|||
if fill is None: fill = np.nanmax(self.material) + 1
|
||||
dtype = float if int(fill) != fill or self.material.dtype in np.sctypes['float'] else int
|
||||
|
||||
canvas = np.full(self.grid if grid is None else grid,fill,dtype)
|
||||
canvas = np.full(self.cells if cells is None else cells,fill,dtype)
|
||||
|
||||
LL = np.clip( offset, 0,np.minimum(self.grid, grid+offset))
|
||||
UR = np.clip( offset+grid, 0,np.minimum(self.grid, grid+offset))
|
||||
ll = np.clip(-offset, 0,np.minimum( grid,self.grid-offset))
|
||||
ur = np.clip(-offset+self.grid,0,np.minimum( grid,self.grid-offset))
|
||||
LL = np.clip( offset, 0,np.minimum(self.cells, cells+offset))
|
||||
UR = np.clip( offset+cells, 0,np.minimum(self.cells, cells+offset))
|
||||
ll = np.clip(-offset, 0,np.minimum( cells,self.cells-offset))
|
||||
ur = np.clip(-offset+self.cells,0,np.minimum( cells,self.cells-offset))
|
||||
|
||||
canvas[ll[0]:ur[0],ll[1]:ur[1],ll[2]:ur[2]] = self.material[LL[0]:UR[0],LL[1]:UR[1],LL[2]:UR[2]]
|
||||
|
||||
return Geom(material = canvas,
|
||||
size = self.size/self.grid*np.asarray(canvas.shape),
|
||||
origin = self.origin+offset*self.size/self.grid,
|
||||
size = self.size/self.cells*np.asarray(canvas.shape),
|
||||
origin = self.origin+offset*self.size/self.cells,
|
||||
comments = self.comments+[util.execution_stamp('Geom','canvas')],
|
||||
)
|
||||
|
||||
|
@ -834,7 +833,7 @@ class Geom:
|
|||
mp = np.vectorize(mp)
|
||||
mapper = dict(zip(from_material,to_material))
|
||||
|
||||
return Geom(material = mp(self.material,mapper).reshape(self.grid),
|
||||
return Geom(material = mp(self.material,mapper).reshape(self.cells),
|
||||
size = self.size,
|
||||
origin = self.origin,
|
||||
comments = self.comments+[util.execution_stamp('Geom','substitute')],
|
||||
|
@ -848,7 +847,7 @@ class Geom:
|
|||
sort_idx = np.argsort(from_ma)
|
||||
ma = np.unique(a)[sort_idx][np.searchsorted(from_ma,a,sorter = sort_idx)]
|
||||
|
||||
return Geom(material = ma.reshape(self.grid,order='F'),
|
||||
return Geom(material = ma.reshape(self.cells,order='F'),
|
||||
size = self.size,
|
||||
origin = self.origin,
|
||||
comments = self.comments+[util.execution_stamp('Geom','sort')],
|
||||
|
@ -916,9 +915,9 @@ class Geom:
|
|||
if not set(directions).issubset(valid):
|
||||
raise ValueError(f'Invalid direction {set(directions).difference(valid)} specified.')
|
||||
|
||||
o = [[0, self.grid[0]+1, np.prod(self.grid[:2]+1)+self.grid[0]+1, np.prod(self.grid[:2]+1)],
|
||||
[0, np.prod(self.grid[:2]+1), np.prod(self.grid[:2]+1)+1, 1],
|
||||
[0, 1, self.grid[0]+1+1, self.grid[0]+1]] # offset for connectivity
|
||||
o = [[0, self.cells[0]+1, np.prod(self.cells[:2]+1)+self.cells[0]+1, np.prod(self.cells[:2]+1)],
|
||||
[0, np.prod(self.cells[:2]+1), np.prod(self.cells[:2]+1)+1, 1],
|
||||
[0, 1, self.cells[0]+1+1, self.cells[0]+1]] # offset for connectivity
|
||||
|
||||
connectivity = []
|
||||
for i,d in enumerate(['x','y','z']):
|
||||
|
@ -933,5 +932,5 @@ class Geom:
|
|||
base_nodes = np.argwhere(mask.flatten(order='F')).reshape(-1,1)
|
||||
connectivity.append(np.block([base_nodes + o[i][k] for k in range(4)]))
|
||||
|
||||
coords = grid_filters.node_coord0(self.grid,self.size,self.origin).reshape(-1,3,order='F')
|
||||
coords = grid_filters.node_coord0(self.cells,self.size,self.origin).reshape(-1,3,order='F')
|
||||
return VTK.from_unstructured_grid(coords,np.vstack(connectivity),'QUAD')
|
||||
|
|
|
@ -46,13 +46,17 @@ class Result:
|
|||
self.version_major = f.attrs['DADF5_version_major']
|
||||
self.version_minor = f.attrs['DADF5_version_minor']
|
||||
|
||||
if self.version_major != 0 or not 7 <= self.version_minor <= 9:
|
||||
if self.version_major != 0 or not 7 <= self.version_minor <= 10:
|
||||
raise TypeError(f'Unsupported DADF5 version {self.version_major}.{self.version_minor}')
|
||||
|
||||
self.structured = 'grid' in f['geometry'].attrs.keys()
|
||||
self.structured = 'grid' in f['geometry'].attrs.keys() or \
|
||||
'cells' in f['geometry'].attrs.keys()
|
||||
|
||||
if self.structured:
|
||||
self.grid = f['geometry'].attrs['grid']
|
||||
try:
|
||||
self.cells = f['geometry'].attrs['cells']
|
||||
except KeyError:
|
||||
self.cells = f['geometry'].attrs['grid']
|
||||
self.size = f['geometry'].attrs['size']
|
||||
self.origin = f['geometry'].attrs['origin']
|
||||
|
||||
|
@ -561,7 +565,7 @@ class Result:
|
|||
def cell_coordinates(self):
|
||||
"""Return initial coordinates of the cell centers."""
|
||||
if self.structured:
|
||||
return grid_filters.cell_coord0(self.grid,self.size,self.origin).reshape(-1,3,order='F')
|
||||
return grid_filters.cell_coord0(self.cells,self.size,self.origin).reshape(-1,3,order='F')
|
||||
else:
|
||||
with h5py.File(self.fname,'r') as f:
|
||||
return f['geometry/x_c'][()]
|
||||
|
@ -570,7 +574,7 @@ class Result:
|
|||
def node_coordinates(self):
|
||||
"""Return initial coordinates of the cell centers."""
|
||||
if self.structured:
|
||||
return grid_filters.node_coord0(self.grid,self.size,self.origin).reshape(-1,3,order='F')
|
||||
return grid_filters.node_coord0(self.cells,self.size,self.origin).reshape(-1,3,order='F')
|
||||
else:
|
||||
with h5py.File(self.fname,'r') as f:
|
||||
return f['geometry/x_n'][()]
|
||||
|
@ -1218,7 +1222,7 @@ class Result:
|
|||
|
||||
topology=ET.SubElement(grid, 'Topology')
|
||||
topology.attrib={'TopologyType': '3DCoRectMesh',
|
||||
'Dimensions': '{} {} {}'.format(*self.grid+1)}
|
||||
'Dimensions': '{} {} {}'.format(*self.cells+1)}
|
||||
|
||||
geometry=ET.SubElement(grid, 'Geometry')
|
||||
geometry.attrib={'GeometryType':'Origin_DxDyDz'}
|
||||
|
@ -1233,7 +1237,7 @@ class Result:
|
|||
delta.attrib={'Format': 'XML',
|
||||
'NumberType': 'Float',
|
||||
'Dimensions': '3'}
|
||||
delta.text="{} {} {}".format(*(self.size/self.grid))
|
||||
delta.text="{} {} {}".format(*(self.size/self.cells))
|
||||
|
||||
|
||||
with h5py.File(self.fname,'r') as f:
|
||||
|
@ -1244,7 +1248,7 @@ class Result:
|
|||
data_items.append(ET.SubElement(attributes[-1], 'DataItem'))
|
||||
data_items[-1].attrib={'Format': 'HDF',
|
||||
'Precision': '8',
|
||||
'Dimensions': '{} {} {} 3'.format(*(self.grid+1))}
|
||||
'Dimensions': '{} {} {} 3'.format(*(self.cells+1))}
|
||||
data_items[-1].text=f'{os.path.split(self.fname)[1]}:/{inc}/geometry/u_n'
|
||||
|
||||
for o,p in zip(['phases','homogenizations'],['out_type_ph','out_type_ho']):
|
||||
|
@ -1267,8 +1271,8 @@ class Result:
|
|||
data_items[-1].attrib={'Format': 'HDF',
|
||||
'NumberType': number_type_map(dtype),
|
||||
'Precision': f'{dtype.itemsize}',
|
||||
'Dimensions': '{} {} {} {}'.format(*self.grid,1 if shape == () else
|
||||
np.prod(shape))}
|
||||
'Dimensions': '{} {} {} {}'.format(*self.cells,1 if shape == () else
|
||||
np.prod(shape))}
|
||||
data_items[-1].text=f'{os.path.split(self.fname)[1]}:{name}'
|
||||
|
||||
with open(self.fname.with_suffix('.xdmf').name,'w') as f:
|
||||
|
@ -1291,7 +1295,7 @@ class Result:
|
|||
if mode.lower()=='cell':
|
||||
|
||||
if self.structured:
|
||||
v = VTK.from_rectilinear_grid(self.grid,self.size,self.origin)
|
||||
v = VTK.from_rectilinear_grid(self.cells,self.size,self.origin)
|
||||
else:
|
||||
with h5py.File(self.fname,'r') as f:
|
||||
v = VTK.from_unstructured_grid(f['/geometry/x_n'][()],
|
||||
|
|
|
@ -73,7 +73,7 @@ class Table:
|
|||
@staticmethod
|
||||
def load(fname):
|
||||
"""
|
||||
Load ASCII table file.
|
||||
Load from ASCII table file.
|
||||
|
||||
In legacy style, the first line indicates the number of
|
||||
subsequent header lines as "N header", with the last header line being
|
||||
|
@ -131,7 +131,7 @@ class Table:
|
|||
@staticmethod
|
||||
def load_ang(fname):
|
||||
"""
|
||||
Load ang file.
|
||||
Load from ang file.
|
||||
|
||||
A valid TSL ang file needs to contains the following columns:
|
||||
* Euler angles (Bunge notation) in radians, 3 floats, label 'eu'.
|
||||
|
|
|
@ -128,7 +128,7 @@ class VTK:
|
|||
@staticmethod
|
||||
def load(fname,dataset_type=None):
|
||||
"""
|
||||
Create VTK from file.
|
||||
Load from VTK file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -181,7 +181,7 @@ class VTK:
|
|||
writer.Write()
|
||||
def save(self,fname,parallel=True,compress=True):
|
||||
"""
|
||||
Write to file.
|
||||
Save as VTK file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
|
@ -8,14 +8,14 @@ This convention is consistent with the geom file format.
|
|||
When converting to/from a plain list (e.g. storage in ASCII table),
|
||||
the following operations are required for tensorial data:
|
||||
|
||||
D3 = D1.reshape(grid+(-1,),order='F').reshape(grid+(3,3))
|
||||
D1 = D3.reshape(grid+(-1,)).reshape(-1,9,order='F')
|
||||
D3 = D1.reshape(cells+(-1,),order='F').reshape(cells+(3,3))
|
||||
D1 = D3.reshape(cells+(-1,)).reshape(-1,9,order='F')
|
||||
|
||||
"""
|
||||
from scipy import spatial as _spatial
|
||||
import numpy as _np
|
||||
|
||||
def _ks(size,grid,first_order=False):
|
||||
def _ks(size,cells,first_order=False):
|
||||
"""
|
||||
Get wave numbers operator.
|
||||
|
||||
|
@ -23,19 +23,19 @@ def _ks(size,grid,first_order=False):
|
|||
----------
|
||||
size : numpy.ndarray of shape (3)
|
||||
physical size of the periodic field.
|
||||
grid : numpy.ndarray of shape (3)
|
||||
number of grid points.
|
||||
cells : numpy.ndarray of shape (3)
|
||||
number of cells.
|
||||
first_order : bool, optional
|
||||
correction for first order derivatives, defaults to False.
|
||||
|
||||
"""
|
||||
k_sk = _np.where(_np.arange(grid[0])>grid[0]//2,_np.arange(grid[0])-grid[0],_np.arange(grid[0]))/size[0]
|
||||
if grid[0]%2 == 0 and first_order: k_sk[grid[0]//2] = 0 # Nyquist freq=0 for even grid (Johnson, MIT, 2011)
|
||||
k_sk = _np.where(_np.arange(cells[0])>cells[0]//2,_np.arange(cells[0])-cells[0],_np.arange(cells[0]))/size[0]
|
||||
if cells[0]%2 == 0 and first_order: k_sk[cells[0]//2] = 0 # Nyquist freq=0 for even cells (Johnson, MIT, 2011)
|
||||
|
||||
k_sj = _np.where(_np.arange(grid[1])>grid[1]//2,_np.arange(grid[1])-grid[1],_np.arange(grid[1]))/size[1]
|
||||
if grid[1]%2 == 0 and first_order: k_sj[grid[1]//2] = 0 # Nyquist freq=0 for even grid (Johnson, MIT, 2011)
|
||||
k_sj = _np.where(_np.arange(cells[1])>cells[1]//2,_np.arange(cells[1])-cells[1],_np.arange(cells[1]))/size[1]
|
||||
if cells[1]%2 == 0 and first_order: k_sj[cells[1]//2] = 0 # Nyquist freq=0 for even cells (Johnson, MIT, 2011)
|
||||
|
||||
k_si = _np.arange(grid[2]//2+1)/size[2]
|
||||
k_si = _np.arange(cells[2]//2+1)/size[2]
|
||||
|
||||
return _np.stack(_np.meshgrid(k_sk,k_sj,k_si,indexing = 'ij'), axis=-1)
|
||||
|
||||
|
@ -110,26 +110,26 @@ def gradient(size,field):
|
|||
return _np.fft.irfftn(grad_,axes=(0,1,2),s=field.shape[:3])
|
||||
|
||||
|
||||
def cell_coord0(grid,size,origin=_np.zeros(3)):
|
||||
def cell_coord0(cells,size,origin=_np.zeros(3)):
|
||||
"""
|
||||
Cell center positions (undeformed).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid : numpy.ndarray of shape (3)
|
||||
number of grid points.
|
||||
cells : numpy.ndarray of shape (3)
|
||||
number of cells.
|
||||
size : numpy.ndarray of shape (3)
|
||||
physical size of the periodic field.
|
||||
origin : numpy.ndarray, optional
|
||||
physical origin of the periodic field. Defaults to [0.0,0.0,0.0].
|
||||
|
||||
"""
|
||||
start = origin + size/grid*.5
|
||||
end = origin + size - size/grid*.5
|
||||
start = origin + size/cells*.5
|
||||
end = origin + size - size/cells*.5
|
||||
|
||||
return _np.stack(_np.meshgrid(_np.linspace(start[0],end[0],grid[0]),
|
||||
_np.linspace(start[1],end[1],grid[1]),
|
||||
_np.linspace(start[2],end[2],grid[2]),indexing = 'ij'),
|
||||
return _np.stack(_np.meshgrid(_np.linspace(start[0],end[0],cells[0]),
|
||||
_np.linspace(start[1],end[1],cells[1]),
|
||||
_np.linspace(start[2],end[2],cells[2]),indexing = 'ij'),
|
||||
axis = -1)
|
||||
|
||||
|
||||
|
@ -210,7 +210,7 @@ def cell_coord(size,F,origin=_np.zeros(3)):
|
|||
|
||||
def cell_coord0_gridSizeOrigin(coord0,ordered=True):
|
||||
"""
|
||||
Return grid 'DNA', i.e. grid, size, and origin from 1D array of cell positions.
|
||||
Return grid 'DNA', i.e. cells, size, and origin from 1D array of cell positions.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -223,31 +223,31 @@ def cell_coord0_gridSizeOrigin(coord0,ordered=True):
|
|||
coords = [_np.unique(coord0[:,i]) for i in range(3)]
|
||||
mincorner = _np.array(list(map(min,coords)))
|
||||
maxcorner = _np.array(list(map(max,coords)))
|
||||
grid = _np.array(list(map(len,coords)),'i')
|
||||
size = grid/_np.maximum(grid-1,1) * (maxcorner-mincorner)
|
||||
delta = size/grid
|
||||
cells = _np.array(list(map(len,coords)),'i')
|
||||
size = cells/_np.maximum(cells-1,1) * (maxcorner-mincorner)
|
||||
delta = size/cells
|
||||
origin = mincorner - delta*.5
|
||||
|
||||
# 1D/2D: size/origin combination undefined, set origin to 0.0
|
||||
size [_np.where(grid==1)] = origin[_np.where(grid==1)]*2.
|
||||
origin[_np.where(grid==1)] = 0.0
|
||||
size [_np.where(cells==1)] = origin[_np.where(cells==1)]*2.
|
||||
origin[_np.where(cells==1)] = 0.0
|
||||
|
||||
if grid.prod() != len(coord0):
|
||||
raise ValueError('Data count {len(coord0)} does not match grid {grid}.')
|
||||
if cells.prod() != len(coord0):
|
||||
raise ValueError('Data count {len(coord0)} does not match cells {cells}.')
|
||||
|
||||
start = origin + delta*.5
|
||||
end = origin - delta*.5 + size
|
||||
|
||||
atol = _np.max(size)*5e-2
|
||||
if not (_np.allclose(coords[0],_np.linspace(start[0],end[0],grid[0]),atol=atol) and \
|
||||
_np.allclose(coords[1],_np.linspace(start[1],end[1],grid[1]),atol=atol) and \
|
||||
_np.allclose(coords[2],_np.linspace(start[2],end[2],grid[2]),atol=atol)):
|
||||
raise ValueError('Regular grid spacing violated.')
|
||||
if not (_np.allclose(coords[0],_np.linspace(start[0],end[0],cells[0]),atol=atol) and \
|
||||
_np.allclose(coords[1],_np.linspace(start[1],end[1],cells[1]),atol=atol) and \
|
||||
_np.allclose(coords[2],_np.linspace(start[2],end[2],cells[2]),atol=atol)):
|
||||
raise ValueError('Regular cells spacing violated.')
|
||||
|
||||
if ordered and not _np.allclose(coord0.reshape(tuple(grid)+(3,),order='F'),cell_coord0(grid,size,origin),atol=atol):
|
||||
if ordered and not _np.allclose(coord0.reshape(tuple(cells)+(3,),order='F'),cell_coord0(cells,size,origin),atol=atol):
|
||||
raise ValueError('Input data is not ordered (x fast, z slow).')
|
||||
|
||||
return (grid,size,origin)
|
||||
return (cells,size,origin)
|
||||
|
||||
|
||||
def coord0_check(coord0):
|
||||
|
@ -263,23 +263,23 @@ def coord0_check(coord0):
|
|||
cell_coord0_gridSizeOrigin(coord0,ordered=True)
|
||||
|
||||
|
||||
def node_coord0(grid,size,origin=_np.zeros(3)):
|
||||
def node_coord0(cells,size,origin=_np.zeros(3)):
|
||||
"""
|
||||
Nodal positions (undeformed).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid : numpy.ndarray of shape (3)
|
||||
number of grid points.
|
||||
cells : numpy.ndarray of shape (3)
|
||||
number of cells.
|
||||
size : numpy.ndarray of shape (3)
|
||||
physical size of the periodic field.
|
||||
origin : numpy.ndarray of shape (3), optional
|
||||
physical origin of the periodic field. Defaults to [0.0,0.0,0.0].
|
||||
|
||||
"""
|
||||
return _np.stack(_np.meshgrid(_np.linspace(origin[0],size[0]+origin[0],grid[0]+1),
|
||||
_np.linspace(origin[1],size[1]+origin[1],grid[1]+1),
|
||||
_np.linspace(origin[2],size[2]+origin[2],grid[2]+1),indexing = 'ij'),
|
||||
return _np.stack(_np.meshgrid(_np.linspace(origin[0],size[0]+origin[0],cells[0]+1),
|
||||
_np.linspace(origin[1],size[1]+origin[1],cells[1]+1),
|
||||
_np.linspace(origin[2],size[2]+origin[2],cells[2]+1),indexing = 'ij'),
|
||||
axis = -1)
|
||||
|
||||
|
||||
|
@ -366,7 +366,7 @@ def node_2_cell(node_data):
|
|||
|
||||
def node_coord0_gridSizeOrigin(coord0,ordered=True):
|
||||
"""
|
||||
Return grid 'DNA', i.e. grid, size, and origin from 1D array of nodal positions.
|
||||
Return grid 'DNA', i.e. cells, size, and origin from 1D array of nodal positions.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -379,37 +379,37 @@ def node_coord0_gridSizeOrigin(coord0,ordered=True):
|
|||
coords = [_np.unique(coord0[:,i]) for i in range(3)]
|
||||
mincorner = _np.array(list(map(min,coords)))
|
||||
maxcorner = _np.array(list(map(max,coords)))
|
||||
grid = _np.array(list(map(len,coords)),'i') - 1
|
||||
cells = _np.array(list(map(len,coords)),'i') - 1
|
||||
size = maxcorner-mincorner
|
||||
origin = mincorner
|
||||
|
||||
if (grid+1).prod() != len(coord0):
|
||||
raise ValueError('Data count {len(coord0)} does not match grid {grid}.')
|
||||
if (cells+1).prod() != len(coord0):
|
||||
raise ValueError('Data count {len(coord0)} does not match cells {cells}.')
|
||||
|
||||
atol = _np.max(size)*5e-2
|
||||
if not (_np.allclose(coords[0],_np.linspace(mincorner[0],maxcorner[0],grid[0]+1),atol=atol) and \
|
||||
_np.allclose(coords[1],_np.linspace(mincorner[1],maxcorner[1],grid[1]+1),atol=atol) and \
|
||||
_np.allclose(coords[2],_np.linspace(mincorner[2],maxcorner[2],grid[2]+1),atol=atol)):
|
||||
raise ValueError('Regular grid spacing violated.')
|
||||
if not (_np.allclose(coords[0],_np.linspace(mincorner[0],maxcorner[0],cells[0]+1),atol=atol) and \
|
||||
_np.allclose(coords[1],_np.linspace(mincorner[1],maxcorner[1],cells[1]+1),atol=atol) and \
|
||||
_np.allclose(coords[2],_np.linspace(mincorner[2],maxcorner[2],cells[2]+1),atol=atol)):
|
||||
raise ValueError('Regular cells spacing violated.')
|
||||
|
||||
if ordered and not _np.allclose(coord0.reshape(tuple(grid+1)+(3,),order='F'),node_coord0(grid,size,origin),atol=atol):
|
||||
if ordered and not _np.allclose(coord0.reshape(tuple(cells+1)+(3,),order='F'),node_coord0(cells,size,origin),atol=atol):
|
||||
raise ValueError('Input data is not ordered (x fast, z slow).')
|
||||
|
||||
return (grid,size,origin)
|
||||
return (cells,size,origin)
|
||||
|
||||
|
||||
def regrid(size,F,new_grid):
|
||||
def regrid(size,F,cells_new):
|
||||
"""
|
||||
Return mapping from coordinates in deformed configuration to a regular grid.
|
||||
Return mapping from coordinates in deformed configuration to a regular cells.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
size : numpy.ndarray of shape (3)
|
||||
physical size
|
||||
Physical size.
|
||||
F : numpy.ndarray of shape (:,:,:,3,3)
|
||||
deformation gradient field
|
||||
new_grid : numpy.ndarray of shape (3)
|
||||
new grid for undeformed coordinates
|
||||
Deformation gradient field.
|
||||
cells_new : numpy.ndarray of shape (3)
|
||||
New cells for undeformed coordinates.
|
||||
|
||||
"""
|
||||
c = cell_coord0(F.shape[:3],size) \
|
||||
|
@ -422,4 +422,4 @@ def regrid(size,F,new_grid):
|
|||
c[_np.where(c[:,:,:,d]>outer[d])] -= outer[d]
|
||||
|
||||
tree = _spatial.cKDTree(c.reshape(-1,3),boxsize=outer)
|
||||
return tree.query(cell_coord0(new_grid,outer))[1].flatten()
|
||||
return tree.query(cell_coord0(cells_new,outer))[1].flatten()
|
||||
|
|
|
@ -7,7 +7,7 @@ from . import util
|
|||
from . import grid_filters
|
||||
|
||||
|
||||
def from_random(size,N_seeds,grid=None,rng_seed=None):
|
||||
def from_random(size,N_seeds,cells=None,rng_seed=None):
|
||||
"""
|
||||
Random seeding in space.
|
||||
|
||||
|
@ -17,7 +17,7 @@ def from_random(size,N_seeds,grid=None,rng_seed=None):
|
|||
Physical size of the seeding domain.
|
||||
N_seeds : int
|
||||
Number of seeds.
|
||||
grid : numpy.ndarray of shape (3), optional.
|
||||
cells : numpy.ndarray of shape (3), optional.
|
||||
If given, ensures that all seeds initiate one grain if using a
|
||||
standard Voronoi tessellation.
|
||||
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
|
||||
|
@ -26,12 +26,12 @@ def from_random(size,N_seeds,grid=None,rng_seed=None):
|
|||
|
||||
"""
|
||||
rng = _np.random.default_rng(rng_seed)
|
||||
if grid is None:
|
||||
if cells is None:
|
||||
coords = rng.random((N_seeds,3)) * size
|
||||
else:
|
||||
grid_coords = grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F')
|
||||
coords = grid_coords[rng.choice(_np.prod(grid),N_seeds, replace=False)] \
|
||||
+ _np.broadcast_to(size/grid,(N_seeds,3))*(rng.random((N_seeds,3))*.5-.25) # wobble without leaving grid
|
||||
grid_coords = grid_filters.cell_coord0(cells,size).reshape(-1,3,order='F')
|
||||
coords = grid_coords[rng.choice(_np.prod(cells),N_seeds, replace=False)] \
|
||||
+ _np.broadcast_to(size/cells,(N_seeds,3))*(rng.random((N_seeds,3))*.5-.25) # wobble without leaving cells
|
||||
|
||||
return coords
|
||||
|
||||
|
@ -51,7 +51,7 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,rng_seed=
|
|||
distance : float
|
||||
Minimum acceptable distance to other seeds.
|
||||
periodic : boolean, optional
|
||||
Calculate minimum distance for periodically repeated grid.
|
||||
Calculate minimum distance for periodically repeated cells.
|
||||
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.
|
||||
|
@ -96,9 +96,9 @@ def from_geom(geom,selection=None,invert=False,average=False,periodic=True):
|
|||
|
||||
"""
|
||||
material = geom.material.reshape((-1,1),order='F')
|
||||
mask = _np.full(geom.grid.prod(),True,dtype=bool) if selection is None else \
|
||||
mask = _np.full(geom.cells.prod(),True,dtype=bool) if selection is None else \
|
||||
_np.isin(material,selection,invert=invert).flatten()
|
||||
coords = grid_filters.cell_coord0(geom.grid,geom.size).reshape(-1,3,order='F')
|
||||
coords = grid_filters.cell_coord0(geom.cells,geom.size).reshape(-1,3,order='F')
|
||||
|
||||
if not average:
|
||||
return (coords[mask],material[mask])
|
||||
|
|
|
@ -12,7 +12,7 @@ from damask import grid_filters
|
|||
|
||||
def geom_equal(a,b):
|
||||
return np.all(a.material == b.material) and \
|
||||
np.all(a.grid == b.grid) and \
|
||||
np.all(a.cells == b.cells) and \
|
||||
np.allclose(a.size, b.size) and \
|
||||
str(a.diff(b)) == str(b.diff(a))
|
||||
|
||||
|
@ -167,7 +167,7 @@ class TestGeom:
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('grid',[
|
||||
@pytest.mark.parametrize('cells',[
|
||||
(10,11,10),
|
||||
[10,13,10],
|
||||
np.array((10,10,10)),
|
||||
|
@ -176,9 +176,9 @@ class TestGeom:
|
|||
np.array((10,20,2))
|
||||
]
|
||||
)
|
||||
def test_scale(self,default,update,ref_path,grid):
|
||||
modified = default.scale(grid)
|
||||
tag = f'grid_{util.srepr(grid,"-")}'
|
||||
def test_scale(self,default,update,ref_path,cells):
|
||||
modified = default.scale(cells)
|
||||
tag = f'grid_{util.srepr(cells,"-")}'
|
||||
reference = ref_path/f'scale_{tag}.vtr'
|
||||
if update: modified.save(reference)
|
||||
assert geom_equal(Geom.load(reference),
|
||||
|
@ -216,8 +216,8 @@ class TestGeom:
|
|||
assert geom_equal(default, modified.substitute(t,f))
|
||||
|
||||
def test_sort(self):
|
||||
grid = np.random.randint(5,20,3)
|
||||
m = Geom(np.random.randint(1,20,grid)*3,np.ones(3)).sort().material.flatten(order='F')
|
||||
cells = np.random.randint(5,20,3)
|
||||
m = Geom(np.random.randint(1,20,cells)*3,np.ones(3)).sort().material.flatten(order='F')
|
||||
for i,v in enumerate(m):
|
||||
assert i==0 or v > m[:i].max() or v in m[:i]
|
||||
|
||||
|
@ -242,10 +242,10 @@ class TestGeom:
|
|||
|
||||
|
||||
def test_canvas(self,default):
|
||||
grid = default.grid
|
||||
cells = default.cells
|
||||
grid_add = np.random.randint(0,30,(3))
|
||||
modified = default.canvas(grid + grid_add)
|
||||
assert np.all(modified.material[:grid[0],:grid[1],:grid[2]] == default.material)
|
||||
modified = default.canvas(cells + grid_add)
|
||||
assert np.all(modified.material[:cells[0],:cells[1],:cells[2]] == default.material)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('center1,center2',[(np.random.random(3)*.5,np.random.random()*8),
|
||||
|
@ -314,38 +314,38 @@ class TestGeom:
|
|||
|
||||
@pytest.mark.parametrize('periodic',[True,False])
|
||||
def test_tessellation_approaches(self,periodic):
|
||||
grid = np.random.randint(10,20,3)
|
||||
cells = np.random.randint(10,20,3)
|
||||
size = np.random.random(3) + 1.0
|
||||
N_seeds= np.random.randint(10,30)
|
||||
seeds = np.random.rand(N_seeds,3) * np.broadcast_to(size,(N_seeds,3))
|
||||
Voronoi = Geom.from_Voronoi_tessellation( grid,size,seeds, np.arange(N_seeds)+5,periodic)
|
||||
Laguerre = Geom.from_Laguerre_tessellation(grid,size,seeds,np.ones(N_seeds),np.arange(N_seeds)+5,periodic)
|
||||
Voronoi = Geom.from_Voronoi_tessellation( cells,size,seeds, np.arange(N_seeds)+5,periodic)
|
||||
Laguerre = Geom.from_Laguerre_tessellation(cells,size,seeds,np.ones(N_seeds),np.arange(N_seeds)+5,periodic)
|
||||
assert geom_equal(Laguerre,Voronoi)
|
||||
|
||||
|
||||
def test_Laguerre_weights(self):
|
||||
grid = np.random.randint(10,20,3)
|
||||
cells = np.random.randint(10,20,3)
|
||||
size = np.random.random(3) + 1.0
|
||||
N_seeds= np.random.randint(10,30)
|
||||
seeds = np.random.rand(N_seeds,3) * np.broadcast_to(size,(N_seeds,3))
|
||||
weights= np.full((N_seeds),-np.inf)
|
||||
ms = np.random.randint(N_seeds)
|
||||
weights[ms] = np.random.random()
|
||||
Laguerre = Geom.from_Laguerre_tessellation(grid,size,seeds,weights,periodic=np.random.random()>0.5)
|
||||
Laguerre = Geom.from_Laguerre_tessellation(cells,size,seeds,weights,periodic=np.random.random()>0.5)
|
||||
assert np.all(Laguerre.material == ms)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('approach',['Laguerre','Voronoi'])
|
||||
def test_tessellate_bicrystal(self,approach):
|
||||
grid = np.random.randint(5,10,3)*2
|
||||
size = grid.astype(np.float)
|
||||
cells = np.random.randint(5,10,3)*2
|
||||
size = cells.astype(np.float)
|
||||
seeds = np.vstack((size*np.array([0.5,0.25,0.5]),size*np.array([0.5,0.75,0.5])))
|
||||
material = np.zeros(grid)
|
||||
material[:,grid[1]//2:,:] = 1
|
||||
material = np.zeros(cells)
|
||||
material[:,cells[1]//2:,:] = 1
|
||||
if approach == 'Laguerre':
|
||||
geom = Geom.from_Laguerre_tessellation(grid,size,seeds,np.ones(2),periodic=np.random.random()>0.5)
|
||||
geom = Geom.from_Laguerre_tessellation(cells,size,seeds,np.ones(2),periodic=np.random.random()>0.5)
|
||||
elif approach == 'Voronoi':
|
||||
geom = Geom.from_Voronoi_tessellation(grid,size,seeds, periodic=np.random.random()>0.5)
|
||||
geom = Geom.from_Voronoi_tessellation(cells,size,seeds, periodic=np.random.random()>0.5)
|
||||
assert np.all(geom.material == material)
|
||||
|
||||
|
||||
|
@ -363,14 +363,14 @@ class TestGeom:
|
|||
'Fisher-Koch S',
|
||||
])
|
||||
def test_minimal_surface_basic_properties(self,surface):
|
||||
grid = np.random.randint(60,100,3)
|
||||
size = np.ones(3)+np.random.rand(3)
|
||||
cells = np.random.randint(60,100,3)
|
||||
size = np.ones(3)+np.random.rand(3)
|
||||
threshold = 2*np.random.rand()-1.
|
||||
periods = np.random.randint(2)+1
|
||||
materials = np.random.randint(0,40,2)
|
||||
geom = Geom.from_minimal_surface(grid,size,surface,threshold,periods,materials)
|
||||
geom = Geom.from_minimal_surface(cells,size,surface,threshold,periods,materials)
|
||||
assert set(geom.material.flatten()) | set(materials) == set(materials) \
|
||||
and (geom.size == size).all() and (geom.grid == grid).all()
|
||||
and (geom.size == size).all() and (geom.cells == cells).all()
|
||||
|
||||
@pytest.mark.parametrize('surface,threshold',[('Schwarz P',0),
|
||||
('Double Primitive',-1./6.),
|
||||
|
@ -386,28 +386,28 @@ class TestGeom:
|
|||
('Fisher-Koch S',0),
|
||||
])
|
||||
def test_minimal_surface_volume(self,surface,threshold):
|
||||
grid = np.ones(3,dtype=int)*64
|
||||
geom = Geom.from_minimal_surface(grid,np.ones(3),surface,threshold)
|
||||
assert np.isclose(np.count_nonzero(geom.material==1)/np.prod(geom.grid),.5,rtol=1e-3)
|
||||
cells = np.ones(3,dtype=int)*64
|
||||
geom = Geom.from_minimal_surface(cells,np.ones(3),surface,threshold)
|
||||
assert np.isclose(np.count_nonzero(geom.material==1)/np.prod(geom.cells),.5,rtol=1e-3)
|
||||
|
||||
|
||||
def test_from_table(self):
|
||||
grid = np.random.randint(60,100,3)
|
||||
cells = np.random.randint(60,100,3)
|
||||
size = np.ones(3)+np.random.rand(3)
|
||||
coords = grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F')
|
||||
z=np.ones(grid.prod())
|
||||
z[grid[:2].prod()*int(grid[2]/2):]=0
|
||||
coords = grid_filters.cell_coord0(cells,size).reshape(-1,3,order='F')
|
||||
z=np.ones(cells.prod())
|
||||
z[cells[:2].prod()*int(cells[2]/2):]=0
|
||||
t = Table(np.column_stack((coords,z)),{'coords':3,'z':1})
|
||||
g = Geom.from_table(t,'coords',['1_coords','z'])
|
||||
assert g.N_materials == g.grid[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == grid[0]).all()
|
||||
assert g.N_materials == g.cells[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == cells[0]).all()
|
||||
|
||||
|
||||
def test_from_table_recover(self,tmp_path):
|
||||
grid = np.random.randint(60,100,3)
|
||||
cells = np.random.randint(60,100,3)
|
||||
size = np.ones(3)+np.random.rand(3)
|
||||
s = seeds.from_random(size,np.random.randint(60,100))
|
||||
geom = Geom.from_Voronoi_tessellation(grid,size,s)
|
||||
coords = grid_filters.cell_coord0(grid,size)
|
||||
geom = Geom.from_Voronoi_tessellation(cells,size,s)
|
||||
coords = grid_filters.cell_coord0(cells,size)
|
||||
t = Table(np.column_stack((coords.reshape(-1,3,order='F'),geom.material.flatten(order='F'))),{'c':3,'m':1})
|
||||
assert geom_equal(geom.sort().renumber(),Geom.from_table(t,'c',['m']))
|
||||
|
||||
|
|
|
@ -356,11 +356,11 @@ class TestResult:
|
|||
@pytest.mark.parametrize('mode',['cell','node'])
|
||||
def test_coordinates(self,default,mode):
|
||||
if mode == 'cell':
|
||||
a = grid_filters.cell_coord0(default.grid,default.size,default.origin)
|
||||
b = default.cell_coordinates.reshape(tuple(default.grid)+(3,),order='F')
|
||||
a = grid_filters.cell_coord0(default.cells,default.size,default.origin)
|
||||
b = default.cell_coordinates.reshape(tuple(default.cells)+(3,),order='F')
|
||||
elif mode == 'node':
|
||||
a = grid_filters.node_coord0(default.grid,default.size,default.origin)
|
||||
b = default.node_coordinates.reshape(tuple(default.grid+1)+(3,),order='F')
|
||||
a = grid_filters.node_coord0(default.cells,default.size,default.origin)
|
||||
b = default.node_coordinates.reshape(tuple(default.cells+1)+(3,),order='F')
|
||||
assert np.allclose(a,b)
|
||||
|
||||
@pytest.mark.parametrize('output',['F',[],['F','P']])
|
||||
|
|
|
@ -16,9 +16,9 @@ def ref_path(ref_path_base):
|
|||
@pytest.fixture
|
||||
def default():
|
||||
"""Simple VTK."""
|
||||
grid = np.array([5,6,7],int)
|
||||
size = np.array([.6,1.,.5])
|
||||
return VTK.from_rectilinear_grid(grid,size)
|
||||
cells = np.array([5,6,7],int)
|
||||
size = np.array([.6,1.,.5])
|
||||
return VTK.from_rectilinear_grid(cells,size)
|
||||
|
||||
class TestVTK:
|
||||
|
||||
|
@ -27,10 +27,10 @@ class TestVTK:
|
|||
print('patched damask.util.execution_stamp')
|
||||
|
||||
def test_rectilinearGrid(self,tmp_path):
|
||||
grid = np.random.randint(5,10,3)*2
|
||||
cells = np.random.randint(5,10,3)*2
|
||||
size = np.random.random(3) + 1.0
|
||||
origin = np.random.random(3)
|
||||
v = VTK.from_rectilinear_grid(grid,size,origin)
|
||||
v = VTK.from_rectilinear_grid(cells,size,origin)
|
||||
string = v.__repr__()
|
||||
v.save(tmp_path/'rectilinearGrid',False)
|
||||
vtr = VTK.load(tmp_path/'rectilinearGrid.vtr')
|
||||
|
@ -152,11 +152,11 @@ class TestVTK:
|
|||
np.allclose(polyData.get('coordinates'),points)
|
||||
|
||||
def test_compare_reference_rectilinearGrid(self,update,ref_path,tmp_path):
|
||||
grid = np.array([5,6,7],int)
|
||||
size = np.array([.6,1.,.5])
|
||||
rectilinearGrid = VTK.from_rectilinear_grid(grid,size)
|
||||
c = grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F')
|
||||
n = grid_filters.node_coord0(grid,size).reshape(-1,3,order='F')
|
||||
cells = np.array([5,6,7],int)
|
||||
size = np.array([.6,1.,.5])
|
||||
rectilinearGrid = VTK.from_rectilinear_grid(cells,size)
|
||||
c = grid_filters.cell_coord0(cells,size).reshape(-1,3,order='F')
|
||||
n = grid_filters.node_coord0(cells,size).reshape(-1,3,order='F')
|
||||
rectilinearGrid.add(c,'cell')
|
||||
rectilinearGrid.add(n,'node')
|
||||
if update:
|
||||
|
|
|
@ -7,58 +7,58 @@ class TestGridFilters:
|
|||
|
||||
def test_cell_coord0(self):
|
||||
size = np.random.random(3)
|
||||
grid = np.random.randint(8,32,(3))
|
||||
coord = grid_filters.cell_coord0(grid,size)
|
||||
assert np.allclose(coord[0,0,0],size/grid*.5) and coord.shape == tuple(grid) + (3,)
|
||||
cells = np.random.randint(8,32,(3))
|
||||
coord = grid_filters.cell_coord0(cells,size)
|
||||
assert np.allclose(coord[0,0,0],size/cells*.5) and coord.shape == tuple(cells) + (3,)
|
||||
|
||||
def test_node_coord0(self):
|
||||
size = np.random.random(3)
|
||||
grid = np.random.randint(8,32,(3))
|
||||
coord = grid_filters.node_coord0(grid,size)
|
||||
assert np.allclose(coord[-1,-1,-1],size) and coord.shape == tuple(grid+1) + (3,)
|
||||
cells = np.random.randint(8,32,(3))
|
||||
coord = grid_filters.node_coord0(cells,size)
|
||||
assert np.allclose(coord[-1,-1,-1],size) and coord.shape == tuple(cells+1) + (3,)
|
||||
|
||||
def test_coord0(self):
|
||||
size = np.random.random(3)
|
||||
grid = np.random.randint(8,32,(3))
|
||||
c = grid_filters.cell_coord0(grid+1,size+size/grid)
|
||||
n = grid_filters.node_coord0(grid,size) + size/grid*.5
|
||||
cells = np.random.randint(8,32,(3))
|
||||
c = grid_filters.cell_coord0(cells+1,size+size/cells)
|
||||
n = grid_filters.node_coord0(cells,size) + size/cells*.5
|
||||
assert np.allclose(c,n)
|
||||
|
||||
@pytest.mark.parametrize('mode',['cell','node'])
|
||||
def test_grid_DNA(self,mode):
|
||||
"""Ensure that xx_coord0_gridSizeOrigin is the inverse of xx_coord0."""
|
||||
grid = np.random.randint(8,32,(3))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
size = np.random.random(3)
|
||||
origin = np.random.random(3)
|
||||
coord0 = eval(f'grid_filters.{mode}_coord0(grid,size,origin)') # noqa
|
||||
_grid,_size,_origin = eval(f'grid_filters.{mode}_coord0_gridSizeOrigin(coord0.reshape(-1,3,order="F"))')
|
||||
assert np.allclose(grid,_grid) and np.allclose(size,_size) and np.allclose(origin,_origin)
|
||||
coord0 = eval(f'grid_filters.{mode}_coord0(cells,size,origin)') # noqa
|
||||
_cells,_size,_origin = eval(f'grid_filters.{mode}_coord0_gridSizeOrigin(coord0.reshape(-1,3,order="F"))')
|
||||
assert np.allclose(cells,_cells) and np.allclose(size,_size) and np.allclose(origin,_origin)
|
||||
|
||||
def test_displacement_fluct_equivalence(self):
|
||||
"""Ensure that fluctuations are periodic."""
|
||||
size = np.random.random(3)
|
||||
grid = np.random.randint(8,32,(3))
|
||||
F = np.random.random(tuple(grid)+(3,3))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
F = np.random.random(tuple(cells)+(3,3))
|
||||
assert np.allclose(grid_filters.node_displacement_fluct(size,F),
|
||||
grid_filters.cell_2_node(grid_filters.cell_displacement_fluct(size,F)))
|
||||
|
||||
def test_interpolation_to_node(self):
|
||||
size = np.random.random(3)
|
||||
grid = np.random.randint(8,32,(3))
|
||||
F = np.random.random(tuple(grid)+(3,3))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
F = np.random.random(tuple(cells)+(3,3))
|
||||
assert np.allclose(grid_filters.node_coord(size,F) [1:-1,1:-1,1:-1],
|
||||
grid_filters.cell_2_node(grid_filters.cell_coord(size,F))[1:-1,1:-1,1:-1])
|
||||
|
||||
def test_interpolation_to_cell(self):
|
||||
grid = np.random.randint(1,30,(3))
|
||||
cells = np.random.randint(1,30,(3))
|
||||
|
||||
node_coord_x = np.linspace(0,np.pi*2,num=grid[0]+1)
|
||||
node_coord_x = np.linspace(0,np.pi*2,num=cells[0]+1)
|
||||
node_field_x = np.cos(node_coord_x)
|
||||
node_field = np.broadcast_to(node_field_x.reshape(-1,1,1),grid+1)
|
||||
node_field = np.broadcast_to(node_field_x.reshape(-1,1,1),cells+1)
|
||||
|
||||
cell_coord_x = node_coord_x[:-1]+node_coord_x[1]*.5
|
||||
cell_field_x = np.interp(cell_coord_x,node_coord_x,node_field_x,period=np.pi*2.)
|
||||
cell_field = np.broadcast_to(cell_field_x.reshape(-1,1,1),grid)
|
||||
cell_field = np.broadcast_to(cell_field_x.reshape(-1,1,1),cells)
|
||||
|
||||
assert np.allclose(cell_field,grid_filters.node_2_cell(node_field))
|
||||
|
||||
|
@ -66,21 +66,21 @@ class TestGridFilters:
|
|||
def test_coord0_origin(self,mode):
|
||||
origin= np.random.random(3)
|
||||
size = np.random.random(3) # noqa
|
||||
grid = np.random.randint(8,32,(3))
|
||||
shifted = eval(f'grid_filters.{mode}_coord0(grid,size,origin)')
|
||||
unshifted = eval(f'grid_filters.{mode}_coord0(grid,size)')
|
||||
cells = np.random.randint(8,32,(3))
|
||||
shifted = eval(f'grid_filters.{mode}_coord0(cells,size,origin)')
|
||||
unshifted = eval(f'grid_filters.{mode}_coord0(cells,size)')
|
||||
if mode == 'cell':
|
||||
assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(grid) +(3,)))
|
||||
assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(cells) +(3,)))
|
||||
elif mode == 'node':
|
||||
assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(grid+1)+(3,)))
|
||||
assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(cells+1)+(3,)))
|
||||
|
||||
@pytest.mark.parametrize('function',[grid_filters.cell_displacement_avg,
|
||||
grid_filters.node_displacement_avg])
|
||||
def test_displacement_avg_vanishes(self,function):
|
||||
"""Ensure that random fluctuations in F do not result in average displacement."""
|
||||
size = np.random.random(3)
|
||||
grid = np.random.randint(8,32,(3))
|
||||
F = np.random.random(tuple(grid)+(3,3))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
F = np.random.random(tuple(cells)+(3,3))
|
||||
F += np.eye(3) - np.average(F,axis=(0,1,2))
|
||||
assert np.allclose(function(size,F),0.0)
|
||||
|
||||
|
@ -89,8 +89,8 @@ class TestGridFilters:
|
|||
def test_displacement_fluct_vanishes(self,function):
|
||||
"""Ensure that constant F does not result in fluctuating displacement."""
|
||||
size = np.random.random(3)
|
||||
grid = np.random.randint(8,32,(3))
|
||||
F = np.broadcast_to(np.random.random((3,3)), tuple(grid)+(3,3))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
F = np.broadcast_to(np.random.random((3,3)), tuple(cells)+(3,3))
|
||||
assert np.allclose(function(size,F),0.0)
|
||||
|
||||
@pytest.mark.parametrize('function',[grid_filters.coord0_check,
|
||||
|
@ -106,11 +106,11 @@ class TestGridFilters:
|
|||
def test_uneven_spaced_coordinates(self,function):
|
||||
start = np.random.random(3)
|
||||
end = np.random.random(3)*10. + start
|
||||
grid = np.random.randint(8,32,(3))
|
||||
uneven = np.stack(np.meshgrid(np.logspace(start[0],end[0],grid[0]),
|
||||
np.logspace(start[1],end[1],grid[1]),
|
||||
np.logspace(start[2],end[2],grid[2]),indexing = 'ij'),
|
||||
axis = -1).reshape((grid.prod(),3),order='F')
|
||||
cells = np.random.randint(8,32,(3))
|
||||
uneven = np.stack(np.meshgrid(np.logspace(start[0],end[0],cells[0]),
|
||||
np.logspace(start[1],end[1],cells[1]),
|
||||
np.logspace(start[2],end[2],cells[2]),indexing = 'ij'),
|
||||
axis = -1).reshape((cells.prod(),3),order='F')
|
||||
with pytest.raises(ValueError):
|
||||
function(uneven)
|
||||
|
||||
|
@ -121,8 +121,8 @@ class TestGridFilters:
|
|||
def test_unordered_coordinates(self,function,mode):
|
||||
origin = np.random.random(3)
|
||||
size = np.random.random(3)*10.+origin
|
||||
grid = np.random.randint(8,32,(3))
|
||||
unordered = grid_filters.node_coord0(grid,size,origin).reshape(-1,3)
|
||||
cells = np.random.randint(8,32,(3))
|
||||
unordered = grid_filters.node_coord0(cells,size,origin).reshape(-1,3)
|
||||
if mode:
|
||||
with pytest.raises(ValueError):
|
||||
function(unordered,mode)
|
||||
|
@ -131,9 +131,9 @@ class TestGridFilters:
|
|||
|
||||
def test_regrid(self):
|
||||
size = np.random.random(3)
|
||||
grid = np.random.randint(8,32,(3))
|
||||
F = np.broadcast_to(np.eye(3), tuple(grid)+(3,3))
|
||||
assert all(grid_filters.regrid(size,F,grid) == np.arange(grid.prod()))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
F = np.broadcast_to(np.eye(3), tuple(cells)+(3,3))
|
||||
assert all(grid_filters.regrid(size,F,cells) == np.arange(cells.prod()))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('differential_operator',[grid_filters.curl,
|
||||
|
@ -141,14 +141,14 @@ class TestGridFilters:
|
|||
grid_filters.gradient])
|
||||
def test_differential_operator_constant(self,differential_operator):
|
||||
size = np.random.random(3)+1.0
|
||||
grid = np.random.randint(8,32,(3))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
shapes = {
|
||||
grid_filters.curl: [(3,),(3,3)],
|
||||
grid_filters.divergence:[(3,),(3,3)],
|
||||
grid_filters.gradient: [(1,),(3,)]
|
||||
}
|
||||
for shape in shapes[differential_operator]:
|
||||
field = np.ones(tuple(grid)+shape)*np.random.random()*1.0e5
|
||||
field = np.ones(tuple(cells)+shape)*np.random.random()*1.0e5
|
||||
assert np.allclose(differential_operator(size,field),0.0)
|
||||
|
||||
|
||||
|
@ -190,15 +190,15 @@ class TestGridFilters:
|
|||
@pytest.mark.parametrize('field_def,grad_def',grad_test_data)
|
||||
def test_grad(self,field_def,grad_def):
|
||||
size = np.random.random(3)+1.0
|
||||
grid = np.random.randint(8,32,(3))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
|
||||
nodes = grid_filters.cell_coord0(grid,size)
|
||||
nodes = grid_filters.cell_coord0(cells,size)
|
||||
my_locals = locals() # needed for list comprehension
|
||||
|
||||
field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1)
|
||||
field = field.reshape(tuple(grid) + ((3,) if len(field_def)==3 else (1,)))
|
||||
grad = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in grad_def], axis=-1)
|
||||
grad = grad.reshape(tuple(grid) + ((3,3) if len(grad_def)==9 else (3,)))
|
||||
field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),cells) for f in field_def],axis=-1)
|
||||
field = field.reshape(tuple(cells) + ((3,) if len(field_def)==3 else (1,)))
|
||||
grad = np.stack([np.broadcast_to(eval(c,globals(),my_locals),cells) for c in grad_def], axis=-1)
|
||||
grad = grad.reshape(tuple(cells) + ((3,3) if len(grad_def)==9 else (3,)))
|
||||
|
||||
assert np.allclose(grad,grid_filters.gradient(size,field))
|
||||
|
||||
|
@ -250,15 +250,15 @@ class TestGridFilters:
|
|||
@pytest.mark.parametrize('field_def,curl_def',curl_test_data)
|
||||
def test_curl(self,field_def,curl_def):
|
||||
size = np.random.random(3)+1.0
|
||||
grid = np.random.randint(8,32,(3))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
|
||||
nodes = grid_filters.cell_coord0(grid,size)
|
||||
nodes = grid_filters.cell_coord0(cells,size)
|
||||
my_locals = locals() # needed for list comprehension
|
||||
|
||||
field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1)
|
||||
field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,)))
|
||||
curl = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in curl_def], axis=-1)
|
||||
curl = curl.reshape(tuple(grid) + ((3,3) if len(curl_def)==9 else (3,)))
|
||||
field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),cells) for f in field_def],axis=-1)
|
||||
field = field.reshape(tuple(cells) + ((3,3) if len(field_def)==9 else (3,)))
|
||||
curl = np.stack([np.broadcast_to(eval(c,globals(),my_locals),cells) for c in curl_def], axis=-1)
|
||||
curl = curl.reshape(tuple(cells) + ((3,3) if len(curl_def)==9 else (3,)))
|
||||
|
||||
assert np.allclose(curl,grid_filters.curl(size,field))
|
||||
|
||||
|
@ -303,17 +303,17 @@ class TestGridFilters:
|
|||
|
||||
def test_div(self,field_def,div_def):
|
||||
size = np.random.random(3)+1.0
|
||||
grid = np.random.randint(8,32,(3))
|
||||
cells = np.random.randint(8,32,(3))
|
||||
|
||||
nodes = grid_filters.cell_coord0(grid,size)
|
||||
nodes = grid_filters.cell_coord0(cells,size)
|
||||
my_locals = locals() # needed for list comprehension
|
||||
|
||||
field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1)
|
||||
field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,)))
|
||||
div = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in div_def], axis=-1)
|
||||
field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),cells) for f in field_def],axis=-1)
|
||||
field = field.reshape(tuple(cells) + ((3,3) if len(field_def)==9 else (3,)))
|
||||
div = np.stack([np.broadcast_to(eval(c,globals(),my_locals),cells) for c in div_def], axis=-1)
|
||||
if len(div_def)==3:
|
||||
div = div.reshape(tuple(grid) + ((3,)))
|
||||
div = div.reshape(tuple(cells) + ((3,)))
|
||||
else:
|
||||
div=div.reshape(tuple(grid))
|
||||
div=div.reshape(tuple(cells))
|
||||
|
||||
assert np.allclose(div,grid_filters.divergence(size,field))
|
||||
|
|
|
@ -8,11 +8,11 @@ from damask import Geom
|
|||
|
||||
class TestSeeds:
|
||||
|
||||
@pytest.mark.parametrize('grid',[None,np.ones(3,dtype='i')*10])
|
||||
def test_from_random(self,grid):
|
||||
@pytest.mark.parametrize('cells',[None,np.ones(3,dtype='i')*10])
|
||||
def test_from_random(self,cells):
|
||||
N_seeds = np.random.randint(30,300)
|
||||
size = np.ones(3) + np.random.random(3)
|
||||
coords = seeds.from_random(size,N_seeds,grid)
|
||||
coords = seeds.from_random(size,N_seeds,cells)
|
||||
assert (0<=coords).all() and (coords<size).all()
|
||||
|
||||
@pytest.mark.parametrize('periodic',[True,False])
|
||||
|
@ -27,36 +27,36 @@ class TestSeeds:
|
|||
assert (0<= coords).all() and (coords<size).all() and np.min(min_dists[:,1])>=distance
|
||||
|
||||
def test_from_geom_reconstruct(self):
|
||||
grid = np.random.randint(10,20,3)
|
||||
cells = np.random.randint(10,20,3)
|
||||
N_seeds = np.random.randint(30,300)
|
||||
size = np.ones(3) + np.random.random(3)
|
||||
coords = seeds.from_random(size,N_seeds,grid)
|
||||
geom_1 = Geom.from_Voronoi_tessellation(grid,size,coords)
|
||||
coords = seeds.from_random(size,N_seeds,cells)
|
||||
geom_1 = Geom.from_Voronoi_tessellation(cells,size,coords)
|
||||
coords,material = seeds.from_geom(geom_1)
|
||||
geom_2 = Geom.from_Voronoi_tessellation(grid,size,coords,material)
|
||||
geom_2 = Geom.from_Voronoi_tessellation(cells,size,coords,material)
|
||||
assert (geom_2.material==geom_1.material).all()
|
||||
|
||||
@pytest.mark.parametrize('periodic',[True,False])
|
||||
@pytest.mark.parametrize('average',[True,False])
|
||||
def test_from_geom_grid(self,periodic,average):
|
||||
grid = np.random.randint(10,20,3)
|
||||
size = np.ones(3) + np.random.random(3)
|
||||
coords = grid_filters.cell_coord0(grid,size).reshape(-1,3)
|
||||
cells = np.random.randint(10,20,3)
|
||||
size = np.ones(3) + np.random.random(3)
|
||||
coords = grid_filters.cell_coord0(cells,size).reshape(-1,3)
|
||||
np.random.shuffle(coords)
|
||||
geom_1 = Geom.from_Voronoi_tessellation(grid,size,coords)
|
||||
geom_1 = Geom.from_Voronoi_tessellation(cells,size,coords)
|
||||
coords,material = seeds.from_geom(geom_1,average=average,periodic=periodic)
|
||||
geom_2 = Geom.from_Voronoi_tessellation(grid,size,coords,material)
|
||||
geom_2 = Geom.from_Voronoi_tessellation(cells,size,coords,material)
|
||||
assert (geom_2.material==geom_1.material).all()
|
||||
|
||||
@pytest.mark.parametrize('periodic',[True,False])
|
||||
@pytest.mark.parametrize('average',[True,False])
|
||||
@pytest.mark.parametrize('invert',[True,False])
|
||||
def test_from_geom_selection(self,periodic,average,invert):
|
||||
grid = np.random.randint(10,20,3)
|
||||
cells = np.random.randint(10,20,3)
|
||||
N_seeds = np.random.randint(30,300)
|
||||
size = np.ones(3) + np.random.random(3)
|
||||
coords = seeds.from_random(size,N_seeds,grid)
|
||||
geom = Geom.from_Voronoi_tessellation(grid,size,coords)
|
||||
coords = seeds.from_random(size,N_seeds,cells)
|
||||
geom = Geom.from_Voronoi_tessellation(cells,size,coords)
|
||||
selection=np.random.randint(N_seeds)+1
|
||||
coords,material = seeds.from_geom(geom,average=average,periodic=periodic,invert=invert,selection=[selection])
|
||||
assert selection not in material if invert else (selection==material).all()
|
||||
|
|
|
@ -86,7 +86,7 @@ subroutine discretization_results
|
|||
|
||||
u = discretization_IPcoords &
|
||||
- discretization_IPcoords0
|
||||
call results_writeDataset('current/geometry',u,'u_p','displacements of the materialpoints','m')
|
||||
call results_writeDataset('current/geometry',u,'u_p','displacements of the materialpoints (cell centers)','m')
|
||||
|
||||
end subroutine discretization_results
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ subroutine discretization_grid_init(restart)
|
|||
call MPI_Bcast(origin,3,MPI_DOUBLE,0,PETSC_COMM_WORLD, ierr)
|
||||
if (ierr /= 0) error stop 'MPI error'
|
||||
|
||||
print'(/,a,3(i12 ))', ' grid a b c: ', grid
|
||||
print'(/,a,3(i12 ))', ' cells a b c: ', grid
|
||||
print'(a,3(es12.5))', ' size x y z: ', geomSize
|
||||
print'(a,3(es12.5))', ' origin x y z: ', origin
|
||||
|
||||
|
@ -125,9 +125,9 @@ subroutine discretization_grid_init(restart)
|
|||
if(.not. restart) then
|
||||
call results_openJobFile
|
||||
call results_closeGroup(results_addGroup('geometry'))
|
||||
call results_addAttribute('grid', grid, 'geometry')
|
||||
call results_addAttribute('size', geomSize,'geometry')
|
||||
call results_addAttribute('origin',origin, 'geometry')
|
||||
call results_addAttribute('cells', grid, '/geometry')
|
||||
call results_addAttribute('size', geomSize,'/geometry')
|
||||
call results_addAttribute('origin',origin, '/geometry')
|
||||
call results_closeJobFile
|
||||
endif
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ subroutine writeGeometry(elem, &
|
|||
|
||||
coordinates_temp = coordinates_points
|
||||
call results_writeDataset('geometry',coordinates_temp,'x_p', &
|
||||
'initial coordinates of the materialpoints','m')
|
||||
'initial coordinates of the materialpoints (cell centers)','m')
|
||||
|
||||
call results_closeJobFile
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ subroutine results_init(restart)
|
|||
if(.not. restart) then
|
||||
resultsFile = HDF5_openFile(trim(getSolverJobName())//'.hdf5','w',.true.)
|
||||
call results_addAttribute('DADF5_version_major',0)
|
||||
call results_addAttribute('DADF5_version_minor',9)
|
||||
call results_addAttribute('DADF5_version_minor',10)
|
||||
call results_addAttribute('DAMASK_version',DAMASKVERSION)
|
||||
call get_command(commandLine)
|
||||
call results_addAttribute('Call',trim(commandLine))
|
||||
|
|
Loading…
Reference in New Issue