#include "TAxis.h"
#include "QFramework/TQHistogramUtils.h"
#include "QFramework/TQTHnBaseUtils.h"
#include "QFramework/TQStringUtils.h"
#include "QFramework/TQTaggable.h"
#include "QFramework/TQCounter.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQUtils.h"
#include "TMath.h"
#include "TList.h"
#include "THn.h"
#include "THnBase.h"
#include "THnSparse.h"
#include "THashList.h"
#include "TROOT.h"
#include "QFramework/TQLibrary.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <limits>
#include <stdio.h>
#include <stdarg.h>
#include "Math/Math.h"
#include "Math/QuantFuncMathCore.h"
#include "Math/SpecFuncMathCore.h"
TString TQTHnBaseUtils::getHistogramDefinition(THnBase * histo) {
if (!histo) {
return "";
}
TString histoType = histo->IsA()->GetName();
if (!TQStringUtils::compare(histoType, "THnSparseT<TArrayF>")) {
histoType = "THnSparseF";
}
else if (!TQStringUtils::compare(histoType,"THnSparseT<TArrayD>")) {
histoType = "THnSparseD";
}
TString def = TString::Format("%s(\"%s\", ", histoType.Data(), histo->GetName());
TString titleDef = "";
TString binDef;
int dim = getDimension(histo);
for (int i = 0; i < dim; ++i) {
TAxis * axis = NULL;
axis = histo->GetAxis(i);
if (!axis) {
break;
}
TString title = axis->GetTitle();
if (!title.IsNull()) {
TQStringUtils::append(titleDef, title, ";");
}
TQStringUtils::append(binDef, TQHistogramUtils::getBinningDefinition(axis), ", ");
}
TQTaggable * binDefTags = TQTaggable::parseParameterList(binDef);
TString nBins = "";
TString min = "";
TString max = "";
for (int i = 0; i < dim; ++i) {
nBins.Append(binDefTags->getTagStringDefault(TString::Format("%d", 3*i)));
min.Append(binDefTags->getTagStringDefault(TString::Format("%d", 3*i+1)));
max.Append(binDefTags->getTagStringDefault(TString::Format("%d", 3*i+2)));
if (i < dim-1) {
nBins.Append(", ");
min.Append(", ");
max.Append(", ");
}
}
binDef = TString::Format("{%s}, {%s}, {%s}", nBins.Data(), min.Data(), max.Data());
def.Append(TString::Format("\"%s\", ", titleDef.Data()));
def.Append(TString::Format("%d, ", dim));
def.Append(binDef + ")");
return def;
}
THnBase * TQTHnBaseUtils::createHistogram(TString definition, bool printErrMsg) {
TString errMsg;
THnBase * histo = createHistogram(definition, errMsg);
if (!histo && printErrMsg) {
std::cout << TQStringUtils::makeBoldRed(errMsg.Prepend(
"TQTHnBaseUtils::createHistogram(...): ")).Data() << std::endl;
}
return histo;
}
THnBase * TQTHnBaseUtils::createHistogram(TString definition, TString &errMsg) {
TString type;
TQStringUtils::readBlanksAndNewlines(definition);
if (TQStringUtils::readToken(definition,type,TQStringUtils::getLetters() + TQStringUtils::getNumerals()) == 0) {
errMsg = TString::Format("Missing valid histogram type, received '%s' from '%s'",type.Data(),definition.Data());
return NULL;
}
bool isTHnSparseF = (type.CompareTo("THnSparseF") == 0);
bool isTHnSparseD = (type.CompareTo("THnSparseD") == 0);
if (!isTHnSparseF && !isTHnSparseD) {
errMsg = TString::Format("Unknown histogram type '%s'", type.Data());
return NULL;
}
TString parameter;
TQStringUtils::readBlanksAndNewlines(definition);
if (TQStringUtils::readBlock(definition, parameter, "()", "''\"\"", false) == 0) {
errMsg = TString::Format("Missing parameter block '(...)' after '%s'", type.Data());
return NULL;
}
TQStringUtils::readBlanksAndNewlines(definition);
if (!definition.IsNull()) {
errMsg = TString::Format("Unrecognized token '%s'", definition.Data());
return NULL;
}
TQTaggable * pars = TQTaggable::parseParameterList(parameter, ",", true, "{}[]()", "''\"\"");
if (!pars) {
errMsg = TString::Format("Failed to parse parameters '%s'", parameter.Data());
return NULL;
}
pars->resetReadFlags();
if (!pars->tagIsOfTypeString("0")) {
errMsg = "Missing valid histogram name";
delete pars;
return NULL;
}
TString name = pars->getTagStringDefault("0");
if (!pars->tagIsOfTypeString("1")) {
errMsg = "Missing valid histogram title";
delete pars;
return NULL;
}
TString title = pars->getTagStringDefault("1");
int dimension = 0;
std::vector<int> nBins;
std::vector<double> min;
std::vector<double> max;
if (!extractBinning(pars, dimension, nBins, min, max, errMsg)) {
errMsg.Append(" when creating THnSparse");
delete pars;
return NULL;
}
if (pars->hasUnreadKeys()) {
errMsg.Append(TString::Format("Too many parameters for '%s'", type.Data()));
delete pars;
return NULL;
}
int i = 2;
TString finalName = name;
while (gDirectory && gDirectory->FindObject(name.Data())) {
name = TString::Format("%s_i%d", finalName.Data(), i++);
}
THnBase * histo = NULL;
if (isTHnSparseF) {
histo = new THnSparseF(name.Data(), title.Data(), dimension,
nBins.data(), min.data(), max.data());
}
else if (isTHnSparseD) {
histo = new THnSparseD(name.Data(), title.Data(), dimension,
nBins.data(), min.data(), max.data());
}
if (histo) {
histo->SetName(finalName.Data());
histo->Sumw2();
}
delete pars;
if(!histo){
errMsg = "unknown error: histogram type is '"+type+"'";
}
return histo;
}
bool TQTHnBaseUtils::extractBinning(TQTaggable * p, int &dimension, std::vector<int> &nBins,std::vector<double> &min,std::vector<double> &max, TString &errMsg) {
p->getTagInteger("2", dimension);
for (int p_bin = 3; p_bin<6; p_bin++) {
double edge = 0.;
for (int i=0; i<dimension; i++) {
if (!p->hasTag(TString::Format("%d.%d", p_bin, i))) {
errMsg = "Invalid array of bins";
}
if (!p->getTagDouble(TString::Format("%d.%d", p_bin, i), edge)) {
errMsg = "Invalid array of bins";
return false;
}
if (p_bin == 3)
nBins.push_back(edge);
if (p_bin == 4)
min.push_back(edge);
if (p_bin == 5)
max.push_back(edge);
}
}
return true;
}
THnBase * TQTHnBaseUtils::copyHistogram(THnBase * histo, const TString& newName) {
if (!histo) {
return NULL;
}
THnBase * copy = TQTHnBaseUtils::createHistogram(TQTHnBaseUtils::getHistogramDefinition(histo));
if (!copyAxisNames(histo, copy)) {
WARN("failed copying axis names");
}
if (!copy) {
return NULL;
}
TQTHnBaseUtils::addHistogram(copy,histo);
int dim = getDimension(histo);
for (int i = 0; i < dim; ++i) {
if (histo->GetAxis(i)) copy->GetAxis(i)->SetTitle(histo->GetAxis(i)->GetTitle());
}
if (newName != "NODIR" && !newName.IsNull()) {
copy->SetName(newName);
}
return copy;
}
bool TQTHnBaseUtils::copyAxisNames(THnBase * histo, THnBase * copy) {
if (!histo || !copy) {
return false;
}
for (int i=0; i<histo->GetNdimensions(); i++) {
copy->GetAxis(i)->SetName(histo->GetAxis(i)->GetName());
}
return true;
}
bool TQTHnBaseUtils::addHistogram(THnBase * histo1, THnBase * histo2,
TQCounter* scale, double corr12, bool includeScaleUncertainty) {
if(scale)
return TQTHnBaseUtils::addHistogram(histo1,histo2,scale->getCounter(),scale->getError(),corr12,includeScaleUncertainty);
else
return TQTHnBaseUtils::addHistogram(histo1,histo2,1.,0.,corr12,false);
}
bool TQTHnBaseUtils::addHistogram(THnBase * histo1, THnBase * histo2,
double scale, double ,
double , bool ) {
if (!histo1 || !histo2 || !checkConsistency(histo1, histo2)) {
return false;
}
histo1->Add(histo2, scale);
return true;
}
bool TQTHnBaseUtils::scaleHistogram(THnBase * histo, TQCounter* scale, bool includeScaleUncertainty) {
if(scale)
return TQTHnBaseUtils::scaleHistogram(histo,scale->getCounter(),scale->getError(),includeScaleUncertainty);
else
return TQTHnBaseUtils::scaleHistogram(histo,1.,0.,false);
}
bool TQTHnBaseUtils::scaleHistogram(THnBase * histo, double scale, double ,
bool ) {
histo->Scale(scale);
return true;
}
int TQTHnBaseUtils::getDimension(THnBase * histo) {
if (!histo) {
return 0;
}
return histo->GetNdimensions();
}
bool TQTHnBaseUtils::checkConsistency(THnBase * histo1, THnBase * histo2, bool verbose) {
if (!histo1 || !histo2) {
if(verbose) ERRORfunc("received NULL pointer");
return false;
}
if (histo1->GetNdimensions() != histo2->GetNdimensions()) {
if(verbose) ERRORfunc("different number of dimensions, cannot carry out operation on the histograms");
return false;
}
DEBUGfunc("function called on histograms '%s' and '%s'",histo1->GetName(),histo2->GetName());
for (int dim = 0; dim < histo1->GetNdimensions(); dim++) {
if (histo1->GetAxis(dim)->GetNbins() != histo2->GetAxis(dim)->GetNbins()) {
if(verbose) ERRORfunc("Different number of bins on axis %i, cannot carry out operation on the histograms", dim);
return false;
}
}
return true;
}
THnBase* TQTHnBaseUtils::projectionND(THnBase *hist, std::vector<TString> axesNamesToUse, const TString& option) {
if (!axesNamesToUse.empty()) {
std::vector<int> axesIndizesToUse;
for (TString name : axesNamesToUse) {
bool found = false;
for (int idim=0; idim<hist->GetNdimensions(); idim++) {
if (name.EqualTo(hist->GetAxis(idim)->GetName())) {
found = true;
axesIndizesToUse.push_back(idim);
}
}
if (!found) {
WARNfunc("Axis with name '%s' not found! Please check your input configuration, for now this is skipped...", name.Data());
}
}
THnSparseF *newhist;
newhist = (THnSparseF*)hist->ProjectionND(axesIndizesToUse.size(), axesIndizesToUse.data(), option);
return newhist;
}
return nullptr;
}
bool TQTHnBaseUtils::getAxisIndex(THnBase* h, const TString& axis_name, int& index) {
bool found = false;
for (int idim=0; idim<h->GetNdimensions(); idim++) {
if (axis_name.EqualTo(h->GetAxis(idim)->GetName())) {
found = true;
index = idim;
}
}
if (!found) {
WARN("Variable '%s' could not be found in input n-dim histogram with name '%s'!", axis_name.Data(), h->GetName());
}
return found;
}
TAxis* TQTHnBaseUtils::getAxis(THnBase* h, const TString& axis_name) {
TAxis *axis = NULL;
for (int idim=0; idim<h->GetNdimensions(); idim++) {
if (axis_name.EqualTo(h->GetAxis(idim)->GetName())) {
axis = h->GetAxis(idim);
}
}
if (!axis) {
WARN("Variable '%s' could not be found in input n-dim histogram with name '%s'!", axis_name.Data(), h->GetName());
}
return axis;
}