42 #include "TStopwatch.h"
44 #include "TLorentzVector.h"
46 #include "TGenPhaseSpace.h"
54 #include "reportingUtils.hpp"
55 #include "physUtils.hpp"
56 #include "conversionUtils.hpp"
70 const double maxPt = 0.150,
71 const double maxEta = 1)
73 double pt = maxPt * random.Rndm();
74 double eta = 2 * maxEta * random.Rndm() - maxEta;
75 double phi = 4 * asin(1.) * random.Rndm();
76 double tanhEta = tanh(eta);
77 TLorentzVector mother;
78 mother.SetPx(pt * cos(phi));
79 mother.SetPy(pt * sin(phi));
80 mother.SetPz(tanhEta * sqrt((mass * mass + pt * pt) / (1 - tanhEta * tanhEta)));
81 mother.SetVectM(mother.Vect(),
mass);
92 const double mass_2 = var[0];
95 const double M = par[0];
96 const double* m = &par[1];
97 const bool min = (par[4] < 0) ?
true :
false;
105 const unsigned int nmbCol = 3;
106 Double_t rChannel[nmbCol] = {0, 1, 1};
107 Double_t gChannel[nmbCol] = {0, 1, 0};
108 Double_t bChannel[nmbCol] = {1, 1, 0};
109 Double_t zPos [nmbCol] = {0, 0.5, 1};
110 TColor::CreateGradientColorTable(nmbCol, zPos, rChannel, gChannel, bChannel, nmbSteps);
119 const double m01_2 = var[0];
120 const double m12_2 = var[1];
123 const double M = par[1];
124 const double* m = &par[2];
142 const double* funcPar,
143 int maxNmbOfPoints = 10000,
144 double epsilon = 0.00001)
147 return f->Integral(min[0], max[0], funcPar);
148 f->SetParameters(funcPar);
152 double result = f->IntegralMultiple(n, min, max, -1, maxNmbOfPoints, epsilon, resRelErr, nmbOfFuncEval, errCode);
161 const int n =
static_cast<int>(par[0]);
162 const double* m = &par[1];
165 for (
int i = 1;
i < (n - 1); ++
i)
167 M[n - 1] = par[n + 1];
170 for (
int i = 1;
i <
n; ++
i)
171 if (M[
i] < M[
i - 1] + m[
i]) {
177 for (
int i = 1; i <
n; ++
i)
178 momProd *= breakupMomentum(M[i], M[i - 1], m[i]);
190 const double M_n = var[0];
192 const int n =
static_cast<int>(par[0]);
193 const double* m = &par[1];
194 const double A = par[n + 1];
198 for (
int i = 0;
i <
n; ++
i)
204 const double f_n = 1 / (2 * pow(twoPi, 2 * n - 3));
207 const double norm = f_n / M_n;
210 return A * norm * breakupMomentum(M_n, m[0], m[1]);
213 double lipsPar[n + 2];
215 for (
int i = 1;
i <=
n; ++
i)
216 lipsPar[
i] = m[
i - 1];
217 lipsPar[n + 1] = M_n;
221 min[0] = m[0] + m[1];
222 for (
int i = 1;
i < n - 2; ++
i)
223 min[
i] = min[
i - 1] + m[
i + 1];
226 for (
int i = n - 3;
i >= 0; --
i) {
232 return A * norm *
nDimIntegral(
dLips, n - 2, min, max, lipsPar, 500000, 0.00001);
237 const string& outFileName =
"./testNBodyPhaseSpaceGen.root")
243 const unsigned int n = 3;
245 const double massRange[2] = {m[0] + m[1] + m[2], 2};
246 const double mass = (massRange[0] + massRange[1]) / 2;
247 const unsigned int seed = 1234567890;
248 const bool hitMissMode =
false;
251 printInfo <<
"creating output file '" << outFileName <<
"' ... " << endl;
252 TFile* outFile = TFile::Open(outFileName.c_str(),
"RECREATE");
254 printErr <<
"could not create output file. aborting..." << endl;
257 cout <<
" ... success" << endl;
260 const unsigned int nmbGen = 5;
262 for (
unsigned int i = 0;
i < nmbGen; ++
i)
269 for (
unsigned int i = 0;
i < 4; ++
i)
270 gen[
i]->setKinematicsType(nBodyPhaseSpaceGen::RAUBOLD_LYNCH);
272 for (
unsigned int i = 0;
i < nmbGen; ++
i) {
279 gRandom->SetSeed(seed);
280 double maxTGenWeight = 0;
281 for (
unsigned int i = 0;
i < 10000; ++
i) {
282 TLorentzVector mother(0, 0, 0, mass);
283 TGen.SetDecay(mother, (
int)n, m);
284 const double weight = TGen.Generate();
285 maxTGenWeight = (weight > maxTGenWeight) ? weight : maxTGenWeight;
287 maxTGenWeight *= 1.01;
288 double maxTGenWeightObserved = 0;
289 TRandom3 random(seed);
292 TH2F* hDalitz [nmbGen + 1];
293 TH1F* hMass [nmbGen + 1];
294 for (
unsigned int i = 0;
i < nmbGen; ++
i) {
295 hDalitz[
i] =
new TH2F((
"hDalitz" + toString(
i)).c_str(),
296 (
"Dalitz Plot Residuum nBodyPhaseSpaceGen " + toString(
i) +
";m_{01}^{2} [(GeV/c^{2})^{2}];m_{12}^{2} [(GeV/c^{2})^{2}]").c_str(),
297 100, 0, 1.5, 100, 0, 1.5);
298 hMass[
i] =
new TH1F((
"hMass" + toString(
i)).c_str(),
299 (
"Mother Mass nBodyPhaseSpaceGen " + toString(
i) +
";m [GeV/c^{2}]").c_str(),
302 hDalitz [nmbGen] =
new TH2F(
"hDalitzTGen",
"Dalitz Plot Residuum TGen;m_{01}^{2} [(GeV/c^{2})^{2}];m_{12}^{2} [(GeV/c^{2})^{2}]", 100, 0, 1.5, 100, 0, 1.5);
303 hMass [nmbGen] =
new TH1F(
"hMassTGen",
"Mother Mass TGen;m [GeV/c^{2}]", 1000, 0, 2.5);
304 TH1F* hMassRaw =
new TH1F(
"hMassRaw",
"Mother Mass Raw;m [GeV/c^{2}]", 1000, 0, 2.5);
307 printInfo <<
"testing generators for constant 3-body mass = " << mass <<
" GeV/c^2" << endl
308 <<
" generating " << nmbEvents <<
" events ... " << endl;
309 unsigned int countAtt[nmbGen + 1];
310 unsigned int countAcc[nmbGen + 1];
312 for (
unsigned int i = 0;
i <= nmbGen; ++
i)
313 countAtt[
i] = countAcc[
i] = 0;
316 for (
unsigned int i = 0;
i < nmbGen; ++
i)
317 if (countAcc[
i] < nmbEvents){
319 if (gen[
i]->generateDecayAccepted(mother)) {
323 hDalitz[
i]->Fill(m01.M2(), m12.M2());
326 TGen.SetDecay(mother, (
int)n, m);
327 const double TGenWeight = TGen.Generate();
328 maxTGenWeightObserved = (TGenWeight > maxTGenWeightObserved) ? TGenWeight : maxTGenWeightObserved;
329 if (countAcc[nmbGen] < nmbEvents) {
331 if ((TGenWeight / maxTGenWeight) > random.Rndm()) {
333 const TLorentzVector m01 = *TGen.GetDecay(0) + *TGen.GetDecay(1);
334 const TLorentzVector m12 = *TGen.GetDecay(1) + *TGen.GetDecay(2);
335 hDalitz[nmbGen]->Fill(m01.M2(), m12.M2());
339 for (
unsigned int i = 0;
i <= nmbGen; ++
i)
340 if (countAcc[
i] < nmbEvents)
343 cout <<
" ... done." << endl << endl;
344 for (
unsigned int i = 0;
i < nmbGen; ++
i)
345 printInfo <<
"gen[" <<
i <<
"]: " << countAtt[
i] <<
" attempts, " << ((
double)nmbEvents / countAtt[
i]) * 100 <<
" % efficiency" << endl
347 printInfo <<
"TGenPhaseSpace: " << countAtt[nmbGen] <<
" attempts, " << ((double)nmbEvents / countAtt[nmbGen]) * 100 <<
" % efficiency" << endl
348 <<
"TGenPhaseSpace maximum weight = " << maxTGenWeight
349 <<
" vs. maximum weight observed = " << maxTGenWeightObserved << endl << endl;
353 for (
unsigned int i = 0;
i <= nmbGen; ++
i) {
355 const double xMin = (m[0] + m[1]) * (m[0] + m[1]);
356 const double xMax = (mass - m[2]) * (mass - m[2]);
357 const double yMin = (m[1] + m[2]) * (m[1] + m[2]);
358 const double yMax = (mass - m[0]) * (mass - m[0]);
359 TF2* dalitzFit =
new TF2(
"dalitzFit",
dalitzFitFunc, xMin, xMax, yMin, yMax, 5);
360 dalitzFit->SetParameter(0, 1);
361 dalitzFit->FixParameter(1, mass);
362 dalitzFit->FixParameter(2, m[0]);
363 dalitzFit->FixParameter(3, m[1]);
364 dalitzFit->FixParameter(4, m[2]);
365 const double dalitzInt = dalitzFit->Integral(xMin, xMax, yMin, yMax, 1e-6)
366 / (hDalitz[
i]->GetXaxis()->GetBinWidth(1) * hDalitz[
i]->GetYaxis()->GetBinWidth(1));
367 dalitzFit->SetParameter(0, nmbEvents / dalitzInt);
369 hDalitz[
i]->Add(dalitzFit, -1,
"I");
371 const double maxVal = max(fabs(hDalitz[
i]->GetMinimum()), fabs(hDalitz[
i]->GetMaximum()));
372 hDalitz[
i]->SetMinimum(-maxVal);
373 hDalitz[
i]->SetMaximum( maxVal);
374 hDalitz[
i]->SetContour(99);
375 hDalitz[
i]->Draw(
"COLZ");
378 dalitzBorder->SetParameter(0, mass);
379 dalitzBorder->SetParameter(1, m[0]);
380 dalitzBorder->SetParameter(2, m[1]);
381 dalitzBorder->SetParameter(3, m[2]);
382 dalitzBorder->SetParameter(4, -1);
383 dalitzBorder->SetNpx(1000);
384 dalitzBorder->SetLineWidth(1);
385 dalitzBorder->SetLineColor(3);
386 dalitzBorder->DrawCopy(
"SAME");
387 dalitzBorder->SetParameter(4, +1);
388 dalitzBorder->DrawCopy(
"SAME");
395 printInfo <<
"testing generators for 3-body in mass range [" << massRange[0] <<
", " << massRange[1] <<
"] GeV/c^2" << endl
396 <<
" generating " << nmbEvents <<
" events ... " << endl;
398 gen[0]->
setMaxWeight(1.01 * gen[0]->estimateMaxWeight(massRange[1]));
399 gen[1]->
setMaxWeight(1.01 * gen[1]->estimateMaxWeight(massRange[1]));
400 gen[2]->
setMaxWeight(1.01 * gen[2]->estimateMaxWeight(massRange[0] + 0.0001));
401 gen[3]->
setMaxWeight(1.01 * gen[3]->estimateMaxWeight(massRange[1]));
402 gen[4]->
setMaxWeight(1.01 * gen[4]->estimateMaxWeight(massRange[1]));
404 for (
unsigned int i = 0;
i < 10000; ++
i) {
405 TLorentzVector mother(0, 0, 0, massRange[0] + 0.0001);
406 TGen.SetDecay(mother, (
int)n, m);
407 const double weight = TGen.Generate();
408 maxTGenWeight = (weight > maxTGenWeight) ? weight : maxTGenWeight;
410 maxTGenWeight *= 1.01;
411 maxTGenWeightObserved = 0;
413 unsigned int countAtt[nmbGen + 1];
414 unsigned int countAcc[nmbGen + 1];
416 for (
unsigned int i = 0;
i <= nmbGen; ++
i)
417 countAtt[
i] = countAcc[
i] = 0;
419 TLorentzVector mother =
constructMother(random, massRange[0] + random.Rndm() * (massRange[1] - massRange[0]));
420 hMassRaw->Fill(mother.M());
421 for (
unsigned int i = 0;
i < nmbGen; ++
i)
422 if (countAcc[
i] < nmbEvents) {
425 if (gen[
i]->generateDecayAccepted(mother)) {
427 hMass[
i]->Fill(mother.M());
431 if (gen[
i]->eventAccepted())
435 TGen.SetDecay(mother, (
int)n, m);
436 const double TGenWeight = TGen.Generate();
437 maxTGenWeightObserved = (TGenWeight > maxTGenWeightObserved) ? TGenWeight : maxTGenWeightObserved;
438 if (countAcc[nmbGen] < nmbEvents) {
441 if ((TGenWeight / maxTGenWeight) > random.Rndm())
442 hMass[nmbGen]->Fill(mother.M());
444 hMass[nmbGen]->Fill(mother.M(), TGenWeight);
445 if ((TGenWeight / maxTGenWeight) > random.Rndm())
449 for (
unsigned int i = 0;
i <= nmbGen; ++
i)
450 if (countAcc[
i] < nmbEvents)
453 cout <<
" ... done." << endl << endl;
454 for (
unsigned int i = 0;
i < nmbGen; ++
i)
455 printInfo <<
"gen[" <<
i <<
"]: " << countAtt[
i] <<
" attempts, " << ((
double)nmbEvents / countAtt[
i]) * 100 <<
" % efficiency" << endl
457 printInfo <<
"TGenPhaseSpace: " << countAtt[nmbGen] <<
" attempts, " << ((double)nmbEvents / countAtt[nmbGen]) * 100 <<
" % efficiency" << endl
458 <<
"maximum weight = " << maxTGenWeight
459 <<
" vs. maximum weight observed = " << maxTGenWeightObserved << endl << endl;
463 TF1* Lips =
new TF1(
"nBodyPhaseSpace",
nBodyPhaseSpace, massRange[0], massRange[1], n + 2);
464 Lips->SetParameter(0, n);
465 for (
unsigned int i = 1;
i <=
n; ++
i)
466 Lips->SetParameter(
i, m[
i - 1]);
467 Lips->SetLineColor(2);
468 Lips->SetLineWidth(2);
469 for (
unsigned int i = 0;
i <= nmbGen; ++
i) {
470 Lips->SetParameter(n + 1, 1);
474 A = hMass[
i]->GetBinContent(hMass[
i]->FindBin(massRange[1]) - 1) / Lips->Eval(massRange[1]);
477 for (
int j = 1; j < hMassRaw->GetNbinsX(); ++j) {
478 const double nmbEvBin = hMassRaw->GetBinContent(j);
480 hMass[
i]->SetBinContent(j, hMass[
i]->GetBinContent(j) / nmbEvBin);
484 Lips->SetParameter(n + 1, A);
487 Lips->DrawCopy(
"LSAME");
489 hMass[
i]->Draw(
"SAME E");
496 const unsigned int n2 = 4;
499 const double massRange2[2] = {m2[0] + m2[1] + m2[2] + m2[3], 2};
500 printInfo <<
"comparing run time of generators for 4-body in mass range [" << massRange2[0] <<
", " << massRange2[1] <<
"] GeV/c^2" << endl
501 <<
" generating " << nmbEvents <<
" events using TGenPhaseSpace ... " << endl;
514 for (
unsigned int i = 0;
i < 10000; ++
i) {
515 TLorentzVector mother(0, 0, 0, massRange2[0] + 0.0001);
516 TGen.SetDecay(mother, (
int)n2, m2);
517 const double weight = TGen.Generate();
518 maxTGenWeight = (weight > maxTGenWeight) ? weight : maxTGenWeight;
520 maxTGenWeight *= 1.01;
521 maxTGenWeightObserved = 0;
525 unsigned int countAtt = 0;
526 unsigned int countAcc = 0;
527 random.SetSeed(seed);
528 while (countAcc < nmbEvents) {
529 TLorentzVector mother =
constructMother(random, massRange2[0] + random.Rndm() * (massRange2[1] - massRange2[0]));
530 TGen.SetDecay(mother, (
int)n2, m2);
531 const double TGenWeight = TGen.Generate();
532 maxTGenWeightObserved = (TGenWeight > maxTGenWeightObserved) ? TGenWeight : maxTGenWeightObserved;
534 if ((TGenWeight / maxTGenWeight) > random.Rndm())
538 const double timeTGen = timer2.RealTime();
539 cout <<
" ... done." << endl
540 <<
" " << countAtt <<
" attempts, " << ((double)nmbEvents / countAtt) * 100 <<
" % efficiency" << endl
541 <<
" consumed time: ";
544 cout <<
" TGenPhaseSpace maximum weight = " << maxTGenWeight
545 <<
" vs. maximum weight observed = " << maxTGenWeightObserved << endl;
547 cout << endl <<
" generating " << nmbEvents <<
" events using nBodyPhaseSpaceGen ... " << endl;
551 random.SetSeed(seed);
552 while (countAcc < nmbEvents) {
553 TLorentzVector mother =
constructMother(random, massRange2[0] + random.Rndm() * (massRange2[1] - massRange2[0]));
559 const double timeNBody = timer2.RealTime();
560 cout <<
" ... done." << endl
561 <<
" " << countAtt <<
" attempts, " << ((double)nmbEvents / countAtt) * 100 <<
" % efficiency" << endl
562 <<
" consumed time: ";
565 printInfo << gen2 << endl;
566 printInfo <<
"nBodyPhaseSpaceGen speed gain w.r.t. TGenPhaseSpace = " << 100 * timeTGen / timeNBody <<
" %" << endl << endl;
568 printInfo <<
"checking mass dependence of nBodyPhaseSpaceGen 4-body phase space in mass range [" << massRange2[0] <<
", " << massRange2[1] <<
"] GeV/c^2" << endl;
574 TH1F* hMass2 =
new TH1F(
"hMass4Body",
"4-Body Mass nBodyPhaseSpaceGen;m [GeV/c^{2}]", 1000, 0, 2.5);
577 random.SetSeed(seed);
578 while (countAcc < nmbEvents) {
579 TLorentzVector mother =
constructMother(random, massRange2[0] + random.Rndm() * (massRange2[1] - massRange2[0]));
583 hMass2->Fill(mother.M());
586 cout <<
" ... done." << endl
587 <<
" " << countAtt <<
" attempts, " << ((double)nmbEvents / countAtt) * 100 <<
" % efficiency" << endl
590 TF1* Lips =
new TF1(
"nBodyPhaseSpace",
nBodyPhaseSpace, massRange2[0], massRange2[1], n2 + 2);
591 Lips->SetParameter(0, n2);
592 for (
unsigned int i = 1;
i <= n2; ++
i)
593 Lips->SetParameter(
i, m2[
i - 1]);
594 Lips->SetLineColor(2);
595 Lips->SetLineWidth(2);
596 Lips->SetParameter(n2 + 1, 1);
597 const double A = hMass2->GetBinContent(hMass2->FindBin(massRange2[1]) - 1) / Lips->Eval(massRange2[1]);
598 Lips->SetParameter(n2 + 1, A);
601 Lips->DrawCopy(
"LSAME");
602 hMass2->Draw(
"SAME E");
606 printInfo << endl <<
"this job consumed: ";