|
[Rivet-svn] r4185 - trunk/binblackhole at projects.hepforge.org blackhole at projects.hepforge.orgTue Mar 5 16:53:34 GMT 2013
Author: hoeth Date: Tue Mar 5 16:53:34 2013 New Revision: 4185 Log: First working version of the YODA replacement for compare-histos. It doesn't have all the functionality of the old script yet, but it should be much cleaner and easier to maintain. Added: trunk/bin/rivet-cmphistos (contents, props changed) Added: trunk/bin/rivet-cmphistos ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/bin/rivet-cmphistos Tue Mar 5 16:53:34 2013 (r4185) @@ -0,0 +1,298 @@ +#! /usr/bin/env python + +'''\ +%prog - generate comparison plots + +USAGE: + %prog [options] yodafile1[:'PlotOption1=Value':'PlotOption2=Value'] [path/to/yodafile2 ...] + +where the plot options are described in the make-plots manual in the HISTOGRAM +section. +''' + +import sys, os +if sys.version_info[:3] < (2, 4, 0): + print 'rivet scripts require Python version >= 2.4.0... exiting' + sys.exit(1) + + +class Plot(dict): + ## A tiny Plot object to help writing out the head in the .dat file + def __repr__(self): + return "# BEGIN PLOT\n" + "\n".join("%s=%s" % (k,v) for k,v in self.iteritems()) + "\n# END PLOT\n\n" + + +def getCommandLineOptions(): + ## Parse command line options + from optparse import OptionParser, OptionGroup + parser = OptionParser(usage=__doc__) + + parser.add_option("--no-rivet-refs", dest="RIVETREFS", action="store_false", + default=True, help="don't use Rivet reference data files") + parser.add_option('-o', '--outdir', dest='OUTDIR', + default='.', help='write data files into this directory') + parser.add_option("--hier-out", action="store_true", dest="HIER_OUTPUT", default=False, + help="write output dat files into a directory hierarchy which matches the analysis paths") + parser.add_option('--plotinfodir', dest='PLOTINFODIR', action='append', + default=['.'], help='directory which may contain plot header information (in addition ' + 'to standard Rivet search paths)') + + stygroup = OptionGroup(parser, "Plot style") + stygroup.add_option("-c", "--config", dest="CONFIGFILES", action="append", default=["~/.make-plots"], + help="additional plot config file(s). Settings will be included in the output configuration.") + parser.add_option_group(stygroup) + + return parser + + +def initPlotparser(filelist): + from lighthisto import PlotParser + + ## Add standard locations and the input files' dirs to the PLOTINFO search paths + import rivet + opts.PLOTINFODIR += rivet.getAnalysisPlotPaths() + for infile in filelist: + adir = os.path.abspath(os.path.split(infile)[0]) + if not adir in opts.PLOTINFODIR: + opts.PLOTINFODIR.append(adir) + + return PlotParser(opts.PLOTINFODIR, opts.CONFIGFILES) + + + +def getHistos(filelist): + ## Loop over all input files. Only use the first occurrence of any REF-histogram + ## and the first occurrence in each MC file for every MC-histogram. + refhistos = {} + mchistos = {} + mchistolist = [] + for infile in filelist: + if not mchistos.has_key(infile): + mchistos[infile] = {} + analysisobjects = yoda.readYODA(infile) + for ao in analysisobjects: + path = ao.annotations()['Path'] + if path.startswith('/REF/'): + if not refhistos.has_key(path): + refhistos[path] = ao + else: + if not mchistos[infile].has_key(path): + mchistos[infile][path] = ao + if path not in mchistolist: + mchistolist.append(path) + return refhistos, mchistos, mchistolist + + +def getRefdata(refhistos): + ## Find all Rivet reference data files + import rivet + rivet_data_dirs = rivet.getAnalysisRefPaths() + dirlist = [] + for d in rivet_data_dirs: + import glob + dirlist.append(glob.glob(os.path.join(d, '*.yoda'))) + for filelist in dirlist: + for infile in filelist: + analysisobjects = yoda.readYODA(infile) + for ao in analysisobjects: + path = ao.annotations()['Path'] + if path.startswith('/REF/'): + if not refhistos.has_key(path): + refhistos[path] = ao + + +def parseArgs(args): + ## Look at the argument list and split it at colons, in order to separate + ## the file names from the plotting options. Store the file names and + ## file specific plotting options. + filelist = [] + plotoptions = {} + for a in args: + asplit = a.split(':') + path = asplit[0] + filelist.append(path) + plotoptions[path] = [] + has_title = False + for i in xrange(1, len(asplit)): + ## Add 'Title' if there is no = sign before math mode + if not '=' in asplit[i] or ('$' in asplit[i] and asplit[i].index('$') < asplit[i].index('=')): + asplit[i] = 'Title=%s' % asplit[i] + if asplit[i].startswith('Title='): + has_title = True + plotoptions[path].append(asplit[i]) + if not has_title: + plotoptions[path].append('Title=%s' %path.split('/')[-1].replace('.yoda', '')) + return filelist, plotoptions + + +def setStyle(ao, style): + ## Set default plot styles (color and line width) + # colors borrowed from Google Ngrams + LINECOLORS = ['ee3311', # red (Google uses 'dc3912') + '3366cc', # blue + '109618', # green + 'ff9900', # orange + '990099', # lila + ] + LINESTYLES = ['solid', + 'dashed', + 'dashdotted', + 'dotted', + ] + + c = style%len(LINECOLORS) + s = style/len(LINECOLORS) + + ao.setAnnotation('LineStyle', '%s' %LINESTYLES[s]) + ao.setAnnotation('LineColor', '{[HTML]{%s}}' %LINECOLORS[c]) + + +def setOptions(ao, options): + ## Set arbitrary annotations + for opt in options: + key = opt.split('=', 1)[0] + val = opt.split('=', 1)[1] + ao.setAnnotation(key, val) + + +def mkoutdir(outdir): + ## Function to make output directories + if not os.path.exists(outdir): + try: + os.makedirs(outdir) + except: + msg = "Can't make output directory '%s'" % outdir + raise Exception(msg) + if not os.access(outdir, os.W_OK): + msg = "Can't write to output directory '%s'" % outdir + raise Exception(msg) + + +def writeOutput(output, h): + ## Choose output file name and dir + if opts.HIER_OUTPUT: + outdir = os.path.dirname(os.path.join(opts.OUTDIR, h[1:])) + outfile = '%s.dat' % os.path.basename(h) + else: + outdir = opts.OUTDIR + outfile = '%s.dat' % h.replace('/', "_")[1:] + mkoutdir(outdir) + outfilepath = os.path.join(outdir, outfile) + f = open(outfilepath, 'w') + f.write(output) + f.close() + + +#-------------------------------------------------------------------------------------------- +#-------------------------------------------------------------------------------------------- + +if __name__ == '__main__': + import os + import yoda + + ## Try to rename the process on Linux + try: + import ctypes + libc = ctypes.cdll.LoadLibrary('libc.so.6') + libc.prctl(15, 'compare-histos', 0, 0, 0) + except Exception: + pass + + ## Try to use Psyco optimiser + try: + import psyco + psyco.full() + except ImportError: + pass + + + ## Command line parsing + parser = getCommandLineOptions() + opts, args = parser.parse_args() + + ## split the input file names and the associated plotting options + ## given on the command line into two separate lists + filelist, plotoptions = parseArgs(args) + + ## read the .plot files + plotparser = initPlotparser(filelist) + + ## create a list of all histograms to be plotted + refhistos, mchistos, mchistolist = getHistos(filelist) + + ## read the reference data from the Rivet search paths and add them + ## to the list of reference histograms + if opts.RIVETREFS: getRefdata(refhistos) + + + ## Now loop over all MC histograms and plot them + for h in mchistolist: + + ## A list of all analysis objects to be plotted + anaobjects = [] + + + ## Plot object for the PLOT section in the .dat file + plot = Plot() + plot['Legend'] = '1' + plot['LogY'] = '1' + for key, val in plotparser.getHeaders(h).iteritems(): + plot[key] = val + + + ## DrawOnly is needed to keep the order in the Legend equal to the + ## order of the files on the command line + drawonly = '' + + + ## Check if we have reference data for the histogram + if refhistos.has_key('/REF' + h): + refdata = refhistos['/REF' + h] + refdata.setAnnotation('ErrorBars', '1') + refdata.setAnnotation('PolyMarker', '*') + refdata.setAnnotation('Title', 'Data') + plot['RatioPlot'] = '1' + plot['RatioPlotReference'] = '/REF'+h + anaobjects.append(refdata) + drawonly += '/REF' + h + ' ' + + + ## Loop over the MC files to plot all instances of the histogram + for i,infile in enumerate(filelist): + if mchistos.has_key(infile) and mchistos[infile].has_key(h): + ## default linecolor, linestyle + setStyle(mchistos[infile][h], i) + ## plot defaults from .plot files + for key, val in plotparser.getHistogramOptions(h).iteritems(): + mchistos[infile][h].setAnnotation(key, val) + ## command line plot options + setOptions(mchistos[infile][h], plotoptions[infile]) + mchistos[infile][h].setAnnotation('Path', infile + h) + anaobjects.append(mchistos[infile][h]) + drawonly += infile + h + ' ' + + plot['DrawOnly'] = drawonly.strip() + + ## Now create the output. We can't use "yoda.writeFLAT(anaobjects, 'foobar.dat')" because + ## the PLOT and SPECIAL blocks don't have a corresponding analysis object. + + output = '' + output += str(plot) + + ## Special + special = plotparser.getSpecial(h) + if special: + output += "\n" + output += "# BEGIN SPECIAL %s\n" % h + output += special + output += "# END SPECIAL\n\n" + + from cStringIO import StringIO + sio = StringIO() + yoda.writeFLAT(anaobjects, sio) + output += sio.getvalue() + + + ## Write everything into a file + writeOutput(output, h) +
More information about the Rivet-svn mailing list |