Page MenuHomeHEPForge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/doc/release.notes b/doc/release.notes
index 89f078b..4de1cb1 100644
--- a/doc/release.notes
+++ b/doc/release.notes
@@ -1,248 +1,254 @@
///////////////////////////////////////////////////////////////
/// ///
/// This is the History file for the Laura++ package. ///
/// ///
///////////////////////////////////////////////////////////////
+19th April 2014 Daniel Craik
+
+* Add LauWeightedSumEffModel which gives an efficiency model from the weighted sum of several LauEffModel objects.
+* Added pABC, LauAbsEffModel, for LauEffModel and LauWeightedSumEffModel.
+* Various classes updated to use pointers to LauAbsEffModel instead of LauEffModel.
+
15th April 2014 Daniel Craik
* Enable LauEfficiencyModel to contain several Lau2DAbsDP objects with the total efficiency calculated as the product.
10th April 2014 Mark Whitehead
* Fix an issue with the likelihood penalty term for Gaussian constraints
- Factor two missing in the denominator
- New penalty term is: ( x-mean )^2 / 2*(width^2)
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Laura++ v2r1
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1st April 2014 Thomas Latham
* Fix issue in LauFitter that prevents compilation with g++ 4.8
- Missing virtual destructor
- Take opportunity to audit other special functions
31st March 2014 Mark Whitehead
(in branch for release in v2r1)
* Added an efficiency branch to the ntuple produced for toy data samples
- Both LauSimpleFitModel and LauCPFitModel updated
28th March 2014 Daniel Craik
* Added support for asymmetric errors to Lau2DHistDP, Lau2DSplineDP and LauEffModel.
27th March 2014 Daniel Craik
* Changed histogram classes to use seeded random number generator for
fluctuation and raising or lowering of bins and updated doxygen.
20th March 2014 Mark Whitehead
(in branch for release in v2r1)
* Added the ability to add Gaussian contraints to LauFormulaPars of fit parameters
- User supplies the information but the LauFormulaPar is constructed behind the scenes
11th March 2014 Mark Whitehead
(in branch for release in v2r1)
* Added the functionality to make LauFormulaPars usable in fits
- Added a new class LauAbsRValue which LauParameter and LauFormularPar inherit from
- Many files updated to accept LauAbsRValues instead of LauParameters
* Fairly major clean up of obsolete functions in LauAbsPdf
- Only LauLinearPdf used any of them, this has now been updated
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Laura++ v2r0
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
8th March 2014 Thomas Latham
* Some additional functionality for the CoeffSet classes:
- allow the parameter values to be set (optionally setting the initial and generated values as well)
- allow the parameters to be set to float or to be fixed in the fit
These are needed when cloning but wanting some of the parameters to have different values and/or floating behaviour from the cloned set.
* Improve the printout of the setting of the coefficient values in the fit models and the creation of resonances
* Add LauFlatNR for the unform NR model - ends its rather strange special treatment
* Fix bug setting resAmpInt to 0 for LauPolNR
* Many other improvements to the info/warning/error printouts
* Modify GenFitBelleCPKpipi example to demonstrate cloning in action
* Add -Werror to compiler flags (treats warnings as errors)
5th March 2014 Thomas Latham
* Some improvements to LauPolNR to speed up amplitude calculation
2nd March 2014 Thomas Latham
* A number of updates to the CoeffSet classes:
- allow specification of the basename just after construction (before being given to the fit model)
- allow configuration of the parameter fit ranges (through static methods of base class)
- more adaptable cloning of the parameters (e.g. can only clone phase but allow magnitude to float independently)
- allow CP-violating parameters to be second-stage in Belle and CLEO formats
* Some improvements to the Doxygen and runtime information printouts
20th February 2014 Louis Henry
* Add LauPolNR - class for modelling the nonresonant contribution based on BaBar 3K model (arXiv:1201.5897)
6th February 2014 Thomas Latham
* Correct helicity convention information in Doxygen for LauKinematics
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Laura++ v1r2
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
5th February 2014 Thomas Latham
* Add rule to the Makefile that creates a rootmap file for the library
4th February 2014 Daniel Craik
* Fixed bug in Lau2DSplineDPPdf - normalisation was not being calculated
* Added out-of-range warning in LauBkgndDPModel and supressed excessive warnings
3rd February 2014 Mark Whitehead
(in branch for release in v2r0)
* Added a new class to allow parameters to be a function of other parameters
- inc/LauFormulaPar.hh
- src/LauFormulaPar.cc
28th January 2014 Daniel Craik
* Improved out-of-range efficiency warnings in LauEffModel and supressed excessive errors
* Modified LauIsobarDynamics to allow LASS parameters to be configured for LauLASSBWRes and
LauLASSNRRes
27th January 2014 Daniel Craik
* Added spline interpolation to DP backgrounds
- Added Lau2DSplineDPPdf which uses a spline to model a normalised PDF across a DP
- Added pABC, Lau2DAbsDPPdf, for Lau2DHistDPPdf and Lau2DSplineDPPdf and moved common
code in Lau2DHistDPPdf and Lau2DSplineDPPdf into ABC Lau2DAbsHistDPPdf
- LauBkgndDPModel, modified to use Lau2DAbsDPPdf instead of Lau2DHistDPPdf
- setBkgndSpline method added to LauBkgndDPModel to allow use of splines
22nd January 2014 Thomas Latham
* Improve some error checks and corresponding warning messages in
LauCPFitModel::setSignalDPParameters
16th January 2014 Thomas Latham
* Add LauRealImagCPCoeffSet, which provides an (x,y), (xbar,ybar) way of
parametrising the complex coefficients.
* Try to improve timing in the *CoeffSet classes by making the complex coeffs
into member variables.
20th December 2013 Daniel Craik
* Added Lau2DCubicSpline which provides cubic spline interpolation of a histogram
- Added Lau2DSplineDP which uses a spline to model variation across a DP (eg efficiency)
- Added pABC, Lau2DAbsDP, for Lau2DHistDP and Lau2DSplineDP and moved common code
in Lau2DHistDP and Lau2DSplineDP into ABC Lau2DAbsHistDP
- LauEffModel, LauDPDepSumPdf and LauDPDepMapPdf modified to use Lau2DAbsDP instead of
Lau2DHistDP
- setEffSpline method added to LauEffModel and useSpline flag added to constructor for
LauDPDepSumPdf to allow use of splines
18th December 2013 Mark Whitehead
(in branch for release in v2r0)
* Added functionality to include Gaussian constraints on floated
parameters in the fit.
The files updated are:
- inc/LauAbsFitModel.hh
- inc/LauParameter.hh
- src/LauAbsFitModel.cc
- src/LauParameter.cc
5th December 2013 Thomas Latham
* Fix small bug in GenFitKpipi example where background asymmetry parameter had
its limits the wrong way around
4th December 2013 Daniel Craik
* Updated 2D chi-squared code to use adaptive binning.
3rd December 2013 Thomas Latham
* Generalise the Makefile in the examples directory
- results in minor changes to the names of 3 of the binaries
3rd December 2013 Thomas Latham
(in branch for release in v2r0)
* Have the master save an ntuple with all fitter parameters and the full correlation matrix information.
29th November 2013 Thomas Latham
* Fixed bug in ResultsExtractor where the output file was not written
29th November 2013 Thomas Latham
(in branch for release in v2r0)
* Allow the slave ntuples to store the partial covariance matrices in the simultaneous fitting
26th November 2013 Thomas Latham
(in branch for release in v2r0)
* Added first version of the simultaneous fitting framework
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Laura++ v1r1p1
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22nd November 2013 Thomas Latham
* Fixed bug in LauCPFitModel where values of q = -1 extra PDFs
were used regardless of the event charge.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Laura++ v1r1
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20th November 2013 Mark Whitehead
* Changed convention for the barrier factors, swapping from p* to p.
This seems to give more physically reasonable results.
The files updated are:
- src/LauGounarisSakuraiRes.cc
- src/LauRelBreitWignerRes.cc
18th October 2013 Thomas Latham
* Fix dependency problem in Makefile
8th October 2013 Thomas Latham
* Some fixes to yield implementation
* Minor bug fix in DP background histogram class
7th October 2013 Mark Whitehead
* Update to accept the yields and yield asymmetries as LauParameters.
All examples have been updated to reflect this change.
This updated the following files:
- inc/LauCPFitModel.hh
- inc/LauSimpleFitModel.hh
- inc/LauAbsFitModel.hh
- src/LauCPFitModel.cc
- src/LauSimpleFitModel.cc
* Addition of the following particles to src/LauResonanceMaker.cc
Ds*+-, Ds0*(2317)+-, Ds2*(2573)+-, Ds1*(2700)+- and Bs*0
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Laura++ v1r0
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
13th September 2013 Thomas Latham
* Initial import of the package into HEPforge
diff --git a/inc/LauAbsDPDynamics.hh b/inc/LauAbsDPDynamics.hh
index 748ca08..32efed6 100644
--- a/inc/LauAbsDPDynamics.hh
+++ b/inc/LauAbsDPDynamics.hh
@@ -1,420 +1,420 @@
// Copyright University of Warwick 2005 - 2013.
// 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 LauAbsDPDynamics.hh
\brief File containing declaration of LauAbsDPDynamics class.
*/
/*! \class LauAbsDPDynamics
\brief Class for defining the abstract interface for signal Dalitz plot dynamics.
*/
#ifndef LAU_ABS_DP_DYNAMICS
#define LAU_ABS_DP_DYNAMICS
#include <vector>
#include <map>
#include "TString.h"
#include "LauCacheData.hh"
#include "LauParameter.hh"
class LauAbsResonance;
class LauComplex;
class LauDaughters;
-class LauEffModel;
+class LauAbsEffModel;
class LauFitDataTree;
class LauKinematics;
class LauResonanceMaker;
class LauAbsDPDynamics {
public:
//! The type used for containing multiple self cross feed fraction models for different categories (e.g. tagging categories)
- typedef std::map<Int_t,LauEffModel*> LauTagCatScfFractionModelMap;
+ typedef std::map<Int_t,LauAbsEffModel*> LauTagCatScfFractionModelMap;
//! 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
*/
- LauAbsDPDynamics(LauDaughters* daughters, LauEffModel* effModel, LauEffModel* scfFractionModel = 0);
+ LauAbsDPDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, LauAbsEffModel* scfFractionModel = 0);
//! Constructor
/*!
\param [in] daughters the daughters of the decay
\param [in] effModel the model to describe 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
*/
- LauAbsDPDynamics(LauDaughters* daughters, LauEffModel* effModel, const LauTagCatScfFractionModelMap& scfFractionModel);
+ LauAbsDPDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, const LauTagCatScfFractionModelMap& scfFractionModel);
//! Destructor
virtual ~LauAbsDPDynamics();
//! 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) */
};
//! Add a resonance to the Dalitz plot
/*!
\param [in] resName the name of the resonant particle
\param [in] resPairAmpInt the index of the daughter not produced by the resonance (the bachelor)
\param [in] resType the type of the resonance. Allowed types are: flatte, relbw, dabba, kappa, sigma, lass-bw, lass-nr, lass, gs, nrmodel, bellesymnr and bellenr
\param [in] newMass set a custom mass for the resonance
\param [in] newWidth set a custom width for the resonance
\param [in] newSpin set a custom spin for the resonance
*/
virtual void addResonance(const TString& resName, Int_t resPairAmpInt, const TString& resType,
Double_t newMass, Double_t newWidth, Int_t newSpin) = 0;
//! Initialise the Dalitz plot dynamics
/*!
\param [in] coeffs the complex coefficients for the resonances
*/
virtual void initialise(const std::vector<LauComplex>& coeffs) = 0;
//! Obtain the efficiency of the current event from the model
/*!
\return the efficiency
*/
virtual 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
*/
virtual Double_t retrieveScfFraction(Int_t tagCat);
//! Obtain data from a fit tree
/*!
\param [in] inputFitTree the tree
*/
virtual void fillDataTree(const LauFitDataTree& inputFitTree) = 0;
//! Load the data for a given event
/*!
\param [in] iEvt the number of the event
*/
virtual void setDataEventNo(UInt_t iEvt);
//! Check whether this model includes a named resonance
/*!
\param [in] resName the resonance
\return true if the resonance is present, false otherwise
*/
virtual Bool_t hasResonance(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
*/
virtual TString getConjResName(const TString& resName) const;
//! Update the complex coefficients for the resonances
/*!
\param [in] coeffs the new set of coefficients
*/
virtual void updateCoeffs(const std::vector<LauComplex>& coeffs);
//! Generate a toy MC signal event
/*!
\return true if the event is successfully generated, false otherwise
*/
virtual Bool_t generate() = 0;
//! 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
*/
virtual ToyMCStatus checkToyMC(Bool_t printErrorMessages = kTRUE, Bool_t printInfoMessages = kFALSE) = 0;
//! 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
*/
virtual void calcLikelihoodInfo(Double_t m13Sq, Double_t m23Sq) = 0;
//! Calculate the likelihood (and all associated information) for the given event number
/*!
\param [in] iEvt the event number
*/
virtual void calcLikelihoodInfo(UInt_t iEvt) = 0;
//! Retrieve the likelihood for the current event
/*!
\return the likelihood for the current event
*/
virtual Double_t getEvtLikelihood() const = 0;
//! 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
*/
virtual Double_t getEvtm13Sq() const = 0;
//! 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
*/
virtual Double_t getEvtm23Sq() const = 0;
//! Retrieve the square Dalitz plot coordinate, m', for the current event
/*!
\return the square Dalitz plot coordinate, m', for the current event
*/
virtual Double_t getEvtmPrime() const = 0;
//! Retrieve the square Dalitz plot coordinate, theta', for the current event
/*!
\return the square Dalitz plot coordinate, theta', for the current event
*/
virtual Double_t getEvtthPrime() const = 0;
//! Retrieve the efficiency for the current event
/*!
\return the efficiency for the current event
*/
virtual Double_t getEvtEff() const = 0;
//! Retrieve the Jacobian, for the transformation into square DP coordinates, for the current event
/*!
\return the Jacobian for the current event
*/
virtual Double_t getEvtJacobian() const = 0; //Not sure whether this should be here or only in LauIsobarDynamics.
//! Retrieve the fraction of events that are poorly reconstructed (the self cross feed fraction) in the Dalitz plot bin of the current event
/*!
\return the self cross feed fraction for the current event
*/
virtual Double_t getEvtScfFraction() const = 0;
//! Retrieve the total amplitude of all amplitude components at the current point in the Dalitz plot
/*!
\return the total amplitude
*/
virtual const LauComplex& getEvtDPAmp() const = 0;
//! Retrieve the amplitude of the given amplitude component at the current point in the Dalitz plot
/*!
\param [in] resID the index of the amplitude component within the model
\return the amplitude of the given amplitude component
*/
virtual LauComplex getDynamicAmp(Int_t resID) const = 0;
//! Calculate the fit fractions, mean efficiency and total DP rate
/*!
\param [in] init whether the calculated values should be used to generate toys and as the initial values when fitting
*/
virtual void calcExtraInfo(Bool_t init = kFALSE) = 0;
// Use this method to select events in the DP for embedded-reweighting.
//! 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
/*!
\return true if the event has been accepted, false otherwise
*/
virtual Bool_t gotReweightedEvent() = 0;
//! Calculate the acceptance rate, for events with the current kinematics, when generating events according to the model
/*!
\return the weight for the current kinematics
*/
virtual Double_t getEventWeight() = 0;
//! Retrieve the mean efficiency across the Dalitz plot
/*!
\return the mean efficiency across the Dalitz plot
*/
inline LauParameter getMeanEff() const {return meanDPEff_;}
//! Retrieve the overall Dalitz plot rate
/*!
\return the overall Dalitz plot rate
*/
inline 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 number of defined resonances in the resonance maker
/*!
\return the number of defined resonances
*/
inline UInt_t getnDefinedResonances() const {return nResDefMax_;}
//! Retrieve the number of amplitude components
/*!
\return the number of amplitude components
*/
inline UInt_t getnAmp() const {return nAmp_;}
//! Retrieve the normalisation factor for the log-likelihood function
/*!
\return the normalisation factor
*/
inline Double_t getDPNorm() const {return DPNorm_;}
//! Retrieve the number of cached events
/*!
\return the number of cached events
*/
inline UInt_t nData() const {return data_.size();}
//! Retrieve the cached data
/*!
\return the cached data
*/
inline const std::vector<LauCacheData*>& getCacheData() const {return data_;}
//! Retrieve the daughters
/*!
\return the daughters
*/
inline LauDaughters* getDaughters() {return daughters_;}
//! Retrieve the resonance maker object
/*!
\return the resonance maker
*/
inline LauResonanceMaker* getResonanceMaker() {return resonanceMaker_;}
//! 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 LauEffModel* getEffModel() {return effModel_;}
+ inline LauAbsEffModel* getEffModel() {return effModel_;}
//! Retrieve the model for the fraction of events that are poorly reconstructed (the self cross feed fraction) in each Dalitz plot bin for the first (or only) tagging category
/*!
\return the self cross feed fraction model
*/
- inline LauEffModel* getScfFractionModel() {return scfFractionModel_[0];}
+ inline LauAbsEffModel* getScfFractionModel() {return scfFractionModel_[0];}
//! Retrieve the model for the fraction of events that are poorly reconstructed (the self cross feed fraction) in each Dalitz plot bin for all tagging categories
/*!
\return the self cross feed fraction models
*/
- inline std::map <Int_t,LauEffModel*> getScfFractionModels() {return scfFractionModel_;}
+ inline std::map <Int_t,LauAbsEffModel*> getScfFractionModels() {return scfFractionModel_;}
//! 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() { return ! scfFractionModel_.empty(); }
//! Retrieve any extra parameters/quantities (e.g. K-matrix total fit fractions)
/*!
\return any extra parameters
*/
std::vector<LauParameter> getExtraParameters() {return extraParameters_;}
protected:
//! Calculate the normalisation factor for the log-likelihood function
/*!
\return the normalisation factor
*/
virtual Double_t calcSigDPNorm() = 0;
//! Retrieve the named resonance
/*!
\param [in] name the name of the resonance to retrieve
\return the named resonance
*/
virtual LauAbsResonance* findResonance(const TString& name) = 0;
//! Retrieve the named resonance
/*!
\param [in] name the name of the resonance to retrieve
\return the named resonance
*/
virtual const LauAbsResonance* findResonance(const TString& name) const = 0;
//! The daughters of the decay
LauDaughters* daughters_;
//! Object to create resonances
LauResonanceMaker* resonanceMaker_;
//! The kinematics of the decay
LauKinematics* kinematics_;
//! The efficiency model across the Dalitz plot
- LauEffModel* effModel_;
+ 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 resonances defined in the resonance maker
UInt_t nResDefMax_;
//! 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_;
private:
ClassDef(LauAbsDPDynamics,0)
};
#endif
diff --git a/inc/LauAbsEffModel.hh b/inc/LauAbsEffModel.hh
new file mode 100644
index 0000000..ac67d23
--- /dev/null
+++ b/inc/LauAbsEffModel.hh
@@ -0,0 +1,77 @@
+
+// Copyright University of Warwick 2004 - 2013.
+// 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 LauAbsEffModel.hh
+ \brief File containing declaration of LauAbsEffModel class.
+*/
+
+/*! \class LauAbsEffModel
+ \brief Pure abstract base class for defining the efficiency description across the signal Dalitz plot.
+
+ Pure abstract base class for defining the efficiency description across the signal Dalitz plot.
+ The efficiency variation is defined in terms of x = m_13^2, y = m_23^2 for the Dalitz plot (default)
+ or x = m', y = theta' for the square Dalitz plot
+*/
+
+#ifndef LAUABSEFFMODEL
+#define LAUABSEFFMODEL
+
+#include "Rtypes.h"
+
+class LauKinematics;
+
+
+class LauAbsEffModel {
+
+ public:
+ //! Constructor
+ LauAbsEffModel() {}
+
+ //! Destructor
+ virtual ~LauAbsEffModel() {}
+
+ //! Determine the efficiency for a given point in the Dalitz plot.
+ /*!
+ \param [in] kinematics the object that defines the DP position
+ \return the efficiency value at the given point in the DP
+ */
+ virtual Double_t calcEfficiency( const LauKinematics* kinematics ) const=0;
+
+ //! Determine whether the given DP position is outside the vetoes
+ /*!
+ \param [in] kinematics the object that defines the DP position
+ \return kTRUE if the DP position is outside all veto regions, kFALSE otherwise
+ */
+ virtual Bool_t passVeto( const LauKinematics* kinematics ) const=0;
+
+ //! Determine whether the efficiency histogram has had its bins fluctuated within their errors
+ virtual Bool_t fluctuateEffHisto() const=0;
+
+ //! Return the daughters object
+ /*
+ \return the LauDaughters object associated with the DP
+ */
+ virtual const LauDaughters* getDaughters() const=0;
+
+ //! Determine whether the efficiency histogram is in the square DP
+ /*
+ \return kTRUE if the square DP is being used, kFALSE otherwise
+ */
+ virtual Bool_t usingSquareDP() const=0;
+
+ private:
+ //! Copy constructor - not implemented
+ LauAbsEffModel( const LauAbsEffModel& rhs );
+
+ ClassDef(LauAbsEffModel, 0) // pABC for the signal efficiency across the DP
+
+};
+
+#endif
diff --git a/inc/LauEffModel.hh b/inc/LauEffModel.hh
index fd53133..b94ae5e 100644
--- a/inc/LauEffModel.hh
+++ b/inc/LauEffModel.hh
@@ -1,250 +1,262 @@
// Copyright University of Warwick 2004 - 2013.
// 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 LauEffModel.hh
\brief File containing declaration of LauEffModel class.
*/
/*! \class LauEffModel
\brief Class that implements the efficiency description across the signal Dalitz plot.
Class that defines the efficiency model variation across the signal Dalitz plot.
The method is based in a predetermined two-dimensional histogram to characterize the phase space acceptance.
The efficiency variation is defined in terms of x = m_13^2, y = m_23^2 for the Dalitz plot (default)
or x = m', y = theta' for the square Dalitz plot
*/
#ifndef LAUEFFMODEL
#define LAUEFFMODEL
-#include "Rtypes.h"
+#include "LauAbsEffModel.hh"
class TH2;
class LauDaughters;
class LauKinematics;
class LauVetoes;
class Lau2DAbsDP;
-class LauEffModel {
+class LauEffModel : public LauAbsEffModel {
public:
//! Constructor
/*!
\param [in] daughters the daughters particles of the Dalitz plot model
\param [in] vetoes the object describing the vetoes applied in the phase space
*/
LauEffModel(const LauDaughters* daughters, const LauVetoes* vetoes);
//! Destructor
virtual ~LauEffModel();
//! Set the efficiency variation across the phase space using a predetermined 2D histogram.
/*!
The efficiency is defined in terms of x = m_13^2, y = m_23^2 or x = m', y = theta' for the square Dalitz plot
\param [in] effHisto the 2-dimensional histogram that describes the efficiency variation
\param [in] useInterpolation boolean flag decision to switch on/off linear interpolation between bins should be used or simply the raw bin values.
\param [in] fluctuateBins boolean flag to determine whether the bin contents should be fluctuated in accordance with their errors.
The seed for the random number generator used to fluctuate the bins should first be set using LauRandom::setSeed.
\param [in] avEff the desired average efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour.
The seed for the random number generator used to raise or lower the bins should first be set using LauRandom::setSeed.
\param [in] absError the error on that efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour
\param [in] useUpperHalfOnly boolean flag to determine whether, in the case of a symmetric DP, the histogram supplied only includes the upper half of the DP.
\param [in] squareDP boolean flag to determine whether the supplied histogram is given in square DP coordinates
*/
void setEffHisto(const TH2* effHisto,
Bool_t useInterpolation = kTRUE, Bool_t fluctuateBins = kFALSE,
Double_t avEff = -1.0, Double_t absError = -1.0,
Bool_t useUpperHalfOnly = kFALSE, Bool_t squareDP = kFALSE);
//! Set the efficiency variation across the phase space using a predetermined 2D histogram.
/*!
The efficiency is defined in terms of x = m_13^2, y = m_23^2 or x = m', y = theta' for the square Dalitz plot
\param [in] effHisto the 2-dimensional histogram that describes the efficiency variation
\param [in] errorHi the 2-dimensional histogram that describes the upper uncertainty on the efficiency variation
\param [in] errorLo the 2-dimensional histogram that describes the lower uncertainty on the efficiency variation
\param [in] useInterpolation boolean flag decision to switch on/off linear interpolation between bins should be used or simply the raw bin values.
\param [in] fluctuateBins boolean flag to determine whether the bin contents should be fluctuated in accordance with their errors.
The seed for the random number generator used to fluctuate the bins should first be set using LauRandom::setSeed.
\param [in] avEff the desired average efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour.
The seed for the random number generator used to raise or lower the bins should first be set using LauRandom::setSeed.
\param [in] absError the error on that efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour
\param [in] useUpperHalfOnly boolean flag to determine whether, in the case of a symmetric DP, the histogram supplied only includes the upper half of the DP.
\param [in] squareDP boolean flag to determine whether the supplied histogram is given in square DP coordinates
*/
void setEffHisto(const TH2* effHisto, const TH2* errorHi, const TH2* errorLo,
Bool_t useInterpolation = kTRUE, Bool_t fluctuateBins = kFALSE,
Double_t avEff = -1.0, Double_t absError = -1.0,
Bool_t useUpperHalfOnly = kFALSE, Bool_t squareDP = kFALSE);
//! Set the efficiency variation across the phase space using a spline based on a predetermined 2D histogram.
/*!
The efficiency is defined in terms of x = m_13^2, y = m_23^2 or x = m', y = theta' for the square Dalitz plot
\param [in] effHisto the 2-dimensional histogram that describes the efficiency variation
\param [in] fluctuateBins boolean flag to determine whether the bin contents should be fluctuated in accordance with their errors.
The seed for the random number generator used to fluctuate the bins should first be set using LauRandom::setSeed.
\param [in] avEff the desired average efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour.
The seed for the random number generator used to raise or lower the bins should first be set using LauRandom::setSeed.
\param [in] absError the error on that efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour
\param [in] useUpperHalfOnly boolean flag to determine whether, in the case of a symmetric DP, the histogram supplied only includes the upper half of the DP.
\param [in] squareDP boolean flag to determine whether the supplied histogram is given in square DP coordinates
*/
void setEffSpline(const TH2* effHisto,
Bool_t fluctuateBins = kFALSE,
Double_t avEff = -1.0, Double_t absError = -1.0,
Bool_t useUpperHalfOnly = kFALSE, Bool_t squareDP = kFALSE);
//! Set the efficiency variation across the phase space using a spline based on a predetermined 2D histogram.
/*!
The efficiency is defined in terms of x = m_13^2, y = m_23^2 or x = m', y = theta' for the square Dalitz plot
\param [in] effHisto the 2-dimensional histogram that describes the efficiency variation
\param [in] errorHi the 2-dimensional histogram that describes the upper uncertainty on the efficiency variation
\param [in] errorLo the 2-dimensional histogram that describes the lower uncertainty on the efficiency variation
\param [in] fluctuateBins boolean flag to determine whether the bin contents should be fluctuated in accordance with their errors.
The seed for the random number generator used to fluctuate the bins should first be set using LauRandom::setSeed.
\param [in] avEff the desired average efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour.
The seed for the random number generator used to raise or lower the bins should first be set using LauRandom::setSeed.
\param [in] absError the error on that efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour
\param [in] useUpperHalfOnly boolean flag to determine whether, in the case of a symmetric DP, the histogram supplied only includes the upper half of the DP.
\param [in] squareDP boolean flag to determine whether the supplied histogram is given in square DP coordinates
*/
void setEffSpline(const TH2* effHisto, const TH2* errorHi, const TH2* errorLo,
Bool_t fluctuateBins = kFALSE,
Double_t avEff = -1.0, Double_t absError = -1.0,
Bool_t useUpperHalfOnly = kFALSE, Bool_t squareDP = kFALSE);
//! Add a multiplicative efficiency variation across the phase space using a predetermined 2D histogram.
/*!
The efficiency is defined in terms of x = m_13^2, y = m_23^2 or x = m', y = theta' for the square Dalitz plot
\param [in] effHisto the 2-dimensional histogram that describes the efficiency variation
\param [in] useInterpolation boolean flag decision to switch on/off linear interpolation between bins should be used or simply the raw bin values.
\param [in] avEff the desired average efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour.
The seed for the random number generator used to raise or lower the bins should first be set using LauRandom::setSeed.
\param [in] absError the error on that efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour
\param [in] useUpperHalfOnly boolean flag to determine whether, in the case of a symmetric DP, the histogram supplied only includes the upper half of the DP.
\param [in] squareDP boolean flag to determine whether the supplied histogram is given in square DP coordinates
*/
void addEffHisto(const TH2* effHisto,
Bool_t useInterpolation = kTRUE,
Double_t avEff = -1.0, Double_t absError = -1.0,
Bool_t useUpperHalfOnly = kFALSE, Bool_t squareDP = kFALSE);
//! Add a multiplicative efficiency variation across the phase space using a predetermined 2D histogram.
/*!
The efficiency is defined in terms of x = m_13^2, y = m_23^2 or x = m', y = theta' for the square Dalitz plot
\param [in] effHisto the 2-dimensional histogram that describes the efficiency variation
\param [in] errorHi the 2-dimensional histogram that describes the upper uncertainty on the efficiency variation
\param [in] errorLo the 2-dimensional histogram that describes the lower uncertainty on the efficiency variation
\param [in] useInterpolation boolean flag decision to switch on/off linear interpolation between bins should be used or simply the raw bin values.
\param [in] avEff the desired average efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour.
The seed for the random number generator used to raise or lower the bins should first be set using LauRandom::setSeed.
\param [in] absError the error on that efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour
\param [in] useUpperHalfOnly boolean flag to determine whether, in the case of a symmetric DP, the histogram supplied only includes the upper half of the DP.
\param [in] squareDP boolean flag to determine whether the supplied histogram is given in square DP coordinates
*/
void addEffHisto(const TH2* effHisto, const TH2* errorHi, const TH2* errorLo,
Bool_t useInterpolation = kTRUE,
Double_t avEff = -1.0, Double_t absError = -1.0,
Bool_t useUpperHalfOnly = kFALSE, Bool_t squareDP = kFALSE);
//! Add a multiplicative efficiency variation across the phase space using a spline based on a predetermined 2D histogram.
/*!
The efficiency is defined in terms of x = m_13^2, y = m_23^2 or x = m', y = theta' for the square Dalitz plot
\param [in] effHisto the 2-dimensional histogram that describes the efficiency variation
\param [in] avEff the desired average efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour.
The seed for the random number generator used to raise or lower the bins should first be set using LauRandom::setSeed.
\param [in] absError the error on that efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour
\param [in] useUpperHalfOnly boolean flag to determine whether, in the case of a symmetric DP, the histogram supplied only includes the upper half of the DP.
\param [in] squareDP boolean flag to determine whether the supplied histogram is given in square DP coordinates
*/
void addEffSpline(const TH2* effHisto,
Double_t avEff = -1.0, Double_t absError = -1.0,
Bool_t useUpperHalfOnly = kFALSE, Bool_t squareDP = kFALSE);
//! Add a multiplicative efficiency variation across the phase space using a spline based on a predetermined 2D histogram.
/*!
The efficiency is defined in terms of x = m_13^2, y = m_23^2 or x = m', y = theta' for the square Dalitz plot
\param [in] effHisto the 2-dimensional histogram that describes the efficiency variation
\param [in] errorHi the 2-dimensional histogram that describes the upper uncertainty on the efficiency variation
\param [in] errorLo the 2-dimensional histogram that describes the lower uncertainty on the efficiency variation
\param [in] avEff the desired average efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour.
The seed for the random number generator used to raise or lower the bins should first be set using LauRandom::setSeed.
\param [in] absError the error on that efficiency - see Lau2DHistDP::raiseOrLowerBins, values less than zero switch off this behaviour
\param [in] useUpperHalfOnly boolean flag to determine whether, in the case of a symmetric DP, the histogram supplied only includes the upper half of the DP.
\param [in] squareDP boolean flag to determine whether the supplied histogram is given in square DP coordinates
*/
void addEffSpline(const TH2* effHisto, const TH2* errorHi, const TH2* errorLo,
Double_t avEff = -1.0, Double_t absError = -1.0,
Bool_t useUpperHalfOnly = kFALSE, Bool_t squareDP = kFALSE);
//! Determine the efficiency for a given point in the Dalitz plot.
/*!
The method uses the 2D histogram set by the setEffHisto() function and the vetoes information.
\param [in] kinematics the object that defines the DP position
\return the efficiency value at the given point in the DP
*/
Double_t calcEfficiency( const LauKinematics* kinematics ) const;
//! Determine whether the given DP position is outside the vetoes
/*!
\param [in] kinematics the object that defines the DP position
\return kTRUE if the DP position is outside all veto regions, kFALSE otherwise
*/
Bool_t passVeto( const LauKinematics* kinematics ) const;
//! Determine whether the efficiency histogram has had its bins fluctuated within their errors
Bool_t fluctuateEffHisto() const {return fluctuateEffHisto_;}
+ //! Return the daughters object
+ /*
+ \return the LauDaughters object associated with the DP
+ */
+ const LauDaughters* getDaughters() const {return daughters_;}
+
+ //! Determine whether the efficiency histogram is in the square DP
+ /*
+ \return kTRUE if the square DP is being used, kFALSE otherwise
+ */
+ Bool_t usingSquareDP() const {return squareDP_;}
+
private:
//! Copy constructor - not implemented
LauEffModel( const LauEffModel& rhs );
//! Get the efficiency from a two-dimensional histogram by interpolating in x and y
/*!
\param [in] xVal the value to be interpolated in x
\param [in] yVal the value to be interpolated in y
*/
Double_t getEffHistValue(Double_t xVal, Double_t yVal) const;
//! The daughters object
const LauDaughters* daughters_;
//! The vetoes object
const LauVetoes* vetoes_;
//! The efficiency histogram objects
std::vector<Lau2DAbsDP*> effHisto_;
//! Use of the square Dalitz plot
Bool_t squareDP_;
//! Fluctuate histogram within the error
Bool_t fluctuateEffHisto_;
//! Flag to track whether a warning has been issued for bin values less than zero
mutable Bool_t lowBinWarningIssued_;
//! Flag to track whether a warning has been issued for bin values greater than one
mutable Bool_t highBinWarningIssued_;
ClassDef(LauEffModel, 0) // Implement the signal efficiency across the DP
};
#endif
diff --git a/inc/LauIsobarDynamics.hh b/inc/LauIsobarDynamics.hh
index ccb3926..bc80426 100644
--- a/inc/LauIsobarDynamics.hh
+++ b/inc/LauIsobarDynamics.hh
@@ -1,763 +1,763 @@
// Copyright University of Warwick 2005 - 2013.
// 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 <vector>
#include "TString.h"
#include "LauAbsDPDynamics.hh"
#include "LauAbsResonance.hh"
#include "LauComplex.hh"
class LauDaughters;
-class LauEffModel;
+class LauAbsEffModel;
class LauFitDataTree;
class LauKMatrixPropagator;
class LauIsobarDynamics : public LauAbsDPDynamics {
public:
//! 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, LauEffModel* effModel, LauEffModel* scfFractionModel = 0);
+ 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, LauEffModel* effModel, LauTagCatScfFractionModelMap scfFractionModel);
+ LauIsobarDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, LauTagCatScfFractionModelMap scfFractionModel);
//! Destructor
virtual ~LauIsobarDynamics();
//! Initialise the Dalitz plot dynamics
/*!
\param [in] coeffs the complex coefficients for the resonances
*/
virtual void initialise(const std::vector<LauComplex>& coeffs);
//! 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
/*!
\param [in] m13BinWidth the bin width to use when integrating over m13
\param [in] m23BinWidth the bin width to use when integrating over m23
*/
virtual void setIntegralBinWidths(Double_t m13BinWidth, Double_t m23BinWidth);
//! Add a resonance to the Dalitz plot
/*!
\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 type of the resonance. Allowed types are: flatte, relbw, dabba, kappa, sigma, lass-bw, lass-nr, lass, gs, nrmodel, bellesymnr and bellenr
\param [in] newMass set a custom mass for the resonance
\param [in] newWidth set a custom width for the resonance
\param [in] newSpin set a custom spin for the resonance
*/
virtual void addResonance(const TString& resName, Int_t resPairAmpInt, const TString& resType,
Double_t newMass = -1.0, Double_t newWidth = -1.0, Int_t newSpin = -1);
//! 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.
*/
virtual 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
/*!
\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
*/
virtual void addKMatrixProdPole(const TString& poleName, const TString& propName, Int_t poleIndex);
//! Add a K-matrix slowly-varying part (SVP) term to the model
/*!
\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
*/
virtual void addKMatrixProdSVP(const TString& SVPName, const TString& propName, Int_t channelIndex);
//! Change the properties of a resonance particle within this model
/*!
Note that parameters set to -1 are ignored.
\param [in] resName the name of the resonance to modify
\param [in] newMass the new mass for this resonance
\param [in] newWidth the new width for this resonance
\param [in] newSpin the new spin for this resonance
*/
virtual void changeResonance(const TString& resName, Double_t newMass = -1.0, Double_t newWidth = -1.0, Int_t newSpin = -1);
//! Generate a toy MC signal event
/*!
\return kTRUE if the event is successfully generated, kFALSE otherwise
*/
virtual 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
*/
virtual 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
*/
virtual void calcLikelihoodInfo(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
*/
virtual void calcLikelihoodInfo(Double_t m13Sq, 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
*/
virtual void calcLikelihoodInfo(Double_t m13Sq, Double_t m23Sq, Int_t tagCat);
//! Retrieve the total amplitude for the current event
/*!
\return the total amplitude
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual Double_t getEvtthPrime() const {return thPrime_;}
//! Retrieve the efficiency for the current event
/*!
\return the efficiency for the current event
*/
virtual 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
*/
virtual 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
*/
virtual Double_t getEvtJacobian() const {return jacobian_;}
//! Retrieve the likelihood for the current event
/*!
evtLike_ = totAmp_.abs2()*eff_/DPNorm_
\return the likelihood for the current event
*/
virtual Double_t getEvtLikelihood() const {return evtLike_;}
//! 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
*/
virtual void calcExtraInfo(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
*/
virtual 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
*/
virtual Double_t getEventWeight();
//! 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_; }
//! 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 amplitude component within the model
\return the amplitude of the given amplitude component
*/
virtual LauComplex getDynamicAmp(Int_t resID) const {return ff_[resID].scale(fNorm_[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
*/
virtual void fillDataTree(const LauFitDataTree& fitDataTree);
//! Load the data for a given event
/*!
\param [in] iEvt the number of the event
*/
virtual void setDataEventNo(UInt_t iEvt);
//! Set the alpha parameter for new Belle non-resonant components
/*!
\param [in] alpha the alpha parameter value
*/
inline void setBelleNRAlpha(Double_t alpha) {BelleNRAlpha_ = alpha;}
//! Retreive the alpha parameter for new Belle non-resonant components
/*!
\return the alpha parameter
*/
inline Double_t getBelleNRAlpha() const {return BelleNRAlpha_;}
//! Set the parameters for new LASS components
/*!
\param [in] a the scattering length
\param [in] r the effective range
\param [in] R the resonance magnitude
\param [in] phiR the resonance phase
\param [in] B the background magnitude
\param [in] phiB the background phase
\param [in] cutOff the cutoff value
*/
inline void setLASSParameters(Double_t a, Double_t r, Double_t R = 1.0, Double_t phiR = 0.0, Double_t B = 1.0, Double_t phiB = 0.0, Double_t cutOff = 1.8)
{
this->setLASSScatteringLength(a);
this->setLASSEffectiveRange(r);
this->setLASSResonanceMag(R);
this->setLASSResonancePhase(phiR);
this->setLASSBackgroundMag(B);
this->setLASSBackgroundPhase(phiB);
this->setLASSCutOff(cutOff);
}
//! Set the scattering length for new LASS components
/*!
\param [in] a the scattering length
*/
inline void setLASSScatteringLength(Double_t a) {LASSScatteringLength_ = a; changeLASSScatteringLength_ = kTRUE;}
//! Set the effective range for new LASS components
/*!
\param [in] r the effective range
*/
inline void setLASSEffectiveRange(Double_t r) {LASSEffectiveRange_ = r; changeLASSEffectiveRange_ = kTRUE;}
//! Set the resonance magnitude for new LASS components
/*!
\param [in] R the resonance magnitude
*/
inline void setLASSResonanceMag(Double_t R) {LASSResonanceMag_ = R; changeLASSResonanceMag_ = kTRUE;}
//! Set the resonance phase for new LASS components
/*!
\param [in] phiR the resonance phase
*/
inline void setLASSResonancePhase(Double_t phiR) {LASSResonancePhase_ = phiR; changeLASSResonancePhase_ = kTRUE;}
//! Set the background magnitude for new LASS components
/*!
\param [in] B the background magnitude
*/
inline void setLASSBackgroundMag(Double_t B) {LASSBackgroundMag_ = B; changeLASSBackgroundMag_ = kTRUE;}
//! Set the background phase for new LASS components
/*!
\param [in] phiB the background phase
*/
inline void setLASSBackgroundPhase(Double_t phiB) {LASSBackgroundPhase_ = phiB; changeLASSBackgroundPhase_ = kTRUE;}
//! Set the cutoff value for new LASS components
/*!
\param [in] cutOff the cutoff value
*/
inline void setLASSCutOff(Double_t cutOff) {LASSCutOff_ = cutOff; changeLASSCutOff_ = kTRUE;}
//! Retrieve the scattering length for new LASS components
/*!
\return the scattering length
*/
inline Double_t getLASSScatteringLength() const {return LASSScatteringLength_;}
//! Retrieve the effective range for new LASS components
/*!
\return the effective range
*/
inline Double_t getLASSEffectiveRange() const {return LASSEffectiveRange_;}
//! Retrieve the resonance magnitude for new LASS components
/*!
\return the resonance magnitude
*/
inline Double_t getLASSResonanceMag() const {return LASSResonanceMag_;}
//! Retrieve the resonance phase for new LASS components
/*!
\return the resonance phase
*/
inline Double_t getLASSResonancePhase() const {return LASSResonancePhase_;}
//! Retrieve the background magnitude for new LASS components
/*!
\return the background magnitude
*/
inline Double_t getLASSBackgroundMag() const {return LASSBackgroundMag_;}
//! Retrieve the background phase for new LASS components
/*!
\return the background phase
*/
inline Double_t getLASSBackgroundPhase() const {return LASSBackgroundPhase_;}
//! Retrieve the cutoff value for new LASS components
/*!
\return the cutoff value
*/
inline Double_t getLASSCutOff() const {return LASSCutOff_;}
//! Set the parameters for new Flatte components
/*!
\param [in] g1 the coupling constant for channel 1
\param [in] g2 the coupling constant for channel 2
*/
inline void setFlatteParameters(Double_t g1, Double_t g2) {this->setFlatteg1(g1); this->setFlatteg2(g2);}
//! Set the g1 parameter for new Flatte components
/*!
\param [in] g1 the coupling constant for channel 1
*/
inline void setFlatteg1(Double_t g1) {FlatteParameterg1_ = g1; changeFlatteParameterg1_ = kTRUE;}
//! Set the g2 parameter for new Flatte components
/*!
\param [in] g2 the coupling constant for channel 2
*/
inline void setFlatteg2(Double_t g2) {FlatteParameterg2_ = g2; changeFlatteParameterg2_ = kTRUE;}
//! Retrieve the g1 parameter for new Flatte components
/*!
\return the constant parameter g1
*/
inline Double_t getFlatteg1() const {return FlatteParameterg1_;}
//! Retrieve the g2 parameter for new Flatte components
/*!
\return the constant parameter g2
*/
inline Double_t getFlatteg2() const {return FlatteParameterg2_;}
//! Set the parameters for the barrier factors for new resonances
/*!
\param [in] resRadius the radius due to the resonance
\param [in] parRadius the radius due to the parent
\param [in] type the type of the barrier factor
*/
inline void setBarrierRadii( Double_t resRadius, Double_t parRadius = 4.0,
LauAbsResonance::BarrierType type = LauAbsResonance::BWPrimeBarrier )
{
this->setResBarrierRadius(resRadius);
this->setParBarrierRadius(parRadius);
this->setBarrierType(type);
}
//! Set the radius of the barrier factor due to the resonance to use for new amplitude components
/*!
\param [in] radius the barrier radius
*/
inline void setResBarrierRadius(Double_t radius) {resBarrierRadius_ = radius;}
//! Set the radius of the barrier factor due to the parent to use for new amplitude components
/*!
\param [in] radius the barrier radius
*/
inline void setParBarrierRadius(Double_t radius) {parBarrierRadius_ = radius;}
//! Set the type of barrier factor to use for new amplitude components
/*!
\param [in] type the type of barrier factor. Allowed types are: BWBarrier, BWPrimeBarrier and ExpBarrier.
*/
inline void setBarrierType( LauAbsResonance::BarrierType type ) {barrierType_ = type;}
//! Retrieve the radius of the barrier factor due to the resonance to use for new amplitude components
/*!
\return the barrier radius
*/
inline Double_t getResBarrierRadius() const {return resBarrierRadius_;}
//! Retrieve the radius of the barrier factor due to the parent to use for new amplitude components
/*!
\return the barrier radius
*/
inline Double_t getParBarrierRadius() const {return parBarrierRadius_;}
//! Set the helicity flip flag for new amplitude components
/*!
\param [in] boolean the helicity flip flag
*/
inline void flipHelicityForCPEigenstates(Bool_t boolean) {flipHelicity_ = boolean;}
protected:
//! Print a summary of the model to be used
virtual void initSummary();
//! Initialise the internal storage for this model
virtual void initialiseVectors();
//! Calculate the Dalitz plot normalisation integrals across the whole Dalitz plot
virtual void calcDPNormalisation();
//! Calculate the Dalitz plot normalisation integrals over a given range
/*!
\param [in] minm13 the minimum value of m13 in the integration range
\param [in] maxm13 the maximum value of m13 in the integration range
\param [in] minm23 the minimum value of m23 in the integration range
\param [in] maxm23 the maximum value of m23 in the integration range
\param [in] m13BinWidth the bin width in m13
\param [in] m23BinWidth the bin width in m23
*/
virtual void calcDPPartialIntegral(Double_t minm13, Double_t maxm13, Double_t minm23,
Double_t maxm23, Double_t m13BinWidth, Double_t m23BinWidth);
//! Write the results of the integrals (and related information) to a file
virtual 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
*/
virtual void setFFTerm(UInt_t index, Double_t realPart, Double_t imagPart);
//! Calculate the total Dalitz plot amplitude at the current point in the Dalitz plot
/*!
\param [in] cacheResData whether the amplitudes have already been cached
\param [in] weight the weight to apply (used when calculating the integrals)
\param [in] useEff whether to apply efficiency corrections
*/
virtual void dynamics(Bool_t cacheResData = kTRUE, Double_t weight = 1.0, Bool_t useEff = kTRUE);
//! 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
*/
virtual 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
*/
virtual LauComplex resAmp(Int_t index);
//! Retrieve the named resonance
/*!
\param [in] name the name of the resonance to retrieve
\return the named resonance
*/
virtual LauAbsResonance* findResonance(const TString& name);
//! Retrieve the named resonance
/*!
\param [in] name the name of the resonance to retrieve
\return the named resonance
*/
virtual const LauAbsResonance* findResonance(const TString& name) const;
//! Remove the charge from the given particle name
/*!
\param [in,out] string the particle name
*/
virtual 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:
//! 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 resonances in the model
std::vector<LauAbsResonance*> sigResonances_;
//! 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 within the resonance maker for each amplitude component
std::vector<Int_t> resIntAmp_;
//! The index of the daughter not produced by the resonance for each amplitude component
std::vector<Int_t> resPairAmp_;
//! The PDG codes of the daughters
std::vector<Int_t> typDaug_;
//! Whether the Dalitz plot is symmetrical
Bool_t symmetricalDP_;
//! Whether the integrals have been performed
Bool_t integralsDone_;
//! 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 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 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 event-by-event running total of the dynamical amplitude squared for each amplitude component
std::vector<Double_t> fSqSum_;
//! 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 alpha parameter for new Belle non-resonant components
Double_t BelleNRAlpha_;
//! The scattering length for new LASS components
Double_t LASSScatteringLength_;
//! The effective range for new LASS components
Double_t LASSEffectiveRange_;
//! The resonance magnitude for new LASS components
Double_t LASSResonanceMag_;
//! The resonance phase for new LASS components
Double_t LASSResonancePhase_;
//! The background magnitude for new LASS components
Double_t LASSBackgroundMag_;
//! The background phase for new LASS components
Double_t LASSBackgroundPhase_;
//! The cutoff value for new LASS components
Double_t LASSCutOff_;
//! Whether the default value of the LASS scattering length has been changed
Bool_t changeLASSScatteringLength_;
//! Whether the default value of the LASS effective range has been changed
Bool_t changeLASSEffectiveRange_;
//! Whether the default value of the LASS resonance magnitude has been changed
Bool_t changeLASSResonanceMag_;
//! Whether the default value of the LASS resonance phase has been changed
Bool_t changeLASSResonancePhase_;
//! Whether the default value of the LASS background magnitude has been changed
Bool_t changeLASSBackgroundMag_;
//! Whether the default value of the LASS background phase has been changed
Bool_t changeLASSBackgroundPhase_;
//! Whether the default value of the LASS cutoff has been changed
Bool_t changeLASSCutOff_;
//! The constant parameter g1 for new Flatte components
Double_t FlatteParameterg1_;
//! The constant parameter g2 for new Flatte components
Double_t FlatteParameterg2_;
//! Whether the default value of the Flatte parameter g1 has been changed
Bool_t changeFlatteParameterg1_;
//! Whether the default value of the Flatte parameter g2 has been changed
Bool_t changeFlatteParameterg2_;
//! The radius of the resonance barrier factor for new amplitude components
Double_t resBarrierRadius_;
//! The radius of the parent barrier factor for new amplitude components
Double_t parBarrierRadius_;
//! The type of the barrier factor for new amplitude components
LauAbsResonance::BarrierType barrierType_;
//! The helicity flip flag for new amplitude components
Bool_t flipHelicity_;
ClassDef(LauIsobarDynamics,0)
};
#endif
diff --git a/inc/LauWeightedSumEffModel.hh b/inc/LauWeightedSumEffModel.hh
new file mode 100644
index 0000000..afec700
--- /dev/null
+++ b/inc/LauWeightedSumEffModel.hh
@@ -0,0 +1,114 @@
+
+// Copyright University of Warwick 2004 - 2013.
+// 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 LauWeightedSumEffModel.hh
+ \brief File containing declaration of LauWeightedSumEffModel class.
+*/
+
+/*! \class LauWeightedSumEffModel
+ \brief Class that implements the efficiency description across the signal Dalitz plot.
+
+ Class that defines the efficiency model variation across the signal Dalitz plot.
+ The phase space acceptance is determined from a weighted sum of LauAbsEffModel objects.
+ This is useful for samples that contain two different categories of signal with different efficiencies.
+ The efficiency variation is defined in terms of x = m_13^2, y = m_23^2 for the Dalitz plot (default)
+ or x = m', y = theta' for the square Dalitz plot
+*/
+
+#ifndef LAUWEIGHTEDSUMEFFMODEL
+#define LAUWEIGHTEDSUMEFFMODEL
+
+#include "LauAbsEffModel.hh"
+
+class LauDaughters;
+class LauKinematics;
+
+
+class LauWeightedSumEffModel : public LauAbsEffModel {
+
+ public:
+ //! Constructor
+ /*!
+ \param [in] daughters the daughters particles of the Dalitz plot model
+ */
+ LauWeightedSumEffModel(const LauDaughters* daughters);
+
+ //! Destructor
+ virtual ~LauWeightedSumEffModel() {}
+
+ //! Add an efficiency variation across the phase space using a predetermined LauAbsEffModel object.
+ /*!
+ The efficiency is defined in terms of x = m_13^2, y = m_23^2 or x = m', y = theta' for the square Dalitz plot
+
+ \param [in] effModel the LauAbsEffModel object that describes the efficiency variation
+ \param [in] coeff the coefficient to multiply this efficiency by
+ */
+ void addEffModel(const LauAbsEffModel* effModel, Double_t coeff);
+
+ //! Determine the efficiency for a given point in the Dalitz plot.
+ /*!
+ The method uses the models set by the addEffModel() function and the vetoes information.
+
+ \param [in] kinematics the object that defines the DP position
+ \return the efficiency value at the given point in the DP
+ */
+ Double_t calcEfficiency( const LauKinematics* kinematics ) const;
+
+ //! Determine whether the given DP position is outside the vetoes
+ /*!
+ \param [in] kinematics the object that defines the DP position
+ \return kTRUE if the DP position is outside all veto regions, kFALSE otherwise
+ */
+ Bool_t passVeto( const LauKinematics* kinematics ) const;
+
+ //! Determine whether the efficiency histogram has had its bins fluctuated within their errors
+ Bool_t fluctuateEffHisto() const {return fluctuateEffHisto_;}
+
+ //! Return the daughters object
+ /*
+ \return the LauDaughters object associated with the DP
+ */
+ const LauDaughters* getDaughters() const {return daughters_;}
+
+ //! Determine whether the efficiency histogram is in the square DP
+ /*
+ \return kTRUE if the square DP is being used, kFALSE otherwise
+ */
+ Bool_t usingSquareDP() const {return squareDP_;}
+
+ private:
+ //! Copy constructor - not implemented
+ LauWeightedSumEffModel( const LauWeightedSumEffModel& rhs );
+
+ //! The daughters object
+ const LauDaughters* daughters_;
+
+ //! The efficiency model objects
+ std::vector<const LauAbsEffModel*> effModel_;
+
+ //! The efficiency model objects
+ std::vector<Double_t> coeff_;
+
+ //! Use of the square Dalitz plot
+ Bool_t squareDP_;
+ //! Fluctuate histogram within the error
+ Bool_t fluctuateEffHisto_;
+
+ //! Flag to track whether a warning has been issued for bin values less than zero
+ mutable Bool_t lowBinWarningIssued_;
+
+ //! Flag to track whether a warning has been issued for bin values greater than one
+ mutable Bool_t highBinWarningIssued_;
+
+ ClassDef(LauWeightedSumEffModel, 0) // Implement the signal efficiency across the DP
+
+};
+
+#endif
diff --git a/inc/Laura++_LinkDef.h b/inc/Laura++_LinkDef.h
index 1084c37..92ff867 100644
--- a/inc/Laura++_LinkDef.h
+++ b/inc/Laura++_LinkDef.h
@@ -1,104 +1,106 @@
#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ class Lau1DHistPdf;
#pragma link C++ class Lau2DAbsDP;
#pragma link C++ class Lau2DAbsDPPdf;
#pragma link C++ class Lau2DAbsHistDP;
#pragma link C++ class Lau2DAbsHistDPPdf;
#pragma link C++ class Lau2DCubicSpline;
#pragma link C++ class Lau2DHistDP;
#pragma link C++ class Lau2DHistDPPdf;
#pragma link C++ class Lau2DHistPdf;
#pragma link C++ class Lau2DSplineDP;
#pragma link C++ class Lau2DSplineDPPdf;
#pragma link C++ class LauAbsBkgndDPModel;
#pragma link C++ class LauAbsCoeffSet;
#pragma link C++ class LauAbsDPDynamics;
+#pragma link C++ class LauAbsEffModel;
#pragma link C++ class LauAbsFitter;
#pragma link C++ class LauAbsFitModel;
#pragma link C++ class LauAbsPdf;
#pragma link C++ class LauAbsResonance;
#pragma link C++ class LauAbsRValue;
#pragma link C++ class LauArgusPdf;
#pragma link C++ class LauAsymmCalc;
#pragma link C++ class LauBelleCPCoeffSet;
#pragma link C++ class LauBelleNR;
#pragma link C++ class LauBelleSymNR;
#pragma link C++ class LauBifurcatedGaussPdf;
#pragma link C++ class LauBkgndDPModel;
#pragma link C++ class LauBreitWignerRes;
#pragma link C++ class LauCacheData;
#pragma link C++ class LauCartesianCPCoeffSet;
#pragma link C++ class LauChebychevPdf;
#pragma link C++ class LauCleoCPCoeffSet;
#pragma link C++ class LauComplex;
#pragma link C++ class LauCPFitModel;
#pragma link C++ class LauCruijffPdf;
#pragma link C++ class LauCrystalBallPdf;
#pragma link C++ class LauDabbaRes;
#pragma link C++ class LauDatabasePDG;
#pragma link C++ class LauDaughters;
#pragma link C++ class LauDPDepBifurGaussPdf;
#pragma link C++ class LauDPDepCruijffPdf;
#pragma link C++ class LauDPDepGaussPdf;
#pragma link C++ class LauDPDepMapPdf;
#pragma link C++ class LauDPDepSumPdf;
#pragma link C++ class LauEffModel;
#pragma link C++ class LauEmbeddedData;
#pragma link C++ class LauExponentialPdf;
#pragma link C++ class LauFitDataTree;
#pragma link C++ class LauFitNtuple;
#pragma link C++ class LauFitter;
#pragma link C++ class LauFitObject;
#pragma link C++ class LauFlatteRes;
#pragma link C++ class LauFlatNR;
#pragma link C++ class LauFormulaPar;
#pragma link C++ class LauGaussPdf;
#pragma link C++ class LauGenNtuple;
#pragma link C++ class LauGounarisSakuraiRes;
#pragma link C++ class LauIntegrals;
#pragma link C++ class LauIsobarDynamics;
#pragma link C++ class LauKappaRes;
#pragma link C++ class LauKinematics;
#pragma link C++ class LauKMatrixProdPole;
#pragma link C++ class LauKMatrixProdSVP;
#pragma link C++ class LauKMatrixPropagator;
#pragma link C++ class LauKMatrixPropFactory;
#pragma link C++ class LauLASSBWRes;
#pragma link C++ class LauLASSNRRes;
#pragma link C++ class LauLASSRes;
#pragma link C++ class LauLinearPdf;
#pragma link C++ class LauMagPhaseCoeffSet;
#pragma link C++ class LauMagPhaseCPCoeffSet;
#pragma link C++ class LauMinuit;
#pragma link C++ class LauNovosibirskPdf;
#pragma link C++ class LauNRAmplitude;
#pragma link C++ class LauParameter;
#pragma link C++ class LauParametricStepFuncPdf;
#pragma link C++ class LauParamFixed;
#pragma link C++ class LauParticlePDG;
#pragma link C++ class LauPolNR;
#pragma link C++ class LauPrint;
#pragma link C++ class LauRealImagCoeffSet;
#pragma link C++ class LauRealImagCPCoeffSet;
#pragma link C++ class LauRelBreitWignerRes;
#pragma link C++ class LauResonanceInfo;
#pragma link C++ class LauResonanceMaker;
#pragma link C++ class LauScfMap;
#pragma link C++ class LauSigmaRes;
#pragma link C++ class LauSigmoidPdf;
#pragma link C++ class LauSimpleFitModel;
#pragma link C++ class LauSimFitMaster;
#pragma link C++ class LauSPlot;
#pragma link C++ class LauString;
#pragma link C++ class LauSumPdf;
#pragma link C++ class LauTextFileParser;
#pragma link C++ class LauVetoes;
+#pragma link C++ class LauWeightedSumEffModel;
#pragma link C++ namespace LauConstants;
#pragma link C++ namespace LauRandom;
#endif
diff --git a/src/LauAbsDPDynamics.cc b/src/LauAbsDPDynamics.cc
index b11057f..3ec7c32 100644
--- a/src/LauAbsDPDynamics.cc
+++ b/src/LauAbsDPDynamics.cc
@@ -1,159 +1,159 @@
// Copyright University of Warwick 2005 - 2013.
// 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 LauAbsDPDynamics.cc
\brief File containing implementation of LauAbsDPDynamics class.
*/
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include "TSystem.h"
#include "LauAbsDPDynamics.hh"
#include "LauComplex.hh"
#include "LauDaughters.hh"
-#include "LauEffModel.hh"
+#include "LauAbsEffModel.hh"
#include "LauKinematics.hh"
#include "LauResonanceMaker.hh"
ClassImp(LauAbsDPDynamics)
-LauAbsDPDynamics::LauAbsDPDynamics(LauDaughters* daughters, LauEffModel* effModel, LauEffModel* scfFractionModel) :
+LauAbsDPDynamics::LauAbsDPDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, LauAbsEffModel* scfFractionModel) :
daughters_(daughters),
resonanceMaker_(new LauResonanceMaker(daughters)),
kinematics_(daughters_ ? daughters_->getKinematics() : 0),
effModel_(effModel),
nAmp_(0),
nResDefMax_(resonanceMaker_ ? resonanceMaker_->getNResDefMax() : 0),
DPNorm_(0.0),
DPRate_("DPRate", 0.0, 0.0, 1000.0),
meanDPEff_("meanDPEff", 0.0, 0.0, 1.0),
currentEvent_(0)
{
if (scfFractionModel != 0) {
scfFractionModel_[0] = scfFractionModel;
}
extraParameters_.clear();
}
-LauAbsDPDynamics::LauAbsDPDynamics(LauDaughters* daughters, LauEffModel* effModel, const LauTagCatScfFractionModelMap& scfFractionModel) :
+LauAbsDPDynamics::LauAbsDPDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, const LauTagCatScfFractionModelMap& scfFractionModel) :
daughters_(daughters),
resonanceMaker_(new LauResonanceMaker(daughters)),
kinematics_(daughters_ ? daughters_->getKinematics() : 0),
effModel_(effModel),
scfFractionModel_(scfFractionModel),
nAmp_(0),
nResDefMax_(resonanceMaker_ ? resonanceMaker_->getNResDefMax() : 0),
DPNorm_(0.0),
DPRate_("DPRate", 0.0, 0.0, 1000.0),
meanDPEff_("meanDPEff", 0.0, 0.0, 1.0),
currentEvent_(0)
{
extraParameters_.clear();
}
LauAbsDPDynamics::~LauAbsDPDynamics()
{
if (resonanceMaker_ != 0) {
delete resonanceMaker_; resonanceMaker_ = 0;
}
extraParameters_.clear();
for ( std::vector<LauCacheData*>::iterator iter = data_.begin(); iter != data_.end(); ++iter ) {
delete (*iter);
}
}
void LauAbsDPDynamics::setDataEventNo(UInt_t iEvt)
{
// Retrieve the data for event iEvt
if (data_.size() > iEvt) {
currentEvent_ = data_[iEvt];
} else {
cerr<<"ERROR in LauAbsDPDynamics::setDataEventNo : Event index too large: "<<iEvt<<" >= "<<data_.size()<<"."<<endl;
}
}
void LauAbsDPDynamics::updateCoeffs(const std::vector<LauComplex>& coeffs)
{
// Check that the number of coeffs is correct
if (coeffs.size() != this->getnAmp()) {
cerr << "ERROR in LauAbsDPDynamics::updateCoeffs : Expected " << this->getnAmp() << " but got " << coeffs.size() << endl;
gSystem->Exit(EXIT_FAILURE);
}
// Now check if the coeffs have changed
Bool_t changed = (Amp_ != coeffs);
if (changed) {
// Copy the coeffs
Amp_ = coeffs;
// Update the total normalisation for the signal likelihood
this->calcSigDPNorm();
}
}
Bool_t LauAbsDPDynamics::hasResonance(const TString& resName) const
{
const LauAbsResonance* theRes = this->findResonance(resName);
if (theRes != 0) {
return kTRUE;
} else {
return kFALSE;
}
}
TString LauAbsDPDynamics::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 LauAbsDPDynamics::retrieveEfficiency()
{
Double_t eff(1.0);
if (effModel_ != 0) {
eff = effModel_->calcEfficiency(kinematics_);
}
return eff;
}
Double_t LauAbsDPDynamics::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 LauEffModel, and the method
+ // 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;
}
diff --git a/src/LauCPFitModel.cc b/src/LauCPFitModel.cc
index 48e5e76..dac906c 100644
--- a/src/LauCPFitModel.cc
+++ b/src/LauCPFitModel.cc
@@ -1,2874 +1,2874 @@
// Copyright University of Warwick 2004 - 2013.
// 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 LauCPFitModel.cc
\brief File containing implementation of LauCPFitModel class.
*/
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include "TVirtualFitter.h"
#include "TSystem.h"
#include "TMinuit.h"
#include "TRandom.h"
#include "TFile.h"
#include "TMath.h"
#include "TH2.h"
#include "LauAbsBkgndDPModel.hh"
#include "LauAbsCoeffSet.hh"
#include "LauAbsDPDynamics.hh"
#include "LauAbsPdf.hh"
#include "LauAsymmCalc.hh"
#include "LauComplex.hh"
#include "LauConstants.hh"
#include "LauCPFitModel.hh"
#include "LauDaughters.hh"
#include "LauEffModel.hh"
#include "LauEmbeddedData.hh"
#include "LauFitNtuple.hh"
#include "LauKinematics.hh"
#include "LauPrint.hh"
#include "LauRandom.hh"
#include "LauScfMap.hh"
ClassImp(LauCPFitModel)
LauCPFitModel::LauCPFitModel(LauAbsDPDynamics* negModel, LauAbsDPDynamics* posModel, Bool_t tagged, const TString& tagVarName) : LauAbsFitModel(),
negSigModel_(negModel), posSigModel_(posModel),
negKinematics_(negModel ? negModel->getKinematics() : 0),
posKinematics_(posModel ? posModel->getKinematics() : 0),
usingBkgnd_(kFALSE),
nSigComp_(0),
nSigDPPar_(0),
nExtraPdfPar_(0),
nNormPar_(0),
negMeanEff_("negMeanEff",0.0,0.0,1.0), posMeanEff_("posMeanEff",0.0,0.0,1.0),
negDPRate_("negDPRate",0.0,0.0,100.0), posDPRate_("posDPRate",0.0,0.0,100.0),
signalEvents_(0),
signalAsym_(0),
forceAsym_(kFALSE),
tagged_(tagged),
tagVarName_(tagVarName),
curEvtCharge_(0),
useSCF_(kFALSE),
useSCFHist_(kFALSE),
scfFrac_("scfFrac",0.0,0.0,1.0),
scfFracHist_(0),
scfMap_(0),
compareFitData_(kFALSE),
negParent_("B-"), posParent_("B+"),
negSignalTree_(0), posSignalTree_(0),
reuseSignal_(kFALSE),
useNegReweighting_(kFALSE), usePosReweighting_(kFALSE),
sigDPLike_(0.0),
scfDPLike_(0.0),
sigExtraLike_(0.0),
scfExtraLike_(0.0),
sigTotalLike_(0.0),
scfTotalLike_(0.0)
{
LauDaughters* negDaug = negSigModel_->getDaughters();
if (negDaug != 0) {negParent_ = negDaug->getNameParent();}
LauDaughters* posDaug = posSigModel_->getDaughters();
if (posDaug != 0) {posParent_ = posDaug->getNameParent();}
}
LauCPFitModel::~LauCPFitModel()
{
delete negSignalTree_;
delete posSignalTree_;
for (LauBkgndEmbDataList::iterator iter = negBkgndTree_.begin(); iter != negBkgndTree_.end(); ++iter) {
delete (*iter);
}
for (LauBkgndEmbDataList::iterator iter = posBkgndTree_.begin(); iter != posBkgndTree_.end(); ++iter) {
delete (*iter);
}
delete scfFracHist_;
}
void LauCPFitModel::setupBkgndVectors()
{
UInt_t nBkgnds = this->nBkgndClasses();
negBkgndDPModels_.resize( nBkgnds );
posBkgndDPModels_.resize( nBkgnds );
negBkgndPdfs_.resize( nBkgnds );
posBkgndPdfs_.resize( nBkgnds );
bkgndEvents_.resize( nBkgnds );
bkgndAsym_.resize( nBkgnds );
negBkgndTree_.resize( nBkgnds );
posBkgndTree_.resize( nBkgnds );
reuseBkgnd_.resize( nBkgnds );
bkgndDPLike_.resize( nBkgnds );
bkgndExtraLike_.resize( nBkgnds );
bkgndTotalLike_.resize( nBkgnds );
}
void LauCPFitModel::setNSigEvents(LauParameter* nSigEvents)
{
if ( nSigEvents == 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNSigEvents : The LauParameter pointer is null." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if ( signalEvents_ != 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNSigEvents : You are trying to overwrite the signal yield." << std::endl;
return;
}
if ( signalAsym_ != 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNSigEvents : You are trying to overwrite the signal asymmetry." << std::endl;
return;
}
signalEvents_ = nSigEvents;
TString name = signalEvents_->name();
if ( ! name.Contains("signalEvents") && !( name.BeginsWith("signal") && name.EndsWith("Events") ) ) {
signalEvents_->name("signalEvents");
}
Double_t value = nSigEvents->value();
signalEvents_->range(-2.0*(TMath::Abs(value)+1.0), 2.0*(TMath::Abs(value)+1.0));
signalAsym_ = new LauParameter("signalAsym",0.0,-1.0,1.0,kTRUE);
}
void LauCPFitModel::setNSigEvents( LauParameter* nSigEvents, LauParameter* sigAsym, Bool_t forceAsym )
{
if ( nSigEvents == 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNSigEvents : The event LauParameter pointer is null." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if ( sigAsym == 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNSigEvents : The asym LauParameter pointer is null." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if ( signalEvents_ != 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNSigEvents : You are trying to overwrite the signal yield." << std::endl;
return;
}
if ( signalAsym_ != 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNSigEvents : You are trying to overwrite the signal asymmetry." << std::endl;
return;
}
signalEvents_ = nSigEvents;
signalEvents_->name("signalEvents");
Double_t value = nSigEvents->value();
signalEvents_->range(-2.0*(TMath::Abs(value)+1.0), 2.0*(TMath::Abs(value)+1.0));
signalAsym_ = sigAsym;
signalAsym_->name("signalAsym");
signalAsym_->range(-1.0,1.0);
forceAsym_ = forceAsym;
}
void LauCPFitModel::setNBkgndEvents( LauParameter* nBkgndEvents )
{
if ( nBkgndEvents == 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNBgkndEvents : The background yield LauParameter pointer is null." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if ( ! this->validBkgndClass( nBkgndEvents->name() ) ) {
std::cerr << "ERROR in LauCPFitModel::setNBkgndEvents : Invalid background class \"" << nBkgndEvents->name() << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
UInt_t bkgndID = this->bkgndClassID( nBkgndEvents->name() );
if ( bkgndEvents_[bkgndID] != 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNBkgndEvents : You are trying to overwrite the background yield." << std::endl;
return;
}
if ( bkgndAsym_[bkgndID] != 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNBkgndEvents : You are trying to overwrite the background asymmetry." << std::endl;
return;
}
bkgndEvents_[bkgndID] = nBkgndEvents;
bkgndEvents_[bkgndID]->name( nBkgndEvents->name()+"Events" );
Double_t value = nBkgndEvents->value();
bkgndEvents_[bkgndID]->range(-2.0*(TMath::Abs(value)+1.0), 2.0*(TMath::Abs(value)+1.0));
bkgndAsym_[bkgndID] = new LauParameter(nBkgndEvents->name()+"Asym",0.0,-1.0,1.0,kTRUE);
}
void LauCPFitModel::setNBkgndEvents(LauParameter* nBkgndEvents, LauParameter* bkgndAsym)
{
if ( nBkgndEvents == 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNBkgndEvents : The background yield LauParameter pointer is null." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if ( bkgndAsym == 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNBkgndEvents : The background asym LauParameter pointer is null." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if ( ! this->validBkgndClass( nBkgndEvents->name() ) ) {
std::cerr << "ERROR in LauCPFitModel::setNBkgndEvents : Invalid background class \"" << nBkgndEvents->name() << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
UInt_t bkgndID = this->bkgndClassID( nBkgndEvents->name() );
if ( bkgndEvents_[bkgndID] != 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNBkgndEvents : You are trying to overwrite the background yield." << std::endl;
return;
}
if ( bkgndAsym_[bkgndID] != 0 ) {
std::cerr << "ERROR in LauCPFitModel::setNBkgndEvents : You are trying to overwrite the background asymmetry." << std::endl;
return;
}
bkgndEvents_[bkgndID] = nBkgndEvents;
bkgndEvents_[bkgndID]->name( nBkgndEvents->name()+"Events" );
Double_t value = nBkgndEvents->value();
bkgndEvents_[bkgndID]->range(-2.0*(TMath::Abs(value)+1.0), 2.0*(TMath::Abs(value)+1.0));
bkgndAsym_[bkgndID] = bkgndAsym;
bkgndAsym_[bkgndID]->name( nBkgndEvents->name()+"Asym" );
bkgndAsym_[bkgndID]->range(-1.0,1.0);
}
void LauCPFitModel::splitSignalComponent( const TH2* dpHisto, Bool_t upperHalf, LauScfMap* scfMap )
{
if ( useSCF_ == kTRUE ) {
std::cerr << "ERROR in LauCPFitModel::splitSignalComponent : Have already setup SCF." << std::endl;
return;
}
if ( dpHisto == 0 ) {
std::cerr << "ERROR in LauCPFitModel::splitSignalComponent : The histogram pointer is null." << std::endl;
return;
}
LauDaughters* daughters = negSigModel_->getDaughters();
scfFracHist_ = new LauEffModel( daughters, 0 );
scfFracHist_->setEffHisto( dpHisto, kTRUE, kFALSE, 0.0, 0.0, upperHalf, daughters->squareDP() );
scfMap_ = scfMap;
useSCF_ = kTRUE;
useSCFHist_ = kTRUE;
}
void LauCPFitModel::splitSignalComponent( Double_t scfFrac, Bool_t fixed )
{
if ( useSCF_ == kTRUE ) {
std::cerr << "ERROR in LauCPFitModel::splitSignalComponent : Have already setup SCF." << std::endl;
return;
}
scfFrac_.range( 0.0, 1.0 );
scfFrac_.value( scfFrac ); scfFrac_.initValue( scfFrac ); scfFrac_.genValue( scfFrac );
scfFrac_.fixed( fixed );
useSCF_ = kTRUE;
useSCFHist_ = kFALSE;
}
void LauCPFitModel::setBkgndDPModels(const TString& bkgndClass, LauAbsBkgndDPModel* negModel, LauAbsBkgndDPModel* posModel)
{
if ((negModel==0) || (posModel==0)) {
std::cerr << "ERROR in LauCPFitModel::setBkgndDPModels : One or both of the model pointers is null." << std::endl;
return;
}
// check that this background name is valid
if ( ! this->validBkgndClass( bkgndClass) ) {
std::cerr << "ERROR in LauCPFitModel::setBkgndDPModel : Invalid background class \"" << bkgndClass << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
return;
}
UInt_t bkgndID = this->bkgndClassID( bkgndClass );
negBkgndDPModels_[bkgndID] = negModel;
posBkgndDPModels_[bkgndID] = posModel;
usingBkgnd_ = kTRUE;
}
void LauCPFitModel::setSignalPdfs(LauAbsPdf* negPdf, LauAbsPdf* posPdf)
{
if ( tagged_ ) {
if (negPdf==0 || posPdf==0) {
std::cerr << "ERROR in LauCPFitModel::setSignalPdfs : One or both of the PDF pointers is null." << std::endl;
return;
}
} else {
// if we're doing an untagged analysis we will only use the negative PDFs
if ( negPdf==0 ) {
std::cerr << "ERROR in LauCPFitModel::setSignalPdfs : The negative PDF pointer is null." << std::endl;
return;
}
if ( posPdf!=0 ) {
std::cerr << "WARNING in LauCPFitModel::setSignalPdfs : Doing an untagged fit so will not use the positive PDF." << std::endl;
}
}
negSignalPdfs_.push_back(negPdf);
posSignalPdfs_.push_back(posPdf);
}
void LauCPFitModel::setSCFPdfs(LauAbsPdf* negPdf, LauAbsPdf* posPdf)
{
if ( tagged_ ) {
if (negPdf==0 || posPdf==0) {
std::cerr << "ERROR in LauCPFitModel::setSCFPdfs : One or both of the PDF pointers is null." << std::endl;
return;
}
} else {
// if we're doing an untagged analysis we will only use the negative PDFs
if ( negPdf==0 ) {
std::cerr << "ERROR in LauCPFitModel::setSCFPdfs : The negative PDF pointer is null." << std::endl;
return;
}
if ( posPdf!=0 ) {
std::cerr << "WARNING in LauCPFitModel::setSCFPdfs : Doing an untagged fit so will not use the positive PDF." << std::endl;
}
}
negScfPdfs_.push_back(negPdf);
posScfPdfs_.push_back(posPdf);
}
void LauCPFitModel::setBkgndPdfs(const TString& bkgndClass, LauAbsPdf* negPdf, LauAbsPdf* posPdf)
{
if ( tagged_ ) {
if (negPdf==0 || posPdf==0) {
std::cerr << "ERROR in LauCPFitModel::setBkgndPdfs : One or both of the PDF pointers is null." << std::endl;
return;
}
} else {
// if we're doing an untagged analysis we will only use the negative PDFs
if ( negPdf==0 ) {
std::cerr << "ERROR in LauCPFitModel::setBkgndPdfs : The negative PDF pointer is null." << std::endl;
return;
}
if ( posPdf!=0 ) {
std::cerr << "WARNING in LauCPFitModel::setBkgndPdfs : Doing an untagged fit so will not use the positive PDF." << std::endl;
}
}
// check that this background name is valid
if ( ! this->validBkgndClass( bkgndClass ) ) {
std::cerr << "ERROR in LauCPFitModel::setBkgndPdfs : Invalid background class \"" << bkgndClass << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
return;
}
UInt_t bkgndID = this->bkgndClassID( bkgndClass );
negBkgndPdfs_[bkgndID].push_back(negPdf);
posBkgndPdfs_[bkgndID].push_back(posPdf);
usingBkgnd_ = kTRUE;
}
void LauCPFitModel::setAmpCoeffSet(LauAbsCoeffSet* coeffSet)
{
// Is there a component called compName in the signal model?
TString compName(coeffSet->name());
Bool_t negOK = negSigModel_->hasResonance(compName);
TString conjName = negSigModel_->getConjResName(compName);
Bool_t posOK = posSigModel_->hasResonance(conjName);
if (!negOK) {
std::cerr << "ERROR in LauCPFitModel::setMagPhase : " << negParent_ << " signal DP model doesn't contain component \"" << compName << "\"." << std::endl;
return;
}
if (!posOK) {
std::cerr << "ERROR in LauCPFitModel::setMagPhase : " << posParent_ << " signal DP model doesn't contain component \"" << conjName << "\"." << std::endl;
return;
}
// Do we already have it in our list of names?
for (std::vector<LauAbsCoeffSet*>::const_iterator iter=coeffPars_.begin(); iter!=coeffPars_.end(); ++iter) {
if ((*iter)->name() == compName) {
std::cerr << "ERROR in LauCPFitModel::setAmpCoeffSet : Have already set coefficients for \"" << compName << "\"." << std::endl;
return;
}
}
coeffSet->index(nSigComp_);
coeffPars_.push_back(coeffSet);
TString parName = coeffSet->baseName(); parName += "FitFracAsym";
fitFracAsymm_.push_back(LauParameter(parName, 0.0, -1.0, 1.0));
acp_.push_back(coeffSet->acp());
++nSigComp_;
std::cout << "INFO in LauCPFitModel::setAmpCoeffSet : Added coefficients for component \"" << compName << "\" to the fit model." << std::endl;
coeffSet->printParValues();
}
void LauCPFitModel::initialise()
{
// First of all check that, if a given component is being used,
// we've got the PDFs for all the variables involved
if ( this->useDP() ) {
if ((negSigModel_ == 0) || (posSigModel_ == 0)) {
std::cerr << "ERROR in LauCPFitModel::initialise : the pointer to one (neg or pos) of the signal DP models is null.\n";
std::cerr << " : Removing the Dalitz Plot from the model." << std::endl;
this->useDP(kFALSE);
}
if ( usingBkgnd_ ) {
if ( negBkgndDPModels_.empty() || posBkgndDPModels_.empty() ) {
std::cerr << "ERROR in LauCPFitModel::initialise : No background DP models found.\n";
std::cerr << " : Removing the Dalitz plot from the model." << std::endl;
this->useDP(kFALSE);
}
for (LauBkgndDPModelList::const_iterator dpmodel_iter = negBkgndDPModels_.begin(); dpmodel_iter != negBkgndDPModels_.end(); ++dpmodel_iter ) {
if ( (*dpmodel_iter) == 0 ) {
std::cerr << "ERROR in LauCPFitModel::initialise : The pointer to one of the background DP models is null.\n";
std::cerr << " : Removing the Dalitz Plot from the model." << std::endl;
this->useDP(kFALSE);
break;
}
}
for (LauBkgndDPModelList::const_iterator dpmodel_iter = posBkgndDPModels_.begin(); dpmodel_iter != posBkgndDPModels_.end(); ++dpmodel_iter ) {
if ( (*dpmodel_iter) == 0 ) {
std::cerr << "ERROR in LauCPFitModel::initialise : The pointer to one of the background DP models is null.\n";
std::cerr << " : Removing the Dalitz Plot from the model." << std::endl;
this->useDP(kFALSE);
break;
}
}
}
}
// Next check that, if a given component is being used we've got the
// right number of PDFs for all the variables involved
// TODO - should probably check variable names and so on as well
UInt_t nsigpdfvars(0);
for ( LauPdfList::const_iterator pdf_iter = negSignalPdfs_.begin(); pdf_iter != negSignalPdfs_.end(); ++pdf_iter ) {
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nsigpdfvars;
}
}
}
if (useSCF_) {
UInt_t nscfpdfvars(0);
for ( LauPdfList::const_iterator pdf_iter = negScfPdfs_.begin(); pdf_iter != negScfPdfs_.end(); ++pdf_iter ) {
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nscfpdfvars;
}
}
}
if (nscfpdfvars != nsigpdfvars) {
std::cerr << "ERROR in LauCPFitModel::initialise : There are " << nsigpdfvars << " TM signal PDF variables but " << nscfpdfvars << " SCF signal PDF variables." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
if (usingBkgnd_) {
for (LauBkgndPdfsList::const_iterator bgclass_iter = negBkgndPdfs_.begin(); bgclass_iter != negBkgndPdfs_.end(); ++bgclass_iter) {
UInt_t nbkgndpdfvars(0);
const LauPdfList& pdfList = (*bgclass_iter);
for ( LauPdfList::const_iterator pdf_iter = pdfList.begin(); pdf_iter != pdfList.end(); ++pdf_iter ) {
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nbkgndpdfvars;
}
}
}
if (nbkgndpdfvars != nsigpdfvars) {
std::cerr << "ERROR in LauCPFitModel::initialise : There are " << nsigpdfvars << " signal PDF variables but " << nbkgndpdfvars << " bkgnd PDF variables." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
}
// Clear the vectors of parameter information so we can start from scratch
this->clearFitParVectors();
// Set the fit parameters for signal and background models
this->setSignalDPParameters();
// Set the fit parameters for the various extra PDFs
this->setExtraPdfParameters();
// Set the initial bg and signal events
this->setFitNEvents();
// Check that we have the expected number of fit variables
const LauParameterPList& fitVars = this->fitPars();
if (fitVars.size() != (nSigDPPar_ + nExtraPdfPar_ + nNormPar_)) {
std::cerr << "ERROR in LauCPFitModel::initialise : Number of fit parameters not of expected size. Exiting" << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
// From the initial parameter values calculate the coefficients
// so they can be passed to the signal model
this->updateCoeffs();
// Initialisation
if (this->useDP() == kTRUE) {
this->initialiseDPModels();
}
if (!this->useDP() && negSignalPdfs_.empty()) {
std::cerr << "ERROR in LauCPFitModel::initialise : Signal model doesn't exist for any variable." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
this->setExtraNtupleVars();
}
void LauCPFitModel::initialiseDPModels()
{
std::cout << "INFO in LauCPFitModel::initialiseDPModels : Initialising signal DP model" << std::endl;
negSigModel_->initialise(negCoeffs_);
posSigModel_->initialise(posCoeffs_);
if (usingBkgnd_ == kTRUE) {
for (LauBkgndDPModelList::iterator iter = negBkgndDPModels_.begin(); iter != negBkgndDPModels_.end(); ++iter) {
(*iter)->initialise();
}
for (LauBkgndDPModelList::iterator iter = posBkgndDPModels_.begin(); iter != posBkgndDPModels_.end(); ++iter) {
(*iter)->initialise();
}
}
}
void LauCPFitModel::setSignalDPParameters()
{
// Set the fit parameters for the signal model.
nSigDPPar_ = 0;
if ( ! this->useDP() ) {
return;
}
std::cout << "INFO in LauCPFitModel::setSignalDPParameters : Setting the initial fit parameters for the signal DP model." << std::endl;
// Need to check that the number of components we have and that the dynamics has matches up
UInt_t nNegAmp = negSigModel_->getnAmp();
UInt_t nPosAmp = posSigModel_->getnAmp();
if ( nNegAmp != nPosAmp ) {
std::cerr << "ERROR in LauCPFitModel::setSignalDPParameters : Unequal number of signal DP components in the negative and positive models: " << nNegAmp << " != " << nPosAmp << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if ( nNegAmp != nSigComp_ ) {
std::cerr << "ERROR in LauCPFitModel::setSignalDPParameters : Number of signal DP components in the model (" << nNegAmp << ") not equal to number of coefficients supplied (" << nSigComp_ << ")." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
// Place signal model parameters in vector of fit variables
LauParameterPList& fitVars = this->fitPars();
for (UInt_t i = 0; i < nSigComp_; i++) {
LauParameterPList pars = coeffPars_[i]->getParameters();
for (LauParameterPList::iterator iter = pars.begin(); iter != pars.end(); ++iter) {
if ( !(*iter)->clone() ) {
fitVars.push_back(*iter);
++nSigDPPar_;
}
}
}
}
void LauCPFitModel::setExtraPdfParameters()
{
// Include all the parameters of the PDF in the fit
// NB all of them are passed to the fit, even though some have been fixed through parameter.fixed(kTRUE)
// With the new "cloned parameter" scheme only "original" parameters are passed to the fit.
// Their clones are updated automatically when the originals are updated.
nExtraPdfPar_ = 0;
nExtraPdfPar_ += this->addFitParameters(negSignalPdfs_);
if ( tagged_ ) {
nExtraPdfPar_ += this->addFitParameters(posSignalPdfs_);
}
if (useSCF_ == kTRUE) {
nExtraPdfPar_ += this->addFitParameters(negScfPdfs_);
if ( tagged_ ) {
nExtraPdfPar_ += this->addFitParameters(posScfPdfs_);
}
}
if (usingBkgnd_ == kTRUE) {
for (LauBkgndPdfsList::iterator iter = negBkgndPdfs_.begin(); iter != negBkgndPdfs_.end(); ++iter) {
nExtraPdfPar_ += this->addFitParameters(*iter);
}
if ( tagged_ ) {
for (LauBkgndPdfsList::iterator iter = posBkgndPdfs_.begin(); iter != posBkgndPdfs_.end(); ++iter) {
nExtraPdfPar_ += this->addFitParameters(*iter);
}
}
}
}
void LauCPFitModel::setFitNEvents()
{
if ( signalEvents_ == 0 ) {
std::cerr << "ERROR in LauCPFitModel::setFitNEvents : Signal yield not defined." << std::endl;
return;
}
nNormPar_ = 0;
// initialise the total number of events to be the sum of all the hypotheses
Double_t nTotEvts = signalEvents_->value();
for (LauBkgndYieldList::const_iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
nTotEvts += (*iter)->value();
if ( (*iter) == 0 ) {
std::cerr << "ERROR in LauCPFitModel::setFitNEvents : Background yield not defined." << std::endl;
return;
}
}
this->eventsPerExpt(TMath::FloorNint(nTotEvts));
LauParameterPList& fitVars = this->fitPars();
// if doing an extended ML fit add the number of signal events into the fit parameters
if (this->doEMLFit()) {
std::cout << "INFO in LauCPFitModel::setFitNEvents : Initialising number of events for signal and background components..." << std::endl;
// add the signal fraction to the list of fit parameters
fitVars.push_back(signalEvents_);
++nNormPar_;
} else {
std::cout << "INFO in LauCPFitModel::setFitNEvents : Initialising number of events for background components (and hence signal)..." << std::endl;
}
// if not using the DP in the model we need an explicit signal asymmetry parameter
if (this->useDP() == kFALSE) {
fitVars.push_back(signalAsym_);
++nNormPar_;
}
if (useSCF_ && !useSCFHist_) {
fitVars.push_back(&scfFrac_);
++nNormPar_;
}
if (usingBkgnd_ == kTRUE) {
for (LauBkgndYieldList::iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
LauParameter* parameter = (*iter);
fitVars.push_back(parameter);
++nNormPar_;
}
for (LauBkgndYieldList::iterator iter = bkgndAsym_.begin(); iter != bkgndAsym_.end(); ++iter) {
LauParameter* parameter = (*iter);
fitVars.push_back(parameter);
++nNormPar_;
}
}
}
void LauCPFitModel::setExtraNtupleVars()
{
// Set-up other parameters derived from the fit results, e.g. fit fractions.
if (this->useDP() != kTRUE) {
return;
}
// First clear the vectors so we start from scratch
this->clearExtraVarVectors();
LauParameterList& extraVars = this->extraPars();
// Add the positive and negative fit fractions for each signal component
negFitFrac_ = negSigModel_->getFitFractions();
if (negFitFrac_.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << negFitFrac_.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (negFitFrac_[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << negFitFrac_[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
posFitFrac_ = posSigModel_->getFitFractions();
if (posFitFrac_.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << posFitFrac_.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (posFitFrac_[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << posFitFrac_[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
// Add the positive and negative fit fractions that have not been corrected for the efficiency for each signal component
negFitFracEffUnCorr_ = negSigModel_->getFitFractionsEfficiencyUncorrected();
if (negFitFracEffUnCorr_.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << negFitFracEffUnCorr_.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (negFitFracEffUnCorr_[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << negFitFracEffUnCorr_[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
posFitFracEffUnCorr_ = posSigModel_->getFitFractionsEfficiencyUncorrected();
if (posFitFracEffUnCorr_.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << posFitFracEffUnCorr_.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (posFitFracEffUnCorr_[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << posFitFracEffUnCorr_[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
for (UInt_t i(0); i<nSigComp_; ++i) {
for (UInt_t j(i); j<nSigComp_; ++j) {
TString name = negFitFrac_[i][j].name();
name.Insert( name.Index("FitFrac"), "Neg" );
negFitFrac_[i][j].name(name);
extraVars.push_back(negFitFrac_[i][j]);
name = posFitFrac_[i][j].name();
name.Insert( name.Index("FitFrac"), "Pos" );
posFitFrac_[i][j].name(name);
extraVars.push_back(posFitFrac_[i][j]);
name = negFitFracEffUnCorr_[i][j].name();
name.Insert( name.Index("FitFrac"), "Neg" );
negFitFracEffUnCorr_[i][j].name(name);
extraVars.push_back(negFitFracEffUnCorr_[i][j]);
name = posFitFracEffUnCorr_[i][j].name();
name.Insert( name.Index("FitFrac"), "Pos" );
posFitFracEffUnCorr_[i][j].name(name);
extraVars.push_back(posFitFracEffUnCorr_[i][j]);
}
}
// Store any extra parameters/quantities from the DP model (e.g. K-matrix total fit fractions)
std::vector<LauParameter> negExtraPars = negSigModel_->getExtraParameters();
std::vector<LauParameter>::iterator negExtraIter;
for (negExtraIter = negExtraPars.begin(); negExtraIter != negExtraPars.end(); ++negExtraIter) {
LauParameter negExtraParameter = (*negExtraIter);
extraVars.push_back(negExtraParameter);
}
std::vector<LauParameter> posExtraPars = posSigModel_->getExtraParameters();
std::vector<LauParameter>::iterator posExtraIter;
for (posExtraIter = posExtraPars.begin(); posExtraIter != posExtraPars.end(); ++posExtraIter) {
LauParameter posExtraParameter = (*posExtraIter);
extraVars.push_back(posExtraParameter);
}
// Now add in the DP efficiency value
Double_t initMeanEff = negSigModel_->getMeanEff().initValue();
negMeanEff_.value(initMeanEff);
negMeanEff_.genValue(initMeanEff);
negMeanEff_.initValue(initMeanEff);
extraVars.push_back(negMeanEff_);
initMeanEff = posSigModel_->getMeanEff().initValue();
posMeanEff_.value(initMeanEff);
posMeanEff_.genValue(initMeanEff);
posMeanEff_.initValue(initMeanEff);
extraVars.push_back(posMeanEff_);
// Also add in the DP rates
Double_t initDPRate = negSigModel_->getDPRate().initValue();
negDPRate_.value(initDPRate);
negDPRate_.genValue(initDPRate);
negDPRate_.initValue(initDPRate);
extraVars.push_back(negDPRate_);
initDPRate = posSigModel_->getDPRate().initValue();
posDPRate_.value(initDPRate);
posDPRate_.genValue(initDPRate);
posDPRate_.initValue(initDPRate);
extraVars.push_back(posDPRate_);
// Calculate the CPC and CPV Fit Fractions, ACPs and FitFrac asymmetries
this->calcExtraFractions(kTRUE);
this->calcAsymmetries(kTRUE);
// Add the CP violating and CP conserving fit fractions for each signal component
for (UInt_t i = 0; i < nSigComp_; i++) {
for (UInt_t j = i; j < nSigComp_; j++) {
extraVars.push_back(CPVFitFrac_[i][j]);
}
}
for (UInt_t i = 0; i < nSigComp_; i++) {
for (UInt_t j = i; j < nSigComp_; j++) {
extraVars.push_back(CPCFitFrac_[i][j]);
}
}
// Add the Fit Fraction asymmetry for each signal component
for (UInt_t i = 0; i < nSigComp_; i++) {
extraVars.push_back(fitFracAsymm_[i]);
}
// Add the calculated CP asymmetry for each signal component
for (UInt_t i = 0; i < nSigComp_; i++) {
extraVars.push_back(acp_[i]);
}
}
void LauCPFitModel::calcExtraFractions(Bool_t initValues)
{
// Calculate the CP-conserving and CP-violating fit fractions
if (initValues) {
// create the structure
CPCFitFrac_.clear();
CPVFitFrac_.clear();
CPCFitFrac_.resize(nSigComp_);
CPVFitFrac_.resize(nSigComp_);
for (UInt_t i(0); i<nSigComp_; ++i) {
CPCFitFrac_[i].resize(nSigComp_);
CPVFitFrac_[i].resize(nSigComp_);
for (UInt_t j(i); j<nSigComp_; ++j) {
TString name = negFitFrac_[i][j].name();
name.Replace( name.Index("Neg"), 3, "CPC" );
CPCFitFrac_[i][j].name( name );
CPCFitFrac_[i][j].valueAndRange( 0.0, -100.0, 100.0 );
name = negFitFrac_[i][j].name();
name.Replace( name.Index("Neg"), 3, "CPV" );
CPVFitFrac_[i][j].name( name );
CPVFitFrac_[i][j].valueAndRange( 0.0, -100.0, 100.0 );
}
}
}
Double_t denom = negDPRate_ + posDPRate_;
for (UInt_t i(0); i<nSigComp_; ++i) {
for (UInt_t j(i); j<nSigComp_; ++j) {
Double_t negTerm = negFitFrac_[i][j]*negDPRate_;
Double_t posTerm = posFitFrac_[i][j]*posDPRate_;
Double_t cpcFitFrac = (negTerm + posTerm)/denom;
Double_t cpvFitFrac = (negTerm - posTerm)/denom;
CPCFitFrac_[i][j] = cpcFitFrac;
CPVFitFrac_[i][j] = cpvFitFrac;
if (initValues) {
CPCFitFrac_[i][j].genValue(cpcFitFrac);
CPCFitFrac_[i][j].initValue(cpcFitFrac);
CPVFitFrac_[i][j].genValue(cpvFitFrac);
CPVFitFrac_[i][j].initValue(cpvFitFrac);
}
}
}
}
void LauCPFitModel::calcAsymmetries(Bool_t initValues)
{
// Calculate the CP asymmetries
// Also calculate the fit fraction asymmetries
for (UInt_t i = 0; i < nSigComp_; i++) {
acp_[i] = coeffPars_[i]->acp();
LauAsymmCalc asymmCalc(negFitFrac_[i][i].value(), posFitFrac_[i][i].value());
Double_t asym = asymmCalc.getAsymmetry();
fitFracAsymm_[i] = asym;
if (initValues) {
fitFracAsymm_[i].genValue(asym);
fitFracAsymm_[i].initValue(asym);
}
}
}
void LauCPFitModel::finaliseFitResults(const TString& tablePrefixName)
{
// Retrieve parameters from the fit results for calculations and toy generation
// and eventually store these in output root ntuples/text files
// Now take the fit parameters and update them as necessary
// i.e. to make mag > 0.0, phase in the right range.
// This function will also calculate any other values, such as the
// fit fractions, using any errors provided by fitParErrors as appropriate.
// Also obtain the pull values: (measured - generated)/(average error)
if (this->useDP() == kTRUE) {
for (UInt_t i = 0; i < nSigComp_; ++i) {
// Check whether we have "a/b > 0.0", and phases in the right range
coeffPars_[i]->finaliseValues();
}
}
// update the pulls on the event fractions and asymmetries
if (this->doEMLFit()) {
signalEvents_->updatePull();
}
if (this->useDP() == kFALSE) {
signalAsym_->updatePull();
}
if (useSCF_ && !useSCFHist_) {
scfFrac_.updatePull();
}
if (usingBkgnd_ == kTRUE) {
for (LauBkgndYieldList::iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
(*iter)->updatePull();
}
for (LauBkgndYieldList::iterator iter = bkgndAsym_.begin(); iter != bkgndAsym_.end(); ++iter) {
(*iter)->updatePull();
}
}
// Update the pulls on all the extra PDFs' parameters
this->updateFitParameters(negSignalPdfs_);
this->updateFitParameters(posSignalPdfs_);
if (useSCF_ == kTRUE) {
this->updateFitParameters(negScfPdfs_);
this->updateFitParameters(posScfPdfs_);
}
if (usingBkgnd_ == kTRUE) {
for (LauBkgndPdfsList::iterator iter = negBkgndPdfs_.begin(); iter != negBkgndPdfs_.end(); ++iter) {
this->updateFitParameters(*iter);
}
for (LauBkgndPdfsList::iterator iter = posBkgndPdfs_.begin(); iter != posBkgndPdfs_.end(); ++iter) {
this->updateFitParameters(*iter);
}
}
// Fill the fit results to the ntuple
// update the coefficients and then calculate the fit fractions and ACP's
if (this->useDP() == kTRUE) {
this->updateCoeffs();
negSigModel_->updateCoeffs(negCoeffs_); negSigModel_->calcExtraInfo();
posSigModel_->updateCoeffs(posCoeffs_); posSigModel_->calcExtraInfo();
LauParArray negFitFrac = negSigModel_->getFitFractions();
if (negFitFrac.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << negFitFrac.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (negFitFrac[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << negFitFrac[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
LauParArray posFitFrac = posSigModel_->getFitFractions();
if (posFitFrac.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << posFitFrac.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (posFitFrac[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << posFitFrac[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
LauParArray negFitFracEffUnCorr = negSigModel_->getFitFractionsEfficiencyUncorrected();
if (negFitFracEffUnCorr.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << negFitFracEffUnCorr.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (negFitFracEffUnCorr[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << negFitFracEffUnCorr[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
LauParArray posFitFracEffUnCorr = posSigModel_->getFitFractionsEfficiencyUncorrected();
if (posFitFracEffUnCorr.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << posFitFracEffUnCorr.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (posFitFracEffUnCorr[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << posFitFracEffUnCorr[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
for (UInt_t i(0); i<nSigComp_; ++i) {
for (UInt_t j(i); j<nSigComp_; ++j) {
negFitFrac_[i][j].value(negFitFrac[i][j].value());
posFitFrac_[i][j].value(posFitFrac[i][j].value());
negFitFracEffUnCorr_[i][j].value(negFitFracEffUnCorr[i][j].value());
posFitFracEffUnCorr_[i][j].value(posFitFracEffUnCorr[i][j].value());
}
}
negMeanEff_.value(negSigModel_->getMeanEff().value());
posMeanEff_.value(posSigModel_->getMeanEff().value());
negDPRate_.value(negSigModel_->getDPRate().value());
posDPRate_.value(posSigModel_->getDPRate().value());
this->calcExtraFractions();
this->calcAsymmetries();
// Then store the final fit parameters, and any extra parameters for
// the signal model (e.g. fit fractions, FF asymmetries, ACPs, mean efficiency and DP rate)
this->clearExtraVarVectors();
LauParameterList& extraVars = this->extraPars();
// Add the positive and negative fit fractions for each signal component
for (UInt_t i(0); i<nSigComp_; ++i) {
for (UInt_t j(i); j<nSigComp_; ++j) {
extraVars.push_back(negFitFrac_[i][j]);
extraVars.push_back(posFitFrac_[i][j]);
extraVars.push_back(negFitFracEffUnCorr_[i][j]);
extraVars.push_back(posFitFracEffUnCorr_[i][j]);
}
}
// Store any extra parameters/quantities from the DP model (e.g. K-matrix total fit fractions)
std::vector<LauParameter> negExtraPars = negSigModel_->getExtraParameters();
std::vector<LauParameter>::iterator negExtraIter;
for (negExtraIter = negExtraPars.begin(); negExtraIter != negExtraPars.end(); ++negExtraIter) {
LauParameter negExtraParameter = (*negExtraIter);
extraVars.push_back(negExtraParameter);
}
std::vector<LauParameter> posExtraPars = posSigModel_->getExtraParameters();
std::vector<LauParameter>::iterator posExtraIter;
for (posExtraIter = posExtraPars.begin(); posExtraIter != posExtraPars.end(); ++posExtraIter) {
LauParameter posExtraParameter = (*posExtraIter);
extraVars.push_back(posExtraParameter);
}
extraVars.push_back(negMeanEff_);
extraVars.push_back(posMeanEff_);
extraVars.push_back(negDPRate_);
extraVars.push_back(posDPRate_);
for (UInt_t i = 0; i < nSigComp_; i++) {
for (UInt_t j(i); j<nSigComp_; ++j) {
extraVars.push_back(CPVFitFrac_[i][j]);
}
}
for (UInt_t i = 0; i < nSigComp_; i++) {
for (UInt_t j(i); j<nSigComp_; ++j) {
extraVars.push_back(CPCFitFrac_[i][j]);
}
}
for (UInt_t i(0); i<nSigComp_; ++i) {
extraVars.push_back(fitFracAsymm_[i]);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
extraVars.push_back(acp_[i]);
}
this->printFitFractions(std::cout);
this->printAsymmetries(std::cout);
}
const LauParameterPList& fitVars = this->fitPars();
const LauParameterList& extraVars = this->extraPars();
LauFitNtuple* ntuple = this->fitNtuple();
ntuple->storeParsAndErrors(fitVars, extraVars);
// find out the correlation matrix for the parameters
ntuple->storeCorrMatrix(this->iExpt(), this->nll(), this->fitStatus(), this->covarianceMatrix());
// Fill the data into ntuple
ntuple->updateFitNtuple();
// Print out the partial fit fractions, phases and the
// averaged efficiency, reweighted by the dynamics (and anything else)
if (this->writeLatexTable()) {
TString sigOutFileName(tablePrefixName);
sigOutFileName += "_"; sigOutFileName += this->iExpt(); sigOutFileName += "Expt.tex";
this->writeOutTable(sigOutFileName);
}
}
void LauCPFitModel::printFitFractions(std::ostream& output)
{
// Print out Fit Fractions, total DP rate and mean efficiency
// First for the B- events
for (UInt_t i = 0; i < nSigComp_; i++) {
const TString compName(coeffPars_[i]->name());
output << negParent_ << " FitFraction for component " << i << " (" << compName << ") = " << negFitFrac_[i][i] << std::endl;
}
output << negParent_ << " overall DP rate (integral of matrix element squared) = " << negDPRate_ << std::endl;
output << negParent_ << " average efficiency weighted by whole DP dynamics = " << negMeanEff_ << std::endl;
// Then for the positive sample
for (UInt_t i = 0; i < nSigComp_; i++) {
const TString compName(coeffPars_[i]->name());
const TString conjName(negSigModel_->getConjResName(compName));
output << posParent_ << " FitFraction for component " << i << " (" << conjName << ") = " << posFitFrac_[i][i] << std::endl;
}
output << posParent_ << " overall DP rate (integral of matrix element squared) = " << posDPRate_ << std::endl;
output << posParent_ << " average efficiency weighted by whole DP dynamics = " << posMeanEff_ << std::endl;
}
void LauCPFitModel::printAsymmetries(std::ostream& output)
{
for (UInt_t i = 0; i < nSigComp_; i++) {
const TString compName(coeffPars_[i]->name());
output << "Fit Fraction asymmetry for component " << i << " (" << compName << ") = " << fitFracAsymm_[i] << std::endl;
}
for (UInt_t i = 0; i < nSigComp_; i++) {
const TString compName(coeffPars_[i]->name());
output << "ACP for component " << i << " (" << compName << ") = " << acp_[i] << std::endl;
}
}
void LauCPFitModel::writeOutTable(const TString& outputFile)
{
// Write out the results of the fit to a tex-readable table
// TODO - need to include the yields in this table
std::ofstream fout(outputFile);
LauPrint print;
std::cout << "INFO in LauCPFitModel::writeOutTable : Writing out results of the fit to the tex file " << outputFile << std::endl;
if (this->useDP() == kTRUE) {
// print the fit coefficients in one table
coeffPars_.front()->printTableHeading(fout);
for (UInt_t i = 0; i < nSigComp_; i++) {
coeffPars_[i]->printTableRow(fout);
}
fout << "\\hline" << std::endl;
fout << "\\end{tabular}" << std::endl << std::endl;
// print the fit fractions and asymmetries in another
fout << "\\begin{tabular}{|l|c|c|c|c|}" << std::endl;
fout << "\\hline" << std::endl;
fout << "Component & " << negParent_ << " Fit Fraction & " << posParent_ << " Fit Fraction & Fit Fraction Asymmetry & ACP \\\\" << std::endl;
fout << "\\hline" << std::endl;
Double_t negFitFracSum(0.0);
Double_t posFitFracSum(0.0);
for (UInt_t i = 0; i < nSigComp_; i++) {
TString resName = coeffPars_[i]->name();
resName = resName.ReplaceAll("_", "\\_");
Double_t negFitFrac = negFitFrac_[i][i].value();
Double_t posFitFrac = posFitFrac_[i][i].value();
negFitFracSum += negFitFrac;
posFitFracSum += posFitFrac;
Double_t fitFracAsymm = fitFracAsymm_[i].value();
Double_t acp = acp_[i].value();
Double_t acpErr = acp_[i].error();
fout << resName << " & $";
print.printFormat(fout, negFitFrac);
fout << "$ & $";
print.printFormat(fout, posFitFrac);
fout << "$ & $";
print.printFormat(fout, fitFracAsymm);
fout << "$ & $";
print.printFormat(fout, acp);
fout << " \\pm ";
print.printFormat(fout, acpErr);
fout << "$ \\\\" << std::endl;
}
fout << "\\hline" << std::endl;
// Also print out sum of fit fractions
fout << "Fit Fraction Sum & $";
print.printFormat(fout, negFitFracSum);
fout << "$ & $";
print.printFormat(fout, posFitFracSum);
fout << "$ & & \\\\" << std::endl;
fout << "\\hline" << std::endl;
fout << "DP rate & $";
print.printFormat(fout, negDPRate_.value());
fout << "$ & $";
print.printFormat(fout, posDPRate_.value());
fout << "$ & & \\\\" << std::endl;
fout << "$< \\varepsilon > $ & $";
print.printFormat(fout, negMeanEff_.value());
fout << "$ & $";
print.printFormat(fout, posMeanEff_.value());
fout << "$ & & \\\\" << std::endl;
fout << "\\hline" << std::endl;
fout << "\\end{tabular}" << std::endl << std::endl;
}
if (!negSignalPdfs_.empty()) {
fout << "\\begin{tabular}{|l|c|}" << std::endl;
fout << "\\hline" << std::endl;
if (useSCF_ == kTRUE) {
fout << "\\Extra TM Signal PDFs' Parameters: & \\\\" << std::endl;
} else {
fout << "\\Extra Signal PDFs' Parameters: & \\\\" << std::endl;
}
this->printFitParameters(negSignalPdfs_, fout);
if ( tagged_ ) {
this->printFitParameters(posSignalPdfs_, fout);
}
if (useSCF_ == kTRUE && !negScfPdfs_.empty()) {
fout << "\\hline" << std::endl;
fout << "\\Extra SCF Signal PDFs' Parameters: & \\\\" << std::endl;
this->printFitParameters(negScfPdfs_, fout);
if ( tagged_ ) {
this->printFitParameters(posScfPdfs_, fout);
}
}
if (usingBkgnd_ == kTRUE && !negBkgndPdfs_.empty()) {
fout << "\\hline" << std::endl;
fout << "\\Extra Background PDFs' Parameters: & \\\\" << std::endl;
for (LauBkgndPdfsList::const_iterator iter = negBkgndPdfs_.begin(); iter != negBkgndPdfs_.end(); ++iter) {
this->printFitParameters(*iter, fout);
}
if ( tagged_ ) {
for (LauBkgndPdfsList::const_iterator iter = posBkgndPdfs_.begin(); iter != posBkgndPdfs_.end(); ++iter) {
this->printFitParameters(*iter, fout);
}
}
}
fout << "\\hline \n\\end{tabular}" << std::endl << std::endl;
}
}
void LauCPFitModel::checkInitFitParams()
{
// Update the number of signal events to be total-sum(background events)
this->updateSigEvents();
// Check whether we want to have randomised initial fit parameters for the signal model
if (this->useRandomInitFitPars() == kTRUE) {
std::cout << "INFO in LauCPFitModel::checkInitFitParams : Setting random parameters for the signal model" << std::endl;
this->randomiseInitFitPars();
}
}
void LauCPFitModel::randomiseInitFitPars()
{
// Only randomise those parameters that are not fixed!
std::cout << "INFO in LauCPFitModel::randomiseInitFitPars : Randomising the initial fit magnitudes and phases of the components..." << std::endl;
for (UInt_t i = 0; i < nSigComp_; i++) {
coeffPars_[i]->randomiseInitValues();
}
}
LauCPFitModel::LauGenInfo LauCPFitModel::eventsToGenerate()
{
// Determine the number of events to generate for each hypothesis
// If we're smearing then smear each one individually
LauGenInfo nEvtsGen;
// Signal
Double_t evtWeight(1.0);
Double_t nEvts = signalEvents_->genValue();
if ( nEvts < 0.0 ) {
evtWeight = -1.0;
nEvts = TMath::Abs( nEvts );
}
Double_t asym(0.0);
Double_t sigAsym(0.0);
// need to include this as an alternative in case the DP isn't in the model
if ( !this->useDP() || forceAsym_ ) {
sigAsym = signalAsym_->genValue();
} else {
Double_t negRate = negSigModel_->getDPNorm();
Double_t posRate = posSigModel_->getDPNorm();
if (negRate+posRate>1e-30) {
sigAsym = (negRate-posRate)/(negRate+posRate);
}
}
asym = sigAsym;
Int_t nPosEvts = static_cast<Int_t>((nEvts/2.0 * (1.0 - asym)) + 0.5);
Int_t nNegEvts = static_cast<Int_t>((nEvts/2.0 * (1.0 + asym)) + 0.5);
if (this->doPoissonSmearing()) {
nNegEvts = LauRandom::randomFun()->Poisson(nNegEvts);
nPosEvts = LauRandom::randomFun()->Poisson(nPosEvts);
}
nEvtsGen[std::make_pair("signal",-1)] = std::make_pair(nNegEvts,evtWeight);
nEvtsGen[std::make_pair("signal",+1)] = std::make_pair(nPosEvts,evtWeight);
// backgrounds
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
const TString& bkgndClass = this->bkgndClassName(bkgndID);
const LauParameter* evtsPar = bkgndEvents_[bkgndID];
const LauParameter* asymPar = bkgndAsym_[bkgndID];
evtWeight = 1.0;
nEvts = TMath::FloorNint( evtsPar->genValue() );
if ( nEvts < 0 ) {
evtWeight = -1.0;
nEvts = TMath::Abs( nEvts );
}
asym = asymPar->genValue();
nPosEvts = static_cast<Int_t>((nEvts/2.0 * (1.0 - asym)) + 0.5);
nNegEvts = static_cast<Int_t>((nEvts/2.0 * (1.0 + asym)) + 0.5);
if (this->doPoissonSmearing()) {
nNegEvts = LauRandom::randomFun()->Poisson(nNegEvts);
nPosEvts = LauRandom::randomFun()->Poisson(nPosEvts);
}
nEvtsGen[std::make_pair(bkgndClass,-1)] = std::make_pair(nNegEvts,evtWeight);
nEvtsGen[std::make_pair(bkgndClass,+1)] = std::make_pair(nPosEvts,evtWeight);
}
std::cout << "INFO in LauCPFitModel::eventsToGenerate : Generating toy MC with:" << std::endl;
std::cout << " : Signal asymmetry = " << sigAsym << " and number of signal events = " << signalEvents_->genValue() << std::endl;
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
const TString& bkgndClass = this->bkgndClassName(bkgndID);
const LauParameter* evtsPar = bkgndEvents_[bkgndID];
const LauParameter* asymPar = bkgndAsym_[bkgndID];
std::cout << " : " << bkgndClass << " asymmetry = " << asymPar->genValue() << " and number of " << bkgndClass << " events = " << evtsPar->genValue() << std::endl;
}
return nEvtsGen;
}
Bool_t LauCPFitModel::genExpt()
{
// Routine to generate toy Monte Carlo events according to the various models we have defined.
// Determine the number of events to generate for each hypothesis
LauGenInfo nEvts = this->eventsToGenerate();
Bool_t genOK(kTRUE);
Int_t evtNum(0);
const UInt_t nBkgnds = this->nBkgndClasses();
std::vector<TString> bkgndClassNames(nBkgnds);
std::vector<TString> bkgndClassNamesGen(nBkgnds);
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name( this->bkgndClassName(iBkgnd) );
bkgndClassNames[iBkgnd] = name;
bkgndClassNamesGen[iBkgnd] = "gen"+name;
}
const Bool_t storeSCFTruthInfo = ( useSCF_ || ( this->enableEmbedding() &&
negSignalTree_ != 0 && negSignalTree_->haveBranch("mcMatch") &&
posSignalTree_ != 0 && posSignalTree_->haveBranch("mcMatch") ) );
// Loop over the hypotheses and generate the requested number of events for each one
for (LauGenInfo::const_iterator iter = nEvts.begin(); iter != nEvts.end(); ++iter) {
const TString& type(iter->first.first);
curEvtCharge_ = iter->first.second;
Double_t evtWeight( iter->second.second );
Int_t nEvtsGen( iter->second.first );
for (Int_t iEvt(0); iEvt<nEvtsGen; ++iEvt) {
this->setGenNtupleDoubleBranchValue( "evtWeight", evtWeight );
this->setGenNtupleDoubleBranchValue( "efficiency", 1.0 );
if (type == "signal") {
this->setGenNtupleIntegerBranchValue("genSig",1);
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
this->setGenNtupleIntegerBranchValue( bkgndClassNamesGen[iBkgnd], 0 );
}
genOK = this->generateSignalEvent();
if ( curEvtCharge_ > 0 ){
this->setGenNtupleDoubleBranchValue( "efficiency", posSigModel_->getEvtEff() );
} else {
this->setGenNtupleDoubleBranchValue( "efficiency", negSigModel_->getEvtEff() );
}
} else {
this->setGenNtupleIntegerBranchValue("genSig",0);
if ( storeSCFTruthInfo ) {
this->setGenNtupleIntegerBranchValue("genTMSig",0);
this->setGenNtupleIntegerBranchValue("genSCFSig",0);
}
UInt_t bkgndID(0);
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
Int_t gen(0);
if ( bkgndClassNames[iBkgnd] == type ) {
gen = 1;
bkgndID = iBkgnd;
}
this->setGenNtupleIntegerBranchValue( bkgndClassNamesGen[iBkgnd], gen );
}
genOK = this->generateBkgndEvent(bkgndID);
}
if (!genOK) {
// If there was a problem with the generation then break out and return.
// The problem model will have adjusted itself so that all should be OK next time.
break;
}
if (this->useDP() == kTRUE) {
this->setDPBranchValues();
}
// Store the event charge
this->setGenNtupleIntegerBranchValue(tagVarName_,curEvtCharge_);
// Store the event number (within this experiment)
// and then increment it
this->setGenNtupleIntegerBranchValue("iEvtWithinExpt",evtNum);
++evtNum;
this->fillGenNtupleBranches();
if (iEvt%500 == 0) {std::cout << "INFO in LauCPFitModel::genExpt : Generated event number " << iEvt << " out of " << nEvtsGen << " " << type << " events." << std::endl;}
}
if (!genOK) {
break;
}
}
if (this->useDP() && genOK) {
negSigModel_->checkToyMC(kTRUE,kTRUE);
posSigModel_->checkToyMC(kTRUE,kTRUE);
// Get the fit fractions if they're to be written into the latex table
if (this->writeLatexTable()) {
LauParArray negFitFrac = negSigModel_->getFitFractions();
if (negFitFrac.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::genExpt : Fit Fraction array of unexpected dimension: " << negFitFrac.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (negFitFrac[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::genExpt : Fit Fraction array of unexpected dimension: " << negFitFrac[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
LauParArray posFitFrac = posSigModel_->getFitFractions();
if (posFitFrac.size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::genExpt : Fit Fraction array of unexpected dimension: " << posFitFrac.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (posFitFrac[i].size() != nSigComp_) {
std::cerr << "ERROR in LauCPFitModel::genExpt : Fit Fraction array of unexpected dimension: " << posFitFrac[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
for (UInt_t i(0); i<nSigComp_; ++i) {
for (UInt_t j(i); j<nSigComp_; ++j) {
negFitFrac_[i][j].value(negFitFrac[i][j].value());
posFitFrac_[i][j].value(posFitFrac[i][j].value());
}
}
negMeanEff_.value(negSigModel_->getMeanEff().value());
posMeanEff_.value(posSigModel_->getMeanEff().value());
negDPRate_.value(negSigModel_->getDPRate().value());
posDPRate_.value(posSigModel_->getDPRate().value());
}
}
// If we're reusing embedded events or if the generation is being
// reset then clear the lists of used events
if (reuseSignal_ || !genOK) {
if (negSignalTree_) {
negSignalTree_->clearUsedList();
}
if (posSignalTree_) {
posSignalTree_->clearUsedList();
}
}
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
LauEmbeddedData* data = negBkgndTree_[bkgndID];
if (reuseBkgnd_[bkgndID] || !genOK) {
if (data) {
data->clearUsedList();
}
}
}
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
LauEmbeddedData* data = posBkgndTree_[bkgndID];
if (reuseBkgnd_[bkgndID] || !genOK) {
if (data) {
data->clearUsedList();
}
}
}
return genOK;
}
Bool_t LauCPFitModel::generateSignalEvent()
{
// Generate signal event
Bool_t genOK(kTRUE);
Bool_t genSCF(kFALSE);
LauAbsDPDynamics* model(0);
LauKinematics* kinematics(0);
LauEmbeddedData* embeddedData(0);
LauPdfList* sigPdfs(0);
LauPdfList* scfPdfs(0);
Bool_t doReweighting(kFALSE);
if (curEvtCharge_<0) {
model = negSigModel_;
kinematics = negKinematics_;
sigPdfs = &negSignalPdfs_;
scfPdfs = &negScfPdfs_;
if (this->enableEmbedding()) {
embeddedData = negSignalTree_;
doReweighting = useNegReweighting_;
}
} else {
model = posSigModel_;
kinematics = posKinematics_;
if ( tagged_ ) {
sigPdfs = &posSignalPdfs_;
scfPdfs = &posScfPdfs_;
} else {
sigPdfs = &negSignalPdfs_;
scfPdfs = &negScfPdfs_;
}
if (this->enableEmbedding()) {
embeddedData = posSignalTree_;
doReweighting = usePosReweighting_;
}
}
if (this->useDP()) {
if (embeddedData) {
if (doReweighting) {
// Select a (random) event from the generated data. Then store the
// reconstructed DP co-ords, together with other pdf information,
// as the embedded data.
genOK = embeddedData->getReweightedEvent(model);
} else {
// Just get the information of a (randomly) selected event in the
// embedded data
embeddedData->getEmbeddedEvent(kinematics);
}
genSCF = this->storeSignalMCMatch( embeddedData );
} else {
genOK = model->generate();
if ( genOK && useSCF_ ) {
Double_t frac(0.0);
if ( useSCFHist_ ) {
frac = scfFracHist_->calcEfficiency( kinematics );
} else {
frac = scfFrac_.genValue();
}
if ( frac < LauRandom::randomFun()->Rndm() ) {
this->setGenNtupleIntegerBranchValue("genTMSig",1);
this->setGenNtupleIntegerBranchValue("genSCFSig",0);
genSCF = kFALSE;
} else {
this->setGenNtupleIntegerBranchValue("genTMSig",0);
this->setGenNtupleIntegerBranchValue("genSCFSig",1);
genSCF = kTRUE;
// Optionally smear the DP position
// of the SCF event
if ( scfMap_ != 0 ) {
Double_t xCoord(0.0), yCoord(0.0);
if ( kinematics->squareDP() ) {
xCoord = kinematics->getmPrime();
yCoord = kinematics->getThetaPrime();
} else {
xCoord = kinematics->getm13Sq();
yCoord = kinematics->getm23Sq();
}
// Find the bin number where this event is generated
Int_t binNo = scfMap_->binNumber( xCoord, yCoord );
// Retrieve the migration histogram
TH2* histo = scfMap_->trueHist( binNo );
- LauEffModel * effModel = model->getEffModel();
+ LauAbsEffModel * effModel = model->getEffModel();
do {
// Get a random point from the histogram
histo->GetRandom2( xCoord, yCoord );
// Update the kinematics
if ( kinematics->squareDP() ) {
kinematics->updateSqDPKinematics( xCoord, yCoord );
} else {
kinematics->updateKinematics( xCoord, yCoord );
}
} while ( ! effModel->passVeto( kinematics ) );
}
}
}
}
} else {
if (embeddedData) {
embeddedData->getEmbeddedEvent(0);
genSCF = this->storeSignalMCMatch( embeddedData );
} else if ( useSCF_ ) {
Double_t frac = scfFrac_.genValue();
if ( frac < LauRandom::randomFun()->Rndm() ) {
this->setGenNtupleIntegerBranchValue("genTMSig",1);
this->setGenNtupleIntegerBranchValue("genSCFSig",0);
genSCF = kFALSE;
} else {
this->setGenNtupleIntegerBranchValue("genTMSig",0);
this->setGenNtupleIntegerBranchValue("genSCFSig",1);
genSCF = kTRUE;
}
}
}
if (genOK) {
if ( useSCF_ ) {
if ( genSCF ) {
this->generateExtraPdfValues(scfPdfs, embeddedData);
} else {
this->generateExtraPdfValues(sigPdfs, embeddedData);
}
} else {
this->generateExtraPdfValues(sigPdfs, embeddedData);
}
}
// Check for problems with the embedding
if (embeddedData && (embeddedData->nEvents() == embeddedData->nUsedEvents())) {
std::cerr << "WARNING in LauCPFitModel::generateSignalEvent : Source of embedded signal events used up, clearing the list of used events." << std::endl;
embeddedData->clearUsedList();
}
return genOK;
}
Bool_t LauCPFitModel::generateBkgndEvent(UInt_t bkgndID)
{
// Generate Bkgnd event
Bool_t genOK(kTRUE);
LauAbsBkgndDPModel* model(0);
LauEmbeddedData* embeddedData(0);
LauPdfList* extraPdfs(0);
LauKinematics* kinematics(0);
if (curEvtCharge_<0) {
model = negBkgndDPModels_[bkgndID];
if (this->enableEmbedding()) {
embeddedData = negBkgndTree_[bkgndID];
}
extraPdfs = &negBkgndPdfs_[bkgndID];
kinematics = negKinematics_;
} else {
model = posBkgndDPModels_[bkgndID];
if (this->enableEmbedding()) {
embeddedData = posBkgndTree_[bkgndID];
}
if ( tagged_ ) {
extraPdfs = &posBkgndPdfs_[bkgndID];
} else {
extraPdfs = &negBkgndPdfs_[bkgndID];
}
kinematics = posKinematics_;
}
if (this->useDP()) {
if (embeddedData) {
embeddedData->getEmbeddedEvent(kinematics);
} else {
if (model == 0) {
const TString& bkgndClass = this->bkgndClassName(bkgndID);
std::cerr << "ERROR in LauCPFitModel::generateBkgndEvent : Can't find the DP model for background class \"" << bkgndClass << "\"." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
genOK = model->generate();
}
} else {
if (embeddedData) {
embeddedData->getEmbeddedEvent(0);
}
}
if (genOK) {
this->generateExtraPdfValues(extraPdfs, embeddedData);
}
// Check for problems with the embedding
if (embeddedData && (embeddedData->nEvents() == embeddedData->nUsedEvents())) {
const TString& bkgndClass = this->bkgndClassName(bkgndID);
std::cerr << "WARNING in LauCPFitModel::generateBkgndEvent : Source of embedded " << bkgndClass << " events used up, clearing the list of used events." << std::endl;
embeddedData->clearUsedList();
}
return genOK;
}
void LauCPFitModel::setupGenNtupleBranches()
{
// Setup the required ntuple branches
this->addGenNtupleDoubleBranch("evtWeight");
this->addGenNtupleIntegerBranch("genSig");
this->addGenNtupleDoubleBranch("efficiency");
if ( useSCF_ || ( this->enableEmbedding() &&
negSignalTree_ != 0 && negSignalTree_->haveBranch("mcMatch") &&
posSignalTree_ != 0 && posSignalTree_->haveBranch("mcMatch") ) ) {
this->addGenNtupleIntegerBranch("genTMSig");
this->addGenNtupleIntegerBranch("genSCFSig");
}
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name( this->bkgndClassName(iBkgnd) );
name.Prepend("gen");
this->addGenNtupleIntegerBranch(name);
}
this->addGenNtupleIntegerBranch("charge");
if (this->useDP() == kTRUE) {
this->addGenNtupleDoubleBranch("m12");
this->addGenNtupleDoubleBranch("m23");
this->addGenNtupleDoubleBranch("m13");
this->addGenNtupleDoubleBranch("m12Sq");
this->addGenNtupleDoubleBranch("m23Sq");
this->addGenNtupleDoubleBranch("m13Sq");
this->addGenNtupleDoubleBranch("cosHel12");
this->addGenNtupleDoubleBranch("cosHel23");
this->addGenNtupleDoubleBranch("cosHel13");
if (negKinematics_->squareDP() && posKinematics_->squareDP()) {
this->addGenNtupleDoubleBranch("mPrime");
this->addGenNtupleDoubleBranch("thPrime");
}
}
for (LauPdfList::const_iterator pdf_iter = negSignalPdfs_.begin(); pdf_iter != negSignalPdfs_.end(); ++pdf_iter) {
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
this->addGenNtupleDoubleBranch( (*var_iter) );
}
}
}
}
void LauCPFitModel::setDPBranchValues()
{
LauKinematics* kinematics(0);
if (curEvtCharge_<0) {
kinematics = negKinematics_;
} else {
kinematics = posKinematics_;
}
// Store all the DP information
this->setGenNtupleDoubleBranchValue("m12", kinematics->getm12());
this->setGenNtupleDoubleBranchValue("m23", kinematics->getm23());
this->setGenNtupleDoubleBranchValue("m13", kinematics->getm13());
this->setGenNtupleDoubleBranchValue("m12Sq", kinematics->getm12Sq());
this->setGenNtupleDoubleBranchValue("m23Sq", kinematics->getm23Sq());
this->setGenNtupleDoubleBranchValue("m13Sq", kinematics->getm13Sq());
this->setGenNtupleDoubleBranchValue("cosHel12", kinematics->getc12());
this->setGenNtupleDoubleBranchValue("cosHel23", kinematics->getc23());
this->setGenNtupleDoubleBranchValue("cosHel13", kinematics->getc13());
if (kinematics->squareDP()) {
this->setGenNtupleDoubleBranchValue("mPrime", kinematics->getmPrime());
this->setGenNtupleDoubleBranchValue("thPrime", kinematics->getThetaPrime());
}
}
void LauCPFitModel::generateExtraPdfValues(LauPdfList* extraPdfs, LauEmbeddedData* embeddedData)
{
LauKinematics* kinematics(0);
if (curEvtCharge_<0) {
kinematics = negKinematics_;
} else {
kinematics = posKinematics_;
}
if (!extraPdfs) {
std::cerr << "ERROR in LauCPFitModel::generateExtraPdfValues : Null pointer to PDF list." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if (extraPdfs->empty()) {
//std::cerr << "WARNING in LauCPFitModel::generateExtraPdfValues : PDF list is empty." << std::endl;
return;
}
// Generate from the extra PDFs
for (LauPdfList::iterator pdf_iter = extraPdfs->begin(); pdf_iter != extraPdfs->end(); ++pdf_iter) {
LauFitData genValues;
if (embeddedData) {
genValues = embeddedData->getValues( (*pdf_iter)->varNames() );
} else {
genValues = (*pdf_iter)->generate(kinematics);
}
for ( LauFitData::const_iterator var_iter = genValues.begin(); var_iter != genValues.end(); ++var_iter ) {
TString varName = var_iter->first;
if ( varName != "m13Sq" && varName != "m23Sq" ) {
Double_t value = var_iter->second;
this->setGenNtupleDoubleBranchValue(varName,value);
}
}
}
}
Bool_t LauCPFitModel::storeSignalMCMatch(LauEmbeddedData* embeddedData)
{
// Default to TM
Bool_t genSCF(kFALSE);
Int_t match(1);
// Check that we have a valid pointer and that embedded data has
// the mcMatch branch. If so then get the match value.
if ( embeddedData && embeddedData->haveBranch("mcMatch") ) {
match = TMath::Nint( embeddedData->getValue("mcMatch") );
}
// Set the variables accordingly.
if (match) {
this->setGenNtupleIntegerBranchValue("genTMSig",1);
this->setGenNtupleIntegerBranchValue("genSCFSig",0);
genSCF = kFALSE;
} else {
this->setGenNtupleIntegerBranchValue("genTMSig",0);
this->setGenNtupleIntegerBranchValue("genSCFSig",1);
genSCF = kTRUE;
}
return genSCF;
}
void LauCPFitModel::propagateParUpdates()
{
// Update the signal parameters and then the total normalisation for the signal likelihood
if (this->useDP() == kTRUE) {
this->updateCoeffs();
negSigModel_->updateCoeffs(negCoeffs_);
posSigModel_->updateCoeffs(posCoeffs_);
}
// Update the signal fraction from the background fractions if not doing an extended fit
if ( !this->doEMLFit() && !signalEvents_->fixed() ) {
this->updateSigEvents();
}
}
void LauCPFitModel::updateSigEvents()
{
// The background parameters will have been set from Minuit.
// We need to update the signal events using these.
Double_t nTotEvts = this->eventsPerExpt();
signalEvents_->range(-2.0*nTotEvts,2.0*nTotEvts);
for (LauBkgndYieldList::iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
(*iter)->range(-2.0*nTotEvts,2.0*nTotEvts);
}
if (signalEvents_->fixed()) {
return;
}
// Subtract background events (if any) from signal.
Double_t signalEvents = nTotEvts;
if (usingBkgnd_ == kTRUE) {
for (LauBkgndYieldList::const_iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
signalEvents -= (*iter)->value();
}
}
signalEvents_->value(signalEvents);
}
void LauCPFitModel::cacheInputFitVars()
{
// Fill the internal data trees of the signal and background models.
// Note that we store the events of both charges in both the
// negative and the positive models. It's only later, at the stage
// when the likelihood is being calculated, that we separate them.
LauFitDataTree* inputFitData = this->fitData();
// First the Dalitz plot variables (m_ij^2)
if (this->useDP() == kTRUE) {
// need to append SCF smearing bins before caching DP amplitudes
if ( scfMap_ != 0 ) {
this->appendBinCentres( inputFitData );
}
negSigModel_->fillDataTree(*inputFitData);
posSigModel_->fillDataTree(*inputFitData);
if (usingBkgnd_ == kTRUE) {
for (LauBkgndDPModelList::iterator iter = negBkgndDPModels_.begin(); iter != negBkgndDPModels_.end(); ++iter) {
(*iter)->fillDataTree(*inputFitData);
}
for (LauBkgndDPModelList::iterator iter = posBkgndDPModels_.begin(); iter != posBkgndDPModels_.end(); ++iter) {
(*iter)->fillDataTree(*inputFitData);
}
}
}
// ...and then the extra PDFs
this->cacheInfo(negSignalPdfs_, *inputFitData);
this->cacheInfo(negScfPdfs_, *inputFitData);
for (LauBkgndPdfsList::iterator iter = negBkgndPdfs_.begin(); iter != negBkgndPdfs_.end(); ++iter) {
this->cacheInfo((*iter), *inputFitData);
}
if ( tagged_ ) {
this->cacheInfo(posSignalPdfs_, *inputFitData);
this->cacheInfo(posScfPdfs_, *inputFitData);
for (LauBkgndPdfsList::iterator iter = posBkgndPdfs_.begin(); iter != posBkgndPdfs_.end(); ++iter) {
this->cacheInfo((*iter), *inputFitData);
}
}
// the SCF fractions and jacobians
if ( useSCF_ && useSCFHist_ ) {
if ( !inputFitData->haveBranch( "m13Sq" ) || !inputFitData->haveBranch( "m23Sq" ) ) {
std::cerr << "ERROR in LauCPFitModel::cacheInputFitVars : Input data does not contain DP branches and so can't cache the SCF fraction." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
UInt_t nEvents = inputFitData->nEvents();
recoSCFFracs_.clear();
recoSCFFracs_.reserve( nEvents );
if ( negKinematics_->squareDP() ) {
recoJacobians_.clear();
recoJacobians_.reserve( nEvents );
}
for (UInt_t iEvt = 0; iEvt < nEvents; iEvt++) {
const LauFitData& dataValues = inputFitData->getData(iEvt);
LauFitData::const_iterator m13_iter = dataValues.find("m13Sq");
LauFitData::const_iterator m23_iter = dataValues.find("m23Sq");
negKinematics_->updateKinematics( m13_iter->second, m23_iter->second );
Double_t scfFrac = scfFracHist_->calcEfficiency( negKinematics_ );
recoSCFFracs_.push_back( scfFrac );
if ( negKinematics_->squareDP() ) {
recoJacobians_.push_back( negKinematics_->calcSqDPJacobian() );
}
}
}
// finally cache the event charge
evtCharges_.clear();
if ( tagged_ ) {
if ( !inputFitData->haveBranch( tagVarName_ ) ) {
std::cerr << "ERROR in LauCPFitModel::cacheInputFitVars : Input data does not contain branch \"" << tagVarName_ << "\"." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
UInt_t nEvents = inputFitData->nEvents();
evtCharges_.reserve( nEvents );
for (UInt_t iEvt = 0; iEvt < nEvents; iEvt++) {
const LauFitData& dataValues = inputFitData->getData(iEvt);
LauFitData::const_iterator iter = dataValues.find( tagVarName_ );
curEvtCharge_ = static_cast<Int_t>( iter->second );
evtCharges_.push_back( curEvtCharge_ );
}
}
}
void LauCPFitModel::appendBinCentres( LauFitDataTree* inputData )
{
// We'll be caching the DP amplitudes and efficiencies of the centres of the true bins.
// To do so, we attach some fake points at the end of inputData, the number of the entry
// minus the total number of events corresponding to the number of the histogram for that
// given true bin in the LauScfMap object. (What this means is that when Laura is provided with
// the LauScfMap object by the user, it's the latter who has to make sure that it contains the
// right number of histograms and in exactly the right order!)
// Get the x and y co-ordinates of the bin centres
std::vector<Double_t> binCentresXCoords;
std::vector<Double_t> binCentresYCoords;
scfMap_->listBinCentres(binCentresXCoords, binCentresYCoords);
// The SCF histograms could be in square Dalitz plot histograms.
// The dynamics takes normal Dalitz plot coords, so we might have to convert them back.
Bool_t sqDP = negKinematics_->squareDP();
UInt_t nBins = binCentresXCoords.size();
fakeSCFFracs_.clear();
fakeSCFFracs_.reserve( nBins );
if ( sqDP ) {
fakeJacobians_.clear();
fakeJacobians_.reserve( nBins );
}
for (UInt_t iBin = 0; iBin < nBins; ++iBin) {
if ( sqDP ) {
negKinematics_->updateSqDPKinematics(binCentresXCoords[iBin],binCentresYCoords[iBin]);
binCentresXCoords[iBin] = negKinematics_->getm13Sq();
binCentresYCoords[iBin] = negKinematics_->getm23Sq();
fakeJacobians_.push_back( negKinematics_->calcSqDPJacobian() );
} else {
negKinematics_->updateKinematics(binCentresXCoords[iBin],binCentresYCoords[iBin]);
}
fakeSCFFracs_.push_back( scfFracHist_->calcEfficiency( negKinematics_ ) );
}
// Set up inputFitVars_ object to hold the fake events
inputData->appendFakePoints(binCentresXCoords,binCentresYCoords);
}
Double_t LauCPFitModel::getTotEvtLikelihood(UInt_t iEvt)
{
// Find out whether we have B- or B+
if ( tagged_ ) {
curEvtCharge_ = evtCharges_[iEvt];
// check that the charge is either +1 or -1
if (TMath::Abs(curEvtCharge_)!=1) {
std::cerr << "ERROR in LauCPFitModel::getTotEvtLikelihood : Charge/tag not accepted value: " << curEvtCharge_ << std::endl;
if (curEvtCharge_>0) {
curEvtCharge_ = +1;
} else {
curEvtCharge_ = -1;
}
std::cerr << " : Making it: " << curEvtCharge_ << "." << std::endl;
}
}
// Get the DP likelihood for signal and backgrounds
this->getEvtDPLikelihood(iEvt);
// Get the combined extra PDFs likelihood for signal and backgrounds
this->getEvtExtraLikelihoods(iEvt);
// If appropriate, combine the TM and SCF likelihoods
Double_t sigLike = sigDPLike_ * sigExtraLike_;
if ( useSCF_ ) {
Double_t scfFrac(0.0);
if (useSCFHist_) {
scfFrac = recoSCFFracs_[iEvt];
} else {
scfFrac = scfFrac_.value();
}
sigLike *= (1.0 - scfFrac);
if ( (scfMap_ != 0) && (this->useDP() == kTRUE) ) {
// if we're smearing the SCF DP PDF then the SCF frac
// is already included in the SCF DP likelihood
sigLike += (scfDPLike_ * scfExtraLike_);
} else {
sigLike += (scfFrac * scfDPLike_ * scfExtraLike_);
}
}
// Get the correct event fractions depending on the charge
// Signal asymmetry is built into the DP model... but when the DP
// isn't in the fit we need an explicit parameter
Double_t signalEvents = signalEvents_->value() * 0.5;
if (this->useDP() == kFALSE) {
signalEvents *= (1.0 - curEvtCharge_ * signalAsym_->value());
}
// Construct the total event likelihood
Double_t likelihood(0.0);
if (usingBkgnd_) {
likelihood = sigLike*signalEvents;
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
Double_t bkgndEvents = bkgndEvents_[bkgndID]->value() * 0.5 * (1.0 - curEvtCharge_ * bkgndAsym_[bkgndID]->value());
likelihood += bkgndEvents*bkgndDPLike_[bkgndID]*bkgndExtraLike_[bkgndID];
}
} else {
likelihood = sigLike*0.5;
}
return likelihood;
}
Double_t LauCPFitModel::getEventSum() const
{
Double_t eventSum(0.0);
eventSum += signalEvents_->value();
if (usingBkgnd_) {
for (LauBkgndYieldList::const_iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
eventSum += (*iter)->value();
}
}
return eventSum;
}
void LauCPFitModel::getEvtDPLikelihood(UInt_t iEvt)
{
// Function to return the signal and background likelihoods for the
// Dalitz plot for the given event evtNo.
if ( ! this->useDP() ) {
// There's always going to be a term in the likelihood for the
// signal, so we'd better not zero it.
sigDPLike_ = 1.0;
scfDPLike_ = 1.0;
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
if (usingBkgnd_ == kTRUE) {
bkgndDPLike_[bkgndID] = 1.0;
} else {
bkgndDPLike_[bkgndID] = 0.0;
}
}
return;
}
const UInt_t nBkgnds = this->nBkgndClasses();
if ( tagged_ ) {
if (curEvtCharge_==+1) {
posSigModel_->calcLikelihoodInfo(iEvt);
sigDPLike_ = posSigModel_->getEvtDPAmp().abs2();
sigDPLike_ *= posSigModel_->getEvtEff();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
if (usingBkgnd_ == kTRUE) {
bkgndDPLike_[bkgndID] = posBkgndDPModels_[bkgndID]->getLikelihood(iEvt);
} else {
bkgndDPLike_[bkgndID] = 0.0;
}
}
} else {
negSigModel_->calcLikelihoodInfo(iEvt);
sigDPLike_ = negSigModel_->getEvtDPAmp().abs2();
sigDPLike_ *= negSigModel_->getEvtEff();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
if (usingBkgnd_ == kTRUE) {
bkgndDPLike_[bkgndID] = negBkgndDPModels_[bkgndID]->getLikelihood(iEvt);
} else {
bkgndDPLike_[bkgndID] = 0.0;
}
}
}
} else {
posSigModel_->calcLikelihoodInfo(iEvt);
negSigModel_->calcLikelihoodInfo(iEvt);
sigDPLike_ = 0.5 * ( posSigModel_->getEvtDPAmp().abs2() * posSigModel_->getEvtEff() +
negSigModel_->getEvtDPAmp().abs2() * negSigModel_->getEvtEff() );
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
if (usingBkgnd_ == kTRUE) {
bkgndDPLike_[bkgndID] = 0.5 * ( posBkgndDPModels_[bkgndID]->getLikelihood(iEvt) +
negBkgndDPModels_[bkgndID]->getLikelihood(iEvt) );
} else {
bkgndDPLike_[bkgndID] = 0.0;
}
}
}
if ( useSCF_ == kTRUE ) {
if ( scfMap_ == 0 ) {
// we're not smearing the SCF DP position
// so the likelihood is the same as the TM
scfDPLike_ = sigDPLike_;
} else {
// calculate the smeared SCF DP likelihood
scfDPLike_ = this->getEvtSCFDPLikelihood(iEvt);
}
}
// Calculate the signal normalisation
// NB the 2.0 is there so that the 0.5 factor is applied to
// signal and background in the same place otherwise you get
// normalisation problems when you switch off the DP in the fit
Double_t norm = negSigModel_->getDPNorm() + posSigModel_->getDPNorm();
sigDPLike_ *= 2.0/norm;
scfDPLike_ *= 2.0/norm;
}
Double_t LauCPFitModel::getEvtSCFDPLikelihood(UInt_t iEvt)
{
Double_t scfDPLike(0.0);
Double_t recoJacobian(1.0);
Double_t xCoord(0.0);
Double_t yCoord(0.0);
Bool_t squareDP = negKinematics_->squareDP();
if ( squareDP ) {
xCoord = negSigModel_->getEvtmPrime();
yCoord = negSigModel_->getEvtthPrime();
recoJacobian = recoJacobians_[iEvt];
} else {
xCoord = negSigModel_->getEvtm13Sq();
yCoord = negSigModel_->getEvtm23Sq();
}
// Find the bin that our reco event falls in
Int_t recoBin = scfMap_->binNumber( xCoord, yCoord );
// Find out which true Bins contribute to the given reco bin
const std::vector<Int_t>* trueBins = scfMap_->trueBins(recoBin);
const Int_t nDataEvents = this->eventsPerExpt();
// Loop over the true bins
for (std::vector<Int_t>::const_iterator iter = trueBins->begin(); iter != trueBins->end(); ++iter)
{
Int_t trueBin = (*iter);
// prob of a true event in the given true bin migrating to the reco bin
Double_t pRecoGivenTrue = scfMap_->prob( recoBin, trueBin );
Double_t pTrue(0.0);
// We've cached the DP amplitudes and the efficiency for the
// true bin centres, just after the data points
if ( tagged_ ) {
LauAbsDPDynamics* sigModel(0);
if (curEvtCharge_<0) {
sigModel = negSigModel_;
} else {
sigModel = posSigModel_;
}
sigModel->calcLikelihoodInfo( nDataEvents + trueBin );
pTrue = sigModel->getEvtDPAmp().abs2() * sigModel->getEvtEff();
} else {
posSigModel_->calcLikelihoodInfo( nDataEvents + trueBin );
negSigModel_->calcLikelihoodInfo( nDataEvents + trueBin );
pTrue = 0.5 * ( posSigModel_->getEvtDPAmp().abs2() * posSigModel_->getEvtEff() +
negSigModel_->getEvtDPAmp().abs2() * negSigModel_->getEvtEff() );
}
// Get the cached SCF fraction (and jacobian if we're using the square DP)
Double_t scfFraction = fakeSCFFracs_[ trueBin ];
Double_t jacobian(1.0);
if ( squareDP ) {
jacobian = fakeJacobians_[ trueBin ];
}
scfDPLike += pTrue * jacobian * scfFraction * pRecoGivenTrue;
}
// Divide by the reco jacobian
scfDPLike /= recoJacobian;
return scfDPLike;
}
void LauCPFitModel::getEvtExtraLikelihoods(UInt_t iEvt)
{
// Function to return the signal and background likelihoods for the
// extra variables for the given event evtNo.
sigExtraLike_ = 1.0;
const UInt_t nBkgnds = this->nBkgndClasses();
if ( ! tagged_ || curEvtCharge_ < 0 ) {
sigExtraLike_ = this->prodPdfValue( negSignalPdfs_, iEvt );
if (useSCF_) {
scfExtraLike_ = this->prodPdfValue( negScfPdfs_, iEvt );
}
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
if (usingBkgnd_) {
bkgndExtraLike_[bkgndID] = this->prodPdfValue( negBkgndPdfs_[bkgndID], iEvt );
} else {
bkgndExtraLike_[bkgndID] = 0.0;
}
}
} else {
sigExtraLike_ = this->prodPdfValue( posSignalPdfs_, iEvt );
if (useSCF_) {
scfExtraLike_ = this->prodPdfValue( posScfPdfs_, iEvt );
}
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
if (usingBkgnd_) {
bkgndExtraLike_[bkgndID] = this->prodPdfValue( posBkgndPdfs_[bkgndID], iEvt );
} else {
bkgndExtraLike_[bkgndID] = 0.0;
}
}
}
}
void LauCPFitModel::updateCoeffs()
{
negCoeffs_.clear(); posCoeffs_.clear();
negCoeffs_.reserve(nSigComp_); posCoeffs_.reserve(nSigComp_);
for (UInt_t i = 0; i < nSigComp_; i++) {
negCoeffs_.push_back(coeffPars_[i]->antiparticleCoeff());
posCoeffs_.push_back(coeffPars_[i]->particleCoeff());
}
}
void LauCPFitModel::setupSPlotNtupleBranches()
{
// add branches for storing the experiment number and the number of
// the event within the current experiment
this->addSPlotNtupleIntegerBranch("iExpt");
this->addSPlotNtupleIntegerBranch("iEvtWithinExpt");
// Store the efficiency of the event (for inclusive BF calculations).
if (this->storeDPEff()) {
this->addSPlotNtupleDoubleBranch("efficiency");
if ( negSigModel_->usingScfModel() && posSigModel_->usingScfModel() ) {
this->addSPlotNtupleDoubleBranch("scffraction");
}
}
// Store the total event likelihood for each species.
if (useSCF_) {
this->addSPlotNtupleDoubleBranch("sigTMTotalLike");
this->addSPlotNtupleDoubleBranch("sigSCFTotalLike");
this->addSPlotNtupleDoubleBranch("sigSCFFrac");
} else {
this->addSPlotNtupleDoubleBranch("sigTotalLike");
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name( this->bkgndClassName(iBkgnd) );
name += "TotalLike";
this->addSPlotNtupleDoubleBranch(name);
}
}
// Store the DP likelihoods
if (this->useDP()) {
if (useSCF_) {
this->addSPlotNtupleDoubleBranch("sigTMDPLike");
this->addSPlotNtupleDoubleBranch("sigSCFDPLike");
} else {
this->addSPlotNtupleDoubleBranch("sigDPLike");
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name( this->bkgndClassName(iBkgnd) );
name += "DPLike";
this->addSPlotNtupleDoubleBranch(name);
}
}
}
// Store the likelihoods for each extra PDF
if (useSCF_) {
this->addSPlotNtupleBranches(&negSignalPdfs_, "sigTM");
this->addSPlotNtupleBranches(&negScfPdfs_, "sigSCF");
} else {
this->addSPlotNtupleBranches(&negSignalPdfs_, "sig");
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
const LauPdfList* pdfList = &(negBkgndPdfs_[iBkgnd]);
this->addSPlotNtupleBranches(pdfList, bkgndClass);
}
}
}
void LauCPFitModel::addSPlotNtupleBranches(const LauPdfList* extraPdfs, const TString& prefix)
{
if (extraPdfs) {
// Loop through each of the PDFs
for (LauPdfList::const_iterator pdf_iter = extraPdfs->begin(); pdf_iter != extraPdfs->end(); ++pdf_iter) {
// Count the number of input variables that are not
// DP variables (used in the case where there is DP
// dependence for e.g. MVA)
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 1 ) {
// If the PDF only has one variable then
// simply add one branch for that variable
TString varName = (*pdf_iter)->varName();
TString name(prefix);
name += varName;
name += "Like";
this->addSPlotNtupleDoubleBranch(name);
} else if ( nVars == 2 ) {
// If the PDF has two variables then we
// need a branch for them both together and
// branches for each
TString allVars("");
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
allVars += (*var_iter);
TString name(prefix);
name += (*var_iter);
name += "Like";
this->addSPlotNtupleDoubleBranch(name);
}
TString name(prefix);
name += allVars;
name += "Like";
this->addSPlotNtupleDoubleBranch(name);
} else {
std::cerr << "WARNING in LauCPFitModel::addSPlotNtupleBranches : Can't yet deal with 3D PDFs." << std::endl;
}
}
}
}
Double_t LauCPFitModel::setSPlotNtupleBranchValues(LauPdfList* extraPdfs, const TString& prefix, UInt_t iEvt)
{
// Store the PDF value for each variable in the list
Double_t totalLike(1.0);
Double_t extraLike(0.0);
if (extraPdfs) {
for (LauPdfList::iterator pdf_iter = extraPdfs->begin(); pdf_iter != extraPdfs->end(); ++pdf_iter) {
// calculate the likelihood for this event
(*pdf_iter)->calcLikelihoodInfo(iEvt);
extraLike = (*pdf_iter)->getLikelihood();
totalLike *= extraLike;
// Count the number of input variables that are not
// DP variables (used in the case where there is DP
// dependence for e.g. MVA)
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 1 ) {
// If the PDF only has one variable then
// simply store the value for that variable
TString varName = (*pdf_iter)->varName();
TString name(prefix);
name += varName;
name += "Like";
this->setSPlotNtupleDoubleBranchValue(name, extraLike);
} else if ( nVars == 2 ) {
// If the PDF has two variables then we
// store the value for them both together
// and for each on their own
TString allVars("");
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
allVars += (*var_iter);
TString name(prefix);
name += (*var_iter);
name += "Like";
Double_t indivLike = (*pdf_iter)->getLikelihood( (*var_iter) );
this->setSPlotNtupleDoubleBranchValue(name, indivLike);
}
TString name(prefix);
name += allVars;
name += "Like";
this->setSPlotNtupleDoubleBranchValue(name, extraLike);
} else {
std::cerr << "WARNING in LauCPFitModel::setSPlotNtupleBranchValues : Can't yet deal with 3D PDFs." << std::endl;
}
}
}
return totalLike;
}
LauSPlot::NameSet LauCPFitModel::variableNames() const
{
LauSPlot::NameSet nameSet;
if (this->useDP()) {
nameSet.insert("DP");
}
// Loop through all the signal PDFs
for (LauPdfList::const_iterator pdf_iter = negSignalPdfs_.begin(); pdf_iter != negSignalPdfs_.end(); ++pdf_iter) {
// Loop over the variables involved in each PDF
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
// If they are not DP coordinates then add them
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
nameSet.insert( (*var_iter) );
}
}
}
return nameSet;
}
LauSPlot::NumbMap LauCPFitModel::freeSpeciesNames() const
{
LauSPlot::NumbMap numbMap;
if (!signalEvents_->fixed() && this->doEMLFit()) {
numbMap["sig"] = signalEvents_->genValue();
}
if ( usingBkgnd_ ) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
const LauParameter* par = bkgndEvents_[iBkgnd];
if (!par->fixed()) {
numbMap[bkgndClass] = par->genValue();
}
}
}
return numbMap;
}
LauSPlot::NumbMap LauCPFitModel::fixdSpeciesNames() const
{
LauSPlot::NumbMap numbMap;
if (signalEvents_->fixed() && this->doEMLFit()) {
numbMap["sig"] = signalEvents_->genValue();
}
if ( usingBkgnd_ ) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
const LauParameter* par = bkgndEvents_[iBkgnd];
if (par->fixed()) {
numbMap[bkgndClass] = par->genValue();
}
}
}
return numbMap;
}
LauSPlot::TwoDMap LauCPFitModel::twodimPDFs() const
{
// This makes the assumption that the form of the positive and
// negative PDFs are the same, which seems reasonable to me
LauSPlot::TwoDMap twodimMap;
for (LauPdfList::const_iterator pdf_iter = negSignalPdfs_.begin(); pdf_iter != negSignalPdfs_.end(); ++pdf_iter) {
// Count the number of input variables that are not DP variables
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 2 ) {
if (useSCF_) {
twodimMap.insert( std::make_pair( "sigTM", std::make_pair( varNames[0], varNames[1] ) ) );
} else {
twodimMap.insert( std::make_pair( "sig", std::make_pair( varNames[0], varNames[1] ) ) );
}
}
}
if ( useSCF_ ) {
for (LauPdfList::const_iterator pdf_iter = negScfPdfs_.begin(); pdf_iter != negScfPdfs_.end(); ++pdf_iter) {
// Count the number of input variables that are not DP variables
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 2 ) {
twodimMap.insert( std::make_pair( "sigSCF", std::make_pair( varNames[0], varNames[1] ) ) );
}
}
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
const LauPdfList& pdfList = negBkgndPdfs_[iBkgnd];
for (LauPdfList::const_iterator pdf_iter = pdfList.begin(); pdf_iter != pdfList.end(); ++pdf_iter) {
// Count the number of input variables that are not DP variables
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 2 ) {
twodimMap.insert( std::make_pair( bkgndClass, std::make_pair( varNames[0], varNames[1] ) ) );
}
}
}
}
return twodimMap;
}
void LauCPFitModel::storePerEvtLlhds()
{
std::cout << "INFO in LauCPFitModel::storePerEvtLlhds : Storing per-event likelihood values..." << std::endl;
// if we've not been using the DP model then we need to cache all
// the info here so that we can get the efficiency from it
LauFitDataTree* inputFitData = this->fitData();
if (!this->useDP() && this->storeDPEff()) {
negSigModel_->initialise(negCoeffs_);
posSigModel_->initialise(posCoeffs_);
negSigModel_->fillDataTree(*inputFitData);
posSigModel_->fillDataTree(*inputFitData);
}
UInt_t evtsPerExpt(this->eventsPerExpt());
LauAbsDPDynamics* sigModel(0);
LauPdfList* sigPdfs(0);
LauPdfList* scfPdfs(0);
LauBkgndPdfsList* bkgndPdfs(0);
for (UInt_t iEvt = 0; iEvt < evtsPerExpt; ++iEvt) {
this->setSPlotNtupleIntegerBranchValue("iExpt",this->iExpt());
this->setSPlotNtupleIntegerBranchValue("iEvtWithinExpt",iEvt);
// Find out whether we have B- or B+
if ( tagged_ ) {
const LauFitData& dataValues = inputFitData->getData(iEvt);
LauFitData::const_iterator iter = dataValues.find("charge");
curEvtCharge_ = static_cast<Int_t>(iter->second);
if (curEvtCharge_==+1) {
sigModel = posSigModel_;
sigPdfs = &posSignalPdfs_;
scfPdfs = &posScfPdfs_;
bkgndPdfs = &posBkgndPdfs_;
} else {
sigModel = negSigModel_;
sigPdfs = &negSignalPdfs_;
scfPdfs = &negScfPdfs_;
bkgndPdfs = &negBkgndPdfs_;
}
} else {
sigPdfs = &negSignalPdfs_;
scfPdfs = &negScfPdfs_;
bkgndPdfs = &negBkgndPdfs_;
}
// the DP information
this->getEvtDPLikelihood(iEvt);
if (this->storeDPEff()) {
if (!this->useDP()) {
posSigModel_->calcLikelihoodInfo(iEvt);
negSigModel_->calcLikelihoodInfo(iEvt);
}
if ( tagged_ ) {
this->setSPlotNtupleDoubleBranchValue("efficiency",sigModel->getEvtEff());
if ( negSigModel_->usingScfModel() && posSigModel_->usingScfModel() ) {
this->setSPlotNtupleDoubleBranchValue("scffraction",sigModel->getEvtScfFraction());
}
} else {
this->setSPlotNtupleDoubleBranchValue("efficiency",0.5*(posSigModel_->getEvtEff() + negSigModel_->getEvtEff()) );
if ( negSigModel_->usingScfModel() && posSigModel_->usingScfModel() ) {
this->setSPlotNtupleDoubleBranchValue("scffraction",0.5*(posSigModel_->getEvtScfFraction() + negSigModel_->getEvtScfFraction()));
}
}
}
if (this->useDP()) {
sigTotalLike_ = sigDPLike_;
if (useSCF_) {
scfTotalLike_ = scfDPLike_;
this->setSPlotNtupleDoubleBranchValue("sigTMDPLike",sigDPLike_);
this->setSPlotNtupleDoubleBranchValue("sigSCFDPLike",scfDPLike_);
} else {
this->setSPlotNtupleDoubleBranchValue("sigDPLike",sigDPLike_);
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name = this->bkgndClassName(iBkgnd);
name += "DPLike";
this->setSPlotNtupleDoubleBranchValue(name,bkgndDPLike_[iBkgnd]);
}
}
} else {
sigTotalLike_ = 1.0;
if (useSCF_) {
scfTotalLike_ = 1.0;
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
bkgndTotalLike_[iBkgnd] = 1.0;
}
}
}
// the signal PDF values
if ( useSCF_ ) {
sigTotalLike_ *= this->setSPlotNtupleBranchValues(sigPdfs, "sigTM", iEvt);
scfTotalLike_ *= this->setSPlotNtupleBranchValues(scfPdfs, "sigSCF", iEvt);
} else {
sigTotalLike_ *= this->setSPlotNtupleBranchValues(sigPdfs, "sig", iEvt);
}
// the background PDF values
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
LauPdfList& pdfs = (*bkgndPdfs)[iBkgnd];
bkgndTotalLike_[iBkgnd] *= this->setSPlotNtupleBranchValues(&(pdfs), bkgndClass, iEvt);
}
}
// the total likelihoods
if (useSCF_) {
Double_t scfFrac(0.0);
if ( useSCFHist_ ) {
scfFrac = recoSCFFracs_[iEvt];
} else {
scfFrac = scfFrac_.value();
}
this->setSPlotNtupleDoubleBranchValue("sigSCFFrac",scfFrac);
sigTotalLike_ *= ( 1.0 - scfFrac );
if ( scfMap_ == 0 ) {
scfTotalLike_ *= scfFrac;
}
this->setSPlotNtupleDoubleBranchValue("sigTMTotalLike",sigTotalLike_);
this->setSPlotNtupleDoubleBranchValue("sigSCFTotalLike",scfTotalLike_);
} else {
this->setSPlotNtupleDoubleBranchValue("sigTotalLike",sigTotalLike_);
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name = this->bkgndClassName(iBkgnd);
name += "TotalLike";
this->setSPlotNtupleDoubleBranchValue(name,bkgndTotalLike_[iBkgnd]);
}
}
// fill the tree
this->fillSPlotNtupleBranches();
}
std::cout << "INFO in LauCPFitModel::storePerEvtLlhds : Finished storing per-event likelihood values." << std::endl;
}
void LauCPFitModel::embedNegSignal(const TString& fileName, const TString& treeName,
Bool_t reuseEventsWithinEnsemble, Bool_t reuseEventsWithinExperiment,
Bool_t useReweighting)
{
if (negSignalTree_) {
std::cerr << "ERROR in LauCPFitModel::embedNegSignal : Already embedding signal from a file." << std::endl;
return;
}
if (!reuseEventsWithinEnsemble && reuseEventsWithinExperiment) {
std::cerr << "WARNING in LauCPFitModel::embedNegSignal : Conflicting options provided, will not reuse events at all." << std::endl;
reuseEventsWithinExperiment = kFALSE;
}
negSignalTree_ = new LauEmbeddedData(fileName,treeName,reuseEventsWithinExperiment);
Bool_t dataOK = negSignalTree_->findBranches();
if (!dataOK) {
delete negSignalTree_; negSignalTree_ = 0;
std::cerr << "ERROR in LauCPFitModel::embedNegSignal : Problem creating data tree for embedding." << std::endl;
return;
}
reuseSignal_ = reuseEventsWithinEnsemble;
useNegReweighting_ = useReweighting;
if (this->enableEmbedding() == kFALSE) {this->enableEmbedding(kTRUE);}
}
void LauCPFitModel::embedNegBkgnd(const TString& bkgndClass, const TString& fileName, const TString& treeName,
Bool_t reuseEventsWithinEnsemble, Bool_t reuseEventsWithinExperiment)
{
if ( ! this->validBkgndClass( bkgndClass ) ) {
std::cerr << "ERROR in LauCPFitModel::embedBkgnd : Invalid background class \"" << bkgndClass << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
return;
}
UInt_t bkgndID = this->bkgndClassID( bkgndClass );
if (negBkgndTree_[bkgndID]) {
std::cerr << "ERROR in LauCPFitModel::embedNegBkgnd : Already embedding background from a file." << std::endl;
return;
}
if (!reuseEventsWithinEnsemble && reuseEventsWithinExperiment) {
std::cerr << "WARNING in LauCPFitModel::embedNegBkgnd : Conflicting options provided, will not reuse events at all." << std::endl;
reuseEventsWithinExperiment = kFALSE;
}
negBkgndTree_[bkgndID] = new LauEmbeddedData(fileName,treeName,reuseEventsWithinExperiment);
Bool_t dataOK = negBkgndTree_[bkgndID]->findBranches();
if (!dataOK) {
delete negBkgndTree_[bkgndID]; negBkgndTree_[bkgndID] = 0;
std::cerr << "ERROR in LauCPFitModel::embedNegBkgnd : Problem creating data tree for embedding." << std::endl;
return;
}
reuseBkgnd_[bkgndID] = reuseEventsWithinEnsemble;
if (this->enableEmbedding() == kFALSE) {this->enableEmbedding(kTRUE);}
}
void LauCPFitModel::embedPosSignal(const TString& fileName, const TString& treeName,
Bool_t reuseEventsWithinEnsemble, Bool_t reuseEventsWithinExperiment,
Bool_t useReweighting)
{
if (posSignalTree_) {
std::cerr << "ERROR in LauCPFitModel::embedPosSignal : Already embedding signal from a file." << std::endl;
return;
}
if (!reuseEventsWithinEnsemble && reuseEventsWithinExperiment) {
std::cerr << "WARNING in LauCPFitModel::embedPosSignal : Conflicting options provided, will not reuse events at all." << std::endl;
reuseEventsWithinExperiment = kFALSE;
}
posSignalTree_ = new LauEmbeddedData(fileName,treeName,reuseEventsWithinExperiment);
Bool_t dataOK = posSignalTree_->findBranches();
if (!dataOK) {
delete posSignalTree_; posSignalTree_ = 0;
std::cerr << "ERROR in LauCPFitModel::embedPosSignal : Problem creating data tree for embedding." << std::endl;
return;
}
reuseSignal_ = reuseEventsWithinEnsemble;
usePosReweighting_ = useReweighting;
if (this->enableEmbedding() == kFALSE) {this->enableEmbedding(kTRUE);}
}
void LauCPFitModel::embedPosBkgnd(const TString& bkgndClass, const TString& fileName, const TString& treeName,
Bool_t reuseEventsWithinEnsemble, Bool_t reuseEventsWithinExperiment)
{
if ( ! this->validBkgndClass( bkgndClass ) ) {
std::cerr << "ERROR in LauCPFitModel::embedBkgnd : Invalid background class \"" << bkgndClass << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
return;
}
UInt_t bkgndID = this->bkgndClassID( bkgndClass );
if (posBkgndTree_[bkgndID]) {
std::cerr << "ERROR in LauCPFitModel::embedPosBkgnd : Already embedding background from a file." << std::endl;
return;
}
if (!reuseEventsWithinEnsemble && reuseEventsWithinExperiment) {
std::cerr << "WARNING in LauCPFitModel::embedPosBkgnd : Conflicting options provided, will not reuse events at all." << std::endl;
reuseEventsWithinExperiment = kFALSE;
}
posBkgndTree_[bkgndID] = new LauEmbeddedData(fileName,treeName,reuseEventsWithinExperiment);
Bool_t dataOK = posBkgndTree_[bkgndID]->findBranches();
if (!dataOK) {
delete posBkgndTree_[bkgndID]; posBkgndTree_[bkgndID] = 0;
std::cerr << "ERROR in LauCPFitModel::embedPosBkgnd : Problem creating data tree for embedding." << std::endl;
return;
}
reuseBkgnd_[bkgndID] = reuseEventsWithinEnsemble;
if (this->enableEmbedding() == kFALSE) {this->enableEmbedding(kTRUE);}
}
void LauCPFitModel::weightEvents( const TString& /*dataFileName*/, const TString& /*dataTreeName*/ )
{
std::cerr << "ERROR in LauCPFitModel::weightEvents : Method not available for this fit model." << std::endl;
return;
}
diff --git a/src/LauEffModel.cc b/src/LauEffModel.cc
index 1ce77bb..95c9895 100644
--- a/src/LauEffModel.cc
+++ b/src/LauEffModel.cc
@@ -1,322 +1,322 @@
// Copyright University of Warwick 2004 - 2013.
// 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 LauEffModel.cc
\brief File containing implementation of LauEffModel class.
*/
#include <cstdlib>
#include <iostream>
#include "TSystem.h"
#include "Lau2DHistDP.hh"
#include "Lau2DSplineDP.hh"
#include "LauDaughters.hh"
#include "LauEffModel.hh"
#include "LauKinematics.hh"
#include "LauVetoes.hh"
ClassImp(LauEffModel)
LauEffModel::LauEffModel(const LauDaughters* daughters, const LauVetoes* vetoes) :
daughters_( daughters ),
vetoes_( vetoes ),
effHisto_( 0 ),
squareDP_( kFALSE ),
fluctuateEffHisto_( kFALSE ),
lowBinWarningIssued_( kFALSE ),
highBinWarningIssued_( kFALSE )
{
if ( daughters_ == 0 ) {
std::cerr << "ERROR in LauEffModel Constructor : invalid pointer to daughters object supplied." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
LauEffModel::~LauEffModel()
{
std::vector<Lau2DAbsDP*>::iterator it = effHisto_.begin();
std::vector<Lau2DAbsDP*>::iterator end = effHisto_.end();
for( ; it!=end; ++it) {
delete *it;
*it=0;
}
effHisto_.clear();
}
void LauEffModel::setEffHisto(const TH2* effHisto, Bool_t useInterpolation,
Bool_t fluctuateBins, Double_t avEff, Double_t absError,
Bool_t useUpperHalfOnly, Bool_t squareDP)
{
// Set the efficiency across the Dalitz plot using a predetermined 2D histogram
// with x = m_13^2, y = m_23^2.
Bool_t upperHalf( kFALSE );
if ( daughters_->gotSymmetricalDP() && useUpperHalfOnly == kTRUE) {upperHalf = kTRUE;}
std::cout<<"INFO in LauEffModel::setEffSpline : Efficiency histogram has upperHalf = "<<static_cast<Int_t>(upperHalf)<<std::endl;
squareDP_ = squareDP;
std::vector<Lau2DAbsDP*>::iterator it = effHisto_.begin();
std::vector<Lau2DAbsDP*>::iterator end = effHisto_.end();
for( ; it!=end; ++it) {
delete *it;
*it=0;
}
effHisto_.clear();
// Copy the histogram.
effHisto_.push_back(new Lau2DHistDP(effHisto, daughters_,
useInterpolation, fluctuateBins,
avEff, absError, upperHalf, squareDP));
fluctuateEffHisto_ = fluctuateBins;
if (avEff > 0.0 && absError > 0.0) {
fluctuateEffHisto_ = kTRUE;
}
}
void LauEffModel::setEffHisto(const TH2* effHisto, const TH2* errorHi, const TH2* errorLo, Bool_t useInterpolation,
Bool_t fluctuateBins, Double_t avEff, Double_t absError,
Bool_t useUpperHalfOnly, Bool_t squareDP)
{
// Set the efficiency across the Dalitz plot using a predetermined 2D histogram
// with x = m_13^2, y = m_23^2.
Bool_t upperHalf( kFALSE );
if ( daughters_->gotSymmetricalDP() && useUpperHalfOnly == kTRUE) {upperHalf = kTRUE;}
std::cout<<"INFO in LauEffModel::setEffSpline : Efficiency histogram has upperHalf = "<<static_cast<Int_t>(upperHalf)<<std::endl;
squareDP_ = squareDP;
std::vector<Lau2DAbsDP*>::iterator it = effHisto_.begin();
std::vector<Lau2DAbsDP*>::iterator end = effHisto_.end();
for( ; it!=end; ++it) {
delete *it;
*it=0;
}
effHisto_.clear();
// Copy the histogram.
effHisto_.push_back(new Lau2DHistDP(effHisto, errorHi, errorLo, daughters_,
useInterpolation, fluctuateBins,
avEff, absError, upperHalf, squareDP));
fluctuateEffHisto_ = fluctuateBins;
if (avEff > 0.0 && absError > 0.0) {
fluctuateEffHisto_ = kTRUE;
}
}
void LauEffModel::setEffSpline(const TH2* effHisto,
Bool_t fluctuateBins, Double_t avEff, Double_t absError,
Bool_t useUpperHalfOnly, Bool_t squareDP)
{
// Set the efficiency across the Dalitz plot using a predetermined 2D histogram
// with x = m_13^2, y = m_23^2.
Bool_t upperHalf( kFALSE );
if ( daughters_->gotSymmetricalDP() && useUpperHalfOnly == kTRUE) {upperHalf = kTRUE;}
std::cout<<"INFO in LauEffModel::setEffSpline : Efficiency histogram has upperHalf = "<<static_cast<Int_t>(upperHalf)<<std::endl;
squareDP_ = squareDP;
std::vector<Lau2DAbsDP*>::iterator it = effHisto_.begin();
std::vector<Lau2DAbsDP*>::iterator end = effHisto_.end();
for( ; it!=end; ++it) {
delete *it;
*it=0;
}
effHisto_.clear();
// Copy the histogram.
effHisto_.push_back(new Lau2DSplineDP(effHisto, daughters_,
fluctuateBins, avEff, absError, upperHalf, squareDP));
fluctuateEffHisto_ = fluctuateBins;
if (avEff > 0.0 && absError > 0.0) {
fluctuateEffHisto_ = kTRUE;
}
}
void LauEffModel::setEffSpline(const TH2* effHisto, const TH2* errorHi, const TH2* errorLo,
Bool_t fluctuateBins, Double_t avEff, Double_t absError,
Bool_t useUpperHalfOnly, Bool_t squareDP)
{
// Set the efficiency across the Dalitz plot using a predetermined 2D histogram
// with x = m_13^2, y = m_23^2.
Bool_t upperHalf( kFALSE );
if ( daughters_->gotSymmetricalDP() && useUpperHalfOnly == kTRUE) {upperHalf = kTRUE;}
std::cout<<"INFO in LauEffModel::setEffSpline : Efficiency histogram has upperHalf = "<<static_cast<Int_t>(upperHalf)<<std::endl;
squareDP_ = squareDP;
std::vector<Lau2DAbsDP*>::iterator it = effHisto_.begin();
std::vector<Lau2DAbsDP*>::iterator end = effHisto_.end();
for( ; it!=end; ++it) {
delete *it;
*it=0;
}
effHisto_.clear();
// Copy the histogram.
effHisto_.push_back(new Lau2DSplineDP(effHisto, errorHi, errorLo, daughters_,
fluctuateBins, avEff, absError, upperHalf, squareDP));
fluctuateEffHisto_ = fluctuateBins;
if (avEff > 0.0 && absError > 0.0) {
fluctuateEffHisto_ = kTRUE;
}
}
void LauEffModel::addEffHisto(const TH2* effHisto, Bool_t useInterpolation,
Double_t avEff, Double_t absError,
Bool_t useUpperHalfOnly, Bool_t squareDP)
{
// Set the efficiency across the Dalitz plot using a predetermined 2D histogram
// with x = m_13^2, y = m_23^2.
Bool_t upperHalf( kFALSE );
if ( daughters_->gotSymmetricalDP() && useUpperHalfOnly == kTRUE) {upperHalf = kTRUE;}
std::cout<<"INFO in LauEffModel::setEffSpline : Efficiency histogram has upperHalf = "<<static_cast<Int_t>(upperHalf)<<std::endl;
squareDP_ = squareDP;
// Copy the histogram.
effHisto_.push_back(new Lau2DHistDP(effHisto, daughters_,
useInterpolation, fluctuateEffHisto_,
avEff, absError, upperHalf, squareDP));
}
void LauEffModel::addEffHisto(const TH2* effHisto, const TH2* errorHi, const TH2* errorLo, Bool_t useInterpolation,
Double_t avEff, Double_t absError,
Bool_t useUpperHalfOnly, Bool_t squareDP)
{
// Set the efficiency across the Dalitz plot using a predetermined 2D histogram
// with x = m_13^2, y = m_23^2.
Bool_t upperHalf( kFALSE );
if ( daughters_->gotSymmetricalDP() && useUpperHalfOnly == kTRUE) {upperHalf = kTRUE;}
std::cout<<"INFO in LauEffModel::setEffSpline : Efficiency histogram has upperHalf = "<<static_cast<Int_t>(upperHalf)<<std::endl;
squareDP_ = squareDP;
// Copy the histogram.
effHisto_.push_back(new Lau2DHistDP(effHisto, errorHi, errorLo, daughters_,
useInterpolation, fluctuateEffHisto_,
avEff, absError, upperHalf, squareDP));
}
void LauEffModel::addEffSpline(const TH2* effHisto,
Double_t avEff, Double_t absError,
Bool_t useUpperHalfOnly, Bool_t squareDP)
{
// Set the efficiency across the Dalitz plot using a predetermined 2D histogram
// with x = m_13^2, y = m_23^2.
Bool_t upperHalf( kFALSE );
if ( daughters_->gotSymmetricalDP() && useUpperHalfOnly == kTRUE) {upperHalf = kTRUE;}
std::cout<<"INFO in LauEffModel::setEffSpline : Efficiency histogram has upperHalf = "<<static_cast<Int_t>(upperHalf)<<std::endl;
squareDP_ = squareDP;
// Copy the histogram.
effHisto_.push_back(new Lau2DSplineDP(effHisto, daughters_,
fluctuateEffHisto_, avEff, absError, upperHalf, squareDP));
}
void LauEffModel::addEffSpline(const TH2* effHisto, const TH2* errorHi, const TH2* errorLo,
Double_t avEff, Double_t absError,
Bool_t useUpperHalfOnly, Bool_t squareDP)
{
// Set the efficiency across the Dalitz plot using a predetermined 2D histogram
// with x = m_13^2, y = m_23^2.
Bool_t upperHalf( kFALSE );
if ( daughters_->gotSymmetricalDP() && useUpperHalfOnly == kTRUE) {upperHalf = kTRUE;}
std::cout<<"INFO in LauEffModel::setEffSpline : Efficiency histogram has upperHalf = "<<static_cast<Int_t>(upperHalf)<<std::endl;
squareDP_ = squareDP;
// Copy the histogram.
effHisto_.push_back(new Lau2DSplineDP(effHisto, errorHi, errorLo, daughters_,
fluctuateEffHisto_, avEff, absError, upperHalf, squareDP));
}
Double_t LauEffModel::getEffHistValue(Double_t xVal, Double_t yVal) const
{
// Get the efficiency from the 2D histo.
Double_t eff(1.0);
std::vector<Lau2DAbsDP*>::const_iterator it = effHisto_.begin();
std::vector<Lau2DAbsDP*>::const_iterator end = effHisto_.end();
for( ; it!=end; ++it) {
eff *= (*it)->interpolateXY(xVal, yVal);
}
return eff;
}
Double_t LauEffModel::calcEfficiency( const LauKinematics* kinematics ) const
{
// Routine to calculate the efficiency for the given event/point in
// the Dalitz plot. This routine uses the 2D histogram set by the
- // setEffHisto() funciton.
+ // setEffHisto() function.
Double_t eff(1.0);
// Check for vetoes
Bool_t vetoOK(kTRUE);
if ( vetoes_ != 0 ) {
vetoOK = vetoes_->passVeto(kinematics);
}
if (vetoOK == kFALSE) {
// We failed the veto.
eff = 0.0;
} else {
// We are using a 2D histogram representation of the efficiency across the Dalitz plot.
// First find out which bin we are in given the x and y Dalitz plot mass values
// Here, x = m13^2, y = m23^2 or if using square DP x = m', y = theta'.
if (squareDP_ == kTRUE) {
eff = this->getEffHistValue(kinematics->getmPrime(), kinematics->getThetaPrime());
} else {
eff = this->getEffHistValue(kinematics->getm13Sq(), kinematics->getm23Sq());
}
}
// Check that the efficiency is in the allowed range (0-1)
// If we're using a spline then out-of-range efficiencies can be caused by adjacent bins that all contain a value of either zero or one.
// The spline requires the efficiency, its first derivatives and the mixed second derivative to be continuous and to match the input histogram
// at the bin centres. Derivatives are calculated using a finite difference approximation taking the difference between the neighbouring bins.
// If two bins are zero but the third is not then the second bin will have a positive first derivative causing the spline to dip below zero
// between the two zero bins to remain smooth. The analogous case with adjacent maximised bins will cause peaks above one. Such dips are
// unavoidable but are correctly removed here.
if ( eff < 0.0 ) {
if(!lowBinWarningIssued_) {
std::cerr << "WARNING in LauEffModel::calcEfficiency : Efficiency " << eff << " is less than 0 - setting to 0. You may want to check your histogram!" << std::endl
<< " : If you are using a spline then this could be caused by adjacent empty bins. Further warnings will be suppressed." << std::endl;
lowBinWarningIssued_=kTRUE;
}
eff = 0.0;
} else if ( eff > 1.0 ) {
if(!highBinWarningIssued_) {
std::cerr << "WARNING in LauEffModel::calcEfficiency : Efficiency " << eff << " is greater than 1 - setting to 1. You may want to check your histogram!" << std::endl
<< " : If you are using a spline then this could be caused by adjacent full bins. Further warnings will be suppressed." << std::endl;
highBinWarningIssued_=kTRUE;
}
eff = 1.0;
}
return eff;
}
Bool_t LauEffModel::passVeto( const LauKinematics* kinematics ) const
{
Bool_t pass = kTRUE;
if ( vetoes_ != 0 ) {
pass = vetoes_->passVeto( kinematics );
}
return pass;
}
diff --git a/src/LauIsobarDynamics.cc b/src/LauIsobarDynamics.cc
index 49490b9..6bd0e84 100644
--- a/src/LauIsobarDynamics.cc
+++ b/src/LauIsobarDynamics.cc
@@ -1,1899 +1,1899 @@
// Copyright University of Warwick 2005 - 2013.
// 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 "TFile.h"
#include "TRandom.h"
#include "TSystem.h"
#include "LauAbsResonance.hh"
#include "LauBelleNR.hh"
#include "LauBelleSymNR.hh"
#include "LauConstants.hh"
#include "LauDaughters.hh"
-#include "LauEffModel.hh"
+#include "LauAbsEffModel.hh"
#include "LauFitDataTree.hh"
#include "LauGounarisSakuraiRes.hh"
#include "LauIntegrals.hh"
#include "LauIsobarDynamics.hh"
#include "LauKinematics.hh"
#include "LauKMatrixPropagator.hh"
#include "LauKMatrixPropFactory.hh"
#include "LauKMatrixProdPole.hh"
#include "LauKMatrixProdSVP.hh"
#include "LauNRAmplitude.hh"
#include "LauPolNR.hh"
#include "LauPrint.hh"
#include "LauRandom.hh"
#include "LauRelBreitWignerRes.hh"
#include "LauResonanceMaker.hh"
ClassImp(LauIsobarDynamics)
// for Kpipi: only one scfFraction 2D histogram is needed
-LauIsobarDynamics::LauIsobarDynamics(LauDaughters* daughters, LauEffModel* effModel, LauEffModel* scfFractionModel) :
+LauIsobarDynamics::LauIsobarDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, LauAbsEffModel* scfFractionModel) :
LauAbsDPDynamics(daughters, effModel, scfFractionModel),
symmetricalDP_(kFALSE),
integralsDone_(kFALSE),
intFileName_("integ.dat"),
m13BinWidth_(0.005),
m23BinWidth_(0.005),
m13Sq_(0.0),
m23Sq_(0.0),
mPrime_(0.0),
thPrime_(0.0),
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),
BelleNRAlpha_(0.0),
LASSScatteringLength_(0.0),
LASSEffectiveRange_(0.0),
LASSResonanceMag_(0.0),
LASSResonancePhase_(0.0),
LASSBackgroundMag_(0.0),
LASSBackgroundPhase_(0.0),
LASSCutOff_(0.0),
changeLASSScatteringLength_(kFALSE),
changeLASSEffectiveRange_(kFALSE),
changeLASSResonanceMag_(kFALSE),
changeLASSResonancePhase_(kFALSE),
changeLASSBackgroundMag_(kFALSE),
changeLASSBackgroundPhase_(kFALSE),
changeLASSCutOff_(kFALSE),
FlatteParameterg1_(0.0),
FlatteParameterg2_(0.0),
changeFlatteParameterg1_(kFALSE),
changeFlatteParameterg2_(kFALSE),
resBarrierRadius_(4.0),
parBarrierRadius_(4.0),
barrierType_( LauAbsResonance::BWPrimeBarrier ),
flipHelicity_(kTRUE)
{
// Constructor for the isobar signal model
if (daughters != 0) {
symmetricalDP_ = daughters->gotSymmetricalDP();
typDaug_.push_back(daughters->getTypeDaug1());
typDaug_.push_back(daughters->getTypeDaug2());
typDaug_.push_back(daughters->getTypeDaug3());
}
sigResonances_.clear();
kMatrixPropagators_.clear();
kMatrixPropSet_.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, LauEffModel* effModel, LauTagCatScfFractionModelMap scfFractionModel) :
+LauIsobarDynamics::LauIsobarDynamics(LauDaughters* daughters, LauAbsEffModel* effModel, LauTagCatScfFractionModelMap scfFractionModel) :
LauAbsDPDynamics(daughters, effModel, scfFractionModel),
symmetricalDP_(kFALSE),
integralsDone_(kFALSE),
intFileName_("integ.dat"),
m13BinWidth_(0.005),
m23BinWidth_(0.005),
m13Sq_(0.0),
m23Sq_(0.0),
mPrime_(0.0),
thPrime_(0.0),
eff_(0.0),
scfFraction_(0.0),
jacobian_(0.0),
ASq_(0.0),
evtLike_(0.0),
iterationsMax_(100000),
nSigGenLoop_(0),
aSqMaxSet_(1.25),
aSqMaxVar_(0.0),
BelleNRAlpha_(0.0),
LASSScatteringLength_(0.0),
LASSEffectiveRange_(0.0),
LASSResonanceMag_(0.0),
LASSResonancePhase_(0.0),
LASSBackgroundMag_(0.0),
LASSBackgroundPhase_(0.0),
LASSCutOff_(0.0),
changeLASSScatteringLength_(kFALSE),
changeLASSEffectiveRange_(kFALSE),
changeLASSResonanceMag_(kFALSE),
changeLASSResonancePhase_(kFALSE),
changeLASSBackgroundMag_(kFALSE),
changeLASSBackgroundPhase_(kFALSE),
changeLASSCutOff_(kFALSE),
FlatteParameterg1_(0.0),
FlatteParameterg2_(0.0),
changeFlatteParameterg1_(kFALSE),
changeFlatteParameterg2_(kFALSE),
resBarrierRadius_(4.0),
parBarrierRadius_(4.0),
barrierType_( LauAbsResonance::BWPrimeBarrier ),
flipHelicity_(kTRUE)
{
// Constructor for the isobar signal model
if (daughters != 0) {
symmetricalDP_ = daughters->gotSymmetricalDP();
typDaug_.push_back(daughters->getTypeDaug1());
typDaug_.push_back(daughters->getTypeDaug2());
typDaug_.push_back(daughters->getTypeDaug3());
}
sigResonances_.clear();
kMatrixPropagators_.clear();
kMatrixPropSet_.clear();
}
LauIsobarDynamics::~LauIsobarDynamics()
{
}
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();
integralsDone_ = kFALSE;
// Print summary of what we have so far to screen
this->initSummary();
if ( nAmp_ == 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;
this->calcDPNormalisation();
// Write the integrals to a file (mainly for debugging purposes)
this->writeIntegralsFile();
}
integralsDone_ = kTRUE;
std::cout << std::setprecision(10);
// Calculate and cache the relative normalisations of each resonance _dynamic_ amplitude
// (e.g. Breit-Wigner contribution, not from the complex amplitude/phase) w.r.t. the
// total DP amplitude. These are stored in fNorm_[i].
// The normalisation uses fSqSum[i], which is calculated within the dynamics() function,
// which has already been called by the calcDPNomalisation() function above to create the
// normalisation integrals.
// fSqSum[i] is the event-by-event running 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.
std::cout<<"INFO in LauIsobarDynamics::initialise : Summary of the integrals:"<<std::endl;
for (UInt_t i = 0; i < nAmp_; i++) {
fNorm_[i] = 0.0;
if (fSqSum_[i] > 0.0) {fNorm_[i] = TMath::Sqrt(1.0/(fSqSum_[i]));}
std::cout<<" fNorm["<<i<<"] = "<<fNorm_[i]<<std::endl;
std::cout<<" fSqSum["<<i<<"] = "<<fSqSum_[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;
}
}
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<<" : "<<resTypAmp_[i]<<" to "<<name2<<", "<< name3<<std::endl;
}
}
std::cout<<std::endl;
std::cout<<" : In tracks 1 and 3:"<<std::endl;
for (i = 0; i < nAmp_; i++) {
if (resPairAmp_[i] == 2) {
std::cout<<" : "<<resTypAmp_[i]<<" to "<<name1<<", "<< name3<<std::endl;
}
}
std::cout<<std::endl;
std::cout<<" : In tracks 1 and 2:"<<std::endl;
for (i = 0; i < nAmp_; i++) {
if (resPairAmp_[i] == 3) {
std::cout<<" : "<<resTypAmp_[i]<<" to "<<name1<<", "<< name2<<std::endl;
}
}
std::cout<<std::endl;
for (i = 0; i < nAmp_; i++) {
if (resPairAmp_[i] == 0) {
std::cout<<" : and a non-resonant amplitude."<<std::endl;
}
}
std::cout<<std::endl;
}
void LauIsobarDynamics::initialiseVectors()
{
fSqSum_.clear(); fSqSum_.resize(nAmp_);
fifjEffSum_.clear(); fifjEffSum_.resize(nAmp_);
fifjSum_.clear(); fifjSum_.resize(nAmp_);
ff_.clear(); ff_.resize(nAmp_);
fNorm_.clear(); fNorm_.resize(nAmp_);
fitFrac_.clear(); fitFrac_.resize(nAmp_);
fitFracEffUnCorr_.clear(); fitFracEffUnCorr_.resize(nAmp_);
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_);
fitFracEffUnCorr_[i].resize(nAmp_);
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);
}
}
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;
// 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;
}
void LauIsobarDynamics::addResonance(const TString& resName, Int_t resPairAmpInt, const TString& resType, Double_t newMass, Double_t newWidth, Int_t newSpin)
{
// 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.
LauAbsResonance *theResonance =
resonanceMaker_->getResonance(resName, resPairAmpInt, resType);
if (theResonance == 0) {
std::cerr<<"ERROR in LauIsobarDynamics::addResonance : Couldn't create the resonance \""<<resName<<"\""<<std::endl;
return;
}
// Change resonance and lineshape parameters as required.
if (newMass > 0.0 || newWidth > 0.0 || newSpin > -1) {
theResonance->changeResonance(newMass, newWidth, newSpin);
}
// implement the helicity flip here
if (flipHelicity_ && daughters_->getCharge(resPairAmpInt) == 0) {
if ( daughters_->getChargeParent() == 0 && daughters_->getTypeParent() > 0 ) {
theResonance->flipHelicity(kTRUE);
}
}
TString resTypeName(resType);
// Reset the Blatt-Weisskopf barrier factors as appropriate
if (!resTypeName.CompareTo("RelBW")) {
LauRelBreitWignerRes* theRBW = dynamic_cast<LauRelBreitWignerRes*>(theResonance);
theRBW->setBarrierRadii(resBarrierRadius_, parBarrierRadius_, barrierType_);
} else if (!resTypeName.CompareTo("GS")) {
LauGounarisSakuraiRes* theGS = dynamic_cast<LauGounarisSakuraiRes*>(theResonance);
theGS->setBarrierRadii(resBarrierRadius_, parBarrierRadius_, barrierType_);
}
if (changeLASSScatteringLength_ == kTRUE && resTypeName.BeginsWith("LASS") ) {
theResonance->setResonanceParameter(LASSScatteringLength_, "a");
}
if (changeLASSEffectiveRange_ == kTRUE && resTypeName.BeginsWith("LASS") ) {
theResonance->setResonanceParameter(LASSEffectiveRange_, "r");
}
if (changeLASSResonanceMag_ == kTRUE && !resTypeName.CompareTo("LASS") ) {
theResonance->setResonanceParameter(LASSResonanceMag_, "R");
}
if (changeLASSResonancePhase_ == kTRUE && !resTypeName.CompareTo("LASS") ) {
theResonance->setResonanceParameter(LASSResonancePhase_, "phiR");
}
if (changeLASSBackgroundMag_ == kTRUE && !resTypeName.CompareTo("LASS") ) {
theResonance->setResonanceParameter(LASSBackgroundMag_, "B");
}
if (changeLASSBackgroundPhase_ == kTRUE && !resTypeName.CompareTo("LASS") ) {
theResonance->setResonanceParameter(LASSBackgroundPhase_, "phiB");
}
if (changeLASSCutOff_ == kTRUE && resTypeName.BeginsWith("LASS") ) {
theResonance->setResonanceParameter(LASSCutOff_, "cutOff");
}
if (changeFlatteParameterg1_ == kTRUE && !resTypeName.CompareTo("Flatte") ) {
theResonance->setResonanceParameter(FlatteParameterg1_, "g1");
}
if (changeFlatteParameterg2_ == kTRUE && !resTypeName.CompareTo("Flatte") ) {
theResonance->setResonanceParameter(FlatteParameterg2_, "g2");
}
TString resonanceName = theResonance->getResonanceName();
if ( resonanceName.BeginsWith("BelleNR", TString::kExact) ) {
LauBelleNR* belleNR = dynamic_cast<LauBelleNR*>(theResonance);
if (belleNR != 0) {
belleNR->setAlpha(BelleNRAlpha_);
} else {
std::cerr<<"ERROR in LauIsobarDynamics::addResonance : Belle non-resonant object is null"<<std::endl;
}
} else if ( resonanceName.BeginsWith("BelleSymNR", TString::kExact) ) {
LauBelleSymNR* belleNR = dynamic_cast<LauBelleSymNR*>(theResonance);
if (belleNR != 0) {
belleNR->initialise(symmetricalDP_, BelleNRAlpha_, resTypeName);
} else {
std::cerr<<"ERROR in LauIsobarDynamics::addResonance : Symmetric Belle non-resonant object is null"<<std::endl;
}
} else if ( resonanceName.BeginsWith("PolNR", TString::kExact) ) {
LauPolNR* polNR = dynamic_cast<LauPolNR*>(theResonance);
Double_t omega = 0.5*(daughters_->getMassParent()+(1./3)*(daughters_->getMassDaug1()+daughters_->getMassDaug2()+daughters_->getMassDaug3()));
if (polNR != 0) {
polNR->setOmega(omega);
} else {
std::cerr<<"ERROR in LauIsobarDynamics::addResonance : Polynomial non-resonant object is null"<<std::endl;
}
}
// Initialise the resonance model
theResonance->initialise();
// Set the resonance name and what track is the bachelor
resTypAmp_.push_back(resonanceName);
resIntAmp_.push_back(resonanceMaker_->resTypeInt(resonanceName));
// Always force the non-resonant amplitude pair to have resPairAmp = 0
// in case the user chooses the wrong number.
if ( (resonanceName.BeginsWith("NonReson", TString::kExact) == kTRUE) ||
(resonanceName.BeginsWith("BelleSymNR", TString::kExact) == kTRUE) ||
(resonanceName.BeginsWith("NRModel", TString::kExact) == kTRUE)) {
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;
}
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.
if (rowIndex < 1) {
std::cerr<<"Error in defineKMatrixPropagator: rowIndex must be > 0 but is equal to "<<rowIndex<<std::endl;
return;
}
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)
{
// 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_);
resTypAmp_.push_back(poleName);
resIntAmp_.push_back(0);
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)
{
// 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_);
resTypAmp_.push_back(SVPName);
resIntAmp_.push_back(0);
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;
}
}
LauAbsResonance* LauIsobarDynamics::findResonance(const TString& name)
{
TString testName(name);
testName.ToLower();
LauAbsResonance* theResonance(0);
for (std::vector<LauAbsResonance*>::iterator iter=sigResonances_.begin(); iter!=sigResonances_.end(); ++iter) {
theResonance = (*iter);
if (theResonance != 0) {
TString resString = theResonance->getResonanceName();
resString.ToLower();
if (resString.BeginsWith(testName, TString::kExact)) {
return theResonance;
}
}
}
std::cerr<<"ERROR in LauIsobarDynamics::findResonance : Couldn't find resonance \""<<name<<"\" in the model."<<std::endl;
return 0;
}
const LauAbsResonance* LauIsobarDynamics::findResonance(const TString& name) const
{
TString testName(name);
testName.ToLower();
const LauAbsResonance* theResonance(0);
for (std::vector<LauAbsResonance*>::const_iterator iter=sigResonances_.begin(); iter!=sigResonances_.end(); ++iter) {
theResonance = (*iter);
if (theResonance != 0) {
TString resString = theResonance->getResonanceName();
resString.ToLower();
if (resString.BeginsWith(testName, TString::kExact)) {
return theResonance;
}
}
}
std::cerr<<"ERROR in LauIsobarDynamics::findResonance : Couldn't find resonance \""<<name<<"\" in the model."<<std::endl;
return 0;
}
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::changeResonance(const TString& resName, Double_t newMass, Double_t newWidth, Int_t newSpin)
{
// Change the mass, width or spin of a resonance.
if (newMass > 0.0 || newWidth > 0.0 || newSpin > -1) {
std::cerr<<"ERROR in LauIsobarDynamics::changeResonance : mass, width and spin parameters all out of range."<<std::endl;
return;
}
LauAbsResonance* theRes = this->findResonance(resName);
if (theRes != 0) {
theRes->changeResonance(newMass, newWidth, newSpin);
}
}
void LauIsobarDynamics::calcDPNormalisation()
{
// Use Gauss-Legendre quadrature integration
// 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();
// Find out whether we have narrow resonances in the DP (defined here as width < 20 MeV).
std::multimap<Double_t,Double_t> m13NarrowRes;
std::multimap<Double_t,Double_t> m23NarrowRes;
std::multimap<Double_t,Double_t> m12NarrowRes;
for ( std::vector<LauAbsResonance*>::const_iterator iter = sigResonances_.begin(); iter != sigResonances_.end(); ++iter ) {
Double_t width = (*iter)->getWidth();
if ( width > 0.020 || width == 0.0 ) { continue; }
Double_t mass = (*iter)->getMass();
Int_t pair = (*iter)->getPairInt();
TString name = (*iter)->getResonanceName();
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Found narrow resonance: "<<name<<", mass = "<<mass<<", width = "<<width<<", pair int = "<<pair<<std::endl;
if ( pair == 1 ) {
if ( mass < minm23 || mass > maxm23 ){ continue; }
m23NarrowRes.insert( std::make_pair(width,mass) );
} else if ( pair == 2 ) {
if ( mass < minm13 || mass > maxm13 ){ continue; }
m13NarrowRes.insert( std::make_pair(width,mass) );
} else if ( pair == 3 ) {
if ( mass < minm12 || mass > maxm12 ){ continue; }
m12NarrowRes.insert( std::make_pair(width,mass) );
} else {
std::cerr<<"WARNING in LauIsobarDynamics::calcDPNormalisation : strange pair integer, "<<pair<<", for resonance \""<<(*iter)->getResonanceName()<<std::endl;
}
}
// Find the narrowest resonance in each mass pairing
const Bool_t e12 = m12NarrowRes.empty();
const Bool_t e13 = m13NarrowRes.empty();
const Bool_t e23 = m23NarrowRes.empty();
//const UInt_t s12 = e12 ? 0 : m12NarrowRes.size();
const UInt_t s13 = e13 ? 0 : m13NarrowRes.size();
const UInt_t s23 = e23 ? 0 : m23NarrowRes.size();
const Double_t w12 = e12 ? DBL_MAX : m12NarrowRes.begin()->first / 100.0;
const Double_t w13 = e13 ? DBL_MAX : m13NarrowRes.begin()->first / 100.0;
const Double_t w23 = e23 ? DBL_MAX : m23NarrowRes.begin()->first / 100.0;
// Start off with default bin width (5 MeV)
Double_t m13BinWidth = m13BinWidth_;
Double_t m23BinWidth = m23BinWidth_;
// Depending on how many narrow resonances we have and where they
// are we adopt different approaches
if ( e12 && e13 && e23 ) {
// If we have no narrow resonances just integrate the whole
// DP with the standard bin widths
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : No narrow resonances found, integrating over whole Dalitz plot..."<<std::endl;
this->calcDPPartialIntegral(minm13, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth);
} else if ( ! e12 ) {
// If we have a narrow resonance on the diagonal then we'll have to
// just use a narrow bin width over the whole DP (1/10 of the width
// of the narrowest resonance in any mass pair)
m13BinWidth = m23BinWidth = 10.0*TMath::Min( w12, TMath::Min( w13, w23 ) );
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : One or more narrow resonances found in m12, integrating over whole Dalitz plot with bin width of "<<m13BinWidth<<" GeV/c2..."<<std::endl;
this->calcDPPartialIntegral(minm13, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth);
} else if ( s13==1 && e23 ) {
// We have a single narrow resonance in m13
// Divide the plot into 3 regions: the resonance band and
// the two areas either side.
Double_t mass = m13NarrowRes.begin()->second;
Double_t width = m13NarrowRes.begin()->first;
Double_t resMin = mass - 5.0*width;
Double_t resMax = mass + 5.0*width;
// if the resonance is close to threshold just go from
// threshold to resMax, otherwise treat threshold to resMin
// as a separate region
if ( resMin < (minm13+50.0*m13BinWidth_) ) {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : One narrow resonance found in m13, close to threshold, dividing Dalitz plot into two regions..."<<std::endl;
this->calcDPPartialIntegral(resMax, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
this->calcDPPartialIntegral(minm13, resMax, minm23, maxm23, m13BinWidth, m23BinWidth);
} else {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : One narrow resonance found in m13, dividing Dalitz plot into three regions..."<<std::endl;
this->calcDPPartialIntegral(minm13, resMin, minm23, maxm23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
this->calcDPPartialIntegral(resMin, resMax, minm23, maxm23, m13BinWidth, m23BinWidth);
}
} else if ( s13==2 && e23 ) {
// We have a two narrow resonances in m13
// Divide the plot into 5 regions: the resonance bands,
// the two areas either side and the area in between.
std::multimap<Double_t,Double_t> massordered;
for ( std::map<Double_t,Double_t>::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
massordered.insert( std::make_pair( iter->second, iter->first ) );
}
Double_t res1Mass = massordered.begin()->first;
Double_t res1Width = massordered.begin()->second;
Double_t res1Min = res1Mass - 5.0*res1Width;
Double_t res1Max = res1Mass + 5.0*res1Width;
Double_t res2Mass = (++(massordered.begin()))->first;
Double_t res2Width = (++(massordered.begin()))->second;
Double_t res2Min = res2Mass - 5.0*res2Width;
Double_t res2Max = res2Mass + 5.0*res2Width;
// if the resonance is close to threshold just go from
// threshold to resMax, otherwise treat threshold to resMin
// as a separate region
if ( res1Min < (minm13+50.0*m13BinWidth_) ) {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Two narrow resonances found in m13, one close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
this->calcDPPartialIntegral(res1Max, res2Min, minm23, maxm23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(res2Max, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = res1Width/100.0;
this->calcDPPartialIntegral(minm13, res1Max, minm23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = res2Width/100.0;
this->calcDPPartialIntegral(res2Min, res2Max, minm23, maxm23, m13BinWidth, m23BinWidth);
} else {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Two narrow resonances found in m13, dividing Dalitz plot into five regions..."<<std::endl;
this->calcDPPartialIntegral(minm13, res1Min, minm23, maxm23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(res1Max, res2Min, minm23, maxm23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(res2Max, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = res1Width/100.0;
this->calcDPPartialIntegral(res1Min, res1Max, minm23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = res2Width/100.0;
this->calcDPPartialIntegral(res2Min, res2Max, minm23, maxm23, m13BinWidth, m23BinWidth);
}
} else if ( s23==1 && e13 ) {
// We have a single narrow resonance in m23
// Divide the plot into 3 regions: the resonance band and
// the two areas either side.
Double_t mass = m23NarrowRes.begin()->second;
Double_t width = m23NarrowRes.begin()->first;
Double_t resMin = mass - 5.0*width;
Double_t resMax = mass + 5.0*width;
// if the resonance is close to threshold just go from
// threshold to resMax, otherwise treat threshold to resMin
// as a separate region
if ( resMin < (minm23+50.0*m23BinWidth_) ) {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : One narrow resonance found in m23, close to threshold, dividing Dalitz plot into two regions..."<<std::endl;
this->calcDPPartialIntegral(minm13, maxm13, resMax, maxm23, m13BinWidth, m23BinWidth);
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, maxm13, minm23, resMax, m13BinWidth, m23BinWidth);
} else {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : One narrow resonance found in m23, dividing Dalitz plot into three regions..."<<std::endl;
this->calcDPPartialIntegral(minm13, maxm13, minm23, resMin, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(minm13, maxm13, resMax, maxm23, m13BinWidth, m23BinWidth);
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, maxm13, resMin, resMax, m13BinWidth, m23BinWidth);
}
} else if ( s23==2 && e13 ) {
// We have a two narrow resonances in m23
// Divide the plot into 5 regions: the resonance bands,
// the two areas either side and the area in between.
std::multimap<Double_t,Double_t> massordered;
for ( std::map<Double_t,Double_t>::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
massordered.insert( std::make_pair( iter->second, iter->first ) );
}
Double_t res1Mass = massordered.begin()->first;
Double_t res1Width = massordered.begin()->second;
Double_t res1Min = res1Mass - 5.0*res1Width;
Double_t res1Max = res1Mass + 5.0*res1Width;
Double_t res2Mass = (++(massordered.begin()))->first;
Double_t res2Width = (++(massordered.begin()))->second;
Double_t res2Min = res2Mass - 5.0*res2Width;
Double_t res2Max = res2Mass + 5.0*res2Width;
// if the resonance is close to threshold just go from
// threshold to resMax, otherwise treat threshold to resMin
// as a separate region
if ( res1Min < (minm23+50.0*m23BinWidth_) ) {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Two narrow resonances found in m23, one close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
this->calcDPPartialIntegral(minm13, maxm13, res1Max, res2Min, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(minm13, maxm13, res2Max, maxm23, m13BinWidth, m23BinWidth);
m23BinWidth = res1Width/100.0;
this->calcDPPartialIntegral(minm13, maxm13, minm23, res1Max, m13BinWidth, m23BinWidth);
m23BinWidth = res2Width/100.0;
this->calcDPPartialIntegral(minm13, maxm13, res2Min, res2Max, m13BinWidth, m23BinWidth);
} else {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Two narrow resonances found in m23, dividing Dalitz plot into five regions..."<<std::endl;
this->calcDPPartialIntegral(minm13, maxm13, minm23, res1Min, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(minm13, maxm13, res1Max, res2Min, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(minm13, maxm13, res2Max, maxm23, m13BinWidth, m23BinWidth);
m23BinWidth = res1Width/100.0;
this->calcDPPartialIntegral(minm13, maxm13, res1Min, res1Max, m13BinWidth, m23BinWidth);
m23BinWidth = res2Width/100.0;
this->calcDPPartialIntegral(minm13, maxm13, res2Min, res2Max, m13BinWidth, m23BinWidth);
}
} else if ( s13==1 && s23==1 ) {
// We have a single narrow resonance in both m13 and m23
// Divide the plot into 9 regions: the point where the
// resonance bands cross, the four other parts of the bands
// and the four remaining areas of the DP.
Double_t mass23 = m23NarrowRes.begin()->second;
Double_t width23 = m23NarrowRes.begin()->first;
Double_t resMin23 = mass23 - 5.0*width23;
Double_t resMax23 = mass23 + 5.0*width23;
Double_t mass13 = m13NarrowRes.begin()->second;
Double_t width13 = m13NarrowRes.begin()->first;
Double_t resMin13 = mass13 - 5.0*width13;
Double_t resMax13 = mass13 + 5.0*width13;
// if either resonance is close to threshold just go from
// threshold to resMax, otherwise treat threshold to resMin
// as a separate region
if ( resMin13 < (minm13+50.0*m13BinWidth_) && resMin23 < (minm23+50.0*m23BinWidth_) ) {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : One narrow resonance found in m13 and one in m23, both close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
m13BinWidth = m13BinWidth_;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = m13BinWidth_;
m23BinWidth = w23;
this->calcDPPartialIntegral(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth);
} else if ( resMin13 < (minm13+50.0*m13BinWidth_) ) {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : One narrow resonance found in m13, close to threshold, and one in m23, not close to threshold, dividing Dalitz plot into six regions..."<<std::endl;
this->calcDPPartialIntegral(resMax13, maxm13, minm23, resMin23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = m13BinWidth_;
m23BinWidth = w23;
this->calcDPPartialIntegral(resMax13, maxm13, resMin23, resMax23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(minm13, resMax13, minm23, resMin23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, resMax13, resMin23, resMax23, m13BinWidth, m23BinWidth);
} else if ( resMin23 < (minm23+50.0*m23BinWidth_) ) {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : One narrow resonance found in m23, close to threshold, and one in m13, not close to threshold, dividing Dalitz plot into six regions..."<<std::endl;
this->calcDPPartialIntegral(minm13, resMin13, resMax23, maxm23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = m13BinWidth_;
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, resMin13, minm23, resMax23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(resMin13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = w23;
this->calcDPPartialIntegral(resMin13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth);
} else {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : One narrow resonance found in both m13 and m23, neither close to threshold, dividing Dalitz plot into nine regions..."<<std::endl;
this->calcDPPartialIntegral(minm13, resMin13, minm23, resMin23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(minm13, resMin13, resMax23, maxm23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax13, maxm13, minm23, resMin23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = m13BinWidth_;
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, resMin13, resMin23, resMax23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax13, maxm13, resMin23, resMax23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(resMin13, resMax13, minm23, resMin23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMin13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = w23;
this->calcDPPartialIntegral(resMin13, resMax13, resMin23, resMax23, m13BinWidth, m23BinWidth);
}
} else if ( e23 && s13>1 ) {
// We have multiple narrow resonances in m13 only.
// Divide the plot into 2 regions: threshold to the most
// massive of the narrow resonances, and the rest
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Multiple narrow resonances found in m13, dividing Dalitz plot into two regions..."<<std::endl;
Double_t mass = 0.0;
Double_t width = 0.0;
for ( std::map<Double_t,Double_t>::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
if ( mass < iter->second ) {
mass = iter->second;
width = iter->first;
}
}
Double_t resMax = mass + 5.0*width;
this->calcDPPartialIntegral(resMax, maxm13, minm23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
this->calcDPPartialIntegral(minm13, resMax, minm23, maxm23, m13BinWidth, m23BinWidth);
} else if ( e13 && s23>1 ) {
// We have multiple narrow resonances in m23 only.
// Divide the plot into 2 regions: threshold to the most
// massive of the narrow resonances, and the rest
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Multiple narrow resonances found in m23, dividing Dalitz plot into two regions..."<<std::endl;
Double_t mass = 0.0;
Double_t width = 0.0;
for ( std::map<Double_t,Double_t>::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
if ( mass < iter->second ) {
mass = iter->second;
width = iter->first;
}
}
Double_t resMax = mass + 5.0*width;
this->calcDPPartialIntegral(minm13, maxm13, resMax, maxm23, m13BinWidth, m23BinWidth);
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, maxm13, minm23, resMax, m13BinWidth, m23BinWidth);
} else if ( s13==1 && s23>1 ) {
// We've got a single narrow resonance in m13 and multiple
// narrow resonances in m23. Divide the plot into 6 regions.
Double_t mass23 = 0.0;
Double_t width23 = 0.0;
for ( std::map<Double_t,Double_t>::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
if ( mass23 < iter->second ) {
mass23 = iter->second;
width23 = iter->first;
}
}
Double_t resMax23 = mass23 + 5.0*width23;
Double_t mass13 = m13NarrowRes.begin()->second;
Double_t width13 = m13NarrowRes.begin()->first;
Double_t resMin13 = mass13 - 5.0*width13;
Double_t resMax13 = mass13 + 5.0*width13;
// if the m13 resonance is close to threshold just go from
// threshold to resMax, otherwise treat threshold to resMin
// as a separate region
if ( resMin13 < (minm13+50.0*m13BinWidth_) ) {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Multiple narrow resonances found in m23 and one in m13, close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
m13BinWidth = m13BinWidth_;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = m13BinWidth_;
m23BinWidth = w23;
this->calcDPPartialIntegral(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth);
} else {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Multiple narrow resonances found in m23 and one in m13, not close to threshold, dividing Dalitz plot into six regions..."<<std::endl;
m13BinWidth = m13BinWidth_;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(minm13, resMin13, resMax23, maxm23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = m13BinWidth_;
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, resMin13, minm23, resMax23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(resMin13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = w23;
this->calcDPPartialIntegral(resMin13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth);
}
} else if ( s13>1 && s23==1 ) {
// We've got a single narrow resonance in m23 and multiple
// narrow resonances in m13. Divide the plot into 6 regions.
Double_t mass13 = 0.0;
Double_t width13 = 0.0;
for ( std::map<Double_t,Double_t>::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
if ( mass13 < iter->second ) {
mass13 = iter->second;
width13 = iter->first;
}
}
Double_t resMax13 = mass13 + 5.0*width13;
Double_t mass23 = m23NarrowRes.begin()->second;
Double_t width23 = m23NarrowRes.begin()->first;
Double_t resMin23 = mass23 - 5.0*width23;
Double_t resMax23 = mass23 + 5.0*width23;
// if the m23 resonance is close to threshold just go from
// threshold to resMax, otherwise treat threshold to resMin
// as a separate region
if ( resMin23 < (minm23+50.0*m23BinWidth_) ) {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Multiple narrow resonances found in m13 and one in m23, close to threshold, dividing Dalitz plot into four regions..."<<std::endl;
m13BinWidth = m13BinWidth_;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = m13BinWidth_;
m23BinWidth = w23;
this->calcDPPartialIntegral(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth);
} else {
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Multiple narrow resonances found in m13 and one in m23, not close to threshold, dividing Dalitz plot into six regions..."<<std::endl;
this->calcDPPartialIntegral(resMax13, maxm13, minm23, resMin23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = m13BinWidth_;
m23BinWidth = w23;
this->calcDPPartialIntegral(resMax13, maxm13, resMin23, resMax23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(minm13, resMax13, minm23, resMin23, m13BinWidth, m23BinWidth);
this->calcDPPartialIntegral(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, resMax13, resMin23, resMax23, m13BinWidth, m23BinWidth);
}
} else {
// We've got multiple narrow resonances in both m13 and m23.
// Divide the plot into 4 regions.
std::cout<<"INFO in LauIsobarDynamics::calcDPNormalisation : Multiple narrow resonances found in both m13 and m23, dividing Dalitz plot into four regions..."<<std::endl;
Double_t mass13 = 0.0;
Double_t width13 = 0.0;
for ( std::map<Double_t,Double_t>::const_iterator iter = m13NarrowRes.begin(); iter != m13NarrowRes.end(); ++iter ) {
if ( mass13 < iter->second ) {
mass13 = iter->second;
width13 = iter->first;
}
}
Double_t resMax13 = mass13 + 5.0*width13;
Double_t mass23 = 0.0;
Double_t width23 = 0.0;
for ( std::map<Double_t,Double_t>::const_iterator iter = m23NarrowRes.begin(); iter != m23NarrowRes.end(); ++iter ) {
if ( mass23 < iter->second ) {
mass23 = iter->second;
width23 = iter->first;
}
}
Double_t resMax23 = mass23 + 5.0*width23;
m13BinWidth = m13BinWidth_;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(resMax13, maxm13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = m13BinWidth_;
m23BinWidth = w23;
this->calcDPPartialIntegral(resMax13, maxm13, minm23, resMax23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = m23BinWidth_;
this->calcDPPartialIntegral(minm13, resMax13, resMax23, maxm23, m13BinWidth, m23BinWidth);
m13BinWidth = w13;
m23BinWidth = w23;
this->calcDPPartialIntegral(minm13, resMax13, minm23, resMax23, m13BinWidth, m23BinWidth);
}
}
void LauIsobarDynamics::setIntegralBinWidths(Double_t m13BinWidth, Double_t m23BinWidth)
{
// Specify whether we're going to use Gauss-Legendre integration to calculate the normalisation
// integrals, and the bin widths we require for the m13 and m23 axes. Note that the integration
// is done over m13, m23 space, with the appropriate Jacobian applied, and not m13^2, m23^2 space.
// The default bin widths in m13 and m23 space are 5 MeV.
m13BinWidth_ = m13BinWidth;
m23BinWidth_ = m23BinWidth;
}
void LauIsobarDynamics::calcDPPartialIntegral(Double_t minm13, Double_t maxm13, Double_t minm23, Double_t maxm23,
Double_t m13BinWidth, Double_t m23BinWidth)
{
// Calculate the total DP area, as well as finding the normalisation terms for
// the signal resonances
Int_t i(0), j(0);
Double_t precision(1e-6);
Double_t meanm13 = 0.5*(minm13 + maxm13);
Double_t rangem13 = maxm13 - minm13;
Double_t halfRangem13 = 0.5*rangem13;
Double_t meanm23 = 0.5*(minm23 + maxm23);
Double_t rangem23 = maxm23 - minm23;
Double_t halfRangem23 = 0.5*rangem23;
Double_t intFactor = halfRangem13*halfRangem23;
// Choose smallest of mass ranges to set number of bins, given specified bin width
Int_t nm13Points = static_cast<Int_t>((rangem13/m13BinWidth));
Int_t nm23Points = static_cast<Int_t>((rangem23/m23BinWidth));
// Avoid integral if we have no points in either x or y space
if (nm13Points == 0 || nm23Points == 0) {return;}
std::cout<<"INFO in LauIsobarDynamics::calcDPPartialIntegral : nm13Points = "<<nm13Points<<", nm23Points = "<<nm23Points<<std::endl;
std::cout<<" : m13BinWidth = "<<m13BinWidth<<", m23BinWidth = "<<m23BinWidth<<std::endl;
std::cout<<" : Integrating over m13 = "<<minm13<<" to "<<maxm13<<", m23 = "<<minm23<<" to "<<maxm23<<std::endl;
LauIntegrals DPIntegrals(precision);
std::vector<Double_t> m13Weights, m23Weights;
std::vector<Double_t> m13Abscissas, m23Abscissas;
DPIntegrals.calcGaussLegendreWeights(nm13Points, m13Abscissas, m13Weights);
DPIntegrals.calcGaussLegendreWeights(nm23Points, m23Abscissas, m23Weights);
Int_t nm13Weights = static_cast<Int_t>(m13Weights.size());
Int_t nm23Weights = static_cast<Int_t>(m23Weights.size());
//std::cout<<" : nm13Weights = "<<nm13Weights<<", nm23Weights = "<<nm23Weights<<std::endl;
// Print out abscissas and weights for the integration
Double_t totm13Weight(0.0), totm23Weight(0.0);
for (i = 0; i < nm13Weights; i++) {
totm13Weight += m13Weights[i];
}
for (i = 0; i < nm23Weights; i++) {
totm23Weight += m23Weights[i];
}
std::cout<<" : totm13Weight = "<<totm13Weight<<", totm23Weight = "<<totm23Weight<<std::endl;
std::vector<Double_t> m13(nm13Weights), m23(nm23Weights);
std::vector<Double_t> m13Sq(nm13Weights), m23Sq(nm23Weights);
// Use same number of abscissas for x and y co-ordinates
Int_t m = (nm13Weights + 1)/2;
for (i = 0; i < m; i++) {
Int_t ii = nm13Weights - 1 - i; // symmetric i index
Double_t dm13 = halfRangem13*m13Abscissas[i];
Double_t m13Val = meanm13 - dm13;
m13[i] = m13Val;
m13Sq[i] = m13Val*m13Val;
m13Val = meanm13 + dm13;
m13[ii] = m13Val;
m13Sq[ii] = m13Val*m13Val;
}
m = (nm23Weights +1)/2;
for (i = 0; i < m; i++) {
Int_t ii = nm23Weights - 1 - i; // symmetric i index
Double_t dm23 = halfRangem23*m23Abscissas[i];
Double_t m23Val = meanm23 - dm23;
m23[i] = m23Val;
m23Sq[i] = m23Val*m23Val;
m23Val = meanm23 + dm23;
m23[ii] = m23Val;
m23Sq[ii] = m23Val*m23Val;
}
// Now compute the integral
Double_t dpArea(0.0);
for (i = 0; i < nm13Weights; i++) {
for (j = 0; j < nm23Weights; j++) {
Double_t weight = m13Weights[i]*m23Weights[j];
Double_t Jacobian = 4.0*m13[i]*m23[j];
weight *= (Jacobian*intFactor);
// Calculate the integral contributions for each resonance.
// Only resonances within the DP area contribute.
// This also calculates the total DP area as a check.
Bool_t withinDP = kinematics_->withinDPLimits(m13Sq[i], m23Sq[j]);
if (withinDP == kTRUE) {
kinematics_->updateKinematics(m13Sq[i], m23Sq[j]);
this->dynamics(kFALSE, 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::dynamics(Bool_t cacheResData, Double_t weight, Bool_t useEff)
{
// Routine that calculates the Dalitz plot amplitude, incorporating
// resonance dynamics (using resAmp()) and any interference between them.
// Used by the fit() and sigGen() functions.
UInt_t i(0), j(0);
// Reset the total amplitude to zero
totAmp_.zero();
// Loop over the number of resonance amplitudes defined in the model
// Have we already calculated this for this event (during fit?)
// Or do we have a resonance that has varying pole mass/width/other factors?
if (cacheResData == kFALSE) {
for (i = 0; i < nAmp_; i++) {
// Calculate the dynamics for this resonance, using the resAmp function.
ff_[i] = resAmp(i);
//std::cout<<"ff_["<<i<<"] = "<<ff_[i]<<std::endl;
// If we have a symmetrical Dalitz plot, flip the m_13^2 and m_23^2
// variables, recalculate the dynamics, and average both contributions.
// Although, the factor of 0.5 cancels out with the fact that
// the resonance appears on both sides of the Dalitz plot.
if (symmetricalDP_ == kTRUE) { // was tieSg_ == 12
kinematics_->flipAndUpdateKinematics();
ff_[i] += resAmp(i);
// Flip the m_13^2 and m_23^2 variables back to their original values
kinematics_->flipAndUpdateKinematics();
}
} // Loop over amplitudes
// If we haven't cached the data, then we need to find out the efficiency.
eff_ = this->retrieveEfficiency();
} // Already cached data?
if (integralsDone_ == kTRUE) {
// Loop over all signal amplitudes
LauComplex ATerm;
for (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
//std::cout<<"For i = "<<i<<", ATerm = "<<ATerm<<", Amp = "<<Amp_[i]<<", ff = "<<ff_[i]<<std::endl;
totAmp_ += ATerm;
} // Loop over amplitudes
// |Sum of partial amplitudes|^2
ASq_ = totAmp_.abs2();
// Apply the efficiency correction for this event.
// Multiply the amplitude squared sum by the DP efficiency
if ( useEff ) {
ASq_ *= eff_;
}
} else { // integrals not done
// Find the efficiency correction to be applied for this event.
eff_ = this->retrieveEfficiency();
Double_t effWeight = eff_*weight;
// Need this for integrals for normalisation of likelihood function.
LauComplex fifjEffSumTerm;
LauComplex fifjSumTerm;
for (i = 0; i < nAmp_; i++) {
// Add the dynamical amplitude squared for this resonance.
Double_t fSqVal = ff_[i].abs2();
fSqSum_[i] += fSqVal*weight;
for (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;
}
}
}
}
LauComplex LauIsobarDynamics::resAmp(Int_t index)
{
// Routine to calculate the resonance dynamics (amplitude)
// using the appropriate Breit-Wigner/Form Factors.
// Called by the dynamics() function.
// Get the signal resonance from the stored vector
LauAbsResonance* sigResonance = sigResonances_[index];
if (sigResonance == 0) {
std::cout<<"ERROR in LauIsobarDynamics::resAmp : Couldn't retrieve resonance with index = "<<index<<std::endl;
return LauComplex(0.0, 0.0);
}
// Get the integer index of the resonance.
Int_t resInt = resIntAmp_[index];
LauComplex resAmplitude(0.0, 0.0);
if (resInt < 0 || resInt >= static_cast<Int_t>(this->getnDefinedResonances())) {
std::cout<<"ERROR in LauIsobarDynamics::resAmp : Probably bad resonance name."<<std::endl;
resAmplitude = LauComplex(0.0, 0.0);
} else {
resAmplitude = sigResonance->amplitude(kinematics_);
}
return resAmplitude;
}
void LauIsobarDynamics::setFFTerm(UInt_t index, Double_t realPart, Double_t imagPart)
{
// Function to set the internal ff = resAmp() term.
if ( index >= nAmp_ ) {
std::cerr<<"ERROR in LauIsobarDynamics::setFFTerm : index = "<<index<<" is not within the range 0 and "<<nAmp_-1<<". Bailing out."<<std::endl;
return;
}
ff_[index].setRealImagPart( realPart, imagPart );
}
void LauIsobarDynamics::calcExtraInfo(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] = sumTerm;
fitFracEffUnCorr_[i][i] = sumEffTerm;
}
for (i = 0; i < nAmp_; i++) {
for (j = i+1; j < nAmp_; 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);
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] = crossTerm;
fitFracEffUnCorr_[i][j] = crossEffTerm;
}
}
if (TMath::Abs(fifjTot) > 1e-10) {
meanDPEff_ = fifjEffTot/fifjTot;
if (init) {
meanDPEff_.genValue( meanDPEff_.value() );
meanDPEff_.initValue( meanDPEff_.value() );
}
}
DPRate_ = 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_; i++) {
for (j = i; j < nAmp_; j++) {
// Get the actual fractions by dividing by the total DP rate
fitFrac_[i][j] /= fifjTot;
fitFracEffUnCorr_[i][j] /= fifjEffTot;
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] = 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];
}
}
return DPNorm_;
}
Bool_t LauIsobarDynamics::generate()
{
// Routine to generate a signal event according to the Dalitz plot
// model we have defined.
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
if ( symmetricalDP_ && m13Sq > m23Sq ) {
Double_t tmpSq = m13Sq;
m13Sq = m23Sq;
m23Sq = tmpSq;
}
// calculates the amplitudes and total amplitude for the given DP point
this->calcLikelihoodInfo(m13Sq, m23Sq);
if (integralsDone_ == kTRUE) {
// No need for efficiency correction here. It is already done in
// the dynamics() function (unlike the Fortran version).
// Very important line to avoid bias in MC generation for the accept/reject method.
// Make sure that the total amplitude squared is below some number, given
// by aSqMaxSet_. If it is, then the event is valid.
// Otherwise, go through another toy MC loop until we can generate the event
// OK, or until we reach the maximum iteration limit.
Double_t randNo = LauRandom::randomFun()->Rndm();
if (randNo > ASq_/aSqMaxSet_) {
nSigGenLoop_++;
} else {
generatedSig = kTRUE;
nSigGenLoop_ = 0;
if (ASq_ > aSqMaxVar_) {aSqMaxVar_ = ASq_;}
}
} else {
// For toy MC numerical integration only
generatedSig = kTRUE;
}
} // while loop
Bool_t sigGenOK(kTRUE);
if (GenOK != this->checkToyMC(kFALSE,kFALSE)) {
sigGenOK = kFALSE;
}
return sigGenOK;
}
LauAbsDPDynamics::ToyMCStatus LauIsobarDynamics::checkToyMC(Bool_t printErrorMessages, Bool_t printInfoMessages)
{
// Check whether we have generated the toy MC OK.
ToyMCStatus ok(GenOK);
if (nSigGenLoop_ >= iterationsMax_) {
if (printErrorMessages) {
std::cerr<<"WARNING in LauIsobarDynamics::checkToyMC : More than "<<iterationsMax_<<" iterations required."<<std::endl;
std::cerr<<" : Try to decrease the maximum allowed value of the total amplitude squared using the "
<<"LauIsobarDynamics::setASqMaxValue(Double_t) function and re-run."<<std::endl;
std::cerr<<" : This needs to be, perhaps significantly, less than "<<aSqMaxSet_<<std::endl;
std::cerr<<" : Maximum value of ASq so far = "<<aSqMaxVar_<<std::endl;
}
aSqMaxSet_ = 1.01 * aSqMaxVar_;
std::cout<<"INFO in LauIsobarDynamics::checkToyMC : |A|^2 max reset to "<<aSqMaxSet_<<std::endl;
ok = MaxIterError;
} else if (aSqMaxVar_ > aSqMaxSet_) {
if (printErrorMessages) {
std::cerr<<"WARNING in LauIsobarDynamics::checkToyMC : aSqMaxSet_ was set to "<<aSqMaxSet_<<" but actual aSqMax was "<<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<<" : Please set aSqMaxSet >= "<<aSqMaxVar_<<" using the LauIsobarDynamics::setASqMaxValue(Double_t) function and re-run."<<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)
{
this->LauAbsDPDynamics::setDataEventNo(iEvt);
m13Sq_ = currentEvent_->retrievem13Sq();
m23Sq_ = currentEvent_->retrievem23Sq();
mPrime_ = currentEvent_->retrievemPrime();
thPrime_ = currentEvent_->retrievethPrime();
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(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
for (UInt_t i = 0; i < nAmp_; i++) {
this->setFFTerm(i, currentEvent_->retrieveRealAmp()[i], currentEvent_->retrieveImagAmp()[i]);
}
// Update the dynamics - calculates totAmp_ and then ASq_ = totAmp_.abs2() * eff_
// All calculated using cached information on the individual amplitudes and efficiency.
this->dynamics(kTRUE, 1.0);
// Calculate the normalised matrix element squared value
if (DPNorm_ > 1e-10) {
evtLike_ = ASq_/DPNorm_;
}
}
void LauIsobarDynamics::calcLikelihoodInfo(Double_t m13Sq, Double_t m23Sq)
{
this->calcLikelihoodInfo(m13Sq, m23Sq, -1);
}
void LauIsobarDynamics::calcLikelihoodInfo(Double_t m13Sq, Double_t m23Sq, 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) {
// If cacheResData == kFALSE, updateKinematics has been called before dynamics(). Then get Jacobian.
jacobian_ = kinematics_->calcSqDPJacobian();
}
// calculates the ff_ terms and retrieves eff_ from the efficiency model
// then calculates totAmp_ and finally ASq_ = totAmp_.abs2() * eff_
this->dynamics(kFALSE, 1.0);
// Calculate the normalised matrix element squared value
if (DPNorm_ > 1e-10) {
evtLike_ = ASq_/DPNorm_;
}
}
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.
UInt_t nBranches = inputFitTree.nBranches();
if (nBranches < 2) {
std::cout<<"ERROR in LauIsobarDynamics::fillDataTree : Expecting at least 2 variables "
<<"in input data tree, but there are "<<nBranches<<"! Make sure you have "
<<"the right number of variables in your input data file!"<<std::endl;
gSystem->Exit(-1);
}
// 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]->storeEff(eff);
data_[iEvt]->storeScfFraction(scfFraction);
data_[iEvt]->storeJacobian(jacobian);
data_[iEvt]->storeRealAmp(realAmp);
data_[iEvt]->storeImagAmp(imagAmp);
}
}
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);
this->dynamics(kFALSE, 1.0, 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 dynamics from the current kinematics
this->dynamics(kFALSE, 1.0, 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_;
}
diff --git a/src/LauSimpleFitModel.cc b/src/LauSimpleFitModel.cc
index 9f7af35..906354b 100644
--- a/src/LauSimpleFitModel.cc
+++ b/src/LauSimpleFitModel.cc
@@ -1,2098 +1,2098 @@
// Copyright University of Warwick 2004 - 2013.
// 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 LauSimpleFitModel.cc
\brief File containing implementation of LauSimpleFitModel class.
*/
#include <iostream>
#include <iomanip>
#include <fstream>
#include "TFile.h"
#include "TH2.h"
#include "TMinuit.h"
#include "TRandom.h"
#include "TSystem.h"
#include "TVirtualFitter.h"
#include "LauAbsBkgndDPModel.hh"
#include "LauAbsCoeffSet.hh"
#include "LauAbsDPDynamics.hh"
#include "LauAbsPdf.hh"
#include "LauComplex.hh"
#include "LauConstants.hh"
#include "LauDaughters.hh"
#include "LauEmbeddedData.hh"
#include "LauEffModel.hh"
#include "LauFitNtuple.hh"
#include "LauGenNtuple.hh"
#include "LauKinematics.hh"
#include "LauPrint.hh"
#include "LauRandom.hh"
#include "LauScfMap.hh"
#include "LauSimpleFitModel.hh"
ClassImp(LauSimpleFitModel)
LauSimpleFitModel::LauSimpleFitModel(LauAbsDPDynamics* sigModel) : LauAbsFitModel(),
sigDPModel_(sigModel),
kinematics_(sigModel ? sigModel->getKinematics() : 0),
usingBkgnd_(kFALSE),
nSigComp_(0),
nSigDPPar_(0),
nExtraPdfPar_(0),
nNormPar_(0),
meanEff_("meanEff",0.0,0.0,1.0),
dpRate_("dpRate",0.0,0.0,100.0),
//signalEvents_("signalEvents",1.0,0.0,1.0),
signalEvents_(0),
useSCF_(kFALSE),
useSCFHist_(kFALSE),
scfFrac_("scfFrac",0.0,0.0,1.0),
scfFracHist_(0),
scfMap_(0),
compareFitData_(kFALSE),
signalTree_(0),
reuseSignal_(kFALSE),
useReweighting_(kFALSE),
sigDPLike_(0.0),
scfDPLike_(0.0),
sigExtraLike_(0.0),
scfExtraLike_(0.0),
sigTotalLike_(0.0),
scfTotalLike_(0.0)
{
}
LauSimpleFitModel::~LauSimpleFitModel()
{
delete signalTree_;
for (LauBkgndEmbDataList::iterator iter = bkgndTree_.begin(); iter != bkgndTree_.end(); ++iter) {
delete (*iter);
}
delete scfFracHist_;
}
void LauSimpleFitModel::setupBkgndVectors()
{
UInt_t nBkgnds = this->nBkgndClasses();
bkgndDPModels_.resize( nBkgnds );
bkgndPdfs_.resize( nBkgnds );
bkgndEvents_.resize( nBkgnds );
bkgndTree_.resize( nBkgnds );
reuseBkgnd_.resize( nBkgnds );
bkgndDPLike_.resize( nBkgnds );
bkgndExtraLike_.resize( nBkgnds );
bkgndTotalLike_.resize( nBkgnds );
}
void LauSimpleFitModel::setNSigEvents(LauParameter* nSigEvents)
{
if ( nSigEvents == 0 ) {
std::cerr << "ERROR in LauSimpleFitModel::setNSigEvents : The signal yield LauParameter pointer is null." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if ( signalEvents_ != 0 ) {
std::cerr << "ERROR in LauSimpleFitModel::setNSigEvents : You are trying to overwrite the signal yield." << std::endl;
return;
}
signalEvents_ = nSigEvents;
TString name = signalEvents_->name();
if ( ! name.Contains("signalEvents") && !( name.BeginsWith("signal") && name.EndsWith("Events") ) ) {
signalEvents_->name("signalEvents");
}
Double_t value = nSigEvents->value();
signalEvents_->range(-2.0*(TMath::Abs(value)+1.0), 2.0*(TMath::Abs(value)+1.0));
}
void LauSimpleFitModel::setNBkgndEvents(LauParameter* nBkgndEvents)
{
if ( nBkgndEvents == 0 ) {
std::cerr << "ERROR in LauSimpleFitModel::setNBkgndEvents : The background yield LauParameter pointer is null." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
if ( ! this->validBkgndClass( nBkgndEvents->name() ) ) {
std::cerr << "ERROR in LauSimpleFitModel::setNBkgndEvents : Invalid background class \"" << nBkgndEvents->name() << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
UInt_t bkgndID = this->bkgndClassID( nBkgndEvents->name() );
if ( bkgndEvents_[bkgndID] != 0 ) {
std::cerr << "ERROR in LauSimpleFitModel::setNBkgndEvents : You are trying to overwrite the background yield." << std::endl;
return;
}
bkgndEvents_[bkgndID] = nBkgndEvents;
bkgndEvents_[bkgndID]->name( nBkgndEvents->name()+"Events" );
Double_t value = nBkgndEvents->value();
bkgndEvents_[bkgndID]->range(-2.0*(TMath::Abs(value)+1.0), 2.0*(TMath::Abs(value)+1.0));
}
void LauSimpleFitModel::splitSignalComponent( const TH2* dpHisto, Bool_t upperHalf, LauScfMap* scfMap )
{
if ( useSCF_ == kTRUE ) {
std::cerr << "ERROR in LauSimpleFitModel::splitSignalComponent : Have already setup SCF." << std::endl;
return;
}
if ( dpHisto == 0 ) {
std::cerr << "ERROR in LauSimpleFitModel::splitSignalComponent : The histogram pointer is null." << std::endl;
return;
}
LauDaughters* daughters = sigDPModel_->getDaughters();
scfFracHist_ = new LauEffModel( daughters, 0 );
scfFracHist_->setEffHisto( dpHisto, kTRUE, kFALSE, 0.0, 0.0, upperHalf, daughters->squareDP() );
scfMap_ = scfMap;
useSCF_ = kTRUE;
useSCFHist_ = kTRUE;
}
void LauSimpleFitModel::splitSignalComponent( Double_t scfFrac, Bool_t fixed )
{
if ( useSCF_ == kTRUE ) {
std::cerr << "ERROR in LauSimpleFitModel::splitSignalComponent : Have already setup SCF." << std::endl;
return;
}
scfFrac_.range( 0.0, 1.0 );
scfFrac_.value( scfFrac ); scfFrac_.initValue( scfFrac ); scfFrac_.genValue( scfFrac );
scfFrac_.fixed( fixed );
useSCF_ = kTRUE;
useSCFHist_ = kFALSE;
}
void LauSimpleFitModel::setBkgndDPModel(const TString& bkgndClass, LauAbsBkgndDPModel* bkgndDPModel)
{
if (bkgndDPModel == 0) {
std::cerr << "ERROR in LauSimpleFitModel::setBkgndDPModel : The model pointer is null." << std::endl;
return;
}
// check that this background name is valid
if ( ! this->validBkgndClass( bkgndClass ) ) {
std::cerr << "ERROR in LauSimpleFitModel::setBkgndDPModel : Invalid background class \"" << bkgndClass << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
return;
}
UInt_t bkgndID = this->bkgndClassID( bkgndClass );
bkgndDPModels_[bkgndID] = bkgndDPModel;
usingBkgnd_ = kTRUE;
}
void LauSimpleFitModel::setSignalPdf(LauAbsPdf* pdf)
{
if (pdf==0) {
std::cerr << "ERROR in LauSimpleFitModel::setSignalPdf : The PDF pointer is null." << std::endl;
return;
}
signalPdfs_.push_back(pdf);
}
void LauSimpleFitModel::setSCFPdf(LauAbsPdf* pdf)
{
if (pdf==0) {
std::cerr << "ERROR in LauSimpleFitModel::setSCFPdf : The PDF pointer is null." << std::endl;
return;
}
scfPdfs_.push_back(pdf);
}
void LauSimpleFitModel::setBkgndPdf(const TString& bkgndClass, LauAbsPdf* pdf)
{
if (pdf == 0) {
std::cerr << "ERROR in LauSimpleFitModel::setBkgndPdf : The PDF pointer is null." << std::endl;
return;
}
// check that this background name is valid
if ( ! this->validBkgndClass( bkgndClass ) ) {
std::cerr << "ERROR in LauSimpleFitModel::setBkgndPdf : Invalid background class \"" << bkgndClass << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
return;
}
UInt_t bkgndID = this->bkgndClassID( bkgndClass );
bkgndPdfs_[bkgndID].push_back(pdf);
usingBkgnd_ = kTRUE;
}
void LauSimpleFitModel::setAmpCoeffSet(LauAbsCoeffSet* coeffSet)
{
// Is there a component called compName in the signal model?
TString compName(coeffSet->name());
Bool_t ok = sigDPModel_->hasResonance(compName);
if (!ok) {
std::cerr << "ERROR in LauSimpleFitModel::setAmpCoeffSet : Signal DP model doesn't contain component \"" << compName << "\"." << std::endl;
return;
}
// Do we already have it in our list of names?
for (std::vector<LauAbsCoeffSet*>::const_iterator iter = coeffPars_.begin(); iter != coeffPars_.end(); ++iter) {
if ((*iter)->name() == compName) {
std::cerr << "ERROR in LauSimpleFitModel::setAmpCoeffSet : Have already set coefficients for \"" << compName << "\"." << std::endl;
return;
}
}
coeffSet->index(nSigComp_);
coeffPars_.push_back(coeffSet);
++nSigComp_;
std::cout << "INFO in LauSimpleFitModel::setAmpCoeffSet : Added coefficients for component \"" << compName << "\" to the fit model." << std::endl;
coeffSet->printParValues();
}
void LauSimpleFitModel::initialise()
{
// First of all check that, we have all the Dalitz-plot models
if (this->useDP()) {
if ( sigDPModel_ == 0 ) {
std::cerr << "ERROR in LauSimpleFitModel::initialise : The pointer to the signal DP model is null.\n";
std::cerr << " : Removing the Dalitz Plot from the model." << std::endl;
this->useDP(kFALSE);
}
if ( usingBkgnd_ ) {
for (LauBkgndDPModelList::const_iterator dpmodel_iter = bkgndDPModels_.begin(); dpmodel_iter != bkgndDPModels_.end(); ++dpmodel_iter ) {
if ( (*dpmodel_iter) == 0 ) {
std::cerr << "ERROR in LauSimpleFitModel::initialise : The pointer to one of the background DP models is null.\n";
std::cerr << " : Removing the Dalitz Plot from the model." << std::endl;
this->useDP(kFALSE);
break;
}
}
}
}
// Next check that, if a given component is being used we've got the
// right number of PDFs for all the variables involved
// TODO - should probably check variable names and so on as well
UInt_t nsigpdfvars(0);
for ( LauPdfList::const_iterator pdf_iter = signalPdfs_.begin(); pdf_iter != signalPdfs_.end(); ++pdf_iter ) {
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nsigpdfvars;
}
}
}
if (useSCF_) {
UInt_t nscfpdfvars(0);
for ( LauPdfList::const_iterator pdf_iter = scfPdfs_.begin(); pdf_iter != scfPdfs_.end(); ++pdf_iter ) {
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nscfpdfvars;
}
}
}
if (nscfpdfvars != nsigpdfvars) {
std::cerr << "ERROR in LauSimpleFitModel::initialise : There are " << nsigpdfvars << " TM signal PDF variables but " << nscfpdfvars << " SCF signal PDF variables." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
if (usingBkgnd_) {
for (LauBkgndPdfsList::const_iterator bgclass_iter = bkgndPdfs_.begin(); bgclass_iter != bkgndPdfs_.end(); ++bgclass_iter) {
UInt_t nbkgndpdfvars(0);
const LauPdfList& pdfList = (*bgclass_iter);
for ( LauPdfList::const_iterator pdf_iter = pdfList.begin(); pdf_iter != pdfList.end(); ++pdf_iter ) {
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nbkgndpdfvars;
}
}
}
if (nbkgndpdfvars != nsigpdfvars) {
std::cerr << "ERROR in LauSimpleFitModel::initialise : There are " << nsigpdfvars << " signal PDF variables but " << nbkgndpdfvars << " bkgnd PDF variables." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
}
// Clear the vectors of parameter information so we can start from scratch
this->clearFitParVectors();
// Set the fit parameters for signal and background models
this->setSignalDPParameters();
// Set the fit parameters for the various extra PDFs
this->setExtraPdfParameters();
// Set the initial bg and signal events
this->setFitNEvents();
// Check that we have the expected number of fit variables
const LauParameterPList& fitVars = this->fitPars();
if (fitVars.size() != (nSigDPPar_ + nExtraPdfPar_ + nNormPar_)) {
std::cerr << "ERROR in LauSimpleFitModel::initialise : Number of fit parameters not of expected size." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
// From the initial parameter values calculate the coefficients
// so they can be passed to the signal model
this->updateCoeffs();
// Initialisation
if (this->useDP() == kTRUE) {
this->initialiseDPModels();
}
if (!this->useDP() && signalPdfs_.empty()) {
std::cerr << "ERROR in LauSimpleFitModel::initialise : Signal model doesn't exist for any variable." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
this->setExtraNtupleVars();
}
void LauSimpleFitModel::initialiseDPModels()
{
std::cout << "INFO in LauSimpleFitModel::initialiseDPModels : Initialising signal DP model" << std::endl;
sigDPModel_->initialise(coeffs_);
if (usingBkgnd_ == kTRUE) {
for (LauBkgndDPModelList::iterator iter = bkgndDPModels_.begin(); iter != bkgndDPModels_.end(); ++iter) {
(*iter)->initialise();
}
}
}
void LauSimpleFitModel::setSignalDPParameters()
{
// Set the fit parameters for the signal model.
nSigDPPar_ = 0;
if ( ! this->useDP() ) {
return;
}
std::cout << "INFO in LauSimpleFitModel::setSignalDPParameters : Setting the initial fit parameters for the signal DP model." << std::endl;
// Need to check that the number of components we have and that the dynamics has matches up
UInt_t nAmp = sigDPModel_->getnAmp();
if (nAmp != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::setSignalDPParameters : Number of signal DP components with magnitude and phase set not right." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
// Place signal model parameters in vector of fit variables
LauParameterPList& fitVars = this->fitPars();
for (UInt_t i = 0; i < nSigComp_; i++) {
LauParameterPList pars = coeffPars_[i]->getParameters();
for (LauParameterPList::iterator iter = pars.begin(); iter != pars.end(); ++iter) {
if ( !(*iter)->clone() ) {
fitVars.push_back(*iter);
++nSigDPPar_;
}
}
}
}
void LauSimpleFitModel::setExtraPdfParameters()
{
// Include all the parameters of the various PDFs in the fit
// NB all of them are passed to the fit, even though some have been fixed through parameter.fixed(kTRUE)
// With the new "cloned parameter" scheme only "original" parameters are passed to the fit.
// Their clones are updated automatically when the originals are updated.
nExtraPdfPar_ = 0;
nExtraPdfPar_ += this->addFitParameters(signalPdfs_);
if (useSCF_ == kTRUE) {
nExtraPdfPar_ += this->addFitParameters(scfPdfs_);
}
if (usingBkgnd_ == kTRUE) {
for (LauBkgndPdfsList::iterator iter = bkgndPdfs_.begin(); iter != bkgndPdfs_.end(); ++iter) {
nExtraPdfPar_ += this->addFitParameters(*iter);
}
}
}
void LauSimpleFitModel::setFitNEvents()
{
if ( signalEvents_ == 0 ) {
std::cerr << "ERROR in LauSimpleFitModel::setFitNEvents : Signal yield not defined." << std::endl;
return;
}
nNormPar_ = 0;
// initialise the total number of events to be the sum of all the hypotheses
Double_t nTotEvts = signalEvents_->value();
for (LauBkgndYieldList::const_iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
nTotEvts += (*iter)->value();
if ( (*iter) == 0 ) {
std::cerr << "ERROR in LauSimpleFitModel::setFitNEvents : Background yield not defined." << std::endl;
return;
}
}
this->eventsPerExpt(TMath::FloorNint(nTotEvts));
LauParameterPList& fitVars = this->fitPars();
// if doing an extended ML fit add the number of signal events into the fit parameters
if (this->doEMLFit()) {
std::cout << "INFO in LauSimpleFitModel::setFitNEvents : Initialising number of events for signal and background components..." << std::endl;
// add the signal events to the list of fit parameters
fitVars.push_back(signalEvents_);
++nNormPar_;
} else {
std::cout << "INFO in LauSimpleFitModel::setFitNEvents : Initialising number of events for background components (and hence signal)..." << std::endl;
}
if (useSCF_ && !useSCFHist_) {
fitVars.push_back(&scfFrac_);
++nNormPar_;
}
if (usingBkgnd_ == kTRUE) {
for (LauBkgndYieldList::iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
LauParameter* parameter = (*iter);
fitVars.push_back(parameter);
++nNormPar_;
}
}
}
void LauSimpleFitModel::setExtraNtupleVars()
{
// Set-up other parameters derived from the fit results, e.g. fit fractions.
if (this->useDP() != kTRUE) {
return;
}
// First clear the vectors so we start from scratch
this->clearExtraVarVectors();
LauParameterList& extraVars = this->extraPars();
// Add a fit fraction for each signal component
fitFrac_ = sigDPModel_->getFitFractions();
if (fitFrac_.size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << fitFrac_.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (fitFrac_[i].size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << fitFrac_[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
// Add the fit fraction that has not been corrected for the efficiency for each signal component
fitFracEffUnCorr_ = sigDPModel_->getFitFractionsEfficiencyUncorrected();
if (fitFracEffUnCorr_.size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << fitFracEffUnCorr_.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (fitFracEffUnCorr_[i].size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::setExtraNtupleVars : Initial Fit Fraction array of unexpected dimension: " << fitFracEffUnCorr_[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
for (UInt_t i = 0; i < nSigComp_; i++) {
for (UInt_t j = i; j < nSigComp_; j++) {
extraVars.push_back(fitFrac_[i][j]);
extraVars.push_back(fitFracEffUnCorr_[i][j]);
}
}
// Store any extra parameters/quantities from the DP model (e.g. K-matrix total fit fractions)
std::vector<LauParameter> extraParams = sigDPModel_->getExtraParameters();
std::vector<LauParameter>::iterator extraIter;
for (extraIter = extraParams.begin(); extraIter != extraParams.end(); ++extraIter) {
LauParameter extraParameter = (*extraIter);
extraVars.push_back(extraParameter);
}
// Now add in the DP efficiency value
Double_t initMeanEff = sigDPModel_->getMeanEff().initValue();
meanEff_.value(initMeanEff); meanEff_.initValue(initMeanEff); meanEff_.genValue(initMeanEff);
extraVars.push_back(meanEff_);
// Also add in the DP rate
Double_t initDPRate = sigDPModel_->getDPRate().initValue();
dpRate_.value(initDPRate); dpRate_.initValue(initDPRate); dpRate_.genValue(initDPRate);
extraVars.push_back(dpRate_);
}
void LauSimpleFitModel::finaliseFitResults(const TString& tablePrefixName)
{
// Retrieve parameters from the fit results for calculations and toy generation
// and eventually store these in output root ntuples/text files
// Now take the fit parameters and update them as necessary
// e.g. to make mag > 0.0 and phase in the right range.
// This function will also calculate any other values, such as the
// fit fractions, using any errors provided by fitParErrors as appropriate.
// Also obtain the pull values: (measured - generated)/(average error)
if (this->useDP() == kTRUE) {
for (UInt_t i = 0; i < nSigComp_; i++) {
// Check whether we have mag > 0.0, and phase in the right range
coeffPars_[i]->finaliseValues();
}
}
// update the pulls on the events
if (this->doEMLFit()) {
signalEvents_->updatePull();
}
if (useSCF_ && !useSCFHist_) {
scfFrac_.updatePull();
}
if (usingBkgnd_ == kTRUE) {
for (LauBkgndYieldList::iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
(*iter)->updatePull();
}
}
// Update the pulls on all the extra PDFs' parameters
this->updateFitParameters(signalPdfs_);
if (useSCF_ == kTRUE) {
this->updateFitParameters(scfPdfs_);
}
if (usingBkgnd_ == kTRUE) {
for (LauBkgndPdfsList::iterator iter = bkgndPdfs_.begin(); iter != bkgndPdfs_.end(); ++iter) {
this->updateFitParameters(*iter);
}
}
// Fill the fit results to the ntuple for current experiment
// update the coefficients and then calculate the fit fractions
if (this->useDP() == kTRUE) {
this->updateCoeffs();
sigDPModel_->updateCoeffs(coeffs_);
sigDPModel_->calcExtraInfo();
LauParArray fitFrac = sigDPModel_->getFitFractions();
if (fitFrac.size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << fitFrac.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (fitFrac[i].size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << fitFrac[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
LauParArray fitFracEffUnCorr = sigDPModel_->getFitFractionsEfficiencyUncorrected();
if (fitFracEffUnCorr.size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << fitFracEffUnCorr.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (fitFracEffUnCorr[i].size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::finaliseFitResults : Fit Fraction array of unexpected dimension: " << fitFracEffUnCorr[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
for (UInt_t i(0); i<nSigComp_; ++i) {
for (UInt_t j(i); j<nSigComp_; ++j) {
fitFrac_[i][j].value(fitFrac[i][j].value());
fitFracEffUnCorr_[i][j].value(fitFracEffUnCorr[i][j].value());
}
}
meanEff_.value(sigDPModel_->getMeanEff().value());
dpRate_.value(sigDPModel_->getDPRate().value());
this->clearExtraVarVectors();
LauParameterList& extraVars = this->extraPars();
// Then store the final fit parameters, and any extra parameters for
// the signal model (e.g. fit fractions)
for (UInt_t i(0); i<nSigComp_; ++i) {
for (UInt_t j(i); j<nSigComp_; ++j) {
extraVars.push_back(fitFrac_[i][j]);
extraVars.push_back(fitFracEffUnCorr_[i][j]);
}
}
// Store any extra parameters/quantities from the DP model (e.g. K-matrix total fit fractions)
std::vector<LauParameter> extraParams = sigDPModel_->getExtraParameters();
std::vector<LauParameter>::iterator extraIter;
for (extraIter = extraParams.begin(); extraIter != extraParams.end(); ++extraIter) {
LauParameter extraParameter = (*extraIter);
extraVars.push_back(extraParameter);
}
// Now add in the DP efficiency value
extraVars.push_back(meanEff_);
// Also add in the DP rate
extraVars.push_back(dpRate_);
this->printFitFractions(std::cout);
}
const LauParameterPList& fitVars = this->fitPars();
const LauParameterList& extraVars = this->extraPars();
LauFitNtuple* ntuple = this->fitNtuple();
ntuple->storeParsAndErrors(fitVars, extraVars);
// find out the correlation matrix for the parameters
ntuple->storeCorrMatrix(this->iExpt(), this->nll(), this->fitStatus(), this->covarianceMatrix());
// Fill the data into ntuple
ntuple->updateFitNtuple();
// Print out the partial fit fractions, phases and the
// averaged efficiency, reweighted by the dynamics (and anything else)
if (this->writeLatexTable()) {
TString sigOutFileName(tablePrefixName);
sigOutFileName += "_"; sigOutFileName += this->iExpt(); sigOutFileName += "Expt.tex";
this->writeOutTable(sigOutFileName);
}
}
void LauSimpleFitModel::printFitFractions(std::ostream& output)
{
// Print out Fit Fractions, total DP rate and mean efficiency
for (UInt_t i = 0; i < nSigComp_; i++) {
output << "FitFraction for component " << i << " (" << coeffPars_[i]->name() << ") = " << fitFrac_[i][i] << std::endl;
}
output << "Overall DP rate (integral of matrix element squared) = " << dpRate_ << std::endl;
output << "Average efficiency weighted by whole DP dynamics = " << meanEff_ << std::endl;
}
void LauSimpleFitModel::writeOutTable(const TString& outputFile)
{
// Write out the results of the fit to a tex-readable table
// TODO - need to include the yields in this table
std::ofstream fout(outputFile);
LauPrint print;
std::cout << "INFO in LauSimpleFitModel::writeOutTable : Writing out results of the fit to the tex file " << outputFile << std::endl;
if (this->useDP() == kTRUE) {
// print the fit coefficients in one table
coeffPars_.front()->printTableHeading(fout);
for (UInt_t i = 0; i < nSigComp_; i++) {
coeffPars_[i]->printTableRow(fout);
}
fout << "\\hline" << std::endl;
fout << "\\end{tabular}" << std::endl << std::endl;
// print the fit fractions in another
fout << "\\begin{tabular}{|l|c|}" << std::endl;
fout << "\\hline" << std::endl;
fout << "Component & FitFraction \\\\" << std::endl;
fout << "\\hline" << std::endl;
Double_t fitFracSum(0.0);
for (UInt_t i = 0; i < nSigComp_; i++) {
TString resName = coeffPars_[i]->name();
resName = resName.ReplaceAll("_", "\\_");
fout << resName << " & $";
Double_t fitFrac = fitFrac_[i][i].value();
fitFracSum += fitFrac;
print.printFormat(fout, fitFrac);
fout << "$ \\\\" << std::endl;
}
fout << "\\hline" << std::endl;
// Also print out sum of fit fractions
fout << "Fit Fraction Sum & $";
print.printFormat(fout, fitFracSum);
fout << "$ \\\\" << std::endl;
fout << "\\hline" << std::endl;
fout << "DP rate & $";
print.printFormat(fout, dpRate_.value());
fout << "$ \\\\" << std::endl;
fout << "\\hline" << std::endl;
fout << "$< \\varepsilon >$ & $";
print.printFormat(fout, meanEff_.value());
fout << "$ \\\\" << std::endl;
fout << "\\hline" << std::endl;
fout << "\\end{tabular}" << std::endl << std::endl;
}
if (!signalPdfs_.empty()) {
fout << "\\begin{tabular}{|l|c|}" << std::endl;
fout << "\\hline" << std::endl;
if (useSCF_ == kTRUE) {
fout << "\\Extra TM Signal PDFs' Parameters: & \\\\" << std::endl;
} else {
fout << "\\Extra Signal PDFs' Parameters: & \\\\" << std::endl;
}
this->printFitParameters(signalPdfs_, fout);
if (useSCF_ == kTRUE && !scfPdfs_.empty()) {
fout << "\\hline" << std::endl;
fout << "\\Extra SCF Signal PDFs' Parameters: & \\\\" << std::endl;
this->printFitParameters(scfPdfs_, fout);
}
if (usingBkgnd_ == kTRUE && !bkgndPdfs_.empty()) {
fout << "\\hline" << std::endl;
fout << "\\Extra Background PDFs' Parameters: & \\\\" << std::endl;
for (LauBkgndPdfsList::const_iterator iter = bkgndPdfs_.begin(); iter != bkgndPdfs_.end(); ++iter) {
this->printFitParameters(*iter, fout);
}
}
fout << "\\hline \n\\end{tabular}" << std::endl << std::endl;
}
}
void LauSimpleFitModel::checkInitFitParams()
{
// Update the number of signal events to be total-sum(background events)
this->updateSigEvents();
// Check whether we want to have randomised initial fit parameters for the signal model
if (this->useRandomInitFitPars() == kTRUE) {
std::cout << "INFO in LauSimpleFitModel::checkInitFitParams : Setting random parameters for the signal DP model" << std::endl;
this->randomiseInitFitPars();
}
}
void LauSimpleFitModel::randomiseInitFitPars()
{
// Only randomise those parameters that are not fixed!
std::cout << "INFO in LauSimpleFitModel::randomiseInitFitPars : Randomising the initial fit magnitudes and phases of the resonances..." << std::endl;
for (UInt_t i = 0; i < nSigComp_; i++) {
coeffPars_[i]->randomiseInitValues();
}
}
LauSimpleFitModel::LauGenInfo LauSimpleFitModel::eventsToGenerate()
{
// Determine the number of events to generate for each hypothesis
// If we're smearing then smear each one individually
LauGenInfo nEvtsGen;
// Signal
Double_t evtWeight(1.0);
Int_t nEvts = TMath::FloorNint(signalEvents_->genValue());
if ( nEvts < 0 ) {
evtWeight = -1.0;
nEvts = TMath::Abs( nEvts );
}
if (this->doPoissonSmearing()) {
nEvts = LauRandom::randomFun()->Poisson(nEvts);
}
nEvtsGen["signal"] = std::make_pair( nEvts, evtWeight );
// Backgrounds
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
const TString& bkgndClass = this->bkgndClassName(bkgndID);
const LauParameter* evtsPar = bkgndEvents_[bkgndID];
evtWeight = 1.0;
nEvts = TMath::FloorNint( evtsPar->genValue() );
if ( nEvts < 0 ) {
evtWeight = -1.0;
nEvts = TMath::Abs( nEvts );
}
if (this->doPoissonSmearing()) {
nEvts = LauRandom::randomFun()->Poisson(nEvts);
}
nEvtsGen[bkgndClass] = std::make_pair( nEvts, evtWeight );
}
return nEvtsGen;
}
Bool_t LauSimpleFitModel::genExpt()
{
// Routine to generate toy Monte Carlo events according to the various models we have defined.
// Determine the number of events to generate for each hypothesis
LauGenInfo nEvts = this->eventsToGenerate();
Bool_t genOK(kTRUE);
Int_t evtNum(0);
const UInt_t nBkgnds = this->nBkgndClasses();
std::vector<TString> bkgndClassNames(nBkgnds);
std::vector<TString> bkgndClassNamesGen(nBkgnds);
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name( this->bkgndClassName(iBkgnd) );
bkgndClassNames[iBkgnd] = name;
bkgndClassNamesGen[iBkgnd] = "gen"+name;
}
const Bool_t storeSCFTruthInfo = ( useSCF_ || ( this->enableEmbedding() && signalTree_ != 0 && signalTree_->haveBranch("mcMatch") ) );
// Loop over the hypotheses and generate the requested number of events for each one
for (LauGenInfo::const_iterator iter = nEvts.begin(); iter != nEvts.end(); ++iter) {
const TString& type(iter->first);
Int_t nEvtsGen( iter->second.first );
Double_t evtWeight( iter->second.second );
for (Int_t iEvt(0); iEvt<nEvtsGen; ++iEvt) {
this->setGenNtupleDoubleBranchValue( "evtWeight", evtWeight );
// Add efficiency information
this->setGenNtupleDoubleBranchValue( "efficiency", 1 );
if (type == "signal") {
this->setGenNtupleIntegerBranchValue("genSig",1);
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
this->setGenNtupleIntegerBranchValue( bkgndClassNamesGen[iBkgnd], 0 );
}
genOK = this->generateSignalEvent();
this->setGenNtupleDoubleBranchValue( "efficiency", sigDPModel_->getEvtEff() );
} else {
this->setGenNtupleIntegerBranchValue("genSig",0);
if ( storeSCFTruthInfo ) {
this->setGenNtupleIntegerBranchValue("genTMSig",0);
this->setGenNtupleIntegerBranchValue("genSCFSig",0);
}
UInt_t bkgndID(0);
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
Int_t gen(0);
if ( bkgndClassNames[iBkgnd] == type ) {
gen = 1;
bkgndID = iBkgnd;
}
this->setGenNtupleIntegerBranchValue( bkgndClassNamesGen[iBkgnd], gen );
}
genOK = this->generateBkgndEvent(bkgndID);
}
if (!genOK) {
// If there was a problem with the generation then break out and return.
// The problem model will have adjusted itself so that all should be OK next time.
break;
}
if (this->useDP() == kTRUE) {
this->setDPBranchValues();
}
// Store the event number (within this experiment)
this->setGenNtupleIntegerBranchValue("iEvtWithinExpt",evtNum);
// and then increment it
++evtNum;
this->fillGenNtupleBranches();
if (iEvt%500 == 0) {
std::cout << "INFO in LauSimpleFitModel::genExpt : Generated event number " << iEvt << " out of " << nEvtsGen << " " << type << " events." << std::endl;
}
}
if (!genOK) {
break;
}
}
if (this->useDP() && genOK) {
sigDPModel_->checkToyMC(kTRUE,kTRUE);
// Get the fit fractions if they're to be written into the latex table
if (this->writeLatexTable()) {
LauParArray fitFrac = sigDPModel_->getFitFractions();
if (fitFrac.size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::genExpt : Fit Fraction array of unexpected dimension: " << fitFrac.size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
for (UInt_t i(0); i<nSigComp_; ++i) {
if (fitFrac[i].size() != nSigComp_) {
std::cerr << "ERROR in LauSimpleFitModel::genExpt : Fit Fraction array of unexpected dimension: " << fitFrac[i].size() << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
}
for (UInt_t i(0); i<nSigComp_; ++i) {
for (UInt_t j = i; j < nSigComp_; j++) {
fitFrac_[i][j].value(fitFrac[i][j].value());
}
}
meanEff_.value(sigDPModel_->getMeanEff().value());
dpRate_.value(sigDPModel_->getDPRate().value());
}
}
// If we're reusing embedded events or if the generation is being
// reset then clear the lists of used events
if (reuseSignal_ || !genOK) {
if (signalTree_) {
signalTree_->clearUsedList();
}
}
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
LauEmbeddedData* data = bkgndTree_[bkgndID];
if (reuseBkgnd_[bkgndID] || !genOK) {
if (data) {
data->clearUsedList();
}
}
}
return genOK;
}
Bool_t LauSimpleFitModel::generateSignalEvent()
{
// Generate signal event
Bool_t genOK(kTRUE);
Bool_t genSCF(kFALSE);
if (this->useDP()) {
if (this->enableEmbedding() && signalTree_) {
if (useReweighting_) {
// Select a (random) event from the generated data. Then store the
// reconstructed DP co-ords, together with other pdf information,
// as the embedded data.
genOK = signalTree_->getReweightedEvent(sigDPModel_);
} else {
signalTree_->getEmbeddedEvent(kinematics_);
}
if (signalTree_->haveBranch("mcMatch")) {
Int_t match = static_cast<Int_t>(signalTree_->getValue("mcMatch"));
if (match) {
this->setGenNtupleIntegerBranchValue("genTMSig",1);
this->setGenNtupleIntegerBranchValue("genSCFSig",0);
genSCF = kFALSE;
} else {
this->setGenNtupleIntegerBranchValue("genTMSig",0);
this->setGenNtupleIntegerBranchValue("genSCFSig",1);
genSCF = kTRUE;
}
}
} else {
genOK = sigDPModel_->generate();
if ( genOK && useSCF_ ) {
Double_t frac(0.0);
if ( useSCFHist_ ) {
frac = scfFracHist_->calcEfficiency( kinematics_ );
} else {
frac = scfFrac_.genValue();
}
if ( frac < LauRandom::randomFun()->Rndm() ) {
this->setGenNtupleIntegerBranchValue("genTMSig",1);
this->setGenNtupleIntegerBranchValue("genSCFSig",0);
genSCF = kFALSE;
} else {
this->setGenNtupleIntegerBranchValue("genTMSig",0);
this->setGenNtupleIntegerBranchValue("genSCFSig",1);
genSCF = kTRUE;
// Optionally smear the DP position
// of the SCF event
if ( scfMap_ != 0 ) {
Double_t xCoord(0.0), yCoord(0.0);
if ( kinematics_->squareDP() ) {
xCoord = kinematics_->getmPrime();
yCoord = kinematics_->getThetaPrime();
} else {
xCoord = kinematics_->getm13Sq();
yCoord = kinematics_->getm23Sq();
}
// Find the bin number where this event is generated
Int_t binNo = scfMap_->binNumber( xCoord, yCoord );
// Retrieve the migration histogram
TH2* histo = scfMap_->trueHist( binNo );
- LauEffModel * effModel = sigDPModel_->getEffModel();
+ LauAbsEffModel * effModel = sigDPModel_->getEffModel();
do {
// Get a random point from the histogram
histo->GetRandom2( xCoord, yCoord );
// Update the kinematics
if ( kinematics_->squareDP() ) {
kinematics_->updateSqDPKinematics( xCoord, yCoord );
} else {
kinematics_->updateKinematics( xCoord, yCoord );
}
} while ( ! effModel->passVeto( kinematics_ ) );
}
}
}
}
} else {
if (this->enableEmbedding() && signalTree_) {
signalTree_->getEmbeddedEvent(0);
if (signalTree_->haveBranch("mcMatch")) {
Int_t match = static_cast<Int_t>(signalTree_->getValue("mcMatch"));
if (match) {
this->setGenNtupleIntegerBranchValue("genTMSig",1);
this->setGenNtupleIntegerBranchValue("genSCFSig",0);
genSCF = kFALSE;
} else {
this->setGenNtupleIntegerBranchValue("genTMSig",0);
this->setGenNtupleIntegerBranchValue("genSCFSig",1);
genSCF = kTRUE;
}
}
} else if ( useSCF_ ) {
Double_t frac = scfFrac_.genValue();
if ( frac < LauRandom::randomFun()->Rndm() ) {
this->setGenNtupleIntegerBranchValue("genTMSig",1);
this->setGenNtupleIntegerBranchValue("genSCFSig",0);
genSCF = kFALSE;
} else {
this->setGenNtupleIntegerBranchValue("genTMSig",0);
this->setGenNtupleIntegerBranchValue("genSCFSig",1);
genSCF = kTRUE;
}
}
}
if (genOK) {
if ( useSCF_ ) {
if ( genSCF ) {
this->generateExtraPdfValues(&scfPdfs_, signalTree_);
} else {
this->generateExtraPdfValues(&signalPdfs_, signalTree_);
}
} else {
this->generateExtraPdfValues(&signalPdfs_, signalTree_);
}
}
// Check for problems with the embedding
if (this->enableEmbedding() && signalTree_ && (signalTree_->nEvents() == signalTree_->nUsedEvents())) {
std::cerr << "WARNING in LauSimpleFitModel::generateSignalEvent : Source of embedded signal events used up, clearing the list of used events." << std::endl;
signalTree_->clearUsedList();
}
return genOK;
}
Bool_t LauSimpleFitModel::generateBkgndEvent(UInt_t bkgndID)
{
// Generate background event
Bool_t genOK(kTRUE);
LauAbsBkgndDPModel* model = bkgndDPModels_[bkgndID];
LauEmbeddedData* embeddedData(0);
if (this->enableEmbedding()) {
embeddedData = bkgndTree_[bkgndID];
}
LauPdfList* extraPdfs = &bkgndPdfs_[bkgndID];
if (this->useDP()) {
if (embeddedData) {
embeddedData->getEmbeddedEvent(kinematics_);
} else {
if (model == 0) {
std::cerr << "ERROR in LauSimpleFitModel::generateBkgndEvent : Can't find the DP model for background class \"" << this->bkgndClassName(bkgndID) << "\"." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
genOK = model->generate();
}
} else {
if (embeddedData) {
embeddedData->getEmbeddedEvent(0);
}
}
if (genOK) {
this->generateExtraPdfValues(extraPdfs, embeddedData);
}
// Check for problems with the embedding
if (embeddedData && (embeddedData->nEvents() == embeddedData->nUsedEvents())) {
std::cerr << "WARNING in LauSimpleFitModel::generateBkgndEvent : Source of embedded " << this->bkgndClassName(bkgndID) << " events used up, clearing the list of used events." << std::endl;
embeddedData->clearUsedList();
}
return genOK;
}
void LauSimpleFitModel::setupGenNtupleBranches()
{
// Setup the required ntuple branches
this->addGenNtupleDoubleBranch("evtWeight");
this->addGenNtupleIntegerBranch("genSig");
this->addGenNtupleDoubleBranch("efficiency");
if ( useSCF_ || ( this->enableEmbedding() && signalTree_ != 0 && signalTree_->haveBranch("mcMatch") ) ) {
this->addGenNtupleIntegerBranch("genTMSig");
this->addGenNtupleIntegerBranch("genSCFSig");
}
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name( this->bkgndClassName(iBkgnd) );
name.Prepend("gen");
this->addGenNtupleIntegerBranch(name);
}
if (this->useDP() == kTRUE) {
this->addGenNtupleDoubleBranch("m12");
this->addGenNtupleDoubleBranch("m23");
this->addGenNtupleDoubleBranch("m13");
this->addGenNtupleDoubleBranch("m12Sq");
this->addGenNtupleDoubleBranch("m23Sq");
this->addGenNtupleDoubleBranch("m13Sq");
this->addGenNtupleDoubleBranch("cosHel12");
this->addGenNtupleDoubleBranch("cosHel23");
this->addGenNtupleDoubleBranch("cosHel13");
if (kinematics_->squareDP()) {
this->addGenNtupleDoubleBranch("mPrime");
this->addGenNtupleDoubleBranch("thPrime");
}
}
for (LauPdfList::const_iterator pdf_iter = signalPdfs_.begin(); pdf_iter != signalPdfs_.end(); ++pdf_iter) {
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
this->addGenNtupleDoubleBranch( (*var_iter) );
}
}
}
}
void LauSimpleFitModel::setDPBranchValues()
{
// Store all the DP information
this->setGenNtupleDoubleBranchValue("m12", kinematics_->getm12());
this->setGenNtupleDoubleBranchValue("m23", kinematics_->getm23());
this->setGenNtupleDoubleBranchValue("m13", kinematics_->getm13());
this->setGenNtupleDoubleBranchValue("m12Sq", kinematics_->getm12Sq());
this->setGenNtupleDoubleBranchValue("m23Sq", kinematics_->getm23Sq());
this->setGenNtupleDoubleBranchValue("m13Sq", kinematics_->getm13Sq());
this->setGenNtupleDoubleBranchValue("cosHel12", kinematics_->getc12());
this->setGenNtupleDoubleBranchValue("cosHel23", kinematics_->getc23());
this->setGenNtupleDoubleBranchValue("cosHel13", kinematics_->getc13());
if (kinematics_->squareDP()) {
this->setGenNtupleDoubleBranchValue("mPrime", kinematics_->getmPrime());
this->setGenNtupleDoubleBranchValue("thPrime", kinematics_->getThetaPrime());
}
}
void LauSimpleFitModel::generateExtraPdfValues(LauPdfList* extraPdfs, LauEmbeddedData* embeddedData)
{
// Generate from the extra PDFs
if (extraPdfs) {
for (LauPdfList::iterator pdf_iter = extraPdfs->begin(); pdf_iter != extraPdfs->end(); ++pdf_iter) {
LauFitData genValues;
if (embeddedData) {
genValues = embeddedData->getValues( (*pdf_iter)->varNames() );
} else {
genValues = (*pdf_iter)->generate(kinematics_);
}
for ( LauFitData::const_iterator var_iter = genValues.begin(); var_iter != genValues.end(); ++var_iter ) {
TString varName = var_iter->first;
if ( varName != "m13Sq" && varName != "m23Sq" ) {
Double_t value = var_iter->second;
this->setGenNtupleDoubleBranchValue(varName,value);
}
}
}
}
}
void LauSimpleFitModel::propagateParUpdates()
{
// Update the total normalisation for the signal likelihood
if (this->useDP() == kTRUE) {
this->updateCoeffs();
sigDPModel_->updateCoeffs(coeffs_);
}
// Update the signal events from the background events if not doing an extended fit
if ( !this->doEMLFit() && !signalEvents_->fixed() ) {
this->updateSigEvents();
}
}
void LauSimpleFitModel::updateSigEvents()
{
// The background parameters will have been set from Minuit.
// We need to update the signal events using these.
Double_t nTotEvts = this->eventsPerExpt();
signalEvents_->range(-2.0*nTotEvts,2.0*nTotEvts);
for (LauBkgndYieldList::iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
(*iter)->range(-2.0*nTotEvts,2.0*nTotEvts);
}
if ( signalEvents_->fixed() ) {
return;
}
// Subtract background events (if any) from signal.
Double_t signalEvents = nTotEvts;
if ( usingBkgnd_ == kTRUE ) {
for (LauBkgndYieldList::const_iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
signalEvents -= (*iter)->value();
}
}
signalEvents_->value(signalEvents);
}
void LauSimpleFitModel::cacheInputFitVars()
{
// Fill the internal data trees of the signal and backgrond models.
LauFitDataTree* inputFitData = this->fitData();
// First the Dalitz plot variables (m_ij^2)
if (this->useDP() == kTRUE) {
// need to append SCF smearing bins before caching DP amplitudes
if ( scfMap_ != 0 ) {
this->appendBinCentres( inputFitData );
}
sigDPModel_->fillDataTree(*inputFitData);
if (usingBkgnd_ == kTRUE) {
for (LauBkgndDPModelList::iterator iter = bkgndDPModels_.begin(); iter != bkgndDPModels_.end(); ++iter) {
(*iter)->fillDataTree(*inputFitData);
}
}
}
// ...and then the extra PDFs
this->cacheInfo(signalPdfs_, *inputFitData);
this->cacheInfo(scfPdfs_, *inputFitData);
for (LauBkgndPdfsList::iterator iter = bkgndPdfs_.begin(); iter != bkgndPdfs_.end(); ++iter) {
this->cacheInfo((*iter), *inputFitData);
}
// and finally the SCF fractions and jacobians
if ( useSCF_ && useSCFHist_ ) {
if ( !inputFitData->haveBranch( "m13Sq" ) || !inputFitData->haveBranch( "m23Sq" ) ) {
std::cerr << "ERROR in LauSimpleFitModel::cacheInputFitVars : Input data does not contain DP branches and so can't cache the SCF fraction." << std::endl;
gSystem->Exit(EXIT_FAILURE);
}
UInt_t nEvents = inputFitData->nEvents();
recoSCFFracs_.clear();
recoSCFFracs_.reserve( nEvents );
if ( kinematics_->squareDP() ) {
recoJacobians_.clear();
recoJacobians_.reserve( nEvents );
}
for (UInt_t iEvt = 0; iEvt < nEvents; iEvt++) {
const LauFitData& dataValues = inputFitData->getData(iEvt);
LauFitData::const_iterator m13_iter = dataValues.find("m13Sq");
LauFitData::const_iterator m23_iter = dataValues.find("m23Sq");
kinematics_->updateKinematics( m13_iter->second, m23_iter->second );
Double_t scfFrac = scfFracHist_->calcEfficiency( kinematics_ );
recoSCFFracs_.push_back( scfFrac );
if ( kinematics_->squareDP() ) {
recoJacobians_.push_back( kinematics_->calcSqDPJacobian() );
}
}
}
}
void LauSimpleFitModel::appendBinCentres( LauFitDataTree* inputData )
{
// We'll be caching the DP amplitudes and efficiencies of the centres of the true bins.
// To do so, we attach some fake points at the end of inputData, the number of the entry
// minus the total number of events corresponding to the number of the histogram for that
// given true bin in the LauScfMap object. (What this means is that when Laura is provided with
// the LauScfMap object by the user, it's the latter who has to make sure that it contains the
// right number of histograms and in exactly the right order!)
// Get the x and y co-ordinates of the bin centres
std::vector<Double_t> binCentresXCoords;
std::vector<Double_t> binCentresYCoords;
scfMap_->listBinCentres(binCentresXCoords, binCentresYCoords);
// The SCF histograms could be in square Dalitz plot histograms.
// The dynamics takes normal Dalitz plot coords, so we might have to convert them back.
Bool_t sqDP = kinematics_->squareDP();
UInt_t nBins = binCentresXCoords.size();
fakeSCFFracs_.clear();
fakeSCFFracs_.reserve( nBins );
if ( sqDP ) {
fakeJacobians_.clear();
fakeJacobians_.reserve( nBins );
}
for (UInt_t iBin = 0; iBin < nBins; ++iBin) {
if ( sqDP ) {
kinematics_->updateSqDPKinematics(binCentresXCoords[iBin],binCentresYCoords[iBin]);
binCentresXCoords[iBin] = kinematics_->getm13Sq();
binCentresYCoords[iBin] = kinematics_->getm23Sq();
fakeJacobians_.push_back( kinematics_->calcSqDPJacobian() );
} else {
kinematics_->updateKinematics(binCentresXCoords[iBin],binCentresYCoords[iBin]);
}
fakeSCFFracs_.push_back( scfFracHist_->calcEfficiency( kinematics_ ) );
}
// Set up inputFitVars_ object to hold the fake events
inputData->appendFakePoints(binCentresXCoords,binCentresYCoords);
}
Double_t LauSimpleFitModel::getTotEvtLikelihood(UInt_t iEvt)
{
// Get the DP likelihood for signal and backgrounds
this->getEvtDPLikelihood(iEvt);
// Get the combined extra PDFs likelihood for signal and backgrounds
this->getEvtExtraLikelihoods(iEvt);
// If appropriate, combine the TM and SCF likelihoods
Double_t sigLike = sigDPLike_ * sigExtraLike_;
if ( useSCF_ ) {
Double_t scfFrac(0.0);
if (useSCFHist_) {
scfFrac = recoSCFFracs_[iEvt];
} else {
scfFrac = scfFrac_.value();
}
sigLike *= (1.0 - scfFrac);
if ( (scfMap_ != 0) && (this->useDP() == kTRUE) ) {
// if we're smearing the SCF DP PDF then the SCF frac
// is already included in the SCF DP likelihood
sigLike += (scfDPLike_ * scfExtraLike_);
} else {
sigLike += (scfFrac * scfDPLike_ * scfExtraLike_);
}
}
// Construct the total event likelihood
Double_t likelihood = signalEvents_->value() * sigLike;
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
likelihood += (bkgndEvents_[bkgndID]->value() * bkgndDPLike_[bkgndID] * bkgndExtraLike_[bkgndID]);
}
return likelihood;
}
Double_t LauSimpleFitModel::getEventSum() const
{
Double_t eventSum(0.0);
eventSum += signalEvents_->value();
for (LauBkgndYieldList::const_iterator iter = bkgndEvents_.begin(); iter != bkgndEvents_.end(); ++iter) {
eventSum += (*iter)->value();
}
return eventSum;
}
void LauSimpleFitModel::getEvtDPLikelihood(UInt_t iEvt)
{
// Function to return the signal and background likelihoods for the
// Dalitz plot for the given event evtNo.
if (this->useDP() == kTRUE) {
sigDPModel_->calcLikelihoodInfo(iEvt);
sigDPLike_ = sigDPModel_->getEvtLikelihood();
if ( useSCF_ == kTRUE ) {
if ( scfMap_ == 0 ) {
// we're not smearing the SCF DP position
// so the likelihood is the same as the TM
scfDPLike_ = sigDPLike_;
} else {
// calculate the smeared SCF DP likelihood
scfDPLike_ = this->getEvtSCFDPLikelihood(iEvt);
}
}
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
if (usingBkgnd_ == kTRUE) {
bkgndDPLike_[bkgndID] = bkgndDPModels_[bkgndID]->getLikelihood(iEvt);
} else {
bkgndDPLike_[bkgndID] = 0.0;
}
}
} else {
// There's always going to be a term in the likelihood for the
// signal, so we'd better not zero it.
sigDPLike_ = 1.0;
scfDPLike_ = 1.0;
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
if (usingBkgnd_ == kTRUE) {
bkgndDPLike_[bkgndID] = 1.0;
} else {
bkgndDPLike_[bkgndID] = 0.0;
}
}
}
}
Double_t LauSimpleFitModel::getEvtSCFDPLikelihood(UInt_t iEvt)
{
Double_t scfDPLike(0.0);
Double_t recoJacobian(1.0);
Double_t xCoord(0.0);
Double_t yCoord(0.0);
Bool_t squareDP = kinematics_->squareDP();
if ( squareDP ) {
xCoord = sigDPModel_->getEvtmPrime();
yCoord = sigDPModel_->getEvtthPrime();
recoJacobian = recoJacobians_[iEvt];
} else {
xCoord = sigDPModel_->getEvtm13Sq();
yCoord = sigDPModel_->getEvtm23Sq();
}
// Find the bin that our reco event falls in
Int_t recoBin = scfMap_->binNumber( xCoord, yCoord );
// Find out which true Bins contribute to the given reco bin
const std::vector<Int_t>* trueBins = scfMap_->trueBins(recoBin);
Int_t nDataEvents = this->eventsPerExpt();
// Loop over the true bins
for (std::vector<Int_t>::const_iterator iter = trueBins->begin(); iter != trueBins->end(); ++iter)
{
Int_t trueBin = (*iter);
// prob of a true event in the given true bin migrating to the reco bin
Double_t pRecoGivenTrue = scfMap_->prob( recoBin, trueBin );
// We've cached the DP amplitudes and the efficiency for the
// true bin centres, just after the data points
sigDPModel_->calcLikelihoodInfo( nDataEvents + trueBin );
Double_t pTrue = sigDPModel_->getEvtLikelihood();
// Get the cached SCF fraction (and jacobian if we're using the square DP)
Double_t scfFraction = fakeSCFFracs_[ trueBin ];
Double_t jacobian(1.0);
if ( squareDP ) {
jacobian = fakeJacobians_[ trueBin ];
}
scfDPLike += pTrue * jacobian * scfFraction * pRecoGivenTrue;
}
// Divide by the reco jacobian
scfDPLike /= recoJacobian;
return scfDPLike;
}
void LauSimpleFitModel::getEvtExtraLikelihoods(UInt_t iEvt)
{
// Function to return the signal and background likelihoods for the
// extra variables for the given event evtNo.
sigExtraLike_ = 1.0;
for (LauPdfList::iterator iter = signalPdfs_.begin(); iter != signalPdfs_.end(); ++iter) {
(*iter)->calcLikelihoodInfo(iEvt);
sigExtraLike_ *= (*iter)->getLikelihood();
}
if (useSCF_) {
scfExtraLike_ = 1.0;
for (LauPdfList::iterator iter = scfPdfs_.begin(); iter != scfPdfs_.end(); ++iter) {
(*iter)->calcLikelihoodInfo(iEvt);
scfExtraLike_ *= (*iter)->getLikelihood();
}
}
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t bkgndID(0); bkgndID < nBkgnds; ++bkgndID ) {
if (usingBkgnd_) {
bkgndExtraLike_[bkgndID] = 1.0;
LauPdfList& pdfList = bkgndPdfs_[bkgndID];
for (LauPdfList::iterator pdf_iter = pdfList.begin(); pdf_iter != pdfList.end(); ++pdf_iter) {
(*pdf_iter)->calcLikelihoodInfo(iEvt);
bkgndExtraLike_[bkgndID] *= (*pdf_iter)->getLikelihood();
}
} else {
bkgndExtraLike_[bkgndID] = 0.0;
}
}
}
void LauSimpleFitModel::updateCoeffs()
{
coeffs_.clear();
coeffs_.reserve(nSigComp_);
for (UInt_t i = 0; i < nSigComp_; i++) {
coeffs_.push_back(coeffPars_[i]->particleCoeff());
}
}
void LauSimpleFitModel::setupSPlotNtupleBranches()
{
// add branches for storing the experiment number and the number of
// the event within the current experiment
this->addSPlotNtupleIntegerBranch("iExpt");
this->addSPlotNtupleIntegerBranch("iEvtWithinExpt");
// Store the efficiency of the event (for inclusive BF calculations).
if (this->storeDPEff()) {
this->addSPlotNtupleDoubleBranch("efficiency");
if ( sigDPModel_->usingScfModel() ) {
this->addSPlotNtupleDoubleBranch("scffraction");
}
}
// Store the total event likelihood for each species.
if (useSCF_) {
this->addSPlotNtupleDoubleBranch("sigTMTotalLike");
this->addSPlotNtupleDoubleBranch("sigSCFTotalLike");
this->addSPlotNtupleDoubleBranch("sigSCFFrac");
} else {
this->addSPlotNtupleDoubleBranch("sigTotalLike");
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name( this->bkgndClassName(iBkgnd) );
name += "TotalLike";
this->addSPlotNtupleDoubleBranch(name);
}
}
// Store the DP likelihoods
if (this->useDP()) {
if (useSCF_) {
this->addSPlotNtupleDoubleBranch("sigTMDPLike");
this->addSPlotNtupleDoubleBranch("sigSCFDPLike");
} else {
this->addSPlotNtupleDoubleBranch("sigDPLike");
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name( this->bkgndClassName(iBkgnd) );
name += "DPLike";
this->addSPlotNtupleDoubleBranch(name);
}
}
}
// Store the likelihoods for each extra PDF
if (useSCF_) {
this->addSPlotNtupleBranches(&signalPdfs_, "sigTM");
this->addSPlotNtupleBranches(&scfPdfs_, "sigSCF");
} else {
this->addSPlotNtupleBranches(&signalPdfs_, "sig");
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
const LauPdfList* pdfList = &(bkgndPdfs_[iBkgnd]);
this->addSPlotNtupleBranches(pdfList, bkgndClass);
}
}
}
void LauSimpleFitModel::addSPlotNtupleBranches(const LauPdfList* extraPdfs, const TString& prefix)
{
if (extraPdfs) {
// Loop through each of the PDFs
for (LauPdfList::const_iterator pdf_iter = extraPdfs->begin(); pdf_iter != extraPdfs->end(); ++pdf_iter) {
// Count the number of input variables that are not
// DP variables (used in the case where there is DP
// dependence for e.g. MVA)
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 1 ) {
// If the PDF only has one variable then
// simply add one branch for that variable
TString varName = (*pdf_iter)->varName();
TString name(prefix);
name += varName;
name += "Like";
this->addSPlotNtupleDoubleBranch(name);
} else if ( nVars == 2 ) {
// If the PDF has two variables then we
// need a branch for them both together and
// branches for each
TString allVars("");
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
allVars += (*var_iter);
TString name(prefix);
name += (*var_iter);
name += "Like";
this->addSPlotNtupleDoubleBranch(name);
}
TString name(prefix);
name += allVars;
name += "Like";
this->addSPlotNtupleDoubleBranch(name);
} else {
std::cerr << "WARNING in LauSimpleFitModel::addSPlotNtupleBranches : Can't yet deal with 3D PDFs." << std::endl;
}
}
}
}
Double_t LauSimpleFitModel::setSPlotNtupleBranchValues(LauPdfList* extraPdfs, const TString& prefix, UInt_t iEvt)
{
// Store the PDF value for each variable in the list
Double_t totalLike(1.0);
Double_t extraLike(0.0);
if (extraPdfs) {
for (LauPdfList::iterator pdf_iter = extraPdfs->begin(); pdf_iter != extraPdfs->end(); ++pdf_iter) {
// calculate the likelihood for this event
(*pdf_iter)->calcLikelihoodInfo(iEvt);
extraLike = (*pdf_iter)->getLikelihood();
totalLike *= extraLike;
// Count the number of input variables that are not
// DP variables (used in the case where there is DP
// dependence for e.g. MVA)
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 1 ) {
// If the PDF only has one variable then
// simply store the value for that variable
TString varName = (*pdf_iter)->varName();
TString name(prefix);
name += varName;
name += "Like";
this->setSPlotNtupleDoubleBranchValue(name, extraLike);
} else if ( nVars == 2 ) {
// If the PDF has two variables then we
// store the value for them both together
// and for each on their own
TString allVars("");
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
allVars += (*var_iter);
TString name(prefix);
name += (*var_iter);
name += "Like";
Double_t indivLike = (*pdf_iter)->getLikelihood( (*var_iter) );
this->setSPlotNtupleDoubleBranchValue(name, indivLike);
}
TString name(prefix);
name += allVars;
name += "Like";
this->setSPlotNtupleDoubleBranchValue(name, extraLike);
} else {
std::cerr << "WARNING in LauSimpleFitModel::setSPlotNtupleBranchValues : Can't yet deal with 3D PDFs." << std::endl;
}
}
}
return totalLike;
}
LauSPlot::NameSet LauSimpleFitModel::variableNames() const
{
LauSPlot::NameSet nameSet;
if (this->useDP()) {
nameSet.insert("DP");
}
// Loop through all the signal PDFs
for (LauPdfList::const_iterator pdf_iter = signalPdfs_.begin(); pdf_iter != signalPdfs_.end(); ++pdf_iter) {
// Loop over the variables involved in each PDF
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
// If they are not DP coordinates then add them
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
nameSet.insert( (*var_iter) );
}
}
}
return nameSet;
}
LauSPlot::NumbMap LauSimpleFitModel::freeSpeciesNames() const
{
LauSPlot::NumbMap numbMap;
if (!signalEvents_->fixed() && this->doEMLFit()) {
numbMap["sig"] = signalEvents_->genValue();
}
if ( usingBkgnd_ ) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
const LauParameter* par = bkgndEvents_[iBkgnd];
if (!par->fixed()) {
numbMap[bkgndClass] = par->genValue();
}
}
}
return numbMap;
}
LauSPlot::NumbMap LauSimpleFitModel::fixdSpeciesNames() const
{
LauSPlot::NumbMap numbMap;
if (signalEvents_->fixed() && this->doEMLFit()) {
numbMap["sig"] = signalEvents_->genValue();
}
if ( usingBkgnd_ ) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
const LauParameter* par = bkgndEvents_[iBkgnd];
if (par->fixed()) {
numbMap[bkgndClass] = par->genValue();
}
}
}
return numbMap;
}
LauSPlot::TwoDMap LauSimpleFitModel::twodimPDFs() const
{
LauSPlot::TwoDMap twodimMap;
for (LauPdfList::const_iterator pdf_iter = signalPdfs_.begin(); pdf_iter != signalPdfs_.end(); ++pdf_iter) {
// Count the number of input variables that are not DP variables
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 2 ) {
if (useSCF_) {
twodimMap.insert( std::make_pair( "sigTM", std::make_pair( varNames[0], varNames[1] ) ) );
} else {
twodimMap.insert( std::make_pair( "sig", std::make_pair( varNames[0], varNames[1] ) ) );
}
}
}
if ( useSCF_ ) {
for (LauPdfList::const_iterator pdf_iter = scfPdfs_.begin(); pdf_iter != scfPdfs_.end(); ++pdf_iter) {
// Count the number of input variables that are not DP variables
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 2 ) {
twodimMap.insert( std::make_pair( "sigSCF", std::make_pair( varNames[0], varNames[1] ) ) );
}
}
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
const LauPdfList& pdfList = bkgndPdfs_[iBkgnd];
for (LauPdfList::const_iterator pdf_iter = pdfList.begin(); pdf_iter != pdfList.end(); ++pdf_iter) {
// Count the number of input variables that are not DP variables
UInt_t nVars(0);
std::vector<TString> varNames = (*pdf_iter)->varNames();
for ( std::vector<TString>::const_iterator var_iter = varNames.begin(); var_iter != varNames.end(); ++var_iter ) {
if ( (*var_iter) != "m13Sq" && (*var_iter) != "m23Sq" ) {
++nVars;
}
}
if ( nVars == 2 ) {
twodimMap.insert( std::make_pair( bkgndClass, std::make_pair( varNames[0], varNames[1] ) ) );
}
}
}
}
return twodimMap;
}
void LauSimpleFitModel::storePerEvtLlhds()
{
std::cout << "INFO in LauSimpleFitModel::storePerEvtLlhds : Storing per-event likelihood values..." << std::endl;
// if we've not been using the DP model then we need to cache all
// the info here so that we can get the efficiency from it
LauFitDataTree* inputFitData = this->fitData();
if (!this->useDP() && this->storeDPEff()) {
sigDPModel_->initialise(coeffs_);
sigDPModel_->fillDataTree(*inputFitData);
}
UInt_t evtsPerExpt(this->eventsPerExpt());
for (UInt_t iEvt = 0; iEvt < evtsPerExpt; ++iEvt) {
this->setSPlotNtupleIntegerBranchValue("iExpt",this->iExpt());
this->setSPlotNtupleIntegerBranchValue("iEvtWithinExpt",iEvt);
// the DP information
this->getEvtDPLikelihood(iEvt);
if (this->storeDPEff()) {
if (!this->useDP()) {
sigDPModel_->calcLikelihoodInfo(iEvt);
}
this->setSPlotNtupleDoubleBranchValue("efficiency",sigDPModel_->getEvtEff());
if ( sigDPModel_->usingScfModel() ) {
this->setSPlotNtupleDoubleBranchValue("scffraction",sigDPModel_->getEvtScfFraction());
}
}
if (this->useDP()) {
sigTotalLike_ = sigDPLike_;
if (useSCF_) {
scfTotalLike_ = scfDPLike_;
this->setSPlotNtupleDoubleBranchValue("sigTMDPLike",sigDPLike_);
this->setSPlotNtupleDoubleBranchValue("sigSCFDPLike",scfDPLike_);
} else {
this->setSPlotNtupleDoubleBranchValue("sigDPLike",sigDPLike_);
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name = this->bkgndClassName(iBkgnd);
name += "DPLike";
this->setSPlotNtupleDoubleBranchValue(name,bkgndDPLike_[iBkgnd]);
}
}
} else {
sigTotalLike_ = 1.0;
if (useSCF_) {
scfTotalLike_ = 1.0;
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
bkgndTotalLike_[iBkgnd] = 1.0;
}
}
}
// the signal PDF values
if ( useSCF_ ) {
sigTotalLike_ *= this->setSPlotNtupleBranchValues(&signalPdfs_, "sigTM", iEvt);
scfTotalLike_ *= this->setSPlotNtupleBranchValues(&scfPdfs_, "sigSCF", iEvt);
} else {
sigTotalLike_ *= this->setSPlotNtupleBranchValues(&signalPdfs_, "sig", iEvt);
}
// the background PDF values
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
const TString& bkgndClass = this->bkgndClassName(iBkgnd);
LauPdfList& pdfs = bkgndPdfs_[iBkgnd];
bkgndTotalLike_[iBkgnd] *= this->setSPlotNtupleBranchValues(&(pdfs), bkgndClass, iEvt);
}
}
// the total likelihoods
if (useSCF_) {
Double_t scfFrac(0.0);
if ( useSCFHist_ ) {
scfFrac = recoSCFFracs_[iEvt];
} else {
scfFrac = scfFrac_.value();
}
this->setSPlotNtupleDoubleBranchValue("sigSCFFrac",scfFrac);
sigTotalLike_ *= ( 1.0 - scfFrac );
if ( scfMap_ == 0 ) {
scfTotalLike_ *= scfFrac;
}
this->setSPlotNtupleDoubleBranchValue("sigTMTotalLike",sigTotalLike_);
this->setSPlotNtupleDoubleBranchValue("sigSCFTotalLike",scfTotalLike_);
} else {
this->setSPlotNtupleDoubleBranchValue("sigTotalLike",sigTotalLike_);
}
if (usingBkgnd_) {
const UInt_t nBkgnds = this->nBkgndClasses();
for ( UInt_t iBkgnd(0); iBkgnd < nBkgnds; ++iBkgnd ) {
TString name = this->bkgndClassName(iBkgnd);
name += "TotalLike";
this->setSPlotNtupleDoubleBranchValue(name,bkgndTotalLike_[iBkgnd]);
}
}
// fill the tree
this->fillSPlotNtupleBranches();
}
std::cout << "INFO in LauSimpleFitModel::storePerEvtLlhds : Finished storing per-event likelihood values." << std::endl;
}
void LauSimpleFitModel::embedSignal(const TString& fileName, const TString& treeName,
Bool_t reuseEventsWithinEnsemble, Bool_t reuseEventsWithinExperiment,
Bool_t useReweighting)
{
if (signalTree_) {
std::cerr << "ERROR in LauSimpleFitModel::embedSignal : Already embedding signal from a file." << std::endl;
return;
}
if (!reuseEventsWithinEnsemble && reuseEventsWithinExperiment) {
std::cerr << "WARNING in LauSimpleFitModel::embedSignal : Conflicting options provided, will not reuse events at all." << std::endl;
reuseEventsWithinExperiment = kFALSE;
}
signalTree_ = new LauEmbeddedData(fileName,treeName,reuseEventsWithinExperiment);
Bool_t dataOK = signalTree_->findBranches();
if (!dataOK) {
delete signalTree_; signalTree_ = 0;
std::cerr << "ERROR in LauSimpleFitModel::embedSignal : Problem creating data tree for embedding." << std::endl;
return;
}
reuseSignal_ = reuseEventsWithinEnsemble;
useReweighting_ = useReweighting;
if (this->enableEmbedding() == kFALSE) {
this->enableEmbedding(kTRUE);
}
}
void LauSimpleFitModel::embedBkgnd(const TString& bkgndClass, const TString& fileName, const TString& treeName,
Bool_t reuseEventsWithinEnsemble, Bool_t reuseEventsWithinExperiment)
{
if ( ! this->validBkgndClass( bkgndClass ) ) {
std::cerr << "ERROR in LauSimpleFitModel::embedBkgnd : Invalid background class \"" << bkgndClass << "\"." << std::endl;
std::cerr << " : Background class names must be provided in \"setBkgndClassNames\" before any other background-related actions can be performed." << std::endl;
return;
}
UInt_t bkgndID = this->bkgndClassID( bkgndClass );
if (bkgndTree_[bkgndID]) {
std::cerr << "ERROR in LauSimpleFitModel::embedBkgnd : Already embedding background from a file." << std::endl;
return;
}
if (!reuseEventsWithinEnsemble && reuseEventsWithinExperiment) {
std::cerr << "WARNING in LauSimpleFitModel::embedBkgnd : Conflicting options provided, will not reuse events at all." << std::endl;
reuseEventsWithinExperiment = kFALSE;
}
bkgndTree_[bkgndID] = new LauEmbeddedData(fileName,treeName,reuseEventsWithinExperiment);
Bool_t dataOK = bkgndTree_[bkgndID]->findBranches();
if (!dataOK) {
delete bkgndTree_[bkgndID]; bkgndTree_[bkgndID] = 0;
std::cerr << "ERROR in LauSimpleFitModel::embedBkgnd : Problem creating data tree for embedding." << std::endl;
return;
}
reuseBkgnd_[bkgndID] = reuseEventsWithinEnsemble;
if (this->enableEmbedding() == kFALSE) {
this->enableEmbedding(kTRUE);
}
}
void LauSimpleFitModel::weightEvents( const TString& dataFileName, const TString& dataTreeName )
{
// Routine to provide weights for events that are uniformly distributed
// in the DP (or square DP) so as to reproduce the given DP model
if ( kinematics_->squareDP() ) {
std::cout << "INFO in LauSimpleFitModel::weightEvents : will create weights assuming events were generated flat in the square DP" << std::endl;
} else {
std::cout << "INFO in LauSimpleFitModel::weightEvents : will create weights assuming events were generated flat in phase space" << std::endl;
}
// This reads in the given dataFile and creates an input
// fit data tree that stores them for all events and experiments.
Bool_t dataOK = this->cacheFitData(dataFileName,dataTreeName);
if (!dataOK) {
std::cerr << "ERROR in LauSimpleFitModel::weightEvents : Problem caching the data." << std::endl;
return;
}
LauFitDataTree* inputFitData = this->fitData();
if ( ! inputFitData->haveBranch( "m13Sq_MC" ) || ! inputFitData->haveBranch( "m23Sq_MC" ) ) {
std::cerr << "WARNING in LauSimpleFitModel::weightEvents : Cannot find MC truth DP coordinate branches in supplied data, aborting." << std::endl;
return;
}
// Create the ntuple to hold the DP weights
TString weightsFileName( dataFileName );
Ssiz_t index = weightsFileName.Last('.');
weightsFileName.Insert( index, "_DPweights" );
LauGenNtuple * weightsTuple = new LauGenNtuple( weightsFileName, dataTreeName );
weightsTuple->addIntegerBranch("iExpt");
weightsTuple->addIntegerBranch("iEvtWithinExpt");
weightsTuple->addDoubleBranch("dpModelWeight");
UInt_t iExpmt = this->iExpt();
UInt_t nExpmt = this->nExpt();
UInt_t firstExpmt = this->firstExpt();
for (iExpmt = firstExpmt; iExpmt < (firstExpmt+nExpmt); ++iExpmt) {
inputFitData->readExperimentData(iExpmt);
UInt_t nEvents = inputFitData->nEvents();
if (nEvents < 1) {
std::cerr << "WARNING in LauSimpleFitModel::weightEvents : Zero events in experiment " << iExpmt << ", skipping..." << std::endl;
continue;
}
weightsTuple->setIntegerBranchValue( "iExpt", iExpmt );
// Calculate and store the weights for the events in this experiment
for ( UInt_t iEvent(0); iEvent < nEvents; ++iEvent ) {
weightsTuple->setIntegerBranchValue( "iEvtWithinExpt", iEvent );
const LauFitData& evtData = inputFitData->getData( iEvent );
Double_t m13Sq_MC = evtData.find("m13Sq_MC")->second;
Double_t m23Sq_MC = evtData.find("m23Sq_MC")->second;
Double_t dpModelWeight(0.0);
if ( kinematics_->withinDPLimits( m13Sq_MC, m23Sq_MC ) ) {
kinematics_->updateKinematics( m13Sq_MC, m23Sq_MC );
dpModelWeight = sigDPModel_->getEventWeight();
if ( kinematics_->squareDP() ) {
dpModelWeight *= kinematics_->calcSqDPJacobian();
}
if (LauAbsDPDynamics::GenOK != sigDPModel_->checkToyMC(kTRUE,kFALSE)) {
std::cerr << "WARNING in LauSimpleFitModel::weightEvents : Problem in calculating the weight, aborting." << std::endl;
delete weightsTuple;
return;
}
}
weightsTuple->setDoubleBranchValue( "dpModelWeight", dpModelWeight );
weightsTuple->fillBranches();
}
}
weightsTuple->buildIndex( "iExpt", "iEvtWithinExpt" );
weightsTuple->addFriendTree(dataFileName, dataTreeName);
weightsTuple->writeOutGenResults();
delete weightsTuple;
}
diff --git a/src/LauWeightedSumEffModel.cc b/src/LauWeightedSumEffModel.cc
new file mode 100644
index 0000000..30f651d
--- /dev/null
+++ b/src/LauWeightedSumEffModel.cc
@@ -0,0 +1,114 @@
+
+// Copyright University of Warwick 2004 - 2013.
+// 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 LauWeightedSumEffModel.cc
+ \brief File containing implementation of LauWeightedSumEffModel class.
+*/
+
+#include <cstdlib>
+#include <iostream>
+
+#include "TSystem.h"
+#include "Lau2DHistDP.hh"
+#include "Lau2DSplineDP.hh"
+#include "LauDaughters.hh"
+#include "LauWeightedSumEffModel.hh"
+#include "LauKinematics.hh"
+#include "LauVetoes.hh"
+
+ClassImp(LauWeightedSumEffModel)
+
+
+LauWeightedSumEffModel::LauWeightedSumEffModel(const LauDaughters* daughters) :
+ daughters_( daughters ),
+ effModel_( 0 ),
+ squareDP_( kFALSE ),
+ fluctuateEffHisto_( kFALSE ),
+ lowBinWarningIssued_( kFALSE ),
+ highBinWarningIssued_( kFALSE )
+{
+ if ( daughters_ == 0 ) {
+ std::cerr << "ERROR in LauWeightedSumEffModel Constructor : invalid pointer to daughters object supplied." << std::endl;
+ gSystem->Exit(EXIT_FAILURE);
+ }
+}
+
+void LauWeightedSumEffModel::addEffModel(const LauAbsEffModel* effModel, Double_t coeff)
+{
+ const LauDaughters* otherDaughters = effModel->getDaughters();
+ if( otherDaughters->getTypeDaug1()!=daughters_->getTypeDaug1() ||
+ otherDaughters->getTypeDaug2()!=daughters_->getTypeDaug2() ||
+ otherDaughters->getTypeDaug3()!=daughters_->getTypeDaug3() ||
+ otherDaughters->getTypeParent()!=daughters_->getTypeParent() ) {
+ std::cerr << "ERROR in LauWeightedSumEffModel::addEffModel : daughters of provided efficiency model do not match those expected." << std::endl;
+ gSystem->Exit(EXIT_FAILURE);
+ }
+
+ if( effModel_.empty() ) {
+ squareDP_=effModel->usingSquareDP();
+ } else if( effModel->usingSquareDP() != usingSquareDP() ) {
+ std::cerr << "ERROR in LauWeightedSumEffModel::addEffModel : either all efficiency models must use the normal DP or all efficiency models must use the square DP." << std::endl;
+ gSystem->Exit(EXIT_FAILURE);
+ }
+
+ effModel_.push_back(effModel);
+ coeff_.push_back(coeff);
+ if(effModel->fluctuateEffHisto()) fluctuateEffHisto_=kTRUE;
+}
+
+Double_t LauWeightedSumEffModel::calcEfficiency( const LauKinematics* kinematics ) const
+{
+ // Routine to calculate the efficiency for the given event/point in
+ // the Dalitz plot. This routine uses the models set by the
+ // addEffModel() function.
+ Double_t eff(0.0);
+
+ std::vector<const LauAbsEffModel*>::const_iterator it = effModel_.begin();
+ std::vector<const LauAbsEffModel*>::const_iterator end = effModel_.end();
+
+ std::vector<Double_t>::const_iterator coeffIt = coeff_.begin();
+
+ for( ; it!=end; ++it) {
+ eff += (*coeffIt)*(*it)->calcEfficiency( kinematics );
+ ++coeffIt;
+ }
+
+ // Check that the efficiency is in the allowed range (0-1)
+ // Out of range efficiencies could be caused by incorrect coefficients.
+ if ( eff < 0.0 ) {
+ if(!lowBinWarningIssued_) {
+ std::cerr << "WARNING in LauWeightedSumEffModel::calcEfficiency : Efficiency " << eff << " is less than 0 - setting to 0. You may want to check your coefficients!" << std::endl
+ << " : Further warnings will be suppressed." << std::endl;
+ lowBinWarningIssued_=kTRUE;
+ }
+ eff = 0.0;
+ } else if ( eff > 1.0 ) {
+ if(!highBinWarningIssued_) {
+ std::cerr << "WARNING in LauWeightedSumEffModel::calcEfficiency : Efficiency " << eff << " is greater than 1 - setting to 1. You may want to check your coefficients!" << std::endl
+ << " : Further warnings will be suppressed." << std::endl;
+ highBinWarningIssued_=kTRUE;
+ }
+ eff = 1.0;
+ }
+
+ return eff;
+}
+
+Bool_t LauWeightedSumEffModel::passVeto( const LauKinematics* kinematics ) const
+{
+ std::vector<const LauAbsEffModel*>::const_iterator it = effModel_.begin();
+ std::vector<const LauAbsEffModel*>::const_iterator end = effModel_.end();
+
+ for( ; it!=end; ++it) {
+ if(!(*it)->passVeto( kinematics )) return kFALSE;
+ }
+ return kTRUE;
+}
+

File Metadata

Mime Type
text/x-diff
Expires
Tue, Nov 19, 5:58 PM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3805471
Default Alt Text
(348 KB)

Event Timeline