2013-06-21 01:15:25 +05:30
#!/usr/bin/env python
# -*- coding: UTF-8 no BOM -*-
2014-11-18 13:30:45 +05:30
import os , sys , string , math
2014-06-18 14:30:57 +05:30
import numpy as np
from optparse import OptionParser
2013-06-21 22:29:49 +05:30
from scipy import ndimage
2014-06-18 14:30:57 +05:30
import damask
2013-06-21 01:15:25 +05:30
2016-01-27 22:36:00 +05:30
scriptName = os . path . splitext ( os . path . basename ( __file__ ) ) [ 0 ]
scriptID = ' ' . join ( [ scriptName , damask . version ] )
2013-07-18 18:58:54 +05:30
2013-06-21 01:15:25 +05:30
#--------------------------------------------------------------------------------------------------
# MAIN
#--------------------------------------------------------------------------------------------------
2014-06-18 14:30:57 +05:30
parser = OptionParser ( option_class = damask . extendableOption , usage = ' % prog options [file[s]] ' , description = """
2013-06-22 00:38:20 +05:30
Smoothens out interface roughness by simulated curvature flow .
2013-06-30 19:21:21 +05:30
This is achieved by the diffusion of each initially sharply bounded grain volume within the periodic domain
up to a given distance ' d ' voxels .
The final geometry is assembled by selecting at each voxel that grain index for which the concentration remains largest .
2014-12-08 14:18:55 +05:30
""" , version = scriptID)
2013-06-21 01:15:25 +05:30
2014-06-07 23:43:29 +05:30
parser . add_option ( ' -d ' , ' --distance ' , dest = ' d ' , type = ' int ' , metavar = ' int ' ,
2014-01-20 20:11:56 +05:30
help = ' diffusion distance in voxels [ %d efault] ' )
2014-06-07 23:43:29 +05:30
parser . add_option ( ' -N ' , ' --smooth ' , dest = ' N ' , type = ' int ' , metavar = ' int ' ,
2013-07-01 22:45:24 +05:30
help = ' N for curvature flow [ %d efault] ' )
2014-06-07 23:43:29 +05:30
parser . add_option ( ' -r ' , ' --renumber ' , dest = ' renumber ' , action = ' store_true ' ,
2014-02-14 18:47:29 +05:30
help = ' renumber microstructure indices from 1...N [ %d efault] ' )
2014-09-12 19:44:55 +05:30
parser . add_option ( ' -i ' , ' --immutable ' , action = ' extend ' , dest = ' immutable ' , metavar = ' <LIST> ' ,
2014-06-07 23:43:29 +05:30
help = ' list of immutable microstructures ' )
2013-06-21 01:15:25 +05:30
2013-07-01 22:45:24 +05:30
parser . set_defaults ( d = 1 )
parser . set_defaults ( N = 1 )
2014-02-14 18:47:29 +05:30
parser . set_defaults ( renumber = False )
2014-06-07 23:43:29 +05:30
parser . set_defaults ( immutable = [ ] )
2013-06-21 01:15:25 +05:30
2014-06-07 23:43:29 +05:30
( options , filenames ) = parser . parse_args ( )
2014-01-20 20:11:56 +05:30
2014-06-07 23:43:29 +05:30
options . immutable = map ( int , options . immutable )
2013-06-22 02:47:03 +05:30
2015-10-26 23:29:36 +05:30
# --- loop over input files -------------------------------------------------------------------------
if filenames == [ ] : filenames = [ None ]
for name in filenames :
try :
table = damask . ASCIItable ( name = name ,
buffered = False , labeled = False )
except : continue
damask . util . report ( scriptName , name )
# --- interpret header ----------------------------------------------------------------------------
table . head_read ( )
info , extra_header = table . head_getGeom ( )
damask . util . croak ( [ ' grid a b c: %s ' % ( ' x ' . join ( map ( str , info [ ' grid ' ] ) ) ) ,
' size x y z: %s ' % ( ' x ' . join ( map ( str , info [ ' size ' ] ) ) ) ,
' origin x y z: %s ' % ( ' : ' . join ( map ( str , info [ ' origin ' ] ) ) ) ,
' homogenization: %i ' % info [ ' homogenization ' ] ,
' microstructures: %i ' % info [ ' microstructures ' ] ,
] )
errors = [ ]
if np . any ( info [ ' grid ' ] < 1 ) : errors . append ( ' invalid grid a b c. ' )
if np . any ( info [ ' size ' ] < = 0.0 ) : errors . append ( ' invalid size x y z. ' )
if errors != [ ] :
damask . util . croak ( errors )
table . close ( dismiss = True )
2013-06-30 19:21:21 +05:30
continue
2013-06-22 02:47:03 +05:30
2015-10-26 23:29:36 +05:30
# --- read data ------------------------------------------------------------------------------------
microstructure = np . tile ( np . array ( table . microstructure_read ( info [ ' grid ' ] ) , ' i ' ) . reshape ( info [ ' grid ' ] , order = ' F ' ) ,
np . where ( info [ ' grid ' ] == 1 , 2 , 1 ) ) # make one copy along dimensions with grid == 1
2014-06-18 14:30:57 +05:30
grid = np . array ( microstructure . shape )
2015-09-24 00:50:18 +05:30
#--- initialize support data -----------------------------------------------------------------------
2014-06-07 23:43:29 +05:30
2014-06-18 14:30:57 +05:30
periodic_microstructure = np . tile ( microstructure , ( 3 , 3 , 3 ) ) [ grid [ 0 ] / 2 : - grid [ 0 ] / 2 ,
2015-10-26 23:29:36 +05:30
grid [ 1 ] / 2 : - grid [ 1 ] / 2 ,
grid [ 2 ] / 2 : - grid [ 2 ] / 2 ] # periodically extend the microstructure
microstructure_original = np . copy ( microstructure ) # store a copy the initial microstructure to find locations of immutable indices
2014-06-07 23:43:29 +05:30
2014-06-18 14:30:57 +05:30
X , Y , Z = np . mgrid [ 0 : grid [ 0 ] , 0 : grid [ 1 ] , 0 : grid [ 2 ] ]
gauss = np . exp ( - ( X * X + Y * Y + Z * Z ) / ( 2.0 * options . d * options . d ) ) / math . pow ( 2.0 * np . pi * options . d * options . d , 1.5 )
2014-06-07 23:43:29 +05:30
gauss [ : , : , grid [ 2 ] / 2 : : ] = gauss [ : , : , round ( grid [ 2 ] / 2. ) - 1 : : - 1 ] # trying to cope with uneven (odd) grid size
gauss [ : , grid [ 1 ] / 2 : : , : ] = gauss [ : , round ( grid [ 1 ] / 2. ) - 1 : : - 1 , : ]
gauss [ grid [ 0 ] / 2 : : , : , : ] = gauss [ round ( grid [ 0 ] / 2. ) - 1 : : - 1 , : , : ]
2014-06-18 14:30:57 +05:30
gauss = np . fft . rfftn ( gauss )
2015-09-24 00:50:18 +05:30
2014-04-01 22:13:39 +05:30
interfacialEnergy = lambda A , B : ( A * B != 0 ) * ( A != B ) * 1.0
2015-10-26 23:29:36 +05:30
struc = ndimage . generate_binary_structure ( 3 , 1 ) # 3D von Neumann neighborhood
2014-06-07 23:43:29 +05:30
2013-07-01 22:45:24 +05:30
for smoothIter in xrange ( options . N ) :
2014-06-18 14:30:57 +05:30
boundary = np . zeros ( microstructure . shape )
2014-06-07 23:43:29 +05:30
for i in ( - 1 , 0 , 1 ) :
for j in ( - 1 , 0 , 1 ) :
for k in ( - 1 , 0 , 1 ) :
2014-06-18 14:30:57 +05:30
interfaceEnergy = np . maximum ( boundary ,
interfacialEnergy ( microstructure , np . roll ( np . roll ( np . roll (
2015-10-26 23:29:36 +05:30
microstructure , i , axis = 0 ) , j , axis = 1 ) , k , axis = 2 ) ) ) # assign interfacial energy to all voxels that have a differing neighbor (in Moore neighborhood)
2014-06-18 14:30:57 +05:30
periodic_interfaceEnergy = np . tile ( interfaceEnergy , ( 3 , 3 , 3 ) ) [ grid [ 0 ] / 2 : - grid [ 0 ] / 2 ,
2014-06-07 23:43:29 +05:30
grid [ 1 ] / 2 : - grid [ 1 ] / 2 ,
2015-10-26 23:29:36 +05:30
grid [ 2 ] / 2 : - grid [ 2 ] / 2 ] # periodically extend interfacial energy array by half a grid size in positive and negative directions
index = ndimage . morphology . distance_transform_edt ( periodic_interfaceEnergy == 0. , # transform bulk volume (i.e. where interfacial energy is zero)
2014-06-07 23:43:29 +05:30
return_distances = False ,
2015-10-26 23:29:36 +05:30
return_indices = True ) # want array index of nearest voxel on periodically extended boundary
# boundaryExt = boundaryExt[index[0].flatten(),index[1].flatten(),index[2].flatten()].reshape(boundaryExt.shape) # fill bulk with energy of nearest interface | question PE: what "flatten" for?
2014-06-07 23:43:29 +05:30
periodic_bulkEnergy = periodic_interfaceEnergy [ index [ 0 ] ,
index [ 1 ] ,
2015-10-26 23:29:36 +05:30
index [ 2 ] ] . reshape ( 2 * grid ) # fill bulk with energy of nearest interface
2014-06-18 14:30:57 +05:30
diffusedEnergy = np . fft . irfftn ( np . fft . rfftn ( np . where ( ndimage . morphology . binary_dilation ( interfaceEnergy > 0. ,
2014-06-07 23:43:29 +05:30
structure = struc ,
iterations = options . d / 2 + 1 ) , # fat boundary | question PE: why 2d - 1? I would argue for d/2 + 1 !!
2015-10-26 23:29:36 +05:30
periodic_bulkEnergy [ grid [ 0 ] / 2 : - grid [ 0 ] / 2 , # retain filled energy on fat boundary...
2014-06-07 23:43:29 +05:30
grid [ 1 ] / 2 : - grid [ 1 ] / 2 ,
2015-10-26 23:29:36 +05:30
grid [ 2 ] / 2 : - grid [ 2 ] / 2 ] , # ...and zero everywhere else
2014-06-07 23:43:29 +05:30
0. ) \
) * gauss )
2014-06-18 14:30:57 +05:30
periodic_diffusedEnergy = np . tile ( diffusedEnergy , ( 3 , 3 , 3 ) ) [ grid [ 0 ] / 2 : - grid [ 0 ] / 2 ,
2014-06-07 23:43:29 +05:30
grid [ 1 ] / 2 : - grid [ 1 ] / 2 ,
2015-10-26 23:29:36 +05:30
grid [ 2 ] / 2 : - grid [ 2 ] / 2 ] # periodically extend the smoothed bulk energy
index = ndimage . morphology . distance_transform_edt ( periodic_diffusedEnergy > = 0.5 , # transform voxels close to interface region | question PE: what motivates 1/2 (could be any small number, or)?
2014-06-07 23:43:29 +05:30
return_distances = False ,
2015-10-26 23:29:36 +05:30
return_indices = True ) # want index of closest bulk grain
2014-06-07 23:43:29 +05:30
microstructure = periodic_microstructure [ index [ 0 ] ,
index [ 1 ] ,
index [ 2 ] ] . reshape ( 2 * grid ) [ grid [ 0 ] / 2 : - grid [ 0 ] / 2 ,
grid [ 1 ] / 2 : - grid [ 1 ] / 2 ,
2015-10-26 23:29:36 +05:30
grid [ 2 ] / 2 : - grid [ 2 ] / 2 ] # extent grains into interface region
2014-06-07 23:43:29 +05:30
2014-06-18 14:30:57 +05:30
immutable = np . zeros ( microstructure . shape , dtype = bool )
2014-06-05 22:48:52 +05:30
for micro in options . immutable :
2015-10-26 23:29:36 +05:30
immutable + = np . logical_or ( microstructure == micro , microstructure_original == micro ) # find locations where immutable microstructures have been or are now
2014-06-05 22:48:52 +05:30
2015-10-26 23:29:36 +05:30
microstructure = np . where ( immutable , microstructure_original , microstructure ) # undo any changes involving immutable microstructures
2013-07-01 22:45:24 +05:30
2014-02-14 18:47:29 +05:30
# --- renumber to sequence 1...Ngrains if requested ------------------------------------------------
2015-09-24 00:50:18 +05:30
# http://stackoverflow.com/questions/10741346/np-frequency-counts-for-unique-values-in-an-array
2014-06-07 23:43:29 +05:30
2014-02-14 18:47:29 +05:30
if options . renumber :
2014-06-07 23:43:29 +05:30
newID = 0
2014-06-18 14:30:57 +05:30
for microstructureID , count in enumerate ( np . bincount ( microstructure . flatten ( ) ) ) :
2014-02-14 18:47:29 +05:30
if count != 0 :
2014-06-07 23:43:29 +05:30
newID + = 1
2014-06-18 14:30:57 +05:30
microstructure = np . where ( microstructure == microstructureID , newID , microstructure )
2014-06-07 23:43:29 +05:30
2015-10-26 23:29:36 +05:30
newInfo = { ' microstructures ' : 0 , }
newInfo [ ' microstructures ' ] = microstructure . max ( )
# --- report ---------------------------------------------------------------------------------------
remarks = [ ]
if ( newInfo [ ' microstructures ' ] != info [ ' microstructures ' ] ) : remarks . append ( ' --> microstructures: %i ' % newInfo [ ' microstructures ' ] )
if remarks != [ ] : damask . util . croak ( remarks )
# --- write header ---------------------------------------------------------------------------------
table . labels_clear ( )
table . info_clear ( )
table . info_append ( extra_header + [
scriptID + ' ' + ' ' . join ( sys . argv [ 1 : ] ) ,
" grid \t a {grid[0]} \t b {grid[1]} \t c {grid[2]} " . format ( grid = info [ ' grid ' ] ) ,
" size \t x {size[0]} \t y {size[1]} \t z {size[2]} " . format ( size = info [ ' size ' ] ) ,
" origin \t x {origin[0]} \t y {origin[1]} \t z {origin[2]} " . format ( origin = info [ ' origin ' ] ) ,
" homogenization \t {homog} " . format ( homog = info [ ' homogenization ' ] ) ,
" microstructures \t {microstructures} " . format ( microstructures = newInfo [ ' microstructures ' ] ) ,
2013-06-30 19:21:21 +05:30
] )
2015-10-26 23:29:36 +05:30
table . head_write ( )
2015-09-24 00:50:18 +05:30
2013-06-21 01:15:25 +05:30
# --- write microstructure information ------------------------------------------------------------
2015-10-26 23:29:36 +05:30
2013-07-01 22:45:24 +05:30
formatwidth = int ( math . floor ( math . log10 ( microstructure . max ( ) ) + 1 ) )
2015-10-26 23:29:36 +05:30
table . data = microstructure . reshape ( ( info [ ' grid ' ] [ 0 ] , info [ ' grid ' ] [ 1 ] * info [ ' grid ' ] [ 2 ] ) , order = ' F ' ) . transpose ( )
table . data_writeArray ( ' %% %i i ' % ( formatwidth ) , delimiter = ' ' )
# --- output finalization --------------------------------------------------------------------------
table . close ( )