import logging, argparse, os, sys, re, math, random
import numpy as np
from fnmatch import fnmatch
from collections import OrderedDict
from .utils import getWorkDirs, checkSymLink, getEnergy4Key, getMassRangesSums
from ..ccsgp.ccsgp import make_plot
from ..ccsgp.utils import getOpts
from ..ccsgp.config import default_colors
from pymodelfit import LinearModel
from uncertainties import ufloat
from decimal import Decimal
dataIMRfit_style = 'with lines lc %s lw 4 lt 1' % default_colors[-2]
cocktailIMRfit_style = 'with lines lc %s lw 4 lt 2' % default_colors[-2]
pseudo_point = np.array([ [-1,1e-7,0,0,1] ])
def truncated_gaus(r, mu, sig):
while 1:
x = r.gauss(mu, sig)
if x > 0: return x
def particleLabel4Key(k):
if k == 'pion': return '{/Symbol \160}^0 {/Symbol \256} e^{+}e^{-}{/Symbol \147}'
if k == 'eta': return '{/Symbol \150} {/Symbol \256} e^{+}e^{-}{/Symbol \147}'
if k == 'etap': return '{/Symbol \150}\' {/Symbol \256} e^{+}e^{-}{/Symbol \147}'
if k == 'omega': return '{/Symbol \167} {/Symbol \256} e^{+}e^{-}({/Symbol \160})'
if k == 'phi': return '{/Symbol \146} {/Symbol \256} e^{+}e^{-}({/Symbol \150})'
if k == 'jpsi': return 'J/{/Symbol \171} {/Symbol \256} e^{+}e^{-}'
if k == 'ccbar':
return 'c@^{/=18-}c {/Symbol \256} D/{/Symbol \514} {/Symbol \256} e^{+}e^{-}'
return k
[docs]def gp_stack(version, energies, inclMed, inclFits):
"""example for a plot w/ stacked graphs using QM12 data (see gp_panel)
* how to omit keys from the legend
* manually add legend entries
* automatically plot arrows for error bars larger than data point value
.. image:: pics/stackQM12.png
:width: 550px
:param version: plot version / input subdir name
:type version: str
"""
inclMed = (inclMed and version != 'QM12')
inclFits = (inclFits and version == 'LatestPatrickJieYi')
cocktail_style = 'with filledcurves pt 0 lc %s lw 4 lt 1' % default_colors[8]
medium_style = 'with lines lc %s lw 4 lt 2' % default_colors[4]
if inclMed:
medium_style = 'with filledcurves pt 0 lc %s lw 4 lt 2' % default_colors[4]
shift = {
'200': 200., '62': 25., '39': 2., '27': 0.03, '19': 2e-3
} if (
version != 'QM12' and version != 'Latest19200_PatrickQM12' and version != 'QM12Latest200'
) else {
'200': 200., '62': 20., '39': 1., '19': 0.05
}
inDir, outDir = getWorkDirs()
inDir = os.path.join(inDir, version)
data, cocktail, medium = OrderedDict(), OrderedDict(), OrderedDict()
dataIMRfit, cocktailIMRfit, dataTvsS = OrderedDict(), OrderedDict(), OrderedDict()
cocktailContribs, medOnly, qgpOnly = OrderedDict(), OrderedDict(), OrderedDict()
linmod = LinearModel()
rangeIMR = [1.15, 2.5]
nPtsMC = 1000 # number of MC points per data point
cRanges = map(Decimal, ['0.', '0.1'])
pi0yld = {}
for filename in os.listdir(inDir):
file_url = os.path.join(inDir, filename)
# take care of cocktail contributions first
if os.path.isdir(file_url):
for fn in os.listdir(file_url):
energy = re.compile('\d+').search(fn).group()
particle = re.sub('%s\.dat' % energy, '', fn)
if version == 'QM14' and energy == '19' and particle == 'jpsi': continue
cocktailContribs[particle] = np.loadtxt(open(
os.path.join(file_url, fn), 'rb'
))
if particle == 'omega' or particle == 'phi' or particle == 'ccbar':
thr = 0.95 if particle == 'omega' else 1.4
if particle == 'ccbar': thr = 2.6
mask = cocktailContribs[particle][:,0] < thr
cocktailContribs[particle] = cocktailContribs[particle][mask]
cocktailContribs[particle][:,(1,3,4)] *= shift[energy]
cocktailContribs[particle][:,2:] = 0
continue
# normal input files
energy = re.compile('\d+').search(filename).group()
data_type = re.sub('%s\.dat' % energy, '', filename)
data_import = np.array([[-1, 1, 0, 0, 0]]) if (
energies is not None and energy not in energies
) else np.loadtxt(open(file_url, 'rb'))
# fit IMR region with exp(-M/kT+C)
if (
inclFits and energies is None and
(data_type == 'data' or data_type == 'cocktail')
):
# data in IMR
mask = (data_import[:,0] > rangeIMR[0]) & (data_import[:,0] < rangeIMR[1])
dataIMR = data_import[mask]
# exp fit in IMR region -> slope parameter
mIMR, bIMR = linmod.fitErrxy(
dataIMR[:,0], np.log10(dataIMR[:,1]), dataIMR[:,2],
np.log10(dataIMR[:,3]) # TODO: include syst. uncertainties
)
slope_par = -1./mIMR
logging.info('%s: m = %g , b = %g => T = %g' % (filename, mIMR, bIMR, slope_par))
# Monte-Carlo the datapoints within dx/dy -> parameter mean & std.dev.
slope_par_err = 0.
if data_type == 'data':
# one random generator per x,y for each data point in IMR
rndm = OrderedDict((ax,[]) for ax in ['x','y'])
rndm_jump = 0
dataMC = OrderedDict((n, []) for n in xrange(nPtsMC))
for i,dp in enumerate(dataIMR): # for each datapoint
logging.info(('MC %d: x = {}, y = {}' % i).format(
ufloat(dp[0], dp[2]), ufloat(dp[1], dp[3]) # TODO: syst. uncertainties
))
for ax in rndm: # for each axis
rndm[ax].append(random.Random())
if ax == 'y' and i == 0: # jumpahead y-axis
rndm[ax][i].setstate(rndm['x'][i].getstate())
rndm[ax][i].jumpahead(nPtsMC)
if i > 0: # jumpahead within axes
rndm[ax][i].setstate(rndm[ax][i-1].getstate())
rndm[ax][i].jumpahead(nPtsMC)
for n in xrange(nPtsMC): # generate nPtsMC new points for current datapoint
dataMC[n].append([
rndm['x'][i].uniform(dp[0] - dp[2], dp[0] + dp[2]),
truncated_gaus(rndm['y'][i], dp[1], dp[3])
])
#logging.info(' %d: x = %g, y = %g' % (n, dataMC[n][i][0], dataMC[n][i][1]))
mIMRMC = []
for dp in dataMC.itervalues():
dp = np.array(dp)
mIMRMC.append([
linmod.fitBasic(dp[:,0], np.log10(dp[:,1]))[0][0],
linmod.stdData(x=dp[:,0], y=np.log10(dp[:,1]))
])
mIMRMC = np.array(mIMRMC)
weights = 1./mIMRMC[:,1]
mIMRMC_avg = np.average(mIMRMC[:,0], weights=weights)
mIMRMC_var = np.average((mIMRMC[:,0]-mIMRMC_avg)**2, weights=weights)
umIMR = ufloat(mIMRMC_avg, math.sqrt(mIMRMC_var))
slope_par_err = abs(math.sqrt(mIMRMC_var)/mIMRMC_avg * slope_par)
logging.info(('=> %g == {} => err = %g' % (mIMR, slope_par_err)).format(umIMR))
# set IMR slope datapoint
IMRfit = np.array([ [x, math.pow(10.,mIMR*x+bIMR), 0., 0., 0.] for x in rangeIMR ])
IMRfit[:,(1,3,4)] *= shift[energy]
if data_type == 'data': dataIMRfit[energy] = IMRfit
else: cocktailIMRfit[energy] = IMRfit
# fill array for T vs sqrt(s) plot
dp = [ float(getEnergy4Key(energy)), slope_par, 0., slope_par_err, 0. ]
if data_type in dataTvsS: dataTvsS[data_type].append(dp)
else: dataTvsS[data_type] = [ dp ]
if data_type != '+medium':
pi0yld['_'.join([energy,data_type])] = getMassRangesSums(
np.copy(data_import), customRanges = cRanges , singleRange = True
)
# function changes syst. uncertainties of input numpy array
# following scaling is wrong for y < 0 && shift != 1
data_import[:,(1,3,4)] *= shift[energy]
if fnmatch(filename, 'data*'):
data[energy] = data_import
elif fnmatch(filename, 'cocktail*'):
data_import[:,(2,3)] = 0 # don't plot dx,dy for cocktail
if inclMed:
for di in data_import:
if (energy != '200' and di[0] < 1.07) or (energy == '200' and di[0] < 0.95):
di[4] = 0 # don't plot dy2 for cocktail
if energy == '19' and (version == 'QM12' or version == 'QM14'):
# cut off cocktail above 1.1 GeV/c^2
cocktail[energy] = data_import[data_import[:,0] < 1.5]
else:
cocktail[energy] = data_import
elif inclMed and fnmatch(filename, '+medium*'):
data_import[:,(2,3)] = 0 # don't plot dx, dy1 for medium
medium[energy] = data_import[data_import[:,0] < 1.07]
elif inclMed and fnmatch(filename, 'medium*Only39.dat'):
data_import[:,2:] = 0 # don't plot any errors
if fnmatch(filename, '*Qgp*'): qgpOnly[energy] = data_import[data_import[:,0] < 1.07]
if fnmatch(filename, '*Med*'): medOnly[energy] = data_import[data_import[:,0] < 1.07]
# calculate data-to-cocktail scaling factors in pi0 region < 0.1 GeV/c2
# cocktail/data
if version == 'LatestPatrickJieYi' or version == 'QM14':
scale = {}
for e in ['19', '27', '39', '62' ]:
scale[e] = (pi0yld[e+'_cocktail'] / pi0yld[e+'_data']).nominal_value
scale['200'] = 1.
for k in cocktail:
if k != '19': cocktail[k][:,(1,3,4)] /= scale[k]
for k in medium:
if k != '19': medium[k][:,(1,3,4)] /= scale[k]
for k in medOnly:
if k != '19': medOnly[k][:,(1,3,4)] /= scale[k]
for k in qgpOnly:
if k != '19': qgpOnly[k][:,(1,3,4)] /= scale[k]
print scale
# ordered
dataOrdered = OrderedDict(
(' '.join([
getEnergy4Key(k), 'GeV', '{/Symbol \264} %g' % shift[k],
' STAR Preliminary' if version == 'QM12Latest200' and k == '39' else '',
' [arXiv:1312.7397]' if version == 'QM12Latest200' and k == '200' else ''
]), data[k]) for k in sorted(data, key=int)
)
cocktailOrdered = OrderedDict((k, cocktail[k]) for k in sorted(cocktail, key=int))
mediumOrdered = OrderedDict((k, medium[k]) for k in sorted(medium, key=int))
dataIMRfitOrdered = OrderedDict((k, dataIMRfit[k]) for k in sorted(dataIMRfit, key=int))
cocktailIMRfitOrdered = OrderedDict((k, cocktailIMRfit[k]) for k in sorted(cocktailIMRfit, key=int))
nSetsData, nSetsCocktail, nSetsMedium = len(dataOrdered), len(cocktail), len(medium)
nSetsDataIMRfit, nSetsCocktailIMRfit = len(dataIMRfitOrdered), len(cocktailIMRfitOrdered)
nSetsCocktailContribs, nSetsModelOnly = len(cocktailContribs), len(qgpOnly) + len(medOnly)
yr_low = 3e-7 if version == 'QM12' else 1e-7
if version == 'Latest19200_PatrickQM12': yr_low = 1e-7
if version == 'QM12Latest200': yr_low = 2e-6
make_plot(
data = cocktailContribs.values()
+ cocktailOrdered.values() + ([ pseudo_point ] if inclMed else [])
+ qgpOnly.values() + medOnly.values()
+ mediumOrdered.values() + [ pseudo_point ] + dataOrdered.values()
+ dataIMRfitOrdered.values() + ([ pseudo_point ] if inclFits else [])
+ cocktailIMRfitOrdered.values() + ([ pseudo_point ] if inclFits else []),
properties = [
'with lines lc %s lw 4 lt 3' % default_colors[-i-2]
for i in xrange(nSetsCocktailContribs)
] + [ cocktail_style ] * (nSetsCocktail+1)
+ [
'with lines lc %s lw 4 lt 2' % default_colors[-i-16] for i in xrange(nSetsModelOnly)
] * (nSetsModelOnly/2)
+ [ medium_style ] * (nSetsMedium+bool(nSetsMedium)) + [
'lt 1 lw 4 ps 1.5 lc %s pt 18' % default_colors[i]
for i in xrange(nSetsData)
] + [ dataIMRfit_style ] * (nSetsDataIMRfit+1)
+ [ cocktailIMRfit_style ] * (nSetsCocktailIMRfit+1),
titles = [ particleLabel4Key(k) for k in cocktailContribs.keys() ]
+ [''] * nSetsCocktail + ['Cocktail w/o {/Symbol \162}']
+ ['QGP', 'in-Medium'] * bool(nSetsModelOnly)
+ [''] * nSetsMedium + ['Cocktail + Model'] * bool(nSetsMedium) + dataOrdered.keys()
+ [''] * nSetsDataIMRfit + [''] * inclFits
+ [''] * nSetsCocktailIMRfit + [''] * inclFits,
name = os.path.join(outDir, 'stack%s%s%s%s' % (
version, 'InclMed' if inclMed else '', 'InclFits' if inclFits else '',
'_' + '-'.join(energies) if energies is not None else ''
)),
ylabel = '1/N@_{mb}^{evt} dN@_{ee}^{acc.}/dM_{ee} [ (GeV/c^2)^{-1} ]',
xlabel = 'dielectron invariant mass, M_{ee} (GeV/c^{2})',
ylog = True, xr = [0, 3.2], yr = [yr_low, 1.7e3],
lmargin = 0.14, rmargin = 0.99, bmargin = 0.08, arrow_offset = 0.8,
#tmargin = 0.9 if version != 'QM12Latest200' else 0.99,
key = [
'width -6.3', 'maxrows 7', 'font ",21"', 'samplen 0.5'#, 'spacing 0.9'
] if version != 'QM12Latest200' else [
'width -14', 'maxcols 1'
],
labels = {
'BES: STAR Preliminary': [0.4,0.75,False],
'200 GeV: PRL 113 022301': [0.4,0.71,False],
#'{/Symbol=50 \775}': [0.64,0.81 if not inclMed else 0.75,False]
} if version == 'QM12Latest200' or version == 'QM14' else {},
size = '11in,13in',
#arrows = [ # example arrow
# [ [2.4, 5e-5], [2.3, 1e-5], 'head filled lc 1 lw 4 lt 1 front' ],
#],
)
if inclFits:
for t in dataTvsS: dataTvsS[t].sort(key=lambda x: x[0])
make_plot(
data = [ np.array(dataTvsS['cocktail']), np.array(dataTvsS['data']) ],
properties = [
'with lines lt 2 lw 4 lc %s' % default_colors[0],
'lt 1 lw 4 ps 1.5 lc %s pt 18' % default_colors[0]
],
titles = [ 'cocktail', 'data' ],
name = os.path.join(outDir, 'IMRslope%s' % version),
xlabel = '{/Symbol \326}s_{NN} (GeV)',
ylabel = 'Slope Parameter T [log(dN/dM) = -M/T+C] (GeV/c^{2})',
lmargin = 0.1, xlog = True, yr = [0,3.5], gpcalls = [
'format x "%g"',
'xtics (20,"" 30, 40,"" 50, 60,"" 70,"" 80,"" 90, 100, 200)',
]
)
return 'done'
if __name__ == '__main__':
checkSymLink()
parser = argparse.ArgumentParser()
parser.add_argument("version", help="version = subdir name of input dir")
parser.add_argument("--energies", nargs='*', help="list of energies to plot (for animation)")
parser.add_argument("--med", help="include medium calculations", action="store_true")
parser.add_argument("--fit", help="include IMR fits", action="store_true")
parser.add_argument("--log", help="show log output", action="store_true")
args = parser.parse_args()
loglevel = 'DEBUG' if args.log else 'WARNING'
logging.basicConfig(
format='%(message)s', level=getattr(logging, loglevel)
)
print gp_stack(args.version, args.energies, args.med, args.fit)