Angular analysis of B+->K*+(K+pi0)mumu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5380 lines
251 KiB

  1. //Renata Kopecna
  2. #include <fstream>
  3. #include "folder.hh"
  4. #include <funcs.hh>
  5. #include <constants.hh>
  6. #include <bu2kstarmumu_pdf.hh>
  7. #include <pdf.hh>
  8. #include <options.hh>
  9. #include <values.hh>
  10. #include <design.hh>
  11. #include <integrals.hh>
  12. #include <event.hh>
  13. #include <helpers.hh>
  14. #include <paths.hh>
  15. #include <TMinuit.h>
  16. #include <spdlog.h>
  17. #include <TROOT.h>
  18. #include <TFile.h>
  19. #include <TStyle.h>
  20. //Helper function to create a polynomial for the background
  21. std::vector<double> init_ch_ctl(const fcnc::bu2kstarmumu_parameters* params){
  22. std::vector<double> bkg_ctl;
  23. bkg_ctl.push_back(params->cbkgctl0());
  24. bkg_ctl.push_back(params->cbkgctl1());
  25. bkg_ctl.push_back(params->cbkgctl2());
  26. bkg_ctl.push_back(params->cbkgctl3());
  27. bkg_ctl.push_back(params->cbkgctl4());
  28. return bkg_ctl;
  29. }
  30. std::vector<double> init_ch_ctk(const fcnc::bu2kstarmumu_parameters* params){
  31. std::vector<double> bkg_ctk;
  32. bkg_ctk.push_back(params->cbkgctk0());
  33. bkg_ctk.push_back(params->cbkgctk1());
  34. bkg_ctk.push_back(params->cbkgctk2());
  35. bkg_ctk.push_back(params->cbkgctk3());
  36. bkg_ctk.push_back(params->cbkgctk4());
  37. bkg_ctk.push_back(params->cbkgctk5());
  38. bkg_ctk.push_back(params->cbkgctk6());
  39. return bkg_ctk;
  40. }
  41. std::vector<double> init_ch_phi(const fcnc::bu2kstarmumu_parameters* params){
  42. std::vector<double> bkg_phi;
  43. bkg_phi.push_back(params->cbkgphi0());
  44. bkg_phi.push_back(params->cbkgphi1());
  45. bkg_phi.push_back(params->cbkgphi2());
  46. bkg_phi.push_back(params->cbkgphi3());
  47. bkg_phi.push_back(params->cbkgphi4());
  48. return bkg_phi;
  49. }
  50. //using namespace std;
  51. using namespace fcnc;
  52. //this is a wrapper for the complex error function
  53. //which is needed for a gaussian convolution of exp*cos/sin
  54. //this fortran implementation however is not thread safe!
  55. extern "C" void wwerfwrap_(double *zr, double *zi, double *wr, double* wi);
  56. //boost::mutex global_mutex_2;
  57. std::mutex global_mutex_2;
  58. bu2kstarmumu_pdf* bu2kstarmumu_pdf::current_pdf;
  59. bu2kstarmumu_pdf::bu2kstarmumu_pdf(options* o, const bu2kstarmumu_parameters* params):
  60. opts(o)
  61. {
  62. //vector of efficiency coefficients containing 1260 elements, coefficients stored in bu2kstarmumu_coefficients.cc
  63. //coeffs_eff_4d = fcnc::coefficients_nominal;
  64. //load_coeffs_eff_phsp_4d();
  65. fldr = new fcnc::folder(opts);
  66. };
  67. bu2kstarmumu_pdf::~bu2kstarmumu_pdf()
  68. {
  69. };
  70. void bu2kstarmumu_pdf::get_moments(std::vector<fcnc::event> events, std::vector<double>& moments, std::vector<double>& covariance) const
  71. {
  72. if(!opts->full_angular){
  73. spdlog::error("No folding implemented for moments. Debug: 1");
  74. assert(0);
  75. }
  76. std::vector<double> cov(NTERMS*NTERMS, 0.0);//the actual covariance matrix for the moments
  77. std::vector<double> m(NTERMS, 0.0);//need to first calculate the mean
  78. double nweight = 0.0; //sum of weights
  79. double nweightsquared = 0.0; //sum of weights squared, not used anywhere
  80. for (auto meas: events){
  81. double weight = meas.weight*meas.sweight;
  82. nweight += weight;
  83. nweightsquared += weight*weight;
  84. }
  85. for (auto meas: events){
  86. double weight = meas.weight*meas.sweight;
  87. weight /= nweight;//nominal
  88. //Calculate the angular terms for each parameter
  89. double f1=0.0, f2=0.0, f3=0.0, f4=0.0, f5=0.0, f6=0.0,
  90. f7=0.0, f8=0.0, f9=0.0, f10=0.0, f11=0.0, f12=0.0;
  91. fj(meas.costhetal, meas.costhetak, meas.phi,
  92. f1, f2, f3, f4, f5, f6,
  93. f7, f8, f9, f10, f11, f12);
  94. double ffs=0.0, fs1=0.0, fs2=0.0, fs3=0.0, fs4=0.0, fs5=0.0;
  95. if(opts->swave){
  96. swave_fj(meas.costhetal, meas.costhetak, meas.phi,
  97. ffs, fs1, fs2, fs3, fs4, fs5);
  98. }
  99. //TODO when bored: this is very annoying and f_whatever should be a struct or so and one should loop
  100. m.at(0) += f1*weight;
  101. m.at(1) += f2*weight;
  102. m.at(2) += f3*weight;
  103. m.at(3) += f4*weight;
  104. m.at(4) += f5*weight;
  105. m.at(5) += f6*weight;
  106. m.at(6) += f7*weight;
  107. m.at(7) += f8*weight;
  108. m.at(8) += f9*weight;
  109. m.at(9) += f10*weight;
  110. m.at(10) += f11*weight;
  111. m.at(11) += f12*weight;
  112. if(opts->swave){
  113. m.at(12) += ffs*weight;
  114. m.at(13) += fs1*weight;
  115. m.at(14) += fs2*weight;
  116. m.at(15) += fs3*weight;
  117. m.at(16) += fs4*weight;
  118. m.at(17) += fs5*weight;
  119. }
  120. }
  121. //calculate rms
  122. for (auto meas: events){
  123. double weight = meas.weight*meas.sweight;//dangerous?
  124. weight /= nweight;//nominal
  125. double f1=0.0, f2=0.0, f3=0.0, f4=0.0, f5=0.0, f6=0.0,
  126. f7=0.0, f8=0.0, f9=0.0, f10=0.0, f11=0.0, f12=0.0;
  127. fj(meas.costhetal, meas.costhetak, meas.phi,
  128. f1, f2, f3, f4, f5, f6,
  129. f7, f8, f9, f10, f11, f12);
  130. double ffs=0.0, fs1=0.0, fs2=0.0, fs3=0.0, fs4=0.0, fs5=0.0;
  131. if(opts->swave){
  132. swave_fj(meas.costhetal, meas.costhetak, meas.phi,
  133. ffs, fs1, fs2, fs3, fs4, fs5);
  134. }
  135. std::vector<double> diff(NTERMS*NTERMS, 0.0);
  136. diff.at(0) = f1 - m.at(0); //aaaaaaaarrrrggghhh
  137. diff.at(1) = f2 - m.at(1);
  138. diff.at(2) = f3 - m.at(2);
  139. diff.at(3) = f4 - m.at(3);
  140. diff.at(4) = f5 - m.at(4);
  141. diff.at(5) = f6 - m.at(5);
  142. diff.at(6) = f7 - m.at(6);
  143. diff.at(7) = f8 - m.at(7);
  144. diff.at(8) = f9 - m.at(8);
  145. diff.at(9) = f10 - m.at(9);
  146. diff.at(10) = f11 - m.at(10);
  147. diff.at(11) = f12 - m.at(11);
  148. if(opts->swave){
  149. diff.at(12) = ffs - m.at(12);
  150. diff.at(13) = fs1 - m.at(13);
  151. diff.at(14) = fs2 - m.at(14);
  152. diff.at(15) = fs3 - m.at(15);
  153. diff.at(16) = fs4 - m.at(16);
  154. diff.at(17) = fs5 - m.at(17);
  155. }
  156. //for swave==false, only loop over the first 12x12 elements
  157. //the matrix however stays in the 18x18 format, with 0.0 for all j > 11 || k > 11
  158. UInt_t mm = opts->swave ? NTERMS : NTERMS_P;
  159. for (unsigned int j = 0; j<mm; j++){
  160. for (unsigned int k = 0; k<mm; k++){
  161. cov.at(j*NTERMS+k) += (diff.at(j))*(diff.at(k))*sqr(weight);
  162. }
  163. }
  164. }
  165. moments = m;
  166. covariance = cov;
  167. return;
  168. };
  169. double corr_from_obs(std::vector<double> obs, std::vector<double> obscov, int i, int k){
  170. return obscov.at(i+NTERMS*k)/sqrt(obscov.at(k+NTERMS*k))/sqrt(obscov.at(i+NTERMS*i));
  171. }
  172. void bu2kstarmumu_pdf::save_moments_to_obs(bu2kstarmumu_parameters* params,
  173. std::vector<double> obs,
  174. std::vector<double> obscov) const
  175. {
  176. assert(obs.size() == NTERMS);
  177. assert(obscov.size() == NTERMS*NTERMS);
  178. //**** Fl ****//
  179. params->Fl.set_value(1.0-4.0/3.0*obs.at(0));
  180. params->Fl.set_error(4.0/3.0*sqrt(obscov.at(0+NTERMS*0)));
  181. if(opts->fit_fl) params->Fl.set_step_size(0.0001);
  182. for(unsigned int i = 0; i < NTERMS; i++){
  183. if(i == 0) params->Fl.set_correlation(1.0, 0); //self correlation is one by definition
  184. else if(i == 7 && opts->fit_afb){
  185. //correlation to Afb is equal to correlation of S1s and S6s
  186. params->Fl.set_correlation(corr_from_obs(obs,obscov,7,0), 7);
  187. }
  188. else{
  189. params->Fl.set_correlation(corr_from_obs(obs,obscov,i,0)/sqrt(3.0/4.0), i);
  190. }
  191. }
  192. //**** S1s ****//
  193. params->S1s.set_value(obs.at(0));
  194. params->S1s.set_error(sqrt(obscov.at(0+NTERMS*0)));
  195. if(!opts->fit_fl) params->S1s.set_step_size(0.0001);
  196. for(unsigned int i = 0; i < NTERMS; i++){
  197. params->S1s.set_correlation(corr_from_obs(obs,obscov,i,0), i);
  198. }
  199. //**** S3 ****//
  200. params->S3.set_value(obs.at(4));
  201. params->S3.set_error(sqrt(obscov.at(4+NTERMS*4)));
  202. params->S3.set_step_size(0.0001);
  203. for(unsigned int i = 0; i < NTERMS; i++){
  204. params->S3.set_correlation(corr_from_obs(obs,obscov,i,4), i);
  205. }
  206. //**** S4 ****//
  207. params->S4.set_value(obs.at(5));
  208. params->S4.set_error(sqrt(obscov.at(5+NTERMS*5)));
  209. params->S4.set_step_size(0.0001);
  210. for(unsigned int i = 0; i < NTERMS; i++)
  211. params->S4.set_correlation(corr_from_obs(obs,obscov,i,5), i);
  212. //**** S5 ****//
  213. params->S5.set_value(obs.at(6));
  214. params->S5.set_error(sqrt(obscov.at(6+NTERMS*6)));
  215. params->S5.set_step_size(0.0001);
  216. for(unsigned int i = 0; i < NTERMS; i++)
  217. params->S5.set_correlation(corr_from_obs(obs,obscov,i,6), i);
  218. //**** Afb ****//
  219. params->Afb.set_value(3.0/4.0*obs.at(7));
  220. params->Afb.set_error(3.0/4.0*sqrt(obscov.at(7+NTERMS*7)));
  221. if(opts->fit_afb)
  222. params->Afb.set_step_size(0.0001);
  223. for(unsigned int i = 0; i < NTERMS; i++){
  224. if(i == 7) params->Afb.set_correlation(1.0, 7);//self correlation is not scaled
  225. else if(i == 0 && opts->fit_afb){
  226. //correlation to Fl is equal to correlation of S1s and S6s
  227. params->Afb.set_correlation(corr_from_obs(obs,obscov,0,7), 0);
  228. }
  229. else params->Afb.set_correlation(corr_from_obs(obs,obscov,i,7)/sqrt(4.0/3.0), i);
  230. }
  231. //**** S6s ****//
  232. params->S6s.set_value(obs.at(7));
  233. params->S6s.set_error(sqrt(obscov.at(7+NTERMS*7)));
  234. if(!opts->fit_afb) params->S6s.set_step_size(0.0001);
  235. for(unsigned int i = 0; i < NTERMS; i++) params->S6s.set_correlation(corr_from_obs(obs,obscov,i,7), i);
  236. //**** S7 ****//
  237. params->S7.set_value(obs.at(9));
  238. params->S7.set_error(sqrt(obscov.at(9+NTERMS*9)));
  239. params->S7.set_step_size(0.0001);
  240. for(unsigned int i = 0; i < NTERMS; i++) params->S7.set_correlation(corr_from_obs(obs,obscov,i,9), i);
  241. //**** S8 ****//
  242. params->S8.set_value(obs.at(10));
  243. params->S8.set_error(sqrt(obscov.at(10+NTERMS*10)));
  244. params->S8.set_step_size(0.0001);
  245. for(unsigned int i = 0; i < NTERMS; i++) params->S8.set_correlation(corr_from_obs(obs,obscov,i,10), i);
  246. //**** S9 ****//
  247. params->S9.set_value(obs.at(11));
  248. params->S9.set_error(sqrt(obscov.at(11+NTERMS*11)));
  249. params->S9.set_step_size(0.0001);
  250. for(unsigned int i = 0; i < NTERMS; i++) params->S9.set_correlation(corr_from_obs(obs,obscov,i,11), i);
  251. //**** FS ****//
  252. params->FS.set_value(obs.at(12));
  253. params->FS.set_error(sqrt(obscov.at(12+NTERMS*12)));
  254. if(opts->swave) params->FS.set_step_size(0.0001);
  255. for(unsigned int i = 0; i < NTERMS; i++) params->FS.set_correlation(corr_from_obs(obs,obscov,i,12), i);
  256. //**** SS1 ****//
  257. params->SS1.set_value(obs.at(13));
  258. params->SS1.set_error(sqrt(obscov.at(13+NTERMS*13)));
  259. if(opts->swave) params->SS1.set_step_size(0.0001);
  260. for(unsigned int i = 0; i < NTERMS; i++) params->SS1.set_correlation(corr_from_obs(obs,obscov,i,13), i);
  261. //**** SS2 ****//
  262. params->SS2.set_value(obs.at(14));
  263. params->SS2.set_error(sqrt(obscov.at(14+NTERMS*14)));
  264. if(opts->swave) params->SS2.set_step_size(0.0001);
  265. for(unsigned int i = 0; i < NTERMS; i++) params->SS2.set_correlation(corr_from_obs(obs,obscov,i,14), i);
  266. //**** SS3 ****//
  267. params->SS3.set_value(obs.at(15));
  268. params->SS3.set_error(sqrt(obscov.at(15+NTERMS*15)));
  269. if(opts->swave) params->SS3.set_step_size(0.0001);
  270. for(unsigned int i = 0; i < NTERMS; i++) params->SS3.set_correlation(corr_from_obs(obs,obscov,i,15), i);
  271. //**** SS4 ****//
  272. params->SS4.set_value(obs.at(16));
  273. params->SS4.set_error(sqrt(obscov.at(16+NTERMS*16)));
  274. if(opts->swave)params->SS4.set_step_size(0.0001);
  275. for(unsigned int i = 0; i < NTERMS; i++) params->SS4.set_correlation(corr_from_obs(obs,obscov,i,16), i);
  276. //**** SS5 ****//
  277. params->SS5.set_value(obs.at(17));
  278. params->SS5.set_error(sqrt(obscov.at(17+NTERMS*17)));
  279. if(opts->swave) params->SS5.set_step_size(0.0001);
  280. for(unsigned int i = 0; i < NTERMS; i++) params->SS5.set_correlation(corr_from_obs(obs,obscov,i,17), i);
  281. }
  282. double bu2kstarmumu_pdf::prob(const bu2kstarmumu_parameters* params, const event& meas) const
  283. {
  284. //safety checks:
  285. if(opts->fit_mkpi && opts->use_mkpi){
  286. spdlog::critical("Do not use the direct fit of m(Kpi) and the included fit of m(Kpi) in the angular s-Wave at the same time!");
  287. spdlog::critical("5D fit:\t'use_mkpi'");
  288. spdlog::critical("4D+1D fit:\t'fit_mkpi'");
  289. assert(0);
  290. }
  291. if(opts->only_mass2DFit && opts->only_Bmass){
  292. spdlog::critical("Cannot fit m(Kpi) and m(B) with option 'only_Bmass'!");
  293. assert(0);
  294. }
  295. if(opts->only_mass2DFit && !opts->fit_mkpi){
  296. spdlog::critical("When using the 2D mass fit, enable 'fit_mkpi' as well!");
  297. assert(0);
  298. }
  299. if(opts->only_mkpi && !opts->fit_mkpi){
  300. spdlog::critical("When using the m(Kpi) mass fit, enable 'fit_mkpi' as well!");
  301. assert(0);
  302. }
  303. if((opts->only_angles && opts->only_Bmass) || (opts->only_mkpi && opts->only_Bmass) || (opts->only_angles && opts->only_mkpi)){
  304. spdlog::critical("Do not use two or more of 'only_Bmass', 'only_mkpi' and 'only_angles' at the same time!");
  305. spdlog::critical("only_Bmass = " + boolToString(opts->only_Bmass));
  306. spdlog::critical("only_mkpi = " + boolToString(opts->only_mkpi));
  307. spdlog::critical("only_angles = " + boolToString(opts->only_angles));
  308. assert(0);
  309. }
  310. if(opts->use_angular_acc && opts->weighted_fit){
  311. spdlog::critical("Do not use 'use_angular_acc' and 'weighted_fit' at the same time!");
  312. spdlog::critical("'use_angular_acc'\tConvolute acceptance function into fit pdf");
  313. spdlog::critical("'weighted_fit'\tAssign per event weight according to acceptance");
  314. assert(0);
  315. }
  316. if(opts->twotailedcrystalball && opts->crystalball){
  317. spdlog::critical("Cannot use CB and two-tailed CB option. Choose only one and chose wisely:");
  318. spdlog::critical("Either 'twotailedcrystalball' or 'crystalball'");
  319. assert(0);
  320. }
  321. if(opts->full_angular && opts->folding > -1){
  322. spdlog::critical("Cannot run full angular fit and folding at the same time");
  323. assert(0);
  324. }
  325. //determine signal and background probability
  326. double fsig = (opts->extended_ml ? params->n_sig()/(params->n_sig()+params->n_bkg()) : params->f_sig());
  327. double sig_part = 0.0;
  328. double bkg_part = 0.0;
  329. if(fsig != 0.0)//signal part:
  330. sig_part += fsig
  331. * angular_sig_prob(params, meas)
  332. * m_sig_prob(params, meas)
  333. * mkpi_sig_prob(params, meas);
  334. if(fsig != 1.0)//background part:
  335. bkg_part += (1.0-fsig)
  336. * angular_bkg_prob(params, meas)
  337. * m_bkg_prob(params, meas)
  338. * mkpi_bkg_prob(params, meas);
  339. //force individual probabilities for signal and background to be positive
  340. if(opts->individual_penalties){
  341. if(sig_part < 0.0){
  342. sig_part = 1.0e-12;
  343. bkg_part = 0.0;
  344. }
  345. if(bkg_part < 0.0){
  346. bkg_part = 1.0e-12;
  347. sig_part = 0.0;
  348. }
  349. }
  350. //add background and signal parts:
  351. double result = sig_part + bkg_part;
  352. //check final probability
  353. if(result < 0.0){
  354. std::lock_guard<std::mutex> lock(global_mutex_2);
  355. spdlog::debug("Event has negative probability {0:e}", result);
  356. spdlog::debug("Signal_part:\t{0:e}", sig_part);
  357. spdlog::debug("m(B):\t\t{0:e}",m_sig_prob(params, meas)); //THIS one crashes and idk why
  358. spdlog::debug("m(Kpi):\t{0:e}",mkpi_sig_prob(params, meas));
  359. spdlog::debug("angles:\t{0:e}",angular_sig_prob(params, meas));
  360. spdlog::debug("FS:\t\t{0:e}", params->FS.get_value());
  361. spdlog::debug("Backgrnd_part:\t{0:e}", bkg_part);
  362. if (fsig != 1.0){
  363. spdlog::debug("m(B):\t{0:e}",m_bkg_prob(params, meas));
  364. spdlog::debug("m(Kpi):\t{0:e}",mkpi_bkg_prob(params, meas));
  365. spdlog::debug("angles:\t{0:e}",angular_bkg_prob(params, meas));
  366. }
  367. const bool variablepushback = false; //OMFG
  368. if(variablepushback){
  369. double baseline = 1.0e-12;
  370. double absres = fabs(result) > 1.0e-6 ? fabs(result) : 1.0e-6;
  371. double logres = log10(absres)+6.0;
  372. double factor = pow(10.0, -logres);
  373. result = baseline*factor;
  374. }
  375. else{
  376. result = 1.0e-12;
  377. }
  378. }
  379. else if(std::isinf(result) || std::isnan(result)){
  380. std::lock_guard<std::mutex> lock(global_mutex_2);
  381. params->print_parameters(false);
  382. spdlog::error("Event has probability {0:f}", result);
  383. spdlog::error("Signal_part:\t{0:f}", sig_part);
  384. spdlog::error("fsig:\t\t{0:f}", fsig);
  385. spdlog::error("m(B):\t\t{0:f}", m_sig_prob(params, meas));
  386. spdlog::error("m(Kpi):\t{0:e}", mkpi_sig_prob(params, meas));
  387. spdlog::error("angles:\t{0:e}",angular_sig_prob(params, meas));
  388. spdlog::error("FS:\t\t{0:f}", params->FS.get_value());
  389. spdlog::error("m(K*+) s-Wave NORM:\t{0:f}", mkpi_swave_2_norm);
  390. spdlog::error("m(K*+) p-Wave NORM:\t{0:f}", mkpi_pwave_2_norm);
  391. spdlog::error("Backgrnd_part:\t{0:f}", bkg_part);
  392. assert(0);
  393. }
  394. return result;
  395. };
  396. void bu2kstarmumu_pdf::init(parameters* params) {
  397. init(dynamic_cast<bu2kstarmumu_parameters*>(params));
  398. //update_cached_normalization(params);
  399. };
  400. struct bin_edges{ //This could've been a class in case someone is bored in the future
  401. //limits for all variable (range) (4D):
  402. double q2min, q2max;
  403. double ctkmin, ctkmax;
  404. double ctlmin, ctlmax;
  405. double phimin, phimax;
  406. unsigned int nq2bins, nctlbins, nctkbins, nphibins;
  407. //keep this as functions in case of modyfing the ranges during running the code!
  408. //range of each dimension (4D):
  409. double range_q2(){
  410. return q2max - q2min;
  411. }
  412. double range_ctk(){
  413. return ctkmax - ctkmin;
  414. }
  415. double range_ctl(){
  416. return ctlmax - ctlmin;
  417. }
  418. double range_phi(){
  419. return phimax - phimin;
  420. }
  421. //bin width for each variable
  422. double binWidth_q2(){
  423. return range_q2()/nq2bins;
  424. }
  425. double binWidth_ctl(){
  426. return range_ctl()/nctlbins;
  427. }
  428. double binWidth_ctk(){
  429. return range_ctk()/nctkbins;
  430. }
  431. double binWidth_phi(){
  432. return range_phi()/nphibins;
  433. }
  434. //bin edges for each variable
  435. std::vector<double> edges_q2(){
  436. std::vector<double> tmp;
  437. for (unsigned int h = 0; h<=nq2bins; h++){
  438. tmp.push_back(q2min + h * binWidth_q2());
  439. }
  440. return tmp;
  441. }
  442. std::vector<double> edges_ctl(){
  443. std::vector<double> tmp;
  444. for (unsigned int h = 0; h<=nctlbins; h++){
  445. tmp.push_back(ctlmin + h * binWidth_ctl());
  446. }
  447. return tmp;
  448. }
  449. std::vector<double> edges_ctk(){
  450. std::vector<double> tmp;
  451. for (unsigned int h = 0; h<=nctkbins; h++){
  452. tmp.push_back(ctkmin + h * binWidth_ctk());
  453. }
  454. return tmp;
  455. }
  456. std::vector<double> edges_phi(){
  457. std::vector<double> tmp;
  458. for (unsigned int h = 0; h<=nphibins; h++){
  459. tmp.push_back(phimin + h * binWidth_phi());
  460. }
  461. return tmp;
  462. }
  463. //Total number of bins in 4D
  464. unsigned int getNbins(){
  465. return nq2bins*nctlbins*nctkbins*nphibins;
  466. }
  467. //constructor
  468. bin_edges(fcnc::options *opts, unsigned int nq2,unsigned int nctl,unsigned int nctk,unsigned int nphi){
  469. //get the limits for all variables (4D):
  470. q2min = opts->TheQ2binsmin.front(); q2max = opts->TheQ2binsmax.back();
  471. ctkmin = opts->ctk_min; ctkmax = opts->ctk_max;
  472. ctlmin = opts->ctl_min; ctlmax = opts->ctl_max;
  473. phimin = opts->phi_min; phimax = opts->phi_max;
  474. nq2bins = nq2;
  475. nctlbins = nctl;
  476. nctkbins = nctk;
  477. nphibins = nphi;
  478. }
  479. };
  480. unsigned int get_bin_in4D(int h, int i, int j, int k, bin_edges edges){
  481. /// h = q2, i = ctl, j = ctk, k = phi
  482. //Return the bin number for given event evt in 4D (q2, thetal, thetak, phi)
  483. //Starting from 0!
  484. unsigned int bin = edges.nctlbins*edges.nctkbins*edges.nphibins*h //q2
  485. +edges.nctkbins*edges.nphibins*i //thetaL
  486. +edges.nphibins*j //thetaK
  487. +k; //phi
  488. if (bin >= edges.getNbins()){
  489. spdlog::critical("Bin {0:d} is larger than the dimension of {1:d}!",bin,edges.getNbins());
  490. spdlog::error("h {0:d},\ti {1:d},\tj {2:d},\tk {3:d}", h, i, j, k);
  491. spdlog::error("q2 {0:d},\tctl {1:d},\tctk {2:d},\tphi {3:d}",
  492. edges.nq2bins, edges.nctlbins, edges.nctkbins, edges.nphibins);
  493. assert(0);
  494. }
  495. else return bin;
  496. }
  497. unsigned int get_bin_in4D(event evt, bin_edges edges ){
  498. //Return the bin number for given event evt in 4D (q2, thetal, thetak, phi)
  499. //Starting from 0!
  500. unsigned int h = (evt.q2 - edges.q2min ) / edges.binWidth_q2(); //division here truncates the result"chi
  501. unsigned int i = (evt.costhetal - edges.ctlmin) / edges.binWidth_ctl();//eg 18/10 = 1
  502. unsigned int j = (evt.costhetak - edges.ctkmin) / edges.binWidth_ctk();
  503. unsigned int k = (evt.phi - edges.phimin) / edges.binWidth_phi();
  504. return get_bin_in4D(h,i,j,k, edges);
  505. }
  506. unsigned int npolynom::get_bin_in4D(int h, int i, int j, int k){
  507. /// h = q2, i = ctl, j = ctk, k = phi
  508. //Return the bin number for given event evt in 4D (q2, thetal, thetak, phi)
  509. //Starting from 0!
  510. return ctl*ctk*phi*h //q2
  511. +ctk*phi*i //thetaL
  512. +phi*j //thetaK
  513. +k; //phi
  514. }
  515. unsigned int get_bin_in3D(int i, int j, int k, npolynom npol){
  516. /// h = q2, i = ctl, j = ctk, k = phi
  517. //Return the bin number for given event evt in 4D (q2, thetal, thetak, phi)
  518. //Starting from 0!
  519. return npol.ctk*npol.phi*i //thetaL
  520. +npol.phi*j //thetaK
  521. +k; //phi
  522. }
  523. unsigned int get_bin_in3D(int i, int j, int k, bin_edges edges){
  524. /// h = q2, i = ctl, j = ctk, k = phi
  525. //Return the bin number for given event evt in 4D (q2, thetal, thetak, phi)
  526. //Starting from 0!
  527. return edges.nctkbins*edges.nphibins*i //thetaL
  528. +edges.nphibins*j //thetaK
  529. +k; //phi
  530. }
  531. void get_chi2(bin_edges edges, npolynom npol,
  532. std::vector<event> eventsInQ2bin, std::vector<double> coeffs_moments,
  533. values* globalvalues,
  534. bool assumectleven, bool assumePhiEven, bool write_eps,
  535. std::string subfolder, std::string appendix){
  536. spdlog::info( "Starting chi2 calculation" );
  537. std::vector<double> nsel_hist(edges.getNbins(), 0.0);
  538. std::vector<double> nsel_hist_errsq(edges.getNbins(), 0.0);
  539. //this is actually not the correct error here, due to the weights!
  540. //should be sqrt(sum_i weights_i^2)
  541. double nsel = 0.0;
  542. int nEvents = eventsInQ2bin.size();
  543. for (auto &meas: eventsInQ2bin) {
  544. unsigned int bin = get_bin_in4D(meas,edges);
  545. nsel_hist.at(bin) += meas.weight;
  546. nsel += meas.weight;
  547. nsel_hist_errsq.at(bin) += sqr(meas.weight);
  548. }
  549. //Set errors
  550. for (auto err: nsel_hist_errsq){
  551. if (err == 0.0) err = 1.0;
  552. }
  553. //compare with prediction
  554. double neps = 0.0;
  555. std::vector<double> neps_hist(edges.getNbins(), 0.0);
  556. std::vector<double> q2_edges = edges.edges_q2();
  557. std::vector<double> ctl_edges = edges.edges_ctl();
  558. std::vector<double> ctk_edges = edges.edges_ctk();
  559. std::vector<double> phi_edges = edges.edges_phi();
  560. for (unsigned int h = 0; h<edges.nq2bins; h++){
  561. for (unsigned int i = 0; i<edges.nctlbins; i++){
  562. for (unsigned int j = 0; j<edges.nctkbins; j++){
  563. for (unsigned int k = 0; k<edges.nphibins; k++){
  564. double integral = 0.0;
  565. for (unsigned int l = 0; l<npol.q2; l++){
  566. for (unsigned int m = 0; m<npol.ctl; m++){
  567. for (unsigned int n = 0; n<npol.ctk; n++){
  568. for (unsigned int o = 0; o<npol.phi; o++){
  569. double result = coeffs_moments.at(npol.get_bin_in4D(l,m,n,o))
  570. *(pow(q2_edges[h+1],l+1) - pow(q2_edges[h],l+1))/(l+1.0)
  571. *(pow(ctl_edges[i+1],m+1) - pow(ctl_edges[i],m+1))/(m+1.0)
  572. *(pow(ctk_edges[j+1],n+1) - pow(ctk_edges[j],n+1))/(n+1.0)
  573. *(pow(phi_edges[k+1],o+1) - pow(phi_edges[k],o+1))/(o+1.0);
  574. integral += result;
  575. }
  576. }
  577. }
  578. }
  579. neps_hist.at(get_bin_in4D(h,i,j,k,edges)) = integral;
  580. neps += integral;
  581. }
  582. }
  583. }
  584. }
  585. spdlog::debug( "nsel {0:f}\n\t nEvents {1:d}\n\t neps {2:f}\n\t nsel/neps {3:f} ", nsel, nEvents, neps, nsel/neps );
  586. TH1D* hpull = new TH1D("hpull", ";(N_{sel}-N_{fit})/#sqrt{N_{sel}};",100, -5.0, +5.0);
  587. TH1D* hnsel = new TH1D("hnsel", ";N_{sel};",100, 0.0, +25.0);
  588. TH1D* hnfit = new TH1D("hnfit", ";N_{fit};",100, 0.0, +25.0);
  589. //rescale fitted efficiency to MC statistics
  590. //This would be nicer in a vector of vectors or so, but oh well
  591. for (unsigned int h = 0; h<edges.nq2bins; h++)
  592. for (unsigned int i = 0; i<edges.nctlbins; i++)
  593. for (unsigned int j = 0; j<edges.nctkbins; j++)
  594. for (unsigned int k = 0; k<edges.nphibins; k++)
  595. neps_hist.at(get_bin_in4D(h,i,j,k, edges)) *= nsel/neps;
  596. //calculate chi2 and perform "pull" plot
  597. double chi2 = 0.0;
  598. //double errorscale = 1.01;
  599. for (unsigned int h = 0; h<edges.nq2bins; h++){
  600. for (unsigned int i = 0; i<edges.nctlbins; i++){
  601. for (unsigned int j = 0; j<edges.nctkbins; j++){
  602. for (unsigned int k = 0; k<edges.nphibins; k++){
  603. unsigned int bin = get_bin_in4D(h,i,j,k, edges);
  604. //nominal
  605. chi2 += sqr(nsel_hist.at(bin)-neps_hist.at(bin))/fabs(neps_hist.at(bin));
  606. hpull->Fill((nsel_hist.at(bin)-neps_hist.at(bin))/sqrt(fabs(neps_hist.at(bin))));
  607. spdlog::trace("nsel_hist.at({0:d})\t{1:f}",bin,nsel_hist.at(bin));
  608. spdlog::trace("neps_hist.at({0:d})\t{1:f}",bin,neps_hist.at(bin));
  609. hnsel->Fill(nsel_hist.at(bin));
  610. hnfit->Fill(neps_hist.at(bin));
  611. }
  612. }
  613. }
  614. }
  615. spdlog::debug( "chi2\t {0:f}", chi2 );
  616. //Calculate the number of parameters
  617. int nparams = npol.q2*npol.ctl*npol.ctk*npol.phi-1;
  618. spdlog::debug( "Nparams\t {0:d}", nparams );
  619. if (assumectleven && assumePhiEven){
  620. nparams = npol.q2*((npol.ctl+1)/2)*npol.ctk*((npol.phi+1)/2)-1;
  621. }
  622. else{
  623. if (assumectleven) nparams = npol.q2*((npol.ctl+1)/2)*npol.ctk*npol.phi-1;
  624. if (assumePhiEven) nparams = npol.q2*npol.ctl*npol.ctk*((npol.phi+1)/2)-1;
  625. }
  626. spdlog::debug( "Nparams (accounting for even ctl and phi)\t {0:d}", nparams );
  627. //Get degrees of freedom
  628. int nbins = edges.getNbins();
  629. spdlog::debug( "Nbins\t {0:d}", nbins);
  630. int ndof = nbins - nparams - 1;
  631. spdlog::debug( "ndof\t {0:d}", ndof );
  632. spdlog::debug( "chi2/ndof (accounting for even ctl and phi)\t {0:f}",chi2/ndof );
  633. spdlog::debug( "chi2/Nbins\t\t {0:f}",chi2/nbins );
  634. spdlog::debug( "pvalue using ndof\t {0:f}",TMath::Prob(chi2, ndof) );
  635. spdlog::debug( "pvalue using nbins\t {0:f}", TMath::Prob(chi2, nbins) );
  636. //=========================================
  637. //
  638. // save chi2 to global values:
  639. //
  640. //=========================================
  641. globalvalues->angacccorr_chi2 = chi2;
  642. globalvalues->angacccorr_ndof = ndof;
  643. //recount of nparams
  644. int ncount = 0;
  645. for (unsigned int l = 0; l<npol.q2; l++)
  646. for (unsigned int m = 0; m<npol.ctl; m++)
  647. for (unsigned int n = 0; n<npol.ctk; n++)
  648. for (unsigned int o = 0; o<npol.phi; o++)
  649. if (coeffs_moments.at(npol.get_bin_in4D(l,m,n,o)) != 0.0) ncount++;
  650. spdlog::debug( "Recount of Nparams gives:\t {0:d}",ncount );
  651. if(write_eps){
  652. plotAndSave(hpull,"cpull",subfolder + "pull"+appendix, "eps");
  653. plotAndSave(hnsel,"csel",subfolder + "nsel"+appendix, "eps");
  654. plotAndSave(hnfit,"cfit",subfolder + "nfit"+appendix, "eps");
  655. }
  656. delete hpull;
  657. delete hnsel;
  658. delete hnfit;
  659. return;
  660. }
  661. void get_legendre(bin_edges edges, npolynom npol,
  662. std::vector<event> eventsInQ2bin, double nWeightedEvents,
  663. std::vector<double> &poly_moments,
  664. bool fejerkernel, bool assumectleven, bool assumePhiEven,
  665. bool checkSignificance, bool calculateCovariance){
  666. //use Legendre polynomials
  667. spdlog::info("DOLEGENDRE start");
  668. //should def use this:
  669. //calculates all legendre polynomials up to including degree n
  670. //void fcnc::legendre(double x, int n, std::vector<double>& results)
  671. //this is not the best way to do things
  672. //should rather
  673. //loop over events
  674. //determine, for every event the legendre polynomials order 0 to nq2/nctl/nctk/nphi
  675. //loop over all orders
  676. //add weight*leg_q2.at(h)*leg_ctl.at(i)*leg_ctk.at(j)*leg_phi.at(k) in correct bin
  677. //optimized version
  678. std::vector<double> chijk_moments = std::vector<double>(npol.getSize(), 0.0);
  679. for (auto & meas: eventsInQ2bin){ //This is all computed then in the range of -1 to +1
  680. double q2 = 2.0 * (meas.q2 - edges.q2min ) / edges.range_q2() - 1.0;
  681. double ctl = 2.0 * (meas.costhetal - edges.ctlmin) / edges.range_ctl()- 1.0;
  682. double ctk = 2.0 * (meas.costhetak - edges.ctkmin) / edges.range_ctk()- 1.0;
  683. double phi = 2.0 * (meas.phi - edges.phimin) / edges.range_phi()- 1.0;
  684. double weight = meas.weight;
  685. //calculates all legendre polynomials up to including degree n
  686. std::vector<double> leg_q2(npol.q2, 0.0);
  687. fcnc::legendre(q2, npol.q2, leg_q2);
  688. std::vector<double> leg_ctl(npol.ctl, 0.0);
  689. fcnc::legendre(ctl, npol.ctl, leg_ctl);
  690. std::vector<double> leg_ctk(npol.ctk, 0.0);
  691. fcnc::legendre(ctk, npol.ctk, leg_ctk);
  692. std::vector<double> leg_phi(npol.phi, 0.0);
  693. fcnc::legendre(phi, npol.phi, leg_phi);
  694. double result = 0.0;
  695. for (unsigned int h = 0; h<npol.q2; h++){
  696. for (unsigned int i = 0; i<npol.ctl; i++){
  697. for (unsigned int j = 0; j<npol.ctk; j++){
  698. for (unsigned int k = 0; k<npol.phi; k++){
  699. unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  700. result = 0.0;
  701. //result
  702. if (assumectleven && i%2 != 0 ) result = 0.0;
  703. else if (assumePhiEven && k%2 != 0) result = 0.0;
  704. else{
  705. result =
  706. weight
  707. *leg_q2.at(h)*(2.0*h+1.0)/2.0
  708. *leg_ctl.at(i)*(2.0*i+1.0)/2.0
  709. *leg_ctk.at(j)*(2.0*j+1.0)/2.0
  710. *leg_phi.at(k)*(2.0*k+1.0)/2.0
  711. /nWeightedEvents;
  712. if (fejerkernel)
  713. result *= (1.0 - h/double(npol.q2-1))
  714. *(1.0 - i/double(npol.ctl-1))
  715. *(1.0 - j/double(npol.ctk-1))
  716. *(1.0 - k/double(npol.phi-1));
  717. }
  718. chijk_moments.at(bin) += result;
  719. }
  720. }
  721. }
  722. }
  723. }
  724. //check significance
  725. //can be optimized as above
  726. if (checkSignificance){
  727. spdlog::info("starting CHECK SIGNIFICANT for LEGENDRE" );
  728. for (unsigned int h = 0; h<npol.q2; h++){
  729. for (unsigned int i = 0; i<npol.ctl; i++){
  730. for (unsigned int j = 0; j<npol.ctk; j++){
  731. for (unsigned int k = 0; k<npol.phi; k++){
  732. unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  733. double result = chijk_moments.at(bin);
  734. double sigma = 0.0;
  735. for (unsigned int e=0; e<eventsInQ2bin.size(); e++){
  736. const event & meas = eventsInQ2bin.at(e);
  737. double q2 = 2.0 * (meas.q2 - edges.q2min ) / edges.range_q2() - 1.0;
  738. double ctl = 2.0 * (meas.costhetal - edges.ctlmin ) / edges.range_ctl() - 1.0;
  739. double ctk = 2.0 * (meas.costhetak - edges.ctkmin ) / edges.range_ctk() - 1.0;
  740. double phi = 2.0 * (meas.phi - edges.phimin ) / edges.range_phi() - 1.0;
  741. sigma += sqr(result - meas.weight // /nWeightedEvents
  742. *fcnc::legendre(q2, h)*(2.0*h+1.0)/2.0
  743. *fcnc::legendre(ctl, i)*(2.0*i+1.0)/2.0
  744. *fcnc::legendre(ctk, j)*(2.0*j+1.0)/2.0
  745. *fcnc::legendre(phi, k)*(2.0*k+1.0)/2.0
  746. );// /eventsInQ2bin.size();
  747. }
  748. sigma = sqrt(sigma);
  749. sigma /= nWeightedEvents;
  750. if (fabs(result/sigma) < 1.0) chijk_moments.at(bin) = 0.0;
  751. }
  752. }
  753. }
  754. }
  755. spdlog::info( "finished CHECK SIGNIFICANT for LEGENDRE" );
  756. }
  757. //Log
  758. spdlog::debug( "//vector of legendre efficiency coefficients containing {0:d} elements", chijk_moments.size());
  759. spdlog::trace( "legendre_coeffs_eff_4d = { " );
  760. if (spdlog_trace()){
  761. for (unsigned int i=0; i<chijk_moments.size(); i++){
  762. std::cout<< std::setprecision(15) << std::scientific << chijk_moments.at(i) << (i<chijk_moments.size()-1 ? ", " : " ");
  763. }
  764. }
  765. //calculate covariance
  766. if (calculateCovariance){
  767. const unsigned int nsize = npol.getSize();
  768. spdlog::info( "Start COVARIANCE matrix for LEGENDRE polynoms" );
  769. spdlog::debug( "calculating {0:d} by {1:d} convariance matrix ({2:d} doubles)" , nsize, nsize, nsize*nsize );
  770. //optimized
  771. std::vector<double> covariance(nsize*nsize, 0.0);
  772. //startB = clock();
  773. for (unsigned int e=0; e<eventsInQ2bin.size(); e++){
  774. if (e % (eventsInQ2bin.size()/100) == 0)spdlog::debug( "{0:f}%", round(double(e*100)/eventsInQ2bin.size()));
  775. const event & meas = eventsInQ2bin.at(e);
  776. double q2 = 2.0 * (meas.q2 - edges.q2min ) / edges.range_q2() - 1.0;
  777. double ctl = 2.0 * (meas.costhetal - edges.ctlmin) / edges.range_ctl()- 1.0;
  778. double ctk = 2.0 * (meas.costhetak - edges.ctkmin) / edges.range_ctk()- 1.0;
  779. double phi = 2.0 * (meas.phi - edges.phimin) / edges.range_phi()- 1.0;
  780. double weight = meas.weight;
  781. //calculates all legendre polynomials up to including degree n
  782. std::vector<double> leg_q2(npol.q2, 0.0);
  783. legendre(q2, npol.q2, leg_q2);
  784. std::vector<double> leg_ctl(npol.ctl, 0.0);
  785. legendre(ctl, npol.ctl, leg_ctl);
  786. std::vector<double> leg_ctk(npol.ctk, 0.0);
  787. legendre(ctk, npol.ctk, leg_ctk);
  788. std::vector<double> leg_phi(npol.phi, 0.0);
  789. legendre(phi, npol.phi, leg_phi);
  790. double wfactor = weight*weight/(nWeightedEvents*nWeightedEvents);
  791. double resulti=0.0, resultj=0.0, cov=0.0;
  792. unsigned int bini=0, binj=0;
  793. int hfactor=0, ifactor=0, jfactor=0, kfactor=0,
  794. lfactor=0, mfactor=0, nfactor=0, ofactor=0,
  795. hifactor=0, hijfactor=0, hijkfactor=0,
  796. lmfactor=0, lmnfactor=0, lmnofactor=0;
  797. double aq2=0.0,aq2ctl=0.0,aq2ctlctk=0.0,aq2ctlctkphi=0.0;
  798. double bq2=0.0,bq2ctl=0.0,bq2ctlctk=0.0,bq2ctlctkphi=0.0;
  799. for (unsigned int h = 0; h<npol.q2; h++){
  800. hfactor = (2*h+1);
  801. aq2 = 0.0625*leg_q2[h];
  802. for (unsigned int i = 0; i<npol.ctl; i++){
  803. ifactor = (2*i+1);
  804. hifactor = hfactor*ifactor;
  805. aq2ctl = aq2*leg_ctl[i];
  806. for (unsigned int j = 0; j<npol.ctk; j++){
  807. jfactor = (2*j+1);
  808. hijfactor = hifactor*jfactor;
  809. aq2ctlctk = aq2ctl*leg_ctk[j];
  810. for (unsigned int k = 0; k<npol.phi; k++){
  811. kfactor = (2*k+1);
  812. hijkfactor = hijfactor*kfactor;
  813. aq2ctlctkphi = aq2ctlctk*leg_phi[k];
  814. bini = npol.get_bin_in4D(h,i,j,k);
  815. resulti = chijk_moments[bini];
  816. if (resulti != 0.0){
  817. for (unsigned int l = 0; l<npol.q2; l++){
  818. lfactor = (2*l+1);
  819. bq2 = 0.0625*leg_q2[l];
  820. for (unsigned int m = 0; m<npol.ctl; m++)
  821. {
  822. mfactor = (2*m+1);
  823. lmfactor = lfactor*mfactor;
  824. bq2ctl = bq2*leg_ctl[m];
  825. for (unsigned int n = 0; n<npol.ctk; n++){
  826. nfactor = (2*n+1);
  827. lmnfactor = lmfactor*nfactor;
  828. bq2ctlctk = bq2ctl*leg_ctk[n];
  829. for (unsigned int o = 0; o<npol.phi; o++){
  830. ofactor = (2*o+1);
  831. lmnofactor = lmnfactor*ofactor;
  832. bq2ctlctkphi = bq2ctlctk*leg_phi[o];
  833. binj = npol.get_bin_in4D(l,m,n,o);
  834. resultj = chijk_moments[binj];
  835. if (binj <= bini && resultj != 0.0){
  836. cov = (wfactor
  837. *(resulti-hijkfactor*aq2ctlctkphi)
  838. *(resultj-lmnofactor*bq2ctlctkphi)
  839. );
  840. covariance[nsize*bini+binj] += cov;
  841. }
  842. }
  843. }
  844. }
  845. }
  846. }
  847. }
  848. }
  849. }
  850. }
  851. }
  852. for (unsigned int bini = 0; bini<nsize; bini++){
  853. for (unsigned int binj = 0; binj<nsize; binj++){
  854. //covariance matrix is symmetric
  855. if (binj < bini) covariance.at(nsize*binj+bini) = covariance.at(nsize*bini+binj);
  856. }
  857. }
  858. //Print uncertanities in a matrix
  859. spdlog::info("uncertainties[{0:0.8e}]", nsize);
  860. for (unsigned int i =0; i<nsize; i++) std::cout << covariance.at(nsize*i+i) << (i < nsize-1 ? ", " : " };");
  861. //Print covariance matrix
  862. spdlog::info("Covariance matrix cov[{0:0.8e}]", nsize*nsize);
  863. for (unsigned int i =0; i<nsize; i++){
  864. for (unsigned int j =0; j<nsize; j++){
  865. std::cout <<covariance.at(nsize*i+j) << ", ";
  866. }
  867. std::cout << std::endl;
  868. }
  869. std::cout << "};" << std::endl;//needs to be converted into correct range and translated to monomial coefficients? no, should do these transformations after every acceptance randomization
  870. double correlation = 0.0;
  871. for (unsigned int i =0; i<nsize; i++){
  872. for (unsigned int j =0; j<nsize; j++){
  873. double corr = covariance.at(nsize*i+j)/sqrt(covariance.at(nsize*i+i))/sqrt(covariance.at(nsize*j+j));
  874. if (fabs(corr) > fabs(correlation) && i != j) correlation = corr;
  875. }
  876. }
  877. spdlog::info("Largest correlation found is {0:f}", correlation );
  878. }
  879. spdlog::debug("start CONVERT legendre to monomial coefficients" );
  880. //transform legendre coefficients to monomial coefficients
  881. for (unsigned int h = 0; h<npol.q2; h++)
  882. for (unsigned int i = 0; i<npol.ctl; i++)
  883. for (unsigned int j = 0; j<npol.ctk; j++)
  884. for (unsigned int k = 0; k<npol.phi; k++){
  885. double tmp = chijk_moments.at(npol.get_bin_in4D(h,i,j,k));
  886. std::vector<double> leg_coeffs_q2(npol.q2, 0.0);
  887. std::vector<double> leg_coeffs_ctl(npol.ctl, 0.0);
  888. std::vector<double> leg_coeffs_ctk(npol.ctk, 0.0);
  889. std::vector<double> leg_coeffs_phi(npol.phi, 0.0);
  890. std::vector<double> poly_coeffs_q2(npol.q2, 0.0);
  891. std::vector<double> poly_coeffs_ctl(npol.ctl, 0.0);
  892. std::vector<double> poly_coeffs_ctk(npol.ctk, 0.0);
  893. std::vector<double> poly_coeffs_phi(npol.phi, 0.0);
  894. leg_coeffs_q2.at(h) = 1.0;
  895. leg_coeffs_ctl.at(i) = 1.0;
  896. leg_coeffs_ctk.at(j) = 1.0;
  897. leg_coeffs_phi.at(k) = 1.0;
  898. legendre_to_poly(leg_coeffs_q2, poly_coeffs_q2);
  899. legendre_to_poly(leg_coeffs_ctl, poly_coeffs_ctl);
  900. legendre_to_poly(leg_coeffs_ctk, poly_coeffs_ctk);
  901. legendre_to_poly(leg_coeffs_phi, poly_coeffs_phi);
  902. for (unsigned int l = 0; l<=h; l++)
  903. for (unsigned int m = 0; m<=i; m++)
  904. for (unsigned int n = 0; n<=j; n++)
  905. for (unsigned int o = 0; o<=k; o++){
  906. unsigned int bin = npol.get_bin_in4D(l,m,n,o);
  907. poly_moments.at(bin) += tmp*poly_coeffs_q2.at(l)*poly_coeffs_ctl.at(m)*poly_coeffs_ctk.at(n)*poly_coeffs_phi.at(o);
  908. }
  909. }//tested, works
  910. spdlog::debug( "end CONVERT legendre to monomial coefficients" );
  911. spdlog::debug( "poly_moments size: {0:d}", poly_moments.size() );
  912. spdlog::info( "DOLEGENDRE end" );
  913. }
  914. void get_chebyschev(bin_edges edges, npolynom npol,
  915. std::vector<event> eventsInQ2bin, double nWeightedEvents,
  916. std::vector<double> &poly_moments,
  917. bool fejerkernel, bool assumectleven, bool assumePhiEven,
  918. bool checkSignificance, bool calculateCovariance
  919. ){
  920. //use Legendre polynomials
  921. spdlog::info("CHEBYSCHEV start");
  922. std::vector<double> chijk_moments = std::vector<double>(npol.getSize(), 0.0);
  923. for (unsigned int h = 0; h<npol.q2; h++)
  924. for (unsigned int i = 0; i<npol.ctl; i++)
  925. for (unsigned int j = 0; j<npol.ctk; j++)
  926. for (unsigned int k = 0; k<npol.phi; k++){
  927. double result = 0.0;
  928. if (assumectleven && i%2 != 0)result = 0.0;
  929. else if (assumePhiEven && k%2 != 0)result = 0.0;
  930. else{
  931. for (auto &meas: eventsInQ2bin){
  932. double q2 = 2.0 * (meas.q2 - edges.q2min ) / edges.range_q2() - 1.0;
  933. double ctl = 2.0 * (meas.costhetal - edges.ctlmin) / edges.range_ctl()- 1.0;
  934. double ctk = 2.0 * (meas.costhetak - edges.ctkmin) / edges.range_ctk()- 1.0;
  935. double phi = 2.0 * (meas.phi - edges.phimin) / edges.range_phi()- 1.0;
  936. result += meas.weight
  937. *fcnc::chebyshev(q2, h)/sqrt(1.0-q2*q2)*(h == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  938. *fcnc::chebyshev(ctl, i)/sqrt(1.0-ctl*ctl)*(i == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  939. *fcnc::chebyshev(ctk, j)/sqrt(1.0-ctk*ctk)*(j == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  940. *fcnc::chebyshev(phi, k)/sqrt(1.0-phi*phi)*(k == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  941. /nWeightedEvents;// /eventsInQ2bin.size();
  942. }
  943. if (fejerkernel){
  944. result *= (1.0 - h/double(npol.q2-1))
  945. *(1.0 - i/double(npol.ctl-1))
  946. *(1.0 - j/double(npol.ctk-1))
  947. *(1.0 - k/double(npol.phi-1));
  948. }
  949. }
  950. //now have the "mean" in result
  951. //mu = sum_i w_i/N
  952. //sigma(mu) = sqrt(sum_i (w_i-mu)^2)/N
  953. //else
  954. chijk_moments.push_back(result);
  955. }
  956. //check significance
  957. if (checkSignificance){
  958. spdlog::info( "start CHECK SIGNIFICANCE for CHEBYSHEV polynoms" );
  959. for (unsigned int h = 0; h<npol.q2; h++)
  960. for (unsigned int i = 0; i<npol.ctl; i++)
  961. for (unsigned int j = 0; j<npol.ctk; j++)
  962. for (unsigned int k = 0; k<npol.phi; k++){
  963. unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  964. double result = chijk_moments.at(bin);
  965. double sigma = 0.0;
  966. for (auto &meas : eventsInQ2bin){
  967. double q2 = 2.0 * (meas.q2 - edges.q2min ) / edges.range_q2() - 1.0;
  968. double ctl = 2.0 * (meas.costhetal - edges.ctlmin) / edges.range_ctl()- 1.0;
  969. double ctk = 2.0 * (meas.costhetak - edges.ctkmin) / edges.range_ctk()- 1.0;
  970. double phi = 2.0 * (meas.phi - edges.phimin) / edges.range_phi()- 1.0;
  971. sigma += sqr(result - meas.weight // /nWeightedEvents
  972. *fcnc::chebyshev(q2, h)/sqrt(1-q2*q2)*(h == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  973. *fcnc::chebyshev(ctl, i)/sqrt(1-ctl*ctl)*(i == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  974. *fcnc::chebyshev(ctk, j)/sqrt(1-ctk*ctk)*(j == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  975. *fcnc::chebyshev(phi, k)/sqrt(1-phi*phi)*(k == 0 ? 1.0/MY_PI : 2.0/MY_PI));// /eventsInQ2bin.size();
  976. }
  977. sigma = sqrt(sigma);
  978. sigma /= nWeightedEvents;
  979. if (fabs(result/sigma) < 1.0) chijk_moments.at(bin) = 0.0;
  980. }
  981. spdlog::info( "end CHECK SIGNIFICANCE for CHEBYSHEV polynoms" );
  982. }
  983. //printchebyshev
  984. spdlog::debug( "//vector of chebyshev efficiency coefficients containing {0:d} elements",chijk_moments.size());
  985. spdlog::trace( "chebyshev_coeffs_eff_4d = { " );
  986. if (spdlog_trace()){
  987. for (unsigned int i=0; i<chijk_moments.size(); i++){
  988. std::cout<< std::setprecision(15) << std::scientific << chijk_moments.at(i) << (i<chijk_moments.size()-1 ? ", " : " ");
  989. }
  990. }
  991. //calculate covariance
  992. if (calculateCovariance){
  993. spdlog::debug( "calculating {0:d} by {1:d} convariance matrix ({2:d} doubles)" , npol.getSize(), npol.getSize(), npol.getSize2() );
  994. std::vector<double> covariance(npol.getSize2(), 0.0);
  995. for (unsigned int h = 0; h<npol.q2; h++){
  996. for (unsigned int i = 0; i<npol.ctl; i++){
  997. for (unsigned int j = 0; j<npol.ctk; j++){
  998. for (unsigned int k = 0; k<npol.phi; k++){
  999. unsigned int bini = npol.get_bin_in4D(h,i,j,k);
  1000. double resulti = chijk_moments.at(bini);
  1001. if (resulti != 0.0){
  1002. for (unsigned int l = 0; l<npol.q2; l++){
  1003. for (unsigned int m = 0; m<npol.ctl; m++){
  1004. for (unsigned int n = 0; n<npol.ctk; n++){
  1005. for (unsigned int o = 0; o<npol.phi; o++){
  1006. unsigned int binj = npol.get_bin_in4D(l,m,n,o);
  1007. if (binj > bini) continue;//covariance matrix is symmetric
  1008. double resultj = chijk_moments.at(binj);
  1009. if (((bini*npol.getSize()+binj) * 100) % (npol.getSize2()) == 0)
  1010. spdlog::debug( "covariance matrix calculation {0:f}%", ((bini*npol.getSize()+binj) * 100) / (npol.getSize2()));
  1011. if (resultj != 0.0){
  1012. double cov = 0.0;
  1013. for (auto &meas : eventsInQ2bin){
  1014. double q2 = 2.0 * (meas.q2 - edges.q2min ) / edges.range_q2() - 1.0;
  1015. double ctl = 2.0 * (meas.costhetal - edges.ctlmin) / edges.range_ctl()- 1.0;
  1016. double ctk = 2.0 * (meas.costhetak - edges.ctkmin) / edges.range_ctk()- 1.0;
  1017. double phi = 2.0 * (meas.phi - edges.phimin) / edges.range_phi()- 1.0;
  1018. cov += ((resulti - meas.weight
  1019. *fcnc::chebyshev(q2, h)/sqrt(1-q2*q2)*(h == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  1020. *fcnc::chebyshev(ctl, i)/sqrt(1-ctl*ctl)*(i == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  1021. *fcnc::chebyshev(ctk, j)/sqrt(1-ctk*ctk)*(j == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  1022. *fcnc::chebyshev(phi, k)/sqrt(1-phi*phi)*(k == 0 ? 1.0/MY_PI : 2.0/MY_PI))
  1023. *(resultj - meas.weight
  1024. *fcnc::chebyshev(q2, l)/sqrt(1-q2*q2)*(l == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  1025. *fcnc::chebyshev(ctl, m)/sqrt(1-ctl*ctl)*(m == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  1026. *fcnc::chebyshev(ctk, n)/sqrt(1-ctk*ctk)*(n == 0 ? 1.0/MY_PI : 2.0/MY_PI)
  1027. *fcnc::chebyshev(phi, o)/sqrt(1-phi*phi)*(o == 0 ? 1.0/MY_PI : 2.0/MY_PI))
  1028. );
  1029. }
  1030. //cov = sqrt(cov); //to get sigma on diagonal
  1031. cov /= sqr(nWeightedEvents);
  1032. covariance.at(npol.getSize()*bini+binj) = cov;
  1033. covariance.at(npol.getSize()*binj+bini) = cov;
  1034. }
  1035. }
  1036. }
  1037. }
  1038. }
  1039. }
  1040. }
  1041. }
  1042. }
  1043. }
  1044. spdlog::info("uncertainties[{0:0.8e}]", npol.getSize());
  1045. if (spdlog_info()){
  1046. for (unsigned int i =0; i<npol.getSize(); i++){
  1047. std::cout <<covariance.at(npol.getSize()*i+i) << (i < npol.getSize()-1 ? ", " : " };");
  1048. }
  1049. std::cout << std::endl;//needs to be converted into correct range and translated to monomial coefficients?
  1050. }
  1051. spdlog::info("Covariance matrix cov[{0:0.8e}]", npol.getSize2());
  1052. for (unsigned int i =0; i<npol.getSize(); i++){
  1053. for (unsigned int j =0; j<npol.getSize(); j++){
  1054. std::cout << covariance.at(npol.getSize()*i+j) << ", ";
  1055. }
  1056. std::cout << std::endl;
  1057. }
  1058. std::cout <<"};" << std::endl;//needs to be converted into correct range and translated to monomial coefficients? no, should do these transformations after every acceptance randomization
  1059. double correlation = 0.0;
  1060. for (unsigned int i =0; i<npol.getSize(); i++)
  1061. for (unsigned int j =0; j<npol.getSize(); j++)
  1062. {
  1063. double corr = covariance.at(npol.getSize()*i+j)/sqrt(covariance.at(npol.getSize()*i+i))/sqrt(covariance.at(npol.getSize()*j+j));
  1064. if (fabs(corr) > fabs(correlation) && i != j)
  1065. correlation = corr;
  1066. }
  1067. spdlog::info( "Largest correlation found is {0:f}", correlation );
  1068. }
  1069. //transform chebyshev coefficients to monomial coefficients
  1070. for (unsigned int h = 0; h<npol.q2; h++){
  1071. for (unsigned int i = 0; i<npol.ctl; i++){
  1072. for (unsigned int j = 0; j<npol.ctk; j++){
  1073. for (unsigned int k = 0; k<npol.phi; k++){
  1074. double c = chijk_moments.at(npol.get_bin_in4D(h,i,j,k));
  1075. std::vector<double> ch_coeffs_q2(npol.q2, 0.0);
  1076. std::vector<double> ch_coeffs_ctl(npol.ctl, 0.0);
  1077. std::vector<double> ch_coeffs_ctk(npol.ctk, 0.0);
  1078. std::vector<double> ch_coeffs_phi(npol.phi, 0.0);
  1079. std::vector<double> poly_coeffs_q2(npol.q2, 0.0);
  1080. std::vector<double> poly_coeffs_ctl(npol.ctl, 0.0);
  1081. std::vector<double> poly_coeffs_ctk(npol.ctk, 0.0);
  1082. std::vector<double> poly_coeffs_phi(npol.phi, 0.0);
  1083. ch_coeffs_q2.at(h) = 1.0;
  1084. ch_coeffs_ctl.at(i) = 1.0;
  1085. ch_coeffs_ctk.at(j) = 1.0;
  1086. ch_coeffs_phi.at(k) = 1.0;
  1087. chebyshev_to_poly(ch_coeffs_q2, poly_coeffs_q2);
  1088. chebyshev_to_poly(ch_coeffs_ctl, poly_coeffs_ctl);
  1089. chebyshev_to_poly(ch_coeffs_ctk, poly_coeffs_ctk);
  1090. chebyshev_to_poly(ch_coeffs_phi, poly_coeffs_phi);
  1091. for (unsigned int l = 0; l<=h; l++){
  1092. for (unsigned int m = 0; m<=i; m++){
  1093. for (unsigned int n = 0; n<=j; n++){
  1094. for (unsigned int o = 0; o<=k; o++){
  1095. unsigned int bin = npol.get_bin_in4D(l,m,n,o);
  1096. poly_moments.at(bin) += c*poly_coeffs_q2.at(l)*poly_coeffs_ctl.at(m)*poly_coeffs_ctk.at(n)*poly_coeffs_phi.at(o);
  1097. }
  1098. }
  1099. }
  1100. }
  1101. }
  1102. }
  1103. }
  1104. }
  1105. }
  1106. double integrate_4D(bin_edges edges, int h, int i, int j, int k){
  1107. return integrate_x_to_n(edges.q2min, edges.q2max,h)//careful with q2max
  1108. *integrate_x_to_n(edges.ctlmin, edges.ctlmax,i)
  1109. *integrate_x_to_n(edges.ctkmin, edges.ctkmax,j)
  1110. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1111. }
  1112. double integrate_3D(bin_edges edges, int i, int j, int k){
  1113. return integrate_x_to_n(edges.ctlmin, edges.ctlmax,i)
  1114. *integrate_x_to_n(edges.ctkmin, edges.ctkmax,j)
  1115. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1116. }
  1117. void fill_moments_hist_1D(TH1D *hist_moments, std::vector<double> coeffs_moments,
  1118. bin_edges edges, npolynom npol, double q2low, double q2high){
  1119. bool do_ctl = (std::string(hist_moments->GetName()).find("ctl") != std::string::npos);
  1120. bool do_ctk = (std::string(hist_moments->GetName()).find("ctk") != std::string::npos);
  1121. bool do_phi = (std::string(hist_moments->GetName()).find("phi") != std::string::npos);
  1122. bool do_q2 = (std::string(hist_moments->GetName()).find("q2") != std::string::npos);
  1123. for (int l=1; l<=hist_moments->GetNbinsX(); l++){
  1124. double a = hist_moments->GetBinLowEdge(l);
  1125. double b = hist_moments->GetBinLowEdge(l+1);
  1126. double integral = 0.0;
  1127. for (unsigned int h = 0; h<npol.q2; h++){
  1128. for (unsigned int i = 0; i<npol.ctl; i++){
  1129. for (unsigned int j = 0; j<npol.ctk; j++){
  1130. for (unsigned int k = 0; k<npol.phi; k++){
  1131. double result = coeffs_moments.at(npol.get_bin_in4D(h,i,j,k))
  1132. *(pow(do_q2 ? b : q2high ,h+1)/(h+1.0) - pow(do_q2 ? a : q2low ,h+1)/(h+1.0)) //Possibly replace by get_result;
  1133. *(pow(do_ctl ? b : edges.ctlmax,i+1)/(i+1.0) - pow(do_ctl ? a : edges.ctlmin,i+1)/(i+1.0))
  1134. *(pow(do_ctk ? b : edges.ctkmax,j+1)/(j+1.0) - pow(do_ctk ? a : edges.ctkmin,j+1)/(j+1.0))
  1135. *(pow(do_phi ? b : edges.phimax,k+1)/(k+1.0) - pow(do_phi ? a : edges.phimin,k+1)/(k+1.0));
  1136. integral += result;
  1137. }
  1138. }
  1139. }
  1140. }
  1141. hist_moments->SetBinContent(l, integral);
  1142. }
  1143. return;
  1144. }
  1145. void fill_moments_hist_2D(TH2D *hist_moments, std::vector<double> coeffs_moments,
  1146. bin_edges edges, npolynom npol, double q2low, double q2high){
  1147. bool do_ctl = (std::string(hist_moments->GetName()).find("ctl") != std::string::npos);
  1148. bool do_ctk = (std::string(hist_moments->GetName()).find("ctk") != std::string::npos);
  1149. bool do_phi = (std::string(hist_moments->GetName()).find("phi") != std::string::npos);
  1150. bool do_q2 = (std::string(hist_moments->GetName()).find("q2") != std::string::npos);
  1151. spdlog::trace("do_ctl\t"+boolToString(do_ctl));
  1152. spdlog::trace("do_ctk\t"+boolToString(do_ctk));
  1153. spdlog::trace("do_phi\t"+boolToString(do_phi));
  1154. spdlog::trace("do_q2\t"+boolToString(do_q2));
  1155. bool is_ctl_First = !do_q2; //ctl is second if q2
  1156. bool is_ctk_First = !(do_q2 || do_ctl); //ctk is second if ctl or q2
  1157. //phi is always second and q2 always first
  1158. spdlog::trace("is_ctl_First\t"+boolToString(is_ctl_First));
  1159. spdlog::trace("is_ctk_First\t"+boolToString(is_ctk_First));
  1160. for (int l=1; l<=hist_moments->GetNbinsX(); l++){
  1161. double a = hist_moments->GetXaxis()->GetBinLowEdge(l);
  1162. double b = hist_moments->GetXaxis()->GetBinLowEdge(l+1);
  1163. for (int m=1; m<=hist_moments->GetNbinsY(); m++){
  1164. double c = hist_moments->GetYaxis()->GetBinLowEdge(m);
  1165. double d = hist_moments->GetYaxis()->GetBinLowEdge(m+1);
  1166. double integral = 0.0;
  1167. for (unsigned int h = 0; h<npol.q2; h++){
  1168. for (unsigned int i = 0; i<npol.ctl; i++){
  1169. for (unsigned int j = 0; j<npol.ctk; j++){
  1170. for (unsigned int k = 0; k<npol.phi; k++){
  1171. double result = coeffs_moments.at(npol.get_bin_in4D(h,i,j,k))
  1172. *integrate_x_to_n(do_q2 ? a : q2low, do_q2 ? b : q2high ,h)
  1173. *integrate_x_to_n(do_ctl ? (is_ctl_First ? a : c) : edges.ctlmin,
  1174. do_ctl ? (is_ctl_First ? b : d) : edges.ctlmax,i)
  1175. *integrate_x_to_n(do_ctk ? (is_ctk_First ? a : c) : edges.ctkmin,
  1176. do_ctk ? (is_ctk_First ? b : d) : edges.ctkmax, j)
  1177. *integrate_x_to_n(do_phi ? c : edges.phimin,do_phi ? d : edges.phimax,k);
  1178. integral += result;
  1179. }
  1180. }
  1181. }
  1182. }
  1183. spdlog::trace("\t*** fill_moments_hist_2D: ***\t´");
  1184. spdlog::trace("l: {0:d}\tm: {1:d}\tint: {2:f}", l, m, integral);
  1185. hist_moments->SetBinContent(l, m, integral);
  1186. }
  1187. }
  1188. return;
  1189. }
  1190. int get_correct_index(std::string whichVar, int l, int m, int n, int o){
  1191. if (whichVar == "q2") return l;
  1192. if (whichVar == "ctl") return m;
  1193. if (whichVar == "ctk") return n;
  1194. if (whichVar == "phi") return o;
  1195. return -1;
  1196. }
  1197. int change_index(std::string whichVar, npolynom npol, int p, int l, int m, int n, int o){
  1198. if (whichVar == "q2") return npol.get_bin_in4D(p,m,n,o);
  1199. if (whichVar == "ctl") return npol.get_bin_in4D(l,p,n,o);
  1200. if (whichVar == "ctk") return npol.get_bin_in4D(l,m,p,o);
  1201. if (whichVar == "phi") return npol.get_bin_in4D(l,m,n,p);
  1202. return -1;
  1203. }
  1204. void correct_coefficients(npolynom npol, bin_edges edges, std::vector<double> &out_poly_moments, std::vector<double> in_poly_moments, std::string whichVar){
  1205. //Just rebin
  1206. unsigned int npol_var;
  1207. double intvar_min;
  1208. double intvar_max;
  1209. if (whichVar == "q2"){ //If this would be na efin array, my life would be orders of magnitute easier
  1210. npol_var = npol.q2;
  1211. intvar_min = edges.q2min;
  1212. intvar_max = edges.q2max;
  1213. }
  1214. else if (whichVar == "ctl") {
  1215. npol_var = npol.ctl;
  1216. intvar_min = edges.ctlmin;
  1217. intvar_max = edges.ctlmax;
  1218. }
  1219. else if (whichVar == "ctk") {
  1220. npol_var = npol.ctk;
  1221. intvar_min = edges.ctkmin;
  1222. intvar_max = edges.ctkmax;
  1223. }
  1224. else if (whichVar == "phi") {
  1225. npol_var = npol.phi;
  1226. intvar_min = edges.phimin;
  1227. intvar_max = edges.phimax;
  1228. }
  1229. else{
  1230. spdlog::error("Wrong index name! Either q2, ctl, ctk or phi!");
  1231. assert (0);
  1232. }
  1233. spdlog::debug("npol_var = {0:d}\tintvar_min = {1:f}\tintvar_max = {2:f}", npol_var, intvar_min, intvar_max);
  1234. for (unsigned int l = 0; l<npol.q2; l++){
  1235. for (unsigned int m = 0; m<npol.ctl; m++){
  1236. for (unsigned int n = 0; n<npol.ctk; n++){
  1237. for (unsigned int o = 0; o<npol.phi; o++){
  1238. unsigned int bin = npol.get_bin_in4D(l,m,n,o);
  1239. spdlog::trace("l={0:d}\tm={1:d}\tn={2:d}\to={3:d}\t bin ={4:d}",l,m,n,o,bin);
  1240. std::vector<double> poly(npol_var, 0.0);
  1241. poly.at(get_correct_index(whichVar,l,m,n,o)) = in_poly_moments.at(bin);
  1242. std::vector<double> correct(npol_var, 0.0);
  1243. correct_poly(poly, correct, intvar_min, intvar_max);
  1244. for (unsigned int p = 0; p<npol_var; p++){
  1245. unsigned int tobin = change_index(whichVar,npol,p,l,m,n,o);
  1246. spdlog::trace("p={0:d}\t tobin ={1:d}",p,tobin);
  1247. out_poly_moments.at(tobin) += correct.at(p);
  1248. }
  1249. }
  1250. }
  1251. }
  1252. }
  1253. return;
  1254. }
  1255. void bu2kstarmumu_pdf::parametrize_eff_phsp_4d(const std::vector<event>& events, values* globalvalues, int tagNumber, bool assumePhiEven, bool checkSignificance, bool runMinuit, bool checkFactorization, bool do3Dmoments){
  1256. spdlog::debug("----> start parametrization of angular acceptance correction coefficients with {0:d} events.", events.size());
  1257. const UInt_t nBinsQ2 = 40;
  1258. const UInt_t nBinsAngles = 40;
  1259. bool ignore_q2weights = false;
  1260. if (ignore_q2weights) spdlog::warn("Not using weights from genLvl PHSP to flatten the q2 distribution!!!");
  1261. //Get the pointer to this class of bu2kstarmumu_pdf
  1262. current_pdf = this;
  1263. std::vector<double> q2binsmin = opts->TheQ2binsmin; //Check TheQ2binsmax and q2binsmin
  1264. std::vector<double> q2binsmax = opts->TheQ2binsmax;
  1265. spdlog::debug("Vector q2binsmin:\t"+convert_vector_to_string(q2binsmin));
  1266. spdlog::debug("Vector q2binsmax:\t"+convert_vector_to_string(q2binsmax));
  1267. //name tag for all plots:
  1268. std::string appendix = "_"+DECAY_NAME
  1269. + (opts->KS ? opts->DDLL+"_" : "_")
  1270. + "Run" + std::to_string(opts->run)
  1271. + ((opts->angacccorrperyear && opts->year != -1) ? "_"+std::to_string(opts->year) : "")
  1272. + ((opts->folding != -1) ? "_folding"+std::to_string(opts->folding) : "")
  1273. + ((opts->systematic == 3) ? "_"+std::to_string(opts->orderincrease)+"moreOrders" : "")
  1274. + std::string(tagNumber != 0 ? "_"+std::to_string(tagNumber) : "");
  1275. std::string subfolder = "plots/angular/" + std::string(tagNumber != 0 ? "test/" : "");
  1276. spdlog::debug("Saving all plots into folder " + subfolder);
  1277. //Set orders of chebyshev/legendre polynomials
  1278. npolynom npol(opts); //Should be a const, but then all the future shuffling gets difficult
  1279. //fold the events if needed:
  1280. spdlog::debug("Init folder....");
  1281. //TODO remove fcnc::folder fldr(opts);
  1282. //only accept events inside q2min and q2max
  1283. std::vector<event> filtered_events;
  1284. //std::vector<event> fullrange_events;
  1285. unsigned int ee;
  1286. unsigned int N = events.size();
  1287. TRandom3 * rnd = new TRandom3(15*opts->job_id);
  1288. spdlog::debug("Filtering events...");
  1289. for (unsigned int e=0; e<N; e++){
  1290. //choose random events for bootstrapping
  1291. if (opts->systematic == 1) ee = int(rnd->Rndm() * N);
  1292. else ee = e; //or the correct, nominal order
  1293. fcnc::event evt = events.at(ee);
  1294. if (!isEvtInAngleRange(&(evt), opts)) continue;
  1295. filtered_events.push_back(evt);
  1296. if(!opts->full_angular) fldr->fold(&filtered_events.back());
  1297. }
  1298. if (!ignore_q2weights){
  1299. spdlog::debug("Getting q2 weights...");
  1300. //weight for all events, reweight from PHSP q2 model to flat q2 distribution using histogram
  1301. TFile* fphspweightq2 = new TFile(CONFIG_PHSP_WEIGHT.c_str());
  1302. TH1D* phspweightq2 = dynamic_cast<TH1D*>(fphspweightq2->Get(opts->IsFlatQ2 ? "flatq2weights" : "phspweightq2"));
  1303. bool keep_weights = opts->systematic != 2;
  1304. bool vary_weights = opts->systematic == 4;
  1305. //reweight filtered events
  1306. for (auto evt: filtered_events){
  1307. double q2 = evt.q2;
  1308. if(vary_weights){
  1309. evt.weight += evt.delta_weight * rnd->Gaus(0., 1.);
  1310. }
  1311. if (q2 < 0.2){
  1312. if(keep_weights) evt.weight *= phspweightq2->GetBinContent(2);//keep loaded totalweight!
  1313. else evt.weight = phspweightq2->GetBinContent(2);
  1314. }
  1315. else{
  1316. int bin = phspweightq2->FindFixBin(q2);
  1317. if (bin >=1 && bin <= phspweightq2->GetNbinsX()){
  1318. if(keep_weights) evt.weight *= phspweightq2->GetBinContent(bin);//keep loaded totalweight!
  1319. else evt.weight = phspweightq2->GetBinContent(bin);
  1320. }
  1321. }
  1322. }
  1323. delete phspweightq2;
  1324. fphspweightq2->Close();
  1325. delete fphspweightq2;
  1326. }
  1327. //for systematic 9: trigger weights, multiply existing weights by 1/L0Muon_eff
  1328. if(opts->systematic == 9){
  1329. spdlog::debug("Getting systematic 9");
  1330. //get years from current data-set:
  1331. std::vector<int> years; //empty vector
  1332. for (auto event: filtered_events){
  1333. bool year_found = false;
  1334. for(auto yr: years){
  1335. if(yr == event.year){
  1336. year_found = true;
  1337. break;
  1338. }
  1339. }
  1340. if(!year_found) years.push_back(event.year); //First event always gets filled
  1341. //Technically one should make an if to check it is all years, but given the size of the event sample this is okayish
  1342. }
  1343. assert(years.size());
  1344. std::sort(years.begin(), years.end());
  1345. //get L0Muon efficiency histo(s)
  1346. TFile * f_L0_w[years.size()];
  1347. TH1D * h_L0_w[years.size()];
  1348. for(unsigned int y = 0; y < years.size(); y++){
  1349. f_L0_w[y] = new TFile((std::string("config/")+(opts->KS?"KshortPiplus":"KplusPi0Resolved")+"_L0MuonEfficiency_"+std::to_string(years.at(y))+".root").c_str(), "READ");
  1350. if(!f_L0_w[y]->IsOpen()){
  1351. spdlog::critical( "Could not find file with L0Muon efficiencies: 'config/" + std::string(opts->KS ? "KshortPiplus" : "KplusPi0Resolved") + "_L0MuonEfficiency_{0:d}.root'", years.at(y) );
  1352. assert(0);
  1353. }
  1354. h_L0_w[y] = dynamic_cast<TH1D*>(f_L0_w[y]->Get("L0MuonEffRatioPHSP"));
  1355. spdlog::info("Succesfully loaded L0Muon efficiency reweighting histogram for year={0:d}", years.at(y));
  1356. }
  1357. for (unsigned int i=0; i<filtered_events.size(); i++){
  1358. double max_mu_pt = filtered_events.at(i).max_mu_pt;
  1359. unsigned int year_idx = 0;
  1360. for(unsigned int y = 0; y < years.size(); y++){
  1361. if(years.at(y) == filtered_events.at(i).year){
  1362. year_idx = y;
  1363. break;
  1364. }
  1365. }
  1366. if(max_mu_pt > 20000.){
  1367. filtered_events.at(i).weight *= h_L0_w[year_idx]->GetBinContent(h_L0_w[year_idx]->GetNbinsX());
  1368. }
  1369. else{
  1370. int bin = h_L0_w[year_idx]->FindFixBin(max_mu_pt);
  1371. filtered_events.at(i).weight *= h_L0_w[year_idx]->GetBinContent(bin);
  1372. }
  1373. }
  1374. for(unsigned int y = 0; y < years.size(); y++){
  1375. delete h_L0_w[y];
  1376. f_L0_w[y]->Close();
  1377. delete f_L0_w[y];
  1378. }
  1379. }
  1380. //set the pointer that is accessible from the minuit fcn
  1381. eff_events = filtered_events;
  1382. //make plot to check weight distribution if running a test
  1383. if(tagNumber >0){
  1384. spdlog::debug("Plotting weights");
  1385. TH1D* hweight = new TH1D("hweight", ";w;", 100, 0.0, 1.0/EFF_CUTOFF);
  1386. for (unsigned int i=0; i<filtered_events.size(); i++){
  1387. spdlog::trace("Weight of event {0:d}\t\t{1:f}", i , filtered_events.at(i).weight);
  1388. hweight->Fill(filtered_events.at(i).weight);
  1389. }
  1390. TCanvas * cweights = new TCanvas();
  1391. cweights->cd();
  1392. hweight->Draw("");
  1393. if(opts->write_eps)cweights->Print((subfolder + "weights"+appendix+".eps").c_str(), "eps");
  1394. if(opts->write_eps)cweights->Print((subfolder + "weights"+appendix+".root").c_str(), "root");
  1395. delete hweight;
  1396. delete cweights;
  1397. }
  1398. //---------------------------------------
  1399. //DETERMINATION FROM ACCEPTANCE HISTOGRAM
  1400. //---------------------------------------
  1401. unsigned int nq2bins = 18;
  1402. unsigned int nctlbins = 10;
  1403. unsigned int nctkbins = 10;
  1404. unsigned int nphibins = 5;
  1405. bool adapt_bins_to_folding = false;
  1406. if(adapt_bins_to_folding){
  1407. nphibins /= 2;
  1408. if(opts->folding > 0)nctlbins /= 2;
  1409. }
  1410. spdlog::debug("Options: ");
  1411. spdlog::debug("q2min={0:f}\tq2max={1:f}", opts->TheQ2binsmin.front(),opts->TheQ2binsmax.back());
  1412. spdlog::debug("ctkmin={0:f}\tctkmax={1:f}", opts->ctk_min, opts->ctk_max);
  1413. spdlog::debug("ctlmin={0:f}\tctlmax={1:f}", opts->ctl_min, opts->ctl_max);
  1414. spdlog::debug("phimin={0:f}\tphimax={1:f}", opts->phi_min, opts->phi_max);
  1415. bin_edges edges (opts, nq2bins, nctlbins, nctkbins, nphibins);
  1416. const std::vector<double> q2_edges = edges.edges_q2();
  1417. const std::vector<double> ctl_edges = edges.edges_ctl();
  1418. const std::vector<double> ctk_edges = edges.edges_ctk();
  1419. const std::vector<double> phi_edges = edges.edges_phi(); //This could've been a struct/class
  1420. spdlog::trace("q2 edges: " + convert_vector_to_string(q2_edges));
  1421. spdlog::trace("ctl edges: " + convert_vector_to_string(ctl_edges));
  1422. spdlog::trace("ctk edges: " + convert_vector_to_string(ctk_edges));
  1423. spdlog::trace("phi edges: " + convert_vector_to_string(phi_edges));
  1424. //should compare full 4D with
  1425. //3D in q2 bins
  1426. //3D factorizing in bins of q2
  1427. spdlog::debug("Getting number of weighted events...");
  1428. std::vector<double> eps_hist(edges.getNbins(), 0.0);
  1429. double nWeightedEvents = 0.0;
  1430. for (auto &meas: filtered_events){
  1431. unsigned int bin = get_bin_in4D(meas,edges);
  1432. eps_hist.at(bin) += meas.weight;
  1433. nWeightedEvents += meas.weight;
  1434. }
  1435. //rescale efficiency
  1436. spdlog::debug("Rescaling efficiency...");
  1437. for (unsigned int h = 0; h<edges.nq2bins; h++){
  1438. for (unsigned int i = 0; i<edges.nctlbins; i++){
  1439. for (unsigned int j = 0; j<edges.nctkbins; j++){
  1440. for (unsigned int k = 0; k<edges.nphibins; k++){
  1441. eps_hist.at(get_bin_in4D(h,i,j,k,edges)) *= edges.getNbins()/nWeightedEvents;
  1442. }
  1443. }
  1444. }
  1445. }
  1446. //determine xis in bins of q2
  1447. spdlog::debug("Getting xis in bins of q2...");
  1448. std::vector<TH1D*> hxi_hist;
  1449. for (auto angObs: get_angObser_withTeX_vec()){
  1450. hxi_hist.push_back(new TH1D(("hxi"+angObs[0]+"hist").c_str(), (";q^{2};"+angObs[1]).c_str(),
  1451. edges.nq2bins, edges.q2min, edges.q2max));
  1452. }
  1453. std::vector<int>int_xi(hxi_hist.size(),0);
  1454. for (unsigned int h = 0; h<edges.nq2bins; h++){
  1455. std::fill(int_xi.begin(), int_xi.end(), 0); //fill int_xi with zeroes
  1456. for (unsigned int i = 0; i<edges.nctlbins; i++)
  1457. for (unsigned int j = 0; j<edges.nctkbins; j++)
  1458. for (unsigned int k = 0; k<edges.nphibins; k++){
  1459. unsigned int bin = get_bin_in4D(h,i,j,k,edges);
  1460. double eps = eps_hist.at(bin);
  1461. double f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12;
  1462. if(opts->full_angular){
  1463. integrated_fj_noacc(ctl_edges[i], ctl_edges[i+1],
  1464. ctk_edges[j], ctk_edges[j+1],
  1465. phi_edges[k], phi_edges[k+1],
  1466. f1, f2, f3, f4, f5, f6,
  1467. f7, f8, f9, f10, f11, f12);
  1468. }
  1469. else{
  1470. folded_integrated_fj_noacc(ctl_edges[i], ctl_edges[i+1],
  1471. ctk_edges[j], ctk_edges[j+1],
  1472. phi_edges[k], phi_edges[k+1],
  1473. f1, f2, f3, f4, f5, f6,
  1474. f7, f8, f9, f10, f11, f12);
  1475. }
  1476. int_xi[0] += eps*f1; //KILL ME
  1477. int_xi[1] += eps*f2;
  1478. int_xi[2] += eps*f3;
  1479. int_xi[3] += eps*f4;
  1480. int_xi[4] += eps*f5;
  1481. int_xi[5] += eps*f6;
  1482. int_xi[6] += eps*f7;
  1483. int_xi[7] += eps*f8;
  1484. int_xi[8] += eps*f9;
  1485. int_xi[9] += eps*f10;
  1486. int_xi[10] += eps*f11;
  1487. int_xi[11] += eps*f12;
  1488. }
  1489. for_indexed(auto hist: hxi_hist) hist->SetBinContent(h+1,int_xi[i]);
  1490. }
  1491. //-----------------------------------
  1492. //DETERMINE XIS USING UNBINNED METHOD
  1493. //-----------------------------------
  1494. spdlog::debug("Getting xis using unbinned method...");
  1495. std::vector<TH1D*> hxi_ub;
  1496. for (auto angObs: get_angObser_withTeX_vec()){
  1497. hxi_ub.push_back(new TH1D(("hxi"+angObs[0]+"ub").c_str(), (";q^{2};"+angObs[1]).c_str(),
  1498. edges.nq2bins, edges.q2min, edges.q2max));
  1499. }
  1500. //make it pretty
  1501. for (auto hist: hxi_ub) hist->SetLineColor(4);
  1502. for (unsigned int h = 0; h<edges.nq2bins; h++){
  1503. std::fill(int_xi.begin(), int_xi.end(), 0); //fill int_xi with zeroes, no need to initialize (see line 961)
  1504. //double q2a = hxi_ub[0]->GetBinLowEdge(h); //check this is the same as q2_edges!!!!! should be, but to be sure
  1505. //double q2b = hxi_ub[0]->GetBinLowEdge(h+1);
  1506. for (auto &&meas: filtered_events){
  1507. if (meas.q2 < q2_edges[h] || meas.q2 > q2_edges[h]) continue;
  1508. double f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12;
  1509. if(opts->full_angular){
  1510. fj(meas.costhetal, meas.costhetak, meas.phi,
  1511. f1, f2, f3, f4, f5, f6,
  1512. f7, f8, f9, f10, f11, f12);
  1513. }
  1514. else{
  1515. folded_fj(meas.costhetal, meas.costhetak, meas.phi,
  1516. f1, f2, f3, f4, f5, f6,
  1517. f7, f8, f9, f10, f11, f12);
  1518. }
  1519. double weight = meas.weight/nWeightedEvents*edges.nq2bins*(edges.range_ctl()*edges.range_ctk()*edges.range_phi());
  1520. int_xi[0] += f1*weight; //KILL ME
  1521. int_xi[1] += f2*weight;
  1522. int_xi[2] += f3*weight;
  1523. int_xi[3] += f4*weight;
  1524. int_xi[4] += f5*weight;
  1525. int_xi[5] += f6*weight;
  1526. int_xi[6] += f7*weight;
  1527. int_xi[7] += f8*weight;
  1528. int_xi[8] += f9*weight;
  1529. int_xi[9] += f10*weight;
  1530. int_xi[10] += f11*weight;
  1531. int_xi[11] += f12*weight;
  1532. }
  1533. for_indexed(auto hist: hxi_ub) hist->SetBinContent(h,int_xi[i]);
  1534. }
  1535. //------------------------------------------------------
  1536. //DETERMINE POLYNOMIAL ACCEPTANCE WITH METHOD OF MOMENTS
  1537. //------------------------------------------------------
  1538. const bool calculateCovariance = false;
  1539. const bool assumectleven = opts->systematic == 2;
  1540. const bool fejerkernel = false; //see Alexander Weisse, Holger Feshke, Chebyshev expansion techniques
  1541. const bool doLegendre = true; //somehow, chebyshev is broken now, great job me
  1542. std::vector<double> poly_moments(npol.getSize(), 0.0);
  1543. if (doLegendre){
  1544. get_legendre(edges, npol,
  1545. filtered_events, nWeightedEvents,
  1546. poly_moments,
  1547. fejerkernel, assumectleven, assumePhiEven,
  1548. checkSignificance, calculateCovariance);
  1549. }
  1550. else{
  1551. get_chebyschev(edges, npol,
  1552. filtered_events, nWeightedEvents,
  1553. poly_moments,
  1554. fejerkernel, assumectleven, assumePhiEven,
  1555. checkSignificance, calculateCovariance);
  1556. }
  1557. spdlog::debug("Getting correct polynomial coefficients in cos(thetak) and cos(thetal)");
  1558. spdlog::debug("poly_moments size:{0:d}", poly_moments.size());
  1559. //correct coefficients from -1 +1 to ctlmin .. ctlmax for ctl, bit difficult, requires binomial coefficients
  1560. std::vector<double> poly_moments_ctl(npol.getSize(), 0.0);
  1561. std::vector<double> poly_moments_ctk(npol.getSize(), 0.0);
  1562. std::vector<double> poly_moments_phi(npol.getSize(), 0.0);
  1563. std::vector<double> poly_moments_q2(npol.getSize(), 0.0);
  1564. correct_coefficients(npol,edges,poly_moments_ctl,poly_moments, "ctl");
  1565. correct_coefficients(npol,edges,poly_moments_ctk,poly_moments_ctl, "ctk");
  1566. correct_coefficients(npol,edges,poly_moments_phi,poly_moments_ctk, "phi");
  1567. correct_coefficients(npol,edges,poly_moments_q2, poly_moments_phi, "q2");
  1568. spdlog::debug("Getting moments....");
  1569. std::vector<double> coeffs_moments(poly_moments_q2);
  1570. //calculate norm after full integration
  1571. double full_norm = 0.0;
  1572. for (unsigned int h = 0; h<npol.q2; h++){
  1573. for (unsigned int i = 0; i<npol.ctl; i++){
  1574. for (unsigned int j = 0; j<npol.ctk; j++){
  1575. for (unsigned int k = 0; k<npol.phi; k++){
  1576. full_norm += coeffs_moments.at(npol.get_bin_in4D(h,i,j,k))*integrate_4D(edges, h, i, j, k);
  1577. }
  1578. }
  1579. }
  1580. }
  1581. //assume a flat efficiency of 1.0 -> scale by edges.range_q2()*RANGE_3D()/full_norm
  1582. for (unsigned int h = 0; h<npol.q2; h++){
  1583. for (unsigned int i = 0; i<npol.ctl; i++){
  1584. for (unsigned int j = 0; j<npol.ctk; j++){
  1585. for (unsigned int k = 0; k<npol.phi; k++){
  1586. coeffs_moments.at(npol.get_bin_in4D(h,i,j,k)) *= edges.range_q2()*RANGE_3D()/full_norm;
  1587. }
  1588. }
  1589. }
  1590. }
  1591. //print to std::out
  1592. if (spdlog_trace()){
  1593. spdlog::trace( "//vector of efficiency coefficients containing {0:d} elements", coeffs_moments.size());
  1594. spdlog::trace( "coeffs_eff_4d = { " );
  1595. for (unsigned int i=0; i<coeffs_moments.size(); i++){
  1596. std::cout << std::setprecision(5) << std::scientific << coeffs_moments.at(i)<< (i<coeffs_moments.size()-1 ? ", " : " ");
  1597. }
  1598. }
  1599. //set this as default coefficients now
  1600. coeffs_eff_4d = coeffs_moments;
  1601. //calculate the integrated angular terms int f_i dOmega (q2) = xi(q2)
  1602. std::vector<TH1D*> hxi_moments;
  1603. for (auto &angObs: get_angObser_withTeX_vec()){
  1604. hxi_moments.push_back(new TH1D(("hxi"+angObs[0]+"_moments").c_str(), (";q^{2};"+angObs[1]).c_str(),
  1605. edges.nq2bins, edges.q2min, edges.q2max));
  1606. }
  1607. for (int l=1; l<=hxi_moments[0]->GetNbinsX(); l++) {
  1608. double a = hxi_moments[0]->GetXaxis()->GetBinLowEdge(l);
  1609. double b = hxi_moments[0]->GetXaxis()->GetBinLowEdge(l+1);
  1610. std::vector<double> integral_xi(hxi_moments.size(),0.0);
  1611. for (unsigned int h = 0; h<npol.q2; h++){
  1612. for (unsigned int i = 0; i<npol.ctl; i++){
  1613. for (unsigned int j = 0; j<npol.ctk; j++){
  1614. for (unsigned int k = 0; k<npol.phi; k++){
  1615. unsigned int bin =npol.get_bin_in4D(h, i, j, k);
  1616. double coeff = C_PWAVE*coeffs_moments.at(bin)*pow(0.5*(a+b), h);
  1617. //f1 = c * sinthetak2; //j1s
  1618. integral_xi[0] += coeff
  1619. * integrate_x_to_n(edges.ctlmin, edges.ctlmax, i)
  1620. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j) - integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1621. * integrate_x_to_n(edges.phimin, edges.phimax,k);
  1622. //f2 = c * costhetak2; //j1c
  1623. integral_xi[1] += coeff
  1624. *integrate_x_to_n(edges.ctlmin, edges.ctlmax, i)
  1625. *integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2)
  1626. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1627. //f3 = c * sinthetak2*cos2thetal; //j2s
  1628. integral_xi[2] += coeff
  1629. *(2.0*integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+2)-integrate_x_to_n(edges.ctlmin, edges.ctlmax, i))
  1630. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j)-integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1631. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1632. //f4 = c * costhetak2*cos2thetal; //j2c
  1633. integral_xi[3] += coeff
  1634. *(2.0*integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+2)-integrate_x_to_n(edges.ctlmin, edges.ctlmax, i))
  1635. *integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2)
  1636. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1637. //f5 = c * sinthetak2*sinthetal2*cos(2.0*phi); //j3
  1638. integral_xi[4] += coeff
  1639. *(integrate_x_to_n(edges.ctlmin, edges.ctlmax, i)-integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+2))
  1640. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j)-integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1641. *integrate_x_to_n_times_cos_2x(edges.phimin, edges.phimax,k);
  1642. //f6 = c * sin2thetak*sin2thetal*cos(phi); //j4
  1643. integral_xi[5] += coeff
  1644. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctlmin, edges.ctlmax, i+1)
  1645. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctkmin, edges.ctkmax, j+1)
  1646. *integrate_x_to_n_times_cos_x(edges.phimin, edges.phimax,k);
  1647. //f7 = c * sin2thetak*sinthetal*cos(phi); //j5
  1648. integral_xi[6] += coeff
  1649. *integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctlmin, edges.ctlmax, i)
  1650. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctkmin, edges.ctkmax, j+1)
  1651. *integrate_x_to_n_times_cos_x(edges.phimin, edges.phimax,k);
  1652. //f8 = c * sinthetak2*costhetal; //j6s
  1653. integral_xi[7] += coeff
  1654. *integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+1)
  1655. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j)-integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1656. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1657. //f9 = c * costhetak2*costhetal; //j6c
  1658. integral_xi[8] += coeff
  1659. *integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+1)
  1660. *integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2)
  1661. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1662. //f10 = c * sin2thetak*sinthetal*sin(phi); //j7
  1663. integral_xi[9] += coeff
  1664. *integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctlmin, edges.ctlmax, i)
  1665. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctkmin, edges.ctkmax, j+1)
  1666. *integrate_x_to_n_times_sin_x(edges.phimin, edges.phimax,k);
  1667. //f11 = c * sin2thetak*sin2thetal*sin(phi); //j8
  1668. integral_xi[10] += coeff
  1669. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctlmin, edges.ctlmax, i+1)
  1670. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctkmin, edges.ctkmax, j+1)
  1671. *integrate_x_to_n_times_sin_x(edges.phimin, edges.phimax,k);
  1672. //f12 = c * sinthetak2*sinthetal2*sin(2.0*phi); //j9
  1673. integral_xi[11] += coeff
  1674. *(integrate_x_to_n(edges.ctlmin, edges.ctlmax, i) - integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+2))
  1675. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j) - integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1676. *integrate_x_to_n_times_sin_2x(edges.phimin, edges.phimax,k);
  1677. }
  1678. }
  1679. }
  1680. }
  1681. for_indexed(auto hist: hxi_moments) hist->SetBinContent(l, is_param_folded(i,opts) ? 0.0 : integral_xi[i]);
  1682. }
  1683. //-----------------------------------------------------
  1684. //DETERMINE POLYNOMIAL ACCEPTANCE USING UNBINNED ML FIT
  1685. //-----------------------------------------------------
  1686. std::vector<TH1D*> hxi_ml_hist;
  1687. for (auto &angObs: get_angObser_withTeX_vec()){
  1688. hxi_ml_hist.push_back(new TH1D(("hxi"+angObs[0]+"_ml").c_str(), (";q^{2};"+angObs[1]).c_str(),
  1689. nBinsQ2, edges.q2min, edges.q2max));
  1690. }
  1691. for (auto &hist: hxi_ml_hist){
  1692. hist->SetLineColor(3);
  1693. }
  1694. //possible TODO for when you're bored: move into it's own function
  1695. //Running minuit is expensive, use only if necesary!
  1696. if (runMinuit){
  1697. spdlog::info("Running Minuit....");
  1698. //setup minuit
  1699. TMinuit* minuit_eff = new TMinuit(10000);
  1700. int errorcode;
  1701. minuit_eff->SetFCN(&(eff_fcn_phsp_4d));
  1702. double strategy_list[1] = {2.0};
  1703. minuit_eff->mnexcm("SET STR", strategy_list, 1, errorcode);
  1704. minuit_eff->SetMaxIterations(1000000);
  1705. minuit_eff->SetErrorDef(1.0);
  1706. const bool second_run = false;
  1707. //define params (could also feed with starting values from method of moments)
  1708. unsigned int q2_limit = 6;
  1709. unsigned int ctl_limit = 3;
  1710. unsigned int ctk_limit = 4;
  1711. unsigned int phi_limit = 1;
  1712. for (unsigned int h = 0; h<npol.q2; h++){
  1713. for (unsigned int i = 0; i<npol.ctl; i++){
  1714. for (unsigned int j = 0; j<npol.ctk; j++){
  1715. for (unsigned int k = 0; k<npol.phi; k++){
  1716. std::ostringstream sout;
  1717. sout << "c" << h << i << j << k;
  1718. if (h==0 && i==0 && j==0 && k==0){
  1719. minuit_eff->DefineParameter(npol.get_bin_in4D(h,i,j,k), sout.str().c_str(), 1.0, 0.0, 0.0, 0.0);
  1720. }
  1721. else if (h >= q2_limit || i >= ctl_limit || j >= ctk_limit || k >= phi_limit){
  1722. //this is to be able to do higher orders with the moments method and lower ones with minuit
  1723. minuit_eff->DefineParameter(npol.get_bin_in4D(h,i,j,k), sout.str().c_str(), 0.0, 0.0, 0.0, 0.0);
  1724. }
  1725. else if ((second_run && i == 0 && k == 0)|| (!second_run && i % 2 == 0 && k % 2 == 0)){
  1726. minuit_eff->DefineParameter(npol.get_bin_in4D(h,i,j,k), sout.str().c_str(), 0.0, 0.001, 0.0, 0.0);
  1727. }
  1728. else{
  1729. minuit_eff->DefineParameter(npol.get_bin_in4D(h,i,j,k), sout.str().c_str(), 0.0, 0.0, 0.0, 0.0);
  1730. }
  1731. }
  1732. }
  1733. }
  1734. }
  1735. double migrad_options[2] = {100000000.0, 0.1}; //{max calls, tolerance}
  1736. spdlog::info( "Running Migrad to determine eff shape" );
  1737. minuit_eff->mnset();
  1738. minuit_eff->mnexcm("MIG", migrad_options, 2, errorcode);
  1739. if (second_run){
  1740. spdlog::info( "Running Migrad a second time releasing parameters" );
  1741. //second run releasing some parameters
  1742. for (unsigned int h = 0; h<npol.q2; h++)
  1743. for (unsigned int i = 0; i<npol.ctl; i++)
  1744. for (unsigned int j = 0; j<npol.ctk; j++)
  1745. for (unsigned int k = 0; k<npol.phi; k++){
  1746. std::ostringstream sout;
  1747. sout << "c" << h << i << j << k;
  1748. if ((i > 0 || k > 0) && i % 2 == 0 && k % 2 == 0
  1749. && h < q2_limit && i < ctl_limit && j < ctk_limit && k < phi_limit
  1750. )// && (i+j+k)<=4)
  1751. minuit_eff->DefineParameter(npol.get_bin_in4D(h,i,j,k), sout.str().c_str(), 0.0, 0.001, 0.0, 0.0);
  1752. }
  1753. spdlog::info( "Running Migrad to determine eff shape" );
  1754. minuit_eff->mnexcm("MIG", migrad_options, 2, errorcode);
  1755. }
  1756. //extract fitted parameters
  1757. spdlog::debug("Extracting fitted parameters.");
  1758. std::vector<double> chijk_ml;
  1759. for (unsigned int h = 0; h<npol.q2; h++)
  1760. for (unsigned int i = 0; i<npol.ctl; i++)
  1761. for (unsigned int j = 0; j<npol.ctk; j++)
  1762. for (unsigned int k = 0; k<npol.phi; k++){
  1763. double v,e;
  1764. minuit_eff->GetParameter(npol.get_bin_in4D(h,i,j,k), v, e);
  1765. chijk_ml.push_back(v);
  1766. }
  1767. delete minuit_eff;
  1768. spdlog::info( "Minuit finished" );
  1769. //transform chebyshev coefficients to monomial coefficients
  1770. std::vector<double> poly_ml(npol.getSize(), 0.0);
  1771. for (unsigned int h = 0; h<npol.q2; h++)
  1772. for (unsigned int i = 0; i<npol.ctl; i++)
  1773. for (unsigned int j = 0; j<npol.ctk; j++)
  1774. for (unsigned int k = 0; k<npol.phi; k++){
  1775. double c = chijk_ml.at(npol.get_bin_in4D(h,i,j,k));
  1776. std::vector<double> ch_coeffs_q2(npol.q2, 0.0);
  1777. std::vector<double> ch_coeffs_ctl(npol.ctl, 0.0);
  1778. std::vector<double> ch_coeffs_ctk(npol.ctk, 0.0);
  1779. std::vector<double> ch_coeffs_phi(npol.phi,0.0);
  1780. ch_coeffs_q2.at(h) = 1.0;
  1781. ch_coeffs_ctl.at(i) = 1.0;
  1782. ch_coeffs_ctk.at(j) = 1.0;
  1783. ch_coeffs_phi.at(k) = 1.0;
  1784. std::vector<double> poly_coeffs_q2(npol.q2, 0.0);
  1785. std::vector<double> poly_coeffs_ctl(npol.ctl, 0.0);
  1786. std::vector<double> poly_coeffs_ctk(npol.ctk, 0.0);
  1787. std::vector<double> poly_coeffs_phi(npol.phi,0.0);
  1788. chebyshev_to_poly(ch_coeffs_q2, poly_coeffs_q2);
  1789. chebyshev_to_poly(ch_coeffs_ctl, poly_coeffs_ctl);
  1790. chebyshev_to_poly(ch_coeffs_ctk, poly_coeffs_ctk);
  1791. chebyshev_to_poly(ch_coeffs_phi, poly_coeffs_phi);
  1792. for (unsigned int l = 0; l<=h; l++)
  1793. for (unsigned int m = 0; m<=i; m++)
  1794. for (unsigned int n = 0; n<=j; n++)
  1795. for (unsigned int o = 0; o<=k; o++){
  1796. unsigned int bin = npol.get_bin_in4D(l,m,n,o);
  1797. poly_ml.at(bin) += c*poly_coeffs_q2.at(l)*poly_coeffs_ctl.at(m)*poly_coeffs_ctk.at(n)*poly_coeffs_phi.at(o);
  1798. }
  1799. }//tested, works
  1800. //correct coefficients from -1 +1 to ctlmin .. ctlmax for ctl, bit difficult, requires binomial coefficients
  1801. std::vector<double> poly_ml_ctl(npol.getSize(), 0.0);
  1802. std::vector<double> poly_ml_ctk(npol.getSize(), 0.0);
  1803. std::vector<double> poly_ml_phi(npol.getSize(), 0.0);
  1804. std::vector<double> poly_ml_q2(npol.getSize(), 0.0);
  1805. correct_coefficients(npol, edges, poly_ml_ctl, poly_ml, "ctl");
  1806. correct_coefficients(npol, edges, poly_ml_ctk, poly_ml_ctl, "ctk");
  1807. correct_coefficients(npol, edges, poly_ml_phi, poly_ml_ctk, "phi");
  1808. correct_coefficients(npol, edges, poly_ml_q2, poly_ml_phi, "q2");
  1809. std::vector<double> coeffs_ml(poly_ml_q2);
  1810. //calculate norm after full integration
  1811. double full_norm = 0.0;
  1812. for (unsigned int h = 0; h<npol.q2; h++){
  1813. for (unsigned int i = 0; i<npol.ctl; i++){
  1814. for (unsigned int j = 0; j<npol.ctk; j++){
  1815. for (unsigned int k = 0; k<npol.phi; k++){
  1816. full_norm += coeffs_ml.at(npol.get_bin_in4D(h,i,j,k))*integrate_4D(edges,h,i,j,k);
  1817. }
  1818. }
  1819. }
  1820. }
  1821. //assume a flat efficiency of 1.0 -> scale by edges.range_q2()*RANGE_3D()/full_norm
  1822. for (unsigned int h = 0; h<npol.q2; h++){
  1823. for (unsigned int i = 0; i<npol.ctl; i++){
  1824. for (unsigned int j = 0; j<npol.ctk; j++){
  1825. for (unsigned int k = 0; k<npol.phi; k++){
  1826. coeffs_ml.at(npol.get_bin_in4D(h,i,j,k)) *= edges.range_q2()*RANGE_3D()/full_norm;
  1827. // delta_q2*delta_ctl*delta_ctk*delta_phi/full_norm;
  1828. }
  1829. }
  1830. }
  1831. }
  1832. //calculate the integrated angular terms int f_i dOmega (q2) = xi(q2)
  1833. for (int l=1; l<=hxi_ml_hist[0]->GetNbinsX(); l++){
  1834. double a = hxi_ml_hist[0]->GetXaxis()->GetBinLowEdge(l);
  1835. double b = hxi_ml_hist[0]->GetXaxis()->GetBinLowEdge(l+1);
  1836. std::vector<double> integral_xi(hxi_ml_hist.size(), 0.0);
  1837. for (unsigned int h = 0; h<npol.q2; h++){
  1838. for (unsigned int i = 0; i<npol.ctl; i++){
  1839. for (unsigned int j = 0; j<npol.ctk; j++){
  1840. for (unsigned int k = 0; k<npol.phi; k++){
  1841. unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  1842. double coeff = C_PWAVE*coeffs_ml.at(bin)*pow(0.5*(a+b), h);
  1843. //f1 = c * sinthetak2; //j1s
  1844. integral_xi[0] += coeff
  1845. *integrate_x_to_n(edges.ctlmin, edges.ctlmax, i)
  1846. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j)-integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1847. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1848. //f2 = c * costhetak2; //j1c
  1849. integral_xi[1] += coeff
  1850. *integrate_x_to_n(edges.ctlmin, edges.ctlmax, i)
  1851. *integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2)
  1852. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1853. //f3 = c * sinthetak2*cos2thetal; //j2s
  1854. integral_xi[2] += coeff
  1855. *(2.0*integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+2)-integrate_x_to_n(edges.ctlmin, edges.ctlmax, i))
  1856. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j)-integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1857. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1858. //f4 = c * costhetak2*cos2thetal; //j2c
  1859. integral_xi[3] += coeff
  1860. *(2.0*integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+2)-integrate_x_to_n(edges.ctlmin, edges.ctlmax, i))
  1861. *integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2)
  1862. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1863. //f5 = c * sinthetak2*sinthetal2*cos(2.0*phi); //j3
  1864. integral_xi[4] += coeff
  1865. *(integrate_x_to_n(edges.ctlmin, edges.ctlmax, i)-integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+2))
  1866. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j)-integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1867. *integrate_x_to_n_times_cos_2x(edges.phimin, edges.phimax,k);
  1868. //f6 = c * sin2thetak*sin2thetal*cos(phi); //j4
  1869. integral_xi[5] += coeff
  1870. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctlmin, edges.ctlmax, i+1)
  1871. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctkmin, edges.ctkmax, j+1)
  1872. *integrate_x_to_n_times_cos_x(edges.phimin, edges.phimax,k);
  1873. //f7 = c * sin2thetak*sinthetal*cos(phi); //j5
  1874. integral_xi[6] += coeff
  1875. *integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctlmin, edges.ctlmax, i)
  1876. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctkmin, edges.ctkmax, j+1)
  1877. *integrate_x_to_n_times_cos_x(edges.phimin, edges.phimax,k);
  1878. //f8 = c * sinthetak2*costhetal; //j6s
  1879. integral_xi[7] += coeff
  1880. *integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+1)
  1881. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j)-integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1882. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1883. //f9 = c * costhetak2*costhetal; //j6c
  1884. integral_xi[8] += coeff
  1885. *integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+1)
  1886. *integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2)
  1887. *integrate_x_to_n(edges.phimin, edges.phimax,k);
  1888. //f10 = c * sin2thetak*sinthetal*sin(phi); //j7
  1889. integral_xi[9] += coeff
  1890. *integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctlmin, edges.ctlmax, i)
  1891. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctkmin, edges.ctkmax, j+1)
  1892. *integrate_x_to_n_times_sin_x(edges.phimin, edges.phimax,k);
  1893. //f11 = c * sin2thetak*sin2thetal*sin(phi); //j8
  1894. integral_xi[10] += coeff
  1895. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctlmin, edges.ctlmax, i+1)
  1896. *2.0*integrate_x_to_n_times_sqrt_1_minus_x2(edges.ctkmin, edges.ctkmax, j+1)
  1897. *integrate_x_to_n_times_sin_x(edges.phimin, edges.phimax,k);
  1898. //f12 = c * sinthetak2*sinthetal2*sin(2.0*phi); //j9
  1899. integral_xi[11] += coeff
  1900. *(integrate_x_to_n(edges.ctlmin, edges.ctlmax, i) - integrate_x_to_n(edges.ctlmin, edges.ctlmax, i+2))
  1901. *(integrate_x_to_n(edges.ctkmin, edges.ctkmax, j) - integrate_x_to_n(edges.ctkmin, edges.ctkmax, j+2))
  1902. *integrate_x_to_n_times_sin_2x(edges.phimin, edges.phimax,k);
  1903. }
  1904. }
  1905. }
  1906. }
  1907. for_indexed(auto hist: hxi_ml_hist) hist->SetBinContent(l, is_param_folded(i,opts) ? 0.0 : integral_xi[i]);
  1908. }
  1909. }
  1910. //-----------------------
  1911. // Factorization in q2 bins
  1912. //-----------------------
  1913. //std::vector<double> nfact();
  1914. if (checkFactorization){ //possible TODO for when you're bored: move into it's own function
  1915. spdlog::info( "CHECKFACTORIZATION start " );
  1916. //fill histo for comparison
  1917. std::vector<double> nsel_hist(edges.getNbins(), 0.0);
  1918. std::vector<double> nsel_hist_errsq(edges.getNbins(), 0.0);
  1919. for (auto &meas: filtered_events){
  1920. unsigned int h = (meas.q2 - edges.q2min ) / edges.binWidth_q2();
  1921. unsigned int i = (meas.costhetal - edges.ctlmin ) / edges.binWidth_ctl();
  1922. unsigned int j = (meas.costhetak - edges.ctkmin ) / edges.binWidth_ctk();
  1923. unsigned int k = (meas.phi - edges.phimin ) / edges.binWidth_phi();
  1924. unsigned int bin = get_bin_in4D(h,i,j,k,edges);
  1925. nsel_hist.at(bin) += meas.weight;
  1926. nsel_hist_errsq.at(bin) += sqr(meas.weight);
  1927. }
  1928. for (unsigned int i=0; i<nsel_hist_errsq.size(); i++){
  1929. if (nsel_hist_errsq.at(i) == 0.0) nsel_hist_errsq.at(i) = 1.0;
  1930. }
  1931. //loop over all q2 bins
  1932. double chi2 = 0.0;
  1933. for (unsigned int h=0; h<q2_edges.size()-1; h++){
  1934. double q2a = q2_edges.at(h);
  1935. double q2b = q2_edges.at(h+1);
  1936. std::vector<double> ctl_moments(npol.ctl, 0.0);
  1937. std::vector<double> ctk_moments(npol.ctk, 0.0);
  1938. std::vector<double> phi_moments(npol.phi,0.0);
  1939. double nfactweighted = 0.0;
  1940. //determine weighted number of events in this bin and fill control histos
  1941. std::ostringstream sout;
  1942. sout << h;
  1943. sout << "_" << DECAY_NAME << (opts->KS ? opts->DDLL+"_" : "_")
  1944. << "Run" << opts->run
  1945. << ((opts->angacccorrperyear && opts->year != -1) ? "_"+std::to_string(opts->year) : "")
  1946. << "_" << tagNumber;
  1947. TH1D* hctl = new TH1D("hctl", ";cos#Theta_{L};", nBinsAngles, edges.ctlmin, edges.ctlmax);
  1948. TH1D* hctk = new TH1D("hctk", ";cos#Theta_{K};", nBinsAngles, edges.ctkmin, edges.ctkmax);
  1949. TH1D* hphi = new TH1D("hphi", ";#phi [rad];" , nBinsAngles, edges.phimin, edges.phimax);
  1950. for (auto &meas : filtered_events){
  1951. if (meas.q2 > q2a && meas.q2 < q2b){
  1952. nfactweighted += meas.weight;
  1953. hctl->Fill(meas.costhetal, meas.weight);
  1954. hctk->Fill(meas.costhetak, meas.weight);
  1955. hphi->Fill(meas.phi, meas.weight);
  1956. }
  1957. }
  1958. //loop over events in this bin, determine factorizing moments
  1959. for (auto & meas: filtered_events){
  1960. if (meas.q2 > q2a && meas.q2 < q2b){
  1961. double weight = meas.weight;
  1962. double ctl = 2.0 * (meas.costhetal - edges.ctlmin ) / edges.range_ctl() - 1.0;
  1963. double ctk = 2.0 * (meas.costhetak - edges.ctkmin ) / edges.range_ctk() - 1.0;
  1964. double phi = 2.0 * (meas.phi - edges.phimin ) / edges.range_phi() - 1.0;
  1965. for (unsigned int i = 0; i<npol.ctl; i++){
  1966. if (assumectleven && i%2 != 0){
  1967. ctl_moments.at(i) = 0.0;
  1968. }
  1969. else{
  1970. //ctl_moments.at(i)+=weight*fcnc::chebyshev(ctl,i)/sqrt(1-ctl*ctl)*(i==0?1.0/pi:2.0/pi)/nfactweighted;
  1971. ctl_moments.at(i) += weight*fcnc::legendre(ctl, i)*(2.0*i+1.0)/2.0/nfactweighted;
  1972. }
  1973. }
  1974. for (unsigned int j = 0; j<npol.ctk; j++){
  1975. //ctk_moments.at(j) += weight*fcnc::chebyshev(ctk, j)/sqrt(1-ctk*ctk)*(j == 0 ? 1.0/pi : 2.0/pi)/nfactweighted;
  1976. ctk_moments.at(j) += weight*fcnc::legendre(ctk, j)*(2.0*j+1.0)/2.0/nfactweighted;
  1977. }
  1978. for (unsigned int k = 0; k<npol.phi; k++){
  1979. if (assumePhiEven && k%2 != 0){
  1980. phi_moments.at(k) = 0.0;
  1981. }
  1982. else{
  1983. //phi_moments.at(k) += weight*fcnc::chebyshev(phi, k)/sqrt(1-phi*phi)*(k == 0 ? 1.0/pi : 2.0/pi)/nfactweighted;
  1984. phi_moments.at(k) += weight*fcnc::legendre(phi, k)*(2.0*k+1.0)/2.0/nfactweighted;
  1985. }
  1986. }
  1987. }
  1988. }
  1989. //make polynomial
  1990. std::vector<double> ctl_polys(npol.ctl, 0.0);
  1991. std::vector<double> ctk_polys(npol.ctk, 0.0);
  1992. std::vector<double> phi_polys(npol.phi,0.0);
  1993. if (doLegendre){
  1994. legendre_to_poly(ctl_moments, ctl_polys);
  1995. legendre_to_poly(ctk_moments, ctk_polys);
  1996. legendre_to_poly(phi_moments, phi_polys);
  1997. }
  1998. else{
  1999. chebyshev_to_poly(ctl_moments, ctl_polys);
  2000. chebyshev_to_poly(ctk_moments, ctk_polys);
  2001. chebyshev_to_poly(phi_moments, phi_polys);
  2002. }
  2003. //transform angles from -1 +1 to angle_min angle_max
  2004. std::vector<double> ctl_correct(npol.ctl, 0.0);
  2005. std::vector<double> ctk_correct(npol.ctk, 0.0);
  2006. std::vector<double> phi_correct(npol.phi,0.0);
  2007. for (unsigned int i=0; i<ctk_polys.size(); i++) ctk_correct.at(i) = ctk_polys.at(i);
  2008. for (unsigned int i=0; i<ctl_polys.size(); i++) ctl_correct.at(i) = ctl_polys.at(i);
  2009. correct_poly(phi_polys, phi_correct, -TMath::Pi(), +TMath::Pi());
  2010. //determine chi2 in this bin
  2011. std::vector<double> neps_hist(nctlbins*nctkbins*nphibins, 0.0);
  2012. for (unsigned int i = 0; i<nctlbins; i++){
  2013. double ctla = edges.ctlmin + edges.range_ctl() * i /double(edges.nctlbins);
  2014. double ctlb = edges.ctlmin + edges.range_ctl() * (i+1.0) /double(edges.nctlbins);
  2015. for (unsigned int j = 0; j<nctkbins; j++){
  2016. double ctka = edges.ctkmin + edges.range_ctk() * j /double(edges.nctkbins);
  2017. double ctkb = edges.ctkmin + edges.range_ctk() * (j+1.0) /double(edges.nctkbins);
  2018. for (unsigned int k = 0; k<nphibins; k++){
  2019. double phi_a = edges.phimin + edges.range_phi() * k / double(edges.nphibins);
  2020. double phi_b = edges.phimin + edges.range_phi() * (k+1.0) / double(edges.nphibins);
  2021. double result_ctl = 0.0, result_ctk = 0.0, result_phi = 0.0;
  2022. for (unsigned int m = 0; m<npol.ctl; m++) result_ctl += ctl_correct.at(m)*integrate_x_to_n(ctla,ctlb,m);
  2023. for (unsigned int n = 0; n<npol.ctk; n++) result_ctk += ctk_correct.at(n)*integrate_x_to_n(ctka,ctkb,n);
  2024. for (unsigned int o = 0; o<npol.phi; o++) result_phi += phi_correct.at(o)*integrate_x_to_n(phi_a,phi_b,o);
  2025. neps_hist.at(get_bin_in3D(i,j,k,edges)) = result_ctl*result_ctk*result_phi;
  2026. }
  2027. }
  2028. }
  2029. //rescale to be sure
  2030. double nnorm_ctl = 0.0, nnorm_ctk = 0.0, nnorm_phi = 0.0;
  2031. for (unsigned int m = 0; m<npol.ctl; m++) nnorm_ctl += ctl_correct.at(m)*integrate_x_to_n(edges.ctlmin, edges.ctlmax, m);
  2032. for (unsigned int n = 0; n<npol.ctk; n++) nnorm_ctk += ctk_correct.at(n)*integrate_x_to_n(edges.ctkmin, edges.ctkmax, n);
  2033. for (unsigned int o = 0; o<npol.phi; o++) nnorm_phi += phi_correct.at(o)*integrate_x_to_n(edges.phimin, edges.phimax, o);
  2034. for (unsigned int i = 0; i<nctlbins; i++){
  2035. for (unsigned int j = 0; j<nctkbins; j++){
  2036. for (unsigned int k = 0; k<nphibins; k++){
  2037. neps_hist.at(get_bin_in3D(i,j,k,edges)) *= (nfactweighted/nnorm_ctl/nnorm_ctk/nnorm_phi);
  2038. }
  2039. }
  2040. }
  2041. //should scale nfactweighted/nfactfit
  2042. //determine chi2 //TODO: not working?
  2043. double curr_chi2 = 0.0;
  2044. TH1D* hpull = new TH1D("hpull", ";(N_{sel}-N_{fit})/#sqrt{N_{sel}};", 100, -5.0, 5.0);
  2045. for (unsigned int i = 0; i<nctlbins; i++){
  2046. for (unsigned int j = 0; j<nctkbins; j++){
  2047. for (unsigned int k = 0; k<nphibins; k++){
  2048. unsigned int bin = get_bin_in4D(h,i,j,k,edges);
  2049. curr_chi2 += sqr(nsel_hist.at(bin)-neps_hist.at(get_bin_in3D(i,j,k,edges)))/fabs(neps_hist.at(get_bin_in3D(i,j,k,edges))); //TODO: h is a wrong bin!
  2050. hpull->Fill((nsel_hist.at(bin)-neps_hist.at(get_bin_in3D(i,j,k,edges)))/sqrt(fabs(neps_hist.at(get_bin_in3D(i,j,k,edges)))));//TODO: h is a wrong bin!
  2051. }
  2052. }
  2053. }
  2054. //do plots
  2055. TH1D* ectl = new TH1D("ectl", ";cos#Theta_{L};", nBinsAngles, edges.ctlmin, edges.ctlmax);
  2056. TH1D* ectk = new TH1D("ectk", ";cos#Theta_{K};", nBinsAngles, edges.ctkmin, edges.ctkmax);
  2057. TH1D* ephi = new TH1D("ephi", ";#phi [rad];" , nBinsAngles, edges.phimin, edges.phimax);
  2058. for (int l=1; l<=ectl->GetNbinsX(); l++){
  2059. double integral = 0.0;
  2060. for (unsigned int i = 0; i<npol.ctl; i++){
  2061. integral += ctl_correct.at(i)*integrate_x_to_n(ectl->GetBinLowEdge(l),ectl->GetBinLowEdge(l+1),i);
  2062. }
  2063. ectl->SetBinContent(l, integral);
  2064. }
  2065. for (int l=1; l<=ectk->GetNbinsX(); l++){
  2066. double integral = 0.0;
  2067. for (unsigned int j = 0; j<npol.ctk; j++){
  2068. integral += ctk_correct.at(j)*integrate_x_to_n(ectl->GetBinLowEdge(l),ectl->GetBinLowEdge(l+1),j);
  2069. }
  2070. ectk->SetBinContent(l, integral);
  2071. }
  2072. for (int l=1; l<=ephi->GetNbinsX(); l++){
  2073. double integral = 0.0;
  2074. for (unsigned int k = 0; k<npol.phi; k++){
  2075. integral += phi_correct.at(k)*integrate_x_to_n(ectl->GetBinLowEdge(l),ectl->GetBinLowEdge(l+1),k);
  2076. }
  2077. ephi->SetBinContent(l, integral);
  2078. }
  2079. TLatex *tex = getPrettyTex(0.06,31);
  2080. std::ostringstream sregion;
  2081. sregion << std::fixed << std::setprecision(2) << q2a << "<q^{2}<" << q2b;
  2082. TCanvas* c_pull = new TCanvas("c_pull", "c_pull", 1600, 1200);
  2083. c_pull->cd();
  2084. hpull->Draw();
  2085. tex->DrawLatex(0.85, 0.15, sregion.str().c_str());
  2086. if(opts->write_eps)c_pull->Print((std::string(subfolder + "fact_pull")+sout.str()+std::string(".eps")).c_str(),"eps");
  2087. plotAngular(hctl,ectl,opts->write_eps,"fact_ctleff",sout.str(),sregion.str(),tex,subfolder);
  2088. plotAngular(hctk,ectk,opts->write_eps,"fact_ctkeff",sout.str(),sregion.str(),tex,subfolder);
  2089. plotAngular(hphi,ephi,opts->write_eps,"fact_phieff",sout.str(),sregion.str(),tex,subfolder);
  2090. delete hpull;
  2091. delete ectl;
  2092. delete ectk;
  2093. delete ephi;
  2094. delete hctl;
  2095. delete hctk;
  2096. delete hphi;
  2097. delete c_pull;
  2098. spdlog::debug( "fact chi2 in bin {0:d}: {1:f}", h, curr_chi2 );
  2099. chi2 += curr_chi2;
  2100. }
  2101. spdlog::info( "fact total chi2: {0:f}",chi2 );
  2102. spdlog::info( "uses {0:d}*{1:d}*{2:d}*{3:d}={4:d} bins",edges.nq2bins, edges.nctlbins, edges.nctkbins, edges.nphibins, edges.getNbins());
  2103. spdlog::info( "Chi2/Nbins = {0:f}", chi2/(edges.getNbins()) );
  2104. spdlog::info( "CHECKFACTORIZATION end " );
  2105. }
  2106. //-----------------------
  2107. // 3D MOMENTS in q2 bins
  2108. //-----------------------
  2109. if (do3Dmoments){
  2110. spdlog::info("DOTHREEDMOMENTS start ");
  2111. //fill histo for comparison
  2112. std::vector<double> nsel_hist(edges.getNbins(), 0.0);
  2113. std::vector<double> nsel_hist_errsq(edges.getNbins(), 0.0);
  2114. for (unsigned int e=0; e<filtered_events.size(); e++){
  2115. const event & meas = filtered_events.at(e);
  2116. unsigned int bin = get_bin_in4D(meas,edges);
  2117. nsel_hist.at(bin) += meas.weight;
  2118. nsel_hist_errsq.at(bin) += sqr(meas.weight);
  2119. }
  2120. for (unsigned int i=0; i<nsel_hist_errsq.size(); i++){
  2121. if (nsel_hist_errsq.at(i) == 0.0) nsel_hist_errsq.at(i) = 1.0;
  2122. }
  2123. //loop over all q2 bins
  2124. double chi2 = 0.0;
  2125. for (unsigned int h=0; h<q2_edges.size()-1; h++){
  2126. double q2a = q2_edges.at(h);
  2127. double q2b = q2_edges.at(h+1);
  2128. double nthreedweighted = 0.0;
  2129. //determine weighted number of events in this bin and fill control histos
  2130. std::ostringstream sout;
  2131. sout << h;
  2132. sout << "_" << DECAY_NAME << (opts->KS ? opts->DDLL+"_" : "_")
  2133. << "Run" << opts->run
  2134. << ((opts->angacccorrperyear && opts->year != -1) ? "_"+std::to_string(opts->year) : "");
  2135. TH1D* hctl = new TH1D("hctl", ";cos#Theta_{L};", nBinsAngles, edges.ctlmin, edges.ctlmax);
  2136. TH1D* hctk = new TH1D("hctk", ";cos#Theta_{K};", nBinsAngles, edges.ctkmin, edges.ctkmax);
  2137. TH1D* hphi = new TH1D("hphi", ";#phi [rad];" , nBinsAngles, edges.phimin, edges.phimax);
  2138. for (auto &meas: filtered_events){
  2139. if (meas.q2 > q2a && meas.q2 < q2b){
  2140. nthreedweighted += meas.weight;
  2141. hctl->Fill(meas.costhetal, meas.weight);
  2142. hctk->Fill(meas.costhetak, meas.weight);
  2143. hphi->Fill(meas.phi, meas.weight);
  2144. }
  2145. }
  2146. //loop over events in this bin, determine factorizing moments
  2147. spdlog::debug("Getting factorizing moments");
  2148. std::vector<double> threed_moments(npol.ctl*npol.ctk*npol.phi,0.0);
  2149. for (unsigned int i = 0; i<npol.ctl; i++){
  2150. for (unsigned int j = 0; j<npol.ctk; j++){
  2151. for (unsigned int k = 0; k<npol.phi; k++){
  2152. for (auto &meas: filtered_events){
  2153. if (meas.q2 > q2a && meas.q2 < q2b){
  2154. double weight = meas.weight;
  2155. double ctl = 2.0 * (meas.costhetal - edges.ctlmin ) / edges.range_ctl() - 1.0;
  2156. double ctk = 2.0 * (meas.costhetak - edges.ctkmin ) / edges.range_ctk() - 1.0;
  2157. double phi = 2.0 * (meas.phi - edges.phimin ) / edges.range_phi() - 1.0;
  2158. double result = 0.0;
  2159. if (assumectleven && i%2 != 0) result = 0.0;
  2160. else if (assumePhiEven && k%2 != 0) result = 0.0;
  2161. else {
  2162. if (doLegendre){
  2163. result = weight
  2164. *fcnc::legendre(ctl, i)*(2.0*i+1.0)/2.0
  2165. *fcnc::legendre(ctk, j)*(2.0*j+1.0)/2.0
  2166. *fcnc::legendre(phi, k)*(2.0*k+1.0)/2.0
  2167. /nthreedweighted;// /filtered_events.size();
  2168. }
  2169. else{
  2170. result = weight
  2171. *fcnc::chebyshev(ctl, i)/sqrt(1-ctl*ctl)*(i==0 ? 1.0/MY_PI : 2.0/MY_PI)
  2172. *fcnc::chebyshev(ctk, j)/sqrt(1-ctk*ctk)*(j==0 ? 1.0/MY_PI : 2.0/MY_PI)
  2173. *fcnc::chebyshev(phi, k)/sqrt(1-phi*phi)*(k==0 ? 1.0/MY_PI : 2.0/MY_PI)
  2174. /nthreedweighted;// /filtered_events.size();
  2175. }
  2176. }
  2177. threed_moments.at( get_bin_in3D(i,j,k,npol)) += result;
  2178. }
  2179. }
  2180. }
  2181. }
  2182. }
  2183. //make polynomial
  2184. //transform legendre coefficients to monomial coefficients
  2185. spdlog::debug("Transforming legendre coefficients to monomial coefficients....");
  2186. std::vector<double> threedpoly_moments(npol.ctl*npol.ctk*npol.phi,0.0);
  2187. for (unsigned int i = 0; i<npol.ctl; i++){
  2188. for (unsigned int j = 0; j<npol.ctk; j++){
  2189. for (unsigned int k = 0; k<npol.phi; k++){
  2190. double tmp = threed_moments.at(get_bin_in3D(i,j,k,npol));
  2191. std::vector<double> leg_coeffs_ctl(npol.ctl, 0.0);
  2192. std::vector<double> leg_coeffs_ctk(npol.ctk, 0.0);
  2193. std::vector<double> leg_coeffs_phi(npol.phi,0.0);
  2194. leg_coeffs_ctl.at(i) = 1.0;
  2195. leg_coeffs_ctk.at(j) = 1.0;
  2196. leg_coeffs_phi.at(k) = 1.0;
  2197. std::vector<double> poly_coeffs_ctl(npol.ctl, 0.0);
  2198. std::vector<double> poly_coeffs_ctk(npol.ctk, 0.0);
  2199. std::vector<double> poly_coeffs_phi(npol.phi,0.0);
  2200. legendre_to_poly(leg_coeffs_ctl, poly_coeffs_ctl);
  2201. legendre_to_poly(leg_coeffs_ctk, poly_coeffs_ctk);
  2202. legendre_to_poly(leg_coeffs_phi, poly_coeffs_phi);
  2203. for (unsigned int m = 0; m<=i; m++){
  2204. for (unsigned int n = 0; n<=j; n++){
  2205. for (unsigned int o = 0; o<=k; o++){
  2206. unsigned int bin = get_bin_in3D(m,n,o,npol);
  2207. threedpoly_moments.at(bin) += tmp*poly_coeffs_ctl.at(m)*poly_coeffs_ctk.at(n)*poly_coeffs_phi.at(o);
  2208. }
  2209. }
  2210. }
  2211. }
  2212. }
  2213. }
  2214. //correct coefficients from -1 +1 to -pi .. +pi for phi, this is easy
  2215. std::vector<double> threedpoly_moments_phi(threedpoly_moments);
  2216. for (unsigned int m = 0; m<npol.ctl; m++){
  2217. for (unsigned int n = 0; n<npol.ctk; n++){
  2218. for (unsigned int o = 0; o<npol.phi; o++){
  2219. threedpoly_moments_phi.at(get_bin_in3D(m,n,o,npol)) *= pow(1.0/MY_PI, o);
  2220. }
  2221. }
  2222. }
  2223. //calculate norm after full integration
  2224. double full_norm = 0.0;
  2225. for (unsigned int i = 0; i<npol.ctl; i++){
  2226. for (unsigned int j = 0; j<npol.ctk; j++){
  2227. for (unsigned int k = 0; k<npol.phi; k++){
  2228. double result = threedpoly_moments_phi.at(get_bin_in3D(i,j,k,npol))*integrate_3D(edges,i,j,k);
  2229. full_norm += result;
  2230. }
  2231. }
  2232. }
  2233. spdlog::debug("Rescaling...");
  2234. //rescale to be sure
  2235. for (unsigned int i = 0; i<npol.ctl; i++){
  2236. for (unsigned int j = 0; j<npol.ctk; j++){
  2237. for (unsigned int k = 0; k<npol.phi; k++){
  2238. threedpoly_moments_phi.at(get_bin_in3D(i,j,k,npol)) *= nthreedweighted/full_norm;
  2239. }
  2240. }
  2241. }
  2242. //determine nfit in this bin
  2243. std::vector<double> neps_hist(nctlbins*nctkbins*nphibins, 0.0);
  2244. for (unsigned int i = 0; i<nctlbins; i++){
  2245. double ctla = edges.ctlmin + i * edges.range_ctl();
  2246. double ctlb = edges.ctlmin + (i+1) * edges.range_ctl();
  2247. for (unsigned int j = 0; j<nctkbins; j++){
  2248. double ctka = edges.ctkmin + j * edges.range_ctk();
  2249. double ctkb = edges.ctkmin + (j+1) * edges.range_ctk();
  2250. for (unsigned int k = 0; k<nphibins; k++){
  2251. double phi_a = edges.phimin + k * edges.range_phi();
  2252. double phi_b = edges.phimin + (k+1) * edges.range_phi();
  2253. double result = 0.0;
  2254. for (unsigned int m = 0; m<npol.ctl; m++)
  2255. for (unsigned int n = 0; n<npol.ctk; n++)
  2256. for (unsigned int o = 0; o<npol.phi; o++)
  2257. result += threedpoly_moments_phi.at(get_bin_in3D(m,n,o,npol))
  2258. *(pow(ctlb,m+1)/(m+1.0) - pow(ctla, m+1)/(m+1.0))
  2259. *(pow(ctkb,n+1)/(n+1.0) - pow(ctka, n+1)/(n+1.0))
  2260. *(pow(phi_b,o+1)/(o+1.0) - pow(phi_a, o+1)/(o+1.0));
  2261. unsigned int bin = get_bin_in3D(i,j,k,edges);
  2262. neps_hist.at(bin) = result;
  2263. }
  2264. }
  2265. }
  2266. spdlog::debug("Getting chi2...");
  2267. //determine chi2
  2268. double curr_chi2 = 0.0;
  2269. TH1D* hpull = new TH1D("hpull", ";(N_{sel}-N_{fit})/#sqrt{N_{sel}};", 100, -5.0, 5.0);
  2270. for (unsigned int i = 0; i<nctlbins; i++)
  2271. for (unsigned int j = 0; j<nctkbins; j++)
  2272. for (unsigned int k = 0; k<nphibins; k++){
  2273. unsigned int bin =get_bin_in4D(h,i,j,k,edges);
  2274. curr_chi2 += sqr(nsel_hist.at(bin)-neps_hist.at(get_bin_in3D(i,j,k,edges)))/fabs(neps_hist.at(get_bin_in3D(i,j,k,edges)));
  2275. hpull->Fill((nsel_hist.at(bin)-neps_hist.at(get_bin_in3D(i,j,k,edges)))/sqrt(fabs(neps_hist.at(get_bin_in3D(i,j,k,edges)))));
  2276. }
  2277. //spdlog::debug( "ok" );
  2278. //do plots
  2279. TH1D* ectl = new TH1D("ectl", ";cos#Theta_{L};", nBinsAngles, edges.ctlmin, edges.ctlmax);
  2280. TH1D* ectk = new TH1D("ectk", ";cos#Theta_{K};", nBinsAngles, edges.ctkmin, edges.ctkmax);
  2281. TH1D* ephi = new TH1D("ephi", ";#phi [rad];" , nBinsAngles, edges.phimin, edges.phimax);
  2282. for (int l=1; l<=ectl->GetNbinsX(); l++){
  2283. double a = ectl->GetBinLowEdge(l);
  2284. double b = ectl->GetBinLowEdge(l+1);
  2285. double integral = 0.0;
  2286. for (unsigned int i = 0; i<npol.ctl; i++)
  2287. for (unsigned int j = 0; j<npol.ctk; j++)
  2288. for (unsigned int k = 0; k<npol.phi; k++){
  2289. double result = threedpoly_moments_phi.at(get_bin_in3D(i,j,k,npol))
  2290. *(pow(b ,i+1)/(i+1.0) - pow(a ,i+1)/(i+1.0))
  2291. *(pow(edges.ctkmax,j+1)/(j+1.0) - pow(edges.ctkmin,j+1)/(j+1.0))
  2292. *(pow(edges.phimax,k+1)/(k+1.0) - pow(edges.phimin,k+1)/(k+1.0));
  2293. integral += result;
  2294. }
  2295. ectl->SetBinContent(l, integral);
  2296. }
  2297. for (int l=1; l<=ectk->GetNbinsX(); l++){
  2298. double a = ectk->GetBinLowEdge(l);
  2299. double b = ectk->GetBinLowEdge(l+1);
  2300. double integral = 0.0;
  2301. for (unsigned int i = 0; i<npol.ctl; i++)
  2302. for (unsigned int j = 0; j<npol.ctk; j++)
  2303. for (unsigned int k = 0; k<npol.phi; k++){
  2304. double result = threedpoly_moments_phi.at(get_bin_in3D(i,j,k,npol))
  2305. *(pow(edges.ctlmax,i+1)/(i+1.0) - pow(edges.ctlmin,i+1)/(i+1.0))
  2306. *(pow(b ,j+1)/(j+1.0) - pow(a ,j+1)/(j+1.0))
  2307. *(pow(edges.phimax,k+1)/(k+1.0) - pow(edges.phimin,k+1)/(k+1.0));
  2308. integral += result;
  2309. }
  2310. ectk->SetBinContent(l, integral);
  2311. }
  2312. for (int l=1; l<=ephi->GetNbinsX(); l++){
  2313. double a = ephi->GetBinLowEdge(l);
  2314. double b = ephi->GetBinLowEdge(l+1);
  2315. double integral = 0.0;
  2316. for (unsigned int i = 0; i<npol.ctl; i++)
  2317. for (unsigned int j = 0; j<npol.ctk; j++)
  2318. for (unsigned int k = 0; k<npol.phi; k++){
  2319. double result = threedpoly_moments_phi.at(get_bin_in3D(i,j,k,npol))
  2320. *(pow(edges.ctlmax,i+1)/(i+1.0) - pow(edges.ctlmin,i+1)/(i+1.0))
  2321. *(pow(edges.ctkmax,j+1)/(j+1.0) - pow(edges.ctkmin,j+1)/(j+1.0))
  2322. *(pow(b ,k+1)/(k+1.0) - pow(a ,k+1)/(k+1.0));
  2323. integral += result;
  2324. }
  2325. ephi->SetBinContent(l, integral);
  2326. }
  2327. spdlog::debug("Plotting...");
  2328. TLatex *tex = getPrettyTex(0.06,31);
  2329. std::ostringstream sregion;
  2330. sregion << std::fixed << std::setprecision(2) << q2a << "<q^{2}<" << q2b;
  2331. TCanvas* c_zero = new TCanvas("c_zero", "c_zero", 1600, 1200);
  2332. c_zero->cd();
  2333. hpull->Draw();
  2334. tex->DrawLatex(0.85, 0.15, sregion.str().c_str());
  2335. if(opts->write_eps)c_zero->Print((std::string(subfolder + "3d_pull")+sout.str()+std::string(".eps")).c_str(),"eps");
  2336. plotAngular(hctl,ectl,opts->write_eps,"3d_ctleff", sout.str(), sregion.str(),tex,subfolder);
  2337. plotAngular(hctk,ectk,opts->write_eps,"3d_ctkeff", sout.str(), sregion.str(),tex,subfolder);
  2338. plotAngular(hphi,ephi,opts->write_eps,"3d_phieff", sout.str(), sregion.str(),tex,subfolder);
  2339. delete hpull;
  2340. delete ectl;
  2341. delete ectk;
  2342. delete ephi;
  2343. delete hctl;
  2344. delete hctk;
  2345. delete hphi;
  2346. delete c_zero;
  2347. spdlog::debug( "3d chi2 in bin {0:d}: {1:f}", h, curr_chi2 );
  2348. chi2 += curr_chi2;
  2349. }
  2350. spdlog::debug( "3d total chi2: {0:f}",chi2 );
  2351. spdlog::debug( "3d uses {0:d}*{1:d}*{2:d}*{3:d}={4_d} bins",edges.nq2bins, edges.nctlbins, edges.nctkbins, edges.nphibins, edges.getNbins());
  2352. spdlog::debug( "3d chi2/Nbins = {0:f}", chi2/(edges.getNbins()) );
  2353. spdlog::info( "DOTHREEDMOMENTS end " );
  2354. }
  2355. //-----------------------
  2356. // CHI2 TEST FOR MOMENTS
  2357. //-----------------------
  2358. bool dochi2test = true;
  2359. if(opts->only_4_1D_chi2)dochi2test = false;
  2360. spdlog::debug("dochi2: "+boolToString(dochi2test));
  2361. if (dochi2test) {
  2362. get_chi2(edges, npol, filtered_events, coeffs_moments, globalvalues,
  2363. assumectleven, assumePhiEven, opts->write_eps, subfolder, appendix);
  2364. }
  2365. //-----------------------
  2366. //MAKE NICE CONTROL PLOTS
  2367. //-----------------------
  2368. const bool do_plots = opts->write_eps || opts->only_4_1D_chi2;
  2369. if (do_plots){
  2370. spdlog::info( "Start PLOTS.." );
  2371. gROOT->SetStyle("Plain");
  2372. TPad foo;
  2373. const int NRGBs = 5;
  2374. const int NCont = 250;
  2375. double stops[NRGBs] = { 0.00, 0.34, 0.61, 0.84, 1.00 };
  2376. double red[NRGBs] = { 0.00, 0.00, 0.87, 1.00, 0.51 };
  2377. double green[NRGBs] = { 0.00, 0.81, 1.00, 0.20, 0.00 };
  2378. double blue[NRGBs] = { 0.51, 1.00, 0.12, 0.00, 0.00 };
  2379. TColor::CreateGradientColorTable(NRGBs, stops, red, green, blue, NCont);
  2380. gStyle->SetNumberContours(NCont);
  2381. gStyle->SetLabelFont(132, "xyz");
  2382. gStyle->SetTitleFont(132, "xyz");
  2383. gStyle->SetLegendFont(132);
  2384. gStyle->SetStatFont(132);
  2385. //new histograms binned in q2
  2386. //compare the three angular projections for data and moments
  2387. for (unsigned int u=0; u<q2_edges.size()-1; u++){
  2388. std::ostringstream sout;
  2389. sout << u;
  2390. std::string binno = sout.str();
  2391. TH1D* hctl = new TH1D("hctl", ";cos#Theta_{L};", nBinsAngles, edges.ctlmin, edges.ctlmax);
  2392. TH1D* hctk = new TH1D("hctk", ";cos#Theta_{K};", nBinsAngles, edges.ctkmin, edges.ctkmax);
  2393. TH1D* hphi = new TH1D("hphi", ";#phi [rad];" , nBinsAngles, edges.phimin, edges.phimax);
  2394. TH2D* hctlctk = new TH2D("hctlctk", ";cos#Theta_{L};cos#Theta_{K}", nBinsAngles, edges.ctlmin, edges.ctlmax, nBinsAngles, edges.ctkmin, edges.ctkmax);
  2395. TH2D* hctlphi = new TH2D("hctlphi", ";cos#Theta_{L};#phi [rad]" , nBinsAngles, edges.ctlmin, edges.ctlmax, nBinsAngles, edges.phimin, edges.phimax);
  2396. TH2D* hctkphi = new TH2D("hctkphi", ";cos#Theta_{K};#phi [rad]" , nBinsAngles, edges.ctkmin, edges.ctkmax, nBinsAngles, edges.phimin, edges.phimax);
  2397. double q2a = q2_edges.at(u);
  2398. double q2b = q2_edges.at(u+1);
  2399. for (auto & meas: filtered_events){
  2400. if (meas.q2 > q2a && meas.q2 < q2b){
  2401. hctl->Fill(meas.costhetal, meas.weight);
  2402. hctk->Fill(meas.costhetak, meas.weight);
  2403. hphi->Fill(meas.phi, meas.weight);
  2404. hctlctk->Fill(meas.costhetal, meas.costhetak, meas.weight);
  2405. hctlphi->Fill(meas.costhetal, meas.phi, meas.weight);
  2406. hctkphi->Fill(meas.costhetak, meas.phi, meas.weight);
  2407. }
  2408. }
  2409. TH1D* hctl_moments = new TH1D("hctl_moments", ";cos#Theta_{L};", nBinsAngles, edges.ctlmin, edges.ctlmax);
  2410. TH1D* hctk_moments = new TH1D("hctk_moments", ";cos#Theta_{K};", nBinsAngles, edges.ctkmin, edges.ctkmax);
  2411. TH1D* hphi_moments = new TH1D("hphi_moments", ";#phi [rad];" , nBinsAngles, edges.phimin, edges.phimax);
  2412. TH2D* hctlctk_moments = new TH2D("hctlctk_moments", ";cos#Theta_{L};cos#Theta_{K}", nBinsAngles, edges.ctlmin, edges.ctlmax, nBinsAngles, edges.ctkmin, edges.ctkmax);
  2413. TH2D* hctlphi_moments = new TH2D("hctlphi_moments", ";cos#Theta_{L};#phi [rad]" , nBinsAngles, edges.ctlmin, edges.ctlmax, nBinsAngles, edges.phimin, edges.phimax);
  2414. TH2D* hctkphi_moments = new TH2D("hctkphi_moments", ";cos#Theta_{K};#phi [rad]" , nBinsAngles, edges.ctkmin, edges.ctkmax, nBinsAngles, edges.phimin, edges.phimax);
  2415. //1d plots
  2416. fill_moments_hist_1D(hctl_moments, coeffs_moments, edges, npol, q2a, q2b);
  2417. fill_moments_hist_1D(hctk_moments, coeffs_moments, edges, npol, q2a, q2b);
  2418. fill_moments_hist_1D(hphi_moments, coeffs_moments, edges, npol, q2a, q2b);
  2419. //2d plots
  2420. fill_moments_hist_2D(hctlctk_moments, coeffs_moments, edges, npol, q2a, q2b);
  2421. fill_moments_hist_2D(hctlphi_moments, coeffs_moments, edges, npol, q2a, q2b);
  2422. fill_moments_hist_2D(hctkphi_moments, coeffs_moments, edges, npol, q2a, q2b);
  2423. TLatex *tex = getPrettyTex(0.06,31);
  2424. std::ostringstream sregion;
  2425. sregion << std::fixed << std::setprecision(2) << q2a << "<q^{2}<" << q2b;
  2426. plotAngular(hctl,hctl_moments,opts->write_eps,"ctleff",binno+appendix,sregion.str(), tex, subfolder);
  2427. plotAngular(hctk,hctk_moments,opts->write_eps,"ctkeff",binno+appendix,sregion.str(), tex, subfolder);
  2428. plotAngular(hphi,hphi_moments,opts->write_eps,"phieff",binno+appendix,sregion.str(), tex, subfolder);
  2429. if (tagNumber < 0){ //Do not plot when testing quickly
  2430. plotAngular(hctlctk,hctlctk_moments,opts->write_eps,"ctlctkeff",binno+appendix,
  2431. sregion.str(), tex, subfolder);
  2432. plotAngular(hctlphi,hctlphi_moments,opts->write_eps,"ctlphieff",binno+appendix,
  2433. sregion.str(), tex, subfolder);
  2434. plotAngular(hctkphi,hctkphi_moments,opts->write_eps,"ctkphieff",binno+appendix,
  2435. sregion.str(), tex, subfolder);
  2436. }
  2437. delete hctl; delete hctl_moments;
  2438. delete hctk; delete hctk_moments;
  2439. delete hphi; delete hphi_moments;
  2440. delete hctlctk; delete hctlctk_moments;
  2441. delete hctkphi; delete hctkphi_moments;
  2442. delete hctlphi; delete hctlphi_moments;
  2443. }//end extra plots in bins of q2
  2444. //data histograms
  2445. TH1D* hq2 = new TH1D("hq2" , ";q^{2} [GeV^{2}];" , nBinsQ2 ,edges.q2min, edges.q2max);
  2446. TH1D* hctl = new TH1D("hctl", ";cos(#Theta_{L});", nBinsAngles, edges.ctlmin, edges.ctlmax);
  2447. TH1D* hctk = new TH1D("hctk", ";cos(#Theta_{K});", nBinsAngles, edges.ctkmin, edges.ctkmax);
  2448. TH1D* hphi = new TH1D("hphi", ";#phi [rad];" , nBinsAngles, edges.phimin, edges.phimax);
  2449. TH2D* hctlctk = new TH2D("hctlctk", ";cos#Theta_{L};cos#Theta_{K}", nBinsAngles, edges.ctlmin, edges.ctlmax, nBinsAngles, edges.ctkmin, edges.ctkmax);
  2450. TH2D* hctlphi = new TH2D("hctlphi", ";cos#Theta_{L};#phi [rad]" , nBinsAngles, edges.ctlmin, edges.ctlmax, nBinsAngles, edges.phimin, edges.phimax);
  2451. TH2D* hctkphi = new TH2D("hctkphi", ";cos#Theta_{K};#phi [rad]" , nBinsAngles, edges.ctkmin, edges.ctkmax, nBinsAngles, edges.phimin, edges.phimax);
  2452. TH2D* hq2ctl = new TH2D("hq2ctl", ";q^{2};cos#Theta_{L}", nBinsQ2, edges.q2min, edges.q2max, nBinsAngles, edges.ctlmin, edges.ctlmax);
  2453. TH2D* hq2ctk = new TH2D("hq2ctk", ";q^{2};cos#Theta_{K}", nBinsQ2, edges.q2min, edges.q2max, nBinsAngles, edges.ctkmin, edges.ctkmax);
  2454. TH2D* hq2phi = new TH2D("hq2phi", ";q^{2};#phi [rad]" , nBinsQ2, edges.q2min, edges.q2max, nBinsAngles, edges.phimin, edges.phimax);
  2455. hq2->Sumw2();
  2456. hctl->Sumw2();
  2457. hctk->Sumw2();
  2458. hphi->Sumw2();
  2459. for (unsigned int i=0; i<filtered_events.size(); i++){
  2460. const event& meas = filtered_events.at(i);
  2461. hq2->Fill(meas.q2, meas.weight);
  2462. hctl->Fill(meas.costhetal, meas.weight);
  2463. hctk->Fill(meas.costhetak, meas.weight);
  2464. hphi->Fill(meas.phi, meas.weight);
  2465. hctlctk->Fill(meas.costhetal, meas.costhetak, meas.weight);
  2466. hctlphi->Fill(meas.costhetal, meas.phi, meas.weight);
  2467. hctkphi->Fill(meas.costhetak, meas.phi, meas.weight);
  2468. hq2ctl->Fill(meas.q2, meas.costhetal, meas.weight);
  2469. hq2ctk->Fill(meas.q2, meas.costhetak, meas.weight);
  2470. hq2phi->Fill(meas.q2, meas.phi, meas.weight);
  2471. }
  2472. //fitted histograms, moments method
  2473. TH1D* hq2_moments = new TH1D("hq2_moments" , ";q^{2} [GeV^{2}];" , nBinsQ2, edges.q2min, edges.q2max);
  2474. TH1D* hctl_moments = new TH1D("hctl_moments", ";cos(#Theta_{L});", nBinsAngles, edges.ctlmin, edges.ctlmax);
  2475. TH1D* hctk_moments = new TH1D("hctk_moments", ";cos(#Theta_{K});", nBinsAngles, edges.ctkmin, edges.ctkmax);
  2476. TH1D* hphi_moments = new TH1D("hphi_moments", ";#phi [rad];" , nBinsAngles, edges.phimin, edges.phimax);
  2477. TH2D* hctlctk_moments = new TH2D("hctlctk_moments", ";cos#Theta_{L};cos#Theta_{K}", nBinsAngles, edges.ctlmin, edges.ctlmax, nBinsAngles, edges.ctkmin, edges.ctkmax);
  2478. TH2D* hctlphi_moments = new TH2D("hctlphi_moments", ";cos#Theta_{L};#phi [rad]" , nBinsAngles, edges.ctlmin, edges.ctlmax, nBinsAngles, edges.phimin, edges.phimax);
  2479. TH2D* hctkphi_moments = new TH2D("hctkphi_moments", ";cos#Theta_{K};#phi [rad]" , nBinsAngles, edges.ctkmin, edges.ctkmax, nBinsAngles, edges.phimin, edges.phimax);
  2480. TH2D* hq2ctl_moments = new TH2D("hq2ctl_moments", ";q^{2};cos#Theta_{L}", nBinsQ2, edges.q2min, edges.q2max, nBinsAngles, edges.ctlmin, edges.ctlmax);
  2481. TH2D* hq2ctk_moments = new TH2D("hq2ctk_moments", ";q^{2};cos#Theta_{K}", nBinsQ2, edges.q2min, edges.q2max, nBinsAngles, edges.ctkmin, edges.ctkmax);
  2482. TH2D* hq2phi_moments = new TH2D("hq2phi_moments", ";q^{2};#phi [rad]" , nBinsQ2, edges.q2min, edges.q2max, nBinsAngles, edges.phimin, edges.phimax);
  2483. //1d plots
  2484. fill_moments_hist_1D(hq2_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2485. fill_moments_hist_1D(hctl_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2486. fill_moments_hist_1D(hctk_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2487. fill_moments_hist_1D(hphi_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2488. //2d plots
  2489. fill_moments_hist_2D(hctlctk_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2490. fill_moments_hist_2D(hctlphi_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2491. fill_moments_hist_2D(hctkphi_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2492. fill_moments_hist_2D(hq2ctl_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2493. fill_moments_hist_2D(hq2ctk_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2494. fill_moments_hist_2D(hq2phi_moments,coeffs_moments,edges,npol,edges.q2min,edges.q2max);
  2495. if(opts->only_4_1D_chi2){
  2496. //reset globalvalues
  2497. globalvalues->chi2_4_1D = 0.0;
  2498. globalvalues->chi2_4_1D_ctk = 0.0;
  2499. globalvalues->chi2_4_1D_ctl = 0.0;
  2500. globalvalues->chi2_4_1D_phi = 0.0;
  2501. globalvalues->chi2_4_1D_q2 = 0.0;
  2502. globalvalues->ndof_4_1D = 0;
  2503. globalvalues->ndof_4_1D_ctk = 0;
  2504. globalvalues->ndof_4_1D_ctl = 0;
  2505. globalvalues->ndof_4_1D_phi = 0;
  2506. globalvalues->ndof_4_1D_q2 = 0;
  2507. //first scale moments to match integral of event histograms
  2508. hctk_moments->Scale(hctk->Integral()/hctk_moments->Integral());
  2509. hctl_moments->Scale(hctl->Integral()/hctl_moments->Integral());
  2510. hphi_moments->Scale(hphi->Integral()/hphi_moments->Integral());
  2511. hq2_moments ->Scale(hq2->Integral()/hq2_moments->Integral());
  2512. //get chi2 from all 4 variables
  2513. for(UInt_t b = 1; b <= nBinsAngles; b++){
  2514. globalvalues->chi2_4_1D_ctk += sqr((hctk->GetBinContent(b) - hctk_moments->GetBinContent(b))) / fabs(hctk_moments->GetBinContent(b));
  2515. globalvalues->chi2_4_1D_ctl += sqr((hctl->GetBinContent(b) - hctl_moments->GetBinContent(b))) / fabs(hctl_moments->GetBinContent(b));
  2516. globalvalues->chi2_4_1D_phi += sqr((hphi->GetBinContent(b) - hphi_moments->GetBinContent(b))) / fabs(hphi_moments->GetBinContent(b));
  2517. }
  2518. for(UInt_t b = 1; b <= nBinsQ2; b++){
  2519. globalvalues->chi2_4_1D_q2 += sqr((hq2->GetBinContent(b) - hq2_moments->GetBinContent(b))) / fabs(hq2_moments->GetBinContent(b));
  2520. }
  2521. //sum of all four 1D histograms
  2522. globalvalues->chi2_4_1D = globalvalues->chi2_4_1D_ctk + globalvalues->chi2_4_1D_ctl + globalvalues->chi2_4_1D_phi + globalvalues->chi2_4_1D_q2;
  2523. //determine ndof for all angles and q2
  2524. //NOT sure if these ndofs are 100% correct, but good enough for a relative measure
  2525. globalvalues->ndof_4_1D_ctk = nBinsAngles - (npol.ctk-1) - 1;
  2526. globalvalues->ndof_4_1D_ctl = nBinsAngles - (npol.ctl-1) - 1;
  2527. globalvalues->ndof_4_1D_phi = nBinsAngles - (npol.phi-1) - 1;
  2528. globalvalues->ndof_4_1D_q2 = nBinsQ2 - (npol.q2-1) - 1;
  2529. globalvalues->ndof_4_1D = 3*nBinsAngles + nBinsQ2 - 1 - (npol.ctk + npol.ctl + npol.phi + npol.q2 - 1);
  2530. }
  2531. //plot
  2532. plotAngular(hq2,hq2_moments,opts->write_eps,"q2eff",appendix, subfolder);
  2533. plotAngular(hctl,hctl_moments,opts->write_eps,"ctleff",appendix, subfolder);
  2534. plotAngular(hctk,hctk_moments,opts->write_eps,"ctkeff",appendix, subfolder);
  2535. plotAngular(hphi,hphi_moments,opts->write_eps,"phieff",appendix, subfolder);
  2536. if (tagNumber < 0){ //do not plot when testing
  2537. plotAngular(hctlctk,hctlctk_moments,opts->write_eps,"ctlctkeff",appendix, subfolder);
  2538. plotAngular(hctlphi,hctlphi_moments,opts->write_eps,"ctlphieff",appendix, subfolder);
  2539. plotAngular(hctkphi,hctkphi_moments,opts->write_eps,"ctkphieff",appendix, subfolder);
  2540. plotAngular(hq2ctl,hq2ctl_moments,opts->write_eps,"q2ctleff",appendix, subfolder);
  2541. plotAngular(hq2ctk,hq2ctk_moments,opts->write_eps,"q2ctkeff",appendix, subfolder);
  2542. plotAngular(hq2phi,hq2phi_moments,opts->write_eps,"q2phieff",appendix, subfolder);
  2543. }
  2544. delete hq2; delete hq2_moments;
  2545. delete hctl; delete hctl_moments;
  2546. delete hctk; delete hctk_moments;
  2547. delete hphi; delete hphi_moments;
  2548. delete hctlctk; delete hctlctk_moments;
  2549. delete hctkphi; delete hctkphi_moments;
  2550. delete hctlphi; delete hctlphi_moments;
  2551. delete hq2ctl; delete hq2ctl_moments;
  2552. delete hq2ctk; delete hq2ctk_moments;
  2553. delete hq2phi; delete hq2phi_moments;
  2554. hxi_moments[0]->SetMinimum(1.0); hxi_moments[0]->SetMaximum(+2.0);
  2555. hxi_moments[1]->SetMinimum(0.25); hxi_moments[1]->SetMaximum(+1.25);
  2556. hxi_moments[2]->SetMinimum(-1.0); hxi_moments[2]->SetMaximum(+0.0);
  2557. hxi_moments[3]->SetMinimum(-0.75); hxi_moments[3]->SetMaximum(+0.25);
  2558. for (int i = 4; i<12; i++){
  2559. hxi_moments[i]->SetMinimum(-0.5);
  2560. hxi_moments[i]->SetMaximum(+0.5);
  2561. }
  2562. for (auto hist: hxi_moments) hist->GetYaxis()->SetTitleOffset(1.4);
  2563. TCanvas* c10 = new TCanvas("c10", "c10", 1600, 1200);
  2564. c10->Divide(4,3);
  2565. plotAngularInOne(c10,1,hxi_moments[0],hxi_ub[0],hxi_hist[0],hxi_ml_hist[0],runMinuit,edges.q2min,edges.q2max,1.5,false);
  2566. plotAngularInOne(c10,2,hxi_moments[1],hxi_ub[1],hxi_hist[1],hxi_ml_hist[1],runMinuit,edges.q2min,edges.q2max,0.75,false);
  2567. plotAngularInOne(c10,3,hxi_moments[2],hxi_ub[2],hxi_hist[2],hxi_ml_hist[2],runMinuit,edges.q2min,edges.q2max,-0.5,false);
  2568. plotAngularInOne(c10,4,hxi_moments[3],hxi_ub[3],hxi_hist[3],hxi_ml_hist[3],runMinuit,edges.q2min,edges.q2max,-0.25,false);
  2569. for (int i = 4; i<12; i++){
  2570. plotAngularInOne(c10,i+1,hxi_moments[i],hxi_ub[i],hxi_hist[i],hxi_ml_hist[i],runMinuit,
  2571. edges.q2min,edges.q2max,0.0,is_param_folded(i,opts));
  2572. }
  2573. if(opts->write_eps)c10->Print((subfolder + "/xis"+appendix+".eps").c_str(),"eps");
  2574. delete c10;
  2575. spdlog::info( "end PLOTS" );
  2576. }//end make plots
  2577. //delete histograms
  2578. for (auto hist: hxi_moments) delete hist;
  2579. for (auto hist: hxi_ml_hist) delete hist;
  2580. for (auto hist: hxi_hist) delete hist;
  2581. for (auto hist: hxi_ub) delete hist;
  2582. }; //end parametrize_eff_phsp_4d()
  2583. double bu2kstarmumu_pdf::get_ang_eff(fcnc::options *opts,
  2584. double q2, double ctl, double ctk, double phi) const{
  2585. npolynom npol(opts);
  2586. assert(coeffs_eff_4d.size() == npol.getSize());
  2587. //Posibly can be faster, but with more memory consumption and unless I calculate this for like a million events it doesn't make a difference. This way the code is readable and usable at many places
  2588. double eff = 0.0;
  2589. for(unsigned int h = 0; h<npol.q2; h++){
  2590. for(unsigned int i = 0; i<npol.ctl; i++){
  2591. for(unsigned int j = 0; j<npol.ctk; j++){
  2592. for(unsigned int k = 0; k<npol.phi; k++){
  2593. eff += coeffs_eff_4d[npol.get_bin_in4D(h,i,j,k)]
  2594. *pow(q2,h)*pow(ctl,i)*pow(ctk,j)*pow(phi,k);
  2595. }
  2596. }
  2597. }
  2598. }
  2599. //spdlog::trace("ctl={0:f}\t ctk={1:f}\t phi={2:f}\t eff={3:f}", ctl, ctk, phi, eff);
  2600. return eff;
  2601. }
  2602. double bu2kstarmumu_pdf::get_ang_eff(fcnc::options *opts, fcnc::event evt, bool fa) const{
  2603. //fa=true meansusing the evt. _fa values
  2604. if (fa) return get_ang_eff(opts, evt.q2, evt.costhetal_fa, evt.costhetak_fa, evt.phi_fa);
  2605. else return get_ang_eff(opts, evt.q2, evt.costhetal, evt.costhetak, evt.phi);
  2606. }
  2607. void bu2kstarmumu_pdf::eff_fcn(Int_t &npar, Double_t *grad, Double_t &lh, Double_t *params, Int_t iflag)
  2608. {
  2609. //TODO full angular fit
  2610. npolynom npol(current_pdf->opts);
  2611. std::vector<double> chebyshev_costhetal(npol.ctl, 0.0);
  2612. std::vector<double> chebyshev_costhetak(npol.ctk, 0.0);
  2613. std::vector<double> chebyshev_phi(npol.phi, 0.0);
  2614. for (unsigned int j = 0; j<npol.ctl; j++) chebyshev_costhetal.at(j) = params[j];
  2615. for (unsigned int j = 0; j<npol.ctk; j++) chebyshev_costhetak.at(j) = params[npol.ctl+j];
  2616. for (unsigned int j = 0; j<npol.phi; j++) chebyshev_phi.at(j) = params[npol.ctl+npol.ctk+j];
  2617. std::vector<double> coeffs_costhetal(npol.ctl, 0.0);
  2618. std::vector<double> coeffs_costhetak(npol.ctk, 0.0);
  2619. std::vector<double> coeffs_phi(npol.phi, 0.0);
  2620. std::vector<double> temp_ctl(npol.ctl, 0.0);
  2621. std::vector<double> temp_ctk(npol.ctk, 0.0);
  2622. std::vector<double> temp_phi(npol.phi, 0.0);
  2623. chebyshev_to_poly(chebyshev_costhetal, temp_ctl);
  2624. chebyshev_to_poly(chebyshev_costhetak, temp_ctk);
  2625. chebyshev_to_poly(chebyshev_phi, temp_phi);
  2626. for (unsigned int i=0; i<coeffs_costhetak.size(); i++){
  2627. coeffs_costhetak.at(i) = temp_ctk.at(i);
  2628. }
  2629. for (unsigned int i=0; i<coeffs_costhetal.size(); i++){
  2630. coeffs_costhetal.at(i) = temp_ctl.at(i);
  2631. }
  2632. correct_poly(temp_phi, coeffs_phi, -TMath::Pi(), +TMath::Pi());
  2633. double cijk = 0.0;
  2634. double f1 = 0.0, f2 = 0.0, f3 = 0.0, f4 = 0.0, f5 = 0.0,
  2635. f6 = 0.0, f7 = 0.0, f8 = 0.0, f9 = 0.0, f10 = 0.0, f11 = 0.0, f12 = 0.0;
  2636. const double pi = MY_PI;
  2637. double c = C_PWAVE;
  2638. if(current_pdf->opts->full_angular)c *= 2.0; //folding in phi
  2639. if (current_pdf->opts->full_angular)
  2640. {
  2641. for (unsigned int i = 0; i<npol.ctl; i++)
  2642. for (unsigned int j = 0; j<npol.ctk; j++)
  2643. for (unsigned int k = 0; k<npol.phi; k++)
  2644. {
  2645. cijk = c*coeffs_costhetal.at(i)*coeffs_costhetak.at(j)*coeffs_phi.at(k);
  2646. f1 += cijk * (pow(-1,i)/(i+1.0)+1.0/(i+1.0))*(2.0*pow(-1,j)/(j*j+4.0*j+3.0)+2.0/(j*j+4.0*j+3.0))*(pow(-1,k)*pow(pi,k+1)/(k+1.0)+pow(pi,k+1)/(k+1.0));
  2647. f2 += cijk * (pow(-1,i)/(i+1.0)+1.0/(i+1.0))*(pow(-1,j)/(j+3.0)+1.0/(j+3.0))*(pow(-1,k)*pow(pi,k+1)/(k+1.0)+pow(pi,k+1)/(k+1.0));
  2648. f3 += cijk * (((i-1.0)*pow(-1,i)/(i*i+4.0*i+3.0)+(i-1.0)/(i*i+4.0*i+3.0))*(2.0*pow(-1,j)/(j*j+4.0*j+3.0)+2.0/(j*j+4.0*j+3.0))*(pow(-1,k)*pow(pi,k+1)/(k+1.0)+pow(pi,k+1)/(k+1.0)));
  2649. f4 += cijk * (((i-1.0)*pow(-1,i)/(i*i+4.0*i+3.0)+(i-1.0)/(i*i+4.0*i+3.0))*(pow(-1,j)/(j+3.0)+1/(j+3.0))*(pow(-1,k)*pow(pi,k+1.0)/(k+1.0)+pow(pi,k+1)/(k+1.0)));
  2650. f5 += cijk * (2.0*pow(-1,i)/(i*i+4.0*i+3.0)+2.0/(i*i+4.0*i+3.0))*(2.0*pow(-1,j)/(j*j+4.0*j+3.0)+2.0/(j*j+4.0*j+3.0))
  2651. *(integral_x_to_n_times_cos_2x(pi,k)-integral_x_to_n_times_cos_2x(-pi,k));
  2652. f6 += cijk * 4.0
  2653. *(integral_x_to_n_times_sqrt_1_minus_x2(1,j+1)-integral_x_to_n_times_sqrt_1_minus_x2(-1,j+1))
  2654. *(integral_x_to_n_times_sqrt_1_minus_x2(1,i+1)-integral_x_to_n_times_sqrt_1_minus_x2(-1,i+1))
  2655. *(integral_x_to_n_times_cos_x(pi,k)-integral_x_to_n_times_cos_x(-pi,k));
  2656. f7 += cijk * 2.0
  2657. *(integral_x_to_n_times_sqrt_1_minus_x2(1,j+1)-integral_x_to_n_times_sqrt_1_minus_x2(-1,j+1))
  2658. *(integral_x_to_n_times_sqrt_1_minus_x2(1,i)-integral_x_to_n_times_sqrt_1_minus_x2(-1,i))
  2659. *(integral_x_to_n_times_cos_x(pi,k)-integral_x_to_n_times_cos_x(-pi,k));
  2660. f8 += cijk * (1.0/(i+2.0)-pow(-1,i)/(i+2.0))*(2.0*pow(-1,j)/(j*j+4.0*j+3.0)+2.0/(j*j+4.0*j+3.0))*(pow(-1,k)*pow(pi,k+1)/(k+1.0)+pow(pi,k+1)/(k+1.0));
  2661. f9 += cijk * (1.0/(i+2.0)-pow(-1,i)/(i+2.0))*(pow(-1,j)/(j+3.0)+1.0/(j+3.0))*(pow(-1,k)*pow(pi,k+1)/(k+1.0)+pow(pi,k+1)/(k+1.0));
  2662. f10 += cijk * 2.0
  2663. *(integral_x_to_n_times_sqrt_1_minus_x2(1,j+1)-integral_x_to_n_times_sqrt_1_minus_x2(-1,j+1))
  2664. *(integral_x_to_n_times_sqrt_1_minus_x2(1,i)-integral_x_to_n_times_sqrt_1_minus_x2(-1,i))
  2665. *(integral_x_to_n_times_sin_x(pi,k)-integral_x_to_n_times_sin_x(-pi,k));
  2666. f11 += cijk * 4.0
  2667. *(integral_x_to_n_times_sqrt_1_minus_x2(1,j+1)-integral_x_to_n_times_sqrt_1_minus_x2(-1,j+1))
  2668. *(integral_x_to_n_times_sqrt_1_minus_x2(1,i+1)-integral_x_to_n_times_sqrt_1_minus_x2(-1,i+1))
  2669. *(integral_x_to_n_times_sin_x(pi,k)-integral_x_to_n_times_sin_x(-pi,k));
  2670. f12 += cijk * (2.0*pow(-1,i)/(i*i+4.0*i+3.0)+2.0/(i*i+4.0*i+3.0))*(2.0*pow(-1,j)/(j*j+4.0*j+3.0)+2.0/(j*j+4.0*j+3.0))
  2671. *(integral_x_to_n_times_sin_2x(pi,k)-integral_x_to_n_times_sin_2x(-pi,k));
  2672. }
  2673. }
  2674. else
  2675. {
  2676. for (unsigned int i = 0; i<npol.ctl; i++)
  2677. for (unsigned int j = 0; j<npol.ctk; j++)
  2678. for (unsigned int k = 0; k<npol.phi; k++)
  2679. {
  2680. cijk = c * coeffs_costhetal.at(i)*coeffs_costhetak.at(j)*coeffs_phi.at(k);
  2681. /*
  2682. f1 += cijk * 2.0*(2.0*pow(-1,i)/(i*i+4.0*i+3.0)+2.0/(i*i+4.0*i+3.0))*(pow(-1,j)/(j+3.0)+1.0/(j+3.0))*pow(MY_PI,k+1)/(k+1.0);
  2683. f2 += cijk * ((i+2.0)*pow(-1,i)/(i*i+4.0*i+3.0)+(i+2.0)/(i*i+4.0*i+3.0))*(2.0*pow(-1,j)/(j*j+4.0*j+3.0)+2.0/(j*j+4.0*j+3.0))*pow(MY_PI,k+1)/(k+1.0);
  2684. f3 += cijk * (2.0*pow(-1,i)/(i*i+4.0*i+3.0)+2.0/(i*i+4.0*i+3.0))*(2.0*pow(-1,j)/(j*j+4.0*j+3.0)+2.0/(j*j+4.0*j+3.0))
  2685. *(integral_x_to_n_times_cos_2x(MY_PI, k) - integral_x_to_n_times_cos_2x(0.0, k));
  2686. f4 += cijk * 4.0*(1.0/(i+2.0)-pow(-1,i)/(i+2.0))*(2.0*pow(-1,j)/(j*j+4.0*j+3.0)+2.0/(j*j+4.0*j+3.0))*pow(MY_PI,k+1)/(3.0*(k+1.0));
  2687. f5 += cijk * (2.0*pow(-1,i)/(i*i+4.0*i+3.0)+2.0/(i*i+4.0*i+3.0))*(2.0*pow(-1,j)/(j*j+4.0*j+3.0)+2.0/(j*j+4.0*j+3.0))
  2688. *(integral_x_to_n_times_sin_2x(MY_PI, k) - integral_x_to_n_times_sin_2x(0.0, k));
  2689. */
  2690. //TODO add f1 to f12 for new folding!
  2691. spdlog::error("Function 'eff_fcn' not yet implemented for folding");
  2692. assert(0);
  2693. }
  2694. }
  2695. //calculate eps()
  2696. std::vector<double> ch_costhetal;
  2697. std::vector<double> ch_costhetak;
  2698. std::vector<double> ch_phi;
  2699. double lh_costhetal = 0.0;
  2700. double lh_costhetak = 0.0;
  2701. double lh_phi = 0.0;
  2702. unsigned int nsize = current_pdf->eff_events.size();
  2703. for (unsigned int i=0; i<nsize; i++)
  2704. {
  2705. event meas = current_pdf->eff_events.at(i);
  2706. chebyshev(meas.costhetal, npol.ctl, ch_costhetal);
  2707. chebyshev(meas.costhetak, npol.ctk, ch_costhetak);
  2708. if (current_pdf->opts->full_angular)
  2709. chebyshev(meas.phi/MY_PI, npol.phi, ch_phi);
  2710. else
  2711. chebyshev(2.0*meas.phi/MY_PI-1.0, npol.phi, ch_phi);
  2712. //double result = 0.0;
  2713. double result_costhetal = 0.0;
  2714. for (unsigned int j = 0; j<npol.ctl; j++){
  2715. result_costhetal += params[j]*ch_costhetal.at(j);// /norm_costhetal;
  2716. }
  2717. lh_costhetal += -2.0*TMath::Log(result_costhetal);
  2718. double result_costhetak = 0.0;
  2719. for (unsigned int j = 0; j<npol.ctk; j++){
  2720. result_costhetak += params[npol.ctl+j]*ch_costhetak.at(j);// /norm_costhetak;
  2721. }
  2722. lh_costhetak += -2.0*TMath::Log(result_costhetak);
  2723. double result_phi = 0.0;
  2724. for (unsigned int j = 0; j<npol.phi; j++){
  2725. result_phi += params[npol.ctl+npol.ctk+j]*ch_phi.at(j);// /norm_phi;
  2726. }
  2727. lh_phi += -2.0*TMath::Log(result_phi);
  2728. }
  2729. //multiply with the pdf
  2730. const double j1s = current_pdf->eff_params->J1s();
  2731. const double j1c = current_pdf->eff_params->J1c();
  2732. const double j2s = current_pdf->eff_params->J2s();
  2733. const double j2c = current_pdf->eff_params->J2c();
  2734. const double j3 = current_pdf->eff_params->J3();
  2735. const double j4 = current_pdf->eff_params->J4();
  2736. const double j5 = current_pdf->eff_params->J5();
  2737. const double j6s = current_pdf->eff_params->J6s();
  2738. const double j6c = current_pdf->eff_params->J6c();
  2739. const double j7 = current_pdf->eff_params->J7();
  2740. const double j8 = current_pdf->eff_params->J8();
  2741. const double j9 = current_pdf->eff_params->J9();
  2742. double sig_norm = 0.0;
  2743. sig_norm = (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4
  2744. + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9);
  2745. double lh_sig = 0.0, prob = 0.0;
  2746. for (unsigned int i=0; i<nsize; i++)
  2747. {
  2748. event meas = current_pdf->eff_events.at(i);
  2749. if (current_pdf->opts->full_angular)
  2750. {
  2751. current_pdf->fj(meas.costhetal, meas.costhetak, meas.phi,
  2752. f1, f2, f3, f4, f5, f6,
  2753. f7, f8, f9, f10, f11, f12);
  2754. prob = (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4
  2755. + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9)/sig_norm;
  2756. }
  2757. else
  2758. {
  2759. current_pdf->folded_fj(meas.costhetal, meas.costhetak, meas.phi, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12);
  2760. /*
  2761. prob = 9.0/16.0/MY_PI * (fl * f1
  2762. +ft * f2
  2763. +s3 * f3
  2764. +afb * f4
  2765. +aim * f5
  2766. )/sig_norm;
  2767. */
  2768. prob = (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4
  2769. + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9)/sig_norm;
  2770. }
  2771. lh_sig += -2.0*TMath::Log(prob);
  2772. }
  2773. //is the integral correct here?
  2774. //need to do a nice integration over pdf_sig(costhetal,costhetak,phi)*eps(costhetal,costhetak,phi)
  2775. lh = lh_sig + lh_costhetal + lh_costhetak + lh_phi;
  2776. };
  2777. //this does not assume factorisation of the three dependencies, but assumes phsp MC in 3D
  2778. void bu2kstarmumu_pdf::eff_fcn_phsp(Int_t &npar, Double_t *grad, Double_t &lh, Double_t *params, Int_t iflag)
  2779. {
  2780. //TODO
  2781. unsigned int ncosthetal = 5;
  2782. unsigned int ncosthetak = 5;
  2783. unsigned int nphi = 5;
  2784. //make sure we are doing full angular acceptance, no phi folding
  2785. assert(current_pdf->opts->full_angular);
  2786. //need to account for the norm given the current parameters
  2787. double norm = 0.0;
  2788. for (unsigned int i = 0; i<ncosthetal; i++)
  2789. for (unsigned int j = 0; j<ncosthetak; j++)
  2790. for (unsigned int k = 0; k<nphi; k++)
  2791. {
  2792. double cijk = params[ncosthetak*nphi*i+nphi*j+k];
  2793. norm += cijk
  2794. *(integral_chebyshev(+1.0, i)-integral_chebyshev(-1.0, i)) //TODO: check the -1,+1
  2795. *(integral_chebyshev(+1.0, j)-integral_chebyshev(-1.0, j))
  2796. *(integral_chebyshev(+1.0, k)-integral_chebyshev(-1.0, k));//there surely is a more efficient way
  2797. }
  2798. //this gives Sum_events Log(eps(event))
  2799. lh = 0.0;
  2800. unsigned int nsize = current_pdf->eff_events.size();
  2801. //loop over all events
  2802. for (unsigned int l=0; l<nsize; l++) {
  2803. const event& meas = current_pdf->eff_events.at(l);
  2804. std::vector<double> ch_costhetal;
  2805. std::vector<double> ch_costhetak;
  2806. std::vector<double> ch_phi;
  2807. chebyshev(meas.costhetal, ncosthetal, ch_costhetal);
  2808. chebyshev(meas.costhetak, ncosthetak, ch_costhetak);
  2809. chebyshev(meas.phi/MY_PI, nphi, ch_phi);
  2810. double result = 0.0;
  2811. for (unsigned int i = 0; i<ncosthetal; i++)
  2812. for (unsigned int j = 0; j<ncosthetak; j++)
  2813. for (unsigned int k = 0; k<nphi; k++)
  2814. {
  2815. double cijk = params[ncosthetak*nphi*i+nphi*j+k];
  2816. result += cijk*ch_costhetal.at(i)*ch_costhetak.at(j)*ch_phi.at(k);
  2817. }
  2818. if (result > 0.0 && !std::isnan(result) && !std::isinf(result))
  2819. lh += -2.0*TMath::Log(result/norm) - (-2.0*TMath::Log(1.0/8.0));//can subtract
  2820. else
  2821. lh += (-100.0*2.0*TMath::Log(1.0/8.0));
  2822. }
  2823. spdlog::debug( "eff_fcn_phsp lh {0:f}\t npar {1:d}\tiflag {2:d}\tnorm {3:f}", lh, npar, iflag, norm);
  2824. };
  2825. void bu2kstarmumu_pdf::eff_fcn_phsp_4d(Int_t &npar, Double_t *grad, Double_t &lh, Double_t *params, Int_t iflag)
  2826. {
  2827. npolynom npol(current_pdf->opts);
  2828. double q2min = current_pdf->opts->TheQ2binsmin.front(), q2max = current_pdf->opts->TheQ2binsmax.back();
  2829. double ctkmin = current_pdf->opts->ctk_min, ctkmax = current_pdf->opts->ctk_max;
  2830. double ctlmin = current_pdf->opts->ctl_min, ctlmax = current_pdf->opts->ctl_max;
  2831. double phimin = current_pdf->opts->phi_min, phimax = current_pdf->opts->phi_max;
  2832. spdlog::warn("The TMinuit version was not yet tested for folded analysis!");
  2833. assert(current_pdf->opts->full_angular);
  2834. //need to account for the norm given the current parameters
  2835. double norm = 0.0;
  2836. for (unsigned int h = 0; h<npol.q2; h++){
  2837. for (unsigned int i = 0; i<npol.ctl; i++){
  2838. for (unsigned int j = 0; j<npol.ctk; j++){
  2839. for (unsigned int k = 0; k<npol.phi; k++){
  2840. double chijk = params[npol.get_bin_in4D(h,i,j,k)];
  2841. if (chijk == 0.0) continue;
  2842. norm += chijk
  2843. *(integral_chebyshev(+1.0, h)-integral_chebyshev(-1.0, h))
  2844. *(integral_chebyshev(+1.0, i)-integral_chebyshev(-1.0, i))
  2845. *(integral_chebyshev(+1.0, j)-integral_chebyshev(-1.0, j))
  2846. *(integral_chebyshev(+1.0, k)-integral_chebyshev(-1.0, k));//there surely is a more efficient way
  2847. }
  2848. }
  2849. }
  2850. }
  2851. //this gives Sum_events Log(eps(event))
  2852. lh = 0.0;
  2853. unsigned int nsize = current_pdf->eff_events.size();
  2854. //loop over all events
  2855. for (unsigned int l=0; l<nsize; l++){
  2856. const event& meas = current_pdf->eff_events.at(l);
  2857. if (meas.q2 < q2min || meas.q2 > q2max) continue;
  2858. std::vector<double> ch_q2;
  2859. std::vector<double> ch_costhetal;
  2860. std::vector<double> ch_costhetak;
  2861. std::vector<double> ch_phi;
  2862. chebyshev(2.0*(meas.q2 - q2min ) / (q2max - q2min ) - 1.0, npol.q2, ch_q2);
  2863. chebyshev(2.0*(meas.costhetal - ctlmin) / (ctlmax - ctlmin) - 1.0, npol.ctl, ch_costhetal);
  2864. chebyshev(2.0*(meas.costhetak - ctkmin) / (ctkmax - ctkmin) - 1.0, npol.ctk, ch_costhetak);
  2865. chebyshev(2.0*(meas.phi - phimin) / (phimax - phimin) - 1.0, npol.phi, ch_phi);
  2866. /*
  2867. chebyshev(meas.costhetal, ncosthetal, ch_costhetal);
  2868. chebyshev(meas.costhetak, ncosthetak, ch_costhetak);
  2869. chebyshev(meas.phi/pi, nphi, ch_phi);
  2870. */
  2871. double result = 0.0;
  2872. for (unsigned int h = 0; h<npol.q2; h++)
  2873. for (unsigned int i = 0; i<npol.ctl; i++)
  2874. for (unsigned int j = 0; j<npol.ctk; j++)
  2875. for (unsigned int k = 0; k<npol.q2; k++)
  2876. {
  2877. double chijk = params[npol.get_bin_in4D(h,i,j,k)];
  2878. result += chijk*ch_q2.at(h)*ch_costhetal.at(i)*ch_costhetak.at(j)*ch_phi.at(k);
  2879. }
  2880. if (result > 0.0 && !std::isnan(result) && !std::isinf(result)){
  2881. lh += -2.0*meas.weight*TMath::Log(result/norm) - (-2.0*TMath::Log(1.0/16.0));
  2882. }
  2883. else{
  2884. lh += (-100.0*2.0*TMath::Log(1.0/8.0));
  2885. }
  2886. }
  2887. spdlog::debug( "eff_fcn_phsp_4d lh {0:f}\t npar {1:d}\tiflag {2:d}\tnorm {3:f}", lh, npar, iflag, norm);
  2888. };
  2889. void bu2kstarmumu_pdf::update_cached_normalization(const bu2kstarmumu_parameters* params)
  2890. {
  2891. spdlog::trace("updating cached normalisation");
  2892. //this caches the overall normalisation for both signal and background
  2893. double q2 = params->eff_q2();
  2894. //swave norm
  2895. if (opts->use_mkpi || opts->fit_mkpi){
  2896. double mkpi_min = opts->mkpi_min/1.0e+3;
  2897. double mkpi_max = opts->mkpi_max/1.0e+3;
  2898. //double q2 = params->eff_q2();
  2899. double asphase = params->asphase();
  2900. double a = params->a();
  2901. double r = params->r();
  2902. double gammakstar = params->gammakstar();
  2903. double mkstar = params->mkstar();
  2904. double gammakstarplus = params->gammakstarplus();
  2905. double mkstarplus = params->mkstarplus();
  2906. double R = params->R();
  2907. double gammaf800 = params->gammaf800();
  2908. double mf800 = params->mf800();
  2909. double f800mag = params->f800mag();
  2910. double f800phase = params->f800phase();
  2911. //integrate over mkpi2
  2912. const double mk = PDGMASS_KST_KAON/1.0e+3;
  2913. const double mpi = PDGMASS_KST_PION/1.0e+3;
  2914. const double mb = PDGMASS_B/1.0e+3;
  2915. const double from = opts->mkpi_full_range_norm ? (mk+mpi) : mkpi_min;
  2916. const double to = opts->mkpi_full_range_norm ? mb : mkpi_max;
  2917. std::complex<double> mkpi_swavepwave_norm;
  2918. if (opts->simple_mkpi){
  2919. mkpi_swave_2_norm = int_mkpi_simple_kstarzero_amp_squared(from, to, q2,
  2920. f800mag, f800phase, gammaf800, mf800, gammakstarplus, mkstarplus);
  2921. mkpi_pwave_2_norm = int_mkpi_simple_bw_kstar_amp_squared(from, to, q2, gammakstar, mkstar);
  2922. mkpi_swavepwave_norm = int_mkpi_simple_bw_kstar_amp_bar_kstarzero_amp(from, to, q2,
  2923. gammakstar, mkstar, asphase,
  2924. f800mag, f800phase, gammaf800, mf800, gammakstarplus, mkstarplus);
  2925. mkpi_re_swavepwave_norm = mkpi_swavepwave_norm.real();
  2926. mkpi_im_swavepwave_norm = mkpi_swavepwave_norm.imag();
  2927. }
  2928. else if (opts->isobar){
  2929. mkpi_swave_2_norm = int_mkpi_kstarzero_isobar_amp_squared(from, to, q2,
  2930. f800mag, f800phase, gammaf800, mf800, gammakstarplus, mkstarplus, R);
  2931. mkpi_pwave_2_norm = int_mkpi_bw_kstar_amp_squared(from, to, q2, gammakstar, mkstar, R);
  2932. mkpi_swavepwave_norm = int_mkpi_bw_kstar_amp_bar_kstarzero_isobar_amp(from, to, q2,
  2933. gammakstar, mkstar, asphase,
  2934. f800mag, f800phase, gammaf800, mf800, gammakstarplus, mkstarplus, R);
  2935. mkpi_re_swavepwave_norm = mkpi_swavepwave_norm.real();
  2936. mkpi_im_swavepwave_norm = mkpi_swavepwave_norm.imag();
  2937. }
  2938. else{//nominal lass
  2939. mkpi_swave_2_norm = int_mkpi_kstarzero_lass_amp_squared(from, to, q2, asphase, a, r, gammakstarplus, mkstarplus, R);
  2940. mkpi_pwave_2_norm = int_mkpi_bw_kstar_amp_squared(from, to, q2, gammakstar, mkstar, R);
  2941. mkpi_swavepwave_norm = int_mkpi_bw_kstar_amp_bar_kstarzero_lass_amp(from, to, q2,
  2942. gammakstar, mkstar,
  2943. asphase, a, r, gammakstarplus, mkstarplus, R);
  2944. mkpi_re_swavepwave_norm = mkpi_swavepwave_norm.real();
  2945. mkpi_im_swavepwave_norm = mkpi_swavepwave_norm.imag();
  2946. }
  2947. if (opts->use_p2){
  2948. //mkpi_bkg(
  2949. std::vector<double> ch_p2(5, 0.0);
  2950. ch_p2.at(0) = params->cbkgp20();
  2951. ch_p2.at(1) = params->cbkgp21();
  2952. ch_p2.at(2) = params->cbkgp22();
  2953. ch_p2.at(3) = params->cbkgp23();
  2954. ch_p2.at(4) = params->cbkgp24();
  2955. std::vector<double> poly_p2(ch_p2.size(), 0.0);
  2956. chebyshev_to_poly(ch_p2, poly_p2);
  2957. std::vector<double> poly_corr_p2(ch_p2.size(), 0.0);
  2958. correct_poly(poly_p2, poly_corr_p2, mkpi_min*mkpi_min, mkpi_max*mkpi_max);
  2959. mkpi_bkg_norm = 0.0;
  2960. for (unsigned int i=0; i<ch_p2.size(); i++)
  2961. mkpi_bkg_norm += poly_corr_p2.at(i)*(pow(mkpi_max*mkpi_max,i+1)-pow(mkpi_min*mkpi_min,i+1))/(i+1.0);
  2962. }
  2963. else{
  2964. std::vector<double> ch_mkpi(5, 0.0);
  2965. ch_mkpi.at(0) = params->cbkgmkpi0();
  2966. ch_mkpi.at(1) = params->cbkgmkpi1();
  2967. ch_mkpi.at(2) = params->cbkgmkpi2();
  2968. ch_mkpi.at(3) = params->cbkgmkpi3();
  2969. ch_mkpi.at(4) = params->cbkgmkpi4();
  2970. std::vector<double> poly_mkpi(ch_mkpi.size(), 0.0);
  2971. chebyshev_to_poly(ch_mkpi, poly_mkpi);
  2972. std::vector<double> poly_corr_mkpi(ch_mkpi.size(), 0.0);
  2973. correct_poly(poly_mkpi, poly_corr_mkpi, mkpi_min, mkpi_max);
  2974. mkpi_bkg_norm = 0.0;
  2975. if (opts->mkpi_threshold){
  2976. mkpi_bkg_norm = fcnc::int_threshold(mkpi_min, mkpi_max, 0.633, params->nthreshold());
  2977. }
  2978. else{
  2979. for(unsigned int i=0; i<poly_mkpi.size(); i++)
  2980. mkpi_bkg_norm += poly_corr_mkpi.at(i)*(pow(mkpi_max,i+1)-pow(mkpi_min,i+1))/(i+1.0);
  2981. }
  2982. }
  2983. }
  2984. double f1=0.0, f2=0.0, f3=0.0, f4=0.0, f5=0.0, f6=0.0,
  2985. f7=0.0, f8=0.0, f9=0.0, f10=0.0, f11=0.0, f12=0.0;
  2986. double fs1=0.0, fs2=0.0, fs3=0.0, fs4=0.0, fs5=0.0, fs6=0.0;
  2987. const double j1s = params->J1s();
  2988. const double j1c = params->J1c();
  2989. const double j2s = params->J2s();
  2990. const double j2c = params->J2c();
  2991. const double j3 = params->J3();
  2992. const double j4 = params->J4();
  2993. const double j5 = params->J5();
  2994. const double j6s = params->J6s();
  2995. const double j6c = params->J6c();
  2996. const double j7 = params->J7();
  2997. const double j8 = params->J8();
  2998. const double j9 = params->J9();
  2999. const double fs = params->FS();
  3000. const double js1 = params->SS1();
  3001. const double js2 = params->SS2();
  3002. const double js3 = params->SS3();
  3003. const double js4 = params->SS4();
  3004. const double js5 = params->SS5();
  3005. if(spdlog_trace()){ //print out the integrated angular moments. with and without weights, as well as their ratios
  3006. load_coeffs_eff_phsp_4d();
  3007. integrated_fj_chebyshev(f1, f2, f3, f4, f5, f6,
  3008. f7, f8, f9, f10, f11, f12, q2);
  3009. double pwave_weighted = (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4
  3010. + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9);
  3011. integrated_fj_noacc(f1, f2, f3, f4, f5, f6,
  3012. f7, f8, f9, f10, f11, f12);
  3013. double pwave_noweights = (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4
  3014. + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9);
  3015. swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  3016. swave_integrated_fj_noacc(fs1, fs2, fs3, fs4, fs5, fs6);
  3017. spdlog::trace("Integrated P-wave:");
  3018. spdlog::trace("P-wave no weights: {0:0.5f}",pwave_noweights);
  3019. spdlog::trace("P-wave weighted: {0:0.5f}",pwave_weighted);
  3020. spdlog::trace("P-wave ratio: {0:0.5f}\n",pwave_weighted / pwave_noweights);
  3021. if (opts->swave){
  3022. double swave_noweights = (fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  3023. double swave_weighted = (fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  3024. spdlog::trace("Integrated S-wave:");
  3025. spdlog::trace("S-wave weighted: {0:0.5f}{0:0.5f}",swave_weighted);
  3026. spdlog::trace("S-wave no weights: {0:0.5f}",swave_noweights);
  3027. spdlog::trace("S-wave ratio: {0:0.5f}\n",swave_weighted / swave_noweights);
  3028. spdlog::trace("Double ratio (s/p):{0:0.5f}",(swave_weighted / swave_noweights) / (pwave_weighted / pwave_noweights));
  3029. }
  3030. //assert(0);
  3031. }
  3032. if(opts->full_angular){
  3033. if(!opts->cache_fis){
  3034. if(opts->use_angular_acc){
  3035. integrated_fj_chebyshev(f1, f2, f3, f4, f5, f6,
  3036. f7, f8, f9, f10, f11, f12, q2);
  3037. }
  3038. else{//this is also what the weighted fit uses!
  3039. integrated_fj_noacc(f1, f2, f3, f4, f5, f6,
  3040. f7, f8, f9, f10, f11, f12);
  3041. }
  3042. fbuffer_f1 = f1;
  3043. fbuffer_f2 = f2;
  3044. fbuffer_f3 = f3;
  3045. fbuffer_f4 = f4;
  3046. fbuffer_f5 = f5;
  3047. fbuffer_f6 = f6;
  3048. fbuffer_f7 = f7;
  3049. fbuffer_f8 = f8;
  3050. fbuffer_f9 = f9;
  3051. fbuffer_f10 = f10;
  3052. fbuffer_f11 = f11;
  3053. fbuffer_f12 = f12;
  3054. }
  3055. else{
  3056. f1 = fbuffer_f1;
  3057. f2 = fbuffer_f2;
  3058. f3 = fbuffer_f3;
  3059. f4 = fbuffer_f4;
  3060. f5 = fbuffer_f5;
  3061. f6 = fbuffer_f6;
  3062. f7 = fbuffer_f7;
  3063. f8 = fbuffer_f8;
  3064. f9 = fbuffer_f9;
  3065. f10 = fbuffer_f10;
  3066. f11 = fbuffer_f11;
  3067. f12 = fbuffer_f12;
  3068. }
  3069. fnorm_sig = (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4
  3070. + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9);
  3071. if (opts->fit_asymmetries){
  3072. fnorm_sig = (f1*j1s + f2*j1c + f3*j2s + f4*j2c);
  3073. }
  3074. bool swave = opts->swave;
  3075. if (swave){
  3076. if (!opts->cache_fis){
  3077. if (opts->use_angular_acc){
  3078. swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  3079. }
  3080. else{//weighted fit and fit without acceptance
  3081. swave_integrated_fj_noacc(fs1, fs2, fs3, fs4, fs5, fs6);
  3082. }
  3083. fbuffer_fs1 = fs1;
  3084. fbuffer_fs2 = fs2;
  3085. fbuffer_fs3 = fs3;
  3086. fbuffer_fs4 = fs4;
  3087. fbuffer_fs5 = fs5;
  3088. fbuffer_fs6 = fs6;
  3089. }
  3090. else{
  3091. fs1 = fbuffer_fs1;
  3092. fs2 = fbuffer_fs2;
  3093. fs3 = fbuffer_fs3;
  3094. fs4 = fbuffer_fs4;
  3095. fs5 = fbuffer_fs5;
  3096. fs6 = fbuffer_fs6;
  3097. }
  3098. fnorm_sig = (1.0-fs) * (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4 + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9)
  3099. + (fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  3100. if (opts->fit_asymmetries){
  3101. fnorm_sig = (1.0-fs)*(f1*j1s + f2*j1c + f3*j2s + f4*j2c)
  3102. + (fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  3103. }
  3104. }
  3105. spdlog::trace("Fnormsig (full_angular) {0:f}",fnorm_sig );
  3106. spdlog::trace("Normalization integrals P-wave");
  3107. spdlog::trace("\tj1s {0:0.4f}",f1/fnorm_sig);
  3108. spdlog::trace("\tj1c {0:0.4f}",f2/fnorm_sig);
  3109. spdlog::trace("\tj2s {0:0.4f}",f3/fnorm_sig);
  3110. spdlog::trace("\tj2c {0:0.4f}",f4/fnorm_sig);
  3111. spdlog::trace("\tj3 {0:0.4f}",f5/fnorm_sig);
  3112. spdlog::trace("\tj4 {0:0.4f}",f6/fnorm_sig);
  3113. spdlog::trace("\tj5 {0:0.4f}",f7/fnorm_sig);
  3114. spdlog::trace("\tj6s {0:0.4f}",f8/fnorm_sig);
  3115. spdlog::trace("\tj6c {0:0.4f}",f9/fnorm_sig);
  3116. spdlog::trace("\tj7 {0:0.4f}",f10/fnorm_sig);
  3117. spdlog::trace("\tj8 {0:0.4f}",f11/fnorm_sig);
  3118. spdlog::trace("\tj9 {0:0.4f}",f12/fnorm_sig);
  3119. if(opts->swave){
  3120. spdlog::trace("Normalization integrals S-wave");
  3121. spdlog::trace("fs {0:0.4f}",fs1/fnorm_sig);
  3122. spdlog::trace("\tas1 {0:0.4f}",fs2/fnorm_sig);
  3123. spdlog::trace("\tas2 {0:0.4f}",fs3/fnorm_sig);
  3124. spdlog::trace("\tas3 {0:0.4f}",fs4/fnorm_sig);
  3125. spdlog::trace("\tas4 {0:0.4f}",fs5/fnorm_sig);
  3126. spdlog::trace("\tas5 {0:0.4f}",fs6/fnorm_sig);
  3127. }
  3128. spdlog::trace("Angular amplitudes: ");
  3129. spdlog::trace("\tj1s {0:0.4f}",j1s);
  3130. spdlog::trace("\tj1c {0:0.4f}",j1c);
  3131. spdlog::trace("\tj2s {0:0.4f}",j2s);
  3132. spdlog::trace("\tj2c {0:0.4f}",j2c);
  3133. spdlog::trace("\tj3 {0:0.4f}",j3);
  3134. spdlog::trace("\tj4 {0:0.4f}",j4);
  3135. spdlog::trace("\tj5 {0:0.4f}",j5);
  3136. spdlog::trace("\tj6s {0:0.4f}",j6s);
  3137. spdlog::trace("\tj6c {0:0.4f}",j6c);
  3138. spdlog::trace("\tj7 {0:0.4f}",j7);
  3139. spdlog::trace("\tj8 {0:0.4f}",j8);
  3140. spdlog::trace("\tj9 {0:0.4f}",j9);
  3141. }
  3142. else //folded normalization!
  3143. {
  3144. if (!opts->cache_fis) {
  3145. if (opts->use_angular_acc){
  3146. folded_integrated_fj_chebyshev(f1, f2, f3, f4, f5, f6,
  3147. f7, f8, f9, f10, f11, f12, q2);
  3148. }
  3149. else{//this is also what the weighted fit uses!
  3150. folded_integrated_fj_noacc(f1, f2, f3, f4, f5, f6,
  3151. f7, f8, f9, f10, f11, f12);
  3152. }
  3153. fbuffer_f1 = f1;
  3154. fbuffer_f2 = f2;
  3155. fbuffer_f3 = f3;
  3156. fbuffer_f4 = f4;
  3157. fbuffer_f5 = f5;
  3158. fbuffer_f6 = f6;
  3159. fbuffer_f7 = f7;
  3160. fbuffer_f8 = f8;
  3161. fbuffer_f9 = f9;
  3162. fbuffer_f10 = f10;
  3163. fbuffer_f11 = f11;
  3164. fbuffer_f12 = f12;
  3165. }
  3166. else{
  3167. f1 = fbuffer_f1;
  3168. f2 = fbuffer_f2;
  3169. f3 = fbuffer_f3;
  3170. f4 = fbuffer_f4;
  3171. f5 = fbuffer_f5;
  3172. f6 = fbuffer_f6;
  3173. f7 = fbuffer_f7;
  3174. f8 = fbuffer_f8;
  3175. f9 = fbuffer_f9;
  3176. f10 = fbuffer_f10;
  3177. f11 = fbuffer_f11;
  3178. f12 = fbuffer_f12;
  3179. }
  3180. fnorm_sig = (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4
  3181. + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9);
  3182. if (opts->fit_asymmetries){
  3183. fnorm_sig = (f1*j1s + f2*j1c + f3*j2s + f4*j2c);
  3184. }
  3185. bool swave = opts->swave;
  3186. if (swave){
  3187. if (!opts->cache_fis) {
  3188. if (opts->use_angular_acc ){
  3189. folded_swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  3190. }
  3191. else{//weighted fit and fit without acceptance
  3192. folded_swave_integrated_fj_noacc(fs1, fs2, fs3, fs4, fs5, fs6);
  3193. }
  3194. fbuffer_fs1 = fs1;
  3195. fbuffer_fs2 = fs2;
  3196. fbuffer_fs3 = fs3;
  3197. fbuffer_fs4 = fs4;
  3198. fbuffer_fs5 = fs5;
  3199. fbuffer_fs6 = fs6;
  3200. }
  3201. else {
  3202. fs1 = fbuffer_fs1;
  3203. fs2 = fbuffer_fs2;
  3204. fs3 = fbuffer_fs3;
  3205. fs4 = fbuffer_fs4;
  3206. fs5 = fbuffer_fs5;
  3207. fs6 = fbuffer_fs6;
  3208. }
  3209. fnorm_sig = (1-fs) * (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4 + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9)
  3210. + (fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  3211. if (opts->fit_asymmetries)
  3212. fnorm_sig = (1-fs)*(f1*j1s + f2*j1c + f3*j2s + f4*j2c)
  3213. +(fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  3214. }
  3215. spdlog::trace("Fnormsig (folding {0:d}) {1:f}", opts->folding, fnorm_sig );
  3216. spdlog::trace("Normalization integrals P-wave");
  3217. spdlog::trace("\tj1s {0:0.4f}",f1/fnorm_sig);
  3218. spdlog::trace("\tj1c {0:0.4f}",f2/fnorm_sig);
  3219. spdlog::trace("\tj2s {0:0.4f}",f3/fnorm_sig);
  3220. spdlog::trace("\tj2c {0:0.4f}",f4/fnorm_sig);
  3221. spdlog::trace("\tj3 {0:0.4f}",f5/fnorm_sig);
  3222. spdlog::trace("\tj4 {0:0.4f}",f6/fnorm_sig);
  3223. spdlog::trace("\tj5 {0:0.4f}",f7/fnorm_sig);
  3224. spdlog::trace("\tj6s {0:0.4f}",f8/fnorm_sig);
  3225. spdlog::trace("\tj6c {0:0.4f}",f9/fnorm_sig);
  3226. spdlog::trace("\tj7 {0:0.4f}",f10/fnorm_sig);
  3227. spdlog::trace("\tj8 {0:0.4f}",f11/fnorm_sig);
  3228. spdlog::trace("\tj9 {0:0.4f}",f12/fnorm_sig);
  3229. if(opts->swave){
  3230. spdlog::trace("Normalization integrals S-wave");
  3231. spdlog::trace("fs {0:0.4f}",fs1/fnorm_sig);
  3232. spdlog::trace("\tas1 {0:0.4f}",fs2/fnorm_sig);
  3233. spdlog::trace("\tas2 {0:0.4f}",fs3/fnorm_sig);
  3234. spdlog::trace("\tas3 {0:0.4f}",fs4/fnorm_sig);
  3235. spdlog::trace("\tas4 {0:0.4f}",fs5/fnorm_sig);
  3236. spdlog::trace("\tas5 {0:0.4f}",fs6/fnorm_sig);
  3237. }
  3238. spdlog::trace("Angular amplitudes: ");
  3239. spdlog::trace("\tj1s {0:0.4f}",j1s);
  3240. spdlog::trace("\tj1c {0:0.4f}",j1c);
  3241. spdlog::trace("\tj2s {0:0.4f}",j2s);
  3242. spdlog::trace("\tj2c {0:0.4f}",j2c);
  3243. spdlog::trace("\tj3 {0:0.4f}",j3);
  3244. spdlog::trace("\tj4 {0:0.4f}",j4);
  3245. spdlog::trace("\tj5 {0:0.4f}",j5);
  3246. spdlog::trace("\tj6s {0:0.4f}",j6s);
  3247. spdlog::trace("\tj6c {0:0.4f}",j6c);
  3248. spdlog::trace("\tj7 {0:0.4f}",j7);
  3249. spdlog::trace("\tj8 {0:0.4f}",j8);
  3250. spdlog::trace("\tj9 {0:0.4f}",j9);
  3251. }
  3252. //bkg norm
  3253. //this is used to convolute the acceptance into the pdf
  3254. if(opts->use_angular_acc && opts->use_weighted_bkg){ //weighted background pdf
  3255. if (opts->full_angular){
  3256. fnorm_bkg = integral_bkg_chebyshev(params, CTL_MIN, CTL_MAX, CTK_MIN, CTK_MAX, PHI_MIN, PHI_MAX, q2);
  3257. }
  3258. else if(opts->fit_full_angular_bkg){
  3259. fnorm_bkg = integral_bkg_chebyshev(params, CTL_MIN, CTL_MAX, opts->ctk_min, opts->ctk_max, PHI_MIN, PHI_MAX, q2); //TODO: check here whether this makes any sense (https://gitlab.cern.ch/LHCb-RD/ewp-Bplus2Kstmumu-AngAna/-/merge_requests/21)
  3260. }
  3261. else{
  3262. fnorm_bkg = integral_bkg_chebyshev(params, opts->ctl_min, opts->ctl_max, opts->ctk_min, opts->ctk_max, opts->phi_min, opts->phi_max, q2);
  3263. }
  3264. }
  3265. else{ //non weighted background pdf
  3266. if (opts->full_angular){
  3267. if (opts->flat_bkg) fnorm_bkg = RANGE_3D();
  3268. else fnorm_bkg = integral_bkg(params, opts->ctl_min, opts->ctl_max,
  3269. opts->ctk_min, opts->ctk_max,
  3270. opts->phi_min, opts->phi_max);
  3271. }
  3272. else{ //folded angles
  3273. if (opts->flat_bkg){
  3274. fnorm_bkg = (opts->ctk_max - opts->ctk_min) * (opts->ctl_max - opts->ctl_min) * (opts->phi_max - opts->phi_min);
  3275. }
  3276. else{
  3277. if(opts->fit_full_angular_bkg){
  3278. fnorm_bkg = integral_bkg(params, CTL_MIN, CTL_MAX, CTK_MIN, CTK_MAX, PHI_MIN, PHI_MAX);
  3279. }
  3280. else{
  3281. fnorm_bkg = integral_bkg(params, opts->ctl_min, opts->ctl_max, opts->ctk_min, opts->ctk_max, opts->phi_min, opts->phi_max);
  3282. }
  3283. }
  3284. }
  3285. }
  3286. }
  3287. void bu2kstarmumu_pdf::update_cached_integrated_fis(const bu2kstarmumu_parameters* params)
  3288. {
  3289. if(opts->cache_fis){
  3290. double q2 = params->eff_q2();
  3291. if(opts->full_angular){
  3292. if(opts->use_angular_acc){
  3293. integrated_fj_chebyshev(fbuffer_f1, fbuffer_f2, fbuffer_f3, fbuffer_f4, fbuffer_f5, fbuffer_f6,
  3294. fbuffer_f7, fbuffer_f8, fbuffer_f9, fbuffer_f10, fbuffer_f11, fbuffer_f12, q2);
  3295. swave_integrated_fj_chebyshev(fbuffer_fs1, fbuffer_fs2, fbuffer_fs3, fbuffer_fs4, fbuffer_fs5, fbuffer_fs6, q2);
  3296. }
  3297. else{//this is also what the weighted fit uses!
  3298. integrated_fj_noacc(fbuffer_f1, fbuffer_f2, fbuffer_f3, fbuffer_f4, fbuffer_f5, fbuffer_f6,
  3299. fbuffer_f7, fbuffer_f8, fbuffer_f9, fbuffer_f10, fbuffer_f11, fbuffer_f12);
  3300. swave_integrated_fj_noacc(fbuffer_fs1, fbuffer_fs2, fbuffer_fs3, fbuffer_fs4, fbuffer_fs5, fbuffer_fs6);
  3301. }
  3302. }
  3303. else{ //folded
  3304. if(opts->use_angular_acc){
  3305. folded_integrated_fj_chebyshev(fbuffer_f1, fbuffer_f2, fbuffer_f3, fbuffer_f4, fbuffer_f5, fbuffer_f6,
  3306. fbuffer_f7, fbuffer_f8, fbuffer_f9, fbuffer_f10, fbuffer_f11, fbuffer_f12, q2);
  3307. folded_swave_integrated_fj_chebyshev(fbuffer_fs1, fbuffer_fs2, fbuffer_fs3, fbuffer_fs4, fbuffer_fs5, fbuffer_fs6, q2);
  3308. }
  3309. else{//this is also what the weighted fit uses!
  3310. folded_integrated_fj_noacc(fbuffer_f1, fbuffer_f2, fbuffer_f3, fbuffer_f4, fbuffer_f5, fbuffer_f6,
  3311. fbuffer_f7, fbuffer_f8, fbuffer_f9, fbuffer_f10, fbuffer_f11, fbuffer_f12);
  3312. folded_swave_integrated_fj_noacc(fbuffer_fs1, fbuffer_fs2, fbuffer_fs3, fbuffer_fs4, fbuffer_fs5, fbuffer_fs6);
  3313. }
  3314. }
  3315. }
  3316. }
  3317. double bu2kstarmumu_pdf::mkpi_pwave_2(const bu2kstarmumu_parameters* params, const event& meas) const
  3318. {
  3319. double mkpi = meas.mkpi/1.0e+3;
  3320. double q2 = params->eff_q2();
  3321. //if (opts->weighted_fit) TODO
  3322. // q2 = meas.q2;
  3323. double gammakstar = params->gammakstar();
  3324. double mkstar = params->mkstar();
  3325. double R = params->R();
  3326. if (opts->simple_mkpi) return mkpi_simple_bw_kstar_amp_squared(mkpi, q2, gammakstar, mkstar);
  3327. else return mkpi_bw_kstar_amp_squared(mkpi, q2, gammakstar, mkstar, R);
  3328. }
  3329. double bu2kstarmumu_pdf::mkpi_swave_2(const bu2kstarmumu_parameters* params, const event& meas) const
  3330. {
  3331. double mkpi = meas.mkpi/1.0e+3;
  3332. double q2 = params->eff_q2();
  3333. //if (opts->weighted_fit) TODO
  3334. // q2 = meas.q2;
  3335. double asphase = params->asphase();
  3336. double a = params->a();
  3337. double r = params->r();
  3338. double R = params->R();
  3339. double gammakstarplus = params->gammakstarplus();
  3340. double mkstarplus = params->mkstarplus();
  3341. double gammaf800 = params->gammaf800();
  3342. double mf800 = params->mf800();
  3343. double f800mag = params->f800mag();
  3344. double f800phase = params->f800phase();
  3345. if (opts->simple_mkpi){
  3346. return mkpi_simple_kstarzero_amp_squared(mkpi, q2,
  3347. f800mag, f800phase, gammaf800, mf800,
  3348. gammakstarplus, mkstarplus);
  3349. }
  3350. else if (opts->isobar){
  3351. return mkpi_kstarzero_isobar_amp_squared(mkpi, q2,
  3352. f800mag, f800phase, gammaf800, mf800,
  3353. gammakstarplus, mkstarplus, R);
  3354. }
  3355. else{//LASS
  3356. return mkpi_kstarzero_lass_amp_squared(mkpi, q2, asphase, a, r, gammakstarplus, mkstarplus, R);
  3357. }
  3358. }
  3359. double bu2kstarmumu_pdf::mkpi_re_swavepwave(const bu2kstarmumu_parameters* params, const event& meas) const
  3360. {
  3361. double mkpi = meas.mkpi/1.0e+3;
  3362. double q2 = params->eff_q2();
  3363. // if (opts->weighted_fit) //TODO
  3364. // q2 = meas.q2;
  3365. double gammakstar = params->gammakstar();
  3366. double mkstar = params->mkstar();
  3367. double asphase = params->asphase();
  3368. double a = params->a();
  3369. double r = params->r();
  3370. double gammakstarplus = params->gammakstarplus();
  3371. double mkstarplus = params->mkstarplus();
  3372. double R = params->R();
  3373. double gammaf800 = params->gammaf800();
  3374. double mf800 = params->mf800();
  3375. double f800mag = params->f800mag();
  3376. double f800phase = params->f800phase();
  3377. std::complex<double> swavepwave;
  3378. if (opts->simple_mkpi){
  3379. swavepwave = mkpi_simple_bw_kstar_amp_bar_kstarzero_amp(mkpi, q2,
  3380. gammakstar, mkstar, asphase,
  3381. f800mag, f800phase, gammaf800, mf800,
  3382. gammakstarplus, mkstarplus);
  3383. }
  3384. else if (opts->isobar){
  3385. swavepwave = mkpi_bw_kstar_amp_bar_kstarzero_isobar_amp(mkpi, q2,
  3386. gammakstar, mkstar, asphase,
  3387. f800mag, f800phase, gammaf800, mf800,
  3388. gammakstarplus, mkstarplus, R);
  3389. }
  3390. else{//LASS
  3391. swavepwave = mkpi_bw_kstar_amp_bar_kstarzero_lass_amp(mkpi, q2, gammakstar, mkstar, asphase,
  3392. a, r, gammakstarplus, mkstarplus, R);
  3393. }
  3394. return swavepwave.real();
  3395. }
  3396. double bu2kstarmumu_pdf::mkpi_im_swavepwave(const bu2kstarmumu_parameters* params, const event& meas) const
  3397. {
  3398. double mkpi = meas.mkpi/1.0e+3;
  3399. double q2 = params->eff_q2();
  3400. //if (opts->weighted_fit) //TODO
  3401. // q2 = meas.q2;
  3402. double gammakstar = params->gammakstar();
  3403. double mkstar = params->mkstar();
  3404. double asphase = params->asphase();
  3405. double a = params->a();
  3406. double r = params->r();
  3407. double gammakstarplus = params->gammakstarplus();
  3408. double mkstarplus = params->mkstarplus();
  3409. double R = params->R();
  3410. double gammaf800 = params->gammaf800();
  3411. double mf800 = params->mf800();
  3412. double f800mag = params->f800mag();
  3413. double f800phase = params->f800phase();
  3414. std::complex<double> swavepwave;
  3415. if (opts->simple_mkpi){
  3416. swavepwave = mkpi_simple_bw_kstar_amp_bar_kstarzero_amp(mkpi, q2,
  3417. gammakstar, mkstar, asphase,
  3418. f800mag, f800phase, gammaf800, mf800,
  3419. gammakstarplus, mkstarplus);
  3420. }
  3421. else if (opts->isobar){
  3422. swavepwave = mkpi_bw_kstar_amp_bar_kstarzero_isobar_amp(mkpi, q2,
  3423. gammakstar, mkstar, asphase,
  3424. f800mag, f800phase, gammaf800, mf800,
  3425. gammakstarplus, mkstarplus, R);
  3426. }
  3427. else{//LASS
  3428. swavepwave = mkpi_bw_kstar_amp_bar_kstarzero_lass_amp(mkpi, q2, gammakstar, mkstar, asphase,
  3429. a, r, gammakstarplus, mkstarplus, R);
  3430. }
  3431. return swavepwave.imag();
  3432. }
  3433. double bu2kstarmumu_pdf::mkpi_bkg(const bu2kstarmumu_parameters* params, const event& meas) const
  3434. {
  3435. double mkpi = meas.mkpi/1.0e+3;
  3436. double mkpi_min = opts->mkpi_min/1.0e+3;
  3437. double mkpi_max = opts->mkpi_max/1.0e+3;
  3438. double probbkg = 0.0;
  3439. if (opts->use_p2) {
  3440. std::vector<double> ch_p2(5, 0.0);
  3441. ch_p2.at(0) = params->cbkgp20();
  3442. ch_p2.at(1) = params->cbkgp21();
  3443. ch_p2.at(2) = params->cbkgp22();
  3444. ch_p2.at(3) = params->cbkgp23();
  3445. ch_p2.at(4) = params->cbkgp24();
  3446. std::vector<double> poly_p2(ch_p2.size(), 0.0);
  3447. chebyshev_to_poly(ch_p2, poly_p2);
  3448. std::vector<double> poly_corr_p2(ch_p2.size(), 0.0);
  3449. correct_poly(poly_p2, poly_corr_p2, mkpi_min*mkpi_min, mkpi_max*mkpi_max);
  3450. for (unsigned int i=0; i<ch_p2.size(); i++)
  3451. probbkg += poly_corr_p2.at(i)*pow(mkpi*mkpi,i);
  3452. }
  3453. else
  3454. {
  3455. std::vector<double> ch_mkpi(5, 0.0);
  3456. ch_mkpi.at(0) = params->cbkgmkpi0();
  3457. ch_mkpi.at(1) = params->cbkgmkpi1();
  3458. ch_mkpi.at(2) = params->cbkgmkpi2();
  3459. ch_mkpi.at(3) = params->cbkgmkpi3();
  3460. ch_mkpi.at(4) = params->cbkgmkpi4();
  3461. std::vector<double> poly_mkpi(ch_mkpi.size(), 0.0);
  3462. chebyshev_to_poly(ch_mkpi, poly_mkpi);
  3463. std::vector<double> poly_corr_mkpi(ch_mkpi.size(), 0.0);
  3464. correct_poly(poly_mkpi, poly_corr_mkpi, mkpi_min, mkpi_max);
  3465. if (opts->mkpi_threshold){
  3466. //threshold(double x, double thr, double n);
  3467. probbkg = fcnc::threshold(mkpi, 0.633, params->nthreshold());
  3468. }
  3469. else{
  3470. for (unsigned int i=0; i<ch_mkpi.size(); i++) probbkg += poly_corr_mkpi.at(i)*pow(mkpi,i);
  3471. }
  3472. }
  3473. return probbkg;
  3474. }
  3475. void bu2kstarmumu_pdf::update_cached_xis(const bu2kstarmumu_parameters* params, std::vector<event>* events)
  3476. {
  3477. spdlog::info("Updating cached xis");
  3478. //this is used if per_event_norm is on
  3479. //it stores the 18 xis for every event
  3480. //otherwise using a different norm per event is computationally not possible
  3481. //double q2 = params->eff_q2();
  3482. assert(opts->use_event_norm);
  3483. /*
  3484. for (unsigned int e=0; e<events->size(); e++)
  3485. {
  3486. if ((e*100) % events->size() == 0)
  3487. std::cout << (e*100)/events->size() << "% " << std::endl;
  3488. event& meas = events->at(e);D
  3489. double q2 = meas.q2;
  3490. double f1=0.0, f2=0.0, f3=0.0, f4=0.0, f5=0.0, f6=0.0,
  3491. f7=0.0, f8=0.0, f9=0.0, f10=0.0, f11=0.0, f12=0.0;
  3492. integrated_fj_chebyshev(f1, f2, f3, f4, f5, f6,
  3493. f7, f8, f9, f10, f11, f12, q2);
  3494. meas.xis[0] = f1;
  3495. meas.xis[1] = f2;
  3496. meas.xis[2] = f3;
  3497. meas.xis[3] = f4;
  3498. meas.xis[4] = f5;
  3499. meas.xis[5] = f6;
  3500. meas.xis[6] = f7;
  3501. meas.xis[7] = f8;
  3502. meas.xis[8] = f9;
  3503. meas.xis[9] = f10;
  3504. meas.xis[10] = f11;
  3505. meas.xis[11] = f12;
  3506. bool swave = opts->swave;
  3507. if (swave)
  3508. {
  3509. double fs1=0.0, fs2=0.0, fs3=0.0, fs4=0.0, fs5=0.0, fs6=0.0;
  3510. swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  3511. meas.xis[12] = fs1;
  3512. meas.xis[13] = fs2;
  3513. meas.xis[14] = fs3;
  3514. meas.xis[15] = fs4;
  3515. meas.xis[16] = fs5;
  3516. meas.xis[17] = fs6;
  3517. }
  3518. }
  3519. */
  3520. /*
  3521. for (unsigned int e=0; e<events->size(); e++)
  3522. {
  3523. event& meas = events->at(e);
  3524. std::cout << meas.xis[0] << " "
  3525. << meas.xis[1] << " "
  3526. << meas.xis[2] << " "
  3527. << meas.xis[3] << " "
  3528. << meas.xis[4] << " "
  3529. << meas.xis[5] << " "
  3530. << meas.xis[6] << " "
  3531. << meas.xis[7] << " "
  3532. << meas.xis[8] << " "
  3533. << meas.xis[9] << " "
  3534. << meas.xis[10] << " "
  3535. << meas.xis[11] << " "
  3536. << meas.xis[12] << " "
  3537. << meas.xis[13] << " "
  3538. << meas.xis[14] << " "
  3539. << meas.xis[15] << " "
  3540. << meas.xis[16] << " "
  3541. << meas.xis[17] << " q2 " << meas.q2 << std::endl;
  3542. }
  3543. */
  3544. //std::cout << std::endl;
  3545. }
  3546. void bu2kstarmumu_pdf::update_cached_normalization(const parameters* params){
  3547. update_cached_normalization(static_cast<const bu2kstarmumu_parameters*>(params));
  3548. }
  3549. void bu2kstarmumu_pdf::update_cached_integrated_fis(const parameters* params){
  3550. update_cached_integrated_fis(static_cast<const bu2kstarmumu_parameters*>(params));
  3551. }
  3552. void bu2kstarmumu_pdf::update_cached_efficiencies(const parameters* params, std::vector<event>* events)
  3553. {
  3554. update_cached_efficiencies(static_cast<const bu2kstarmumu_parameters*>(params), events);
  3555. }
  3556. void bu2kstarmumu_pdf::update_cached_xis(const parameters* params, std::vector<event>* events)
  3557. {
  3558. update_cached_xis(static_cast<const bu2kstarmumu_parameters*>(params), events);
  3559. }
  3560. double bu2kstarmumu_pdf::m_sig_prob(const bu2kstarmumu_parameters* params, const event& meas) const{
  3561. if (opts->only_angles || opts->only_mkpi) return 1.0;
  3562. double mmin=params->m_b.get_min();
  3563. double mmax=params->m_b.get_max();
  3564. if(meas.m > mmax || meas.m < mmin){
  3565. spdlog::error("m(B) outside of allowed range: mmin={0:f}, mmax={1:f} m={2:f}", mmin, mmax, meas.m);
  3566. assert(0);
  3567. }
  3568. double result = 0.0;
  3569. if(opts->crystalball){
  3570. result = params->m_res_1()
  3571. * crystalball(meas.m, params->m_b(), params->m_scale()*params->m_sigma_1(), params->alpha_1(), params->n_1())
  3572. / integrate_crystalball(params->m_b(), params->m_scale()*params->m_sigma_1(), params->alpha_1(), params->n_1(), mmin, mmax);
  3573. if(params->m_res_1() != 1.0)
  3574. result += (1.0-params->m_res_1())
  3575. * crystalball(meas.m, params->m_b(), params->m_scale()*params->m_sigma_2(), params->alpha_2(), params->n_2())
  3576. / integrate_crystalball(params->m_b(), params->m_scale()*params->m_sigma_2(), params->alpha_2(), params->n_2(), mmin, mmax);
  3577. }
  3578. else if(opts->twotailedcrystalball){
  3579. result = twotailedcrystalball(meas.m, params->m_b(), params->m_scale()*params->m_sigma_1(), params->alpha_1(), params->alpha_2(), params->n_1(), params->n_2())
  3580. / integrate_twotailedcrystalball(params->m_b(), params->m_scale()*params->m_sigma_1(), params->alpha_1(), params->alpha_2(), params->n_1(), params->n_2(), mmin, mmax);
  3581. }
  3582. else{
  3583. result = params->m_res_1()
  3584. * normed_gauss(meas.m, params->m_scale()*params->m_sigma_1(), params->m_b(), mmin, mmax);
  3585. if(params->m_res_1() != 1.0)
  3586. result += (1.0-params->m_res_1())
  3587. * normed_gauss(meas.m, params->m_scale()*params->m_sigma_2(), params->m_b(), mmin, mmax);
  3588. }
  3589. return result;
  3590. };
  3591. double bu2kstarmumu_pdf::mkpi_sig_prob(const bu2kstarmumu_parameters* params, const event& meas) const
  3592. {
  3593. if(!opts->fit_mkpi || opts->only_angles || opts->only_Bmass) return 1.0;
  3594. assert(meas.mkpi <= opts->mkpi_max);
  3595. assert(meas.mkpi >= opts->mkpi_min);
  3596. double result = 0.0;
  3597. double prob_mkpi_pwave = mkpi_pwave_2(params, meas);
  3598. double prob_mkpi_swave = mkpi_swave_2(params, meas);
  3599. double prob_mkpi_pwaveswave_re = mkpi_re_swavepwave(params, meas);
  3600. double prob_mkpi_pwaveswave_im = mkpi_im_swavepwave(params, meas);
  3601. double fs = params->FS();
  3602. //only m(B) and m(K*+) fitted
  3603. if(opts->only_mass2DFit){
  3604. if(opts->swave){
  3605. result = (1.0-fs)
  3606. * prob_mkpi_pwave/mkpi_pwave_2_norm
  3607. + fs
  3608. * prob_mkpi_swave/mkpi_swave_2_norm;
  3609. }
  3610. else{
  3611. result = prob_mkpi_pwave/mkpi_pwave_2_norm;
  3612. }
  3613. }//end only m(B) and m(K*+)
  3614. else{//angular dimensions included in the fit
  3615. double q2 = meas.q2;
  3616. //integrated S_i
  3617. double xi1, xi2, xi3, xi4, xi5, xi6, xi7, xi8, xi9, xi10, xi11, xi12;
  3618. if(opts->use_angular_acc) integrated_fj_chebyshev(xi1, xi2, xi3, xi4, xi5, xi6, xi7, xi8, xi9, xi10, xi11, xi12, q2);
  3619. else integrated_fj_noacc(xi1, xi2, xi3, xi4, xi5, xi6, xi7, xi8, xi9, xi10, xi11, xi12);
  3620. //integrated SS_i
  3621. double sxi1, sxi2, sxi3, sxi4, sxi5, sxi6;
  3622. if(opts->use_angular_acc) swave_integrated_fj_chebyshev(sxi1, sxi2, sxi3, sxi4, sxi5, sxi6, q2);
  3623. else swave_integrated_fj_noacc(sxi1, sxi2, sxi3, sxi4, sxi5, sxi6);
  3624. //load values for required parameters:
  3625. const double s1s = params->S1s();
  3626. const double s2s = s1s/3.0;
  3627. const double s1c = 1.0 - 4.0/3.0 * s1s;
  3628. const double s2c = -s1c;
  3629. const double s3 = params->S3();
  3630. const double s4 = params->S4();
  3631. const double s5 = params->S5();
  3632. const double s6s = params->S6s();
  3633. const double s6c = 0.;
  3634. const double s7 = params->S7();
  3635. const double s8 = params->S8();
  3636. const double s9 = params->S9();
  3637. const double ss1 = params->SS1();
  3638. const double ss2 = params->SS2();
  3639. const double ss3 = params->SS3();
  3640. const double ss4 = params->SS4();
  3641. const double ss5 = params->SS5();
  3642. double norm = (1 - fs) * (xi1*s1s + xi2*s1c + xi3*s2s + xi4*s2c + xi5*s3 + xi6*s4
  3643. + xi7*s5 + xi8*s6s + xi9*s6c + xi10*s7 + xi11*s8 + xi12*s9)
  3644. + (sxi1*fs)
  3645. + (sxi2*ss1 + sxi3*ss2 + sxi4*ss3)
  3646. + (sxi5*ss4 + sxi6*ss5);
  3647. double A = (xi1*s1s + xi2*s1c + xi3*s2s + xi4*s2c + xi5*s3 + xi6*s4
  3648. + xi7*s5 + xi8*s6s + xi9*s6c + xi10*s7 + xi11*s8 + xi12*s9)/norm;
  3649. double B = sxi1/norm;
  3650. double C = (sxi2*ss1 + sxi3*ss2 + sxi4*ss3)/norm;
  3651. double D = (sxi5*ss4 + sxi6*ss5)/norm;
  3652. result = (1.0-fs) * A * prob_mkpi_pwave/mkpi_pwave_2_norm
  3653. + fs * B * prob_mkpi_swave/mkpi_swave_2_norm
  3654. + C * prob_mkpi_pwaveswave_re/mkpi_re_swavepwave_norm
  3655. + D * prob_mkpi_pwaveswave_im/mkpi_im_swavepwave_norm;
  3656. }//end of prob with angular parts included
  3657. return result;
  3658. };
  3659. double bu2kstarmumu_pdf::integral_m_sig_prob(const bu2kstarmumu_parameters* params, double ma, double mb) const
  3660. {
  3661. double result = 0.0;
  3662. if (opts->crystalball){
  3663. double mmin=params->m_b.get_min(), mmax=params->m_b.get_max();
  3664. result = params->m_res_1()*integrate_crystalball(params->m_b(), params->m_scale()*params->m_sigma_1(), params->alpha_1(), params->n_1(), ma, mb)
  3665. / integrate_crystalball(params->m_b(), params->m_scale()*params->m_sigma_1(), params->alpha_1(), params->n_1(), mmin, mmax);
  3666. if (params->m_res_1() != 1.0)
  3667. result += (1.0-params->m_res_1()) * integrate_crystalball(params->m_b(), params->m_scale()*params->m_sigma_2(), params->alpha_2(), params->n_2(), ma, mb)
  3668. / integrate_crystalball(params->m_b(), params->m_scale()*params->m_sigma_2(), params->alpha_2(), params->n_2(), mmin, mmax);
  3669. }
  3670. else if(opts->twotailedcrystalball){
  3671. double mmin=params->m_b.get_min(), mmax=params->m_b.get_max();
  3672. result = integrate_twotailedcrystalball(params->m_b(), params->m_scale()*params->m_sigma_1(), params->alpha_1(), params->alpha_2(), params->n_1(), params->n_2(), ma, mb)
  3673. / integrate_twotailedcrystalball(params->m_b(), params->m_scale()*params->m_sigma_1(), params->alpha_1(), params->alpha_2(), params->n_1(), params->n_2(), mmin, mmax);
  3674. }
  3675. else{
  3676. double mean = params->m_b();
  3677. double min = params->m_b.get_min();
  3678. double max = params->m_b.get_max();
  3679. double sigma1 = params->m_scale()*params->m_sigma_1();
  3680. double sigma2 = params->m_scale()*params->m_sigma_2();
  3681. double fres = params->m_res_1();
  3682. double fullrange = (fres)*1.0/2.0*(TMath::Erf((max-mean)/(sqrt(2.0)*sigma1))-TMath::Erf((min-mean)/(sqrt(2.0)*sigma1)));
  3683. if (params->m_res_1() != 1.0)
  3684. fullrange += (1.0-fres)*1.0/2.0*(TMath::Erf((max-mean)/(sqrt(2.0)*sigma2))-TMath::Erf((min-mean)/(sqrt(2.0)*sigma2)));
  3685. double integral = (fres)*1.0/2.0*(TMath::Erf((mb-mean)/(sqrt(2.0)*sigma1))-TMath::Erf((ma-mean)/(sqrt(2.0)*sigma1)));
  3686. if (params->m_res_1() != 1.0)
  3687. integral += (1.0-fres)*1.0/2.0*(TMath::Erf((mb-mean)/(sqrt(2.0)*sigma2))-TMath::Erf((ma-mean)/(sqrt(2.0)*sigma2)));
  3688. result = integral/fullrange;
  3689. }
  3690. return result;
  3691. };
  3692. double bu2kstarmumu_pdf::m_bkg_prob(const bu2kstarmumu_parameters* params, const event& meas) const
  3693. {
  3694. if (opts->only_angles || opts->only_mkpi) return 1.0;
  3695. double mmin=params->m_b.get_min(), mmax=params->m_b.get_max();
  3696. assert(meas.m <= mmax);
  3697. assert(meas.m >= mmin);
  3698. if(opts->cutsignalwindow){
  3699. assert(meas.m <= opts->m_min || meas.m >= opts->m_max);
  3700. }
  3701. double fm1 = params->fm_tau();
  3702. double tau1 = params->m_tau();
  3703. double tau2 = params->m_tau_2();
  3704. double lambda1 = params->m_lambda();
  3705. double lambda2 = params->m_lambda_2();
  3706. double result = 0.;
  3707. if(opts->fit_lambda){
  3708. if(lambda1 == 0.0) return 1.0;
  3709. double norm1 = 1.0/lambda1*(exp(mmax*lambda1) - exp(mmin*lambda1));
  3710. if(opts->cutsignalwindow){
  3711. norm1 -= 1.0/lambda1*(exp(opts->m_max*lambda1) - exp(opts->m_min*lambda1));
  3712. }
  3713. result = exp(meas.m*lambda1)/norm1;
  3714. if (fm1 != 1.0){
  3715. if(lambda2 == 0.0) return result;
  3716. result *= fm1;
  3717. double norm2 = 1.0/lambda2*(exp(mmax*lambda2) - exp(mmin*lambda2));
  3718. if(opts->cutsignalwindow)
  3719. norm2 -= 1.0/lambda2*(exp(opts->m_max*lambda2) - exp(opts->m_min*lambda2));
  3720. result += (1.0-fm1)*exp(meas.m*lambda2)/norm2;
  3721. }
  3722. }
  3723. else{
  3724. double norm1 = tau1*(exp(-mmin/tau1) - exp(-mmax/tau1));
  3725. if(opts->cutsignalwindow)
  3726. norm1 -= tau1*(exp(-opts->m_min/tau1) - exp(-opts->m_max/tau1));
  3727. result = exp(-meas.m/tau1)/norm1;
  3728. if (fm1 != 1.0){
  3729. result *= fm1;
  3730. double norm2 = tau2*(exp(-mmin/tau2) - exp(-mmax/tau2));
  3731. if(opts->cutsignalwindow)
  3732. norm2 -= tau2*(exp(-opts->m_min/tau2) - exp(-opts->m_max/tau2));
  3733. result += (1.0-fm1)*exp(-meas.m/tau2)/norm2;
  3734. }
  3735. }
  3736. return result;
  3737. };
  3738. double bu2kstarmumu_pdf::mkpi_bkg_prob(const bu2kstarmumu_parameters* params, const event& meas) const
  3739. {
  3740. if(!(opts->fit_mkpi || opts->use_mkpi) || opts->only_angles || opts->only_Bmass)
  3741. return 1.0;
  3742. assert(meas.mkpi <= opts->mkpi_max);
  3743. assert(meas.mkpi >= opts->mkpi_min);
  3744. double result = 0.0;
  3745. double mkpi_min = opts->mkpi_min/1.0e+3;
  3746. double mkpi_max = opts->mkpi_max/1.0e+3;
  3747. double mkpi = meas.mkpi/1.0e+3;
  3748. double normbkg=0.0;
  3749. std::vector<double> ch_mkpi(5, 0.0);
  3750. ch_mkpi.at(0) = params->cbkgmkpi0();
  3751. ch_mkpi.at(1) = params->cbkgmkpi1();
  3752. ch_mkpi.at(2) = params->cbkgmkpi2();
  3753. ch_mkpi.at(3) = params->cbkgmkpi3();
  3754. ch_mkpi.at(4) = params->cbkgmkpi4();
  3755. std::vector<double> poly_mkpi(ch_mkpi.size(), 0.0);
  3756. chebyshev_to_poly(ch_mkpi, poly_mkpi);
  3757. std::vector<double> poly_corr_mkpi(ch_mkpi.size(), 0.0);
  3758. correct_poly(poly_mkpi, poly_corr_mkpi, mkpi_min, mkpi_max);
  3759. for(unsigned int i=0; i<poly_mkpi.size(); i++)
  3760. normbkg += poly_corr_mkpi.at(i)*(pow(mkpi_max,i+1)-pow(mkpi_min,i+1))/(i+1.0);
  3761. double probbkg = 0.0;
  3762. for (unsigned int i=0; i<ch_mkpi.size(); i++)
  3763. probbkg += poly_corr_mkpi.at(i)*pow(mkpi,i);
  3764. result = probbkg/normbkg;
  3765. return result;
  3766. };
  3767. double bu2kstarmumu_pdf::integral_m_bkg_prob(const bu2kstarmumu_parameters* params, double ma, double mb) const
  3768. {
  3769. double mmin=params->m_b.get_min(), mmax=params->m_b.get_max();
  3770. double bkg_frac = params->fm_tau();
  3771. double tau1 = params->m_tau();
  3772. double tau2 = params->m_tau_2();
  3773. double lambda1 = params->m_lambda();
  3774. double lambda2 = params->m_lambda_2();
  3775. double result = 0.0;
  3776. if(opts->fit_lambda){
  3777. assert(lambda1 <= 0.);
  3778. double fullrange1 = 1.0/lambda1*(exp(mmax*lambda1) - exp(mmin*lambda1));
  3779. if(opts->cutsignalwindow){
  3780. fullrange1 -= 1.0/lambda1*(exp(opts->m_max*lambda1) - exp(opts->m_min*lambda1));
  3781. }
  3782. double integral1 = 1.0/lambda1*(exp(mb*lambda1) - exp(ma*lambda1));
  3783. result = integral1/fullrange1;
  3784. if (bkg_frac != 1.0){
  3785. assert(lambda2 <= 0.);
  3786. result *= bkg_frac;
  3787. double fullrange2 = 1.0/lambda2*(exp(mmax*lambda2) - exp(mmin*lambda2));
  3788. if(opts->cutsignalwindow){
  3789. fullrange2 -= 1.0/lambda2*(exp(opts->m_max*lambda2) - exp(opts->m_min*lambda2));
  3790. }
  3791. double integral2 = 1.0/lambda2*(exp(mb*lambda2) - exp(ma*lambda2));
  3792. result += (1.0-bkg_frac)*integral2/fullrange2;
  3793. }
  3794. }
  3795. else{
  3796. double fullrange1 = tau1*(exp(-mmin/tau1) - exp(-mmax/tau1));
  3797. if(opts->cutsignalwindow){
  3798. fullrange1 -= tau1*(exp(opts->m_max/tau1) - exp(opts->m_min/tau1));
  3799. }
  3800. double integral1 = tau1*(exp(-ma/tau1) - exp(-mb/tau1));
  3801. result = integral1/fullrange1;
  3802. if (bkg_frac != 1.0){
  3803. result *= bkg_frac;
  3804. double fullrange2 = tau2*(exp(-mmin/tau2) - exp(-mmax/tau2));
  3805. if(opts->cutsignalwindow){
  3806. fullrange2 -= tau2*(exp(opts->m_max/tau2) - exp(opts->m_min/tau2));
  3807. }
  3808. double integral2 = tau2*(exp(-ma/tau2) - exp(-mb/tau2));
  3809. result += (1.0-bkg_frac)*integral2/fullrange2;
  3810. }
  3811. }
  3812. return result;
  3813. };
  3814. double bu2kstarmumu_pdf::angular_sig_prob(const bu2kstarmumu_parameters* params, const event& meas) const
  3815. {
  3816. //Don't when only fitting the mass
  3817. if (opts->only_Bmass || opts->only_mass2DFit || opts->only_mkpi) return 1.0;
  3818. double ctl = meas.costhetal;
  3819. double ctk = meas.costhetak;
  3820. double phi = meas.phi;
  3821. double result_swave = 0.0, result_pwave = 0.0;
  3822. double result = 0.0;
  3823. double f1=0.0, f2=0.0, f3=0.0, f4=0.0, f5=0.0, f6=0.0,
  3824. f7=0.0, f8=0.0, f9=0.0, f10=0.0, f11=0.0, f12=0.0;
  3825. const double j1s = params->J1s();
  3826. const double j1c = params->J1c();
  3827. const double j2s = params->J2s();
  3828. const double j2c = params->J2c();
  3829. const double j3 = params->J3();
  3830. const double j4 = params->J4();
  3831. const double j5 = params->J5();
  3832. const double j6s = params->J6s();
  3833. const double j6c = params->J6c();
  3834. const double j7 = params->J7();
  3835. const double j8 = params->J8();
  3836. const double j9 = params->J9();
  3837. if (opts->full_angular) fj(ctl, ctk, phi, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12);
  3838. else folded_fj(ctl, ctk, phi, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12);
  3839. if (opts->fit_asymmetries && meas.cp_conjugate){
  3840. result_pwave += (f1*j1s + f2*j1c + f3*j2s + f4*j2c - f5*j3 - f6*j4
  3841. - f7*j5 - f8*j6s - f9*j6c - f10*j7 - f11*j8 - f12*j9);
  3842. }
  3843. else{
  3844. result_pwave += (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4
  3845. + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9);
  3846. }
  3847. if (opts->swave){
  3848. double f1=0.0, f2=0.0, f3=0.0, f4=0.0, f5=0.0, f6=0.0;
  3849. if(opts->full_angular) swave_fj(ctl, ctk, phi, f1, f2, f3, f4, f5, f6);
  3850. else folded_swave_fj(ctl, ctk, phi, f1, f2, f3, f4, f5, f6);
  3851. const double fs = params->FS();
  3852. const double js1 = params->SS1();
  3853. const double js2 = params->SS2();
  3854. const double js3 = params->SS3();
  3855. const double js4 = params->SS4();
  3856. const double js5 = params->SS5();
  3857. result_pwave *= (1.0 - fs);
  3858. result_swave += (fs*f1 + js1*f2 + js2*f3 + js3*f4 + js4*f5 + js5*f6);
  3859. if (opts->use_mkpi){
  3860. double prob_mkpi_pwave = mkpi_pwave_2(params, meas);
  3861. double prob_mkpi_swave = mkpi_swave_2(params, meas);
  3862. double prob_mkpi_re_swavepwave = mkpi_re_swavepwave(params, meas);
  3863. double prob_mkpi_im_swavepwave = mkpi_im_swavepwave(params, meas);
  3864. result_pwave *= prob_mkpi_pwave/mkpi_pwave_2_norm;
  3865. if (std::isnan(result_pwave)) spdlog::warn("prob_mkpi_pwave {0:f}",prob_mkpi_pwave );
  3866. result_swave = (fs*f1*prob_mkpi_swave/mkpi_swave_2_norm
  3867. + (js1*f2 + js2*f3 + js3*f4)*prob_mkpi_re_swavepwave/mkpi_re_swavepwave_norm
  3868. + (js4*f5 + js5*f6)*prob_mkpi_im_swavepwave/mkpi_im_swavepwave_norm);
  3869. }
  3870. if (std::isnan(result_swave) || std::isinf(result_swave)){
  3871. spdlog::warn("\tresult_swave {0:0.6f}",result_swave);
  3872. spdlog::warn("\t mkpi_swave_2_norm {0:0.6f}",mkpi_swave_2_norm);
  3873. spdlog::warn("\t mkpi_pwave_2_norm {0:0.6f}",mkpi_pwave_2_norm);
  3874. spdlog::warn("\t prob_mkpi_swave {0:0.6f}",mkpi_swave_2(params, meas));
  3875. spdlog::warn("\t prob_mkpi_re_swavepwave {0:0.6f}",mkpi_re_swavepwave(params, meas));
  3876. spdlog::warn("\t prob_mkpi_im_swavepwave {0:0.6f}",mkpi_im_swavepwave(params, meas));
  3877. result_swave = 1.0e-12;
  3878. }
  3879. }
  3880. result = result_pwave + result_swave;
  3881. if(std::isnan(result) || std::isinf(result)){
  3882. spdlog::error("result={0:0f}",result );
  3883. spdlog::error("pwave={0:0f}",result_pwave );
  3884. spdlog::error("swave={0:0f}",result_swave );
  3885. assert(0);
  3886. }
  3887. //spdlog::trace("result={0:0f}",result );
  3888. //spdlog::trace("pwave={0:0f}",result_pwave );
  3889. //spdlog::trace("swave={0:0f}",result_swave );
  3890. double eff = 1.0;
  3891. if (opts->use_angular_acc){
  3892. //for fixed effq2 the efficiency should have been calculated beforehand
  3893. //for floating q2 should recalculate as done below
  3894. //for event_norm, the efficiency should also have been calculated before
  3895. bool q2fixed = (params->eff_q2.get_step_size() == 0.0);
  3896. if ((q2fixed || opts->use_event_norm) && (!opts->mcweight)) { //use event norm is only used when convoluting the acceptance into the pdf
  3897. if (meas.weight > 0.0) eff = 1.0/meas.weight;
  3898. spdlog::trace("eff={0:f}",eff);
  3899. }
  3900. else{
  3901. double q2 = params->eff_q2();
  3902. eff = this->get_ang_eff(opts,q2,meas.costhetal_fa, meas.costhetal_fa,meas.phi_fa);
  3903. spdlog::trace("eff={0:f}",eff);
  3904. spdlog::trace("q2={0:f}",q2);
  3905. }
  3906. }
  3907. if(std::isnan(eff) || std::isinf(eff)){
  3908. spdlog::error("eff={0:f}",eff );
  3909. assert(0);
  3910. }
  3911. if(eff/fnorm_sig < 0.0){
  3912. spdlog::info("negative acc corr and/or normalizing");
  3913. spdlog::info("eff={0:f}",eff );
  3914. spdlog::info("norm={0:f}",fnorm_sig );
  3915. assert(eff > 0.0);
  3916. assert(fnorm_sig > 0.0);
  3917. }
  3918. //spdlog::trace("eff={0:f},\t fnorm_sig={1:f}",eff, fnorm_sig);
  3919. result *= eff/fnorm_sig;
  3920. return result;
  3921. };
  3922. double bu2kstarmumu_pdf::angular_bkg_prob(const bu2kstarmumu_parameters* params, const event& meas) const{
  3923. //Don't when only fitting the mass
  3924. if (opts->only_Bmass || opts->only_mass2DFit || opts->only_mkpi) return 1.0;
  3925. //calculate bkg prob for all 2(4) possible inversed folding angles:
  3926. if(opts->fit_full_angular_bkg && !opts->flat_bkg && !opts->full_angular){
  3927. fcnc::event e[3];
  3928. fldr->invers_fold(&meas, &e[0], &e[1], &e[2]);
  3929. double p1, p2, p3, p4;
  3930. p1 = simple_angular_bkg_prob(params, meas);
  3931. p4 = simple_angular_bkg_prob(params, e[2]);
  3932. if(opts->folding > 0){
  3933. p2 = simple_angular_bkg_prob(params, e[0]);
  3934. p3 = simple_angular_bkg_prob(params, e[1]);
  3935. return p1+p2+p3+p4;
  3936. }
  3937. else{
  3938. return p1+p4;
  3939. }
  3940. }
  3941. else{
  3942. return simple_angular_bkg_prob(params, meas);
  3943. }
  3944. }
  3945. double bu2kstarmumu_pdf::simple_angular_bkg_prob(const bu2kstarmumu_parameters* params, const event& meas) const{
  3946. if (opts->only_Bmass) return 1.0;
  3947. if (opts->only_mass2DFit) return 1.0; //Don't when fitting only mass
  3948. double result = 1.0;
  3949. double costhetal = meas.costhetal;
  3950. double costhetak = meas.costhetak;
  3951. double phi = meas.phi;
  3952. npolynom npol(opts);
  3953. assert(coeffs_eff_4d.size() == npol.getSize());
  3954. //determine weight/efficiency for this event
  3955. double eff = 1.0;
  3956. if(opts->use_angular_acc && opts->use_weighted_bkg){
  3957. //for fixed effq2 the efficiency should have been calculated beforehand
  3958. //for floating q2 should recalculate as done below
  3959. //for event_norm, the efficiency should also have been calculated before
  3960. bool q2fixed = (params->eff_q2.get_step_size() == 0.0);
  3961. if ((q2fixed || opts->use_event_norm) && (!opts->mcweight)){//use event norm is only used when convoluting the acceptance into the pdf
  3962. if (meas.weight > 0.0) eff = 1.0/meas.weight;
  3963. }
  3964. else eff = this->get_ang_eff(opts,meas,true);
  3965. }
  3966. if (opts->flat_bkg){ //for a flat background, only - if at all - the angular acceptance correction is needed
  3967. result *= eff/fnorm_bkg;
  3968. }
  3969. else{ //Chebyshev background
  3970. //read angular bkg coefficients from parameter object
  3971. std::vector<double> ch_ctl = init_ch_ctl(params);
  3972. std::vector<double> ch_ctk = init_ch_ctk(params);
  3973. std::vector<double> ch_phi = init_ch_phi(params);
  3974. //reserve vectors for the (non-)Chebyshev polynomial coefficients
  3975. std::vector<double> poly_ctl(ch_ctl.size(), 0.0);
  3976. std::vector<double> poly_ctk(ch_ctk.size(), 0.0);
  3977. std::vector<double> poly_phi(ch_phi.size(), 0.0);
  3978. //these temporary coefficients are defined in the range from -1 to +1
  3979. std::vector<double> temp_ctl(ch_ctl.size(), 0.0);
  3980. std::vector<double> temp_ctk(ch_ctk.size(), 0.0);
  3981. std::vector<double> temp_phi(ch_phi.size(), 0.0);
  3982. //transform chebyshev polynomial coefficients to Standard Form polynomials
  3983. chebyshev_to_poly(ch_ctl, temp_ctl);
  3984. chebyshev_to_poly(ch_ctk, temp_ctk);
  3985. chebyshev_to_poly(ch_phi, temp_phi);
  3986. //stretch or squeeze the definition of the polynomials in phi
  3987. //for (unsigned int i=0; i<poly_ctk.size(); i++) poly_ctk.at(i) = temp_ctk.at(i);
  3988. for (unsigned int i=0; i<poly_ctk.size(); i++) poly_ctk.at(i) = temp_ctk.at(i);
  3989. for (unsigned int i=0; i<poly_ctl.size(); i++) poly_ctl.at(i) = temp_ctl.at(i);
  3990. correct_poly(temp_phi, poly_phi, -TMath::Pi(), +TMath::Pi());
  3991. //add up all power terms of the polynomials
  3992. double p_costhetal = 0.0;
  3993. for (unsigned int i=0; i<ch_ctl.size(); i++) p_costhetal += poly_ctl.at(i)*pow(costhetal,i);
  3994. double p_costhetak = 0.0;
  3995. for (unsigned int i=0; i<ch_ctk.size(); i++) p_costhetak += poly_ctk.at(i)*pow(costhetak,i);
  3996. double p_phi = 0.0;
  3997. for (unsigned int i=0; i<ch_phi.size(); i++) p_phi += poly_phi.at(i)*pow(phi,i);
  3998. //multiply the indidivual angular dimensions. divide by the normalisation to obtain the angular background probability
  3999. result = p_costhetal*p_costhetak*p_phi*eff/fnorm_bkg;
  4000. }
  4001. return result;
  4002. };
  4003. double bu2kstarmumu_pdf::integral_bkg(const bu2kstarmumu_parameters* params, double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b) const
  4004. {
  4005. if (opts->flat_bkg){
  4006. return (ctl_b-ctl_a)*(ctk_b-ctk_a)*(phi_b-phi_a); // RANGE_3D() for non-folded
  4007. }
  4008. else{
  4009. std::vector<double> ch_ctl = init_ch_ctl(params);
  4010. std::vector<double> ch_ctk = init_ch_ctk(params);
  4011. std::vector<double> ch_phi = init_ch_phi(params);
  4012. std::vector<double> poly_ctl(ch_ctl.size(), 0.0);
  4013. std::vector<double> poly_ctk(ch_ctk.size(), 0.0);
  4014. std::vector<double> poly_phi(ch_phi.size(), 0.0);
  4015. std::vector<double> temp_ctl(ch_ctl.size(), 0.0);
  4016. std::vector<double> temp_ctk(ch_ctk.size(), 0.0);
  4017. std::vector<double> temp_phi(ch_phi.size(), 0.0);
  4018. chebyshev_to_poly(ch_ctl, temp_ctl);
  4019. chebyshev_to_poly(ch_ctk, temp_ctk);
  4020. chebyshev_to_poly(ch_phi, temp_phi);
  4021. for (unsigned int i=0; i<poly_ctk.size(); i++) poly_ctk.at(i) = temp_ctk.at(i);
  4022. for (unsigned int i=0; i<poly_ctl.size(); i++)poly_ctl.at(i) = temp_ctl.at(i);
  4023. correct_poly(temp_phi, poly_phi, -TMath::Pi(), +TMath::Pi());
  4024. double norm_costhetal = 0.0;
  4025. for (unsigned int i=0; i<poly_ctl.size(); i++)norm_costhetal += poly_ctl.at(i)*(pow(ctl_b,i+1)-pow(ctl_a,i+1))/(i+1.0);
  4026. double norm_costhetak = 0.0;
  4027. for (unsigned int i=0; i<poly_ctk.size(); i++)norm_costhetak += poly_ctk.at(i)*(pow(ctk_b,i+1)-pow(ctk_a,i+1))/(i+1.0);
  4028. double norm_phi = 0.0;
  4029. for (unsigned int i=0; i<poly_phi.size(); i++)norm_phi += poly_phi.at(i)*(pow(phi_b,i+1)-pow(phi_a,i+1))/(i+1.0);
  4030. return norm_costhetal*norm_costhetak*norm_phi;
  4031. }
  4032. }
  4033. double bu2kstarmumu_pdf::integral_bkg_chebyshev(const bu2kstarmumu_parameters* params, double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b, double q2) const{
  4034. double result = 0.0;
  4035. if (opts->flat_bkg){
  4036. double c = 1.0;
  4037. //new improved non-factorizing acceptance
  4038. npolynom npol = npolynom(opts);
  4039. assert(coeffs_eff_4d.size() == npol.getSize());
  4040. double chijk = 0.0;
  4041. for (unsigned int h = 0; h<npol.q2; h++){
  4042. for (unsigned int i = 0; i<npol.ctl; i++){
  4043. for (unsigned int j = 0; j<npol.ctk; j++){
  4044. for (unsigned int k = 0; k<npol.phi; k++){
  4045. const unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  4046. chijk = c*pow(q2, h)*coeffs_eff_4d.at(bin);
  4047. result += chijk
  4048. * (pow(ctl_b, i+1)/(i+1.0) - pow(ctl_a, i+1)/(i+1.0))
  4049. * (pow(ctk_b, j+1)/(j+1.0) - pow(ctk_a, j+1)/(j+1.0))
  4050. * (pow(phi_b, k+1)/(k+1.0) - pow(phi_a, k+1)/(k+1.0));
  4051. }
  4052. }
  4053. }
  4054. }
  4055. }
  4056. else{
  4057. //calculate integral of background with efficiency correction
  4058. std::vector<double> ch_ctl = init_ch_ctl(params);
  4059. std::vector<double> ch_ctk = init_ch_ctk(params);
  4060. std::vector<double> ch_phi = init_ch_phi(params);
  4061. std::vector<double> poly_ctl(ch_ctl.size(), 0.0);
  4062. std::vector<double> poly_ctk(ch_ctk.size(), 0.0);
  4063. std::vector<double> poly_phi(ch_phi.size(), 0.0);
  4064. std::vector<double> temp_ctl(ch_ctl.size(), 0.0);
  4065. std::vector<double> temp_ctk(ch_ctk.size(), 0.0);
  4066. std::vector<double> temp_phi(ch_phi.size(), 0.0);
  4067. chebyshev_to_poly(ch_ctl, temp_ctl);
  4068. chebyshev_to_poly(ch_ctk, temp_ctk);
  4069. chebyshev_to_poly(ch_phi, temp_phi);
  4070. for (unsigned int i=0; i<poly_ctk.size(); i++) poly_ctk.at(i) = temp_ctk.at(i);
  4071. for (unsigned int i=0; i<poly_ctl.size(); i++) poly_ctl.at(i) = temp_ctl.at(i);
  4072. correct_poly(temp_phi, poly_phi, -TMath::Pi(), +TMath::Pi());
  4073. double c = 1.0;
  4074. //new improved non-factorizing acceptance
  4075. //double q2 = params->eff_q2();
  4076. npolynom npol(opts);
  4077. assert(coeffs_eff_4d.size() == npol.getSize());
  4078. double chijk = 0.0;
  4079. for (unsigned int h = 0; h<npol.q2; h++){
  4080. for (unsigned int i = 0; i<npol.ctl; i++){
  4081. for (unsigned int j = 0; j<npol.ctk; j++){
  4082. for (unsigned int k = 0; k<npol.phi; k++){
  4083. const unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  4084. chijk = c*pow(q2, h)*coeffs_eff_4d.at(bin);
  4085. for (unsigned int l=0; l<poly_ctl.size(); l++){
  4086. for (unsigned int m=0; m<poly_ctk.size(); m++){
  4087. for (unsigned int n=0; n<poly_phi.size(); n++){
  4088. result += chijk * poly_ctl.at(l) * poly_ctk.at(m) * poly_phi.at(n)
  4089. * (pow(ctl_b, i+l+1) - pow(ctl_a, i+l+1)) / (i+l+1.0)
  4090. * (pow(ctk_b, j+m+1) - pow(ctk_a, j+m+1)) / (j+m+1.0)
  4091. * (pow(phi_b, k+n+1) - pow(phi_a, k+n+1)) / (k+n+1.0);
  4092. }
  4093. }
  4094. }
  4095. }
  4096. }
  4097. }
  4098. }
  4099. }
  4100. return result;
  4101. }
  4102. double bu2kstarmumu_pdf::angular_bkg_norm(const bu2kstarmumu_parameters* params, bool weighted){
  4103. npolynom npol(opts);
  4104. assert(coeffs_eff_4d.size() == npol.getSize());
  4105. //bkg norm
  4106. if(weighted){ //weighted background pdf
  4107. double q2 = params->eff_q2();
  4108. if (opts->full_angular){
  4109. if (opts->flat_bkg){
  4110. double integral = 0.0;
  4111. for (unsigned int h = 0; h<npol.q2; h++){
  4112. for (unsigned int i = 0; i<npol.ctl; i++){
  4113. for (unsigned int j = 0; j<npol.ctk; j++){
  4114. for (unsigned int k = 0; k<npol.phi; k++){
  4115. integral += pow(q2, h)*coeffs_eff_4d.at(npol.get_bin_in4D(h,i,j,k))
  4116. * integrate_x_to_n(CTL_MIN,CTL_MAX,i)
  4117. * integrate_x_to_n(CTK_MIN,CTK_MAX,j)
  4118. * integrate_x_to_n(PHI_MIN,PHI_MAX,k);
  4119. }
  4120. }
  4121. }
  4122. }
  4123. return integral;
  4124. }
  4125. else{
  4126. return integral_bkg_chebyshev(params, CTL_MIN, CTL_MAX, CTK_MIN, CTK_MAX, PHI_MIN, PHI_MAX, q2);
  4127. }
  4128. }
  4129. else{ //folded angles
  4130. if (opts->flat_bkg){
  4131. double integral = 0.0;
  4132. for (unsigned int h = 0; h<npol.q2; h++){
  4133. for (unsigned int i = 0; i<npol.ctl; i++){
  4134. for (unsigned int j = 0; j<npol.ctk; j++){
  4135. for (unsigned int k = 0; k<npol.phi; k++){
  4136. integral += pow(q2, h)*coeffs_eff_4d.at(npol.get_bin_in4D(h,i,j,k))
  4137. * integrate_x_to_n(opts->ctl_min,opts->ctl_max,i)
  4138. * integrate_x_to_n(opts->ctk_min,opts->ctk_max,j)
  4139. * integrate_x_to_n(opts->phi_min,opts->phi_max,k);
  4140. }
  4141. }
  4142. }
  4143. }
  4144. return integral;
  4145. }
  4146. else{
  4147. if(opts->fit_full_angular_bkg){
  4148. return integral_bkg_chebyshev(params, CTL_MIN, CTL_MAX, opts->ctk_min, opts->ctk_max, PHI_MIN, PHI_MAX, q2); //TODO: check if that makes sense (https://gitlab.cern.ch/LHCb-RD/ewp-Bplus2Kstmumu-AngAna/-/merge_requests/21)
  4149. }
  4150. else{
  4151. return integral_bkg_chebyshev(params, opts->ctl_min, opts->ctl_max, opts->ctk_min, opts->ctk_max, opts->phi_min, opts->phi_max, q2);
  4152. }
  4153. }
  4154. }
  4155. }
  4156. else{ //non weighted background pdf
  4157. if (opts->full_angular){
  4158. if (opts->flat_bkg) return RANGE_3D();
  4159. else return integral_bkg(params, CTL_MIN, CTL_MAX, CTK_MIN, CTK_MAX, PHI_MIN, PHI_MAX);
  4160. }
  4161. else{ //folded angles
  4162. if (opts->flat_bkg){
  4163. return (opts->ctk_max - opts->ctk_min) * (opts->ctl_max - opts->ctl_min) * (opts->phi_max - opts->phi_min);
  4164. }
  4165. else{
  4166. if(opts->fit_full_angular_bkg){
  4167. return integral_bkg(params, CTL_MIN, CTL_MAX, CTK_MIN, CTK_MAX, PHI_MIN, PHI_MAX);
  4168. }
  4169. else{
  4170. return integral_bkg(params, opts->ctl_min, opts->ctl_max, opts->ctk_min, opts->ctk_max, opts->phi_min, opts->phi_max);
  4171. }
  4172. }
  4173. }
  4174. }
  4175. }
  4176. double bu2kstarmumu_pdf::angular_sig_norm(const bu2kstarmumu_parameters* params, bool weighted){
  4177. double f1=0.0, f2=0.0, f3=0.0, f4=0.0, f5=0.0, f6=0.0,
  4178. f7=0.0, f8=0.0, f9=0.0, f10=0.0, f11=0.0, f12=0.0;
  4179. double fs1=0.0, fs2=0.0, fs3=0.0, fs4=0.0, fs5=0.0, fs6=0.0;
  4180. const double j1s = params->J1s();
  4181. const double j1c = params->J1c();
  4182. const double j2s = params->J2s();
  4183. const double j2c = params->J2c();
  4184. const double j3 = params->J3();
  4185. const double j4 = params->J4();
  4186. const double j5 = params->J5();
  4187. const double j6s = params->J6s();
  4188. const double j6c = params->J6c();
  4189. const double j7 = params->J7();
  4190. const double j8 = params->J8();
  4191. const double j9 = params->J9();
  4192. const double fs = params->FS();
  4193. const double js1 = params->SS1();
  4194. const double js2 = params->SS2();
  4195. const double js3 = params->SS3();
  4196. const double js4 = params->SS4();
  4197. const double js5 = params->SS5();
  4198. //sig norm
  4199. double q2 = params->eff_q2();
  4200. if (opts->full_angular){
  4201. //get signal pdf
  4202. if (weighted) integrated_fj_chebyshev(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, q2);
  4203. else integrated_fj_noacc(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12);
  4204. //swave
  4205. if(opts->swave){
  4206. if (weighted) swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  4207. else swave_integrated_fj_noacc(fs1, fs2, fs3, fs4, fs5, fs6);
  4208. }
  4209. //if asymmetries are fitted:
  4210. if(opts->fit_asymmetries){
  4211. if(opts->swave) return (1.0-fs) * (f1*j1s + f2*j1c + f3*j2s + f4*j2c) + (fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  4212. else return f1*j1s + f2*j1c + f3*j2s + f4*j2c;
  4213. }
  4214. if (opts->swave){
  4215. return (1.0-fs) * (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4 + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9)
  4216. + (fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  4217. }
  4218. //signal pdf without swave, without asymmetries and without m(Kpi)
  4219. return f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4 + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9;
  4220. }
  4221. else{ //folded angles
  4222. if (weighted) folded_integrated_fj_chebyshev(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, q2);
  4223. else folded_integrated_fj_noacc(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12);
  4224. if(opts->swave){
  4225. if (weighted) folded_swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  4226. else folded_swave_integrated_fj_noacc(fs1, fs2, fs3, fs4, fs5, fs6);
  4227. }
  4228. if(opts->fit_asymmetries){
  4229. if(opts->swave) return (1-fs) * (f1*j1s + f2*j1c + f3*j2s + f4*j2c) + (fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  4230. else return (f1*j1s + f2*j1c + f3*j2s + f4*j2c);
  4231. }
  4232. if(opts->swave){
  4233. return (1-fs) * (f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4 + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9)
  4234. + (fs1*fs + fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5);
  4235. }
  4236. //signal pdf without swave, without asymmetries and without m(Kpi)
  4237. return f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4 + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9;
  4238. }
  4239. }
  4240. double bu2kstarmumu_pdf::angular_swave_norm(const bu2kstarmumu_parameters* params, bool weighted){
  4241. double fs1=0.0, fs2=0.0, fs3=0.0, fs4=0.0, fs5=0.0, fs6=0.0;
  4242. const double fs = params->FS();
  4243. //sig norm
  4244. double q2 = params->eff_q2();
  4245. if (opts->full_angular){
  4246. if (weighted) swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  4247. else swave_integrated_fj_noacc(fs1, fs2, fs3, fs4, fs5, fs6);
  4248. }
  4249. else{ //folded angles
  4250. if (weighted) folded_swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  4251. else folded_swave_integrated_fj_noacc(fs1, fs2, fs3, fs4, fs5, fs6);
  4252. }
  4253. return fs1*fs;
  4254. }
  4255. double bu2kstarmumu_pdf::angular_pwave_norm(const bu2kstarmumu_parameters* params, bool weighted){
  4256. double f1=0.0, f2=0.0, f3=0.0, f4=0.0, f5=0.0, f6=0.0,
  4257. f7=0.0, f8=0.0, f9=0.0, f10=0.0, f11=0.0, f12=0.0;
  4258. const double j1s = params->J1s();
  4259. const double j1c = params->J1c();
  4260. const double j2s = params->J2s();
  4261. const double j2c = params->J2c();
  4262. const double j3 = params->J3();
  4263. const double j4 = params->J4();
  4264. const double j5 = params->J5();
  4265. const double j6s = params->J6s();
  4266. const double j6c = params->J6c();
  4267. const double j7 = params->J7();
  4268. const double j8 = params->J8();
  4269. const double j9 = params->J9();
  4270. //sig norm
  4271. double q2 = params->eff_q2();
  4272. if (opts->full_angular){
  4273. if (weighted) integrated_fj_chebyshev(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, q2);
  4274. else integrated_fj_noacc(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12);
  4275. }
  4276. else{ //folded angles
  4277. if (weighted) folded_integrated_fj_chebyshev(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, q2);
  4278. else folded_integrated_fj_noacc(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12);
  4279. }
  4280. //if asymmetries are fitted:
  4281. if(opts->fit_asymmetries)return f1*j1s + f2*j1c + f3*j2s + f4*j2c;
  4282. else return f1*j1s + f2*j1c + f3*j2s + f4*j2c + f5*j3 + f6*j4 + f7*j5 + f8*j6s + f9*j6c + f10*j7 + f11*j8 + f12*j9;
  4283. }
  4284. double bu2kstarmumu_pdf::angular_pswave_norm(const bu2kstarmumu_parameters* params, bool weighted){
  4285. double fs1=0.0, fs2=0.0, fs3=0.0, fs4=0.0, fs5=0.0, fs6=0.0;
  4286. const double js1 = params->SS1();
  4287. const double js2 = params->SS2();
  4288. const double js3 = params->SS3();
  4289. const double js4 = params->SS4();
  4290. const double js5 = params->SS5();
  4291. //sig norm
  4292. double q2 = params->eff_q2();
  4293. if (opts->full_angular){
  4294. if (weighted) swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  4295. else swave_integrated_fj_noacc(fs1, fs2, fs3, fs4, fs5, fs6);
  4296. }
  4297. else{ //folded angles
  4298. if (weighted) folded_swave_integrated_fj_chebyshev(fs1, fs2, fs3, fs4, fs5, fs6, q2);
  4299. else folded_swave_integrated_fj_noacc(fs1, fs2, fs3, fs4, fs5, fs6);
  4300. }
  4301. return fs2*js1 + fs3*js2 + fs4*js3 + fs5*js4 + fs6*js5;
  4302. }
  4303. void bu2kstarmumu_pdf::update_cached_efficiencies(const bu2kstarmumu_parameters* params, std::vector<event>* events)
  4304. {
  4305. if (opts->update_efficiencies){
  4306. spdlog::info("Updating cached efficiencies");
  4307. //assert(0);
  4308. //three ways this is usefull
  4309. //-q2_eff is fixed and you want to avoid recalculating this every time
  4310. //-weighted fit to determine the event weight that needs to be used
  4311. //-when using per event norm this can also be cached
  4312. npolynom npol(opts);
  4313. assert(coeffs_eff_4d.size() == npol.getSize());
  4314. double q2 = params->eff_q2();
  4315. unsigned int N = events->size();
  4316. for (unsigned int e=0; e<N; e++){
  4317. double eff = 0.0;
  4318. event& meas = events->at(e);
  4319. if (opts->weighted_fit || (opts->use_angular_acc && opts->use_event_norm)){
  4320. q2 = meas.q2;
  4321. }
  4322. eff = this->get_ang_eff(opts,q2, meas.costhetal_fa, meas.costhetak_fa, meas.phi_fa);
  4323. if (eff > EFF_CUTOFF){
  4324. if (opts->multiply_eff) meas.weight *= 1.0/eff;
  4325. else meas.weight = 1.0/eff;
  4326. }
  4327. else{
  4328. spdlog::warn("Event with too low efficiency: {0:f}", eff);
  4329. spdlog::warn("\t q2: {0:f} \tq2_eff {1:f} \tctl: {2:f} \tctk: {3:f} \tphi: {4:f} ",
  4330. meas.q2, q2, meas.costhetal_fa, meas.costhetak_fa , meas.phi_fa);
  4331. if (opts->multiply_eff) meas.weight *= 1.0;
  4332. else meas.weight = 1.0;
  4333. }
  4334. }
  4335. return;
  4336. }
  4337. else return;
  4338. }
  4339. ////////////////////////
  4340. /// Full angular ///
  4341. ////////////////////////
  4342. //--------------------//
  4343. // S-wave
  4344. //--------------------//
  4345. void bu2kstarmumu_pdf::swave_fj(double ctl, double ctk, double phi,
  4346. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6) const{
  4347. f1 = C_SWAVE * sintheta2(ctl);
  4348. f2 = C_SWAVE * sintheta2(ctl)*ctk;
  4349. f3 = C_SWAVE * sin2theta(ctl)*sintheta_abs(ctk)*cos(phi);
  4350. f4 = C_SWAVE * sintheta_abs(ctl)*sintheta_abs(ctk)*cos(phi);
  4351. f5 = C_SWAVE * sintheta_abs(ctl)*sintheta_abs(ctk)*sin(phi);
  4352. f6 = C_SWAVE * sin2theta(ctl)*sintheta_abs(ctk)*sin(phi);
  4353. }
  4354. void bu2kstarmumu_pdf::swave_integrated_fj_noacc(double& f1, double& f2, double& f3, double& f4, double& f5, double& f6) const{
  4355. f1 = 1.0;
  4356. f2 = 0.0;
  4357. f3 = 0.0;
  4358. f4 = 0.0;
  4359. f5 = 0.0;
  4360. f6 = 0.0;
  4361. swave_integrated_fj_noacc(opts->ctl_min, opts->ctl_max, opts->ctk_min, opts->ctk_max, opts->phi_min, opts->phi_max,
  4362. f1, f2, f3, f4, f5, f6);
  4363. }
  4364. void bu2kstarmumu_pdf::swave_integrated_fj_noacc(double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b,
  4365. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6) const{
  4366. f1 = C_SWAVE * integrate_s_f1(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4367. f2 = C_SWAVE * integrate_s_f2(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4368. f3 = C_SWAVE * integrate_s_f3(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4369. f4 = C_SWAVE * integrate_s_f4(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4370. f5 = C_SWAVE * integrate_s_f5(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4371. f6 = C_SWAVE * integrate_s_f6(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4372. return;
  4373. }
  4374. void bu2kstarmumu_pdf::swave_integrated_fj_chebyshev(double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b,
  4375. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6, double q2) const //TODO: modify this according to the normDebug branch
  4376. {
  4377. f1 = 0.0; f2 = 0.0; f3 = 0.0; f4 = 0.0; f5 = 0.0; f6 = 0.0;
  4378. npolynom npol(opts);
  4379. assert(coeffs_eff_4d.size() == npol.getSize());
  4380. double chijk = 0.0;
  4381. for (unsigned int h = 0; h<npol.q2; h++){
  4382. for (unsigned int i = 0; i<npol.ctl; i++){
  4383. for (unsigned int j = 0; j<npol.ctk; j++){
  4384. for (unsigned int k = 0; k<npol.phi; k++){
  4385. const unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  4386. chijk = C_SWAVE*pow(q2, h)*coeffs_eff_4d.at(bin);
  4387. f1 += chijk * integrate_s_f1(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4388. f2 += chijk * integrate_s_f2(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4389. f3 += chijk * integrate_s_f3(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4390. f4 += chijk * integrate_s_f4(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4391. f5 += chijk * integrate_s_f5(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4392. f6 += chijk * integrate_s_f6(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4393. }
  4394. }
  4395. }
  4396. }
  4397. return;
  4398. };
  4399. void bu2kstarmumu_pdf::swave_integrated_fj_chebyshev(double& f1, double& f2, double& f3, double& f4, double& f5, double& f6, double q2) const{
  4400. f1 = 0.0; f2 = 0.0; f3 = 0.0; f4 = 0.0; f5 = 0.0; f6 = 0.0;
  4401. swave_integrated_fj_chebyshev(CTL_MIN, CTL_MAX, CTK_MIN, CTK_MAX, PHI_MIN, PHI_MAX,
  4402. f1, f2, f3, f4, f5, f6, q2);
  4403. return;
  4404. };
  4405. //--------------------//
  4406. // P-wave
  4407. //--------------------//
  4408. void bu2kstarmumu_pdf::fj(double ctl, double ctk, double phi,
  4409. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6,
  4410. double& f7, double& f8, double& f9, double& f10, double& f11, double& f12) const{
  4411. f1 = C_PWAVE * sintheta2(ctk); //j1s = 3/4*(1-FL)
  4412. f2 = C_PWAVE * costheta2(ctk); //j1c = FL
  4413. f3 = C_PWAVE * sintheta2(ctk)*cos2theta(ctl); //j2s = 1/4*(1-FL)
  4414. f4 = C_PWAVE * costheta2(ctk)*cos2theta(ctl); //j2c = -FL
  4415. f5 = C_PWAVE * sintheta2(ctk)*sintheta2(ctl)*cos(2.0*phi); //j3
  4416. f6 = C_PWAVE * sin2theta(ctk)*sin2theta(ctl)*cos(phi); //j4
  4417. f7 = C_PWAVE * sin2theta(ctk)*sintheta_abs(ctl)*cos(phi); //j5
  4418. f8 = C_PWAVE * sintheta2(ctk)*ctl; //j6s
  4419. f9 = C_PWAVE * costheta2(ctk)*ctl; //j6c
  4420. f10 = C_PWAVE * sin2theta(ctk)*sintheta_abs(ctl)*sin(phi); //j7
  4421. f11 = C_PWAVE * sin2theta(ctk)*sin2theta(ctl)*sin(phi); //j8
  4422. f12 = C_PWAVE * sintheta2(ctk)*sintheta2(ctl)*sin(2.0*phi); //j9
  4423. };
  4424. void bu2kstarmumu_pdf::integrated_fj_noacc(double& f1, double& f2, double& f3, double& f4, double& f5, double& f6,
  4425. double& f7, double& f8, double& f9, double& f10, double& f11, double& f12) const{
  4426. //Normalization of the p-wave in principle
  4427. f1 = 0.0; f2 = 0.0; f3 = 0.0; f4 = 0.0; f5 = 0.0; f6 = 0.0;
  4428. f7 = 0.0; f8 = 0.0; f9 = 0.0; f10 = 0.0; f11 = 0.0; f12 = 0.0;
  4429. integrated_fj_noacc(CTL_MIN, CTL_MAX, CTK_MIN, CTK_MAX, PHI_MIN, PHI_MAX,
  4430. f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12);
  4431. return;
  4432. };
  4433. void bu2kstarmumu_pdf::integrated_fj_noacc(double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b,
  4434. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6,
  4435. double& f7, double& f8, double& f9, double& f10, double& f11, double& f12) const{
  4436. f1 = C_PWAVE * integrate_f1(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4437. f2 = C_PWAVE * integrate_f2(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4438. f3 = C_PWAVE * integrate_f3(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4439. f4 = C_PWAVE * integrate_f4(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4440. f5 = C_PWAVE * integrate_f5(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4441. f6 = C_PWAVE * integrate_f6(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4442. f7 = C_PWAVE * integrate_f7(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4443. f8 = C_PWAVE * integrate_f8(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4444. f9 = C_PWAVE * integrate_f9(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4445. f10 = C_PWAVE * integrate_f10(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4446. f11 = C_PWAVE * integrate_f11(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4447. f12 = C_PWAVE * integrate_f12(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4448. return;
  4449. };
  4450. void bu2kstarmumu_pdf::integrated_fj_chebyshev(double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b,
  4451. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6,
  4452. double& f7, double& f8, double& f9, double& f10, double& f11, double& f12, double q2) const{
  4453. f1 = 0.0;
  4454. f2 = 0.0;
  4455. f3 = 0.0;
  4456. f4 = 0.0;
  4457. f5 = 0.0;
  4458. f6 = 0.0;
  4459. f7 = 0.0;
  4460. f8 = 0.0;
  4461. f9 = 0.0;
  4462. f10 = 0.0;
  4463. f11 = 0.0;
  4464. f12 = 0.0;
  4465. //new improved non-factorizing acceptance
  4466. npolynom npol = npolynom(opts);
  4467. assert(coeffs_eff_4d.size() == npol.getSize());
  4468. for (unsigned int h = 0; h<npol.q2; h++){
  4469. for (unsigned int i = 0; i<npol.ctl; i++){
  4470. for (unsigned int j = 0; j<npol.ctk; j++){
  4471. for (unsigned int k = 0; k<npol.phi; k++){
  4472. const unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  4473. double chijk = C_PWAVE*coeffs_eff_4d.at(bin)*pow(q2, h); //9/32pi * angCorr(bin) * q2^h (not integrating over q2)
  4474. f1 += chijk * integrate_f1(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4475. f2 += chijk * integrate_f2(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4476. f3 += chijk * integrate_f3(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4477. f4 += chijk * integrate_f4(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4478. f5 += chijk * integrate_f5(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4479. f6 += chijk * integrate_f6(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4480. f7 += chijk * integrate_f7(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4481. f8 += chijk * integrate_f8(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4482. f9 += chijk * integrate_f9(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4483. f10 += chijk * integrate_f10(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4484. f11 += chijk * integrate_f11(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4485. f12 += chijk * integrate_f12(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4486. }
  4487. }
  4488. }
  4489. }
  4490. }
  4491. void bu2kstarmumu_pdf::integrated_fj_chebyshev(double& f1, double& f2, double& f3, double& f4, double& f5, double& f6,
  4492. double& f7, double& f8, double& f9, double& f10, double& f11, double& f12, double q2) const{
  4493. f1 = 0.0; f2 = 0.0; f3 = 0.0; f4 = 0.0; f5 = 0.0; f6 = 0.0;
  4494. f7 = 0.0; f8 = 0.0; f9 = 0.0; f10 = 0.0; f11 = 0.0; f12 = 0.0;
  4495. integrated_fj_chebyshev(CTL_MIN, CTL_MAX, CTK_MIN, CTK_MAX, PHI_MIN, PHI_MAX,
  4496. f1, f2, f3, f4, f5, f6,
  4497. f7, f8, f9, f10, f11, f12, q2);
  4498. return;
  4499. };
  4500. /////////////////////
  4501. ///Angular folding///
  4502. /////////////////////
  4503. //S-wave
  4504. void bu2kstarmumu_pdf::folded_swave_fj(double ctl, double ctk, double phi,
  4505. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6) const
  4506. {
  4507. double c = C_SWAVE*2.0; // folding in phi
  4508. if(opts->folding > 0) c *= 2.0; //folding in cos(thetaL)
  4509. f2 = 0.0; f3 = 0.0; f4 = 0.0; f5 = 0.0; f6 = 0.0;
  4510. f1 = c * sintheta2(ctl);
  4511. if(opts->folding != 4) f2 = c * sintheta2(ctl)*(ctk);
  4512. if(opts->folding == 1) f3 = c * sintheta_abs(ctk)*sin2theta(ctl)*cos(phi);
  4513. if(opts->folding == 2) f4 = c * sintheta_abs(ctk)*sintheta_abs(ctl)*cos(phi);
  4514. if(opts->folding > 2) f5 = c * sintheta_abs(ctk)*sintheta_abs(ctl)*sin(phi);
  4515. //f6 always zero no matter what folding
  4516. }
  4517. void bu2kstarmumu_pdf::folded_swave_integrated_fj_noacc(double& f1, double& f2, double& f3, double& f4, double& f5, double& f6) const
  4518. {
  4519. f1 = 1.0;
  4520. f2 = 0.0;
  4521. f3 = 0.0;
  4522. f4 = 0.0;
  4523. f5 = 0.0;
  4524. f6 = 0.0;
  4525. folded_swave_integrated_fj_noacc(opts->ctl_min, opts->ctl_max, opts->ctk_min, opts->ctk_max, opts->phi_min, opts->phi_max,
  4526. f1, f2, f3, f4, f5, f6);
  4527. }
  4528. void bu2kstarmumu_pdf::folded_swave_integrated_fj_noacc(double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b,
  4529. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6) const{
  4530. double c = C_SWAVE*2.0; // folding in phi
  4531. if(opts->folding > 0) c *= 2.0; //folding in cos(thetaL)
  4532. f2 = 0.0; f3 = 0.0; f4 = 0.0; f5 = 0.0;
  4533. f1 = c * integrate_s_f1(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4534. if(opts->folding != 4) f2 = c * integrate_s_f2(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4535. if(opts->folding == 1) f3 = c * integrate_s_f3(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4536. if(opts->folding == 2) f4 = c * integrate_s_f4(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4537. if(opts->folding > 2) f5 = c * integrate_s_f5(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4538. f6 = 0.0;
  4539. return;
  4540. }
  4541. void bu2kstarmumu_pdf::folded_swave_integrated_fj_chebyshev(double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b,
  4542. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6, double q2) const{
  4543. double c = C_SWAVE*2.0; // folding in phi
  4544. if(opts->folding > 0) c *= 2.0; //folding in cos(thetaL)
  4545. f1 = 0.0; f2 = 0.0; f3 = 0.0; f4 = 0.0; f5 = 0.0; f6 = 0.0;
  4546. npolynom npol = npolynom(opts);
  4547. assert(coeffs_eff_4d.size() == npol.getSize());
  4548. double chijk = 0.0;
  4549. for (unsigned int h = 0; h<npol.q2; h++){
  4550. for (unsigned int i = 0; i<npol.ctl; i++){
  4551. for (unsigned int j = 0; j<npol.ctk; j++){
  4552. for (unsigned int k = 0; k<npol.phi; k++){
  4553. const unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  4554. chijk = c*pow(q2, h)*coeffs_eff_4d.at(bin);
  4555. f1 += chijk * integrate_s_f1(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4556. if(opts->folding != 4) f2 += chijk * integrate_s_f2(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4557. if(opts->folding == 1) f3 += chijk * integrate_s_f3(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4558. if(opts->folding == 2) f4 += chijk * integrate_s_f4(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4559. if(opts->folding > 2) f5 += chijk * integrate_s_f5(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4560. f6 = 0.0;
  4561. }
  4562. }
  4563. }
  4564. }
  4565. }
  4566. void bu2kstarmumu_pdf::folded_swave_integrated_fj_chebyshev(double& f1, double& f2, double& f3, double& f4, double& f5, double& f6, double q2) const{
  4567. folded_swave_integrated_fj_chebyshev(opts->ctl_min, opts->ctl_max, opts->ctk_min, opts->ctk_max, opts->phi_min, opts->phi_max,
  4568. f1, f2, f3, f4, f5, f6, q2);
  4569. return;
  4570. }
  4571. //P-wave
  4572. void bu2kstarmumu_pdf::folded_fj(double ctl, double ctk, double phi, double& f1, double& f2, double& f3, double& f4, double& f5, double& f6, double& f7, double& f8, double& f9, double& f10, double& f11, double& f12) const
  4573. {
  4574. //reset all coefficients that might not be calculated due to folding!
  4575. f6 = 0.;
  4576. f7 = 0.;
  4577. f8 = 0.;
  4578. f9 = 0.;
  4579. f10 = 0.;
  4580. f11 = 0.;
  4581. f12 = 0.;
  4582. //constant coefficient
  4583. double c = 2.0*C_PWAVE; //multiply by 2 due to folding in phi
  4584. if(opts->folding > 0) c *= 2.0; //folding in cos(thetaL)
  4585. f1 = c * sintheta2(ctk); //j1s = 3/4*(1-FL)
  4586. f2 = c * costheta2(ctk); //j1c = FL
  4587. f3 = c * sintheta2(ctk)*cos2theta(ctl); //j2s = 1/4*(1-FL)
  4588. f4 = c * costheta2(ctk)*cos2theta(ctl); //j2c = -FL
  4589. f5 = c * sintheta2(ctk)*sintheta2(ctl)*cos(2.0*phi); //j3
  4590. if(opts->folding == 1) f6 = c * sin2theta(ctk)*sin2theta(ctl)*cos(phi); //j4
  4591. if(opts->folding == 2) f7 = c * sin2theta(ctk)*sintheta_abs(ctl)*cos(phi); //j5
  4592. if(opts->folding == 0){
  4593. f8 = c * sintheta2(ctk)*ctl; //j6s
  4594. f9 = c * costheta2(ctk)*ctl; //j6c
  4595. }
  4596. if(opts->folding == 3) f10 = c * sin2theta(ctk)*sintheta_abs(ctl)*sin(phi); //j7
  4597. if(opts->folding == 4) f11 = c * sin2theta(ctk)*sin2theta(ctl)*sin(phi); //j8
  4598. if(opts->folding == 0) f12 = c * sintheta2(ctk)*sintheta2(ctl)*sin(2.0*phi); //j9
  4599. };
  4600. void bu2kstarmumu_pdf::folded_integrated_fj_noacc(double& f1, double& f2, double& f3, double& f4, double& f5, double& f6, double& f7, double& f8, double& f9, double& f10, double& f11, double& f12) const
  4601. {
  4602. folded_integrated_fj_noacc(opts->ctl_min, opts->ctl_max, opts->ctk_min, opts->ctk_max, opts->phi_min, opts->phi_max,
  4603. f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12);
  4604. };
  4605. void bu2kstarmumu_pdf::folded_integrated_fj_noacc(double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b,
  4606. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6, double& f7, double& f8, double& f9, double& f10, double& f11, double& f12) const
  4607. {
  4608. if(opts->full_angular){
  4609. spdlog::error("Cannot use folded integrals for full angular fit");
  4610. assert(0);
  4611. }
  4612. f1 = 0.0;
  4613. f2 = 0.0;
  4614. f3 = 0.0;
  4615. f4 = 0.0;
  4616. f5 = 0.0;
  4617. f6 = 0.0;
  4618. f7 = 0.0;
  4619. f8 = 0.0;
  4620. f9 = 0.0;
  4621. f10 = 0.0;
  4622. f11 = 0.0;
  4623. f12 = 0.0;
  4624. //copied from full angular integral:
  4625. double c = C_PWAVE*2.; //folding in phi
  4626. if(opts->folding > 0)c *= 2.; //folding in cos(theta_L)
  4627. f1 = c * integrate_f1(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4628. f2 = c * integrate_f2(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4629. f3 = c * integrate_f3(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4630. f4 = c * integrate_f4(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4631. f5 = c * integrate_f5(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4632. if(opts->folding == 0){
  4633. f8 = c * integrate_f8(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4634. f9 = c * integrate_f9(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4635. f12 = c * integrate_f12(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4636. }
  4637. else if(opts->folding == 1) f6 = c * integrate_f6(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4638. else if(opts->folding == 2) f7 = c * integrate_f7(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4639. else if(opts->folding == 3) f10 = c * integrate_f10(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4640. else if(opts->folding == 4) f11 = c * integrate_f11(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, 0, 0, 0);
  4641. return;
  4642. };
  4643. void bu2kstarmumu_pdf::folded_integrated_fj_chebyshev(double ctl_a, double ctl_b, double ctk_a, double ctk_b, double phi_a, double phi_b,
  4644. double& f1, double& f2, double& f3, double& f4, double& f5, double& f6, double& f7, double& f8, double& f9, double& f10, double& f11, double& f12, double q2) const{
  4645. if(opts->full_angular){
  4646. spdlog::error("Cannot use folded integrals for full angular fit");
  4647. assert(0);
  4648. }
  4649. double c = C_PWAVE* 2.; //folding in phi
  4650. if(opts->folding > 0)c *= 2.; //folding in cos(theta_L)
  4651. f1 = 0.0;
  4652. f2 = 0.0;
  4653. f3 = 0.0;
  4654. f4 = 0.0;
  4655. f5 = 0.0;
  4656. f6 = 0.0;
  4657. f7 = 0.0;
  4658. f8 = 0.0;
  4659. f9 = 0.0;
  4660. f10 = 0.0;
  4661. f11 = 0.0;
  4662. f12 = 0.0;
  4663. //new improved non-factorizing acceptance
  4664. npolynom npol = npolynom(opts);
  4665. assert(coeffs_eff_4d.size() == npol.getSize());
  4666. double chijk = 0.0;
  4667. for (unsigned int h = 0; h<npol.q2; h++)
  4668. for (unsigned int i = 0; i<npol.ctl; i++)
  4669. for (unsigned int j = 0; j<npol.ctk; j++)
  4670. for (unsigned int k = 0; k<npol.phi; k++)
  4671. {
  4672. const unsigned int bin = npol.get_bin_in4D(h,i,j,k);
  4673. chijk = c*pow(q2, h)*coeffs_eff_4d.at(bin);
  4674. f1 += chijk*integrate_f1(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4675. f2 += chijk*integrate_f2(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4676. f3 += chijk*integrate_f3(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4677. f4 += chijk*integrate_f4(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4678. f5 += chijk*integrate_f5(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4679. if(opts->folding == 0){
  4680. f8 += chijk*integrate_f8(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4681. f9 += chijk*integrate_f9(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4682. f12 += chijk*integrate_f12(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4683. }
  4684. else if(opts->folding == 1) f6 += chijk*integrate_f6(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4685. else if(opts->folding == 2) f7 += chijk*integrate_f7(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4686. else if(opts->folding == 3) f10 += chijk*integrate_f10(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4687. else if(opts->folding == 4) f11 += chijk*integrate_f11(ctl_a, ctl_b, ctk_a, ctk_b, phi_a, phi_b, i, j, k);
  4688. }
  4689. };
  4690. void bu2kstarmumu_pdf::folded_integrated_fj_chebyshev(double& f1, double& f2, double& f3, double& f4, double& f5, double& f6, double& f7, double& f8, double& f9, double& f10, double& f11, double& f12, double q2) const{
  4691. folded_integrated_fj_chebyshev(opts->ctl_min, opts->ctl_max, opts->ctk_min, opts->ctk_max, opts->phi_min, opts->phi_max,
  4692. f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, q2);
  4693. return;
  4694. };
  4695. void bu2kstarmumu_pdf::calculate_sweights(const bu2kstarmumu_parameters* parms, std::vector<event>* ev) const
  4696. {
  4697. assert(opts->extended_ml);
  4698. parameter* psig = parms->get_parameter("n_sig");
  4699. parameter* pbkg = parms->get_parameter("n_bkg");
  4700. if (psig != 0 && pbkg != 0){
  4701. double nsig = psig->get_value();
  4702. double nbkg = pbkg->get_value();
  4703. double sweight = 0.0, prob_sig_m = 0.0, prob_bkg_m = 0.0;
  4704. //obtain inverse variant matrix (V_{nj}^{-1})
  4705. double inv_cov_matrix[2*2] = {0.0, 0.0, 0.0, 0.0};
  4706. for (unsigned int i = 0; i<ev->size(); i++){
  4707. const event& meas = ev->at(i);
  4708. prob_sig_m = m_sig_prob(parms, meas);
  4709. prob_bkg_m = m_bkg_prob(parms, meas);
  4710. inv_cov_matrix[0] += prob_sig_m*prob_sig_m/sqr(nsig*prob_sig_m + nbkg*prob_bkg_m);
  4711. inv_cov_matrix[1] += prob_sig_m*prob_bkg_m/sqr(nsig*prob_sig_m + nbkg*prob_bkg_m);
  4712. inv_cov_matrix[2] += prob_bkg_m*prob_sig_m/sqr(nsig*prob_sig_m + nbkg*prob_bkg_m);
  4713. inv_cov_matrix[3] += prob_bkg_m*prob_bkg_m/sqr(nsig*prob_sig_m + nbkg*prob_bkg_m);
  4714. }
  4715. spdlog::info("Inverse covariance matrix");
  4716. spdlog::info("{0:0.8f} {1:.8f}", inv_cov_matrix[0],inv_cov_matrix[1] );
  4717. spdlog::info("{0:0.8f} {1:.8f}", inv_cov_matrix[2],inv_cov_matrix[3] );
  4718. //invert inserve matrix to get V_{nj}
  4719. double cov_matrix[2*2] = {0.0, 0.0, 0.0, 0.0};
  4720. cov_matrix[0] = +inv_cov_matrix[3]/(inv_cov_matrix[0]*inv_cov_matrix[3]-inv_cov_matrix[1]*inv_cov_matrix[2]);
  4721. cov_matrix[1] = -inv_cov_matrix[1]/(inv_cov_matrix[0]*inv_cov_matrix[3]-inv_cov_matrix[1]*inv_cov_matrix[2]);
  4722. cov_matrix[2] = -inv_cov_matrix[2]/(inv_cov_matrix[0]*inv_cov_matrix[3]-inv_cov_matrix[1]*inv_cov_matrix[2]);
  4723. cov_matrix[3] = +inv_cov_matrix[0]/(inv_cov_matrix[0]*inv_cov_matrix[3]-inv_cov_matrix[1]*inv_cov_matrix[2]);
  4724. spdlog::info("Covariance matrix");
  4725. spdlog::info("{0:0.8f} {1:.8f}", cov_matrix[0], cov_matrix[1] );
  4726. spdlog::info("{0:0.8f} {1:.8f}", cov_matrix[2], cov_matrix[3] );
  4727. //get sWeights for all events
  4728. for (unsigned int i = 0; i<ev->size(); i++){
  4729. const event& meas = ev->at(i);
  4730. prob_sig_m = m_sig_prob(parms, meas);
  4731. prob_bkg_m = m_bkg_prob(parms, meas);
  4732. sweight = (prob_sig_m * cov_matrix[0] + prob_bkg_m * cov_matrix[1]) / ( prob_sig_m * nsig + prob_bkg_m * nbkg );
  4733. ev->at(i).sweight = sweight;
  4734. }
  4735. }
  4736. };
  4737. void bu2kstarmumu_pdf::save_coeffs_eff_phsp_4d(){
  4738. std::ofstream ostr(coeffs_eff_phsp_4D(opts));
  4739. for(unsigned int c = 0; c < this->coeffs_eff_4d.size(); c++){
  4740. ostr << std::setprecision(15) << std::scientific << this->coeffs_eff_4d.at(c) << "\n";
  4741. }
  4742. spdlog::info("[SAVE]\t\tSaved a total of {0:d} angular acceptance correction coefficients",this->coeffs_eff_4d.size());
  4743. }
  4744. std::vector<double> bu2kstarmumu_pdf::read_coeffs_eff_phsp_4d(){
  4745. unsigned int nCoeffs = opts->eff_order_q2 * opts->eff_order_costhetal * opts->eff_order_costhetak * opts->eff_order_phi;
  4746. std::string filename = coeffs_eff_phsp_4D(opts);
  4747. std::ifstream file(filename);
  4748. if(!file.is_open())spdlog::error("File " + filename + " not found to load coefficients!");
  4749. else spdlog::info("Loading a total of {0:d} coefficients from file " + filename + ".",nCoeffs);
  4750. std::string line;
  4751. double coeff;
  4752. std::vector<double>coeffs;
  4753. assert(file.is_open());
  4754. while(1){
  4755. getline(file, line);
  4756. if(file.eof())break;
  4757. std::istringstream istr(line);
  4758. istr >> coeff;
  4759. coeffs.push_back(coeff);
  4760. }
  4761. if(coeffs.size() != nCoeffs){
  4762. spdlog::critical("Number of coefficients loaded from file ({0:d}) does not match the number of configurated coefficients ({1:d}). Abort", coeffs.size(), nCoeffs);
  4763. assert(0);
  4764. }
  4765. return coeffs;
  4766. }
  4767. void bu2kstarmumu_pdf::load_coeffs_eff_phsp_4d(){
  4768. this->coeffs_eff_4d = read_coeffs_eff_phsp_4d();
  4769. }