NAGASH 0.9.8
Next Generation Analysis System
Loading...
Searching...
No Matches
ProfileFitter.cxx
Go to the documentation of this file.
1//***************************************************************************************
4//***************************************************************************************
5
7#include "NAGASH/ThreadPool.h"
8
9using namespace NAGASH;
10using namespace std;
11
113ProfileFitter::ProfileFitter(std::shared_ptr<MSGTool> msg, int nthread) : Tool(msg)
114{
115 NTHREAD = nthread;
116 if (NTHREAD > 1)
117 pool = std::make_shared<ThreadPool>(NTHREAD);
118
119 vector<TString> Sample_Name_vec;
120 Gamma_Map.emplace(std::pair<TString, vector<TString>>("Gamma", Sample_Name_vec));
121}
122
123void ProfileFitter::BookParameter(TString name, double init, double min, double max, ParameterType type)
124{
125 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::BookParameter");
126
127 Parameter par;
128 par.Name = name;
129 par.Init = init;
130 par.Value = init;
131 par.Max = max;
132 par.Min = min;
133 par.Type = type;
134
135 if (par.Type == ParameterType::Interest)
137 else
139
140 auto findpar = Par_Map.find(name);
141 if (findpar != Par_Map.end())
142 {
143 MSGUser()->MSG_ERROR("Parameter ", name.TString::Data(), " has already been defined !");
144 MSGUser()->MSG_ERROR("This defination is ignored !");
145 return;
146 }
147 else
148 {
149 Par_Map.emplace(std::pair<TString, Parameter>(name, par));
150 }
151}
152
153void ProfileFitter::BookObservableData(TString name, const std::vector<double> &vec, const std::vector<double> &vec_stat)
154{
155 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::BookObservableData");
156
157 auto findobs = Obs_Map.find(name);
158 Observable *obs = nullptr;
159 if (findobs != Obs_Map.end())
160 {
161 obs = &(findobs->second);
162 }
163 else
164 {
165 obs = InitializeNewObservable(name);
166 }
167
168 if (obs->isdata_booked)
169 {
170 MSGUser()->MSG_ERROR("The data of Observable ", name.TString::Data(), " has already been booked !");
171 MSGUser()->MSG_ERROR("This new booking is ignored !");
172 return;
173 }
174
175 obs->Data = vec;
176 obs->Profile = vec;
177 obs->Data_Stat = vec_stat;
178 obs->isdata_booked = true;
179}
180
181void ProfileFitter::BookObservableNominal(TString name, TString samplename, const std::vector<double> &vec, const std::vector<double> &vec_stat)
182{
183 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::BookObservableNominal");
184
185 bool isfindgamma = false;
186 for (auto &g : Gamma_Map)
187 {
188 if (g.second.size() > 0)
189 {
190 for (int i = 0; i < g.second.size(); i++)
191 {
192 if (g.second[i].TString::EqualTo(samplename.TString::Data()))
193 isfindgamma = true;
194 }
195 }
196 }
197 if (!isfindgamma)
198 Gamma_Map["Gamma"].emplace_back(samplename);
199
200 auto findobs = Obs_Map.find(name);
201 Observable *obs = nullptr;
202 if (findobs != Obs_Map.end())
203 {
204 obs = &(findobs->second);
205 }
206 else
207 {
208 obs = InitializeNewObservable(name);
209 }
210
211 auto findsample = obs->Sample_Map.find(samplename);
212 Observable::Sample *samp = nullptr;
213 if (findsample != obs->Sample_Map.end())
214 {
215 samp = &(findsample->second);
216 if (samp->isnominal_booked)
217 {
218 MSGUser()->MSG_ERROR("The nominal of Sample ", samplename.TString::Data(), " in Observable ", name.TString::Data(), " has already been booked !");
219 MSGUser()->MSG_ERROR("This new booking is ignored !");
220 return;
221 }
222 }
223 else
224 {
225 Observable::Sample newsamp;
226 newsamp.Name = samplename;
227 obs->Sample_Map.emplace(std::pair<TString, ProfileFitter::Observable::Sample>(samplename, newsamp));
228 samp = &((obs->Sample_Map)[samplename]);
229
230 obs->N_Samples = obs->N_Samples + 1;
231 }
232 samp->Nominal = vec;
233 samp->Profile = vec;
234 samp->Nominal_Stat = vec_stat;
235 samp->isnominal_booked = true;
236
237 // check if any value below zero
238 for (int i = 0; i < vec.size(); i++)
239 {
240 if (vec[i] < 0)
241 {
242 MSGUser()->MSG_WARNING("Nominal value of sample ", samplename, " at bin ", i, " is below zero, set to 1e-5! Orignal value and error ", vec[i], " ", vec_stat[i]);
243 samp->Nominal[i] = 1e-5;
244 samp->Profile[i] = 1e-5;
245 }
246 }
247}
248
250{
251 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::GetParamter");
252
253 auto findpar = Par_Map.find(name);
254 if (findpar != Par_Map.end())
255 return &(findpar->second);
256
257 MSGUser()->MSG_ERROR("Parameter ", name.TString::Data(), " has not been defined !");
258 return nullptr;
259}
260
261void ProfileFitter::BookObservableVariation(TString name, TString samplename, const std::vector<double> &vec, TString parname, double sigma)
262{
263 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::BookObservableVariation");
264
265 bool isfindgamma = false;
266 for (auto &g : Gamma_Map)
267 {
268 if (g.second.size() > 0)
269 {
270 for (int i = 0; i < g.second.size(); i++)
271 {
272 if (g.second[i].TString::EqualTo(samplename.TString::Data()))
273 isfindgamma = true;
274 }
275 }
276 }
277 if (!isfindgamma)
278 Gamma_Map["Gamma"].emplace_back(samplename);
279
280 auto findpar = Par_Map.find(parname);
281 if (findpar == Par_Map.end())
282 {
283 MSGUser()->MSG_ERROR("Parameter ", parname.TString::Data(), " has not been defined !");
284 MSGUser()->MSG_ERROR("This Variation has been ignored !");
285 return;
286 }
287
288 // check the input vector
289 std::vector<double> modified_vec = vec;
290 for (int i = 0; i < vec.size(); i++)
291 {
292 if (vec[i] < 0)
293 {
294 modified_vec[i] = 1e-5;
295 MSGUser()->MSG_WARNING("Variation value of sample ", samplename, " at bin ", i, " of par ", parname, " is below zero, set to 1e-5! Orignal value ", vec[i]);
296 }
297 }
298
299 Parameter *par = GetParameter(parname);
300 Observable *obs = nullptr;
301
302 auto findobs = Obs_Map.find(name);
303 if (findobs != Obs_Map.end())
304 {
305 obs = &(findobs->second);
306 }
307 else
308 {
309 obs = InitializeNewObservable(name);
310 }
311
312 auto findsample = obs->Sample_Map.find(samplename);
313 Observable::Sample *samp = nullptr;
314 if (findsample != obs->Sample_Map.end())
315 {
316 samp = &(findsample->second);
317 }
318 else
319 {
320 Observable::Sample newsamp;
321 newsamp.Name = samplename;
322 obs->Sample_Map.emplace(std::pair<TString, ProfileFitter::Observable::Sample>(samplename, newsamp));
323 samp = &((obs->Sample_Map)[samplename]);
324
325 obs->N_Samples = obs->N_Samples + 1;
326 }
327
328 auto findsigma = samp->Variation_Sigma_Map.find(par);
329 if (findsigma != samp->Variation_Sigma_Map.end())
330 {
331 findsigma->second.emplace_back(sigma);
332 }
333 else
334 {
335 vector<double> sigma_vec;
336 sigma_vec.emplace_back(sigma);
337 samp->Variation_Sigma_Map.emplace(std::pair<Parameter *, vector<double>>(par, sigma_vec));
338 }
339
340 auto findvar = samp->Variation_Map.find(par);
341 if (findvar != samp->Variation_Map.end())
342 {
343 findvar->second.emplace_back(modified_vec);
344 }
345 else
346 {
347 vector<vector<double>> var_vec;
348 var_vec.emplace_back(modified_vec);
349 samp->Variation_Map.emplace(std::pair<Parameter *, vector<vector<double>>>(par, var_vec));
350 vector<std::shared_ptr<ProfileCache>> cache_vec;
351 for (int index = 0; index < vec.size(); index++)
352 cache_vec.emplace_back(nullptr);
353 samp->Variation_Cache.emplace(std::pair<Parameter *, vector<std::shared_ptr<ProfileCache>>>(par, cache_vec));
354 }
355
356 auto findsym = samp->NeedSymmetrization_Map.find(par);
357 if (findsym == samp->NeedSymmetrization_Map.end())
358 {
359 samp->NeedSymmetrization_Map.emplace(std::pair<Parameter *, bool>(par, false));
360 }
361
362 auto findsmooth = samp->SmoothLevel_Map.find(par);
363 if (findsmooth == samp->SmoothLevel_Map.end())
364 {
365 samp->SmoothLevel_Map.emplace(std::pair<Parameter *, int>(par, -1));
366 }
367
368 samp->N_Variations = samp->N_Variations + 1;
369
370 if (fabs(sigma) < 1e-5)
371 {
372 auto findvar = samp->Variation_Nominal_Map.find(par);
373 if (findvar != samp->Variation_Nominal_Map.end())
374 {
375 findvar->second = modified_vec;
376 MSGUser()->MSG_ERROR("Nominal for Parameter ", par->Name.TString::Data(), " Sample ", samplename.TString::Data(), " has already defined !");
377 }
378 else
379 {
380 samp->Variation_Nominal_Map.emplace(std::pair<Parameter *, vector<double>>(par, modified_vec));
381 }
382 } // 0 sigma
383 if (fabs(sigma - 1) < 1e-5)
384 {
385 auto findvar = samp->Variation_Up_Map.find(par);
386 if (findvar != samp->Variation_Up_Map.end())
387 {
388 findvar->second = modified_vec;
389 MSGUser()->MSG_ERROR("Up Variation for Parameter ", par->Name.TString::Data(), " Sample ", samplename.TString::Data(), " has already defined !");
390 }
391 else
392 {
393 samp->Variation_Up_Map.emplace(std::pair<Parameter *, vector<double>>(par, modified_vec));
394 }
395 } // 1 sigma
396 if (fabs(sigma + 1) < 1e-5)
397 {
398 auto findvar = samp->Variation_Down_Map.find(par);
399 if (findvar != samp->Variation_Down_Map.end())
400 {
401 findvar->second = modified_vec;
402 MSGUser()->MSG_ERROR("Down Variation for Parameter ", par->Name.TString::Data(), " Sample ", samplename.TString::Data(), " has already defined !");
403 }
404 else
405 {
406 samp->Variation_Down_Map.emplace(std::pair<Parameter *, vector<double>>(par, modified_vec));
407 }
408 } // -1 sigma
409}
410
411void ProfileFitter::BookObservableVariationFromUnc(TString name, TString samplename, const std::vector<double> &vec, const std::vector<double> &vec_unc, TString parname)
412{
413 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::BookObservableVariationUnc");
414
415 bool isfindgamma = false;
416 for (auto &g : Gamma_Map)
417 {
418 if (g.second.size() > 0)
419 {
420 for (int i = 0; i < g.second.size(); i++)
421 {
422 if (g.second[i].TString::EqualTo(samplename.TString::Data()))
423 isfindgamma = true;
424 }
425 }
426 }
427 if (!isfindgamma)
428 Gamma_Map["Gamma"].emplace_back(samplename);
429
430 auto findpar = Par_Map.find(parname);
431 if (findpar == Par_Map.end())
432 {
433 MSGUser()->MSG_ERROR("Parameter ", parname.TString::Data(), " has not been defined !");
434 MSGUser()->MSG_ERROR("This Variation has been ignored !");
435 return;
436 }
437
438 std::vector<double> vec_up = vec;
439 std::vector<double> vec_down = vec;
440
441 for (int i = 0; i < vec.size(); i++)
442 {
443 vec_up[i] += vec_unc[i];
444 vec_down[i] -= vec_unc[i];
445 }
446
447 BookObservableVariationNominal(name, samplename, vec, parname);
448 BookObservableVariationUp(name, samplename, vec_up, parname);
449 BookObservableVariationDown(name, samplename, vec_down, parname);
450}
451
453{
454 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::InitializeNewObservable");
455
456 auto findobs = Obs_Map.find(name);
457 if (findobs != Obs_Map.end())
458 {
459 MSGUser()->MSG_ERROR("Observable ", name.TString::Data(), " has already been defined !");
460 return nullptr;
461 }
462
464 obs.Name = name;
465 Obs_Map.emplace(std::pair<TString, ProfileFitter::Observable>(name, obs));
466
467 return &(Obs_Map[name]);
468}
469
470// Main Fitting
472{
473 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::Fit");
474 PrintInfo();
475 Prepare(method);
476
477 if (!Check())
478 {
479 MSGUser()->MSG_ERROR("Inputs check failed ! The fitting is not processed ! ");
480 return;
481 }
482
484 FitPLH();
485
487 FitACS();
488
490 {
491 FitACS();
492 FitPLH();
493 }
494
495 PrintResult();
496}
497
499{
500 MSGUser()->MSG_INFO("// ------------------------ //");
501 MSGUser()->MSG_INFO("// Parameter Fitting Result //");
502 MSGUser()->MSG_INFO("// ------------------------ //");
503 MSGUser()->MSG_INFO("Name Type");
504 for (auto &p : Par_Map)
505 {
506 if (p.second.isFixed)
507 continue;
508 if (p.second.Type == ParameterType::Interest)
509 MSGUser()->MSG_INFO(p.second.Name.TString::Data(), " POI ", p.second.Value, " ", p.second.Error);
510 }
511 for (auto &p : Par_Map)
512 {
513 if (p.second.isFixed)
514 continue;
515 if (p.second.Type == ParameterType::Normalization)
516 MSGUser()->MSG_INFO(p.second.Name.TString::Data(), " Normalization ", p.second.Value, " ", p.second.Error);
517 }
518 for (auto &p : Par_Map)
519 {
520 if (p.second.isFixed)
521 continue;
522 if (p.second.Type == ParameterType::Nuisance)
523 MSGUser()->MSG_INFO(p.second.Name.TString::Data(), " Nuisance ", p.second.Value, " ", p.second.Error);
524 }
525 for (auto &p : Par_Map)
526 {
527 if (p.second.isFixed)
528 continue;
529 if (p.second.Type == ParameterType::StatGamma)
530 MSGUser()->MSG_INFO(p.second.Name.TString::Data(), " Gamma ", p.second.Value, " ", p.second.Error);
531 }
532}
533
535{
536 MSGUser()->MSG_INFO("// ---------- //");
537 MSGUser()->MSG_INFO("// Basic Info //");
538 MSGUser()->MSG_INFO("//----------- //");
539 MSGUser()->MSG_INFO("Number of Observables: ", Obs_Map.size());
540 MSGUser()->MSG_INFO("Number of Parameters: ", Par_Map.size());
541 MSGUser()->MSG_INFO("Number of Parameters of Interest (POIS): ", GetNParameters(ParameterType::Interest));
542 MSGUser()->MSG_INFO("Number of Nuisance Parameters: ", GetNParameters(ParameterType::Nuisance));
543 MSGUser()->MSG_INFO("Number of Normalization Parameter: ", GetNParameters(ParameterType::Normalization));
544 MSGUser()->MSG_INFO("// -------------- //");
545 MSGUser()->MSG_INFO("// Parameter List //");
546 MSGUser()->MSG_INFO("// -------------- //");
547 MSGUser()->MSG_INFO("Name Type");
548 for (auto &p : Par_Map)
549 {
550 if (p.second.Type == ParameterType::Interest)
551 MSGUser()->MSG_INFO(p.second.Name.TString::Data(), " POI");
552 }
553 for (auto &p : Par_Map)
554 {
555 if (p.second.Type == ParameterType::Nuisance)
556 MSGUser()->MSG_INFO(p.second.Name.TString::Data(), " Nuisance");
557 }
558 for (auto &p : Par_Map)
559 {
560 if (p.second.Type == ParameterType::Normalization)
561 MSGUser()->MSG_INFO(p.second.Name.TString::Data(), " Normalization");
562 }
563 MSGUser()->MSG_INFO("// --------------- //");
564 MSGUser()->MSG_INFO("// Observable List //");
565 MSGUser()->MSG_INFO("// --------------- //");
566 for (auto &obs : Obs_Map)
567 {
568 MSGUser()->MSG_INFO(obs.second.Name.TString::Data(), " NBins: ", obs.second.Data.size(), " NSamples: ", obs.second.Sample_Map.size());
569 for (auto &samp : obs.second.Sample_Map)
570 MSGUser()->MSG_INFO(" ", samp.second.Name, " NParameters: ", samp.second.Variation_Map.size(), " NVariations: ", samp.second.N_Variations);
571 }
572}
573
575{
576 // TODO
577 return true;
578}
579
581{
582 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::Prepare");
583
584 for (auto &obs : Obs_Map)
585 {
586 for (auto &samp : obs.second.Sample_Map)
587 {
588 samp.second.Start_Index = obs.second.Start_Index;
589 samp.second.End_Index = obs.second.End_Index;
590 samp.second.Rebin_Index = obs.second.Rebin_Index;
591 }
592 }
593
594 for (auto &obs : Obs_Map)
595 obs.second.SortVariations();
596 if (method == FitMethod::ProfileLikelihood ||
598 {
599 // Book Gamma Variations
600 for (auto &obs : Obs_Map)
601 {
602 if (obs.second.isgamma_booked == true)
603 {
604 MSGUser()->MSG_ERROR("Statistical Nuisance Parameters for Observable ", obs.first.TString::Data(), " have already been booked !");
605 return;
606 }
607
608 for (auto &g : Gamma_Map)
609 {
610 bool needtobook = false;
611 vector<Parameter *> gamma_vec;
612 if (g.second.size() > 0)
613 {
614 for (int i = 0; i < g.second.size(); i++)
615 {
616 auto findsample = obs.second.Sample_Map.find(g.second[i]);
617 if (findsample != obs.second.Sample_Map.end())
618 {
619 needtobook = true;
620 }
621 }
622 }
623 if (needtobook)
624 {
625 int ncount = 0;
626 Parameter *gamma_ptr;
627 for (int i = 0; i < obs.second.Data.size(); i++)
628 {
629 if ((i >= (obs.second.Start_Index > 0 ? obs.second.Start_Index : 0)) &&
630 (i <= (obs.second.End_Index > 0 ? obs.second.End_Index : obs.second.Data.size())))
631 {
632 if (ncount == 0)
633 {
634 TString gamma_name = TString::Format("Stat_%s_%s_Bin_%d", g.first.TString::Data(), obs.first.TString::Data(), i);
636 MSGUser()->MSG_INFO("Book Stat Gamma: ", gamma_name.TString::Data());
637 gamma_ptr = GetParameter(gamma_name);
638 gamma_vec.emplace_back(gamma_ptr);
639 ncount = ncount + 1;
640 }
641 else
642 {
643 gamma_vec.emplace_back(gamma_ptr);
644 ncount = ncount + 1;
645 }
646 if (ncount == obs.second.Rebin_Index)
647 ncount = 0;
648 }
649 else
650 gamma_vec.emplace_back(nullptr);
651 }
652
653 for (auto &samp : obs.second.Sample_Map)
654 {
655 bool isprefix = false;
656 if (g.second.size() > 0)
657 {
658 for (int i = 0; i < g.second.size(); i++)
659 {
660 if (g.second[i].TString::EqualTo(samp.first.TString::Data()))
661 isprefix = true;
662 }
663 }
664 if (isprefix)
665 samp.second.Gamma_Vec = gamma_vec;
666 }
667 }
668 }
669 obs.second.isgamma_booked = true;
670 }
671
672 // Calculate the sigma of the gammas
673 for (auto &par : Par_Map)
674 {
675 if (par.second.Type != ParameterType::StatGamma)
676 continue;
677
678 Parameter *par_ptr = GetParameter(par.first);
679
680 double val = 0;
681 double err = 0;
682
683 for (auto &obs : Obs_Map)
684 {
685 for (auto &samp : obs.second.Sample_Map)
686 {
687 for (int index = 0; index < samp.second.Gamma_Vec.size(); index++)
688 {
689 if (par_ptr == samp.second.Gamma_Vec[index])
690 {
691 val = val + samp.second.Nominal[index];
692 err = err + pow(samp.second.Nominal_Stat[index], 2);
693 }
694 }
695 }
696 }
697
698 err = sqrt(err);
699
700 par_ptr->Nuisance_Gaus_Mean = 1;
701 par_ptr->Nuisance_Gaus_Sigma = err / val;
702 MSGUser()->MSG_INFO(par_ptr->Name.TString::Data(),
703 " Mean : ", par_ptr->Nuisance_Gaus_Mean,
704 " Sigma : ", par_ptr->Nuisance_Gaus_Sigma);
705
706 par_ptr->Init = 1;
707 par_ptr->Value = 1;
708 par_ptr->Error = err / val;
709 par_ptr->Max = 1 + MAX_NUISANCE_SIGMA * err / val;
710 par_ptr->Min = 1 - MAX_NUISANCE_SIGMA * err / val;
711 }
712 }
713
714 // Link Normalization Factor
715 for (auto &obs : Obs_Map)
716 {
717 for (auto &samp : obs.second.Sample_Map)
718 {
719 for (auto &par : Norm_Map)
720 {
721 if (par.second.size() > 0)
722 {
723 for (int i = 0; i < par.second.size(); i++)
724 {
725 if (par.second[i].TString::EqualTo(samp.second.Name.TString::Data()))
726 {
727 samp.second.Norm_Par = GetParameter(par.first);
728 }
729 }
730 }
731 }
732 }
733 }
734
735 // Symmetrization
736 for (auto &obs : Obs_Map)
737 {
738 for (auto &samp : obs.second.Sample_Map)
739 {
740 for (auto &par : samp.second.NeedSymmetrization_Map)
741 {
742 if (par.second == true)
743 {
744 MSGUser()->MSG_INFO("Symmetrize Variations for Obs: ", obs.first.TString::Data(), " Sample: ", samp.first.TString::Data(), " Parameter: ", par.first->Name.TString::Data());
745 auto findnom = samp.second.Variation_Nominal_Map.find(par.first);
746 auto findup = samp.second.Variation_Up_Map.find(par.first);
747 auto finddown = samp.second.Variation_Down_Map.find(par.first);
748 if (findnom != samp.second.Variation_Nominal_Map.end())
749 {
750 for (int i = 0; i < samp.second.Variation_Sigma_Map[par.first].size(); i++)
751 {
752 for (int j = 0; j < samp.second.Variation_Sigma_Map[par.first].size(); j++)
753 {
754 if (fabs(samp.second.Variation_Sigma_Map[par.first][i] + samp.second.Variation_Sigma_Map[par.first][j]) < 1e-5)
755 {
756 if (samp.second.Variation_Sigma_Map[par.first][i] > 0)
757 SymmetrizeVariation(samp.second.Variation_Map[par.first][i],
758 samp.second.Variation_Map[par.first][j],
759 samp.second.Variation_Nominal_Map[par.first]);
760 }
761 }
762 }
763 if ((findup != samp.second.Variation_Up_Map.end()) &&
764 (finddown != samp.second.Variation_Down_Map.end()))
765 SymmetrizeVariation(samp.second.Variation_Up_Map[par.first],
766 samp.second.Variation_Down_Map[par.first],
767 samp.second.Variation_Nominal_Map[par.first]);
768 }
769 }
770 }
771 }
772 }
773
774 // Smooth
775 for (auto &obs : Obs_Map)
776 {
777 for (auto &samp : obs.second.Sample_Map)
778 {
779 for (auto &par : samp.second.SmoothLevel_Map)
780 {
781 if (par.second > 0)
782 {
783 MSGUser()->MSG_INFO("Smooth Variations for Obs: ", obs.first.TString::Data(), " Sample: ", samp.first.TString::Data(), " Parameter: ", par.first->Name.TString::Data());
784 auto findnom = samp.second.Variation_Nominal_Map.find(par.first);
785 auto findup = samp.second.Variation_Up_Map.find(par.first);
786 auto finddown = samp.second.Variation_Down_Map.find(par.first);
787 auto findvar = samp.second.Variation_Map.find(par.first);
788 if (findnom != samp.second.Variation_Nominal_Map.end())
789 {
790 if (findup != samp.second.Variation_Up_Map.end())
791 SmoothVariation(findup->second, findnom->second, par.second);
792 if (finddown != samp.second.Variation_Down_Map.end())
793 SmoothVariation(finddown->second, findnom->second, par.second);
794
795 if (findvar != samp.second.Variation_Map.end())
796 {
797 for (int i = 0; i < (findvar->second).size(); i++)
798 SmoothVariation((findvar->second)[i], findnom->second, par.second);
799 }
800 }
801 }
802 }
803 }
804 }
805}
806
808{
809 int n = 0;
810 if (type == ParameterType::Unknown)
811 return Par_Map.size();
812 for (auto &p : Par_Map)
813 {
814 if (p.second.Type == type)
815 n = n + 1;
816 }
817 return n;
818}
819
821{
822 if (i >= Par_Map.size() || i < 0)
823 {
824 MSGUser()->MSG_ERROR("Negative Index or Index Too Large! Return Parameter Name : Unknown");
825 return "Unknown";
826 }
827 else
828 {
829 int n = 0;
830 for (auto &p : Par_Map)
831 {
832 if (n == i)
833 return p.second.Name;
834 n = n + 1;
835 }
836 }
837 return "Unknown";
838}
839
841{
842 // if (std::isnan(aim_sigma))
843 // aim_sigma = 0.0;
844
845 vector<double> sigma_vec = Variation_Sigma_Map[par];
846 vector<vector<double>> variation_vec = Variation_Map[par];
847 std::shared_ptr<ProfileCache> m_cache = Variation_Cache[par][i];
848
849 if (sigma_vec.size() < 2 || variation_vec.size() != sigma_vec.size())
850 cout << "Variation Number Less Than 2 !" << endl;
851
853 {
854
855 bool isok = true;
856
857 auto findnom = Variation_Nominal_Map.find(par);
858 auto finddown = Variation_Down_Map.find(par);
859 auto findup = Variation_Up_Map.find(par);
860 if (findnom != Variation_Nominal_Map.end() &&
861 (finddown != Variation_Down_Map.end() || findup != Variation_Up_Map.end()))
862 isok = true;
863 else
864 {
865 cout << par->Name.TString::Data() << " Not Satisfy the condition of Extrap Strategy POLY6EXP !" << endl;
866 isok = false;
867 }
868
869 // 1 + a1 x + a2 x^2 + a3 x^3 + ... a6 x^6
870 // a1 + 2 a2 x + ... + 6 a6 x^5
871 // 2 a2 + 3 * 2 a3 + ... + 6 * 5 a6 x^4
872 if (isok)
873 {
874
875 if (m_cache == nullptr)
876 {
877 m_cache = std::make_shared<ProfileCache>();
878 Variation_Cache[par][i] = m_cache;
879
880 double base = 1;
881 if (findup != Variation_Up_Map.end())
882 base = (findup->second)[i] / (findnom->second)[i];
883 else
884 base = (-(finddown->second)[i] + 2 * (findnom->second)[i]) / (findnom->second)[i];
885 m_cache->SaveCache("BaseUp", base);
886
887 if (finddown != Variation_Down_Map.end())
888 base = (finddown->second)[i] / (findnom->second)[i];
889 else
890 base = (-(findup->second)[i] + 2 * (findnom->second)[i]) / (findnom->second)[i];
891 m_cache->SaveCache("BaseDown", base);
892
893 double Y1 = 0;
894 if (findup != Variation_Up_Map.end())
895 Y1 = (findup->second)[i];
896 else
897 Y1 = (-(finddown->second)[i] + 2 * (findnom->second)[i]);
898 double Y2 = 0;
899 if (finddown != Variation_Down_Map.end())
900 Y2 = (finddown->second)[i];
901 else
902 Y2 = (-(findup->second)[i] + 2 * (findnom->second)[i]);
903 double Y0 = (findnom->second)[i];
904
905 double LGY1 = TMath::Log(Y1 / Y0);
906 double LGY2 = TMath::Log(Y2 / Y0);
907 double LGY1S = pow(TMath::Log(Y1 / Y0), 2);
908 double LGY2S = pow(TMath::Log(Y2 / Y0), 2);
909
910 double a[6];
911 a[0] = -(-15 * Y1 + 15 * Y2 + 7 * Y1 * LGY1 - Y1 * LGY1S - 7 * Y2 * LGY2 + Y2 * LGY2S) / (16 * Y0);
912 a[1] = -(48 * Y0 - 24 * Y1 - 24 * Y2 + 9 * Y1 * LGY1 - Y1 * LGY1S + 9 * Y2 * LGY2 - Y2 * LGY2S) / (16 * Y0);
913 a[2] = -(5 * Y1 - 5 * Y2 - 5 * Y1 * LGY1 + Y1 * LGY1S + 5 * Y2 * LGY2 - Y2 * LGY2S) / (8 * Y0);
914 a[3] = -(-24 * Y0 + 12 * Y1 + 12 * Y2 - 7 * Y1 * LGY1 + Y1 * LGY1S - 7 * Y2 * LGY2 + Y2 * LGY2S) / (8 * Y0);
915 a[4] = -(-3 * Y1 + 3 * Y2 + 3 * Y1 * LGY1 - Y1 * LGY1S - 3 * Y2 * LGY2 + Y2 * LGY2S) / (16 * Y0);
916 a[5] = -(16 * Y0 - 8 * Y1 - 8 * Y2 + 5 * Y1 * LGY1 - Y1 * LGY1S + 5 * Y2 * LGY2 - Y2 * LGY2S) / (16 * Y0);
917
918 m_cache->SaveCache("A0", a[0]);
919 m_cache->SaveCache("A1", a[1]);
920 m_cache->SaveCache("A2", a[2]);
921 m_cache->SaveCache("A3", a[3]);
922 m_cache->SaveCache("A4", a[4]);
923 m_cache->SaveCache("A5", a[5]);
924 }
925
926 if (aim_sigma >= 1)
927 return (findnom->second)[i] * pow(m_cache->GetCache("BaseUp"), aim_sigma);
928 else if (aim_sigma <= -1)
929 return (findnom->second)[i] * pow(m_cache->GetCache("BaseDown"), -aim_sigma);
930 else
931 {
932
933 double a[6];
934
935 a[0] = m_cache->GetCache("A0");
936 a[1] = m_cache->GetCache("A1");
937 a[2] = m_cache->GetCache("A2");
938 a[3] = m_cache->GetCache("A3");
939 a[4] = m_cache->GetCache("A4");
940 a[5] = m_cache->GetCache("A5");
941
942 double base = aim_sigma;
943 double sum = 1.0;
944 for (int k = 0; k < 6; k++)
945 {
946 sum = sum + a[k] * base;
947 base = base * aim_sigma;
948 }
949
950 return (findnom->second)[i] * sum;
951 }
952 }
953 }
954
955 // Linear Extrapolation
956
957 if (m_cache == nullptr)
958 {
959 m_cache = std::make_shared<ProfileCache>();
960 Variation_Cache[par][i] = m_cache;
961
962 for (int index = 0; index < sigma_vec.size() - 1; index++)
963 {
964 double X1 = sigma_vec[index];
965 double X2 = sigma_vec[index + 1];
966 double Y1 = variation_vec[index][i];
967 double Y2 = variation_vec[index + 1][i];
968
969 double A = Y2 - Y1;
970 double B = X1 - X2;
971 double C = X2 * Y1 - X1 * Y2;
972
973 m_cache->SaveCache(TString::Format("A_%d", index), A);
974 m_cache->SaveCache(TString::Format("B_%d", index), B);
975 m_cache->SaveCache(TString::Format("C_%d", index), C);
976 }
977 }
978
979 int index1 = -1;
980 int index2 = -1;
981 if (aim_sigma <= sigma_vec[0])
982 {
983 index1 = 0;
984 index2 = 1;
985 }
986 else if (aim_sigma >= sigma_vec[sigma_vec.size() - 1])
987 {
988 index1 = sigma_vec.size() - 1;
989 index2 = sigma_vec.size() - 2;
990 }
991 else
992 {
993 for (int j = 0; j < sigma_vec.size() - 1; j++)
994 {
995 if (aim_sigma >= sigma_vec[j] &&
996 aim_sigma < sigma_vec[j + 1])
997 {
998 index1 = j;
999 index2 = j + 1;
1000 }
1001 }
1002 }
1003
1004 if (index1 < 0 || index2 < 0)
1005 {
1006 cout << "Negative Extrapolation Index for parameter " << par->Name << endl;
1007 std::cout << aim_sigma << std::endl;
1008 for (int i = 0; i < sigma_vec.size(); i++)
1009 std::cout << sigma_vec[i] << " ";
1010 std::cout << std::endl;
1011 }
1012
1013 double A;
1014 double B;
1015 double C;
1016
1017 if (index1 < index2)
1018 {
1019 A = m_cache->GetCache(TString::Format("A_%d", index1));
1020 B = m_cache->GetCache(TString::Format("B_%d", index1));
1021 C = m_cache->GetCache(TString::Format("C_%d", index1));
1022 }
1023 else
1024 {
1025 A = m_cache->GetCache(TString::Format("A_%d", index2));
1026 B = m_cache->GetCache(TString::Format("B_%d", index2));
1027 C = m_cache->GetCache(TString::Format("C_%d", index2));
1028 }
1029
1030 return (-A * aim_sigma - C) / B;
1031}
1032
1033void ProfileFitter::Observable::GetProfile(std::map<TString, Parameter> &m_par)
1034{
1035 for (auto &samp : Sample_Map)
1036 samp.second.GetProfile(m_par);
1037
1038 for (int i = (Start_Index > 0 ? Start_Index : 0); i < (End_Index > 0 ? End_Index + 1 : Profile.size()); i++)
1039 {
1040 double sum = 0;
1041 for (auto &samp : Sample_Map)
1042 sum = sum + samp.second.Profile[i];
1043 Profile[i] = sum;
1044 }
1045}
1046
1047void ProfileFitter::Observable::Sample::GetProfile(std::map<TString, Parameter> &m_par)
1048{
1049 for (int i = (Start_Index > 0 ? Start_Index : 0); i < (End_Index > 0 ? End_Index + 1 : Profile.size()); i++)
1050 {
1051 Profile[i] = Nominal[i];
1052
1053 for (auto &itr : Variation_Sigma_Map)
1054 {
1055 if (Variation_Cache[itr.first][i] == nullptr)
1056 {
1057 double aim_profile = GetProfileBinVariation(i, (m_par[itr.first->Name]).Value, itr.first);
1058 double aim_nominal = GetProfileBinVariation(i, (m_par[itr.first->Name]).Init, itr.first);
1059 Variation_Cache[itr.first][i]->SaveCache("Nominal", aim_nominal);
1060 Profile[i] = Profile[i] + (aim_profile - aim_nominal);
1061
1062 // std::cout << this->Name << " " << itr.first->Name << " " << i << " " << aim_profile << " " << aim_nominal << std::endl;
1063 }
1064 else
1065 {
1066 double aim_profile = GetProfileBinVariation(i, (m_par[itr.first->Name]).Value, itr.first);
1067 double aim_nominal = Variation_Cache[itr.first][i]->GetCache("Nominal");
1068 Profile[i] = Profile[i] + (aim_profile - aim_nominal);
1069
1070 // std::cout << this->Name << " " << itr.first->Name << " " << i << " " << aim_profile << " " << aim_nominal << std::endl;
1071 }
1072 }
1073
1074 if (Norm_Par != nullptr)
1075 {
1076 Profile[i] = Profile[i] * (m_par[Norm_Par->Name]).Value;
1077 }
1078
1079 if (Gamma_Vec.size() > 0)
1080 {
1081 Profile[i] = Profile[i] * (m_par[Gamma_Vec[i]->Name]).Value;
1082 }
1083 }
1084}
1085
1087{
1088 double prob = 0;
1089
1090 int ncount = 0;
1091 double D = 0;
1092 double P = 0;
1093 double D_S = 0;
1094
1095 for (int i = (Start_Index > 0 ? Start_Index : 0); i < (End_Index > 0 ? End_Index + 1 : Profile.size()); i++)
1096 {
1097 ncount = ncount + 1;
1098 D = D + Data[i];
1099 P = P + Profile[i];
1100 if (!USE_POISSON)
1101 D_S = D_S + Data_Stat[i] * Data_Stat[i];
1102
1103 if (ncount == Rebin_Index)
1104 {
1105 double p = 1;
1106 if (USE_POISSON)
1107 p = D * std::log(P) - P - std::lgamma(D + 1.);
1108 else
1109 p = -0.5 * std::pow((D - P) / std::sqrt(D_S), 2);
1110
1111 prob += p;
1112
1113 ncount = 0;
1114 D = 0;
1115 P = 0;
1116 D_S = 0;
1117 }
1118 }
1119
1120 if (ncount > 0)
1121 {
1122 double p = 1;
1123 if (USE_POISSON)
1124 p = D * std::log(P) - P - std::lgamma(D + 1.);
1125 else
1126 p = -0.5 * std::pow((D - P) / std::sqrt(D_S), 2);
1127
1128 prob += p;
1129 }
1130
1131 return prob;
1132}
1133
1135{
1136 for (auto &samp : Sample_Map)
1137 samp.second.SortVariations();
1138}
1139
1141{
1142 std::map<Parameter *, std::vector<double>>::iterator sig_itr;
1143 std::map<Parameter *, std::vector<std::vector<double>>>::iterator var_itr;
1144
1145 var_itr = Variation_Map.begin();
1146 for (sig_itr = Variation_Sigma_Map.begin(); sig_itr != Variation_Sigma_Map.end(); sig_itr++)
1147 {
1148 if (sig_itr->second.size() >= 2)
1149 {
1150 for (int i = 0; i < sig_itr->second.size() - 1; i++)
1151 {
1152 for (int j = i + 1; j < sig_itr->second.size(); j++)
1153 {
1154 if ((sig_itr->second)[i] > (sig_itr->second)[j])
1155 {
1156 double temp = (sig_itr->second)[i];
1157 (sig_itr->second)[i] = (sig_itr->second)[j];
1158 (sig_itr->second)[j] = temp;
1159
1160 std::vector<double> temp_vec = (var_itr->second)[i];
1161 (var_itr->second)[i] = (var_itr->second)[j];
1162 (var_itr->second)[j] = temp_vec;
1163 }
1164 }
1165 }
1166 }
1167 var_itr++;
1168 }
1169}
1170
1172{
1173 // Calculate Gamma Matrix
1174 // Sensitivity Matrix : dt_i / da_l
1175 int Total_Template_BinNum = 0;
1176 for (auto &obs : Obs_Map)
1177 {
1178 Total_Template_BinNum = Total_Template_BinNum +
1179 (obs.second.End_Index > 0 ? obs.second.End_Index + 1 : obs.second.GetNbins()) -
1180 (obs.second.Start_Index > 0 ? obs.second.Start_Index : 0);
1181 }
1182 int NP_Num = 0;
1183 int POI_Num = 0;
1184 for (auto &par : Par_Map)
1185 {
1186 if (par.second.isFixed)
1187 continue;
1188
1189 if (par.second.Type == ParameterType::Interest)
1190 POI_Num++;
1191 if (par.second.Type == ParameterType::Nuisance)
1192 NP_Num++;
1193 if (par.second.Type == ParameterType::Normalization)
1194 POI_Num++;
1195 }
1196
1197 Gamma_Matrix = Eigen::MatrixXd(Total_Template_BinNum, NP_Num);
1198 V_Matrix = Eigen::MatrixXd(Total_Template_BinNum, Total_Template_BinNum);
1199 H_Matrix = Eigen::MatrixXd(Total_Template_BinNum, POI_Num);
1200 Y0_Matrix = Eigen::MatrixXd(Total_Template_BinNum, 1);
1201
1202 int bin_index = 0;
1203 int par_index = 0;
1204 int poi_index = 0;
1205 for (auto &obs : Obs_Map)
1206 {
1207 for (int index = (obs.second.Start_Index > 0 ? obs.second.Start_Index : 0); index < (obs.second.End_Index > 0 ? obs.second.End_Index + 1 : obs.second.GetNbins()); index++)
1208 {
1209 par_index = 0;
1210 poi_index = 0;
1211 for (auto &par : Par_Map)
1212 {
1213 if (par.second.isFixed)
1214 continue;
1215
1216 if ((par.second.Type == ParameterType::Nuisance) ||
1217 (par.second.Type == ParameterType::Interest))
1218 {
1219 Parameter *par_ptr = &(par.second);
1220 double sum_k = 0;
1221 for (auto &samp : obs.second.Sample_Map)
1222 {
1223 if (samp.second.Variation_Map.find(par_ptr) != samp.second.Variation_Map.end())
1224 {
1225 double k = 0;
1226 // calculate k
1227
1228 // Average values
1229 double ax = 0;
1230 double ay = 0;
1231 for (int v = 0; v < samp.second.Variation_Sigma_Map[par_ptr].size(); v++)
1232 {
1233 ax = ax + samp.second.Variation_Sigma_Map[par_ptr][v];
1234 ay = ay + samp.second.Variation_Map[par_ptr][v][index];
1235 }
1236 ax = ax / samp.second.Variation_Sigma_Map[par_ptr].size();
1237 ay = ay / samp.second.Variation_Sigma_Map[par_ptr].size();
1238
1239 double top = 0;
1240 double bottom = 0;
1241 for (int v = 0; v < samp.second.Variation_Sigma_Map[par_ptr].size(); v++)
1242 {
1243 top = top + (samp.second.Variation_Sigma_Map[par_ptr][v] - ax) * (samp.second.Variation_Map[par_ptr][v][index] - ay);
1244 bottom = bottom + pow(samp.second.Variation_Sigma_Map[par_ptr][v] - ax, 2);
1245 }
1246
1247 k = top / bottom;
1248
1249 sum_k = sum_k + k;
1250 }
1251 }
1252
1253 if (!isfinite(sum_k))
1254 MSGUser()->MSG_INFO("Sensitivity : ", sum_k);
1255 if (par.second.Type == ParameterType::Nuisance)
1256 {
1257 Gamma_Matrix(bin_index, par_index) = sum_k;
1258 par_index++;
1259 }
1260 if (par.second.Type == ParameterType::Interest)
1261 {
1262 H_Matrix(bin_index, poi_index) = sum_k;
1263 poi_index++;
1264 }
1265 }
1266
1267 if (par.second.Type == ParameterType::Normalization)
1268 {
1269 Parameter *par_ptr = &(par.second);
1270 double sum_k = 0;
1271 for (auto &samp : obs.second.Sample_Map)
1272 {
1273 if (samp.second.Norm_Par == par_ptr)
1274 {
1275 sum_k = sum_k + samp.second.Nominal[index];
1276 }
1277 }
1278
1279 if (!isfinite(sum_k))
1280 MSGUser()->MSG_INFO("Sensitivity : ", sum_k);
1281
1282 H_Matrix(bin_index, poi_index) = sum_k;
1283 poi_index++;
1284 }
1285 }
1286
1287 for (int i = 0; i < Total_Template_BinNum; i++)
1288 {
1289 V_Matrix(bin_index, i) = 0;
1290 V_Matrix(i, bin_index) = 0;
1291 }
1292 double stat_err = pow(obs.second.Data_Stat[index], 2);
1293 double y0 = obs.second.Data[index];
1294 for (auto &samp : obs.second.Sample_Map)
1295 {
1296 stat_err = stat_err + pow(samp.second.Nominal_Stat[index], 2);
1297 y0 = y0 - samp.second.Nominal[index];
1298 }
1299 V_Matrix(bin_index, bin_index) = stat_err;
1300 Y0_Matrix(bin_index, 0) = y0;
1301 if (!isfinite(stat_err))
1302 MSGUser()->MSG_INFO("Stat_Err^2 : ", stat_err);
1303
1304 bin_index++;
1305 }
1306 }
1307
1308 Q_Matrix = (Eigen::MatrixXd::Identity(NP_Num, NP_Num) + Gamma_Matrix.transpose() * V_Matrix.inverse() * Gamma_Matrix).inverse() * (Gamma_Matrix.transpose() * V_Matrix.inverse());
1309 S_Matrix = V_Matrix.inverse() * (Eigen::MatrixXd::Identity(Total_Template_BinNum, Total_Template_BinNum) - Gamma_Matrix * Q_Matrix);
1310 C_Matrix = V_Matrix + Gamma_Matrix * Gamma_Matrix.transpose();
1311 Lambda_Matrix = (-1) * (H_Matrix.transpose() * S_Matrix * H_Matrix).inverse() * H_Matrix.transpose() * S_Matrix;
1313 Nuisance_Shift = Q_Matrix * (Eigen::MatrixXd::Identity(Total_Template_BinNum, Total_Template_BinNum) + H_Matrix * Lambda_Matrix) * Y0_Matrix;
1314
1315 POI_Cov_Matrix = (H_Matrix.transpose() * S_Matrix * H_Matrix).inverse();
1316
1317 Rho_Matrix = (H_Matrix.transpose() * V_Matrix.inverse() * H_Matrix).inverse() * (H_Matrix.transpose() * V_Matrix.inverse());
1318 Epsilon_Matrix = H_Matrix * Rho_Matrix - Eigen::MatrixXd::Identity(Total_Template_BinNum, Total_Template_BinNum);
1319 Nuisance_Cov_Matrix = (Eigen::MatrixXd::Identity(NP_Num, NP_Num) + (Epsilon_Matrix * Gamma_Matrix).transpose() * V_Matrix.inverse() * (Epsilon_Matrix * Gamma_Matrix)).inverse();
1320
1321 poi_index = 0;
1322 par_index = 0;
1323 for (auto &par : Par_Map)
1324 {
1325 if (par.second.isFixed)
1326 continue;
1327 if (par.second.Type == ParameterType::Nuisance)
1328 {
1329 par.second.Value = Nuisance_Shift(par_index, 0);
1330 par.second.Error = sqrt(Nuisance_Cov_Matrix(par_index, par_index));
1331 par_index++;
1332 }
1333 if (par.second.Type == ParameterType::Normalization)
1334 {
1335 par.second.Value = par.second.Init - POI_Shift(poi_index, 0);
1336 par.second.Error = sqrt(POI_Cov_Matrix(poi_index, poi_index));
1337 poi_index++;
1338 }
1339 if (par.second.Type == ParameterType::Interest)
1340 {
1341 par.second.Value = par.second.Init - POI_Shift(poi_index, 0);
1342 par.second.Error = sqrt(POI_Cov_Matrix(poi_index, poi_index));
1343 poi_index++;
1344 }
1345 }
1346}
1347
1349{
1351
1352 // Define Parameters
1353 ROOT::Minuit2::MnUserParameters upar;
1354 for (auto &p : Par_Map)
1355 {
1356 if (p.second.Type == ParameterType::Interest)
1357 {
1358 upar.Add(p.second.Name.TString::Data(),
1359 p.second.Value,
1360 15,
1361 p.second.Min,
1362 p.second.Max);
1363 }
1364 else
1365 {
1366 upar.Add(p.second.Name.TString::Data(),
1367 p.second.Value,
1368 1,
1369 p.second.Min,
1370 p.second.Max);
1371 }
1372 if (p.second.isFixed)
1373 upar.Fix(p.second.Name.TString::Data());
1374 }
1375
1376 // Pre Run
1377 int index = 0;
1378 vector<int> NuisanceIndex_vec;
1379 vector<double> DeltaLH_vec;
1380 for (auto &p : Par_Map)
1381 {
1382 if ((p.second.Type == ParameterType::Nuisance) &&
1383 (!p.second.isFixed))
1384 {
1385 ROOT::Minuit2::MnScan scan(fcn, upar, 2);
1386 auto res = scan.Scan(index, 3, -1, 1);
1387 double delta_lh = res[1].second - res[2].second;
1388 if (fabs(delta_lh - 0.5) < 1e-5)
1389 {
1390 upar.Fix(index);
1391 MSGUser()->MSG_INFO(p.second.Name.TString::Data(), " Fixed to 0 ! ( ", fabs(delta_lh - 0.5), " )");
1392 }
1393 else
1394 {
1395 NuisanceIndex_vec.emplace_back(index);
1396 DeltaLH_vec.emplace_back(fabs(delta_lh - 0.5));
1397 }
1398 }
1399 index = index + 1;
1400 }
1401
1402 if (DeltaLH_vec.size() > 1)
1403 {
1404 for (int i = 0; i < DeltaLH_vec.size() - 1; i++)
1405 {
1406 for (int j = 1; j < DeltaLH_vec.size(); j++)
1407 {
1408 if (DeltaLH_vec[i] < DeltaLH_vec[j])
1409 {
1410 int temp_index = NuisanceIndex_vec[i];
1411 NuisanceIndex_vec[i] = NuisanceIndex_vec[j];
1412 NuisanceIndex_vec[j] = temp_index;
1413 double temp_delta = DeltaLH_vec[i];
1414 DeltaLH_vec[i] = DeltaLH_vec[j];
1415 DeltaLH_vec[j] = temp_delta;
1416 }
1417 }
1418 }
1419 }
1420
1421 MSGUser()->MSG_INFO("Number of Nuisance Parameters to Fit: ", NuisanceIndex_vec.size());
1422 // for (int i = 20; i < NuisanceIndex_vec.size(); i++)
1423 // upar.Fix(NuisanceIndex_vec[i]);
1424
1425 fcn.Reset();
1426 MSGUser()->MSG_INFO("Start Simplex");
1427 ROOT::Minuit2::MnSimplex simplex(fcn, upar, 2);
1428 auto minsimplex = simplex();
1429 MSGUser()->MSG_INFO("Start Migrad");
1430 ROOT::Minuit2::MnMigrad migrad(fcn, minsimplex.UserState(), ROOT::Minuit2::MnStrategy(2));
1431 auto minmigrad = migrad();
1432
1433 MSGUser()->MSG_INFO("Final -Log(LH) : ", minmigrad.Fval());
1434
1435 index = 0;
1436 for (auto &p : Par_Map)
1437 {
1438 p.second.Value = minmigrad.UserState().Value(index);
1439 p.second.Error = minmigrad.UserState().Error(index);
1440 p.second.isFitted = true;
1441 index = index + 1;
1442 }
1443}
1444
1445double ProfileFitter::PLH_FCN::operator()(const std::vector<double> &vpara) const
1446{
1447 std::map<TString, Parameter> Temp_Par_Map = (*Par_Map);
1448 int index = 0;
1449 double prob = 0;
1450
1451 if (pool == nullptr)
1452 {
1453 index = 0;
1454 std::map<TString, Parameter>::iterator par_itr;
1455 for (par_itr = Temp_Par_Map.begin(); par_itr != Temp_Par_Map.end(); par_itr++)
1456 {
1457 par_itr->second.Value = vpara[index];
1458 prob = prob + par_itr->second.GetLikelihood();
1459 index = index + 1;
1460 }
1461
1462 std::map<TString, Observable>::iterator obs_itr;
1463 for (obs_itr = Obs_Map->begin(); obs_itr != Obs_Map->end(); obs_itr++)
1464 {
1465 obs_itr->second.GetProfile(Temp_Par_Map);
1466 prob = prob + obs_itr->second.GetLikelihood();
1467 }
1468 } // Single Thread Mode
1469 else
1470 {
1471 index = 0;
1472 std::map<TString, Parameter>::iterator par_itr;
1473 for (par_itr = Temp_Par_Map.begin(); par_itr != Temp_Par_Map.end(); par_itr++)
1474 {
1475 par_itr->second.Value = vpara[index];
1476 index = index + 1;
1477 }
1478
1479 std::vector<std::future<StatusCode>> vfuture_obs;
1480 std::map<TString, Observable>::iterator obs_itr;
1481 for (obs_itr = Obs_Map->begin(); obs_itr != Obs_Map->end(); obs_itr++)
1482 {
1483 for (auto &samp : obs_itr->second.Sample_Map)
1484 {
1485 vfuture_obs.emplace_back(pool->enqueue(Observable::Sample::GetProfile_Thread, &(samp.second), Temp_Par_Map));
1486 }
1487 }
1488
1489 std::vector<std::future<double>> vfuture_par;
1490 for (auto &par : Temp_Par_Map)
1491 vfuture_par.emplace_back(pool->enqueue(Parameter::GetLikelihood_Thread, &(par.second)));
1492
1493 for (int i = 0; i < vfuture_obs.size(); i++)
1494 vfuture_obs[i].get();
1495 vfuture_obs.clear();
1496
1497 for (obs_itr = Obs_Map->begin(); obs_itr != Obs_Map->end(); obs_itr++)
1498 vfuture_par.emplace_back(pool->enqueue(Observable::GetLikelihood_Thread, &(obs_itr->second)));
1499
1500 for (int i = 0; i < vfuture_par.size(); i++)
1501 prob = prob + vfuture_par[i].get();
1502 vfuture_par.clear();
1503
1504 } // Multi Thread Mode
1505
1506 if (NCall == 0)
1507 {
1508 MSGUser()->MSG_DEBUG("First -Log(LH): ", -prob);
1509 Max_Log_Likelihood = -prob;
1510 }
1511 else if ((-prob) < Max_Log_Likelihood)
1512 {
1513 PrintMutex.lock();
1514 index = 0;
1515 std::map<TString, Parameter>::iterator par_itr;
1516 for (par_itr = Temp_Par_Map.begin(); par_itr != Temp_Par_Map.end(); par_itr++)
1517 {
1518 if (par_itr->second.Type == ParameterType::Interest)
1519 MSGUser()->MSG_DEBUG("POI: ", par_itr->second.Name.TString::Data(), " = ", par_itr->second.Value, " ( Index No. ", index, " )");
1520 else if (par_itr->second.Value != par_itr->second.Init)
1521 MSGUser()->MSG_DEBUG("Nuisance: ", par_itr->second.Name.TString::Data(), " = ", par_itr->second.Value, " ( Index No. ", index, " )");
1522 index = index + 1;
1523 }
1524 MSGUser()->MSG_DEBUG("New Minimum -Log(LH): ", -prob, " ( NCall = ", NCall + 1, " )");
1525 PrintMutex.unlock();
1526 Max_Log_Likelihood = -prob;
1527 }
1528 // else if ((NCall + 1) % 1000 == 0)
1529 else
1530 MSGUser()->MSG_DEBUG("New -Log(LH): ", -prob, " ( NCall = ", NCall + 1, " )");
1531 NCall = NCall + 1;
1532
1533 return -prob;
1534}
1535
1537{
1538 if (Type == ParameterType::Nuisance ||
1540 return -0.5 * std::pow((Value - Nuisance_Gaus_Mean) / Nuisance_Gaus_Sigma, 2);
1541 // return -0.5 * std::pow((Value - Nuisance_Gaus_Mean) / Nuisance_Gaus_Sigma, 2) - std::log(2.50662827463100024 * Nuisance_Gaus_Sigma);
1542
1543 return 0;
1544}
1545
1546void ProfileFitter::SetGammaPrefix(TString samplename, TString prefix)
1547{
1548 auto findprefix = Gamma_Map.find(prefix);
1549 if (findprefix != Gamma_Map.end())
1550 {
1551 bool findsample = false;
1552 if (findprefix->second.size() > 0)
1553 {
1554 for (int i = 0; i < findprefix->second.size(); i++)
1555 {
1556 if ((findprefix->second)[i].TString::EqualTo(samplename))
1557 findsample = true;
1558 }
1559 }
1560 if (!findsample)
1561 {
1562 findprefix->second.emplace_back(samplename);
1563 }
1564 }
1565 else
1566 {
1567 vector<TString> Sample_Vec;
1568 Sample_Vec.emplace_back(samplename);
1569 for (auto &g : Gamma_Map)
1570 {
1571 if (g.second.size() > 0)
1572 {
1573 for (int i = 0; i < g.second.size(); i++)
1574 {
1575 if ((g.second)[i].TString::EqualTo(samplename.TString::Data()))
1576 {
1577 g.second.erase(g.second.begin() + i);
1578 i--;
1579 }
1580 }
1581 }
1582 }
1583 Gamma_Map.emplace(std::pair<TString, vector<TString>>(prefix, Sample_Vec));
1584 }
1585}
1586
1587void ProfileFitter::LinkNormalizationSample(TString name, TString samplename)
1588{
1589 bool exist = false;
1590 for (auto &par : Norm_Map)
1591 {
1592 if (par.second.size() > 0)
1593 {
1594 for (int i = 0; i < par.second.size(); i++)
1595 {
1596 if (par.second[i].TString::EqualTo(samplename))
1597 exist = true;
1598 }
1599 }
1600 }
1601 if (exist)
1602 {
1603 MSGUser()->MSG_ERROR("Normalization Factor for ", samplename.TString::Data(), " already exist!");
1604 return;
1605 }
1606 if (GetParameter(name) != nullptr)
1607 {
1608 auto findpar = Norm_Map.find(name);
1609 if (findpar != Norm_Map.end())
1610 {
1611 bool findsamp = false;
1612 if (findpar->second.size() > 0)
1613 {
1614 for (int i = 0; i < findpar->second.size(); i++)
1615 {
1616 if ((findpar->second)[i].TString::EqualTo(samplename))
1617 findsamp = true;
1618 }
1619 }
1620 if (!findsamp)
1621 findpar->second.emplace_back(samplename);
1622 }
1623 else
1624 {
1625 vector<TString> sample_vec;
1626 sample_vec.emplace_back(samplename);
1627 Norm_Map.emplace(std::pair<TString, vector<TString>>(name, sample_vec));
1628 }
1629 }
1630}
1631void ProfileFitter::SymmetrizeVariation(vector<double> &up, vector<double> &down, vector<double> &norm)
1632{
1633 for (int i = 0; i < norm.size(); i++)
1634 {
1635 double delta_up = up[i] - norm[i];
1636 double delta_down = down[i] - norm[i];
1637
1638 double new_delta_up = (delta_up - delta_down) / 2;
1639 double new_delta_down = -new_delta_up;
1640
1641 up[i] = norm[i] + new_delta_up;
1642 down[i] = norm[i] + new_delta_down;
1643
1644 if (up[i] < 0)
1645 up[i] = 1e-5;
1646 if (down[i] < 0)
1647 down[i] = 1e-5;
1648 }
1649}
1650
1651void ProfileFitter::SmoothVariation(vector<double> &var, vector<double> &norm, int level)
1652{
1653 if (level <= 0)
1654 return;
1655 if (norm.size() > 2)
1656 {
1657 double sum_init = 0;
1658 sum_init = accumulate(var.begin(), var.end(), 0);
1659 vector<double> new_ratio_vec;
1660 for (int i = 1; i < norm.size() - 1; i++)
1661 {
1662 double ratio_p = var[i - 1] / norm[i - 1];
1663 double ratio_n = var[i + 1] / norm[i + 1];
1664
1665 double ratio = var[i] / norm[i];
1666
1667 if (!isfinite(ratio_p))
1668 ratio_p = 0;
1669 if (!isfinite(ratio_n))
1670 ratio_n = 0;
1671 if (!isfinite(ratio))
1672 ratio = 0;
1673
1674 double new_ratio = (level * ratio + ratio_p + ratio_n) / (level + 2);
1675
1676 new_ratio_vec.emplace_back(new_ratio);
1677 }
1678
1679 for (int i = 1; i < norm.size() - 1; i++)
1680 var[i] = norm[i] * new_ratio_vec[i - 1];
1681
1682 double sum_new = 0;
1683 sum_new = accumulate(var.begin(), var.end(), 0);
1684
1685 double scale = sum_init / sum_new;
1686 for (int i = 0; i < norm.size(); i++)
1687 var[i] = var[i] * scale;
1688 }
1689}
1690
1691void ProfileFitter::RebinObservable(TString name, int index)
1692{
1693 if (index < 2)
1694 {
1695 MSGUser()->MSG_ERROR("Rebin Index ", index, " is smaller than 2 !");
1696 return;
1697 }
1698
1699 auto findobs = Obs_Map.find(name);
1700 if (findobs == Obs_Map.end())
1701 {
1702 MSGUser()->MSG_ERROR("Observable ", name.TString::Data(), " has not been defined !");
1703 return;
1704 }
1705
1706 findobs->second.Rebin_Index = index;
1707}
1708
1709void ProfileFitter::SetObservableRange(TString name, int start, int end)
1710{
1711 if (end < start)
1712 {
1713 MSGUser()->MSG_ERROR("Start Index ", start, "is larger than End Index ", end, " !");
1714 return;
1715 }
1716
1717 auto findobs = Obs_Map.find(name);
1718 if (findobs == Obs_Map.end())
1719 {
1720 MSGUser()->MSG_ERROR("Observable ", name.TString::Data(), " has not been defined !");
1721 return;
1722 }
1723
1724 findobs->second.Start_Index = start;
1725 findobs->second.End_Index = end;
1726}
1727
1728void ProfileFitter::SetSymmetrization(TString obsname, TString samplename, TString parname, bool need)
1729{
1730 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::SetSymmetrization");
1731 auto findobs = Obs_Map.find(obsname);
1732 if (findobs != Obs_Map.end())
1733 {
1734 auto findsample = findobs->second.Sample_Map.find(samplename);
1735 if (findsample != findobs->second.Sample_Map.end())
1736 {
1737 auto findpar = findsample->second.NeedSymmetrization_Map.find(GetParameter(parname));
1738 if (findpar != findsample->second.NeedSymmetrization_Map.end())
1739 {
1740 findpar->second = need;
1741 }
1742 else
1743 MSGUser()->MSG_ERROR("Sample ", samplename.TString::Data(),
1744 " of Observable ", obsname.TString::Data(),
1745 " Not Affected by Parameter ", parname.TString::Data(), " !");
1746 }
1747 else
1748 MSGUser()->MSG_ERROR("Sample ", samplename.TString::Data(),
1749 " of Observable ", obsname.TString::Data(), " Not Defined !");
1750 }
1751 else
1752 MSGUser()->MSG_ERROR("Observable ", obsname.TString::Data(), " Not Defined !");
1753}
1754
1755void ProfileFitter::SetSmooth(TString obsname, TString samplename, TString parname, int slevel)
1756{
1757 auto msgguard = MSGUser()->StartTitleWithGuard("ProfileFitter::SetSymmetrization");
1758 auto findobs = Obs_Map.find(obsname);
1759 if (findobs != Obs_Map.end())
1760 {
1761 auto findsample = findobs->second.Sample_Map.find(samplename);
1762 if (findsample != findobs->second.Sample_Map.end())
1763 {
1764 auto findpar = findsample->second.SmoothLevel_Map.find(GetParameter(parname));
1765 if (findpar != findsample->second.SmoothLevel_Map.end())
1766 {
1767 findpar->second = slevel;
1768 }
1769 else
1770 MSGUser()->MSG_ERROR("Sample ", samplename.TString::Data(),
1771 " of Observable ", obsname.TString::Data(),
1772 " Not Affected by Parameter ", parname.TString::Data(), " !");
1773 }
1774 else
1775 MSGUser()->MSG_ERROR("Sample ", samplename.TString::Data(),
1776 " of Observable ", obsname.TString::Data(), " Not Defined !");
1777 }
1778 else
1779 MSGUser()->MSG_ERROR("Observable ", obsname.TString::Data(), " Not Defined !");
1780}
1781
1782void ProfileFitter::SetParameterGroup(TString gname, TString parname)
1783{
1784 auto findgroup = ParGroup_Map.find(gname);
1785 if (findgroup != ParGroup_Map.end())
1786 {
1787 if (GetParameter(parname) != nullptr)
1788 {
1789 findgroup->second.emplace_back(parname);
1790 }
1791 }
1792 else
1793 {
1794 if (GetParameter(parname) != nullptr)
1795 {
1796 vector<TString> empty_vec;
1797 empty_vec.emplace_back(parname);
1798 ParGroup_Map.emplace(std::pair<TString, vector<TString>>(gname, empty_vec));
1799 }
1800 }
1801}
1802
1808std::map<TString, double> ProfileFitter::EstimateUnc(TString g_name, FitMethod method, int toy_num)
1809{
1810 auto findgroup = ParGroup_Map.find(g_name);
1811 if (findgroup != ParGroup_Map.end())
1812 {
1813 return EstimateUnc(findgroup->second, method, toy_num);
1814 }
1815 else
1816 {
1817 auto guard = MSGUser()->StartTitleWithGuard("ProfileFitter::EstimateUnc");
1818 MSGUser()->MSG_ERROR("Parameter group ", g_name.TString::Data(), " is not defined, return an empty map!");
1819 return std::map<TString, double>();
1820 }
1821}
1822
1828std::map<TString, double> ProfileFitter::EstimateUnc(const std::vector<TString> &par_vec, FitMethod method, int toy_num)
1829{
1830 std::map<TString, vector<double>> Original_Data_Map;
1831 for (auto &obs : Obs_Map)
1832 {
1833 Original_Data_Map.emplace(std::pair<TString, vector<double>>(obs.first, obs.second.Data));
1834 }
1835
1836 TRandom3 *my_rnd = new TRandom3(12345);
1837 std::map<TString, double> Sum_Par_Map;
1838 std::map<TString, double> Sum_Par2_Map;
1839
1840 for (auto &par : Par_Map)
1841 {
1842 Sum_Par_Map.emplace(std::pair<TString, double>(par.first, 0));
1843 Sum_Par2_Map.emplace(std::pair<TString, double>(par.first, 0));
1844 }
1845
1846 for (int i = 0; i < toy_num; i++)
1847 {
1848 if (i % 100 == 0 && i != 0)
1849 MSGUser()->MSG_DEBUG("Produced ", i, " Toys ! ( Total Number = ", toy_num, " )");
1850 std::map<TString, Parameter> Temp_Par_Map = Par_Map;
1851 for (auto &par : Temp_Par_Map)
1852 {
1853 par.second.Value = par.second.Init;
1854 }
1855
1856 for (int j = 0; j < par_vec.size(); j++)
1857 {
1858 Parameter *par = GetParameter(par_vec[j]);
1859 Temp_Par_Map[par_vec[j]].Value = my_rnd->Gaus(par->Nuisance_Gaus_Mean, par->Nuisance_Gaus_Sigma);
1860 } // Random Nuisance
1861
1862 for (auto &obs : Obs_Map)
1863 {
1864 obs.second.GetProfile(Temp_Par_Map);
1865 for (int j = 0; j < obs.second.Data.size(); j++)
1866 {
1867 obs.second.Data[j] = Original_Data_Map[obs.first][j] - (obs.second.Profile[j]);
1868 for (auto &samp : obs.second.Sample_Map)
1869 {
1870 obs.second.Data[j] = obs.second.Data[j] + samp.second.Nominal[j];
1871 }
1872 }
1873 } // Shifted Data
1874
1876 FitPLH();
1877
1879 FitACS();
1880
1882 {
1883 FitACS();
1884 FitPLH();
1885 }
1886
1887 for (auto &par : Par_Map)
1888 {
1889 Sum_Par_Map[par.first] = Sum_Par_Map[par.first] + par.second.Value;
1890 Sum_Par2_Map[par.first] = Sum_Par2_Map[par.first] + pow(par.second.Value, 2);
1891 }
1892 }
1893 std::map<TString, double> Unc_Map;
1894
1895 for (auto &par : Par_Map)
1896 {
1897 // add fabs to prevent numerical errors
1898 double unc = sqrt(std::fabs(Sum_Par2_Map[par.first] / toy_num - pow(Sum_Par_Map[par.first] / toy_num, 2)));
1899 Unc_Map.emplace(std::pair<TString, double>(par.first, unc));
1900 }
1901
1902 for (auto &obs : Obs_Map)
1903 {
1904 obs.second.Data = Original_Data_Map[obs.first];
1905 }
1906
1907 delete my_rnd;
1908
1909 return Unc_Map;
1910}
1911
1913{
1914 std::map<TString, Parameter> Temp_Par_Map = Par_Map;
1915
1916 double Chi2 = 0;
1917 for (auto &obs : Obs_Map)
1918 {
1919 obs.second.GetProfile(Temp_Par_Map);
1920 for (int i = 0; i < obs.second.Profile.size(); i++)
1921 {
1922 double err2 = pow(obs.second.Data_Stat[i], 2);
1923 double diff2 = pow(obs.second.Data[i] - obs.second.Profile[i], 2);
1924 for (auto &samp : obs.second.Sample_Map)
1925 {
1926 if (samp.second.Gamma_Vec.size() == 0)
1927 err2 = err2 + pow(samp.second.Nominal_Stat[i], 2);
1928 }
1929 Chi2 = Chi2 + diff2 / err2;
1930 }
1931 }
1932
1933 return Chi2;
1934}
1935
1936double ProfileFitter::GetChi2(const std::map<TString, double> &par_val)
1937{
1938 std::map<TString, Parameter> Temp_Par_Map = Par_Map;
1939
1940 for (auto &val : par_val)
1941 {
1942 Parameter *par = GetParameter(val.first);
1943 if (par != nullptr)
1944 Temp_Par_Map[val.first].Value = val.second;
1945 }
1946
1947 double Chi2 = 0;
1948 for (auto &obs : Obs_Map)
1949 {
1950 obs.second.GetProfile(Temp_Par_Map);
1951 for (int i = 0; i < obs.second.Profile.size(); i++)
1952 {
1953 double err2 = pow(obs.second.Data_Stat[i], 2);
1954 double diff2 = pow(obs.second.Data[i] - obs.second.Profile[i], 2);
1955 for (auto &samp : obs.second.Sample_Map)
1956 {
1957 if (samp.second.Gamma_Vec.size() == 0)
1958 err2 = err2 + pow(samp.second.Nominal_Stat[i], 2);
1959 }
1960 Chi2 = Chi2 + diff2 / err2;
1961 }
1962 }
1963
1964 return Chi2;
1965}
std::map< Parameter *, std::vector< double > > Variation_Nominal_Map
std::map< Parameter *, bool > NeedSymmetrization_Map
std::map< Parameter *, std::vector< double > > Variation_Sigma_Map
std::map< Parameter *, std::vector< std::vector< double > > > Variation_Map
std::map< Parameter *, int > SmoothLevel_Map
double GetProfileBinVariation(int i, double aim_sigma, Parameter *par)
std::map< Parameter *, std::vector< double > > Variation_Up_Map
std::map< Parameter *, std::vector< double > > Variation_Down_Map
void GetProfile(std::map< TString, Parameter > &m_par)
std::map< Parameter *, std::vector< std::shared_ptr< ProfileCache > > > Variation_Cache
static NAGASH::StatusCode GetProfile_Thread(Sample *tsample, std::map< TString, Parameter > &m_par)
std::vector< double > Data_Stat
std::map< TString, Sample > Sample_Map
static double GetLikelihood_Thread(Observable *tobs)
std::vector< double > Profile
void GetProfile(std::map< TString, Parameter > &m_par)
double operator()(const std::vector< double > &) const override
static double GetLikelihood_Thread(Parameter *tpar)
void SetStrategy(ExtrapStrategy str)
void BookObservableData(TString name, const std::vector< double > &vec, const std::vector< double > &vec_stat)
void BookObservableVariation(TString name, TString samplename, const std::vector< double > &vec, TString parname, double sigma)
ProfileFitter(std::shared_ptr< MSGTool > msg, int nthread=1)
Eigen::MatrixXd Nuisance_Cov_Matrix
Eigen::MatrixXd V_Matrix
TString GetParameterName(int index)
void SetSymmetrization(TString obsname, TString samplename, TString parname, bool need=true)
Eigen::MatrixXd Q_Matrix
Parameter::ExtrapStrategy POI_DEFAULT_STRATEGY
Eigen::MatrixXd Nuisance_Shift
void SetGammaPrefix(TString samplename, TString prefix)
void SetParameterGroup(TString gname, TString parname)
Eigen::MatrixXd Y0_Matrix
std::map< TString, std::vector< TString > > Norm_Map
void BookObservableVariationNominal(TString name, TString samplename, const std::vector< double > &vec, TString parname)
Eigen::MatrixXd S_Matrix
Eigen::MatrixXd Epsilon_Matrix
void BookObservableNominal(TString name, TString samplename, const std::vector< double > &vec, const std::vector< double > &vec_stat)
void Prepare(FitMethod method)
@ AnalyticalChiSquare
Analytical method, described in https://arxiv.org/abs/2307.04007, very fast.
@ ProfileLikelihood
Traditional profile likelihood.
@ AnalyticalBoostedProfileLikelihood
use analytical method first, then run profile likelihood fit on top of it.
void BookObservableVariationFromUnc(TString name, TString samplename, const std::vector< double > &vec, const std::vector< double > &vec_unc, TString parname)
Observable * InitializeNewObservable(TString name)
Parameter * GetParameter(TString name)
void RebinObservable(TString name, int index)
Eigen::MatrixXd Lambda_Matrix
void BookParameter(TString name, double init, double min, double max, ParameterType type)
Eigen::MatrixXd POI_Shift
std::map< TString, Observable > Obs_Map
void LinkNormalizationSample(TString name, TString samplename)
std::map< TString, Parameter > Par_Map
void SymmetrizeVariation(std::vector< double > &up, std::vector< double > &down, std::vector< double > &norm)
int GetNParameters(ParameterType type=ParameterType::Unknown)
Eigen::MatrixXd C_Matrix
std::shared_ptr< ThreadPool > pool
void BookObservableVariationUp(TString name, TString samplename, const std::vector< double > &vec, TString parname)
void SmoothVariation(std::vector< double > &var, std::vector< double > &norm, int level)
void SetObservableRange(TString name, int start, int end)
void Fit(FitMethod method)
void BookObservableVariationDown(TString name, TString samplename, const std::vector< double > &vec, TString parname)
Eigen::MatrixXd Gamma_Matrix
std::map< TString, double > EstimateUnc(const std::vector< TString > &par_vec, FitMethod method, int toy_num)
Estimate uncertainty decomposition using toy method.
ParameterType
Type of the parameter.
@ StatGamma
Statistical Gamma, used to represent the statistical uncertainties.
@ Normalization
Normalization parameter.
std::map< TString, std::vector< TString > > ParGroup_Map
Eigen::MatrixXd H_Matrix
std::map< TString, std::vector< TString > > Gamma_Map
void SetSmooth(TString obsname, TString samplename, TString parname, int slevel)
Eigen::MatrixXd POI_Cov_Matrix
Parameter::ExtrapStrategy NUISANCE_DEFAULT_STRATEGY
Eigen::MatrixXd Rho_Matrix
Provide interface for all tools in NAGASH.
Definition Tool.h:72
std::shared_ptr< MSGTool > MSGUser()
return the MSGTool inside.
Definition Tool.h:91