import random from datetime import datetime import os import subprocess import inspect import argparse import sys import re def parsestat(s): return int(s. replace("k","000"). replace("M","000000"). replace("G","000000000") ) def getref(): try: rev = subprocess.check_output([ 'git', 'rev-parse', '--short', 'HEAD' ], stderr=subprocess.PIPE).splitlines()[0] return rev except subprocess.CalledProcessError: return "not on git" def getbranch(): try: rev = subprocess.check_output([ 'git', 'rev-parse', '--abbrev-ref', 'HEAD' ], stderr=subprocess.PIPE).splitlines()[0] return rev except subprocess.CalledProcessError: return "not on git" def rerunconfig( flavour="mu-e", whichbase="m2enn", seeds=5, xicuts=[.5, .25, .125], stats={ "0": (10000, 20, 100000, 100), "V": (10000, 20, 100000, 100), "R": (20000, 20, 500000, 100) }, folder="", binary='xs_main' ): if len(folder) == 0: folder = whichbase + flavour cargs = [ "--seeds %s" % ' '.join(str(i) for i in seeds), "-xi %s" % ' '.join(str(i) for i in xicuts), "--flavour %s" % flavour, "--piece %s" % whichbase, "--output-dir %s" % folder, "--prog %s" % binary ] for part, stat in stats.iteritems(): if len(stat) == 5: cargs.append("--stat %s,%d,%d,%d,%d,%d" % ( part, stat[0], stat[1], stat[2], stat[3], stat[4]) ) else: cargs.append("--stat %s,%d,%d,%d,%d" % ( part, stat[0], stat[1], stat[2], stat[3]) ) return cargs def create_menu( flavour="mu-e", whichbase="m2enn", seeds=5, xicuts=[.5, .25, .125], stats={ "0": (10000, 20, 100000, 100), "V": (10000, 20, 100000, 100), "R": (20000, 20, 500000, 100) }, folder="", binary='xs_main' ): totalstat = [0,0] if type(seeds) == int: n = seeds # Get n random numbers seeds = [] while len(seeds) < n: r = random.randint(10000, 100000) if r in seeds: continue seeds.append(r) elif type(seeds) == list: pass else: raise TypeError( "Seeds needs to be either list or int, is type " + str(type(seeds)) ) if len(folder) == 0: folder = whichbase + flavour rrc = rerunconfig( flavour, whichbase, seeds, xicuts, stats, folder, binary ) print "Building files. To rerun this, execute" print "python %s \\" % sys.argv[0] print " \\\n".join( " " + i for i in rrc ) header = ( "## Generated at %s by %s\n" + "# git version: %s (%s)\n" + "# To re-generate, run python %s \\\n" ) % ( datetime.now().strftime("%H:%M on %B %d %Y"), os.environ['USER'], getbranch(), getref(), sys.argv[0] ) + " \\\n".join( "# " + i for i in rrc ) menu = "\n\nconf %s/%s-%s.conf" % (folder, whichbase, flavour) config = ("\n\n# specify the program to run relative to `pwd`\n" + "binary=%s\n\n" + "# specify the output folder\n" + "folder=%s/\n\n" + "# Specify the variables nenter_ad, itmx_ad, nenter and itmx\n" + "# for each piece you want to run.\n" + "declare -A STAT=(\n") % (binary, folder) for part,stat in stats.iteritems(): config += ' ["%s%s"]="%d\\n%d\\n%d\\n%d"\n' % ( whichbase, part, stat[0], stat[1], stat[2], stat[3] ) if stat[0] < stat[1] or stat[2] < stat[3]: print "Warning! In part %s, calls and itmx might be swapped!" % part n = stat[4] if len(stat) == 5 else len(seeds) xiloop = ( "R" in part or # real corrections "F" in part or # real-virtual corrections "CT" in part or # explicit counter term ("V" in part and # virtual corrections and ... "CT" not in "".join(stats.keys())) # ... never and explicit CT ) for xi in (xicuts if xiloop else [1.]): totalstat[0] += n*(stat[1] + stat[3]) # iterations totalstat[1] += 1000*n*(stat[0]*stat[1] + stat[2]*stat[3]) # iterations menu += "\n\n" menu += '\n'.join( "run %d %f %s%s %s 0" % (seed, xi, whichbase, part, flavour) for seed in seeds[:n] ) menu += "\n\n" config += ")" if totalstat[1] > 999999999999: c = 'T' p = float(totalstat[1])/1.e12 elif totalstat[1] > 999999999: c = 'G' p = float(totalstat[1])/1.e9 elif totalstat[1] > 999999: c = 'M' p = float(totalstat[1])/1.e6 elif totalstat[1] > 999: c = 'k' p = float(totalstat[1])/1.e3 print "Expect %d iterations, %f%s calls" % ( totalstat[0], p,c ) return ( ["%s/menu-%s-%s.txt" % (folder, whichbase, flavour), header + menu], ["%s/%s-%s.conf" % (folder, whichbase, flavour), header + config], folder ) def interogate(args={}): specs = inspect.getargspec(create_menu) defaults = dict(zip(specs.args, specs.defaults)) def basic_ask(msg, default, parser=(lambda x: x)): ans = raw_input("%s? [%s] " % (msg, default)) if ans == '': return default else: return parser(ans) def ask(key, msg, parser=(lambda x: x)): if key not in args: args[key] = basic_ask(msg, defaults[key], parser) ask('whichbase', "What type of process") ask('flavour', "Which flavour combination") ask('seeds', "How many / which seeds", parser=lambda x: int(x) if ',' not in x else [int(i) for i in x.split(',')] ) ask('xicuts', "Which xi cuts", parser=lambda x: [float(i) for i in x.split(',')] ) defaults['folder'] = args['whichbase'] + args['flavour'] ask('folder', "Where to store data") ask('binary', "Which binary to run") if 'stats' not in args: pieces = basic_ask( "Which pieces", ['0', 'V', 'R'], parser=lambda x: x.split(',') ) args['stats'] = {} for piece in pieces: args['stats'][piece] = basic_ask( "How much statistics for " + piece + " (pc, pi, c, i)", (10000, 20, 100000, 100), parser=lambda x: tuple(parsestat(i) for i in x.split(',')) ) return args def parseargs(): specs = inspect.getargspec(create_menu) defaults = dict(zip(specs.args, specs.defaults)) parser = argparse.ArgumentParser( description='Generate menu and config files' ) parser.add_argument( '-i', action='store_true', help='reads all arguments and questions the user about the rest' ) group = parser.add_mutually_exclusive_group() group.add_argument( '-ns', '--nseeds', type=int, help="number of random seeds to use [%d]" % defaults['seeds'] ) group.add_argument('--seeds', nargs='+', type=int, help="list of seeds") parser.add_argument( '-xi', nargs='+', type=float, help="list of xicut [%s]" % ( ','.join(str(i) for i in defaults['xicuts']) ) ) parser.add_argument( '-f', '--flavour', type=str, help="flavour variable [%s]" % defaults['flavour'] ) parser.add_argument( '-p', '--piece', type=str, help="the which_piece prefix [%s]" % defaults['whichbase'] ) parser.add_argument( '-d', '--output-dir', help="output folder, aborts if folder exists" ) parser.add_argument( '--force', action='store_true', help="overwrite existing files" ) parser.add_argument( '--prog', default='xs_main', help="executable of the MC [xs_main]" ) parser.add_argument( '-s', '--stat', action="append", help="comma seperated list of piece,pc,pi,c,i[,seeds to use]" ) parsed = parser.parse_args() args = {} if parsed.nseeds: args['seeds'] = parsed.nseeds if parsed.seeds: args['seeds'] = parsed.seeds if parsed.xi: args['xicuts'] = parsed.xi if parsed.stat: args['stats'] = {} for stat in parsed.stat: s = stat.split(',') args['stats'][s[0]] = tuple(parsestat(i) for i in s[1:]) elif not parsed.i: args['stats'] = defaults['stats'] if parsed.flavour: args['flavour'] = parsed.flavour if parsed.piece: args['whichbase'] = parsed.piece if parsed.output_dir: args['folder'] = parsed.output_dir if parsed.prog: args['binary'] = parsed.prog if parsed.i: args = interogate(args) elif not parsed.output_dir: parser.error("Check your flags") return args, parsed.force def save(menu, conf, folder, force=False): toolspath = os.path.dirname(os.path.realpath(__file__)) if os.path.isdir(folder): print "The folder ", folder, " already exists." if not force: raise SystemExit("File exists") else: print "Overwritting." else: os.mkdir(folder) os.mkdir(folder+"/out/") if 'afs' in toolspath: print "You are running on AFS, won't fix permissions" else: os.chmod(folder, 0o2775) os.chmod(folder+"/out/", 0o2775) with open(toolspath + "/submit.sh") as fp: submit = fp.read() submit = re.sub( "^#SBATCH --output=.*/slurm-%j.out$", "#SBATCH --output=%s/slurm-%%j.out" % folder, submit, flags=re.M ) submit = re.sub( "^#SBATCH --input=.*$", "#SBATCH --input=%s" % menu[0], submit, flags=re.M ) submit = re.sub( "^this=\./submit\.sh$", "this=%s/submit.sh" % folder, submit, flags=re.M ) with open(menu[0], 'w') as fp: fp.write(menu[1]) with open(conf[0], 'w') as fp: fp.write(conf[1]) with open(folder + "/submit.sh", 'w') as fp: fp.write(submit) os.chmod(menu[0], 0o664) os.chmod(folder + "/submit.sh", 0o775) print "Created menu, config and submit script in ",folder print "Please change the ntasks and time options accordingly" if __name__ == '__main__': import sys args, force = parseargs() menu, config, folder = create_menu(**args) save(menu, config, folder, force=force)