2014-09-29 15:49:49 +05:30
#!/usr/bin/python
# -*- coding: UTF-8 no BOM -*-
import threading , time , os , subprocess , shlex , string , sys , random
import numpy as np
from optparse import OptionParser
from operator import mul
from cStringIO import StringIO
import damask
2014-10-03 02:57:03 +05:30
scriptID = string . replace ( ' $Id$ ' , ' \n ' , ' \\ n ' )
2014-11-06 03:35:37 +05:30
scriptName = os . path . splitext ( scriptID . split ( ) [ 1 ] ) [ 0 ]
2015-04-11 02:17:20 +05:30
2014-09-29 15:49:49 +05:30
mismatch = None
currentSeedsName = None
def execute ( cmd , streamIn = None , dir = ' ./ ' ) :
2014-10-09 16:31:07 +05:30
'''
executes a command in given directory and returns stdout and stderr for optional stdin
'''
2014-09-29 15:49:49 +05:30
initialPath = os . getcwd ( )
os . chdir ( dir )
process = subprocess . Popen ( shlex . split ( cmd ) , stdout = subprocess . PIPE , stderr = subprocess . PIPE , stdin = subprocess . PIPE )
if streamIn != None :
out , error = process . communicate ( streamIn . read ( ) )
else :
out , error = process . communicate ( )
os . chdir ( initialPath )
return out , error
#---------------------------------------------------------------------------------------------------
class myThread ( threading . Thread ) :
#---------------------------------------------------------------------------------------------------
'''
2014-10-09 16:31:07 +05:30
perturbes seed in seed file , performes Voronoi tessellation , evaluates , and updates best match
2014-09-29 15:49:49 +05:30
'''
def __init__ ( self , threadID ) :
threading . Thread . __init__ ( self )
self . threadID = threadID
def run ( self ) :
global bestSeedsUpdate
global bestSeedsVFile
global nMicrostructures
global delta
global points
global target
global match
global baseFile
2015-04-10 23:38:17 +05:30
global maxSeeds
2014-09-29 15:49:49 +05:30
s . acquire ( )
2014-09-29 21:25:17 +05:30
bestMatch = match
2014-09-29 15:49:49 +05:30
s . release ( )
2014-10-09 16:31:07 +05:30
random . seed ( options . randomSeed + self . threadID ) # initializes to given seeds
knownSeedsUpdate = bestSeedsUpdate - 1.0 # trigger update of local best seeds (time when the best seed file was found known to thread)
randReset = True # aquire new direction
2014-09-29 15:49:49 +05:30
2014-10-09 16:31:07 +05:30
myBestSeedsVFile = StringIO ( ) # in-memory file to store local copy of best seeds file
perturbedSeedsVFile = StringIO ( ) # in-memory file for perturbed best seeds file
perturbedGeomVFile = StringIO ( ) # in-memory file for tessellated geom file
2014-09-29 15:49:49 +05:30
2014-10-09 16:31:07 +05:30
#--- still not matching desired bin class ----------------------------------------------------------
2014-09-29 21:25:17 +05:30
while bestMatch < options . threshold :
2014-10-09 16:31:07 +05:30
s . acquire ( ) # accessing global data, ensure only one thread does it per time
if bestSeedsUpdate > knownSeedsUpdate : # if a newer best seed file exist, read it into a virtual file
2014-09-29 15:49:49 +05:30
knownSeedsUpdate = bestSeedsUpdate
bestSeedsVFile . reset ( )
myBestSeedsVFile . close ( )
myBestSeedsVFile = StringIO ( )
i = 0
for line in bestSeedsVFile :
myBestSeedsVFile . write ( line )
s . release ( )
2014-10-09 16:31:07 +05:30
if randReset : # new direction because current one led to worse fit
2014-09-29 15:49:49 +05:30
randReset = False
2015-04-14 18:12:35 +05:30
NmoveGrains = random . randrange ( 1 , maxSeeds )
selectedMs = [ ]
direction = [ ]
for i in xrange ( NmoveGrains ) :
selectedMs . append ( random . randrange ( 1 , nMicrostructures ) )
direction . append ( np . array ( ( ( random . random ( ) - 0.5 ) * delta [ 0 ] ,
( random . random ( ) - 0.5 ) * delta [ 1 ] ,
( random . random ( ) - 0.5 ) * delta [ 2 ] ) ) )
2014-10-09 16:31:07 +05:30
perturbedSeedsVFile . close ( ) # reset virtual file
2014-09-29 15:49:49 +05:30
perturbedSeedsVFile = StringIO ( )
myBestSeedsVFile . reset ( )
2014-10-09 16:31:07 +05:30
perturbedSeedsTable = damask . ASCIItable ( myBestSeedsVFile , perturbedSeedsVFile , labels = True ) # read current best fitting seed file and to perturbed seed file
perturbedSeedsTable . head_read ( )
2014-09-29 15:49:49 +05:30
perturbedSeedsTable . head_write ( )
outputAlive = True
ms = 1
2015-04-11 02:17:20 +05:30
while outputAlive and perturbedSeedsTable . data_read ( ) : # perturbe selected microstructure
2015-04-14 18:12:35 +05:30
if ms in selectedMs :
2014-09-29 15:49:49 +05:30
direction + = direction
2015-04-14 18:12:35 +05:30
newCoords = np . array ( tuple ( map ( float , perturbedSeedsTable . data [ 0 : 3 ] ) ) + direction [ i ] )
2015-04-11 02:17:20 +05:30
newCoords = np . where ( newCoords > = 1.0 , newCoords - 1.0 , newCoords ) # ensure that the seeds remain in the box (move one side out, other side in)
2014-12-05 16:05:56 +05:30
newCoords = np . where ( newCoords < 0.0 , newCoords + 1.0 , newCoords )
2014-09-29 15:49:49 +05:30
perturbedSeedsTable . data [ 0 : 3 ] = [ format ( f , ' 8.6f ' ) for f in newCoords ]
ms + = 1
perturbedSeedsTable . data_write ( )
2014-10-09 16:31:07 +05:30
#--- do tesselation with perturbed seed file ----------------------------------------------------------
2014-09-29 15:49:49 +05:30
perturbedGeomVFile . close ( )
perturbedGeomVFile = StringIO ( )
perturbedSeedsVFile . reset ( )
perturbedGeomVFile . write ( execute ( ' geom_fromVoronoiTessellation ' +
' -g ' + ' ' . join ( map ( str , options . grid ) ) , streamIn = perturbedSeedsVFile ) [ 0 ] )
perturbedGeomVFile . reset ( )
2014-10-09 16:31:07 +05:30
#--- evaluate current seeds file ----------------------------------------------------------------------
2014-09-29 15:49:49 +05:30
perturbedGeomTable = damask . ASCIItable ( perturbedGeomVFile , labels = False )
perturbedGeomTable . head_read ( )
for i in perturbedGeomTable . info :
if i . startswith ( ' microstructures ' ) : myNmicrostructures = int ( i . split ( ' \t ' ) [ 1 ] )
perturbedGeomTable . data_readArray ( )
perturbedGeomTable . output_flush ( )
currentData = np . bincount ( perturbedGeomTable . data . astype ( int ) . ravel ( ) ) [ 1 : ] / points
currentError = [ ]
currentHist = [ ]
2015-04-11 02:17:20 +05:30
for i in xrange ( nMicrostructures ) : # calculate the deviation in all bins per histogram
2014-09-29 15:49:49 +05:30
currentHist . append ( np . histogram ( currentData , bins = target [ i ] [ ' bins ' ] ) [ 0 ] )
currentError . append ( np . sqrt ( np . square ( np . array ( target [ i ] [ ' histogram ' ] - currentHist [ i ] ) ) . sum ( ) ) )
2015-04-11 02:17:20 +05:30
if currentError [ 0 ] > 0.0 : # as long as not all grains are within the range of the target, use the deviation to left and right as error
2015-04-14 18:12:35 +05:30
currentError [ 0 ] * = ( ( target [ 0 ] [ ' bins ' ] [ 0 ] - np . min ( currentData ) ) * * 2.0 +
( target [ 0 ] [ ' bins ' ] [ 1 ] - np . max ( currentData ) ) * * 2.0 ) * * 0.5 # norm of deviations by number of usual bin deviation
2015-04-11 02:17:20 +05:30
s . acquire ( ) # do the evaluation serially
2014-09-29 21:25:17 +05:30
bestMatch = match
2014-10-09 16:31:07 +05:30
#--- count bin classes with no mismatch ----------------------------------------------------------------------
2014-09-29 21:25:17 +05:30
myMatch = 0
for i in xrange ( nMicrostructures ) :
if currentError [ i ] > 0.0 : break
myMatch = i + 1
2014-09-29 15:49:49 +05:30
2014-10-09 16:31:07 +05:30
if myNmicrostructures == nMicrostructures :
2014-12-18 23:33:36 +05:30
for i in xrange ( min ( nMicrostructures , myMatch + options . bins ) ) :
2015-04-11 02:17:20 +05:30
if currentError [ i ] > target [ i ] [ ' error ' ] : # worse fitting, next try
2014-09-29 15:49:49 +05:30
randReset = True
break
2015-04-11 02:17:20 +05:30
elif currentError [ i ] < target [ i ] [ ' error ' ] : # better fit
bestSeedsUpdate = time . time ( ) # save time of better fit
2014-09-29 21:25:17 +05:30
print ' Thread %i : Better match ( %i bins, %6.4f --> %6.4f ) ' % ( self . threadID , i + 1 , target [ i ] [ ' error ' ] , currentError [ i ] )
print ' target: ' , target [ i ] [ ' histogram ' ]
print ' best: ' , currentHist [ i ]
2015-04-11 02:17:20 +05:30
currentSeedsName = baseFile + ' _ ' + str ( bestSeedsUpdate ) . replace ( ' . ' , ' - ' ) # name of new seed file (use time as unique identifier)
2014-09-29 15:49:49 +05:30
perturbedSeedsVFile . reset ( )
bestSeedsVFile . close ( )
bestSeedsVFile = StringIO ( )
2014-09-29 21:25:17 +05:30
sys . stdout . flush ( )
2015-04-11 02:17:20 +05:30
with open ( currentSeedsName + ' .seeds ' , ' w ' ) as currentSeedsFile : # write to new file
2014-09-29 15:49:49 +05:30
for line in perturbedSeedsVFile :
currentSeedsFile . write ( line )
bestSeedsVFile . write ( line )
2015-04-11 02:17:20 +05:30
for j in xrange ( nMicrostructures ) : # save new errors for all bins
2014-09-29 15:49:49 +05:30
target [ j ] [ ' error ' ] = currentError [ j ]
2015-04-11 02:17:20 +05:30
if myMatch > match : # one or more new bins have no deviation
2014-09-29 21:25:17 +05:30
print ' Stage %i cleared ' % ( myMatch )
match = myMatch
sys . stdout . flush ( )
2014-09-29 15:49:49 +05:30
break
2015-04-11 02:17:20 +05:30
if i == min ( nMicrostructures , myMatch + options . bins ) - 1 : # same quality as before (for the considered bins): take it to keep on moving
2014-12-18 23:33:36 +05:30
bestSeedsUpdate = time . time ( )
perturbedSeedsVFile . reset ( )
bestSeedsVFile . close ( )
bestSeedsVFile = StringIO ( )
for line in perturbedSeedsVFile :
bestSeedsVFile . write ( line )
for j in xrange ( nMicrostructures ) :
target [ j ] [ ' error ' ] = currentError [ j ]
randReset = True
2015-04-11 02:17:20 +05:30
else : #--- not all grains are tessellated
2014-10-09 16:31:07 +05:30
print ' Thread %i : Microstructure mismatch ( %i microstructures mapped) ' % ( self . threadID , myNmicrostructures )
randReset = True
2014-09-29 21:25:17 +05:30
2014-09-29 15:49:49 +05:30
s . release ( )
# --------------------------------------------------------------------
# MAIN
# --------------------------------------------------------------------
parser = OptionParser ( option_class = damask . extendableOption , usage = ' % prog options [file[s]] ' , description = """
Monte Carlo simulation to produce seed file that gives same size distribution like given geometry file .
2014-10-13 15:24:01 +05:30
""" , version = scriptID)
2014-09-29 15:49:49 +05:30
parser . add_option ( ' -s ' , ' --seeds ' , dest = ' seedFile ' , metavar = ' string ' ,
help = ' name of the intial seed file. If not found, a new one is created [ %d efault] ' )
parser . add_option ( ' -g ' , ' --grid ' , dest = ' grid ' , type = ' int ' , nargs = 3 , metavar = ' int int int ' ,
help = ' a,b,c grid of hexahedral box [ %d efault] ' )
parser . add_option ( ' -t ' , ' --threads ' , dest = ' threads ' , type = ' int ' , metavar = ' int ' ,
help = ' number of parallel executions [ %d efault] ' )
parser . add_option ( ' -r ' , ' --rnd ' , dest = ' randomSeed ' , type = ' int ' , metavar = ' int ' ,
help = ' seed of random number generator [ %d efault] ' )
parser . add_option ( ' --target ' , dest = ' target ' , metavar = ' string ' ,
help = ' name of the geom file with target distribution [ %d efault] ' )
2014-09-29 21:25:17 +05:30
parser . add_option ( ' --tolerance ' , dest = ' threshold ' , type = ' int ' , metavar = ' int ' ,
help = ' stopping criterion (bin number) [ %d efault] ' )
2014-09-29 15:49:49 +05:30
parser . add_option ( ' --scale ' , dest = ' scale ' , type = ' float ' , metavar = ' float ' ,
help = ' maximum moving distance of perturbed seed in pixel [ %d efault] ' )
2014-12-18 23:33:36 +05:30
parser . add_option ( ' --bins ' , dest = ' bins ' , type = ' int ' , metavar = ' int ' ,
help = ' bins to sort beyond current best fit [ %d efault] ' )
2015-04-10 23:38:17 +05:30
parser . add_option ( ' --maxseeds ' , dest = ' maxseeds ' , type = ' int ' , metavar = ' int ' ,
help = ' maximum number of seeds to move simulateneously [number of seeds] ' )
2014-09-29 15:49:49 +05:30
parser . set_defaults ( seedFile = ' seeds ' )
parser . set_defaults ( grid = ( 64 , 64 , 64 ) )
parser . set_defaults ( threads = 2 )
parser . set_defaults ( randomSeed = None )
parser . set_defaults ( target = ' geom ' )
2014-09-29 21:25:17 +05:30
parser . set_defaults ( threshold = 20 )
2014-12-18 23:33:36 +05:30
parser . set_defaults ( bins = 15 )
2014-09-29 15:49:49 +05:30
parser . set_defaults ( scale = 1.0 )
2015-04-10 23:38:17 +05:30
parser . set_defaults ( maxseeds = 0 )
2014-09-29 15:49:49 +05:30
options = parser . parse_args ( ) [ 0 ]
if options . randomSeed == None :
options . randomSeed = int ( os . urandom ( 4 ) . encode ( ' hex ' ) , 16 )
print ' random seed ' , options . randomSeed
delta = ( options . scale / options . grid [ 0 ] , options . scale / options . grid [ 1 ] , options . scale / options . grid [ 2 ] )
baseFile = os . path . splitext ( os . path . basename ( options . seedFile ) ) [ 0 ]
points = float ( reduce ( mul , options . grid ) )
# ----------- calculate target distribution and bin edges
with open ( os . path . splitext ( os . path . basename ( options . target ) ) [ 0 ] + ' .geom ' ) as targetGeomFile :
2014-09-29 21:25:17 +05:30
targetGeomTable = damask . ASCIItable ( targetGeomFile , labels = False )
2014-09-29 15:49:49 +05:30
targetGeomTable . head_read ( )
for i in targetGeomTable . info :
if i . startswith ( ' microstructures ' ) : nMicrostructures = int ( i . split ( ) [ 1 ] )
2014-09-29 21:25:17 +05:30
if i . startswith ( ' grid ' ) : targetPoints = np . array ( map ( float , i . split ( ) [ 2 : 7 : 2 ] ) ) . prod ( )
2014-09-29 15:49:49 +05:30
targetGeomTable . data_readArray ( )
2014-09-29 21:25:17 +05:30
targetVolFrac = np . bincount ( targetGeomTable . data . astype ( int ) . ravel ( ) ) [ 1 : nMicrostructures + 1 ] / targetPoints
2014-09-29 15:49:49 +05:30
target = [ ]
for i in xrange ( 1 , nMicrostructures + 1 ) :
2014-09-29 21:25:17 +05:30
targetHist , targetBins = np . histogram ( targetVolFrac , bins = i ) #bin boundaries
2014-09-29 15:49:49 +05:30
target . append ( { ' histogram ' : targetHist , ' bins ' : targetBins } )
# ----------- create initial seed file or open existing one
bestSeedsVFile = StringIO ( )
if os . path . isfile ( os . path . splitext ( options . seedFile ) [ 0 ] + ' .seeds ' ) :
with open ( os . path . splitext ( options . seedFile ) [ 0 ] + ' .seeds ' ) as initialSeedFile :
for line in initialSeedFile : bestSeedsVFile . write ( line )
else :
bestSeedsVFile . write ( execute ( ' seeds_fromRandom ' + \
' -g ' + ' ' . join ( map ( str , options . grid ) ) + \
' -r %i ' % options . randomSeed + \
' -N ' + str ( nMicrostructures ) ) [ 0 ] )
bestSeedsUpdate = time . time ( )
# ----------- tessellate initial seed file to get and evaluate geom file
bestSeedsVFile . reset ( )
initialGeomVFile = StringIO ( )
initialGeomVFile . write ( execute ( ' geom_fromVoronoiTessellation ' +
' -g ' + ' ' . join ( map ( str , options . grid ) ) , bestSeedsVFile ) [ 0 ] )
initialGeomVFile . reset ( )
initialGeomTable = damask . ASCIItable ( initialGeomVFile , labels = False )
initialGeomTable . head_read ( )
for i in initialGeomTable . info :
if i . startswith ( ' microstructures ' ) : initialMicrostructures = int ( i . split ( ' \t ' ) [ 1 ] )
if initialMicrostructures != nMicrostructures : print ' error. Microstructure count mismatch '
initialGeomTable . data_readArray ( )
initialData = np . bincount ( initialGeomTable . data . astype ( int ) . ravel ( ) ) [ 1 : ] / points
for i in xrange ( nMicrostructures ) :
initialHist = np . histogram ( initialData , bins = target [ i ] [ ' bins ' ] ) [ 0 ]
target [ i ] [ ' error ' ] = np . sqrt ( np . square ( np . array ( target [ i ] [ ' histogram ' ] - initialHist ) ) . sum ( ) )
2014-09-29 21:25:17 +05:30
2015-04-11 02:17:20 +05:30
# as long as not all grain sizes are within the range, the error is the deviation to left and right
if target [ 0 ] [ ' error ' ] > 0.0 :
2015-04-14 18:12:35 +05:30
target [ 0 ] [ ' error ' ] * = ( ( target [ 0 ] [ ' bins ' ] [ 0 ] - np . min ( initialData ) ) * * 2.0 +
( target [ 0 ] [ ' bins ' ] [ 1 ] - np . max ( initialData ) ) * * 2.0 ) * * 0.5
2014-09-29 21:25:17 +05:30
match = 0
for i in xrange ( nMicrostructures ) :
if target [ i ] [ ' error ' ] > 0.0 : break
match = i + 1
2014-09-29 15:49:49 +05:30
2015-04-10 23:38:17 +05:30
2015-04-14 18:12:35 +05:30
if options . maxseeds < 1 :
maxSeeds = initialMicrostructures
else :
maxSeeds = options . maxseeds
2015-04-10 23:38:17 +05:30
2015-04-11 02:17:20 +05:30
if match > 0 : print ' Stage %i cleared ' % match
2014-12-18 23:33:36 +05:30
sys . stdout . flush ( )
2014-09-29 15:49:49 +05:30
initialGeomVFile . close ( )
2014-12-05 16:05:56 +05:30
# start mulithreaded monte carlo simulation
2014-09-29 15:49:49 +05:30
threads = [ ]
s = threading . Semaphore ( 1 )
for i in range ( options . threads ) :
threads . append ( myThread ( i ) )
threads [ i ] . start ( )
for i in range ( options . threads ) :
threads [ i ] . join ( )