2016-07-18 23:05:35 +05:30
#!/usr/bin/env python2.7
2016-03-17 00:32:38 +05:30
# -*- coding: UTF-8 no BOM -*-
import os , sys , math
import numpy as np
from optparse import OptionParser
import damask
scriptName = os . path . splitext ( os . path . basename ( __file__ ) ) [ 0 ]
scriptID = ' ' . join ( [ scriptName , damask . version ] )
2018-01-30 00:42:19 +05:30
def merge_dicts ( * dict_args ) :
"""
Given any number of dicts , shallow copy and merge into a new dict ,
precedence goes to key value pairs in latter dicts .
"""
result = { }
for dictionary in dict_args :
result . update ( dictionary )
return result
2016-03-17 00:32:38 +05:30
def gradFFT ( geomdim , field ) :
2016-04-11 23:55:24 +05:30
shapeFFT = np . array ( np . shape ( field ) ) [ 0 : 3 ]
2016-03-17 00:32:38 +05:30
grid = np . array ( np . shape ( field ) [ 2 : : - 1 ] )
2016-11-07 14:19:53 +05:30
N = grid . prod ( ) # field size
n = np . array ( np . shape ( field ) [ 3 : ] ) . prod ( ) # data size
2016-04-25 16:27:38 +05:30
2016-03-17 00:32:38 +05:30
if n == 3 : dataType = ' vector '
elif n == 1 : dataType = ' scalar '
2016-06-29 14:28:15 +05:30
field_fourier = np . fft . rfftn ( field , axes = ( 0 , 1 , 2 ) , s = shapeFFT )
2016-04-11 23:55:24 +05:30
grad_fourier = np . empty ( field_fourier . shape + ( 3 , ) , ' c16 ' )
2016-03-17 00:32:38 +05:30
# differentiation in Fourier space
2018-01-29 04:32:35 +05:30
# Question: why are grid[0,1,2] normalized by geomdim[2,1,0]??
2016-03-17 00:32:38 +05:30
TWOPIIMG = 2.0 j * math . pi
2016-11-04 23:20:39 +05:30
k_sk = np . where ( np . arange ( grid [ 2 ] ) > grid [ 2 ] / / 2 , np . arange ( grid [ 2 ] ) - grid [ 2 ] , np . arange ( grid [ 2 ] ) ) / geomdim [ 0 ]
2016-11-07 14:19:53 +05:30
if grid [ 2 ] % 2 == 0 : k_sk [ grid [ 2 ] / / 2 ] = 0 # for even grid, set Nyquist freq to 0 (Johnson, MIT, 2011)
2016-11-04 23:20:39 +05:30
k_sj = np . where ( np . arange ( grid [ 1 ] ) > grid [ 1 ] / / 2 , np . arange ( grid [ 1 ] ) - grid [ 1 ] , np . arange ( grid [ 1 ] ) ) / geomdim [ 1 ]
2016-11-07 14:19:53 +05:30
if grid [ 1 ] % 2 == 0 : k_sj [ grid [ 1 ] / / 2 ] = 0 # for even grid, set Nyquist freq to 0 (Johnson, MIT, 2011)
2016-11-04 23:20:39 +05:30
k_si = np . arange ( grid [ 0 ] / / 2 + 1 ) / geomdim [ 2 ]
kk , kj , ki = np . meshgrid ( k_sk , k_sj , k_si , indexing = ' ij ' )
k_s = np . concatenate ( ( ki [ : , : , : , None ] , kj [ : , : , : , None ] , kk [ : , : , : , None ] ) , axis = 3 ) . astype ( ' c16 ' )
2016-11-07 14:19:53 +05:30
if dataType == ' vector ' : # vector, 3 -> 3x3
2016-11-04 23:20:39 +05:30
grad_fourier = np . einsum ( ' ijkl,ijkm->ijklm ' , field_fourier , k_s ) * TWOPIIMG
2016-11-07 14:19:53 +05:30
elif dataType == ' scalar ' : # scalar, 1 -> 3
2018-01-29 19:48:05 +05:30
grad_fourier = np . einsum ( ' ijkl,ijkm->ijkm ' , field_fourier , k_s ) * TWOPIIMG
2016-03-17 00:32:38 +05:30
2016-06-29 14:28:15 +05:30
return np . fft . irfftn ( grad_fourier , axes = ( 0 , 1 , 2 ) , s = shapeFFT ) . reshape ( [ N , 3 * n ] )
2016-03-17 00:32:38 +05:30
# --------------------------------------------------------------------
# MAIN
# --------------------------------------------------------------------
2016-04-25 16:27:38 +05:30
parser = OptionParser ( option_class = damask . extendableOption , usage = ' % prog option(s) [ASCIItable(s)] ' , description = """
2016-03-17 00:32:38 +05:30
Add column ( s ) containing gradient of requested column ( s ) .
2018-01-29 04:32:35 +05:30
Operates on periodic ordered three - dimensional data sets
of vector and scalar fields .
2016-03-17 00:32:38 +05:30
""" , version = scriptID)
2016-04-25 16:52:34 +05:30
parser . add_option ( ' -p ' , ' --pos ' , ' --periodiccellcenter ' ,
2016-04-27 02:19:58 +05:30
dest = ' pos ' ,
2016-04-25 16:27:38 +05:30
type = ' string ' , metavar = ' string ' ,
help = ' label of coordinates [ %d efault] ' )
2018-01-29 04:32:35 +05:30
parser . add_option ( ' -d ' , ' --data ' ,
dest = ' data ' ,
2016-03-17 00:32:38 +05:30
action = ' extend ' , metavar = ' <string LIST> ' ,
2018-01-29 04:32:35 +05:30
help = ' label(s) of field values ' )
2016-03-17 00:32:38 +05:30
2016-04-27 02:19:58 +05:30
parser . set_defaults ( pos = ' pos ' ,
2016-03-17 00:32:38 +05:30
)
( options , filenames ) = parser . parse_args ( )
2018-01-29 04:32:35 +05:30
if options . data is None : parser . error ( ' no data column specified. ' )
2016-03-17 00:32:38 +05:30
2018-01-30 00:42:19 +05:30
# --- define possible data types -------------------------------------------------------------------
datatypes = {
1 : { ' name ' : ' scalar ' ,
' shape ' : [ 1 ] ,
} ,
3 : { ' name ' : ' vector ' ,
' shape ' : [ 3 ] ,
} ,
}
2016-03-17 00:42:53 +05:30
# --- loop over input files ------------------------------------------------------------------------
2016-03-17 00:32:38 +05:30
if filenames == [ ] : filenames = [ None ]
for name in filenames :
try : table = damask . ASCIItable ( name = name , buffered = False )
except : continue
damask . util . report ( scriptName , name )
2018-01-29 04:32:35 +05:30
# --- interpret header ----------------------------------------------------------------------------
2016-03-17 00:32:38 +05:30
table . head_read ( )
remarks = [ ]
2018-01-29 04:32:35 +05:30
errors = [ ]
2018-01-30 00:42:19 +05:30
active = [ ]
2018-01-29 04:32:35 +05:30
coordDim = table . label_dimension ( options . pos )
if coordDim != 3 :
errors . append ( ' coordinates " {} " must be three-dimensional. ' . format ( options . pos ) )
else : coordCol = table . label_index ( options . pos )
2018-01-30 00:42:19 +05:30
for me in options . data :
dim = table . label_dimension ( me )
if dim in datatypes :
active . append ( merge_dicts ( { ' label ' : me } , datatypes [ dim ] ) )
remarks . append ( ' differentiating {} " {} " ... ' . format ( datatypes [ dim ] [ ' name ' ] , me ) )
2018-01-29 04:32:35 +05:30
else :
2018-01-30 00:42:19 +05:30
remarks . append ( ' skipping " {} " of dimension {} ... ' . format ( me , dim ) if dim != - 1 else \
' " {} " not found... ' . format ( me ) )
2016-03-17 00:32:38 +05:30
if remarks != [ ] : damask . util . croak ( remarks )
if errors != [ ] :
damask . util . croak ( errors )
table . close ( dismiss = True )
continue
# ------------------------------------------ assemble header --------------------------------------
table . info_append ( scriptID + ' \t ' + ' ' . join ( sys . argv [ 1 : ] ) )
2018-01-30 00:42:19 +05:30
for data in active :
table . labels_append ( [ ' {} _gradFFT( {} ) ' . format ( i + 1 , data [ ' label ' ] ) for i in range ( coordDim * np . prod ( np . array ( data [ ' shape ' ] ) ) ) ] ) # extend ASCII header with new labels
2016-03-17 00:32:38 +05:30
table . head_write ( )
# --------------- figure out size and grid ---------------------------------------------------------
table . data_readArray ( )
2018-01-29 04:32:35 +05:30
coords = [ np . unique ( table . data [ : , coordCol + i ] ) for i in range ( 3 ) ]
2016-03-17 00:32:38 +05:30
mincorner = np . array ( map ( min , coords ) )
maxcorner = np . array ( map ( max , coords ) )
grid = np . array ( map ( len , coords ) , ' i ' )
size = grid / np . maximum ( np . ones ( 3 , ' d ' ) , grid - 1.0 ) * ( maxcorner - mincorner ) # size from edge to edge = dim * n/(n-1)
2016-04-25 16:27:38 +05:30
size = np . where ( grid > 1 , size , min ( size [ grid > 1 ] / grid [ grid > 1 ] ) ) # spacing for grid==1 equal to smallest among other ones
2016-03-17 00:32:38 +05:30
# ------------------------------------------ process value field -----------------------------------
stack = [ table . data ]
2018-01-30 00:42:19 +05:30
for data in active :
# we need to reverse order here, because x is fastest,ie rightmost, but leftmost in our x,y,z notation
stack . append ( gradFFT ( size [ : : - 1 ] ,
table . data [ : , table . label_indexrange ( data [ ' label ' ] ) ] .
reshape ( grid [ : : - 1 ] . tolist ( ) + data [ ' shape ' ] ) ) )
2016-03-17 00:32:38 +05:30
# ------------------------------------------ output result -----------------------------------------
if len ( stack ) > 1 : table . data = np . hstack ( tuple ( stack ) )
table . data_writeArray ( ' %.12g ' )
# ------------------------------------------ output finalization -----------------------------------
table . close ( ) # close input ASCII table (works for stdin)