Source code for nrelmat.execMimic

#!/usr/bin/env python

import filecmp, json, os, re, shutil, sys



#====================================================================



def badparms( msg):
  print '\nError: %s' % (msg,)
  print 'Parms:'
  print '  -bugLev             debug level'
  print '  -specFile           input file in some ancestor dir'
  sys.exit( 1)

#====================================================================
#====================================================================

[docs]def main(): ''' Mimics the execution of a program by checking that the input files are as we expect, and then copying previously calculated output files. This program is used to mimic the execution of VASP for validity testing. See pylada/testValid. Command line parameters: ============== =========== =============================================== Parameter Type Description ============== =========== =============================================== **-bugLev** integer Debug level. Normally 0. **-specFile** string JSON file containing specs. See below. ============== =========== =============================================== **specFile Contents:** =================== ================================================= Parameter Description =================== ================================================= **refRoot** Root dir of the reference tree **workRoot** Root dir of the tree to be checked **inFiles** List of files to be checked in each work dir **outFiles** List of files to copy from ref dir to work dir. If '', copy all except inFiles and omits. **omitFiles** List of regexs of outFiles to omit. **absEpsilon** Absolute epsilon for comparing floats of work inFile vs ref inFile. **relEpsilon** Relative epsilon for comparing floats of work inFile vs ref inFile. **logFile** Log file for execMimic output. =================== ================================================= **inSpec file example:**:: { "absEpsilon": "1.e-6", "relEpsilon": "1.e-6", "refRoot": "/home/me/reference", "workRoot": "/home/me/test", "inFiles": "INCAR,KPOINTS,POSCAR,POTCAR", "outFiles": "", "omitFiles": "^pbs.*$,^std.*$", "logFile": "/home/me/execMimic.log" } ''' bugLev = 1 specFile = 'pylada.execMimic.json' if len(sys.argv) % 2 != 1: badparms('parms must be key/value pairs') for iarg in range( 1, len(sys.argv), 2): key = sys.argv[iarg] val = sys.argv[iarg+1] if key == '-bugLev': bugLev = int( val) elif key == '-specFile': specFile = val else: badparms('unknown parm: "%s"' % (key,)) # Find the spec file by looking at ancestor dirs specPath = None curDir = os.getcwd().rstrip('/') # no trailing '/' while curDir != '': spath = os.path.join( curDir, specFile) if os.access( spath, os.R_OK): specPath = spath break ix = curDir.rfind('/') if ix < 0: break curDir = curDir[:ix] # Omit print as it overwrites PyLada's stdout ##if bugLev >= 1: print 'specPath: %s' % (specPath,) if specPath == None: throwerr( None, 'missing specFile: %s' % specFile, None) with open( specPath) as fin: specMap = json.load( fin) # Omit print as it overwrites PyLada's stdout ##if bugLev >= 1: print 'specMap: %s' % (specMap,) if type(specMap).__name__ != 'dict': throwerr( None, 'invalid json type', specPath) refRoot = specMap.get('refRoot', None) workRoot = specMap.get('workRoot', None) refRoot = os.path.expanduser( refRoot) workRoot = os.path.expanduser( workRoot) inFileStg = specMap.get('inFiles', None) outFileStg = specMap.get('outFiles', None) omitFileStg = specMap.get('omitFiles', None) absEpsilon = float( specMap.get('absEpsilon', None)) relEpsilon = float( specMap.get('relEpsilon', None)) logFileStg = specMap.get('logFile', None) if refRoot == None or refRoot != os.path.abspath( refRoot): throwerr( None, 'refRoot is missing or not absolute', specPath) if workRoot == None or workRoot != os.path.abspath( workRoot): throwerr( None, 'workRoot is missing or not absolute', specPath) if logFileStg == None or len(logFileStg) == 0: throwerr( None, 'logFile is missing', specPath) logName = os.path.expanduser( logFileStg) if bugLev >= 1: printLog( logName, 'specPath: %s' % (specPath,)) printLog( logName, 'refRoot: %s' % (refRoot,)) printLog( logName, 'workRoot: %s' % (workRoot,)) printLog( logName, 'inFileStg: %s' % (inFileStg,)) printLog( logName, 'outFileStg: %s' % (outFileStg,)) printLog( logName, 'omitFileStg: %s' % (omitFileStg,)) printLog( logName, 'absEpsilon: %s' % (absEpsilon,)) printLog( logName, 'relEpsilon: %s' % (relEpsilon,)) printLog( logName, 'logFile: %s' % (logFileStg,)) if inFileStg == None or len(inFileStg) == 0: throwerr( logName, 'inFiles is missing', specPath) if outFileStg == None: throwerr( logName, 'outFiles is missing', specPath) if omitFileStg == None: throwerr( logName, 'omitFiles is missing', specPath) inFiles = inFileStg.split(',') if outFileStg == '': outFiles = None # implies all non-input files else: outFiles = outFileStg.split(',') if omitFileStg == '': omitFiles = None else: omitFiles = omitFileStg.split(',') if bugLev >= 1: printLog( logName, 'inFiles: %s' % (inFiles,)) printLog( logName, 'outFiles: %s' % (outFiles,)) printLog( logName, 'omitFiles: %s' % (omitFiles,)) workDir = os.getcwd() if bugLev >= 1: printLog( logName, 'workDir: %s' % (workDir,)) if not workDir.startswith( workRoot): throwerr( logName, 'cwd not within workRoot', specPath) deltaPath = workDir[ len(workRoot) :].strip('/') refDir = os.path.join( refRoot, deltaPath) if bugLev >= 1: printLog( logName, 'deltaPath: %s' % (deltaPath,)) printLog( logName, 'refDir: %s' % (refDir,)) # Make sure all input files match for inFile in inFiles: refPath = os.path.join( refDir, inFile) workPath = os.path.join( workDir, inFile) if bugLev >= 1: printLog( logName, 'inFile: %s' % (inFile,)) printLog( logName, ' refPath: %s' % (refPath,)) printLog( logName, ' workPath: %s' % (workPath,)) if not os.access( refPath, os.R_OK): throwerr( logName, 'cannot read refPath: %s' % (refPath,), specPath) if not os.access( workPath, os.R_OK): throwerr( logName, 'cannot read workPath: %s' % (workPath,), specPath) # We cannot use filecmp.cmp since roundoff errors # may cause slight differences between the machine # creating the reference and the machine running the test. # cmp = filecmp.cmp( refPath, workPath) #if not cmp: # throwerr( logName, 'infile mismatch.\n refPath: %s\n workPath: %s' \ # % (refPath, workPath,), specPath) checkFiles( logName, absEpsilon, relEpsilon, refPath, workPath) # If we copy all output files except the input files if outFiles == None: fnames = os.listdir( refDir) else: fnames = outFiles # Else we copy only the named output files fnames.sort() for outFile in fnames: isMatched = testRegexs( omitFiles, outFile) if outFile in inFiles: if bugLev >= 1: printLog( logName, 'outFile omitted (inFile): %s' % (outFile,)) elif isMatched: if bugLev >= 1: printLog( logName, 'outFile omitted (omitFile): %s' % (outFile,)) else: outRef = os.path.join( refDir, outFile) outWork = os.path.join( workDir, outFile) if bugLev >= 1: printLog( logName, 'outFile: %s' % (outFile,)) printLog( logName, ' outRef: %s' % (outRef,)) printLog( logName, ' outWork: %s' % (outWork,)) if os.path.isfile( outRef): # Allow overwrite #if os.access( outWork, os.F_OK): # if not filecmp.cmp( outRef, outWork): # throwerr( logName, # 'outWork differs.\n outRef: %s\n outWork: %s' # % (outRef, outWork,), specPath) shutil.copyfile( outRef, outWork) #====================================================================
[docs]def testRegexs( regexs, fname): ''' Returns True if fname matches any of the regex. ''' bres = False if regexs != None: for regex in regexs: if re.match( regex, fname): bres = True break return bres #====================================================================
[docs]def checkFiles( logName, absEpsilon, relEpsilon, patha, pathb): ''' Compares two files. If they are identical except for possible floating points within absolute absEpsilon and relative relEpsilon, return True. ''' fina = open( patha) finb = open( pathb) errMsg = None iline = 0 linea = None lineb = None while True: linea = fina.readline() lineb = finb.readline() if linea == '' and lineb == '': break if linea == '': errMsg = 'early eof on A' break if lineb == '': errMsg = 'early eof on B' break iline += 1 tokas = linea.split() tokbs = lineb.split() if len(tokas) != len(tokbs): errMsg = 'num tokens differs' break for ii in range(len(tokas)): toka = tokas[ii] tokb = tokbs[ii] vala = None valb = None try: vala = float( toka) except ValueError, exc: pass try: valb = float( tokb) except ValueError, exc: pass if vala == None and valb == None: # if neither is float if toka != tokb: errMsg = 'strings differ' break elif vala == None or valb == None: # if only one is float errMsg = 'only one token is float' break else: # Both are float if abs( vala - valb) >= absEpsilon: errMsg = 'absEpsilon err: ii: %d\n vala: %g\n valb: %g\n' \ % (ii, vala, valb,) errMsg += ' valb-vala: %g\n' % (valb - vala,) break if vala != 0: relErr = abs( (valb - vala) / vala) if relErr >= relEpsilon: errMsg = 'relEpsilon err: ii: %d vala: %g valb: %g valb-vala: %g relErr: %g' \ % (ii, vala, valb, valb - vala, relErr) break if errMsg != None: break fina.close() finb.close() if errMsg != None: fullMsg = 'Mismatch:\n' \ + errMsg + '\n' \ + ' iline: %d\n' % (iline,) \ + ' linea: %s\n' % (linea,) \ + ' lineb: %s\n' % (lineb,) \ + ' patha: %s\n' % (patha,) \ + ' pathb: %s\n' % (pathb,) \ + ' absEpsilon: %g\n' % (absEpsilon,) \ + ' relEpsilon: %g\n' % (relEpsilon,) throwerr( logName, fullMsg, patha) #====================================================================
def printLog( logName, msg): logFile = open( os.path.expanduser( logName), 'a') print >> logFile, msg logFile.close() #==================================================================== def throwerr( logName, msg, specPath): fullMsg = 'Error: %s\n cwd: %s\n specPath: %s\n' \ % (msg, os.getcwd(), specPath,) if logName != None: printLog( logName, fullMsg) raise Exception( fullMsg) #==================================================================== if __name__ == '__main__': main()