laura is hosted by Hepforge, IPPP Durham
Laura++  v3r0
A maximum likelihood fitting package for performing Dalitz-plot analysis.
LauIsobarDynamics.cc
Go to the documentation of this file.
1 
2 // Copyright University of Warwick 2005 - 2014.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 // Authors:
7 // Thomas Latham
8 // John Back
9 // Paul Harrison
10 
15 #include <iostream>
16 #include <iomanip>
17 #include <fstream>
18 #include <set>
19 #include <vector>
20 
21 #include "TFile.h"
22 #include "TRandom.h"
23 #include "TSystem.h"
24 
25 #include "LauAbsEffModel.hh"
26 #include "LauAbsResonance.hh"
27 #include "LauAbsIncohRes.hh"
28 #include "LauBelleNR.hh"
29 #include "LauBelleSymNR.hh"
30 #include "LauCacheData.hh"
31 #include "LauConstants.hh"
32 #include "LauDaughters.hh"
34 #include "LauFitDataTree.hh"
35 #include "LauIsobarDynamics.hh"
36 #include "LauKinematics.hh"
37 #include "LauKMatrixProdPole.hh"
38 #include "LauKMatrixProdSVP.hh"
39 #include "LauKMatrixPropagator.hh"
40 #include "LauKMatrixPropFactory.hh"
41 #include "LauNRAmplitude.hh"
42 #include "LauPrint.hh"
43 #include "LauRandom.hh"
44 #include "LauResonanceMaker.hh"
45 
47 
48 // for Kpipi: only one scfFraction 2D histogram is needed
50  daughters_(daughters),
51  kinematics_(daughters_ ? daughters_->getKinematics() : 0),
52  effModel_(effModel),
53  nAmp_(0),
54  nIncohAmp_(0),
55  DPNorm_(0.0),
56  DPRate_("DPRate", 0.0, 0.0, 1000.0),
57  meanDPEff_("meanDPEff", 0.0, 0.0, 1.0),
58  currentEvent_(0),
59  symmetricalDP_(kFALSE),
60  fullySymmetricDP_(kFALSE),
61  integralsDone_(kFALSE),
62  normalizationSchemeDone_(kFALSE),
63  intFileName_("integ.dat"),
64  m13BinWidth_(0.005),
65  m23BinWidth_(0.005),
66  narrowWidth_(0.020),
67  binningFactor_(100.0),
68  m13Sq_(0.0),
69  m23Sq_(0.0),
70  mPrime_(0.0),
71  thPrime_(0.0),
72  tagCat_(-1),
73  eff_(1.0),
74  scfFraction_(0.0),
75  jacobian_(0.0),
76  ASq_(0.0),
77  evtLike_(0.0),
78  iterationsMax_(100000),
79  nSigGenLoop_(0),
80  aSqMaxSet_(1.25),
81  aSqMaxVar_(0.0),
82  flipHelicity_(kTRUE),
83  recalcNormalisation_(kFALSE)
84 {
85  if (daughters != 0) {
86  symmetricalDP_ = daughters->gotSymmetricalDP();
87  fullySymmetricDP_ = daughters->gotFullySymmetricDP();
88  typDaug_.push_back(daughters->getTypeDaug1());
89  typDaug_.push_back(daughters->getTypeDaug2());
90  typDaug_.push_back(daughters->getTypeDaug3());
91  }
92 
93  if (scfFractionModel != 0) {
94  scfFractionModel_[0] = scfFractionModel;
95  }
96 
97  sigResonances_.clear();
98  sigIncohResonances_.clear();
99  kMatrixPropagators_.clear();
100  kMatrixPropSet_.clear();
101  extraParameters_.clear();
102 }
103 
104 // for Kspipi, we need a scfFraction 2D histogram for each tagging category. They are provided by the map.
105 // Also, we need to know the place that the tagging category of the current event occupies in the data structure inputFitTree
107  daughters_(daughters),
108  kinematics_(daughters_ ? daughters_->getKinematics() : 0),
109  effModel_(effModel),
110  scfFractionModel_(scfFractionModel),
111  nAmp_(0),
112  nIncohAmp_(0),
113  DPNorm_(0.0),
114  DPRate_("DPRate", 0.0, 0.0, 1000.0),
115  meanDPEff_("meanDPEff", 0.0, 0.0, 1.0),
116  currentEvent_(0),
117  symmetricalDP_(kFALSE),
118  fullySymmetricDP_(kFALSE),
119  integralsDone_(kFALSE),
120  normalizationSchemeDone_(kFALSE),
121  intFileName_("integ.dat"),
122  m13BinWidth_(0.005),
123  m23BinWidth_(0.005),
124  narrowWidth_(0.020),
125  binningFactor_(100.0),
126  m13Sq_(0.0),
127  m23Sq_(0.0),
128  mPrime_(0.0),
129  thPrime_(0.0),
130  tagCat_(-1),
131  eff_(1.0),
132  scfFraction_(0.0),
133  jacobian_(0.0),
134  ASq_(0.0),
135  evtLike_(0.0),
136  iterationsMax_(100000),
137  nSigGenLoop_(0),
138  aSqMaxSet_(1.25),
139  aSqMaxVar_(0.0),
140  flipHelicity_(kTRUE),
141  recalcNormalisation_(kFALSE)
142 {
143  // Constructor for the isobar signal model
144  if (daughters != 0) {
145  symmetricalDP_ = daughters->gotSymmetricalDP();
146  fullySymmetricDP_ = daughters->gotFullySymmetricDP();
147  typDaug_.push_back(daughters->getTypeDaug1());
148  typDaug_.push_back(daughters->getTypeDaug2());
149  typDaug_.push_back(daughters->getTypeDaug3());
150  }
151 
152  sigResonances_.clear();
153  sigIncohResonances_.clear();
154  kMatrixPropagators_.clear();
155  kMatrixPropSet_.clear();
156  extraParameters_.clear();
157 }
158 
160 {
161  extraParameters_.clear();
162 
163  for ( std::vector<LauCacheData*>::iterator iter = data_.begin(); iter != data_.end(); ++iter ) {
164  delete (*iter);
165  }
166  data_.clear();
167 
168  for (std::vector<LauDPPartialIntegralInfo*>::iterator it = dpPartialIntegralInfo_.begin(); it != dpPartialIntegralInfo_.end(); ++it)
169  {
170  delete (*it);
171  }
172  dpPartialIntegralInfo_.clear();
173 }
174 
176 {
177  for (UInt_t i = 0; i < nAmp_; i++) {
178 
179  fSqSum_[i] = 0.0;
180  fSqEffSum_[i] = 0.0;
181  fNorm_[i] = 0.0;
182  ff_[i].zero();
183 
184  for (UInt_t j = 0; j < nAmp_; j++) {
185 
186  fifjEffSum_[i][j].zero();
187  fifjSum_[i][j].zero();
188 
189  }
190  }
191 
192  for (UInt_t i = 0; i < nIncohAmp_; i++) {
193  fSqSum_[i+nAmp_] = 0.0;
194  fSqEffSum_[i+nAmp_] = 0.0;
195  fNorm_[i+nAmp_] = 0.0;
196  incohInten_[i] = 0.0;
197  }
198 }
199 
201 {
202  if ( recalcNormalisation_ == kFALSE ) {
203  return;
204  }
205 
206  // We need to calculate the normalisation constants for the
207  // Dalitz plot generation/fitting.
208 
209  integralsDone_ = kFALSE;
210 
211  this->resetNormVectors();
213  this->calcDPNormalisation();
214 
215  integralsDone_ = kTRUE;
216 }
217 
219 {
220  // Loop through the resonance parameters and see which ones have changed
221  // For those that have changed mark the corresponding resonance(s) as needing to be re-evaluated
222 
223  integralsToBeCalculated_.clear();
224 
225  const UInt_t nResPars = resonancePars_.size();
226  for ( UInt_t iPar(0); iPar < nResPars; ++iPar ) {
227  const Double_t newValue = resonancePars_[iPar]->value();
228  if ( newValue != resonanceParValues_[iPar] ) {
229  resonanceParValues_[iPar] = newValue;
230 
231  const std::vector<UInt_t>& indices = resonanceParResIndex_[iPar];
232  std::vector<UInt_t>::const_iterator indexIter = indices.begin();
233  const std::vector<UInt_t>::const_iterator indexEnd = indices.end();
234  for( ; indexIter != indexEnd; ++indexIter) {
235  integralsToBeCalculated_.insert(*indexIter);
236  }
237  }
238  }
239 }
240 
241 void LauIsobarDynamics::initialise(const std::vector<LauComplex>& coeffs)
242 {
243  // Check whether we have a valid set of integration constants for
244  // the normalisation of the signal likelihood function.
245  this->initialiseVectors();
246 
247  // Mark the DP integrals as undetermined
248  integralsDone_ = kFALSE;
249 
250  // Initialise all resonance models
251  resonancePars_.clear();
252  resonanceParValues_.clear();
253  resonanceParResIndex_.clear();
254 
255  std::set<LauParameter*> uniqueResPars;
256  UInt_t resIndex(0);
257  for ( std::vector<LauAbsResonance*>::iterator resIter = sigResonances_.begin(); resIter != sigResonances_.end(); ++resIter ) {
258  (*resIter)->initialise();
259 
260  // Check if this resonance has floating parameters
261  // Append all unique parameters to our list
262  const std::vector<LauParameter*>& resPars = (*resIter)->getFloatingParameters();
263 
264  for ( std::vector<LauParameter*>::const_iterator parIter = resPars.begin(); parIter != resPars.end(); ++parIter ) {
265  if ( uniqueResPars.insert( *parIter ).second ) {
266  // This parameter has not already been added to
267  // the list of unique ones. Add it, its value
268  // and its associated resonance ID to the
269  // appropriate lists.
270  resonancePars_.push_back( *parIter );
271  resonanceParValues_.push_back( (*parIter)->value() );
272  std::vector<UInt_t> resIndices( 1, resIndex );
273  resonanceParResIndex_.push_back( resIndices );
274  } else {
275  // This parameter has already been added to the
276  // list of unique ones. However, we still need
277  // to indicate that this resonance should be
278  // associated with it.
279  std::vector<LauParameter*>::const_iterator uniqueParIter = resonancePars_.begin();
280  std::vector<std::vector<UInt_t> >::iterator indicesIter = resonanceParResIndex_.begin();
281  while( (*uniqueParIter) != (*parIter) ) {
282  ++uniqueParIter;
283  ++indicesIter;
284  }
285  ( *indicesIter ).push_back( resIndex );
286  }
287  }
288 
289  ++resIndex;
290  }
291 
292  for ( std::vector<LauAbsIncohRes*>::iterator resIter = sigIncohResonances_.begin(); resIter != sigIncohResonances_.end(); ++resIter ) {
293  (*resIter)->initialise();
294 
295  // Check if this resonance has floating parameters
296  // Append all unique parameters to our list
297  const std::vector<LauParameter*>& resPars = (*resIter)->getFloatingParameters();
298 
299  for ( std::vector<LauParameter*>::const_iterator parIter = resPars.begin(); parIter != resPars.end(); ++parIter ) {
300  if ( uniqueResPars.insert( *parIter ).second ) {
301  // This parameter has not already been added to
302  // the list of unique ones. Add it, its value
303  // and its associated resonance ID to the
304  // appropriate lists.
305  resonancePars_.push_back( *parIter );
306  resonanceParValues_.push_back( (*parIter)->value() );
307  std::vector<UInt_t> resIndices( 1, resIndex );
308  resonanceParResIndex_.push_back( resIndices );
309  } else {
310  // This parameter has already been added to the
311  // list of unique ones. However, we still need
312  // to indicate that this resonance should be
313  // associated with it.
314  std::vector<LauParameter*>::const_iterator uniqueParIter = resonancePars_.begin();
315  std::vector<std::vector<UInt_t> >::iterator indicesIter = resonanceParResIndex_.begin();
316  while( (*uniqueParIter) != (*parIter) ) {
317  ++uniqueParIter;
318  ++indicesIter;
319  }
320  ( *indicesIter ).push_back( resIndex );
321  }
322  }
323 
324  ++resIndex;
325  }
326 
327  if ( resonancePars_.empty() ) {
328  recalcNormalisation_ = kFALSE;
329  } else {
330  recalcNormalisation_ = kTRUE;
331  }
332 
333  // Print summary of what we have so far to screen
334  this->initSummary();
335 
336  if ( nAmp_+nIncohAmp_ == 0 ) {
337  std::cout << "INFO in LauIsobarDynamics::initialise : No contributions to DP model, not performing normalisation integrals." << std::endl;
338  } else {
339 
340  // We need to calculate the normalisation constants for the Dalitz plot generation/fitting.
341 
342  std::cout<<"INFO in LauIsobarDynamics::initialise : Starting special run to generate the integrals for normalising the PDF..."<<std::endl;
343 
344  // Since this is the initialisation, we need to calculate everything for every resonance
345  integralsToBeCalculated_.clear();
346  for ( UInt_t i(0); i < nAmp_+nIncohAmp_; ++i ) {
347  integralsToBeCalculated_.insert(i);
348  }
349 
350  // Calculate and cache the normalisations of each resonance _dynamic_ amplitude
351  // (e.g. Breit-Wigner contribution, not from the complex coefficients).
352  // These are stored in fNorm_[i].
353  // fSqSum[i] is the total of the dynamical amplitude squared for a given resonance, i.
354  // We require that:
355  // |fNorm_[i]|^2 * |fSqSum[i]|^2 = 1,
356  // i.e. fNorm_[i] normalises each resonance contribution to give the same number of
357  // events in the DP, accounting for the total DP area and the dynamics of the resonance.
358  this->calcDPNormalisation();
359 
360  // Write the integrals to a file (mainly for debugging purposes)
361  this->writeIntegralsFile();
362  }
363 
364 
365  integralsDone_ = kTRUE;
366 
367  std::cout << std::setprecision(10);
368 
369  std::cout<<"INFO in LauIsobarDynamics::initialise : Summary of the integrals:"<<std::endl;
370 
371  for (UInt_t i = 0; i < nAmp_+nIncohAmp_; i++) {
372  std::cout<<" fNorm["<<i<<"] = "<<fNorm_[i]<<std::endl;
373  std::cout<<" fSqSum["<<i<<"] = "<<fSqSum_[i]<<std::endl;
374  std::cout<<" fSqEffSum["<<i<<"] = "<<fSqEffSum_[i]<<std::endl;
375  }
376 
377  for (UInt_t i = 0; i < nAmp_; i++) {
378  for (UInt_t j = 0; j < nAmp_; j++) {
379  std::cout<<" fifjEffSum["<<i<<"]["<<j<<"] = "<<fifjEffSum_[i][j];
380  }
381  std::cout<<std::endl;
382  }
383 
384  for (UInt_t i = 0; i < nAmp_; i++) {
385  for (UInt_t j = 0; j < nAmp_; j++) {
386  std::cout<<" fifjSum["<<i<<"]["<<j<<"] = "<<fifjSum_[i][j];
387  }
388  std::cout<<std::endl;
389  }
390 
391  // Calculate the initial fit fractions (for later comparison with Toy MC, if required)
392  this->updateCoeffs(coeffs);
393  this->calcExtraInfo(kTRUE);
394 
395  for (UInt_t i = 0; i < nAmp_; i++) {
396  for (UInt_t j = i; j < nAmp_; j++) {
397  std::cout<<"INFO in LauIsobarDynamics::initialise : Initial fit fraction for amplitude ("<<i<<","<<j<<") = "<<fitFrac_[i][j].genValue()<<std::endl;
398  }
399  }
400 
401  for (UInt_t i = 0; i < nIncohAmp_; i++) {
402  std::cout<<"INFO in LauIsobarDynamics::initialise : Initial fit fraction for incoherent amplitude ("<<i<<","<<i<<") = "<<fitFrac_[i+nAmp_][i+nAmp_].genValue()<<std::endl;
403  }
404 
405  std::cout<<"INFO in LauIsobarDynamics::initialise : Initial efficiency = "<<meanDPEff_.initValue()<<std::endl;
406 
407  std::cout<<"INFO in LauIsobarDynamics::initialise : Initial DPRate = "<<DPRate_.initValue()<<std::endl;
408 }
409 
411 {
412 
413  UInt_t i(0);
414  TString nameP = daughters_->getNameParent();
415  TString name1 = daughters_->getNameDaug1();
416  TString name2 = daughters_->getNameDaug2();
417  TString name3 = daughters_->getNameDaug3();
418 
419  std::cout<<"INFO in LauIsobarDynamics::initSummary : We are going to do a DP with "<<nameP<<" going to "<<name1<<" "<<name2<<" "<<name3<<std::endl;
420 
421  std::cout<<" : For the following resonance combinations:"<<std::endl;
422 
423  std::cout<<" : In tracks 2 and 3:"<<std::endl;
424  for (i = 0; i < nAmp_; i++) {
425  if (resPairAmp_[i] == 1) {
426  std::cout<<" : "<<resTypAmp_[i]<<" to "<<name2<<", "<< name3<<std::endl;
427  }
428  }
429 
430  for (i = 0; i < nIncohAmp_; i++) {
431  if (incohResPairAmp_[i] == 1) {
432  std::cout<<" : "<<incohResTypAmp_[i]<<" (incoherent) to "<<name2<<", "<< name3<<std::endl;
433  }
434  }
435 
436  std::cout<<std::endl;
437 
438  std::cout<<" : In tracks 1 and 3:"<<std::endl;
439  for (i = 0; i < nAmp_; i++) {
440  if (resPairAmp_[i] == 2) {
441  std::cout<<" : "<<resTypAmp_[i]<<" to "<<name1<<", "<< name3<<std::endl;
442  }
443  }
444 
445  for (i = 0; i < nIncohAmp_; i++) {
446  if (incohResPairAmp_[i] == 2) {
447  std::cout<<" : "<<incohResTypAmp_[i]<<" (incoherent) to "<<name1<<", "<< name3<<std::endl;
448  }
449  }
450 
451  std::cout<<std::endl;
452 
453  std::cout<<" : In tracks 1 and 2:"<<std::endl;
454  for (i = 0; i < nAmp_; i++) {
455  if (resPairAmp_[i] == 3) {
456  std::cout<<" : "<<resTypAmp_[i]<<" to "<<name1<<", "<< name2<<std::endl;
457  }
458  }
459 
460  for (i = 0; i < nIncohAmp_; i++) {
461  if (incohResPairAmp_[i] == 3) {
462  std::cout<<" : "<<incohResTypAmp_[i]<<" (incoherent) to "<<name1<<", "<< name2<<std::endl;
463  }
464  }
465 
466  std::cout<<std::endl;
467 
468  for (i = 0; i < nAmp_; i++) {
469  if (resPairAmp_[i] == 0) {
470  std::cout<<" : and a non-resonant amplitude."<<std::endl;
471  }
472  }
473 
474  std::cout<<std::endl;
475 }
476 
478 {
479  fSqSum_.clear(); fSqSum_.resize(nAmp_+nIncohAmp_);
480  fSqEffSum_.clear(); fSqEffSum_.resize(nAmp_+nIncohAmp_);
481  fifjEffSum_.clear(); fifjEffSum_.resize(nAmp_);
482  fifjSum_.clear(); fifjSum_.resize(nAmp_);
483  ff_.clear(); ff_.resize(nAmp_);
484  incohInten_.clear(); incohInten_.resize(nIncohAmp_);
485  fNorm_.clear(); fNorm_.resize(nAmp_+nIncohAmp_);
486  fitFrac_.clear(); fitFrac_.resize(nAmp_+nIncohAmp_);
488 
489  LauComplex null(0.0, 0.0);
490 
491  for (UInt_t i = 0; i < nAmp_; i++) {
492 
493  fSqSum_[i] = 0.0; fNorm_[i] = 0.0;
494  ff_[i] = null;
495  fifjEffSum_[i].resize(nAmp_);
496  fifjSum_[i].resize(nAmp_);
497  fitFrac_[i].resize(nAmp_+nIncohAmp_);
498  fitFracEffUnCorr_[i].resize(nAmp_+nIncohAmp_);
499 
500  for (UInt_t j = 0; j < nAmp_; j++) {
501  fifjEffSum_[i][j] = null;
502  fifjSum_[i][j] = null;
503  fitFrac_[i][j].valueAndRange(0.0, -100.0, 100.0);
504  fitFracEffUnCorr_[i][j].valueAndRange(0.0, -100.0, 100.0);
505  }
506  for (UInt_t j = nAmp_; j < nAmp_+nIncohAmp_; j++) {
507  fitFrac_[i][j].valueAndRange(0.0, -100.0, 100.0);
508  fitFracEffUnCorr_[i][j].valueAndRange(0.0, -100.0, 100.0);
509  }
510  }
511  for (UInt_t i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
512  fSqSum_[i] = 0.0; fNorm_[i] = 0.0;
513  incohInten_[i-nAmp_] = 0.0;
514  fitFrac_[i].resize(nAmp_+nIncohAmp_);
515  fitFracEffUnCorr_[i].resize(nAmp_+nIncohAmp_);
516 
517  for (UInt_t j = 0; j < nAmp_+nIncohAmp_; j++) {
518  fitFrac_[i][j].valueAndRange(0.0, -100.0, 100.0);
519  fitFracEffUnCorr_[i][j].valueAndRange(0.0, -100.0, 100.0);
520  }
521  }
522 
523  UInt_t nKMatrixProps = kMatrixPropagators_.size();
524  extraParameters_.clear();
525  extraParameters_.resize( nKMatrixProps );
526 
527  for ( UInt_t i = 0; i < nKMatrixProps; ++i ) {
528  extraParameters_[i].valueAndRange(0.0, -100.0, 100.0);
529  }
530 }
531 
532 
534 {
535  // Routine to end integration calculation for loglike normalisation.
536  // This writes out the normalisation integral output into the file named
537  // outputFileName.
538  std::cout<<"INFO in LauIsobarDynamics::writeIntegralsFile : Writing integral output to integrals file "<<intFileName_.Data()<<std::endl;
539 
540  UInt_t i(0), j(0);
541  std::ofstream getChar(intFileName_.Data());
542 
543  getChar << std::setprecision(10);
544 
545  // Write out daughter types (pi, pi0, K, K0s?)
546  for (i = 0; i < 3; i++) {
547  getChar << typDaug_[i] << " ";
548  }
549 
550  // Write out number of resonances in the Dalitz plot model
551  getChar << nAmp_ << std::endl;
552 
553  // Write out the resonances
554  for (i = 0; i < nAmp_; i++) {
555  getChar << resTypAmp_[i] << " ";
556  }
557 
558  getChar << std::endl;
559 
560  // Write out the resonance model types (BW, RelBW etc...)
561  for (i = 0; i < nAmp_; i++) {
562  LauAbsResonance* theResonance = sigResonances_[i];
563  Int_t resModelInt = theResonance->getResonanceModel();
564  getChar << resModelInt << " ";
565  }
566 
567  getChar << std::endl;
568 
569  // Write out the track pairings for each resonance. This is specified
570  // by the resPairAmpInt integer in the addResonance function.
571  for (i = 0; i < nAmp_; i++) {
572  getChar << resPairAmp_[i] << " ";
573  }
574 
575  getChar << std::endl;
576 
577  // Write out the fSqSum = |ff|^2, where ff = resAmp()
578  for (i = 0; i < nAmp_; i++) {
579  getChar << fSqSum_[i] << " ";
580  }
581 
582  getChar << std::endl;
583 
584  // Similar to fSqSum, but with the efficiency term included.
585  for (i = 0; i < nAmp_; i++) {
586  getChar << fSqEffSum_[i] << " ";
587  }
588 
589  getChar << std::endl;
590 
591  // Write out the f_i*f_j_conj*eff values = resAmp_i*resAmp_j_conj*eff.
592  // Note that only the top half of the i*j "matrix" is required, as it
593  // is symmetric w.r.t i, j.
594  for (i = 0; i < nAmp_; i++) {
595  for (j = i; j < nAmp_; j++) {
596  getChar << fifjEffSum_[i][j] << " ";
597  }
598  }
599 
600  getChar << std::endl;
601 
602  // Similar to fifjEffSum, but without the efficiency term included.
603  for (i = 0; i < nAmp_; i++) {
604  for (j = i; j < nAmp_; j++) {
605  getChar << fifjSum_[i][j] << " ";
606  }
607  }
608 
609  getChar << std::endl;
610 
611  // Write out number of incoherent resonances in the Dalitz plot model
612  getChar << nIncohAmp_ << std::endl;
613 
614  // Write out the incoherent resonances
615  for (i = 0; i < nIncohAmp_; i++) {
616  getChar << incohResTypAmp_[i] << " ";
617  }
618 
619  getChar << std::endl;
620 
621  // Write out the incoherent resonance model types (BW, RelBW etc...)
622  for (i = 0; i < nIncohAmp_; i++) {
623  LauAbsResonance* theResonance = sigIncohResonances_[i];
624  Int_t resModelInt = theResonance->getResonanceModel();
625  getChar << resModelInt << " ";
626  }
627 
628  getChar << std::endl;
629 
630  // Write out the track pairings for each incoherent resonance. This is specified
631  // by the resPairAmpInt integer in the addIncohResonance function.
632  for (i = 0; i < nIncohAmp_; i++) {
633  getChar << incohResPairAmp_[i] << " ";
634  }
635 
636  getChar << std::endl;
637 
638  // Write out the fSqSum = |ff|^2, where |ff|^2 = incohResAmp()
639  for (i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
640  getChar << fSqSum_[i] << " ";
641  }
642 
643  getChar << std::endl;
644 
645  // Similar to fSqSum, but with the efficiency term included.
646  for (i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
647  getChar << fSqEffSum_[i] << " ";
648  }
649 
650  getChar << std::endl;
651 
652 }
653 
655 {
656  // Function to add a resonance in a Dalitz plot.
657  // No check is made w.r.t flavour and charge conservation rules, and so
658  // the user is responsible for checking the internal consistency of
659  // their function statements with these laws. For example, the program
660  // will not prevent the user from asking for a rho resonance in a K-pi
661  // pair or a K* resonance in a pi-pi pair.
662  // However, to assist the user, a summary of the resonant structure requested
663  // by the user is printed before the program runs. It is important to check this
664  // information when you first define your Dalitz plot model before doing
665  // any fitting/generating.
666  // Arguments are: resonance name, integer to specify the resonance track pairing
667  // (1 => m_23, 2 => m_13, 3 => m_12), i.e. the bachelor track number.
668  // The third argument resType specifies whether the resonance is a Breit-Wigner (BW)
669  // Relativistic Breit-Wigner (RelBW) or Flatte distribution (Flatte), for example.
670 
671  LauResonanceMaker& resonanceMaker = LauResonanceMaker::get();
672  LauAbsResonance *theResonance = resonanceMaker.getResonance(daughters_, resName, resPairAmpInt, resType, bwCategory, bwType);
673 
674  if (theResonance == 0) {
675  std::cerr<<"ERROR in LauIsobarDynamics::addResonance : Couldn't create the resonance \""<<resName<<"\""<<std::endl;
676  return 0;
677  }
678 
679  // implement the helicity flip here
680  if (flipHelicity_ && daughters_->getCharge(resPairAmpInt) == 0 && daughters_->getChargeParent() == 0 && daughters_->getTypeParent() > 0 ) {
681  if ( ( resPairAmpInt == 1 && TMath::Abs(daughters_->getTypeDaug2()) == TMath::Abs(daughters_->getTypeDaug3()) ) ||
682  ( resPairAmpInt == 2 && TMath::Abs(daughters_->getTypeDaug1()) == TMath::Abs(daughters_->getTypeDaug3()) ) ||
683  ( resPairAmpInt == 3 && TMath::Abs(daughters_->getTypeDaug1()) == TMath::Abs(daughters_->getTypeDaug2()) ) ) {
684  theResonance->flipHelicity(kTRUE);
685  }
686  }
687 
688  // Set the resonance name and what track is the bachelor
689  TString resonanceName = theResonance->getResonanceName();
690  resTypAmp_.push_back(resonanceName);
691 
692  // Always force the non-resonant amplitude pair to have resPairAmp = 0
693  // in case the user chooses the wrong number.
694  if ( resType == LauAbsResonance::FlatNR ||
695  resType == LauAbsResonance::NRModel ) {
696  std::cout<<"INFO in LauIsobarDynamics::addResonance : Setting resPairAmp to 0 for "<<resonanceName<<" contribution."<<std::endl;
697  resPairAmp_.push_back(0);
698  } else {
699  resPairAmp_.push_back(resPairAmpInt);
700  }
701 
702  // Increment the number of resonance amplitudes we have so far
703  ++nAmp_;
704 
705  // Finally, add the resonance object to the internal array
706  sigResonances_.push_back(theResonance);
707 
708  std::cout<<"INFO in LauIsobarDynamics::addResonance : Successfully added resonance. Total number of resonances so far = "<<nAmp_<<std::endl;
709 
710  return theResonance;
711 }
712 
713 LauAbsResonance* LauIsobarDynamics::addIncoherentResonance(const TString& resName, const Int_t resPairAmpInt, const LauAbsResonance::LauResonanceModel resType)
714 {
715  // Function to add an incoherent resonance in a Dalitz plot.
716  // No check is made w.r.t flavour and charge conservation rules, and so
717  // the user is responsible for checking the internal consistency of
718  // their function statements with these laws. For example, the program
719  // will not prevent the user from asking for a rho resonance in a K-pi
720  // pair or a K* resonance in a pi-pi pair.
721  // However, to assist the user, a summary of the resonant structure requested
722  // by the user is printed before the program runs. It is important to check this
723  // information when you first define your Dalitz plot model before doing
724  // any fitting/generating.
725  // Arguments are: resonance name, integer to specify the resonance track pairing
726  // (1 => m_23, 2 => m_13, 3 => m_12), i.e. the bachelor track number.
727  // The third argument resType specifies the shape of the resonance
728  // Gaussian (GaussIncoh), for example.
729 
730  LauResonanceMaker& resonanceMaker = LauResonanceMaker::get();
731  LauAbsIncohRes *theResonance = (LauAbsIncohRes*)resonanceMaker.getResonance(daughters_, resName, resPairAmpInt, resType);
732 
733  if (theResonance == 0) {
734  std::cerr<<"ERROR in LauIsobarDynamics::addIncohResonance : Couldn't create the resonance \""<<resName<<"\""<<std::endl;
735  return 0;
736  }
737 
738  // Set the resonance name and what track is the bachelor
739  TString resonanceName = theResonance->getResonanceName();
740  incohResTypAmp_.push_back(resonanceName);
741  incohResPairAmp_.push_back(resPairAmpInt);
742 
743  // Increment the number of resonance amplitudes we have so far
744  ++nIncohAmp_;
745 
746  // Finally, add the resonance object to the internal array
747  sigIncohResonances_.push_back(theResonance);
748 
749  std::cout<<"INFO in LauIsobarDynamics::addIncohResonance : Successfully added incoherent resonance. Total number of incoherent resonances so far = "<<nIncohAmp_<<std::endl;
750 
751  return theResonance;
752 }
753 
754 void LauIsobarDynamics::defineKMatrixPropagator(const TString& propName, const TString& paramFileName, Int_t resPairAmpInt,
755  Int_t nChannels, Int_t nPoles, Int_t rowIndex)
756 {
757  // Define the K-matrix propagator. The resPairAmpInt integer specifies which mass combination should be used
758  // for the invariant mass-squared variable "s". The pole masses and coupling constants are defined in the
759  // paramFileName parameter file.
760  // The number of channels and poles are defined by the nChannels and nPoles integers, respectively.
761  // The integer rowIndex specifies which row of the propagator should be used when
762  // summing over all amplitude channels: S-wave will be the first row, so rowIndex = 1.
763 
764  // Check that the rowIndex is valid
765  if (rowIndex < 1 || rowIndex > nChannels) {
766  std::cerr << "ERROR in LauIsobarDynamics::defineKMatrixPropagator. The rowIndex, which is set to "
767  << rowIndex << ", must be between 1 and the number of channels "
768  << nChannels << std::endl;
769  gSystem->Exit(EXIT_FAILURE);
770  }
771 
772  TString propagatorName(propName), parameterFile(paramFileName);
773 
774  LauKMatrixPropagator* thePropagator = LauKMatrixPropFactory::getInstance()->getPropagator(propagatorName, parameterFile,
775  resPairAmpInt, nChannels,
776  nPoles, rowIndex);
777  kMatrixPropagators_[propagatorName] = thePropagator;
778 
779 }
780 
781 void LauIsobarDynamics::addKMatrixProdPole(const TString& poleName, const TString& propName, Int_t poleIndex)
782 {
783 
784  // Add a K-matrix production pole term, using the K-matrix propagator given by the propName.
785  // Here, poleIndex is the integer specifying the pole number.
786 
787  // First, find the K-matrix propagator.
788  KMPropMap::iterator mapIter = kMatrixPropagators_.find(propName);
789  if (mapIter != kMatrixPropagators_.end()) {
790 
791  LauKMatrixPropagator* thePropagator = mapIter->second;
792 
793  // Make sure the pole index is valid
794  Int_t nPoles = thePropagator->getNPoles();
795  if (poleIndex < 1 || poleIndex > nPoles) {
796  std::cerr<<"ERROR in LauIsobarDynamics::addKMatrixProdPole : The pole index "<<poleIndex
797  <<" is not between 1 and "<<nPoles<<". Not adding production pole "<<poleName
798  <<" for K-matrix propagator "<<propName<<std::endl;
799  return;
800  }
801 
802  // Now add the K-matrix production pole amplitude to the vector of LauAbsResonance pointers.
803  Int_t resPairAmpInt = thePropagator->getResPairAmpInt();
804  LauAbsResonance* prodPole = new LauKMatrixProdPole(poleName, poleIndex, resPairAmpInt, thePropagator, daughters_);
805 
806  resTypAmp_.push_back(poleName);
807  resPairAmp_.push_back(resPairAmpInt);
808 
809  nAmp_++;
810  sigResonances_.push_back(prodPole);
811 
812  // Also store the propName-poleName pair for calculating total fit fractions later on
813  // (avoiding the need to use dynamic casts to check which resonances are of the K-matrix type)
814  kMatrixPropSet_[poleName] = propName;
815 
816  std::cout<<"INFO in LauIsobarDynamics::addKMatrixProdPole : Successfully added K-matrix production pole term. Total number of resonances so far = "<<nAmp_<<std::endl;
817 
818  } else {
819 
820  std::cerr<<"ERROR in LauIsobarDynamics::addKMatrixProdPole : The propagator of the name "<<propName
821  <<" could not be found for the production pole "<<poleName<<std::endl;
822 
823  }
824 
825 }
826 
827 
828 void LauIsobarDynamics::addKMatrixProdSVP(const TString& SVPName, const TString& propName, Int_t channelIndex)
829 {
830 
831  // Add a K-matrix production "slowly-varying part" (SVP) term, using the K-matrix propagator
832  // given by the propName. Here, channelIndex is the integer specifying the channel number.
833 
834  // First, find the K-matrix propagator.
835  KMPropMap::iterator mapIter = kMatrixPropagators_.find(propName);
836  if (mapIter != kMatrixPropagators_.end()) {
837 
838  LauKMatrixPropagator* thePropagator = mapIter->second;
839 
840  // Make sure the channel index is valid
841  Int_t nChannels = thePropagator->getNChannels();
842  if (channelIndex < 1 || channelIndex > nChannels) {
843  std::cerr<<"ERROR in LauIsobarDynamics::addKMatrixProdSVP : The channel index "<<channelIndex
844  <<" is not between 1 and "<<nChannels<<". Not adding production slowly-varying part "<<SVPName
845  <<" for K-matrix propagator "<<propName<<std::endl;
846  return;
847  }
848 
849  // Now add the K-matrix production SVP amplitude to the vector of LauAbsResonance pointers.
850  Int_t resPairAmpInt = thePropagator->getResPairAmpInt();
851  LauAbsResonance* prodSVP = new LauKMatrixProdSVP(SVPName, channelIndex, resPairAmpInt, thePropagator, daughters_);
852 
853  resTypAmp_.push_back(SVPName);
854  resPairAmp_.push_back(resPairAmpInt);
855 
856  ++nAmp_;
857  sigResonances_.push_back(prodSVP);
858 
859  // Also store the SVPName-propName pair for calculating total fit fractions later on
860  // (avoiding the need to use dynamic casts to check which resonances are of the K-matrix type)
861  kMatrixPropSet_[SVPName] = propName;
862 
863  std::cout<<"INFO in LauIsobarDynamics::addKMatrixProdSVP : Successfully added K-matrix production slowly-varying (SVP) term. Total number of resonances so far = "<<nAmp_<<std::endl;
864 
865  } else {
866 
867  std::cerr<<"ERROR in LauIsobarDynamics::addKMatrixProdSVP : The propagator of the name "<<propName
868  <<" could not be found for the production slowly-varying part "<<SVPName<<std::endl;
869 
870  }
871 }
872 
874 {
875  TString testName(name);
876  testName.ToLower();
877  LauAbsResonance* theResonance(0);
878 
879  for (std::vector<LauAbsResonance*>::iterator iter=sigResonances_.begin(); iter!=sigResonances_.end(); ++iter) {
880  theResonance = (*iter);
881  if (theResonance != 0) {
882  TString resString = theResonance->getResonanceName();
883  resString.ToLower();
884  if (resString.BeginsWith(testName, TString::kExact)) {
885  return theResonance;
886  }
887  }
888  }
889 
890  for (std::vector<LauAbsIncohRes*>::iterator iter=sigIncohResonances_.begin(); iter!=sigIncohResonances_.end(); ++iter) {
891  theResonance = (*iter);
892  if (theResonance != 0) {
893  TString resString = theResonance->getResonanceName();
894  resString.ToLower();
895  if (resString.BeginsWith(testName, TString::kExact)) {
896  return theResonance;
897  }
898  }
899  }
900 
901  std::cerr<<"ERROR in LauIsobarDynamics::findResonance : Couldn't find resonance \""<<name<<"\" in the model."<<std::endl;
902  return 0;
903 }
904 
906 {
907  TString testName(name);
908  testName.ToLower();
909  const LauAbsResonance* theResonance(0);
910 
911  for (std::vector<LauAbsResonance*>::const_iterator iter=sigResonances_.begin(); iter!=sigResonances_.end(); ++iter) {
912  theResonance = (*iter);
913  if (theResonance != 0) {
914  TString resString = theResonance->getResonanceName();
915  resString.ToLower();
916  if (resString.BeginsWith(testName, TString::kExact)) {
917  return theResonance;
918  }
919  }
920  }
921 
922  for (std::vector<LauAbsIncohRes*>::const_iterator iter=sigIncohResonances_.begin(); iter!=sigIncohResonances_.end(); ++iter) {
923  theResonance = (*iter);
924  if (theResonance != 0) {
925  TString resString = theResonance->getResonanceName();
926  resString.ToLower();
927  if (resString.BeginsWith(testName, TString::kExact)) {
928  return theResonance;
929  }
930  }
931  }
932 
933  std::cerr<<"ERROR in LauIsobarDynamics::findResonance : Couldn't find resonance \""<<name<<"\" in the model."<<std::endl;
934  return 0;
935 }
936 
937 void LauIsobarDynamics::removeCharge(TString& string) const
938 {
939  Ssiz_t index = string.Index("+");
940  if (index != -1) {
941  string.Remove(index,1);
942  }
943  index = string.Index("-");
944  if (index != -1) {
945  string.Remove(index,1);
946  }
947 }
948 
950 {
953  }
954 
955  for (std::vector<LauDPPartialIntegralInfo*>::iterator it = dpPartialIntegralInfo_.begin(); it != dpPartialIntegralInfo_.end(); ++it)
956  {
957  this->calcDPPartialIntegral( *it );
958  }
959 
960  for (UInt_t i = 0; i < nAmp_+nIncohAmp_; ++i) {
961  fNorm_[i] = 0.0;
962  if (fSqSum_[i] > 0.0) {fNorm_[i] = TMath::Sqrt(1.0/(fSqSum_[i]));}
963  }
964 }
965 
967 {
968  if ( ! dpPartialIntegralInfo_.empty() ) {
969  std::cerr<<"ERROR in LauIsobarDynamics::calcDPNormalisationScheme : Scheme already stored!"<<std::endl;
970  return;
971  }
972 
973  // The precision for the Gauss-Legendre weights
974  const Double_t precision(1e-6);
975 
976  // Get the rectangle that encloses the DP
977  Double_t minm13 = kinematics_->getm13Min();
978  Double_t maxm13 = kinematics_->getm13Max();
979  Double_t minm23 = kinematics_->getm23Min();
980  Double_t maxm23 = kinematics_->getm23Max();
981  Double_t minm12 = kinematics_->getm12Min();
982  Double_t maxm12 = kinematics_->getm12Max();
983 
984  // Find out whether we have narrow resonances in the DP (defined here as width < 20 MeV).
985  std::multimap<Double_t,Double_t> m13NarrowRes;
986  std::multimap<Double_t,Double_t> m23NarrowRes;
987  std::multimap<Double_t,Double_t> m12NarrowRes;
988  for ( std::vector<LauAbsResonance*>::const_iterator iter = sigResonances_.begin(); iter != sigResonances_.end(); ++iter ) {
989  Double_t width = (*iter)->getWidth();
990  if ( width > 0.020 || width == 0.0 ) { continue; }
991  Double_t mass = (*iter)->getMass();
992  Int_t pair = (*iter)->getPairInt();
993  TString name = (*iter)->getResonanceName();
994  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Found narrow resonance: "<<name<<", mass = "<<mass<<", width = "<<width<<", pair int = "<<pair<<std::endl;
995  if ( pair == 1 ) {
996  if ( mass < minm23 || mass > maxm23 ){ continue; }
997  m23NarrowRes.insert( std::make_pair(width,mass) );
998  } else if ( pair == 2 ) {
999  if ( mass < minm13 || mass > maxm13 ){ continue; }
1000  m13NarrowRes.insert( std::make_pair(width,mass) );
1001  } else if ( pair == 3 ) {
1002  if ( mass < minm12 || mass > maxm12 ){ continue; }
1003  m12NarrowRes.insert( std::make_pair(width,mass) );
1004  } else {
1005  std::cerr<<"WARNING in LauIsobarDynamics::calcDPNormalisationScheme : strange pair integer, "<<pair<<", for resonance \""<<(*iter)->getResonanceName()<<std::endl;
1006  }
1007  }
1008 
1009  for ( std::vector<LauAbsIncohRes*>::const_iterator iter = sigIncohResonances_.begin(); iter != sigIncohResonances_.end(); ++iter ) {
1010  Double_t width = (*iter)->getWidth();
1011  if ( width > narrowWidth_ || width == 0.0 ) { continue; }
1012  Double_t mass = (*iter)->getMass();
1013  Int_t pair = (*iter)->getPairInt();
1014  TString name = (*iter)->getResonanceName();
1015  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Found narrow resonance: "<<name<<", mass = "<<mass<<", width = "<<width<<", pair int = "<<pair<<std::endl;
1016  if ( pair == 1 ) {
1017  if ( mass < minm23 || mass > maxm23 ){ continue; }
1018  m23NarrowRes.insert( std::make_pair(width,mass) );
1019  } else if ( pair == 2 ) {
1020  if ( mass < minm13 || mass > maxm13 ){ continue; }
1021  m13NarrowRes.insert( std::make_pair(width,mass) );
1022  } else if ( pair == 3 ) {
1023  if ( mass < minm12 || mass > maxm12 ){ continue; }
1024  m12NarrowRes.insert( std::make_pair(width,mass) );
1025  } else {
1026  std::cerr<<"WARNING in LauIsobarDynamics::calcDPNormalisationScheme : strange pair integer, "<<pair<<", for resonance \""<<(*iter)->getResonanceName()<<std::endl;
1027  }
1028  }
1029 
1030  // Find the narrowest resonance in each mass pairing
1031  const Bool_t e12 = m12NarrowRes.empty();
1032  const Bool_t e13 = m13NarrowRes.empty();
1033  const Bool_t e23 = m23NarrowRes.empty();
1034  //const UInt_t s12 = e12 ? 0 : m12NarrowRes.size();
1035  const UInt_t s13 = e13 ? 0 : m13NarrowRes.size();
1036  const UInt_t s23 = e23 ? 0 : m23NarrowRes.size();
1037  const Double_t w12 = e12 ? DBL_MAX : m12NarrowRes.begin()->first / binningFactor_;
1038  const Double_t w13 = e13 ? DBL_MAX : m13NarrowRes.begin()->first / binningFactor_;
1039  const Double_t w23 = e23 ? DBL_MAX : m23NarrowRes.begin()->first / binningFactor_;
1040 
1041  // Start off with default bin width (5 MeV)
1042  Double_t m13BinWidth = m13BinWidth_;
1043  Double_t m23BinWidth = m23BinWidth_;
1044 
1045  // Depending on how many narrow resonances we have and where they
1046  // are we adopt different approaches
1047  if ( e12 && e13 && e23 ) {
1048  // If we have no narrow resonances just integrate the whole
1049  // DP with the standard bin widths
1050  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : No narrow resonances found, integrating over whole Dalitz plot..."<<std::endl;
1051  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1052  } else if ( ! e12 ) {
1053  // If we have a narrow resonance on the diagonal then we'll
1054  // have to just use a narrow bin width over the whole DP
1055  // (a factor 10 larger than if we were doing this in a small region)
1056  m13BinWidth = m23BinWidth = 10.0*TMath::Min( w12, TMath::Min( w13, w23 ) );
1057  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One or more narrow resonances found in m12, integrating over whole Dalitz plot with bin width of "<<m13BinWidth<<" GeV/c2..."<<std::endl;
1058  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1059  } else if ( s13==1 && e23 ) {
1060  // We have a single narrow resonance in m13
1061  // Divide the plot into 3 regions: the resonance band and
1062  // the two areas either side.
1063  Double_t mass = m13NarrowRes.begin()->second;
1064  Double_t width = m13NarrowRes.begin()->first;
1065  Double_t resMin = mass - 5.0*width;
1066  Double_t resMax = mass + 5.0*width;
1067  // if the resonance is close to threshold just go from
1068  // threshold to resMax, otherwise treat threshold to resMin
1069  // as a separate region
1070  if ( resMin < (minm13+50.0*m13BinWidth_) ) {
1071  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One narrow resonance found in m13, close to threshold, dividing Dalitz plot into two regions..."<<std::endl;
1072  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1073  m13BinWidth = w13;
1074  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1075  } else {
1076  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One narrow resonance found in m13, dividing Dalitz plot into three regions..."<<std::endl;
1077  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMin, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1078  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1079  m13BinWidth = w13;
1080  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMin, resMax, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1081  }
1082  } else if ( s13==2 && e23 ) {
1083  // We have a two narrow resonances in m13
1084  // Divide the plot into 5 regions: the resonance bands,
1085  // the two areas either side and the area in between.
1086  std::multimap<Double_t,Double_t> massordered;
1087  for ( std::map<Double_t,Double_t>::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
1088  massordered.insert( std::make_pair( iter->second, iter->first ) );
1089  }
1090  Double_t res1Mass = massordered.begin()->first;
1091  Double_t res1Width = massordered.begin()->second;
1092  Double_t res1Min = res1Mass - 5.0*res1Width;
1093  Double_t res1Max = res1Mass + 5.0*res1Width;
1094  Double_t res2Mass = (++(massordered.begin()))->first;
1095  Double_t res2Width = (++(massordered.begin()))->second;
1096  Double_t res2Min = res2Mass - 5.0*res2Width;
1097  Double_t res2Max = res2Mass + 5.0*res2Width;
1098  // if the resonance is close to threshold just go from
1099  // threshold to resMax, otherwise treat threshold to resMin
1100  // as a separate region
1101  if ( res1Min < (minm13+50.0*m13BinWidth_) ) {
1102  if ( res1Max > res2Min ) {
1103  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Two narrow resonances found in m13, both close to threshold, dividing Dalitz plot into two regions..."<<std::endl;
1104  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res2Max, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1105  m13BinWidth = TMath::Min(res1Width,res2Width)/100.0;
1106  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, res2Max, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1107  } else {
1108  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Two narrow resonances found in m13, one close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
1109  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res1Max, res2Min, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1110  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res2Max, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1111  m13BinWidth = res1Width/100.0;
1112  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, res1Max, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1113  m13BinWidth = res2Width/100.0;
1114  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res2Min, res2Max, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1115  }
1116  } else {
1117  if ( res1Max > res2Min ) {
1118  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Two narrow resonances found close together in m13, dividing Dalitz plot into three regions..."<<std::endl;
1119  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, res1Min, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1120  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res2Max, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1121  m13BinWidth = TMath::Min(res1Width,res2Width)/100.0;
1122  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res1Min, res2Max, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1123  } else {
1124  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Two narrow resonances found in m13, dividing Dalitz plot into five regions..."<<std::endl;
1125  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, res1Min, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1126  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res1Max, res2Min, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1127  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res2Max, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1128  m13BinWidth = res1Width/100.0;
1129  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res1Min, res1Max, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1130  m13BinWidth = res2Width/100.0;
1131  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(res2Min, res2Max, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1132  }
1133  }
1134  } else if ( s23==1 && e13 ) {
1135  // We have a single narrow resonance in m23
1136  // Divide the plot into 3 regions: the resonance band and
1137  // the two areas either side.
1138  Double_t mass = m23NarrowRes.begin()->second;
1139  Double_t width = m23NarrowRes.begin()->first;
1140  Double_t resMin = mass - 5.0*width;
1141  Double_t resMax = mass + 5.0*width;
1142  // if the resonance is close to threshold just go from
1143  // threshold to resMax, otherwise treat threshold to resMin
1144  // as a separate region
1145  if ( resMin < (minm23+50.0*m23BinWidth_) ) {
1146  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One narrow resonance found in m23, close to threshold, dividing Dalitz plot into two regions..."<<std::endl;
1147  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, resMax, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1148  m23BinWidth = w23;
1149  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, resMax, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1150  } else {
1151  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One narrow resonance found in m23, dividing Dalitz plot into three regions..."<<std::endl;
1152  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, resMin, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1153  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, resMax, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1154  m23BinWidth = w23;
1155  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, resMin, resMax, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1156  }
1157  } else if ( s23==2 && e13 ) {
1158  // We have a two narrow resonances in m23
1159  // Divide the plot into 5 regions: the resonance bands,
1160  // the two areas either side and the area in between.
1161  std::multimap<Double_t,Double_t> massordered;
1162  for ( std::map<Double_t,Double_t>::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
1163  massordered.insert( std::make_pair( iter->second, iter->first ) );
1164  }
1165  Double_t res1Mass = massordered.begin()->first;
1166  Double_t res1Width = massordered.begin()->second;
1167  Double_t res1Min = res1Mass - 5.0*res1Width;
1168  Double_t res1Max = res1Mass + 5.0*res1Width;
1169  Double_t res2Mass = (++(massordered.begin()))->first;
1170  Double_t res2Width = (++(massordered.begin()))->second;
1171  Double_t res2Min = res2Mass - 5.0*res2Width;
1172  Double_t res2Max = res2Mass + 5.0*res2Width;
1173  // if the resonance is close to threshold just go from
1174  // threshold to resMax, otherwise treat threshold to resMin
1175  // as a separate region
1176  if ( res1Min < (minm23+50.0*m23BinWidth_) ) {
1177  if ( res1Max > res2Min ) {
1178  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Two narrow resonances found in m23, both close to threshold, dividing Dalitz plot into two regions..."<<std::endl;
1179  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res2Max, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1180  m23BinWidth = TMath::Min(res1Width,res2Width)/100.0;
1181  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, res2Max, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1182  } else {
1183  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Two narrow resonances found in m23, one close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
1184  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res1Max, res2Min, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1185  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res2Max, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1186  m23BinWidth = res1Width/100.0;
1187  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, res1Max, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1188  m23BinWidth = res2Width/100.0;
1189  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res2Min, res2Max, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1190  }
1191  } else {
1192  if ( res1Max > res2Min ) {
1193  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Two narrow resonances found close together in m23, dividing Dalitz plot into three regions..."<<std::endl;
1194  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, res1Min, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1195  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res2Max, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1196  m23BinWidth = TMath::Min(res1Width,res2Width)/100.0;
1197  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res1Min, res2Max, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1198  } else {
1199  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Two narrow resonances found in m23, dividing Dalitz plot into five regions..."<<std::endl;
1200  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, res1Min, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1201  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res1Max, res2Min, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1202  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res2Max, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1203  m23BinWidth = res1Width/100.0;
1204  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res1Min, res1Max, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1205  m23BinWidth = res2Width/100.0;
1206  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, res2Min, res2Max, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1207  }
1208  }
1209  } else if ( s13==1 && s23==1 ) {
1210  // We have a single narrow resonance in both m13 and m23
1211  // Divide the plot into 9 regions: the point where the
1212  // resonance bands cross, the four other parts of the bands
1213  // and the four remaining areas of the DP.
1214  Double_t mass23 = m23NarrowRes.begin()->second;
1215  Double_t width23 = m23NarrowRes.begin()->first;
1216  Double_t resMin23 = mass23 - 5.0*width23;
1217  Double_t resMax23 = mass23 + 5.0*width23;
1218  Double_t mass13 = m13NarrowRes.begin()->second;
1219  Double_t width13 = m13NarrowRes.begin()->first;
1220  Double_t resMin13 = mass13 - 5.0*width13;
1221  Double_t resMax13 = mass13 + 5.0*width13;
1222  // if either resonance is close to threshold just go from
1223  // threshold to resMax, otherwise treat threshold to resMin
1224  // as a separate region
1225  if ( resMin13 < (minm13+50.0*m13BinWidth_) && resMin23 < (minm23+50.0*m23BinWidth_) ) {
1226  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One narrow resonance found in m13 and one in m23, both close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
1227  m13BinWidth = m13BinWidth_;
1228  m23BinWidth = m23BinWidth_;
1229  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1230  m13BinWidth = m13BinWidth_;
1231  m23BinWidth = w23;
1232  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1233  m13BinWidth = w13;
1234  m23BinWidth = m23BinWidth_;
1235  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1236  m13BinWidth = w13;
1237  m23BinWidth = w23;
1238  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1239  } else if ( resMin13 < (minm13+50.0*m13BinWidth_) ) {
1240  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One narrow resonance found in m13, close to threshold, and one in m23, not close to threshold, dividing Dalitz plot into six regions..."<<std::endl;
1241  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, minm23, resMin23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1242  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1243  m13BinWidth = m13BinWidth_;
1244  m23BinWidth = w23;
1245  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMin23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1246  m13BinWidth = w13;
1247  m23BinWidth = m23BinWidth_;
1248  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, minm23, resMin23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1249  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1250  m13BinWidth = w13;
1251  m23BinWidth = w23;
1252  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, resMin23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1253  } else if ( resMin23 < (minm23+50.0*m23BinWidth_) ) {
1254  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One narrow resonance found in m23, close to threshold, and one in m13, not close to threshold, dividing Dalitz plot into six regions..."<<std::endl;
1255  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMin13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1256  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1257  m13BinWidth = m13BinWidth_;
1258  m23BinWidth = w23;
1259  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMin13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1260  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1261  m13BinWidth = w13;
1262  m23BinWidth = m23BinWidth_;
1263  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMin13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1264  m13BinWidth = w13;
1265  m23BinWidth = w23;
1266  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMin13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1267  } else {
1268  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One narrow resonance found in both m13 and m23, neither close to threshold, dividing Dalitz plot into nine regions..."<<std::endl;
1269  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMin13, minm23, resMin23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1270  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMin13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1271  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, minm23, resMin23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1272  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1273  m13BinWidth = m13BinWidth_;
1274  m23BinWidth = w23;
1275  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMin13, resMin23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1276  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMin23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1277  m13BinWidth = w13;
1278  m23BinWidth = m23BinWidth_;
1279  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMin13, resMax13, minm23, resMin23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1280  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMin13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1281  m13BinWidth = w13;
1282  m23BinWidth = w23;
1283  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMin13, resMax13, resMin23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1284  }
1285  } else if ( e23 && s13>1 ) {
1286  // We have multiple narrow resonances in m13 only.
1287  // Divide the plot into 2 regions: threshold to the most
1288  // massive of the narrow resonances, and the rest
1289  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Multiple narrow resonances found in m13, dividing Dalitz plot into two regions..."<<std::endl;
1290  Double_t mass = 0.0;
1291  Double_t width = 0.0;
1292  for ( std::map<Double_t,Double_t>::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
1293  if ( mass < iter->second ) {
1294  mass = iter->second;
1295  width = iter->first;
1296  }
1297  }
1298  Double_t resMax = mass + 5.0*width;
1299  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1300  m13BinWidth = w13;
1301  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1302  } else if ( e13 && s23>1 ) {
1303  // We have multiple narrow resonances in m23 only.
1304  // Divide the plot into 2 regions: threshold to the most
1305  // massive of the narrow resonances, and the rest
1306  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Multiple narrow resonances found in m23, dividing Dalitz plot into two regions..."<<std::endl;
1307  Double_t mass = 0.0;
1308  Double_t width = 0.0;
1309  for ( std::map<Double_t,Double_t>::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
1310  if ( mass < iter->second ) {
1311  mass = iter->second;
1312  width = iter->first;
1313  }
1314  }
1315  Double_t resMax = mass + 5.0*width;
1316  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, resMax, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1317  m23BinWidth = w23;
1318  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, resMax, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1319  } else if ( s13==1 && s23>1 ) {
1320  // We've got a single narrow resonance in m13 and multiple
1321  // narrow resonances in m23. Divide the plot into 6 regions.
1322  Double_t mass23 = 0.0;
1323  Double_t width23 = 0.0;
1324  for ( std::map<Double_t,Double_t>::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
1325  if ( mass23 < iter->second ) {
1326  mass23 = iter->second;
1327  width23 = iter->first;
1328  }
1329  }
1330  Double_t resMax23 = mass23 + 5.0*width23;
1331  Double_t mass13 = m13NarrowRes.begin()->second;
1332  Double_t width13 = m13NarrowRes.begin()->first;
1333  Double_t resMin13 = mass13 - 5.0*width13;
1334  Double_t resMax13 = mass13 + 5.0*width13;
1335  // if the m13 resonance is close to threshold just go from
1336  // threshold to resMax, otherwise treat threshold to resMin
1337  // as a separate region
1338  if ( resMin13 < (minm13+50.0*m13BinWidth_) ) {
1339  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Multiple narrow resonances found in m23 and one in m13, close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
1340  m13BinWidth = m13BinWidth_;
1341  m23BinWidth = m23BinWidth_;
1342  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1343  m13BinWidth = m13BinWidth_;
1344  m23BinWidth = w23;
1345  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1346  m13BinWidth = w13;
1347  m23BinWidth = m23BinWidth_;
1348  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1349  m13BinWidth = w13;
1350  m23BinWidth = w23;
1351  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1352  } else {
1353  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Multiple narrow resonances found in m23 and one in m13, not close to threshold, dividing Dalitz plot into six regions..."<<std::endl;
1354  m13BinWidth = m13BinWidth_;
1355  m23BinWidth = m23BinWidth_;
1356  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMin13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1357  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1358  m13BinWidth = m13BinWidth_;
1359  m23BinWidth = w23;
1360  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMin13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1361  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1362  m13BinWidth = w13;
1363  m23BinWidth = m23BinWidth_;
1364  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMin13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1365  m13BinWidth = w13;
1366  m23BinWidth = w23;
1367  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMin13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1368  }
1369  } else if ( s13>1 && s23==1 ) {
1370  // We've got a single narrow resonance in m23 and multiple
1371  // narrow resonances in m13. Divide the plot into 6 regions.
1372  Double_t mass13 = 0.0;
1373  Double_t width13 = 0.0;
1374  for ( std::map<Double_t,Double_t>::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
1375  if ( mass13 < iter->second ) {
1376  mass13 = iter->second;
1377  width13 = iter->first;
1378  }
1379  }
1380  Double_t resMax13 = mass13 + 5.0*width13;
1381  Double_t mass23 = m23NarrowRes.begin()->second;
1382  Double_t width23 = m23NarrowRes.begin()->first;
1383  Double_t resMin23 = mass23 - 5.0*width23;
1384  Double_t resMax23 = mass23 + 5.0*width23;
1385  // if the m23 resonance is close to threshold just go from
1386  // threshold to resMax, otherwise treat threshold to resMin
1387  // as a separate region
1388  if ( resMin23 < (minm23+50.0*m23BinWidth_) ) {
1389  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Multiple narrow resonances found in m13 and one in m23, close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
1390  m13BinWidth = m13BinWidth_;
1391  m23BinWidth = m23BinWidth_;
1392  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1393  m13BinWidth = m13BinWidth_;
1394  m23BinWidth = w23;
1395  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1396  m13BinWidth = w13;
1397  m23BinWidth = m23BinWidth_;
1398  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1399  m13BinWidth = w13;
1400  m23BinWidth = w23;
1401  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1402  } else {
1403  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Multiple narrow resonances found in m13 and one in m23, not close to threshold, dividing Dalitz plot into six regions..."<<std::endl;
1404  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, minm23, resMin23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1405  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1406  m13BinWidth = m13BinWidth_;
1407  m23BinWidth = w23;
1408  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMin23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1409  m13BinWidth = w13;
1410  m23BinWidth = m23BinWidth_;
1411  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, minm23, resMin23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1412  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1413  m13BinWidth = w13;
1414  m23BinWidth = w23;
1415  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, resMin23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1416  }
1417  } else {
1418  // We've got multiple narrow resonances in both m13 and m23.
1419  // Divide the plot into 4 regions.
1420  std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Multiple narrow resonances found in both m13 and m23, dividing Dalitz plot into four regions..."<<std::endl;
1421  Double_t mass13 = 0.0;
1422  Double_t width13 = 0.0;
1423  for ( std::map<Double_t,Double_t>::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
1424  if ( mass13 < iter->second ) {
1425  mass13 = iter->second;
1426  width13 = iter->first;
1427  }
1428  }
1429  Double_t resMax13 = mass13 + 5.0*width13;
1430 
1431  Double_t mass23 = 0.0;
1432  Double_t width23 = 0.0;
1433  for ( std::map<Double_t,Double_t>::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
1434  if ( mass23 < iter->second ) {
1435  mass23 = iter->second;
1436  width23 = iter->first;
1437  }
1438  }
1439  Double_t resMax23 = mass23 + 5.0*width23;
1440 
1441  m13BinWidth = m13BinWidth_;
1442  m23BinWidth = m23BinWidth_;
1443  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1444  m13BinWidth = m13BinWidth_;
1445  m23BinWidth = w23;
1446  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1447  m13BinWidth = w13;
1448  m23BinWidth = m23BinWidth_;
1449  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1450  m13BinWidth = w13;
1451  m23BinWidth = w23;
1452  dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth, precision, nAmp_, nIncohAmp_));
1453  }
1454 
1455  normalizationSchemeDone_ = kTRUE;
1456 }
1457 
1458 void LauIsobarDynamics::setIntegralBinWidths(const Double_t m13BinWidth, const Double_t m23BinWidth)
1459 {
1460  // Specify whether we're going to use Gauss-Legendre integration to calculate the normalisation
1461  // integrals, and the bin widths we require for the m13 and m23 axes. Note that the integration
1462  // is done over m13, m23 space, with the appropriate Jacobian applied, and not m13^2, m23^2 space.
1463  // The default bin widths in m13 and m23 space are 5 MeV.
1464 
1465  m13BinWidth_ = m13BinWidth;
1466  m23BinWidth_ = m23BinWidth;
1467 }
1468 
1470 {
1471  // Calculate the integrals for all parts of the amplitude in the given region of the DP
1472 
1473  const UInt_t nm13Points = intInfo->getnm13Points();
1474  const UInt_t nm23Points = intInfo->getnm23Points();
1475 
1476  //Double_t dpArea(0.0);
1477  for (UInt_t i = 0; i < nm13Points; ++i) {
1478 
1479  const Double_t m13 = intInfo->getM13Value(i);
1480  const Double_t m13Sq = m13*m13;
1481 
1482  for (UInt_t j = 0; j < nm23Points; ++j) {
1483 
1484  const Double_t m23 = intInfo->getM23Value(j);
1485  const Double_t m23Sq = m23*m23;
1486  const Double_t weight = intInfo->getWeight(i,j);
1487 
1488  // Calculate the integral contributions for each resonance.
1489  // Only resonances within the DP area contribute.
1490  // This also calculates the total DP area as a check.
1491  Bool_t withinDP = kinematics_->withinDPLimits(m13Sq, m23Sq);
1492  if (withinDP == kTRUE) {
1493 
1494  kinematics_->updateKinematics(m13Sq, m23Sq);
1495 
1496  this->calculateAmplitudes(intInfo, i, j);
1497 
1498  this->addGridPointToIntegrals(weight);
1499 
1500  // Increment total DP area
1501  //dpArea += weight;
1502  }
1503 
1504  } // j weights loop
1505  } // i weights loop
1506 
1507  // Print out DP area to check whether we have a sensible output
1508  //std::cout<<" : dpArea = "<<dpArea<<std::endl;
1509 }
1510 
1511 void LauIsobarDynamics::calculateAmplitudes( LauDPPartialIntegralInfo* intInfo, const UInt_t m13Point, const UInt_t m23Point )
1512 {
1513  const std::set<UInt_t>::const_iterator intEnd = integralsToBeCalculated_.end();
1514 
1515  for (UInt_t iAmp = 0; iAmp < nAmp_; ++iAmp) {
1516 
1517  if ( integralsToBeCalculated_.find(iAmp) != intEnd ) {
1518  // Calculate the dynamics for this resonance
1519  this->resAmp(iAmp);
1520 
1521  // Store the new value in the integration info object
1522  intInfo->storeAmplitude( m13Point, m23Point, iAmp, ff_[iAmp] );
1523  } else {
1524  // Retrieve the cached value of the amplitude
1525  ff_[iAmp] = intInfo->getAmplitude( m13Point, m23Point, iAmp );
1526  }
1527  }
1528 
1529  for (UInt_t iAmp = 0; iAmp < nIncohAmp_; ++iAmp) {
1530 
1531  if ( integralsToBeCalculated_.find(iAmp+nAmp_) != intEnd ) {
1532  // Calculate the dynamics for this resonance
1533  this->incohResAmp(iAmp);
1534 
1535  // Store the new value in the integration info object
1536  intInfo->storeIntensity( m13Point, m23Point, iAmp, incohInten_[iAmp] );
1537  } else {
1538  // Retrieve the cached value of the amplitude
1539  incohInten_[iAmp] = intInfo->getIntensity( m13Point, m23Point, iAmp );
1540  }
1541  }
1542 
1543  // If we haven't cached the data, then we need to find out the efficiency.
1544  eff_ = this->retrieveEfficiency();
1545 
1546  intInfo->storeEfficiency( m13Point, m23Point, eff_ );
1547 }
1548 
1550 {
1551  std::set<UInt_t>::const_iterator iter = integralsToBeCalculated_.begin();
1552  const std::set<UInt_t>::const_iterator intEnd = integralsToBeCalculated_.end();
1553 
1554  for ( ; iter != intEnd; ++iter) {
1555 
1556  // Calculate the dynamics for this resonance
1557  if(*iter < nAmp_) {
1558  this->resAmp(*iter);
1559  } else {
1560  this->incohResAmp(*iter-nAmp_);
1561  }
1562  }
1563 
1564  // If we haven't cached the data, then we need to find out the efficiency.
1565  eff_ = this->retrieveEfficiency();
1566 }
1567 
1568 void LauIsobarDynamics::calcTotalAmp(const Bool_t useEff)
1569 {
1570  // Reset the total amplitude to zero
1571  totAmp_.zero();
1572 
1573  // Loop over all signal amplitudes
1574  LauComplex ATerm;
1575  for (UInt_t i = 0; i < nAmp_; ++i) {
1576 
1577  // Get the partial complex amplitude - (mag, phase)*(resonance dynamics)
1578  ATerm = Amp_[i]*ff_[i];
1579 
1580  // Scale this contribution by its relative normalisation w.r.t. the whole dynamics
1581  ATerm.rescale(fNorm_[i]);
1582 
1583  // Add this partial amplitude to the sum
1584  totAmp_ += ATerm;
1585 
1586  } // Loop over amplitudes
1587 
1588  // |Sum of partial amplitudes|^2
1589  ASq_ = totAmp_.abs2();
1590 
1591  for (UInt_t i = 0; i < nIncohAmp_; ++i) {
1592 
1593  // Get the partial complex amplitude - (mag, phase)
1594  ATerm = Amp_[i+nAmp_];
1595 
1596  // Scale this contribution by its relative normalisation w.r.t. the whole dynamics
1597  ATerm.rescale(fNorm_[i+nAmp_]);
1598 
1599  // Add this partial amplitude to the sum
1600  ASq_ += ATerm.abs2()*incohInten_[i];
1601 
1602  }
1603 
1604  // Apply the efficiency correction for this event.
1605  // Multiply the amplitude squared sum by the DP efficiency
1606  if ( useEff ) {
1607  ASq_ *= eff_;
1608  }
1609 }
1610 
1612 {
1613  // Combine the Gauss-Legendre weight with the efficiency
1614  const Double_t effWeight = eff_*weight;
1615 
1616  LauComplex fifjEffSumTerm;
1617  LauComplex fifjSumTerm;
1618 
1619  // Calculates the half-matrix of amplitude-squared and interference
1620  // terms (dynamical part only)
1621  // Add the values at this point on the integration grid to the sums
1622  // (one weighted only by the integration weights, one also weighted by
1623  // the efficiency)
1624  for (UInt_t i = 0; i < nAmp_; ++i) {
1625 
1626  // Add the dynamical amplitude squared for this resonance.
1627  Double_t fSqVal = ff_[i].abs2();
1628  fSqSum_[i] += fSqVal*weight;
1629  fSqEffSum_[i] += fSqVal*effWeight;
1630 
1631  for (UInt_t j = i; j < nAmp_; ++j) {
1632 
1633  fifjEffSumTerm = fifjSumTerm = ff_[i]*ff_[j].conj();
1634 
1635  fifjEffSumTerm.rescale(effWeight);
1636  fifjEffSum_[i][j] += fifjEffSumTerm;
1637 
1638  fifjSumTerm.rescale(weight);
1639  fifjSum_[i][j] += fifjSumTerm;
1640  }
1641  }
1642  for (UInt_t i = 0; i < nIncohAmp_; ++i) {
1643 
1644  // Add the dynamical amplitude squared for this resonance.
1645  Double_t fSqVal = incohInten_[i];
1646  fSqSum_[i+nAmp_] += fSqVal*weight;
1647  fSqEffSum_[i+nAmp_] += fSqVal*effWeight;
1648  }
1649 }
1650 
1651 void LauIsobarDynamics::resAmp(const UInt_t index)
1652 {
1653  // Routine to calculate the resonance dynamics (amplitude)
1654  // using the appropriate Breit-Wigner/Form Factors.
1655 
1656  if ( index >= nAmp_ ) {
1657  std::cerr<<"ERROR in LauIsobarDynamics::resAmp : index = "<<index<<" is not within the range 0 to "<<nAmp_-1<<std::endl;
1658  return;
1659  }
1660 
1661  // Get the signal resonance from the stored vector
1662  LauAbsResonance* sigResonance = sigResonances_[index];
1663 
1664  if (sigResonance == 0) {
1665  std::cerr<<"ERROR in LauIsobarDynamics::resAmp : Couldn't retrieve valid resonance with index = "<<index<<std::endl;
1666  ff_[index] = LauComplex(0.0, 0.0);
1667  return;
1668  }
1669 
1670  ff_[index] = sigResonance->amplitude(kinematics_);
1671 
1672  // If we have a symmetrical Dalitz plot, flip the m_13^2 and m_23^2
1673  // variables, recalculate the dynamics, and combine both contributions.
1674  if (symmetricalDP_ == kTRUE) {
1676 
1677  ff_[index] += sigResonance->amplitude(kinematics_);
1678 
1679  // Flip the m_13^2 and m_23^2 variables back to their original values
1681  }
1682 
1683  // If we have a fully symmetric DP we need to calculate the amplitude at 6 points
1684  else if (fullySymmetricDP_ == kTRUE) {
1685  // rotate and evaluate
1687  ff_[index] += sigResonance->amplitude(kinematics_);
1688 
1689  // rotate and evaluate
1691  ff_[index] += sigResonance->amplitude(kinematics_);
1692 
1693  // rotate, flip and evaluate
1696  ff_[index] += sigResonance->amplitude(kinematics_);
1697 
1698  // rotate and evaluate
1700  ff_[index] += sigResonance->amplitude(kinematics_);
1701 
1702  // rotate and evaluate
1704  ff_[index] += sigResonance->amplitude(kinematics_);
1705 
1706  // rotate and flip to get us back to where we started
1709  }
1710 }
1711 
1712 void LauIsobarDynamics::incohResAmp(const UInt_t index)
1713 {
1714  // Routine to calculate the resonance dynamics (amplitude)
1715  // using the appropriate Breit-Wigner/Form Factors.
1716 
1717  if ( index >= nIncohAmp_ ) {
1718  std::cerr<<"ERROR in LauIsobarDynamics::incohResAmp : index = "<<index<<" is not within the range 0 to "<<nIncohAmp_-1<<std::endl;
1719  return;
1720  }
1721 
1722  // Get the signal resonance from the stored vector
1723  LauAbsIncohRes* sigResonance = sigIncohResonances_[index];
1724 
1725  if (sigResonance == 0) {
1726  std::cerr<<"ERROR in LauIsobarDynamics::incohResAmp : Couldn't retrieve valid incoherent resonance with index = "<<index<<std::endl;
1727  incohInten_[index] = 0.0;
1728  return;
1729  }
1730 
1731  LauComplex ff = sigResonance->amplitude(kinematics_);
1732  incohInten_[index] = sigResonance->intensityFactor(kinematics_)*ff.abs2();
1733 
1734  // If we have a symmetrical Dalitz plot, flip the m_13^2 and m_23^2
1735  // variables, recalculate the dynamics, and combine both contributions.
1736  if (symmetricalDP_ == kTRUE) {
1738 
1739  ff = sigResonance->amplitude(kinematics_);
1740  incohInten_[index] += sigResonance->intensityFactor(kinematics_)*ff.abs2();
1741 
1742  // Flip the m_13^2 and m_23^2 variables back to their original values
1744  }
1745 
1746  // If we have a fully symmetric DP we need to calculate the amplitude at 6 points
1747  else if (fullySymmetricDP_ == kTRUE) {
1748  // rotate and evaluate
1750  ff = sigResonance->amplitude(kinematics_);
1751  incohInten_[index] += sigResonance->intensityFactor(kinematics_)*ff.abs2();
1752 
1753  // rotate and evaluate
1755  ff = sigResonance->amplitude(kinematics_);
1756  incohInten_[index] += sigResonance->intensityFactor(kinematics_)*ff.abs2();
1757 
1758  // rotate, flip and evaluate
1761  ff = sigResonance->amplitude(kinematics_);
1762  incohInten_[index] += sigResonance->intensityFactor(kinematics_)*ff.abs2();
1763 
1764  // rotate and evaluate
1766  ff = sigResonance->amplitude(kinematics_);
1767  incohInten_[index] += sigResonance->intensityFactor(kinematics_)*ff.abs2();
1768 
1769  // rotate and evaluate
1771  ff = sigResonance->amplitude(kinematics_);
1772  incohInten_[index] += sigResonance->intensityFactor(kinematics_)*ff.abs2();
1773 
1774  // rotate and flip to get us back to where we started
1777  }
1778 
1779 }
1780 
1781 void LauIsobarDynamics::setFFTerm(const UInt_t index, const Double_t realPart, const Double_t imagPart)
1782 {
1783  // Function to set the internal ff term (normally calculated using resAmp(index).
1784  if ( index >= nAmp_ ) {
1785  std::cerr<<"ERROR in LauIsobarDynamics::setFFTerm : index = "<<index<<" is not within the range 0 to "<<nAmp_-1<<std::endl;
1786  return;
1787  }
1788 
1789  ff_[index].setRealImagPart( realPart, imagPart );
1790 }
1791 
1792 void LauIsobarDynamics::setIncohIntenTerm(const UInt_t index, const Double_t value)
1793 {
1794  // Function to set the internal incoherent intensity term (normally calculated using incohResAmp(index).
1795  if ( index >= nIncohAmp_ ) {
1796  std::cerr<<"ERROR in LauIsobarDynamics::setFFTerm : index = "<<index<<" is not within the range 0 to "<<nIncohAmp_-1<<std::endl;
1797  return;
1798  }
1799 
1800  incohInten_[index] = value;
1801 }
1802 
1803 void LauIsobarDynamics::calcExtraInfo(const Bool_t init)
1804 {
1805  // This method calculates the fit fractions, mean efficiency and total DP rate
1806 
1807  Double_t fifjEffTot(0.0), fifjTot(0.0);
1808  UInt_t i, j;
1809  for (i = 0; i < nAmp_; i++) {
1810 
1811  // Calculate the diagonal terms
1812  TString name = "A"; name += i; name += "Sq_FitFrac";
1813  fitFrac_[i][i].name(name);
1814 
1815  name += "EffUnCorr";
1816  fitFracEffUnCorr_[i][i].name(name);
1817 
1818  Double_t fifjSumReal = fifjSum_[i][i].re();
1819  Double_t sumTerm = Amp_[i].abs2()*fifjSumReal*fNorm_[i]*fNorm_[i];
1820  fifjTot += sumTerm;
1821 
1822  Double_t fifjEffSumReal = fifjEffSum_[i][i].re();
1823  Double_t sumEffTerm = Amp_[i].abs2()*fifjEffSumReal*fNorm_[i]*fNorm_[i];
1824  fifjEffTot += sumEffTerm;
1825 
1826  fitFrac_[i][i] = sumTerm;
1827  fitFracEffUnCorr_[i][i] = sumEffTerm;
1828  }
1829 
1830  for (i = 0; i < nAmp_; i++) {
1831  for (j = i+1; j < nAmp_+nIncohAmp_; j++) {
1832  // Calculate the cross-terms
1833  TString name = "A"; name += i; name += "A"; name += j; name += "_FitFrac";
1834  fitFrac_[i][j].name(name);
1835 
1836  name += "EffUnCorr";
1837  fitFracEffUnCorr_[i][j].name(name);
1838 
1839  if(j >= nAmp_) {
1840  //Set off-diagonal incoherent terms to zero
1841  fitFrac_[i][j] = 0.;
1842  fitFracEffUnCorr_[i][j] = 0.;
1843  continue;
1844  }
1845 
1846  LauComplex AmpjConj = Amp_[j].conj();
1847  LauComplex AmpTerm = Amp_[i]*AmpjConj;
1848 
1849  Double_t crossTerm = 2.0*(AmpTerm*fifjSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
1850  fifjTot += crossTerm;
1851 
1852  Double_t crossEffTerm = 2.0*(AmpTerm*fifjEffSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
1853  fifjEffTot += crossEffTerm;
1854 
1855  fitFrac_[i][j] = crossTerm;
1856  fitFracEffUnCorr_[i][j] = crossEffTerm;
1857  }
1858  }
1859 
1860  for (i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
1861 
1862  // Calculate the incoherent terms
1863  TString name = "A"; name += i; name += "Sq_FitFrac";
1864  fitFrac_[i][i].name(name);
1865 
1866  name += "EffUnCorr";
1867  fitFracEffUnCorr_[i][i].name(name);
1868 
1869  Double_t sumTerm = Amp_[i].abs2()*fSqSum_[i]*fNorm_[i]*fNorm_[i];
1870  fifjTot += sumTerm;
1871 
1872  Double_t sumEffTerm = Amp_[i].abs2()*fSqEffSum_[i]*fNorm_[i]*fNorm_[i];
1873  fifjEffTot += sumEffTerm;
1874 
1875  fitFrac_[i][i] = sumTerm;
1876  fitFracEffUnCorr_[i][i] = sumEffTerm;
1877  }
1878 
1879  for (i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
1880  for (j = i+1; j < nAmp_+nIncohAmp_; j++) {
1881  //Set off-diagonal incoherent terms to zero
1882  TString name = "A"; name += i; name += "A"; name += j; name += "_FitFrac";
1883  fitFrac_[i][j].name(name);
1884 
1885  name += "EffUnCorr";
1886  fitFracEffUnCorr_[i][j].name(name);
1887 
1888  fitFrac_[i][j] = 0.;
1889  fitFracEffUnCorr_[i][j] = 0.;
1890  }
1891  }
1892 
1893  if (TMath::Abs(fifjTot) > 1e-10) {
1894  meanDPEff_ = fifjEffTot/fifjTot;
1895  if (init) {
1898  }
1899  }
1900  DPRate_ = fifjTot;
1901  if (init) {
1904  }
1905 
1906  // Now divide the fitFraction sums by the overall integral
1907  for (i = 0; i < nAmp_+nIncohAmp_; i++) {
1908  for (j = i; j < nAmp_+nIncohAmp_; j++) {
1909  // Get the actual fractions by dividing by the total DP rate
1910  fitFrac_[i][j] /= fifjTot;
1911  fitFracEffUnCorr_[i][j] /= fifjEffTot;
1912  if (init) {
1913  fitFrac_[i][j].genValue( fitFrac_[i][j].value() );
1914  fitFrac_[i][j].initValue( fitFrac_[i][j].value() );
1915  fitFracEffUnCorr_[i][j].genValue( fitFracEffUnCorr_[i][j].value() );
1916  fitFracEffUnCorr_[i][j].initValue( fitFracEffUnCorr_[i][j].value() );
1917  }
1918  }
1919  }
1920 
1921  // Work out total fit fraction over all K-matrix components (for each propagator)
1922  KMPropMap::iterator mapIter;
1923  Int_t propInt(0);
1924 
1925  for (mapIter = kMatrixPropagators_.begin(); mapIter != kMatrixPropagators_.end(); ++mapIter) {
1926 
1927  LauKMatrixPropagator* thePropagator = mapIter->second;
1928 
1929  TString propName = thePropagator->getName();
1930 
1931  // Now loop over all resonances and find those which are K-matrix components for this propagator
1932  Double_t kMatrixTotFitFrac(0.0);
1933 
1934  for (i = 0; i < nAmp_; i++) {
1935 
1936  Bool_t gotKMRes1 = this->gotKMatrixMatch(i, propName);
1937  if (gotKMRes1 == kFALSE) {continue;}
1938 
1939  Double_t fifjSumReal = fifjSum_[i][i].re();
1940  Double_t sumTerm = Amp_[i].abs2()*fifjSumReal*fNorm_[i]*fNorm_[i];
1941 
1942  //Double_t fifjEffSumReal = fifjEffSum_[i][i].re();
1943  //Double_t sumEffTerm = Amp_[i].abs2()*fifjEffSumReal*fNorm_[i]*fNorm_[i];
1944 
1945  kMatrixTotFitFrac += sumTerm;
1946 
1947  for (j = i+1; j < nAmp_; j++) {
1948 
1949  Bool_t gotKMRes2 = this->gotKMatrixMatch(j, propName);
1950  if (gotKMRes2 == kFALSE) {continue;}
1951 
1952  LauComplex AmpjConj = Amp_[j].conj();
1953  LauComplex AmpTerm = Amp_[i]*AmpjConj;
1954 
1955  Double_t crossTerm = 2.0*(AmpTerm*fifjSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
1956  //Double_t crossEffTerm = 2.0*(AmpTerm*fifjEffSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
1957 
1958  kMatrixTotFitFrac += crossTerm;
1959 
1960  }
1961 
1962  }
1963 
1964  kMatrixTotFitFrac /= fifjTot;
1965 
1966  TString parName("KMatrixTotFF_"); parName += propInt;
1967  extraParameters_[propInt].name( parName );
1968  extraParameters_[propInt] = kMatrixTotFitFrac;
1969  if (init) {
1970  extraParameters_[propInt].genValue(kMatrixTotFitFrac);
1971  extraParameters_[propInt].initValue(kMatrixTotFitFrac);
1972  }
1973 
1974  std::cout<<"INFO in LauIsobarDynamics::calcExtraInfo : Total K-matrix fit fraction for propagator "<<propName<<" is "<<kMatrixTotFitFrac<<std::endl;
1975 
1976  ++propInt;
1977 
1978  }
1979 
1980 
1981 }
1982 
1983 Bool_t LauIsobarDynamics::gotKMatrixMatch(UInt_t resAmpInt, const TString& propName) const
1984 {
1985 
1986  Bool_t gotMatch(kFALSE);
1987 
1988  if (resAmpInt >= nAmp_) {return kFALSE;}
1989 
1990  const LauAbsResonance* theResonance = sigResonances_[resAmpInt];
1991 
1992  if (theResonance == 0) {return kFALSE;}
1993 
1994  Int_t resModelInt = theResonance->getResonanceModel();
1995 
1996  if (resModelInt == LauAbsResonance::KMatrix) {
1997 
1998  TString resName = theResonance->getResonanceName();
1999 
2000  KMStringMap::const_iterator kMPropSetIter = kMatrixPropSet_.find(resName);
2001 
2002  if (kMPropSetIter != kMatrixPropSet_.end()) {
2003  TString kmPropString = kMPropSetIter->second;
2004  if (kmPropString == propName) {gotMatch = kTRUE;}
2005  }
2006 
2007  }
2008 
2009  return gotMatch;
2010 
2011 }
2012 
2014 {
2015  // Calculate the normalisation for the log-likelihood function.
2016  DPNorm_ = 0.0;
2017 
2018  for (UInt_t i = 0; i < nAmp_; i++) {
2019  // fifjEffSum is the contribution from the term involving the resonance
2020  // dynamics (f_i for resonance i) and the efficiency term.
2021  Double_t fifjEffSumReal = fifjEffSum_[i][i].re();
2022  // We need to normalise this contribution w.r.t. the complete dynamics in the DP.
2023  // Hence we scale by the fNorm_i factor (squared), which is calculated by the
2024  // initialise() function, when the normalisation integrals are calculated and cached.
2025  // We also include the complex amplitude squared to get the total normalisation
2026  // contribution from this resonance.
2027  DPNorm_ += Amp_[i].abs2()*fifjEffSumReal*fNorm_[i]*fNorm_[i];
2028  }
2029 
2030  // We now come to the cross-terms (between resonances i and j) in the normalisation.
2031  for (UInt_t i = 0; i < nAmp_; i++) {
2032  for (UInt_t j = i+1; j < nAmp_; j++) {
2033  LauComplex AmpjConj = Amp_[j].conj();
2034  LauComplex AmpTerm = Amp_[i]*AmpjConj;
2035  // Again, fifjEffSum is the contribution from the term involving the resonance
2036  // dynamics (f_i*f_j_conjugate) and the efficiency cross term.
2037  // Also include the relative normalisation between these two resonances w.r.t. the
2038  // total DP dynamical structure (fNorm_i and fNorm_j) and the complex
2039  // amplitude squared (mag,phase) part.
2040  DPNorm_ += 2.0*(AmpTerm*fifjEffSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
2041  }
2042  }
2043 
2044  for (UInt_t i = 0; i < nIncohAmp_; i++) {
2045  DPNorm_ += Amp_[i+nAmp_].abs2()*fSqEffSum_[i+nAmp_]*fNorm_[i+nAmp_]*fNorm_[i+nAmp_];
2046  }
2047 
2048  return DPNorm_;
2049 }
2050 
2052 {
2053  // Routine to generate a signal event according to the Dalitz plot
2054  // model we have defined.
2055 
2056  // We need to make sure to calculate everything for every resonance
2057  integralsToBeCalculated_.clear();
2058  for ( UInt_t i(0); i < nAmp_+nIncohAmp_; ++i ) {
2059  integralsToBeCalculated_.insert(i);
2060  }
2061 
2062  nSigGenLoop_ = 0;
2063  Bool_t generatedSig(kFALSE);
2064 
2065  while (generatedSig == kFALSE && nSigGenLoop_ < iterationsMax_) {
2066 
2067  // Generates uniform DP phase-space distribution
2068  Double_t m13Sq(0.0), m23Sq(0.0);
2069  kinematics_->genFlatPhaseSpace(m13Sq, m23Sq);
2070 
2071  // If we're in a symmetrical DP then we should only generate events in one half
2072  // TODO - what do we do for fully symmetric?
2073  if ( symmetricalDP_ && !fullySymmetricDP_ && m13Sq > m23Sq ) {
2074  Double_t tmpSq = m13Sq;
2075  m13Sq = m23Sq;
2076  m23Sq = tmpSq;
2077  }
2078 
2079  // Calculate the amplitudes and total amplitude for the given DP point
2080  this->calcLikelihoodInfo(m13Sq, m23Sq);
2081 
2082 
2083  // Throw the random number and check it against the ratio of ASq and the accept/reject ceiling
2084  const Double_t randNo = LauRandom::randomFun()->Rndm();
2085  if (randNo > ASq_/aSqMaxSet_) {
2086  ++nSigGenLoop_;
2087  } else {
2088  generatedSig = kTRUE;
2089  nSigGenLoop_ = 0;
2090 
2091  // Keep a note of the maximum ASq that we've found
2092  if (ASq_ > aSqMaxVar_) {aSqMaxVar_ = ASq_;}
2093  }
2094 
2095  } // while loop
2096 
2097  // Check that all is well with the generation
2098  Bool_t sigGenOK(kTRUE);
2099  if (GenOK != this->checkToyMC(kTRUE,kFALSE)) {
2100  sigGenOK = kFALSE;
2101  }
2102 
2103  return sigGenOK;
2104 }
2105 
2106 LauIsobarDynamics::ToyMCStatus LauIsobarDynamics::checkToyMC(Bool_t printErrorMessages, Bool_t printInfoMessages)
2107 {
2108  // Check whether we have generated the toy MC OK.
2109  ToyMCStatus ok(GenOK);
2110 
2111  if (nSigGenLoop_ >= iterationsMax_) {
2112  // Exceeded maximum allowed iterations - the generation is too inefficient
2113  if (printErrorMessages) {
2114  std::cerr<<"WARNING in LauIsobarDynamics::checkToyMC : More than "<<iterationsMax_<<" iterations performed and no event accepted."<<std::endl;
2115  }
2116 
2117  if ( aSqMaxSet_ > 1.01 * aSqMaxVar_ ) {
2118  if (printErrorMessages) {
2119  std::cerr<<" : |A|^2 maximum was set to "<<aSqMaxSet_<<" but this appears to be too high."<<std::endl;
2120  std::cerr<<" : Maximum value of |A|^2 found so far = "<<aSqMaxVar_<<std::endl;
2121  std::cerr<<" : The value of |A|^2 maximum will be decreased and the generation restarted."<<std::endl;
2122  }
2123  aSqMaxSet_ = 1.01 * aSqMaxVar_;
2124  std::cout<<"INFO in LauIsobarDynamics::checkToyMC : |A|^2 max reset to "<<aSqMaxSet_<<std::endl;
2125  ok = MaxIterError;
2126  } else {
2127  if (printErrorMessages) {
2128  std::cerr<<" : |A|^2 maximum was set to "<<aSqMaxSet_<<", which seems to be correct for the given model."<<std::endl;
2129  std::cerr<<" : However, the generation is very inefficient - please check your model."<<std::endl;
2130  std::cerr<<" : The maximum number of iterations will be increased and the generation restarted."<<std::endl;
2131  }
2132  iterationsMax_ *= 2;
2133  std::cout<<"INFO in LauIsobarDynamics::checkToyMC : max number of iterations reset to "<<iterationsMax_<<std::endl;
2134  ok = MaxIterError;
2135  }
2136  } else if (aSqMaxVar_ > aSqMaxSet_) {
2137  // Found a value of ASq higher than the accept/reject ceiling - the generation is biased
2138  if (printErrorMessages) {
2139  std::cerr<<"WARNING in LauIsobarDynamics::checkToyMC : |A|^2 maximum was set to "<<aSqMaxSet_<<" but a value exceeding this was found: "<<aSqMaxVar_<<std::endl;
2140  std::cerr<<" : Run was invalid, as any generated MC will be biased, according to the accept/reject method!"<<std::endl;
2141  std::cerr<<" : The value of |A|^2 maximum be reset to be > "<<aSqMaxVar_<<" and the generation restarted."<<std::endl;
2142  }
2143  aSqMaxSet_ = 1.01 * aSqMaxVar_;
2144  std::cout<<"INFO in LauIsobarDynamics::checkToyMC : |A|^2 max reset to "<<aSqMaxSet_<<std::endl;
2145  ok = ASqMaxError;
2146  } else if (printInfoMessages) {
2147  std::cout<<"INFO in LauIsobarDynamics::checkToyMC : aSqMaxSet = "<<aSqMaxSet_<<" and aSqMaxVar = "<<aSqMaxVar_<<std::endl;
2148  }
2149 
2150  return ok;
2151 }
2152 
2154 {
2155  // Retrieve the data for event iEvt
2156  if (data_.size() > iEvt) {
2157  currentEvent_ = data_[iEvt];
2158  } else {
2159  std::cerr<<"ERROR in LauIsobarDynamics::setDataEventNo : Event index too large: "<<iEvt<<" >= "<<data_.size()<<"."<<std::endl;
2160  }
2161 
2168  scfFraction_ = currentEvent_->retrieveScfFraction(); // These two are necessary, even though the dynamics don't actually use scfFraction_ or jacobian_,
2169  jacobian_ = currentEvent_->retrieveJacobian(); // since this is at the heart of the caching mechanism.
2170 }
2171 
2173 {
2174  // Calculate the likelihood and associated info
2175  // for the given event using cached information
2176  evtLike_ = 0.0;
2177 
2178  // retrieve the cached dynamics from the tree:
2179  // realAmp, imagAmp for each resonance plus efficiency, scf fraction and jacobian
2180  this->setDataEventNo(iEvt);
2181 
2182  // use realAmp and imagAmp to create the resonance amplitudes
2183  const std::vector<Double_t>& realAmp = currentEvent_->retrieveRealAmp();
2184  const std::vector<Double_t>& imagAmp = currentEvent_->retrieveImagAmp();
2185  const std::vector<Double_t>& incohInten = currentEvent_->retrieveIncohIntensities();
2186  for (UInt_t i = 0; i < nAmp_; i++) {
2187  this->setFFTerm(i, realAmp[i], imagAmp[i]);
2188  }
2189  for (UInt_t i = 0; i < nIncohAmp_; i++) {
2190  this->setIncohIntenTerm(i, incohInten[i]);
2191  }
2192 
2193  // Update the dynamics - calculates totAmp_ and then ASq_ = totAmp_.abs2() * eff_
2194  // All calculated using cached information on the individual amplitudes and efficiency.
2195  this->calcTotalAmp(kTRUE);
2196 
2197  // Calculate the normalised matrix element squared value
2198  if (DPNorm_ > 1e-10) {
2199  evtLike_ = ASq_/DPNorm_;
2200  }
2201 }
2202 
2203 void LauIsobarDynamics::calcLikelihoodInfo(const Double_t m13Sq, const Double_t m23Sq)
2204 {
2205  this->calcLikelihoodInfo(m13Sq, m23Sq, -1);
2206 }
2207 
2208 void LauIsobarDynamics::calcLikelihoodInfo(const Double_t m13Sq, const Double_t m23Sq, const Int_t tagCat)
2209 {
2210  // Calculate the likelihood and associated info
2211  // for the given point in the Dalitz plot
2212  // Also retrieves the SCF fraction in the bin where the event lies (done
2213  // here to cache it along with the the rest of the DP quantities, like eff)
2214  // The jacobian for the square DP is calculated here for the same reason.
2215  evtLike_ = 0.0;
2216 
2217  // update the kinematics for the specified DP point
2218  kinematics_->updateKinematics(m13Sq, m23Sq);
2219 
2220  // calculate the jacobian and the scfFraction to cache them later
2221  scfFraction_ = this->retrieveScfFraction(tagCat);
2222  if (kinematics_->squareDP() == kTRUE) {
2224  }
2225 
2226  // calculate the ff_ terms and retrieves eff_ from the efficiency model
2227  this->calculateAmplitudes();
2228  // then calculate totAmp_ and finally ASq_ = totAmp_.abs2() * eff_
2229  this->calcTotalAmp(kTRUE);
2230 
2231  // Calculate the normalised matrix element squared value
2232  if (DPNorm_ > 1e-10) {
2233  evtLike_ = ASq_/DPNorm_;
2234  }
2235 }
2236 
2238 {
2239  if ( recalcNormalisation_ == kFALSE ) {
2240  return;
2241  }
2242 
2243  const UInt_t nEvents = data_.size();
2244 
2245  std::set<UInt_t>::const_iterator iter = integralsToBeCalculated_.begin();
2246  const std::set<UInt_t>::const_iterator intEnd = integralsToBeCalculated_.end();
2247 
2248  for (UInt_t iEvt = 0; iEvt < nEvents; ++iEvt) {
2249 
2250  currentEvent_ = data_[iEvt];
2251 
2252  std::vector<Double_t>& realAmp = currentEvent_->retrieveRealAmp();
2253  std::vector<Double_t>& imagAmp = currentEvent_->retrieveImagAmp();
2254  std::vector<Double_t>& incohInten = currentEvent_->retrieveIncohIntensities();
2255 
2256  const Double_t m13Sq = currentEvent_->retrievem13Sq();
2257  const Double_t m23Sq = currentEvent_->retrievem23Sq();
2258  const Int_t tagCat = currentEvent_->retrieveTagCat();
2259 
2260  this->calcLikelihoodInfo(m13Sq, m23Sq, tagCat);
2261 
2262  for ( iter = integralsToBeCalculated_.begin(); iter != intEnd; ++iter) {
2263  const UInt_t i = *iter;
2264  if(*iter < nAmp_) {
2265  realAmp[i] = ff_[i].re();
2266  imagAmp[i] = ff_[i].im();
2267  } else {
2268  incohInten[i-nAmp_] = incohInten_[i-nAmp_];
2269  }
2270  }
2271  }
2272 }
2273 
2275 {
2276  // In LauFitDataTree, the first two variables should always be m13^2 and m23^2.
2277  // Other variables follow thus: charge/flavour tag prob, etc.
2278 
2279  // Since this is the first caching, we need to make sure to calculate everything for every resonance
2280  integralsToBeCalculated_.clear();
2281  for ( UInt_t i(0); i < nAmp_+nIncohAmp_; ++i ) {
2282  integralsToBeCalculated_.insert(i);
2283  }
2284 
2285  UInt_t nBranches = inputFitTree.nBranches();
2286 
2287  if (nBranches < 2) {
2288  std::cerr<<"ERROR in LauIsobarDynamics::fillDataTree : Expecting at least 2 variables " <<"in input data tree, but there are "<<nBranches<<"!\n";
2289  std::cerr<<" : Make sure you have the right number of variables in your input data file!"<<std::endl;
2290  gSystem->Exit(EXIT_FAILURE);
2291  }
2292 
2293  // Data structure that will cache the variables required to
2294  // calculate the signal likelihood for this experiment
2295  for ( std::vector<LauCacheData*>::iterator iter = data_.begin(); iter != data_.end(); ++iter ) {
2296  delete (*iter);
2297  }
2298  data_.clear();
2299 
2300  Double_t m13Sq(0.0), m23Sq(0.0);
2301  Double_t mPrime(0.0), thPrime(0.0);
2302  Int_t tagCat(-1);
2303  std::vector<Double_t> realAmp(nAmp_), imagAmp(nAmp_);
2304  Double_t eff(0.0), scfFraction(0.0), jacobian(0.0);
2305 
2306  UInt_t nEvents = inputFitTree.nEvents() + inputFitTree.nFakeEvents();
2307 
2308  data_.reserve(nEvents);
2309 
2310  for (UInt_t iEvt = 0; iEvt < nEvents; ++iEvt) {
2311 
2312  const LauFitData& dataValues = inputFitTree.getData(iEvt);
2313  LauFitData::const_iterator iter = dataValues.find("m13Sq");
2314  m13Sq = iter->second;
2315  iter = dataValues.find("m23Sq");
2316  m23Sq = iter->second;
2317 
2318  // is there more than one tagging category?
2319  // if so then we need to know the category from the data
2320  if (scfFractionModel_.size()>1) {
2321  iter = dataValues.find("tagCat");
2322  tagCat = static_cast<Int_t>(iter->second);
2323  }
2324 
2325  // calculates the amplitudes and total amplitude for the given DP point
2326  // tagging category not needed by dynamics, but to find out the scfFraction
2327  this->calcLikelihoodInfo(m13Sq, m23Sq, tagCat);
2328 
2329  // extract the real and imaginary parts of the ff_ terms for storage
2330  for (UInt_t i = 0; i < nAmp_; i++) {
2331  realAmp[i] = ff_[i].re();
2332  imagAmp[i] = ff_[i].im();
2333  }
2334 
2335  if ( kinematics_->squareDP() ) {
2336  mPrime = kinematics_->getmPrime();
2337  thPrime = kinematics_->getThetaPrime();
2338  }
2339 
2340  eff = this->getEvtEff();
2341  scfFraction = this->getEvtScfFraction();
2342  jacobian = this->getEvtJacobian();
2343 
2344  // store the data for each event in the list
2345  data_.push_back( new LauCacheData() );
2346  data_[iEvt]->storem13Sq(m13Sq);
2347  data_[iEvt]->storem23Sq(m23Sq);
2348  data_[iEvt]->storemPrime(mPrime);
2349  data_[iEvt]->storethPrime(thPrime);
2350  data_[iEvt]->storeTagCat(tagCat);
2351  data_[iEvt]->storeEff(eff);
2352  data_[iEvt]->storeScfFraction(scfFraction);
2353  data_[iEvt]->storeJacobian(jacobian);
2354  data_[iEvt]->storeRealAmp(realAmp);
2355  data_[iEvt]->storeImagAmp(imagAmp);
2356  data_[iEvt]->storeIncohIntensities(incohInten_);
2357  }
2358 }
2359 
2361 {
2362  // Select the event (kinematics_) using an accept/reject method based on the
2363  // ratio of the current value of ASq to the maximal value.
2364  Bool_t accepted(kFALSE);
2365 
2366  // calculate the ff_ terms and retrieves eff_ from the efficiency model
2367  this->calculateAmplitudes();
2368  // then calculate totAmp_ and finally ASq_ = totAmp_.abs2() (without the efficiency correction!)
2369  this->calcTotalAmp(kFALSE);
2370 
2371  // Compare the ASq value with the maximal value (set by the user)
2372  if (LauRandom::randomFun()->Rndm() < ASq_/aSqMaxSet_) {
2373  accepted = kTRUE;
2374  }
2375 
2376  if (ASq_ > aSqMaxVar_) {aSqMaxVar_ = ASq_;}
2377 
2378  return accepted;
2379 }
2380 
2382 {
2383  // calculate the ff_ terms and retrieves eff_ from the efficiency model
2384  this->calculateAmplitudes();
2385  // then calculate totAmp_ and finally ASq_ = totAmp_.abs2() (without the efficiency correction!)
2386  this->calcTotalAmp(kFALSE);
2387 
2388  if (ASq_ > aSqMaxVar_) {aSqMaxVar_ = ASq_;}
2389 
2390  // return the event weight = the value of the squared amplitude divided
2391  // by the user-defined ceiling
2392  return ASq_ / aSqMaxSet_;
2393 }
2394 
2395 void LauIsobarDynamics::updateCoeffs(const std::vector<LauComplex>& coeffs)
2396 {
2397  // Check that the number of coeffs is correct
2398  if (coeffs.size() != this->getnTotAmp()) {
2399  std::cerr << "ERROR in LauIsobarDynamics::updateCoeffs : Expected " << this->getnTotAmp() << " but got " << coeffs.size() << std::endl;
2400  gSystem->Exit(EXIT_FAILURE);
2401  }
2402 
2403  // Now check if the coeffs have changed
2404  Bool_t changed = (Amp_ != coeffs);
2405  if (changed) {
2406  // Copy the coeffs
2407  Amp_ = coeffs;
2408  }
2409 
2410  // TODO should perhaps keep track of whether the resonance parameters have changed here and if none of those and none of the coeffs have changed then we don't need to update the norm
2411 
2412  // Update the total normalisation for the signal likelihood
2413  this->calcSigDPNorm();
2414 }
2415 
2416 Bool_t LauIsobarDynamics::hasResonance(const TString& resName) const
2417 {
2418  const LauAbsResonance* theRes = this->findResonance(resName);
2419  if (theRes != 0) {
2420  return kTRUE;
2421  } else {
2422  return kFALSE;
2423  }
2424 }
2425 
2426 TString LauIsobarDynamics::getConjResName(const TString& resName) const
2427 {
2428  // Get the name of the charge conjugate resonance
2429  TString conjName(resName);
2430 
2431  Ssiz_t index1 = resName.Index("+");
2432  Ssiz_t index2 = resName.Index("-");
2433  if (index1 != -1) {
2434  conjName.Replace(index1, 1, "-");
2435  } else if (index2 != -1) {
2436  conjName.Replace(index2, 1, "+");
2437  }
2438 
2439  return conjName;
2440 
2441 }
2442 
2444 {
2445  Double_t eff(1.0);
2446  if (effModel_ != 0) {
2448  }
2449  return eff;
2450 }
2451 
2453 {
2454  Double_t scfFraction(0.0);
2455 
2456  // scf model and eff model are exactly the same, functionally
2457  // so we use an instance of LauAbsEffModel, and the method
2458  // calcEfficiency actually calculates the scf fraction
2459  if (tagCat == -1) {
2460  if (!scfFractionModel_.empty()) {
2461  scfFraction = scfFractionModel_[0]->calcEfficiency(kinematics_);
2462  }
2463  } else {
2464  scfFraction = scfFractionModel_[tagCat]->calcEfficiency(kinematics_);
2465  }
2466  return scfFraction;
2467 }
2468 
KMStringMap kMatrixPropSet_
The names of the M-matrix components in the model mapped to their propagators.
std::vector< LauComplex > Amp_
The complex coefficients for the amplitude components.
void modifyDataTree()
Recache the amplitude values for those that have changed.
Int_t nSigGenLoop_
The number of unsucessful attempts to generate an event so far.
TString getNameDaug1() const
Get name of the first daughter particle.
Double_t getm23Max() const
Get the m23 maximum defined as (mParent - m1)
Double_t retrievemPrime() const
Retrieve the square Dalitz plot coordinate, m&#39;.
Bool_t squareDP() const
Are the square Dalitz plot co-ordinates being calculated?
TRandom * randomFun()
Access the singleton random number generator with a particular seed.
Definition: LauRandom.cc:20
File containing declaration of LauKMatrixPropFactory class.
File containing declaration of LauFitDataTree class.
File containing declaration of LauNRAmplitude class.
Bool_t recalcNormalisation_
Flag to recalculate the normalisation.
void storeIntensity(const UInt_t m13Point, const UInt_t m23Point, const UInt_t iAmp, const Double_t intensity)
Store the intensity for the given grid point and intensity index.
Double_t retrievem23Sq() const
Retrieve the invariant mass squared of the second and third daugthers.
virtual ~LauIsobarDynamics()
Destructor.
Int_t getTypeDaug1() const
Get PDG code of the first daughter particle.
const TString & getResonanceName() const
Get the name of the resonance.
void updateCoeffs(const std::vector< LauComplex > &coeffs)
Update the complex coefficients for the resonances.
std::set< UInt_t > integralsToBeCalculated_
Resonance indices for which the amplitudes and integrals should be recalculated.
Double_t m13BinWidth_
The bin width to use when integrating over m13.
Bool_t flipHelicity_
The helicity flip flag for new amplitude components.
File containing declaration of LauAbsEffModel class.
ClassImp(LauAbsCoeffSet)
std::vector< Int_t > resPairAmp_
The index of the daughter not produced by the resonance for each amplitude component.
Bool_t hasResonance(const TString &resName) const
Check whether this model includes a named resonance.
std::vector< LauParameter > extraParameters_
any extra parameters/quantities (e.g. K-matrix total fit fractions)
File containing declaration of LauKMatrixProdPole class.
const TString & name() const
The parameter name.
Double_t getmPrime() const
Get m&#39; value.
Int_t getNPoles() const
Get the number of poles.
Class that defines the particular 3-body decay under study.
Definition: LauDaughters.hh:33
const std::vector< Double_t > & retrieveImagAmp() const
Retrieve the imaginary parts of the amplitudes.
Int_t getTypeParent() const
Get PDG code of the parent particle.
Int_t getCharge(Int_t resPairAmpInt) const
Get charge of a particular two-daughter combination.
Double_t getEvtJacobian() const
Retrieve the Jacobian, for the transformation into square DP coordinates, for the current event...
File containing declaration of LauBelleNR class.
void defineKMatrixPropagator(const TString &propName, const TString &paramFileName, Int_t resPairAmpInt, Int_t nChannels, Int_t nPoles, Int_t rowIndex=1)
Define a new K-matrix Propagator.
std::vector< Double_t > fSqEffSum_
The event-by-event running total of the dynamical amplitude squared for each amplitude component...
File containing declaration of LauKMatrixProdSVP class.
void calcDPNormalisationScheme()
Calculate the Dalitz plot normalisation integrals across the whole Dalitz plot.
LauAbsEffModel * effModel_
The efficiency model across the Dalitz plot.
void calcExtraInfo(const Bool_t init=kFALSE)
Calculate the fit fractions, mean efficiency and total DP rate.
std::vector< Int_t > incohResPairAmp_
The index of the daughter not produced by the resonance for each incoherent amplitude component...
Double_t DPNorm_
The normalisation factor for the log-likelihood function.
LauTagCatScfFractionModelMap scfFractionModel_
The self cross feed fraction models across the Dalitz plot.
LauParArray fitFrac_
The fit fractions for the amplitude components.
File containing declaration of LauDaughters class.
Double_t aSqMaxVar_
The maximum value of A squared that has been seen so far while generating.
Double_t scfFraction_
The fraction of events that are poorly reconstructed (the self cross feed fraction) at the current po...
Abstract class for defining incoherent resonant amplitude models.
Double_t m13Sq_
The invariant mass squared of the first and third daughters.
LauAbsResonance * getResonance(const LauDaughters *daughters, const TString &resName, const Int_t resPairAmpInt, const LauAbsResonance::LauResonanceModel resType, const LauBlattWeisskopfFactor::BlattWeisskopfCategory bwCategory=LauBlattWeisskopfFactor::Default, const LauBlattWeisskopfFactor::BarrierType bwType=LauBlattWeisskopfFactor::BWPrimeBarrier)
Create a resonance.
Int_t iterationsMax_
The maximum allowed number of attempts when generating an event.
LauComplex totAmp_
The total amplitude for the current event.
TString getConjResName(const TString &resName) const
Retrieve the name of the charge conjugate of a named resonance.
Double_t aSqMaxSet_
The maximum allowed value of A squared.
std::vector< Double_t > resonanceParValues_
List of floating resonance parameter values from previous calculation.
File containing declaration of LauBelleSymNR class.
Bool_t symmetricalDP_
Whether the Dalitz plot is symmetrical.
File containing declaration of LauPrint class.
Pure abstract base class for defining the efficiency description across the signal Dalitz plot...
void setIncohIntenTerm(const UInt_t index, const Double_t value)
Set the dynamic part of the intensity for a given incoherent amplitude component at the current point...
Int_t getNChannels() const
Get the number of channels.
Double_t getm13Min() const
Get the m13 minimum defined as (m1 + m3)
Class for defining (a section of) the Dalitz plot integration binning scheme.
Double_t retrieveJacobian() const
Retrieve the Jacobian for the transformation into square-Dalitz-plot coordinates. ...
Class to contain cached data relating to an event.
Definition: LauCacheData.hh:30
std::map< TString, Double_t > LauFitData
Type for holding event data.
void calcDPNormalisation()
Calculate the Dalitz plot normalisation integrals across the whole Dalitz plot.
TString getNameDaug2() const
Get name of the second daughter particle.
Double_t getM23Value(const UInt_t m23Point) const
Retrieve the m23 value at the given grid point.
void recalculateNormalisation()
recalculate Normalization
std::vector< TString > incohResTypAmp_
The resonance types of all of the incoherent amplitude components.
std::vector< LauAbsIncohRes * > sigIncohResonances_
The incoherent resonances in the model.
UInt_t nBranches() const
Obtain the number of branches in the tree.
Double_t getEvtScfFraction() const
Retrieve the fraction of events that are poorly reconstructed (the self cross feed fraction) for the ...
void resAmp(const UInt_t index)
Calculate the dynamic part of the amplitude for a given component at the current point in the Dalitz ...
LauKMatrixPropagator * getPropagator(const TString &name, const TString &paramFileName, Int_t resPairAmpInt, Int_t nChannels, Int_t nPoles, Int_t rowIndex)
Retrieve the propagator if it already exists, otherwise create one.
LauParameter DPRate_
The overall Dalitz plot rate.
void calcLikelihoodInfo(const UInt_t iEvt)
Calculate the likelihood (and all associated information) for the given event number.
ToyMCStatus
The possible statuses for toy MC generation.
KMPropMap kMatrixPropagators_
The K-matrix propagators.
std::vector< Double_t > fSqSum_
The event-by-event running total of the dynamical amplitude squared for each amplitude component...
Bool_t flipHelicity() const
Get the helicity flip flag.
File containing declaration of LauKinematics class.
UInt_t getnm23Points() const
Retrieve the number of bins in m23.
File containing declaration of LauKMatrixPropagator class.
Double_t getm13Max() const
Get the m13 maximum defined as (mParent - m2)
UInt_t getnm13Points() const
Retrieve the number of bins in m13.
Class for defining a K-matrix production pole amplitude term.
Double_t getm12Min() const
Get the m12 minimum defined as (m1 + m2)
UInt_t nAmp_
The number of amplitude components.
Double_t retrievem13Sq() const
Retrieve the invariant mass squared of the first and third daugthers.
Double_t m23Sq_
The invariant mass squared of the second and third daughters.
Double_t thPrime_
The square Dalitz plot coordinate theta&#39;.
Double_t evtLike_
The normalised likelihood for the current event.
File containing declaration of LauIsobarDynamics class.
std::vector< std::vector< LauComplex > > fifjEffSum_
The event-by-event running total of efficiency corrected amplitude cross terms for each pair of ampli...
Singleton factory class for creating resonances.
void updateKinematics(Double_t m13Sq, Double_t m23Sq)
Update all kinematic quantities based on the DP co-ordinates m13Sq and m23Sq.
void initSummary()
Print a summary of the model to be used.
Bool_t fullySymmetricDP_
Whether the Dalitz plot is fully symmetric.
void fillDataTree(const LauFitDataTree &fitDataTree)
Fill the internal data structure that caches the resonance dynamics.
LauAbsResonance * findResonance(const TString &name)
Retrieve the named resonance.
void resetNormVectors()
Zero the various values used to store integrals info.
Double_t ASq_
The value of A squared for the current event.
Double_t abs2() const
Obtain the square of the absolute value of the complex number.
Definition: LauComplex.hh:232
Bool_t gotSymmetricalDP() const
Is Dalitz plot symmetric, i.e. 2 identical particles.
Definition: LauDaughters.hh:66
static LauKMatrixPropFactory * getInstance()
Get a static instance of this factory class. Only one is created per application. ...
File containing declaration of LauResonanceMaker class.
Double_t m23BinWidth_
The bin width to use when integrating over m23.
TString intFileName_
The name of the file to save integrals to.
Int_t getResPairAmpInt() const
Get the DP axis identifier.
File containing declaration of LauCacheData class.
virtual LauResonanceModel getResonanceModel() const =0
Get the resonance model type.
Double_t getm12Max() const
Get the m12 maximum defined as (mParent - m3)
void addKMatrixProdPole(const TString &poleName, const TString &propName, Int_t poleIndex)
Add a K-matrix production pole term to the model.
void calcTotalAmp(const Bool_t useEff)
Calculate the total Dalitz plot amplitude at the current point in the Dalitz plot.
Double_t retrieveScfFraction(Int_t tagCat)
Obtain the self cross feed fraction of the current event from the model.
std::vector< TString > resTypAmp_
The resonance types of all of the amplitude components.
const std::vector< Double_t > & retrieveIncohIntensities() const
Retrieve the incoherent intensities.
const std::vector< Double_t > & retrieveRealAmp() const
Retrieve the real parts of the amplitudes.
Int_t retrieveTagCat() const
Retrieve the tagging category.
LauIsobarDynamics(LauDaughters *daughters, LauAbsEffModel *effModel, LauAbsEffModel *scfFractionModel=0)
Constructor.
Int_t tagCat_
The tagging category.
LauCacheData * currentEvent_
The cached data for the current event.
void initialiseVectors()
Initialise the internal storage for this model.
Double_t jacobian_
The Jacobian, for the transformation into square DP coordinates at the current point in the Dalitz pl...
LauDaughters * daughters_
The daughters of the decay.
void flipAndUpdateKinematics()
Flips the DP variables m13^2 &lt;-&gt; m23^2 and recalculates all kinematic quantities. ...
std::map< Int_t, LauAbsEffModel * > LauTagCatScfFractionModelMap
The type used for containing multiple self cross feed fraction models for different categories (e...
Double_t narrowWidth_
The value below which a resonance width is considered to be narrow.
Double_t getM13Value(const UInt_t m13Point) const
Retrieve the m13 value at the given grid point.
void incohResAmp(const UInt_t index)
Calculate the dynamic part of the intensity for a given incoherent component at the current point in ...
File containing declaration of LauDPPartialIntegralInfo class.
std::vector< std::vector< LauComplex > > fifjSum_
The event-by-event running total of the amplitude cross terms for each pair of amplitude components...
Double_t getm23Min() const
Get the m23 minimum defined as (m2 + m3)
Double_t retrieveScfFraction() const
Retrieve the fraction of poorly reconstructed events (the so-called self cross feed fraction) ...
Double_t retrievethPrime() const
Retrieve the square Dalitz plot coordinate, theta&#39;.
UInt_t getnTotAmp() const
Retrieve the total number of amplitude components.
virtual Double_t calcEfficiency(const LauKinematics *kinematics) const =0
Determine the efficiency for a given point in the Dalitz plot.
Double_t calcSigDPNorm()
Calculate the normalisation factor for the log-likelihood function.
Bool_t withinDPLimits(Double_t m13Sq, Double_t m23Sq) const
Check whether a given (m13Sq,m23Sq) point is within the kinematic limits of the Dalitz plot...
Int_t getTypeDaug3() const
Get PDG code of the third daughter particle.
void addGridPointToIntegrals(const Double_t weight)
Add the amplitude values (with the appropriate weight) at the current grid point to the running integ...
const LauFitData & getData(UInt_t iEvt) const
Retrieve the data for a given event.
File containing LauRandom namespace.
Bool_t generate()
Generate a toy MC signal event.
LauAbsResonance * addResonance(const TString &resName, const Int_t resPairAmpInt, const LauAbsResonance::LauResonanceModel resType, const LauBlattWeisskopfFactor::BlattWeisskopfCategory bwCategory=LauBlattWeisskopfFactor::Default, const LauBlattWeisskopfFactor::BarrierType bwType=LauBlattWeisskopfFactor::BWPrimeBarrier)
Add a resonance to the Dalitz plot.
void rotateAndUpdateKinematics()
Cyclically rotates the DP variables (m12 -&gt; m23, m23 -&gt; m13, m13 -&gt; m12) and recalculates all kinemat...
void removeCharge(TString &string) const
Remove the charge from the given particle name.
std::vector< Int_t > typDaug_
The PDG codes of the daughters.
LauResonanceModel
Define the allowed resonance types.
Double_t eff_
The efficiency at the current point in the Dalitz plot.
void calculateAmplitudes()
Calculate the amplitudes for all resonances for the current kinematics.
Int_t getTypeDaug2() const
Get PDG code of the second daughter particle.
BarrierType
Define the allowed types of barrier factors.
Double_t getWeight(const UInt_t m13Point, const UInt_t m23Point) const
Retrieve the weight for the given grid point.
UInt_t nFakeEvents() const
Retrieve the number of fake events.
Bool_t gotReweightedEvent()
Calculates whether an event with the current kinematics should be accepted in order to produce a dist...
Abstract class for defining type for resonance amplitude models (Breit-Wigner, Flatte etc...
TString getNameParent() const
Get name of the parent particle.
Double_t binningFactor_
The factor relating the width of the narrowest resonance and the binning size.
void addKMatrixProdSVP(const TString &SVPName, const TString &propName, Int_t channelIndex)
Add a K-matrix slowly-varying part (SVP) term to the model.
std::vector< LauCacheData * > data_
The cached data for all events.
Bool_t gotFullySymmetricDP() const
Is Dalitz plot fully symmetric, i.e. 3 identical particles.
Definition: LauDaughters.hh:72
void rescale(Double_t scaleVal)
Scale this by a factor.
Definition: LauComplex.hh:285
Int_t getChargeParent() const
Get charge of the parent particle.
void findIntegralsToBeRecalculated()
Determine which amplitudes and integrals need to be recalculated.
void zero()
Set both real and imaginary part to zero.
Definition: LauComplex.hh:321
Double_t initValue() const
The initial value of the parameter.
Class for defining signal dynamics using the isobar model.
Double_t getEventWeight()
Calculate the acceptance rate, for events with the current kinematics, when generating events accordi...
LauAbsResonance * addIncoherentResonance(const TString &resName, const Int_t resPairAmpInt, const LauAbsResonance::LauResonanceModel resType)
Add an incoherent resonance to the Dalitz plot.
File containing LauConstants namespace.
void writeIntegralsFile()
Write the results of the integrals (and related information) to a file.
File containing declaration of LauAbsResonance class.
void calcDPPartialIntegral(LauDPPartialIntegralInfo *intInfo)
Calculate the Dalitz plot normalisation integrals over a given range.
ToyMCStatus checkToyMC(Bool_t printErrorMessages=kTRUE, Bool_t printInfoMessages=kFALSE)
Check the status of the toy MC generation.
LauKinematics * kinematics_
The kinematics of the decay.
Double_t getThetaPrime() const
Get theta&#39; value.
Class for defining a complex number.
Definition: LauComplex.hh:47
Double_t getEvtEff() const
Retrieve the efficiency for the current event.
UInt_t nIncohAmp_
The number of incoherent amplitude components.
Bool_t gotKMatrixMatch(UInt_t resAmpInt, const TString &propName) const
Check whether a resonance is a K-matrix component of a given propagator.
std::vector< LauDPPartialIntegralInfo * > dpPartialIntegralInfo_
The storage of the integration scheme.
Double_t getIntensity(const UInt_t m13Point, const UInt_t m23Point, const UInt_t iAmp) const
Retrieve the intensity for the given grid point and intensity index.
void genFlatPhaseSpace(Double_t &m13Sq, Double_t &m23Sq) const
Routine to generate events flat in phase-space.
TString getName() const
Get the propagator name.
void setDataEventNo(UInt_t iEvt)
Load the data for a given event.
Double_t value() const
The value of the parameter.
void setIntegralBinWidths(const Double_t m13BinWidth, const Double_t m23BinWidth)
Set the widths of the bins to use when integrating across the Dalitz plot.
Bool_t normalizationSchemeDone_
Whether the scheme for the integration has been determined.
UInt_t nEvents() const
Retrieve the number of events.
std::vector< LauParameter * > resonancePars_
List of floating resonance parameters.
std::vector< std::vector< UInt_t > > resonanceParResIndex_
Indices in sigResonances_ to point to the corresponding signal resonance(s) for each floating paramet...
BlattWeisskopfCategory
Define resonance categories that will share common barrier factor radii.
Double_t calcSqDPJacobian()
Calculate the Jacobian for the transformation m23^2, m13^2 -&gt; m&#39;, theta&#39; (square DP) ...
void storeEfficiency(const UInt_t m13Point, const UInt_t m23Point, const Double_t efficiency)
Store the efficiency for the given grid point.
const LauComplex & getAmplitude(const UInt_t m13Point, const UInt_t m23Point, const UInt_t iAmp) const
Retrieve the amplitude for the given grid point and amplitude index.
LauParameter meanDPEff_
The mean efficiency across the Dalitz plot.
static LauResonanceMaker & get()
Get the factory instance.
Bool_t integralsDone_
Whether the integrals have been performed.
std::vector< Double_t > incohInten_
The dynamic part of the intensity for each incoherent amplitude component at the current point in the...
virtual LauComplex amplitude(const LauKinematics *kinematics)
Calculate the complex amplitude.
void storeAmplitude(const UInt_t m13Point, const UInt_t m23Point, const UInt_t iAmp, const LauComplex &amplitude)
Store the amplitude for the given grid point and amplitude index.
std::vector< LauComplex > ff_
The dynamic part of the amplitude for each amplitude component at the current point in the Dalitz plo...
void initialise(const std::vector< LauComplex > &coeffs)
Initialise the Dalitz plot dynamics.
TString getNameDaug3() const
Get name of the third daughter particle.
Double_t genValue() const
The value generated for the parameter.
Double_t mPrime_
The square Dalitz plot coordinate, m&#39;.
std::vector< Double_t > fNorm_
The normalisation factors for the dynamic parts of the amplitude for each amplitude component...
Class for defining a K-matrix production &quot;slowly-varying part&quot; (SVP) amplitude.
Class to store the input fit variables.
Double_t retrieveEff() const
Retrieve the efficiency.
File containing declaration of LauAbsIncohRes class.
std::vector< LauAbsResonance * > sigResonances_
The resonances in the model.
virtual Double_t intensityFactor(const LauKinematics *kinematics)=0
Get intensity factor.
void setFFTerm(const UInt_t index, const Double_t realPart, const Double_t imagPart)
Set the dynamic part of the amplitude for a given amplitude component at the current point in the Dal...
Double_t retrieveEfficiency()
Obtain the efficiency of the current event from the model.
LauParArray fitFracEffUnCorr_
The efficiency-uncorrected fit fractions for the amplitude components.
Class for defining a K-matrix propagator.