"""
.. module:: slhaPrinter
:synopsis: Class for describing a printer in SLHA format
.. moduleauthor:: Andre Lessa <lessa.a.p@gmail.com>
"""
from __future__ import print_function
import os
from smodels.matching.theoryPrediction import TheoryPredictionList,TheoryPrediction,TheoryPredictionsCombiner
from smodels.tools.ioObjects import OutputStatus
from smodels.tools.coverage import Uncovered
from smodels.base.physicsUnits import GeV, fb, TeV
from smodels.base.smodelsLogging import logger
from smodels.tools.printers.txtPrinter import TxTPrinter
import numpy as np
import unum
[docs]class SLHAPrinter(TxTPrinter):
"""
Printer class to handle the printing of slha format summary output.
It uses the facilities of the TxTPrinter.
"""
def __init__(self, output='file', filename=None, outputFormat='current'):
TxTPrinter.__init__(self, output, filename, outputFormat)
self.name = "slha"
self.docompress = 0
self.combinesr = 0
self.combineanas = 0
self.printingOrder = [OutputStatus, TheoryPredictionList,
TheoryPredictionsCombiner,
TheoryPrediction, Uncovered]
self.toPrint = [None]*len(self.printingOrder)
[docs] def setOutPutFile(self, filename, overwrite=True, silent=False):
"""
Set the basename for the text printer. The output filename will be
filename.smodels.
:param filename: Base filename
:param overwrite: If True and the file already exists, it will be removed.
:param silent: dont comment removing old files
"""
self.filename = filename + '.smodelsslha'
if overwrite and os.path.isfile(self.filename):
if not silent:
logger.warning("Removing old output file " + self.filename)
os.remove(self.filename)
def _formatOutputStatus(self, obj):
smodelsversion = obj.smodelsVersion
if not smodelsversion.startswith("v"):
smodelsversion = "v" + smodelsversion
keysDict = {0: "%-25s #SModelS version\n" % (smodelsversion),
1: "%-25s #database version\n" % (obj.databaseVersion.replace(" ", "")),
2: "%-25s #maximum condition violation\n" % (obj.parameters['maxcond']),
3: "%-25s #compression (0 off, 1 on)\n" % (self.docompress),
4: "%-25s #minimum mass gap for mass compression [GeV]\n" % (obj.parameters['minmassgap']),
5: "%-25s #sigmacut [fb]\n" % (obj.parameters['sigmacut']),
6: "%-25s #signal region combination (0 off, 1 on)\n" % (self.combinesr),
7: "%-25s #analyses combination (0 off, 1 on)\n" % (self.combineanas)}
if 'promptwidth' in obj.parameters:
keysDict[8] = "%-25s #prompt width [GeV] \n" % (obj.parameters['promptwidth'])
if 'stablewidth' in obj.parameters:
keysDict[9] = "%-25s #stable width [GeV] \n" % (obj.parameters['stablewidth'])
output = "BLOCK SModelS_Settings\n"
for key in sorted(list(keysDict.keys())):
output += " %i %s" % (key, keysDict[key])
output += '\n'
# for SLHA output we always want to have SModelS_Exclusion block, if no results we write it here
if obj.status <= 0:
output += "BLOCK SModelS_Exclusion\n"
output += " 0 0 %-30s #output status (-1 not tested, 0 not excluded, 1 excluded)\n\n" % (-1)
return output
def _formatTheoryPredictionList(self, obj):
printAll = True # Controls which theory predictions are printed
if hasattr(self, "expandedoutput") and not self.expandedoutput:
printAll = False
output = "BLOCK SModelS_Exclusion\n"
if not obj._theoryPredictions[0]:
excluded = -1
else:
obj.sortTheoryPredictions()
firstResult = obj._theoryPredictions[0]
r = firstResult.getRValue()
excluded = 0
if r is not None and r > 1:
excluded = 1
output += " 0 0 %-30s #output status (-1 not tested, 0 not excluded, 1 excluded)\n" % (
excluded)
if excluded == -1:
rList = []
elif not printAll:
rList = [firstResult] + [res for res in obj._theoryPredictions[1:]
if (res.getRValue() is not None
and res.getRValue() >= 1.0)]
else:
rList = obj._theoryPredictions[:]
for iTP, theoPred in enumerate(rList):
cter = iTP + 1
expResult = theoPred.expResult
txnames = theoPred.txnames
signalRegion = theoPred.dataId()
if signalRegion is None:
signalRegion = '(UL)'
r = theoPred.getRValue()
r_expected = theoPred.getRValue(expected=self.getTypeOfExpected())
txnameStr = str(sorted(list(set([str(tx) for tx in txnames]))))
txnameStr = txnameStr.replace(
"'", "").replace("[", "").replace("]", "")
output += " %d 0 %-30s #txname \n" % (cter, txnameStr)
if r is not None:
output += " %d 1 %-30.3E #r value\n" % (cter, r)
else:
output += " %d 1 NaN #r value (failed to compute r-value)\n" % (cter)
if not r_expected:
output += " %d 2 N/A #expected r value\n" % (cter) # r_expected could fail or simply not be available
else:
output += " %d 2 %-30.3E #expected r value\n" % (
cter, r_expected)
output += " %d 3 %-30.2f #condition violation\n" % (
cter, theoPred.getmaxCondition())
output += " %d 4 %-30s #analysis\n" % (cter,
expResult.globalInfo.id)
output += " %d 5 %-30s #signal region \n" % (
cter, signalRegion.replace(" ", "_"))
nll = theoPred.likelihood( return_nll = True )
if nll is not None:
nllmin = theoPred.lmax(return_nll=True)
nllsm = theoPred.lsm( return_nll=True )
lvals = [nll, nllmin, nllsm]
for i, lv in enumerate(lvals):
if isinstance(lv, (float, np.float64)):
lv = "%-30.2E" % lv
else:
lv = str(lv)
lvals[i] = lv
nll, nllmin, nllsm = lvals[:]
output += " %d 6 %s #nll\n" % (cter, nll)
output += " %d 7 %s #nll_min\n" % (cter, nllmin)
output += " %d 8 %s #nll_SM\n" % (cter, nllsm)
else:
output += " %d 6 N/A #nll\n" % (
cter)
output += " %d 7 N/A #nll_min\n" % (
cter)
output += " %d 8 N/A #nll_SM\n" % (
cter)
output += "\n"
return output
def _formatUncovered(self, obj):
# First sort groups by label
groups = sorted(obj.groups[:], key=lambda g: g.label)
# Get summary of groups:
output = "\nBLOCK SModelS_Coverage"
for i, group in enumerate(sorted(groups, key=lambda g: g.label)):
output += "\n %d 0 %-30s # %s" % (
i, group.label, group.description)
output += "\n %d 1 %-30.3E # %s" % (
i, group.getTotalXSec(), "Total cross-section (fb)")
output += "\n"
return output
def _formatTheoryPrediction(self,obj):
return self._formatTheoryPredictionsCombiner(obj)
def _formatTheoryPredictionsCombiner(self, obj):
"""
Format data of the TheoryPredictionsCombiner object.
:param obj: A TheoryPredictionsCombiner object to be printed.
"""
output = "BLOCK SModelS_CombinedAnas\n"
combRes = [obj] # For now use a dummy list (only a single combined result is expected)
for icomb, cRes in enumerate(combRes):
cter = icomb + 1
# Get list of analyses IDs used in combination:
expIDs = cRes.analysisId()
ul = cRes.getUpperLimit()
ulExpected = cRes.getUpperLimit(expected=True)
if isinstance(ul, unum.Unum):
ul = ul.asNumber(fb)
if isinstance(ulExpected, unum.Unum):
ulExpected = ulExpected.asNumber(fb)
r = self._round(cRes.getRValue(expected=False))
r_expected = self._round(cRes.getRValue(expected=True))
nll = cRes.likelihood(return_nll=True)
nllmin = cRes.lmax(return_nll=True)
nllsm = cRes.lsm(return_nll=True)
lvals = [nll, nllmin, nllsm]
for i, lv in enumerate(lvals):
if isinstance(lv, (float, np.float64)):
lv = "%-30.2E" % lv
else:
lv = str(lv)
lvals[i] = lv
nll, nllmin, nllsm = lvals[:]
if r is not None:
output += " %d 1 %-30.3E #r value\n" % (cter, r)
else:
output += " %d 1 NaN #r value (failed to compute r-value)\n" % (cter)
if r_expected is not None:
output += " %d 2 %-30.3E #expected r value\n" % (cter, r_expected)
else:
output += " %d 2 NaN #expected r value (failed to compute expected r-value)\n" % (cter)
output += " %d 3 %s #nll\n" % (cter, nll)
output += " %d 4 %s #nll_min\n" % (cter, nllmin)
output += " %d 5 %s #nll_SM\n" % (cter, nllsm)
output += " %d 6 %s #IDs of combined analyses\n" % (cter, expIDs)
output += "\n"
return output