119 vector<TString> Sample_Name_vec;
120 Gamma_Map.emplace(std::pair<TString, vector<TString>>(
"Gamma", Sample_Name_vec));
125 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::BookParameter");
140 auto findpar =
Par_Map.find(name);
143 MSGUser()->MSG_ERROR(
"Parameter ", name.TString::Data(),
" has already been defined !");
144 MSGUser()->MSG_ERROR(
"This defination is ignored !");
149 Par_Map.emplace(std::pair<TString, Parameter>(name, par));
155 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::BookObservableData");
157 auto findobs =
Obs_Map.find(name);
161 obs = &(findobs->second);
170 MSGUser()->MSG_ERROR(
"The data of Observable ", name.TString::Data(),
" has already been booked !");
171 MSGUser()->MSG_ERROR(
"This new booking is ignored !");
183 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::BookObservableNominal");
185 bool isfindgamma =
false;
188 if (g.second.size() > 0)
190 for (
int i = 0; i < g.second.size(); i++)
192 if (g.second[i].TString::EqualTo(samplename.TString::Data()))
198 Gamma_Map[
"Gamma"].emplace_back(samplename);
200 auto findobs =
Obs_Map.find(name);
204 obs = &(findobs->second);
211 auto findsample = obs->
Sample_Map.find(samplename);
215 samp = &(findsample->second);
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 !");
226 newsamp.
Name = samplename;
227 obs->
Sample_Map.emplace(std::pair<TString, ProfileFitter::Observable::Sample>(samplename, newsamp));
238 for (
int i = 0; i < vec.size(); i++)
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]);
251 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::GetParamter");
253 auto findpar =
Par_Map.find(name);
255 return &(findpar->second);
257 MSGUser()->MSG_ERROR(
"Parameter ", name.TString::Data(),
" has not been defined !");
263 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::BookObservableVariation");
265 bool isfindgamma =
false;
268 if (g.second.size() > 0)
270 for (
int i = 0; i < g.second.size(); i++)
272 if (g.second[i].TString::EqualTo(samplename.TString::Data()))
278 Gamma_Map[
"Gamma"].emplace_back(samplename);
280 auto findpar =
Par_Map.find(parname);
283 MSGUser()->MSG_ERROR(
"Parameter ", parname.TString::Data(),
" has not been defined !");
284 MSGUser()->MSG_ERROR(
"This Variation has been ignored !");
289 std::vector<double> modified_vec = vec;
290 for (
int i = 0; i < vec.size(); i++)
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]);
302 auto findobs =
Obs_Map.find(name);
305 obs = &(findobs->second);
312 auto findsample = obs->
Sample_Map.find(samplename);
316 samp = &(findsample->second);
321 newsamp.
Name = samplename;
322 obs->
Sample_Map.emplace(std::pair<TString, ProfileFitter::Observable::Sample>(samplename, newsamp));
331 findsigma->second.emplace_back(sigma);
335 vector<double> sigma_vec;
336 sigma_vec.emplace_back(sigma);
343 findvar->second.emplace_back(modified_vec);
347 vector<vector<double>> var_vec;
348 var_vec.emplace_back(modified_vec);
350 vector<std::shared_ptr<ProfileCache>> cache_vec;
351 for (
int index = 0; index < vec.size(); index++)
352 cache_vec.emplace_back(
nullptr);
370 if (fabs(sigma) < 1e-5)
375 findvar->second = modified_vec;
376 MSGUser()->MSG_ERROR(
"Nominal for Parameter ", par->
Name.TString::Data(),
" Sample ", samplename.TString::Data(),
" has already defined !");
383 if (fabs(sigma - 1) < 1e-5)
388 findvar->second = modified_vec;
389 MSGUser()->MSG_ERROR(
"Up Variation for Parameter ", par->
Name.TString::Data(),
" Sample ", samplename.TString::Data(),
" has already defined !");
396 if (fabs(sigma + 1) < 1e-5)
401 findvar->second = modified_vec;
402 MSGUser()->MSG_ERROR(
"Down Variation for Parameter ", par->
Name.TString::Data(),
" Sample ", samplename.TString::Data(),
" has already defined !");
413 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::BookObservableVariationUnc");
415 bool isfindgamma =
false;
418 if (g.second.size() > 0)
420 for (
int i = 0; i < g.second.size(); i++)
422 if (g.second[i].TString::EqualTo(samplename.TString::Data()))
428 Gamma_Map[
"Gamma"].emplace_back(samplename);
430 auto findpar =
Par_Map.find(parname);
433 MSGUser()->MSG_ERROR(
"Parameter ", parname.TString::Data(),
" has not been defined !");
434 MSGUser()->MSG_ERROR(
"This Variation has been ignored !");
438 std::vector<double> vec_up = vec;
439 std::vector<double> vec_down = vec;
441 for (
int i = 0; i < vec.size(); i++)
443 vec_up[i] += vec_unc[i];
444 vec_down[i] -= vec_unc[i];
454 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::InitializeNewObservable");
456 auto findobs =
Obs_Map.find(name);
459 MSGUser()->MSG_ERROR(
"Observable ", name.TString::Data(),
" has already been defined !");
465 Obs_Map.emplace(std::pair<TString, ProfileFitter::Observable>(name, obs));
473 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::Fit");
479 MSGUser()->MSG_ERROR(
"Inputs check failed ! The fitting is not processed ! ");
500 MSGUser()->MSG_INFO(
"// ------------------------ //");
501 MSGUser()->MSG_INFO(
"// Parameter Fitting Result //");
502 MSGUser()->MSG_INFO(
"// ------------------------ //");
503 MSGUser()->MSG_INFO(
"Name Type");
506 if (p.second.isFixed)
509 MSGUser()->MSG_INFO(p.second.Name.TString::Data(),
" POI ", p.second.Value,
" ", p.second.Error);
513 if (p.second.isFixed)
516 MSGUser()->MSG_INFO(p.second.Name.TString::Data(),
" Normalization ", p.second.Value,
" ", p.second.Error);
520 if (p.second.isFixed)
523 MSGUser()->MSG_INFO(p.second.Name.TString::Data(),
" Nuisance ", p.second.Value,
" ", p.second.Error);
527 if (p.second.isFixed)
530 MSGUser()->MSG_INFO(p.second.Name.TString::Data(),
" Gamma ", p.second.Value,
" ", p.second.Error);
536 MSGUser()->MSG_INFO(
"// ---------- //");
537 MSGUser()->MSG_INFO(
"// Basic Info //");
538 MSGUser()->MSG_INFO(
"//----------- //");
544 MSGUser()->MSG_INFO(
"// -------------- //");
545 MSGUser()->MSG_INFO(
"// Parameter List //");
546 MSGUser()->MSG_INFO(
"// -------------- //");
547 MSGUser()->MSG_INFO(
"Name Type");
551 MSGUser()->MSG_INFO(p.second.Name.TString::Data(),
" POI");
556 MSGUser()->MSG_INFO(p.second.Name.TString::Data(),
" Nuisance");
561 MSGUser()->MSG_INFO(p.second.Name.TString::Data(),
" Normalization");
563 MSGUser()->MSG_INFO(
"// --------------- //");
564 MSGUser()->MSG_INFO(
"// Observable List //");
565 MSGUser()->MSG_INFO(
"// --------------- //");
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);
582 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::Prepare");
586 for (
auto &samp : obs.second.Sample_Map)
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;
595 obs.second.SortVariations();
602 if (obs.second.isgamma_booked ==
true)
604 MSGUser()->MSG_ERROR(
"Statistical Nuisance Parameters for Observable ", obs.first.TString::Data(),
" have already been booked !");
610 bool needtobook =
false;
611 vector<Parameter *> gamma_vec;
612 if (g.second.size() > 0)
614 for (
int i = 0; i < g.second.size(); i++)
616 auto findsample = obs.second.Sample_Map.find(g.second[i]);
617 if (findsample != obs.second.Sample_Map.end())
627 for (
int i = 0; i < obs.second.Data.size(); i++)
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())))
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());
638 gamma_vec.emplace_back(gamma_ptr);
643 gamma_vec.emplace_back(gamma_ptr);
646 if (ncount == obs.second.Rebin_Index)
650 gamma_vec.emplace_back(
nullptr);
653 for (
auto &samp : obs.second.Sample_Map)
655 bool isprefix =
false;
656 if (g.second.size() > 0)
658 for (
int i = 0; i < g.second.size(); i++)
660 if (g.second[i].TString::EqualTo(samp.first.TString::Data()))
665 samp.second.Gamma_Vec = gamma_vec;
669 obs.second.isgamma_booked =
true;
685 for (
auto &samp : obs.second.Sample_Map)
687 for (
int index = 0; index < samp.second.Gamma_Vec.size(); index++)
689 if (par_ptr == samp.second.Gamma_Vec[index])
691 val = val + samp.second.Nominal[index];
692 err = err + pow(samp.second.Nominal_Stat[index], 2);
708 par_ptr->
Error = err / val;
717 for (
auto &samp : obs.second.Sample_Map)
721 if (par.second.size() > 0)
723 for (
int i = 0; i < par.second.size(); i++)
725 if (par.second[i].TString::EqualTo(samp.second.Name.TString::Data()))
738 for (
auto &samp : obs.second.Sample_Map)
740 for (
auto &par : samp.second.NeedSymmetrization_Map)
742 if (par.second ==
true)
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())
750 for (
int i = 0; i < samp.second.Variation_Sigma_Map[par.first].size(); i++)
752 for (
int j = 0; j < samp.second.Variation_Sigma_Map[par.first].size(); j++)
754 if (fabs(samp.second.Variation_Sigma_Map[par.first][i] + samp.second.Variation_Sigma_Map[par.first][j]) < 1e-5)
756 if (samp.second.Variation_Sigma_Map[par.first][i] > 0)
758 samp.second.Variation_Map[par.first][j],
759 samp.second.Variation_Nominal_Map[par.first]);
763 if ((findup != samp.second.Variation_Up_Map.end()) &&
764 (finddown != samp.second.Variation_Down_Map.end()))
766 samp.second.Variation_Down_Map[par.first],
767 samp.second.Variation_Nominal_Map[par.first]);
777 for (
auto &samp : obs.second.Sample_Map)
779 for (
auto &par : samp.second.SmoothLevel_Map)
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())
790 if (findup != samp.second.Variation_Up_Map.end())
792 if (finddown != samp.second.Variation_Down_Map.end())
795 if (findvar != samp.second.Variation_Map.end())
797 for (
int i = 0; i < (findvar->second).size(); i++)
814 if (p.second.Type == type)
822 if (i >=
Par_Map.size() || i < 0)
824 MSGUser()->MSG_ERROR(
"Negative Index or Index Too Large! Return Parameter Name : Unknown");
833 return p.second.Name;
849 if (sigma_vec.size() < 2 || variation_vec.size() != sigma_vec.size())
850 cout <<
"Variation Number Less Than 2 !" << endl;
865 cout << par->
Name.TString::Data() <<
" Not Satisfy the condition of Extrap Strategy POLY6EXP !" << endl;
875 if (m_cache ==
nullptr)
877 m_cache = std::make_shared<ProfileCache>();
882 base = (findup->second)[i] / (findnom->second)[i];
884 base = (-(finddown->second)[i] + 2 * (findnom->second)[i]) / (findnom->second)[i];
885 m_cache->SaveCache(
"BaseUp", base);
888 base = (finddown->second)[i] / (findnom->second)[i];
890 base = (-(findup->second)[i] + 2 * (findnom->second)[i]) / (findnom->second)[i];
891 m_cache->SaveCache(
"BaseDown", base);
895 Y1 = (findup->second)[i];
897 Y1 = (-(finddown->second)[i] + 2 * (findnom->second)[i]);
900 Y2 = (finddown->second)[i];
902 Y2 = (-(findup->second)[i] + 2 * (findnom->second)[i]);
903 double Y0 = (findnom->second)[i];
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);
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);
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]);
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);
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");
942 double base = aim_sigma;
944 for (
int k = 0; k < 6; k++)
946 sum = sum + a[k] * base;
947 base = base * aim_sigma;
950 return (findnom->second)[i] * sum;
957 if (m_cache ==
nullptr)
959 m_cache = std::make_shared<ProfileCache>();
962 for (
int index = 0; index < sigma_vec.size() - 1; index++)
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];
971 double C = X2 * Y1 - X1 * Y2;
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);
981 if (aim_sigma <= sigma_vec[0])
986 else if (aim_sigma >= sigma_vec[sigma_vec.size() - 1])
988 index1 = sigma_vec.size() - 1;
989 index2 = sigma_vec.size() - 2;
993 for (
int j = 0; j < sigma_vec.size() - 1; j++)
995 if (aim_sigma >= sigma_vec[j] &&
996 aim_sigma < sigma_vec[j + 1])
1004 if (index1 < 0 || index2 < 0)
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;
1017 if (index1 < index2)
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));
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));
1030 return (-A * aim_sigma - C) / B;
1036 samp.second.GetProfile(m_par);
1042 sum = sum + samp.second.Profile[i];
1053 for (
auto &itr : Variation_Sigma_Map)
1055 if (Variation_Cache[itr.first][i] ==
nullptr)
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);
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");
1074 if (Norm_Par !=
nullptr)
1079 if (Gamma_Vec.size() > 0)
1097 ncount = ncount + 1;
1107 p = D * std::log(P) - P - std::lgamma(D + 1.);
1109 p = -0.5 * std::pow((D - P) / std::sqrt(D_S), 2);
1124 p = D * std::log(P) - P - std::lgamma(D + 1.);
1126 p = -0.5 * std::pow((D - P) / std::sqrt(D_S), 2);
1137 samp.second.SortVariations();
1142 std::map<Parameter *, std::vector<double>>::iterator sig_itr;
1143 std::map<Parameter *, std::vector<std::vector<double>>>::iterator var_itr;
1145 var_itr = Variation_Map.begin();
1146 for (sig_itr = Variation_Sigma_Map.begin(); sig_itr != Variation_Sigma_Map.end(); sig_itr++)
1148 if (sig_itr->second.size() >= 2)
1150 for (
int i = 0; i < sig_itr->second.size() - 1; i++)
1152 for (
int j = i + 1; j < sig_itr->second.size(); j++)
1154 if ((sig_itr->second)[i] > (sig_itr->second)[j])
1156 double temp = (sig_itr->second)[i];
1157 (sig_itr->second)[i] = (sig_itr->second)[j];
1158 (sig_itr->second)[j] = temp;
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;
1175 int Total_Template_BinNum = 0;
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);
1186 if (par.second.isFixed)
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);
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++)
1213 if (par.second.isFixed)
1221 for (
auto &samp : obs.second.Sample_Map)
1223 if (samp.second.Variation_Map.find(par_ptr) != samp.second.Variation_Map.end())
1231 for (
int v = 0; v < samp.second.Variation_Sigma_Map[par_ptr].size(); v++)
1233 ax = ax + samp.second.Variation_Sigma_Map[par_ptr][v];
1234 ay = ay + samp.second.Variation_Map[par_ptr][v][index];
1236 ax = ax / samp.second.Variation_Sigma_Map[par_ptr].size();
1237 ay = ay / samp.second.Variation_Sigma_Map[par_ptr].size();
1241 for (
int v = 0; v < samp.second.Variation_Sigma_Map[par_ptr].size(); v++)
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);
1253 if (!isfinite(sum_k))
1254 MSGUser()->MSG_INFO(
"Sensitivity : ", sum_k);
1262 H_Matrix(bin_index, poi_index) = sum_k;
1271 for (
auto &samp : obs.second.Sample_Map)
1273 if (samp.second.Norm_Par == par_ptr)
1275 sum_k = sum_k + samp.second.Nominal[index];
1279 if (!isfinite(sum_k))
1280 MSGUser()->MSG_INFO(
"Sensitivity : ", sum_k);
1282 H_Matrix(bin_index, poi_index) = sum_k;
1287 for (
int i = 0; i < Total_Template_BinNum; i++)
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)
1296 stat_err = stat_err + pow(samp.second.Nominal_Stat[index], 2);
1297 y0 = y0 - samp.second.Nominal[index];
1299 V_Matrix(bin_index, bin_index) = stat_err;
1301 if (!isfinite(stat_err))
1302 MSGUser()->MSG_INFO(
"Stat_Err^2 : ", stat_err);
1325 if (par.second.isFixed)
1335 par.second.Value = par.second.Init -
POI_Shift(poi_index, 0);
1341 par.second.Value = par.second.Init -
POI_Shift(poi_index, 0);
1353 ROOT::Minuit2::MnUserParameters upar;
1358 upar.Add(p.second.Name.TString::Data(),
1366 upar.Add(p.second.Name.TString::Data(),
1372 if (p.second.isFixed)
1373 upar.Fix(p.second.Name.TString::Data());
1378 vector<int> NuisanceIndex_vec;
1379 vector<double> DeltaLH_vec;
1383 (!p.second.isFixed))
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)
1391 MSGUser()->MSG_INFO(p.second.Name.TString::Data(),
" Fixed to 0 ! ( ", fabs(delta_lh - 0.5),
" )");
1395 NuisanceIndex_vec.emplace_back(index);
1396 DeltaLH_vec.emplace_back(fabs(delta_lh - 0.5));
1402 if (DeltaLH_vec.size() > 1)
1404 for (
int i = 0; i < DeltaLH_vec.size() - 1; i++)
1406 for (
int j = 1; j < DeltaLH_vec.size(); j++)
1408 if (DeltaLH_vec[i] < DeltaLH_vec[j])
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;
1421 MSGUser()->MSG_INFO(
"Number of Nuisance Parameters to Fit: ", NuisanceIndex_vec.size());
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();
1433 MSGUser()->MSG_INFO(
"Final -Log(LH) : ", minmigrad.Fval());
1438 p.second.Value = minmigrad.UserState().Value(index);
1439 p.second.Error = minmigrad.UserState().Error(index);
1440 p.second.isFitted =
true;
1447 std::map<TString, Parameter> Temp_Par_Map = (*Par_Map);
1451 if (
pool ==
nullptr)
1454 std::map<TString, Parameter>::iterator par_itr;
1455 for (par_itr = Temp_Par_Map.begin(); par_itr != Temp_Par_Map.end(); par_itr++)
1457 par_itr->second.Value = vpara[index];
1458 prob = prob + par_itr->second.GetLikelihood();
1462 std::map<TString, Observable>::iterator obs_itr;
1463 for (obs_itr =
Obs_Map->begin(); obs_itr !=
Obs_Map->end(); obs_itr++)
1465 obs_itr->second.GetProfile(Temp_Par_Map);
1466 prob = prob + obs_itr->second.GetLikelihood();
1472 std::map<TString, Parameter>::iterator par_itr;
1473 for (par_itr = Temp_Par_Map.begin(); par_itr != Temp_Par_Map.end(); par_itr++)
1475 par_itr->second.Value = vpara[index];
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++)
1483 for (
auto &samp : obs_itr->second.Sample_Map)
1489 std::vector<std::future<double>> vfuture_par;
1490 for (
auto &par : Temp_Par_Map)
1493 for (
int i = 0; i < vfuture_obs.size(); i++)
1494 vfuture_obs[i].get();
1495 vfuture_obs.clear();
1497 for (obs_itr =
Obs_Map->begin(); obs_itr !=
Obs_Map->end(); obs_itr++)
1500 for (
int i = 0; i < vfuture_par.size(); i++)
1501 prob = prob + vfuture_par[i].get();
1502 vfuture_par.clear();
1508 MSGUser()->MSG_DEBUG(
"First -Log(LH): ", -prob);
1509 Max_Log_Likelihood = -prob;
1511 else if ((-prob) < Max_Log_Likelihood)
1515 std::map<TString, Parameter>::iterator par_itr;
1516 for (par_itr = Temp_Par_Map.begin(); par_itr != Temp_Par_Map.end(); par_itr++)
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,
" )");
1524 MSGUser()->MSG_DEBUG(
"New Minimum -Log(LH): ", -prob,
" ( NCall = ", NCall + 1,
" )");
1525 PrintMutex.unlock();
1526 Max_Log_Likelihood = -prob;
1530 MSGUser()->MSG_DEBUG(
"New -Log(LH): ", -prob,
" ( NCall = ", NCall + 1,
" )");
1540 return -0.5 * std::pow((Value - Nuisance_Gaus_Mean) / Nuisance_Gaus_Sigma, 2);
1548 auto findprefix =
Gamma_Map.find(prefix);
1551 bool findsample =
false;
1552 if (findprefix->second.size() > 0)
1554 for (
int i = 0; i < findprefix->second.size(); i++)
1556 if ((findprefix->second)[i].TString::EqualTo(samplename))
1562 findprefix->second.emplace_back(samplename);
1567 vector<TString> Sample_Vec;
1568 Sample_Vec.emplace_back(samplename);
1571 if (g.second.size() > 0)
1573 for (
int i = 0; i < g.second.size(); i++)
1575 if ((g.second)[i].TString::EqualTo(samplename.TString::Data()))
1577 g.second.erase(g.second.begin() + i);
1583 Gamma_Map.emplace(std::pair<TString, vector<TString>>(prefix, Sample_Vec));
1592 if (par.second.size() > 0)
1594 for (
int i = 0; i < par.second.size(); i++)
1596 if (par.second[i].TString::EqualTo(samplename))
1603 MSGUser()->MSG_ERROR(
"Normalization Factor for ", samplename.TString::Data(),
" already exist!");
1608 auto findpar =
Norm_Map.find(name);
1611 bool findsamp =
false;
1612 if (findpar->second.size() > 0)
1614 for (
int i = 0; i < findpar->second.size(); i++)
1616 if ((findpar->second)[i].TString::EqualTo(samplename))
1621 findpar->second.emplace_back(samplename);
1625 vector<TString> sample_vec;
1626 sample_vec.emplace_back(samplename);
1627 Norm_Map.emplace(std::pair<TString, vector<TString>>(name, sample_vec));
1633 for (
int i = 0; i < norm.size(); i++)
1635 double delta_up = up[i] - norm[i];
1636 double delta_down = down[i] - norm[i];
1638 double new_delta_up = (delta_up - delta_down) / 2;
1639 double new_delta_down = -new_delta_up;
1641 up[i] = norm[i] + new_delta_up;
1642 down[i] = norm[i] + new_delta_down;
1655 if (norm.size() > 2)
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++)
1662 double ratio_p = var[i - 1] / norm[i - 1];
1663 double ratio_n = var[i + 1] / norm[i + 1];
1665 double ratio = var[i] / norm[i];
1667 if (!isfinite(ratio_p))
1669 if (!isfinite(ratio_n))
1671 if (!isfinite(ratio))
1674 double new_ratio = (level * ratio + ratio_p + ratio_n) / (level + 2);
1676 new_ratio_vec.emplace_back(new_ratio);
1679 for (
int i = 1; i < norm.size() - 1; i++)
1680 var[i] = norm[i] * new_ratio_vec[i - 1];
1683 sum_new = accumulate(var.begin(), var.end(), 0);
1685 double scale = sum_init / sum_new;
1686 for (
int i = 0; i < norm.size(); i++)
1687 var[i] = var[i] * scale;
1695 MSGUser()->MSG_ERROR(
"Rebin Index ", index,
" is smaller than 2 !");
1699 auto findobs =
Obs_Map.find(name);
1702 MSGUser()->MSG_ERROR(
"Observable ", name.TString::Data(),
" has not been defined !");
1706 findobs->second.Rebin_Index = index;
1713 MSGUser()->MSG_ERROR(
"Start Index ", start,
"is larger than End Index ", end,
" !");
1717 auto findobs =
Obs_Map.find(name);
1720 MSGUser()->MSG_ERROR(
"Observable ", name.TString::Data(),
" has not been defined !");
1724 findobs->second.Start_Index = start;
1725 findobs->second.End_Index = end;
1730 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::SetSymmetrization");
1731 auto findobs =
Obs_Map.find(obsname);
1734 auto findsample = findobs->second.Sample_Map.find(samplename);
1735 if (findsample != findobs->second.Sample_Map.end())
1737 auto findpar = findsample->second.NeedSymmetrization_Map.find(
GetParameter(parname));
1738 if (findpar != findsample->second.NeedSymmetrization_Map.end())
1740 findpar->second = need;
1743 MSGUser()->MSG_ERROR(
"Sample ", samplename.TString::Data(),
1744 " of Observable ", obsname.TString::Data(),
1745 " Not Affected by Parameter ", parname.TString::Data(),
" !");
1748 MSGUser()->MSG_ERROR(
"Sample ", samplename.TString::Data(),
1749 " of Observable ", obsname.TString::Data(),
" Not Defined !");
1752 MSGUser()->MSG_ERROR(
"Observable ", obsname.TString::Data(),
" Not Defined !");
1757 auto msgguard =
MSGUser()->StartTitleWithGuard(
"ProfileFitter::SetSymmetrization");
1758 auto findobs =
Obs_Map.find(obsname);
1761 auto findsample = findobs->second.Sample_Map.find(samplename);
1762 if (findsample != findobs->second.Sample_Map.end())
1764 auto findpar = findsample->second.SmoothLevel_Map.find(
GetParameter(parname));
1765 if (findpar != findsample->second.SmoothLevel_Map.end())
1767 findpar->second = slevel;
1770 MSGUser()->MSG_ERROR(
"Sample ", samplename.TString::Data(),
1771 " of Observable ", obsname.TString::Data(),
1772 " Not Affected by Parameter ", parname.TString::Data(),
" !");
1775 MSGUser()->MSG_ERROR(
"Sample ", samplename.TString::Data(),
1776 " of Observable ", obsname.TString::Data(),
" Not Defined !");
1779 MSGUser()->MSG_ERROR(
"Observable ", obsname.TString::Data(),
" Not Defined !");
1789 findgroup->second.emplace_back(parname);
1796 vector<TString> empty_vec;
1797 empty_vec.emplace_back(parname);
1798 ParGroup_Map.emplace(std::pair<TString, vector<TString>>(gname, empty_vec));
1813 return EstimateUnc(findgroup->second, method, toy_num);
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>();
1830 std::map<TString, vector<double>> Original_Data_Map;
1833 Original_Data_Map.emplace(std::pair<TString, vector<double>>(obs.first, obs.second.Data));
1836 TRandom3 *my_rnd =
new TRandom3(12345);
1837 std::map<TString, double> Sum_Par_Map;
1838 std::map<TString, double> Sum_Par2_Map;
1842 Sum_Par_Map.emplace(std::pair<TString, double>(par.first, 0));
1843 Sum_Par2_Map.emplace(std::pair<TString, double>(par.first, 0));
1846 for (
int i = 0; i < toy_num; i++)
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)
1853 par.second.Value = par.second.Init;
1856 for (
int j = 0; j < par_vec.size(); j++)
1864 obs.second.GetProfile(Temp_Par_Map);
1865 for (
int j = 0; j < obs.second.Data.size(); j++)
1867 obs.second.Data[j] = Original_Data_Map[obs.first][j] - (obs.second.Profile[j]);
1868 for (
auto &samp : obs.second.Sample_Map)
1870 obs.second.Data[j] = obs.second.Data[j] + samp.second.Nominal[j];
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);
1893 std::map<TString, double> Unc_Map;
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));
1904 obs.second.Data = Original_Data_Map[obs.first];
1914 std::map<TString, Parameter> Temp_Par_Map =
Par_Map;
1919 obs.second.GetProfile(Temp_Par_Map);
1920 for (
int i = 0; i < obs.second.Profile.size(); i++)
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)
1926 if (samp.second.Gamma_Vec.size() == 0)
1927 err2 = err2 + pow(samp.second.Nominal_Stat[i], 2);
1929 Chi2 = Chi2 + diff2 / err2;
1938 std::map<TString, Parameter> Temp_Par_Map =
Par_Map;
1940 for (
auto &val : par_val)
1944 Temp_Par_Map[val.first].Value = val.second;
1950 obs.second.GetProfile(Temp_Par_Map);
1951 for (
int i = 0; i < obs.second.Profile.size(); i++)
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)
1957 if (samp.second.Gamma_Vec.size() == 0)
1958 err2 = err2 + pow(samp.second.Nominal_Stat[i], 2);
1960 Chi2 = Chi2 + diff2 / err2;
std::vector< double > Nominal
std::map< Parameter *, std::vector< double > > Variation_Nominal_Map
std::vector< double > Profile
std::vector< double > Nominal_Stat
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
std::vector< double > Data
void GetProfile(std::map< TString, Parameter > &m_par)
double operator()(const std::vector< double > &) const override
static double GetLikelihood_Thread(Parameter *tpar)
double Nuisance_Gaus_Mean
void SetStrategy(ExtrapStrategy str)
double Nuisance_Gaus_Sigma
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
TString GetParameterName(int index)
void SetSymmetrization(TString obsname, TString samplename, TString parname, bool need=true)
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 Epsilon_Matrix
double MAX_NUISANCE_SIGMA
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)
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.
@ Nuisance
Nuisance parameter.
@ Normalization
Normalization parameter.
std::map< TString, std::vector< TString > > ParGroup_Map
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