Page MenuHomeHEPForge

No OneTemporary

diff --git a/inc/LauIsobarDynamics.hh b/inc/LauIsobarDynamics.hh
index 1d2663f..e7773bf 100644
--- a/inc/LauIsobarDynamics.hh
+++ b/inc/LauIsobarDynamics.hh
@@ -1,907 +1,943 @@
// Copyright University of Warwick 2005 - 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Authors:
// Thomas Latham
// John Back
// Paul Harrison
/*! \file LauIsobarDynamics.hh
\brief File containing declaration of LauIsobarDynamics class.
*/
/*! \class LauIsobarDynamics
\brief Class for defining signal dynamics using the isobar model.
*/
#ifndef LAU_ISOBAR_DYNAMICS
#define LAU_ISOBAR_DYNAMICS
#include <set>
#include <vector>
#include "TString.h"
#include "LauAbsResonance.hh"
#include "LauComplex.hh"
class LauCacheData;
class LauDaughters;
class LauAbsEffModel;
class LauAbsIncohRes;
class LauFitDataTree;
class LauKMatrixPropagator;
class LauDPPartialIntegralInfo;
class LauKinematics;
class LauIsobarDynamics {
public:
//! The type used for containing multiple self cross feed fraction models for different categories (e.g. tagging categories)
typedef std::map<Int_t,LauAbsEffModel*> LauTagCatScfFractionModelMap;
//! The possible statuses for toy MC generation
enum ToyMCStatus {
GenOK, /*!< Generation completed OK */
MaxIterError, /*!< Maximum allowed number of iterations completed without success (ASqMax is too high) */
ASqMaxError /*!< An amplitude squared value was returned that was larger than the maximum expected (ASqMax is too low) */
};
//! Constructor
/*!
\param [in] daughters the daughters of the decay
\param [in] effModel the model to describe the efficiency across the Dalitz plot
\param [in] scfFractionModel the model to describe the fraction of poorly constructed events (the self cross feed fraction) across the Dalitz plot
*/
LauIsobarDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, LauAbsEffModel* scfFractionModel = 0);
//! Constructor
/*!
\param [in] daughters the daughters of the decay
\param [in] effModel the model to describe the efficiency across the Dalitz plot
\param [in] scfFractionModel the models to describe the fraction of poorly constructed events (the self cross feed fraction) across the Dalitz plot for various tagging categories
*/
LauIsobarDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, LauTagCatScfFractionModelMap scfFractionModel);
//! Destructor
virtual ~LauIsobarDynamics();
//! Initialise the Dalitz plot dynamics
/*!
\param [in] coeffs the complex coefficients for the resonances
*/
void initialise(const std::vector<LauComplex>& coeffs);
//! recalculate Normalization
void recalculateNormalisation();
//! Set the name of the file to which to save the results of the integrals
/*!
\param [in] fileName the name of the file
*/
inline void setIntFileName(const TString& fileName) {intFileName_ = fileName;}
// Integration
//! Set the widths of the bins to use when integrating across the Dalitz plot or square Dalitz plot
/*!
Specify the bin widths required when performing the DP integration.
Note that the integration is not performed in m13^2 vs m23^2 space
but in either m13 vs m23 space or mPrime vs thetaPrime space,
with the appropriate Jacobian applied.
The default bin widths in m13 vs m23 space are 0.005 GeV.
The default bin widths in mPrime vs thetaPrime space are 0.001.
\param [in] m13BinWidth the bin width to use when integrating over m13
\param [in] m23BinWidth the bin width to use when integrating over m23
\param [in] mPrimeBinWidth the bin width to use when integrating over mPrime
\param [in] thPrimeBinWidth the bin width to use when integrating over thetaPrime
*/
void setIntegralBinWidths(const Double_t m13BinWidth, const Double_t m23BinWidth,
const Double_t mPrimeBinWidth = 0.001, const Double_t thPrimeBinWidth = 0.001);
//! Set the value below which a resonance width is considered to be narrow
/*!
Narrow resonances trigger different integration behaviour - dividing the DP into regions where a finer binning is used.
This can cause high memory usage, so use this method and LauIsobarDynamics::setIntegralBinningFactor to tune this behaviour, if needed.
\param [in] narrowWidth the value below which a resonance is considered to be narrow (defaults to 0.02 GeV/c2)
*/
void setNarrowResonanceThreshold(const Double_t narrowWidth) { narrowWidth_ = narrowWidth; }
//! Set the factor relating the width of a narrow resonance and the binning size in its integration region
/*!
Narrow resonances trigger different integration behaviour - dividing the DP into regions where a finer binning is used.
This can cause high memory usage, so use this method and LauIsobarDynamics::setNarrowResonanceThreshold to tune this behaviour, if needed.
\param [in] binningFactor the factor by which the resonance width is divided to obtain the bin size (defaults to 100)
*/
void setIntegralBinningFactor(const Double_t binningFactor) { binningFactor_ = binningFactor; }
//! Add a resonance to the Dalitz plot
/*!
NB the stored order of resonances is:
- Firstly, all coherent resonances (i.e. those added using addResonance() or addKMatrixProdPole() or addKMatrixProdSVP()) in order of addition
- Followed by all incoherent resonances (i.e. those added using addIncoherentResonance()) in order of addition
\param [in] resName the name of the resonant particle
\param [in] resPairAmpInt the index of the daughter not produced by the resonance
\param [in] resType the model for the resonance dynamics
\param [in] bwCategory the Blatt-Weisskopf barrier factor category
\param [in] bwType the Blatt-Weisskopf barrier type
\return the newly created resonance
*/
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 an incoherent resonance to the Dalitz plot
/*!
NB the stored order of resonances is:
- Firstly, all coherent resonances (i.e. those added using addResonance() or addKMatrixProdPole() or addKMatrixProdSVP()) in order of addition
- Followed by all incoherent resonances (i.e. those added using addIncoherentResonance()) in order of addition
\param [in] resName the name of the resonant particle
\param [in] resPairAmpInt the index of the daughter not produced by the resonance
\param [in] resType the model for the resonance dynamics
\return the newly created resonance
*/
LauAbsResonance* addIncoherentResonance(const TString& resName, const Int_t resPairAmpInt, const LauAbsResonance::LauResonanceModel resType);
//! Define a new K-matrix Propagator
/*!
\param [in] propName the name of the propagator
\param [in] paramFileName the file that defines the propagator
\param [in] resPairAmpInt the index of the bachelor
\param [in] nChannels the number of channels
\param [in] nPoles the number of poles
\param [in] rowIndex the index of the row to be used when summing over all amplitude channels: S-wave corresponds to rowIndex = 1.
*/
void defineKMatrixPropagator(const TString& propName, const TString& paramFileName,
Int_t resPairAmpInt, Int_t nChannels, Int_t nPoles, Int_t rowIndex = 1);
//! Add a K-matrix production pole term to the model
/*!
NB the stored order of resonances is:
- Firstly, all coherent resonances (i.e. those added using addResonance() or addKMatrixProdPole() or addKMatrixProdSVP()) in order of addition
- Followed by all incoherent resonances (i.e. those added using addIncoherentResonance()) in order of addition
\param [in] poleName the name of the pole
\param [in] propName the name of the propagator to use
\param [in] poleIndex the index of the pole within the propagator
\param [in] useProdAdler boolean to turn on/off the production Adler zero factor (default = off)
*/
void addKMatrixProdPole(const TString& poleName, const TString& propName, Int_t poleIndex, Bool_t useProdAdler = kFALSE);
//! Add a K-matrix slowly-varying part (SVP) term to the model
/*!
NB the stored order of resonances is:
- Firstly, all coherent resonances (i.e. those added using addResonance() or addKMatrixProdPole() or addKMatrixProdSVP()) in order of addition
- Followed by all incoherent resonances (i.e. those added using addIncoherentResonance()) in order of addition
\param [in] SVPName the name of the term
\param [in] propName the name of the propagator to use
\param [in] channelIndex the index of the channel within the propagator
\param [in] useProdAdler boolean to turn on/off the production Adler zero factor (default = off)
*/
void addKMatrixProdSVP(const TString& SVPName, const TString& propName, Int_t channelIndex, Bool_t useProdAdler = kFALSE);
//! Set the maximum value of A squared to be used in the accept/reject
/*!
\param [in] value the new value
*/
inline void setASqMaxValue(Double_t value) {aSqMaxSet_ = value;}
//! Retrieve the maximum value of A squared to be used in the accept/reject
/*!
\return the maximum value of A squared
*/
inline Double_t getASqMaxSetValue() const { return aSqMaxSet_; }
//! Retrieve the maximum of A squared that has been found while generating
/*!
\return the maximum of A squared that has been found
*/
inline Double_t getASqMaxVarValue() const { return aSqMaxVar_; }
//! Generate a toy MC signal event
/*!
\return kTRUE if the event is successfully generated, kFALSE otherwise
*/
Bool_t generate();
//! Check the status of the toy MC generation
/*!
\param [in] printErrorMessages whether error messages should be printed
\param [in] printInfoMessages whether info messages should be printed
\return the status of the toy MC generation
*/
ToyMCStatus checkToyMC(Bool_t printErrorMessages = kTRUE, Bool_t printInfoMessages = kFALSE);
//! Retrieve the maximum number of iterations allowed when generating an event
/*!
\return the maximum number of iterations allowed
*/
inline Int_t maxGenIterations() const {return iterationsMax_;}
//! Calculate the likelihood (and all associated information) for the given event number
/*!
\param [in] iEvt the event number
*/
void calcLikelihoodInfo(const UInt_t iEvt);
//! Calculate the likelihood (and all associated information) given values of the Dalitz plot coordinates
/*!
\param [in] m13Sq the invariant mass squared of the first and third daughters
\param [in] m23Sq the invariant mass squared of the second and third daughters
*/
void calcLikelihoodInfo(const Double_t m13Sq, const Double_t m23Sq);
//! Calculate the likelihood (and all associated information) given values of the Dalitz plot coordinates and the tagging category
/*!
Also obtain the self cross feed fraction to cache with the rest of the Dalitz plot quantities.
\param [in] m13Sq the invariant mass squared of the first and third daughters
\param [in] m23Sq the invariant mass squared of the second and third daughters
\param [in] tagCat the tagging category
*/
void calcLikelihoodInfo(const Double_t m13Sq, const Double_t m23Sq, const Int_t tagCat);
//! Calculate the fit fractions, mean efficiency and total DP rate
/*!
\param [in] init whether the calculated values should be stored as the initial/generated values or the fitted values
*/
void calcExtraInfo(const Bool_t init = kFALSE);
//! Calculates whether an event with the current kinematics should be accepted in order to produce a distribution of events that matches the model e.g. when reweighting embedded data
/*!
Uses the accept/reject method.
\return kTRUE if the event has been accepted, kFALSE otherwise
*/
Bool_t gotReweightedEvent();
//! Calculate the acceptance rate, for events with the current kinematics, when generating events according to the model
/*!
\return the weight for the current kinematics
*/
Double_t getEventWeight();
//! Retrieve the total amplitude for the current event
/*!
\return the total amplitude
*/
inline const LauComplex& getEvtDPAmp() const {return totAmp_;}
//! Retrieve the invariant mass squared of the first and third daughters in the current event
/*!
\return the invariant mass squared of the first and third daughters in the current event
*/
inline Double_t getEvtm13Sq() const {return m13Sq_;}
//! Retrieve the invariant mass squared of the second and third daughters in the current event
/*!
\return the invariant mass squared of the second and third daughters in the current event
*/
inline Double_t getEvtm23Sq() const {return m23Sq_;}
//! Retrieve the square Dalitz plot coordinate, m', for the current event
/*!
\return the square Dalitz plot coordinate, m', for the current event
*/
inline Double_t getEvtmPrime() const {return mPrime_;}
//! Retrieve the square Dalitz plot coordinate, theta', for the current event
/*!
\return the square Dalitz plot coordinate, theta', for the current event
*/
inline Double_t getEvtthPrime() const {return thPrime_;}
//! Retrieve the efficiency for the current event
/*!
\return the efficiency for the current event
*/
inline Double_t getEvtEff() const {return eff_;}
//! Retrieve the fraction of events that are poorly reconstructed (the self cross feed fraction) for the current event
/*!
\return the self cross feed fraction for the current event
*/
inline Double_t getEvtScfFraction() const {return scfFraction_;}
//! Retrieve the Jacobian, for the transformation into square DP coordinates, for the current event
/*!
\return the Jacobian for the current event
*/
inline Double_t getEvtJacobian() const {return jacobian_;}
//! Retrieve the total intensity multiplied by the efficiency for the current event
/*!
\return the total intensity multiplied by the efficiency for the current event
*/
inline Double_t getEvtIntensity() const {return ASq_;}
//! Retrieve the likelihood for the current event
/*!
The likelihood is the normalised total intensity:
evtLike_ = ASq_/DPNorm_
\return the likelihood for the current event
*/
inline Double_t getEvtLikelihood() const {return evtLike_;}
//! Retrieve the normalised dynamic part of the amplitude of the given amplitude component at the current point in the Dalitz plot
/*!
\param [in] resID the index of the component within the model
\return the amplitude of the given component
*/
inline LauComplex getDynamicAmp(const Int_t resID) const {return ff_[resID].scale(fNorm_[resID]);}
//! Retrieve the Amplitude of resonance resID
/*!
\param [in] resID the index of the component within the model
\return the amplitude of the given component
*/
inline LauComplex getFullAmplitude(const Int_t resID) const {return Amp_[resID] * this->getDynamicAmp(resID);}
//! Retrieve the event-by-event running totals of amplitude cross terms for all pairs of amplitude components
/*!
\return the event-by-event running totals of amplitude cross terms
*/
inline const std::vector< std::vector<LauComplex> >& getFiFjSum() const {return fifjSum_;}
//! Retrieve the event-by-event running totals of efficiency corrected amplitude cross terms for all pairs of amplitude components
/*!
\return the event-by-event running totals of amplitude cross terms with efficiency corrections applied
*/
inline const std::vector< std::vector<LauComplex> >& getFiFjEffSum() const {return fifjEffSum_;}
//! Retrieve the normalisation factors for the dynamic parts of the amplitudes for all of the amplitude components
/*!
\return the normalisation factors
*/
inline const std::vector<Double_t>& getFNorm() const {return fNorm_;}
//! Fill the internal data structure that caches the resonance dynamics
/*!
\param [in] fitDataTree the data source
*/
void fillDataTree(const LauFitDataTree& fitDataTree);
//! Recache the amplitude values for those that have changed
void modifyDataTree();
//! Check whether this model includes a named resonance
/*!
\param [in] resName the resonance
\return true if the resonance is present, false otherwise
*/
Bool_t hasResonance(const TString& resName) const;
//! Retrieve the index for the given resonance
/*!
\param [in] resName the resonance
\return the index of the resonance if it is present, -1 otherwise
*/
Int_t resonanceIndex(const TString& resName) const;
//! Retrieve the name of the charge conjugate of a named resonance
/*!
\param [in] resName the resonance
\return the name of the charge conjugate
*/
TString getConjResName(const TString& resName) const;
//! Retrieve the named resonance
/*!
\param [in] resName the name of the resonance to retrieve
\return the requested resonance
*/
const LauAbsResonance* findResonance(const TString& resName) const;
//! Retrieve a resonance by its index
/*!
\param [in] resIndex the index of the resonance to retrieve
\return the requested resonance
*/
const LauAbsResonance* getResonance(const UInt_t resIndex) const;
//! Update the complex coefficients for the resonances
/*!
\param [in] coeffs the new set of coefficients
*/
void updateCoeffs(const std::vector<LauComplex>& coeffs);
//! Set the helicity flip flag for new amplitude components
/*!
\param [in] boolean the helicity flip flag
*/
inline void flipHelicityForCPEigenstates(Bool_t boolean) {flipHelicity_ = boolean;}
//! Retrieve the mean efficiency across the Dalitz plot
/*!
\return the mean efficiency across the Dalitz plot
*/
inline const LauParameter& getMeanEff() const {return meanDPEff_;}
//! Retrieve the overall Dalitz plot rate
/*!
\return the overall Dalitz plot rate
*/
inline const LauParameter& getDPRate() const {return DPRate_;}
//! Retrieve the fit fractions for the amplitude components
/*!
\return the fit fractions
*/
inline const LauParArray& getFitFractions() const {return fitFrac_;}
//! Retrieve the fit fractions for the amplitude components
/*!
\return the fit fractions
*/
inline const LauParArray& getFitFractionsEfficiencyUncorrected() const {return fitFracEffUnCorr_;}
//! Retrieve the total number of amplitude components
/*!
\return the total number of amplitude components
*/
inline UInt_t getnTotAmp() const {return nAmp_+nIncohAmp_;}
//! Retrieve the number of coherent amplitude components
/*!
\return the number of coherent amplitude components
*/
inline UInt_t getnCohAmp() const {return nAmp_;}
//! Retrieve the number of incoherent amplitude components
/*!
\return the number of incoherent amplitude components
*/
inline UInt_t getnIncohAmp() const {return nIncohAmp_;}
//! Retrieve the normalisation factor for the log-likelihood function
/*!
\return the normalisation factor
*/
inline Double_t getDPNorm() const {return DPNorm_;}
//! Retrieve the daughters
/*!
\return the daughters
*/
inline const LauDaughters* getDaughters() const {return daughters_;}
//! Retrieve the Dalitz plot kinematics
/*!
\return the Dalitz plot kinematics
*/
inline const LauKinematics* getKinematics() const {return kinematics_;}
//! Retrieve the Dalitz plot kinematics
/*!
\return the Dalitz plot kinematics
*/
inline LauKinematics* getKinematics() {return kinematics_;}
//! Retrieve the model for the efficiency across the Dalitz plot
/*!
\return the efficiency model
*/
inline const LauAbsEffModel* getEffModel() const {return effModel_;}
//! Check whether a self cross feed fraction model is being used
/*!
\return true if a self cross feed fraction model is being used, false otherwise
*/
inline Bool_t usingScfModel() const { return ! scfFractionModel_.empty(); }
//! Retrieve any extra parameters/quantities (e.g. K-matrix total fit fractions)
/*!
\return any extra parameters
*/
inline const std::vector<LauParameter>& getExtraParameters() const {return extraParameters_;}
//! Retrieve the floating parameters of the resonance models
/*!
\return the list of floating parameters
*/
inline std::vector<LauParameter*>& getFloatingParameters() {return resonancePars_;}
protected:
//! Print a summary of the model to be used
void initSummary();
//! Initialise the internal storage for this model
void initialiseVectors();
//! Zero the various values used to store integrals info
void resetNormVectors();
//! Calculate the Dalitz plot normalisation integrals across the whole Dalitz plot
void calcDPNormalisation();
- //! Form the regions that are produced by the spaces between narrow resonances in m13
- /*!
- \return vector of pointers to LauDPPartialIntegralInfo objects that contain the individual coarse regions
- */
- std::vector<std::pair<Double_t, Double_t> > formGapsFromRegions(const std::vector<std::pair<Double_t, Double_t> > & regions, Double_t min, Double_t max);
-
- //! Removes entries in the vector of LauDPPartialIntegralInfo * that are null
- void cullNullRegions(std::vector<LauDPPartialIntegralInfo *> & regions);
-
- //! Wrapper for LauDPPartialIntegralInfo constructor
- /*!
- \return NULL if the integration region has zero internal points, else returns the corresponding LauDPPartialIntegralInfo
- */
- LauDPPartialIntegralInfo * newDPIntegrationRegion(const Double_t minm13, const Double_t maxm13,
- const Double_t minm23, const Double_t maxm23,
- const Double_t m13BinWidth, const Double_t m23BinWidth,
- const Double_t precision,
- const UInt_t nAmp,
- const UInt_t nIncohAmp);
-
- //! Correct regions to ensure that the finest integration grid takes precedence
- void correctDPOverlap(std::vector<std::pair<Double_t, Double_t> > & regions, const std::vector<Double_t> & binnings);
-
- //! Calculate the integration scheme for narrow m23Regions that are integrated according to m23Binnings grid size, and the overlap according to m13Binnings x m23Binnings
- /*!
- \return vector of pointers to LauDPPartialIntegralInfo objects that contain the individual regions
- */
- std::vector<LauDPPartialIntegralInfo *> m23IntegrationRegions(const std::vector<std::pair<Double_t, Double_t> > & m13Regions,
- const std::vector<std::pair<Double_t, Double_t> > & m23Regions,
- const std::vector<Double_t> & m13Binnings,
- const std::vector<Double_t> & m23Binnings, // Needed for overlap region
- const Double_t precision,
- const Double_t defaultBinning);
-
- //! Calculate the integration scheme for narrow m13Regions that are integrated according to m13Binnings grid size
- /*!
- \return vector of pointers to LauDPPartialIntegralInfo objects that contain the individual regions
- */
- std::vector<LauDPPartialIntegralInfo *> m13IntegrationRegions(const std::vector<std::pair<Double_t, Double_t> > & m13Regions,
- const std::vector<std::pair<Double_t, Double_t> > & m23Regions,
- const std::vector<Double_t> & m13Binnings,
- const Double_t precision,
- const Double_t defaultBinning);
+ //! Form the regions that are produced by the spaces between narrow resonances
+ /*!
+ \param [in] regions the regions defined around narrow resonances
+ \param [in] min the minimum value of the invariant mass
+ \param [in] max the maximum value of the invariant mass
+ \return vector of pointers to LauDPPartialIntegralInfo objects that contain the individual coarse regions
+ */
+ std::vector< std::pair<Double_t,Double_t> > formGapsFromRegions(const std::vector< std::pair<Double_t,Double_t> >& regions, const Double_t min, const Double_t max) const;
+
+ //! Removes entries in the vector of LauDPPartialIntegralInfo* that are null
+ /*!
+ \param [in] regions the list of region pointers
+ */
+ void cullNullRegions(std::vector<LauDPPartialIntegralInfo*>& regions) const;
+
+ //! Wrapper for LauDPPartialIntegralInfo constructor
+ /*!
+ \param [in] minm13 the minimum of the m13 range
+ \param [in] maxm13 the maximum of the m13 range
+ \param [in] minm23 the minimum of the m23 range
+ \param [in] maxm23 the maximum of the m23 range
+ \param [in] m13BinWidth the m13 bin width
+ \param [in] m23BinWidth the m23 bin width
+ \param [in] precision the precision required for the Gauss-Legendre weights
+ \param [in] nAmp the number of coherent amplitude components
+ \param [in] nIncohAmp the number of incoherent amplitude components
+ \return 0 if the integration region has no internal points, otherwise returns a pointer to the newly constructed LauDPPartialIntegralInfo object
+ */
+ LauDPPartialIntegralInfo* newDPIntegrationRegion(const Double_t minm13, const Double_t maxm13,
+ const Double_t minm23, const Double_t maxm23,
+ const Double_t m13BinWidth, const Double_t m23BinWidth,
+ const Double_t precision,
+ const UInt_t nAmp,
+ const UInt_t nIncohAmp) const;
+
+ //! Correct regions to ensure that the finest integration grid takes precedence
+ /*!
+ \param [in] regions the windows in invariant mass
+ \param [in] binnings the corresponding binnings for each window
+ */
+ void correctDPOverlap(std::vector< std::pair<Double_t,Double_t> >& regions, const std::vector<Double_t>& binnings) const;
+
+ //! Create the integration grid objects for the m23 narrow resonance regions, including the overlap regions with the m13 narrow resonances
+ /*!
+ The overlap regions will have an m13Binnings x m23Binnings grid.
+ The other regions will have a defaultBinning x m23Binnings grid.
+
+ \param [in] m13Regions the limits of each narrow-resonance region in m13
+ \param [in] m23Regions the limits of each narrow-resonance region in m23
+ \param [in] m13Binnings the binning of each narrow-resonance region in m13
+ \param [in] m23Binnings the binning of each narrow-resonance region in m23
+ \param [in] precision the precision required for the Gauss-Legendre weights
+ \param [in] defaultBinning the binning used in the bulk of the phase space
+ \return vector of pointers to LauDPPartialIntegralInfo objects that contain the individual regions
+ */
+ std::vector<LauDPPartialIntegralInfo*> m23IntegrationRegions(const std::vector< std::pair<Double_t,Double_t> >& m13Regions,
+ const std::vector< std::pair<Double_t,Double_t> >& m23Regions,
+ const std::vector<Double_t>& m13Binnings,
+ const std::vector<Double_t>& m23Binnings,
+ const Double_t precision,
+ const Double_t defaultBinning) const;
+
+ //! Create the integration grid objects for the m13 narrow resonance regions, excluding the overlap regions with the m23 narrow resonances
+ /*!
+ The regions will have a m13Binnings x defaultBinning grid.
+ The overlap regions are created by the m23IntegrationRegions function.
+
+ \param [in] m13Regions the limits of each narrow-resonance region in m13
+ \param [in] m23Regions the limits of each narrow-resonance region in m23
+ \param [in] m13Binnings the binning of each narrow-resonance region in m13
+ \param [in] precision the precision required for the Gauss-Legendre weights
+ \param [in] defaultBinning the binning used in the bulk of the phase space
+ \return vector of pointers to LauDPPartialIntegralInfo objects that contain the individual regions
+ */
+ std::vector<LauDPPartialIntegralInfo*> m13IntegrationRegions(const std::vector< std::pair<Double_t,Double_t> >& m13Regions,
+ const std::vector< std::pair<Double_t,Double_t> >& m23Regions,
+ const std::vector<Double_t>& m13Binnings,
+ const Double_t precision,
+ const Double_t defaultBinning) const;
//! Calculate the Dalitz plot normalisation integrals across the whole Dalitz plot
void calcDPNormalisationScheme();
//! Determine which amplitudes and integrals need to be recalculated
void findIntegralsToBeRecalculated();
//! Calculate the Dalitz plot normalisation integrals over a given range
/*!
\param [in] intInfo the integration information object
*/
void calcDPPartialIntegral(LauDPPartialIntegralInfo* intInfo);
//! Write the results of the integrals (and related information) to a file
void writeIntegralsFile();
//! Set the dynamic part of the amplitude for a given amplitude component at the current point in the Dalitz plot
/*!
\param [in] index the index of the amplitude component
\param [in] realPart the real part of the amplitude
\param [in] imagPart the imaginary part of the amplitude
*/
void setFFTerm(const UInt_t index, const Double_t realPart, const Double_t imagPart);
//! Set the dynamic part of the intensity for a given incoherent amplitude component at the current point in the Dalitz plot
/*!
\param [in] index the index of the incoherent amplitude component
\param [in] value the intensity
*/
void setIncohIntenTerm(const UInt_t index, const Double_t value);
//! Calculate the amplitudes for all resonances for the current kinematics
void calculateAmplitudes();
//! Calculate or retrieve the cached value of the amplitudes for all resonances at the specified integration grid point
/*!
\param [in,out] intInfo the integration information object
\param [in] m13Point the grid index in m13
\param [in] m23Point the grid index in m23
*/
void calculateAmplitudes( LauDPPartialIntegralInfo* intInfo, const UInt_t m13Point, const UInt_t m23Point );
//! Add the amplitude values (with the appropriate weight) at the current grid point to the running integral values
/*!
\param [in] weight the weight to apply
*/
void addGridPointToIntegrals(const Double_t weight);
//! Calculate the total Dalitz plot amplitude at the current point in the Dalitz plot
/*!
\param [in] useEff whether to apply efficiency corrections
*/
void calcTotalAmp(const Bool_t useEff);
//! Obtain the efficiency of the current event from the model
/*!
\return the efficiency
*/
Double_t retrieveEfficiency();
//! Obtain the self cross feed fraction of the current event from the model
/*!
\param [in] tagCat the tagging category of the current event
\return the self cross feed fraction
*/
Double_t retrieveScfFraction(Int_t tagCat);
//! Set the maximum of A squared that has been found
/*!
\param [in] value the new value
*/
inline void setASqMaxVarValue(Double_t value) {aSqMaxVar_ = value;}
//! Calculate the normalisation factor for the log-likelihood function
/*!
\return the normalisation factor
*/
Double_t calcSigDPNorm();
//! Calculate the dynamic part of the amplitude for a given component at the current point in the Dalitz plot
/*!
\param [in] index the index of the amplitude component within the model
*/
LauComplex resAmp(const UInt_t index);
//! Calculate the dynamic part of the intensity for a given incoherent component at the current point in the Dalitz plot
/*!
\param [in] index the index of the incoherent component within the model
*/
Double_t incohResAmp(const UInt_t index);
//! Load the data for a given event
/*!
\param [in] iEvt the number of the event
*/
void setDataEventNo(UInt_t iEvt);
//! Retrieve the named resonance
/*!
\param [in] resName the name of the resonance to retrieve
\return the requested resonance
*/
LauAbsResonance* findResonance(const TString& resName);
//! Retrieve a resonance by its index
/*!
\param [in] resIndex the index of the resonance to retrieve
\return the requested resonance
*/
LauAbsResonance* getResonance(const UInt_t resIndex);
//! Remove the charge from the given particle name
/*!
\param [in,out] string the particle name
*/
void removeCharge(TString& string) const;
//! Check whether a resonance is a K-matrix component of a given propagator
/*!
\param [in] resAmpInt the index of the resonance within the model
\param [in] propName the name of the K-matrix propagator
\return true if the resonance is a component of the given propagator, otherwise return false
*/
Bool_t gotKMatrixMatch(UInt_t resAmpInt, const TString& propName) const;
private:
//! Copy constructor (not implemented)
LauIsobarDynamics(const LauIsobarDynamics& rhs);
//! Copy assignment operator (not implemented)
LauIsobarDynamics& operator=(const LauIsobarDynamics& rhs);
//! The type used for containing the K-matrix propagators
typedef std::map<TString, LauKMatrixPropagator*> KMPropMap;
//! The type used for mapping K-matrix components to their propagators
typedef std::map<TString, TString> KMStringMap;
//! The daughters of the decay
LauDaughters* daughters_;
//! The kinematics of the decay
LauKinematics* kinematics_;
//! The efficiency model across the Dalitz plot
LauAbsEffModel* effModel_;
//! The self cross feed fraction models across the Dalitz plot
/*!
These model the fraction of signal events that are poorly reconstructed (the self cross feed fraction) as a function of Dalitz plot position.
If the self cross feed is depependent on the tagging category then seperate models can be defined.
*/
LauTagCatScfFractionModelMap scfFractionModel_;
//! The number of amplitude components
UInt_t nAmp_;
//! The number of incoherent amplitude components
UInt_t nIncohAmp_;
//! The complex coefficients for the amplitude components
std::vector<LauComplex> Amp_;
//! The normalisation factor for the log-likelihood function
Double_t DPNorm_;
//! The fit fractions for the amplitude components
LauParArray fitFrac_;
//! The efficiency-uncorrected fit fractions for the amplitude components
LauParArray fitFracEffUnCorr_;
//! The overall Dalitz plot rate
LauParameter DPRate_;
//! The mean efficiency across the Dalitz plot
LauParameter meanDPEff_;
//! The cached data for all events
std::vector<LauCacheData*> data_;
//! The cached data for the current event
LauCacheData* currentEvent_;
//! any extra parameters/quantities (e.g. K-matrix total fit fractions)
std::vector<LauParameter> extraParameters_;
//! The resonances in the model
std::vector<LauAbsResonance*> sigResonances_;
//! The incoherent resonances in the model
std::vector<LauAbsIncohRes*> sigIncohResonances_;
//! The K-matrix propagators
KMPropMap kMatrixPropagators_;
//! The names of the M-matrix components in the model mapped to their propagators
KMStringMap kMatrixPropSet_;
//! The resonance types of all of the amplitude components
std::vector<TString> resTypAmp_;
//! The index of the daughter not produced by the resonance for each amplitude component
std::vector<Int_t> resPairAmp_;
//! The resonance types of all of the incoherent amplitude components
std::vector<TString> incohResTypAmp_;
//! The index of the daughter not produced by the resonance for each incoherent amplitude component
std::vector<Int_t> incohResPairAmp_;
//! The PDG codes of the daughters
std::vector<Int_t> typDaug_;
//! Whether the Dalitz plot is symmetrical
Bool_t symmetricalDP_;
//! Whether the Dalitz plot is fully symmetric
Bool_t fullySymmetricDP_;
//! Whether the integrals have been performed
Bool_t integralsDone_;
//! Whether the scheme for the integration has been determined
Bool_t normalizationSchemeDone_;
//! The storage of the integration scheme
std::vector<LauDPPartialIntegralInfo*> dpPartialIntegralInfo_;
//! The name of the file to save integrals to
TString intFileName_;
//! The bin width to use when integrating over m13
Double_t m13BinWidth_;
//! The bin width to use when integrating over m23
Double_t m23BinWidth_;
//! The bin width to use when integrating over mPrime
Double_t mPrimeBinWidth_;
//! The bin width to use when integrating over thetaPrime
Double_t thPrimeBinWidth_;
//! The value below which a resonance width is considered to be narrow
Double_t narrowWidth_;
//! The factor relating the width of the narrowest resonance and the binning size
Double_t binningFactor_;
//! The invariant mass squared of the first and third daughters
Double_t m13Sq_;
//! The invariant mass squared of the second and third daughters
Double_t m23Sq_;
//! The square Dalitz plot coordinate, m'
Double_t mPrime_;
//! The square Dalitz plot coordinate theta'
Double_t thPrime_;
//! The tagging category
Int_t tagCat_;
//! The efficiency at the current point in the Dalitz plot
Double_t eff_;
//!The fraction of events that are poorly reconstructed (the self cross feed fraction) at the current point in the Dalitz plot
Double_t scfFraction_;
//! The Jacobian, for the transformation into square DP coordinates at the current point in the Dalitz plot
Double_t jacobian_;
//! The value of A squared for the current event
Double_t ASq_;
//! The normalised likelihood for the current event
Double_t evtLike_;
//! The total amplitude for the current event
LauComplex totAmp_;
//! The event-by-event running total of efficiency corrected amplitude cross terms for each pair of amplitude components
/*!
Calculated as the sum of ff_[i]*ff_[j]*efficiency for all events
*/
std::vector< std::vector<LauComplex> > fifjEffSum_;
//! The event-by-event running total of the amplitude cross terms for each pair of amplitude components
/*!
Calculated as the sum of ff_[i]*ff_[j] for all events
*/
std::vector< std::vector<LauComplex> > fifjSum_;
//! The dynamic part of the amplitude for each amplitude component at the current point in the Dalitz plot
std::vector<LauComplex> ff_;
//! The dynamic part of the intensity for each incoherent amplitude component at the current point in the Dalitz plot
std::vector<Double_t> incohInten_;
//! The event-by-event running total of the dynamical amplitude squared for each amplitude component
std::vector<Double_t> fSqSum_;
//! The event-by-event running total of the dynamical amplitude squared for each amplitude component
std::vector<Double_t> fSqEffSum_;
//! The normalisation factors for the dynamic parts of the amplitude for each amplitude component
std::vector<Double_t> fNorm_;
//! The maximum allowed number of attempts when generating an event
Int_t iterationsMax_;
//! The number of unsucessful attempts to generate an event so far
Int_t nSigGenLoop_;
//! The maximum allowed value of A squared
Double_t aSqMaxSet_;
//! The maximum value of A squared that has been seen so far while generating
Double_t aSqMaxVar_;
//! The helicity flip flag for new amplitude components
Bool_t flipHelicity_;
//! Flag to recalculate the normalisation
Bool_t recalcNormalisation_;
//! List of floating resonance parameters
std::vector<LauParameter*> resonancePars_;
//! List of floating resonance parameter values from previous calculation
std::vector<Double_t> resonanceParValues_;
//! Indices in sigResonances_ to point to the corresponding signal resonance(s) for each floating parameter
std::vector< std::vector<UInt_t> > resonanceParResIndex_;
//! Resonance indices for which the amplitudes and integrals should be recalculated
std::set<UInt_t> integralsToBeCalculated_;
ClassDef(LauIsobarDynamics,0)
};
#endif
diff --git a/src/LauIsobarDynamics.cc b/src/LauIsobarDynamics.cc
index 7bffd99..49f12b3 100644
--- a/src/LauIsobarDynamics.cc
+++ b/src/LauIsobarDynamics.cc
@@ -1,2394 +1,2430 @@
// Copyright University of Warwick 2005 - 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Authors:
// Thomas Latham
// John Back
// Paul Harrison
/*! \file LauIsobarDynamics.cc
\brief File containing implementation of LauIsobarDynamics class.
*/
#include <iostream>
#include <iomanip>
#include <fstream>
#include <set>
#include <vector>
#include "TFile.h"
#include "TRandom.h"
#include "TSystem.h"
#include "LauAbsEffModel.hh"
#include "LauAbsResonance.hh"
#include "LauAbsIncohRes.hh"
#include "LauBelleNR.hh"
#include "LauBelleSymNR.hh"
#include "LauCacheData.hh"
#include "LauConstants.hh"
#include "LauDaughters.hh"
#include "LauDPPartialIntegralInfo.hh"
#include "LauFitDataTree.hh"
#include "LauIsobarDynamics.hh"
#include "LauKinematics.hh"
#include "LauKMatrixProdPole.hh"
#include "LauKMatrixProdSVP.hh"
#include "LauKMatrixPropagator.hh"
#include "LauKMatrixPropFactory.hh"
#include "LauNRAmplitude.hh"
#include "LauPrint.hh"
#include "LauRandom.hh"
+#include "LauResonanceInfo.hh"
#include "LauResonanceMaker.hh"
ClassImp(LauIsobarDynamics)
// for Kpipi: only one scfFraction 2D histogram is needed
LauIsobarDynamics::LauIsobarDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, LauAbsEffModel* scfFractionModel) :
daughters_(daughters),
kinematics_(daughters_ ? daughters_->getKinematics() : 0),
effModel_(effModel),
nAmp_(0),
nIncohAmp_(0),
DPNorm_(0.0),
DPRate_("DPRate", 0.0, 0.0, 1000.0),
meanDPEff_("meanDPEff", 0.0, 0.0, 1.0),
currentEvent_(0),
symmetricalDP_(kFALSE),
fullySymmetricDP_(kFALSE),
integralsDone_(kFALSE),
normalizationSchemeDone_(kFALSE),
intFileName_("integ.dat"),
m13BinWidth_(0.005),
m23BinWidth_(0.005),
mPrimeBinWidth_(0.001),
thPrimeBinWidth_(0.001),
narrowWidth_(0.020),
binningFactor_(100.0),
m13Sq_(0.0),
m23Sq_(0.0),
mPrime_(0.0),
thPrime_(0.0),
tagCat_(-1),
eff_(1.0),
scfFraction_(0.0),
jacobian_(0.0),
ASq_(0.0),
evtLike_(0.0),
iterationsMax_(100000),
nSigGenLoop_(0),
aSqMaxSet_(1.25),
aSqMaxVar_(0.0),
flipHelicity_(kTRUE),
recalcNormalisation_(kFALSE)
{
if (daughters != 0) {
symmetricalDP_ = daughters->gotSymmetricalDP();
fullySymmetricDP_ = daughters->gotFullySymmetricDP();
typDaug_.push_back(daughters->getTypeDaug1());
typDaug_.push_back(daughters->getTypeDaug2());
typDaug_.push_back(daughters->getTypeDaug3());
}
if (scfFractionModel != 0) {
scfFractionModel_[0] = scfFractionModel;
}
sigResonances_.clear();
sigIncohResonances_.clear();
kMatrixPropagators_.clear();
kMatrixPropSet_.clear();
extraParameters_.clear();
}
// for Kspipi, we need a scfFraction 2D histogram for each tagging category. They are provided by the map.
// Also, we need to know the place that the tagging category of the current event occupies in the data structure inputFitTree
LauIsobarDynamics::LauIsobarDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, LauTagCatScfFractionModelMap scfFractionModel) :
daughters_(daughters),
kinematics_(daughters_ ? daughters_->getKinematics() : 0),
effModel_(effModel),
scfFractionModel_(scfFractionModel),
nAmp_(0),
nIncohAmp_(0),
DPNorm_(0.0),
DPRate_("DPRate", 0.0, 0.0, 1000.0),
meanDPEff_("meanDPEff", 0.0, 0.0, 1.0),
currentEvent_(0),
symmetricalDP_(kFALSE),
fullySymmetricDP_(kFALSE),
integralsDone_(kFALSE),
normalizationSchemeDone_(kFALSE),
intFileName_("integ.dat"),
m13BinWidth_(0.005),
m23BinWidth_(0.005),
mPrimeBinWidth_(0.001),
thPrimeBinWidth_(0.001),
narrowWidth_(0.020),
binningFactor_(100.0),
m13Sq_(0.0),
m23Sq_(0.0),
mPrime_(0.0),
thPrime_(0.0),
tagCat_(-1),
eff_(1.0),
scfFraction_(0.0),
jacobian_(0.0),
ASq_(0.0),
evtLike_(0.0),
iterationsMax_(100000),
nSigGenLoop_(0),
aSqMaxSet_(1.25),
aSqMaxVar_(0.0),
flipHelicity_(kTRUE),
recalcNormalisation_(kFALSE)
{
// Constructor for the isobar signal model
if (daughters != 0) {
symmetricalDP_ = daughters->gotSymmetricalDP();
fullySymmetricDP_ = daughters->gotFullySymmetricDP();
typDaug_.push_back(daughters->getTypeDaug1());
typDaug_.push_back(daughters->getTypeDaug2());
typDaug_.push_back(daughters->getTypeDaug3());
}
sigResonances_.clear();
sigIncohResonances_.clear();
kMatrixPropagators_.clear();
kMatrixPropSet_.clear();
extraParameters_.clear();
}
LauIsobarDynamics::~LauIsobarDynamics()
{
extraParameters_.clear();
for ( std::vector<LauCacheData*>::iterator iter = data_.begin(); iter != data_.end(); ++iter ) {
delete (*iter);
}
data_.clear();
for (std::vector<LauDPPartialIntegralInfo*>::iterator it = dpPartialIntegralInfo_.begin(); it != dpPartialIntegralInfo_.end(); ++it)
{
delete (*it);
}
dpPartialIntegralInfo_.clear();
}
void LauIsobarDynamics::resetNormVectors()
{
for (UInt_t i = 0; i < nAmp_; i++) {
fSqSum_[i] = 0.0;
fSqEffSum_[i] = 0.0;
fNorm_[i] = 0.0;
ff_[i].zero();
for (UInt_t j = 0; j < nAmp_; j++) {
fifjEffSum_[i][j].zero();
fifjSum_[i][j].zero();
}
}
for (UInt_t i = 0; i < nIncohAmp_; i++) {
fSqSum_[i+nAmp_] = 0.0;
fSqEffSum_[i+nAmp_] = 0.0;
fNorm_[i+nAmp_] = 0.0;
incohInten_[i] = 0.0;
}
}
void LauIsobarDynamics::recalculateNormalisation()
{
if ( recalcNormalisation_ == kFALSE ) {
return;
}
// We need to calculate the normalisation constants for the
// Dalitz plot generation/fitting.
integralsDone_ = kFALSE;
this->resetNormVectors();
this->findIntegralsToBeRecalculated();
this->calcDPNormalisation();
integralsDone_ = kTRUE;
}
void LauIsobarDynamics::findIntegralsToBeRecalculated()
{
// Loop through the resonance parameters and see which ones have changed
// For those that have changed mark the corresponding resonance(s) as needing to be re-evaluated
integralsToBeCalculated_.clear();
const UInt_t nResPars = resonancePars_.size();
for ( UInt_t iPar(0); iPar < nResPars; ++iPar ) {
const Double_t newValue = resonancePars_[iPar]->value();
if ( newValue != resonanceParValues_[iPar] ) {
resonanceParValues_[iPar] = newValue;
const std::vector<UInt_t>& indices = resonanceParResIndex_[iPar];
std::vector<UInt_t>::const_iterator indexIter = indices.begin();
const std::vector<UInt_t>::const_iterator indexEnd = indices.end();
for( ; indexIter != indexEnd; ++indexIter) {
integralsToBeCalculated_.insert(*indexIter);
}
}
}
}
void LauIsobarDynamics::initialise(const std::vector<LauComplex>& coeffs)
{
// Check whether we have a valid set of integration constants for
// the normalisation of the signal likelihood function.
this->initialiseVectors();
// Mark the DP integrals as undetermined
integralsDone_ = kFALSE;
// Initialise all resonance models
resonancePars_.clear();
resonanceParValues_.clear();
resonanceParResIndex_.clear();
std::set<LauParameter*> uniqueResPars;
UInt_t resIndex(0);
for ( std::vector<LauAbsResonance*>::iterator resIter = sigResonances_.begin(); resIter != sigResonances_.end(); ++resIter ) {
(*resIter)->initialise();
// Check if this resonance has floating parameters
// Append all unique parameters to our list
const std::vector<LauParameter*>& resPars = (*resIter)->getFloatingParameters();
for ( std::vector<LauParameter*>::const_iterator parIter = resPars.begin(); parIter != resPars.end(); ++parIter ) {
if ( uniqueResPars.insert( *parIter ).second ) {
// This parameter has not already been added to
// the list of unique ones. Add it, its value
// and its associated resonance ID to the
// appropriate lists.
resonancePars_.push_back( *parIter );
resonanceParValues_.push_back( (*parIter)->value() );
std::vector<UInt_t> resIndices( 1, resIndex );
resonanceParResIndex_.push_back( resIndices );
} else {
// This parameter has already been added to the
// list of unique ones. However, we still need
// to indicate that this resonance should be
// associated with it.
std::vector<LauParameter*>::const_iterator uniqueParIter = resonancePars_.begin();
std::vector<std::vector<UInt_t> >::iterator indicesIter = resonanceParResIndex_.begin();
while( (*uniqueParIter) != (*parIter) ) {
++uniqueParIter;
++indicesIter;
}
( *indicesIter ).push_back( resIndex );
}
}
++resIndex;
}
for ( std::vector<LauAbsIncohRes*>::iterator resIter = sigIncohResonances_.begin(); resIter != sigIncohResonances_.end(); ++resIter ) {
(*resIter)->initialise();
// Check if this resonance has floating parameters
// Append all unique parameters to our list
const std::vector<LauParameter*>& resPars = (*resIter)->getFloatingParameters();
for ( std::vector<LauParameter*>::const_iterator parIter = resPars.begin(); parIter != resPars.end(); ++parIter ) {
if ( uniqueResPars.insert( *parIter ).second ) {
// This parameter has not already been added to
// the list of unique ones. Add it, its value
// and its associated resonance ID to the
// appropriate lists.
resonancePars_.push_back( *parIter );
resonanceParValues_.push_back( (*parIter)->value() );
std::vector<UInt_t> resIndices( 1, resIndex );
resonanceParResIndex_.push_back( resIndices );
} else {
// This parameter has already been added to the
// list of unique ones. However, we still need
// to indicate that this resonance should be
// associated with it.
std::vector<LauParameter*>::const_iterator uniqueParIter = resonancePars_.begin();
std::vector<std::vector<UInt_t> >::iterator indicesIter = resonanceParResIndex_.begin();
while( (*uniqueParIter) != (*parIter) ) {
++uniqueParIter;
++indicesIter;
}
( *indicesIter ).push_back( resIndex );
}
}
++resIndex;
}
if ( resonancePars_.empty() ) {
recalcNormalisation_ = kFALSE;
} else {
recalcNormalisation_ = kTRUE;
}
// Print summary of what we have so far to screen
this->initSummary();
if ( nAmp_+nIncohAmp_ == 0 ) {
std::cout << "INFO in LauIsobarDynamics::initialise : No contributions to DP model, not performing normalisation integrals." << std::endl;
} else {
// We need to calculate the normalisation constants for the Dalitz plot generation/fitting.
std::cout<<"INFO in LauIsobarDynamics::initialise : Starting special run to generate the integrals for normalising the PDF..."<<std::endl;
// Since this is the initialisation, we need to calculate everything for every resonance
integralsToBeCalculated_.clear();
for ( UInt_t i(0); i < nAmp_+nIncohAmp_; ++i ) {
integralsToBeCalculated_.insert(i);
}
// Calculate and cache the normalisations of each resonance _dynamic_ amplitude
// (e.g. Breit-Wigner contribution, not from the complex coefficients).
// These are stored in fNorm_[i].
// fSqSum[i] is the total of the dynamical amplitude squared for a given resonance, i.
// We require that:
// |fNorm_[i]|^2 * |fSqSum[i]|^2 = 1,
// i.e. fNorm_[i] normalises each resonance contribution to give the same number of
// events in the DP, accounting for the total DP area and the dynamics of the resonance.
this->calcDPNormalisation();
// Write the integrals to a file (mainly for debugging purposes)
this->writeIntegralsFile();
}
integralsDone_ = kTRUE;
std::cout << std::setprecision(10);
std::cout<<"INFO in LauIsobarDynamics::initialise : Summary of the integrals:"<<std::endl;
for (UInt_t i = 0; i < nAmp_+nIncohAmp_; i++) {
std::cout<<" fNorm["<<i<<"] = "<<fNorm_[i]<<std::endl;
std::cout<<" fSqSum["<<i<<"] = "<<fSqSum_[i]<<std::endl;
std::cout<<" fSqEffSum["<<i<<"] = "<<fSqEffSum_[i]<<std::endl;
}
for (UInt_t i = 0; i < nAmp_; i++) {
for (UInt_t j = 0; j < nAmp_; j++) {
std::cout<<" fifjEffSum["<<i<<"]["<<j<<"] = "<<fifjEffSum_[i][j];
}
std::cout<<std::endl;
}
for (UInt_t i = 0; i < nAmp_; i++) {
for (UInt_t j = 0; j < nAmp_; j++) {
std::cout<<" fifjSum["<<i<<"]["<<j<<"] = "<<fifjSum_[i][j];
}
std::cout<<std::endl;
}
// Calculate the initial fit fractions (for later comparison with Toy MC, if required)
this->updateCoeffs(coeffs);
this->calcExtraInfo(kTRUE);
for (UInt_t i = 0; i < nAmp_; i++) {
for (UInt_t j = i; j < nAmp_; j++) {
std::cout<<"INFO in LauIsobarDynamics::initialise : Initial fit fraction for amplitude ("<<i<<","<<j<<") = "<<fitFrac_[i][j].genValue()<<std::endl;
}
}
for (UInt_t i = 0; i < nIncohAmp_; i++) {
std::cout<<"INFO in LauIsobarDynamics::initialise : Initial fit fraction for incoherent amplitude ("<<i<<","<<i<<") = "<<fitFrac_[i+nAmp_][i+nAmp_].genValue()<<std::endl;
}
std::cout<<"INFO in LauIsobarDynamics::initialise : Initial efficiency = "<<meanDPEff_.initValue()<<std::endl;
std::cout<<"INFO in LauIsobarDynamics::initialise : Initial DPRate = "<<DPRate_.initValue()<<std::endl;
}
void LauIsobarDynamics::initSummary()
{
UInt_t i(0);
TString nameP = daughters_->getNameParent();
TString name1 = daughters_->getNameDaug1();
TString name2 = daughters_->getNameDaug2();
TString name3 = daughters_->getNameDaug3();
std::cout<<"INFO in LauIsobarDynamics::initSummary : We are going to do a DP with "<<nameP<<" going to "<<name1<<" "<<name2<<" "<<name3<<std::endl;
std::cout<<" : For the following resonance combinations:"<<std::endl;
std::cout<<" : In tracks 2 and 3:"<<std::endl;
for (i = 0; i < nAmp_; i++) {
if (resPairAmp_[i] == 1) {
std::cout<<" : A"<<i<<": "<<resTypAmp_[i]<<" to "<<name2<<", "<< name3<<std::endl;
}
}
for (i = 0; i < nIncohAmp_; i++) {
if (incohResPairAmp_[i] == 1) {
std::cout<<" : A"<<nAmp_+i<<": "<<incohResTypAmp_[i]<<" (incoherent) to "<<name2<<", "<< name3<<std::endl;
}
}
std::cout<<" : In tracks 1 and 3:"<<std::endl;
for (i = 0; i < nAmp_; i++) {
if (resPairAmp_[i] == 2) {
std::cout<<" : A"<<i<<": "<<resTypAmp_[i]<<" to "<<name1<<", "<< name3<<std::endl;
}
}
for (i = 0; i < nIncohAmp_; i++) {
if (incohResPairAmp_[i] == 2) {
std::cout<<" : A"<<nAmp_+i<<": "<<incohResTypAmp_[i]<<" (incoherent) to "<<name1<<", "<< name3<<std::endl;
}
}
std::cout<<" : In tracks 1 and 2:"<<std::endl;
for (i = 0; i < nAmp_; i++) {
if (resPairAmp_[i] == 3) {
std::cout<<" : A"<<i<<": "<<resTypAmp_[i]<<" to "<<name1<<", "<< name2<<std::endl;
}
}
for (i = 0; i < nIncohAmp_; i++) {
if (incohResPairAmp_[i] == 3) {
std::cout<<" : A"<<nAmp_+i<<": "<<incohResTypAmp_[i]<<" (incoherent) to "<<name1<<", "<< name2<<std::endl;
}
}
for (i = 0; i < nAmp_; i++) {
if (resPairAmp_[i] == 0) {
std::cout<<" : and a non-resonant amplitude:"<<std::endl;
std::cout<<" : A"<<i<<std::endl;
}
}
std::cout<<std::endl;
}
void LauIsobarDynamics::initialiseVectors()
{
fSqSum_.clear(); fSqSum_.resize(nAmp_+nIncohAmp_);
fSqEffSum_.clear(); fSqEffSum_.resize(nAmp_+nIncohAmp_);
fifjEffSum_.clear(); fifjEffSum_.resize(nAmp_);
fifjSum_.clear(); fifjSum_.resize(nAmp_);
ff_.clear(); ff_.resize(nAmp_);
incohInten_.clear(); incohInten_.resize(nIncohAmp_);
fNorm_.clear(); fNorm_.resize(nAmp_+nIncohAmp_);
fitFrac_.clear(); fitFrac_.resize(nAmp_+nIncohAmp_);
fitFracEffUnCorr_.clear(); fitFracEffUnCorr_.resize(nAmp_+nIncohAmp_);
LauComplex null(0.0, 0.0);
for (UInt_t i = 0; i < nAmp_; i++) {
fSqSum_[i] = 0.0; fNorm_[i] = 0.0;
ff_[i] = null;
fifjEffSum_[i].resize(nAmp_);
fifjSum_[i].resize(nAmp_);
fitFrac_[i].resize(nAmp_+nIncohAmp_);
fitFracEffUnCorr_[i].resize(nAmp_+nIncohAmp_);
for (UInt_t j = 0; j < nAmp_; j++) {
fifjEffSum_[i][j] = null;
fifjSum_[i][j] = null;
fitFrac_[i][j].valueAndRange(0.0, -100.0, 100.0);
fitFracEffUnCorr_[i][j].valueAndRange(0.0, -100.0, 100.0);
}
for (UInt_t j = nAmp_; j < nAmp_+nIncohAmp_; j++) {
fitFrac_[i][j].valueAndRange(0.0, -100.0, 100.0);
fitFracEffUnCorr_[i][j].valueAndRange(0.0, -100.0, 100.0);
}
}
for (UInt_t i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
fSqSum_[i] = 0.0; fNorm_[i] = 0.0;
incohInten_[i-nAmp_] = 0.0;
fitFrac_[i].resize(nAmp_+nIncohAmp_);
fitFracEffUnCorr_[i].resize(nAmp_+nIncohAmp_);
for (UInt_t j = 0; j < nAmp_+nIncohAmp_; j++) {
fitFrac_[i][j].valueAndRange(0.0, -100.0, 100.0);
fitFracEffUnCorr_[i][j].valueAndRange(0.0, -100.0, 100.0);
}
}
UInt_t nKMatrixProps = kMatrixPropagators_.size();
extraParameters_.clear();
extraParameters_.resize( nKMatrixProps );
for ( UInt_t i = 0; i < nKMatrixProps; ++i ) {
extraParameters_[i].valueAndRange(0.0, -100.0, 100.0);
}
}
void LauIsobarDynamics::writeIntegralsFile()
{
// Routine to end integration calculation for loglike normalisation.
// This writes out the normalisation integral output into the file named
// outputFileName.
std::cout<<"INFO in LauIsobarDynamics::writeIntegralsFile : Writing integral output to integrals file "<<intFileName_.Data()<<std::endl;
UInt_t i(0), j(0);
std::ofstream getChar(intFileName_.Data());
getChar << std::setprecision(10);
// Write out daughter types (pi, pi0, K, K0s?)
for (i = 0; i < 3; i++) {
getChar << typDaug_[i] << " ";
}
// Write out number of resonances in the Dalitz plot model
getChar << nAmp_ << std::endl;
// Write out the resonances
for (i = 0; i < nAmp_; i++) {
getChar << resTypAmp_[i] << " ";
}
getChar << std::endl;
// Write out the resonance model types (BW, RelBW etc...)
for (i = 0; i < nAmp_; i++) {
LauAbsResonance* theResonance = sigResonances_[i];
Int_t resModelInt = theResonance->getResonanceModel();
getChar << resModelInt << " ";
}
getChar << std::endl;
// Write out the track pairings for each resonance. This is specified
// by the resPairAmpInt integer in the addResonance function.
for (i = 0; i < nAmp_; i++) {
getChar << resPairAmp_[i] << " ";
}
getChar << std::endl;
// Write out the fSqSum = |ff|^2, where ff = resAmp()
for (i = 0; i < nAmp_; i++) {
getChar << fSqSum_[i] << " ";
}
getChar << std::endl;
// Similar to fSqSum, but with the efficiency term included.
for (i = 0; i < nAmp_; i++) {
getChar << fSqEffSum_[i] << " ";
}
getChar << std::endl;
// Write out the f_i*f_j_conj*eff values = resAmp_i*resAmp_j_conj*eff.
// Note that only the top half of the i*j "matrix" is required, as it
// is symmetric w.r.t i, j.
for (i = 0; i < nAmp_; i++) {
for (j = i; j < nAmp_; j++) {
getChar << fifjEffSum_[i][j] << " ";
}
}
getChar << std::endl;
// Similar to fifjEffSum, but without the efficiency term included.
for (i = 0; i < nAmp_; i++) {
for (j = i; j < nAmp_; j++) {
getChar << fifjSum_[i][j] << " ";
}
}
getChar << std::endl;
// Write out number of incoherent resonances in the Dalitz plot model
getChar << nIncohAmp_ << std::endl;
// Write out the incoherent resonances
for (i = 0; i < nIncohAmp_; i++) {
getChar << incohResTypAmp_[i] << " ";
}
getChar << std::endl;
// Write out the incoherent resonance model types (BW, RelBW etc...)
for (i = 0; i < nIncohAmp_; i++) {
LauAbsResonance* theResonance = sigIncohResonances_[i];
Int_t resModelInt = theResonance->getResonanceModel();
getChar << resModelInt << " ";
}
getChar << std::endl;
// Write out the track pairings for each incoherent resonance. This is specified
// by the resPairAmpInt integer in the addIncohResonance function.
for (i = 0; i < nIncohAmp_; i++) {
getChar << incohResPairAmp_[i] << " ";
}
getChar << std::endl;
// Write out the fSqSum = |ff|^2, where |ff|^2 = incohResAmp()
for (i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
getChar << fSqSum_[i] << " ";
}
getChar << std::endl;
// Similar to fSqSum, but with the efficiency term included.
for (i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
getChar << fSqEffSum_[i] << " ";
}
getChar << std::endl;
}
LauAbsResonance* LauIsobarDynamics::addResonance(const TString& resName, const Int_t resPairAmpInt, const LauAbsResonance::LauResonanceModel resType, const LauBlattWeisskopfFactor::BlattWeisskopfCategory bwCategory, const LauBlattWeisskopfFactor::BarrierType bwType)
{
// Function to add a resonance in a Dalitz plot.
// No check is made w.r.t flavour and charge conservation rules, and so
// the user is responsible for checking the internal consistency of
// their function statements with these laws. For example, the program
// will not prevent the user from asking for a rho resonance in a K-pi
// pair or a K* resonance in a pi-pi pair.
// However, to assist the user, a summary of the resonant structure requested
// by the user is printed before the program runs. It is important to check this
// information when you first define your Dalitz plot model before doing
// any fitting/generating.
// Arguments are: resonance name, integer to specify the resonance track pairing
// (1 => m_23, 2 => m_13, 3 => m_12), i.e. the bachelor track number.
// The third argument resType specifies whether the resonance is a Breit-Wigner (BW)
// Relativistic Breit-Wigner (RelBW) or Flatte distribution (Flatte), for example.
if( LauAbsResonance::isIncoherentModel(resType) == true ) {
std::cerr<<"ERROR in LauIsobarDynamics::addResonance : Resonance type \""<<resType<<"\" not allowed for a coherent resonance"<<std::endl;
return 0;
}
LauResonanceMaker& resonanceMaker = LauResonanceMaker::get();
LauAbsResonance *theResonance = resonanceMaker.getResonance(daughters_, resName, resPairAmpInt, resType, bwCategory, bwType);
if (theResonance == 0) {
std::cerr<<"ERROR in LauIsobarDynamics::addResonance : Couldn't create the resonance \""<<resName<<"\""<<std::endl;
return 0;
}
// implement the helicity flip here
if (flipHelicity_ && daughters_->getCharge(resPairAmpInt) == 0 && daughters_->getChargeParent() == 0 && daughters_->getTypeParent() > 0 ) {
if ( ( resPairAmpInt == 1 && TMath::Abs(daughters_->getTypeDaug2()) == TMath::Abs(daughters_->getTypeDaug3()) ) ||
( resPairAmpInt == 2 && TMath::Abs(daughters_->getTypeDaug1()) == TMath::Abs(daughters_->getTypeDaug3()) ) ||
( resPairAmpInt == 3 && TMath::Abs(daughters_->getTypeDaug1()) == TMath::Abs(daughters_->getTypeDaug2()) ) ) {
theResonance->flipHelicity(kTRUE);
}
}
// Set the resonance name and what track is the bachelor
TString resonanceName = theResonance->getResonanceName();
resTypAmp_.push_back(resonanceName);
// Always force the non-resonant amplitude pair to have resPairAmp = 0
// in case the user chooses the wrong number.
if ( resType == LauAbsResonance::FlatNR ||
resType == LauAbsResonance::NRModel ) {
std::cout<<"INFO in LauIsobarDynamics::addResonance : Setting resPairAmp to 0 for "<<resonanceName<<" contribution."<<std::endl;
resPairAmp_.push_back(0);
} else {
resPairAmp_.push_back(resPairAmpInt);
}
// Increment the number of resonance amplitudes we have so far
++nAmp_;
// Finally, add the resonance object to the internal array
sigResonances_.push_back(theResonance);
std::cout<<"INFO in LauIsobarDynamics::addResonance : Successfully added resonance. Total number of resonances so far = "<<nAmp_<<std::endl;
return theResonance;
}
LauAbsResonance* LauIsobarDynamics::addIncoherentResonance(const TString& resName, const Int_t resPairAmpInt, const LauAbsResonance::LauResonanceModel resType)
{
// Function to add an incoherent resonance in a Dalitz plot.
// No check is made w.r.t flavour and charge conservation rules, and so
// the user is responsible for checking the internal consistency of
// their function statements with these laws. For example, the program
// will not prevent the user from asking for a rho resonance in a K-pi
// pair or a K* resonance in a pi-pi pair.
// However, to assist the user, a summary of the resonant structure requested
// by the user is printed before the program runs. It is important to check this
// information when you first define your Dalitz plot model before doing
// any fitting/generating.
// Arguments are: resonance name, integer to specify the resonance track pairing
// (1 => m_23, 2 => m_13, 3 => m_12), i.e. the bachelor track number.
// The third argument resType specifies the shape of the resonance
// Gaussian (GaussIncoh), for example.
if( LauAbsResonance::isIncoherentModel(resType) == false ) {
std::cerr<<"ERROR in LauIsobarDynamics::addIncohResonance : Resonance type \""<<resType<<"\" not allowed for an incoherent resonance"<<std::endl;
return 0;
}
LauResonanceMaker& resonanceMaker = LauResonanceMaker::get();
LauAbsIncohRes *theResonance = dynamic_cast<LauAbsIncohRes*>( resonanceMaker.getResonance(daughters_, resName, resPairAmpInt, resType) );
if (theResonance == 0) {
std::cerr<<"ERROR in LauIsobarDynamics::addIncohResonance : Couldn't create the resonance \""<<resName<<"\""<<std::endl;
return 0;
}
// Set the resonance name and what track is the bachelor
TString resonanceName = theResonance->getResonanceName();
incohResTypAmp_.push_back(resonanceName);
incohResPairAmp_.push_back(resPairAmpInt);
// Increment the number of resonance amplitudes we have so far
++nIncohAmp_;
// Finally, add the resonance object to the internal array
sigIncohResonances_.push_back(theResonance);
std::cout<<"INFO in LauIsobarDynamics::addIncohResonance : Successfully added incoherent resonance. Total number of incoherent resonances so far = "<<nIncohAmp_<<std::endl;
return theResonance;
}
void LauIsobarDynamics::defineKMatrixPropagator(const TString& propName, const TString& paramFileName, Int_t resPairAmpInt,
Int_t nChannels, Int_t nPoles, Int_t rowIndex)
{
// Define the K-matrix propagator. The resPairAmpInt integer specifies which mass combination should be used
// for the invariant mass-squared variable "s". The pole masses and coupling constants are defined in the
// paramFileName parameter file.
// The number of channels and poles are defined by the nChannels and nPoles integers, respectively.
// The integer rowIndex specifies which row of the propagator should be used when
// summing over all amplitude channels: S-wave will be the first row, so rowIndex = 1.
// Check that the rowIndex is valid
if (rowIndex < 1 || rowIndex > nChannels) {
std::cerr << "ERROR in LauIsobarDynamics::defineKMatrixPropagator. The rowIndex, which is set to "
<< rowIndex << ", must be between 1 and the number of channels "
<< nChannels << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
TString propagatorName(propName), parameterFile(paramFileName);
LauKMatrixPropagator* thePropagator = LauKMatrixPropFactory::getInstance()->getPropagator(propagatorName, parameterFile,
resPairAmpInt, nChannels,
nPoles, rowIndex);
kMatrixPropagators_[propagatorName] = thePropagator;
}
void LauIsobarDynamics::addKMatrixProdPole(const TString& poleName, const TString& propName, Int_t poleIndex, Bool_t useProdAdler)
{
// Add a K-matrix production pole term, using the K-matrix propagator given by the propName.
// Here, poleIndex is the integer specifying the pole number.
// First, find the K-matrix propagator.
KMPropMap::iterator mapIter = kMatrixPropagators_.find(propName);
if (mapIter != kMatrixPropagators_.end()) {
LauKMatrixPropagator* thePropagator = mapIter->second;
// Make sure the pole index is valid
Int_t nPoles = thePropagator->getNPoles();
if (poleIndex < 1 || poleIndex > nPoles) {
std::cerr<<"ERROR in LauIsobarDynamics::addKMatrixProdPole : The pole index "<<poleIndex
<<" is not between 1 and "<<nPoles<<". Not adding production pole "<<poleName
<<" for K-matrix propagator "<<propName<<std::endl;
return;
}
// Now add the K-matrix production pole amplitude to the vector of LauAbsResonance pointers.
Int_t resPairAmpInt = thePropagator->getResPairAmpInt();
LauAbsResonance* prodPole = new LauKMatrixProdPole(poleName, poleIndex, resPairAmpInt,
thePropagator, daughters_, useProdAdler);
resTypAmp_.push_back(poleName);
resPairAmp_.push_back(resPairAmpInt);
++nAmp_;
sigResonances_.push_back(prodPole);
// Also store the propName-poleName pair for calculating total fit fractions later on
// (avoiding the need to use dynamic casts to check which resonances are of the K-matrix type)
kMatrixPropSet_[poleName] = propName;
std::cout<<"INFO in LauIsobarDynamics::addKMatrixProdPole : Successfully added K-matrix production pole term. Total number of resonances so far = "<<nAmp_<<std::endl;
} else {
std::cerr<<"ERROR in LauIsobarDynamics::addKMatrixProdPole : The propagator of the name "<<propName
<<" could not be found for the production pole "<<poleName<<std::endl;
}
}
void LauIsobarDynamics::addKMatrixProdSVP(const TString& SVPName, const TString& propName, Int_t channelIndex, Bool_t useProdAdler)
{
// Add a K-matrix production "slowly-varying part" (SVP) term, using the K-matrix propagator
// given by the propName. Here, channelIndex is the integer specifying the channel number.
// First, find the K-matrix propagator.
KMPropMap::iterator mapIter = kMatrixPropagators_.find(propName);
if (mapIter != kMatrixPropagators_.end()) {
LauKMatrixPropagator* thePropagator = mapIter->second;
// Make sure the channel index is valid
Int_t nChannels = thePropagator->getNChannels();
if (channelIndex < 1 || channelIndex > nChannels) {
std::cerr<<"ERROR in LauIsobarDynamics::addKMatrixProdSVP : The channel index "<<channelIndex
<<" is not between 1 and "<<nChannels<<". Not adding production slowly-varying part "<<SVPName
<<" for K-matrix propagator "<<propName<<std::endl;
return;
}
// Now add the K-matrix production SVP amplitude to the vector of LauAbsResonance pointers.
Int_t resPairAmpInt = thePropagator->getResPairAmpInt();
LauAbsResonance* prodSVP = new LauKMatrixProdSVP(SVPName, channelIndex, resPairAmpInt,
thePropagator, daughters_, useProdAdler);
resTypAmp_.push_back(SVPName);
resPairAmp_.push_back(resPairAmpInt);
++nAmp_;
sigResonances_.push_back(prodSVP);
// Also store the SVPName-propName pair for calculating total fit fractions later on
// (avoiding the need to use dynamic casts to check which resonances are of the K-matrix type)
kMatrixPropSet_[SVPName] = propName;
std::cout<<"INFO in LauIsobarDynamics::addKMatrixProdSVP : Successfully added K-matrix production slowly-varying (SVP) term. Total number of resonances so far = "<<nAmp_<<std::endl;
} else {
std::cerr<<"ERROR in LauIsobarDynamics::addKMatrixProdSVP : The propagator of the name "<<propName
<<" could not be found for the production slowly-varying part "<<SVPName<<std::endl;
}
}
Int_t LauIsobarDynamics::resonanceIndex(const TString& resName) const
{
Int_t index(0);
const LauAbsResonance* theResonance(0);
for (std::vector<LauAbsResonance*>::const_iterator iter=sigResonances_.begin(); iter!=sigResonances_.end(); ++iter) {
theResonance = (*iter);
if (theResonance != 0) {
const TString& resString = theResonance->getResonanceName();
if (resString == resName) {
return index;
}
}
++index;
}
for (std::vector<LauAbsIncohRes*>::const_iterator iter=sigIncohResonances_.begin(); iter!=sigIncohResonances_.end(); ++iter) {
theResonance = (*iter);
if (theResonance != 0) {
const TString& resString = theResonance->getResonanceName();
if (resString == resName) {
return index;
}
}
++index;
}
return -1;
}
Bool_t LauIsobarDynamics::hasResonance(const TString& resName) const
{
const Int_t index = this->resonanceIndex(resName);
if (index < 0) {
return kFALSE;
} else {
return kTRUE;
}
}
const LauAbsResonance* LauIsobarDynamics::getResonance(const UInt_t resIndex) const
{
if ( resIndex < this->getnCohAmp() ) {
return sigResonances_[resIndex];
} else if ( resIndex < this->getnTotAmp() ) {
return sigIncohResonances_[ resIndex - nAmp_ ];
} else {
std::cerr<<"ERROR in LauIsobarDynamics::getResonance : Couldn't find resonance with index \""<<resIndex<<"\" in the model."<<std::endl;
return 0;
}
}
LauAbsResonance* LauIsobarDynamics::getResonance(const UInt_t resIndex)
{
if ( resIndex < this->getnCohAmp() ) {
return sigResonances_[resIndex];
} else if ( resIndex < this->getnTotAmp() ) {
return sigIncohResonances_[ resIndex - nAmp_ ];
} else {
std::cerr<<"ERROR in LauIsobarDynamics::getResonance : Couldn't find resonance with index \""<<resIndex<<"\" in the model."<<std::endl;
return 0;
}
}
LauAbsResonance* LauIsobarDynamics::findResonance(const TString& resName)
{
const Int_t index = this->resonanceIndex( resName );
if ( index < 0 ) {
std::cerr<<"ERROR in LauIsobarDynamics::findResonance : Couldn't find resonance with name \""<<resName<<"\" in the model."<<std::endl;
return 0;
} else {
return this->getResonance( index );
}
}
const LauAbsResonance* LauIsobarDynamics::findResonance(const TString& resName) const
{
const Int_t index = this->resonanceIndex( resName );
if ( index < 0 ) {
std::cerr<<"ERROR in LauIsobarDynamics::findResonance : Couldn't find resonance with name \""<<resName<<"\" in the model."<<std::endl;
return 0;
} else {
return this->getResonance( index );
}
}
void LauIsobarDynamics::removeCharge(TString& string) const
{
Ssiz_t index = string.Index("+");
if (index != -1) {
string.Remove(index,1);
}
index = string.Index("-");
if (index != -1) {
string.Remove(index,1);
}
}
void LauIsobarDynamics::calcDPNormalisation()
{
if (!normalizationSchemeDone_) {
this->calcDPNormalisationScheme();
}
for (std::vector<LauDPPartialIntegralInfo*>::iterator it = dpPartialIntegralInfo_.begin(); it != dpPartialIntegralInfo_.end(); ++it)
{
this->calcDPPartialIntegral( *it );
}
for (UInt_t i = 0; i < nAmp_+nIncohAmp_; ++i) {
fNorm_[i] = 0.0;
if (fSqSum_[i] > 0.0) {fNorm_[i] = TMath::Sqrt(1.0/(fSqSum_[i]));}
}
}
-
-std::vector<std::pair<Double_t, Double_t> > LauIsobarDynamics::formGapsFromRegions(const std::vector<std::pair<Double_t, Double_t> > & regions, Double_t min, Double_t max)
+std::vector< std::pair<Double_t, Double_t> > LauIsobarDynamics::formGapsFromRegions( const std::vector< std::pair<Double_t, Double_t> >& regions, const Double_t min, const Double_t max ) const
{
-
- std::vector<std::pair<Double_t, Double_t> > gaps(regions.size() + 1, std::make_pair(0., 0.));
+ std::vector< std::pair<Double_t, Double_t> > gaps(regions.size() + 1, std::make_pair(0., 0.));
// Given some narrow resonance regions, find the regions that correspond to the gaps between them
gaps[0].first = min;
- gaps[gaps.size() - 1].second = max;
- for (Int_t i = Int_t(regions.size() - 1); i >= 0; i--) {
- gaps[i + 1].first = regions[i].second;
+ for (UInt_t i = 0; i < regions.size(); ++i) {
gaps[i].second = regions[i].first;
+ gaps[i + 1].first = regions[i].second;
}
- return gaps;
+ gaps[gaps.size() - 1].second = max;
+ return gaps;
}
-void LauIsobarDynamics::cullNullRegions(std::vector<LauDPPartialIntegralInfo *> & regions)
+void LauIsobarDynamics::cullNullRegions( std::vector<LauDPPartialIntegralInfo*>& regions ) const
{
- LauDPPartialIntegralInfo * tmp(0);
- regions.erase(std::remove(regions.begin(), regions.end(), tmp), regions.end());
+ LauDPPartialIntegralInfo* tmp(0);
+ regions.erase( std::remove(regions.begin(), regions.end(), tmp), regions.end() );
}
-void LauIsobarDynamics::correctDPOverlap(std::vector<std::pair<Double_t, Double_t> > & regions, const std::vector<Double_t> & binnings)
+void LauIsobarDynamics::correctDPOverlap( std::vector< std::pair<Double_t, Double_t> >& regions, const std::vector<Double_t>& binnings ) const
{
- if (regions.empty()) return;
+ if (regions.empty()) {
+ return;
+ }
- // If the regions overlap, ensure that the one with the finest binning takes precedence (i.e., extends its full width)
+ // If the regions overlap, ensure that the one with the finest binning takes precedence (i.e., extends its full width)
- for (UInt_t i = 0; i < regions.size() - 1; i++) {
- if ( regions[i + 1].first <= regions[i].second ) {
- if ((binnings[i] < binnings[i + 1])) {
- regions[i + 1] = std::make_pair(regions[i].second, regions[i + 1].second);
- } else {
- regions[i] = std::make_pair(regions[i].first, regions[i + 1].first);
- }
- }
- }
+ for (UInt_t i = 0; i < regions.size() - 1; ++i) {
+ if ( regions[i + 1].first <= regions[i].second ) {
+ if ((binnings[i] < binnings[i + 1])) {
+ regions[i + 1] = std::make_pair(regions[i].second, regions[i + 1].second);
+ } else {
+ regions[i] = std::make_pair(regions[i].first, regions[i + 1].first);
+ }
+ }
+ }
}
-std::vector<LauDPPartialIntegralInfo *> LauIsobarDynamics::m13IntegrationRegions(const std::vector<std::pair<Double_t, Double_t> > & m13Regions,
- const std::vector<std::pair<Double_t, Double_t> > & m23Regions,
- const std::vector<Double_t> & m13Binnings,
- const Double_t precision,
- const Double_t defaultBinning)
+std::vector<LauDPPartialIntegralInfo*> LauIsobarDynamics::m13IntegrationRegions( const std::vector< std::pair<Double_t,Double_t> >& m13Regions,
+ const std::vector< std::pair<Double_t,Double_t> >& m23Regions,
+ const std::vector<Double_t>& m13Binnings,
+ const Double_t precision,
+ const Double_t defaultBinning ) const
{
+ // Create integration regions for all narrow resonances in m13 except for the overlaps with narrow resonances in m23
+ std::vector<LauDPPartialIntegralInfo*> integrationRegions;
- Double_t m23Min = kinematics_->getm23Min();
- Double_t m23Max = kinematics_->getm23Max();
-
- std::vector<LauDPPartialIntegralInfo *> integrationRegions;
-
- // For narrow resonances in m13
-
- for (UInt_t m13i = 0; m13i < m13Regions.size(); m13i++) {
+ const Double_t m23Min = kinematics_->getm23Min();
+ const Double_t m23Max = kinematics_->getm23Max();
- Double_t m13Binning = m13Binnings[m13i];
+ // Loop over narrow resonances in m13
+ for (UInt_t m13i = 0; m13i < m13Regions.size(); ++m13i) {
- Double_t resMin13 = m13Regions[m13i].first;
- Double_t resMax13 = m13Regions[m13i].second;
+ const Double_t m13Binning = m13Binnings[m13i];
- // Initialise to the full height of the DP in case there are no narrow resonances in m23
- Double_t lastResMax23 = m23Min;
-
- for (UInt_t m23i = 0; m23i < m23Regions.size(); m23i++){
-
- Double_t resMin23 = m23Regions[m23i].first;
- Double_t resMax23 = m23Regions[m23i].second;
-
- if (m23i == 0) {
-
- integrationRegions.push_back(newDPIntegrationRegion(resMin13, resMax13, m23Min, resMin23, m13Binning, defaultBinning, precision, nAmp_, nIncohAmp_));
-
- }
+ const Double_t resMin13 = m13Regions[m13i].first;
+ const Double_t resMax13 = m13Regions[m13i].second;
- if (m23i != m23Regions.size() - 1) {
+ // Initialise to the full height of the DP in case there are no narrow resonances in m23
+ Double_t lastResMax23 = m23Min;
- Double_t nextResMin23 = m23Regions[m23i + 1].first;
+ // Loop over narrow resonances in m23
+ for (UInt_t m23i = 0; m23i < m23Regions.size(); m23i++) {
- integrationRegions.push_back(newDPIntegrationRegion(resMin13, resMax13, resMax23, nextResMin23, m13Binning, defaultBinning, precision, nAmp_, nIncohAmp_));
+ const Double_t resMin23 = m23Regions[m23i].first;
+ const Double_t resMax23 = m23Regions[m23i].second;
- } else {
-
- lastResMax23 = resMax23;
-
- }
-
- }
-
- integrationRegions.push_back(newDPIntegrationRegion(resMin13, resMax13, lastResMax23, m23Max, m13Binning, defaultBinning, precision, nAmp_, nIncohAmp_));
+ // For the first entry, add the area between m23 threshold and this first entry
+ if (m23i == 0) {
+ integrationRegions.push_back(this->newDPIntegrationRegion(resMin13, resMax13, m23Min, resMin23, m13Binning, defaultBinning, precision, nAmp_, nIncohAmp_));
+ }
- }
+ // For all entries except the last one, add the area between this and the next entry
+ if (m23i != (m23Regions.size() - 1)) {
+ const Double_t nextResMin23 = m23Regions[m23i + 1].first;
+ integrationRegions.push_back(this->newDPIntegrationRegion(resMin13, resMax13, resMax23, nextResMin23, m13Binning, defaultBinning, precision, nAmp_, nIncohAmp_));
+ } else {
+ lastResMax23 = resMax23;
+ }
+ }
- return integrationRegions;
+ // Add the area between the last entry and the maximum m23 (which could be the whole strip if there are no entries in m23Regions)
+ integrationRegions.push_back(this->newDPIntegrationRegion(resMin13, resMax13, lastResMax23, m23Max, m13Binning, defaultBinning, precision, nAmp_, nIncohAmp_));
+ }
+ return integrationRegions;
}
-std::vector<LauDPPartialIntegralInfo *> LauIsobarDynamics::m23IntegrationRegions(const std::vector<std::pair<Double_t, Double_t> > & m13Regions,
- const std::vector<std::pair<Double_t, Double_t> > & m23Regions,
- const std::vector<Double_t> & m13Binnings,
- const std::vector<Double_t> & m23Binnings,
- const Double_t precision,
- const Double_t defaultBinning)
+std::vector<LauDPPartialIntegralInfo*> LauIsobarDynamics::m23IntegrationRegions( const std::vector<std::pair<Double_t,Double_t> >& m13Regions,
+ const std::vector<std::pair<Double_t,Double_t> >& m23Regions,
+ const std::vector<Double_t>& m13Binnings,
+ const std::vector<Double_t>& m23Binnings,
+ const Double_t precision,
+ const Double_t defaultBinning ) const
{
+ // Create integration regions for all narrow resonances in m23 (including the overlap regions with m13 narrow resonances)
+ std::vector<LauDPPartialIntegralInfo *> integrationRegions;
- Double_t m13Min = kinematics_->getm13Min();
- Double_t m13Max = kinematics_->getm13Max();
- std::vector<LauDPPartialIntegralInfo *> integrationRegions;
-
- // For narrow resonances in m23
+ const Double_t m13Min = kinematics_->getm13Min();
+ const Double_t m13Max = kinematics_->getm13Max();
- for (UInt_t m23i = 0; m23i < m23Regions.size(); m23i++) {
+ // Loop over narrow resonances in m23
+ for (UInt_t m23i = 0; m23i < m23Regions.size(); m23i++) {
- Double_t m23Binning = m23Binnings[m23i];
+ const Double_t m23Binning = m23Binnings[m23i];
- Double_t resMin23 = m23Regions[m23i].first;
- Double_t resMax23 = m23Regions[m23i].second;
+ const Double_t resMin23 = m23Regions[m23i].first;
+ const Double_t resMax23 = m23Regions[m23i].second;
- // Initialise to the full width of the DP in case there are no narrow resonances in m13
- Double_t lastResMax13 = m13Min;
+ // Initialise to the full width of the DP in case there are no narrow resonances in m13
+ Double_t lastResMax13 = m13Min;
- for (UInt_t m13i = 0; m13i < m13Regions.size(); m13i++){
+ // Loop over narrow resonances in m13
+ for (UInt_t m13i = 0; m13i < m13Regions.size(); m13i++){
- Double_t m13Binning = m13Binnings[m23i];
+ const Double_t m13Binning = m13Binnings[m23i];
- Double_t resMin13 = m13Regions[m13i].first;
- Double_t resMax13 = m13Regions[m13i].second;
-
- // Overlap region (only needed in m23)
- integrationRegions.push_back(newDPIntegrationRegion(resMin13, resMax13, resMin23, resMax23, m13Binning, m23Binning, precision, nAmp_, nIncohAmp_));
-
- if (m13i == 0) {
-
- integrationRegions.push_back(newDPIntegrationRegion(m13Min, resMin13, resMin23, resMax23, defaultBinning, m23Binning, precision, nAmp_, nIncohAmp_));
-
- }
-
- if (m13i != m13Regions.size() - 1) {
-
- Double_t nextResMin13 = m23Regions[m13i + 1].first;
-
- integrationRegions.push_back(newDPIntegrationRegion(resMax13, nextResMin13, resMin23, resMax23, defaultBinning, m23Binning, precision, nAmp_, nIncohAmp_));
-
- } else {
-
- lastResMax13 = resMax13;
-
- }
+ const Double_t resMin13 = m13Regions[m13i].first;
+ const Double_t resMax13 = m13Regions[m13i].second;
- }
+ // Overlap region (only needed in m23)
+ integrationRegions.push_back(this->newDPIntegrationRegion(resMin13, resMax13, resMin23, resMax23, m13Binning, m23Binning, precision, nAmp_, nIncohAmp_));
- integrationRegions.push_back(newDPIntegrationRegion(lastResMax13, m13Max, resMin23, resMax23, defaultBinning, m23Binning, precision, nAmp_, nIncohAmp_));
+ // For the first entry, add the area between m13 threshold and this first entry
+ if (m13i == 0) {
+ integrationRegions.push_back(this->newDPIntegrationRegion(m13Min, resMin13, resMin23, resMax23, defaultBinning, m23Binning, precision, nAmp_, nIncohAmp_));
+ }
- }
+ // For all entries except the last one, add the area between this and the next entry
+ if (m13i != m13Regions.size() - 1) {
+ const Double_t nextResMin13 = m23Regions[m13i + 1].first;
+ integrationRegions.push_back(this->newDPIntegrationRegion(resMax13, nextResMin13, resMin23, resMax23, defaultBinning, m23Binning, precision, nAmp_, nIncohAmp_));
+ } else {
+ lastResMax13 = resMax13;
+ }
+ }
- return integrationRegions;
+ // Add the area between the last entry and the maximum m13 (which could be the whole strip if there are no entries in m13Regions)
+ integrationRegions.push_back(this->newDPIntegrationRegion(lastResMax13, m13Max, resMin23, resMax23, defaultBinning, m23Binning, precision, nAmp_, nIncohAmp_));
+ }
+ return integrationRegions;
}
-LauDPPartialIntegralInfo * LauIsobarDynamics::newDPIntegrationRegion(const Double_t minm13, const Double_t maxm13,
+LauDPPartialIntegralInfo* LauIsobarDynamics::newDPIntegrationRegion( const Double_t minm13, const Double_t maxm13,
const Double_t minm23, const Double_t maxm23,
const Double_t m13BinWidth, const Double_t m23BinWidth,
const Double_t precision,
const UInt_t nAmp,
- const UInt_t nIncohAmp)
+ const UInt_t nIncohAmp ) const
{
- UInt_t nm13Points = static_cast<UInt_t>((maxm13-minm13)/m13BinWidth);
- UInt_t nm23Points = static_cast<UInt_t>((maxm23-minm23)/m23BinWidth);
+ const UInt_t nm13Points = static_cast<UInt_t>((maxm13-minm13)/m13BinWidth);
+ const UInt_t nm23Points = static_cast<UInt_t>((maxm23-minm23)/m23BinWidth);
- // If we would create a region with no interior points, just return NULL
-
- if (nm13Points == 0 || nm23Points == 0) return NULL;
- return new LauDPPartialIntegralInfo(minm13, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp, nIncohAmp);
+ // If we would create a region with no interior points, just return a null pointer
+ if (nm13Points == 0 || nm23Points == 0) {
+ return 0;
+ }
+ return new LauDPPartialIntegralInfo(minm13, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth, precision, nAmp, nIncohAmp);
}
void LauIsobarDynamics::calcDPNormalisationScheme()
{
if ( ! dpPartialIntegralInfo_.empty() ) {
std::cerr << "ERROR in LauIsobarDynamics::calcDPNormalisationScheme : Scheme already stored!" << std::endl;
return;
}
// The precision for the Gauss-Legendre weights
const Double_t precision(1e-6);
// Get the rectangle that encloses the DP
- Double_t minm13 = kinematics_->getm13Min();
- Double_t maxm13 = kinematics_->getm13Max();
- Double_t minm23 = kinematics_->getm23Min();
- Double_t maxm23 = kinematics_->getm23Max();
- Double_t minm12 = kinematics_->getm12Min();
- Double_t maxm12 = kinematics_->getm12Max();
+ const Double_t minm13 = kinematics_->getm13Min();
+ const Double_t maxm13 = kinematics_->getm13Max();
+ const Double_t minm23 = kinematics_->getm23Min();
+ const Double_t maxm23 = kinematics_->getm23Max();
+ const Double_t minm12 = kinematics_->getm12Min();
+ const Double_t maxm12 = kinematics_->getm12Max();
// Find out whether we have narrow resonances in the DP (defined here as width < 20 MeV).
- std::vector<std::pair<Double_t,Double_t> > m13NarrowRes;
- std::vector<std::pair<Double_t,Double_t> > m23NarrowRes;
- std::vector<std::pair<Double_t,Double_t> > m12NarrowRes;
+ std::vector< std::pair<Double_t,Double_t> > m13NarrowRes;
+ std::vector< std::pair<Double_t,Double_t> > m23NarrowRes;
+ std::vector< std::pair<Double_t,Double_t> > m12NarrowRes;
// Rho-omega mixing models implicitly contains omega(782) model, but width is of rho(770) - handle as a special case
- Double_t omegaMass = 0.783;
- Double_t omegaWidth = 0.00849;
+ LauResonanceMaker& resonanceMaker = LauResonanceMaker::get();
+ LauResonanceInfo* omega_info = resonanceMaker.getResInfo("omega(782)");
+ const Double_t omegaMass = (omega_info!=0) ? omega_info->getMass()->unblindValue() : 0.78265;
+ const Double_t omegaWidth = (omega_info!=0) ? omega_info->getWidth()->unblindValue() : 0.00849;
for ( std::vector<LauAbsResonance*>::const_iterator iter = sigResonances_.begin(); iter != sigResonances_.end(); ++iter ) {
- Bool_t isRhomega = kFALSE;
-
- if ( (*iter)->getResonanceModel() == LauAbsResonance::RhoOmegaMix_GS ||
- (*iter)->getResonanceModel() == LauAbsResonance::RhoOmegaMix_GS_1 ||
- (*iter)->getResonanceModel() == LauAbsResonance::RhoOmegaMix_RBW ||
- (*iter)->getResonanceModel() == LauAbsResonance::RhoOmegaMix_RBW_1 ) {
- isRhomega = kTRUE;
- }
-
- Double_t width = (*iter)->getWidth();
-
- if ( (width > narrowWidth_ || width == 0.0) && !isRhomega) { continue; }
+ LauAbsResonance::LauResonanceModel model = (*iter)->getResonanceModel();
+ const TString& name = (*iter)->getResonanceName();
+ Int_t pair = (*iter)->getPairInt();
+ Double_t mass = (*iter)->getMass();
+ Double_t width = (*iter)->getWidth();
- Double_t mass = (*iter)->getMass();
- Int_t pair = (*iter)->getPairInt();
+ if ( model == LauAbsResonance::RhoOmegaMix_GS ||
+ model == LauAbsResonance::RhoOmegaMix_GS_1 ||
+ model == LauAbsResonance::RhoOmegaMix_RBW ||
+ model == LauAbsResonance::RhoOmegaMix_RBW_1 ) {
+ mass = omegaMass;
+ width = omegaWidth;
+ }
- TString name = (*iter)->getResonanceName();
+ if ( width > narrowWidth_ || width == 0.0 ) {
+ continue;
+ }
- std::cout << "INFO in LauIsobarDynamics::calcDPNormalisationScheme : Found narrow resonance: " << name << ", mass = " << mass << ", width = " << width << ", pair int = " << pair << std::endl;
- if ( pair == 1 ) {
- if ( mass < minm23 || mass > maxm23 ){ continue; }
- if ( !isRhomega ) m23NarrowRes.push_back( std::make_pair(width,mass) );
- else { m23NarrowRes.push_back( std::make_pair(omegaWidth, omegaMass) );}
+ std::cout << "INFO in LauIsobarDynamics::calcDPNormalisationScheme : Found narrow resonance: " << name << ", mass = " << mass << ", width = " << width << ", pair int = " << pair << std::endl;
+ if ( pair == 1 ) {
+ if ( mass < minm23 || mass > maxm23 ){
+ std::cout << std::string(53, ' ') << ": But its pole is outside the kinematically allowed range, so will not consider it narrow for the purposes of integration" << std::endl;
+ } else {
+ m23NarrowRes.push_back( std::make_pair(mass,width) );
+ }
} else if ( pair == 2 ) {
- if ( mass < minm13 || mass > maxm13 ){ continue; }
- if ( !isRhomega ) m13NarrowRes.push_back( std::make_pair(width,mass) );
- else { m13NarrowRes.push_back( std::make_pair(omegaWidth, omegaMass) );}
+ if ( mass < minm13 || mass > maxm13 ){
+ std::cout << std::string(53, ' ') << ": But its pole is outside the kinematically allowed range, so will not consider it narrow for the purposes of integration" << std::endl;
+ } else {
+ m13NarrowRes.push_back( std::make_pair(mass,width) );
+ }
} else if ( pair == 3 ) {
- if ( mass < minm12 || mass > maxm12 ){ continue; }
- if ( !isRhomega ) m12NarrowRes.push_back( std::make_pair(width,mass) );
- else { m12NarrowRes.push_back( std::make_pair(omegaWidth, omegaMass) );}
+ if ( mass < minm12 || mass > maxm12 ){
+ std::cout << std::string(53, ' ') << ": But its pole is outside the kinematically allowed range, so will not consider it narrow for the purposes of integration" << std::endl;
+ } else {
+ m12NarrowRes.push_back( std::make_pair(mass,width) );
+ }
} else {
std::cerr << "WARNING in LauIsobarDynamics::calcDPNormalisationScheme : strange pair integer, " << pair << ", for resonance \"" << (*iter)->getResonanceName() << std::endl;
}
}
for ( std::vector<LauAbsIncohRes*>::const_iterator iter = sigIncohResonances_.begin(); iter != sigIncohResonances_.end(); ++iter ) {
- Double_t width = (*iter)->getWidth();
- if ( width > narrowWidth_ || width == 0.0 ) { continue; }
-
- Double_t mass = (*iter)->getMass();
+ const TString& name = (*iter)->getResonanceName();
Int_t pair = (*iter)->getPairInt();
+ Double_t mass = (*iter)->getMass();
+ Double_t width = (*iter)->getWidth();
- TString name = (*iter)->getResonanceName();
+ if ( width > narrowWidth_ || width == 0.0 ) {
+ continue;
+ }
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : Found narrow resonance: " << name << ", mass = " << mass << ", width = " << width << ", pair int = " << pair << std::endl;
if ( pair == 1 ) {
if ( mass < minm23 || mass > maxm23 ){
std::cout << std::string(53, ' ') << ": But its pole is outside the kinematically allowed range, so will not consider it narrow for the purposes of integration" << std::endl;
} else {
- m23NarrowRes.push_back( std::make_pair(width,mass) );
+ m23NarrowRes.push_back( std::make_pair(mass,width) );
}
} else if ( pair == 2 ) {
if ( mass < minm13 || mass > maxm13 ){
std::cout << std::string(53, ' ') << ": But its pole is outside the kinematically allowed range, so will not consider it narrow for the purposes of integration" << std::endl;
} else {
- m13NarrowRes.push_back( std::make_pair(width,mass) );
+ m13NarrowRes.push_back( std::make_pair(mass,width) );
}
} else if ( pair == 3 ) {
if ( mass < minm12 || mass > maxm12 ){
std::cout << std::string(53, ' ') << ": But its pole is outside the kinematically allowed range, so will not consider it narrow for the purposes of integration" << std::endl;
} else {
- m12NarrowRes.push_back( std::make_pair(width,mass) );
+ m12NarrowRes.push_back( std::make_pair(mass,width) );
}
} else {
std::cerr << "WARNING in LauIsobarDynamics::calcDPNormalisationScheme : strange pair integer, " << pair << ", for resonance \"" << (*iter)->getResonanceName() << std::endl;
}
}
- if (m13NarrowRes.empty() && m23NarrowRes.empty()) {
-
- std::cout << "INFO in LauIsobarDynamics::calcDPNormalisationScheme : No narrow resonances found, integrating over whole Dalitz plot..." << std::endl;
- dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, maxm23, m13BinWidth_, m23BinWidth_, precision, nAmp_, nIncohAmp_));
+ // Depending on how many narrow resonances we have and where they are
+ // we adopt different approaches
+ if ( ! m12NarrowRes.empty() ) {
- } else {
+ // We have at least one narrow resonance in m12
+ // Switch to using the square DP for the integration
+ // TODO - for the time being just use a single, reasonably fine by default and tunable, grid
+ // - can later consider whether there's a need to split up the mPrime axis into regions around particularly narrow resonances in m12
+ // - but it seems that this isn't really needed since even the default tune gives a good resolution for most narrow resonances such as phi / chi_c0
+ std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisationScheme : One or more narrow resonances found in m12, integrating over whole square Dalitz plot with bin widths of "<<mPrimeBinWidth_<<" in mPrime and "<<thPrimeBinWidth_<<" in thetaPrime..."<<std::endl;
+ dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(0.0, 1.0, 0.0, 1.0, mPrimeBinWidth_, thPrimeBinWidth_, precision, nAmp_, nIncohAmp_, kTRUE, kinematics_));
- // Get regions in that correspond to narrow resonances in m13 and m23, and correct for overlaps in each dimension (to use the finest binning)
- // Sort resonances by ascending mass to calculate regions properly
+ } else if (m13NarrowRes.empty() && m23NarrowRes.empty()) {
- std::sort(m13NarrowRes.begin(), m13NarrowRes.end());
- std::sort(m23NarrowRes.begin(), m23NarrowRes.end());
+ // There are no narrow resonances, so we just do a single grid over the whole DP
+ std::cout << "INFO in LauIsobarDynamics::calcDPNormalisationScheme : No narrow resonances found, integrating over whole Dalitz plot..." << std::endl;
+ dpPartialIntegralInfo_.push_back(new LauDPPartialIntegralInfo(minm13, maxm13, minm23, maxm23, m13BinWidth_, m23BinWidth_, precision, nAmp_, nIncohAmp_));
- std::vector<std::pair<Double_t, Double_t> > m13Regions;
- std::vector<Double_t> m13Binnings;
+ } else {
- for ( std::vector<std::pair<Double_t, Double_t> >::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
- Double_t width = iter->first;
- Double_t mass = iter->second;
+ // Get regions in that correspond to narrow resonances in m13 and m23, and correct for overlaps in each dimension (to use the finest binning)
- Double_t regionBegin = mass - 5.0 * width;
- Double_t regionEnd = mass + 5.0 * width;
+ // Sort resonances by ascending mass to calculate regions properly
+ std::sort(m13NarrowRes.begin(), m13NarrowRes.end());
+ std::sort(m23NarrowRes.begin(), m23NarrowRes.end());
- m13Regions.push_back(std::make_pair(regionBegin, regionEnd));
- m13Binnings.push_back(width / binningFactor_);
- }
+ // For each narrow resonance in m13, determine the corresponding window and its binning
+ std::vector<std::pair<Double_t, Double_t> > m13Regions;
+ std::vector<Double_t> m13Binnings;
- std::vector<std::pair<Double_t, Double_t> > m23Regions;
- std::vector<Double_t> m23Binnings;
+ for ( std::vector<std::pair<Double_t, Double_t> >::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
+ Double_t mass = iter->first;
+ Double_t width = iter->second;
- for ( std::vector<std::pair<Double_t, Double_t> >::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
- Double_t width = iter->first;
- Double_t mass = iter->second;
+ Double_t regionBegin = mass - 5.0 * width;
+ Double_t regionEnd = mass + 5.0 * width;
+ Double_t binning = width / binningFactor_;
- Double_t regionBegin = mass - 5.0 * width;
- Double_t regionEnd = mass + 5.0 * width;
+ // check if we ought to extend the region to the edge of the phase space (in either direction)
+ if ( regionBegin < (minm13+50.0*m13BinWidth_) ) {
+ std::cout << "INFO in LauIsobarDynamics::calcDPNormalisationScheme : Resonance at m13 = " << mass << " is close to threshold, extending integration region" << std::endl;
+ regionBegin = minm13;
+ }
+ if ( regionEnd > (maxm13-50.0*m13BinWidth_) ) {
+ std::cout << "INFO in LauIsobarDynamics::calcDPNormalisationScheme : Resonance at m13 = " << mass << " is close to upper edge of phase space, extending integration region" << std::endl;
+ regionEnd = maxm13;
+ }
- m23Regions.push_back(std::make_pair(regionBegin, regionEnd));
- m23Binnings.push_back(width / binningFactor_);
- }
+ m13Regions.push_back(std::make_pair(regionBegin, regionEnd));
+ m13Binnings.push_back(binning);
+ }
- correctDPOverlap(m13Regions, m13Binnings);
- correctDPOverlap(m23Regions, m23Binnings);
+ // For each narrow resonance in m23, determine the corresponding window and its binning
+ std::vector<std::pair<Double_t, Double_t> > m23Regions;
+ std::vector<Double_t> m23Binnings;
- // Get the narrow resonance regions plus any overlap region
+ for ( std::vector<std::pair<Double_t, Double_t> >::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
+ Double_t mass = iter->first;
+ Double_t width = iter->second;
- std::vector<LauDPPartialIntegralInfo *> fineScheme13 = m13IntegrationRegions(m13Regions, m23Regions, m13Binnings, precision, m13BinWidth_);
- std::vector<LauDPPartialIntegralInfo *> fineScheme23 = m23IntegrationRegions(m13Regions, m23Regions, m13Binnings, m23Binnings, precision, m23BinWidth_);
+ Double_t regionBegin = mass - 5.0 * width;
+ Double_t regionEnd = mass + 5.0 * width;
+ Double_t binning = width / binningFactor_;
- // Get coarse regions by calculating the gaps between the narrow resonances and using the same functions to calculate the integrate scheme for each
+ // check if we ought to extend the region to the edge of the phase space (in either direction)
+ if ( regionBegin < (minm23+50.0*m23BinWidth_) ) {
+ std::cout << "INFO in LauIsobarDynamics::calcDPNormalisationScheme : Resonance at m23 = " << mass << " is close to threshold, extending integration region" << std::endl;
+ regionBegin = minm23;
+ }
+ if ( regionEnd > (maxm23-50.0*m23BinWidth_) ) {
+ std::cout << "INFO in LauIsobarDynamics::calcDPNormalisationScheme : Resonance at m23 = " << mass << " is close to upper edge of phase space, extending integration region" << std::endl;
+ regionEnd = maxm23;
+ }
- std::vector<std::pair<Double_t, Double_t> > coarseRegions = formGapsFromRegions(m13Regions, minm13, maxm13);
- std::vector<LauDPPartialIntegralInfo *> coarseScheme = m13IntegrationRegions(coarseRegions, m23Regions, std::vector<Double_t>(1 + fineScheme13.size(),m13BinWidth_), precision, m13BinWidth_);
+ m23Regions.push_back(std::make_pair(regionBegin, regionEnd));
+ m23Binnings.push_back(binning);
+ }
- dpPartialIntegralInfo_.insert(dpPartialIntegralInfo_.end(), fineScheme13.begin(), fineScheme13.end());
- dpPartialIntegralInfo_.insert(dpPartialIntegralInfo_.end(), fineScheme23.begin(), fineScheme23.end());
- dpPartialIntegralInfo_.insert(dpPartialIntegralInfo_.end(), coarseScheme.begin(), coarseScheme.end());
+ // Sort out overlaps between regions in the same mass pairing
+ this->correctDPOverlap(m13Regions, m13Binnings);
+ this->correctDPOverlap(m23Regions, m23Binnings);
- // Remove any possible NULL entries to the integral list that are produced when an integration region with no interior points is defined
+ // Get the narrow resonance regions plus any overlap region
+ std::vector<LauDPPartialIntegralInfo*> fineScheme13 = this->m13IntegrationRegions(m13Regions, m23Regions, m13Binnings, precision, m13BinWidth_);
+ std::vector<LauDPPartialIntegralInfo*> fineScheme23 = this->m23IntegrationRegions(m13Regions, m23Regions, m13Binnings, m23Binnings, precision, m23BinWidth_);
- cullNullRegions(dpPartialIntegralInfo_);
+ // Get coarse regions by calculating the gaps between the
+ // narrow resonances and using the same functions to create
+ // the integration grid object for each
+ std::vector< std::pair<Double_t,Double_t> > coarseRegions = this->formGapsFromRegions(m13Regions, minm13, maxm13);
+ std::vector<Double_t> coarseBinning( fineScheme13.size()+1, m13BinWidth_ );
+ std::vector<LauDPPartialIntegralInfo*> coarseScheme = this->m13IntegrationRegions(coarseRegions, m23Regions, coarseBinning, precision, m13BinWidth_);
- } // narrowRes
+ dpPartialIntegralInfo_.insert(dpPartialIntegralInfo_.end(), fineScheme13.begin(), fineScheme13.end());
+ dpPartialIntegralInfo_.insert(dpPartialIntegralInfo_.end(), fineScheme23.begin(), fineScheme23.end());
+ dpPartialIntegralInfo_.insert(dpPartialIntegralInfo_.end(), coarseScheme.begin(), coarseScheme.end());
- normalizationSchemeDone_ = kTRUE;
+ // Remove any null pointer entries in the integral list
+ // (that are produced when an integration region with no
+ // interior points is defined)
+ this->cullNullRegions(dpPartialIntegralInfo_);
+ }
+ normalizationSchemeDone_ = kTRUE;
}
void LauIsobarDynamics::setIntegralBinWidths(const Double_t m13BinWidth, const Double_t m23BinWidth,
const Double_t mPrimeBinWidth, const Double_t thPrimeBinWidth)
{
// Set the bin widths for the m13 vs m23 integration grid
m13BinWidth_ = m13BinWidth;
m23BinWidth_ = m23BinWidth;
// Set the bin widths for the m' vs theta' integration grid
mPrimeBinWidth_ = mPrimeBinWidth;
thPrimeBinWidth_ = thPrimeBinWidth;
}
void LauIsobarDynamics::calcDPPartialIntegral(LauDPPartialIntegralInfo* intInfo)
{
// Calculate the integrals for all parts of the amplitude in the given region of the DP
const Bool_t squareDP = intInfo->getSquareDP();
const UInt_t nm13Points = intInfo->getnm13Points();
const UInt_t nm23Points = intInfo->getnm23Points();
//Double_t dpArea(0.0);
for (UInt_t i = 0; i < nm13Points; ++i) {
const Double_t m13 = intInfo->getM13Value(i);
const Double_t m13Sq = m13*m13;
for (UInt_t j = 0; j < nm23Points; ++j) {
const Double_t m23 = intInfo->getM23Value(j);
const Double_t m23Sq = m23*m23;
const Double_t weight = intInfo->getWeight(i,j);
// Calculate the integral contributions for each resonance.
// Only points within the DP area contribute.
// This also calculates the total DP area as a check.
// NB if squareDP is true, m13 and m23 are actually mPrime and thetaPrime
Bool_t withinDP = squareDP ? kinematics_->withinSqDPLimits(m13, m23) : kinematics_->withinDPLimits(m13Sq, m23Sq);
if (withinDP == kTRUE) {
if ( squareDP ) {
// NB m13 and m23 are actually mPrime and thetaPrime
kinematics_->updateSqDPKinematics(m13, m23);
} else {
kinematics_->updateKinematics(m13Sq, m23Sq);
}
this->calculateAmplitudes(intInfo, i, j);
this->addGridPointToIntegrals(weight);
// Increment total DP area
//dpArea += weight;
}
} // j weights loop
} // i weights loop
// Print out DP area to check whether we have a sensible output
//std::cout<<" : dpArea = "<<dpArea<<std::endl;
}
void LauIsobarDynamics::calculateAmplitudes( LauDPPartialIntegralInfo* intInfo, const UInt_t m13Point, const UInt_t m23Point )
{
const std::set<UInt_t>::const_iterator intEnd = integralsToBeCalculated_.end();
for (UInt_t iAmp = 0; iAmp < nAmp_; ++iAmp) {
if ( integralsToBeCalculated_.find(iAmp) != intEnd ) {
// Calculate the dynamics for this resonance
ff_[iAmp] = this->resAmp(iAmp);
// Store the new value in the integration info object
intInfo->storeAmplitude( m13Point, m23Point, iAmp, ff_[iAmp] );
} else {
// Retrieve the cached value of the amplitude
ff_[iAmp] = intInfo->getAmplitude( m13Point, m23Point, iAmp );
}
}
for (UInt_t iAmp = 0; iAmp < nIncohAmp_; ++iAmp) {
if ( integralsToBeCalculated_.find(iAmp+nAmp_) != intEnd ) {
// Calculate the dynamics for this resonance
incohInten_[iAmp] = this->incohResAmp(iAmp);
// Store the new value in the integration info object
intInfo->storeIntensity( m13Point, m23Point, iAmp, incohInten_[iAmp] );
} else {
// Retrieve the cached value of the amplitude
incohInten_[iAmp] = intInfo->getIntensity( m13Point, m23Point, iAmp );
}
}
// If symmetric, do as above with flipped kinematics and add to amplitude
// (No need to retrive the cache if this was done in the first case)
if ( symmetricalDP_ == kTRUE ) {
kinematics_->flipAndUpdateKinematics();
for (UInt_t iAmp = 0; iAmp < nAmp_; ++iAmp) {
if ( (integralsToBeCalculated_.find(iAmp) != intEnd) && !sigResonances_[iAmp]->preSymmetrised() ) {
// Calculate the dynamics for this resonance
ff_[iAmp] += this->resAmp(iAmp);
// Store the new value in the integration info object
intInfo->storeAmplitude( m13Point, m23Point, iAmp, ff_[iAmp] );
}
}
for (UInt_t iAmp = 0; iAmp < nIncohAmp_; ++iAmp) {
if ( (integralsToBeCalculated_.find(iAmp+nAmp_) != intEnd) && !sigResonances_[iAmp]->preSymmetrised() ) {
// Calculate the dynamics for this resonance
incohInten_[iAmp] += this->incohResAmp(iAmp);
// Store the new value in the integration info object
intInfo->storeIntensity( m13Point, m23Point, iAmp, incohInten_[iAmp] );
}
}
kinematics_->flipAndUpdateKinematics();
}
// If we haven't cached the data, then we need to find out the efficiency.
eff_ = this->retrieveEfficiency();
intInfo->storeEfficiency( m13Point, m23Point, eff_ );
}
void LauIsobarDynamics::calculateAmplitudes()
{
std::set<UInt_t>::const_iterator iter = integralsToBeCalculated_.begin();
const std::set<UInt_t>::const_iterator intEnd = integralsToBeCalculated_.end();
for ( iter = integralsToBeCalculated_.begin(); iter != intEnd; ++iter) {
// Calculate the dynamics for this resonance
if(*iter < nAmp_) {
ff_[*iter] = this->resAmp(*iter);
} else {
incohInten_[*iter-nAmp_] = this->incohResAmp(*iter-nAmp_);
}
}
if ( symmetricalDP_ == kTRUE ) {
kinematics_->flipAndUpdateKinematics();
for ( iter = integralsToBeCalculated_.begin(); iter != intEnd; ++iter) {
// Calculate the dynamics for this resonance
if(*iter < nAmp_ && !sigResonances_[*iter]->preSymmetrised() ) {
ff_[*iter] += this->resAmp(*iter);
} else if (*iter >= nAmp_ && !sigResonances_[*iter-nAmp_]->preSymmetrised() ){
incohInten_[*iter-nAmp_] += this->incohResAmp(*iter-nAmp_);
}
}
kinematics_->flipAndUpdateKinematics();
}
// If we haven't cached the data, then we need to find out the efficiency.
eff_ = this->retrieveEfficiency();
}
void LauIsobarDynamics::calcTotalAmp(const Bool_t useEff)
{
// Reset the total amplitude to zero
totAmp_.zero();
// Loop over all signal amplitudes
LauComplex ATerm;
for (UInt_t i = 0; i < nAmp_; ++i) {
// Get the partial complex amplitude - (mag, phase)*(resonance dynamics)
ATerm = Amp_[i]*ff_[i];
// Scale this contribution by its relative normalisation w.r.t. the whole dynamics
ATerm.rescale(fNorm_[i]);
// Add this partial amplitude to the sum
totAmp_ += ATerm;
} // Loop over amplitudes
// |Sum of partial amplitudes|^2
ASq_ = totAmp_.abs2();
for (UInt_t i = 0; i < nIncohAmp_; ++i) {
// Get the partial complex amplitude - (mag, phase)
ATerm = Amp_[i+nAmp_];
// Scale this contribution by its relative normalisation w.r.t. the whole dynamics
ATerm.rescale(fNorm_[i+nAmp_]);
// Add this partial amplitude to the sum
ASq_ += ATerm.abs2()*incohInten_[i];
}
// Apply the efficiency correction for this event.
// Multiply the amplitude squared sum by the DP efficiency
if ( useEff ) {
ASq_ *= eff_;
}
}
void LauIsobarDynamics::addGridPointToIntegrals(const Double_t weight)
{
// Combine the Gauss-Legendre weight with the efficiency
const Double_t effWeight = eff_*weight;
LauComplex fifjEffSumTerm;
LauComplex fifjSumTerm;
// Calculates the half-matrix of amplitude-squared and interference
// terms (dynamical part only)
// Add the values at this point on the integration grid to the sums
// (one weighted only by the integration weights, one also weighted by
// the efficiency)
for (UInt_t i = 0; i < nAmp_; ++i) {
// Add the dynamical amplitude squared for this resonance.
Double_t fSqVal = ff_[i].abs2();
fSqSum_[i] += fSqVal*weight;
fSqEffSum_[i] += fSqVal*effWeight;
for (UInt_t j = i; j < nAmp_; ++j) {
fifjEffSumTerm = fifjSumTerm = ff_[i]*ff_[j].conj();
fifjEffSumTerm.rescale(effWeight);
fifjEffSum_[i][j] += fifjEffSumTerm;
fifjSumTerm.rescale(weight);
fifjSum_[i][j] += fifjSumTerm;
}
}
for (UInt_t i = 0; i < nIncohAmp_; ++i) {
// Add the dynamical amplitude squared for this resonance.
Double_t fSqVal = incohInten_[i];
fSqSum_[i+nAmp_] += fSqVal*weight;
fSqEffSum_[i+nAmp_] += fSqVal*effWeight;
}
}
LauComplex LauIsobarDynamics::resAmp(const UInt_t index)
{
// Routine to calculate the resonance dynamics (amplitude)
// using the appropriate Breit-Wigner/Form Factors.
LauComplex amp = LauComplex(0.0, 0.0);
if ( index >= nAmp_ ) {
std::cerr<<"ERROR in LauIsobarDynamics::resAmp : index = "<<index<<" is not within the range 0 to "<<nAmp_-1<<std::endl;
return amp;
}
// Get the signal resonance from the stored vector
LauAbsResonance* sigResonance = sigResonances_[index];
if (sigResonance == 0) {
std::cerr<<"ERROR in LauIsobarDynamics::resAmp : Couldn't retrieve valid resonance with index = "<<index<<std::endl;
return amp;
}
amp = sigResonance->amplitude(kinematics_);
// If we have a fully symmetric DP we need to calculate the amplitude at 6 points
if (fullySymmetricDP_ == kTRUE) {
// rotate and evaluate
kinematics_->rotateAndUpdateKinematics();
amp += sigResonance->amplitude(kinematics_);
// rotate and evaluate
kinematics_->rotateAndUpdateKinematics();
amp += sigResonance->amplitude(kinematics_);
// rotate, flip and evaluate
kinematics_->rotateAndUpdateKinematics();
kinematics_->flipAndUpdateKinematics();
amp += sigResonance->amplitude(kinematics_);
// rotate and evaluate
kinematics_->rotateAndUpdateKinematics();
amp += sigResonance->amplitude(kinematics_);
// rotate and evaluate
kinematics_->rotateAndUpdateKinematics();
amp += sigResonance->amplitude(kinematics_);
// rotate and flip to get us back to where we started
kinematics_->rotateAndUpdateKinematics();
kinematics_->flipAndUpdateKinematics();
}
return amp;
}
Double_t LauIsobarDynamics::incohResAmp(const UInt_t index)
{
// Routine to calculate the resonance dynamics (amplitude)
// using the appropriate Breit-Wigner/Form Factors.
Double_t intensity = 0.;
if ( index >= nIncohAmp_ ) {
std::cerr<<"ERROR in LauIsobarDynamics::incohResAmp : index = "<<index<<" is not within the range 0 to "<<nIncohAmp_-1<<std::endl;
return intensity;
}
// Get the signal resonance from the stored vector
LauAbsIncohRes* sigResonance = sigIncohResonances_[index];
if (sigResonance == 0) {
std::cerr<<"ERROR in LauIsobarDynamics::incohResAmp : Couldn't retrieve valid incoherent resonance with index = "<<index<<std::endl;
return intensity;
}
LauComplex ff = sigResonance->amplitude(kinematics_);
intensity = sigResonance->intensityFactor(kinematics_)*ff.abs2();
// If we have a fully symmetric DP we need to calculate the amplitude at 6 points
if (fullySymmetricDP_ == kTRUE) {
// rotate and evaluate
kinematics_->rotateAndUpdateKinematics();
ff = sigResonance->amplitude(kinematics_);
intensity += sigResonance->intensityFactor(kinematics_)*ff.abs2();
// rotate and evaluate
kinematics_->rotateAndUpdateKinematics();
ff = sigResonance->amplitude(kinematics_);
intensity += sigResonance->intensityFactor(kinematics_)*ff.abs2();
// rotate, flip and evaluate
kinematics_->rotateAndUpdateKinematics();
kinematics_->flipAndUpdateKinematics();
ff = sigResonance->amplitude(kinematics_);
intensity += sigResonance->intensityFactor(kinematics_)*ff.abs2();
// rotate and evaluate
kinematics_->rotateAndUpdateKinematics();
ff = sigResonance->amplitude(kinematics_);
intensity += sigResonance->intensityFactor(kinematics_)*ff.abs2();
// rotate and evaluate
kinematics_->rotateAndUpdateKinematics();
ff = sigResonance->amplitude(kinematics_);
intensity += sigResonance->intensityFactor(kinematics_)*ff.abs2();
// rotate and flip to get us back to where we started
kinematics_->rotateAndUpdateKinematics();
kinematics_->flipAndUpdateKinematics();
}
return intensity;
}
void LauIsobarDynamics::setFFTerm(const UInt_t index, const Double_t realPart, const Double_t imagPart)
{
// Function to set the internal ff term (normally calculated using resAmp(index).
if ( index >= nAmp_ ) {
std::cerr<<"ERROR in LauIsobarDynamics::setFFTerm : index = "<<index<<" is not within the range 0 to "<<nAmp_-1<<std::endl;
return;
}
ff_[index].setRealImagPart( realPart, imagPart );
}
void LauIsobarDynamics::setIncohIntenTerm(const UInt_t index, const Double_t value)
{
// Function to set the internal incoherent intensity term (normally calculated using incohResAmp(index).
if ( index >= nIncohAmp_ ) {
std::cerr<<"ERROR in LauIsobarDynamics::setFFTerm : index = "<<index<<" is not within the range 0 to "<<nIncohAmp_-1<<std::endl;
return;
}
incohInten_[index] = value;
}
void LauIsobarDynamics::calcExtraInfo(const Bool_t init)
{
// This method calculates the fit fractions, mean efficiency and total DP rate
Double_t fifjEffTot(0.0), fifjTot(0.0);
UInt_t i, j;
for (i = 0; i < nAmp_; i++) {
// Calculate the diagonal terms
TString name = "A"; name += i; name += "Sq_FitFrac";
fitFrac_[i][i].name(name);
name += "EffUnCorr";
fitFracEffUnCorr_[i][i].name(name);
Double_t fifjSumReal = fifjSum_[i][i].re();
Double_t sumTerm = Amp_[i].abs2()*fifjSumReal*fNorm_[i]*fNorm_[i];
fifjTot += sumTerm;
Double_t fifjEffSumReal = fifjEffSum_[i][i].re();
Double_t sumEffTerm = Amp_[i].abs2()*fifjEffSumReal*fNorm_[i]*fNorm_[i];
fifjEffTot += sumEffTerm;
fitFrac_[i][i].value(sumTerm);
fitFracEffUnCorr_[i][i].value(sumEffTerm);
}
for (i = 0; i < nAmp_; i++) {
for (j = i+1; j < nAmp_+nIncohAmp_; j++) {
// Calculate the cross-terms
TString name = "A"; name += i; name += "A"; name += j; name += "_FitFrac";
fitFrac_[i][j].name(name);
name += "EffUnCorr";
fitFracEffUnCorr_[i][j].name(name);
if(j >= nAmp_) {
//Set off-diagonal incoherent terms to zero
fitFrac_[i][j].value(0.);
fitFracEffUnCorr_[i][j].value(0.);
continue;
}
LauComplex AmpjConj = Amp_[j].conj();
LauComplex AmpTerm = Amp_[i]*AmpjConj;
Double_t crossTerm = 2.0*(AmpTerm*fifjSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
fifjTot += crossTerm;
Double_t crossEffTerm = 2.0*(AmpTerm*fifjEffSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
fifjEffTot += crossEffTerm;
fitFrac_[i][j].value(crossTerm);
fitFracEffUnCorr_[i][j].value(crossEffTerm);
}
}
for (i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
// Calculate the incoherent terms
TString name = "A"; name += i; name += "Sq_FitFrac";
fitFrac_[i][i].name(name);
name += "EffUnCorr";
fitFracEffUnCorr_[i][i].name(name);
Double_t sumTerm = Amp_[i].abs2()*fSqSum_[i]*fNorm_[i]*fNorm_[i];
fifjTot += sumTerm;
Double_t sumEffTerm = Amp_[i].abs2()*fSqEffSum_[i]*fNorm_[i]*fNorm_[i];
fifjEffTot += sumEffTerm;
fitFrac_[i][i].value(sumTerm);
fitFracEffUnCorr_[i][i].value(sumEffTerm);
}
for (i = nAmp_; i < nAmp_+nIncohAmp_; i++) {
for (j = i+1; j < nAmp_+nIncohAmp_; j++) {
//Set off-diagonal incoherent terms to zero
TString name = "A"; name += i; name += "A"; name += j; name += "_FitFrac";
fitFrac_[i][j].name(name);
name += "EffUnCorr";
fitFracEffUnCorr_[i][j].name(name);
fitFrac_[i][j].value(0.);
fitFracEffUnCorr_[i][j].value(0.);
}
}
if (TMath::Abs(fifjTot) > 1e-10) {
meanDPEff_.value(fifjEffTot/fifjTot);
if (init) {
meanDPEff_.genValue( meanDPEff_.value() );
meanDPEff_.initValue( meanDPEff_.value() );
}
}
DPRate_.value(fifjTot);
if (init) {
DPRate_.genValue( DPRate_.value() );
DPRate_.initValue( DPRate_.value() );
}
// Now divide the fitFraction sums by the overall integral
for (i = 0; i < nAmp_+nIncohAmp_; i++) {
for (j = i; j < nAmp_+nIncohAmp_; j++) {
// Get the actual fractions by dividing by the total DP rate
Double_t fitFracVal = fitFrac_[i][j].value();
fitFracVal /= fifjTot;
fitFrac_[i][j].value( fitFracVal );
Double_t fitFracEffUnCorrVal = fitFracEffUnCorr_[i][j].value();
fitFracEffUnCorrVal /= fifjEffTot;
fitFracEffUnCorr_[i][j].value( fitFracEffUnCorrVal );
if (init) {
fitFrac_[i][j].genValue( fitFrac_[i][j].value() );
fitFrac_[i][j].initValue( fitFrac_[i][j].value() );
fitFracEffUnCorr_[i][j].genValue( fitFracEffUnCorr_[i][j].value() );
fitFracEffUnCorr_[i][j].initValue( fitFracEffUnCorr_[i][j].value() );
}
}
}
// Work out total fit fraction over all K-matrix components (for each propagator)
KMPropMap::iterator mapIter;
Int_t propInt(0);
for (mapIter = kMatrixPropagators_.begin(); mapIter != kMatrixPropagators_.end(); ++mapIter) {
LauKMatrixPropagator* thePropagator = mapIter->second;
TString propName = thePropagator->getName();
// Now loop over all resonances and find those which are K-matrix components for this propagator
Double_t kMatrixTotFitFrac(0.0);
for (i = 0; i < nAmp_; i++) {
Bool_t gotKMRes1 = this->gotKMatrixMatch(i, propName);
if (gotKMRes1 == kFALSE) {continue;}
Double_t fifjSumReal = fifjSum_[i][i].re();
Double_t sumTerm = Amp_[i].abs2()*fifjSumReal*fNorm_[i]*fNorm_[i];
//Double_t fifjEffSumReal = fifjEffSum_[i][i].re();
//Double_t sumEffTerm = Amp_[i].abs2()*fifjEffSumReal*fNorm_[i]*fNorm_[i];
kMatrixTotFitFrac += sumTerm;
for (j = i+1; j < nAmp_; j++) {
Bool_t gotKMRes2 = this->gotKMatrixMatch(j, propName);
if (gotKMRes2 == kFALSE) {continue;}
LauComplex AmpjConj = Amp_[j].conj();
LauComplex AmpTerm = Amp_[i]*AmpjConj;
Double_t crossTerm = 2.0*(AmpTerm*fifjSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
//Double_t crossEffTerm = 2.0*(AmpTerm*fifjEffSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
kMatrixTotFitFrac += crossTerm;
}
}
kMatrixTotFitFrac /= fifjTot;
TString parName("KMatrixTotFF_"); parName += propInt;
extraParameters_[propInt].name( parName );
extraParameters_[propInt].value(kMatrixTotFitFrac);
if (init) {
extraParameters_[propInt].genValue(kMatrixTotFitFrac);
extraParameters_[propInt].initValue(kMatrixTotFitFrac);
}
std::cout<<"INFO in LauIsobarDynamics::calcExtraInfo : Total K-matrix fit fraction for propagator "<<propName<<" is "<<kMatrixTotFitFrac<<std::endl;
++propInt;
}
}
Bool_t LauIsobarDynamics::gotKMatrixMatch(UInt_t resAmpInt, const TString& propName) const
{
Bool_t gotMatch(kFALSE);
if (resAmpInt >= nAmp_) {return kFALSE;}
const LauAbsResonance* theResonance = sigResonances_[resAmpInt];
if (theResonance == 0) {return kFALSE;}
Int_t resModelInt = theResonance->getResonanceModel();
if (resModelInt == LauAbsResonance::KMatrix) {
TString resName = theResonance->getResonanceName();
KMStringMap::const_iterator kMPropSetIter = kMatrixPropSet_.find(resName);
if (kMPropSetIter != kMatrixPropSet_.end()) {
TString kmPropString = kMPropSetIter->second;
if (kmPropString == propName) {gotMatch = kTRUE;}
}
}
return gotMatch;
}
Double_t LauIsobarDynamics::calcSigDPNorm()
{
// Calculate the normalisation for the log-likelihood function.
DPNorm_ = 0.0;
for (UInt_t i = 0; i < nAmp_; i++) {
// fifjEffSum is the contribution from the term involving the resonance
// dynamics (f_i for resonance i) and the efficiency term.
Double_t fifjEffSumReal = fifjEffSum_[i][i].re();
// We need to normalise this contribution w.r.t. the complete dynamics in the DP.
// Hence we scale by the fNorm_i factor (squared), which is calculated by the
// initialise() function, when the normalisation integrals are calculated and cached.
// We also include the complex amplitude squared to get the total normalisation
// contribution from this resonance.
DPNorm_ += Amp_[i].abs2()*fifjEffSumReal*fNorm_[i]*fNorm_[i];
}
// We now come to the cross-terms (between resonances i and j) in the normalisation.
for (UInt_t i = 0; i < nAmp_; i++) {
for (UInt_t j = i+1; j < nAmp_; j++) {
LauComplex AmpjConj = Amp_[j].conj();
LauComplex AmpTerm = Amp_[i]*AmpjConj;
// Again, fifjEffSum is the contribution from the term involving the resonance
// dynamics (f_i*f_j_conjugate) and the efficiency cross term.
// Also include the relative normalisation between these two resonances w.r.t. the
// total DP dynamical structure (fNorm_i and fNorm_j) and the complex
// amplitude squared (mag,phase) part.
DPNorm_ += 2.0*(AmpTerm*fifjEffSum_[i][j]).re()*fNorm_[i]*fNorm_[j];
}
}
for (UInt_t i = 0; i < nIncohAmp_; i++) {
DPNorm_ += Amp_[i+nAmp_].abs2()*fSqEffSum_[i+nAmp_]*fNorm_[i+nAmp_]*fNorm_[i+nAmp_];
}
return DPNorm_;
}
Bool_t LauIsobarDynamics::generate()
{
// Routine to generate a signal event according to the Dalitz plot
// model we have defined.
// We need to make sure to calculate everything for every resonance
integralsToBeCalculated_.clear();
for ( UInt_t i(0); i < nAmp_+nIncohAmp_; ++i ) {
integralsToBeCalculated_.insert(i);
}
nSigGenLoop_ = 0;
Bool_t generatedSig(kFALSE);
while (generatedSig == kFALSE && nSigGenLoop_ < iterationsMax_) {
// Generates uniform DP phase-space distribution
Double_t m13Sq(0.0), m23Sq(0.0);
kinematics_->genFlatPhaseSpace(m13Sq, m23Sq);
// If we're in a symmetrical DP then we should only generate events in one half
// TODO - what do we do for fully symmetric?
if ( symmetricalDP_ && !fullySymmetricDP_ && m13Sq > m23Sq ) {
Double_t tmpSq = m13Sq;
m13Sq = m23Sq;
m23Sq = tmpSq;
}
// Calculate the amplitudes and total amplitude for the given DP point
this->calcLikelihoodInfo(m13Sq, m23Sq);
// Throw the random number and check it against the ratio of ASq and the accept/reject ceiling
const Double_t randNo = LauRandom::randomFun()->Rndm();
if (randNo > ASq_/aSqMaxSet_) {
++nSigGenLoop_;
} else {
generatedSig = kTRUE;
nSigGenLoop_ = 0;
// Keep a note of the maximum ASq that we've found
if (ASq_ > aSqMaxVar_) {aSqMaxVar_ = ASq_;}
}
} // while loop
// Check that all is well with the generation
Bool_t sigGenOK(kTRUE);
if (GenOK != this->checkToyMC(kTRUE,kFALSE)) {
sigGenOK = kFALSE;
}
return sigGenOK;
}
LauIsobarDynamics::ToyMCStatus LauIsobarDynamics::checkToyMC(Bool_t printErrorMessages, Bool_t printInfoMessages)
{
// Check whether we have generated the toy MC OK.
ToyMCStatus ok(GenOK);
if (nSigGenLoop_ >= iterationsMax_) {
// Exceeded maximum allowed iterations - the generation is too inefficient
if (printErrorMessages) {
std::cerr<<"WARNING in LauIsobarDynamics::checkToyMC : More than "<<iterationsMax_<<" iterations performed and no event accepted."<<std::endl;
}
if ( aSqMaxSet_ > 1.01 * aSqMaxVar_ ) {
if (printErrorMessages) {
std::cerr<<" : |A|^2 maximum was set to "<<aSqMaxSet_<<" but this appears to be too high."<<std::endl;
std::cerr<<" : Maximum value of |A|^2 found so far = "<<aSqMaxVar_<<std::endl;
std::cerr<<" : The value of |A|^2 maximum will be decreased and the generation restarted."<<std::endl;
}
aSqMaxSet_ = 1.01 * aSqMaxVar_;
std::cout<<"INFO in LauIsobarDynamics::checkToyMC : |A|^2 max reset to "<<aSqMaxSet_<<std::endl;
ok = MaxIterError;
} else {
if (printErrorMessages) {
std::cerr<<" : |A|^2 maximum was set to "<<aSqMaxSet_<<", which seems to be correct for the given model."<<std::endl;
std::cerr<<" : However, the generation is very inefficient - please check your model."<<std::endl;
std::cerr<<" : The maximum number of iterations will be increased and the generation restarted."<<std::endl;
}
iterationsMax_ *= 2;
std::cout<<"INFO in LauIsobarDynamics::checkToyMC : max number of iterations reset to "<<iterationsMax_<<std::endl;
ok = MaxIterError;
}
} else if (aSqMaxVar_ > aSqMaxSet_) {
// Found a value of ASq higher than the accept/reject ceiling - the generation is biased
if (printErrorMessages) {
std::cerr<<"WARNING in LauIsobarDynamics::checkToyMC : |A|^2 maximum was set to "<<aSqMaxSet_<<" but a value exceeding this was found: "<<aSqMaxVar_<<std::endl;
std::cerr<<" : Run was invalid, as any generated MC will be biased, according to the accept/reject method!"<<std::endl;
std::cerr<<" : The value of |A|^2 maximum be reset to be > "<<aSqMaxVar_<<" and the generation restarted."<<std::endl;
}
aSqMaxSet_ = 1.01 * aSqMaxVar_;
std::cout<<"INFO in LauIsobarDynamics::checkToyMC : |A|^2 max reset to "<<aSqMaxSet_<<std::endl;
ok = ASqMaxError;
} else if (printInfoMessages) {
std::cout<<"INFO in LauIsobarDynamics::checkToyMC : aSqMaxSet = "<<aSqMaxSet_<<" and aSqMaxVar = "<<aSqMaxVar_<<std::endl;
}
return ok;
}
void LauIsobarDynamics::setDataEventNo(UInt_t iEvt)
{
// Retrieve the data for event iEvt
if (data_.size() > iEvt) {
currentEvent_ = data_[iEvt];
} else {
std::cerr<<"ERROR in LauIsobarDynamics::setDataEventNo : Event index too large: "<<iEvt<<" >= "<<data_.size()<<"."<<std::endl;
}
m13Sq_ = currentEvent_->retrievem13Sq();
m23Sq_ = currentEvent_->retrievem23Sq();
mPrime_ = currentEvent_->retrievemPrime();
thPrime_ = currentEvent_->retrievethPrime();
tagCat_ = currentEvent_->retrieveTagCat();
eff_ = currentEvent_->retrieveEff();
scfFraction_ = currentEvent_->retrieveScfFraction(); // These two are necessary, even though the dynamics don't actually use scfFraction_ or jacobian_,
jacobian_ = currentEvent_->retrieveJacobian(); // since this is at the heart of the caching mechanism.
}
void LauIsobarDynamics::calcLikelihoodInfo(const UInt_t iEvt)
{
// Calculate the likelihood and associated info
// for the given event using cached information
evtLike_ = 0.0;
// retrieve the cached dynamics from the tree:
// realAmp, imagAmp for each resonance plus efficiency, scf fraction and jacobian
this->setDataEventNo(iEvt);
// use realAmp and imagAmp to create the resonance amplitudes
const std::vector<Double_t>& realAmp = currentEvent_->retrieveRealAmp();
const std::vector<Double_t>& imagAmp = currentEvent_->retrieveImagAmp();
const std::vector<Double_t>& incohInten = currentEvent_->retrieveIncohIntensities();
for (UInt_t i = 0; i < nAmp_; i++) {
this->setFFTerm(i, realAmp[i], imagAmp[i]);
}
for (UInt_t i = 0; i < nIncohAmp_; i++) {
this->setIncohIntenTerm(i, incohInten[i]);
}
// Update the dynamics - calculates totAmp_ and then ASq_ = totAmp_.abs2() * eff_
// All calculated using cached information on the individual amplitudes and efficiency.
this->calcTotalAmp(kTRUE);
// Calculate the normalised matrix element squared value
if (DPNorm_ > 1e-10) {
evtLike_ = ASq_/DPNorm_;
}
}
void LauIsobarDynamics::calcLikelihoodInfo(const Double_t m13Sq, const Double_t m23Sq)
{
this->calcLikelihoodInfo(m13Sq, m23Sq, -1);
}
void LauIsobarDynamics::calcLikelihoodInfo(const Double_t m13Sq, const Double_t m23Sq, const Int_t tagCat)
{
// Calculate the likelihood and associated info
// for the given point in the Dalitz plot
// Also retrieves the SCF fraction in the bin where the event lies (done
// here to cache it along with the the rest of the DP quantities, like eff)
// The jacobian for the square DP is calculated here for the same reason.
evtLike_ = 0.0;
// update the kinematics for the specified DP point
kinematics_->updateKinematics(m13Sq, m23Sq);
// calculate the jacobian and the scfFraction to cache them later
scfFraction_ = this->retrieveScfFraction(tagCat);
if (kinematics_->squareDP() == kTRUE) {
jacobian_ = kinematics_->calcSqDPJacobian();
}
// calculate the ff_ terms and retrieves eff_ from the efficiency model
this->calculateAmplitudes();
// then calculate totAmp_ and finally ASq_ = totAmp_.abs2() * eff_
this->calcTotalAmp(kTRUE);
// Calculate the normalised matrix element squared value
if (DPNorm_ > 1e-10) {
evtLike_ = ASq_/DPNorm_;
}
}
void LauIsobarDynamics::modifyDataTree()
{
if ( recalcNormalisation_ == kFALSE ) {
return;
}
const UInt_t nEvents = data_.size();
std::set<UInt_t>::const_iterator iter = integralsToBeCalculated_.begin();
const std::set<UInt_t>::const_iterator intEnd = integralsToBeCalculated_.end();
for (UInt_t iEvt = 0; iEvt < nEvents; ++iEvt) {
currentEvent_ = data_[iEvt];
std::vector<Double_t>& realAmp = currentEvent_->retrieveRealAmp();
std::vector<Double_t>& imagAmp = currentEvent_->retrieveImagAmp();
std::vector<Double_t>& incohInten = currentEvent_->retrieveIncohIntensities();
const Double_t m13Sq = currentEvent_->retrievem13Sq();
const Double_t m23Sq = currentEvent_->retrievem23Sq();
const Int_t tagCat = currentEvent_->retrieveTagCat();
this->calcLikelihoodInfo(m13Sq, m23Sq, tagCat);
for ( iter = integralsToBeCalculated_.begin(); iter != intEnd; ++iter) {
const UInt_t i = *iter;
if(*iter < nAmp_) {
realAmp[i] = ff_[i].re();
imagAmp[i] = ff_[i].im();
} else {
incohInten[i-nAmp_] = incohInten_[i-nAmp_];
}
}
}
}
void LauIsobarDynamics::fillDataTree(const LauFitDataTree& inputFitTree)
{
// In LauFitDataTree, the first two variables should always be m13^2 and m23^2.
// Other variables follow thus: charge/flavour tag prob, etc.
// Since this is the first caching, we need to make sure to calculate everything for every resonance
integralsToBeCalculated_.clear();
for ( UInt_t i(0); i < nAmp_+nIncohAmp_; ++i ) {
integralsToBeCalculated_.insert(i);
}
UInt_t nBranches = inputFitTree.nBranches();
if (nBranches < 2) {
std::cerr<<"ERROR in LauIsobarDynamics::fillDataTree : Expecting at least 2 variables " <<"in input data tree, but there are "<<nBranches<<"!\n";
std::cerr<<" : Make sure you have the right number of variables in your input data file!"<<std::endl;
gSystem->Exit(EXIT_FAILURE);
}
// Data structure that will cache the variables required to
// calculate the signal likelihood for this experiment
for ( std::vector<LauCacheData*>::iterator iter = data_.begin(); iter != data_.end(); ++iter ) {
delete (*iter);
}
data_.clear();
Double_t m13Sq(0.0), m23Sq(0.0);
Double_t mPrime(0.0), thPrime(0.0);
Int_t tagCat(-1);
std::vector<Double_t> realAmp(nAmp_), imagAmp(nAmp_);
Double_t eff(0.0), scfFraction(0.0), jacobian(0.0);
UInt_t nEvents = inputFitTree.nEvents() + inputFitTree.nFakeEvents();
data_.reserve(nEvents);
for (UInt_t iEvt = 0; iEvt < nEvents; ++iEvt) {
const LauFitData& dataValues = inputFitTree.getData(iEvt);
LauFitData::const_iterator iter = dataValues.find("m13Sq");
m13Sq = iter->second;
iter = dataValues.find("m23Sq");
m23Sq = iter->second;
// is there more than one tagging category?
// if so then we need to know the category from the data
if (scfFractionModel_.size()>1) {
iter = dataValues.find("tagCat");
tagCat = static_cast<Int_t>(iter->second);
}
// calculates the amplitudes and total amplitude for the given DP point
// tagging category not needed by dynamics, but to find out the scfFraction
this->calcLikelihoodInfo(m13Sq, m23Sq, tagCat);
// extract the real and imaginary parts of the ff_ terms for storage
for (UInt_t i = 0; i < nAmp_; i++) {
realAmp[i] = ff_[i].re();
imagAmp[i] = ff_[i].im();
}
if ( kinematics_->squareDP() ) {
mPrime = kinematics_->getmPrime();
thPrime = kinematics_->getThetaPrime();
}
eff = this->getEvtEff();
scfFraction = this->getEvtScfFraction();
jacobian = this->getEvtJacobian();
// store the data for each event in the list
data_.push_back( new LauCacheData() );
data_[iEvt]->storem13Sq(m13Sq);
data_[iEvt]->storem23Sq(m23Sq);
data_[iEvt]->storemPrime(mPrime);
data_[iEvt]->storethPrime(thPrime);
data_[iEvt]->storeTagCat(tagCat);
data_[iEvt]->storeEff(eff);
data_[iEvt]->storeScfFraction(scfFraction);
data_[iEvt]->storeJacobian(jacobian);
data_[iEvt]->storeRealAmp(realAmp);
data_[iEvt]->storeImagAmp(imagAmp);
data_[iEvt]->storeIncohIntensities(incohInten_);
}
}
Bool_t LauIsobarDynamics::gotReweightedEvent()
{
// Select the event (kinematics_) using an accept/reject method based on the
// ratio of the current value of ASq to the maximal value.
Bool_t accepted(kFALSE);
// calculate the ff_ terms and retrieves eff_ from the efficiency model
this->calculateAmplitudes();
// then calculate totAmp_ and finally ASq_ = totAmp_.abs2() (without the efficiency correction!)
this->calcTotalAmp(kFALSE);
// Compare the ASq value with the maximal value (set by the user)
if (LauRandom::randomFun()->Rndm() < ASq_/aSqMaxSet_) {
accepted = kTRUE;
}
if (ASq_ > aSqMaxVar_) {aSqMaxVar_ = ASq_;}
return accepted;
}
Double_t LauIsobarDynamics::getEventWeight()
{
// calculate the ff_ terms and retrieves eff_ from the efficiency model
this->calculateAmplitudes();
// then calculate totAmp_ and finally ASq_ = totAmp_.abs2() (without the efficiency correction!)
this->calcTotalAmp(kFALSE);
if (ASq_ > aSqMaxVar_) {aSqMaxVar_ = ASq_;}
// return the event weight = the value of the squared amplitude divided
// by the user-defined ceiling
return ASq_ / aSqMaxSet_;
}
void LauIsobarDynamics::updateCoeffs(const std::vector<LauComplex>& coeffs)
{
// Check that the number of coeffs is correct
if (coeffs.size() != this->getnTotAmp()) {
std::cerr << "ERROR in LauIsobarDynamics::updateCoeffs : Expected " << this->getnTotAmp() << " but got " << coeffs.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
// Now check if the coeffs have changed
Bool_t changed = (Amp_ != coeffs);
if (changed) {
// Copy the coeffs
Amp_ = coeffs;
}
// 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
// Update the total normalisation for the signal likelihood
this->calcSigDPNorm();
}
TString LauIsobarDynamics::getConjResName(const TString& resName) const
{
// Get the name of the charge conjugate resonance
TString conjName(resName);
Ssiz_t index1 = resName.Index("+");
Ssiz_t index2 = resName.Index("-");
if (index1 != -1) {
conjName.Replace(index1, 1, "-");
} else if (index2 != -1) {
conjName.Replace(index2, 1, "+");
}
return conjName;
}
Double_t LauIsobarDynamics::retrieveEfficiency()
{
Double_t eff(1.0);
if (effModel_ != 0) {
eff = effModel_->calcEfficiency(kinematics_);
}
return eff;
}
Double_t LauIsobarDynamics::retrieveScfFraction(Int_t tagCat)
{
Double_t scfFraction(0.0);
// scf model and eff model are exactly the same, functionally
// so we use an instance of LauAbsEffModel, and the method
// calcEfficiency actually calculates the scf fraction
if (tagCat == -1) {
if (!scfFractionModel_.empty()) {
scfFraction = scfFractionModel_[0]->calcEfficiency(kinematics_);
}
} else {
scfFraction = scfFractionModel_[tagCat]->calcEfficiency(kinematics_);
}
return scfFraction;
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Dec 21, 6:25 PM (8 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4023793
Default Alt Text
(142 KB)

Event Timeline