Newer
Older
#include <map>
#include <set>
#include "TString.h"
#include "QFramework/TQTable.h"
#include "QFramework/TQFolder.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQUtils.h"
#include "QFramework/TQStringUtils.h"
#include "TString.h"
#include "SFramework/TSStatisticsManager.h"
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*<cafdoc name=TransferSystematics>
TransferSystematics
===========================
Transfer systematics from one sample to another, or from one channel/region to another.
This is useful in cases where individual samples or regions have low
MC statistics and a larger region with similar kinematics is
avialable to estimate the systematics from. What is transferred is
the relative normalization and/or shape.
Usage:
---------------
```
+TransferSystematics {
+HWWRun2GGF {
+ZtautauMerging {
<mode = "channel">
# wildcarding is allowed everywhere
# you can also mix values and lists of values
<source = "SR_*Mll1_PtSubLeadincl*_x">
<select.Channels={"SR_*Mll1_PtSubLead2*_e","SR_*Mll1_PtSubLead2*_m","SR_*Mll1_PtSubLead2*_x"}>
<select.Samples = {"Zjets*"}>
<select.Systematics = "theo_ztautau_*">
}
+ww_0j_merging_all {
<mode = "channel">
<select.Samples = {"qqWW0jet"}>
# it is typically useful to define merged regions to evaluate the systematics on
# these merged regions can be present when the model is built, and can be removed from the model before building the workspace using EditModel
<source = "SR_All">
<select.Channels={"SR_bin*"}>
<select.Systematics ={"theo_ww_CKKW","theo_ww_QSF" }>
}
+zttandvgamma_0j_merging_from_all {
<mode = "channel">
<source = "SR_All">
<select.Samples = {"Zjets0jet","Vgamma0jet"}>
<select.Channels={"SR_bin*"}>
<select.Systematics ={"ATLAS_JER*","ATLAS_JES*","ATLAS_MET*","MUONS_SAGITTA*", "MUONS_SCALE", "MUONS_MS", "MUONS_ID", "ATLAS_EG_SCALE_AF2","ATLAS_EG_SCALE_ALL","EG_RESOLUTION_ALL","PRW_DATASF"}>
}
# you can instruct the action to create a table of all the transfers actually made in the end like this
<writeTable="transfer.tex">
}
}
```
The edits will be made in-place on the model.
</cafdoc> */
namespace TSBaseActions {
class TransferSystematics : public TSStatisticsManager::Action {
typedef std::map<TString,std::set<TString> > LogElement;
typedef std::map<TString,LogElement> Log;
void addToLog(Log& log, const TString& sysname, const TString& originname, const TString& targetname) const{
if(log.find(sysname) == log.end()) log[sysname] = LogElement();
if(log[sysname].find(originname) == log[sysname].end()) log[sysname][originname] = LogElement::mapped_type();
log[sysname][originname].insert(targetname);
}
TString cleanup(TString input) const {
TQStringUtils::removeLeadingText(input,"Sample.");
TQStringUtils::removeLeadingText(input,"Channel.");
// TQStringUtils::removeLeadingText(input,"OverallSys.");
// TQStringUtils::removeLeadingText(input,"HistoSys.");
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
void writeLog(const Log& log,TQTaggable* config) const {
TString tableFile;
bool writeTable = config->getTagString("writeTable",tableFile);
if(!writeTable) return;
TQTable table;
table.setEntry(0,0,"Systematic");
table.setEntry(0,2,"Source");
table.setEntry(0,3,"Target");
int line = 1;
for(const auto& sys:log){
table.setEntry(line,0,sys.first);
for(const auto& source:sys.second){
table.setEntry(line,1,source.first);
for(const auto& target:source.second){
table.setEntry(line,2,"$\\rightarrow$");
table.setEntry(line,3,target);
line++;
}
}
}
if(tableFile.EndsWith(".tex")){
table.writeLaTeX(tableFile);
} else if(tableFile.EndsWith(".html")){
table.writeHTML(tableFile);
} else {
table.write(tableFile);
}
}
bool matchesAny(TQFolder* f,const std::vector<TString>& filters, const TString&prefix = "") const {
bool matched = false;
for(const auto& x:filters){
if(TQStringUtils::matches(f->GetName(),prefix+"."+x)){
matched = true;
return matched;
}
bool execute(TQFolder * config) const override {
TQFolder* model = models()->getFolder(config->GetName());
if(!model){
manager->error(TString::Format("no such model available: '%s'",config->GetName()));
}
TQFolderIterator transfers = config->getListOfFolders("?");
int nOK = 0;
while(transfers.hasNext()){
TQFolder* transfer = transfers.readNext();
if(!transfer) continue;
nOK += performTransfer(transfer,model,log);
if(nOK>0){
writeLog(log,config);
}
bool performTransfer(TQFolder * config,TQFolder* model,Log& log) const {
TString mode = config->getTagStringDefault("mode","sample");
Carsten Burgard
committed
mode.ToLower();
TQFolder* histograms = model->getFolder(".Histograms");
TSSystematicsManager man;
man.setRepository(histograms);
bool verbose = config->getTagBoolDefault("~verbose",false);
Carsten Burgard
committed
TString tagCheckFilter = config->getTagStringDefault("compareTags","rebin*,include*flow,remap");
std::vector<TString> exceptRegions = config->getTagVString("except.Channels");
std::vector<TString> exceptSamples = config->getTagVString("except.Samples");
std::vector<TString> exceptSystematics = config->getTagVString("except");
Carsten Burgard
committed
manager->info(TString::Format("performing transfer '%s' in mode '%s'",config->GetName(),mode.Data()));
std::vector<TString> targetSamples = config->getTagVString("select.Samples");
if(targetSamples.empty()){
targetSamples.push_back("*");
}
std::vector<TString> targetChannels = config->getTagVString("select.Channels");
if(targetChannels.empty()){
targetChannels.push_back("*");
}
std::vector<TString> targetSystematics = config->getTagVString("select.Systematics");
if(targetSystematics.empty()){
targetSystematics.push_back("*");
bool marked = config->getTagString("selectTag",mark);
std::vector<TString> sysTypes = config->getTagVString("types");
if(sysTypes.size() == 0){
sysTypes.push_back("OverallSys");
if(mode.Contains("sample")){
sysTypes.push_back("HistoSys");
}
}
if (mode.Contains("sample",TString::kIgnoreCase)) {
TString sourceSample;
if(!config->getTagString("source",sourceSample)){
manager->error(TString::Format("missing required 'source' information on transfer '%s'",config->GetName()));
return false;
}
int i=0;
for(const auto& channelExp:targetChannels){
TQFolderIterator regions(model->getListOfFolders("Channel."+channelExp),true);
while(regions.hasNext()){
TQFolder* region = regions.readNext();
if(!region) continue;
if(matchesAny(region,exceptRegions,"Channel")) continue;
if(verbose) manager->info(TString::Format("transferring in region '%s'",region->GetName()));
TQFolder* source = region->getFolder("Sample."+sourceSample);
if(!source){
manager->warn(TString::Format("unable to find source '%s' in channel '%s', skipping!",sourceSample.Data(),region->GetName()));
continue;
}
for(const auto& sampleExp:targetSamples){
TQFolderIterator samples(region->getListOfFolders("Sample."+sampleExp),true);
while(samples.hasNext()){
TQFolder* sample = samples.readNext();
if(!sample) continue;
if(matchesAny(sample,exceptSamples,"Sample")) continue;
if(TQStringUtils::matches(sample->GetName(),"Sample."+sourceSample)) continue;
if(verbose) manager->info(TString::Format("\tfor sample '%s'",sample->GetName()));
sample->deleteObject(".Dropped!");
TQFolderIterator oldsystematics(sample->getListOfFolders(systType+".*"),true);
while(oldsystematics.hasNext()){
TQFolder* systematic = oldsystematics.readNext();
if(!systematic) continue;
if(matchesAny(systematic,exceptSystematics,systType) || !matchesAny(systematic,targetSystematics,systType)) continue;
if(marked && !systematic->getTagBoolDefault(mark,false)) continue;
if(verbose) manager->info(TString::Format("\t\tremoving '%s'",systematic->GetName()));
remove.push_back(systematic);
}
}
for(auto systematic:remove){
systematic->detachFromBase();
delete systematic;
}
{
TQFolderIterator newsystematics(source->getListOfFolders(systType+".*"),true);
while(newsystematics.hasNext()){
TQFolder* systematic = newsystematics.readNext();
if(!systematic) continue;
if(matchesAny(systematic,exceptSystematics,systType) || !matchesAny(systematic,targetSystematics,systType)) continue;
if(marked && !systematic->getTagBoolDefault(mark,false)) continue;
if(verbose) manager->info(TString::Format("\t\tcopying '%s'",systematic->GetName()));
TQFolder* copy = systematic->copy();
copy->setTagString("transferred",source->GetName());
if(systematic->hasTagString("HistoLow") && systematic->hasTagString("HistoHigh")){
TH1* nomHist = man.getHisto(sample->getTagStringDefault("Histo",""));
TH1* lowHist = man.getHisto(systematic->getTagStringDefault("HistoLow",""));
TH1* highHist = man.getHisto(systematic->getTagStringDefault("HistoHigh",""));
if(!TQHistogramUtils::checkConsistency(nomHist,lowHist) || !TQHistogramUtils::checkConsistency(nomHist,highHist)){
manager->error(TString::Format("transferred histograms for systematic '%s' in sample '%s' in region '%s' are inconsistent, skipping!\n\tnom\t%s\n\tlow\t%s\n\thigh\t%s",systematic->GetName(),sample->GetName(),region->GetName(),TQStringUtils::getDetails(nomHist).Data(),TQStringUtils::getDetails(lowHist).Data(),TQStringUtils::getDetails(highHist).Data()));
addToLog(log,cleanup(systematic->GetName()),sourceSample,cleanup(sample->GetName()));
sample->addFolder(copy);
}
}
if(verbose && j==0){
manager->warn(TString::Format("\tno systematics of type %s found in '%s' matching '%s' except '%s'!",systType.Data(),source->GetName(),TQStringUtils::concat(targetSystematics,",").Data(),TQStringUtils::concat(exceptSystematics,",").Data()));
}
}
}
}
if(i>0) return true;
manager->error("no targets found for sample transfer!");
return false;
} else if (mode.Contains("channel",TString::kIgnoreCase)) {
TString sourceChannel;
if(!config->getTagString("source",sourceChannel)){
manager->error(TString::Format("missing required 'source' information on transfer '%s'",config->GetName()));
return false;
}
int i=0;
for(const auto& channelExp:targetChannels){
TQFolderIterator regions(model->getListOfFolders("Channel."+channelExp),true);
while(regions.hasNext()){
TQFolder* region = regions.readNext();
if(!region) continue;
if(region->GetName() == sourceChannel) continue; //there is no point in transfering from A to A (it would even delete some stuff!)
if(matchesAny(region,exceptRegions,"Channel")) continue;
if(verbose) manager->info(TString::Format("transferring in region '%s'",region->GetName()));
for(const auto& sampleExp:targetSamples){
TQFolderIterator samples(region->getListOfFolders("Sample."+sampleExp),true);
while(samples.hasNext()){
TQFolder* sample = samples.readNext();
if(matchesAny(sample,exceptSamples,"Sample")) continue;
TQFolder* sourceRegion = model->getFolder("Channel."+sourceChannel);
TQFolder* source = sourceRegion ? sourceRegion->getFolder(sample->GetName()) : NULL;
if(!source){
manager->warn(TString::Format("unable to find source '%s'/'%s' in model '%s', skipping!",sourceChannel.Data(),sample->GetName(),model->GetName()));
continue;
}
if(verbose) manager->info(TString::Format("\tfor sample '%s'",sample->GetName()));
sample->deleteObject(".Dropped!");
for (const auto& systType : sysTypes){
std::vector<TQFolder*> remove;
{
TQFolderIterator oldsystematics(sample->getListOfFolders(systType+".*"),true);
while(oldsystematics.hasNext()){
TQFolder* systematic = oldsystematics.readNext();
if(!systematic) continue;
if(matchesAny(region,exceptSystematics,systType)) continue;
if(marked && !systematic->getTagBoolDefault(mark,false)) continue;
if(!matchesAny(systematic,targetSystematics,systType)) continue;
if(verbose) manager->info(TString::Format("\t\tremoving '%s'",systematic->GetName()));
remove.push_back(systematic);
}
}
for(auto systematic:remove){
systematic->detachFromBase();
delete systematic;
}
{
int j=0;
TQFolderIterator newsystematics(source->getListOfFolders(systType+".*"),true);
while(newsystematics.hasNext()){
TQFolder* systematic = newsystematics.readNext();
if(!systematic) continue;
if(matchesAny(region,exceptSystematics,systType)) continue;
if(marked && !systematic->getTagBoolDefault(mark,false)) continue;
if(!matchesAny(systematic,targetSystematics,systType)) continue;
if(verbose) manager->info(TString::Format("\t\tcopying '%s'",systematic->GetName()));
TQFolder* copy = systematic->copy();
copy->setTagString("transferred",sourceRegion->GetName());
if(systematic->hasTagString("HistoLow") && systematic->hasTagString("HistoHigh")){
TString histoPathLow=systematic->getTagStringDefault("HistoLow","");
TString histoPathHigh=systematic->getTagStringDefault("HistoHigh","");
TString nameLow = TString::Format("%s_%s_HistoLow",region->GetName(),sample->GetName());
TString nameHigh = TString::Format("%s_%s_HistoHigh",region->GetName(),sample->GetName());
TH1* TargetnomHist = man.getHisto(sample->getTagStringDefault("Histo",""));
TH1* nomHist = man.getHisto(source->getTagStringDefault("Histo",""));
const TH1* lowHistOrig = man.getHisto(histoPathLow);
const TH1* highHistOrig = man.getHisto(histoPathHigh);
if(!TQHistogramUtils::checkConsistency(nomHist,lowHistOrig) || !TQHistogramUtils::checkConsistency(nomHist,highHistOrig)){
manager->error(TString::Format("transferred histograms for systematic '%s' in sample '%s' in region '%s' are inconsistent, skipping!\n\tnom\t%s\n\tlow\t%s\n\thigh\t%s",systematic->GetName(),sample->GetName(),region->GetName(),TQStringUtils::getDetails(nomHist).Data(),TQStringUtils::getDetails(lowHistOrig).Data(),TQStringUtils::getDetails(highHistOrig).Data()));
Carsten Burgard
committed
if(!systematic->getBase()->tagsAreEquivalentTo(sample,tagCheckFilter)){
manager->error(TString::Format("cowardly refusing to transfer histogram with inconsistent production tags!"));
continue;
}
TH1* lowHist = TQHistogramUtils::copyHistogram(lowHistOrig,nameLow);
TQHistogramUtils::normalize(lowHist,nomHist);
lowHist->Divide(nomHist);
lowHist->Multiply(TargetnomHist);
TQHistogramUtils::normalize(lowHist,TargetnomHist);
TQFolder::getPathTail(histoPathLow);
histograms->addObject(lowHist,histoPathLow+"+");
copy->setTagString("HistoLow",TQFolder::concatPaths(histoPathLow,lowHist->GetName()));
TH1* highHist = TQHistogramUtils::copyHistogram(highHistOrig,nameHigh);
TQHistogramUtils::normalize(highHist,nomHist);
highHist->Divide(nomHist);
highHist->Multiply(TargetnomHist);
TQHistogramUtils::normalize(highHist,TargetnomHist);
TQFolder::getPathTail(histoPathHigh);
histograms->addObject(highHist,histoPathHigh+"+");
copy->setTagString("HistoHigh",TQFolder::concatPaths(histoPathHigh,highHist->GetName()));
sample->addFolder(copy);
addToLog(log,cleanup(systematic->GetName()),sourceChannel,cleanup(region->GetName()));
}
manager->warn(TString::Format("\tno systematics of type %s found in '%s/%s' matching '%s' except '%s'!",systType.Data(),sourceRegion->GetName(),source->GetName(),TQStringUtils::concat(targetSystematics,",").Data(),TQStringUtils::concat(exceptSystematics,",").Data()));
}
if(i>0) return true;
manager->error("no targets found for channel transfer!");
return false;
//no valid mode was selected
manager->error("Failed to perform, no valid mode was selected!");
return false;