6 #include <ROOT/RDataFrame.hxx>
17 std::vector<std::string>
GetParams(std::vector<std::string> &PoIs, ROOT::RDataFrame Map)
20 std::vector<std::string> PtPs;
23 MACH3LOG_INFO(
"No parameters requested, processing all parameters found in the LLHMap!");
26 for(
auto p : Map.GetColumnNames())
28 if(p.find(
"_LLH") != std::string::npos)
36 for(
auto pit = PoIs.begin(); pit != PoIs.end();)
38 if(std::find(PtPs.begin(), PtPs.end(), *pit) != PtPs.end())
43 pit = PoIs.erase(pit);
49 for(
auto pit = PtPs.begin(); pit != PtPs.end();)
51 if(std::find(PoIs.begin(), PoIs.end(), *pit) != PoIs.end() || PoIs.empty())
54 pit = PtPs.erase(pit);
63 std::pair<bool,std::vector<double>>
ExtractBinning(std::string param, YAML::Node Settings, ROOT::RDataFrame Map)
67 unsigned int nExpBins = GetFromManager<unsigned int>(Settings[
"LLHScan"][
"LLHScanPoints"], 20, __FILE__, __LINE__);
69 nExpBins = GetFromManager<unsigned int>(Settings[
"LLHScan"][
"ScanPoints"][param], nExpBins, __FILE__, __LINE__);
73 auto values = Map.Take<
double>(param.c_str());
76 std::set<double> unique(values->begin(), values->end());
78 MACH3LOG_INFO(
"There are {} values (bins) for parameter {} inside LLHMap.", unique.size(), param);
80 if(nExpBins !=
static_cast<unsigned int>(unique.size())) {
81 MACH3LOG_WARN(
"The config expects different number of {} bins for parameter {} than {} values included in LLHMap!", nExpBins, param, unique.size());
82 nExpBins =
static_cast<unsigned int>(unique.size());
86 double minx = *unique.begin();
87 double maxx = *unique.rbegin();
90 double minDiff = maxx - minx;
92 for (
auto it = std::next(unique.begin()); it != unique.end(); ++it) {
93 auto prev = std::prev(it);
94 minDiff = std::min(minDiff, *it - *prev);
97 if (unique.size() > 1) {
98 unsigned int bins =
static_cast<unsigned int>( 1 + std::abs(maxx-minx) / minDiff );
99 if (nExpBins != bins) {
100 MACH3LOG_WARN(
"The scan is not uniform! Instead, we will use bins based on unique scan values and minimal {:.3e} distance between them!", minDiff);
105 double half_w = std::max(1e-12*minx, .5*minDiff);
109 std::vector<double> binning = {minx, maxx};
113 for (
auto it = std::next(unique.begin()); std::next(it) != unique.end(); ++it)
116 double next_edge = *it + half_w;
117 binning.insert(binning.end()-1, next_edge);
120 auto next = std::next(it);
121 if ( std::abs((next_edge - *next + half_w) / (next_edge + *next - half_w )) < 1e-12 )
124 binning.insert(binning.end()-1, *next-half_w);
127 for (
auto it = unique.begin(); std::next(it) != unique.end(); ++it)
128 binning.insert(binning.end()-1, *it + half_w);
131 return std::make_pair(nExpBins>0, binning);
135 int main(
int argc,
char *argv[]) {
142 MACH3LOG_ERROR(
"No arguments! Usage: {} <config.yaml> <file1.root> <file2.root> ...", argv[0]);
147 YAML::Node Settings =
M3OpenConfig(std::string(argv[1]));
148 auto OutFileName = GetFromManager<std::string>(Settings[
"General"][
"OutputFile"],
"LLHMap.root");
149 auto Plot2D = GetFromManager<bool>(Settings[
"LLHScan"][
"Plot2D"],
false, __FILE__, __LINE__);
151 auto OutFile =
new TFile(
OutFileName.c_str(),
"UPDATE");
155 TDirectory* DirProfile1D = OutFile->mkdir(
"Profiled1D_LLH",
"profile1D",
true);
156 TDirectory* DirProfile2D;
157 if (Plot2D) DirProfile2D = OutFile->mkdir(
"Profiled2D_LLH",
"profile2D",
true);
159 TDirectory* DirMarginal1D = OutFile->mkdir(
"Marginal1D_L",
"marginal1D",
true);
160 TDirectory* DirMarginal2D;
161 if (Plot2D) DirMarginal2D = OutFile->mkdir(
"Marginal2D_L",
"marginal2D",
true);
166 for(
int i = 2; i < argc; ++i)
173 auto Map = ROOT::RDataFrame(
"llhmap",
inpFileList);
177 auto LLHMap = Map.Define(
"L",
"exp(-0.5*Total_LLH)");
180 auto ParamsOfInterest = GetFromManager<std::vector<std::string>>(Settings[
"LLHScan"][
"LLHParameters"],{});
181 std::vector<std::string> ParamsToProfile =
GetParams(ParamsOfInterest, Map);
183 MACH3LOG_INFO(
"... Starting generating 1D profiled and marginalized likelihoods ...");
184 MACH3LOG_WARN(
"!!! LLHMap numerical marginalization assumes uncorrelated priors !!!");
186 std::map<std::string, std::unique_ptr<TH1D>> hProfiles1d;
187 std::map<std::string, std::unique_ptr<TH1D>> hMarginals1d;
188 for(
auto p = ParamsToProfile.begin(); p != ParamsToProfile.end(); ++p)
193 std::pair<bool, std::vector<double>> binning =
ExtractBinning(*p, Settings, Map);
195 std::string hProfTitle = *p+
" profiled -2LogL";
196 std::string hProfName = *p+
"_LLHProf1D";
197 std::string hMargTitle = *p+
" marginalized L";
198 std::string hMargName = *p+
"_LMarg1D";
201 auto hprof1d = std::make_unique<TH1D>(hProfName.c_str(), hProfTitle.c_str(),
int(binning.second.size()-1), binning.second.data());
202 hprof1d->SetDirectory(
nullptr);
204 auto hmarg1d = std::make_unique<TH1D>(hMargName.c_str(), hMargTitle.c_str(),
int(binning.second.size()-1), binning.second.data());
205 hmarg1d->SetDirectory(
nullptr);
209 MACH3LOG_INFO(
"Initializing 1D profiled -2LogL and marginalized L histograms for {} of {} bins from {:.3e} to {:.3e} (bin center at {:.3e} and {:.3e})", *p, hprof1d->GetNbinsX(), hprof1d->GetXaxis()->GetXmin(), hprof1d->GetXaxis()->GetXmax(), hprof1d->GetBinCenter(1), hprof1d->GetBinCenter(hprof1d->GetNbinsX()));
213 for (
auto binnie : binning.second)
215 std::ostringstream os;
216 os << std::scientific << std::setprecision(4) << binnie;
217 binnies +=
" "+os.str();
221 MACH3LOG_INFO(
"Initializing 1D profiled -2LogL and marginalized L histograms of {} bins with edges{}.", binning.second.size(), binnies);
224 hProfiles1d[*p] = std::move(hprof1d);
225 hMarginals1d[*p] = std::move(hmarg1d);
228 for(
auto p = ParamsToProfile.begin(); p != ParamsToProfile.end(); ++p)
233 const int count = hProfiles1d[*p]->GetNbinsX() > 5 ? int(
double(hProfiles1d[*p]->GetNbinsX())/
double(5)) : 1;
236 MACH3LOG_INFO(
"Profiling 1D -2LogL and numerically profiling 1D L for parameter {}!", *p);
237 for(
int bidx = 1; bidx < hProfiles1d[*p]->GetNbinsX() + 1; ++bidx)
239 if (bidx % count == 0)
242 auto b_lo = hProfiles1d[*p]->GetXaxis()->GetBinLowEdge(bidx);
243 auto b_hi = b_lo + hProfiles1d[*p]->GetXaxis()->GetBinWidth(bidx);
245 double llhmin = LLHMap.Filter(*p+
">"+std::to_string(b_lo)+
"&&"+*p+
"<"+std::to_string(b_hi)).Min(
"Total_LLH").GetValue();
249 hProfiles1d[*p]->SetBinContent(bidx, llhmin);
251 auto L = LLHMap.Filter(*p+
">"+std::to_string(b_lo)+
"&&"+*p+
"<"+std::to_string(b_hi)).Sum(
"L");
253 hMarginals1d[*p]->SetBinContent(bidx, *L);
258 hProfiles1d[*p]->Write(hProfiles1d[*p]->GetName(), TObject::kOverwrite);
261 hMarginals1d[*p]->Scale(1./hMarginals1d[*p]->Integral());
262 hMarginals1d[*p]->Write(hMarginals1d[*p]->GetName(), TObject::kOverwrite);
268 MACH3LOG_INFO(
"... Starting generating 2D profiled and marginalized likelihoods ...");
270 MACH3LOG_WARN(
"!!! LLHMap numerical marginalization assumes uncorrelated priors !!!");
272 std::vector<std::string> Keys2D;
273 std::vector<std::string> ParamsFiltered;
274 std::map<std::string, std::unique_ptr<TH2D>> hProfiles2d;
275 std::map<std::string, std::unique_ptr<TH2D>> hMarginals2d;
277 for(
auto p : ParamsToProfile)
279 auto h = DirProfile1D->Get<TH1D>((p+
"_LLHProf1D").c_str());
282 MACH3LOG_WARN(
"There is less than 2 bins for {}, 2D is equivalent to 1D! Removing from 2D plots ...", p);
284 ParamsFiltered.push_back(p);
289 for(
auto p1 = ParamsFiltered.begin(); p1 != ParamsFiltered.end(); ++p1)
291 for(
auto p2 = std::next(p1); p2 != ParamsFiltered.end(); ++p2)
293 auto h1 = DirProfile1D->Get<TH1D>((*p1+
"_LLHProf1D").c_str());
294 auto h2 = DirProfile1D->Get<TH1D>((*p2+
"_LLHProf1D").c_str());
296 std::string key = *p1+
"_"+*p2;
297 Keys2D.push_back(key);
299 MACH3LOG_INFO(
"Initializing 2D profiled -2LogL and marginalized L histograms for {} vs. {} based on previously generated 1D histograms.", *p1, *p2);
301 std::string hProfTitle = *p1+
" vs. "+*p2+
" profiled -2LogL";
302 std::string hProfName = key+
"_LLHProf2D";
303 auto hprof2d = std::make_unique<TH2D>(
304 hProfName.c_str(), hProfTitle.c_str(),
305 h1->GetXaxis()->GetNbins(), h1->GetXaxis()->GetXbins()->GetArray(),
306 h2->GetXaxis()->GetNbins(), h2->GetXaxis()->GetXbins()->GetArray()
308 hprof2d->SetDirectory(
nullptr);
310 hProfiles2d[key] = std::move(hprof2d);
312 std::string hMargTitle = *p1+
" vs. "+*p2+
" marginalized L";
313 std::string hMargName = key+
"_LMarg1D";
314 auto hmarg2d = std::make_unique<TH2D>(
315 hMargName.c_str(), hMargTitle.c_str(),
316 h1->GetXaxis()->GetNbins(), h1->GetXaxis()->GetXbins()->GetArray(),
317 h2->GetXaxis()->GetNbins(), h2->GetXaxis()->GetXbins()->GetArray()
319 hmarg2d->SetDirectory(
nullptr);
321 hMarginals2d[key] = std::move(hmarg2d);
325 for(
auto p1 = ParamsFiltered.begin(); p1 != ParamsFiltered.end(); ++p1)
327 for(
auto p2 = std::next(p1); p2 != ParamsFiltered.end(); ++p2)
329 std::string key = *p1+
"_"+*p2;
331 MACH3LOG_INFO(
"Numerically profiling 2D -2LogL and marginalizing 2D L for parameters {} and {}!",*p1, *p2);
332 const Long64_t nBinsX =
static_cast<Long64_t
>(hProfiles2d[key]->GetNbinsX());
333 const Long64_t nBinsY =
static_cast<Long64_t
>(hProfiles2d[key]->GetNbinsY());
335 const Long64_t TotalBins = nBinsX * nBinsY;
336 const int count = TotalBins > 5 ? int(
double(TotalBins)/
double(5)) : 1;
338 for(
int bidx = 1; bidx < nBinsX + 1; ++bidx)
340 for(
int bidy = 1; bidy < nBinsY + 1; ++bidy)
342 if ( ((bidx-1)*hProfiles2d[key]->GetNbinsY() + bidy) % count == 0)
345 auto bx_lo = hProfiles2d[key]->GetXaxis()->GetBinLowEdge(bidx);
346 auto bx_hi = bx_lo + hProfiles2d[key]->GetXaxis()->GetBinWidth(bidx);
348 auto by_lo = hProfiles2d[key]->GetYaxis()->GetBinLowEdge(bidy);
349 auto by_hi = by_lo + hProfiles2d[key]->GetYaxis()->GetBinWidth(bidy);
352 double llhmin = LLHMap.Filter(*p1+
">"+std::to_string(bx_lo)+
"&&"+*p1+
"<"+std::to_string(bx_hi)+
"&&"+*p2+
">"+std::to_string(by_lo)+
"&&"+*p2+
"<"+std::to_string(by_hi)).Min(
"Total_LLH").GetValue();
356 hProfiles2d[key]->SetBinContent(bidx, bidy, llhmin);
358 auto L = LLHMap.Filter(*p1+
">"+std::to_string(bx_lo)+
"&&"+*p1+
"<"+std::to_string(bx_hi)
359 +
"&&"+*p2+
">"+std::to_string(by_lo)+
"&&"+*p2+
"<"+std::to_string(by_hi)).Sum(
"L");
361 hMarginals2d[key]->SetBinContent(bidx,bidy, *L);
367 hProfiles2d[key]->Write(hProfiles2d[key]->GetName(), TObject::kOverwrite);
370 hMarginals2d[key]->Scale(1./hMarginals2d[key]->Integral());
371 hMarginals2d[key]->Write(hMarginals2d[key]->GetName(), TObject::kOverwrite);
std::vector< std::string > inpFileList
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
#define _MaCh3_Safe_Include_End_
void SetMaCh3LoggerFormat()
Set messaging format of the logger.
int main(int argc, char *argv[])
std::pair< bool, std::vector< double > > ExtractBinning(std::string param, YAML::Node Settings, ROOT::RDataFrame Map)
std::vector< std::string > GetParams(std::vector< std::string > &PoIs, ROOT::RDataFrame Map)
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
Custom exception class used throughout MaCh3.
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
void MaCh3Welcome()
KS: Prints welcome message with MaCh3 logo.
constexpr static const double _LARGE_LOGL_
Large Likelihood is used it parameter go out of physical boundary, this indicates in MCMC that such s...