PageRenderTime 45ms CodeModel.GetById 1ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 1ms

/42TestingPoints/TOOLS/make42tree.py

http://github.com/xyan075/examples
Python | 280 lines | 153 code | 28 blank | 99 comment | 11 complexity | 3cb1487687d3f1e76a32d59bd39de74a MD5 | raw file
  1#! /usr/bin/env python
  2#
  3# Script to aid in setting up a 42 Testing points example.
  4#
  5# Bojan Blazevic
  6# Nov 2010
  7#
  8#
  9# USAGE:
 10# ./make42tree.py EXECUTABLE ARGS ROOT_DIR
 11#
 12#   EXECUTABLE :  Path to the compiled example binary
 13#                 This must be with respect to OPENCMISS_ROOT,
 14#                 which will be prepended to this string.
 15#   ARGS       :  Default arguments that the example requires [= '']
 16#   ROOT_DIR   :  Directory to build the folder structure [= ./]
 17#
 18# This file can also be loaded as a module, so that more parameters can be
 19# changed, individual functions run etc.
 20#
 21#
 22# BEHAVIOUR:
 23# 1) Creates the directory structure as defined by the 'spec' argument of the 
 24#    'traverseDirTree' function.
 25# 2) Creates the 'input' 'output' and 'expected_results' folders in each leaf
 26#    folder. Creates a 'run42.sh' that points to the executable passed in on
 27#    the command line.
 28# 3) Runs every 'run42.sh' in the directory tree
 29#
 30#
 31# USE CASES:
 32# 'I have an example file that takes care of all 42 points in one go. It is
 33#  located in $OPENCMISS_ROOT/cm/examples/.../jimmysexample/':
 34#  ./make42tree.py /cm/examples/.../jimmysexample/bin/x86_64-linux/mpich2/gnu/jimmysexample
 35#
 36# 'I have made some changes and I need to regenerate my expected output':
 37# python
 38# import make42tree
 39# run42FirstTime()
 40#
 41# 'But I don't want to re-run _everything_!':
 42# Read the 'TODO' below
 43#
 44#
 45# ARGUMENT FORMAT:
 46# -DIM = 2D | 3D
 47# -ELEM = TRI | TET | QUAD | HEX | HERMITE
 48# -BASIS = linear | quadratic | cubic | hermite
 49# -LEVEL = 1 | 2 | 3
 50#
 51#
 52# TODO:
 53# - Add docstrings
 54# - Add 'exceptions' (folders to be skipped when traversing the tree). We kinda
 55#   need this for steps 2/3 above.
 56# - Add parameter checking/automatic replacement of path with $OPENCMISS_ROOT
 57
 58
 59import sys
 60import os
 61import subprocess
 62import stat
 63
 64
 65# This function traverses a directory tree, calling 'nodeFunc' in every folder
 66# that has subfolders and calling 'leafFunc' in the remaining folders. By
 67# changing the functions passed in 'traverseDirTree' can be used for each step
 68# of setting up a '42 Testing Points' example and the structure specification
 69# format allows flexibility in the exact structure of the tree. (Eg. 'cubic'
 70# was changed to 'CubicVelocityLinearPressure' in the Navier Stokes tree)
 71#
 72# The tree structure specification is defined below
 73#
 74#     tree   ::= [level, level, ...]
 75#     level  ::= [option, option, ...]
 76#              | (tree, tree, ...)
 77#
 78# Here 'option' must be a string - this denotes an actual folder name.
 79#
 80# INTERPRETATION:
 81# This structure in essence just defines a tree where each folder has a sub-
 82# folders that are defined by the next 'level' spec. in the list. 
 83#
 84# Eg. [['left', 'right'], ['up', 'down'], ['forward', 'reverse']] would
 85#     define a tree where 'left' and 'right' had as subfolders 'up' and 'down'
 86#     etc.
 87#
 88# We can define more complex trees by throwing in tuples of trees where lists
 89# of folder names once were. A tuple of trees effectively results in each tree
 90# being substituted into the whole spec and executed as above.
 91#
 92# Eg. [['L', 'R'], ([['U'], ['F', 'R']], [['D'],['N', 'S']]), ['foo', 'bar']]
 93#     results in the following two trees:
 94#     [['L', 'R'], ['U'], ['F', 'R'], ['foo', 'bar']]
 95#     and
 96#     [['L', 'R'], ['D'], ['N', 'S'], ['foo', 'bar']]
 97#
 98# Notice how difficult this is to read and write. One should probably proceed
 99# by carefully modifying the specification defined later in the document.
100
101def traverseDirTree(spec, funcs, sofar = []):
102    if len(spec) == 0:              # Leaf node
103        funcs.leafFunc(sofar)
104    else:
105        cur = spec[0]
106        if type(cur) == tuple:      # Tuple trees
107            for t in cur:
108                traverseDirTree(t + spec[1:], funcs, sofar)
109        else:                       # An actual tree
110            for n in cur:
111                funcs.nodeFunc(sofar + [n])
112                try:
113                    os.chdir(n)
114                    traverseDirTree(spec[1:], funcs, sofar + [n])
115                    os.chdir('..')
116                except OSError:
117                    print('%s does not exist, continuing...' % n)
118
119
120
121class makeDirFuncs(object):
122    def nodeFunc(self, sofar):
123        d = sofar[-1]
124        print('Making directory %s' % d)
125        try:
126            os.mkdir(d)
127        except OSError:
128            print('Cannot create %s (or it exists), continuing...' % d)
129            
130    def leafFunc(self, sofar): pass
131
132
133    
134class makeScriptFuncs(object):
135    def __init__(self, defaultargs = '', execdir = '/'):
136        self.defaultargs = defaultargs
137        self.execdir = execdir
138    
139    @staticmethod
140    def makeArgs(sofar):
141        # The easiest way to do this
142        args = ''
143        args += '-DIM=' + sofar[0] + ' '
144        args += '-ELEM=' + sofar[1] + ' '
145        if (sofar[1] == 'HERMITE'):
146            args += '-BASIS=hermite '
147        else:
148            args += '-BASIS=' + sofar[2] + ' '
149        args += '-LEVEL=' + sofar[-1][-1]
150        return args
151    
152    @staticmethod
153    def makeLocalDirs(sofar):
154        try:
155            os.mkdir('input')
156            os.mkdir('output')
157            os.mkdir('expected_results')
158        except OSError:
159            print('Error making leaf folders, continuing...')
160    
161    def nodeFunc(self, sofar): pass
162        
163    def leafFunc(self, sofar):
164        print('Making leaf %s' % '/'.join(sofar))
165        makeScriptFuncs.makeLocalDirs(sofar)
166        options = makeScriptFuncs.makeArgs(sofar)
167    
168        # Make the run script
169        try:
170            run42 = open('run42.sh', 'w')
171        except IOError:
172            print('Cannot make run42.sh in leaf, continuing...!?')
173        else:
174            run42.write('#!/bin/bash\n')
175            # Should look at making following line more robust, people will most likely make mistakes
176            if sofar[-1] == 'LEVEL_3':
177                run42.write('mpiexec -n 2 $OPENCMISS_ROOT/' + self.execdir + ' ' + self.defaultargs + ' ' + options + '\n')
178            else:
179                run42.write('$OPENCMISS_ROOT/' + self.execdir + ' ' + self.defaultargs + ' ' + options + '\n')
180            run42.write('mv *.exnode *.exelem output/\n')
181            run42.close()
182            
183            # This method did not work, need to read more help
184            # os.chmod('run42.sh', stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
185            os.chmod('run42.sh', 0755)
186            # Neither does this
187            # subprocess.call('chmod +x run42.sh')
188        
189        
190        
191class firstTimeRunFuncs(object):
192    def nodeFunc(self, sofar): pass
193    
194    def leafFunc(self, sofar):
195        print('Running %s' % '/'.join(sofar) + '/run42.sh')
196        try:
197            ret = subprocess.call('/bin/bash run42.sh', shell=True)
198        except Exception:
199            print('Could not run subprocess')
200        else:
201            if not ret == 0:
202                print('Bad return code %d, continuing...' % ret)
203            else:
204                subprocess.call('mv *.exnode *.exelem expected_results')
205     
206        
207
208# The specification for the default 42 Testing Points tree
209spec42 = [(
210           [['2D'], (
211                     [['TRI', 'QUAD'], ['linear', 'quadratic', 'cubic']],
212                     [['HERMITE']]
213                    )
214           ],
215           [['3D'], (
216                     [['TET', 'HEX'], ['linear', 'quadratic', 'cubic']],
217                     [['HERMITE']]
218                    )
219           ]
220          ), 
221           ['LEVEL_1', 'LEVEL_2', 'LEVEL_3']
222         ]
223 
224
225
226# Nice wrappers for the 3 main stages of setup
227def make42Structure(spec = spec42):
228    traverseDirTree(spec, makeDirFuncs())
229    
230def make42Scripts(defaultargs, execdir, spec = spec42):
231    traverseDirTree(spec, makeScriptFuncs(defaultargs, execdir))
232    
233def run42FirstTime(spec = spec42):
234    traverseDirTree(spec, firstTimeRunFuncs())
235
236
237# When used as a script
238if __name__ == '__main__':
239
240    def printUsageDie():
241        print('make42tree.py')
242        print('')
243        print('Usage:')
244        print('  ./make42tree.py EXECUTABLE ARGS ROOT_DIR')
245        print('')
246        print('   EXECUTABLE :  Path to the compiled example binary')
247        print('                 This must be with respect to OPENCMISS_ROOT,')
248        print('                 which will be prepended to this string.') 
249        print('   ARGS       :  Default arguments that the example requires '
250                                  '[= \'\']')
251        print('   ROOT_DIR   :  Directory to build the folder structure '
252                                  '[= ./]')
253        sys.exit('Incorrect usage!')
254    
255    if len(sys.argv) < 2:
256        printUsageDie()
257        
258    execdir = sys.argv[1]
259    
260    if len(sys.argv) < 3:
261        rootdir = './'
262    else:
263        rootdir = sys.argv[2]
264        
265    if len(sys.argv) < 4:
266        defaultargs = ''
267    else:
268        defaultargs = sys.argv[3]
269    
270    try:
271        os.chdir(rootdir)
272    except OSError:
273        print('Cannot go to ROOT_DIR=%s' % rootdir)
274        printUsageDie()
275    
276    make42Structure()
277    make42Scripts(defaultargs, execdir)
278    run42FirstTime()
279
280