#include "QFramework/TQNFChainloader.h"
#include "QFramework/TQStringUtils.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQUtils.h"
#include "TMath.h"
#include "TRandom.h"
#include "QFramework/TQHistogramUtils.h"
#include "QFramework/TQNFCalculator.h"
#include "QFramework/TQABCDCalculator.h"
#include "QFramework/TQNFManualSetter.h"
#include "QFramework/TQNFTop0jetEstimator.h"
#include "QFramework/TQNFTop1jetEstimator.h"
#include "QFramework/TQNFCustomCalculator.h"
#include "QFramework/TQNFUncertaintyScaler.h"
#include "TMatrixD.h"
#include "TFile.h"
#include <limits>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <fstream>
#include "QFramework/TQLibrary.h"
ClassImp(TQNFChainloader)
TQNFChainloader::TQNFChainloader():
TQNamedTaggable(),
fReader(NULL),
status(-999),
verbosity(0)
{
rnd=TRandom3();
}
TQNFChainloader::TQNFChainloader(const std::vector<TString>& nfconfigs, TQSampleFolder* f ):
TQNamedTaggable(),
fReader(new TQSampleDataReader(f)),
vNFconfig(nfconfigs),
status(-999),
verbosity(0)
{
rnd=TRandom3();
}
TQNFChainloader::~TQNFChainloader(){
if(fReader)
delete fReader;
this->finalize();
this->clear();
}
int TQNFChainloader::addNFconfigs(const std::vector<TString>& nfconfigs) {
this->vNFconfig.insert( this->vNFconfig.end(), nfconfigs.begin(), nfconfigs.end() );
return 0;
}
int TQNFChainloader::setNFconfigs(const std::vector<TString>& nfconfigs){
this->finalize();
this->addNFconfigs(nfconfigs);
return 0;
}
void TQNFChainloader::setSampleFolder(TQSampleFolder* f){
if (!f) return;
if(!this->fReader){
this->fReader = new TQSampleDataReader(f);
}
}
bool TQNFChainloader::initialize(){
if(!this->fReader) return false;
TString prefix = this->getTagStringDefault("pathprefix","");
TQSampleFolder* sf = this->fReader->getSampleFolder();
TQFolder * nfinfo = sf->getFolder("info/normalization+");
TQFolder * cutinfo = sf->getFolder("info/cuts");
for (uint v=0; v<this->vNFconfig.size(); v++) {
bool execAtEnd = false;
TString nfconfigname = this->vNFconfig.at(v);
TString errMsg;
TQFolder * nfconfig = TQFolder::loadFromTextFile(nfconfigname,errMsg);
if (!nfconfig){
ERRORclass("unable to import configuration from '%s', error message was '%s'",nfconfigname.Data(),errMsg.Data());
continue;
}
nfconfig->replaceInFolderTags(this->fVariationTags,"*");
nfconfig->replaceInFolderTags(this->fCampaignTag, "*");
INFOclass("setting up normalization factor configuration '%s'",nfconfigname.Data());
TQFolderIterator itr(nfconfig->getListOfFolders("?"),true);
while(itr.hasNext()){
TQFolder * conf = itr.readNext();
if (!conf) continue;
TString mode = conf->getTagStringDefault("mode","TQNF");
#ifdef _DEBUG_
std::cout<<"mode = "<<mode<<std::endl;
#endif
if (!(conf->hasTag("applyToCut") || conf->hasTag("applyToCut.0") ) && !TQStringUtils::equal(mode,"MANUAL") && !TQStringUtils::equal(mode,"ERRSCALE") && !TQStringUtils::equal(mode,"UNCSCALE") && !TQStringUtils::equal(mode,"UNCERTSCALE")) {
WARNclass("skipping calculation of NFs for instance '%s - no target cut given!",conf->getName().Data());
continue;
}
TString stopatcutname = conf->getTagStringDefault("stopAtCut","");
TQNFBase* nfbase = NULL;
DEBUGclass("instantiating TQNFBase of type '%s'",mode.Data());
if(TQStringUtils::equal(mode,"TQNF")){
TQNFCalculator* tqnf = new TQNFCalculator(this->fReader);
if (!tqnf->readConfiguration(conf)) {
ERRORclass("cannot calculate NFs for instance '%s' - there was an error parsing the configuration!",conf->getName().Data());
continue;
}
tqnf->setTag("mode.matrix.nToyHits",1);
nfbase = tqnf;
} else if (TQStringUtils::equal(mode,"ABCD")) {
TQABCDCalculator * abcd = new TQABCDCalculator(this->fReader);
if (!abcd->readConfiguration(conf)) {
ERRORclass("cannot perform ABCD for instance '%s' - there was an error parsing the configuration!",conf->getName().Data());
continue;
}
nfbase=abcd;
} else if (TQStringUtils::equal(mode,"TOP0JET")) {
TQNFTop0jetEstimator * top0jet = new TQNFTop0jetEstimator(this->fReader);
if (!top0jet->readConfiguration(conf)) {
ERRORclass("cannot perform TOP0JET for instance '%s' - there was an error parsing the configuration!",conf->getName().Data());
continue;
}
nfbase=top0jet;
} else if (TQStringUtils::equal(mode,"TOP1JET")) {
TQNFTop1jetEstimator * top1jet = new TQNFTop1jetEstimator(this->fReader);
if (!top1jet->readConfiguration(conf)) {
ERRORclass("cannot perform TOP1JET for instance '%s' - there was an error parsing the configuration!",conf->getName().Data());
continue;
}
nfbase=top1jet;
} else if (TQStringUtils::equal(mode,"MANUAL")) {
TQNFManualSetter * manSetter = new TQNFManualSetter(this->fReader);
if (!manSetter->readConfiguration(conf)) {
ERRORclass("cannot perform MANUAL for instance '%s' - there was an error parsing the configuration!",conf->getName().Data());
continue;
}
nfbase=manSetter;
} else if (TQStringUtils::equal(mode,"CUSTOM")) {
TQNFCustomCalculator * custCalc = new TQNFCustomCalculator(this->fReader);
if (!custCalc->readConfiguration(conf)) {
ERRORclass("cannot perform MANUAL for instance '%s' - there was an error parsing the configuration!",conf->getName().Data());
continue;
}
nfbase=custCalc;
} else if (TQStringUtils::equal(mode,"ERRSCALE") || TQStringUtils::equal(mode,"UNCSCALE") || TQStringUtils::equal(mode,"UNCERTSCALE")) {
TQNFUncertaintyScaler * uncScaler = new TQNFUncertaintyScaler(this->fReader);
if (!uncScaler->readConfiguration(conf)) {
ERRORclass("cannot perform ERRSCALE/UNCSCALE/UNCERTSCALE for instance '%s' - there was an error parsing the configuration!",conf->getName().Data());
continue;
}
nfbase=uncScaler;
execAtEnd = true;
}
DEBUGclass("done");
if(nfbase){
DEBUGclass("performing final setup");
nfbase->importTags(conf);
nfbase->setTagString("saveLog.prefix",prefix);
nfbase->setTagString("writePreFitHistograms.prefix",prefix);
nfbase->setTagString("writePostFitHistograms.prefix",prefix);
nfbase->setTagString("saveResults.prefix",prefix);
nfbase->setChainLoader(this);
nfbase->setCutInfoFolder(cutinfo);
nfbase->setInfoFolder(nfinfo);
if (!execAtEnd) {
this->vNFcalc.push_back(nfbase);
} else {
this->vNFpostCalc.push_back(nfbase);
}
DEBUGclass("done");
} else {
WARNclass("unable to initialize NF calculator '%s'",conf->GetName());
}
}
}
this->initialized = true;
return true;
}
bool TQNFChainloader::finalize(){
if(this->initialized){
for(size_t i=0; i<vNFcalc.size(); ++i){
#ifdef _DEBUG_
DEBUGclass("finalizing NFBase '%s'",vNFcalc[i]->GetName());
#endif
vNFcalc[i]->finalize();
#ifdef _DEBUG_
DEBUGclass("deleting");
#endif
delete vNFcalc[i];
#ifdef _DEBUG_
DEBUGclass("done");
#endif
}
this->vNFcalc.clear();
if (this->vNFpostCalc.size()>0) {
#ifdef _DEBUG_
DEBUGclass("Executing post-calculation methods)");
#endif
for (size_t i=0; i<vNFpostCalc.size(); ++i) {
TQNFBase* nfcalc = this->vNFpostCalc[i];
#ifdef _DEBUG_
DEBUGclass("initializing '%s'",nfcalc->GetName());
#endif
if(!nfcalc->initialize()){
ERRORclass("unable to initialize calculator '%s'",nfcalc->GetName());
continue;
}
#ifdef _DEBUG_
DEBUGclass("executing '%s'",nfcalc->GetName());
#endif
int retval = nfcalc->execute(-1);
if (0 != retval){
ERRORclass("an error occured while performing calculation '%s' (return value: %d)!",nfcalc->GetName(),retval);
continue;
}
std::vector<TString> startAtCutNames = nfcalc->getTagVString("applyToCut");
std::vector<TString> stopatcutname = nfcalc->getTagVString("stopAtCut");
if (!nfcalc->success()){
WARN("TQNFBase '%s' failed to calculate NFs for cut(s) '%s' with status %d: %s!",nfcalc->GetName(),TQListUtils::makeCSV(startAtCutNames).Data(),nfcalc->getStatus(),nfcalc->getStatusMessage().Data());
return false;
} else if (!(nfcalc->deployResult(startAtCutNames,stopatcutname)>0)){
ERRORclass("unable to deploy results of NF calculation!");
return false;
}
#ifdef _DEBUG_
DEBUGclass("finalizing '%s'",nfcalc->GetName());
#endif
nfcalc->finalize();
}
}
}
for(size_t i=0; i<vNFpostCalc.size(); ++i){
#ifdef _DEBUG_
DEBUGclass("finalizing NFBase '%s'",vNFpostCalc[i]->GetName());
#endif
vNFpostCalc[i]->finalize();
#ifdef _DEBUG_
DEBUGclass("deleting");
#endif
delete vNFpostCalc[i];
#ifdef _DEBUG_
DEBUGclass("done");
#endif
}
this->vNFpostCalc.clear();
this->initialized = false;
return true;
}
int TQNFChainloader::execute() {
if(!this->initialized){
ERRORclass("cannot bootstrap NF calculation uninitialized!");
return -1;
}
int iterations = this->getTagDefault("numberOfIterations",1);
int nToy = this->getTagDefault("toySize",1);
bool doVariations = (nToy>1);
#ifdef _DEBUG_
DEBUGclass("bootstrapping nf calculations");
#endif
INFOclass("running calculation of normalization factors with %d toys!", nToy);
for (int t = 0;t<nToy;t++) {
#ifdef _DEBUG_
DEBUGclass("rolling toy %d/%d",t+1,nToy);
#endif
for (int i=0;i<iterations;++i) {
#ifdef _DEBUG_
DEBUGclass("undergoing iteration %d/%d",i+1,iterations);
#endif
for(size_t k=0; k<this->vNFcalc.size(); k++){
TQNFBase* nfcalc = this->vNFcalc[k];
#ifdef _DEBUG_
DEBUGclass("initializing '%s'",nfcalc->GetName());
#endif
if(!nfcalc->initialize()){
ERRORclass("unable to initialize calculator '%s'",nfcalc->GetName());
continue;
}
#ifdef _DEBUG_
DEBUGclass("executing '%s'",nfcalc->GetName());
#endif
int retval = nfcalc->execute(doVariations ? t : -1);
if (0 != retval){
ERRORclass("an error occured while performing calculation '%s' (return value: %d)!",nfcalc->GetName(),retval);
continue;
}
std::vector<TString> startAtCutNames = nfcalc->getTagVString("applyToCut");
std::vector<TString> stopatcutname = nfcalc->getTagVString("stopAtCut");
if (!nfcalc->success()){
WARN("TQNFBase '%s' failed to calculate NFs for cut '%s' with status %d: %s!",nfcalc->GetName(),TQListUtils::makeCSV(startAtCutNames).Data(),nfcalc->getStatus(),nfcalc->getStatusMessage().Data());
return -1;
} else if (!nfcalc->deployResult(startAtCutNames,stopatcutname)){
ERRORclass("unable to deploy results of NF calculation!");
return -1;
} else {
DEBUGclass("successfully deployed results for '%s' to cuts '%s'-'%s'",nfcalc->GetName(),TQStringUtils::concat(startAtCutNames,",").Data(),TQStringUtils::concat(stopatcutname,",").Data());
}
if (t==0 && doVariations){
this->registerTargetPaths(nfcalc->getNFpaths());
}
#ifdef _DEBUG_
DEBUGclass("finalizing '%s'",nfcalc->GetName());
#endif
nfcalc->finalize();
#ifdef _DEBUG_
DEBUGclass("done!");
#endif
}
}
if (doVariations) {
this->relativeVariationMap.clear();
this->collectNFs();
}
#ifdef _DEBUG_
DEBUGclass("end of iteration");
#endif
}
if (doVariations) {
#ifdef _DEBUG_
DEBUGclass("deploying NFs");
for(size_t i=0; i<this->vNFcalc.size(); ++i){
this->vNFcalc[i]->printNFPaths();
}
#endif
this->deployNFs();
}
DEBUGclass("end of function");
return 0;
}
double TQNFChainloader::getRelVariation(const TString& key, double value, double uncertainty) {
if (key=="") {
WARN("No valid key has been given! Returning 0!");
return 0;
}
if (this->relativeVariationMap.count(key)==0) {
if (value == 0) return 0;
this->relativeVariationMap[key] = (rnd.Gaus(value,uncertainty))/value;
}
double retval = this->relativeVariationMap[key];
return retval;
}
int TQNFChainloader::registerTargetPaths(const std::vector<TString>& vec){
int npre = this->targetNFpaths.size();
for (uint i=0;i<vec.size();i++){
this->targetNFpaths[vec[i]] = true;
}
return this->targetNFpaths.size()-npre;
}
int TQNFChainloader::collectNFs() {
int nNFs = 0;
for (auto& item : this->targetNFpaths) {
TString path = item.first;
TString cut = TQFolder::getPathTail(path);
TString scheme = TQStringUtils::readPrefix(cut, ":", ".default");
double nf = 1;
TQSampleFolder* sf = this->fReader->getSampleFolder();
if (sf->getSampleFolder(path)){
nf = sf->getSampleFolder(path)->getScaleFactor(scheme+":"+cut);
sf->getSampleFolder(path)->setScaleFactor(scheme+":"+cut,1.,0.);
}else {
ERRORclass("Failed to retrieve scale factor, results may be unreliable!");
}
mNFvectors[item.first].push_back(nf);
nNFs++;
}
return nNFs;
}
int TQNFChainloader::deployNFs() {
int nNFs = 0;
std::vector<TString> names;
std::vector<TString> identifier;
std::vector<std::vector<double>> toys;
for (auto& item : this->mNFvectors) {
names.push_back(item.first);
toys.push_back(item.second);
}
if (this->getTagBoolDefault("doNFplots",false)) {
std::vector<TString> NFpatterns;
this->getTag("NFplotsPattern",NFpatterns);
if (NFpatterns.size()>0) {
std::vector<uint> indicesToPlot;
for (uint i=0; i<names.size(); ++i) {
for (uint j=0;j<NFpatterns.size();++j) {
if (TQStringUtils::matches(names.at(i),NFpatterns.at(j))) {
indicesToPlot.push_back(i);
break;
}
}
}
TString NFPlotsFileName = this->getTagStringDefault("NFplotsFile","NFplots.root");
TQUtils::ensureDirectoryForFile(NFPlotsFileName);
TFile* f = TFile::Open(NFPlotsFileName,"RECREATE");
for (uint i=0; i<indicesToPlot.size();++i) {
uint index = indicesToPlot.at(i);
double avg = TQUtils::getAverage(toys.at(index));
double stddev = sqrt(TQUtils::getSampleVariance(toys.at(index)));
TH1F* hist1 = new TH1F(names.at(index),names.at(index), (int)ceil(this->getTagIntegerDefault("toySize",1)/this->getTagDoubleDefault("NFplotsEntriesPerBin",10.)) ,avg-3*stddev , avg+3*stddev);
for (uint j=0; j<toys.at(index).size();++j) {
hist1->Fill(toys[index][j]);
}
hist1->Write();
delete hist1;
if (this->hasTagDouble("NFplotsLow") && this->hasTagDouble("NFplotsHigh") ) {
TH1F* hist2 = new TH1F(names.at(index),names.at(index), (int)ceil(this->getTagIntegerDefault("toySize",1)/this->getTagDoubleDefault("NFplotsEntriesPerBin",10.)) ,this->getTagDoubleDefault("NFplotsLow",0.) , this->getTagDoubleDefault("NFplotsHigh",2.));
for (uint j=0; j<toys.at(index).size();++j) {
hist2->Fill(toys[index][j]);
}
hist2->Write();
delete hist2;
}
if (this->getTagBoolDefault("doNFcorrelationPlots",false) && i<indicesToPlot.size()-1) {
for (uint j=i+1; j<indicesToPlot.size(); ++j) {
uint index2 = indicesToPlot.at(j);
TGraph* gr = TQHistogramUtils::scatterPlot(names.at(index) + " vs " + names.at(index2), toys.at(index), toys.at(index2), names.at(index), names.at(index2) );
gr->Write();
delete gr;
}
}
}
f->Close();
} else {
WARN("No pattern for NF plots given, skipping!");
}
}
for (uint i=0; i<names.size(); ++i) {
identifier.push_back(TString::Format("%lu_%d",TQUtils::getCurrentTime(),i));
}
#ifdef _DEBUG_
for(size_t i=0; i<names.size(); ++i){
std::cout << names[i] << "\t";
for(size_t j = 0; j < toys[i].size(); ++j){
std::cout << toys[i][j] << " ";
}
std::cout << std::endl;
}
#endif
TMatrixD correlations(names.size(),names.size());
bool ok = true;
for (uint i=0;i<names.size();i++) {
for (uint j=0;j<names.size();j++) {
double val = TQUtils::getSampleCorrelation(toys.at(i),toys.at(j),ok);
if(TQUtils::isNum(val)){
correlations[i][j] = val;
} else {
ok = false;
correlations[i][j] = 0;
}
}
}
TQSampleFolder* sf = this->fReader->getSampleFolder();
TQSampleFolder* writeOut = NULL;
if (this->hasTagString("exportNFsTo")) writeOut = TQSampleFolder::newSampleFolder("writeOut");
for (uint i=0;i<names.size();i++) {
TString path = names.at(i);
TString cut = TQFolder::getPathTail(path);
TString scheme = TQStringUtils::readPrefix(cut, ":", ".default");
TQSampleFolder* subFolder = sf->getSampleFolder(path);
TQSampleFolder* subWriteOut = NULL;
if (writeOut) subWriteOut = writeOut->getSampleFolder(path+"+");
if (!subFolder || (writeOut && !subWriteOut) ) {
ERRORclass("Failed to deploy NF!");
break;
}
double average = TQUtils::getAverage(toys.at(i));
double uncertainty = sqrt(TQUtils::getSampleVariance(toys.at(i)));
#ifdef _DEBUG_
DEBUGclass("setting scale factor '%s:%s' = %f +/- %f with ID='%s' on '%s'",scheme.Data(),cut.Data(),average,uncertainty,identifier.at(i).Data(),subFolder->getPath().Data());
#endif
int n = subFolder->setScaleFactor(scheme+":"+cut,identifier.at(i),average,uncertainty);
if (subWriteOut) subWriteOut->setScaleFactor(scheme+":"+cut,identifier.at(i),average,uncertainty);
if(n == 0){
WARNclass("failure to set scale factor on '%s', skipping",subFolder->getPath().Data());
} else {
if (this->getTagBoolDefault("saveNFCorrelations", true)) {
TQFolder* corrFolder = subFolder->getFolder(TQFolder::concatPaths(".scalefactors/",scheme,".correlations/",identifier.at(i))+"+");
TQFolder* corrWriteOut = NULL;
if (subWriteOut) corrWriteOut = subWriteOut->getFolder(TQFolder::concatPaths(".scalefactors/",scheme,".correlations/",identifier.at(i))+"+");
for(uint j=0; j<identifier.size();++j) {
TQCounter* corrCounter = new TQCounter(identifier.at(j),correlations[i][j],0.);
corrFolder->addObject(corrCounter,"");
if (corrWriteOut) {
TQCounter* corrCounterWriteOut = new TQCounter(identifier.at(j),correlations[i][j],0.);
corrWriteOut->addObject(corrCounterWriteOut,"");
}
}
}
}
nNFs+=n;
}
if (writeOut) {
TString exportFileName = this->getTagStringDefault("exportNFsTo","");
if (exportFileName.EndsWith(".root",TString::kIgnoreCase)) writeOut->writeToFile(exportFileName, true,-1,true);
else writeOut->exportToTextFile(exportFileName,true);
delete writeOut;
}
return nNFs;
}
TList* TQNFChainloader::getListOfFolders(){
TQSampleFolder* sf = this->fReader->getSampleFolder();
TList* l = new TList();
for(auto itr=this->targetNFpaths.begin(); itr!=this->targetNFpaths.end(); ++itr){
TQFolder* f = sf->getFolder(itr->first);
if(f){
l->Add(f);
}
}
return l;
}
int TQNFChainloader::setVariationTags(const TQTaggable& tags) {
this->fVariationTags.clear();
return this->fVariationTags.importTags(tags);
}
int TQNFChainloader::setVariationTags(TQTaggable* tags) {
this->fVariationTags.clear();
return this->fVariationTags.importTags(tags);
}
int TQNFChainloader::setCampaignTag(TQTaggable* tag) {
this->fCampaignTag.clear();
return this->fCampaignTag.importTags(tag);
}