Page MenuHomeHEPForge

No OneTemporary

diff --git a/bin/make-plots b/bin/make-plots
--- a/bin/make-plots
+++ b/bin/make-plots
@@ -1,2601 +1,2615 @@
#! /usr/bin/env python
"""\
Usage: %prog [options] file.dat [file2.dat ...]
TODO
* Optimise output for e.g. lots of same-height bins in a row
* Add a RatioFullRange directive to show the full range of error bars + MC envelope in the ratio
* Tidy LaTeX-writing code -- faster to compile one doc only, then split it?
* Handle boolean values flexibly (yes, no, true, false, etc. as well as 1, 0)
"""
##
## This program is copyright by Hendrik Hoeth <hoeth@linta.de> and
## the Rivet team https://rivet.hepforge.org. It may be used
## for scientific and private purposes. Patches are welcome, but please don't
## redistribute changed versions yourself.
##
## Check the Python version
import sys
if sys.version_info[:3] < (2,6,0):
print "make-plots requires Python version >= 2.6.0... exiting"
sys.exit(1)
## Try to rename the process on Linux
try:
import ctypes
libc = ctypes.cdll.LoadLibrary('libc.so.6')
libc.prctl(15, 'make-plots', 0, 0, 0)
except Exception, e:
pass
import os, logging, re
import tempfile
import getopt
import string
from math import *
## Regex patterns
pat_begin_block = re.compile(r'^#+\s*BEGIN ([A-Z0-9_]+) ?(\S+)?')
pat_end_block = re.compile('^#+\s*END ([A-Z0-9_]+)')
pat_comment = re.compile('^#|^\s*$')
pat_property = re.compile('^(\w+?)=(.*)$')
pat_path_property = re.compile('^(\S+?)::(\w+?)=(.*)$')
def fuzzyeq(a, b, tolerance=1e-6):
"Fuzzy equality comparison function for floats, with given fractional tolerance"
# if type(a) is not float or type(a) is not float:
# print a, b
if (a == 0 and abs(b) < 1e-12) or (b == 0 and abs(a) < 1e-12):
return True
return 2.0*abs(a-b)/abs(a+b) < tolerance
def is_end_marker(line, blockname):
m = pat_end_block.match(line)
return m and m.group(1) == blockname
def is_comment(line):
return pat_comment.match(line) is not None
class Inputdata(object):
def __init__(self, filename):
self.filename=filename+".dat"
self.histos = {}
self.special = {}
self.functions = {}
self.description = {}
self.pathdescriptions = []
self.description['is2dim'] = False
f = open(filename+'.dat')
for line in f:
m = pat_begin_block.match(line)
if m:
name, path = m.group(1,2)
if path is None and name != 'PLOT':
raise Exception('BEGIN sections need a path name.')
## Pass the reading of the block to separate functions
if name == 'PLOT':
self.read_input(f);
elif name == 'SPECIAL':
self.special[path] = Special(f)
elif name == 'HISTOGRAM' or name == 'HISTOGRAM2D':
self.histos[path] = Histogram(f)
self.histos[path].path = path
self.description['is2dim'] = self.histos[path].is2dim
elif name == 'HISTO1D':
self.histos[path] = Histo1D(f)
elif name == 'HISTO2D':
self.histos[path] = Histo2D(f)
self.description['is2dim'] = True
elif name == 'FUNCTION':
self.functions[path] = Function(f)
# elif is_comment(line):
# continue
# else:
# self.read_path_based_input(line)
f.close()
self.apply_config_files(opts.CONFIGFILES)
self.description['PlotSizeX'] = 10.
if self.description['is2dim']:
self.description['PlotSizeX'] -= 1.5
self.description['PlotSizeY'] = 6.
if self.description.has_key('PlotSize') and self.description['PlotSize']!='':
plotsizex,plotsizey = self.description['PlotSize'].split(',')
self.description['PlotSizeX'] = float(plotsizex)
self.description['PlotSizeY'] = float(plotsizey)
del self.description['PlotSize']
self.description['RatioPlotSizeY'] = 0.
if self.description.has_key('MainPlot') and self.description['MainPlot']=='0':
self.description['RatioPlot'] = '1'
self.description['PlotSizeY'] = 0.
if self.description.has_key('RatioPlot') and self.description['RatioPlot']=='1':
if self.description.has_key('RatioPlotYSize') and self.description['RatioPlotYSize']!='':
self.description['RatioPlotSizeY'] = float(self.description['RatioPlotYSize'])
else:
if self.description.has_key('MainPlot') and self.description['MainPlot']=='0':
self.description['RatioPlotSizeY'] = 6.
else:
self.description['RatioPlotSizeY'] = 3.
self.description['LogX'] = self.description.has_key('LogX') and self.description['LogX']=='1'
self.description['LogY'] = self.description.has_key('LogY') and self.description['LogY']=='1'
self.description['LogZ'] = self.description.has_key('LogZ') and self.description['LogZ']=='1'
if self.description.has_key('Rebin'):
for i in self.histos:
self.histos[i].description['Rebin'] = self.description['Rebin']
histoordermap = {}
histolist = self.histos.keys()
if self.description.has_key('DrawOnly'):
histolist = filter(self.histos.keys().count, self.description['DrawOnly'].strip().split())
for histo in histolist:
order = 0
if self.histos[histo].description.has_key('PlotOrder'):
order = int(self.histos[histo].description['PlotOrder'])
if not order in histoordermap:
histoordermap[order] = []
histoordermap[order].append(histo)
sortedhistolist = []
for i in sorted(histoordermap.keys()):
sortedhistolist.extend(histoordermap[i])
self.description['DrawOnly']=sortedhistolist
# inherit various values from histograms if not explicitly
# set.
for k in ['LogX', 'LogY', 'LogZ',
'XLabel', 'YLabel', 'ZLabel',
'XCustomMajorTicks', 'YCustomMajorTicks',
'ZCustomMajorTicks']:
self.inherit_from_histos(k)
return
def inherit_from_histos(self, k):
# note: this will inherit the key from a random histogram:
# only use if you're sure all histograms have this key!
if not self.description.has_key(k):
h = list(self.histos.itervalues())[0]
if h.description.has_key(k):
self.description[k] = h.description[k]
return
def read_input(self, f):
for line in f:
if is_end_marker(line, 'PLOT'):
break
elif is_comment(line):
continue
m = pat_property.match(line)
if m:
prop, value = m.group(1,2)
if prop in self.description:
logging.debug("Overwriting property %s = %s -> %s" % (prop, self.description[prop], value))
## Use strip here to deal with DOS newlines containing \r
self.description[prop.strip()] = value.strip()
def apply_config_files(self, conffiles):
if conffiles is not None:
for filename in conffiles:
cf = open(filename,'r')
lines = cf.readlines()
for i in range(0, len(lines)):
## First evaluate PLOT sections
m = pat_begin_block.match(lines[i])
if m and m.group(1) == 'PLOT' and re.match(m.group(2),self.filename):
while i<len(lines)-1:
i = i+1
if is_end_marker(lines[i], 'PLOT'):
break
elif is_comment(lines[i]):
continue
m = pat_property.match(lines[i])
if m:
prop, value = m.group(1,2)
if prop in self.description:
logging.debug("Overwriting from conffile property %s = %s -> %s" % (prop, self.description[prop], value))
## Use strip here to deal with DOS newlines containing \r
self.description[prop.strip()] = value.strip()
elif is_comment(lines[i]):
continue
else:
## Then evaluate path-based settings, e.g. for HISTOGRAMs
m = pat_path_property.match(lines[i])
if m:
regex, prop, value=m.group(1,2,3)
for obj_dict in [self.special, self.histos, self.functions]:
for path, obj in obj_dict.iteritems():
if re.match(regex, path):
## Use strip here to deal with DOS newlines containing \r
obj.description.update({prop.strip() : value.strip()})
cf.close()
class Plot(object):
def __init__(self,inputdata):
pass
def set_normalization(self,inputdata):
for method in ['NormalizeToIntegral', 'NormalizeToSum']:
if inputdata.description.has_key(method):
for i in inputdata.description['DrawOnly']:
if not inputdata.histos[i].description.has_key(method):
inputdata.histos[i].description[method] = inputdata.description[method]
if inputdata.description.has_key('Scale'):
for i in inputdata.description['DrawOnly']:
inputdata.histos[i].description['Scale'] = float(inputdata.description['Scale'])
for i in inputdata.description['DrawOnly']:
inputdata.histos[i].mangle_input()
def stack_histograms(self,inputdata):
if inputdata.description.has_key('Stack'):
foo=[]
for i in inputdata.description['Stack'].strip().split():
if i in inputdata.histos.keys():
foo.append(i)
previous=''
for i in foo:
if previous!='':
inputdata.histos[i].add(inputdata.histos[previous])
previous=i
def set_histo_options(self,inputdata):
if inputdata.description.has_key('ConnectGaps'):
for i in inputdata.histos.keys():
if not inputdata.histos[i].description.has_key('ConnectGaps'):
inputdata.histos[i].description['ConnectGaps']=inputdata.description['ConnectGaps']
def set_borders(self,inputdata):
self.set_xmax(inputdata)
self.set_xmin(inputdata)
self.set_ymax(inputdata)
self.set_ymin(inputdata)
self.set_zmax(inputdata)
self.set_zmin(inputdata)
inputdata.description['Borders']=(self.xmin, self.xmax, self.ymin, self.ymax, self.zmin, self.zmax)
def set_xmin(self,inputdata):
if inputdata.description.has_key('XMin'):
self.xmin = float(inputdata.description['XMin'])
else:
self.xmin = min(inputdata.histos[i].getXMin() for i in inputdata.description['DrawOnly'])
def set_xmax(self,inputdata):
#print inputdata.description
if inputdata.description.has_key('XMax'):
self.xmax = float(inputdata.description['XMax'])
else:
#print inputdata.description['DrawOnly']
self.xmax = max(inputdata.histos[i].getXMax() for i in inputdata.description['DrawOnly'])
def set_ymin(self,inputdata):
if inputdata.description.has_key('YMin'):
self.ymin = float(inputdata.description['YMin'])
else:
foo=[]
for i in inputdata.description['DrawOnly']:
foo.append(inputdata.histos[i].getYMin(self.xmin, self.xmax, inputdata.description['LogY']))
if inputdata.description['is2dim']:
self.ymin=min(foo)
else:
showzero = True
if inputdata.description.has_key('ShowZero'):
if inputdata.description['ShowZero']=='0':
showzero = False
if showzero:
if min(foo) > -1e-4:
self.ymin = 0
else:
self.ymin = 1.1*min(foo)
else:
if min(foo) < -1e-4:
self.ymin = 1.1*min(foo)
elif min(foo) < 1e-4:
self.ymin = 0
else:
self.ymin = 0.9*min(foo)
if inputdata.description['LogY']:
foo=[item for item in foo if item>0.0]
if len(foo)==0:
if self.ymax==0:
self.ymax=1
foo.append(2e-7*self.ymax)
fullrange = opts.FULL_RANGE
if inputdata.description.has_key('FullRange'):
if inputdata.description['FullRange']=='1':
fullrange = True
else:
fullrange = False
if fullrange:
self.ymin = min(foo)/1.7
else:
self.ymin = max(min(foo)/1.7, 2e-7*self.ymax)
if self.ymin==self.ymax:
self.ymin-=1
self.ymax+=1
def set_ymax(self,inputdata):
if inputdata.description.has_key('YMax'):
self.ymax = float(inputdata.description['YMax'])
else:
foo=[]
for i in inputdata.description['DrawOnly']:
foo.append(inputdata.histos[i].getYMax(self.xmin, self.xmax))
if inputdata.description['is2dim']:
self.ymax=max(foo)
else:
if inputdata.description['LogY']:
self.ymax=1.7*max(foo)
else:
self.ymax=1.1*max(foo)
def set_zmin(self,inputdata):
if inputdata.description.has_key('ZMin'):
self.zmin = float(inputdata.description['ZMin'])
else:
foo=[]
for i in inputdata.description['DrawOnly']:
foo.append(inputdata.histos[i].getZMin(self.xmin, self.xmax, self.ymin, self.ymax))
if not foo:
self.zmin = min(foo)
else:
showzero = True
if inputdata.description.has_key('ShowZero'):
if inputdata.description['ShowZero']=='0':
showzero = False
if showzero:
if min(foo) > -1e-4:
self.zmin = 0
else:
self.zmin = 1.1*min(foo)
else:
if min(foo) < -1e-4:
self.zmin = 1.1*min(foo)
elif min(foo) < 1e-4:
self.zmin = 0
else:
self.zmin = 0.9*min(foo)
if inputdata.description['LogZ']:
foo=[item for item in foo if item>0.0]
if len(foo)==0:
if self.zmax==0:
self.zmax=1
foo.append(2e-7*self.zmax)
fullrange = opts.FULL_RANGE
if inputdata.description.has_key('FullRange'):
if inputdata.description['FullRange']=='1':
fullrange = True
else:
fullrange = False
if fullrange:
self.zmin = min(foo)/1.7
else:
self.zmin = max(min(foo)/1.7, 2e-7*self.zmax)
if self.zmin==self.zmax:
self.zmin-=1
self.zmax+=1
def set_zmax(self,inputdata):
if inputdata.description.has_key('ZMax'):
self.zmax = float(inputdata.description['ZMax'])
else:
foo=[]
for i in inputdata.description['DrawOnly']:
foo.append(inputdata.histos[i].getZMax(self.xmin, self.xmax, self.ymin, self.ymax))
if foo:
self.zmax = max(foo)
else:
self.zmax = 1
def draw(self):
pass
def write_header(self,inputdata):
if inputdata.description.has_key('LeftMargin') and inputdata.description['LeftMargin']!='':
inputdata.description['LeftMargin'] = float(inputdata.description['LeftMargin'])
else:
inputdata.description['LeftMargin'] = 1.4
if inputdata.description.has_key('RightMargin') and inputdata.description['RightMargin']!='':
inputdata.description['RightMargin'] = float(inputdata.description['RightMargin'])
else:
inputdata.description['RightMargin'] = 0.35
if inputdata.description.has_key('TopMargin') and inputdata.description['TopMargin']!='':
inputdata.description['TopMargin'] = float(inputdata.description['TopMargin'])
else:
inputdata.description['TopMargin'] = 0.65
if inputdata.description.has_key('BottomMargin') and inputdata.description['BottomMargin']!='':
inputdata.description['BottomMargin'] = float(inputdata.description['BottomMargin'])
else:
inputdata.description['BottomMargin'] = 0.95
if inputdata.description['is2dim']:
inputdata.description['RightMargin'] += 1.5
papersizex = inputdata.description['PlotSizeX'] + 0.1 + \
inputdata.description['LeftMargin'] + inputdata.description['RightMargin']
papersizey = inputdata.description['PlotSizeY'] + inputdata.description['RatioPlotSizeY'] + 0.1 + \
inputdata.description['TopMargin'] + inputdata.description['BottomMargin']
#
out = ""
out += '\\documentclass{article}\n'
if opts.OUTPUT_FONT == "MINION":
out += ('\\usepackage{minion}\n')
elif opts.OUTPUT_FONT == "PALATINO_OSF":
out += ('\\usepackage[osf,sc]{mathpazo}\n')
elif opts.OUTPUT_FONT == "PALATINO":
out += ('\\usepackage{mathpazo}\n')
elif opts.OUTPUT_FONT == "TIMES":
out += ('\\usepackage{mathptmx}\n')
elif opts.OUTPUT_FONT == "HELVETICA":
out += ('\\renewcommand{\\familydefault}{\\sfdefault}\n')
out += ('\\usepackage{sfmath}\n')
out += ('\\usepackage{helvet}\n')
out += ('\\usepackage[symbolgreek]{mathastext}\n')
for pkg in opts.LATEXPKGS:
out += ('\\usepackage{%s}\n' % pkg)
out += ('\\usepackage{pst-all}\n')
out += ('\\selectcolormodel{rgb}\n')
out += ('\\usepackage{amsmath}\n')
out += ('\\usepackage{amssymb}\n')
out += ('\\usepackage{relsize}\n')
out += ('\\usepackage[dvips,\n')
out += (' left=%4.3fcm, right=0cm,\n' %(inputdata.description['LeftMargin']-0.45,))
out += (' top=%4.3fcm, bottom=0cm,\n' %(inputdata.description['TopMargin']-0.30,))
out += (' paperwidth=%scm,paperheight=%scm\n' %(papersizex,papersizey))
out += (']{geometry}\n')
out += ('\\begin{document}\n')
out += ('\\pagestyle{empty}\n')
out += ('\\SpecialCoor\n')
out += ('\\begin{pspicture}(0,0)(0,0)\n')
out += ('\\psset{xunit=%scm}\n' %(inputdata.description['PlotSizeX']))
if inputdata.description['is2dim']:
if inputdata.description.has_key('ColorSeries') and inputdata.description['ColorSeries']!='':
colorseries = inputdata.description['ColorSeries']
else:
colorseries = '{hsb}{grad}[rgb]{0,0,1}{-.700,0,0}'
out += ('\\definecolorseries{gradientcolors}%s\n' %colorseries)
out += ('\\resetcolorseries[130]{gradientcolors}\n')
return out
def write_footer(self):
out = ""
out += ('\\end{pspicture}\n')
out += ('\\end{document}\n')
return out
class MainPlot(Plot):
def __init__(self, inputdata):
self.set_normalization(inputdata)
self.stack_histograms(inputdata)
if (inputdata.description.has_key('GofLegend') and inputdata.description['GofLegend']=='1') or \
(inputdata.description.has_key('GofFrame') and inputdata.description['GofFrame']!='') and not \
(inputdata.description.has_key('TaylorPlot') and inputdata.description['TaylorPlot']=='1'):
self.calculate_gof(inputdata)
self.set_histo_options(inputdata)
self.set_borders(inputdata)
self.yoffset = inputdata.description['PlotSizeY']
self.coors = Coordinates(inputdata)
def draw(self, inputdata):
out = ""
out += ('\n%\n% MainPlot\n%\n')
out += ('\\psset{yunit=%scm}\n' %(self.yoffset))
out += ('\\rput(0,-1){%\n')
out += ('\\psset{yunit=%scm}\n' %(inputdata.description['PlotSizeY']))
out += self._draw(inputdata)
out += ('}\n')
return out
def _draw(self, inputdata):
out = ""
if inputdata.description.has_key('DrawSpecialFirst') and inputdata.description['DrawSpecialFirst']=='1':
for i in inputdata.special.keys():
out += inputdata.special[i].draw(self.coors)
if inputdata.description.has_key('DrawFunctionFirst') and inputdata.description['DrawFunctionFirst']=='1':
for i in inputdata.functions.keys():
out += inputdata.functions[i].draw(self.coors)
for i in inputdata.description['DrawOnly']:
out += inputdata.histos[i].draw(self.coors)
else:
for i in inputdata.description['DrawOnly']:
out += inputdata.histos[i].draw(self.coors)
for i in inputdata.functions.keys():
out += inputdata.functions[i].draw(self.coors)
else:
if inputdata.description.has_key('DrawFunctionFirst') and inputdata.description['DrawFunctionFirst']=='1':
for i in inputdata.functions.keys():
out += inputdata.functions[i].draw(self.coors)
for i in inputdata.description['DrawOnly']:
out += inputdata.histos[i].draw(self.coors)
else:
for i in inputdata.description['DrawOnly']:
out += inputdata.histos[i].draw(self.coors)
for i in inputdata.functions.keys():
out += inputdata.functions[i].draw(self.coors)
for i in inputdata.special.keys():
out += inputdata.special[i].draw(self.coors)
if inputdata.description.has_key('Legend') and inputdata.description['Legend']=='1':
legend = Legend(inputdata.description,inputdata.histos,inputdata.functions)
out += legend.draw()
if inputdata.description['is2dim']:
colorscale = Colorscale(inputdata.description,self.coors)
out += colorscale.draw()
frame = Frame()
out += frame.draw(inputdata)
if inputdata.description.has_key('XMajorTickMarks') and inputdata.description['XMajorTickMarks']!='':
xcustommajortickmarks=int(inputdata.description['XMajorTickMarks'])
else:
xcustommajortickmarks=-1
if inputdata.description.has_key('XMinorTickMarks') and inputdata.description['XMinorTickMarks']!='':
xcustomminortickmarks=int(inputdata.description['XMinorTickMarks'])
else:
xcustomminortickmarks=-1
xcustommajorticks=[]
xcustomminorticks=[]
# # TODO: remove XCustomTicks after 2011-12-31:
# if inputdata.description.has_key('XCustomTicks') and inputdata.description['XCustomTicks']!='':
# logging.warning('Warning: XCustomTicks is deprecated. Use XCustomMajorTicks instead.')
# inputdata.description['XCustomMajorTicks']=inputdata.description['XCustomTicks']
if inputdata.description.has_key('XCustomMajorTicks') and inputdata.description['XCustomMajorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=inputdata.description['XCustomMajorTicks'].strip().split('\t')
if not len(FOO) % 2:
for i in range(0,len(FOO),2):
xcustommajorticks.append({'Value': float(FOO[i]), 'Label': FOO[i+1]})
if inputdata.description.has_key('XCustomMinorTicks') and inputdata.description['XCustomMinorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=inputdata.description['XCustomMinorTicks'].strip().split('\t')
for i in range(len(FOO)):
xcustomminorticks.append({'Value': float(FOO[i])})
xticks = XTicks(inputdata.description, self.coors)
- if (inputdata.description.has_key('RatioPlot') and inputdata.description['RatioPlot']=='1') or (inputdata.description.has_key('PlotTickLabels') and inputdata.description['PlotTickLabels']=='0'):
- drawlabels=False
+ if (inputdata.description.has_key('RatioPlot') and inputdata.description['RatioPlot']=='1') or (inputdata.description.has_key('PlotXTickLabels') and inputdata.description['PlotXTickLabels']=='0'):
+ drawxlabels=False
else:
- drawlabels=True
+ drawxlabels=True
out += xticks.draw(custommajortickmarks=xcustommajortickmarks,\
customminortickmarks=xcustomminortickmarks,\
custommajorticks=xcustommajorticks,\
customminorticks=xcustomminorticks,\
- drawlabels=drawlabels)
+ drawlabels=drawxlabels)
if inputdata.description.has_key('YMajorTickMarks') and inputdata.description['YMajorTickMarks']!='':
ycustommajortickmarks=int(inputdata.description['YMajorTickMarks'])
else:
ycustommajortickmarks=-1
if inputdata.description.has_key('YMinorTickMarks') and inputdata.description['YMinorTickMarks']!='':
ycustomminortickmarks=int(inputdata.description['YMinorTickMarks'])
else:
ycustomminortickmarks=-1
ycustommajorticks=[]
ycustomminorticks=[]
# # TODO: remove YCustomTicks after 2011-12-31:
# if inputdata.description.has_key('YCustomTicks') and inputdata.description['YCustomTicks']!='':
# logging.warning('Warning: YCustomTicks is deprecated. Use YCustomMajorTicks instead.')
# inputdata.description['YCustomMajorTicks']=inputdata.description['YCustomTicks']
if inputdata.description.has_key('YCustomMajorTicks') and inputdata.description['YCustomMajorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=inputdata.description['YCustomMajorTicks'].strip().split('\t')
if not len(FOO)%2:
for i in range(0,len(FOO),2):
ycustommajorticks.append({'Value': float(FOO[i]), 'Label': FOO[i+1]})
if inputdata.description.has_key('YCustomMinorTicks') and inputdata.description['YCustomMinorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=inputdata.description['YCustomMinorTicks'].strip().split('\t')
for i in range(len(FOO)):
ycustomminorticks.append({'Value': float(FOO[i])})
yticks = YTicks(inputdata.description, self.coors)
+ if (inputdata.description.has_key('PlotYTickLabels') and inputdata.description['PlotYTickLabels']=='0'):
+ drawylabels=False
+ else:
+ drawylabels=True
out += yticks.draw(custommajortickmarks=ycustommajortickmarks,\
customminortickmarks=ycustomminortickmarks,\
custommajorticks=ycustommajorticks,\
- customminorticks=ycustomminorticks)
+ customminorticks=ycustomminorticks,
+ drawlabels=drawylabels)
labels = Labels(inputdata.description)
if inputdata.description.has_key('RatioPlot') and inputdata.description['RatioPlot']=='1':
out += labels.draw(['Title','YLabel'])
else:
if not inputdata.description['is2dim']:
out += labels.draw(['Title','XLabel','YLabel'])
else:
out += labels.draw(['Title','XLabel','YLabel','ZLabel'])
return out
def calculate_gof(self, inputdata):
refdata = inputdata.description.get('GofReference')
if refdata is None:
refdata = inputdata.description.get('RatioPlotReference')
if refdata is None:
inputdata.description['GofLegend'] = '0'
inputdata.description['GofFrame'] = ''
return
def pickcolor(gof):
color=None
colordefs = {}
for i in inputdata.description.setdefault('GofFrameColor', '0:green 3:yellow 6:red!70').strip().split():
foo = i.split(':')
if len(foo)!=2: continue
colordefs[float(foo[0])] = foo[1]
for i in sorted(colordefs.keys()):
if gof>=i:
color=colordefs[i]
return color
inputdata.description.setdefault('GofLegend','0')
inputdata.description.setdefault('GofFrame','')
inputdata.description.setdefault('FrameColor',None)
for i in inputdata.description['DrawOnly']:
if i==refdata: continue
if inputdata.description['GofLegend']!='1' and i!=inputdata.description['GofFrame']: continue
if inputdata.description.has_key('GofType') and inputdata.description['GofType']!='chi2':
return
gof = inputdata.histos[i].getChi2(inputdata.histos[refdata])
if i==inputdata.description['GofFrame'] and inputdata.description['FrameColor']==None:
inputdata.description['FrameColor']=pickcolor(gof)
if inputdata.histos[i].description.setdefault('Title', '')!='':
inputdata.histos[i].description['Title'] += ', '
inputdata.histos[i].description['Title'] += '$\\chi^2/n={}$%1.2f' %gof
class TaylorPlot(Plot):
def __init__(self, inputdata):
self.refdata = inputdata.description['TaylorPlotReference']
self.calculate_taylorcoordinates(inputdata)
def calculate_taylorcoordinates(self,inputdata):
foo=inputdata.description['DrawOnly'].pop(inputdata.description['DrawOnly'].index(self.refdata))
inputdata.description['DrawOnly'].append(foo)
for i in inputdata.description['DrawOnly']:
print i
print 'meanbinval = ', inputdata.histos[i].getMeanBinValue()
print 'sigmabinval = ', inputdata.histos[i].getSigmaBinValue()
print 'chi2/nbins = ', inputdata.histos[i].getChi2(inputdata.histos[self.refdata])
print 'correlation = ', inputdata.histos[i].getCorrelation(inputdata.histos[self.refdata])
print 'distance = ', inputdata.histos[i].getRMSdistance(inputdata.histos[self.refdata])
class RatioPlot(Plot):
def __init__(self, inputdata):
self.refdata = inputdata.description['RatioPlotReference']
self.yoffset = inputdata.description['PlotSizeY'] + inputdata.description['RatioPlotSizeY']
inputdata.description['RatioPlotStage'] = True
inputdata.description['PlotSizeY'] = inputdata.description['RatioPlotSizeY']
inputdata.description['LogY'] = False
if inputdata.description.has_key('RatioPlotMode') and inputdata.description['RatioPlotMode']=='deviation':
inputdata.description['YLabel']='$(\\text{MC}-\\text{data})$'
inputdata.description['YMin']=-3.5
inputdata.description['YMax']=3.5
elif inputdata.description.has_key('RatioPlotMode') and inputdata.description['RatioPlotMode']=='datamc':
inputdata.description['YLabel']='Data/MC'
inputdata.description['YMin']=0.5
inputdata.description['YMax']=1.5
else:
inputdata.description['YLabel']='MC/Data'
inputdata.description['YMin']=0.5
inputdata.description['YMax']=1.5
if inputdata.description.has_key('RatioPlotYLabel'):
inputdata.description['YLabel']=inputdata.description['RatioPlotYLabel']
inputdata.description['YLabel']='\\rput(-%s,0){%s}'%(0.5*inputdata.description['PlotSizeY']/inputdata.description['PlotSizeX'],inputdata.description['YLabel'])
if inputdata.description.has_key('RatioPlotYMin'):
inputdata.description['YMin']=inputdata.description['RatioPlotYMin']
if inputdata.description.has_key('RatioPlotYMax'):
inputdata.description['YMax']=inputdata.description['RatioPlotYMax']
if not inputdata.description.has_key('RatioPlotErrorBandColor'):
inputdata.description['RatioPlotErrorBandColor']='yellow'
if not inputdata.description.has_key('RatioPlotSameStyle') or inputdata.description['RatioPlotSameStyle']=='0':
inputdata.histos[self.refdata].description['ErrorBandColor']=inputdata.description['RatioPlotErrorBandColor']
inputdata.histos[self.refdata].description['ErrorBands']='1'
inputdata.histos[self.refdata].description['ErrorBars']='0'
inputdata.histos[self.refdata].description['LineStyle']='solid'
inputdata.histos[self.refdata].description['LineColor']='black'
inputdata.histos[self.refdata].description['LineWidth']='0.3pt'
inputdata.histos[self.refdata].description['PolyMarker']=''
inputdata.histos[self.refdata].description['ConnectGaps']='1'
self.calculate_ratios(inputdata)
self.set_borders(inputdata)
self.coors = Coordinates(inputdata)
def draw(self, inputdata):
out = ""
out += ('\n%\n% RatioPlot\n%\n')
out += ('\\psset{yunit=%scm}\n' %(self.yoffset))
out += ('\\rput(0,-1){%\n')
out += ('\\psset{yunit=%scm}\n' %(inputdata.description['PlotSizeY']))
out += self._draw(inputdata)
out += ('}\n')
return out
def calculate_ratios(self,inputdata):
foo=inputdata.description['DrawOnly'].pop(inputdata.description['DrawOnly'].index(self.refdata))
if inputdata.histos[self.refdata].description.has_key('ErrorBands') and inputdata.histos[self.refdata].description['ErrorBands']=='1':
inputdata.description['DrawOnly'].insert(0,foo)
else:
inputdata.description['DrawOnly'].append(foo)
for i in inputdata.description['DrawOnly']:
if i!=self.refdata:
if inputdata.description.has_key('RatioPlotMode') and inputdata.description['RatioPlotMode']=='deviation':
inputdata.histos[i].deviation(inputdata.histos[self.refdata])
elif inputdata.description.has_key('RatioPlotMode') and inputdata.description['RatioPlotMode']=='datamc':
inputdata.histos[i].dividereverse(inputdata.histos[self.refdata])
inputdata.histos[i].description['ErrorBars']='1'
else:
inputdata.histos[i].divide(inputdata.histos[self.refdata])
if inputdata.description.has_key('RatioPlotMode') and inputdata.description['RatioPlotMode']=='deviation':
inputdata.histos[self.refdata].deviation(inputdata.histos[self.refdata])
elif inputdata.description.has_key('RatioPlotMode') and inputdata.description['RatioPlotMode']=='datamc':
inputdata.histos[self.refdata].dividereverse(inputdata.histos[self.refdata])
else:
inputdata.histos[self.refdata].divide(inputdata.histos[self.refdata])
def _draw(self, inputdata):
out = ""
for i in inputdata.description['DrawOnly']:
if inputdata.description.has_key('RatioPlotMode') and inputdata.description['RatioPlotMode']=='datamc':
if i!=self.refdata:
out += inputdata.histos[i].draw(self.coors)
else:
out += inputdata.histos[i].draw(self.coors)
frame = Frame()
out += frame.draw(inputdata)
# TODO: so much duplication with MainPlot... yuck!
if inputdata.description.has_key('XMajorTickMarks') and inputdata.description['XMajorTickMarks']!='':
xcustommajortickmarks=int(inputdata.description['XMajorTickMarks'])
else:
xcustommajortickmarks=-1
if inputdata.description.has_key('XMinorTickMarks') and inputdata.description['XMinorTickMarks']!='':
xcustomminortickmarks=int(inputdata.description['XMinorTickMarks'])
else:
xcustomminortickmarks=-1
xcustommajorticks=[]
xcustomminorticks=[]
# # TODO: remove XCustomTicks after 2011-12-31:
# if inputdata.description.has_key('XCustomTicks') and inputdata.description['XCustomTicks']!='':
# logging.warning('Warning: XCustomTicks is deprecated. Use XCustomMajorTicks instead.')
# inputdata.description['XCustomMajorTicks']=inputdata.description['XCustomTicks']
if inputdata.description.has_key('XCustomMajorTicks') and inputdata.description['XCustomMajorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=inputdata.description['XCustomMajorTicks'].strip().split('\t')
if not len(FOO)%2:
for i in range(0,len(FOO),2):
xcustommajorticks.append({'Value': float(FOO[i]), 'Label': FOO[i+1]})
if inputdata.description.has_key('XCustomMinorTicks') and inputdata.description['XCustomMinorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=inputdata.description['XCustomMinorTicks'].strip().split('\t')
for i in range(len(FOO)):
xcustomminorticks.append({'Value': float(FOO[i])})
xticks = XTicks(inputdata.description, self.coors)
if inputdata.description.has_key('RatioPlotTickLabels') and inputdata.description['RatioPlotTickLabels']=='0':
drawlabels=False
else:
drawlabels=True
out += xticks.draw(custommajortickmarks=xcustommajortickmarks,\
customminortickmarks=xcustomminortickmarks,\
custommajorticks=xcustommajorticks,\
customminorticks=xcustomminorticks,
drawlabels=drawlabels)
if inputdata.description.has_key('YMajorTickMarks') and inputdata.description['YMajorTickMarks']!='':
ycustommajortickmarks=int(inputdata.description['YMajorTickMarks'])
else:
ycustommajortickmarks=-1
if inputdata.description.has_key('YMinorTickMarks') and inputdata.description['YMinorTickMarks']!='':
ycustomminortickmarks=int(inputdata.description['YMinorTickMarks'])
else:
ycustomminortickmarks=-1
ycustommajorticks=[]
ycustomminorticks=[]
# # TODO: remove YCustomTicks after 2011-12-31:
# if inputdata.description.has_key('YCustomTicks') and inputdata.description['YCustomTicks']!='':
# logging.warning('Warning: YCustomTicks is deprecated. Use YCustomMajorTicks instead.')
# inputdata.description['YCustomMajorTicks']=inputdata.description['YCustomTicks']
if inputdata.description.has_key('YCustomMajorTicks') and inputdata.description['YCustomMajorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=inputdata.description['YCustomMajorTicks'].strip().split('\t')
if not len(FOO)%2:
for i in range(0,len(FOO),2):
ycustommajorticks.append({'Value': float(FOO[i]), 'Label': FOO[i+1]})
if inputdata.description.has_key('YCustomMinorTicks') and inputdata.description['YCustomMinorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=inputdata.description['YCustomMinorTicks'].strip().split('\t')
for i in range(len(FOO)):
ycustomminorticks.append({'Value': float(FOO[i])})
yticks = YTicks(inputdata.description, self.coors)
out += yticks.draw(custommajortickmarks=ycustommajortickmarks,\
customminortickmarks=ycustomminortickmarks,\
custommajorticks=ycustommajorticks,\
customminorticks=ycustomminorticks)
if inputdata.description.has_key('MainPlot') and inputdata.description['MainPlot']=='0':
if inputdata.description.has_key('Legend') and inputdata.description['Legend']=='1':
legend = Legend(inputdata.description,inputdata.histos,inputdata.functions)
out += legend.draw()
labels = Labels(inputdata.description)
if inputdata.description.has_key('MainPlot') and inputdata.description['MainPlot']=='0':
out += labels.draw(['Title','XLabel','YLabel'])
else:
out += labels.draw(['XLabel','YLabel'])
return out
class Legend(object):
def __init__(self, description, histos, functions):
self.histos = histos
self.functions = functions
self.description = description
def draw(self):
out = ""
out += '\n%\n% Legend\n%\n'
out += '\\rput[tr](%s,%s){%%\n' % (self.getLegendXPos(), self.getLegendYPos())
ypos = -0.05*6/self.description['PlotSizeY']
legendordermap = {}
legendlist = self.description['DrawOnly']+self.functions.keys()
if self.description.has_key('LegendOnly'):
legendlist = []
for legend in self.description['LegendOnly'].strip().split():
if legend in self.histos.keys() or legend in self.functions.keys():
legendlist.append(legend)
for legend in legendlist:
order = 0
if self.histos.has_key(legend) and self.histos[legend].description.has_key('LegendOrder'):
order = int(self.histos[legend].description['LegendOrder'])
if self.functions.has_key(legend) and self.functions[legend].description.has_key('LegendOrder'):
order = int(self.functions[legend].description['LegendOrder'])
if not order in legendordermap:
legendordermap[order] = []
legendordermap[order].append(legend)
foo=[]
for i in sorted(legendordermap.keys()):
foo.extend(legendordermap[i])
rel_xpos_sign = 1.0
if self.getLegendAlign()=='r':
rel_xpos_sign = -1.0
xpos1 = -0.10*rel_xpos_sign
xpos2 = -0.02*rel_xpos_sign
for i in foo:
if self.histos.has_key(i):
drawobject=self.histos[i]
elif self.functions.has_key(i):
drawobject=self.functions[i]
else:
continue
title = drawobject.getTitle()
if title == '':
continue
else:
out += ('\\rput[B%s](%s,%s){%s}\n' %(self.getLegendAlign(),rel_xpos_sign*0.1,ypos,title))
out += ('\\rput[B%s](%s,%s){%s\n' %(self.getLegendAlign(),rel_xpos_sign*0.1,ypos,'%'))
if drawobject.getErrorBands():
out += ('\\psframe[linewidth=0pt,linestyle=none,fillstyle=solid,fillcolor=%s,opacity=%s]' %(drawobject.getErrorBandColor(),drawobject.getErrorBandOpacity()))
out += ('(%s, 0.033)(%s, 0.001)\n' %(xpos1, xpos2))
out += ('\\psline[linestyle=' + drawobject.getLineStyle() \
+ ', linecolor=' + drawobject.getLineColor() \
+ ', linewidth=' + drawobject.getLineWidth() \
+ ', strokeopacity=' + drawobject.getLineOpacity() \
+ ', opacity=' + drawobject.getFillOpacity())
if drawobject.getLineDash()!='':
out += (', dash=' + drawobject.getLineDash())
if drawobject.getFillStyle()!='none':
out += (', fillstyle=' + drawobject.getFillStyle() \
+ ', fillcolor=' + drawobject.getFillColor() \
+ ', hatchcolor=' + drawobject.getHatchColor() \
+ ']{C-C}(%s, 0.030)(%s, 0.030)(%s, 0.004)(%s, 0.004)(%s, 0.030)\n' \
%(xpos1, xpos2, xpos2, xpos1, xpos1))
else:
out += ('](%s, 0.016)(%s, 0.016)\n' %(xpos1, xpos2))
if drawobject.getPolyMarker() != '':
out += (' \\psdot[dotstyle=' + drawobject.getPolyMarker() \
+ ', dotsize=' + drawobject.getDotSize() \
+ ', dotscale=' + drawobject.getDotScale() \
+ ', linecolor=' + drawobject.getLineColor() \
+ ', linewidth=' + drawobject.getLineWidth() \
+ ', linestyle=' + drawobject.getLineStyle() \
+ ', fillstyle=' + drawobject.getFillStyle() \
+ ', fillcolor=' + drawobject.getFillColor() \
+ ', strokeopacity=' + drawobject.getLineOpacity() \
+ ', opacity=' + drawobject.getFillOpacity() \
+ ', hatchcolor=' + drawobject.getHatchColor())
if drawobject.getFillStyle()!='none':
out += ('](%s, 0.028)\n' % (rel_xpos_sign*-0.06))
else:
out += ('](%s, 0.016)\n' % (rel_xpos_sign*-0.06))
out += ('}\n')
ypos -= 0.075*6/self.description['PlotSizeY']
if self.description.has_key('CustomLegend'):
for i in self.description['CustomLegend'].strip().split('\\\\'):
out += ('\\rput[B%s](%s,%s){%s}\n' %(self.getLegendAlign(),rel_xpos_sign*0.1,ypos,i))
ypos -= 0.075*6/self.description['PlotSizeY']
out += ('}\n')
return out
def getLegendXPos(self):
if self.description.has_key('LegendXPos'):
return self.description['LegendXPos']
else:
if self.getLegendAlign()=='r':
return '0.95'
else:
return '0.53'
def getLegendYPos(self):
if self.description.has_key('LegendYPos'):
return self.description['LegendYPos']
else:
return '0.93'
def getLegendAlign(self):
if self.description.has_key('LegendAlign'):
return self.description['LegendAlign']
else:
return 'l'
class Colorscale(object):
def __init__(self, description, coors):
self.description = description
self.coors = coors
def draw(self):
out = ''
out += '\n%\n% Colorscale\n%\n'
out += '\\rput(1,0){\n'
out += ' \\psset{xunit=4mm}\n'
out += ' \\rput(0.5,0){\n'
out += ' \\psset{yunit=0.0076923, linestyle=none, fillstyle=solid}\n'
out += ' \\multido{\\ic=0+1,\\id=1+1}{130}{\n'
out += ' \\psframe[fillcolor={gradientcolors!![\\ic]},dimen=inner,linewidth=0.1pt](0, \\ic)(1, \\id)\n'
out += ' }\n'
out += ' }\n'
out += ' \\rput(0.5,0){\n'
out += ' \\psframe[linewidth=0.3pt,dimen=middle](0,0)(1,1)\n'
# TODO: so much parsing duplication with MainPlot... yuck!
if self.description.has_key('ZMajorTickMarks') and self.description['ZMajorTickMarks']!='':
zcustommajortickmarks=int(self.description['ZMajorTickMarks'])
else:
zcustommajortickmarks=-1
if self.description.has_key('ZMinorTickMarks') and self.description['ZMinorTickMarks']!='':
zcustomminortickmarks=int(self.description['ZMinorTickMarks'])
else:
zcustomminortickmarks=-1
zcustommajorticks=[]
zcustomminorticks=[]
# # TODO: remove ZCustomTicks after 2011-12-31:
# if self.description.has_key('ZCustomTicks') and self.description['ZCustomTicks']!='':
# logging.warning('Warning: ZCustomTicks is deprecated. Use ZCustomMajorTicks instead.')
# self.description['ZCustomMajorTicks']=self.description['ZCustomTicks']
if self.description.has_key('ZCustomMajorTicks') and self.description['ZCustomMajorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=self.description['ZCustomMajorTicks'].strip().split('\t')
if not len(FOO)%2:
for i in range(0,len(FOO),2):
zcustommajorticks.append({'Value': float(FOO[i]), 'Label': FOO[i+1]})
if self.description.has_key('ZCustomMinorTicks') and self.description['ZCustomMinorTicks']!='':
# TODO: Would be nice to have less invisible separation of the custom ticks than split on tabs
FOO=self.description['ZCustomMinorTicks'].strip().split('\t')
for i in range(len(FOO)):
zcustomminorticks.append({'Value': float(FOO[i])})
+ if (self.description.has_key('PlotZTickLabels') and self.description['PlotZTickLabels']=='0'):
+ drawzlabels=False
+ else:
+ drawzlabels=True
zticks = ZTicks(self.description, self.coors)
out += zticks.draw(custommajortickmarks=zcustommajortickmarks,\
customminortickmarks=zcustomminortickmarks,\
custommajorticks=zcustommajorticks,\
- customminorticks=zcustomminorticks)
+ customminorticks=zcustomminorticks,
+ drawlabels=drawzlabels)
out += ' }\n'
out += '}\n'
return out
class Labels(object):
def __init__(self, description):
self.description = description
def draw(self, axis=[]):
out = ""
out += ('\n%\n% Labels\n%\n')
if self.description.has_key('Title') and (axis.count('Title') or axis==[]):
out += ('\\rput(0,1){\\rput[lB](0, 1.7\\labelsep){\\normalsize '+self.description['Title']+'}}\n')
if self.description.has_key('XLabel') and (axis.count('XLabel') or axis==[]):
xlabelsep=4.7
if self.description.has_key('XLabelSep'):
xlabelsep=float(self.description['XLabelSep'])
out += ('\\rput(1,0){\\rput[rB](0,-%4.3f\\labelsep){\\normalsize '%(xlabelsep) +self.description['XLabel']+'}}\n')
if self.description.has_key('YLabel') and (axis.count('YLabel') or axis==[]):
ylabelsep=6.5
if self.description.has_key('YLabelSep'):
ylabelsep=float(self.description['YLabelSep'])
out += ('\\rput(0,1){\\rput[rB]{90}(-%4.3f\\labelsep,0){\\normalsize '%(ylabelsep) +self.description['YLabel']+'}}\n')
if self.description.has_key('ZLabel') and (axis.count('ZLabel') or axis==[]):
zlabelsep=5.3
if self.description.has_key('ZLabelSep'):
zlabelsep=float(self.description['ZLabelSep'])
out += ('\\rput(1,1){\\rput(%4.3f\\labelsep,0){\\psset{xunit=4mm}\\rput[lB]{270}(1.5,0){\\normalsize '%(zlabelsep) +self.description['ZLabel']+'}}}\n')
return out
class Special(object):
def __init__(self, f):
self.description = {}
self.data = []
self.read_input(f)
def read_input(self, f):
for line in f:
if is_end_marker(line, 'SPECIAL'):
break
elif is_comment(line):
continue
else:
self.data.append(line)
def draw(self,coors):
out = ""
out += ('\n%\n% Special\n%\n')
import re
regex = re.compile(r'^(.*?)(\\physics[xy]?coor)\(\s?([0-9\.eE+-]+)\s?,\s?([0-9\.eE+-]+)\s?\)(.*)')
# TODO: More precise number string matching, something like this:
# num = r"-?[0-9]*(?:\.[0-9]*)(?:[eE][+-]?\d+]"
# regex = re.compile(r'^(.*?)(\\physics[xy]?coor)\(\s?(' + num + ')\s?,\s?(' + num + ')\s?\)(.*)')
for i in xrange(len(self.data)):
while regex.search(self.data[i]):
match = regex.search(self.data[i])
xcoor, ycoor = float(match.group(3)), float(match.group(4))
if match.group(2)[1:] in ["physicscoor", "physicsxcoor"]:
xcoor = coors.phys2frameX(xcoor)
if match.group(2)[1:] in ["physicscoor", "physicsycoor"]:
ycoor = coors.phys2frameY(ycoor)
line = "%s(%f, %f)%s" % (match.group(1), xcoor, ycoor, match.group(5))
self.data[i] = line
out += self.data[i]+'\n'
return out
class DrawableObject(object):
def __init__(self, f):
pass
def getTitle(self):
if self.description.has_key('Title'):
return self.description['Title']
else:
return ''
def getLineStyle(self):
if self.description.has_key('LineStyle'):
## I normally like there to be "only one way to do it", but providing
## this dashdotted/dotdashed synonym just seems humane ;-)
if self.description['LineStyle'] in ('dashdotted', 'dotdashed'):
self.description['LineStyle']='dashed'
self.description['LineDash']='3pt 3pt .8pt 3pt'
return self.description['LineStyle']
else:
return 'solid'
def getLineDash(self):
if self.description.has_key('LineDash'):
# Check if LineStyle=='dashdotted' before returning something
self.getLineStyle()
return self.description['LineDash']
else:
return ''
def getLineWidth(self):
if self.description.has_key('LineWidth'):
return self.description['LineWidth']
else:
return '0.8pt'
def getLineColor(self):
if self.description.has_key('LineColor'):
return self.description['LineColor']
else:
return 'black'
def getLineOpacity(self):
if self.description.has_key('LineOpacity'):
return self.description['LineOpacity']
else:
return '1.0'
def getFillColor(self):
if self.description.has_key('FillColor'):
return self.description['FillColor']
else:
return 'white'
def getFillOpacity(self):
if self.description.has_key('FillOpacity'):
return self.description['FillOpacity']
else:
return '1.0'
def getHatchColor(self):
if self.description.has_key('HatchColor'):
return self.description['HatchColor']
else:
return 'black'
def getFillStyle(self):
if self.description.has_key('FillStyle'):
return self.description['FillStyle']
else:
return 'none'
def getPolyMarker(self):
if self.description.has_key('PolyMarker'):
return self.description['PolyMarker']
else:
return ''
def getDotSize(self):
if self.description.has_key('DotSize'):
return self.description['DotSize']
else:
return '2pt 2'
def getDotScale(self):
if self.description.has_key('DotScale'):
return self.description['DotScale']
else:
return '1'
def getErrorBars(self):
if self.description.has_key('ErrorBars'):
return bool(int(self.description['ErrorBars']))
else:
return False
def getErrorBands(self):
if self.description.has_key('ErrorBands'):
return bool(int(self.description['ErrorBands']))
else:
return False
def getErrorBandColor(self):
if self.description.has_key('ErrorBandColor'):
return self.description['ErrorBandColor']
else:
return 'yellow'
def getErrorBandOpacity(self):
if self.description.has_key('ErrorBandOpacity'):
return self.description['ErrorBandOpacity']
else:
return '1.0'
def getSmoothLine(self):
if self.description.has_key('SmoothLine'):
return bool(int(self.description['SmoothLine']))
else:
return False
def startclip(self):
return '\\psclip{\\psframe[linewidth=0, linestyle=none](0,0)(1,1)}\n'
def stopclip(self):
return '\\endpsclip\n'
def startpsset(self):
out = ""
out += ('\\psset{linecolor='+self.getLineColor()+'}\n')
out += ('\\psset{linewidth='+self.getLineWidth()+'}\n')
out += ('\\psset{linestyle='+self.getLineStyle()+'}\n')
out += ('\\psset{fillstyle='+self.getFillStyle()+'}\n')
out += ('\\psset{fillcolor='+self.getFillColor()+'}\n')
out += ('\\psset{hatchcolor='+self.getHatchColor()+'}\n')
out += ('\\psset{strokeopacity='+self.getLineOpacity()+'}\n')
out += ('\\psset{opacity='+self.getFillOpacity()+'}\n')
if self.getLineDash()!='':
out += ('\\psset{dash='+self.getLineDash()+'}\n')
return out
def stoppsset(self):
out = ""
out += ('\\psset{linecolor=black}\n')
out += ('\\psset{linewidth=0.8pt}\n')
out += ('\\psset{linestyle=solid}\n')
out += ('\\psset{fillstyle=none}\n')
out += ('\\psset{fillcolor=white}\n')
out += ('\\psset{hatchcolor=black}\n')
out += ('\\psset{strokeopacity=1.0}\n')
out += ('\\psset{opacity=1.0}\n')
return out
class Function(DrawableObject):
def __init__(self, f):
self.description = {}
self.read_input(f)
def read_input(self, f):
self.code='def plotfunction(x):\n'
iscode=False
for line in f:
if is_end_marker(line, 'FUNCTION'):
break
elif is_comment(line):
continue
else:
m = pat_property.match(line)
if iscode:
self.code+=' '+line
elif m:
prop, value = m.group(1,2)
if prop=='Code':
iscode=True
else:
self.description[prop] = value
if not iscode:
print '++++++++++ ERROR: No code in function'
else:
foo = compile(self.code, '<string>', 'exec')
exec(foo)
self.plotfunction = plotfunction
def draw(self,coors):
out = ""
out += self.startclip()
out += self.startpsset()
xmin = coors.xmin()
if self.description.has_key('XMin') and self.description['XMin']:
xmin = float(self.description['XMin'])
xmax=coors.xmax()
if self.description.has_key('XMax') and self.description['XMax']:
xmax=float(self.description['XMax'])
# TODO: Space sample points logarithmically if LogX=1
dx = (xmax-xmin)/500.
x = xmin-dx
out += '\\pscurve'
if self.description.has_key('FillStyle') and self.description['FillStyle']!='none':
out += '(%s,%s)\n' % (coors.strphys2frameX(xmin),coors.strphys2frameY(coors.ymin()))
while x < (xmax+2*dx):
y = self.plotfunction(x)
out += ('(%s,%s)\n' % (coors.strphys2frameX(x), coors.strphys2frameY(y)))
x += dx
if self.description.has_key('FillStyle') and self.description['FillStyle']!='none':
out += '(%s,%s)\n' % (coors.strphys2frameX(xmax),coors.strphys2frameY(coors.ymin()))
out += self.stoppsset()
out += self.stopclip()
return out
class Histogram(DrawableObject):
def __init__(self, f, p=None):
self.description = {}
self.is2dim = False
self.data = []
self.read_input_data(f)
self.sigmabinvalue = None
self.meanbinvalue = None
self.path = p
def read_input_data(self, f):
for line in f:
if is_end_marker(line, 'HISTOGRAM'):
break
elif is_comment(line):
continue
else:
line = line.rstrip()
m = pat_property.match(line)
if m:
prop, value = m.group(1,2)
self.description[prop] = value
else:
## Detect symm errs
linearray = line.split()
if len(linearray) == 4:
self.data.append({'LowEdge': float(linearray[0]),
'UpEdge': float(linearray[1]),
'Content': float(linearray[2]),
'Error': [float(linearray[3]),float(linearray[3])]})
## Detect asymm errs
elif len(linearray) == 5:
self.data.append({'LowEdge': float(linearray[0]),
'UpEdge': float(linearray[1]),
'Content': float(linearray[2]),
'Error': [float(linearray[3]),float(linearray[4])]})
## Detect two-dimensionality
elif len(linearray) in [6,7]:
self.is2dim = True
# If asymm z error, use the max or average of +- error
err = float(linearray[5])
if len(linearray) == 7:
if self.description.get("ShowMaxZErr", 1):
err = max(err, float(linearray[6]))
else:
err = 0.5 * (err + float(linearray[6]))
self.data.append({'LowEdge': [float(linearray[0]), float(linearray[2])],
'UpEdge': [float(linearray[1]), float(linearray[3])],
'Content': float(linearray[4]),
'Error': err})
## Unknown histo format
else:
raise RuntimeError("Unknown HISTOGRAM data line format with %d entries" % len(linearray))
def mangle_input(self):
if (self.description.has_key('NormalizeToIntegral') and self.description['NormalizeToIntegral']=='1') or \
(self.description.has_key('NormalizeToSum') and self.description['NormalizeToSum']=='1'):
if (self.description.has_key('NormalizeToIntegral') and self.description['NormalizeToIntegral']=='1') and \
(self.description.has_key('NormalizeToSum') and self.description['NormalizeToSum']=='1'):
print 'Can\'t normalize to Integral and to Sum at the same time. Will normalize to the Sum.'
foo = 0
for i in range(len(self.data)):
if self.description.has_key('NormalizeToSum') and self.description['NormalizeToSum']=='1':
foo += self.data[i]['Content']
else:
foo += self.data[i]['Content']*(self.data[i]['UpEdge']-self.data[i]['LowEdge'])
for i in range(len(self.data)):
self.data[i]['Content'] /= foo
self.data[i]['Error'][0] /= foo
self.data[i]['Error'][1] /= foo
if self.description.has_key('Scale') and self.description['Scale']!='':
scale = float(self.description['Scale'])
for i in range(len(self.data)):
self.data[i]['Content'] *= scale
self.data[i]['Error'][0] *= scale
self.data[i]['Error'][1] *= scale
if self.description.has_key('Rebin') and self.description['Rebin']!='':
rebin=int(self.description['Rebin'])
errortype = "stat"
if self.description.has_key('ErrorType') and self.description['ErrorType']!='':
errortype = self.description['ErrorType']
newdata=[]
if rebin>=2:
for i in range(0,(len(self.data)/rebin)*rebin,rebin):
foo=0.
barl=0.
baru=0.
for j in range(rebin):
binwidth=self.data[i+j]['UpEdge']-self.data[i+j]['LowEdge']
foo +=self.data[i+j]['Content']*binwidth
if errortype=="stat":
barl+=(binwidth*self.data[i+j]['Error'][0])**2
baru+=(binwidth*self.data[i+j]['Error'][1])**2
elif errortype=="env":
barl+=(self.data[i+j]['Content']-self.data[i+j]['Error'][0])*binwidth
baru+=(self.data[i+j]['Content']+self.data[i+j]['Error'][1])*binwidth
else:
logging.error("Rebinning for ErrorType not implemented.")
sys.exit(1)
newbinwidth=self.data[i+rebin-1]['UpEdge']-self.data[i]['LowEdge']
newcentral=foo/newbinwidth
if errortype=="stat":
newerror=[sqrt(barl)/newbinwidth,sqrt(baru)/newbinwidth]
elif errortype=="env":
newerror=[(foo-barl)/newbinwidth,(baru-foo)/newbinwidth]
newdata.append({'LowEdge': self.data[i]['LowEdge'],
'UpEdge': self.data[i+rebin-1]['UpEdge'],
'Content': newcentral,
'Error': newerror})
self.data=newdata
def add(self, name):
if len(self.data) != len(name.data):
print '+++ Error in Histogram.add() for %s: different numbers of bins' % self.path
for i in range(len(self.data)):
if fuzzyeq(self.data[i]['LowEdge'], name.data[i]['LowEdge']) and \
fuzzyeq(self.data[i]['UpEdge'], name.data[i]['UpEdge']):
self.data[i]['Content'] += name.data[i]['Content']
self.data[i]['Error'][0] = sqrt(self.data[i]['Error'][0]**2 + name.data[i]['Error'][0]**2)
self.data[i]['Error'][1] = sqrt(self.data[i]['Error'][1]**2 + name.data[i]['Error'][1]**2)
else:
print '+++ Error in Histogram.add() for %s: binning of histograms differs' % self.path
def divide(self, name):
if len(self.data) != len(name.data):
print '+++ Error in Histogram.divide() for %s: different numbers of bins' % self.path
for i in range(len(self.data)):
if fuzzyeq(self.data[i]['LowEdge'], name.data[i]['LowEdge']) and \
fuzzyeq(self.data[i]['UpEdge'], name.data[i]['UpEdge']):
try:
self.data[i]['Error'][0] /= name.data[i]['Content']
except ZeroDivisionError:
self.data[i]['Error'][0]=0.
try:
self.data[i]['Error'][1] /= name.data[i]['Content']
except ZeroDivisionError:
self.data[i]['Error'][1]=0.
try:
self.data[i]['Content'] /= name.data[i]['Content']
except ZeroDivisionError:
self.data[i]['Content']=1.
# self.data[i]['Error'][0] = sqrt(self.data[i]['Error'][0]**2 + name.data[i]['Error'][0]**2)
# self.data[i]['Error'][1] = sqrt(self.data[i]['Error'][1]**2 + name.data[i]['Error'][1]**2)
else:
print '+++ Error in Histogram.divide() for %s: binning of histograms differs' % self.path
def dividereverse(self, name):
if len(self.data) != len(name.data):
print '+++ Error in Histogram.dividereverse() for %s: different numbers of bins' % self.path
for i in range(len(self.data)):
if fuzzyeq(self.data[i]['LowEdge'], name.data[i]['LowEdge']) and \
fuzzyeq(self.data[i]['UpEdge'], name.data[i]['UpEdge']):
try:
self.data[i]['Error'][0] = name.data[i]['Error'][0]/self.data[i]['Content']
except ZeroDivisionError:
self.data[i]['Error'][0]=0.
try:
self.data[i]['Error'][1] = name.data[i]['Error'][1]/self.data[i]['Content']
except ZeroDivisionError:
self.data[i]['Error'][1]=0.
try:
self.data[i]['Content'] = name.data[i]['Content']/self.data[i]['Content']
except ZeroDivisionError:
self.data[i]['Content']=1.
else:
print '+++ Error in Histogram.dividereverse(): binning of histograms differs'
def deviation(self, name):
if len(self.data) != len(name.data):
print '+++ Error in Histogram.deviation() for %s: different numbers of bins' % self.path
for i in range(len(self.data)):
if fuzzyeq(self.data[i]['LowEdge'], name.data[i]['LowEdge']) and \
fuzzyeq(self.data[i]['UpEdge'], name.data[i]['UpEdge']):
self.data[i]['Content'] -= name.data[i]['Content']
try:
self.data[i]['Content'] /= 0.5*sqrt((name.data[i]['Error'][0] + name.data[i]['Error'][1])**2 + \
(self.data[i]['Error'][0] + self.data[i]['Error'][1])**2)
except ZeroDivisionError:
self.data[i]['Content'] = 0.0
try:
self.data[i]['Error'][0] /= name.data[i]['Error'][0]
except ZeroDivisionError:
self.data[i]['Error'][0] = 0.0
try:
self.data[i]['Error'][1] /= name.data[i]['Error'][1]
except ZeroDivisionError:
self.data[i]['Error'][1] = 0.0
else:
print '+++ Error in Histogram.deviation() for %s: binning of histograms differs' % self.path
def getChi2(self, name):
chi2 = 0.
for i in range(len(self.data)):
if fuzzyeq(self.data[i]['LowEdge'], name.data[i]['LowEdge']) and \
fuzzyeq(self.data[i]['UpEdge'], name.data[i]['UpEdge']):
try:
chi2 += (self.data[i]['Content']-name.data[i]['Content'])**2/((0.5*self.data[i]['Error'][0]+0.5*self.data[i]['Error'][1])**2 + (0.5*name.data[i]['Error'][0]+0.5*name.data[i]['Error'][1])**2)
except ZeroDivisionError:
pass
else:
print '+++ Error in Histogram.getChi2() for %s: binning of histograms differs' % self.path
return chi2/len(self.data)
def getSigmaBinValue(self):
if self.sigmabinvalue==None:
self.sigmabinvalue = 0.
sumofweights = 0.
for i in range(len(self.data)):
if self.is2dim:
binwidth = abs( (self.data[i]['UpEdge'][0] - self.data[i]['LowEdge'][0])
*(self.data[i]['UpEdge'][1] - self.data[i]['LowEdge'][1]))
else:
binwidth = abs(self.data[i]['UpEdge'] - self.data[i]['LowEdge'])
self.sigmabinvalue += binwidth*(self.data[i]['Content']-self.getMeanBinValue())**2
sumofweights += binwidth
self.sigmabinvalue = sqrt(self.sigmabinvalue/sumofweights)
return self.sigmabinvalue
def getMeanBinValue(self):
if self.meanbinvalue==None:
self.meanbinvalue = 0.
sumofweights = 0.
for i in range(len(self.data)):
if self.is2dim:
binwidth = abs( (self.data[i]['UpEdge'][0] - self.data[i]['LowEdge'][0])
*(self.data[i]['UpEdge'][1] - self.data[i]['LowEdge'][1]))
else:
binwidth = abs(self.data[i]['UpEdge'] - self.data[i]['LowEdge'])
self.meanbinvalue += binwidth*self.data[i]['Content']
sumofweights += binwidth
self.meanbinvalue /= sumofweights
return self.meanbinvalue
def getCorrelation(self, name):
correlation = 0.
sumofweights = 0.
for i in range(len(self.data)):
if fuzzyeq(self.data[i]['LowEdge'], name.data[i]['LowEdge']) and \
fuzzyeq(self.data[i]['UpEdge'], name.data[i]['UpEdge']):
if self.is2dim:
binwidth = abs( (self.data[i]['UpEdge'][0] - self.data[i]['LowEdge'][0])
* (self.data[i]['UpEdge'][1] - self.data[i]['LowEdge'][1]) )
else:
binwidth = abs(self.data[i]['UpEdge'] - self.data[i]['LowEdge'])
correlation += binwidth * ( self.data[i]['Content'] - self.getMeanBinValue() ) \
* ( name.data[i]['Content'] - name.getMeanBinValue() )
sumofweights += binwidth
else:
print '+++ Error in Histogram.getCorrelation(): binning of histograms differs' % self.path
correlation /= sumofweights
try:
correlation /= self.getSigmaBinValue()*name.getSigmaBinValue()
except ZeroDivisionError:
correlation = 0
return correlation
def getRMSdistance(self,name):
distance = 0.
sumofweights = 0.
for i in range(len(self.data)):
if fuzzyeq(self.data[i]['LowEdge'], name.data[i]['LowEdge']) and \
fuzzyeq(self.data[i]['UpEdge'], name.data[i]['UpEdge']):
if self.is2dim:
binwidth = abs( (self.data[i]['UpEdge'][0] - self.data[i]['LowEdge'][0])
* (self.data[i]['UpEdge'][1] - self.data[i]['LowEdge'][1]) )
else:
binwidth = abs(self.data[i]['UpEdge'] - self.data[i]['LowEdge'])
distance += binwidth * ( (self.data[i]['Content'] - self.getMeanBinValue())
-(name.data[i]['Content'] - name.getMeanBinValue()))**2
sumofweights += binwidth
else:
print '+++ Error in Histogram.getRMSdistance() for %s: binning of histograms differs' % self.path
distance = sqrt(distance/sumofweights)
return distance
def draw(self,coors):
seen_nan = False
out = ""
out += self.startclip()
out += self.startpsset()
#
if self.is2dim:
for i in range(len(self.data)):
out += ('\\psframe')
color=int(129*coors.phys2frameZ(self.data[i]['Content']))
if self.data[i]['Content']>coors.zmax():
color=129
if self.data[i]['Content']<coors.zmin():
color=0
out += ('[linewidth=0pt, linestyle=none, fillstyle=solid, fillcolor={gradientcolors!!['+str(color)+']}]')
out += ('(' + coors.strphys2frameX(self.data[i]['LowEdge'][0]) + ', ' \
+ coors.strphys2frameY(self.data[i]['LowEdge'][1]) + ')(' \
+ coors.strphys2frameX(self.data[i]['UpEdge'][0]) + ', ' \
+ coors.strphys2frameY(self.data[i]['UpEdge'][1]) + ')\n')
else:
if self.getErrorBands():
self.description['SmoothLine']=0
for i in range(len(self.data)):
out += ('\\psframe[dimen=inner,linewidth=0pt,linestyle=none,fillstyle=solid,fillcolor=%s,opacity=%s]' %(self.getErrorBandColor(),self.getErrorBandOpacity()))
out += ('(' + coors.strphys2frameX(self.data[i]['LowEdge']) + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']-self.data[i]['Error'][0]) + ')(' \
+ coors.strphys2frameX(self.data[i]['UpEdge']) + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']+self.data[i]['Error'][1]) + ')\n')
if self.getErrorBars():
for i in range(len(self.data)):
if isnan(self.data[i]['Content']) or isnan(self.data[i]['Error'][0]) or isnan(self.data[i]['Error'][1]):
seen_nan = True
continue
if self.data[i]['Content']==0. and self.data[i]['Error']==[0.,0.]:
continue
out += ('\psline')
out += ('(' + coors.strphys2frameX(self.data[i]['LowEdge']) + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']) + ')(' \
+ coors.strphys2frameX(self.data[i]['UpEdge']) + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']) + ')\n')
out += ('\psline')
bincenter = coors.strphys2frameX(.5*(self.data[i]['LowEdge']+self.data[i]['UpEdge']))
out += ('(' + bincenter + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']-self.data[i]['Error'][0]) + ')(' \
+ bincenter + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']+self.data[i]['Error'][1]) + ')\n')
if self.getSmoothLine():
out += ('\psbezier')
else:
out += ('\psline')
if (self.getFillStyle() != 'none'): # make sure that filled areas go all the way down to the x-axis
if (coors.phys2frameX(self.data[0]['LowEdge']) > 1e-4):
out += '(' + coors.strphys2frameX(self.data[0]['LowEdge']) + ', -0.1)\n'
else:
out += '(-0.1, -0.1)\n'
for i in range(len(self.data)):
if isnan(self.data[i]['Content']):
seen_nan = True
continue
if self.getSmoothLine():
out += ('(' + coors.strphys2frameX(0.5*(self.data[i]['LowEdge']+self.data[i]['UpEdge'])) + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']) + ')\n')
else:
out += ('(' + coors.strphys2frameX(self.data[i]['LowEdge']) + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']) + ')(' \
+ coors.strphys2frameX(self.data[i]['UpEdge']) + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']) + ')\n')
## Join/separate data points, with vertical/diagonal lines
if (i+1 < len(self.data)): #< If this is not the last point
if self.description.get('ConnectBins', '1') != '1':
out += ('\\psline')
else:
## If bins are joined, but there is a gap in binning, choose whether to fill the gap
if (abs(coors.phys2frameX(self.data[i]['UpEdge']) - coors.phys2frameX(self.data[i+1]['LowEdge'])) > 1e-4):
if self.description.get('ConnectGaps', '0') != '1':
out += ('\\psline')
# TODO: Perhaps use a new dashed line to fill the gap?
if (self.getFillStyle() != 'none'): # make sure that filled areas go all the way down to the x-axis
if (coors.phys2frameX(self.data[-1]['UpEdge']) < 1-1e-4):
out += '(' + coors.strphys2frameX(self.data[-1]['UpEdge']) + ', -0.1)\n'
else:
out += '(1.1, -0.1)\n'
#
if self.getPolyMarker() != '':
for i in range(len(self.data)):
if isnan(self.data[i]['Content']):
seen_nan = True
continue
if self.data[i]['Content']==0. and self.data[i]['Error']==[0.,0.]:
continue
out += ('\\psdot[dotstyle=%s,dotsize=%s,dotscale=%s](' %(self.getPolyMarker(),self.getDotSize(),self.getDotScale()) \
+ coors.strphys2frameX(.5*(self.data[i]['LowEdge']+self.data[i]['UpEdge'])) + ', ' \
+ coors.strphys2frameY(self.data[i]['Content']) + ')\n')
out += self.stoppsset()
out += self.stopclip()
if seen_nan:
print "WARNING: NaN-valued value or error bar!"
return out
# def is2dimensional(self):
# return self.is2dim
def getXMin(self):
if self.is2dim:
return min([self.data[i]['LowEdge'][0] for i in range(len(self.data))])
else:
return min([self.data[i]['LowEdge'] for i in range(len(self.data))])
def getXMax(self):
if self.is2dim:
return max([self.data[i]['UpEdge'][0] for i in range(len(self.data))])
else:
return max([self.data[i]['UpEdge'] for i in range(len(self.data))])
def getYMin(self, xmin, xmax, logy):
if self.is2dim:
return min([self.data[i]['LowEdge'][1] for i in range(len(self.data))])
else:
yvalues = []
for i in range(len(self.data)):
if ((self.data[i]['UpEdge'] > xmin or self.data[i]['LowEdge'] >= xmin) and \
(self.data[i]['LowEdge'] < xmax or self.data[i]['UpEdge'] <= xmax)):
foo = 0
if self.getErrorBars() or self.getErrorBands():
foo = self.data[i]['Content']-self.data[i]['Error'][0]
else:
foo = self.data[i]['Content']
if logy:
if foo>0: yvalues.append(foo)
else:
yvalues.append(foo)
if len(yvalues) > 0:
return min(yvalues)
else:
return self.data[0]['Content']
def getYMax(self, xmin, xmax):
if self.is2dim:
return max([self.data[i]['UpEdge'][1] for i in range(len(self.data))])
else:
yvalues = []
for i in range(len(self.data)):
if ((self.data[i]['UpEdge'] > xmin or self.data[i]['LowEdge'] >= xmin) and \
(self.data[i]['LowEdge'] < xmax or self.data[i]['UpEdge'] <= xmax)):
if self.getErrorBars() or self.getErrorBands():
yvalues.append(self.data[i]['Content']+self.data[i]['Error'][1])
else:
yvalues.append(self.data[i]['Content'])
if len(yvalues) > 0:
return max(yvalues)
else:
return self.data[0]['Content']
def getZMin(self, xmin, xmax, ymin, ymax):
if not self.is2dim:
return 0
zvalues = []
for i in range(len(self.data)):
if (self.data[i]['UpEdge'][0] > xmin and self.data[i]['LowEdge'][0] < xmax) and \
(self.data[i]['UpEdge'][1] > ymin and self.data[i]['LowEdge'][1] < ymax):
zvalues.append(self.data[i]['Content'])
return min(zvalues)
def getZMax(self, xmin, xmax, ymin, ymax):
if not self.is2dim:
return 0
zvalues = []
for i in range(len(self.data)):
if (self.data[i]['UpEdge'][0] > xmin and self.data[i]['LowEdge'][0] < xmax) and \
(self.data[i]['UpEdge'][1] > ymin and self.data[i]['LowEdge'][1] < ymax):
zvalues.append(self.data[i]['Content'])
return max(zvalues)
class Histo1D(Histogram):
def read_input_data(self, f):
for line in f:
if is_end_marker(line, 'HISTO1D'):
break
elif is_comment(line):
continue
else:
line = line.rstrip()
m = pat_property.match(line)
if m:
prop, value = m.group(1,2)
self.description[prop] = value
else:
linearray = line.split()
## Detect symm errs
if len(linearray) == 4:
self.data.append({'LowEdge': float(linearray[0]),
'UpEdge': float(linearray[1]),
'Content': float(linearray[2]),
'Error': [float(linearray[3]),float(linearray[3])]})
## Detect asymm errs
elif len(linearray) == 5:
self.data.append({'LowEdge': float(linearray[0]),
'UpEdge': float(linearray[1]),
'Content': float(linearray[2]),
'Error': [float(linearray[3]),float(linearray[4])]})
## Not sure what this is for... auto-compatibility with YODA format? Urgh
elif len(linearray) == 8:
self.data.append({'LowEdge': float(linearray[0]),
'UpEdge': float(linearray[1]),
'Content': float(linearray[2]),
'Error': [float(linearray[3]),float(linearray[3])]})
else:
raise Exception('Histo1D does not have 8 columns.'+line)
class Histo2D(Histogram):
def read_input_data(self, f):
self.is2dim = True #< Should really be done in a constructor, but this is easier for now...
for line in f:
if is_end_marker(line, 'HISTO2D'):
break
elif is_comment(line):
continue
else:
line = line.rstrip()
m = pat_property.match(line)
if m:
prop, value = m.group(1,2)
self.description[prop] = value
else:
linearray = line.split()
if len(linearray) in [6,7]:
# If asymm z error, use the max or average of +- error
err = float(linearray[5])
if len(linearray) == 7:
if self.description.get("ShowMaxZErr", 1):
err = max(err, float(linearray[6]))
else:
err = 0.5 * (err + float(linearray[6]))
self.data.append({'LowEdge': [float(linearray[0]), float(linearray[2])],
'UpEdge': [float(linearray[1]), float(linearray[3])],
'Content': float(linearray[4]),
'Error': err})
else:
raise Exception('Histo1D does not have 6 or 7 columns.'+line)
class Frame(object):
def __init__(self):
self.framelinewidth = '0.3pt'
def draw(self,inputdata):
out = ('\n%\n% Frame\n%\n')
if inputdata.description.has_key('FrameColor') and inputdata.description['FrameColor']!=None:
color = inputdata.description['FrameColor']
# We want to draw this frame only once, so set it to False for next time:
inputdata.description['FrameColor']=None
# Calculate how high and wide the overall plot is
height = [0,0]
width = inputdata.description['PlotSizeX']
if inputdata.description.has_key('RatioPlot') and inputdata.description['RatioPlot']=='1':
height[1] = -inputdata.description['RatioPlotSizeY']
if not (inputdata.description.has_key('MainPlot') and inputdata.description['MainPlot']=='0'):
height[0] = inputdata.description['PlotSizeY']
else:
height[0] = -height[1]
height[1] = 0
# Get the margin widths
left = inputdata.description['LeftMargin']+0.1
right = inputdata.description['RightMargin']+0.1
top = inputdata.description['TopMargin']+0.1
bottom = inputdata.description['BottomMargin']+0.1
#
out += ('\\rput(0,1){\\psline[linewidth=%scm,linecolor=%s](%scm,%scm)(%scm,%scm)}\n' %(top, color, -left, top/2, width+right, top/2))
out += ('\\rput(0,%scm){\\psline[linewidth=%scm,linecolor=%s](%scm,%scm)(%scm,%scm)}\n' %(height[1], bottom, color, -left, -bottom/2, width+right, -bottom/2))
out += ('\\rput(0,0){\\psline[linewidth=%scm,linecolor=%s](%scm,%scm)(%scm,%scm)}\n' %(left, color, -left/2, height[1]-0.05, -left/2, height[0]+0.05))
out += ('\\rput(1,0){\\psline[linewidth=%scm,linecolor=%s](%scm,%scm)(%scm,%scm)}\n' %(right, color, right/2, height[1]-0.05, right/2, height[0]+0.05))
out += ('\\psframe[linewidth='+self.framelinewidth+',dimen=middle](0,0)(1,1)\n')
return out
class Ticks(object):
def __init__(self, description, coors):
self.majorticklinewidth = '0.3pt'
self.minorticklinewidth = '0.3pt'
self.majorticklength = '9pt'
self.minorticklength = '4pt'
self.description = description
self.coors = coors
def draw_ticks(self, min, max, plotlog=False, custommajorticks=[], customminorticks=[], custommajortickmarks=-1, customminortickmarks=-1, drawlabels=True, twosided=False):
out = ""
if plotlog:
if min <= 0 or max <= 0:
raise Exception("Cannot place log axis min or max tick <= 0")
if len(custommajorticks) ==0:
x=int(log10(min))
n_labels=0
while (x<log10(max)+1):
if 10**x>=min:
ticklabel=10**x
if ticklabel>min and ticklabel<max:
out += self.draw_majortick(ticklabel,twosided)
if drawlabels:
out += self.draw_majorticklabel(ticklabel)
n_labels+=1
if ticklabel==min or ticklabel==max:
if drawlabels:
out += self.draw_majorticklabel(ticklabel)
n_labels+=1
for i in range(2,10):
ticklabel=i*10**(x-1)
if ticklabel>min and ticklabel<max:
out += self.draw_minortick(ticklabel,twosided)
if drawlabels and n_labels==0:
if (i+1)*10**(x-1)<max: # some special care for the last minor tick
out += self.draw_minorticklabel(ticklabel)
else:
out += self.draw_minorticklabel(ticklabel, last=True)
x+=1
elif (custommajorticks!=[] or customminorticks!=[]):
for i in range(len(custommajorticks)):
value=custommajorticks[i]['Value']
label=custommajorticks[i]['Label']
if value>=min and value<=max:
out += self.draw_majortick(value,twosided)
if drawlabels:
out += self.draw_majorticklabel(value, label=label)
for i in range(len(customminorticks)):
value=customminorticks[i]['Value']
if value>=min and value<=max:
out += self.draw_minortick(value,twosided)
else:
xrange = max-min
digits = int(log10(xrange))+1
if (xrange < 1):
digits -= 1
foo = int(xrange/(10**(digits-1)))
if (foo/9. > 0.5):
tickmarks = 10
elif (foo/9. > 0.2):
tickmarks = 5
elif (foo/9. > 0.1):
tickmarks = 2
if (custommajortickmarks>-1):
if custommajortickmarks not in [1, 2, 5, 10, 20]:
print '+++ Error in Ticks.draw_ticks(): MajorTickMarks must be in [1, 2, 5, 10, 20]'
else:
#if custommajortickmarks==1: custommajortickmarks=10
tickmarks = custommajortickmarks
if (tickmarks == 2 or tickmarks == 20):
minortickmarks = 3
else:
minortickmarks = 4
if (customminortickmarks>-1):
minortickmarks = customminortickmarks
#
x = 0
while (x > min*10**digits):
x -= tickmarks*100**(digits-1)
while (x <= max*10**digits):
if (x >= min*10**digits-tickmarks*100**(digits-1)):
ticklabel = 1.*x/10**digits
if (int(ticklabel) == ticklabel):
ticklabel = int(ticklabel)
if (float(ticklabel-min)/xrange >= -1e-5):
if (fabs(ticklabel-min)/xrange > 1e-5 and fabs(ticklabel-max)/xrange > 1e-5):
out += self.draw_majortick(ticklabel,twosided)
if drawlabels:
out += self.draw_majorticklabel(ticklabel)
xminor = x
for i in range(minortickmarks):
xminor += 1.*tickmarks*100**(digits-1)/(minortickmarks+1)
ticklabel = 1.*xminor/10**digits
if (ticklabel > min and ticklabel < max):
if (fabs(ticklabel-min)/xrange > 1e-5 and fabs(ticklabel-max)/xrange > 1e-5):
out += self.draw_minortick(ticklabel,twosided)
x += tickmarks*100**(digits-1)
return out
def draw(self):
pass
def draw_minortick(self, ticklabel, twosided):
pass
def draw_majortick(self, ticklabel, twosided):
pass
def draw_majorticklabel(self, ticklabel):
pass
def draw_minorticklabel(self, value, label='', last=False):
return ''
def get_ticklabel(self, value, plotlog=False, minor=False, lastminor=False):
label=''
prefix = ""
if plotlog:
bar = int(log10(value))
if bar<0:
sign='-'
else:
sign='\\,'
if minor: # The power of ten is only to be added to the last minor tick label
if lastminor:
label = str(int(value/(10**bar))) + "\cdot" + '10$^{'+sign+'\\text{'+str(abs(bar))+'}}$'
else:
label = str(int(value/(10**bar))) # The naked prefactor
else:
if bar==0:
label = '1'
else:
label = '10$^{'+sign+'\\text{'+str(abs(bar))+'}}$'
else:
if fabs(value) < 1e-10: value=0
label=str(value)
return label
class XTicks(Ticks):
def draw(self, custommajorticks=[], customminorticks=[], custommajortickmarks=-1, customminortickmarks=-1,drawlabels=True):
twosided = False
if self.description.has_key('XTwosidedTicks') and self.description['XTwosidedTicks']=='1':
twosided = True
out = ""
out += ('\n%\n% X-Ticks\n%\n')
out += ('\\def\\majortickmarkx{\\psline[linewidth='+self.majorticklinewidth+'](0,0)(0,'+self.majorticklength+')}%\n')
out += ('\\def\\minortickmarkx{\\psline[linewidth='+self.minorticklinewidth+'](0,0)(0,'+self.minorticklength+')}%\n')
uselog = self.description['LogX'] and (self.coors.xmin() > 0 and self.coors.xmax() > 0)
out += self.draw_ticks(self.coors.xmin(), self.coors.xmax(),\
plotlog=uselog,\
custommajorticks=custommajorticks,\
customminorticks=customminorticks,\
custommajortickmarks=custommajortickmarks,\
customminortickmarks=customminortickmarks,\
drawlabels=drawlabels,\
twosided=twosided)
return out
def draw_minortick(self, ticklabel, twosided):
out = ''
out += '\\rput('+self.coors.strphys2frameX(ticklabel)+', 0){\\minortickmarkx}\n'
if twosided:
out += '\\rput{180}('+self.coors.strphys2frameX(ticklabel)+', 1){\\minortickmarkx}\n'
return out
def draw_minorticklabel(self, value, label='', last=False):
if label=='':
label=self.get_ticklabel(value,self.description['LogX'], minor=True, lastminor=last)
if last: # Some more indentation for the last minor label
return ('\\rput('+self.coors.strphys2frameX(value)+', 0){\\rput[B](1.9\\labelsep,-2.3\\labelsep){\\strut{}'+label+'}}\n')
else:
return ('\\rput('+self.coors.strphys2frameX(value)+', 0){\\rput[B](0,-2.3\\labelsep){\\strut{}'+label+'}}\n')
def draw_majortick(self, ticklabel, twosided):
out = ''
out += '\\rput('+self.coors.strphys2frameX(ticklabel)+', 0){\\majortickmarkx}\n'
if twosided:
out += '\\rput{180}('+self.coors.strphys2frameX(ticklabel)+', 1){\\majortickmarkx}\n'
return out
def draw_majorticklabel(self, value, label=''):
if label=='':
label=self.get_ticklabel(value, self.description['LogX'] and (self.coors.xmin() > 0 and self.coors.xmax() > 0))
return ('\\rput('+self.coors.strphys2frameX(value)+', 0){\\rput[B](0,-2.3\\labelsep){\\strut{}'+label+'}}\n')
class YTicks(Ticks):
- def draw(self, custommajorticks=[], customminorticks=[], custommajortickmarks=-1, customminortickmarks=-1):
+ def draw(self, custommajorticks=[], customminorticks=[], custommajortickmarks=-1, customminortickmarks=-1,drawlabels=True):
twosided = False
if self.description.has_key('YTwosidedTicks') and self.description['YTwosidedTicks']=='1':
twosided = True
out = ""
out += ('\n%\n% Y-Ticks\n%\n')
out += ('\\def\\majortickmarky{\\psline[linewidth='+self.majorticklinewidth+'](0,0)('+self.majorticklength+',0)}%\n')
out += ('\\def\\minortickmarky{\\psline[linewidth='+self.minorticklinewidth+'](0,0)('+self.minorticklength+',0)}%\n')
uselog = self.description['LogY'] and (self.coors.ymin() > 0 and self.coors.ymax() > 0)
out += self.draw_ticks(self.coors.ymin(), self.coors.ymax(),\
plotlog=uselog,\
custommajorticks=custommajorticks,\
customminorticks=customminorticks,\
custommajortickmarks=custommajortickmarks,\
customminortickmarks=customminortickmarks,\
- twosided=twosided)
+ twosided=twosided,
+ drawlabels=drawlabels)
return out
def draw_minortick(self, ticklabel, twosided):
out = ''
out += '\\rput(0, '+self.coors.strphys2frameY(ticklabel)+'){\\minortickmarky}\n'
if twosided:
out += '\\rput{180}(1, '+self.coors.strphys2frameY(ticklabel)+'){\\minortickmarky}\n'
return out
def draw_majortick(self, ticklabel, twosided):
out = ''
out += '\\rput(0, '+self.coors.strphys2frameY(ticklabel)+'){\\majortickmarky}\n'
if twosided:
out += '\\rput{180}(1, '+self.coors.strphys2frameY(ticklabel)+'){\\majortickmarky}\n'
return out
def draw_majorticklabel(self, value, label=''):
if label=='':
label=self.get_ticklabel(value, self.description['LogY'] and (self.coors.ymin() > 0 and self.coors.ymax() > 0))
if self.description.has_key('RatioPlotMode') and self.description['RatioPlotMode']=='deviation' \
and self.description.has_key('RatioPlotStage') and self.description['RatioPlotStage']:
return ('\\uput[180]{0}(0, '+self.coors.strphys2frameY(value)+'){\\strut{}'+label+'\\,$\\sigma$}\n')
else:
return ('\\uput[180]{0}(0, '+self.coors.strphys2frameY(value)+'){\\strut{}'+label+'}\n')
class ZTicks(Ticks):
def __init__(self, description, coors):
self.majorticklinewidth = '0.3pt'
self.minorticklinewidth = '0.3pt'
self.majorticklength = '6pt'
self.minorticklength = '2.6pt'
self.description = description
self.coors = coors
- def draw(self, custommajorticks=[], customminorticks=[], custommajortickmarks=-1, customminortickmarks=-1):
+ def draw(self, custommajorticks=[], customminorticks=[],
+ custommajortickmarks=-1, customminortickmarks=-1,
+ drawlabels=True):
out = ""
out += ('\n%\n% Z-Ticks\n%\n')
out += ('\\def\\majortickmarkz{\\psline[linewidth='+self.majorticklinewidth+'](0,0)('+self.majorticklength+',0)}%\n')
out += ('\\def\\minortickmarkz{\\psline[linewidth='+self.minorticklinewidth+'](0,0)('+self.minorticklength+',0)}%\n')
out += self.draw_ticks(self.coors.zmin(), self.coors.zmax(),\
plotlog=self.description['LogZ'],\
custommajorticks=custommajorticks,\
customminorticks=customminorticks,\
custommajortickmarks=custommajortickmarks,\
customminortickmarks=customminortickmarks,\
- twosided=False)
+ twosided=False,\
+ drawlabels=drawlabels)
return out
def draw_minortick(self, ticklabel, twosided):
return '\\rput{180}(1, '+self.coors.strphys2frameZ(ticklabel)+'){\\minortickmarkz}\n'
def draw_majortick(self, ticklabel, twosided):
return '\\rput{180}(1, '+self.coors.strphys2frameZ(ticklabel)+'){\\majortickmarkz}\n'
def draw_majorticklabel(self, value, label=''):
if label=='':
label=self.get_ticklabel(value,self.description['LogZ'])
if self.description.has_key('RatioPlotMode') and self.description['RatioPlotMode']=='deviation' \
and self.description.has_key('RatioPlotStage') and self.description['RatioPlotStage']:
return ('\\uput[0]{0}(1, '+self.coors.strphys2frameZ(value)+'){\\strut{}'+label+'\\,$\\sigma$}\n')
else:
return ('\\uput[0]{0}(1, '+self.coors.strphys2frameZ(value)+'){\\strut{}'+label+'}\n')
class Coordinates(object):
def __init__(self, inputdata):
self.description = inputdata.description
def phys2frameX(self, x):
if self.description['LogX']:
if x>0:
result = 1.*(log10(x)-log10(self.xmin()))/(log10(self.xmax())-log10(self.xmin()))
else:
return -10
else:
result = 1.*(x-self.xmin())/(self.xmax()-self.xmin())
if (fabs(result) < 1e-4):
return 0
else:
return min(max(result,-10),10)
def phys2frameY(self, y):
if self.description['LogY']:
if y > 0 and self.ymin() > 0 and self.ymax() > 0:
result = 1.*(log10(y)-log10(self.ymin()))/(log10(self.ymax())-log10(self.ymin()))
else:
return -10
else:
result = 1.*(y-self.ymin())/(self.ymax()-self.ymin())
if (fabs(result) < 1e-4):
return 0
else:
return min(max(result,-10),10)
def phys2frameZ(self, z):
if self.description['LogZ']:
if z>0:
result = 1.*(log10(z)-log10(self.zmin()))/(log10(self.zmax())-log10(self.zmin()))
else:
return -10
else:
result = 1.*(z-self.zmin())/(self.zmax()-self.zmin())
if (fabs(result) < 1e-4):
return 0
else:
return min(max(result,-10),10)
# TODO: Add frame2phys functions (to allow linear function sampling in the frame space rather than the physical space)
def strphys2frameX(self, x):
return str(self.phys2frameX(x))
def strphys2frameY(self, y):
return str(self.phys2frameY(y))
def strphys2frameZ(self, z):
return str(self.phys2frameZ(z))
def xmin(self):
return self.description['Borders'][0]
def xmax(self):
return self.description['Borders'][1]
def ymin(self):
return self.description['Borders'][2]
def ymax(self):
return self.description['Borders'][3]
def zmin(self):
return self.description['Borders'][4]
def zmax(self):
return self.description['Borders'][5]
####################
def try_cmd(args):
"Run the given command + args and return True/False if it succeeds or not"
import subprocess
try:
subprocess.check_output(args, stderr=subprocess.STDOUT)
return True
except AttributeError:
# Python <=2.6 does not provide check_output
return True
except:
return False
def have_cmd(cmd):
return try_cmd(["which", cmd])
import shutil, subprocess
def process_datfile(datfile):
global opts
if not os.access(datfile, os.R_OK):
raise Exception("Could not read data file '%s'" % datfile)
dirname = os.path.dirname(datfile)
datfile = os.path.basename(datfile)
filename = datfile.replace('.dat','')
## Create a temporary directory
cwd = os.getcwd()
datpath = os.path.join(cwd, dirname, datfile)
tempdir = tempfile.mkdtemp('.make-plots')
tempdatpath = os.path.join(tempdir, datfile)
shutil.copy(datpath, tempdir)
## Make TeX file
inputdata = Inputdata(os.path.join(dirname,filename))
texpath = os.path.join(tempdir, '%s.tex' % filename)
texfile = open(texpath, 'w')
p = Plot(inputdata)
texfile.write(p.write_header(inputdata))
if inputdata.description.get('MainPlot', '1') == '1':
mp = MainPlot(inputdata)
texfile.write(mp.draw(inputdata))
if not inputdata.description.get('is2dim', False) and \
inputdata.description.get('RatioPlot', '1') == '1' and \
inputdata.description.get('RatioPlotReference') is not None:
rp = RatioPlot(inputdata)
texfile.write(rp.draw(inputdata))
texfile.write(p.write_footer())
texfile.close()
if opts.OUTPUT_FORMAT != "TEX":
## Check for the required programs
latexavailable = have_cmd("latex")
dvipsavailable = have_cmd("dvips")
convertavailable = have_cmd("convert")
ps2pnmavailable = have_cmd("ps2pnm")
pnm2pngavailable = have_cmd("pnm2png")
# TODO: It'd be nice to be able to control the size of the PNG between thumb and full-size...
# currently defaults (and is used below) to a size suitable for thumbnails
def mkpng(infile, outfile, density=100):
if convertavailable:
pngcmd = ["convert", "-flatten", "-density", str(density), infile, "-quality", "100", "-sharpen", "0x1.0", outfile]
logging.debug(" ".join(pngcmd))
pngproc = subprocess.Popen(pngcmd, stdout=subprocess.PIPE, cwd=tempdir)
pngproc.wait()
else:
raise Exception("Required PNG maker program (convert) not found")
# elif ps2pnmavailable and pnm2pngavailable:
# pstopnm = "pstopnm -stdout -xsize=461 -ysize=422 -xborder=0.01 -yborder=0.01 -portrait " + infile
# p1 = subprocess.Popen(pstopnm.split(), stdout=subprocess.PIPE, stderr=open("/dev/null", "w"), cwd=tempdir)
# p2 = subprocess.Popen(["pnmtopng"], stdin=p1.stdout, stdout=open("%s/%s.png" % (tempdir, outfile), "w"), stderr=open("/dev/null", "w"), cwd=tempdir)
# p2.wait()
# else:
# raise Exception("Required PNG maker programs (convert, or ps2pnm and pnm2png) not found")
## Run LaTeX (in no-stop mode)
logging.debug(os.listdir(tempdir))
texcmd = ["latex", "\scrollmode\input", texpath]
logging.debug("TeX command: " + " ".join(texcmd))
texproc = subprocess.Popen(texcmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tempdir)
logging.debug(texproc.communicate()[0])
logging.debug(os.listdir(tempdir))
## Run dvips
dvcmd = ["dvips", filename]
if not logging.getLogger().isEnabledFor(logging.DEBUG):
dvcmd.append("-q")
## Handle Minion Font
if opts.OUTPUT_FONT == "MINION":
dvcmd.append('-Pminion')
## Choose format
# TODO: Rationalise... this is a mess! Maybe we can use tex2pix?
if opts.OUTPUT_FORMAT == "PS":
dvcmd += ["-o", "%s.ps" % filename]
logging.debug(" ".join(dvcmd))
dvproc = subprocess.Popen(dvcmd, stdout=subprocess.PIPE, cwd=tempdir)
dvproc.wait()
elif opts.OUTPUT_FORMAT == "PDF":
dvcmd.append("-f")
logging.debug(" ".join(dvcmd))
dvproc = subprocess.Popen(dvcmd, stdout=subprocess.PIPE, cwd=tempdir)
cnvproc = subprocess.Popen(["ps2pdf", "-"], stdin=dvproc.stdout, stdout=subprocess.PIPE, cwd=tempdir)
f = open(os.path.join(tempdir, "%s.pdf" % filename), "w")
f.write(cnvproc.communicate()[0])
f.close()
elif opts.OUTPUT_FORMAT == "EPS":
dvcmd.append("-f")
logging.debug(" ".join(dvcmd))
dvproc = subprocess.Popen(dvcmd, stdout=subprocess.PIPE, cwd=tempdir)
cnvproc = subprocess.Popen(["ps2eps"], stdin=dvproc.stdout, stderr=subprocess.PIPE, stdout=subprocess.PIPE, cwd=tempdir)
f = open(os.path.join(tempdir, "%s.eps" % filename), "w")
f.write(cnvproc.communicate()[0])
f.close()
elif opts.OUTPUT_FORMAT == "PNG":
dvcmd.append("-f")
logging.debug(" ".join(dvcmd))
dvproc = subprocess.Popen(dvcmd, stdout=subprocess.PIPE, cwd=tempdir)
pngcmd = ["convert", "-flatten", "-density", "100", "-", "-quality", "100", "-sharpen", "0x1.0", "%s.png" % filename]
logging.debug(" ".join(pngcmd))
pngproc = subprocess.Popen(pngcmd, stdin=dvproc.stdout, stdout=subprocess.PIPE, cwd=tempdir)
pngproc.wait()
elif opts.OUTPUT_FORMAT == "PSPNG":
dvcmd += ["-o", "%s.ps" % filename]
logging.debug(" ".join(dvcmd))
dvproc = subprocess.Popen(dvcmd, stdout=subprocess.PIPE, cwd=tempdir)
dvproc.wait()
mkpng("%s.ps" % filename, "%s.png" % filename)
elif opts.OUTPUT_FORMAT == "PDFPNG":
dvcmd.append("-f")
logging.debug(" ".join(dvcmd))
dvproc = subprocess.Popen(dvcmd, stdout=subprocess.PIPE, cwd=tempdir)
cnvproc = subprocess.Popen(["ps2pdf", "-"], stdin=dvproc.stdout, stdout=subprocess.PIPE, cwd=tempdir)
f = open(os.path.join(tempdir, "%s.pdf" % filename), "w")
f.write(cnvproc.communicate()[0])
f.close()
logging.debug(os.listdir(tempdir))
mkpng("%s.pdf" % filename, "%s.png" % filename)
elif opts.OUTPUT_FORMAT == "EPSPNG":
dvcmd.append("-f")
logging.debug(" ".join(dvcmd))
dvproc = subprocess.Popen(dvcmd, stdout=subprocess.PIPE, cwd=tempdir)
cnvproc = subprocess.Popen(["ps2eps"], stdin=dvproc.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=tempdir)
f = open(os.path.join(tempdir, "%s.eps" % filename), "w")
f.write(cnvproc.communicate()[0])
f.close()
mkpng("%s.eps" % filename, "%s.png" % filename)
else:
logging.error("Unknown format: %s" % opts.OUTPUT_FORMAT)
sys.exit(1)
logging.debug(os.listdir(tempdir))
## Copy results back to main dir
outbasename = filename
outname = outbasename + "." + opts.OUTPUT_FORMAT.lower()
## TODO: Make this neater: if "PNG" in opts.OUTPUT_FORMAT: ...
if opts.OUTPUT_FORMAT == "PSPNG":
outpath = os.path.join(tempdir, outbasename+".ps")
shutil.copy(outpath, os.path.join(cwd,dirname))
outpath = os.path.join(tempdir, outbasename+".png")
shutil.copy(outpath, os.path.join(cwd,dirname))
elif opts.OUTPUT_FORMAT == "PDFPNG":
outpath = os.path.join(tempdir, outbasename+".pdf")
shutil.copy(outpath, os.path.join(cwd,dirname))
outpath = os.path.join(tempdir, outbasename+".png")
shutil.copy(outpath, os.path.join(cwd,dirname))
elif opts.OUTPUT_FORMAT == "EPSPNG":
outpath = os.path.join(tempdir, outbasename+".eps")
shutil.copy(outpath, os.path.join(cwd,dirname))
outpath = os.path.join(tempdir, outbasename+".png")
shutil.copy(outpath, os.path.join(cwd,dirname))
else:
outpath = os.path.join(tempdir, outname)
if os.path.exists(outpath):
shutil.copy(outpath, os.path.join(cwd,dirname))
else:
logging.error("No output file '%s' from processing %s" % (outname, datfile))
## Clean up
if opts.NO_CLEANUP:
logging.info('Keeping temp-files in %s' % tempdir)
else:
shutil.rmtree(tempdir, ignore_errors=True)
## Wrapper for a process thread which attempts to process datfiles until empty
import threading, Queue
class MkPlotThread( threading.Thread ):
def run(self):
global opts
global datfiles
global RECVD_KILL_SIGNAL
while True:
if RECVD_KILL_SIGNAL is not None:
## Empty the queue
while not datfiles.empty():
dummy = datfiles.get_nowait()
break
try:
datfile = datfiles.get_nowait()
rem = datfiles.qsize()
logging.info("Plotting %s (%d remaining)" % (datfile, rem))
process_datfile(datfile)
except Queue.Empty, e:
#print "%s ending." % self.getName()
break
# except Exception, e:
# print "Error: %s" % str(e)
# import traceback
# logging.debug(traceback.format_exc())
# #exit(1)
####################
if __name__ == '__main__':
## Try to rename the process on Linux
try:
import ctypes
libc = ctypes.cdll.LoadLibrary('libc.so.6')
libc.prctl(15, 'make-plots', 0, 0, 0)
except Exception:
pass
## Try to use Psyco optimiser
try:
import psyco
psyco.full()
except ImportError:
pass
## Find number of (virtual) processing units
numcores = os.sysconf('SC_NPROCESSORS_ONLN')
if numcores is None:
numcores = 1
## Parse command line options
from optparse import OptionParser, OptionGroup
parser = OptionParser(usage=__doc__)
parser.add_option("-n", "-j", "--num-threads", dest="NUM_THREADS", type="int",
default=numcores, help="max number of threads to be used [%s]" % numcores)
parser.add_option("--palatino", dest="OUTPUT_FONT", action="store_const", const="PALATINO", default="PALATINO",
help="Use Palatino as font (default).")
parser.add_option("--cm", dest="OUTPUT_FONT", action="store_const", const="CM", default="PALATINO",
help="Use Computer Modern as font.")
parser.add_option("--times", dest="OUTPUT_FONT", action="store_const", const="TIMES", default="PALATINO",
help="Use Times as font.")
parser.add_option("--minion", dest="OUTPUT_FONT", action="store_const", const="MINION", default="PALATINO",
help="Use Adobe Minion Pro as font. Note: You need to set TEXMFHOME first.")
parser.add_option("--helvetica", dest="OUTPUT_FONT", action="store_const", const="HELVETICA", default="PALATINO",
help="Use Helvetica as font.")
parser.add_option("--ps", dest="OUTPUT_FORMAT", action="store_const", const="PS", default="PDF",
help="Create PostScript output (default).")
parser.add_option("--pdf", dest="OUTPUT_FORMAT", action="store_const", const="PDF", default="PDF",
help="Create PDF output.")
parser.add_option("--eps", dest="OUTPUT_FORMAT", action="store_const", const="EPS", default="PDF",
help="Create Encapsulated PostScript output.")
parser.add_option("--png", dest="OUTPUT_FORMAT", action="store_const", const="PNG", default="PDF",
help="Create PNG output.")
parser.add_option("--pspng", dest="OUTPUT_FORMAT", action="store_const", const="PSPNG", default="PDF",
help="Create PS and PNG output.")
parser.add_option("--pdfpng", dest="OUTPUT_FORMAT", action="store_const", const="PDFPNG", default="PDF",
help="Create PDF and PNG output.")
parser.add_option("--epspng", dest="OUTPUT_FORMAT", action="store_const", const="EPSPNG", default="PDF",
help="Create EPS and PNG output.")
parser.add_option("--tex", dest="OUTPUT_FORMAT", action="store_const", const="TEX", default="PDF",
help="Create TeX/LaTeX output.")
parser.add_option("--no-cleanup", dest="NO_CLEANUP", action="store_true", default=False,
help="Keep temporary directory and print its filename.")
parser.add_option("--full-range", dest="FULL_RANGE", action="store_true", default=False,
help="Plot full y range in LogY plots.")
parser.add_option("-c", "--config", dest="CONFIGFILES", action="append", default=None,
help="Plot config file to be used. Overrides internal config blocks.")
verbgroup = OptionGroup(parser, "Verbosity control")
verbgroup.add_option("-v", "--verbose", action="store_const", const=logging.DEBUG, dest="LOGLEVEL",
default=logging.INFO, help="print debug (very verbose) messages")
verbgroup.add_option("-q", "--quiet", action="store_const", const=logging.WARNING, dest="LOGLEVEL",
default=logging.INFO, help="be very quiet")
parser.add_option_group(verbgroup)
opts, args = parser.parse_args()
logging.basicConfig(level=opts.LOGLEVEL, format="%(message)s")
## Check for no args
if len(args) == 0:
logging.error(parser.get_usage())
sys.exit(2)
## Test for external programs (kpsewhich, latex, dvips, ps2pdf/ps2eps, and convert)
opts.LATEXPKGS = []
if opts.OUTPUT_FORMAT != "TEX":
try:
## latex
if not have_cmd("latex"):
logging.error("ERROR: required program 'latex' could not be found. Exiting...")
sys.exit(1)
## dvips
if not have_cmd("dvips"):
logging.error("ERROR: required program 'dvips' could not be found. Exiting...")
sys.exit(1)
## ps2pdf / ps2eps
if "PDF" in opts.OUTPUT_FORMAT:
if not have_cmd("ps2pdf"):
logging.error("ERROR: required program 'ps2pdf' (for PDF output) could not be found. Exiting...")
sys.exit(1)
elif "EPS" in opts.OUTPUT_FORMAT:
if not have_cmd("ps2eps"):
logging.error("ERROR: required program 'ps2eps' (for EPS output) could not be found. Exiting...")
sys.exit(1)
## PNG output converter
if "PNG" in opts.OUTPUT_FORMAT:
if not have_cmd("convert"):
logging.error("ERROR: required program 'convert' (for PNG output) could not be found. Exiting...")
sys.exit(1)
## kpsewhich: required for LaTeX package testing
if not have_cmd("kpsewhich"):
logging.warning("WARNING: required program 'kpsewhich' (for LaTeX package checks) could not be found")
else:
## Check minion font
if opts.OUTPUT_FONT == "MINION":
p = subprocess.Popen(["kpsewhich", "minion.sty"], stdout=subprocess.PIPE)
p.wait()
if p.returncode != 0:
logging.warning('Warning: Using "--minion" requires minion.sty to be installed. Ignoring it.')
opts.OUTPUT_FONT = "PALATINO"
## Check for HEP LaTeX packages
# TODO: remove HEP-specifics/non-standards?
for pkg in ["hepnicenames", "hepunits", "underscore"]:
p = subprocess.Popen(["kpsewhich", "%s.sty" % pkg], stdout=subprocess.PIPE)
p.wait()
if p.returncode == 0:
opts.LATEXPKGS.append(pkg)
## Check for Palatino old style figures and small caps
if opts.OUTPUT_FONT == "PALATINO":
p = subprocess.Popen(["kpsewhich", "ot1pplx.fd"], stdout=subprocess.PIPE)
p.wait()
if p.returncode == 0:
opts.OUTPUT_FONT = "PALATINO_OSF"
except Exception, e:
logging.warning("Problem while testing for external packages. I'm going to try and continue without testing, but don't hold your breath...")
## Fill queue
datfiles = Queue.Queue(maxsize=-1)
plotword = "plot"
if len(args) > 1:
plotword = "plots"
logging.info("Making %d %s" % (len(args), plotword))
for d in args:
datfiles.put(d)
## Set up signal handling
import signal
RECVD_KILL_SIGNAL = None
def handleKillSignal(signum, frame):
"Declare us as having been signalled, and return to default handling behaviour"
global RECVD_KILL_SIGNAL
logging.critical("Signal handler called with signal " + str(signum))
RECVD_KILL_SIGNAL = signum
signal.signal(signum, signal.SIG_DFL)
## Signals to handle
signal.signal(signal.SIGINT, handleKillSignal)
signal.signal(signal.SIGTERM, handleKillSignal)
signal.signal(signal.SIGHUP, handleKillSignal)
signal.signal(signal.SIGUSR2, handleKillSignal)
## Run threads
for threadnum in range(opts.NUM_THREADS):
procthread = MkPlotThread()
#procthread.daemon = True
procthread.start()
import time
while not datfiles.empty() and not RECVD_KILL_SIGNAL:
time.sleep(0.25)
diff --git a/data/anainfo/ATLAS_2015_I1345452.info b/data/anainfo/ATLAS_2015_I1345452.info
new file mode 100644
--- /dev/null
+++ b/data/anainfo/ATLAS_2015_I1345452.info
@@ -0,0 +1,54 @@
+Name: ATLAS_2015_I1345452
+Year: 2015
+Summary: Pseudo-top-antitop cross sections
+Experiment: ATLAS
+Collider: LHC
+InspireID:i 1345452
+Status: VALIDATED
+Authors:
+ - Longen Lan <llongen@physics.usyd.edu.au>
+ - Aldo Saavedra <a.saavedra@physics.usyd.edu.au>
+ - Kevin Finelli <kevin.finelli@cern.ch>
+References:
+ - arXiv:1502.05923 [hep-ex]
+RunInfo:
+ top-antitop production, reconstructed from leptons + jets final state
+Beams: [p+, p+]
+Energies: [7000]
+PtCuts: [25,25,25]
+NeedCrossSection: True
+Description:
+ 'Various differential cross-sections are measured in top-quark pair
+ ($t\bar{t}$) events produced in proton-proton collisions at a centre-of-mass
+ energy of $\sqrt{s}=7$ TeV at the LHC with the ATLAS detector. These
+ differential cross-sections are presented in a data set corresponding to an
+ integrated luminosity of 4.6 fb$^{-1}$. The differential cross-sections are
+ presented in terms of kinematic variables of a top-quark proxy referred to as
+ the pseudo-top-quark whose dependence on theoretical models is minimal. The
+ pseudo-top-quark can be defined in terms of either reconstructed detector
+ objects or stable particles in an analogous way. The measurements are
+ performed on $t\bar{t}$ events in the lepton+jets channel, requiring exactly
+ one charged lepton and at least four jets with at least two of them tagged as
+ originating from a $b$-quark. The hadronic and leptonic pseudo-top-quarks are
+ defined via the leptonic or hadronic decay mode of the W boson produced by
+ the top-quark decay in events with a single charged lepton. The cross-section
+ is measured as a function of the transverse momentum and rapidity of both the
+ hadronic and leptonic pseudo-top-quark as well as the transverse momentum,
+ rapidity and invariant mass of the pseudo-top-quark pair system. The
+ measurements are corrected for detector effects and are presented within a
+ kinematic range that closely matches the detector acceptance.'
+BibKey: Aad:2015eia
+BibTeX: '@article{Aad:2015eia,
+ author = "Aad, Georges and others",
+ title = "{Differential top-antitop cross-section measurements as a
+ function of observables constructed from final-state
+ particles using pp collisions at $\sqrt{s}=7$ TeV in the
+ ATLAS detector}",
+ collaboration = "ATLAS Collaboration",
+ year = "2015",
+ eprint = "1502.05923",
+ archivePrefix = "arXiv",
+ primaryClass = "hep-ex",
+ reportNumber = "CERN-PH-EP-2014-295",
+ SLACcitation = "%%CITATION = ARXIV:1502.05923;%%",
+}'
diff --git a/data/anainfo/Makefile.am b/data/anainfo/Makefile.am
--- a/data/anainfo/Makefile.am
+++ b/data/anainfo/Makefile.am
@@ -1,330 +1,331 @@
dist_pkgdata_DATA = \
ALEPH_1991_S2435284.info \
ALEPH_1996_S3486095.info \
ALEPH_1996_S3196992.info \
ALEPH_1999_S4193598.info \
ALEPH_2001_S4656318.info \
ALEPH_2002_S4823664.info \
ALEPH_2004_S5765862.info \
ALICE_2010_S8624100.info \
ALICE_2010_S8625980.info \
ALICE_2010_S8706239.info \
ALICE_2011_S8909580.info \
ALICE_2011_S8945144.info \
ALICE_2012_I1181770.info \
ARGUS_1993_S2653028.info \
ARGUS_1993_S2669951.info \
ARGUS_1993_S2789213.info \
ATLAS_2010_S8591806.info \
ATLAS_2010_S8817804.info \
ATLAS_2010_S8894728.info \
ATLAS_2010_S8914702.info \
ATLAS_2010_S8918562.info \
ATLAS_2010_S8919674.info \
ATLAS_2010_CONF_2010_049.info \
ATLAS_2011_S8924791.info \
ATLAS_2011_S8971293.info \
ATLAS_2011_S8983313.info \
ATLAS_2011_S8994773.info \
ATLAS_2011_S9002537.info \
ATLAS_2011_S9019561.info \
ATLAS_2011_S9041966.info \
ATLAS_2011_S9120807.info \
ATLAS_2011_S9126244.info \
ATLAS_2011_S9128077.info \
ATLAS_2011_S9131140.info \
ATLAS_2011_S9108483.info \
ATLAS_2011_S9212183.info \
ATLAS_2011_I894867.info \
ATLAS_2011_I921594.info \
ATLAS_2011_I928289_W.info \
ATLAS_2011_I928289_Z.info \
ATLAS_2011_I930220.info \
ATLAS_2011_S9035664.info \
ATLAS_2011_I919017.info \
ATLAS_2011_I925932.info \
ATLAS_2011_I926145.info \
ATLAS_2011_I944826.info \
ATLAS_2011_I945498.info \
ATLAS_2011_I954993.info \
ATLAS_2011_S9225137.info \
ATLAS_2011_S9212353.info \
ATLAS_2011_CONF_2011_090.info \
ATLAS_2011_CONF_2011_098.info \
ATLAS_2012_I943401.info \
ATLAS_2012_I946427.info \
ATLAS_2012_I1083318.info \
ATLAS_2012_I1082936.info \
ATLAS_2012_I1084540.info \
ATLAS_2012_I1093734.info \
ATLAS_2012_I1093738.info \
ATLAS_2012_I1094061.info \
ATLAS_2012_I1094564.info \
ATLAS_2012_I1094568.info \
ATLAS_2012_I1095236.info \
ATLAS_2012_I1082009.info \
ATLAS_2012_I1091481.info \
ATLAS_2012_I1119557.info \
ATLAS_2012_I1124167.info \
ATLAS_2012_I1125575.info \
ATLAS_2012_I1183818.info \
ATLAS_2012_I1188891.info \
ATLAS_2012_I1112263.info \
ATLAS_2012_I1125961.info \
ATLAS_2012_I1126136.info \
ATLAS_2012_I1117704.info \
ATLAS_2012_I1118269.info \
ATLAS_2012_I1180197.info \
ATLAS_2012_I1186556.info \
ATLAS_2012_I1190891.info \
ATLAS_2012_I1199269.info \
ATLAS_2012_I1203852.info \
ATLAS_2012_I1204447.info \
ATLAS_2012_I1204784.info \
ATLAS_2012_CONF_2012_001.info \
ATLAS_2012_CONF_2012_103.info \
ATLAS_2012_CONF_2012_104.info \
ATLAS_2012_CONF_2012_105.info \
ATLAS_2012_CONF_2012_109.info \
ATLAS_2012_CONF_2012_153.info \
ATLAS_2013_I1190187.info \
ATLAS_2013_I1217863_W.info \
ATLAS_2013_I1217863_W_EL.info \
ATLAS_2013_I1217863_W_MU.info \
ATLAS_2013_I1217863_Z.info \
ATLAS_2013_I1217863_Z_EL.info \
ATLAS_2013_I1217863_Z_MU.info \
ATLAS_2013_I1217867.info \
ATLAS_2013_I1219109.info \
ATLAS_2013_I1219109_EL.info \
ATLAS_2013_I1219109_MU.info \
ATLAS_2013_I1230812.info \
ATLAS_2013_I1230812_EL.info \
ATLAS_2013_I1230812_MU.info \
ATLAS_2013_I1243871.info \
ATLAS_2013_I1263495.info \
ATLAS_2014_I1268975.info \
ATLAS_2014_I1279489.info \
ATLAS_2014_I1282441.info \
ATLAS_2014_I1298811.info \
ATLAS_2014_I1304688.info \
ATLAS_2014_I1307756.info \
ATLAS_2014_I1306294.info \
ATLAS_2014_I1306294_EL.info \
ATLAS_2014_I1306294_MU.info \
ATLAS_2014_I1315949.info \
ATLAS_2014_I1325553.info \
ATLAS_2014_I1300647.info \
ATLAS_2014_I1288706.info \
ATLAS_2014_I1307243.info \
ATLAS_2014_I1312627.info \
ATLAS_2014_I1312627_EL.info \
ATLAS_2014_I1312627_MU.info \
ATLAS_2014_I1306615.info \
ATLAS_2015_I1364361.info \
+ ATLAS_2015_I1345452.info \
ATLAS_2013_I1216670.info \
ATLAS_2013_I1244522.info \
BABAR_2003_I593379.info \
BABAR_2005_S6181155.info \
BABAR_2007_S6895344.info \
BABAR_2007_S7266081.info \
BELLE_2008_I786560.info \
BABAR_2013_I1238276.info \
BELLE_2001_S4598261.info \
BELLE_2013_I1216515.info \
CDF_1988_S1865951.info \
CDF_1990_S2089246.info \
CDF_1993_S2742446.info \
CDF_1994_S2952106.info \
CDF_1996_S3108457.info \
CDF_1996_S3349578.info \
CDF_1996_S3418421.info \
CDF_1997_S3541940.info \
CDF_1998_S3618439.info \
CDF_2000_S4155203.info \
CDF_2000_S4266730.info \
CDF_2001_S4517016.info \
CDF_2001_S4563131.info \
CDF_2001_S4751469.info \
CDF_2002_S4796047.info \
CDF_2004_S5839831.info \
CDF_2005_S6080774.info \
CDF_2005_S6217184.info \
CDF_2006_S6450792.info \
CDF_2006_S6653332.info \
CDF_2007_S7057202.info \
CDF_2008_S7540469.info \
CDF_2008_S7541902.info \
CDF_2008_S7782535.info \
CDF_2008_S7828950.info \
CDF_2008_S8093652.info \
CDF_2008_S8095620.info \
CDF_2009_S8233977.info \
CDF_2009_NOTE_9936.info \
CDF_2009_S8383952.info \
CDF_2009_S8436959.info \
CDF_2010_S8591881_DY.info \
CDF_2010_S8591881_QCD.info \
CDF_2012_NOTE10874.info \
CLEO_2004_S5809304.info\
CMS_2010_S8547297.info \
CMS_2010_S8656010.info \
CMS_2011_S8884919.info \
CMS_2011_S9215166.info \
CMS_2012_I941555.info \
CMS_2011_I954992.info \
CMS_2011_S8941262.info \
CMS_2011_S8950903.info \
CMS_2011_S8957746.info \
CMS_2011_S8968497.info \
CMS_2011_S8973270.info \
CMS_2011_S8978280.info \
CMS_2011_S9086218.info \
CMS_2011_S9088458.info \
CMS_2011_S9120041.info \
CMS_2012_I1087342.info \
CMS_2012_I1090423.info \
CMS_2012_I1102908.info \
CMS_2012_I1107658.info \
CMS_2012_I1184941.info \
CMS_2012_I1193338.info \
CMS_2013_I1209721.info \
CMS_2013_I1218372.info \
CMS_2013_I1224539_DIJET.info \
CMS_2013_I1224539_WJET.info \
CMS_2013_I1224539_ZJET.info \
CMS_2013_I1256943.info \
CMS_2013_I1258128.info \
CMS_2013_I1261026.info \
CMS_2013_I1265659.info \
CMS_2013_I1272853.info \
CMS_2013_I1273574.info \
CMS_2014_I1298810.info \
CMS_2014_I1303894.info \
CMSTOTEM_2014_I1294140.info \
CMS_2012_PAS_QCD_11_010.info \
CMS_QCD_10_024.info \
CMS_2015_I1356998.info \
D0_1996_S3214044.info \
D0_1996_S3324664.info \
D0_2000_S4480767.info \
D0_2000_I499943.info \
D0_2001_S4674421.info \
D0_2004_S5992206.info \
D0_2006_S6438750.info \
D0_2007_S7075677.info \
D0_2008_S6879055.info \
D0_2008_S7554427.info \
D0_2008_S7662670.info \
D0_2008_S7719523.info \
D0_2008_S7837160.info \
D0_2008_S7863608.info \
D0_2009_S8202443.info \
D0_2009_S8320160.info \
D0_2009_S8349509.info \
D0_2010_S8566488.info \
D0_2010_S8570965.info \
D0_2010_S8671338.info \
D0_2010_S8821313.info \
D0_2011_I895662.info \
E735_1998_S3905616.info \
DELPHI_1995_S3137023.info \
DELPHI_1996_S3430090.info \
DELPHI_1999_S3960137.info \
DELPHI_2000_S4328825.info \
DELPHI_2002_069_CONF_603.info \
DELPHI_2003_WUD_03_11.info \
EXAMPLE.info \
EXAMPLE_CUTS.info \
H1_1994_S2919893.info \
H1_1995_S3167097.info \
H1_2000_S4129130.info \
JADE_OPAL_2000_S4300807.info \
JADE_1998_S3612880.info \
LHCB_2010_S8758301.info \
LHCB_2010_I867355.info \
LHCB_2011_I917009.info \
LHCB_2011_I919315.info \
LHCB_2012_I1119400.info \
LHCB_2012_I1208102.info \
LHCB_2013_I1208105.info \
LHCB_2013_I1218996.info \
LHCB_2014_I1281685.info \
LHCF_2012_I1115479.info \
MC_DIJET.info \
MC_DIPHOTON.info \
MC_ELECTRONS.info \
MC_GENERIC.info \
MC_HFJETS.info \
MC_HINC.info \
MC_HJETS.info \
MC_HKTSPLITTINGS.info \
MC_IDENTIFIED.info \
MC_JETS.info \
MC_JETTAGS.info \
MC_KTSPLITTINGS.info \
MC_LEADJETUE.info \
MC_MUONS.info \
MC_PDFS.info \
MC_PHOTONINC.info \
MC_PHOTONJETS.info \
MC_PHOTONKTSPLITTINGS.info \
MC_PHOTONJETUE.info \
MC_PHOTONS.info \
MC_PRINTEVENT.info \
MC_QCD_PARTONS.info \
MC_SUSY.info \
MC_TAUS.info \
MC_TTBAR.info \
MC_VH2BB.info \
MC_WINC.info \
MC_WJETS.info \
MC_WKTSPLITTINGS.info \
MC_WPOL.info \
MC_WWINC.info \
MC_WWJETS.info \
MC_WWKTSPLITTINGS.info \
MC_XS.info \
MC_ZINC.info \
MC_ZJETS.info \
MC_ZKTSPLITTINGS.info \
MC_ZZINC.info \
MC_ZZJETS.info \
MC_ZZKTSPLITTINGS.info \
OPAL_1993_S2692198.info \
OPAL_1994_S2927284.info \
OPAL_1995_S3198391.info \
OPAL_1996_S3257789.info \
OPAL_1997_S3396100.info \
OPAL_1997_S3608263.info \
OPAL_1998_S3702294.info \
OPAL_1998_S3780481.info \
OPAL_1998_S3749908.info \
OPAL_2000_S4418603.info \
OPAL_2001_S4553896.info \
OPAL_2002_S5361494.info \
OPAL_2004_S6132243.info \
PDG_HADRON_MULTIPLICITIES.info \
PDG_HADRON_MULTIPLICITIES_RATIOS.info \
PDG_TAUS.info \
SFM_1984_S1178091.info \
SLD_1996_S3398250.info \
SLD_1999_S3743934.info \
SLD_2002_S4869273.info \
SLD_2004_S5693039.info \
STAR_2006_S6500200.info \
STAR_2006_S6860818.info \
STAR_2006_S6870392.info \
STAR_2008_S7869363.info \
STAR_2008_S7993412.info \
STAR_2009_UE_HELEN.info \
TASSO_1990_S2148048.info \
TOTEM_2012_I1115294.info \
TOTEM_2012_002.info \
ZEUS_2001_S4815815.info \
UA1_1990_S2044935.info \
UA5_1982_S875503.info \
UA5_1986_S1583476.info \
UA5_1987_S1640666.info \
UA5_1988_S1867512.info \
UA5_1989_S1926373.info
diff --git a/data/plotinfo/ATLAS_2015_I1345452.plot b/data/plotinfo/ATLAS_2015_I1345452.plot
new file mode 100644
--- /dev/null
+++ b/data/plotinfo/ATLAS_2015_I1345452.plot
@@ -0,0 +1,123 @@
+# BEGIN PLOT /ATLAS_2015_I1345452/d.
+LeftMargin=1.9
+LegendXPos=0.6
+YLabelSep=8.0
+RatioPlotYMin=0.6
+RatioPlotYMax=1.8
+RatioPlotYLabel=Expected/Data
+Title=combined lepton channels
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d0[1-2].
+XLabel=$p_\text{T} (\hat{t}_\text{h})$ [GeV]
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}p_\text{T}(\hat{t}_\text{h})}$ [$\dfrac{\text{pb}}{\text{GeV}}$]
+Title=muon channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d02.
+Title=electron channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d0[3-4].
+RatioPlotYMax=1.4
+XLabel=$|y (\hat{t}_\text{h})|$
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}|y(\hat{t}_\text{h})|}$ [pb]
+Title=muon channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d04.
+Title=electron channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d0[5-6].
+XLabel=$p_\text{T} (\hat{t}_\text{l})$ [GeV]
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}p_\text{T}(\hat{t}_\text{l})}$ [$\dfrac{\text{pb}}{\text{GeV}}$]
+Title=muon channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d06.
+Title=electron channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d0[7-8].
+RatioPlotYMax=1.4
+XLabel=$|y (\hat{t}_\text{h})|$
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}|y(\hat{t}_\text{l})|}$ [pb]
+Title=muon channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d08.
+Title=electron channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d09.
+XLabel=$p_\text{T} (\hat{t}_\text{l}\hat{t}_\text{h})$ [GeV]
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}p_\text{T}(\hat{t}_\text{l}\hat{t}_\text{h})}$ [$\dfrac{\text{pb}}{\text{GeV}}$]
+Title=muon channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d10.
+XLabel=$p_\text{T} (\hat{t}_\text{l}\hat{t}_\text{h})$ [GeV]
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}p_\text{T}(\hat{t}_\text{l}\hat{t}_\text{h})}$ [$\dfrac{\text{pb}}{\text{GeV}}$]
+Title=electron channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d1[1-2].
+RatioPlotYMax=1.4
+XLabel=$|y(\hat{t}_\text{h}\hat{t}_\text{l})|$
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}|y(\hat{t}_\text{l}\hat{t}_\text{h})|}$ [pb]
+Title=muon channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d12.
+Title=electron channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d1[3-4].
+XLabel=$m (\hat{t}_\text{l}\hat{t}_\text{h})$ [GeV]
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}m(\hat{t}_\text{l}\hat{t}_\text{h})}$ [$\dfrac{\text{pb}}{\text{GeV}}$]
+Title=muon channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d14.
+Title=electron channel
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d15.
+XLabel=$p_\text{T} (\hat{t}_\text{h})$ [GeV]
+YLabel=$\dfrac{\text{d}\sigma^text{fid}}{\text{d}p_\text{T}(\hat{t}_\text{h})}$ [$\dfrac{\text{pb}}{\text{GeV}}$]
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d16.
+RatioPlotYMax=1.4
+XLabel=$|y (\hat{t}_\text{h})|$
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}|y(\hat{t}_\text{h})|}$ [pb]
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d17.
+XLabel=$p_\text{T} (\hat{t}_\text{l})$ [GeV]
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}p_\text{T}(\hat{t}_\text{l})}$ [$\dfrac{\text{pb}}{\text{GeV}}$]
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d18.
+RatioPlotYMax=1.4
+XLabel=$|y (\hat{t}_\text{h})|$
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}|y(\hat{t}_\text{l})|}$ [pb]
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d19.
+XLabel=$p_\text{T} (\hat{t}_\text{l}\hat{t}_\text{h})$ [GeV]
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}p_\text{T}(\hat{t}_\text{l} \hat{t}_\text{h})}$ [$\dfrac{\text{pb}}{\text{GeV}}$]
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d20.
+RatioPlotYMax=1.4
+XLabel=$|y (\hat{t}_\text{h}\hat{t}_\text{l})|$
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}|y(\hat{t}_\text{l}\hat{t}_\text{h})|}$ [pb]
+# END PLOT
+
+# BEGIN PLOT /ATLAS_2015_I1345452/d21.
+XLabel=$m (\hat{t}_\text{l}\hat{t}_\text{h})$ [GeV]
+YLabel=$\dfrac{\text{d}\sigma^\text{fid}}{\text{d}m(\hat{t}_\text{l} \hat{t}_\text{h})}$ [$\dfrac{\text{pb}}{\text{GeV}}$]
+# END PLOT
+
diff --git a/data/plotinfo/Makefile.am b/data/plotinfo/Makefile.am
--- a/data/plotinfo/Makefile.am
+++ b/data/plotinfo/Makefile.am
@@ -1,324 +1,325 @@
dist_pkgdata_DATA = \
ALEPH_1991_S2435284.plot \
ALEPH_1996_S3486095.plot \
ALEPH_1996_S3196992.plot \
ALEPH_1999_S4193598.plot \
ALEPH_2001_S4656318.plot \
ALEPH_2002_S4823664.plot \
ALEPH_2004_S5765862.plot \
ALICE_2010_S8624100.plot \
ALICE_2010_S8625980.plot \
ALICE_2010_S8706239.plot \
ALICE_2011_S8909580.plot \
ALICE_2011_S8945144.plot \
ALICE_2012_I1181770.plot \
ARGUS_1993_S2653028.plot \
ARGUS_1993_S2669951.plot \
ARGUS_1993_S2789213.plot \
ATLAS_2010_S8591806.plot \
ATLAS_2010_S8817804.plot \
ATLAS_2010_S8894728.plot \
ATLAS_2010_S8914702.plot \
ATLAS_2010_S8918562.plot \
ATLAS_2010_S8919674.plot \
ATLAS_2010_CONF_2010_049.plot \
ATLAS_2011_S8924791.plot \
ATLAS_2011_S8971293.plot \
ATLAS_2011_S8994773.plot \
ATLAS_2011_S9002537.plot \
ATLAS_2011_S9120807.plot \
ATLAS_2011_S9126244.plot \
ATLAS_2011_S9128077.plot \
ATLAS_2011_S9131140.plot \
ATLAS_2011_I894867.plot \
ATLAS_2011_I919017.plot \
ATLAS_2011_I921594.plot \
ATLAS_2011_I928289_W.plot \
ATLAS_2011_I928289_Z.plot \
ATLAS_2011_I925932.plot \
ATLAS_2011_I926145.plot \
ATLAS_2011_I930220.plot \
ATLAS_2011_I944826.plot \
ATLAS_2011_I945498.plot \
ATLAS_2011_I954993.plot \
ATLAS_2011_S9225137.plot \
ATLAS_2011_S9212183.plot \
ATLAS_2011_S8983313.plot \
ATLAS_2011_S9212353.plot \
ATLAS_2011_CONF_2011_090.plot \
ATLAS_2011_CONF_2011_098.plot \
ATLAS_2012_I1082936.plot \
ATLAS_2012_I1083318.plot \
ATLAS_2012_I1084540.plot \
ATLAS_2012_I1091481.plot \
ATLAS_2012_I1093734.plot \
ATLAS_2012_I1093738.plot \
ATLAS_2012_I1094061.plot \
ATLAS_2012_I1094564.plot \
ATLAS_2012_I1094568.plot \
ATLAS_2012_I1095236.plot \
ATLAS_2012_I943401.plot \
ATLAS_2012_I946427.plot \
ATLAS_2012_I1119557.plot \
ATLAS_2012_I1124167.plot \
ATLAS_2012_I1125575.plot \
ATLAS_2012_I1112263.plot \
ATLAS_2012_I1125961.plot \
ATLAS_2012_I1126136.plot \
ATLAS_2012_I1117704.plot \
ATLAS_2012_I1118269.plot \
ATLAS_2012_I1180197.plot \
ATLAS_2012_I1082009.plot \
ATLAS_2012_I1183818.plot \
ATLAS_2012_I1188891.plot \
ATLAS_2012_I1186556.plot \
ATLAS_2012_I1190891.plot \
ATLAS_2012_I1199269.plot \
ATLAS_2012_I1203852.plot \
ATLAS_2012_I1204447.plot \
ATLAS_2012_I1204784.plot \
ATLAS_2012_CONF_2012_001.plot \
ATLAS_2012_CONF_2012_103.plot \
ATLAS_2012_CONF_2012_104.plot \
ATLAS_2012_CONF_2012_105.plot \
ATLAS_2012_CONF_2012_109.plot \
ATLAS_2012_CONF_2012_153.plot \
ATLAS_2013_I1190187.plot \
ATLAS_2013_I1219109.plot \
ATLAS_2013_I1219109_EL.plot \
ATLAS_2013_I1219109_MU.plot \
ATLAS_2013_I1217863_W.plot \
ATLAS_2013_I1217863_W_EL.plot \
ATLAS_2013_I1217863_W_MU.plot \
ATLAS_2013_I1217863_Z.plot \
ATLAS_2013_I1217863_Z_EL.plot \
ATLAS_2013_I1217863_Z_MU.plot \
ATLAS_2013_I1217867.plot \
ATLAS_2013_I1230812.plot \
ATLAS_2013_I1230812_EL.plot \
ATLAS_2013_I1230812_MU.plot \
ATLAS_2013_I1243871.plot \
ATLAS_2013_I1263495.plot \
ATLAS_2014_I1268975.plot \
ATLAS_2014_I1279489.plot \
ATLAS_2014_I1282441.plot \
ATLAS_2014_I1298811.plot \
ATLAS_2014_I1304688.plot \
ATLAS_2014_I1307756.plot \
ATLAS_2014_I1306294.plot \
ATLAS_2014_I1306294_EL.plot \
ATLAS_2014_I1306294_MU.plot \
ATLAS_2014_I1315949.plot \
ATLAS_2014_I1325553.plot \
ATLAS_2014_I1300647.plot \
ATLAS_2014_I1288706.plot \
ATLAS_2014_I1307243.plot \
ATLAS_2014_I1312627.plot \
ATLAS_2014_I1312627_EL.plot \
ATLAS_2014_I1312627_MU.plot \
ATLAS_2014_I1306615.plot \
ATLAS_2015_I1364361.plot \
+ ATLAS_2015_I1345452.plot \
ATLAS_2013_I1216670.plot \
ATLAS_2013_I1244522.plot \
BABAR_2003_I593379.plot \
BABAR_2005_S6181155.plot \
BABAR_2007_S6895344.plot \
BABAR_2007_S7266081.plot \
BABAR_2013_I1238276.plot \
BELLE_2001_S4598261.plot \
BELLE_2008_I786560.plot \
BELLE_2013_I1216515.plot \
CDF_1988_S1865951.plot \
CDF_1990_S2089246.plot \
CDF_1993_S2742446.plot \
CDF_1994_S2952106.plot \
CDF_1996_S3108457.plot \
CDF_1996_S3349578.plot \
CDF_1996_S3418421.plot \
CDF_1997_S3541940.plot \
CDF_1998_S3618439.plot \
CDF_2000_S4155203.plot \
CDF_2000_S4266730.plot \
CDF_2001_S4517016.plot \
CDF_2001_S4563131.plot \
CDF_2001_S4751469.plot \
CDF_2002_S4796047.plot \
CDF_2004_S5839831.plot \
CDF_2005_S6080774.plot \
CDF_2005_S6217184.plot \
CDF_2006_S6450792.plot \
CDF_2006_S6653332.plot \
CDF_2007_S7057202.plot \
CDF_2008_S7540469.plot \
CDF_2008_S7541902.plot \
CDF_2008_S7782535.plot \
CDF_2008_S7828950.plot \
CDF_2008_S8093652.plot \
CDF_2008_S8095620.plot \
CDF_2009_S8233977.plot \
CDF_2009_NOTE_9936.plot \
CDF_2009_S8383952.plot \
CDF_2009_S8436959.plot \
CDF_2010_S8591881_DY.plot \
CDF_2010_S8591881_QCD.plot \
CDF_2012_NOTE10874.plot \
CLEO_2004_S5809304.plot \
CMS_2010_S8547297.plot \
CMS_2010_S8656010.plot \
CMS_2011_S8884919.plot \
CMS_2011_S8941262.plot \
CMS_2011_S8950903.plot \
CMS_2011_S8957746.plot \
CMS_2011_S8968497.plot \
CMS_2011_S8973270.plot \
CMS_2011_S8978280.plot \
CMS_2011_S9086218.plot \
CMS_2011_S9088458.plot \
CMS_2011_S9120041.plot \
CMS_2011_S9215166.plot \
CMS_2012_I941555.plot \
CMS_2011_I954992.plot \
CMS_2012_I1087342.plot \
CMS_2012_I1090423.plot \
CMS_2012_I1102908.plot \
CMS_2012_I1107658.plot \
CMS_2012_I1184941.plot \
CMS_2012_I1193338.plot \
CMS_2013_I1209721.plot \
CMS_2013_I1218372.plot \
CMS_2013_I1224539_DIJET.plot \
CMS_2013_I1224539_WJET.plot \
CMS_2013_I1224539_ZJET.plot \
CMS_2013_I1256943.plot \
CMS_2013_I1258128.plot \
CMS_2013_I1261026.plot \
CMS_2013_I1265659.plot \
CMS_2013_I1272853.plot \
CMS_2013_I1273574.plot \
CMS_2014_I1298810.plot \
CMS_2014_I1303894.plot \
CMSTOTEM_2014_I1294140.plot \
CMS_2012_PAS_QCD_11_010.plot \
CMS_QCD_10_024.plot \
CMS_2015_I1356998.plot \
D0_1996_S3214044.plot \
D0_1996_S3324664.plot \
D0_2000_S4480767.plot \
D0_2000_I499943.plot \
D0_2001_S4674421.plot \
D0_2004_S5992206.plot \
D0_2006_S6438750.plot \
D0_2007_S7075677.plot \
D0_2008_S6879055.plot \
D0_2008_S7554427.plot \
D0_2008_S7662670.plot \
D0_2008_S7719523.plot \
D0_2008_S7837160.plot \
D0_2008_S7863608.plot \
D0_2009_S8202443.plot \
D0_2009_S8320160.plot \
D0_2009_S8349509.plot \
D0_2010_S8566488.plot \
D0_2010_S8570965.plot \
D0_2010_S8671338.plot \
D0_2010_S8821313.plot \
D0_2011_I895662.plot \
E735_1998_S3905616.plot \
DELPHI_1995_S3137023.plot \
DELPHI_1996_S3430090.plot \
DELPHI_1999_S3960137.plot \
DELPHI_2000_S4328825.plot \
DELPHI_2002_069_CONF_603.plot \
DELPHI_2003_WUD_03_11.plot \
EXAMPLE.plot \
H1_1994_S2919893.plot \
H1_1995_S3167097.plot \
H1_2000_S4129130.plot \
JADE_OPAL_2000_S4300807.plot \
JADE_1998_S3612880.plot \
LHCB_2010_S8758301.plot \
LHCB_2010_I867355.plot \
LHCB_2011_I917009.plot \
LHCB_2011_I919315.plot \
LHCB_2012_I1119400.plot \
LHCB_2012_I1208102.plot \
LHCB_2013_I1208105.plot \
LHCB_2013_I1218996.plot \
LHCB_2014_I1281685.plot \
LHCF_2012_I1115479.plot \
MC_DIJET.plot \
MC_DIPHOTON.plot \
MC_ELECTRONS.plot \
MC_GENERIC.plot \
MC_HFJETS.plot \
MC_HINC.plot \
MC_HJETS.plot \
MC_HKTSPLITTINGS.plot \
MC_IDENTIFIED.plot \
MC_JETS.plot \
MC_JETTAGS.plot \
MC_KTSPLITTINGS.plot \
MC_LEADJETUE.plot \
MC_MUONS.plot \
MC_PDFS.plot \
MC_PHOTONINC.plot \
MC_PHOTONJETS.plot \
MC_PHOTONKTSPLITTINGS.plot \
MC_PHOTONS.plot \
MC_PHOTONJETUE.plot \
MC_QCD_PARTONS.plot \
MC_SUSY.plot \
MC_TAUS.plot \
MC_TTBAR.plot \
MC_VH2BB.plot \
MC_WINC.plot \
MC_WJETS.plot \
MC_WKTSPLITTINGS.plot \
MC_WPOL.plot \
MC_WWINC.plot \
MC_WWJETS.plot \
MC_WWKTSPLITTINGS.plot \
MC_XS.plot \
MC_ZINC.plot \
MC_ZJETS.plot \
MC_ZKTSPLITTINGS.plot \
MC_ZZINC.plot \
MC_ZZJETS.plot \
MC_ZZKTSPLITTINGS.plot \
OPAL_1993_S2692198.plot \
OPAL_1994_S2927284.plot \
OPAL_1995_S3198391.plot \
OPAL_1996_S3257789.plot \
OPAL_1997_S3396100.plot \
OPAL_1997_S3608263.plot \
OPAL_1998_S3702294.plot \
OPAL_1998_S3749908.plot \
OPAL_1998_S3780481.plot \
OPAL_2000_S4418603.plot \
OPAL_2001_S4553896.plot \
OPAL_2002_S5361494.plot \
OPAL_2004_S6132243.plot \
PDG_HADRON_MULTIPLICITIES.plot \
PDG_HADRON_MULTIPLICITIES_RATIOS.plot \
PDG_TAUS.plot \
SFM_1984_S1178091.plot \
SLD_1996_S3398250.plot \
SLD_1999_S3743934.plot \
SLD_2002_S4869273.plot \
SLD_2004_S5693039.plot \
STAR_2006_S6500200.plot \
STAR_2006_S6860818.plot \
STAR_2006_S6870392.plot \
STAR_2008_S7869363.plot \
STAR_2008_S7993412.plot \
STAR_2009_UE_HELEN.plot \
TASSO_1990_S2148048.plot \
TOTEM_2012_I1115294.plot \
TOTEM_2012_002.plot \
ZEUS_2001_S4815815.plot \
UA1_1990_S2044935.plot \
UA5_1982_S875503.plot \
UA5_1986_S1583476.plot \
UA5_1987_S1640666.plot \
UA5_1988_S1867512.plot \
UA5_1989_S1926373.plot
diff --git a/data/refdata/ATLAS_2015_I1345452.yoda b/data/refdata/ATLAS_2015_I1345452.yoda
new file mode 100644
--- /dev/null
+++ b/data/refdata/ATLAS_2015_I1345452.yoda
@@ -0,0 +1,311 @@
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d01-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d01-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+22.5 22.5 22.5 0.013 0.0012068313883886181 0.0012068313883886181
+67.5 22.5 22.5 0.031 0.0026546210652369953 0.0026546210652369953
+105.0 15.0 15.0 0.033 0.0030250399997355406 0.0030250399997355406
+135.0 15.0 15.0 0.025 0.0024752525123712126 0.0024752525123712126
+165.0 15.0 15.0 0.017 0.002032904326327238 0.002032904326327238
+200.0 20.0 20.0 0.01 0.0013188252348207477 0.0013188252348207477
+240.0 20.0 20.0 0.0057 9.180008823525172E-4 9.180008823525172E-4
+280.0 20.0 20.0 0.003 4.0477771677798673E-4 4.0477771677798673E-4
+325.0 25.0 25.0 0.0014 2.5296647999290336E-4 2.5296647999290336E-4
+575.0 225.0 225.0 1.2E-4 2.8897833828852984E-5 2.8897833828852984E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d02-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d02-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+22.5 22.5 22.5 0.013 0.0014166421566507187 0.0014166421566507187
+67.5 22.5 22.5 0.029 0.0029877038005799703 0.0029877038005799703
+105.0 15.0 15.0 0.033 0.0035313083977472144 0.0035313083977472144
+135.0 15.0 15.0 0.025 0.002923396996646196 0.002923396996646196
+165.0 15.0 15.0 0.016 0.002291521765115924 0.002291521765115924
+200.0 20.0 20.0 0.0095 0.001426487556903319 0.001426487556903319
+240.0 20.0 20.0 0.0057 8.839963122095026E-4 8.839963122095026E-4
+280.0 20.0 20.0 0.0028 4.839466086253731E-4 4.839466086253731E-4
+325.0 25.0 25.0 0.0012 3.043248264601493E-4 3.043248264601493E-4
+575.0 225.0 225.0 1.2E-4 3.979624102851926E-5 3.979624102851926E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d03-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d03-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+0.2 0.2 0.2 4.4 0.3874998838709504 0.3874998838709504
+0.6000000000000001 0.20000000000000007 0.19999999999999996 3.7 0.33894908172172417 0.33894908172172417
+0.9500000000000001 0.15000000000000002 0.15000000000000002 2.7 0.27749643240949967 0.27749643240949967
+1.25 0.1499999999999999 0.1499999999999999 1.8 0.19934542884149614 0.19934542884149614
+1.6 0.20000000000000018 0.19999999999999996 0.93 0.10221541958041361 0.10221541958041361
+2.15 0.34999999999999987 0.3500000000000001 0.13 0.022154990408483594 0.022154990408483594
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d04-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d04-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+0.2 0.2 0.2 4.3 0.5023092075604427 0.5023092075604427
+0.6000000000000001 0.20000000000000007 0.19999999999999996 3.7 0.38886982397712483 0.38886982397712483
+0.9500000000000001 0.15000000000000002 0.15000000000000002 2.7 0.3118120106730978 0.3118120106730978
+1.25 0.1499999999999999 0.1499999999999999 1.6 0.2484486264804054 0.2484486264804054
+1.6 0.20000000000000018 0.19999999999999996 0.88 0.11210937516550523 0.11210937516550523
+2.15 0.34999999999999987 0.3500000000000001 0.12 0.022587111369097197 0.022587111369097197
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d05-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d05-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+22.5 22.5 22.5 0.012 0.0012262919717587653 0.0012262919717587653
+67.5 22.5 22.5 0.029 0.0024525154433764533 0.0024525154433764533
+105.0 15.0 15.0 0.033 0.002763146575916667 0.002763146575916667
+135.0 15.0 15.0 0.026 0.0025511816869835044 0.0025511816869835044
+165.0 15.0 15.0 0.017 0.002069536179920516 0.002069536179920516
+200.0 20.0 20.0 0.011 0.0012780371669086936 0.0012780371669086936
+240.0 20.0 20.0 0.0059 8.558864644332213E-4 8.558864644332213E-4
+280.0 20.0 20.0 0.0029 4.913168326039725E-4 4.913168326039725E-4
+325.0 25.0 25.0 0.0014 2.6076479823779897E-4 2.6076479823779897E-4
+575.0 225.0 225.0 1.7E-4 3.449031458250272E-5 3.449031458250272E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d06-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d06-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+22.5 22.5 22.5 0.012 0.001385415461152358 0.001385415461152358
+67.5 22.5 22.5 0.028 0.0028025188670194536 0.0028025188670194536
+105.0 15.0 15.0 0.032 0.0032135712221763504 0.0032135712221763504
+135.0 15.0 15.0 0.026 0.0028903300849556957 0.0028903300849556957
+165.0 15.0 15.0 0.017 0.0024712059808927305 0.0024712059808927305
+200.0 20.0 20.0 0.0099 0.0015392510321581728 0.0015392510321581728
+240.0 20.0 20.0 0.0059 9.224211782044035E-4 9.224211782044035E-4
+280.0 20.0 20.0 0.0033 5.867971625698271E-4 5.867971625698271E-4
+325.0 25.0 25.0 0.0015 3.194330915857028E-4 3.194330915857028E-4
+575.0 225.0 225.0 1.2E-4 3.698259049877388E-5 3.698259049877388E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d07-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d07-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+0.2 0.2 0.2 5.1 0.4749028426952191 0.4749028426952191
+0.6000000000000001 0.20000000000000007 0.19999999999999996 3.6 0.3179433911878025 0.3179433911878025
+0.9500000000000001 0.15000000000000002 0.15000000000000002 2.3 0.2154278765619714 0.2154278765619714
+1.25 0.1499999999999999 0.1499999999999999 1.6 0.16771785832164685 0.16771785832164685
+1.6 0.20000000000000018 0.19999999999999996 0.8 0.08687278054718865 0.08687278054718865
+2.15 0.34999999999999987 0.3500000000000001 0.11 0.02373120940870903 0.02373120940870903
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d08-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d08-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+0.2 0.2 0.2 4.8 0.5903024309622992 0.5903024309622992
+0.6000000000000001 0.20000000000000007 0.19999999999999996 3.6 0.37382840983531473 0.37382840983531473
+0.9500000000000001 0.15000000000000002 0.15000000000000002 2.3 0.2587678882705503 0.2587678882705503
+1.25 0.1499999999999999 0.1499999999999999 1.6 0.20452481512031737 0.20452481512031737
+1.6 0.20000000000000018 0.19999999999999996 0.81 0.10499424841390124 0.10499424841390124
+2.15 0.34999999999999987 0.3500000000000001 0.13 0.025027616746306467 0.025027616746306467
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d09-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d09-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+12.5 12.5 12.5 0.074 0.007836316992056919 0.007836316992056919
+37.5 12.5 12.5 0.073 0.0073813072013024904 0.0073813072013024904
+67.5 17.5 17.5 0.028 0.003742270968275815 0.003742270968275815
+105.0 20.0 20.0 0.0076 0.0013865782920556634 0.0013865782920556634
+312.5 187.5 187.5 2.9E-4 7.055766152587541E-5 7.055766152587541E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d10-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d10-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+12.5 12.5 12.5 0.072 0.008180163323552899 0.008180163323552899
+37.5 12.5 12.5 0.072 0.00823007557680973 0.00823007557680973
+67.5 17.5 17.5 0.029 0.004806832012875008 0.004806832012875008
+105.0 20.0 20.0 0.0065 0.0015424734195440774 0.0015424734195440774
+312.5 187.5 187.5 2.3E-4 8.160106984592788E-5 8.160106984592788E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d11-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d11-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+0.05 0.05 0.05 6.0 0.5468564711146792 0.5468564711146792
+0.175 0.07499999999999998 0.07500000000000001 5.7 0.4991651129636365 0.4991651129636365
+0.325 0.07500000000000001 0.07500000000000001 5.3 0.4871965722375312 0.4871965722375312
+0.47500000000000003 0.07500000000000001 0.07500000000000001 4.9 0.4423318776665322 0.4423318776665322
+0.625 0.07499999999999996 0.07499999999999996 4.0 0.40282998895315625 0.40282998895315625
+0.7749999999999999 0.07499999999999996 0.07500000000000007 3.2 0.37359229114102444 0.37359229114102444
+0.925 0.07500000000000007 0.07499999999999996 2.2 0.27215164890185767 0.27215164890185767
+1.1 0.10000000000000009 0.09999999999999987 1.7 0.1811118438976314 0.1811118438976314
+1.4 0.19999999999999996 0.20000000000000018 0.7 0.08766783902891641 0.08766783902891641
+2.05 0.44999999999999973 0.4500000000000002 0.04 0.012934419198402377 0.012934419198402377
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d12-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d12-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+0.05 0.05 0.05 5.8 0.6968453199957649 0.6968453199957649
+0.175 0.07499999999999998 0.07500000000000001 5.6 0.6514559693486582 0.6514559693486582
+0.325 0.07500000000000001 0.07500000000000001 5.2 0.5896671603540425 0.5896671603540425
+0.47500000000000003 0.07500000000000001 0.07500000000000001 4.8 0.5153689164084307 0.5153689164084307
+0.625 0.07499999999999996 0.07499999999999996 4.0 0.4632407581377096 0.4632407581377096
+0.7749999999999999 0.07499999999999996 0.07500000000000007 3.0 0.3581452219421613 0.3581452219421613
+0.925 0.07500000000000007 0.07499999999999996 2.4 0.3166999842121878 0.3166999842121878
+1.1 0.10000000000000009 0.09999999999999987 1.5 0.22506998911449744 0.22506998911449744
+1.4 0.19999999999999996 0.20000000000000018 0.59 0.0985052663566776 0.0985052663566776
+2.05 0.44999999999999973 0.4500000000000002 0.038 0.012211783489728272 0.012211783489728272
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d13-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d13-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+312.5 87.5 87.5 0.0052 5.627783933308029E-4 5.627783933308029E-4
+450.0 50.0 50.0 0.015 0.0014324803663575989 0.0014324803663575989
+550.0 50.0 50.0 0.011 0.0011397082960126245 0.0011397082960126245
+650.0 50.0 50.0 0.0064 6.888552823343957E-4 6.888552823343957E-4
+775.0 75.0 75.0 0.0033 3.9246421492920863E-4 3.9246421492920863E-4
+925.0 75.0 75.0 0.0016 2.2435400598161824E-4 2.2435400598161824E-4
+1125.0 125.0 125.0 6.2E-4 9.723727063220151E-5 9.723727063220151E-5
+1875.0 625.0 625.0 5.8E-5 1.2483211605993065E-5 1.2483211605993065E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d14-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d14-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+312.5 87.5 87.5 0.0049 6.486719124488124E-4 6.486719124488124E-4
+450.0 50.0 50.0 0.014 0.0014516184071580245 0.0014516184071580245
+550.0 50.0 50.0 0.011 0.0012654303615766455 0.0012654303615766455
+650.0 50.0 50.0 0.0063 8.504533320529704E-4 8.504533320529704E-4
+775.0 75.0 75.0 0.0034 4.6371064253476003E-4 4.6371064253476003E-4
+925.0 75.0 75.0 0.0015 2.6112066176386733E-4 2.6112066176386733E-4
+1125.0 125.0 125.0 5.7E-4 1.0142957408961156E-4 1.0142957408961156E-4
+1875.0 625.0 625.0 5.6E-5 1.4352396872996514E-5 1.4352396872996514E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d15-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d15-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+22.5 22.5 22.5 0.013 0.0011017068575623916 0.0011017068575623916
+67.5 22.5 22.5 0.03 0.0024181191037663963 0.0024181191037663963
+105.0 15.0 15.0 0.033 0.0028983695416561366 0.0028983695416561366
+135.0 15.0 15.0 0.025 0.0024040330696560724 0.0024040330696560724
+165.0 15.0 15.0 0.017 0.0019927016836445944 0.0019927016836445944
+200.0 20.0 20.0 0.0096 0.0012280872933142823 0.0012280872933142823
+240.0 20.0 20.0 0.0057 8.415177003486022E-4 8.415177003486022E-4
+280.0 20.0 20.0 0.0029 3.8292081426843325E-4 3.8292081426843325E-4
+325.0 25.0 25.0 0.0014 2.500558337651813E-4 2.500558337651813E-4
+575.0 225.0 225.0 1.2E-4 2.7760749269427148E-5 2.7760749269427148E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d16-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d16-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+0.2 0.2 0.2 4.4 0.36915449340350714 0.36915449340350714
+0.6000000000000001 0.20000000000000007 0.19999999999999996 3.7 0.3226646091532197 0.3226646091532197
+0.9500000000000001 0.15000000000000002 0.15000000000000002 2.7 0.26501294308014467 0.26501294308014467
+1.25 0.1499999999999999 0.1499999999999999 1.8 0.19270931477227563 0.19270931477227563
+1.6 0.20000000000000018 0.19999999999999996 0.91 0.09561930819661896 0.09561930819661896
+2.15 0.34999999999999987 0.3500000000000001 0.13 0.020418278575825143 0.020418278575825143
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d17-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d17-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+22.5 22.5 22.5 0.012 0.0011283829137309729 0.0011283829137309729
+67.5 22.5 22.5 0.029 0.0023045422538977237 0.0023045422538977237
+105.0 15.0 15.0 0.033 0.0026377302743078187 0.0026377302743078187
+135.0 15.0 15.0 0.026 0.0024535239962144243 0.0024535239962144243
+165.0 15.0 15.0 0.017 0.00202214267548064 0.00202214267548064
+200.0 20.0 20.0 0.011 0.001243729874209026 0.001243729874209026
+240.0 20.0 20.0 0.0059 8.205243506441475E-4 8.205243506441475E-4
+280.0 20.0 20.0 0.003 4.920457295821192E-4 4.920457295821192E-4
+325.0 25.0 25.0 0.0014 2.550076077296519E-4 2.550076077296519E-4
+575.0 225.0 225.0 1.6E-4 3.3437320466807745E-5 3.3437320466807745E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d18-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d18-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+0.2 0.2 0.2 5.1 0.4437293093767866 0.4437293093767866
+0.6000000000000001 0.20000000000000007 0.19999999999999996 3.6 0.30479055103464087 0.30479055103464087
+0.9500000000000001 0.15000000000000002 0.15000000000000002 2.3 0.20576967706637436 0.20576967706637436
+1.25 0.1499999999999999 0.1499999999999999 1.6 0.163716828701267 0.163716828701267
+1.6 0.20000000000000018 0.19999999999999996 0.8 0.08380167062773869 0.08380167062773869
+2.15 0.34999999999999987 0.3500000000000001 0.12 0.020323267453832318 0.020323267453832318
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d19-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d19-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+12.5 12.5 12.5 0.073 0.00747314659296872 0.00747314659296872
+37.5 12.5 12.5 0.073 0.007139459713451712 0.007139459713451712
+67.5 17.5 17.5 0.028 0.003496077802337929 0.003496077802337929
+105.0 20.0 20.0 0.008 0.001390182721803145 0.001390182721803145
+312.5 187.5 187.5 3.1E-4 7.321843005691941E-5 7.321843005691941E-5
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d20-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d20-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+0.05 0.05 0.05 6.0 0.5235150427638159 0.5235150427638159
+0.175 0.07499999999999998 0.07500000000000001 5.7 0.4780190058983011 0.4780190058983011
+0.325 0.07500000000000001 0.07500000000000001 5.3 0.4697307207326342 0.4697307207326342
+0.47500000000000003 0.07500000000000001 0.07500000000000001 4.9 0.4238995635760905 0.4238995635760905
+0.625 0.07499999999999996 0.07499999999999996 4.0 0.38872097962420293 0.38872097962420293
+0.7749999999999999 0.07499999999999996 0.07500000000000007 3.1 0.32773612861568985 0.32773612861568985
+0.925 0.07500000000000007 0.07499999999999996 2.3 0.2641597811931256 0.2641597811931256
+1.1 0.10000000000000009 0.09999999999999987 1.7 0.17552036918830818 0.17552036918830818
+1.4 0.19999999999999996 0.20000000000000018 0.69 0.08423088625913894 0.08423088625913894
+2.05 0.44999999999999973 0.4500000000000002 0.039 0.010981876478999389 0.010981876478999389
+# END YODA_SCATTER2D
+
+
+# BEGIN YODA_SCATTER2D /REF/ATLAS_2015_I1345452/d21-x01-y02
+Path=/REF/ATLAS_2015_I1345452/d21-x01-y02
+Type=Scatter2D
+# xval xerr- xerr+ yval yerr- yerr+
+312.5 87.5 87.5 0.0052 5.464207902340466E-4 5.464207902340466E-4
+450.0 50.0 50.0 0.015 0.0013781237244892056 0.0013781237244892056
+550.0 50.0 50.0 0.011 0.0010990095540985984 0.0010990095540985984
+650.0 50.0 50.0 0.0064 6.673822293109099E-4 6.673822293109099E-4
+775.0 75.0 75.0 0.0033 3.800448263034244E-4 3.800448263034244E-4
+925.0 75.0 75.0 0.0016 2.1798788957187504E-4 2.1798788957187504E-4
+1125.0 125.0 125.0 6.1E-4 8.98896629207163E-5 8.98896629207163E-5
+1875.0 625.0 625.0 6.0E-5 1.1933515827282419E-5 1.1933515827282419E-5
+# END YODA_SCATTER2D
+
diff --git a/data/refdata/Makefile.am b/data/refdata/Makefile.am
--- a/data/refdata/Makefile.am
+++ b/data/refdata/Makefile.am
@@ -1,275 +1,276 @@
dist_pkgdata_DATA = \
ALEPH_1991_S2435284.yoda \
ALEPH_1996_S3486095.yoda \
ALEPH_1996_S3196992.yoda \
ALEPH_1999_S4193598.yoda \
ALEPH_2001_S4656318.yoda \
ALEPH_2002_S4823664.yoda \
ALEPH_2004_S5765862.yoda \
ALICE_2010_S8624100.yoda \
ALICE_2010_S8625980.yoda \
ALICE_2010_S8706239.yoda \
ALICE_2011_S8909580.yoda \
ALICE_2011_S8945144.yoda \
ALICE_2012_I1181770.yoda \
ARGUS_1993_S2653028.yoda \
ARGUS_1993_S2669951.yoda \
ARGUS_1993_S2789213.yoda \
ATLAS_2010_S8591806.yoda \
ATLAS_2010_S8817804.yoda \
ATLAS_2010_S8894728.yoda \
ATLAS_2010_S8914702.yoda \
ATLAS_2010_S8918562.yoda \
ATLAS_2010_S8919674.yoda \
ATLAS_2011_S8924791.yoda \
ATLAS_2011_S8971293.yoda \
ATLAS_2011_S8994773.yoda \
ATLAS_2011_S9002537.yoda \
ATLAS_2010_CONF_2010_049.yoda \
ATLAS_2011_S9120807.yoda \
ATLAS_2011_S9126244.yoda \
ATLAS_2011_S9128077.yoda \
ATLAS_2011_S9131140.yoda \
ATLAS_2011_I894867.yoda \
ATLAS_2011_S9035664.yoda \
ATLAS_2011_I919017.yoda \
ATLAS_2011_I921594.yoda \
ATLAS_2011_I925932.yoda \
ATLAS_2011_I926145.yoda \
ATLAS_2011_I930220.yoda \
ATLAS_2011_I944826.yoda \
ATLAS_2011_I945498.yoda \
ATLAS_2011_I954993.yoda \
ATLAS_2011_S9225137.yoda \
ATLAS_2011_S9212183.yoda \
ATLAS_2012_I1082936.yoda \
ATLAS_2012_I1083318.yoda \
ATLAS_2012_I1084540.yoda \
ATLAS_2012_I1091481.yoda \
ATLAS_2012_I1093734.yoda \
ATLAS_2012_I1093738.yoda \
ATLAS_2012_I1094061.yoda \
ATLAS_2012_I1094564.yoda \
ATLAS_2012_I1094568.yoda \
ATLAS_2012_I943401.yoda \
ATLAS_2012_I1082009.yoda \
ATLAS_2012_I1118269.yoda \
ATLAS_2012_I1119557.yoda \
ATLAS_2012_I1124167.yoda \
ATLAS_2012_I1125575.yoda \
ATLAS_2012_I1183818.yoda \
ATLAS_2012_I1188891.yoda \
ATLAS_2012_I1199269.yoda \
ATLAS_2012_CONF_2012_001.yoda \
ATLAS_2012_I1203852.yoda \
ATLAS_2012_I1204784.yoda \
ATLAS_2013_I1190187.yoda \
ATLAS_2013_I1217863_W.yoda \
ATLAS_2013_I1217863_W_EL.yoda \
ATLAS_2013_I1217863_W_MU.yoda \
ATLAS_2013_I1217863_Z.yoda \
ATLAS_2013_I1217863_Z_EL.yoda \
ATLAS_2013_I1217863_Z_MU.yoda \
ATLAS_2013_I1217867.yoda \
ATLAS_2013_I1219109.yoda \
ATLAS_2013_I1219109_EL.yoda \
ATLAS_2013_I1219109_MU.yoda \
ATLAS_2013_I1230812.yoda \
ATLAS_2013_I1230812_EL.yoda \
ATLAS_2013_I1230812_MU.yoda \
ATLAS_2013_I1243871.yoda \
ATLAS_2013_I1263495.yoda \
ATLAS_2014_I1268975.yoda \
ATLAS_2014_I1279489.yoda \
ATLAS_2014_I1282441.yoda \
ATLAS_2014_I1298811.yoda \
ATLAS_2014_I1304688.yoda \
ATLAS_2014_I1307756.yoda \
ATLAS_2014_I1306294.yoda \
ATLAS_2014_I1306294_EL.yoda \
ATLAS_2014_I1306294_MU.yoda \
ATLAS_2014_I1315949.yoda \
ATLAS_2014_I1325553.yoda \
ATLAS_2014_I1300647.yoda \
ATLAS_2014_I1288706.yoda \
ATLAS_2014_I1307243.yoda \
ATLAS_2014_I1312627.yoda \
ATLAS_2014_I1312627_EL.yoda \
ATLAS_2014_I1312627_MU.yoda \
ATLAS_2014_I1306615.yoda \
ATLAS_2015_I1364361.yoda \
+ ATLAS_2015_I1345452.yoda \
ATLAS_2013_I1216670.yoda \
ATLAS_2013_I1244522.yoda \
ATLAS_2011_I928289_W.yoda \
ATLAS_2011_I928289_Z.yoda \
BABAR_2003_I593379.yoda \
BABAR_2005_S6181155.yoda \
BABAR_2006_S6511112.yoda \
BABAR_2007_S6895344.yoda \
BABAR_2007_S7266081.yoda \
BELLE_2001_S4598261.yoda \
BELLE_2008_I786560.yoda \
BELLE_2013_I1216515.yoda \
BABAR_2013_I1238276.yoda \
CLEO_2001_S4557530.yoda \
CLEO_2004_S5809304.yoda \
CMS_2010_S8547297.yoda \
CMS_2010_S8656010.yoda \
CMS_2011_S8884919.yoda \
CMS_2011_S8941262.yoda \
CMS_2011_S8950903.yoda \
CMS_2011_S8957746.yoda \
CMS_2011_S8968497.yoda \
CMS_2011_S8973270.yoda \
CMS_2011_S8978280.yoda \
CMS_2011_S9086218.yoda \
CMS_2011_S9088458.yoda \
CMS_2011_S9120041.yoda \
CMS_2011_S9215166.yoda \
CMS_2012_I941555.yoda \
CMS_2011_I954992.yoda \
CMS_2012_I1087342.yoda \
CMS_2012_I1090423.yoda \
CMS_2012_I1102908.yoda \
CMS_2012_I1107658.yoda \
CMS_2012_I1184941.yoda \
CMS_2012_I1193338.yoda \
CMS_2013_I1209721.yoda \
CMS_2013_I1218372.yoda \
CMS_2013_I1224539_DIJET.yoda \
CMS_2013_I1224539_WJET.yoda \
CMS_2013_I1224539_ZJET.yoda \
CMS_2013_I1256943.yoda \
CMS_2013_I1258128.yoda \
CMS_2013_I1261026.yoda \
CMS_2013_I1265659.yoda \
CMS_2013_I1272853.yoda \
CMS_2013_I1273574.yoda \
CMS_2014_I1298810.yoda \
CMS_2014_I1303894.yoda \
CMS_2015_I1356998.yoda \
CMSTOTEM_2014_I1294140.yoda \
CMS_2012_PAS_QCD_11_010.yoda \
CMS_QCD_10_024.yoda \
LHCB_2010_S8758301.yoda \
LHCB_2010_I867355.yoda \
LHCB_2011_I917009.yoda \
LHCB_2011_I919315.yoda \
LHCB_2012_I1119400.yoda \
LHCB_2012_I1208102.yoda \
LHCB_2013_I1208105.yoda \
LHCB_2013_I1218996.yoda \
LHCB_2014_I1281685.yoda \
LHCF_2012_I1115479.yoda \
DELPHI_1994_S3021912.yoda \
DELPHI_1995_S3137023.yoda \
DELPHI_1996_S3430090.yoda \
DELPHI_1999_S3960137.yoda \
DELPHI_2000_S4328825.yoda \
DELPHI_2002_069_CONF_603.yoda \
DELPHI_2003_WUD_03_11.yoda \
OPAL_1993_S2692198.yoda \
OPAL_1994_S2927284.yoda \
OPAL_1995_S3198391.yoda \
OPAL_1996_S3257789.yoda \
OPAL_1997_S3396100.yoda \
OPAL_1997_S3608263.yoda \
OPAL_1998_S3702294.yoda \
OPAL_1998_S3780481.yoda \
OPAL_1998_S3749908.yoda \
OPAL_2000_S4418603.yoda \
OPAL_2001_S4553896.yoda \
OPAL_2002_S5361494.yoda \
OPAL_2004_S6132243.yoda \
JADE_OPAL_2000_S4300807.yoda \
JADE_1998_S3612880.yoda \
TASSO_1990_S2148048.yoda \
H1_1994_S2919893.yoda \
H1_1995_S3167097.yoda \
H1_2000_S4129130.yoda \
H1_2007_S7223935.yoda \
ZEUS_2001_S4815815.yoda \
PHENIX_2003_S5538505.yoda \
STAR_2006_S6500200.yoda \
STAR_2006_S6860818.yoda \
STAR_2006_S6870392.yoda \
STAR_2008_S7993412.yoda \
STAR_2009_UE_HELEN.yoda \
BRAHMS_2007_S7052448.yoda \
UA1_1990_S2044935.yoda \
UA5_1982_S875503.yoda \
UA5_1986_S1583476.yoda \
UA5_1989_S1926373.yoda \
UA5_1988_S1867512.yoda \
UA5_1987_S1640666.yoda \
CDF_1988_S1865951.yoda \
CDF_1990_S2089246.yoda \
CDF_1993_S2742446.yoda \
CDF_1994_S2952106.yoda \
CDF_1996_S3108457.yoda \
CDF_1996_S3349578.yoda \
CDF_1996_S3418421.yoda \
CDF_1997_S3541940.yoda \
CDF_1998_S3618439.yoda \
CDF_2000_S4155203.yoda \
CDF_2000_S4266730.yoda \
CDF_2001_S4517016.yoda \
CDF_2001_S4563131.yoda \
CDF_2001_S4751469.yoda \
CDF_2002_S4796047.yoda \
CDF_2004_S5839831.yoda \
CDF_2005_S6080774.yoda \
CDF_2005_S6217184.yoda \
CDF_2006_S6450792.yoda \
CDF_2006_S6653332.yoda \
CDF_2007_S7057202.yoda \
CDF_2008_S7541902.yoda \
CDF_2008_S7554427.yoda \
CDF_2008_S7540469.yoda \
CDF_2008_S7782535.yoda \
CDF_2008_S7828950.yoda \
CDF_2008_S8093652.yoda \
CDF_2008_S8095620.yoda \
CDF_2009_S8233977.yoda \
CDF_2009_NOTE_9936.yoda \
CDF_2009_S8383952.yoda \
CDF_2009_S8436959.yoda \
CDF_2010_S8591881_DY.yoda \
CDF_2010_S8591881_QCD.yoda \
CDF_2012_NOTE10874.yoda \
D0_1996_S3214044.yoda \
D0_1996_S3324664.yoda \
D0_2000_S4480767.yoda \
D0_2000_I499943.yoda \
D0_2001_S4674421.yoda \
D0_2004_S5992206.yoda \
D0_2006_S6438750.yoda \
D0_2007_S7075677.yoda \
D0_2008_S6879055.yoda \
D0_2008_S7554427.yoda \
D0_2008_S7662670.yoda \
D0_2008_S7719523.yoda \
D0_2008_S7837160.yoda \
D0_2008_S7863608.yoda \
D0_2009_S8202443.yoda \
D0_2009_S8320160.yoda \
D0_2009_S8349509.yoda \
D0_2010_S8566488.yoda \
D0_2010_S8570965.yoda \
D0_2010_S8671338.yoda \
D0_2010_S8821313.yoda \
D0_2011_I895662.yoda \
E735_1992_S2485869.yoda \
E735_1993_S2896508.yoda \
E735_1998_S3905616.yoda \
SFM_1984_S1178091.yoda \
SLD_1996_S3398250.yoda \
SLD_1999_S3743934.yoda \
SLD_2002_S4869273.yoda \
SLD_2004_S5693039.yoda \
STAR_2008_S7869363.yoda \
TOTEM_2012_I1115294.yoda \
TOTEM_2012_002.yoda \
PDG_HADRON_MULTIPLICITIES.yoda \
PDG_HADRON_MULTIPLICITIES_RATIOS.yoda \
PDG_TAUS.yoda
diff --git a/src/Analyses/ATLAS_2015_I1345452.cc b/src/Analyses/ATLAS_2015_I1345452.cc
new file mode 100644
--- /dev/null
+++ b/src/Analyses/ATLAS_2015_I1345452.cc
@@ -0,0 +1,287 @@
+// -*- C++ -*-
+#include "Rivet/Analysis.hh"
+#include "Rivet/Projections/FinalState.hh"
+#include "Rivet/Projections/VetoedFinalState.hh"
+#include "Rivet/Projections/IdentifiedFinalState.hh"
+#include "Rivet/Projections/PromptFinalState.hh"
+#include "Rivet/Projections/DressedLeptons.hh"
+#include "Rivet/Projections/FastJets.hh"
+
+namespace Rivet {
+
+ /// @brief ATLAS 7 TeV pseudo-top analysis
+ ///
+ /// @author K .Finelli <kevin.finelli@cern.ch>
+ /// @author A. Saavedra <a.saavedra@physics.usyd.edu.au>
+ /// @author L. Lan <llan@physics.usyd.edu.au>
+ class ATLAS_2015_I1345452 : public Analysis {
+ public:
+
+ /// Constructor
+ ATLAS_2015_I1345452()
+ : Analysis("ATLAS_2015_I1345452")
+ {
+ setNeedsCrossSection(true);
+ }
+
+
+ void init() {
+ // Eta ranges
+ Cut eta_full = (Cuts::abseta < 5.0) & (Cuts::pT >= 1.0*MeV);
+ Cut eta_lep = (Cuts::abseta < 2.5);
+
+ // All final state particles
+ FinalState fs(eta_full);
+
+ // Get photons to dress leptons
+ IdentifiedFinalState photons(fs);
+ photons.acceptIdPair(PID::PHOTON);
+
+ // Projection to find the electrons
+ IdentifiedFinalState el_id(fs);
+ el_id.acceptIdPair(PID::ELECTRON);
+
+ PromptFinalState electrons(el_id);
+ electrons.acceptTauDecays(true);
+ addProjection(electrons, "electrons");
+
+ DressedLeptons dressedelectrons(photons, electrons, 0.1, eta_lep & (Cuts::pT >= 25.0*GeV), true, true);
+ addProjection(dressedelectrons, "dressedelectrons");
+
+ DressedLeptons ewdressedelectrons(photons, electrons, 0.1, eta_full, true, true);
+ addProjection(ewdressedelectrons, "ewdressedelectrons");
+
+ DressedLeptons vetodressedelectrons(photons, electrons, 0.1, eta_lep & (Cuts::pT >= 15.0*GeV), true, true);
+ addProjection(vetodressedelectrons, "vetodressedelectrons");
+
+ // Projection to find the muons
+ IdentifiedFinalState mu_id(fs);
+ mu_id.acceptIdPair(PID::MUON);
+ PromptFinalState muons(mu_id);
+ muons.acceptTauDecays(true);
+ addProjection(muons, "muons");
+ DressedLeptons dressedmuons(photons, muons, 0.1, eta_lep & (Cuts::pT >= 25.0*GeV), true, true);
+ addProjection(dressedmuons, "dressedmuons");
+ DressedLeptons ewdressedmuons(photons, muons, 0.1, eta_full, true, true);
+ addProjection(ewdressedmuons, "ewdressedmuons");
+ DressedLeptons vetodressedmuons(photons, muons, 0.1, eta_lep & (Cuts::pT >= 15.0*GeV), true, true);
+ addProjection(vetodressedmuons, "vetodressedmuons");
+
+ // Projection to find neutrinos and produce MET
+ IdentifiedFinalState nu_id;
+ nu_id.acceptNeutrinos();
+ PromptFinalState neutrinos(nu_id);
+ neutrinos.acceptTauDecays(true);
+ addProjection(neutrinos, "neutrinos");
+
+ // Jet clustering.
+ VetoedFinalState vfs;
+ vfs.addVetoOnThisFinalState(ewdressedelectrons);
+ vfs.addVetoOnThisFinalState(ewdressedmuons);
+ vfs.addVetoOnThisFinalState(neutrinos);
+ FastJets jets(vfs, FastJets::ANTIKT, 0.4);
+ jets.useInvisibles();
+ addProjection(jets, "jets");
+
+ //pseudotop leptons and hadrons
+ _h["ptpseudotophadron_mu"] = bookHisto1D( 1, 1, 2);
+ _h["ptpseudotophadron_el"] = bookHisto1D( 2, 1, 2);
+ _h["absrappseudotophadron_mu"] = bookHisto1D( 3, 1, 2);
+ _h["absrappseudotophadron_el"] = bookHisto1D( 4, 1, 2);
+ _h["ptpseudotoplepton_mu"] = bookHisto1D( 5, 1, 2);
+ _h["ptpseudotoplepton_el"] = bookHisto1D( 6, 1, 2);
+ _h["absrappseudotoplepton_mu"] = bookHisto1D( 7, 1, 2);
+ _h["absrappseudotoplepton_el"] = bookHisto1D( 8, 1, 2);
+ _h["ptttbar_mu"] = bookHisto1D( 9, 1, 2);
+ _h["ptttbar_el"] = bookHisto1D(10, 1, 2);
+ _h["absrapttbar_mu"] = bookHisto1D(11, 1, 2);
+ _h["absrapttbar_el"] = bookHisto1D(12, 1, 2);
+ _h["ttbarmass_mu"] = bookHisto1D(13, 1, 2);
+ _h["ttbarmass_el"] = bookHisto1D(14, 1, 2);
+ _h["ptpseudotophadron"] = bookHisto1D(15, 1, 2);
+ _h["absrappseudotophadron"] = bookHisto1D(16, 1, 2);
+ _h["ptpseudotoplepton"] = bookHisto1D(17, 1, 2);
+ _h["absrappseudotoplepton"] = bookHisto1D(18, 1, 2);
+ _h["ptttbar"] = bookHisto1D(19, 1, 2);
+ _h["absrapttbar"] = bookHisto1D(20, 1, 2);
+ _h["ttbarmass"] = bookHisto1D(21, 1, 2);
+
+ }
+
+ void analyze(const Event& event) {
+
+ // Get the selected objects, using the projections.
+ _dressedelectrons = applyProjection<DressedLeptons>( event, "dressedelectrons").dressedLeptons();
+ _vetodressedelectrons = applyProjection<DressedLeptons>( event, "vetodressedelectrons").dressedLeptons();
+ _dressedmuons = applyProjection<DressedLeptons>( event, "dressedmuons").dressedLeptons();
+ _vetodressedmuons = applyProjection<DressedLeptons>( event, "vetodressedmuons").dressedLeptons();
+ _neutrinos = applyProjection<PromptFinalState>(event, "neutrinos").particlesByPt();
+ const Jets& all_jets = applyProjection<FastJets>( event, "jets").jetsByPt(Cuts::pT > 25.0*GeV && Cuts::abseta < 2.5);
+
+ //get true l+jets events by removing events with more than 1 electron||muon neutrino
+ unsigned int n_elmu_neutrinos = 0;
+ foreach (const Particle p, _neutrinos) {
+ if (p.abspid() == 12 || p.abspid() == 14) ++n_elmu_neutrinos;
+ }
+ if (n_elmu_neutrinos != 1) vetoEvent;
+
+ DressedLepton *lepton;
+ if ( _dressedelectrons.size()) lepton = &_dressedelectrons[0];
+ else if (_dressedmuons.size()) lepton = &_dressedmuons[0];
+ else vetoEvent;
+
+ // Calculate the missing ET, using the prompt neutrinos only (really?)
+ /// @todo Why not use MissingMomentum?
+ FourMomentum met;
+ foreach (const Particle& p, _neutrinos) met += p.momentum();
+
+ //remove jets if they are within dR < 0.2 of lepton
+ Jets jets;
+ foreach(const Jet& jet, all_jets) {
+ bool keep = true;
+ foreach (const DressedLepton& el, _vetodressedelectrons) {
+ keep &= deltaR(jet, el) >= 0.2;
+ }
+ if (keep) jets += jet;
+ }
+
+ bool overlap = false;
+ Jets bjets, lightjets;
+ for (unsigned int i = 0; i < jets.size(); ++i) {
+ const Jet& jet = jets[i];
+ foreach (const DressedLepton& el, _dressedelectrons) overlap |= deltaR(jet, el) < 0.4;
+ foreach (const DressedLepton& mu, _dressedmuons) overlap |= deltaR(jet, mu) < 0.4;
+ for (unsigned int j = i + 1; j < jets.size(); ++j) {
+ overlap |= deltaR(jet, jets[j]) < 0.5;
+ }
+ // Count the number of b-tags
+ if ( !jet.bTags().empty() ) bjets += jet;
+ else lightjets += jet;
+ }
+
+ // remove events with object overlap
+ if (overlap) vetoEvent;
+
+ if (bjets.size() < 2 || lightjets.size() < 2) vetoEvent;
+
+ FourMomentum pbjet1; //Momentum of bjet1
+ FourMomentum pbjet2; //Momentum of bjet2
+ if ( deltaR(bjets[0], *lepton) <= deltaR(bjets[1], *lepton) ) {
+ pbjet1 = bjets[0].momentum();
+ pbjet2 = bjets[1].momentum();
+ } else {
+ pbjet1 = bjets[1].momentum();
+ pbjet2 = bjets[0].momentum();
+ }
+
+ FourMomentum pjet1; // Momentum of jet1
+ if (lightjets.size()) pjet1 = lightjets[0].momentum();
+
+ FourMomentum pjet2; // Momentum of jet 2
+ if (lightjets.size() > 1) pjet2 = lightjets[1].momentum();
+
+ double pz = computeneutrinoz(lepton->momentum(), met);
+ FourMomentum ppseudoneutrino( sqrt(sqr(met.px()) + sqr(met.py()) + sqr(pz)), met.px(), met.py(), pz);
+
+ //compute leptonic, hadronic, combined pseudo-top
+ FourMomentum ppseudotoplepton = lepton->momentum() + ppseudoneutrino + pbjet1;
+ FourMomentum ppseudotophadron = pbjet2 + pjet1 + pjet2;
+ FourMomentum pttbar = ppseudotoplepton + ppseudotophadron;
+
+ // Evaluate basic event selection
+ bool pass_eljets = (_dressedelectrons.size() == 1) &&
+ (_vetodressedelectrons.size() < 2) &&
+ (_vetodressedmuons.empty()) &&
+ (met.pT() > 30*GeV) &&
+ (_mT(_dressedelectrons[0].momentum(), met) > 35*GeV) &&
+ (jets.size() >= 4);
+ bool pass_mujets = (_dressedmuons.size() == 1) &&
+ (_vetodressedmuons.size() < 2) &&
+ (_vetodressedelectrons.empty()) &&
+ (met.pT() > 30*GeV) &&
+ (_mT(_dressedmuons[0].momentum(), met) > 35*GeV) &&
+ (jets.size() >= 4);
+
+ // basic event selection requirements
+ if (!pass_eljets && !pass_mujets) vetoEvent;
+
+ // Fill histograms
+ const double weight = event.weight();
+
+ //pseudotop hadrons and leptons fill histogram
+ _h["ptpseudotoplepton"]->fill( ppseudotoplepton.pt(), weight); //pT of pseudo top lepton
+ _h["absrappseudotoplepton"]->fill(ppseudotoplepton.absrap(), weight); //absolute rapidity of pseudo top lepton
+ _h["ptpseudotophadron"]->fill( ppseudotophadron.pt(), weight); //pT of pseudo top hadron
+ _h["absrappseudotophadron"]->fill(ppseudotophadron.absrap(), weight); //absolute rapidity of pseudo top hadron
+ _h["absrapttbar"]->fill( pttbar.absrap(), weight); //absolute rapidity of ttbar
+ _h["ttbarmass"]->fill( pttbar.mass(), weight); //mass of ttbar
+ _h["ptttbar"]->fill( pttbar.pt(), weight); //fill pT of ttbar in combined channel
+
+ if (pass_eljets) { // electron channel fill histogram
+ _h["ptpseudotoplepton_el"]->fill( ppseudotoplepton.pt(), weight); //pT of pseudo top lepton
+ _h["absrappseudotoplepton_el"]->fill(ppseudotoplepton.absrap(), weight); //absolute rapidity of pseudo top lepton
+ _h["ptpseudotophadron_el"]->fill( ppseudotophadron.pt(), weight); //pT of pseudo top hadron
+ _h["absrappseudotophadron_el"]->fill(ppseudotophadron.absrap(), weight); //absolute rapidity of pseudo top hadron
+ _h["absrapttbar_el"]->fill( pttbar.absrap(), weight); //absolute rapidity of ttbar
+ _h["ttbarmass_el"]->fill( pttbar.mass(), weight); // fill electron channel ttbar mass
+ _h["ptttbar_el"]->fill( pttbar.pt(), weight); //fill pT of ttbar in electron channel
+ }
+ else { // muon channel fill histogram
+ _h["ptpseudotoplepton_mu"]->fill( ppseudotoplepton.pt(), weight); //pT of pseudo top lepton
+ _h["absrappseudotoplepton_mu"]->fill(ppseudotoplepton.absrap(), weight); //absolute rapidity of pseudo top lepton
+ _h["ptpseudotophadron_mu"]->fill( ppseudotophadron.pt(), weight); //pT of pseudo top hadron
+ _h["absrappseudotophadron_mu"]->fill(ppseudotophadron.absrap(), weight); //absolute rapidity of pseudo top hadron
+ _h["absrapttbar_mu"]->fill( pttbar.absrap(), weight); //absolute rapidity of ttbar
+ _h["ttbarmass_mu"]->fill( pttbar.mass(), weight); //fill muon channel histograms
+ _h["ptttbar_mu"]->fill( pttbar.pt(), weight); //fill pT of ttbar in electron channel
+ }
+ }
+
+ void finalize() {
+ // Normalize to cross-section
+ const double scalefactor(crossSection() / sumOfWeights());
+ for (map<string, Histo1DPtr>::iterator hit = _h.begin(); hit != _h.end(); ++hit) {
+ double sf = scalefactor;
+ if ( (hit->first).find("_") == std::string::npos ) sf *= 0.5;
+ scale(hit->second, sf);
+ }
+ }
+
+ private:
+
+
+ double computeneutrinoz(const FourMomentum& lepton, FourMomentum& met) const {
+ //computing z component of neutrino momentum given lepton and met
+ double pzneutrino;
+ double m_W = 80.399; // in GeV, given in the paper
+ double k = (( sqr( m_W ) - sqr( lepton.mass() ) ) / 2 ) + (lepton.px() * met.px() + lepton.py() * met.py());
+ double a = sqr ( lepton.E() )- sqr ( lepton.pz() );
+ double b = -2*k*lepton.pz();
+ double c = sqr( lepton.E() ) * sqr( met.pT() ) - sqr( k );
+ double discriminant = sqr(b) - 4 * a * c;
+ double quad[2] = { (- b - sqrt(discriminant)) / (2 * a), (- b + sqrt(discriminant)) / (2 * a) }; //two possible quadratic solns
+ if (discriminant < 0) pzneutrino = - b / (2 * a); //if the discriminant is negative
+ else { //if the discriminant is greater than or equal to zero, take the soln with smallest absolute value
+ double absquad[2];
+ for (int n=0; n<2; ++n) absquad[n] = fabs(quad[n]);
+ if (absquad[0] < absquad[1]) pzneutrino = quad[0];
+ else pzneutrino = quad[1];
+ }
+ if ( !std::isfinite(pzneutrino) ) std::cout << "Found non-finite value" << std::endl;
+ return pzneutrino;
+ }
+
+ double _mT(const FourMomentum &l, FourMomentum &nu) const {
+ return sqrt( 2 * l.pT() * nu.pT() * (1 - cos(deltaPhi(l, nu))) );
+ }
+
+ /// @name Objects that are used by the event selection decisions
+ vector<DressedLepton> _dressedelectrons, _vetodressedelectrons, _dressedmuons, _vetodressedmuons;
+ Particles _neutrinos;
+ map<string, Histo1DPtr> _h;
+ };
+
+ // The hook for the plugin system
+ DECLARE_RIVET_PLUGIN(ATLAS_2015_I1345452);
+
+}
diff --git a/src/Analyses/Makefile.am b/src/Analyses/Makefile.am
--- a/src/Analyses/Makefile.am
+++ b/src/Analyses/Makefile.am
@@ -1,458 +1,459 @@
## Flags for building all plugins
AM_LDFLAGS = $(LDFLAGS) -module -avoid-version -L$(FASTJETLIBPATH)
LIBS = $(FASTJETCONFIGLIBADD)
lib_LTLIBRARIES =
noinst_LTLIBRARIES = libRivetAnalysisTools.la
libRivetAnalysisTools_la_SOURCES = \
MC_ParticleAnalysis.cc \
MC_JetAnalysis.cc \
MC_JetSplittings.cc
## ANALYSIS CATEGORIES
##
## Unvalidated analyses: add new standard analyses here, and only
## move them into the collider-specific standard plugin libraries
## once they have been finished and checked. The --enable-unvalidated
## flag is needed to install the unvalidated analyses.
##
## Preliminary analyses: validated analyses whose experimental paper has not
## been fully accepted for publication should go here. Analyses in this group
## are considered safe to use but the reference data may yet change. In
## progressing from preliminary status to a permanent published analyses
## collection, the analysis name is very likely to change, so you should ensure
## that any Rivet-using scripts are not broken by such name changes when
## upgrading between Rivet versions. These analyses will not be available if
## Rivet is built with the --disable-preliminary configure flag.
##
## Obsolete analyses: as mentioned above, when a preliminary analysis becomes
## permanent its name will change to reflect its newly published status via the
## publication's SPIRES ID. The previous form of the analysis, possibly with
## different reference histograms, will be retained for one major version of
## Rivet with a status of "obsolete" before being removed, to give users time to
## migrate their run scripts, i.e. if an analysis is marked as obsolete in
## version 1.4.2, it will remain in Rivet's distribution until version
## 1.5.0. Obsolete analyses will not be available if Rivet is built with the
## --disable-obsolete configure flag.
if ENABLE_ANALYSES
lib_LTLIBRARIES += RivetALICEAnalyses.la
RivetALICEAnalyses_la_SOURCES = \
ALICE_2010_S8624100.cc \
ALICE_2010_S8625980.cc \
ALICE_2010_S8706239.cc \
ALICE_2011_S8909580.cc \
ALICE_2011_S8945144.cc \
ALICE_2012_I1181770.cc
lib_LTLIBRARIES += RivetATLASAnalyses.la
RivetATLASAnalyses_la_SOURCES = \
ATLAS_2010_S8591806.cc \
ATLAS_2010_S8817804.cc \
ATLAS_2010_S8894728.cc \
ATLAS_2010_S8914702.cc \
ATLAS_2010_S8918562.cc \
ATLAS_2010_S8919674.cc \
ATLAS_2011_S8924791.cc \
ATLAS_2011_S8971293.cc \
ATLAS_2011_S8994773.cc \
ATLAS_2011_S8983313.cc \
ATLAS_2011_S9002537.cc \
ATLAS_2011_S9120807.cc \
ATLAS_2011_S9126244.cc \
ATLAS_2011_S9128077.cc \
ATLAS_2011_S9131140.cc \
ATLAS_2011_S9212183.cc \
ATLAS_2011_S9225137.cc \
ATLAS_2011_S9019561.cc \
ATLAS_2011_I894867.cc \
ATLAS_2011_I919017.cc \
ATLAS_2011_I921594.cc \
ATLAS_2011_I925932.cc \
ATLAS_2011_I926145.cc \
ATLAS_2011_I930220.cc \
ATLAS_2011_I944826.cc \
ATLAS_2011_I945498.cc \
ATLAS_2011_I954993.cc \
ATLAS_2011_I928289_W.cc \
ATLAS_2011_I928289_Z.cc \
ATLAS_2012_I943401.cc \
ATLAS_2012_I1082936.cc \
ATLAS_2012_I1083318.cc \
ATLAS_2012_I1084540.cc \
ATLAS_2012_I1091481.cc \
ATLAS_2012_I1093734.cc \
ATLAS_2012_I1093738.cc \
ATLAS_2012_I1094564.cc \
ATLAS_2012_I1094568.cc \
ATLAS_2012_I1112263.cc \
ATLAS_2012_I1117704.cc \
ATLAS_2012_I1118269.cc \
ATLAS_2012_I1119557.cc \
ATLAS_2012_I1124167.cc \
ATLAS_2012_I1125575.cc \
ATLAS_2012_I1125961.cc \
ATLAS_2012_I1183818.cc \
ATLAS_2012_I1188891.cc \
ATLAS_2012_I1199269.cc \
ATLAS_2012_I1203852.cc \
ATLAS_2012_I1204447.cc \
ATLAS_2012_I1204784.cc \
ATLAS_2013_I1190187.cc \
ATLAS_2013_I1217867.cc \
ATLAS_2013_I1219109.cc \
ATLAS_2013_I1230812.cc \
ATLAS_2013_I1243871.cc \
ATLAS_2013_I1263495.cc \
ATLAS_2014_I1268975.cc \
ATLAS_2014_I1279489.cc \
ATLAS_2014_I1282441.cc \
ATLAS_2014_I1298811.cc \
ATLAS_2014_I1304688.cc \
ATLAS_2014_I1307756.cc \
ATLAS_2014_I1306294.cc \
ATLAS_2014_I1315949.cc \
ATLAS_2014_I1325553.cc \
ATLAS_2014_I1300647.cc \
ATLAS_2014_I1288706.cc \
ATLAS_2014_I1307243.cc \
ATLAS_2014_I1312627.cc \
ATLAS_2013_I1217863_W.cc \
ATLAS_2013_I1217863_Z.cc \
ATLAS_2014_I1306615.cc \
ATLAS_2013_I1216670.cc \
ATLAS_2013_I1244522.cc \
+ ATLAS_2015_I1345452.cc \
ATLAS_2015_I1364361.cc
if ENABLE_PRELIMINARY
RivetATLASAnalyses_la_SOURCES += \
ATLAS_2012_CONF_2012_001.cc
endif
if ENABLE_UNVALIDATED
RivetATLASAnalyses_la_SOURCES += \
ATLAS_2010_CONF_2010_049.cc \
ATLAS_2011_S9041966.cc \
ATLAS_2011_CONF_2011_090.cc \
ATLAS_2011_CONF_2011_098.cc \
ATLAS_2011_S9108483.cc \
ATLAS_2011_S9212353.cc \
ATLAS_2011_S9035664.cc \
ATLAS_2012_I1095236.cc \
ATLAS_2012_I1082009.cc \
ATLAS_2012_I946427.cc \
ATLAS_2012_I1126136.cc \
ATLAS_2012_I1180197.cc \
ATLAS_2012_I1186556.cc \
ATLAS_2012_I1190891.cc \
ATLAS_2012_CONF_2012_103.cc \
ATLAS_2012_CONF_2012_104.cc \
ATLAS_2012_CONF_2012_105.cc \
ATLAS_2012_CONF_2012_109.cc \
ATLAS_2012_CONF_2012_153.cc
endif
lib_LTLIBRARIES += RivetCMSAnalyses.la
RivetCMSAnalyses_la_SOURCES = \
CMS_2010_S8547297.cc \
CMS_2010_S8656010.cc \
CMS_2011_S8884919.cc \
CMS_2011_S8941262.cc \
CMS_2011_S8950903.cc \
CMS_2011_S8957746.cc \
CMS_2011_S8968497.cc \
CMS_2011_S8973270.cc \
CMS_2011_S8978280.cc \
CMS_2011_S9086218.cc \
CMS_2011_S9088458.cc \
CMS_2011_S9120041.cc \
CMS_2011_S9215166.cc \
CMS_2012_I941555.cc \
CMS_2011_I954992.cc \
CMS_2012_I1087342.cc \
CMS_2012_I1090423.cc \
CMS_2012_I1102908.cc \
CMS_2012_I1107658.cc \
CMS_2012_I1184941.cc \
CMS_2012_I1193338.cc \
CMS_2013_I1209721.cc \
CMS_2013_I1218372.cc \
CMS_2013_I1224539_DIJET.cc \
CMS_2013_I1224539_WJET.cc \
CMS_2013_I1224539_ZJET.cc \
CMS_2013_I1256943.cc \
CMS_2013_I1258128.cc \
CMS_2013_I1261026.cc \
CMS_2013_I1265659.cc \
CMS_2013_I1272853.cc \
CMS_2013_I1273574.cc \
CMS_2014_I1298810.cc \
CMS_2014_I1303894.cc \
CMSTOTEM_2014_I1294140.cc \
CMS_2015_I1356998.cc
if ENABLE_PRELIMINARY
RivetCMSAnalyses_la_SOURCES += \
CMS_QCD_10_024.cc \
CMS_2012_PAS_QCD_11_010.cc
endif
lib_LTLIBRARIES += RivetLHCbAnalyses.la
RivetLHCbAnalyses_la_SOURCES = \
LHCB_2010_I867355.cc \
LHCB_2012_I1208102.cc \
LHCB_2013_I1218996.cc \
LHCB_2013_I1208105.cc \
LHCB_2014_I1281685.cc
if ENABLE_UNVALIDATED
RivetLHCbAnalyses_la_SOURCES += \
LHCB_2010_S8758301.cc \
LHCB_2011_I917009.cc \
LHCB_2011_I919315.cc \
LHCB_2012_I1119400.cc
endif
lib_LTLIBRARIES += RivetLHCfAnalyses.la
RivetLHCfAnalyses_la_SOURCES = \
LHCF_2012_I1115479.cc
lib_LTLIBRARIES += RivetTOTEMAnalyses.la
RivetTOTEMAnalyses_la_SOURCES = \
TOTEM_2012_I1115294.cc \
TOTEM_2012_002.cc # TODO: update to Inspire ID
lib_LTLIBRARIES += RivetCDFAnalyses.la
RivetCDFAnalyses_la_SOURCES = \
CDF_1988_S1865951.cc \
CDF_1990_S2089246.cc \
CDF_1994_S2952106.cc \
CDF_1996_S3418421.cc \
CDF_1998_S3618439.cc \
CDF_2000_S4155203.cc \
CDF_2000_S4266730.cc \
CDF_2001_S4517016.cc \
CDF_2001_S4563131.cc \
CDF_2001_S4751469.cc \
CDF_2002_S4796047.cc \
CDF_2004_S5839831.cc \
CDF_2005_S6080774.cc \
CDF_2005_S6217184.cc \
CDF_2006_S6450792.cc \
CDF_2006_S6653332.cc \
CDF_2007_S7057202.cc \
CDF_2008_S7540469.cc \
CDF_2008_S7828950.cc \
CDF_2008_S8093652.cc \
CDF_2008_S8095620.cc \
CDF_2009_S8233977.cc \
CDF_2009_S8383952.cc \
CDF_2009_S8436959.cc \
CDF_2010_S8591881_DY.cc \
CDF_2010_S8591881_QCD.cc
if ENABLE_PRELIMINARY
RivetCDFAnalyses_la_SOURCES += \
CDF_2009_NOTE_9936.cc \
CDF_2012_NOTE10874.cc
endif
# if ENABLE_OBSOLETE
# RivetCDFAnalyses_la_SOURCES +=
# endif
if ENABLE_UNVALIDATED
RivetCDFAnalyses_la_SOURCES += \
CDF_1993_S2742446.cc \
CDF_1996_S3108457.cc \
CDF_1996_S3349578.cc \
CDF_1997_S3541940.cc \
CDF_2008_S7541902.cc \
CDF_2008_S7782535.cc
endif
lib_LTLIBRARIES += RivetD0Analyses.la
RivetD0Analyses_la_SOURCES = \
D0_2000_S4480767.cc \
D0_2000_I499943.cc \
D0_2001_S4674421.cc \
D0_2004_S5992206.cc \
D0_2006_S6438750.cc \
D0_2007_S7075677.cc \
D0_2008_S6879055.cc \
D0_2008_S7554427.cc \
D0_2008_S7662670.cc \
D0_2008_S7719523.cc \
D0_2008_S7837160.cc \
D0_2008_S7863608.cc \
D0_2009_S8202443.cc \
D0_2009_S8320160.cc \
D0_2009_S8349509.cc \
D0_2010_S8566488.cc \
D0_2010_S8570965.cc \
D0_2010_S8671338.cc \
D0_2010_S8821313.cc \
D0_2011_I895662.cc
if ENABLE_UNVALIDATED
RivetD0Analyses_la_SOURCES += \
D0_1996_S3214044.cc \
D0_1996_S3324664.cc
endif
lib_LTLIBRARIES += RivetHERAAnalyses.la
RivetHERAAnalyses_la_SOURCES = \
H1_1994_S2919893.cc \
H1_2000_S4129130.cc
if ENABLE_UNVALIDATED
RivetHERAAnalyses_la_SOURCES += \
H1_1995_S3167097.cc \
ZEUS_2001_S4815815.cc
endif
lib_LTLIBRARIES += RivetPetraAnalyses.la
RivetPetraAnalyses_la_SOURCES = \
JADE_1998_S3612880.cc \
TASSO_1990_S2148048.cc
lib_LTLIBRARIES += RivetLEPAnalyses.la
RivetLEPAnalyses_la_SOURCES = \
ALEPH_1991_S2435284.cc \
ALEPH_1996_S3486095.cc \
ALEPH_1996_S3196992.cc \
ALEPH_1999_S4193598.cc \
ALEPH_2001_S4656318.cc \
ALEPH_2002_S4823664.cc \
ALEPH_2004_S5765862.cc \
DELPHI_1995_S3137023.cc \
DELPHI_1996_S3430090.cc \
DELPHI_1999_S3960137.cc \
DELPHI_2000_S4328825.cc \
OPAL_1994_S2927284.cc \
OPAL_1995_S3198391.cc \
OPAL_1996_S3257789.cc \
OPAL_1997_S3396100.cc \
OPAL_1997_S3608263.cc \
OPAL_1998_S3702294.cc \
OPAL_1998_S3749908.cc \
OPAL_1998_S3780481.cc \
OPAL_2000_S4418603.cc \
OPAL_2001_S4553896.cc \
OPAL_2002_S5361494.cc \
OPAL_2004_S6132243.cc \
SLD_1996_S3398250.cc \
SLD_1999_S3743934.cc \
SLD_2002_S4869273.cc \
SLD_2004_S5693039.cc
if ENABLE_PRELIMINARY
RivetLEPAnalyses_la_SOURCES += \
DELPHI_2002_069_CONF_603.cc
endif
if ENABLE_UNVALIDATED
RivetLEPAnalyses_la_SOURCES += \
OPAL_1993_S2692198.cc \
DELPHI_2003_WUD_03_11.cc
endif
lib_LTLIBRARIES += RivetRHICAnalyses.la
RivetRHICAnalyses_la_SOURCES = \
STAR_2006_S6500200.cc \
STAR_2006_S6860818.cc \
STAR_2006_S6870392.cc
if ENABLE_PRELIMINARY
RivetRHICAnalyses_la_SOURCES += \
STAR_2009_UE_HELEN.cc
endif
if ENABLE_UNVALIDATED
RivetRHICAnalyses_la_SOURCES += \
STAR_2008_S7869363.cc \
STAR_2008_S7993412.cc
endif
lib_LTLIBRARIES += RivetSPSAnalyses.la
RivetSPSAnalyses_la_SOURCES = \
UA1_1990_S2044935.cc \
UA5_1982_S875503.cc \
UA5_1986_S1583476.cc \
UA5_1987_S1640666.cc \
UA5_1988_S1867512.cc \
UA5_1989_S1926373.cc
lib_LTLIBRARIES += RivetMiscAnalyses.la
RivetMiscAnalyses_la_SOURCES = \
PDG_HADRON_MULTIPLICITIES.cc \
PDG_HADRON_MULTIPLICITIES_RATIOS.cc \
PDG_TAUS.cc \
JADE_OPAL_2000_S4300807.cc \
ARGUS_1993_S2653028.cc \
ARGUS_1993_S2669951.cc \
ARGUS_1993_S2789213.cc \
BABAR_2003_I593379.cc \
BABAR_2005_S6181155.cc \
BABAR_2007_S6895344.cc \
BABAR_2007_S7266081.cc \
BABAR_2013_I1238276.cc \
BELLE_2001_S4598261.cc \
BELLE_2008_I786560.cc \
BELLE_2013_I1216515.cc \
CLEO_2004_S5809304.cc
if ENABLE_UNVALIDATED
RivetMiscAnalyses_la_SOURCES += \
E735_1998_S3905616.cc \
SFM_1984_S1178091.cc
endif
lib_LTLIBRARIES += RivetMCAnalyses.la
RivetMCAnalyses_la_SOURCES = \
EXAMPLE.cc \
EXAMPLE_CUTS.cc \
MC_QCD_PARTONS.cc \
MC_DIPHOTON.cc \
MC_ELECTRONS.cc \
MC_GENERIC.cc \
MC_HINC.cc \
MC_HJETS.cc \
MC_HKTSPLITTINGS.cc \
MC_IDENTIFIED.cc \
MC_JETS.cc \
MC_JETTAGS.cc \
MC_HFJETS.cc \
MC_LEADJETUE.cc \
MC_MUONS.cc \
MC_PDFS.cc \
MC_PHOTONINC.cc \
MC_PHOTONJETS.cc \
MC_PHOTONKTSPLITTINGS.cc \
MC_PHOTONS.cc \
MC_PRINTEVENT.cc \
MC_SUSY.cc \
MC_TTBAR.cc \
MC_VH2BB.cc \
MC_WINC.cc \
MC_WJETS.cc \
MC_WKTSPLITTINGS.cc \
MC_WPOL.cc \
MC_WWINC.cc \
MC_WWJETS.cc \
MC_WWKTSPLITTINGS.cc \
MC_XS.cc \
MC_ZINC.cc \
MC_ZJETS.cc \
MC_ZKTSPLITTINGS.cc \
MC_ZZINC.cc \
MC_ZZJETS.cc \
MC_ZZKTSPLITTINGS.cc
if ENABLE_UNVALIDATED
RivetMCAnalyses_la_SOURCES += \
MC_DIJET.cc \
MC_PHOTONJETUE.cc
endif
endif

File Metadata

Mime Type
text/x-diff
Expires
Tue, Nov 19, 5:31 PM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3805401
Default Alt Text
(201 KB)

Event Timeline