diff --git a/inc/Lau1DCubicSpline.hh b/inc/Lau1DCubicSpline.hh index 6f73b51..6a0180b 100644 --- a/inc/Lau1DCubicSpline.hh +++ b/inc/Lau1DCubicSpline.hh @@ -1,313 +1,309 @@ /* Copyright 2015 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file Lau1DCubicSpline.hh \brief File containing declaration of Lau1DCubicSpline class. */ +#ifndef LAU_1DCUBICSPLINE +#define LAU_1DCUBICSPLINE + +#include "LauJsonTools.hh" +#include "LauPrint.hh" + +#include "Rtypes.h" +#include "TF1.h" +#include "TFitResultPtr.h" + +#include +#include +#include + +class TH1; +class LauAbsRValue; +class LauParameter; + /*! \class Lau1DCubicSpline \brief Class for defining a 1D cubic spline based on a set of knots. Class for defining a 1D cubic spline based on a set of knots. Interpolation between the knots is performed either by one of two types of cubic spline (standard or Akima) or by linear interpolation. The splines are defined by a piecewise cubic function which, between knots i and i+1, has the form f_i(x) = (1 - t)*y_i + t*y_i+1 + t*(1 - t)(a*(1 - t) + b*t) where t = (x - x_i)/(x_i+1 - x_i), a = k_i *(x_i+1 - x_i) - (y_i+1 - y_i), b = -k_i+1*(x_i+1 - x_i) + (y_i+1 - y_i) and k_i is (by construction) the first derivative at knot i. f(x) and f'(x) are continuous at the internal knots by construction. For the standard splines, f''(x) is required to be continuous at all internal knots placing n-2 constraints on the n parameters, k_i. The final two constraints are set by the boundary conditions. At each boundary, the function may be: (i) Clamped : f'(x) = C at the last knot (ii) Natural : f''(x) = 0 at the last knot (iii) Not a knot : f'''(x) continuous at the second last knot The algorithms used in these splines can be found on: http://en.wikipedia.org/wiki/Spline_interpolation#Algorithm_to_find_the_interpolating_cubic_spline http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm For the Akima splines, the values of k_i are determined from the slopes of the four nearest segments (a_i-1, a_i, a_i+1 and a_i+2) as k_i = ( | a_i+2 - a_i+1 | a_i + | a_i - a_i-1 | a_i+1 ) / ( | a_i+2 - a_i+1 | + | a_i - a_i-1 | ) and as k_i = ( a_i + a_i+1 ) / 2 in the special case a_i-1 == a_i != a_i+1 == a_i+2. Boundary conditions are specified by the relations a_2 - a_1 = a_1 - a_0 = a_0 - a_-1 and a_n-1 - a_n-2 = a_n - a_n-1 = a_n+1 - a_n The algorithms used in these splines can be found in: J.ACM vol. 17 no. 4 pp 589-602 */ -#ifndef LAU_1DCUBICSPLINE -#define LAU_1DCUBICSPLINE - -#include -#include -#include - -#include - -#include "Rtypes.h" -#include "TF1.h" -#include "TFitResultPtr.h" - -#include "LauPrint.hh" - -class TH1; -class LauAbsRValue; -class LauParameter; - class Lau1DCubicSpline final { public: //! Define the allowed interpolation types enum class SplineType { StandardSpline, /*!< standard cubic splines with f''(x) continuous at all internal knots */ AkimaSpline, /*!< Akima cubic splines with f'(x) at each knot defined locally by the positions of only five knots */ LinearInterpolation /*! Linear interpolation between each pair of knots */ }; //! Define the allowed boundary condition types /*! These are only supported by standard splines */ enum class BoundaryType { Clamped, /*!< clamped boundary - f'(x) = C */ Natural, /*!< natural boundary - f''(x) = 0 */ NotAKnot /*!< 'not a knot' boundary - f'''(x) continuous at second last knot */ }; //! Constructor /*! \param [in] xs the x-values of the knots \param [in] ys the y-values of the knots \param [in] type the type of spline (Standard, Akima, Linear) \param [in] leftBound the left-hand boundary condition \param [in] rightBound the right-hand boundary condition \param [in] dydx0 the gradient at the left-hand boundary of a clamped spline \param [in] dydxn the gradient at the right-hand boundary of a clamped spline */ Lau1DCubicSpline(const std::vector& xs, const std::vector& ys, const SplineType type = SplineType::StandardSpline, const BoundaryType leftBound = BoundaryType::NotAKnot, const BoundaryType rightBound = BoundaryType::NotAKnot, const Double_t dydx0 = 0.0, const Double_t dydxn = 0.0); //! Evaluate the function at given point /*! \param [in] x the x-coordinate \return the value of the spline at x */ Double_t evaluate(const Double_t x) const; //! Update the y-values of the knots /*! \param [in] ys the y-values of the knots */ void updateYValues(const std::vector& ys); //! Update the y-values of the knots /*! \param [in] ys the y-values of the knots */ void updateYValues(const std::vector& ys); //! Update the y-values of the knots /*! \param [in] ys the y-values of the knots */ void updateYValues(const std::vector& ys); //! Update the type of interpolation to perform /*! \param [in] type the type of interpolation */ void updateType(const SplineType type); //! Update the boundary conditions for the spline /*! \param [in] leftBound the left-hand boundary condition \param [in] rightBound the right-hand boundary condition \param [in] dydx0 the gradient at the left-hand boundary of a clamped spline \param [in] dydxn the gradient at the right-hand boundary of a clamped spline */ void updateBoundaryConditions(const BoundaryType leftBound, const BoundaryType rightBound, const Double_t dydx0 = 0.0, const Double_t dydxn = 0.0); //! Get the number of knots std::size_t getnKnots() const {return nKnots_;} //! Get y values const std::vector& getYValues() const {return y_;} //! Get x values const std::vector& getXValues() const {return x_;} //! Get the coefficients of a given spline segment in the form a + bx + cx^2 + dx^3 /*! \param [in] segIndex refers to the index of the knot at the left end of the segment (segIndex = 0 gets the coefficients of the the segment between x_0 and x_1) \param [in] normalise if true, the coefficients returned will be normalised by the integral of the complete spline (defaults to false) \return coefficients {a, b, c, d} */ std::array getCoefficients(const std::size_t segIndex, const bool normalise = false) const; //! Get the integral over all the spline segments Double_t integral() const; //! Make a TF1 showing the spline with its current knot values /*! \param [in] normalise whether or not you want the spline normalised \return 1D function object */ TF1* makeTF1(const bool normalise = false) const; //! Fit the the normalisation of the spline to a TH1 /*! \param [in] hist the histogram to be fitted \param [in] printLevel the level of printout desired from fit \return a TF1 fit to the histogram */ TF1* normaliseToTH1(TH1* hist, const LauOutputLevel printLevel = LauOutputLevel::Standard) const; //! Fit the spline to a TH1 /*! \param [in] hist the histogram to be fitted \param [in] printLevel the level of printout desired from fit \param [in] doWL If true do a weighted likelihood fit, else chi2 \param [in] fixedParams Provide a map of knots to be fixed and to what values \return a shared-ownership smart pointer to the fit results */ TFitResultPtr fitToTH1(TH1* hist, const LauOutputLevel printLevel = LauOutputLevel::Standard, const bool doWL = false, std::map fixedParams = {}); //! Write the spline to a json file /*! \param [in] fileName the name of the file to which the JSON should be written \param [in] splineName the (optional) name of the entry in the JSON to which the spline should be written \param [in] append if true, append the spline to the existing JSON within the file - if using this option it is then mandatory to provide splineName \param [in] indent the indentation level to use in the output in number of spaces (defaults to 4) */ void writeToJson(const TString& fileName, const TString& splineName = "", const bool append = false, const int indent = 4) const; //! Construct a new Lau1DCubicSpline object based on values read from a json file /*! \param [in] fileName the name of the file from which the JSON should be read \param [in] splineName the (optional) name of the entry in the JSON from which the spline should be read \return the newly constructed spline */ static std::unique_ptr readFromJson(const TString& fileName, const TString& splineName = ""); //! Find the maximum of the spline /*! \return the maximum of the spline */ Double_t findMaximum() const; private: //! Default constructor - only for use in readFromJson Lau1DCubicSpline() = default; //! Initialise the class void init(); //! Calculate the first derivative at each knot void calcDerivatives(); //! Calculate the first derivatives according to the standard method void calcDerivativesStandard(); //! Calculate the first derivatives according to the Akima method void calcDerivativesAkima(); //! The number of knots in the spline std::size_t nKnots_{0}; //! The x-value at each knot std::vector x_; //! The y-value at each knot std::vector y_; //! The first derivative at each knot std::vector dydx_; //! The 'a' coefficients used to determine the derivatives std::vector a_; //! The 'b' coefficients used to determine the derivatives std::vector b_; //! The 'c' coefficients used to determine the derivatives std::vector c_; //! The 'd' coefficients used to determine the derivatives std::vector d_; //! The type of interpolation to be performed SplineType type_{SplineType::StandardSpline}; //! The left-hand boundary condition on the spline BoundaryType leftBound_{BoundaryType::NotAKnot}; //! The right-hand boundary condition on the spline BoundaryType rightBound_{BoundaryType::NotAKnot}; //! The gradient at the left boundary for a clamped spline Double_t dydx0_{0.0}; //! The gradient at the right boundary for a clamped spline Double_t dydxn_{0.0}; // enable JSON serialisation of this class NLOHMANN_DEFINE_TYPE_INTRUSIVE(Lau1DCubicSpline, nKnots_, x_, y_, type_, leftBound_, rightBound_, dydx0_, dydxn_) ClassDef(Lau1DCubicSpline, 0) // Class for defining a 1D cubic spline }; //! \cond DOXYGEN_IGNORE // map Lau1DCubicSpline::SplineType values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( Lau1DCubicSpline::SplineType, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( Lau1DCubicSpline::SplineType, { {Lau1DCubicSpline::SplineType::StandardSpline, "StandardSpline"}, {Lau1DCubicSpline::SplineType::AkimaSpline, "AkimaSpline"}, {Lau1DCubicSpline::SplineType::LinearInterpolation, "LinearInterpolation"}, }) // map Lau1DCubicSpline::BoundaryType values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( Lau1DCubicSpline::BoundaryType, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( Lau1DCubicSpline::BoundaryType, { {Lau1DCubicSpline::BoundaryType::Clamped, "Clamped"}, {Lau1DCubicSpline::BoundaryType::Natural, "Natural"}, {Lau1DCubicSpline::BoundaryType::NotAKnot, "NotAKnot"}, }) - -std::ostream& operator<<(std::ostream& out, const Lau1DCubicSpline::SplineType type); -std::ostream& operator<<(std::ostream& out, const Lau1DCubicSpline::BoundaryType type); //! \endcond #endif diff --git a/inc/LauAbsCoeffSet.hh b/inc/LauAbsCoeffSet.hh index f68a109..306cde8 100644 --- a/inc/LauAbsCoeffSet.hh +++ b/inc/LauAbsCoeffSet.hh @@ -1,542 +1,539 @@ /* Copyright 2006 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauAbsCoeffSet.hh \brief File containing declaration of LauAbsCoeffSet class. */ #ifndef LAU_ABS_COEFF_SET #define LAU_ABS_COEFF_SET #include "LauJsonTools.hh" #include "TString.h" #include #include #include #include #include class TRandom; class LauComplex; class LauParameter; /*! \brief Types of coefficient sets The different forms that are implemented for the complex coefficients. Each form is represented by a class that inherits from LauAbsCoeffSet. The corresponding class is named in a simlar manner, replacing "Abs" with the enum label. */ enum class LauCoeffType { MagPhase, /*!< \see LauMagPhaseCoeffSet */ RealImag, /*!< \see LauRealImagCoeffSet */ BelleCP, /*!< \see LauBelleCPCoeffSet */ CartesianCP, /*!< \see LauCartesianCPCoeffSet */ CartesianGammaCP, /*!< \see LauCartesianGammaCPCoeffSet */ CleoCP, /*!< \see LauCleoCPCoeffSet */ MagPhaseCP, /*!< \see LauMagPhaseCPCoeffSet */ NSCCartesianCP, /*!< \see LauNSCCartesianCPCoeffSet */ PolarGammaCP, /*!< \see LauPolarGammaCPCoeffSet */ RealImagCP, /*!< \see LauRealImagCPCoeffSet */ RealImagGammaCP /*!< \see LauRealImagGammaCPCoeffSet */ }; -//! Output stream operator -std::ostream& operator<<( std::ostream& os, const LauCoeffType type ); - /*! \class LauAbsCoeffSet \brief Class for defining the abstract interface for complex coefficient classes. Class for defining the abstract interface for complex coefficient classes. Some common code is implemented but most methods are not. */ class LauAbsCoeffSet { public: //! Options for cloning operation enum class CloneOption { All, /*!< no special operation, all parameters cloned */ TiePhase, /*!< phase cloned, magnitude free to vary */ TieMagnitude, /*!< magnitude cloned, phase free to vary */ TieRealPart, /*!< real part cloned, imaginary part free to vary */ TieImagPart, /*!< imaginary part cloned, real part free to vary */ TieCPPars /*!< CP-violating parameters cloned, CP-conserving ones free to vary */ }; //! Construct a collection of coefficient objects based on values read from a JSON file /*! \param [in] fileName the name of the file from which the JSON should be read \param [in] elementName the optional name of the JSON element that contains the coefficient definitions (defaults to using the root record) \return the collection of newly constructed coefficients */ static std::vector> readFromJson( const TString& fileName, const TString& elementName = "" ); //! Write a collection of coefficient objects to a JSON file /*! \tparam Collection the type of the collection, which should contain either smart or raw pointers to LauAbsCoeffSet or derived types \param [in] coeffs the collection of coefficients to be written out \param [in] fileName the name of the file to which the JSON should be written \param [in] elementName the (optional) name of the JSON element to which the coefficients should be written \param [in] append if true, append the spline to the existing JSON within the file - if using this option it is then mandatory to provide elementName \param [in] indent the indentation level to use in the output in number of spaces (defaults to 4) */ template static void writeToJson( const Collection& coeffs, const TString& fileName, const TString& elementName = "", const bool append = false, const int indent = 4 ); //! Destructor virtual ~LauAbsCoeffSet() = default; //! Determine the type of the coefficient /*! \return the type of the coefficient */ virtual LauCoeffType type() const = 0; //! Retrieve the parameters of the coefficient so that they can be loaded into a fit /*! \return the parameters of the coefficient */ virtual std::vector getParameters() = 0; //! Retrieve the (const) parameters of the coefficient, e.g. so that they can be queried /*! \return the (const) parameters of the coefficient */ virtual std::vector getParameters() const = 0; //! Retrieve the names of the parameters of the coefficient (in the same order as the parameters in getParameters) /*! \return the parameter names */ virtual std::vector getParNames() const = 0; //! Print the current values of the parameters virtual void printParValues() const = 0; //! Print the column headings for a results table /*! \param [out] stream the stream to print to */ virtual void printTableHeading(std::ostream& stream) const = 0; //! Print the parameters of the complex coefficient as a row in the results table /*! \param [out] stream the stream to print to */ virtual void printTableRow(std::ostream& stream) const = 0; //! Randomise the starting values of the parameters for a fit virtual void randomiseInitValues() = 0; //! Make sure values are in "standard" ranges, e.g. phases should be between -pi and pi virtual void finaliseValues() = 0; //! Retrieve the complex coefficient for a particle /*! \return the complex coefficient for a particle */ virtual const LauComplex& particleCoeff() = 0; //! Retrieve the complex coefficient for an antiparticle /*! \return the complex coefficient for an antiparticle */ virtual const LauComplex& antiparticleCoeff() = 0; //! Set the parameters based on the complex coefficients for particles and antiparticles /*! \param [in] coeff the complex coefficient for a particle \param [in] coeffBar the complex coefficient for an antiparticle \param [in] init whether or not the initial and generated values should also be adjusted */ virtual void setCoeffValues( const LauComplex& coeff, const LauComplex& coeffBar, const Bool_t init ) = 0; //! Calculate the CP asymmetry /*! \return the CP asymmetry */ virtual LauParameter acp() = 0; //! Write state to a JSON record /*! \param [in,out] j the JSON record to write to */ virtual void serialiseToJson( nlohmann::json& j ) const; //! Apply the blinding information in the JSON record to all parameters /*! \param [in] j the JSON record to read from */ virtual void applyBlinding( const nlohmann::json& j ); //! Create a clone of the coefficient set /*! \param [in] newName the clone's name \param [in] cloneOption special option for the cloning operation \param [in] constFactor a constant factor by which to multiply the cloned parameters \param [in] coeffInfo an optional JSON entry that contains the values of any non-cloned parameters (depending on the CloneOption) \return a clone of the coefficient set */ std::unique_ptr createClone(const TString& newName, const CloneOption cloneOption = CloneOption::All, const Double_t constFactor = 1.0, const nlohmann::json& coeffInfo = {}) const { return std::unique_ptr{this->createClone_impl(newName,cloneOption,constFactor,coeffInfo)}; } //! Retrieve the name of the coefficient set /*! The name should correspond to the name of the resonance in the model. \return the name of the coefficient set */ TString name() const {return name_;} //! Set the name of the coefficient set /*! The name should correspond to the name of the resonance in the model. \param [in] theName the name to set */ void name(const TString& theName) {name_ = theName;} //! Retrieve the base name of the coefficient set /*! The base name is generally of the form "Ai", where i is an integer. This is used in the fit results ntuple. \return the base name of the coefficient set */ const TString& baseName() const {return basename_;} //! Set the base name of the coefficient set /*! The base name is generally of the form "Ai", where i is an integer. This is used in the fit results ntuple. \param [in] theBasename the base name to set */ void baseName(const TString& theBasename) {basename_ = theBasename;} //! Retrieve the index number of the coefficient set /*! \return the index number of the coefficient set */ UInt_t index() const {return index_;} //! Set the index number of the coefficient set /*! \param [in] newIndex the new index */ void index(const UInt_t newIndex); //! Is this coefficient set a clone of another? /*! \return whether this coefficient set is a clone */ Bool_t clone() const {return parent_ != nullptr;} //! From which coefficient set was this one cloned? /*! \return the parent of this coefficient set, or nullptr if this isn't a clone */ const LauAbsCoeffSet* parent() const {return parent_;} //! What clone option was this cloned with? /*! \return the clone option with which this was cloned */ CloneOption cloneOption() const {return cloneOption_;} //! What constant factor was this cloned with? /*! \return the constant factor with which this was cloned */ Double_t constFactor() const {return constFactor_;} //! Set the value of the named parameter /*! \param [in] parName the name of the parameter to adjust \param [in] value the new value for the parameter to take \param [in] init whether or not the initial and generated values should also be adjusted */ void setParameterValue(const TString& parName, const Double_t value, const Bool_t init); //! Set the error of the named parameter /*! This is particularly useful for tuning the step size used by MINUIT \param [in] parName the name of the parameter to adjust \param [in] error the new error value for the parameter to take */ void setParameterError(const TString& parName, const Double_t error); //! Set the named parameter to be fixed in the fit /*! \param [in] parName the name of the parameter to adjust */ void fixParameter(const TString& parName); //! Set the named parameter to float in the fit /*! \param [in] parName the name of the parameter to adjust */ void floatParameter(const TString& parName); //! Blind the named parameter /*! See LauBlind documentation for details of blinding procedure \param [in] parName the name of the parameter to adjust \param [in] blindingString the unique blinding string used to seed the random number generator \param [in] width the width of the Gaussian from which the offset should be sampled */ void blindParameter(const TString& parName, const TString& blindingString, const Double_t width); //! Add Gaussian constraint to the named parameter /*! \param [in] parName the name of the parameter to adjust \param [in] mean the mean of the Gaussian constraint \param [in] width the width of the Gaussian constraint */ void addGaussianConstraint(const TString& parName, const Double_t mean, const Double_t width); //! Add suffix to the name of the given parameter /*! \param [in] parName the name of the parameter to adjust \param [in] suffix the suffix to add to the parameter name */ void addSuffixToParameterName(const TString& parName, const TString& suffix); //! Set the allowed range for magnitude parameters /*! \param [in] minMag the lower edge of the range \param [in] maxMag the upper edge of the range */ static void setMagnitudeRange(const Double_t minMag, const Double_t maxMag) { minMagnitude_ = minMag; maxMagnitude_ = maxMag; } //! Set the allowed range for phase parameters /*! \param [in] minPhase the lower edge of the range \param [in] maxPhase the upper edge of the range */ static void setPhaseRange(const Double_t minPhase, const Double_t maxPhase) { minPhase_ = minPhase; maxPhase_ = maxPhase; } //! Set the allowed range for real/imaginary part parameters /*! \param [in] minPar the lower edge of the range \param [in] maxPar the upper edge of the range */ static void setRealImagRange(const Double_t minPar, const Double_t maxPar) { minRealImagPart_ = minPar; maxRealImagPart_ = maxPar; } //! Set the allowed range for CP-violating parameters /*! \param [in] minPar the lower edge of the range \param [in] maxPar the upper edge of the range */ static void setCPParRange(const Double_t minPar, const Double_t maxPar) { minDelta_ = minPar; maxDelta_ = maxPar; } //! Set the randomiser /*! Set the random number generator to use for randomising parameter starting values. Will default to LauRandom::zeroSeedRandom if not explicitly supplied via this function. \param [in] randomiser the random number generator to use for randomising parameter starting values */ static void setRandomiser(TRandom* randomiser) { randomiser_ = randomiser; } //! Access the randomiser /*! \return the random number generator to use for randomising parameter starting values */ static TRandom* getRandomiser(); protected: //! Constructor /*! \param [in] theName the name of the coefficient set \param [in] theBaseName the single character base for the parameter names \param [in] parent the coefficient set from which this one has been cloned (or nullptr if we are not a clone) \param [in] cloneOption the cloning option that was used (if applicable) \param [in] constFactor the constant factor that was used when cloning (if applicable) */ LauAbsCoeffSet(const TString& theName, const TString& theBaseName = "A", const LauAbsCoeffSet* parent = nullptr, const CloneOption cloneOption = CloneOption::All, const Double_t constFactor = 1.0); //! Copy constructor /*! \param [in] rhs the coefficient to clone */ LauAbsCoeffSet(const LauAbsCoeffSet& rhs) = default; //! Move constructor /*! \param [in] rhs the coefficient to clone */ LauAbsCoeffSet(LauAbsCoeffSet&& rhs) = default; //! Copy assignment operator /*! \param [in] rhs the coefficient to clone */ LauAbsCoeffSet& operator=(const LauAbsCoeffSet& rhs) = delete; //! Move assignment operator /*! \param [in] rhs the coefficient to clone */ LauAbsCoeffSet& operator=(LauAbsCoeffSet&& rhs) = delete; //! Find the parameter with the given name /*! \param [in] parName the name of the parameter to be found return the retrieved parameter */ LauParameter* findParameter(const TString& parName); //! Prepend the base name and index to the name of a parameter /*! \param [in,out] par the parameter to be renamed \param [in] oldBaseName the old base name, which might need to be removed before adding the new one */ virtual void adjustName(LauParameter& par, const TString& oldBaseName); //! Minimum allowed value of magnitude parameters static Double_t minMagnitude_; //! Maximum allowed value of magnitude parameters static Double_t maxMagnitude_; //! Minimum allowed value of phase parameters static Double_t minPhase_; //! Maximum allowed value of phase parameters static Double_t maxPhase_; //! Minimum allowed value of real/imaginary part parameters static Double_t minRealImagPart_; //! Maximum allowed value of real/imaginary part parameters static Double_t maxRealImagPart_; //! Minimum allowed value of CP-violating real/imaginary part parameters static Double_t minDelta_; //! Maximum allowed value of CP-violating real/imaginary part parameters static Double_t maxDelta_; private: //! Create a clone of the coefficient set /*! \param [in] newName the clone's name \param [in] cloneOption special option for the cloning operation \param [in] constFactor a constant factor by which to multiply the cloned parameters \param [in] coeffInfo an optional JSON entry that contains the values of any non-cloned parameters (depending on the CloneOption) \return a clone of the coefficient set */ virtual LauAbsCoeffSet* createClone_impl(const TString& newName, const CloneOption cloneOption, const Double_t constFactor, const nlohmann::json& coeffInfo) const = 0; //! Random number generator to use for randomising parameter starting values static TRandom* randomiser_; //! The name of the coefficient set TString name_; //! The base name of the coefficient set TString basename_; //! The index number of the coefficient set UInt_t index_{0}; //! The parent of this coefficient set, if this is a clone const LauAbsCoeffSet* const parent_{nullptr}; //! The clone option used, if applicable const CloneOption cloneOption_{CloneOption::All}; //! The constant factor used, if applicable const Double_t constFactor_{1.0}; ClassDef(LauAbsCoeffSet, 0) }; template void LauAbsCoeffSet::writeToJson( const Collection& coeffs, const TString& fileName, const TString& elementName, const bool append, const int indent ) { using nlohmann::json; json j; j["nCoeffs"] = coeffs.size(); j["coeffs"] = json::array(); for ( auto& coeffset : coeffs ) { j["coeffs"].push_back( *coeffset ); } const bool writeOK { LauJsonTools::writeJsonFile( j, fileName.Data(), elementName.Data(), append, indent ) }; if ( ! writeOK ) { std::cerr << "ERROR in LauAbsCoeffSet::writeToJson : could not successfully write to file \"" << fileName << std::endl; } } //! \cond DOXYGEN_IGNORE // map LauCoeffType values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauCoeffType, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauCoeffType, { {LauCoeffType::MagPhase, "MagPhase"}, {LauCoeffType::RealImag, "RealImag"}, {LauCoeffType::BelleCP, "BelleCP"}, {LauCoeffType::CartesianCP, "CartesianCP"}, {LauCoeffType::CartesianGammaCP, "CartesianGammaCP"}, {LauCoeffType::CleoCP, "CleoCP"}, {LauCoeffType::MagPhaseCP, "MagPhaseCP"}, {LauCoeffType::NSCCartesianCP, "NSCCartesianCP"}, {LauCoeffType::PolarGammaCP, "PolarGammaCP"}, {LauCoeffType::RealImagCP, "RealImagCP"}, {LauCoeffType::RealImagGammaCP, "RealImagGammaCP"}, }) // map Lau1DCubicSpline::BoundaryType values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauAbsCoeffSet::CloneOption, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauAbsCoeffSet::CloneOption, { {LauAbsCoeffSet::CloneOption::All, "All"}, {LauAbsCoeffSet::CloneOption::TiePhase, "TiePhase"}, {LauAbsCoeffSet::CloneOption::TieMagnitude, "TieMagnitude"}, {LauAbsCoeffSet::CloneOption::TieRealPart, "TieRealPart"}, {LauAbsCoeffSet::CloneOption::TieImagPart, "TieImagPart"}, {LauAbsCoeffSet::CloneOption::TieCPPars, "TieCPPars"}, }) // exceptions to be thrown in case of JSON type issues class LauWrongCoeffType : public std::runtime_error { public: LauWrongCoeffType(const std::string& what) : std::runtime_error(what) {} }; class LauClonedCoeff : public std::runtime_error { public: LauClonedCoeff(const std::string& what) : std::runtime_error(what) {} }; namespace nlohmann { template <> struct adl_serializer { static void to_json(json& j, const LauAbsCoeffSet& t) { t.serialiseToJson(j); } }; } //! \endcond #endif diff --git a/inc/LauAbsResonance.hh b/inc/LauAbsResonance.hh index f0931a9..a976b19 100644 --- a/inc/LauAbsResonance.hh +++ b/inc/LauAbsResonance.hh @@ -1,650 +1,651 @@ /* Copyright 2004 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauAbsResonance.hh \brief File containing declaration of LauAbsResonance class. */ /*! \class LauAbsResonance \brief Abstract class for defining type for resonance amplitude models (Breit-Wigner, Flatte etc.) Abstract Class for defining the type for all classes used to model resonances in the Dalitz plot, such as Breit-Wigner functions. In addition, some common functionality is implemented, including data such as the mass and width of the desired state. */ #ifndef LAU_ABS_RESONANCE #define LAU_ABS_RESONANCE #include "LauBlattWeisskopfFactor.hh" #include "LauComplex.hh" +#include "LauJsonTools.hh" #include "LauParameter.hh" #include "TString.h" #include class LauDaughters; class LauKinematics; class LauResonanceInfo; class LauAbsResonance { public: //! Define the allowed resonance types enum class ResonanceModel { BW, /*!< simple Breit-Wigner */ RelBW, /*!< relativistic Breit-Wigner */ GS, /*!< a modified Breit-Wigner from Gounaris-Sakurai */ Flatte, /*!< Flatte or coupled-channel Breit-Wigner */ Sigma, /*!< special shape for the sigma or f_0(600) */ Bugg, /*!< special shape for the sigma or f_0(600) */ Kappa, /*!< special shape for the kappa, a low-mass Kpi scalar */ Dabba, /*!< special shape for the dabba, a low-mass Dpi scalar */ LASS, /*!< the LASS amplitude to describe the Kpi S-wave */ LASS_BW, /*!< the resonant part of the LASS amplitude */ LASS_NR, /*!< the nonresonant part of the LASS amplitude */ EFKLLM, /*!< a form-factor-based description of the Kpi S-wave */ KMatrix_Pole, /*!< description using K-matrix and P-vector */ KMatrix_SVP, /*!< description using K-matrix and P-vector */ FlatNR, /*!< a uniform nonresonant amplitude */ NRModel, /*!< a theoretical model nonresonant amplitude */ BelleNR, /*!< an empirical exponential nonresonant amplitude */ PowerLawNR, /*!< an empirical power law nonresonant amplitude */ BelleSymNR, /*!< an empirical exponential nonresonant amplitude for symmetrised DPs */ BelleSymNRNoInter, /*!< an empirical exponential nonresonant amplitude for symmetrised DPs without interference */ LHCbNR, /*!< an empirical exponential nonresonant amplitude with phase */ TaylorNR, /*!< an empirical Taylor expansion nonresonant amplitude for symmetrised DPs */ PolNR, /*!< an empirical polynomial nonresonant amplitude */ Pole, /*!< scalar Pole lineshape */ PolarFFNR, /*!< Polar Form Factor nonresonant amplitude */ PolarFFSymNR, /*!< Polar Form Factor nonresonant amplitude for symmetrised DPs */ PolarFFSymNRNoInter, /*!< Polar Form Factor nonresonant amplitude for symmetrised DPs without interference */ Rescattering, /*!< KK-PiPi inelastic scattering amplitude */ Rescattering2, /*!< KK-PiPi inelastic scattering amplitude */ RescatteringNoInter, /*!< KK-PiPi inelastic scattering amplitude */ MIPW_MagPhase, /*!< a model independent partial wave - magnitude and phase representation */ MIPW_RealImag, /*!< a model independent partial wave - real and imaginary part representation */ GaussIncoh, /*!< an incoherent Gaussian shape */ RhoOmegaMix_GS, /*!< mass mixing model using GS for res 1 and RBW for res 2 */ RhoOmegaMix_RBW, /*!< mass mixing model using two RBWs */ RhoOmegaMix_GS_1, /*!< mass mixing model using GS for res 1 and RBW for res 2, with denominator factor = 1 */ RhoOmegaMix_RBW_1 /*!< mass mixing model using two RBWs, with denominator factor = 1 */ }; //! Define the allowed spin formalisms enum class SpinType { Zemach_P, /*!< Zemach tensor formalism, bachelor momentum in resonance rest frame */ Zemach_Pstar, /*!< Zemach tensor formalism, bachelor momentum in parent rest frame */ Covariant, /*!< Covariant tensor formalism, bachelor momentum in parent rest frame */ Covariant_P, /*!< Covariant tensor formalism, bachelor momentum in resonance rest frame */ Legendre /*!< Legendre polynomials only */ }; //! Is the resonance model incoherent? /*! \param [in] model the resonance model \return true if the model is incoherent */ static bool isIncoherentModel(ResonanceModel model); //! Constructor (for use by standard resonances) /*! \param [in] resInfo the object containing information on the resonance name, mass, width, spin, charge, etc. \param [in] resPairAmpInt the number of the daughter not produced by the resonance \param [in] daughters the daughter particles */ LauAbsResonance(LauResonanceInfo* resInfo, const Int_t resPairAmpInt, const LauDaughters* daughters); //! Constructor (for use by K-matrix components) /*! \param [in] resName the name of the component \param [in] resPairAmpInt the number of the daughter not produced by the resonance \param [in] daughters the daughter particles \param [in] resSpin the spin of the final channel into which the K-matrix scatters */ LauAbsResonance(const TString& resName, const Int_t resPairAmpInt, const LauDaughters* daughters, const Int_t resSpin); //! Destructor virtual ~LauAbsResonance(); //! Initialise the model virtual void initialise() = 0; //! Calculate the complex amplitude /*! \param [in] kinematics the kinematic variables of the current event \return the complex amplitude */ virtual LauComplex amplitude(const LauKinematics* kinematics); //! Get the resonance model type /*! \return the resonance model type */ virtual ResonanceModel getResonanceModel() const = 0; //! Get the spin type /*! \return the spin formalism */ SpinType getSpinType() const {return spinType_;} //! Get the name of the resonance /*! \return the resonance name */ const TString& getResonanceName() const {return resName_;} //! Get the name of the resonance /*! \return the resonance name */ const TString& getSanitisedName() const {return sanitisedName_;} //! Get the integer to identify which DP axis the resonance belongs to /*! \return the DP axis identification number, the ID of the bachelor */ Int_t getPairInt() const {return resPairAmpInt_;} //! Get the spin of the resonance /*! \return the resonance spin */ Int_t getSpin() const {return resSpin_;} //! Get the charge of the resonance /*! \return the resonance charge */ Int_t getCharge() const {return resCharge_;} //! Get the mass of the resonance /*! \return the resonance mass */ Double_t getMass() const {return (resMass_!=nullptr) ? resMass_->unblindValue() : -1.0;} //! Get the width of the resonance /*! \return the resonance width */ Double_t getWidth() const {return (resWidth_!=nullptr) ? resWidth_->unblindValue() : -1.0;} //! Get the mass parameter of the resonance /*! \return the resonance mass parameter */ LauParameter* getMassPar() {return resMass_;} //! Get the width parameter of the resonance /*! \return the resonance width parameter */ LauParameter* getWidthPar() {return resWidth_;} //! Retrieve the resonance parameters, e.g. so that they can be loaded into a fit /*! \return floating parameters of the resonance */ virtual const std::vector& getFloatingParameters() { return this->getParameters(); }; //! Is the amplitude pre-symmetrised? /*! The default value is kFALSE, so pre-symmetrised lineshapes should override this. \return whether the amplitude is already symmetrised */ virtual Bool_t preSymmetrised() const {return kFALSE;} //! Get the helicity flip flag /*! \return the flip helicity flag */ Bool_t flipHelicity() const {return flipHelicity_;} //! Set the helicity flip flag /*! \param [in] boolean the helicity flip status */ void flipHelicity(const Bool_t boolean) {flipHelicity_ = boolean;} //! Get the ignore momenta flag /*! Whether to ignore the momentum factors in both the spin factor and the mass-dependent width \return the ignore momenta flag */ Bool_t ignoreMomenta() const {return ignoreMomenta_;} //! Set the ignore momenta flag /*! Whether to ignore the momentum factors in both the spin factor and the mass-dependent width \param [in] boolean the ignore momenta status */ void ignoreMomenta(const Bool_t boolean) {ignoreMomenta_ = boolean;} //! Get the ignore spin flag /*! Whether to set the spinTerm to unity always \return the ignore spin flag */ Bool_t ignoreSpin() const {return ignoreSpin_;} //! Set the ignore spin flag /*! Whether to set the spinTerm to unity always \param [in] boolean the ignore spin status */ void ignoreSpin(const Bool_t boolean) {ignoreSpin_ = boolean;} //! Get the ignore barrier factor scaling flag /*! Whether to ignore barrier factor scaling in the amplitude numerator, they are still used for the mass-dependent width \return the ignore barrier amplitude scaling flag */ Bool_t ignoreBarrierScaling() const {return ignoreBarrierScaling_;} //! Set the ignore barrier factor scaling flag /*! Whether to ignore barrier factor scaling in the amplitude numerator, they are still used for the mass-dependent width \param [in] boolean the ignore barrier factor scaling status */ void ignoreBarrierScaling(const Bool_t boolean) {ignoreBarrierScaling_ = boolean;} //! Allow the mass, width and spin of the resonance to be changed /*! Negative values wil be ignored, so if, for example, you want to only change the spin you can provide negative values for the mass and width \param [in] newMass new value of the resonance mass \param [in] newWidth new value of the resonance width \param [in] newSpin new value of the resonance spin */ void changeResonance(const Double_t newMass, const Double_t newWidth, const Int_t newSpin); //! Allow the Blatt-Weisskopf radius for the resonance and parent factors to be changed /*! Negative values wil be ignored, so if, for example, you want to only change the parent radius you can provide a negative value for the resonance radius \param [in] resRadius new value of the resonance radius \param [in] parRadius new value of the parent radius */ void changeBWBarrierRadii(const Double_t resRadius, const Double_t parRadius); //! Set value of the various parameters /*! \param [in] name the name of the parameter to be changed \param [in] value the new parameter value */ virtual void setResonanceParameter(const TString& name, const Double_t value); //! Allow the various parameters to float in the fit /*! \param [in] name the name of the parameter to be floated */ virtual void floatResonanceParameter(const TString& name); //! Access the given resonance parameter /*! \param [in] name the name of the parameter \return the corresponding parameter */ virtual LauParameter* getResonanceParameter(const TString& name); //! Fix or release the resonance mass /*! \param [in] parFixed new status of mass */ void fixMass(const Bool_t parFixed) { if (resMass_!=nullptr) { resMass_->fixed(parFixed); } } //! Fix or release the resonance width /*! \param [in] parFixed new status of width */ void fixWidth(const Bool_t parFixed) { if (resWidth_!=nullptr) { resWidth_->fixed(parFixed); } } //! Get the status of resonance mass (fixed or released) /*! \return the status of resonance mass (fixed or released) */ Bool_t fixMass() const { return (resMass_!=nullptr) ? resMass_->fixed() : kTRUE; } //! Get the status of resonance width (fixed or released) /*! \return the status of resonance width (fixed or released) */ Bool_t fixWidth() const { return (resWidth_!=nullptr) ? resWidth_->fixed() : kTRUE; } //! Set the spin formalism to be used /*! \param [in] spinType the spin formalism */ void setSpinType(const SpinType spinType) {spinType_ = spinType;} //! Set the form factor model and parameters /*! \param [in] resFactor the barrier factor for the resonance decay \param [in] parFactor the barrier factor for the parent decay */ void setBarrierRadii(LauBlattWeisskopfFactor* resFactor, LauBlattWeisskopfFactor* parFactor) { resBWFactor_ = resFactor; parBWFactor_ = parFactor; } //! Fix or release the Blatt-Weisskopf barrier radii void fixBarrierRadii(const Bool_t fixResRadius, const Bool_t fixParRadius); //! Get the status of resonance barrier radius (fixed or released) Bool_t fixResRadius() const; //! Get the status of parent barrier radius (fixed or released) Bool_t fixParRadius() const; //! Get the radius of the resonance barrier factor Double_t getResRadius() const; //! Get the radius of the parent barrier factor Double_t getParRadius() const; //! Access the resonance info object const LauResonanceInfo* getResInfo() const {return resInfo_;} //! Get the centrifugal barrier for the parent decay const LauBlattWeisskopfFactor* getParBWFactor() const {return parBWFactor_;} //! Get the centrifugal barrier for the resonance decay const LauBlattWeisskopfFactor* getResBWFactor() const {return resBWFactor_;} //! Create a JSON object containing the current settings virtual nlohmann::json writeSettingsToJson() const; protected: //! Get the name of the parent particle TString getNameParent() const; //! Get the name of the first daughter of the resonance TString getNameDaug1() const; //! Get the name of the second daughter of the resonance TString getNameDaug2() const; //! Get the name of the daughter that does not originate form the resonance TString getNameBachelor() const; //! Get the parent particle mass Double_t getMassParent() const; //! Get the mass of daughter 1 Double_t getMassDaug1() const; //! Get the mass of daughter 2 Double_t getMassDaug2() const; //! Get the mass of the bachelor daughter Double_t getMassBachelor() const; //! Get the Charge of the parent particle Int_t getChargeParent() const; //! Get the charge of daughter 1 Int_t getChargeDaug1() const; //! Get the charge of daughter 2 Int_t getChargeDaug2() const; //! Get the charge of the bachelor daughter Int_t getChargeBachelor() const; //! Get the current value of the daughter momentum in the resonance rest frame Double_t getQ() const {return q_;} //! Get the current value of the bachelor momentum in the resonance rest frame Double_t getP() const {return p_;} //! Get the current value of the bachelor momentum in the parent rest frame Double_t getPstar() const {return pstar_;} //! Get the current value of the full spin-dependent covariant factor Double_t getCovFactor() const {return covFactor_;} //! Get the centrifugal barrier for the parent decay LauBlattWeisskopfFactor* getParBWFactor() {return parBWFactor_;} //! Get the centrifugal barrier for the resonance decay LauBlattWeisskopfFactor* getResBWFactor() {return resBWFactor_;} //! Access the resonance info object LauResonanceInfo* getResInfo() {return resInfo_;} //! Access the daughters object const LauDaughters* getDaughters() const {return daughters_;} //! Calculate the amplitude spin term using the Zemach tensor formalism /*! \param [in] pProd the momentum factor (either q * p or q * pstar) */ Double_t calcZemachSpinFactor( const Double_t pProd ) const; //! Calculate the amplitude spin term using the covariant tensor formalism /*! \param [in] pProd the momentum factor (q * pstar) */ Double_t calcCovSpinFactor( const Double_t pProd ); //! Calculate the spin-dependent covariant factor /*! \param [in] erm E_ij in the parent rest-frame divided by m_ij (equivalent to sqrt(1 + p^2/mParent^2)) */ void calcCovFactor( const Double_t erm ); //! Calculate the Legendre polynomial for the spin factor /*! Uses the current-event value of cosHel_ */ Double_t calcLegendrePoly() const; //! Calculate the Legendre polynomial for the spin factor (specifying the cosHel value) /*! \param [in] cosHel the cosine of the helicity angle */ Double_t calcLegendrePoly( const Double_t cosHel ); //! Complex resonant amplitude /*! \param [in] mass appropriate invariant mass for the resonance \param [in] spinTerm spin term */ virtual LauComplex resAmp(Double_t mass, Double_t spinTerm) = 0; //! Clear list of floating parameters void clearFloatingParameters() { resParameters_.clear(); } //! Add parameter to the list of floating parameters /*! \param [in] param the parameter to be added to the list */ void addFloatingParameter( LauParameter* param ); //! Access the list of floating parameters std::vector& getParameters() { return resParameters_; } //! Retrieve all resonance parameters (excluding mass and width), so that they can be saved to JSON virtual std::vector getResonanceParameters() const { return {}; } private: //! Copy constructor (not implemented) LauAbsResonance(const LauAbsResonance& rhs); //! Copy assignment operator (not implemented) LauAbsResonance& operator=(const LauAbsResonance& rhs); //! Information on the resonance LauResonanceInfo* resInfo_{nullptr}; //! Information on the particles const LauDaughters* daughters_; //! Parent name TString nameParent_{""}; //! Daughter 1 name TString nameDaug1_{""}; //! Daughter 2 name TString nameDaug2_{""}; //! Bachelor name TString nameBachelor_{""}; //! Parent charge Int_t chargeParent_{0}; //! Daughter 1 charge Int_t chargeDaug1_{0}; //! Daughter 2 charge Int_t chargeDaug2_{0}; //! Bachelor charge Int_t chargeBachelor_{0}; //! Parent mass Double_t massParent_{0.0}; //! Daughter 1 mass Double_t massDaug1_{0.0}; //! Daughter 2 mass Double_t massDaug2_{0.0}; //! Bachelor mass Double_t massBachelor_{0.0}; //! Resonance name TString resName_; //! Resonance name with illegal characters removed TString sanitisedName_; //! Resonance mass LauParameter* resMass_{nullptr}; //! Resonance width LauParameter* resWidth_{nullptr}; //! All parameters of the resonance std::vector resParameters_; //! Resonance spin Int_t resSpin_; //! Resonance charge Int_t resCharge_{0}; //! DP axis identifier Int_t resPairAmpInt_; //! Blatt Weisskopf barrier for parent decay LauBlattWeisskopfFactor* parBWFactor_{nullptr}; //! Blatt Weisskopf barrier for resonance decay LauBlattWeisskopfFactor* resBWFactor_{nullptr}; //! Spin formalism SpinType spinType_{SpinType::Zemach_P}; //! Boolean to flip helicity Bool_t flipHelicity_{kFALSE}; //! Boolean to ignore the momentum factors in both the spin factor and the mass-dependent width Bool_t ignoreMomenta_{kFALSE}; //! Boolean to set the spinTerm to unity always Bool_t ignoreSpin_{kFALSE}; //! Boolean to ignore barrier factor scaling in the amplitude numerator, they are still used for the mass-dependent width Bool_t ignoreBarrierScaling_{kFALSE}; // Event kinematics information //! Invariant mass Double_t mass_{0.0}; //! Helicity angle cosine Double_t cosHel_{0.0}; //! Daughter momentum in resonance rest frame Double_t q_{0.0}; //! Bachelor momentum in resonance rest frame Double_t p_{0.0}; //! Bachelor momentum in parent rest frame Double_t pstar_{0.0}; //! Covariant factor /*! sqrt(1 + z*z), where z = p / mParent Can also be expressed as E_ij in the parent rest-frame divided by m_ij - indeed this is how LauKinematics calculates it. \see LauKinematics::getcov12 \see LauKinematics::getcov13 \see LauKinematics::getcov23 */ Double_t erm_{1.0}; //! Covariant factor (full spin-dependent expression) Double_t covFactor_{1.0}; ClassDef(LauAbsResonance,0) // Abstract resonance class }; //! \cond DOXYGEN_IGNORE // map LauAbsResonance::ResonanceModel values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauAbsResonance::ResonanceModel, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauAbsResonance::ResonanceModel, { {LauAbsResonance::ResonanceModel::BW, "BW"}, {LauAbsResonance::ResonanceModel::RelBW, "RelBW"}, {LauAbsResonance::ResonanceModel::GS, "GS"}, {LauAbsResonance::ResonanceModel::Flatte, "Flatte"}, {LauAbsResonance::ResonanceModel::Sigma, "Sigma"}, {LauAbsResonance::ResonanceModel::Bugg, "Bugg"}, {LauAbsResonance::ResonanceModel::Kappa, "Kappa"}, {LauAbsResonance::ResonanceModel::Dabba, "Dabba"}, {LauAbsResonance::ResonanceModel::LASS, "LASS"}, {LauAbsResonance::ResonanceModel::LASS_BW, "LASS_BW"}, {LauAbsResonance::ResonanceModel::LASS_NR, "LASS_NR"}, {LauAbsResonance::ResonanceModel::EFKLLM, "EFKLLM"}, {LauAbsResonance::ResonanceModel::KMatrix_Pole, "KMatrix_Pole"}, {LauAbsResonance::ResonanceModel::KMatrix_SVP, "KMatrix_SVP"}, {LauAbsResonance::ResonanceModel::FlatNR, "FlatNR"}, {LauAbsResonance::ResonanceModel::NRModel, "NRModel"}, {LauAbsResonance::ResonanceModel::BelleNR, "BelleNR"}, {LauAbsResonance::ResonanceModel::PowerLawNR, "PowerLawNR"}, {LauAbsResonance::ResonanceModel::BelleSymNR, "BelleSymNR"}, {LauAbsResonance::ResonanceModel::BelleSymNRNoInter, "BelleSymNRNoInter"}, {LauAbsResonance::ResonanceModel::LHCbNR, "LHCbNR"}, {LauAbsResonance::ResonanceModel::TaylorNR, "TaylorNR"}, {LauAbsResonance::ResonanceModel::PolNR, "PolNR"}, {LauAbsResonance::ResonanceModel::Pole, "Pole"}, {LauAbsResonance::ResonanceModel::PolarFFNR, "PolarFFNR"}, {LauAbsResonance::ResonanceModel::PolarFFSymNR, "PolarFFSymNR"}, {LauAbsResonance::ResonanceModel::PolarFFSymNRNoInter, "PolarFFSymNRNoInter"}, {LauAbsResonance::ResonanceModel::Rescattering, "Rescattering"}, {LauAbsResonance::ResonanceModel::Rescattering2, "Rescattering2"}, {LauAbsResonance::ResonanceModel::RescatteringNoInter, "RescatteringNoInter"}, {LauAbsResonance::ResonanceModel::MIPW_MagPhase, "MIPW_MagPhase"}, {LauAbsResonance::ResonanceModel::MIPW_RealImag, "MIPW_RealImag"}, {LauAbsResonance::ResonanceModel::GaussIncoh, "GaussIncoh"}, {LauAbsResonance::ResonanceModel::RhoOmegaMix_GS, "RhoOmegaMix_GS"}, {LauAbsResonance::ResonanceModel::RhoOmegaMix_RBW, "RhoOmegaMix_RBW"}, {LauAbsResonance::ResonanceModel::RhoOmegaMix_GS_1, "RhoOmegaMix_GS_1"}, {LauAbsResonance::ResonanceModel::RhoOmegaMix_RBW_1, "RhoOmegaMix_RBW_1"}, }) // map LauAbsResonance::SpinType values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauAbsResonance::SpinType, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauAbsResonance::SpinType, { {LauAbsResonance::SpinType::Zemach_P, "Zemach_P"}, {LauAbsResonance::SpinType::Zemach_Pstar, "Zemach_Pstar"}, {LauAbsResonance::SpinType::Covariant, "Covariant"}, {LauAbsResonance::SpinType::Covariant_P, "Covariant_P"}, {LauAbsResonance::SpinType::Legendre, "Legendre"}, }) //! \endcond #endif diff --git a/inc/LauBlattWeisskopfFactor.hh b/inc/LauBlattWeisskopfFactor.hh index 4c516eb..7168386 100644 --- a/inc/LauBlattWeisskopfFactor.hh +++ b/inc/LauBlattWeisskopfFactor.hh @@ -1,236 +1,238 @@ /* Copyright 2014 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauBlattWeisskopfFactor.hh \brief File containing declaration of LauBlattWeisskopfFactor class. */ /*! \class LauBlattWeisskopfFactor \brief Class that implements the Blatt-Weisskopf barrier factor This factor is used in resonance models such as the Relativistic Breit-Wigner. */ #ifndef LAU_BLATTWEISSKOPFFACTOR #define LAU_BLATTWEISSKOPFFACTOR +#include "LauJsonTools.hh" + #include "Rtypes.h" #include "TString.h" #include #include #include class LauParameter; class LauResonanceInfo; class LauBlattWeisskopfFactor final { public: //! Define the allowed types of barrier factors enum class BarrierType { BWBarrier, /*!< Blatt-Weisskopf barrier factor (for use when momentum terms not used in angular term) */ BWPrimeBarrier, /*!< Blatt-Weisskopf barrier factor (for use when momentum terms are used in angular term) - the default */ ExpBarrier /*!< expoential barrier factor (mostly used for virtual contributions) */ }; //! Define the rest frame in which the momentum should be calculated (only relevant for bachelor) enum class RestFrame { Covariant, /*!< use expression from Covariant spin factor */ ParentFrame, /*!< momentum calculated in parent rest frame */ ResonanceFrame /*!< momentum calculated in resonance rest frame */ }; //! Define resonance categories that will share common barrier factor radii enum class Category { Default, //*!< indicates that LauResonanceMaker should use the appropriate category for the given resonance */ Parent, //*!< indicates that this is the factor for the decay of the parent particle */ Indep, //*!< indicates that this resonance should be independent of all others */ Light, //*!< default category for light unflavoured states, e.g. rho(77), f0(980), etc. */ Kstar, //*!< default category for K* states */ Charm, //*!< default category for D* states */ StrangeCharm, //*!< default category for Ds* states */ Charmonium, //*!< default category for ccbar states */ Beauty, //*!< default category for B* states */ StrangeBeauty, //*!< default category for Bs* states */ CharmBeauty, //*!< default category for Bc* states */ Custom1, //*!< user-defined category */ Custom2, //*!< user-defined category */ Custom3, //*!< user-defined category */ Custom4 //*!< user-defined category */ }; //! Constructor LauBlattWeisskopfFactor( const LauResonanceInfo& resInfo, const BarrierType barrierType, const RestFrame restFrame, const Category category ); //! Constructor LauBlattWeisskopfFactor( const LauResonanceInfo& resInfo, const Double_t resRadius, const BarrierType barrierType, const RestFrame restFrame, const Category category ); //! Constructor LauBlattWeisskopfFactor( const UInt_t spin, const Double_t resRadius, const BarrierType barrierType, const RestFrame restFrame, const Category category ); //! Copy constructor (deleted) LauBlattWeisskopfFactor( const LauBlattWeisskopfFactor& other ) = delete; //! Move constructor (deleted) LauBlattWeisskopfFactor( LauBlattWeisskopfFactor&& other ) = delete; //! Copy assignment operator (deleted) LauBlattWeisskopfFactor& operator=( const LauBlattWeisskopfFactor& other ) = delete; //! Move assignment operator (deleted) LauBlattWeisskopfFactor& operator=( LauBlattWeisskopfFactor&& other ) = delete; //! Destructor ~LauBlattWeisskopfFactor() noexcept; //! Method to create a new factor with cloned radius parameter /*! \param newSpin the value of the spin to use for the created instance \param newBarrierType the BarrierType to use for the created instance */ LauBlattWeisskopfFactor* createClone( const UInt_t newSpin , const BarrierType newBarrierType ); //! Check whether is a clone or not Bool_t clone() const { return parent_ != nullptr; } //! Get the parent factor const LauBlattWeisskopfFactor* getParent() const { return parent_; } //! Get the parent factor LauBlattWeisskopfFactor* getParent() { return parent_; } //! Retrieve the radius parameter const LauParameter* getRadiusParameter() const { return radius_.get(); } //! Retrieve the radius parameter LauParameter* getRadiusParameter() { return radius_.get(); } //! Retrieve the barrier type BarrierType getBarrierType() const { return barrierType_; } //! Retrieve the rest frame information RestFrame getRestFrame() const { return restFrame_; } //! Calculate form factor value /*! \param p the value of the momentum */ Double_t calcFormFactor( const Double_t p ) const; private: //! Copy constructor (with options) LauBlattWeisskopfFactor( LauBlattWeisskopfFactor& other, const UInt_t newSpin, const BarrierType newBarrierType ); //! Mark this as a clone of the given parent /*! \param theparent the parent parameter */ void setParent(LauBlattWeisskopfFactor* theparent) { parent_ = theparent; } //! Method to remove a clone from the list of clones /*! This is used in the destructor to allow a clone to inform its parent it is no longer around \param [in] clone the clone to be removed from the list */ void removeFromCloneList(LauBlattWeisskopfFactor* clone) { auto iter = clones_.find( clone ); if ( iter != clones_.end() ) { clones_.erase( iter ); } } //! Set the name of the radius parameter TString setRadiusName( const LauResonanceInfo& resInfo, const Category category ); //! Set the name of the radius parameter TString setRadiusName( const Category category ); //! Set the name of the radius parameter TString setRadiusName( const TString& categoryName ); //! The parent factor (nullptr if this is not a clone) LauBlattWeisskopfFactor* parent_{nullptr}; //! The clones of this factor std::set clones_; //! Resonance spin const UInt_t spin_; //! Radius parameter std::unique_ptr radius_; //! Barrier type const BarrierType barrierType_; //! Rest frame const RestFrame restFrame_; ClassDef(LauBlattWeisskopfFactor, 0) }; //! \cond DOXYGEN_IGNORE // map LauBlattWeisskopfFactor::BarrierType values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauBlattWeisskopfFactor::BarrierType, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauBlattWeisskopfFactor::BarrierType, { {LauBlattWeisskopfFactor::BarrierType::BWPrimeBarrier, "BWPrimeBarrier"}, {LauBlattWeisskopfFactor::BarrierType::BWBarrier, "BWBarrier"}, {LauBlattWeisskopfFactor::BarrierType::ExpBarrier, "ExpBarrier"}, }) // map LauBlattWeisskopfFactor::RestFrame values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauBlattWeisskopfFactor::RestFrame, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauBlattWeisskopfFactor::RestFrame, { {LauBlattWeisskopfFactor::RestFrame::ResonanceFrame, "ResonanceFrame"}, {LauBlattWeisskopfFactor::RestFrame::Covariant, "Covariant"}, {LauBlattWeisskopfFactor::RestFrame::ParentFrame, "ParentFrame"}, }) // map LauBlattWeisskopfFactor::Category values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauBlattWeisskopfFactor::Category, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauBlattWeisskopfFactor::Category, { {LauBlattWeisskopfFactor::Category::Default, "Default"}, {LauBlattWeisskopfFactor::Category::Parent, "Parent"}, {LauBlattWeisskopfFactor::Category::Indep, "Indep"}, {LauBlattWeisskopfFactor::Category::Light, "Light"}, {LauBlattWeisskopfFactor::Category::Kstar, "Kstar"}, {LauBlattWeisskopfFactor::Category::Charm, "Charm"}, {LauBlattWeisskopfFactor::Category::StrangeCharm, "StrangeCharm"}, {LauBlattWeisskopfFactor::Category::Charmonium, "Charmonium"}, {LauBlattWeisskopfFactor::Category::Beauty, "Beauty"}, {LauBlattWeisskopfFactor::Category::StrangeBeauty, "StrangeBeauty"}, {LauBlattWeisskopfFactor::Category::CharmBeauty, "CharmBeauty"}, {LauBlattWeisskopfFactor::Category::Custom1, "Custom1"}, {LauBlattWeisskopfFactor::Category::Custom2, "Custom2"}, {LauBlattWeisskopfFactor::Category::Custom3, "Custom3"}, {LauBlattWeisskopfFactor::Category::Custom4, "Custom4"}, }) //! \endcond #endif diff --git a/inc/LauDecayTime.hh b/inc/LauDecayTime.hh index e789397..e640e53 100644 --- a/inc/LauDecayTime.hh +++ b/inc/LauDecayTime.hh @@ -1,88 +1,88 @@ /* Copyright 2021 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauDecayTime.hh \brief File containing declaration of utilities for decay time modelling */ #ifndef LAU_DECAYTIME_UTILS #define LAU_DECAYTIME_UTILS -#include +#include "LauJsonTools.hh" /*! \namespace LauDecayTime \brief Namespace to contain various definitions that are common to the description of the decay time dependence of the amplitudes */ namespace LauDecayTime { // TODO - can we think of better names? //! The functional form of the decay time PDF enum class FuncType { Hist, //< Hist PDF for fixed background Delta, //< Delta function - for prompt background Exp, //< Exponential function - for non-prompt background or charged B's DeltaExp, //< Delta + Exponential function - for background with prompt and non-prompt parts ExpTrig, //< Exponential function with Delta m driven mixing - for neutral B_d's ExpHypTrig //< Exponential function with both Delta m and Delta Gamma driven mixing - for neutral B_s's }; //! How is the decay time measured - absolute or difference? enum class TimeMeasurementMethod { DecayTime, //< Absolute measurement of decay time, e.g. LHCb scenario DecayTimeDiff //< Measurement of the difference of two decay times, e.g. BaBar/Belle(II) scenario }; //! How is the TD efficiency information going to be given? enum class EfficiencyMethod { Uniform, //< As a uniform distribution (constant) Binned, //< As a histogram (TH1D/TH1F) Spline //< As a cubic spline (or products thereof) }; //! \cond DOXYGEN_IGNORE // map FuncType values to JSON as strings - NLOHMANN_JSON_SERIALIZE_ENUM( FuncType, { + LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( FuncType, { {FuncType::Hist, "Hist"}, {FuncType::Delta, "Delta"}, {FuncType::Exp, "Exp"}, {FuncType::DeltaExp, "DeltaExp"}, {FuncType::ExpTrig, "ExpTrig"}, {FuncType::ExpHypTrig, "ExpHypTrig"}, }) // map TimeMeasurementMethod values to JSON as strings - NLOHMANN_JSON_SERIALIZE_ENUM( TimeMeasurementMethod, { + LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( TimeMeasurementMethod, { {TimeMeasurementMethod::DecayTime, "DecayTime"}, {TimeMeasurementMethod::DecayTimeDiff, "DecayTimeDiff"}, }) // map EfficiencyMethod values to JSON as strings - NLOHMANN_JSON_SERIALIZE_ENUM( EfficiencyMethod, { + LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( EfficiencyMethod, { {EfficiencyMethod::Uniform, "Uniform"}, {EfficiencyMethod::Binned, "Binned"}, {EfficiencyMethod::Spline, "Spline"}, }) //! \endcond } #endif diff --git a/inc/LauDecayTimeResolution.hh b/inc/LauDecayTimeResolution.hh index d102e53..d5a4b2e 100644 --- a/inc/LauDecayTimeResolution.hh +++ b/inc/LauDecayTimeResolution.hh @@ -1,327 +1,327 @@ /* Copyright 2021 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauDecayTimeResolution.hh \brief File containing declaration of LauDecayTimeResolution class. */ #ifndef LAU_DECAYTIME_RESOLUTION #define LAU_DECAYTIME_RESOLUTION #include "LauAbsRValue.hh" #include "LauJsonTools.hh" #include "Rtypes.h" #include "TString.h" #include #include #include #include #include /*! \class LauDecayTimeResolution \brief Class for defining the model for decay time resolution */ class LauDecayTimeResolution final { public: /*! \enum ScalingType \brief Define the types of per-event error scaling that can be performed */ enum class ScalingType { None, //!< No scaling is performed Global, //!< All means and widths are scaled PerGaussian, //!< Scaling is enabled/disabled for each Gaussian PerParameter //!< Scaling is enabled/disabled for individual parameters }; //! Constructor /*! \param nGauss the number of Gaussians in the resolution model \param resolutionParams the parameters of the resolution model \param scale if true all means and widths are scaled by per-event decay time error, if false none are scaled */ LauDecayTimeResolution( const std::size_t nGauss, std::vector> resolutionParams, const bool scale = false ); //! Constructor /*! \param nGauss the number of Gaussians in the resolution model \param resolutionParams the parameters of the resolution model \param scale for each Gaussian, if true its mean and width are both scaled by per-event decay time error, if false neither are scaled */ LauDecayTimeResolution( const std::size_t nGauss, std::vector> resolutionParams, const std::vector& scale ); //! Constructor /*! \param nGauss the number of Gaussians in the resolution model \param resolutionParams the parameters of the resolution model \param scaleMeans for each Gaussian, if true its mean is scaled by per-event decay time error, if false its mean is not scaled \param scaleWidths for each Gaussian, if true its width is scaled by per-event decay time error, if false its width is not scaled */ LauDecayTimeResolution( const std::size_t nGauss, std::vector> resolutionParams, const std::vector& scaleMeans, const std::vector& scaleWidths ); //! Retrieve the parameters of the resolution model so that they can be loaded into a fit /*! \return the parameters of the resolution model */ std::vector getParameters() { return params_; } //! Retrieve the number of Gaussians in the model /*! \return the number of Gaussians */ const std::size_t& nGauss() const { return nGauss_; } //! Retrieve the scaling type /*! \return the scaling type */ ScalingType getScalingType() const { return scalingType_; } //! Retrieve whether any of the parameters of the resolution function scaled by the per-event error /*! \return whether scaling or not */ bool scaleWithPerEventError() const { return scaleWithPerEventError_; } //! Retrieve whether the mean of each Gaussian is scaled by the per-event decay time error /*! \return the mean scaling flags */ const std::vector& scaleMeans() const { return scaleMeans_; } //! Retrieve whether the width of each Gaussian is scaled by the per-event decay time error /*! \return the width scaling flags */ const std::vector& scaleWidths() const { return scaleWidths_; } //! Retrieve the up-to-date values of the means /*! \return the mean values */ const std::vector& getMeanValues() const { return meanVals_; } //! Retrieve the up-to-date values of the widths /*! \return the width values */ const std::vector& getWidthValues() const { return widthVals_; } //! Retrieve the up-to-date values of the fractions /*! \return the fraction values */ const std::vector& getFractionValues() const { return fractionVals_; } //! Retrieve whether any of the parameter values have changed in the last fit iteration /*! \return the any param changed flag */ const bool& anythingChanged() const { return anythingChanged_; } //! Initialise the parameter cache /*! Must be called prior to starting fitting or generation */ void initialise(); //! Propagate any updates to parameters and recalculate information as neeeded /*! Should be called at each fit iteration */ void propagateParUpdates(); //! Construct a collection of resolution model objects based on values read from a JSON value /*! The JSON value should be an Object, which must contain the following elements: - "parameters", an Array, which contains an Object for each parameter of the models to be constructed - "signalModel", an Object, which contains: + "nGauss", a Number_Unsigned to specify the number of Gaussian functions in the model + "scalingType", a String to specify the scaling type (must match a state of ScalingType) + "parameters", an Array of Strings that specifies the parameters from the top-level "parameters" Array to be used to build the signal model - "backgroundModels", an Array, which contains Objects for each background component, each of which contain: + "name", a String specifying the background component name + "model", an Object to define the model (definition as per the "signalModel" entry above) \param [in] j the JSON value to deserialise \return the collection of newly constructed models */ static std::map> readFromJson( const nlohmann::json& j ); //! Construct a collection of resolution model objects based on values read from a JSON file /*! The JSON value structure is as defined in readFromJson(nlohmann::json) \param [in] fileName the name of the file from which the JSON should be read \param [in] elementName the optional name of the JSON element that contains the definitions (defaults to using the root record) \return the collection of newly constructed models */ static std::map> readFromJson( const TString& fileName, const TString& elementName = "" ); //! Write a collection of physics model objects to a JSON file /*! \tparam ResModelPtr a pointer-like type that points to LauDecayTimeResolution objects \param [in] models the collection of models to be written out \param [in] fileName the name of the file to which the JSON should be written \param [in] elementName the (optional) name of the JSON element to which the coefficients should be written \param [in] append if true, append the spline to the existing JSON within the file - if using this option it is then mandatory to provide elementName \param [in] indent the indentation level to use in the output in number of spaces (defaults to 4) */ template static void writeToJson( const std::map& models, const TString& fileName, const TString& elementName = "", const bool append = false, const int indent = 4 ); //! Retrieve the specified parameter /*! \param [in] parName the parameter to retrieve */ const LauAbsRValue* findParameter(const TString& parName) const; //! Retrieve the specified parameter /*! \param [in] parName the parameter to retrieve */ LauAbsRValue* findParameter(const TString& parName); private: //! Resize the internal vectors to match nGauss_ void resizeVectors(); //! Do an initial sanity check of our setup void checkSetup(); //! Update the cached parameter values void updateParameterCache(); //! Read the resolution model part of the JSON serialisation /*! \param [in] j the JSON value from which to read the model \param [in] parameters the collection of parameters, some of which should be used to construct the model \return the newly constructed signal model */ static std::unique_ptr readResolutionModelFromJson( const nlohmann::json& j, std::vector>& parameters ); //! Read the background models part of the JSON serialisation /*! \param [in] j the JSON value from which to read the model \param [in] parameters the collection of parameters, which should be used to construct the models \return the newly constructed background models */ static std::map> readBackgroundModelsFromJson( const nlohmann::json& j, std::vector>& parameters ); //! Write this model to JSON objects /*! \param [in,out] model the JSON record to which to write this model \param [in,out] parameters the JSON record to which to write the parameters */ void serialiseToJson( nlohmann::json& model, nlohmann::json& parameters ) const; //! The number of Gaussians in the resolution function const std::size_t nGauss_; //! Are any of the parameters of the resolution function scaled by the per-event error? const bool scaleWithPerEventError_{false}; //! Scale the mean of each Gaussian by the per-event decay time error? const std::vector scaleMeans_; //! Scale the width of each Gaussian by the per-event decay time error? const std::vector scaleWidths_; //! Scaling type const ScalingType scalingType_{ScalingType::None}; //! Store of all parameters of the resolution function std::vector> paramsOwned_; //! Store of all parameters of the resolution function std::vector params_; //! Fraction parameter for each Gaussian in the resolution function std::vector fractions_; //! Mean parameter for each Gaussian in the resolution function std::vector means_; //! Width parameter for each Gaussian in the resolution function std::vector widths_; //! Fraction of each Gaussian in the resolution function std::vector fractionVals_; //! Mean of each Gaussian in the resolution function std::vector meanVals_; //! Width of each Gaussian in the resolution function std::vector widthVals_; //! Is any parameter floating in the fit? bool anythingFloating_{false}; //! Has any floating parameter changed in the last fit iteration? bool anythingChanged_{false}; ClassDef(LauDecayTimeResolution, 0) }; //! \cond DOXYGEN_IGNORE // map LauDecayTimeResolution::ScalingType values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauDecayTimeResolution::ScalingType, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauDecayTimeResolution::ScalingType, { {LauDecayTimeResolution::ScalingType::None, "None"}, {LauDecayTimeResolution::ScalingType::Global, "Global"}, {LauDecayTimeResolution::ScalingType::PerGaussian, "PerGaussian"}, {LauDecayTimeResolution::ScalingType::PerParameter, "PerParameter"}, }) //! \endcond template void LauDecayTimeResolution::writeToJson( const std::map& models, const TString& fileName, const TString& elementName, const bool append, const int indent ) { using nlohmann::json; // Check for a signal model auto iter { models.find("signal") }; if ( iter == models.end() ) { std::cerr << "ERROR in LauDecayTimeResolution::writeToJson : cannot locate the signal model in the collection, aborting" << std::endl; return; } json j; json& parameters = j["parameters"] = json::array(); json& signalModel = j["signalModel"] = json::object(); json& backgroundModels = j["backgroundModels"] = json::array(); for ( const auto& [ name, model ] : models ) { if ( name == "signal" ) { model->serialiseToJson( signalModel, parameters ); } else { json modelDef = json::object(); modelDef["name"] = name; json& bkgndModel = modelDef["model"] = json::object(); model->serialiseToJson( bkgndModel, parameters ); backgroundModels.push_back( modelDef ); } } const bool writeOK { LauJsonTools::writeJsonFile( j, fileName.Data(), elementName.Data(), append, indent ) }; if ( ! writeOK ) { std::cerr << "ERROR in LauDecayTimePhysicsModel::writeToJson : could not successfully write to file \"" << fileName << std::endl; } } #endif diff --git a/inc/LauFlavTag.hh b/inc/LauFlavTag.hh index 96664a0..4b343a2 100644 --- a/inc/LauFlavTag.hh +++ b/inc/LauFlavTag.hh @@ -1,540 +1,542 @@ /* Copyright 2017 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauFlavTag.hh \brief File containing declaration of LauFlavTag class. */ /*! \class LauFlavTag \brief Class for defining the flavour tagging approach. Define the flavour tagging categories and all associated parameters to be passed to the relevant fit models. */ #ifndef LAU_FLAVTAG #define LAU_FLAVTAG #include #include #include "TString.h" #include "LauParameter.hh" class LauAbsPdf; class LauFitDataTree; class LauFlavTag final { public: //! Define sign convention for B and Bbar flavours enum Flavour { Bbar = -1, //< Bbar flavour Unknown = 0, //< Unknown flavour B = +1 //< B flavour }; //! Define different types of background to control the behaviour for each source // TODO Might want to move this somewhere more general later enum class BkgndType { Combinatorial, //< combinatorial background FlavourSpecific, //< flavour-specific decay (i.e. the flavour of the parent can be determined from the decay products), e.g. B0 -> K+ pi- pi0 SelfConjugate, //< decays where both B and Bbar can decay to a single self-conjugate final state, e.g. B0 -> pi+ pi- K_S0 NonSelfConjugate //< decays where both B and Bbar can decay to either of two final states that are conjugates of each other, e.g. B0 -> K+ pi- K_S0 and B0 -> K- pi+ K_S0 }; //! Constructor /*! \param [in] useAveDelta use average and delta variables for tagging calibration and efficiency \param [in] useEtaPrime use eta prime rather the eta as the mistag throughout \param [in] bkgndInfo map containing names and types of the background sources (if applicable) */ LauFlavTag(const Bool_t useAveDelta = kFALSE, const Bool_t useEtaPrime = kFALSE, const std::map bkgndInfo={}); //! Initialise // TODO is this needed? Commented for the moment (here and where called in LauTimeDepFitModel) //void initialise(); // TODO - need to decide which functions need to be public (interface) and which should be private (implementation details) // - improve/extend Doxygen comments //! Change the dilutions, delta dilutions and tagCatFrac for signal if needed /*! \param [in] name the name of the tagger \param [in] tagVarName the tagging variable name of the tagger in the ntuple \param [in] mistagVarName the associated mistag variable name of the same tagger in the ntuple \param [in] etapdf the mistag distribution for the tagger \param [in] tagEff tagging efficiency - (particle, antiparticle) or (average, delta) depending on useAveDelta_ flag \param [in] calib_p0 calibration parameter p0 - (particle, antiparticle) or (average, delta) depending on useAveDelta_ flag \param [in] calib_p1 calibration parameter p1 - (particle, antiparticle) or (average, delta) depending on useAveDelta_ flag */ void addTagger(const TString& name, const TString& tagVarName, const TString& mistagVarName, LauAbsPdf* etapdf, const std::pair tagEff, const std::pair calib_p0, const std::pair calib_p1); //! Change the dilutions, delta dilutions and tagCatFrac for signal if needed /*! \param [in] name the name of the tagger \param [in] tagVarName the tagging variable name of the tagger in the ntuple \param [in] mistagVarName the associated mistag variable name of the same tagger in the ntuple \param [in] etapdf the mistag distribution for the tagger \param [in] tagEff tagging efficiency histograms - (particle, antiparticle) or (average, delta) depending on useAveDelta_ flag \param [in] calib_p0 calibration parameter p0 - (particle, antiparticle) or (average, delta) depending on useAveDelta_ flag \param [in] calib_p1 calibration parameter p1 - (particle, antiparticle) or (average, delta) depending on useAveDelta_ flag */ void addTagger(const TString& name, const TString& tagVarName, const TString& mistagVarName, LauAbsPdf* etapdf, const std::pair tagEff, const std::pair calib_p0, const std::pair calib_p1); //! Read in the input fit data variables /*! \param [in] inputFitData the data source \param [in] decayTimeVarName the name of the decay time variable within the input data (used if the tagging efficiencies depend on decay time) */ void cacheInputFitVars(LauFitDataTree* inputFitData, const TString& decayTimeVarName=""); //! Generate values for the signal tag decisions and mis-tag probabilities /*! \param [in] trueTagFlv the true tag flavour \param [in] curEvtDecayTime the generated decay time value (used if the tagging efficiencies depend on decay time) */ void generateEventInfo(const Flavour trueTagFlv, const Double_t curEvtDecayTime); //! Generate values for the background tag decisions and mis-tag probabilities /*! \param [in] bkgndID the background category ID for which to generate \param [in] trueTagFlv the true tag flavour \param [in] trueDecayFlv the true decay flavour (if known) \param [in] curEvtDecayTime the generated decay time value (used if the tagging efficiencies depend on decay time) */ void generateBkgndEventInfo(const std::size_t bkgndID, const Flavour trueTagFlv, const Flavour trueDecayFlv, const Double_t curEvtDecayTime); //! Retrieve the cached info for a given event /*! \param [in] iEvt the event to retrieve */ void updateEventInfo(const std::size_t iEvt); //! Retrieve the name of the true tag variable const TString& getTrueTagVarName() const {return trueTagVarName_;}; //! Retrieve the name of the decay flavour variable const TString& getDecayFlvVarName() const {return decayFlvVarName_;}; //! Retrieve the names of the tag decision variables for each tagger const std::vector& getTagVarNames() const {return tagVarNames_;}; //! Retrieve the names of the mis-tag probability variables for each tagger const std::vector& getMistagVarNames() const {return mistagVarNames_;}; //! Retrieve the current value of the true tag variable Flavour getCurEvtTrueTagFlv() const {return curEvtTrueTagFlv_;}; //! Retrieve the current value of the decay flavour variable Flavour getCurEvtDecayFlv() const {return curEvtDecayFlv_;}; //! Retrieve the current values of the tag decision variables for each tagger const std::vector& getCurEvtTagFlv() const {return curEvtTagFlv_;}; //! Retrieve the current values of the mis-tag probability variables for each tagger const std::vector& getCurEvtMistag() const {return curEvtMistag_;}; //! Retrieve the number of taggers std::size_t getNTaggers() const {return tagVarNames_.size();} //! Get vector of calibration p0 for B0 parameters for each tagger std::vector getCalibP0B0(){return calib_p0_B0_;}; //! Get vector of calibration p0 for B0bar parameters for each tagger std::vector getCalibP0B0bar(){return calib_p0_B0bar_;}; //! Get vector of calibration p1 for B0 parameters for each tagger std::vector getCalibP1B0(){return calib_p1_B0_;}; //! Get vector of calibration p1 for B0bar parameters for each tagger std::vector getCalibP1B0bar(){return calib_p1_B0bar_;}; //! Get vector of calibration p0 average parameters for each tagging category std::vector getCalibP0Ave(){return calib_p0_ave_;}; //! Get vector of calibration p0 difference parameters for each tagging category std::vector getCalibP0Delta(){return calib_p0_delta_;}; //! Get vector of calibration p1 average parameters for each tagging category std::vector getCalibP1Ave(){return calib_p1_ave_;}; //! Get vector of calibration p1 difference parameters for each tagging category std::vector getCalibP1Delta(){return calib_p1_delta_;}; //! Get vector of tagging efficiency for B0 parameters for each tagging category std::vector getTagEffB0(){return tagEff_B0_;}; //! Get vector of tagging efficiency for B0bar parameters for each tagging category std::vector getTagEffB0bar(){return tagEff_B0bar_;}; //! Get vector of tagging efficiency average parameters for each tagging category std::vector getTagEffAve(){return tagEff_ave_;}; //! Get vector of tagging efficiency difference parameters for each tagging category std::vector getTagEffDelta(){return tagEff_delta_;}; //! Get 2D vector of background tagging efficiency for B0 parameters for each tagger (inner vec) and background source (outer vec) auto getTagEffBkgndB0(){return tagEffBkgnd_B0_;}; //! Get 2D vector of background tagging efficiency for B0bar parameters for each tagger (inner vec) and background source (outer vec) auto getTagEffBkgndB0bar(){return tagEffBkgnd_B0bar_;}; //! Get 2D vector of background tagging efficiency average parameters for each tagger (inner vec) and background source (outer vec) auto getTagEffBkgndAve(){return tagEffBkgnd_ave_;}; //! Get 2D vector of background tagging efficiency difference parameters for each tagger (inner vec) and background source (outer vec) auto getTagEffBkgndDelta(){return tagEffBkgnd_delta_;}; //! Set background parameters for a given background and given tagger /*! Set the eta (mis-tag probability) distribution and tagging efficiency constants for B and Bbar \param [in] bkgndName background category name \param [in] taggerName name of the tagger \param [in] etaPdf the eta PDF itself \param [in] tagEff the tagging efficiency parameters */ void setBkgndParams(const TString& bkgndName, const TString& taggerName, LauAbsPdf* etaPdf, std::pair tagEff); //! Set background parameters for a given background and given tagger /*! Set the eta (mis-tag probability) distribution and tagging efficiencies (as a function of decay time) for B and Bbar \param [in] bkgndName background category name \param [in] taggerName name of the tagger \param [in] etaPdf the eta PDF itself \param [in] tagEff the tagging efficiency histograms */ void setBkgndParams(const TString& bkgndName, const TString& taggerName, LauAbsPdf* etaPdf, std::pair tagEff); //! Set background parameters for a given background and given tagger /*! Set the eta (mis-tag probability) distribution and tagging efficiency constants for B and Bbar This version provides different parameters for each decay flavour (used for Combinatorial background in QFS modes) \param [in] bkgndName background category name \param [in] taggerName name of the tagger \param [in] etaPdfB the eta PDF for decay flavour = B \param [in] tagEffB the tagging efficiency parameters for decay flavour = B \param [in] etaPdfBbar the eta PDF for decay flavour = Bbar \param [in] tagEffBbar the tagging efficiency parameters for decay flavour = Bbar */ void setBkgndParams(const TString& bkgndName, const TString& taggerName, LauAbsPdf* etaPdfB, std::pair tagEffB, LauAbsPdf* etaPdfBbar, std::pair tagEffBbar); //! Set background parameters for a given background and given tagger /*! Set the eta (mis-tag probability) distribution and tagging efficiencies (as a function of decay time) for B and Bbar This version provides different parameters for each decay flavour (used for Combinatorial background in QFS modes) \param [in] bkgndName background category name \param [in] taggerName name of the tagger \param [in] etaPdfB the eta PDF for decay flavour = B \param [in] tagEffB the tagging efficiency histograms for decay flavour = B \param [in] etaPdfBbar the eta PDF for decay flavour = Bbar \param [in] tagEffBbar the tagging efficiency histograms for decay flavour = Bbar */ void setBkgndParams(const TString& bkgndName, const TString& taggerName, LauAbsPdf* etaPdfB, std::pair tagEffB, LauAbsPdf* etaPdfBbar, std::pair tagEffBbar); //! Returns little omega (calibrated mistag) /*! \param [in] taggerID index of the tagger in the taggers vectors \param [in] flag choose to calculate omega or omegabar (corrsonding to B or Bbar) */ Double_t getLittleOmega(const std::size_t taggerID, const Flavour flag) const; //! Capital Omega for signal decays /*! \param [in] taggerID index of the tagger in the taggers vectors \param [in] flag choose to calculate Omega or Omegabar (corrsonding to B or Bbar) */ Double_t getCapitalOmega(const std::size_t taggerID, const Flavour flag) const; //! Returns little omega (calibrated mistag) for backgrounds /*! \param [in] bkgndID index of the background vector \param [in] taggerID index of the tagger in the taggers vectors \param [in] flag choose to calculate omega or omegabar (corrsonding to B or Bbar) \param [in] decayFlv the decay flavour of the B */ Double_t getLittleOmegaBkgnd(const std::size_t bkgndID, const std::size_t taggerID, const Flavour flag, const Flavour decayFlv) const; //! Capital Omega for backgrounds /*! \param [in] bkgndID index of the background vector \param [in] taggerID index of the tagger in the taggers vectors \param [in] flag choose to calculate Omega or Omegabar (corrsonding to B or Bbar) \param [in] decayFlv the decay flavour of the B */ Double_t getCapitalOmegaBkgnd(const std::size_t bkgndID, const std::size_t taggerID, const Flavour flag, const Flavour decayFlv) const; //! Get the generated value of signal eta for the given tagger /*! \param [in] taggerID index of the tagger in the taggers vectors */ Double_t getEtaGen(const std::size_t taggerID); //! Get the generated value of background eta for the given tagger and background category /*! \param [in] taggerID index of the tagger in the taggers vectors \param [in] bkgndID index of the background in the backgrounds vectors \param [in] decayFlv the decay flavour of the B */ Double_t getEtaGenBkgnd(const std::size_t taggerID, const std::size_t bkgndID, const Flavour decayFlv); //! Return the Boolean controlling if we use the alternative tagging calibration and efficiency parameters Bool_t getUseAveDelta() const {return useAveDelta_;}; //! Specify the name of the true tag variable /*! \param [in] trueTagVarName the name of the true tag variable */ void setTrueTagVarName(TString trueTagVarName); //! Specify the name of the decay flavour variable /*! \param [in] decayFlvVarName the name of the decay flavour variable */ void setDecayFlvVarName(TString decayFlvVarName); //! Gaussian constraints for P0 parameters for a given tagger /*! \param [in] taggerName name of the tagger \param [in] constraint1 the (mean, sigma) for the particle or average parameter \param [in] constraint2 the (mean, sigma) for the antiparticle or delta parameter */ void addP0GaussianConstraints(const TString& taggerName, const std::pair constraint1, const std::pair constraint2); //! Gaussian constraints for P1 parameters for a given tagger /*! \param [in] taggerName name of the tagger \param [in] constraint1 the (mean, sigma) for the particle or average parameter \param [in] constraint2 the (mean, sigma) for the antiparticle or delta parameter */ void addP1GaussianConstraints(const TString& taggerName, const std::pair constraint1, const std::pair constraint2); //! Gaussian constraints for tagging efficiency parameters for a given tagger /*! \param [in] taggerName name of the tagger \param [in] constraint1 the (mean, sigma) for the particle or average parameter \param [in] constraint2 the (mean, sigma) for the antiparticle or delta parameter */ void addTagEffGaussianConstraints(const TString& taggerName, const std::pair constraint1, const std::pair constraint2); //! Retrieve the names of the background categories std::vector getBkgndNames(); //! Retrieve the types of the background categories std::vector getBkgndTypes(){return bkgndTypes_;} //! Float the P0 calibration parameters for B tags /*! \param [in] taggerName name of the tagger, defaults to empty to float for all taggers */ void floatCalibParP0B0(const TString& taggerName = ""); //! Float the P1 calibration parameters for B tags /*! \param [in] taggerName name of the tagger, defaults to empty to float for all taggers */ void floatCalibParP1B0(const TString& taggerName = ""); //! Float the P0 calibration parameters for Bbar tags /*! \param [in] taggerName name of the tagger, defaults to empty to float for all taggers */ void floatCalibParP0B0bar(const TString& taggerName = ""); //! Float the P1 calibration parameters for Bbar tags /*! \param [in] taggerName name of the tagger, defaults to empty to float for all taggers */ void floatCalibParP1B0bar(const TString& taggerName = ""); //! Float the P0 average calibration parameters /*! \param [in] taggerName name of the tagger, defaults to empty to float for all taggers */ void floatCalibParP0Ave(const TString& taggerName = ""); //! Float the P0 delta calibration parameters /*! \param [in] taggerName name of the tagger, defaults to empty to float for all taggers */ void floatCalibParP0Delta(const TString& taggerName = ""); //! Float the P1 average calibration parameters /*! \param [in] taggerName name of the tagger, defaults to empty to float for all taggers */ void floatCalibParP1Ave(const TString& taggerName = ""); //! Float the P1 delta calibration parameters /*! \param [in] taggerName name of the tagger, defaults to empty to float for all taggers */ void floatCalibParP1Delta(const TString& taggerName = ""); //! Float all calibration parameters void floatAllCalibPars(); //! Update pulls on all floating parameters void updatePulls(); private: //! Internal function to extend vectors void extendVectors(const TString& tagVarName, const TString& mistagVarName); //! Internal function to setup Calib parameters void setupCalibParams(const TString& taggerName, const std::pair calib_p0, const std::pair calib_p1); //! Internal function to find parameters in per-tagger vectors LauParameter* findParameter( const TString& taggerName, std::vector& parameters ); //! Flag to use alternative calibration parameters const Bool_t useAveDelta_; //! Flag to use eta prime not eta for the mistag const Bool_t useEtaPrime_; //! Map to link tagger names to their index in all the vectors std::map taggerIndex_; //! Map to link background names to their index in all the vectors std::map bkgndIndex_; //! Flavour tagging variable name std::vector tagVarNames_; //! Per event mistag variable name std::vector mistagVarNames_; //! True tag variable name for normalisation decays TString trueTagVarName_; //! Decay flavour tag variable name for normalisation decays TString decayFlvVarName_; //! Vector of background types std::vector bkgndTypes_; //! Vector of flags indicating if the background parameters depend on the decay flavour std::vector bkgndDecayFlvDep_; //! Vector of flavour tags for each event std::vector> evtTagFlv_; //! Flavour tag for current event std::vector curEvtTagFlv_; //! Vector of mistags for each event std::vector> evtMistag_; //! Per event mistag for current event std::vector curEvtMistag_; //! Vector of true tags for each event std::vector evtTrueTagFlv_; //! Vector of decay tags for each event std::vector evtDecayFlv_; //! True tag from normalisation mode for current event Flavour curEvtTrueTagFlv_{Flavour::Unknown}; //! True tag from normalisation mode for current event Flavour curEvtDecayFlv_{Flavour::Unknown}; //! Average background mistag value (eta hat) std::vector>> avgMistagBkgnd_; //! Per-event average mistag value (eta hat) std::vector perEvtAvgMistag_; //! Decay time values for each event std::vector evtDecayTime_; //! Decay time value of the current event Double_t curEvtDecayTime_; //! Calibration parameters p0 for B0 std::vector calib_p0_B0_; //! Calibration parameters p0 for B0bar std::vector calib_p0_B0bar_; //! Calibration parameters p1 for B0 std::vector calib_p1_B0_; //! Calibration parameters p1 for B0bar std::vector calib_p1_B0bar_; //! Alternative calibration parameters p0 average std::vector calib_p0_ave_; //! Alternative calibration parameters p0 difference std::vector calib_p0_delta_; //! Alternative calibration parameters p1 average std::vector calib_p1_ave_; //! Alternative calibration parameters p1 difference std::vector calib_p1_delta_; //! Tagging efficiency parameters for B0 std::vector tagEff_B0_; //! Tagging efficiency parameters for B0bar std::vector tagEff_B0bar_; //! Tagging efficiency parameters average of B0 and B0bar std::vector tagEff_ave_; //! Tagging efficiency parameters difference between B0 and B0bar std::vector tagEff_delta_; //! Tagging efficiency histograms for B0 std::vector tagEff_hist_B0_; //! Tagging efficiency histograms for B0bar std::vector tagEff_hist_B0bar_; //! Tagging efficiency histograms average of B0 and B0bar std::vector tagEff_hist_ave_; //! Tagging efficiency histograms difference between B0 and B0bar std::vector tagEff_hist_delta_; //! Background tagging efficiency parameters for B0 std::vector>> tagEffBkgnd_B0_; //! Background tagging efficiency parameters for B0bar std::vector>> tagEffBkgnd_B0bar_; //! Background tagging efficiency parameters average of B0 and B0bar std::vector>> tagEffBkgnd_ave_; //! Background tagging efficiency parameters difference between B0 and B0bar std::vector>> tagEffBkgnd_delta_; //! Background tagging efficiency histograms for B0 std::vector>> tagEffBkgnd_hist_B0_; //! Background tagging efficiency histograms for B0bar std::vector>> tagEffBkgnd_hist_B0bar_; //! Background tagging efficiency histograms average of B0 and B0bar std::vector>> tagEffBkgnd_hist_ave_; //! Background tagging efficiency histograms difference between B0 and B0bar std::vector>> tagEffBkgnd_hist_delta_; //! Eta PDFs std::vector etaPdfs_; //! Eta PDFs for backgrounds per tagger (inner vec) and per background source (outer vec) std::vector>> etaBkgndPdfs_; ClassDef(LauFlavTag,0) // Flavour tagging set up }; -//! output stream operator -/*! - \param [in,out] stream the output stream to which the background type is to be printed - \param [in] bkgndType the type to be written out - return the output stream -*/ -std::ostream& operator<<( std::ostream& stream, const LauFlavTag::BkgndType bkgndType ); +//! \cond DOXYGEN_IGNORE +// map LauKMatrixPropagator::KMatrixChannels values to JSON as strings +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauFlavTag::BkgndType, { + {LauFlavTag::BkgndType::Combinatorial, "Combinatorial"}, + {LauFlavTag::BkgndType::FlavourSpecific, "FlavourSpecific"}, + {LauFlavTag::BkgndType::SelfConjugate, "SelfConjugate"}, + {LauFlavTag::BkgndType::NonSelfConjugate, "NonSelfConjugate"}, + }) +//! \endcond #endif diff --git a/inc/LauJsonTools.hh b/inc/LauJsonTools.hh index 2f43067..b696021 100644 --- a/inc/LauJsonTools.hh +++ b/inc/LauJsonTools.hh @@ -1,181 +1,241 @@ /* Copyright 2023 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ #ifndef LAU_JSON_TOOLS_HH #define LAU_JSON_TOOLS_HH #include "TString.h" #include #include #include /*! \file LauJsonTools.hh \brief File containing LauJsonTools namespace */ /*! \namespace LauJsonTools \brief Namespace containing tools for reading/writing JSON files */ namespace LauJsonTools { /*! \enum JsonType \brief Define types that can be found in JSON fields and that we can handle */ enum class JsonType { Null, //!< JSON value is null Object, //!< JSON value is an object Array, //!< JSON value is an array String, //!< JSON value is a string Boolean, //!< JSON value is a boolean Number_Integer, //!< JSON value is an integer (signed or unsigned) Number_Unsigned, //!< JSON value is an unsigned integer Number_Float, //!< JSON value is a floating point value Number, //!< JSON value is any number (integer, unsigned or float) Primitive, //!< JSON value is any primative type (null, string, boolean, integer, unsigned, float) Structured, //!< JSON value is any structured type (object, array) Any //!< JSON value is any of the above }; //! Typedef to define a combination of a JSON element's name and type using ElementNameType = std::pair< std::string, JsonType >; //! Exception object to be thrown in case of a missing element class MissingJsonElement : public std::runtime_error { public: //! Constructor /*! \param [in] what the message explaining the precise error that has occurred */ MissingJsonElement(const std::string& what) : std::runtime_error(what) {} }; //! Exception object to be thrown in case of malformed JSON class InvalidJson : public std::runtime_error { public: //! Constructor /*! \param [in] what the message explaining the precise error that has occurred */ InvalidJson(const std::string& what) : std::runtime_error(what) {} }; + //! Exception object to be thrown in case of encountering an invalid enumeration state + class InvalidEnumState : public std::runtime_error { + public: + //! Constructor + /*! + \param [in] what the message explaining the precise error that has occurred + */ + InvalidEnumState(const std::string& what) : std::runtime_error(what) {} + }; + //! Deserialise a JSON file to a JSON value /*! \param [in] fileName the name of the file to read \param [in] elementName the optional name of the element within the root object to retrieve - by default retrieve the root structure \param [in] expectedType the expected type of the value */ nlohmann::json readJsonFile(const std::string& fileName, const std::string& elementName = "", const JsonType expectedType = JsonType::Any); //! Serialise a JSON value to a JSON file /*! \param [in] value the JSON value to serialise \param [in] fileName the name of the file to be written \param [in] elementName the (optional) name of the JSON element to which the coefficients should be written \param [in] append if true, append the spline to the existing JSON within the file - if using this option it is then mandatory to provide elementName \param [in] indent the indentation level to use in the output in number of spaces (defaults to 4)\n From the nlohmann::json::dump documentation:\n If indent is nonnegative, then array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines. A value of -1 selects the most compact representation. \return true if file successfully written, false otherwise */ bool writeJsonFile(const nlohmann::json& value, const std::string& fileName, const std::string& elementName = "", const bool append = false, const int indent = 4); //! Check that the type of a JSON value is as expected /*! \param [in] value the JSON value to check \param [in] expectedType the expected type of the value */ bool checkValueType(const nlohmann::json& value, const JsonType expectedType); //! Check that the expected JSON elements are present in the supplied object /*! \param [in] obj the JSON object to check \param [in] expectedElements the elements (names and types) that are expected \return true if all expected elements are present, false otherwise */ bool checkObjectElements( const nlohmann::json& obj, const std::vector& expectedElements ); //! Access the value of an element that should be present in an object (no checking is done) /*! \tparam T the type of the element to be retrieved \param [in] obj the JSON object to access \param [in] elementName the name of the element within the object to retrieve \return the value of the element */ template T getValue( const nlohmann::json& obj, const std::string& elementName ) { return obj.at( elementName ).get(); } //! Access an element that may or may not be present in an object /*! \param [in] obj the JSON object to access \param [in] elementName the name of the element within the object to retrieve \param [in] expectedType the expected type of the element \return a pointer to the element, or nullptr if it is not present */ const nlohmann::json* getOptionalElement( const nlohmann::json& obj, const std::string& elementName, const JsonType expectedType = JsonType::Any ); //! Access the value of an element that may or may not be present in an object /*! \tparam T the type of the element to be retrieved \param [in] obj the JSON object to access \param [in] elementName the name of the element within the object to retrieve \param [in] expectedType the expected type of the element \return the value of the element as a std::optional */ template std::optional getOptionalValue( const nlohmann::json& obj, const std::string& elementName, const JsonType expectedType = JsonType::Any ); } template std::optional LauJsonTools::getOptionalValue( const nlohmann::json& obj, const std::string& elementName, const JsonType expectedType ) { auto elem { getOptionalElement( obj, elementName, expectedType ) }; if ( ! elem ) { return {}; } return elem->get(); } //! \cond DOXYGEN_IGNORE +// Provide conversion of TString to and from JSON namespace nlohmann { template <> struct adl_serializer { static void to_json(json& j, const TString& t) { j = t.Data(); } static TString from_json(const json& j) { return j.get(); } }; } + +// customise NLOHMANN_JSON_SERIALIZE_ENUM to throw in case of invalid enum state +// and extend to include also an output streaming operator +#define LAURA_NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + if (it == std::end(m)) { \ + throw LauJsonTools::InvalidEnumState{"ERROR in conversion to JSON, invalid state for " #ENUM_TYPE}; \ + } \ + j = it->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + if (it == std::end(m)) { \ + throw LauJsonTools::InvalidEnumState{"ERROR in conversion from JSON, invalid state for " #ENUM_TYPE}; \ + } \ + e = it->first; \ + } \ + inline std::ostream& operator<<(std::ostream& out, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& es_pair) -> bool \ + { \ + return es_pair.first == e; \ + }); \ + if (it == std::end(m)) { \ + throw LauJsonTools::InvalidEnumState{"ERROR in conversion from JSON, invalid state for " #ENUM_TYPE}; \ + } \ + out << it->second; \ + return out; \ + } //! \endcond #endif diff --git a/inc/LauPolarGammaCPCoeffSet.hh b/inc/LauPolarGammaCPCoeffSet.hh index 5d53f7d..c5569b0 100644 --- a/inc/LauPolarGammaCPCoeffSet.hh +++ b/inc/LauPolarGammaCPCoeffSet.hh @@ -1,357 +1,356 @@ /* Copyright 2014 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauPolarGammaCPCoeffSet.hh \brief File containing declaration of LauPolarGammaCPCoeffSet class. */ /*! \class LauPolarGammaCPCoeffSet \brief Class for defining a complex coefficient useful for extracting the CKM angle gamma from B -> D h h Dalitz plots. Holds a set of real values that define the complex coefficient of an amplitude component. Depending on the type of the D decay, the amplitude has one of the following forms: CP-odd eigenstate: ( x + i * y ) * ( 1 - rB * exp( i * ( deltaB +/- gamma ) ) ) CP-even eigenstate: ( x + i * y ) * ( 1 + rB * exp( i * ( deltaB +/- gamma ) ) ) ADS favoured state: ( x + i * y ) * ( 1 + rB * rD * exp( i * ( deltaB - deltaD +/- gamma ) ) ) ADS suppressed state: ( x + i * y ) * ( rD * exp( - i * deltaD ) + rB * exp( i * ( deltaB +/- gamma ) ) ) [Phys. Rev. D79, 051301 (2009)] */ #ifndef LAU_POLARGAMMACP_COEFF_SET #define LAU_POLARGAMMACP_COEFF_SET -#include -#include -#include - -#include "Rtypes.h" - #include "LauAbsCoeffSet.hh" + #include "LauComplex.hh" +#include "LauJsonTools.hh" #include "LauParameter.hh" +#include "Rtypes.h" + +#include +#include +#include + class LauPolarGammaCPCoeffSet : public LauAbsCoeffSet { public: //! The possible D decay modes enum class DecayType { GLW_CPOdd, /*!< GLW CP-odd, e.g. D0 -> K0 pi0 */ GLW_CPEven, /*!< GLW CP-even, e.g. D0 -> K+ K- */ ADS_Favoured, /*!< ADS Favoured, e.g. D0 -> K- pi+ */ ADS_Suppressed, /*!< ADS Suppressed, e.g. D0 -> K+ pi- */ GLW_CPOdd_btouOnly, /*!< GLW CP-odd, e.g. D0 -> K0 pi0, where B decay only proceeds via b -> u transition */ GLW_CPEven_btouOnly, /*!< GLW CP-even, e.g. D0 -> K+ K-, where B decay only proceeds via b -> u transition */ ADS_Favoured_btouOnly, /*!< ADS Favoured, e.g. D0 -> K- pi+, where B decay only proceeds via b -> u transition */ ADS_Suppressed_btouOnly, /*!< ADS Suppressed, e.g. D0 -> K+ pi-, where B decay only proceeds via b -> u transition */ }; //! Constructor /*! \param [in] compName the name of the coefficient set \param [in] decayType the type of the D decay \param [in] x the real part of the b -> c amplitude \param [in] y the imaginary part of the b -> c amplitude \param [in] rB the magnitude of the ratio of the b -> u and b -> c amplitudes \param [in] deltaB the relative CP-conserving (strong) phase of the b -> u and b -> c amplitudes \param [in] gamma the relative CP-violating (weak) phase of the b -> u and b -> c amplitudes \param [in] rD the magnitude of the ratio of the favoured and suppressed D-decay amplitudes \param [in] deltaD the relative strong phase of the favoured and suppressed D-decay amplitudes \param [in] xFixed whether x is fixed \param [in] yFixed whether y is fixed \param [in] rBFixed whether rB is fixed \param [in] deltaBFixed whether deltaB is fixed \param [in] gammaFixed whether gamma is fixed \param [in] rDFixed whether rD is fixed \param [in] deltaDFixed whether deltaD is fixed \param [in] rBSecondStage whether rB should be floated only in the second stage of the fit \param [in] deltaBSecondStage whether deltaB should be floated only in the second stage of the fit \param [in] gammaSecondStage whether gamma should be floated only in the second stage of the fit \param [in] rDSecondStage whether rD should be floated only in the second stage of the fit \param [in] deltaDSecondStage whether deltaD should be floated only in the second stage of the fit \param [in] useGlobalGamma whether gamma should be shared with other resonances \param [in] useGlobalADSPars whether rD and deltaD should be shared with other resonances */ LauPolarGammaCPCoeffSet(const TString& compName, const DecayType decayType, const Double_t x, const Double_t y, const Double_t rB, const Double_t deltaB, const Double_t gamma, const Double_t rD, const Double_t deltaD, const Bool_t xFixed, const Bool_t yFixed, const Bool_t rBFixed, const Bool_t deltaBFixed, const Bool_t gammaFixed, const Bool_t rDFixed, const Bool_t deltaDFixed, const Bool_t rBSecondStage = kFALSE, const Bool_t deltaBSecondStage = kFALSE, const Bool_t gammaSecondStage = kFALSE, const Bool_t rDSecondStage = kFALSE, const Bool_t deltaDSecondStage = kFALSE, const Bool_t useGlobalGamma = kFALSE, const Bool_t useGlobalADSPars = kFALSE); //! Move constructor (default) /*! \param [in] rhs the coefficient to clone */ LauPolarGammaCPCoeffSet(LauPolarGammaCPCoeffSet&& rhs) = default; //! Move assignment operator (deleted) /*! \param [in] rhs the coefficient to clone */ LauPolarGammaCPCoeffSet& operator=(LauPolarGammaCPCoeffSet&& rhs) = delete; //! Determine the type of the coefficient /*! \return the type of the coefficient */ LauCoeffType type() const override { return LauCoeffType::PolarGammaCP; } //! Retrieve the parameters of the coefficient, e.g. so that they can be loaded into a fit /*! \return the parameters of the coefficient [ X, Y, gamma, [rB, deltaB, rD, deltaD] ] */ std::vector getParameters() override; //! Retrieve the (const) parameters of the coefficient, e.g. so that they can be queried /*! \return the (const) parameters of the coefficient [ X, Y, gamma, [rB, deltaB, rD, deltaD] ] */ std::vector getParameters() const override; //! Retrieve the names of the parameters of the coefficient (in the same order as the parameters in getParameters) /*! \return the parameter names [ X, Y, gamma, [rB, deltaB, rD, deltaD] ] */ std::vector getParNames() const override; //! Determine the decay type of the coefficient /*! \return the decay type of the coefficient */ DecayType decayType() const { return decayType_; } //! Determine whether the global value of gamma is used for this coefficient /*! \return kTRUE if the global value of gamma is used, false otherwise */ Bool_t useGlobalGamma() const { return useGlobalGamma_; } //! Determine whether the global values of the ADS parameter are used for this coefficient /*! \return kTRUE if the global values are used, false otherwise */ Bool_t useGlobalADSPars() const { return useGlobalADSPars_; } //! Print the current values of the parameters void printParValues() const override; //! Print the column headings for a results table /*! \param [out] stream the stream to print to */ void printTableHeading(std::ostream& stream) const override; //! Print the parameters of the complex coefficient as a row in the results table /*! \param [out] stream the stream to print to */ void printTableRow(std::ostream& stream) const override; //! Randomise the starting values of the parameters for a fit void randomiseInitValues() override; //! Make sure values are in "standard" ranges, e.g. phases should be between -pi and pi void finaliseValues() override; //! Retrieve the complex coefficient for a particle /*! \return the complex coefficient for a particle */ const LauComplex& particleCoeff() override; //! Retrieve the complex coefficient for an antiparticle /*! \return the complex coefficient for an antiparticle */ const LauComplex& antiparticleCoeff() override; //! Set the parameters based on the complex coefficients for particles and antiparticles /*! This method is not supported by this class because there are more than four parameters, hence there is not a unique solution. \param [in] coeff the complex coefficient for a particle \param [in] coeffBar the complex coefficient for an antiparticle \param [in] init whether or not the initial and generated values should also be adjusted */ void setCoeffValues( const LauComplex& coeff, const LauComplex& coeffBar, const Bool_t init ) override; //! Calculate the CP asymmetry /*! \return the CP asymmetry */ LauParameter acp() override; //! Create a clone of the coefficient set /*! \param [in] newName the clone's name \param [in] cloneOption special option for the cloning operation \param [in] constFactor a constant factor to multiply the clone's parameters by \param [in] coeffInfo an optional JSON entry that contains the values of any non-cloned parameters (depending on the CloneOption) \return a clone of the coefficient set */ std::unique_ptr createClone(const TString& newName, const CloneOption cloneOption = CloneOption::All, const Double_t constFactor = 1.0, const nlohmann::json& coeffInfo = {}) const { return std::unique_ptr{this->createClone_impl(newName,cloneOption,constFactor,coeffInfo)}; } //! Write state to a JSON record /*! \param [in,out] j the JSON record to write to */ void serialiseToJson( nlohmann::json& j ) const override; private: //! Copy constructor /*! This creates cloned parameters, not copies. \param [in] rhs the coefficient to clone \param [in] cloneOption special option for the cloning operation \param [in] constFactor a constant factor to multiply the clone's parameters by \param [in] coeffInfo an optional JSON entry that contains the values of any non-cloned parameters (depending on the CloneOption) */ LauPolarGammaCPCoeffSet(const LauPolarGammaCPCoeffSet& rhs, const CloneOption cloneOption = CloneOption::All, const Double_t constFactor = 1.0, const nlohmann::json& coeffInfo = {}); //! Copy constructor (deleted) /*! \param [in] rhs the coefficient to clone */ LauPolarGammaCPCoeffSet(const LauPolarGammaCPCoeffSet& rhs) = delete; //! Copy assignment operator (deleted) /*! \param [in] rhs the coefficient to clone */ LauPolarGammaCPCoeffSet& operator=(const LauPolarGammaCPCoeffSet& rhs) = delete; //! Create a clone of the coefficient set /*! \param [in] newName the clone's name \param [in] cloneOption special option for the cloning operation \param [in] constFactor a constant factor by which to multiply the cloned parameters \param [in] coeffInfo an optional JSON entry that contains the values of any non-cloned parameters (depending on the CloneOption) \return a clone of the coefficient set */ LauPolarGammaCPCoeffSet* createClone_impl(const TString& newName, const LauAbsCoeffSet::CloneOption cloneOption, const Double_t constFactor, const nlohmann::json& coeffInfo) const override; //! Prepend the base name and index to the name of a parameter /*! \param [in,out] par the parameter to be renamed \param [in] oldBaseName the old base name, which might need to be removed before adding the new one */ void adjustName(LauParameter& par, const TString& oldBaseName) override; //! Update the amplitudes based on the new values of the parameters void updateAmplitudes(); //! The type of the D decay const DecayType decayType_; // the actual fit parameters // (need to be pointers so they can be cloned) //! The real part of the b -> c amplitude std::unique_ptr x_; //! The imaginary part of the b -> c amplitude std::unique_ptr y_; //! the magnitude of the ratio of the b -> u and b -> c amplitudes std::unique_ptr rB_; //! the relative CP-conserving (strong) phase of the b -> u and b -> c amplitudes std::unique_ptr deltaB_; //! the relative CP-violating (weak) phase of the b -> u and b -> c amplitudes std::shared_ptr gamma_; //! the magnitude of the ratio of the favoured and suppressed D-decay amplitudes std::shared_ptr rD_; //! the relative strong phase of the favoured and suppressed D-decay amplitudes std::shared_ptr deltaD_; //! The CP-violating phase (shared by multiple resonances) static std::shared_ptr gammaGlobal_; //! the magnitude of the ratio of the favoured and suppressed D-decay amplitudes (shared by multiple resonances) static std::shared_ptr rDGlobal_; //! the relative strong phase of the favoured and suppressed D-decay amplitudes (shared by multiple resonances) static std::shared_ptr deltaDGlobal_; //! Whether the global gamma is used for this resonance const Bool_t useGlobalGamma_; //! Whether the global rD and deltaD are used for this resonance const Bool_t useGlobalADSPars_; //! The b -> c part of the complex coefficient LauComplex nonCPPart_; //! The b -> u part of the complex coefficient for the particle LauComplex cpPart_; //! The b -> u part of the complex coefficient for the antiparticle LauComplex cpAntiPart_; //! The particle complex coefficient LauComplex particleCoeff_; //! The antiparticle complex coefficient LauComplex antiparticleCoeff_; //! The CP asymmetry LauParameter acp_; ClassDefOverride(LauPolarGammaCPCoeffSet, 0) }; -//! Output stream operator -std::ostream& operator<<( std::ostream& os, const LauPolarGammaCPCoeffSet::DecayType type ); - //! \cond DOXYGEN_IGNORE // map LauPolarGammaCPCoeffSet::DecayType values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauPolarGammaCPCoeffSet::DecayType, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauPolarGammaCPCoeffSet::DecayType, { {LauPolarGammaCPCoeffSet::DecayType::GLW_CPOdd, "GLW_CPOdd"}, {LauPolarGammaCPCoeffSet::DecayType::GLW_CPEven, "GLW_CPEven"}, {LauPolarGammaCPCoeffSet::DecayType::ADS_Favoured, "ADS_Favoured"}, {LauPolarGammaCPCoeffSet::DecayType::ADS_Suppressed, "ADS_Suppressed"}, {LauPolarGammaCPCoeffSet::DecayType::GLW_CPOdd_btouOnly, "GLW_CPOdd_btouOnly"}, {LauPolarGammaCPCoeffSet::DecayType::GLW_CPEven_btouOnly, "GLW_CPEven_btouOnly"}, {LauPolarGammaCPCoeffSet::DecayType::ADS_Favoured_btouOnly, "ADS_Favoured_btouOnly"}, {LauPolarGammaCPCoeffSet::DecayType::ADS_Suppressed_btouOnly, "ADS_Suppressed_btouOnly"}, }) namespace nlohmann { template <> struct adl_serializer { static LauPolarGammaCPCoeffSet from_json(const json& j); }; } //! \endcond #endif diff --git a/src/Lau1DCubicSpline.cc b/src/Lau1DCubicSpline.cc index a54ea22..1188f0b 100644 --- a/src/Lau1DCubicSpline.cc +++ b/src/Lau1DCubicSpline.cc @@ -1,725 +1,692 @@ /* Copyright 2015 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file Lau1DCubicSpline.cc \brief File containing implementation of Lau1DCubicSpline class. */ +#include "Lau1DCubicSpline.hh" + +#include "LauAbsRValue.hh" +#include "LauJsonTools.hh" +#include "LauParameter.hh" + +#include "TH2.h" +#include "TSystem.h" + +#include + #include #include #include #include #include -#include - -#include -#include - -#include "Lau1DCubicSpline.hh" -#include "LauAbsRValue.hh" -#include "LauJsonTools.hh" -#include "LauParameter.hh" - ClassImp(Lau1DCubicSpline) Lau1DCubicSpline::Lau1DCubicSpline(const std::vector& xs, const std::vector& ys, const SplineType type, const BoundaryType leftBound, const BoundaryType rightBound, const Double_t dydx0, const Double_t dydxn) : nKnots_{xs.size()}, x_{xs}, y_{ys}, type_{type}, leftBound_{leftBound}, rightBound_{rightBound}, dydx0_{dydx0}, dydxn_{dydxn} { init(); } std::unique_ptr Lau1DCubicSpline::readFromJson(const TString& fileName, const TString& splineName) { // NB deliberately not using uniform initialisation here because of this issue: // https://json.nlohmann.me/home/faq/#brace-initialization-yields-arrays const nlohmann::json j = LauJsonTools::readJsonFile( fileName.Data(), splineName.Data(), LauJsonTools::JsonType::Object ); if ( j.is_null() ) { if ( splineName != "" ) { std::cerr << "ERROR in Lau1DCubicSpline::readFromJson : unable to retrieve JSON object from element \"" << splineName << "\" in file \"" << fileName << "\"" << std::endl; } else { std::cerr << "ERROR in Lau1DCubicSpline::readFromJson : unable to retrieve JSON object from root element of file \"" << fileName << "\"" << std::endl; } return {}; } // NB can't use std::make_unique here because the default constructor is private std::unique_ptr spline{ new Lau1DCubicSpline }; j.get_to(*spline); spline->init(); return spline; } void Lau1DCubicSpline::writeToJson(const TString& fileName, const TString& splineName, const bool append, const int indent) const { const nlohmann::json j = *this; const bool writeOK { LauJsonTools::writeJsonFile( j, fileName.Data(), splineName.Data(), append, indent ) }; if ( ! writeOK ) { std::cerr << "ERROR in Lau1DCubicSpline::writeToJson : could not successfully write to file \"" << fileName << std::endl; } } Double_t Lau1DCubicSpline::evaluate(const Double_t x) const { // do not attempt to extrapolate the spline if( xx_[nKnots_-1] ) { std::cerr << "WARNING in Lau1DCubicSpline::evaluate : function is only defined between " << x_[0] << " and " << x_[nKnots_-1] << std::endl; std::cerr << " value at " << x << " returned as 0" << std::endl; return 0.; } // first determine which 'cell' of the spline x is in // cell i runs from knot i to knot i+1 std::size_t cell{0}; while( x > x_[cell+1] ) { ++cell; } // obtain x- and y-values of the neighbouring knots const Double_t xLow { x_[cell] }; const Double_t xHigh { x_[cell+1] }; const Double_t yLow { y_[cell] }; const Double_t yHigh { y_[cell+1] }; if(type_ == SplineType::LinearInterpolation) { return yHigh*(x-xLow)/(xHigh-xLow) + yLow*(xHigh-x)/(xHigh-xLow); } // obtain t, the normalised x-coordinate within the cell, // and the coefficients a and b, which are defined in cell i as: // // a_i = k_i *(x_i+1 - x_i) - (y_i+1 - y_i), // b_i = -k_i+1*(x_i+1 - x_i) + (y_i+1 - y_i) // // where k_i is (by construction) the first derivative at knot i const Double_t t { (x - xLow) / (xHigh - xLow) }; const Double_t a { dydx_[cell] * (xHigh - xLow) - (yHigh - yLow) }; const Double_t b { -1.*dydx_[cell+1] * (xHigh - xLow) + (yHigh - yLow) }; const Double_t retVal { (1 - t) * yLow + t * yHigh + t * (1 - t) * ( a * (1 - t) + b * t ) }; return retVal; } void Lau1DCubicSpline::updateYValues(const std::vector& ys) { y_ = ys; this->calcDerivatives(); } void Lau1DCubicSpline::updateYValues(const std::vector& ys) { for (std::size_t i{0}; iunblindValue(); } this->calcDerivatives(); } void Lau1DCubicSpline::updateYValues(const std::vector& ys) { for (std::size_t i{0}; iunblindValue(); } this->calcDerivatives(); } void Lau1DCubicSpline::updateType(const SplineType type) { if(type_ != type) { type_ = type; this->calcDerivatives(); } } void Lau1DCubicSpline::updateBoundaryConditions(const BoundaryType leftBound, const BoundaryType rightBound, const Double_t dydx0, const Double_t dydxn) { bool updateDerivatives{false}; if(leftBound_ != leftBound || rightBound_ != rightBound) { leftBound_ = leftBound; rightBound_ = rightBound; updateDerivatives = true; } if(dydx0_ != dydx0) { dydx0_ = dydx0; if(leftBound_ == BoundaryType::Clamped) updateDerivatives = true; } if(dydxn_ != dydxn) { dydxn_ = dydxn; if(rightBound_ == BoundaryType::Clamped) updateDerivatives = true; } if(updateDerivatives) { this->calcDerivatives(); } } std::array Lau1DCubicSpline::getCoefficients(const std::size_t segIndex, const bool normalise) const { std::array result = {0.,0.,0.,0.}; if(segIndex >= nKnots_-1) { std::cerr << "ERROR in Lau1DCubicSpline::getCoefficients requested for too high a knot value" << std::endl; return result; } Double_t xL = x_[segIndex] , xH = x_[segIndex+1]; Double_t yL = y_[segIndex] , yH = y_[segIndex+1]; Double_t h = xH-xL; //This number comes up a lot switch(type_) { case SplineType::StandardSpline: case SplineType::AkimaSpline: { Double_t kL = dydx_[segIndex], kH = dydx_[segIndex+1]; //a and b based on definitions from https://en.wikipedia.org/wiki/Spline_interpolation#Algorithm_to_find_the_interpolating_cubic_spline Double_t a = kL*h-(yH-yL); Double_t b =-kH*h+(yH-yL); Double_t denom = -h*h*h;//The terms have a common demoninator result[0] = -b*xL*xL*xH + a*xL*xH*xH + h*h*(xL*yH - xH*yL); result[1] = -a*xH*(2*xL+xH) + b*xL*(xL+2*xH) + h*h*(yL-yH); result[2] = -b*(2*xL+xH) + a*(xL+2*xH); result[3] = -a+b; for(auto& res : result){res /= denom;} break; } /* case SplineType::AkimaSpline: // Double check the Akima description of splines (in evaluate) right now they're the same except for the first derivatives { //using fomulae from https://asmquantmacro.com/2015/09/01/akima-spline-interpolation-in-excel/ std::function m = [&](Int_t j) //formula to get the straight line gradient { if(j < 0){return 2*m(j+1)-m(j+2);} if(j >= nKnots_){return 2*m(j-1)-m(j-2);} return (y_[j+1]-y_[j]) / (x_[j+1]-x_[j]); }; auto t = [&](Int_t j) { Double_t res = 0.; //originally res was called 't' but that produced a shadow warning Double_t denom = TMath::Abs(m(j+1)-m(j)) + TMath::Abs(m(j-1)-m(j-2)); if(denom == 0){res = (m(j)-m(j-1))/2;} //Special case for when denom = 0 else { res = TMath::Abs(m(j+1)-m(j))*m(j-1) + TMath::Abs(m(j-1)-m(j-2))*m(j); res /= denom; } return res; }; //These are the p's to get the spline in the form p_k(x-xL)^k Double_t pDenom = x_[segIndex+1]/x_[segIndex]; //a denominator used for p[2] and p[3] std::array p = {y_[segIndex],t(segIndex),0.,0.}; //we'll do the last 2 below p[2] = 3*m(segIndex)-2*t(segIndex)-t(segIndex+1); p[2]/= pDenom; p[3] = t(segIndex)+t(segIndex+1)-2*m(segIndex); p[3]/= pDenom*pDenom; //Now finally rearranging the p's into the desired results result[0] = p[0]-p[1]*xL+p[2]*xL*xL-p[3]*xL*xL*xL; result[1] = p[1]-2*p[2]*xL+3*p[3]*xL*xL; result[2] = p[2]-3*p[3]*xL; result[3] = p[3]; break; }*/ case SplineType::LinearInterpolation: { result[0] = xH*yL-xL*yH; result[1] = yH-yL; for(auto& res : result){res /= h;} break; } } if (normalise) { const Double_t integral { this->integral() }; for(auto& res : result){res /= integral;} } return result; } Double_t Lau1DCubicSpline::integral() const { Double_t integral{0.0}; for(std::size_t iKnot{0}; iKnot < nKnots_ -1; ++iKnot) { const Double_t minAbs { x_[iKnot] }; const Double_t maxAbs { x_[iKnot+1] }; const std::array coeffs { this->getCoefficients(iKnot, false) }; auto integralFunc = [&coeffs](Double_t x){return coeffs[0]*x + coeffs[1]*x*x/2.0 + coeffs[2]*x*x*x/3.0 + coeffs[3]*x*x*x*x/4.0;}; integral += integralFunc(maxAbs); integral -= integralFunc(minAbs); } return integral; } TF1* Lau1DCubicSpline::makeTF1(const bool normalise) const { auto fitf = [this](Double_t* x, Double_t* par) {//there is only 1 x (the abscissa) and 1 par (a scaling of the entire thing for normalisation) return this->evaluate( x[0] ) * par[0]; }; //Make the function TF1* func = new TF1("FittedFunc",fitf,x_.front(),x_.back(),1); func -> SetParNames("Normalisation"); if(normalise) { func->SetParameter(0, 1./func->Integral(x_.front(),x_.back())); } else{func->SetParameter(0,1.);} return func; } TF1* Lau1DCubicSpline::normaliseToTH1(TH1* hist, const LauOutputLevel printLevel) const { //first define the fit function auto fitf = [this](Double_t* x, Double_t* par) {//there is only 1 x (the abscissa) and 1 par (a scaling of the entire thing) return this->evaluate( x[0] ) * par[0]; }; //Make the function TF1* FittedFunc = new TF1("FittedFunc",fitf,x_.front(),x_.back(),1); //Set the parameter name FittedFunc -> SetParNames("Constant"); //Set the parameter limits and default value FittedFunc -> SetParLimits(0,0.,10.); FittedFunc -> SetParameter(0,1.); // Options to: // - N = do not store the graphics function // - 0 = do not plot the fit result TString fitOptions {"N 0"}; switch ( printLevel ) { case LauOutputLevel::ExtraVerbose : case LauOutputLevel::Verbose : fitOptions += " V"; break; case LauOutputLevel::Quiet : case LauOutputLevel::None : fitOptions += " Q"; break; case LauOutputLevel::Standard : break; } hist->Fit( "FittedFunc", fitOptions ); return FittedFunc; } TFitResultPtr Lau1DCubicSpline::fitToTH1(TH1* hist, const LauOutputLevel printLevel, const bool doWL, std::map fixedParams) { auto fitf = [this](Double_t* x, Double_t* par) { this -> updateYValues( std::vector(par, par + nKnots_) ); return this -> evaluate( x[0] ); }; TF1 FittedFunc("FittedFunc",fitf,x_.front(),x_.back(),nKnots_); const Double_t knotMax { hist->GetMaximum() * 1.5 }; for(std::size_t knot{0}; knot <= nKnots_ ; ++knot) { FittedFunc.SetParName(knot, Form("Knot%lu",knot)); FittedFunc.SetParLimits(knot, 0., knotMax); FittedFunc.SetParameter(knot, y_[knot]); } for(auto& [knot, val] : fixedParams) { FittedFunc.FixParameter(knot, val); } // Options to: // - N = do not store the graphics function // - 0 = do not plot the fit result // - S = save the result of the fit // - WL= do a weighted likelihood fit (not chi2) TString fitOptions {"N 0 S"}; if(doWL){fitOptions += " WL";} switch ( printLevel ) { case LauOutputLevel::ExtraVerbose : case LauOutputLevel::Verbose : fitOptions += " V"; break; case LauOutputLevel::Quiet : case LauOutputLevel::None : fitOptions += " Q"; break; case LauOutputLevel::Standard : break; } return hist->Fit( "FittedFunc", fitOptions ); } void Lau1DCubicSpline::init() { if( y_.size() != x_.size()) { std::cerr << "ERROR in Lau1DCubicSpline::init : The number of y-values given does not match the number of x-values" << std::endl; std::cerr << " Found " << y_.size() << ", expected " << x_.size() << std::endl; gSystem->Exit(EXIT_FAILURE); } if( nKnots_ < 3 ) { std::cerr << "ERROR in Lau1DCubicSpline::init : The number of knots is too small" << std::endl; std::cerr << " Found " << nKnots_ << ", expected at least 3 (to have at least 1 internal knot)" << std::endl; gSystem->Exit(EXIT_FAILURE); } dydx_.assign(nKnots_,0.0); a_.assign(nKnots_,0.0); b_.assign(nKnots_,0.0); c_.assign(nKnots_,0.0); d_.assign(nKnots_,0.0); this->calcDerivatives(); } void Lau1DCubicSpline::calcDerivatives() { switch ( type_ ) { case SplineType::StandardSpline : this->calcDerivativesStandard(); break; case SplineType::AkimaSpline : this->calcDerivativesAkima(); break; case SplineType::LinearInterpolation : //derivatives not needed for linear interpolation break; } } void Lau1DCubicSpline::calcDerivativesStandard() { // derivatives are determined such that the second derivative is continuous at internal knots // derivatives, k_i, are the solutions to a set of linear equations of the form: // a_i * k_i-1 + b_i * k+i + c_i * k_i+1 = d_i with a_0 = 0, c_n-1 = 0 // this is solved using the tridiagonal matrix algorithm as on en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm // first and last equations give boundary conditions // - for natural boundary, require f''(x) = 0 at end knot // - for 'not a knot' boundary, require f'''(x) continuous at second knot // - for clamped boundary, require predefined value of f'(x) at end knot // non-zero values of a_0 and c_n-1 would give cyclic boundary conditions a_[0] = 0.; c_[nKnots_-1] = 0.; // set left boundary condition switch ( leftBound_ ) { case BoundaryType::Natural : { b_[0] = 2./(x_[1]-x_[0]); c_[0] = 1./(x_[1]-x_[0]); d_[0] = 3.*(y_[1]-y_[0])/((x_[1]-x_[0])*(x_[1]-x_[0])); break; } case BoundaryType::NotAKnot : { // define the width, h, and the 'slope', delta, of the first cell const Double_t h1{x_[1]-x_[0]}; const Double_t h2{x_[2]-x_[0]}; const Double_t delta1{(y_[1]-y_[0])/h1}; const Double_t delta2{(y_[2]-y_[1])/h2}; // these coefficients can be determined by requiring f'''_0(x_1) = f'''_1(x_1) // the requirement f''_0(x_1) = f''_1(x_1) has been used to remove the dependence on k_2 b_[0] = h2; c_[0] = h1+h2; d_[0] = delta1*(2.*h2*h2 + 3.*h1*h2)/(h1+h2) + delta2*5.*h1*h1/(h1+h2); break; } case BoundaryType::Clamped : { b_[0] = 1.; c_[0] = 0.; d_[0] = dydx0_; break; } } // set right boundary condition switch ( rightBound_ ) { case BoundaryType::Natural : { a_[nKnots_-1] = 1./(x_[nKnots_-1]-x_[nKnots_-2]); b_[nKnots_-1] = 2./(x_[nKnots_-1]-x_[nKnots_-2]); d_[nKnots_-1] = 3.*(y_[nKnots_-1]-y_[nKnots_-2])/((x_[nKnots_-1]-x_[nKnots_-2])*(x_[nKnots_-1]-x_[nKnots_-2])); break; } case BoundaryType::NotAKnot : { // define the width, h, and the 'slope', delta, of the last cell const Double_t hnm1{x_[nKnots_-1]-x_[nKnots_-2]}; const Double_t hnm2(x_[nKnots_-2]-x_[nKnots_-3]); const Double_t deltanm1{(y_[nKnots_-1]-y_[nKnots_-2])/hnm1}; const Double_t deltanm2{(y_[nKnots_-2]-y_[nKnots_-3])/hnm2}; // these coefficients can be determined by requiring f'''_n-3(x_n-2) = f'''_n-2(x_n-2) // the requirement f''_n-3(x_n-2) = f''_n-2(x_n-2) has been used to remove // the dependence on k_n-3 a_[nKnots_-1] = hnm2 + hnm1; b_[nKnots_-1] = hnm1; d_[nKnots_-1] = deltanm2*hnm1*hnm1/(hnm2+hnm1) + deltanm1*(2.*hnm2*hnm2 + 3.*hnm2*hnm1)/(hnm2+hnm1); break; } case BoundaryType::Clamped : { a_[nKnots_-1] = 0.; b_[nKnots_-1] = 1.; d_[nKnots_-1] = dydxn_; break; } } // the remaining equations ensure that f_i-1''(x_i) = f''_i(x_i) for all internal knots for(std::size_t i{1}; i(nKnots_-2)}; i>=0; --i) { dydx_[i] = d_[i] - c_[i]*dydx_[i+1]; } } void Lau1DCubicSpline::calcDerivativesAkima() { //derivatives are calculated according to the Akima method // J.ACM vol. 17 no. 4 pp 589-602 Double_t am1{0.0}, an{0.0}, anp1{0.0}; // a[i] is the slope of the segment from point i-1 to point i // // n.b. segment 0 is before point 0 and segment n is after point n-1 // internal segments are numbered 1 - n-1 for(std::size_t i{1}; i coeffs { this->getCoefficients(iSegment, false) }; // first derivative is a parabola const Double_t a { coeffs[3]*3.0 }; const Double_t b { coeffs[2]*2.0 }; const Double_t c { coeffs[1] }; const Double_t discriminant { b*b - 4.0*a*c }; // if no real roots, skip this segment if ( discriminant < 0.0) { continue; } const Double_t x1 { (-b + TMath::Sqrt(discriminant))/(2.0*a) }; if ( x1 > x_[iSegment] and x1 < x_[iSegment+1] ) { // this root is within the segment - check the 2nd derivative const Double_t secondDeriv { 2.0 * a * x1 + b }; if ( secondDeriv < 0.0 ) { // evaluate the function and update max if appropriate const Double_t y1 { this->evaluate(x1) }; if ( y1 > max ) { max = y1; } } } const Double_t x2 { (-b - TMath::Sqrt(discriminant))/(2.0*a) }; if ( x2 > x_[iSegment] and x2 < x_[iSegment+1] ) { // this root is within the segment - check the 2nd derivative const Double_t secondDeriv { 2.0 * a * x2 + b }; if ( secondDeriv < 0.0 ) { // evaluate the function and update max if appropriate const Double_t y2 { this->evaluate(x2) }; if ( y2 > max ) { max = y2; } } } } return max; } - -//! \cond DOXYGEN_IGNORE -std::ostream& operator<<(std::ostream& out, const Lau1DCubicSpline::SplineType type) -{ - switch (type) { - case Lau1DCubicSpline::SplineType::StandardSpline : - out << "StandardSpline"; - break; - case Lau1DCubicSpline::SplineType::AkimaSpline : - out << "AkimaSpline"; - break; - case Lau1DCubicSpline::SplineType::LinearInterpolation : - out << "LinearInterpolation"; - break; - } - return out; -} - -std::ostream& operator<<(std::ostream& out, const Lau1DCubicSpline::BoundaryType type) -{ - switch (type) { - case Lau1DCubicSpline::BoundaryType::Clamped: - out << "Clamped"; - break; - case Lau1DCubicSpline::BoundaryType::Natural : - out << "Natural"; - break; - case Lau1DCubicSpline::BoundaryType::NotAKnot : - out << "NotAKnot"; - break; - } - return out; -} -//! \endcond diff --git a/src/LauAbsCoeffSet.cc b/src/LauAbsCoeffSet.cc index 1a7f931..748f61b 100644 --- a/src/LauAbsCoeffSet.cc +++ b/src/LauAbsCoeffSet.cc @@ -1,462 +1,421 @@ /* Copyright 2006 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauAbsCoeffSet.cc \brief File containing implementation of LauAbsCoeffSet class. */ #include #include #include "TString.h" #include "LauAbsCoeffSet.hh" #include "LauConstants.hh" #include "LauParameter.hh" #include "LauRandom.hh" ClassImp(LauAbsCoeffSet); TRandom* LauAbsCoeffSet::randomiser_ = nullptr; Double_t LauAbsCoeffSet::minMagnitude_ = -10.0; Double_t LauAbsCoeffSet::maxMagnitude_ = 10.0; Double_t LauAbsCoeffSet::minPhase_ = -LauConstants::threePi; Double_t LauAbsCoeffSet::maxPhase_ = LauConstants::threePi; Double_t LauAbsCoeffSet::minRealImagPart_ = -10.0; Double_t LauAbsCoeffSet::maxRealImagPart_ = 10.0; Double_t LauAbsCoeffSet::minDelta_ = -2.0; Double_t LauAbsCoeffSet::maxDelta_ = 2.0; LauAbsCoeffSet::LauAbsCoeffSet(const TString& theName, const TString& theBaseName, const LauAbsCoeffSet* parent, const CloneOption cloneOption, const Double_t constFactor) : name_{theName}, basename_{theBaseName}, parent_{parent}, cloneOption_{cloneOption}, constFactor_{constFactor} { } TRandom* LauAbsCoeffSet::getRandomiser() { if ( randomiser_ == nullptr ) { randomiser_ = LauRandom::zeroSeedRandom(); } return randomiser_; } void LauAbsCoeffSet::index(const UInt_t newIndex) { index_ = newIndex; const TString oldBaseName{ this->baseName() }; TString basename{ oldBaseName }; basename += newIndex; basename += "_"; this->baseName(basename); std::vector pars { this->getParameters() }; for ( LauParameter* par : pars ) { this->adjustName( *par, oldBaseName ); } } void LauAbsCoeffSet::adjustName(LauParameter& par, const TString& oldBaseName) { TString theName{ par.name() }; if ( theName.BeginsWith( oldBaseName ) && theName != oldBaseName ) { theName.Remove(0,oldBaseName.Length()); } theName.Prepend(this->baseName()); par.name(theName); } void LauAbsCoeffSet::setParameterValue(const TString& parName, const Double_t value, const Bool_t init) { LauParameter* par { this->findParameter( parName ) }; if ( par == nullptr ) { std::cerr << "ERROR in LauAbsCoeffSet::setParameterValue : Unable to find parameter \"" << parName << "\"" << std::endl; return; } par->value( value ); if ( init ) { par->genValue( value ); par->initValue( value ); } } void LauAbsCoeffSet::setParameterError(const TString& parName, const Double_t error) { LauParameter* par { this->findParameter( parName ) }; if ( par == nullptr ) { std::cerr << "ERROR in LauAbsCoeffSet::setParameterError : Unable to find parameter \"" << parName << "\"" << std::endl; return; } par->error( error ); } void LauAbsCoeffSet::fixParameter(const TString& parName) { LauParameter* par { this->findParameter( parName ) }; if ( par == nullptr ) { std::cerr << "ERROR in LauAbsCoeffSet::fixParameter : Unable to find parameter \"" << parName << "\"" << std::endl; return; } par->fixed( kTRUE ); } void LauAbsCoeffSet::floatParameter(const TString& parName) { LauParameter* par { this->findParameter( parName ) }; if ( par == nullptr ) { std::cerr << "ERROR in LauAbsCoeffSet::floatParameter : Unable to find parameter \"" << parName << "\"" << std::endl; return; } par->fixed( kFALSE ); } void LauAbsCoeffSet::blindParameter(const TString& parName, const TString& blindingString, const Double_t width) { LauParameter* par { this->findParameter( parName ) }; if ( par == nullptr ) { std::cerr << "ERROR in LauAbsCoeffSet::blindParameter : Unable to find parameter \"" << parName << "\"" << std::endl; return; } par->blindParameter( blindingString, width ); } void LauAbsCoeffSet::addGaussianConstraint(const TString& parName, const Double_t mean, const Double_t width) { LauParameter* par { this->findParameter( parName ) }; if ( par == nullptr ) { std::cerr << "ERROR in LauAbsCoeffSet::addGaussianConstraint : Unable to find parameter \"" << parName << "\"" << std::endl; return; } par->addGaussianConstraint( mean, width ); } void LauAbsCoeffSet::addSuffixToParameterName(const TString& parName, const TString& suffix) { LauParameter* par { this->findParameter( parName ) }; if ( par == nullptr ) { std::cerr << "ERROR in LauAbsCoeffSet::addSuffixToParameterName : Unable to find parameter \"" << parName << "\"" << std::endl; return; } TString newName{ par->name() }; if ( ! suffix.BeginsWith('_') ) { newName += "_"; } newName += suffix; par->name( newName ); } LauParameter* LauAbsCoeffSet::findParameter(const TString& parName) { std::vector pars { this->getParameters() }; for ( LauParameter* par : pars ) { const TString& iName { par->name() }; if ( iName.EndsWith( parName ) ) { return par; } } return nullptr; } void LauAbsCoeffSet::serialiseToJson( nlohmann::json& j ) const { // Check that the number of parameters and names match up const auto pars = this->getParameters(); const auto parNames = this->getParNames(); const std::size_t nPars { pars.size() }; if ( parNames.size() != nPars ) { std::cerr << "ERROR in LauAbsCoeffSet::serialiseToJson : Wrong number of parameter names supplied for coefficient set of type " << this->type() << std::endl; return; } // Serialise the type, name, and clone status j["type"] = this->type(); j["name"] = this->name(); if ( this->clone() ) { j["clone"] = true; j["parent"] = this->parent()->name(); j["cloneOption"] = this->cloneOption(); j["constFactor"] = this->constFactor(); } else { j["clone"] = false; } // Serialise all non-cloned parameters for ( std::size_t i{0}; i < nPars; ++i ) { const auto& par = pars[i]; if ( par->clone() ) { continue; } // Serialise the value, fixed/float flag, second-stage flag, blind flag // Prepare the names of each key const TString& parName { parNames[i] }; const TString parNameFixed {parName+"Fixed"}; const TString parNameSecondStage {parName+"SecondStage"}; const TString parNameBlind {parName+"Blind"}; j[parName.Data()] = par->value(); j[parNameFixed.Data()] = par->fixed(); j[parNameSecondStage.Data()] = par->secondStage(); j[parNameBlind.Data()] = par->blind(); if ( par->blind() ) { // For blinded parameters also serialise the blinding string and width const TString parNameBlindingString {parName+"BlindingString"}; const TString parNameBlindingWidth {parName+"BlindingWidth"}; j[parNameBlindingString.Data()] = par->blinder()->blindingString(); j[parNameBlindingWidth.Data()] = par->blinder()->blindingWidth(); } } } void LauAbsCoeffSet::applyBlinding( const nlohmann::json& j ) { // Reads blinding information for each parameter from the JSON record for ( const auto& parName : this->getParNames() ) { const TString parNameBlind {parName+"Blind"}; const TString parNameBlindingString {parName+"BlindingString"}; const TString parNameBlindingWidth {parName+"BlindingWidth"}; // If the Blind field is present and is true, // retrieve also the blinding string and width, // and apply the blinding to the parameter if ( j.contains(parNameBlind.Data()) && j.at(parNameBlind.Data()).get() ) { const std::string blindingString { j.at(parNameBlindingString.Data()).get() }; const Double_t blindingWidth { j.at(parNameBlindingWidth.Data()).get() }; this->blindParameter(parName, blindingString, blindingWidth); } } } #include "LauBelleCPCoeffSet.hh" #include "LauCartesianCPCoeffSet.hh" #include "LauCartesianGammaCPCoeffSet.hh" #include "LauCleoCPCoeffSet.hh" #include "LauMagPhaseCoeffSet.hh" #include "LauMagPhaseCPCoeffSet.hh" #include "LauNSCCartesianCPCoeffSet.hh" #include "LauPolarGammaCPCoeffSet.hh" #include "LauRealImagCoeffSet.hh" #include "LauRealImagCPCoeffSet.hh" #include "LauRealImagGammaCPCoeffSet.hh" #include "LauJsonTools.hh" std::vector> LauAbsCoeffSet::readFromJson( const TString& fileName, const TString& elementName ) { using nlohmann::json; using LauJsonTools::JsonType; using LauJsonTools::ElementNameType; using LauJsonTools::checkObjectElements; using LauJsonTools::getValue; using LauJsonTools::getOptionalValue; // NB deliberately not using uniform initialisation here because of this issue: // https://json.nlohmann.me/home/faq/#brace-initialization-yields-arrays const json j = LauJsonTools::readJsonFile( fileName.Data(), elementName.Data(), JsonType::Object ); if ( j.is_null() ) { if ( elementName != "" ) { std::cerr << "ERROR in LauAbsCoeffSet::readFromJson : unable to retrieve JSON object from element \"" << elementName << "\" in file \"" << fileName << "\"" << std::endl; } else { std::cerr << "ERROR in LauAbsCoeffSet::readFromJson : unable to retrieve JSON object from root element of file \"" << fileName << "\"" << std::endl; } return {}; } std::vector mandatoryElements { std::make_pair("nCoeffs", JsonType::Number_Integer), std::make_pair("coeffs", JsonType::Array) }; if ( ! checkObjectElements( j, mandatoryElements ) ) { std::cerr << "ERROR in LauAbsCoeffSet::readFromJson : aborting processing due to mis-formatted elements" << std::endl; return {}; } mandatoryElements = { std::make_pair("clone", JsonType::Boolean), std::make_pair("name", JsonType::String), std::make_pair("type", JsonType::String) }; Bool_t allOK{kTRUE}; for ( auto& coeff : j.at("coeffs") ) { allOK &= checkObjectElements( coeff, mandatoryElements ); } if ( ! allOK ) { std::cerr << "ERROR in LauAbsCoeffSet::readFromJson : aborting processing due to mis-formatted elements" << std::endl; return {}; } const auto nCoeffs { getValue( j, "nCoeffs") }; std::vector> coeffs; coeffs.reserve( nCoeffs ); std::vector clonedCoeffs; clonedCoeffs.reserve( nCoeffs ); for ( auto& coeff : j.at("coeffs") ) { // If it's a cloned coeff, we save it for later if ( getValue( coeff, "clone" ) ) { clonedCoeffs.emplace_back( coeff ); continue; } // Otherwise create and store an instance of the appropriate type, // constructed from the JSON record switch ( getValue( coeff, "type" ) ) { case LauCoeffType::MagPhase : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::RealImag : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::BelleCP : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::CartesianCP : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::CartesianGammaCP : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::CleoCP : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::MagPhaseCP : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::NSCCartesianCP : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::PolarGammaCP : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::RealImagCP : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; case LauCoeffType::RealImagGammaCP : coeffs.emplace_back( std::make_unique( coeff.get() ) ); break; } } mandatoryElements = { std::make_pair("parent", JsonType::String), std::make_pair("cloneOption", JsonType::String), std::make_pair("constFactor", JsonType::Number) }; allOK = kTRUE; for ( auto& coeff : clonedCoeffs ) { allOK &= checkObjectElements( coeff, mandatoryElements ); } if ( ! allOK ) { std::cerr << "ERROR in LauAbsCoeffSet::readFromJson : aborting processing due to mis-formatted elements" << std::endl; return {}; } // Now construct the clones for ( auto& coeff : clonedCoeffs ) { const auto name { getValue( coeff, "name" ) }; const auto parentName { getValue( coeff, "parent" ) }; // Find the parent of this coefficient set auto parent = std::find_if( coeffs.begin(), coeffs.end(), [&parentName](const std::unique_ptr& c){ return c->name() == parentName; } ); if ( parent == coeffs.end() ) { throw LauClonedCoeff{"Cannot locate parent (" + parentName + ") for cloned coefficient set " + name}; } const auto cloneOption { getValue( coeff, "cloneOption" ) }; const auto constFactor { getValue( coeff, "constFactor" ) }; // Create a clone from the parent, passing the json // entry for this coeffset to allow any parameters that // are not cloned (depending on the CloneOption) to // have their values etc. set correctly coeffs.emplace_back( (*parent)->createClone( name, cloneOption, constFactor, coeff ) ); } return coeffs; } - -std::ostream& operator<<( std::ostream& os, const LauCoeffType type ) -{ - switch ( type ) { - case LauCoeffType::MagPhase : - os << "MagPhase"; - break; - case LauCoeffType::RealImag : - os << "RealImag"; - break; - case LauCoeffType::BelleCP : - os << "BelleCP"; - break; - case LauCoeffType::CartesianCP : - os << "CartesianCP"; - break; - case LauCoeffType::CartesianGammaCP : - os << "CartesianGammaCP"; - break; - case LauCoeffType::CleoCP : - os << "CleoCP"; - break; - case LauCoeffType::MagPhaseCP : - os << "MagPhaseCP"; - break; - case LauCoeffType::NSCCartesianCP : - os << "NSCCartesianCP"; - break; - case LauCoeffType::PolarGammaCP : - os << "PolarGammaCP"; - break; - case LauCoeffType::RealImagCP : - os << "RealImagCP"; - break; - case LauCoeffType::RealImagGammaCP : - os << "RealImagGammaCP"; - break; - } - - return os; -} diff --git a/src/LauFlavTag.cc b/src/LauFlavTag.cc index b8f7509..4f86f60 100644 --- a/src/LauFlavTag.cc +++ b/src/LauFlavTag.cc @@ -1,1465 +1,1445 @@ /* Copyright 2017 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauFlavTag.cc \brief File containing implementation of LauFlavTag class. */ #include #include #include #include "TMath.h" #include "TString.h" #include "TSystem.h" #include "Lau1DHistPdf.hh" #include "LauAbsPdf.hh" #include "LauFlavTag.hh" #include "LauRandom.hh" ClassImp(LauFlavTag) -std::ostream& operator<<( std::ostream& stream, const LauFlavTag::BkgndType bkgndType ) -{ - switch ( bkgndType ) { - case LauFlavTag::BkgndType::Combinatorial : - stream << "Combinatorial"; - break; - case LauFlavTag::BkgndType::FlavourSpecific : - stream << "FlavourSpecific"; - break; - case LauFlavTag::BkgndType::SelfConjugate : - stream << "SelfConjugate"; - break; - case LauFlavTag::BkgndType::NonSelfConjugate : - stream << "NonSelfConjugate"; - break; - } - - return stream; -} - LauFlavTag::LauFlavTag(const Bool_t useAveDelta, const Bool_t useEtaPrime, const std::map bkgndInfo) : useAveDelta_(useAveDelta), useEtaPrime_(useEtaPrime) { // Put map values into vectors bkgndTypes_.reserve( bkgndInfo.size() ); bkgndDecayFlvDep_.reserve( bkgndInfo.size() ); for (const auto& [ bkgndName, bkgndType ] : bkgndInfo){ const std::size_t bkgndPos { bkgndIndex_.size() }; bkgndIndex_.insert(std::make_pair(bkgndName, bkgndPos)); bkgndTypes_.push_back(bkgndType); bkgndDecayFlvDep_.push_back(false); std::cout<< "INFO in LauFlavTag::LauFlavTag : adding background " << bkgndName << " of type " << bkgndType < LauFlavTag::getBkgndNames() { std::vector names; names.reserve( bkgndIndex_.size() ); for ( auto& [ name, _ ] : bkgndIndex_ ) { names.push_back( name ); } return names; } void LauFlavTag::addTagger(const TString& name, const TString& tagVarName, const TString& mistagVarName, LauAbsPdf* etapdf, const std::pair tagEff, const std::pair calib_p0, const std::pair calib_p1) { // Check that we don't already have a tagger with the same name if ( taggerIndex_.find(name) != taggerIndex_.end() ) { std::cerr << "ERROR in LauFlavTag::addTagger : tagger called " << name << " already added" << std::endl; gSystem->Exit(EXIT_FAILURE); } // Check that the PDF pointer is valid if ( not etapdf ) { std::cerr << "ERROR in LauFlavTag::addTagger : Eta PDF pointer is NULL" << std::endl; gSystem->Exit(EXIT_FAILURE); } // Find how many taggers have already been added const std::size_t index { tagVarNames_.size() }; // Update map to relate tagger name and index in the vectors taggerIndex_[name] = index; // Extend vectors this->extendVectors(tagVarName, mistagVarName); etaPdfs_.push_back(etapdf); Lau1DHistPdf* etahistpdf = dynamic_cast(etapdf); if (etahistpdf){ perEvtAvgMistag_.push_back(etahistpdf->getMean()); } else { std::cerr << "WARNING in LauFlavTag::addTagger : Couldn't determine average eta value from PDF. Setting it to 0.4." << std::endl; perEvtAvgMistag_.push_back(0.4); } //Calib parameters this->setupCalibParams(name,calib_p0,calib_p1); //Tagging efficiencies if (!useAveDelta_){ TString tagEff_b0Name("tagEff_b0_"+name); TString tagEff_b0barName("tagEff_b0bar_"+name); LauParameter* tageffb0 = new LauParameter(tagEff_b0Name,tagEff.first,0.0,1.0,kTRUE); tagEff_B0_.push_back(tageffb0); tagEff_B0_[index]->initValue(tagEff.first); tagEff_B0_[index]->genValue(tagEff.first); tagEff_B0_[index]->fixed(kTRUE); if (tagEff.second==-1.0){ tagEff_B0bar_.push_back(tagEff_B0_[index]->createClone(tagEff_b0barName)); } else { LauParameter* tageffb0bar = new LauParameter(tagEff_b0barName,tagEff.second,0.0,1.0,kTRUE); tagEff_B0bar_.push_back(tageffb0bar); tagEff_B0bar_[index]->initValue(tagEff.second); tagEff_B0bar_[index]->genValue(tagEff.second); tagEff_B0bar_[index]->fixed(kTRUE); } } else { //Use average and delta variables TString tagEff_aveName("tagEff_ave_"+name); TString tagEff_deltaName("tagEff_delta_"+name); LauParameter* tageffave = new LauParameter(tagEff_aveName,tagEff.first,0.0,1.0,kTRUE); tagEff_ave_.push_back(tageffave); tagEff_ave_[index]->initValue(tagEff.first); tagEff_ave_[index]->genValue(tagEff.first); tagEff_ave_[index]->fixed(kTRUE); LauParameter* tageffdelta = new LauParameter(tagEff_deltaName,tagEff.second,-1.0,1.0,kTRUE); tagEff_delta_.push_back(tageffdelta); tagEff_delta_[index]->initValue(tagEff.second); tagEff_delta_[index]->genValue(tagEff.second); tagEff_delta_[index]->fixed(kTRUE); } std::cout<<"INFO in LauFlavTag::addTagger : Added tagger with name "<< name << std::endl; } void LauFlavTag::addTagger(const TString& name, const TString& tagVarName, const TString& mistagVarName, LauAbsPdf* etapdf, const std::pair tagEff, const std::pair calib_p0, const std::pair calib_p1) { // Check that we don't already have a tagger with the same name if ( taggerIndex_.find(name) != taggerIndex_.end() ) { std::cerr << "ERROR in LauFlavTag::addTagger : tagger called " << name << " already added" << std::endl; gSystem->Exit(EXIT_FAILURE); } // Check that the PDF pointer is valid if ( not etapdf ) { std::cerr << "ERROR in LauFlavTag::addTagger : Eta PDF pointer is NULL" << std::endl; gSystem->Exit(EXIT_FAILURE); } // Find how many taggers have already been added const std::size_t index { tagVarNames_.size() }; // Update map to relate tagger name and index in the vectors taggerIndex_[name] = index; // Extend vectors this->extendVectors(tagVarName, mistagVarName); etaPdfs_.push_back(etapdf); Lau1DHistPdf* etahistpdf = dynamic_cast(etapdf); if (etahistpdf){ perEvtAvgMistag_.push_back(etahistpdf->getMean()); } else { std::cerr << "WARNING in LauFlavTag::addTagger : Couldn't determine average eta value from PDF. Setting it to 0.4." << std::endl; perEvtAvgMistag_.push_back(0.4); } //Calib parameters this->setupCalibParams(name,calib_p0,calib_p1); //Tagging efficiencies if (!useAveDelta_){ tagEff_hist_B0_.push_back(tagEff.first); tagEff_B0_.push_back(nullptr); if (tagEff.second==nullptr){ tagEff_hist_B0bar_.push_back(tagEff.first); tagEff_B0bar_.push_back(nullptr); } else { tagEff_hist_B0bar_.push_back(tagEff.second); tagEff_B0bar_.push_back(nullptr); } } else { //Use average and delta variables tagEff_hist_ave_.push_back(tagEff.first); tagEff_hist_delta_.push_back(tagEff.second); tagEff_ave_.push_back(nullptr); tagEff_delta_.push_back(nullptr); } std::cout<<"INFO in LauFlavTag::addTagger : Added tagger with name "<< name << std::endl; } void LauFlavTag::extendVectors(const TString& tagVarName, const TString& mistagVarName) { tagVarNames_.push_back(tagVarName); mistagVarNames_.push_back(mistagVarName); curEvtTagFlv_.push_back(Flavour::Unknown); - curEvtMistag_.push_back(Flavour::Unknown); + curEvtMistag_.push_back(0.5); if ( not bkgndIndex_.empty() ){ if (!useAveDelta_){ //Loop over the outer vector and extend the inner vectors for (auto& innerVec : tagEffBkgnd_B0_){ innerVec.push_back({nullptr,nullptr,nullptr}); } for (auto& innerVec : tagEffBkgnd_hist_B0_){ innerVec.push_back({nullptr,nullptr,nullptr}); } for (auto& innerVec : tagEffBkgnd_B0bar_){ innerVec.push_back({nullptr,nullptr,nullptr}); } for (auto& innerVec : tagEffBkgnd_hist_B0bar_){ innerVec.push_back({nullptr,nullptr,nullptr}); } } else { //Loop over the outer vector and extend the inner vectors for (auto& innerVec : tagEffBkgnd_ave_){ innerVec.push_back({nullptr,nullptr,nullptr}); } for (auto& innerVec : tagEffBkgnd_hist_ave_){ innerVec.push_back({nullptr,nullptr,nullptr}); } for (auto& innerVec : tagEffBkgnd_delta_){ innerVec.push_back({nullptr,nullptr,nullptr}); } for (auto& innerVec : tagEffBkgnd_hist_delta_){ innerVec.push_back({nullptr,nullptr,nullptr}); } } for (auto& innerVec : etaBkgndPdfs_){ innerVec.push_back({nullptr,nullptr,nullptr}); } for (auto& innerVec : avgMistagBkgnd_){ innerVec.push_back({0.0,0.0,0.0}); } } } void LauFlavTag::setupCalibParams(const TString& taggerName, const std::pair calib_p0, const std::pair calib_p1) { const std::size_t taggerID { taggerIndex_.at( taggerName ) }; if (!useAveDelta_){ TString calib_p0_b0Name("calib_p0_b0_"+taggerName); TString calib_p0_b0barName("calib_p0_b0bar_"+taggerName); TString calib_p1_b0Name("calib_p1_b0_"+taggerName); TString calib_p1_b0barName("calib_p1_b0bar_"+taggerName); LauParameter* calibp0b0 = new LauParameter(calib_p0_b0Name,calib_p0.first,0.0,1.0,kTRUE); calib_p0_B0_.push_back(calibp0b0); calib_p0_B0_[taggerID]->initValue(calib_p0.first); calib_p0_B0_[taggerID]->genValue(calib_p0.first); calib_p0_B0_[taggerID]->fixed(kTRUE); LauParameter* calibp1b0 = new LauParameter(calib_p1_b0Name,calib_p1.first,0.0,2.0,kTRUE); calib_p1_B0_.push_back(calibp1b0); calib_p1_B0_[taggerID]->initValue(calib_p1.first); calib_p1_B0_[taggerID]->genValue(calib_p1.first); calib_p1_B0_[taggerID]->fixed(kTRUE); if (calib_p0.second==-1.0 && calib_p1.second==-1.0){ calib_p0_B0bar_.push_back(calib_p0_B0_[taggerID]->createClone(calib_p0_b0barName)); calib_p1_B0bar_.push_back(calib_p1_B0_[taggerID]->createClone(calib_p1_b0barName)); } else { LauParameter* calibp0b0bar = new LauParameter(calib_p0_b0barName,calib_p0.second,0.0,1.0,kTRUE); calib_p0_B0bar_.push_back(calibp0b0bar); calib_p0_B0bar_[taggerID]->initValue(calib_p0.second); calib_p0_B0bar_[taggerID]->genValue(calib_p0.second); calib_p0_B0bar_[taggerID]->fixed(kTRUE); LauParameter* calibp1b0bar = new LauParameter(calib_p1_b0barName,calib_p1.second,0.0,2.0,kTRUE); calib_p1_B0bar_.push_back(calibp1b0bar); calib_p1_B0bar_[taggerID]->initValue(calib_p1.second); calib_p1_B0bar_[taggerID]->genValue(calib_p1.second); calib_p1_B0bar_[taggerID]->fixed(kTRUE); } } else { //Use average and delta variables TString calib_p0_aveName("calib_p0_ave_"+taggerName); TString calib_p0_deltaName("calib_p0_delta_"+taggerName); TString calib_p1_aveName("calib_p1_ave_"+taggerName); TString calib_p1_deltaName("calib_p1_delta_"+taggerName); LauParameter* calibp0ave = new LauParameter(calib_p0_aveName,calib_p0.first,0.0,1.0,kTRUE); calib_p0_ave_.push_back(calibp0ave); calib_p0_ave_[taggerID]->initValue(calib_p0.first); calib_p0_ave_[taggerID]->genValue(calib_p0.first); calib_p0_ave_[taggerID]->fixed(kTRUE); LauParameter* calibp1ave = new LauParameter(calib_p1_aveName,calib_p1.first,0.0,2.0,kTRUE); calib_p1_ave_.push_back(calibp1ave); calib_p1_ave_[taggerID]->initValue(calib_p1.first); calib_p1_ave_[taggerID]->genValue(calib_p1.first); calib_p1_ave_[taggerID]->fixed(kTRUE); LauParameter* calibp0delta = new LauParameter(calib_p0_deltaName,calib_p0.second,-1.0,1.0,kTRUE); calib_p0_delta_.push_back(calibp0delta); calib_p0_delta_[taggerID]->initValue(calib_p0.second); calib_p0_delta_[taggerID]->genValue(calib_p0.second); calib_p0_delta_[taggerID]->fixed(kTRUE); LauParameter* calibp1delta = new LauParameter(calib_p1_deltaName,calib_p1.second,-1.0,1.0,kTRUE); calib_p1_delta_.push_back(calibp1delta); calib_p1_delta_[taggerID]->initValue(calib_p1.second); calib_p1_delta_[taggerID]->genValue(calib_p1.second); calib_p1_delta_[taggerID]->fixed(kTRUE); } } void LauFlavTag::cacheInputFitVars(LauFitDataTree* inputFitData, const TString& decayTimeVarName) { evtTagFlv_.clear(); evtMistag_.clear(); evtTrueTagFlv_.clear(); evtDecayFlv_.clear(); evtDecayTime_.clear(); // Loop over the taggers to check the branches for (std::size_t i=0; i < tagVarNames_.size(); ++i){ if ( not inputFitData->haveBranch( tagVarNames_[i] ) ) { std::cerr << "ERROR in LauFlavTag::cacheInputFitVars : Input data does not contain branch \"" << tagVarNames_[i] << "\"." << std::endl; gSystem->Exit(EXIT_FAILURE); } if ( not inputFitData->haveBranch( mistagVarNames_[i] ) ) { std::cerr << "ERROR in LauFlavTag::cacheInputFitVars : Input data does not contain branch \"" << mistagVarNames_[i] << "\"." << std::endl; gSystem->Exit(EXIT_FAILURE); } } if ( trueTagVarName_ != "" and not inputFitData->haveBranch( trueTagVarName_ ) ) { std::cerr << "ERROR in LauFlavTag::cacheInputFitVars : Input data does not contain branch \"" << trueTagVarName_ << "\"." << std::endl; gSystem->Exit(EXIT_FAILURE); } if ( decayFlvVarName_ != "" and not inputFitData->haveBranch( decayFlvVarName_ ) ) { std::cerr << "ERROR in LauFlavTag::cacheInputFitVars : Input data does not contain branch \"" << decayFlvVarName_ << "\"." << std::endl; gSystem->Exit(EXIT_FAILURE); } if ( decayTimeVarName != "" and not inputFitData->haveBranch( decayTimeVarName ) ) { std::cerr << "ERROR in LauFlavTag::cacheInputFitVars : Input data does not contain branch \"" << decayTimeVarName << "\"." << std::endl; gSystem->Exit(EXIT_FAILURE); } const std::size_t nEvents { inputFitData->nEvents() }; evtTagFlv_.reserve( nEvents ); evtMistag_.reserve( nEvents ); evtTrueTagFlv_.reserve( nEvents ); evtDecayFlv_.reserve( nEvents ); evtDecayTime_.reserve( nEvents ); LauFitData::const_iterator fitdata_iter; for (std::size_t iEvt = 0; iEvt < nEvents; iEvt++) { const LauFitData& dataValues = inputFitData->getData(iEvt); // For untagged events see if we have a truth tag for normalisation modes Int_t curEvtTrueTagFlv { ( trueTagVarName_ != "" ) ? static_cast( dataValues.at( trueTagVarName_ ) ) : 0 }; if ( curEvtTrueTagFlv > 1 ) { std::cerr << "WARNING in LauFlavTag::cacheInputFitVars : Invalid true tag value " << curEvtTrueTagFlv << " for event " << iEvt << ", setting it to +1" << std::endl; curEvtTrueTagFlv = +1; } else if ( curEvtTrueTagFlv < -1 ){ std::cerr << "WARNING in LauFlavTag::cacheInputFitVars : Invalid true tag value " << curEvtTrueTagFlv << " for event " << iEvt << ", setting it to -1" << std::endl; curEvtTrueTagFlv = -1; } curEvtTrueTagFlv_ = static_cast(curEvtTrueTagFlv); evtTrueTagFlv_.push_back(curEvtTrueTagFlv_); // Flavour at decay // TODO put this in a try catch block current error message is unhelpful if this throws Int_t curEvtDecayFlv { ( decayFlvVarName_ != "" ) ? static_cast( dataValues.at( decayFlvVarName_ ) ) : 0 }; if ( curEvtDecayFlv > 1 ) { std::cerr << "WARNING in LauFlavTag::cacheInputFitVars : Invalid decay flavour value " << curEvtDecayFlv << " for event " << iEvt << ", setting it to +1" << std::endl; curEvtDecayFlv = +1; } else if ( curEvtDecayFlv < -1 ){ std::cerr << "WARNING in LauFlavTag::cacheInputFitVars : Invalid decay flavour value " << curEvtDecayFlv << " for event " << iEvt << ", setting it to -1" << std::endl; curEvtDecayFlv = -1; } curEvtDecayFlv_ = static_cast(curEvtDecayFlv); evtDecayFlv_.push_back(curEvtDecayFlv_); for (std::size_t i=0; i < tagVarNames_.size(); ++i){ Int_t curEvtTagFlv { static_cast( dataValues.at( tagVarNames_[i] ) ) }; if ( curEvtTagFlv > 1 ) { std::cerr << "WARNING in LauFlavTag::cacheInputFitVars : Invalid tagging output " << curEvtTagFlv << " for event " << iEvt << ", setting it to +1" << std::endl; curEvtTagFlv = +1; } else if ( curEvtTagFlv < -1 ) { std::cerr << "WARNING in LauFlavTag::cacheInputFitVars : Invalid tagging output " << curEvtTagFlv << " for event " << iEvt << ", setting it to -1" << std::endl; curEvtTagFlv = -1; } curEvtTagFlv_[i] = static_cast( curEvtTagFlv ); curEvtMistag_[i] = static_cast( dataValues.at( mistagVarNames_[i] ) ); // Calibrated mistag > 0.5 is just a tag flip - handled automatically in getCapitalOmega function if (curEvtMistag_[i] > 0.5){ std::cerr<<"WARNING in LauFlavTag::cacheInputFitVars : Mistag value "<( dataValues.at( decayTimeVarName ) ); evtDecayTime_.push_back(curEvtDecayTime_); } } void LauFlavTag::updateEventInfo(const std::size_t iEvt) { //Assign current event variables curEvtTagFlv_ = evtTagFlv_[iEvt]; curEvtMistag_ = evtMistag_[iEvt]; curEvtTrueTagFlv_ = evtTrueTagFlv_[iEvt]; curEvtDecayFlv_ = evtDecayFlv_[iEvt]; curEvtDecayTime_ = evtDecayTime_[iEvt]; } void LauFlavTag::generateEventInfo(const Flavour trueTagFlv, const Double_t curEvtDecayTime) { curEvtTrueTagFlv_ = trueTagFlv; curEvtDecayFlv_ = Flavour::Unknown; curEvtDecayTime_ = curEvtDecayTime; Double_t randNo{0.0}; Double_t tagEffB0{0.0}; Double_t tagEffB0bar{0.0}; const std::size_t nTaggers { this->getNTaggers() }; for ( std::size_t taggerID{0}; taggerIDgetEtaGen(taggerID); if (this->getUseAveDelta()) { if (tagEff_ave_[taggerID]==nullptr){ const Double_t ave = tagEff_hist_ave_[taggerID]->GetBinContent(tagEff_hist_ave_[taggerID]->FindFixBin(curEvtDecayTime_)); const Double_t delta = tagEff_hist_delta_[taggerID]->GetBinContent(tagEff_hist_delta_[taggerID]->FindFixBin(curEvtDecayTime_)); tagEffB0 = ave + 0.5 * delta; tagEffB0bar = ave - 0.5 * delta; } else { tagEffB0 = tagEff_ave_[taggerID]->unblindValue() + 0.5 * tagEff_delta_[taggerID]->unblindValue(); tagEffB0bar = tagEff_ave_[taggerID]->unblindValue() - 0.5 * tagEff_delta_[taggerID]->unblindValue(); } } else { if (tagEff_B0_[taggerID]==nullptr){ tagEffB0 = tagEff_hist_B0_[taggerID]->GetBinContent(tagEff_hist_B0_[taggerID]->FindFixBin(curEvtDecayTime_)); tagEffB0bar = tagEff_hist_B0bar_[taggerID]->GetBinContent(tagEff_hist_B0bar_[taggerID]->FindFixBin(curEvtDecayTime_)); } else { tagEffB0 = tagEff_B0_[taggerID]->unblindValue(); tagEffB0bar = tagEff_B0bar_[taggerID]->unblindValue(); } } if (curEvtTrueTagFlv_ == Flavour::B) { randNo = LauRandom::randomFun()->Rndm(); // Try to tag in tageff% of cases if (randNo <= tagEffB0) { randNo = LauRandom::randomFun()->Rndm(); // Account for (calibrated) mistag if (randNo > this->getLittleOmega(taggerID, Flavour::B)){ curEvtTagFlv_[taggerID] = Flavour::B; } else { curEvtTagFlv_[taggerID] = Flavour::Bbar; } } else { curEvtTagFlv_[taggerID] = Flavour::Unknown; } } else if (curEvtTrueTagFlv_ == Flavour::Bbar) { randNo = LauRandom::randomFun()->Rndm(); // Try to tag in tageff% of cases if (randNo <= tagEffB0bar) { randNo = LauRandom::randomFun()->Rndm(); // Account for (calibrated) mistag if (randNo > this->getLittleOmega(taggerID, Flavour::Bbar)){ curEvtTagFlv_[taggerID] = Flavour::Bbar; } else { curEvtTagFlv_[taggerID] = Flavour::B; } } else { curEvtTagFlv_[taggerID] = Flavour::Unknown; } } else { std::cerr << "ERROR in LauFlavTag::generateEventInfo : Invalid true tag flavour, should be either B (+1) or Bbar (-1)" << std::endl; gSystem->Exit(EXIT_FAILURE); } } } void LauFlavTag::generateBkgndEventInfo(const std::size_t bkgndID, const Flavour trueTagFlv, const Flavour trueDecayFlv, const Double_t curEvtDecayTime) { if (bkgndID > bkgndIndex_.size()){ std::cerr << "ERROR in LauFlavTag::generateBkgndEventInfo : Invalid backgrond class identifier" << std::endl; gSystem->Exit(EXIT_FAILURE); } curEvtTrueTagFlv_ = trueTagFlv; curEvtDecayFlv_ = trueDecayFlv; curEvtDecayTime_ = curEvtDecayTime; Double_t randNo{0.0}; Double_t tagEffB0{0.0}; Double_t tagEffB0bar{0.0}; const std::size_t nTaggers { this->getNTaggers() }; for ( std::size_t taggerID{0}; taggerID( bkgndDecayFlvDep_[bkgndID] * curEvtDecayFlv_ + 1 ) }; this->getEtaGenBkgnd(taggerID,bkgndID,curEvtDecayFlv_); if (this->getUseAveDelta()) { if (tagEffBkgnd_ave_[bkgndID][taggerID][arrayIndex]==nullptr){ const Double_t ave = tagEffBkgnd_hist_ave_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_ave_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)); const Double_t delta = tagEffBkgnd_hist_delta_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_delta_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)); tagEffB0 = ave + 0.5 * delta; tagEffB0bar = ave - 0.5 * delta; } else { tagEffB0 = tagEffBkgnd_ave_[bkgndID][taggerID][arrayIndex]->unblindValue() + 0.5 * tagEffBkgnd_delta_[bkgndID][taggerID][arrayIndex]->unblindValue(); tagEffB0bar = tagEffBkgnd_ave_[bkgndID][taggerID][arrayIndex]->unblindValue() - 0.5 * tagEffBkgnd_delta_[bkgndID][taggerID][arrayIndex]->unblindValue(); } } else { if (tagEffBkgnd_B0_[bkgndID][taggerID][arrayIndex]==nullptr){ tagEffB0 = tagEffBkgnd_hist_B0_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_B0_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)); tagEffB0bar = tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)); } else { tagEffB0 = tagEffBkgnd_B0_[bkgndID][taggerID][arrayIndex]->unblindValue(); tagEffB0bar = tagEffBkgnd_B0bar_[bkgndID][taggerID][arrayIndex]->unblindValue(); } } if (bkgndTypes_[bkgndID] == BkgndType::Combinatorial){ randNo = LauRandom::randomFun()->Rndm(); if (randNo<=tagEffB0){ curEvtTagFlv_[taggerID] = Flavour::B; } else if(randNo<=(tagEffB0+tagEffB0bar)){ curEvtTagFlv_[taggerID] = Flavour::Bbar; } else { curEvtTagFlv_[taggerID] = Flavour::Unknown; } }else{ if (curEvtTrueTagFlv_ == Flavour::B) { randNo = LauRandom::randomFun()->Rndm(); // Try to tag in tageff% of cases if (randNo <= tagEffB0) { randNo = LauRandom::randomFun()->Rndm(); // Account for (calibrated) mistag if (randNo > this->getLittleOmegaBkgnd(bkgndID, taggerID, Flavour::B, curEvtDecayFlv_)){ curEvtTagFlv_[taggerID] = Flavour::B; } else { curEvtTagFlv_[taggerID] = Flavour::Bbar; } } else { curEvtTagFlv_[taggerID] = Flavour::Unknown; } } else if (curEvtTrueTagFlv_ == Flavour::Bbar) { randNo = LauRandom::randomFun()->Rndm(); // Try to tag in tageff% of cases if (randNo <= tagEffB0bar) { randNo = LauRandom::randomFun()->Rndm(); // Account for (calibrated) mistag if (randNo > this->getLittleOmegaBkgnd(bkgndID, taggerID, Flavour::Bbar, curEvtDecayFlv_)){ curEvtTagFlv_[taggerID] = Flavour::Bbar; } else { curEvtTagFlv_[taggerID] = Flavour::B; } } else { curEvtTagFlv_[taggerID] = Flavour::Unknown; } } else { std::cerr << "ERROR in LauFlavTag::generateBkgndEventInfo : Invalid true tag flavour, should be either B (+1) or Bbar (-1)" << std::endl; gSystem->Exit(EXIT_FAILURE); } } } } Double_t LauFlavTag::getLittleOmega(const std::size_t taggerID, const Flavour flag) const { if ( flag == Flavour::Unknown ){ std::cerr << "ERROR in LauFlavTag::getLittleOmega : Invalid flag, you must request either omega (+1) or omega bar (-1) to be returned" << std::endl; return 0.0; } Double_t calibp0(0.), calibp1(0.), calibp0bar(0.), calibp1bar(0.); //If we are floating average omega and delta omega we need to use those parameters instead if (useAveDelta_){ calibp0 = calib_p0_ave_[taggerID]->unblindValue() + 0.5*calib_p0_delta_[taggerID]->unblindValue(); calibp0bar = calib_p0_ave_[taggerID]->unblindValue() - 0.5*calib_p0_delta_[taggerID]->unblindValue(); calibp1 = calib_p1_ave_[taggerID]->unblindValue() + 0.5*calib_p1_delta_[taggerID]->unblindValue(); calibp1bar = calib_p1_ave_[taggerID]->unblindValue() - 0.5*calib_p1_delta_[taggerID]->unblindValue(); } else { calibp0 = calib_p0_B0_[taggerID]->unblindValue(); calibp0bar = calib_p0_B0bar_[taggerID]->unblindValue(); calibp1 = calib_p1_B0_[taggerID]->unblindValue(); calibp1bar = calib_p1_B0bar_[taggerID]->unblindValue(); } if ( flag == Flavour::B ){ return calibp0 + calibp1 * (curEvtMistag_[taggerID] - perEvtAvgMistag_[taggerID]); } else{ return calibp0bar + calibp1bar * (curEvtMistag_[taggerID] - perEvtAvgMistag_[taggerID]); } return 0.0; } Double_t LauFlavTag::getCapitalOmega(const std::size_t taggerID, const Flavour flag) const { if ( flag == Flavour::Unknown ){ std::cerr << "ERROR in LauFlavTag::getCapitalOmega : Invalid flag, you must request either Omega (+1) or Omega bar (-1) to be returned" << std::endl; return 0.0; } //Delta functions to control which terms contribute const bool delta_p1 { curEvtTagFlv_[taggerID] == Flavour::B }; const bool delta_m1 { curEvtTagFlv_[taggerID] == Flavour::Bbar }; const bool delta_0 { curEvtTagFlv_[taggerID] == Flavour::Unknown }; //Efficiency Double_t eff{0.0}; if (useAveDelta_){ if(flag==Flavour::B){ if (tagEff_ave_[taggerID]==nullptr){ eff = tagEff_hist_ave_[taggerID]->GetBinContent(tagEff_hist_ave_[taggerID]->FindFixBin(curEvtDecayTime_)) + 0.5*tagEff_hist_delta_[taggerID]->GetBinContent(tagEff_hist_delta_[taggerID]->FindFixBin(curEvtDecayTime_)); } else { eff = tagEff_ave_[taggerID]->unblindValue() + 0.5*tagEff_delta_[taggerID]->unblindValue(); } } else { if (tagEff_ave_[taggerID]==nullptr){ eff = tagEff_hist_ave_[taggerID]->GetBinContent(tagEff_hist_ave_[taggerID]->FindFixBin(curEvtDecayTime_)) - 0.5*tagEff_hist_delta_[taggerID]->GetBinContent(tagEff_hist_delta_[taggerID]->FindFixBin(curEvtDecayTime_)); } else { eff = tagEff_ave_[taggerID]->unblindValue() - 0.5*tagEff_delta_[taggerID]->unblindValue(); } } }else{ if(flag==Flavour::B){ if (tagEff_B0_[taggerID]==nullptr){ eff = tagEff_hist_B0_[taggerID]->GetBinContent(tagEff_hist_B0_[taggerID]->FindFixBin(curEvtDecayTime_)); } else { eff = tagEff_B0_[taggerID]->unblindValue(); } }else{ if (tagEff_B0bar_[taggerID]==nullptr){ eff = tagEff_hist_B0bar_[taggerID]->GetBinContent(tagEff_hist_B0bar_[taggerID]->FindFixBin(curEvtDecayTime_)); } else { eff = tagEff_B0bar_[taggerID]->unblindValue(); } } } //Little omega const Double_t omega { this->getLittleOmega(taggerID, flag) }; //Transform to omega prime - TODO isn't this the inverse, getLittleOmega is actually giving us omegaPrime and on the next line we convert back to omega? Double_t omegaPrime { useEtaPrime_ ? (1.0/(1.0+TMath::Exp(-1.0*omega))) : omega }; //little omega must be between 0 and 1. Force this for now, if the fits keep getting stuck can look more closely at it. static Bool_t tooSmallWarningIssued {kFALSE}; static Bool_t tooLargeWarningIssued {kFALSE}; if (omegaPrime < 0.0){ if ( not tooSmallWarningIssued ) { std::cerr << "WARNING in LauFlavTag::getCapitalOmega : The value of little omega is less than 0, shifting to 0\n"; std::cerr << " : Further WARNINGs of this type will be suppressed" << std::endl; tooSmallWarningIssued = kTRUE; } omegaPrime = 0.0; } if (omegaPrime > 1.0){ if ( not tooLargeWarningIssued ) { std::cerr << "WARNING in LauFlavTag::getCapitalOmega : The value of little omega is greater than 1, shifting to 1\n"; std::cerr << " : Further WARNINGs of this type will be suppressed" << std::endl; tooLargeWarningIssued = kTRUE; } omegaPrime = 1.0; } //eta PDF value const std::vector abs { curEvtMistag_[taggerID] }; etaPdfs_[taggerID]->calcLikelihoodInfo(abs); const Double_t h { etaPdfs_[taggerID]->getLikelihood() }; const Double_t u { 2.0 }; // the PDF value for a uniform PDF between 0.0 and 0.5 //If h returns 0 for a tagged event, the event likelihood will be zero, so we should warn that this is where the problem lies if (h==0.0 && not delta_0){ std::cerr << "WARNING in LauFlavTag::getCapitalOmega : The value of the signal eta PDF is zero at eta = " << curEvtMistag_[taggerID] << std::endl; return 0.0; } //Put it together if (flag == Flavour::B){ return (delta_p1*eff*(1.0-omegaPrime) + delta_m1*eff*omegaPrime)*h + delta_0*(1.0-eff)*u; } else { return (delta_m1*eff*(1.0-omegaPrime) + delta_p1*eff*omegaPrime)*h + delta_0*(1.0-eff)*u; } } Double_t LauFlavTag::getLittleOmegaBkgnd(const std::size_t bkgndID, const std::size_t taggerID, const Flavour flag, const Flavour decayFlv) const { if ( flag == Flavour::Unknown ){ std::cerr << "ERROR in LauFlavTag::getLittleOmegaBkgnd : Invalid flag, you must request either omega (+1) or omega bar (-1) to be returned" << std::endl; return 0.0; } Double_t calibp0(0.), calibp1(0.), calibp0bar(0.), calibp1bar(0.); //If we are floating average omega and delta omega we need to use those parameters instead if (useAveDelta_){ calibp0 = calib_p0_ave_[taggerID]->unblindValue() + 0.5*calib_p0_delta_[taggerID]->unblindValue(); calibp0bar = calib_p0_ave_[taggerID]->unblindValue() - 0.5*calib_p0_delta_[taggerID]->unblindValue(); calibp1 = calib_p1_ave_[taggerID]->unblindValue() + 0.5*calib_p1_delta_[taggerID]->unblindValue(); calibp1bar = calib_p1_ave_[taggerID]->unblindValue() - 0.5*calib_p1_delta_[taggerID]->unblindValue(); } else { calibp0 = calib_p0_B0_[taggerID]->unblindValue(); calibp0bar = calib_p0_B0bar_[taggerID]->unblindValue(); calibp1 = calib_p1_B0_[taggerID]->unblindValue(); calibp1bar = calib_p1_B0bar_[taggerID]->unblindValue(); } const std::size_t arrayIndex { static_cast( bkgndDecayFlvDep_[bkgndID] * decayFlv + 1 ) }; if ( flag == Flavour::B ){ return calibp0 + calibp1 * (curEvtMistag_[taggerID] - avgMistagBkgnd_[bkgndID][taggerID][arrayIndex]); } else{ return calibp0bar + calibp1bar * (curEvtMistag_[taggerID] - avgMistagBkgnd_[bkgndID][taggerID][arrayIndex]); } return 0.0; } Double_t LauFlavTag::getCapitalOmegaBkgnd(const std::size_t bkgndID, const std::size_t taggerID, const Flavour flag, const Flavour decayFlv) const { //Delta functions to control which terms contribute const bool delta_p1 { curEvtTagFlv_[taggerID] == Flavour::B }; const bool delta_m1 { curEvtTagFlv_[taggerID] == Flavour::Bbar }; const bool delta_0 { curEvtTagFlv_[taggerID] == Flavour::Unknown }; //Use the right histograms/parameters depending on the decay flavour const std::size_t arrayIndex { static_cast( bkgndDecayFlvDep_[bkgndID] * decayFlv + 1 ) }; //Efficiency Double_t effB0{0.0}, effB0bar{0.0}; if (useAveDelta_){ if (tagEffBkgnd_ave_[bkgndID][taggerID][arrayIndex]==nullptr){ effB0 = tagEffBkgnd_hist_ave_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_ave_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)) + 0.5*tagEffBkgnd_hist_delta_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_delta_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)); effB0bar = tagEffBkgnd_hist_ave_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_ave_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)) - 0.5*tagEffBkgnd_hist_delta_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_delta_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)); } else { effB0 = tagEffBkgnd_ave_[bkgndID][taggerID][arrayIndex]->unblindValue() + 0.5*tagEffBkgnd_delta_[bkgndID][taggerID][arrayIndex]->unblindValue(); effB0bar = tagEffBkgnd_ave_[bkgndID][taggerID][arrayIndex]->unblindValue() - 0.5*tagEffBkgnd_delta_[bkgndID][taggerID][arrayIndex]->unblindValue(); } }else{ if (tagEffBkgnd_B0_[bkgndID][taggerID][arrayIndex]==nullptr){ effB0 = tagEffBkgnd_hist_B0_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_B0_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)); effB0bar = tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][arrayIndex]->GetBinContent(tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][arrayIndex]->FindFixBin(curEvtDecayTime_)); } else { effB0 = tagEffBkgnd_B0_[bkgndID][taggerID][arrayIndex]->unblindValue(); effB0bar = tagEffBkgnd_B0bar_[bkgndID][taggerID][arrayIndex]->unblindValue(); } } //Need to know which background eta PDF to use - bkgndID const std::vector abs { curEvtMistag_[taggerID] }; etaBkgndPdfs_[bkgndID][taggerID][arrayIndex]->calcLikelihoodInfo(abs); const Double_t h { etaBkgndPdfs_[bkgndID][taggerID][arrayIndex]->getLikelihood() }; const Double_t u { 2.0 }; // the PDF value for a uniform PDF between 0.0 and 0.5 switch ( bkgndTypes_[bkgndID] ) { case BkgndType::Combinatorial : // Combinatorial efficiences are defined differently // effB0 - chance to tag any combinatorial event as a B0 // effB0bar - chance to tag any combinatorial event as a B0bar return (delta_p1*effB0 + delta_m1*effB0bar)*h + delta_0*(1.0 - effB0 - effB0bar)*u; case BkgndType::FlavourSpecific : case BkgndType::SelfConjugate : case BkgndType::NonSelfConjugate : { if ( flag == Flavour::Unknown ){ std::cerr << "ERROR in LauFlavTag::getCapitalOmegaBkgnd : Invalid flag, you must request either Omega (+1) or Omega bar (-1) to be returned" << std::endl; return 0.0; } const Double_t omega { this->getLittleOmegaBkgnd(bkgndID, taggerID, flag, decayFlv) }; //Transform to omega prime - TODO isn't this the inverse, getLittleOmega is actually giving us omegaPrime and on the next line we convert back to omega? Double_t omegaPrime { useEtaPrime_ ? (1.0/(1.0+TMath::Exp(-1.0*omega))) : omega }; //little omega must be between 0 and 1. Force this for now, if the fits keep getting stuck can look more closely at it. static Bool_t tooSmallWarningIssued {kFALSE}; static Bool_t tooLargeWarningIssued {kFALSE}; if (omegaPrime < 0.0){ if ( not tooSmallWarningIssued ) { std::cerr << "WARNING in LauFlavTag::getCapitalOmegaBkgnd : The value of little omega is less than 0, shifting to 0\n"; std::cerr << " : Further WARNINGs of this type will be suppressed" << std::endl; tooSmallWarningIssued = kTRUE; } omegaPrime = 0.0; } if (omegaPrime > 1.0){ if ( not tooLargeWarningIssued ) { std::cerr << "WARNING in LauFlavTag::getCapitalOmegaBkgnd : The value of little omega is greater than 1, shifting to 1\n"; std::cerr << " : Further WARNINGs of this type will be suppressed" << std::endl; tooLargeWarningIssued = kTRUE; } omegaPrime = 1.0; } if (flag == Flavour::B){ return (delta_p1*effB0*(1.0-omegaPrime) + delta_m1*effB0*omegaPrime)*h + delta_0*(1.0-effB0)*u; } else { return (delta_m1*effB0bar*(1.0-omegaPrime) + delta_p1*effB0bar*omegaPrime)*h + delta_0*(1.0-effB0bar)*u; } } } //Should never get here, but it keeps GCC happy return 0.0; } void LauFlavTag::setBkgndParams(const TString& bkgndName, const TString& taggerName, LauAbsPdf* etaPdf, const std::pair tagEff) { if ( bkgndIndex_.count(bkgndName) == 0 ) { std::cerr << "ERROR in LauFlavTag::setBkgndParams : Background name \"" << bkgndName << "\" not recognised please check your options" << std::endl; return; } if ( taggerIndex_.count(taggerName) == 0 ){ std::cerr << "ERROR in LauFlavTag::setBkgndParams : Tagger name \"" << taggerName << "\" not recognised please check your options" << std::endl; return; } const std::size_t bkgndID { bkgndIndex_.at(bkgndName) }; const std::size_t taggerID { taggerIndex_.at(taggerName) }; bkgndDecayFlvDep_[bkgndID] = false; etaBkgndPdfs_[bkgndID][taggerID][0] = nullptr; etaBkgndPdfs_[bkgndID][taggerID][1] = etaPdf; etaBkgndPdfs_[bkgndID][taggerID][2] = nullptr; Lau1DHistPdf* etahistpdf = dynamic_cast(etaPdf); if (etahistpdf){ avgMistagBkgnd_[bkgndID][taggerID][0] = 0.0; avgMistagBkgnd_[bkgndID][taggerID][1] = etahistpdf->getMean(); avgMistagBkgnd_[bkgndID][taggerID][2] = 0.0; } else { std::cerr << "WARNING in LauFlavTag::setBkgndParams : Couldn't determine average eta value from PDF. Setting it to 0.4." << std::endl; avgMistagBkgnd_[bkgndID][taggerID][0] = 0.0; avgMistagBkgnd_[bkgndID][taggerID][1] = 0.4; avgMistagBkgnd_[bkgndID][taggerID][2] = 0.0; } if (useAveDelta_){ const TString tagEff_aveName{"tagEff_ave_"+taggerName+"_bkgnd_"+bkgndName}; const TString tagEff_deltaName{"tagEff_delta_"+taggerName+"_bkgnd_"+bkgndName}; tagEffBkgnd_ave_[bkgndID][taggerID][0] = nullptr; tagEffBkgnd_delta_[bkgndID][taggerID][0] = nullptr; tagEffBkgnd_ave_[bkgndID][taggerID][1] = new LauParameter{tagEff_aveName, tagEff.first, 0.0, 1.0, kTRUE}; tagEffBkgnd_delta_[bkgndID][taggerID][1] = new LauParameter{tagEff_deltaName, tagEff.second, -1.0, 1.0, kTRUE}; tagEffBkgnd_ave_[bkgndID][taggerID][2] = nullptr; tagEffBkgnd_delta_[bkgndID][taggerID][2] = nullptr; } else { const TString tagEff_b0Name{"tagEff_b0_"+taggerName+"_bkgnd_"+bkgndName}; const TString tagEff_b0barName{"tagEff_b0bar_"+taggerName+"_bkgnd_"+bkgndName}; tagEffBkgnd_B0_[bkgndID][taggerID][0] = nullptr; tagEffBkgnd_B0bar_[bkgndID][taggerID][0] = nullptr; tagEffBkgnd_B0_[bkgndID][taggerID][1] = new LauParameter{tagEff_b0Name, tagEff.first, 0.0, 1.0, kTRUE}; tagEffBkgnd_B0bar_[bkgndID][taggerID][1] = new LauParameter{tagEff_b0barName, tagEff.second, 0.0, 1.0, kTRUE}; tagEffBkgnd_B0_[bkgndID][taggerID][2] = nullptr; tagEffBkgnd_B0bar_[bkgndID][taggerID][2] = nullptr; } std::cout << "INFO in LauFlavTag::setBkgndParams : Added efficiency parameters and eta PDF for background " << bkgndName << " for tagger " << taggerName << std::endl; } void LauFlavTag::setBkgndParams(const TString& bkgndName, const TString& taggerName, LauAbsPdf* etaPdfB, std::pair tagEffB, LauAbsPdf* etaPdfBbar, std::pair tagEffBbar) { if ( bkgndIndex_.count(bkgndName) == 0 ) { std::cerr << "ERROR in LauFlavTag::setBkgndParams : Background name \"" << bkgndName << "\" not recognised please check your options" << std::endl; return; } if ( taggerIndex_.count(taggerName) == 0 ){ std::cerr << "ERROR in LauFlavTag::setBkgndParams : Tagger name \"" << taggerName << "\" not recognised please check your options" << std::endl; return; } const std::size_t bkgndID { bkgndIndex_.at(bkgndName) }; const std::size_t taggerID { taggerIndex_.at(taggerName) }; bkgndDecayFlvDep_[bkgndID] = true; etaBkgndPdfs_[bkgndID][taggerID][0] = etaPdfBbar; Lau1DHistPdf* etahistpdf = dynamic_cast(etaPdfBbar); if (etahistpdf){ avgMistagBkgnd_[bkgndID][taggerID][0] = etahistpdf->getMean(); } else { std::cerr << "WARNING in LauFlavTag::setBkgndParams : Couldn't determine average eta value from PDF. Setting it to 0.4." << std::endl; avgMistagBkgnd_[bkgndID][taggerID][0] = 0.4; } etaBkgndPdfs_[bkgndID][taggerID][1] = nullptr; avgMistagBkgnd_[bkgndID][taggerID][1] = 0.0; etaBkgndPdfs_[bkgndID][taggerID][2] = etaPdfB; etahistpdf = dynamic_cast(etaPdfB); if (etahistpdf){ avgMistagBkgnd_[bkgndID][taggerID][2] = etahistpdf->getMean(); } else { std::cerr << "WARNING in LauFlavTag::setBkgndParams : Couldn't determine average eta value from PDF. Setting it to 0.4." << std::endl; avgMistagBkgnd_[bkgndID][taggerID][2] = 0.4; } if (useAveDelta_){ TString tagEff_aveName { "tagEff_ave_decayFlvB0bar_"+taggerName+"_bkgnd_"+bkgndName }; TString tagEff_deltaName { "tagEff_delta_decayFlvB0bar_"+taggerName+"_bkgnd_"+bkgndName }; tagEffBkgnd_ave_[bkgndID][taggerID][0] = new LauParameter{tagEff_aveName, tagEffBbar.first, 0.0, 1.0, kTRUE}; tagEffBkgnd_delta_[bkgndID][taggerID][0] = new LauParameter{tagEff_deltaName, tagEffBbar.second, -1.0, 1.0, kTRUE}; tagEffBkgnd_ave_[bkgndID][taggerID][1] = nullptr; tagEffBkgnd_delta_[bkgndID][taggerID][1] = nullptr; tagEff_aveName = "tagEff_ave_decayFlvB0_"+taggerName+"_bkgnd_"+bkgndName; tagEff_deltaName = "tagEff_delta_decayFlvB0_"+taggerName+"_bkgnd_"+bkgndName; tagEffBkgnd_ave_[bkgndID][taggerID][2] = new LauParameter{tagEff_aveName, tagEffB.first, 0.0, 1.0, kTRUE}; tagEffBkgnd_delta_[bkgndID][taggerID][2] = new LauParameter{tagEff_deltaName, tagEffB.second, -1.0, 1.0, kTRUE}; } else { TString tagEff_b0Name { "tagEff_b0_decayFlvB0bar_"+taggerName+"_bkgnd_"+bkgndName }; TString tagEff_b0barName { "tagEff_b0bar_decayFlvB0bar_"+taggerName+"_bkgnd_"+bkgndName }; tagEffBkgnd_B0_[bkgndID][taggerID][0] = new LauParameter{tagEff_b0Name, tagEffBbar.first, 0.0, 1.0, kTRUE}; tagEffBkgnd_B0bar_[bkgndID][taggerID][0] = new LauParameter{tagEff_b0barName, tagEffBbar.second, 0.0, 1.0, kTRUE}; tagEffBkgnd_B0_[bkgndID][taggerID][1] = nullptr; tagEffBkgnd_B0bar_[bkgndID][taggerID][1] = nullptr; tagEff_b0Name = "tagEff_b0_decayFlvB0_"+taggerName+"_bkgnd_"+bkgndName; tagEff_b0barName = "tagEff_b0bar_decayFlvB0_"+taggerName+"_bkgnd_"+bkgndName; tagEffBkgnd_B0_[bkgndID][taggerID][2] = new LauParameter{tagEff_b0Name, tagEffB.first, 0.0, 1.0, kTRUE}; tagEffBkgnd_B0bar_[bkgndID][taggerID][2] = new LauParameter{tagEff_b0barName, tagEffB.second, 0.0, 1.0, kTRUE}; } std::cout << "INFO in LauFlavTag::setBkgndParams : Added efficiency parameters and eta PDF for background " << bkgndName << " for tagger " << taggerName << std::endl; } void LauFlavTag::setBkgndParams(const TString& bkgndName, const TString& taggerName, LauAbsPdf* etaPdf, std::pair tagEff) { if ( bkgndIndex_.count(bkgndName) == 0 ) { std::cerr << "ERROR in LauFlavTag::setBkgndParams : Background name \"" << bkgndName << "\" not recognised please check your options" << std::endl; return; } if (taggerIndex_.count(taggerName)==0){ std::cerr << "ERROR in LauFlavTag::setBkgndParams : Tagger name \"" << taggerName << "\" not recognised please check your options" << std::endl; return; } if (tagEff.first==nullptr || tagEff.second==nullptr){ std::cerr << "ERROR in LauFlavTag::setBkgndParams : Efficiency histogram(s) do not exist please check your options" << std::endl; return; } const std::size_t bkgndID { bkgndIndex_.at(bkgndName) }; const std::size_t taggerID { taggerIndex_.at(taggerName) }; bkgndDecayFlvDep_[bkgndID] = false; etaBkgndPdfs_[bkgndID][taggerID][0] = nullptr; etaBkgndPdfs_[bkgndID][taggerID][1] = etaPdf; etaBkgndPdfs_[bkgndID][taggerID][2] = nullptr; Lau1DHistPdf* etahistpdf = dynamic_cast(etaPdf); if (etahistpdf){ avgMistagBkgnd_[bkgndID][taggerID][0] = 0.0; avgMistagBkgnd_[bkgndID][taggerID][1] = etahistpdf->getMean(); avgMistagBkgnd_[bkgndID][taggerID][2] = 0.0; } else { std::cerr << "WARNING in LauFlavTag::setBkgndParams : Couldn't determine average eta value from PDF. Setting it to 0.4." << std::endl; avgMistagBkgnd_[bkgndID][taggerID][0] = 0.0; avgMistagBkgnd_[bkgndID][taggerID][1] = 0.4; avgMistagBkgnd_[bkgndID][taggerID][2] = 0.0; } if (useAveDelta_){ tagEffBkgnd_hist_ave_[bkgndID][taggerID][0] = nullptr; tagEffBkgnd_hist_delta_[bkgndID][taggerID][0] = nullptr; tagEffBkgnd_hist_ave_[bkgndID][taggerID][1] = tagEff.first; tagEffBkgnd_hist_delta_[bkgndID][taggerID][1] = tagEff.second; tagEffBkgnd_hist_ave_[bkgndID][taggerID][2] = nullptr; tagEffBkgnd_hist_delta_[bkgndID][taggerID][2] = nullptr; } else { tagEffBkgnd_hist_B0_[bkgndID][taggerID][0] = nullptr; tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][0] = nullptr; tagEffBkgnd_hist_B0_[bkgndID][taggerID][1] = tagEff.first; tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][1] = tagEff.second; tagEffBkgnd_hist_B0_[bkgndID][taggerID][2] = nullptr; tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][2] = nullptr; } std::cout << "INFO in LauFlavTag::setBkgndParams : Added efficiency histograms and eta PDF for background " << bkgndName << " for tagger " << taggerName << std::endl; } void LauFlavTag::setBkgndParams(const TString& bkgndName, const TString& taggerName, LauAbsPdf* etaPdfB, std::pair tagEffB, LauAbsPdf* etaPdfBbar, std::pair tagEffBbar) { if ( bkgndIndex_.count(bkgndName) == 0 ) { std::cerr << "ERROR in LauFlavTag::setBkgndParams : Background name \"" << bkgndName << "\" not recognised please check your options" << std::endl; return; } if (taggerIndex_.count(taggerName)==0){ std::cerr << "ERROR in LauFlavTag::setBkgndParams : Tagger name \"" << taggerName << "\" not recognised please check your options" << std::endl; return; } if (tagEffB.first==nullptr || tagEffB.second==nullptr || tagEffBbar.first==nullptr || tagEffBbar.second==nullptr){ std::cerr << "ERROR in LauFlavTag::setBkgndParams : Efficiency histogram(s) do not exist please check your options" << std::endl; return; } const std::size_t bkgndID { bkgndIndex_.at(bkgndName) }; const std::size_t taggerID { taggerIndex_.at(taggerName) }; bkgndDecayFlvDep_[bkgndID] = true; etaBkgndPdfs_[bkgndID][taggerID][0] = etaPdfBbar; Lau1DHistPdf* etahistpdf = dynamic_cast(etaPdfBbar); if (etahistpdf){ avgMistagBkgnd_[bkgndID][taggerID][0] = etahistpdf->getMean(); } else { std::cerr << "WARNING in LauFlavTag::setBkgndParams : Couldn't determine average eta value from PDF. Setting it to 0.4." << std::endl; avgMistagBkgnd_[bkgndID][taggerID][0] = 0.4; } etaBkgndPdfs_[bkgndID][taggerID][1] = nullptr; avgMistagBkgnd_[bkgndID][taggerID][1] = 0.0; etaBkgndPdfs_[bkgndID][taggerID][2] = etaPdfB; etahistpdf = dynamic_cast(etaPdfB); if (etahistpdf){ avgMistagBkgnd_[bkgndID][taggerID][2] = etahistpdf->getMean(); } else { std::cerr << "WARNING in LauFlavTag::setBkgndParams : Couldn't determine average eta value from PDF. Setting it to 0.4." << std::endl; avgMistagBkgnd_[bkgndID][taggerID][2] = 0.4; } if (useAveDelta_){ tagEffBkgnd_hist_ave_[bkgndID][taggerID][0] = tagEffBbar.first; tagEffBkgnd_hist_delta_[bkgndID][taggerID][0] = tagEffBbar.second; tagEffBkgnd_hist_ave_[bkgndID][taggerID][1] = nullptr; tagEffBkgnd_hist_delta_[bkgndID][taggerID][1] = nullptr; tagEffBkgnd_hist_ave_[bkgndID][taggerID][2] = tagEffB.first; tagEffBkgnd_hist_delta_[bkgndID][taggerID][2] = tagEffB.second; } else { tagEffBkgnd_hist_B0_[bkgndID][taggerID][0] = tagEffBbar.first; tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][0] = tagEffBbar.second; tagEffBkgnd_hist_B0_[bkgndID][taggerID][1] = nullptr; tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][1] = nullptr; tagEffBkgnd_hist_B0_[bkgndID][taggerID][2] = tagEffB.first; tagEffBkgnd_hist_B0bar_[bkgndID][taggerID][2] = tagEffB.second; } std::cout << "INFO in LauFlavTag::setBkgndParams : Added efficiency histograms and eta PDF for background " << bkgndName << " for tagger " << taggerName << std::endl; } Double_t LauFlavTag::getEtaGen(const std::size_t taggerID) { const LauFitData data { etaPdfs_[taggerID]->generate(nullptr) }; Double_t etagen { data.at(etaPdfs_[taggerID]->varName()) }; if (etagen > 0.5){etagen = 0.5;} if (etagen < 0.0){etagen = 0.0;} curEvtMistag_[taggerID] = etagen; return etagen; } Double_t LauFlavTag::getEtaGenBkgnd(const std::size_t taggerID, const std::size_t bkgndID, const Flavour decayFlv) { const std::size_t arrayIndex { static_cast( bkgndDecayFlvDep_[bkgndID] * decayFlv + 1 ) }; const LauFitData data { etaBkgndPdfs_[bkgndID][taggerID][arrayIndex]->generate(nullptr) }; Double_t etagen { data.at(etaBkgndPdfs_[bkgndID][taggerID][arrayIndex]->varName()) }; if (etagen > 0.5){etagen = 0.5;} if (etagen < 0.0){etagen = 0.0;} curEvtMistag_[taggerID] = etagen; return etagen; } void LauFlavTag::setTrueTagVarName(TString trueTagVarName) { trueTagVarName_ = std::move(trueTagVarName); } void LauFlavTag::setDecayFlvVarName(TString decayFlvVarName) { decayFlvVarName_ = std::move(decayFlvVarName); } void LauFlavTag::addP0GaussianConstraints(const TString& taggerName, const std::pair constraint1, const std::pair constraint2) { // Does key exist? if (taggerIndex_.count(taggerName)==0){ std::cerr << "ERROR in LauFlavTag::addP0GaussianConstraints : Tagger name not recognised please check your options" << std::endl; std::cerr << "ERROR in LauFlavTag::addP0GaussianConstraints : Constraints have not been applied" << std::endl; return; } // Find index in the vectors from the tagger name const std::size_t pos { taggerIndex_.at(taggerName) }; if (!useAveDelta_){ calib_p0_B0_[pos]->addGaussianConstraint(constraint1.first,constraint1.second); calib_p0_B0bar_[pos]->addGaussianConstraint(constraint2.first,constraint2.second); }else{ calib_p0_ave_[pos]->addGaussianConstraint(constraint1.first,constraint1.second); calib_p0_delta_[pos]->addGaussianConstraint(constraint2.first,constraint2.second); } std::cout << "INFO in LauFlavTag::addP0GaussianConstraints : Added Gaussian constraints for the P0 calibration parameters of tagger " << taggerName << std::endl; } void LauFlavTag::addP1GaussianConstraints(const TString& taggerName, const std::pair constraint1, const std::pair constraint2) { // Does key exist? if (taggerIndex_.count(taggerName)==0){ std::cerr << "ERROR in LauFlavTag::addP1GaussianConstraints : Tagger name not recognised please check your options" << std::endl; std::cerr << "ERROR in LauFlavTag::addP1GaussianConstraints : Constraints have not been applied" << std::endl; return; } // Find index in the vector from the tagger name const std::size_t pos { taggerIndex_.at(taggerName) }; if (!useAveDelta_){ calib_p1_B0_[pos]->addGaussianConstraint(constraint1.first,constraint1.second); calib_p1_B0bar_[pos]->addGaussianConstraint(constraint2.first,constraint2.second); }else{ calib_p1_ave_[pos]->addGaussianConstraint(constraint1.first,constraint1.second); calib_p1_delta_[pos]->addGaussianConstraint(constraint2.first,constraint2.second); } std::cout << "INFO in LauFlavTag::addP1GaussianConstraints : Added Gaussian constraints for the P1 calibration parameters of tagger " << taggerName << std::endl; } void LauFlavTag::addTagEffGaussianConstraints(const TString& taggerName, const std::pair constraint1, const std::pair constraint2) { // Does key exist? if (taggerIndex_.count(taggerName)==0){ std::cerr << "ERROR in LauFlavTag::addTagEffGaussianConstraints : Tagger name not recognised please check your options" << std::endl; std::cerr << "ERROR in LauFlavTag::addTagEffGaussianConstraints : Constraints have not been applied" << std::endl; return; } // Find index in the vector from the tagger name const std::size_t pos { taggerIndex_.at(taggerName) }; if (tagEff_B0_[pos] == nullptr){ std::cerr << "ERROR in LauFlavTag::addTagEffGaussianConstraints : Cannot add Gaussian constraints to a histogram!" << std::endl; return; } if (!useAveDelta_){ tagEff_B0_[pos]->addGaussianConstraint(constraint1.first,constraint1.second); tagEff_B0bar_[pos]->addGaussianConstraint(constraint2.first,constraint2.second); }else{ tagEff_ave_[pos]->addGaussianConstraint(constraint1.first,constraint1.second); tagEff_delta_[pos]->addGaussianConstraint(constraint2.first,constraint2.second); } std::cout << "INFO in LauFlavTag::addTagEffGaussianConstraints : Added Gaussian constraints for the tagging efficiency parameters of tagger " << taggerName << std::endl; } LauParameter* LauFlavTag::findParameter( const TString& taggerName, std::vector& parameters ) { // Check the tagger name is valid auto iter = taggerIndex_.find(taggerName); if ( iter == taggerIndex_.end() ){ return nullptr; } // If so, find the appropriate parameter const std::size_t index { iter->second }; return parameters[index]; } void LauFlavTag::floatCalibParP0B0(const TString& taggerName) { if (useAveDelta_){ std::cerr << "ERROR in LauFlavTag::floatCalibParP0B0 : Trying to set calibration parameters for B0/B0bar not average/delta" << std::endl; return; } if (taggerName==""){ // Float parameters for all taggers for (auto& param : calib_p0_B0_){ if (param==nullptr){continue;} param->fixed(kFALSE); } return; } // Float parameter for requested tagger LauParameter* par { this->findParameter( taggerName, calib_p0_B0_ ) }; if ( not par ){ std::cerr << "ERROR in LauFlavTag::floatCalibParP0B0 : Tagger name not recognised please check your options" << std::endl; return; } par->fixed(kFALSE); } void LauFlavTag::floatCalibParP1B0(const TString& taggerName) { if (useAveDelta_){ std::cerr << "ERROR in LauFlavTag::floatCalibParP1B0 : Trying to set calibration parameters for B0/B0bar not average/delta" << std::endl; return; } if (taggerName==""){ // Float parameters for all taggers for (auto& param : calib_p1_B0_){ if (param==nullptr){continue;} param->fixed(kFALSE); } return; } // Float parameter for requested tagger LauParameter* par { this->findParameter( taggerName, calib_p1_B0_ ) }; if ( not par ){ std::cerr << "ERROR in LauFlavTag::floatCalibParP1B0 : Tagger name not recognised please check your options" << std::endl; return; } par->fixed(kFALSE); } void LauFlavTag::floatCalibParP0B0bar(const TString& taggerName) { if (useAveDelta_){ std::cerr << "ERROR in LauFlavTag::floatCalibParP0B0bar : Trying to set calibration parameters for B0/B0bar not average/delta" << std::endl; return; } if (taggerName==""){ // Float parameters for all taggers for (auto& param : calib_p0_B0bar_){ if (param==nullptr){continue;} param->fixed(kFALSE); } return; } // Float parameter for requested tagger LauParameter* par { this->findParameter( taggerName, calib_p0_B0bar_ ) }; if ( not par ) { std::cerr << "ERROR in LauFlavTag::floatCalibParP0B0bar : Tagger name not recognised please check your options" << std::endl; return; } par->fixed(kFALSE); } void LauFlavTag::floatCalibParP1B0bar(const TString& taggerName) { if (useAveDelta_){ std::cerr << "ERROR in LauFlavTag::floatCalibParP1B0bar : Trying to set calibration parameters for B0/B0bar not average/delta" << std::endl; return; } if (taggerName==""){ // Float parameters for all taggers for (auto& param : calib_p1_B0bar_){ if (param==nullptr){continue;} param->fixed(kFALSE); } return; } // Float parameter for requested tagger LauParameter* par { this->findParameter( taggerName, calib_p1_B0bar_ ) }; if ( not par ) { std::cerr << "ERROR in LauFlavTag::floatCalibParP1B0bar : Tagger name not recognised please check your options" << std::endl; return; } par->fixed(kFALSE); } void LauFlavTag::floatCalibParP0Ave(const TString& taggerName) { if (!useAveDelta_){ std::cerr << "ERROR in LauFlavTag::floatCalibParP0Ave : Trying to set calibration parameters for average/delta not B0/B0bar" << std::endl; return; } if (taggerName==""){ // Float parameters for all taggers for (auto& param : calib_p0_ave_){ if (param==nullptr){continue;} param->fixed(kFALSE); } return; } // Float parameter for requested tagger LauParameter* par { this->findParameter( taggerName, calib_p0_ave_ ) }; if ( not par ) { std::cerr << "ERROR in LauFlavTag::floatCalibParP0Ave : Tagger name not recognised please check your options" << std::endl; return; } par->fixed(kFALSE); } void LauFlavTag::floatCalibParP0Delta(const TString& taggerName) { if (!useAveDelta_){ std::cerr << "ERROR in LauFlavTag::floatCalibParP0Delta : Trying to set calibration parameters for average/delta not B0/B0bar" << std::endl; return; } if (taggerName==""){ // Float parameters for all taggers for (auto& param : calib_p0_delta_){ if (param==nullptr){continue;} param->fixed(kFALSE); } return; } // Float parameter for requested tagger LauParameter* par { this->findParameter( taggerName, calib_p0_delta_ ) }; if ( not par ) { std::cerr << "ERROR in LauFlavTag::floatCalibParP0Delta : Tagger name not recognised please check your options" << std::endl; return; } par->fixed(kFALSE); } void LauFlavTag::floatCalibParP1Ave(const TString& taggerName) { if (!useAveDelta_){ std::cerr << "ERROR in LauFlavTag::floatCalibParP1Ave : Trying to set calibration parameters for average/delta not B0/B0bar" << std::endl; return; } if (taggerName==""){ // Float parameters for all taggers for (auto& param : calib_p1_ave_){ if (param==nullptr){continue;} param->fixed(kFALSE); } return; } // Float parameter for requested tagger LauParameter* par { this->findParameter( taggerName, calib_p1_ave_ ) }; if ( not par ) { std::cerr << "ERROR in LauFlavTag::floatCalibParP1Ave : Tagger name not recognised please check your options" << std::endl; return; } par->fixed(kFALSE); } void LauFlavTag::floatCalibParP1Delta(const TString& taggerName) { if (!useAveDelta_){ std::cerr << "ERROR in LauFlavTag::floatCalibParP1Delta : Trying to set calibration parameters for average/delta not B0/B0bar" << std::endl; return; } if (taggerName==""){ // Float parameters for all taggers for (auto& param : calib_p1_delta_){ if (param==nullptr){continue;} param->fixed(kFALSE); } return; } // Float parameter for requested tagger LauParameter* par { this->findParameter( taggerName, calib_p1_delta_ ) }; if ( not par ) { std::cerr << "ERROR in LauFlavTag::floatCalibParP1Delta : Tagger name not recognised please check your options" << std::endl; return; } par->fixed(kFALSE); } void LauFlavTag::floatAllCalibPars() { if (useAveDelta_){ this->floatCalibParP0Ave(); this->floatCalibParP0Delta(); this->floatCalibParP1Ave(); this->floatCalibParP1Delta(); } else { this->floatCalibParP0B0(); this->floatCalibParP1B0(); this->floatCalibParP0B0bar(); this->floatCalibParP1B0bar(); } } void LauFlavTag::updatePulls() { const std::size_t nTaggers { this->getNTaggers() }; if (useAveDelta_){ for ( std::size_t taggerID{0}; taggerIDfixed() ) { calib_p0_ave_[taggerID]->updatePull(); } if ( not calib_p0_delta_[taggerID]->fixed() ) { calib_p0_delta_[taggerID]->updatePull(); } if ( not calib_p1_ave_[taggerID]->fixed() ) { calib_p1_ave_[taggerID]->updatePull(); } if ( not calib_p1_delta_[taggerID]->fixed() ) { calib_p1_delta_[taggerID]->updatePull(); } } } else { for ( std::size_t taggerID{0}; taggerIDfixed() ) { calib_p0_B0_[taggerID]->updatePull(); } if ( not calib_p0_B0bar_[taggerID]->fixed() ) { calib_p0_B0bar_[taggerID]->updatePull(); } if ( not calib_p1_B0_[taggerID]->fixed() ) { calib_p1_B0_[taggerID]->updatePull(); } if ( not calib_p1_B0bar_[taggerID]->fixed() ) { calib_p1_B0bar_[taggerID]->updatePull(); } } } } diff --git a/src/LauKMatrixPropagator.cc b/src/LauKMatrixPropagator.cc index 398a668..ddfebb5 100644 --- a/src/LauKMatrixPropagator.cc +++ b/src/LauKMatrixPropagator.cc @@ -1,1474 +1,1436 @@ /* Copyright 2008 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauKMatrixPropagator.cc \brief File containing implementation of LauKMatrixPropagator class. */ #include "LauKMatrixPropagator.hh" #include "LauComplex.hh" #include "LauJsonTools.hh" #include "LauKinematics.hh" #include "TMath.h" #include "TSystem.h" #include #include #include #include #include ClassImp(LauKMatrixPropagator) //! \cond DOXYGEN_IGNORE // map LauKMatrixPropagator::KMatrixChannels values to JSON as strings -NLOHMANN_JSON_SERIALIZE_ENUM( LauKMatrixPropagator::KMatrixChannels, { +LAURA_NLOHMANN_JSON_SERIALIZE_ENUM( LauKMatrixPropagator::KMatrixChannels, { {LauKMatrixPropagator::KMatrixChannels::PiPi, "PiPi"}, {LauKMatrixPropagator::KMatrixChannels::KK, "KK"}, {LauKMatrixPropagator::KMatrixChannels::FourPi, "FourPi"}, {LauKMatrixPropagator::KMatrixChannels::EtaEta, "EtaEta"}, {LauKMatrixPropagator::KMatrixChannels::EtaEtaP, "EtaEtaP"}, {LauKMatrixPropagator::KMatrixChannels::KPi, "KPi"}, {LauKMatrixPropagator::KMatrixChannels::KEtaP, "KEtaP"}, {LauKMatrixPropagator::KMatrixChannels::KThreePi, "KThreePi"}, {LauKMatrixPropagator::KMatrixChannels::D0K, "D0K"}, {LauKMatrixPropagator::KMatrixChannels::Dstar0K, "Dstar0K"}, }) - -std::ostream& operator<<( std::ostream& out, const LauKMatrixPropagator::KMatrixChannels channel ) -{ - switch ( channel ) { - case LauKMatrixPropagator::KMatrixChannels::PiPi : - out << "PiPi"; - break; - case LauKMatrixPropagator::KMatrixChannels::KK : - out << "KK"; - break; - case LauKMatrixPropagator::KMatrixChannels::FourPi : - out << "FourPi"; - break; - case LauKMatrixPropagator::KMatrixChannels::EtaEta : - out << "EtaEta"; - break; - case LauKMatrixPropagator::KMatrixChannels::EtaEtaP : - out << "EtaEtaP"; - break; - case LauKMatrixPropagator::KMatrixChannels::KPi : - out << "KPi"; - break; - case LauKMatrixPropagator::KMatrixChannels::KEtaP : - out << "KEtaP"; - break; - case LauKMatrixPropagator::KMatrixChannels::KThreePi : - out << "KThreePi"; - break; - case LauKMatrixPropagator::KMatrixChannels::D0K : - out << "D0K"; - break; - case LauKMatrixPropagator::KMatrixChannels::Dstar0K : - out << "Dstar0K"; - break; - } - - return out; -} //! \endcond LauKMatrixPropagator::LauKMatrixPropagator(const TString& name, const TString& paramFile, const UInt_t resPairAmpInt, const UInt_t nChannels, const UInt_t nPoles, const UInt_t rowIndex) : name_{name}, paramFileName_{paramFile}, resPairAmpInt_{resPairAmpInt}, index_{rowIndex - 1}, nChannels_{nChannels}, nPoles_{nPoles} { // Constructor // Check that the index is OK if (index_ < 0 || index_ >= nChannels_) { std::cerr << "ERROR in LauKMatrixPropagator constructor. The rowIndex, which is set to " << rowIndex << ", must be between 1 and the number of channels " << nChannels_ << std::endl; gSystem->Exit(EXIT_FAILURE); } this->setParameters(paramFile); } LauKMatrixPropagator::~LauKMatrixPropagator() { // Destructor realProp_.Clear(); negImagProp_.Clear(); ScattKMatrix_.Clear(); ReRhoMatrix_.Clear(); ImRhoMatrix_.Clear(); GammaMatrix_.Clear(); ReTMatrix_.Clear(); ImTMatrix_.Clear(); IMatrix_.Clear(); zeroMatrix_.Clear(); } LauComplex LauKMatrixPropagator::getPropTerm(const UInt_t channel) const { // Get the (i,j) = (index_, channel) term of the propagator // matrix. This allows us not to return the full propagator matrix. Double_t realTerm = this->getRealPropTerm(channel); Double_t imagTerm = this->getImagPropTerm(channel); LauComplex propTerm(realTerm, imagTerm); return propTerm; } Double_t LauKMatrixPropagator::getRealPropTerm(const UInt_t channel) const { // Get the real part of the (i,j) = (index_, channel) term of the propagator // matrix. This allows us not to return the full propagator matrix. if (parametersSet_ == kFALSE) {return 0.0;} Double_t propTerm = realProp_[index_][channel]; return propTerm; } Double_t LauKMatrixPropagator::getImagPropTerm(const UInt_t channel) const { // Get the imaginary part of the (i,j) = (index_, channel) term of the propagator // matrix. This allows us not to return the full propagator matrix. if (parametersSet_ == kFALSE) {return 0.0;} Double_t imagTerm = -1.0*negImagProp_[index_][channel]; return imagTerm; } void LauKMatrixPropagator::updatePropagator(const Double_t s) { // Calculate the K-matrix propagator for the given s value. // The K-matrix amplitude is given by // T_i = sum_{ij} (I - iK*rho)^-1 * P_j, where P is the production K-matrix. // i = index for the state (e.g. S-wave index = 0). // Here, we only find the (I - iK*rho)^-1 matrix part. // Check if we have almost the same s value as before. If so, don't re-calculate // the propagator nor any of the pole mass summation terms. if (TMath::Abs(s - previousS_) < 1e-6*s) { //std::cout << "Already got propagator for s = " << s << std::endl; return; } if (parametersSet_ == kFALSE) { //std::cerr << "ERROR in LauKMatrixPropagator::updatePropagator. Parameters have not been set." << std::endl; return; } // Calculate the denominator pole mass terms and Adler zero factor this->calcPoleDenomVect(s); this->updateAdlerZeroFactor(s); // Calculate the scattering K-matrix (real and symmetric) this->calcScattKMatrix(s); // Calculate the phase space density matrix, which is diagonal, but can be complex // if the quantity s is below various threshold values (analytic continuation). this->calcRhoMatrix(s); // Calculate the angular momentum barrier matrix, which is real and diagonal this->calcGammaMatrix(s); // Calculate K*rho*(gamma^2) (real and imaginary parts, since rho can be complex) TMatrixD GammaMatrixSq = (GammaMatrix_*GammaMatrix_); TMatrixD K_realRhoGammaSq(ScattKMatrix_); K_realRhoGammaSq *= ReRhoMatrix_; K_realRhoGammaSq *= GammaMatrixSq; TMatrixD K_imagRhoGammaSq(ScattKMatrix_); K_imagRhoGammaSq *= ImRhoMatrix_; K_imagRhoGammaSq *= GammaMatrixSq; // A = I + K*Imag(rho)Gamma^2, B = -K*Real(Rho)Gamma^2 // Calculate C and D matrices such that (A + iB)*(C + iD) = I, // ie. C + iD = (I - i K*rhoGamma^2)^-1, separated into real and imaginary parts. // realProp C = (A + B A^-1 B)^-1, imagProp D = -A^-1 B C TMatrixD A(IMatrix_); A += K_imagRhoGammaSq; TMatrixD B(zeroMatrix_); B -= K_realRhoGammaSq; TMatrixD invA(TMatrixD::kInverted, A); TMatrixD invA_B(invA); invA_B *= B; TMatrixD B_invA_B(B); B_invA_B *= invA_B; TMatrixD invC(A); invC += B_invA_B; // Set the real part of the propagator matrix ("C") realProp_ = TMatrixD(TMatrixD::kInverted, invC); // Set the (negative) imaginary part of the propagator matrix ("-D") TMatrixD BC(B); BC *= realProp_; negImagProp_ = TMatrixD(invA); negImagProp_ *= BC; // Pre-multiply by the Gamma matrix: realProp_ = GammaMatrix_ * realProp_; negImagProp_ = GammaMatrix_ * negImagProp_; if(verbose_) { std::cout << "In LauKMatrixPropagator::updatePropagator(s). D[1-iKrhoD^2]^-1: " << std::endl; TString realOutput("Real part:"), imagOutput("Imag part:"); for (UInt_t iChannel = 0; iChannel < nChannels_; iChannel++) { for (UInt_t jChannel = 0; jChannel < nChannels_; jChannel++) { realOutput += Form("\t%.6f",realProp_[iChannel][jChannel]); imagOutput += Form("\t%.6f",-1*negImagProp_[iChannel][jChannel]); } realOutput += "\n "; imagOutput += "\n "; } std::cout << realOutput << std::endl; std::cout << imagOutput << std::endl; } // Also calculate the production SVP term, since this uses Adler-zero parameters // defined in the parameter file. this->updateProdSVPTerm(s); // Finally, keep track of the value of s we just used. previousS_ = s; } void LauKMatrixPropagator::setParameters(const TString& inputFile) { // Read an input file that specifies the values of the coupling constants g_i for // the given number of poles and their (bare) masses. Also provided are the f_{ab} // slow-varying constants. The input file should also provide the Adler zero // constants s_0, s_A and s_A0. parametersSet_ = kFALSE; std::cout << "INFO in LauKMatrixPropagator::setParameters : Initialising K-matrix propagator " << name_ << " parameters from " << inputFile.Data() << std::endl; std::cout << " : nChannels = " << nChannels_ << ", nPoles = " << nPoles_ << std::endl; // Initialise various matrices this->initialiseMatrices(); // Initialise also the (temporary) barrier factor parameters vector std::vector a(nChannels_,0); // TODO - update to describe the JSON format (and copy to the header) // The format of the input file contains lines starting with a keyword followed by the // appropriate set of parameters. Keywords are case insensitive (treated as lower-case). // 1) Indices (nChannels) of N phase space channel types (defined in KMatrixChannels enum) // "Channels iChannel1 iChannel2 ... iChannelN" // 2) Definition of poles: bare mass (GeV), pole index (1 to NPoles), N channel couplings g_j // "Pole poleIndex mass g_1 g_2 ... g_N" // 3) Definition of scattering f_{ij} constants: scattering index (1 to N), channel values // "Scatt index f_{i1} f_{i2} ... f_{iN}", where i = index // 4) Orbital angular momentu for each channel. If not set here, defaults to 0 // "AngularMomentum L[0] L[1] ... L[N]" // 5) Barrier factor parameter, which appears in the denominator and multiplies the term involving // the nominal radius. If not set here, defaults to 0 or values appropriate to non-zero angular // momenta as set in in (4) above. // "BarrierFactorParameter a[0] a[1] ... a[N]" // 6) Characteristic radius for each channel. If not set here, defaults to 3.0 GeV^{-1} // "Radii radChannel1 radChannel2 ... radChannelN" // 7) Various Adler zero and scattering constants; each line is "name value". // Possible names are mSq0, s0Scatt, s0Prod, sA, sA0 // // By default, the scattering constants are symmetrised: f_{ji} = f_{ij}. // To not assume this use "ScattSymmetry 0" on a line using LauJsonTools::JsonType; // NB deliberately not using uniform initialisation here because of this issue: // https://json.nlohmann.me/home/faq/#brace-initialization-yields-arrays const nlohmann::json j = LauJsonTools::readJsonFile( inputFile.Data(), "", JsonType::Object ); if ( j.is_null() ) { std::cerr << "ERROR in LauKMatrixPropagator::setParameters : unable to retrieve JSON object from root element of file \"" << inputFile << "\"" << std::endl; return; } const std::vector mandatoryElements { std::make_pair("channels", JsonType::Array), std::make_pair("poles", JsonType::Array), std::make_pair("scattering", JsonType::Array), std::make_pair("parameters", JsonType::Array) }; if ( ! LauJsonTools::checkObjectElements( j, mandatoryElements ) ) { std::cerr << "ERROR in LauKMatrixPropagator::setParameters : aborting processing due to mis-formatted elements" << std::endl; return; } // Channel indices for phase-space factors if ( ! this->storeChannels( j.at("channels") ) ) { return; } // Pole terms if ( ! this->storePoles( j.at("poles") ) ) { return; } // Scattering terms if ( ! this->storeScattering( j.at("scattering") ) ) { return; } // Orbital angular momentum state for each channel & set default a values if called before storeBarrierFactorParameter if ( j.contains("angularmomentum") ) { if ( ! this->storeOrbitalAngularMomenta( j.at("angularmomentum"), a ) ) { return; } } // Value of parameter "a" in denominator of centrifugal barrier factor, gamma if ( j.contains("barrierfactorparameter") ) { if ( ! this->storeBarrierFactorParameter( j.at("barrierfactorparameter"), a ) ) { return; } } // Values of characteristic radius if ( j.contains("radii") ) { if ( ! this->storeRadii( j.at("radii") ) ) { return; } } // Other miscellaneous parameters, e.g. Adler-zero constants for ( auto& parameter : j.at("parameters") ) { if ( ! this->storeParameter( parameter ) ) { return; } } sAConst_ = 0.5*sA_.unblindValue()*mPiSq_; // Symmetrise scattering parameters if enabled if ( scattSymmetry_ ) { for (UInt_t iChannel{0}; iChannel < nChannels_; ++iChannel) { for (UInt_t jChannel{iChannel}; jChannel < nChannels_; ++jChannel) { fScattering_[jChannel][iChannel] = fScattering_[iChannel][jChannel]; } } } // Now that radii and barrier-factor-denominator parameters have been set, cache the value of "a/(R*R)" for (UInt_t iChannel{0}; iChannel < nChannels_; ++iChannel) { gamAInvRadSq_[iChannel] = a[iChannel]/(radii_[iChannel]*radii_[iChannel]); } // All required parameters have been set parametersSet_ = kTRUE; std::cout << "INFO in LauKMatrixPropagator::setParameters : Finished initialising K-matrix propagator " << name_ << std::endl; } void LauKMatrixPropagator::initialiseMatrices() { // Identity and null matrices IMatrix_.Clear(); IMatrix_.ResizeTo(nChannels_, nChannels_); for (UInt_t iChannel = 0; iChannel < nChannels_; iChannel++) { IMatrix_[iChannel][iChannel] = 1.0; } zeroMatrix_.Clear(); zeroMatrix_.ResizeTo(nChannels_, nChannels_); // Real K matrix ScattKMatrix_.Clear(); ScattKMatrix_.ResizeTo(nChannels_, nChannels_); // Real and imaginary propagator matrices realProp_.Clear(); negImagProp_.Clear(); realProp_.ResizeTo(nChannels_, nChannels_); negImagProp_.ResizeTo(nChannels_, nChannels_); // Phase space matrices ReRhoMatrix_.Clear(); ImRhoMatrix_.Clear(); ReRhoMatrix_.ResizeTo(nChannels_, nChannels_); ImRhoMatrix_.ResizeTo(nChannels_, nChannels_); // Gamma matrices GammaMatrix_.Clear(); GammaMatrix_.ResizeTo(nChannels_, nChannels_); // Vector of orbital angular momenta for the channels (default is S-wave everywhere) L_.clear(); L_.assign(nChannels_,0); // Characteristic radius (diagonal) vector (default to 3.0) radii_.clear(); radii_.assign(nChannels_,3.0); // Vector to cache ratio a/R^2 gamAInvRadSq_.clear(); gamAInvRadSq_.resize(nChannels_); // Square-root phase space matrices ReSqrtRhoMatrix_.Clear(); ImSqrtRhoMatrix_.Clear(); ReSqrtRhoMatrix_.ResizeTo(nChannels_, nChannels_); ImSqrtRhoMatrix_.ResizeTo(nChannels_, nChannels_); // T matrices ReTMatrix_.Clear(); ImTMatrix_.Clear(); ReTMatrix_.ResizeTo(nChannels_, nChannels_); ImTMatrix_.ResizeTo(nChannels_, nChannels_); // For the coupling and scattering constants, use LauParArrays instead of TMatrices // so that the quantities remain LauParameters instead of just doubles. // Each array is an stl vector of another stl vector of LauParameters: // std::vector< std::vector >. // Set their sizes using the number of poles and channels defined in the constructor gCouplings_.clear(); gCouplings_.resize(nPoles_); for (UInt_t iPole = 0; iPole < nPoles_; iPole++) { gCouplings_[iPole].resize(nChannels_); } fScattering_.clear(); fScattering_.resize(nChannels_); for (UInt_t iChannel = 0; iChannel < nChannels_; iChannel++) { fScattering_[iChannel].resize(nChannels_); } // Clear other vectors phaseSpaceTypes_.clear(); phaseSpaceTypes_.resize(nChannels_); mSqPoles_.clear(); mSqPoles_.resize(nPoles_); haveCalledStoreBarrierFactorParameter_ = kFALSE; } bool LauKMatrixPropagator::storeChannels(const nlohmann::json& j) { // Get the list of channel indices to specify what phase space factors should be used // e.g. pipi, Kpi, eta eta', 4pi etc.. // Check that the array has nChannels_ entries const auto numChannels { j.size() }; if ( numChannels != nChannels_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storeChannels : \"channels\" array contains wrong number of elements, " << numChannels << " instead of " << nChannels_ << ", aborting processing" << std::endl; return false; } phaseSpaceTypes_ = j.get(); for ( UInt_t iChannel{0}; iChannel < nChannels_; ++iChannel) { std::cout << "INFO in LauKMatrixPropagator::storeChannels : added phase space channel " << phaseSpaceTypes_[iChannel] << " with index " << iChannel+1 << " to propagator " << name_ << std::endl; } return true; } bool LauKMatrixPropagator::storePoles(const nlohmann::json& j) { // For each pole, store the pole mass and its coupling constants for each channel // Check that the array has nPoles_ entries const auto numPoles { j.size() }; if ( numPoles != nPoles_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storePoles : \"poles\" array contains wrong number of elements, " << numPoles << " instead of " << nPoles_ << ", aborting processing" << std::endl; return false; } // Each entry in the array should have an index, mass and couplings array using LauJsonTools::JsonType; const std::vector mandatoryElements { std::make_pair("index", JsonType::Number_Unsigned), std::make_pair("mass", JsonType::Number_Float), std::make_pair("couplings", JsonType::Array) }; for ( auto& elem : j ) { if ( ! checkObjectElements( elem, mandatoryElements ) ) { std::cerr << "ERROR in LauKMatrixPropagator::storePoles : aborting processing due to mis-formatted elements" << std::endl; return false; } } for ( auto& poleDef : j ) { const auto poleIndex { LauJsonTools::getValue( poleDef, "index" ) - 1 }; if ( poleIndex >= nPoles_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storePoles : invalid pole index: " << poleIndex+1 << ", aborting processing" << std::endl; return false; } const auto poleMass { LauJsonTools::getValue( poleDef, "mass" ) }; const auto poleMassSq { poleMass * poleMass }; const auto couplings { LauJsonTools::getValue>( poleDef, "couplings" ) }; if ( couplings.size() != nChannels_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storePoles : invalid number of couplings ( " << couplings.size() << " ) provided for pole index " << poleIndex+1 << ", aborting processing" << std::endl; return false; } mSqPoles_[poleIndex] = LauParameter{ Form("KM_%s_poleMassSq_%i", name_.Data(), poleIndex+1), poleMassSq }; std::cout << "INFO in LauKMatrixPropagator::storePoles : added bare pole mass " << poleMass << " GeV for pole number " << poleIndex+1 << std::endl; for ( UInt_t iChannel{0}; iChannel < nChannels_; ++iChannel) { const Double_t couplingConst { couplings[iChannel] }; gCouplings_[poleIndex][iChannel] = LauParameter{ Form("KM_%s_gCoupling_%i_%i", name_.Data(), poleIndex+1, iChannel+1), couplingConst }; std::cout << "INFO in LauKMatrixPropagator::storePoles : added coupling parameter g^{" << poleIndex+1 << "}_" << iChannel+1 << " = " << couplingConst << std::endl; } } return true; } bool LauKMatrixPropagator::storeScattering(const nlohmann::json& j) { // Store the scattering constants (along each of the channel rows) // Check that we have a reasonable number of entries const auto numScatt { j.size() }; if ( numScatt > nChannels_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storeScattering : \"scattering\" array contains too many elements, " << numScatt << " instead of <= " << nChannels_ << ", aborting processing" << std::endl; return false; } // Each entry in the array should have an index and couplings array using LauJsonTools::JsonType; const std::vector mandatoryElements { std::make_pair("index", JsonType::Number_Unsigned), std::make_pair("couplings", JsonType::Array) }; for ( auto& elem : j ) { if ( ! checkObjectElements( elem, mandatoryElements ) ) { std::cerr << "ERROR in LauKMatrixPropagator::storeScattering : aborting processing due to mis-formatted elements" << std::endl; return false; } } for ( auto& scattDef : j ) { const auto scattIndex { LauJsonTools::getValue( scattDef, "index" ) - 1 }; if ( scattIndex >= nChannels_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storeScattering : invalid channel index: " << scattIndex+1 << ", aborting processing" << std::endl; return false; } const auto couplings { LauJsonTools::getValue>( scattDef, "couplings" ) }; if ( couplings.size() != nChannels_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storeScattering : invalid number of couplings ( " << couplings.size() << " ) provided for scattering index " << scattIndex+1 << ", aborting processing" << std::endl; return false; } for ( UInt_t iChannel{0}; iChannel < nChannels_; ++iChannel) { const Double_t couplingConst { couplings[iChannel] }; fScattering_[scattIndex][iChannel] = LauParameter{ Form("KM_%s_fScatteringConst_%i_%i", name_.Data(), scattIndex+1, iChannel+1), couplingConst }; std::cout << "INFO in LauKMatrixPropagator::storeScattering : Added coupling parameter f(" << scattIndex+1 << "," << iChannel+1 << ") = " << couplingConst << std::endl; } } return true; } bool LauKMatrixPropagator::storeOrbitalAngularMomenta(const nlohmann::json& j, std::vector& a) { // Store the orbital angular momentum for each channel if ( ! LauJsonTools::checkValueType( j, LauJsonTools::JsonType::Array ) ) { std::cerr << "ERROR in LauKMatrixPropagator::storeOrbitalAngularMomenta : \"angularmomentum\" element is not an array, aborting processing" << std::endl; return false; } if ( j.size() != nChannels_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storeOrbitalAngularMomenta : \"angularmomentum\" array has incorrect number of elements, " << j.size() << " instead of " << nChannels_ << ", aborting processing" << std::endl; return false; } L_ = j.get(); for ( UInt_t iChannel{0}; iChannel < nChannels_; ++iChannel) { std::cout << "INFO in LauKMatrixPropagator::storeOrbitalAngularMomenta : defined K-matrix orbital angular momentum " << L_[iChannel] << " for channel " << iChannel+1 << std::endl; } // If the barrier factor parameters have already been stored there's nothing more for us to do if ( haveCalledStoreBarrierFactorParameter_ ) { return true; } // Otherwise, set default value of spin-dependent centrifugal-barrier-factor parameter for ( UInt_t iCh{0}; iCh < nChannels_; ++iCh) { switch ( L_[iCh] ) { case 0: a[iCh] = 0; break; case 1: a[iCh] = 1; break; case 2: a[iCh] = 3; break; default: std::cerr << "ERROR in LauKMatrixPropagator::storeOrbitalAngularMomenta : barrier factor and angular-momentum terms of K-matrix are only defined for S-, P-, or D-wave." << std::endl; return false; } } return true; } bool LauKMatrixPropagator::storeRadii(const nlohmann::json& j) { // Store the characteristic barrier radii (measured in GeV^{-1}) if ( ! LauJsonTools::checkValueType( j, LauJsonTools::JsonType::Array ) ) { std::cerr << "ERROR in LauKMatrixPropagator::storeRadii : \"radii\" element is not an array, aborting processing" << std::endl; return false; } if ( j.size() != nChannels_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storeRadii : \"radii\" array has incorrect number of elements, " << j.size() << " instead of " << nChannels_ << ", aborting processing" << std::endl; return false; } radii_ = j.get(); for ( UInt_t iChannel{0}; iChannel < nChannels_; ++iChannel) { std::cout << "INFO in LauKMatrixPropagator::storeRadii : added K-matrix barrier radius " << radii_[iChannel] << " for channel " << iChannel+1 << std::endl; } return true; } bool LauKMatrixPropagator::storeBarrierFactorParameter(const nlohmann::json& j, std::vector& a) { // Store the parameter of the barrier factor if ( ! LauJsonTools::checkValueType( j, LauJsonTools::JsonType::Array ) ) { std::cerr << "ERROR in LauKMatrixPropagator::storeBarrierFactorParameter : \"barrierfactorparameter\" element is not an array, aborting processing" << std::endl; return false; } if ( j.size() != nChannels_ ) { std::cerr << "ERROR in LauKMatrixPropagator::storeBarrierFactorParameter : \"barrierfactorparameter\" array has incorrect number of elements, " << j.size() << " instead of " << nChannels_ << ", aborting processing" << std::endl; return false; } a = j.get>(); for ( UInt_t iChannel{0}; iChannel < nChannels_; ++iChannel) { std::cout << "INFO in LauKMatrixPropagator::storeBarrierFactorParameter : added K-matrix barrier factor parameter " << a[iChannel] << " for channel " << iChannel+1 << std::endl; } // Set flag to stop storeOrbitalAngularMomenta overriding these a values haveCalledStoreBarrierFactorParameter_ = kTRUE; return true; } bool LauKMatrixPropagator::storeParameter(const nlohmann::json& j) { using LauJsonTools::getValue; using LauJsonTools::JsonType; const std::vector mandatoryElements { std::make_pair("name", JsonType::String), std::make_pair("value", JsonType::Any) }; if ( ! checkObjectElements( j, mandatoryElements ) ) { std::cerr << "ERROR in LauKMatrixPropagator::storeParameter : aborting processing due to mis-formatted elements" << std::endl; return false; } auto keyword { getValue( j, "name" ) }; keyword.ToLower(); if ( keyword == "msq0" ) { const auto mSq0Value { getValue( j, "value" ) }; mSq0_ = LauParameter{ Form("KM_%s_mSq0",name_.Data()), mSq0Value }; std::cout << "INFO in LauKMatrixPropagator::storeParameter : Adler zero constant m0Sq = " << mSq0Value << std::endl; } else if ( keyword == "s0scatt" ) { const auto s0ScattValue { getValue( j, "value" ) }; s0Scatt_ = LauParameter{ Form("KM_%s_s0Scatt",name_.Data()), s0ScattValue }; std::cout << "INFO in LauKMatrixPropagator::storeParameter : Adler zero constant s0Scatt = " << s0ScattValue << std::endl; } else if ( keyword == "s0prod" ) { const auto s0ProdValue { getValue( j, "value" ) }; s0Prod_ = LauParameter{ Form("KM_%s_s0Prod",name_.Data()), s0ProdValue }; std::cout << "INFO in LauKMatrixPropagator::storeParameter : Adler zero constant s0Prod = " << s0ProdValue << std::endl; } else if ( keyword == "sa0" ) { const auto sA0Value { getValue( j, "value" ) }; sA0_ = LauParameter{ Form("KM_%s_sA0",name_.Data()), sA0Value }; std::cout << "INFO in LauKMatrixPropagator::storeParameter : Adler zero constant sA0 = " << sA0Value << std::endl; } else if ( keyword == "sa" ) { const auto sAValue { getValue( j, "value" ) }; sA_ = LauParameter{ Form("KM_%s_sA",name_.Data()), sAValue }; std::cout << "INFO in LauKMatrixPropagator::storeParameter : Adler zero constant sA = " << sAValue << std::endl; } else if ( keyword == "scattsymmetry" ) { scattSymmetry_ = getValue( j, "value" ); if ( ! scattSymmetry_ ) { std::cout << "INFO in LauKMatrixPropagator::storeParameter : Turning off scattering parameter symmetry: f_ji = f_ij will not be assumed" << std::endl; } } return true; } void LauKMatrixPropagator::calcScattKMatrix(const Double_t s) { // Calculate the scattering K-matrix for the given value of s. // We need to obtain the complete matrix (not just one row/column) // to get the correct inverted (I - i K rho) terms for the propagator. if (verbose_) {std::cout << "Within calcScattKMatrix for s = " << s << std::endl;} // Initialise the K matrix to zero ScattKMatrix_.Zero(); UInt_t iChannel(0), jChannel(0), iPole(0); // The pole denominator 1/(m^2 - s) terms should already be calculated // by the calcPoleDenomVect() function. These same terms are also // used for calculating the production K-matrix elements. // Calculate the "slowly-varying part" (SVP), e.g. (1 GeV - s0)/(s - s0) this->updateScattSVPTerm(s); // Now loop over iChannel, jChannel to calculate Kij = Kji. for (iChannel = 0; iChannel < nChannels_; iChannel++) { // Scattering matrix is real and symmetric. Start j loop from i. for (jChannel = iChannel; jChannel < nChannels_; jChannel++) { Double_t Kij(0.0); // Calculate pole mass summation term for (iPole = 0; iPole < nPoles_; iPole++) { Double_t g_i = this->getCouplingConstant(iPole, iChannel); Double_t g_j = this->getCouplingConstant(iPole, jChannel); Kij += poleDenomVect_[iPole]*g_i*g_j; if (verbose_) {std::cout << "1: Kij for i = " << iChannel << ", j = " << jChannel << " = " << Kij << std::endl;} } Double_t fij = this->getScatteringConstant(iChannel, jChannel); Kij += fij*scattSVP_; Kij *= adlerZeroFactor_; if (verbose_) {std::cout << "2: Kij for i = " << iChannel << ", j = " << jChannel << " = " << Kij << std::endl;} // Assign the TMatrix (i,j) element to the variable Kij and Kji (symmetry) ScattKMatrix_(iChannel, jChannel) = Kij; ScattKMatrix_(jChannel, iChannel) = Kij; } // j loop } // i loop } void LauKMatrixPropagator::calcPoleDenomVect(const Double_t s) { // Calculate the 1/(m_pole^2 - s) terms for the scattering // and production K-matrix formulae. poleDenomVect_.clear(); UInt_t iPole(0); for (iPole = 0; iPole < nPoles_; iPole++) { Double_t poleTerm = mSqPoles_[iPole].unblindValue() - s; Double_t invPoleTerm(0.0); if (TMath::Abs(poleTerm) > 1.0e-6) {invPoleTerm = 1.0/poleTerm;} poleDenomVect_.push_back(invPoleTerm); } } Double_t LauKMatrixPropagator::getPoleDenomTerm(const UInt_t poleIndex) const { if (parametersSet_ == kFALSE) {return 0.0;} Double_t poleDenom(0.0); poleDenom = poleDenomVect_[poleIndex]; return poleDenom; } LauParameter& LauKMatrixPropagator::getPoleMassSqParameter(const UInt_t poleIndex) { if ( (parametersSet_ == kFALSE) || (poleIndex < 0 || poleIndex >= nPoles_) ) { std::cerr << "ERROR from LauKMatrixPropagator::getPoleMassSqParameter(). Invalid pole." << std::endl; gSystem->Exit(EXIT_FAILURE); } return mSqPoles_[poleIndex]; } Double_t LauKMatrixPropagator::getCouplingConstant(const UInt_t poleIndex, const UInt_t channelIndex) const { if (parametersSet_ == kFALSE) {return 0.0;} if (poleIndex < 0 || poleIndex >= nPoles_) {return 0.0;} if (channelIndex < 0 || channelIndex >= nChannels_) {return 0.0;} Double_t couplingConst = gCouplings_[poleIndex][channelIndex].unblindValue(); return couplingConst; } LauParameter& LauKMatrixPropagator::getCouplingParameter(const UInt_t poleIndex, const UInt_t channelIndex) { if ( (parametersSet_ == kFALSE) || (poleIndex < 0 || poleIndex >= nPoles_) || (channelIndex < 0 || channelIndex >= nChannels_) ) { std::cerr << "ERROR from LauKMatrixPropagator::getCouplingParameter(). Invalid coupling." << std::endl; gSystem->Exit(EXIT_FAILURE); } //std::cout << "Minvalue + range for " << poleIndex << ", " << channelIndex << ": " << gCouplings_[poleIndex][channelIndex].minValue() << " => + " << gCouplings_[poleIndex][channelIndex].range() << // " and init value: " << gCouplings_[poleIndex][channelIndex].initValue() << std::endl; return gCouplings_[poleIndex][channelIndex]; } Double_t LauKMatrixPropagator::getScatteringConstant(const UInt_t channel1Index, const UInt_t channel2Index) const { if (parametersSet_ == kFALSE) {return 0.0;} if (channel1Index < 0 || channel1Index >= nChannels_) {return 0.0;} if (channel2Index < 0 || channel2Index >= nChannels_) {return 0.0;} Double_t scatteringConst = fScattering_[channel1Index][channel2Index].unblindValue(); return scatteringConst; } LauParameter& LauKMatrixPropagator::getScatteringParameter(const UInt_t channel1Index, const UInt_t channel2Index) { if ( (parametersSet_ == kFALSE) || (channel1Index < 0 || channel1Index >= nChannels_) || (channel2Index < 0 || channel2Index >= nChannels_) ) { std::cerr << "ERROR from LauKMatrixPropagator::getScatteringParameter(). Invalid chanel index." << std::endl; gSystem->Exit(EXIT_FAILURE); } return fScattering_[channel1Index][channel2Index]; } Double_t LauKMatrixPropagator::calcSVPTerm(const Double_t s, const Double_t s0) const { if (parametersSet_ == kFALSE) {return 0.0;} // Calculate the "slowly-varying part" (SVP) Double_t result(0.0); Double_t deltaS = s - s0; if (TMath::Abs(deltaS) > 1.0e-6) { result = (mSq0_.unblindValue() - s0)/deltaS; } return result; } void LauKMatrixPropagator::updateScattSVPTerm(const Double_t s) { // Update the scattering "slowly-varying part" (SVP) Double_t s0Scatt = s0Scatt_.unblindValue(); scattSVP_ = this->calcSVPTerm(s, s0Scatt); } void LauKMatrixPropagator::updateProdSVPTerm(const Double_t s) { // Update the production "slowly-varying part" (SVP) Double_t s0Prod = s0Prod_.unblindValue(); prodSVP_ = this->calcSVPTerm(s, s0Prod); } void LauKMatrixPropagator::updateAdlerZeroFactor(const Double_t s) { // Calculate the multiplicative factor containing various Adler zero // constants. adlerZeroFactor_ = 0.0; Double_t sA0Val = sA0_.unblindValue(); Double_t deltaS = s - sA0Val; if (TMath::Abs(deltaS) > 1e-6) { adlerZeroFactor_ = (s - sAConst_)*(1.0 - sA0Val)/deltaS; } } void LauKMatrixPropagator::calcGammaMatrix(const Double_t s) { // Calculate the gamma angular momentum barrier matrix // for the given invariant mass squared quantity, s. // Initialise all entries to zero GammaMatrix_.Zero(); Double_t gamma(0.0); for (UInt_t iChannel (0); iChannel < nChannels_; ++iChannel) { if ( L_[iChannel] != 0 ) { gamma = this->calcGamma(iChannel,s); } else { gamma = 1.0; // S-wave } if (verbose_) { std::cout << "GammaMatrix(" << iChannel << ", " << iChannel << ") = " << gamma << std::endl; } GammaMatrix_(iChannel, iChannel) = gamma; } } Double_t LauKMatrixPropagator::calcGamma(const UInt_t iCh, const Double_t s) const { // Calculate the barrier factor Double_t gamma(0.0); KMatrixChannels phaseSpaceIndex = phaseSpaceTypes_[iCh]; LauComplex rho = getRho(s,phaseSpaceIndex); Double_t q = 0.5 * sqrt(s) * rho.abs(); gamma = pow(q,L_[iCh]); if (includeBWBarrierFactor_) { gamma /= pow( q*q + gamAInvRadSq_[iCh] , L_[iCh]/2. ); } if(verbose_) { std::cout << "In LauKMatrixPropagator::calcGamma(iCh=" << iCh << ", s=" << s << ", prop). "; std::cout << "|q(iCh=" << iCh << ")|: " << q << std::endl; } return gamma; } void LauKMatrixPropagator::calcRhoMatrix(const Double_t s) { // Calculate the real and imaginary part of the phase space density // diagonal matrix for the given invariant mass squared quantity, s. // The matrix can be complex if s is below threshold (so that // the amplitude continues analytically). // Initialise all entries to zero ReRhoMatrix_.Zero(); ImRhoMatrix_.Zero(); for (UInt_t iChannel (0); iChannel < nChannels_; ++iChannel) { KMatrixChannels phaseSpaceIndex = phaseSpaceTypes_[iChannel]; LauComplex rho = getRho(s, phaseSpaceIndex); if (verbose_) { std::cout << "ReRhoMatrix(" << iChannel << ", " << iChannel << ") = " << rho.re() << std::endl; std::cout << "ImRhoMatrix(" << iChannel << ", " << iChannel << ") = " << rho.im() << std::endl; } ReRhoMatrix_(iChannel, iChannel) = rho.re(); ImRhoMatrix_(iChannel, iChannel) = rho.im(); } } LauComplex LauKMatrixPropagator::getRho(const Double_t s, const LauKMatrixPropagator::KMatrixChannels phaseSpaceIndex) const { LauComplex rho(0.0, 0.0); switch (phaseSpaceIndex) { case KMatrixChannels::PiPi : rho = this->calcPiPiRho(s); break; case KMatrixChannels::KK : rho = this->calcKKRho(s); break; case KMatrixChannels::FourPi : rho = this->calcFourPiRho(s); break; case KMatrixChannels::EtaEta : rho = this->calcEtaEtaRho(s); break; case KMatrixChannels::EtaEtaP : rho = this->calcEtaEtaPRho(s); break; case KMatrixChannels::KPi : rho = this->calcKPiRho(s); break; case KMatrixChannels::KEtaP : rho = this->calcKEtaPRho(s); break; case KMatrixChannels::KThreePi : rho = this->calcKThreePiRho(s); break; case KMatrixChannels::D0K : rho = this->calcD0KRho(s); break; case KMatrixChannels::Dstar0K : rho = this->calcDstar0KRho(s); break; } return rho; } LauComplex LauKMatrixPropagator::calcD0KRho(const Double_t s) const { // Calculate the D0K+ phase space factor LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} Double_t sqrtTerm1 = (-mD0KSumSq_/s) + 1.0; Double_t sqrtTerm2 = (-mD0KDiffSq_/s) + 1.0; Double_t sqrtTerm = sqrtTerm1*sqrtTerm2; if (sqrtTerm < 0.0) { rho.setImagPart( TMath::Sqrt(-sqrtTerm) ); } else { rho.setRealPart( TMath::Sqrt(sqrtTerm) ); } return rho; } LauComplex LauKMatrixPropagator::calcDstar0KRho(const Double_t s) const { // Calculate the Dstar0K+ phase space factor LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} Double_t sqrtTerm1 = (-mDstar0KSumSq_/s) + 1.0; Double_t sqrtTerm2 = (-mDstar0KDiffSq_/s) + 1.0; Double_t sqrtTerm = sqrtTerm1*sqrtTerm2; if (sqrtTerm < 0.0) { rho.setImagPart( TMath::Sqrt(-sqrtTerm) ); } else { rho.setRealPart( TMath::Sqrt(sqrtTerm) ); } return rho; } LauComplex LauKMatrixPropagator::calcPiPiRho(const Double_t s) const { // Calculate the pipi phase space factor LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} Double_t sqrtTerm = (-m2piSq_/s) + 1.0; if (sqrtTerm < 0.0) { rho.setImagPart( TMath::Sqrt(-sqrtTerm) ); } else { rho.setRealPart( TMath::Sqrt(sqrtTerm) ); } return rho; } LauComplex LauKMatrixPropagator::calcKKRho(const Double_t s) const { // Calculate the KK phase space factor LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} Double_t sqrtTerm = (-m2KSq_/s) + 1.0; if (sqrtTerm < 0.0) { rho.setImagPart( TMath::Sqrt(-sqrtTerm) ); } else { rho.setRealPart( TMath::Sqrt(sqrtTerm) ); } return rho; } LauComplex LauKMatrixPropagator::calcFourPiRho(const Double_t s) const { // Calculate the 4pi phase space factor. This uses a 6th-order polynomial // parameterisation that approximates the multi-body phase space double integral // defined in Eq 4 of the A&S paper hep-ph/0204328. This form agrees with the // BaBar model (another 6th order polynomial from s^4 down to 1/s^2), but avoids the // exponential increase at small values of s (~< 0.1) arising from 1/s and 1/s^2. // Eq 4 is evaluated for each value of s by assuming incremental steps of 1e-3 GeV^2 // for s1 and s2, the invariant energy squared of each of the di-pion states, // with the integration limits of s1 = (2*mpi)^2 to (sqrt(s) - 2*mpi)^2 and // s2 = (2*mpi)^2 to (sqrt(s) - sqrt(s1))^2. The mass M of the rho is taken to be // 0.775 GeV and the energy-dependent width of the 4pi system // Gamma(s) = gamma_0*rho1^3(s), where rho1 = sqrt(1.0 - 4*mpiSq/s) and gamma_0 is // the "width" of the 4pi state at s = 1, which is taken to be 0.3 GeV // (~75% of the total width from PDG estimates of the f0(1370) -> 4pi state). // The normalisation term rho_0 is found by ensuring that the phase space integral // at s = 1 is equal to sqrt(1.0 - 16*mpiSq/s). Note that the exponent for this // factor in hep-ph/0204328 is wrong; it should be 0.5, i.e. sqrt, not n = 1 to 5. // Plotting the value of this double integral as a function of s can then be fitted // to a 6th-order polynomial (for s < 1), which is the result used below LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} if (s <= 1.0) { Double_t rhoTerm = ((1.07885*s + 0.13655)*s - 0.29744)*s - 0.20840; rhoTerm = ((rhoTerm*s + 0.13851)*s - 0.01933)*s + 0.00051; // For some values of s (below 2*mpi), this term is a very small // negative number. Check for this and set the rho term to zero. if (rhoTerm < 0.0) {rhoTerm = 0.0;} rho.setRealPart( rhoTerm ); } else { rho.setRealPart( TMath::Sqrt(1.0 - (fourPiFactor1_/s)) ); } return rho; } LauComplex LauKMatrixPropagator::calcEtaEtaRho(const Double_t s) const { // Calculate the eta-eta phase space factor LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} Double_t sqrtTerm = (-m2EtaSq_/s) + 1.0; if (sqrtTerm < 0.0) { rho.setImagPart( TMath::Sqrt(-sqrtTerm) ); } else { rho.setRealPart( TMath::Sqrt(sqrtTerm) ); } return rho; } LauComplex LauKMatrixPropagator::calcEtaEtaPRho(const Double_t s) const { // Calculate the eta-eta' phase space factor. Note that the // mass difference term m_eta - m_eta' is not included, // since this corresponds to a "t or u-channel crossing", // which means that we cannot simply analytically continue // this part of the phase space factor below threshold, which // we can do for s-channel contributions. This is actually an // unsolved problem, e.g. see Guo et al 1409.8652, and // Danilkin et al 1409.7708. Anisovich and Sarantsev in // hep-ph/0204328 "solve" this issue by setting the mass // difference term to unity, which is what we do here... LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} Double_t sqrtTerm = (-mEtaEtaPSumSq_/s) + 1.0; if (sqrtTerm < 0.0) { rho.setImagPart( TMath::Sqrt(-sqrtTerm) ); } else { rho.setRealPart( TMath::Sqrt(sqrtTerm) ); } return rho; } LauComplex LauKMatrixPropagator::calcKPiRho(const Double_t s) const { // Calculate the K-pi phase space factor LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} Double_t sqrtTerm1 = (-mKpiSumSq_/s) + 1.0; Double_t sqrtTerm2 = (-mKpiDiffSq_/s) + 1.0; Double_t sqrtTerm = sqrtTerm1*sqrtTerm2; if (sqrtTerm < 0.0) { rho.setImagPart( TMath::Sqrt(-sqrtTerm) ); } else { rho.setRealPart( TMath::Sqrt(sqrtTerm) ); } return rho; } LauComplex LauKMatrixPropagator::calcKEtaPRho(const Double_t s) const { // Calculate the K-eta' phase space factor LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} Double_t sqrtTerm1 = (-mKEtaPSumSq_/s) + 1.0; Double_t sqrtTerm2 = (-mKEtaPDiffSq_/s) + 1.0; Double_t sqrtTerm = sqrtTerm1*sqrtTerm2; if (sqrtTerm < 0.0) { rho.setImagPart( TMath::Sqrt(-sqrtTerm) ); } else { rho.setRealPart( TMath::Sqrt(sqrtTerm) ); } return rho; } LauComplex LauKMatrixPropagator::calcKThreePiRho(const Double_t s) const { // Calculate the Kpipipi + multimeson phase space factor. // Use the simplest definition in hep-ph/9705401 (Eq 14), which is the form // used for the rest of that paper (thankfully, the amplitude does not depend // significantly on the form used for the K3pi phase space factor). LauComplex rho(0.0, 0.0); if (TMath::Abs(s) < 1e-10) {return rho;} if (s < 1.44) { Double_t powerTerm = (-mK3piDiffSq_/s) + 1.0; if (powerTerm < 0.0) { rho.setImagPart( k3piFactor_*TMath::Power(-powerTerm, 2.5) ); } else { rho.setRealPart( k3piFactor_*TMath::Power(powerTerm, 2.5) ); } } else { rho.setRealPart( 1.0 ); } return rho; } LauComplex LauKMatrixPropagator::getTransitionAmp(const Double_t s, const UInt_t channel) { // Get the complex (unitary) transition amplitude T for the given channel LauComplex TAmp(0.0, 0.0); if (channel <= 0 || channel > nChannels_) {return TAmp;} this->getTMatrix(s); TAmp.setRealPart(ReTMatrix_[index_][channel-1]); TAmp.setImagPart(ImTMatrix_[index_][channel-1]); return TAmp; } LauComplex LauKMatrixPropagator::getPhaseSpaceTerm(const Double_t s, const UInt_t channel) { // Get the complex (unitary) transition amplitude T for the given channel LauComplex rho(0.0, 0.0); if (channel <= 0 || channel > nChannels_) {return rho;} // If s has changed from the previous value, recalculate rho if (TMath::Abs(s - previousS_) > 1e-6*s) { this->calcRhoMatrix(s); } rho.setRealPart(ReRhoMatrix_[channel][channel-1]); rho.setImagPart(ImRhoMatrix_[channel][channel-1]); return rho; } void LauKMatrixPropagator::getTMatrix(const LauKinematics* kinematics) { // Find the unitary T matrix, where T = [sqrt(rho)]^{*} T_hat sqrt(rho), // and T_hat = (I - i K rho)^-1 * K is the Lorentz-invariant T matrix, // which has phase-space factors included (rho). This function is not // needed to calculate the K-matrix amplitudes, but allows us // to check the variation of T as a function of s (kinematics) if (!kinematics) {return;} // Get the invariant mass squared (s) from the kinematics object. // Use the resPairAmpInt to find which mass-squared combination to use. Double_t s(0.0); if (resPairAmpInt_ == 1) { s = kinematics->getm23Sq(); } else if (resPairAmpInt_ == 2) { s = kinematics->getm13Sq(); } else if (resPairAmpInt_ == 3) { s = kinematics->getm12Sq(); } this->getTMatrix(s); } void LauKMatrixPropagator::getTMatrix(const Double_t s) { // Find the unitary transition T matrix, where // T = [sqrt(rho)]^{*} T_hat sqrt(rho), and // T_hat = (I - i K rho)^-1 * K is the Lorentz-invariant T matrix, // which has phase-space factors included (rho). Note that the first // sqrt of the rho matrix is complex conjugated. // This function is not needed to calculate the K-matrix amplitudes, but // allows us to check the variation of T as a function of s (kinematics) // Initialse the real and imaginary parts of the T matrix to zero ReTMatrix_.Zero(); ImTMatrix_.Zero(); if (parametersSet_ == kFALSE) {return;} // Update K, rho and the propagator (I - i K rho)^-1 this->updatePropagator(s); // Find the real and imaginary T_hat matrices TMatrixD THatReal = realProp_*ScattKMatrix_; TMatrixD THatImag(zeroMatrix_); THatImag -= negImagProp_*ScattKMatrix_; // Find the square-root of the phase space matrix this->getSqrtRhoMatrix(); // Let sqrt(rho) = A + iB and T_hat = C + iD // => T = A(CA-DB) + B(DA+CB) + i[A(DA+CB) + B(DB-CA)] TMatrixD CA(THatReal); CA *= ReSqrtRhoMatrix_; TMatrixD DA(THatImag); DA *= ReSqrtRhoMatrix_; TMatrixD CB(THatReal); CB *= ImSqrtRhoMatrix_; TMatrixD DB(THatImag); DB *= ImSqrtRhoMatrix_; TMatrixD CAmDB(CA); CAmDB -= DB; TMatrixD DApCB(DA); DApCB += CB; TMatrixD DBmCA(DB); DBmCA -= CA; // Find the real and imaginary parts of the transition matrix T ReTMatrix_ = ReSqrtRhoMatrix_*CAmDB + ImSqrtRhoMatrix_*DApCB; ImTMatrix_ = ReSqrtRhoMatrix_*DApCB + ImSqrtRhoMatrix_*DBmCA; } void LauKMatrixPropagator::getSqrtRhoMatrix() { // Find the square root of the (current) phase space matrix so that // we can find T = [sqrt(rho)}^{*} T_hat sqrt(rho), where T_hat is the // Lorentz-invariant T matrix = (I - i K rho)^-1 * K; note that the first // sqrt of rho matrix is complex conjugated // If rho = rho_i + i rho_r = a + i b, then sqrt(rho) = c + i d, where // c = sqrt(0.5*(r+a)) and d = sqrt(0.5(r-a)), where r = sqrt(a^2 + b^2). // Since rho is diagonal, then the square root of rho will also be diagonal, // with its real and imaginary matrix elements equal to c and d, respectively // Initialise the real and imaginary parts of the square root of // the rho matrix to zero ReSqrtRhoMatrix_.Zero(); ImSqrtRhoMatrix_.Zero(); for (UInt_t iChannel (0); iChannel < nChannels_; ++iChannel) { Double_t realRho = ReRhoMatrix_[iChannel][iChannel]; Double_t imagRho = ImRhoMatrix_[iChannel][iChannel]; Double_t rhoMag = sqrt(realRho*realRho + imagRho*imagRho); Double_t rhoSum = rhoMag + realRho; Double_t rhoDiff = rhoMag - realRho; Double_t reSqrtRho(0.0), imSqrtRho(0.0); if (rhoSum > 0.0) {reSqrtRho = sqrt(0.5*rhoSum);} if (rhoDiff > 0.0) {imSqrtRho = sqrt(0.5*rhoDiff);} ReSqrtRhoMatrix_[iChannel][iChannel] = reSqrtRho; ImSqrtRhoMatrix_[iChannel][iChannel] = imSqrtRho; } } LauComplex LauKMatrixPropagator::getTHat(const Double_t s, const UInt_t channel) { LauComplex THat(0.0, 0.0); if (channel <= 0 || channel > nChannels_) {return THat;} this->updatePropagator(s); // Find the real and imaginary T_hat matrices TMatrixD THatReal = realProp_*ScattKMatrix_; TMatrixD THatImag(zeroMatrix_); THatImag -= negImagProp_*ScattKMatrix_; // Return the specific THat component THat.setRealPart(THatReal[index_][channel-1]); THat.setImagPart(THatImag[index_][channel-1]); return THat; } nlohmann::json LauKMatrixPropagator::writeSettingsToJson() const { using nlohmann::json; json j = json::object(); j[ "propName" ] = name_.Data(); j[ "paramFileName" ] = paramFileName_.Data(); j[ "resPairAmpInt" ] = resPairAmpInt_; j[ "nChannels" ] = nChannels_; j[ "nPoles" ] = nPoles_; if ( index_ > 0 ) { j[ "rowIndex" ] = index_+1; } if ( ! includeBWBarrierFactor_ ) { j[ "ignoreBWBarrierFactor" ] = true; } return j; } diff --git a/src/LauPolarGammaCPCoeffSet.cc b/src/LauPolarGammaCPCoeffSet.cc index 7c237a9..45ff908 100644 --- a/src/LauPolarGammaCPCoeffSet.cc +++ b/src/LauPolarGammaCPCoeffSet.cc @@ -1,1042 +1,1008 @@ /* Copyright 2014 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauPolarGammaCPCoeffSet.cc \brief File containing implementation of LauPolarGammaCPCoeffSet class. */ #include #include #include #include "TMath.h" #include "TRandom.h" #include "LauPolarGammaCPCoeffSet.hh" #include "LauComplex.hh" #include "LauConstants.hh" #include "LauJsonTools.hh" #include "LauParameter.hh" #include "LauPrint.hh" std::shared_ptr LauPolarGammaCPCoeffSet::gammaGlobal_; std::shared_ptr LauPolarGammaCPCoeffSet::rDGlobal_; std::shared_ptr LauPolarGammaCPCoeffSet::deltaDGlobal_; ClassImp(LauPolarGammaCPCoeffSet) LauPolarGammaCPCoeffSet::LauPolarGammaCPCoeffSet(const TString& compName, const DecayType decayType, const Double_t x, const Double_t y, const Double_t rB, const Double_t deltaB, const Double_t gamma, const Double_t rD, const Double_t deltaD, const Bool_t xFixed, const Bool_t yFixed, const Bool_t rBFixed, const Bool_t deltaBFixed, const Bool_t gammaFixed, const Bool_t rDFixed, const Bool_t deltaDFixed, const Bool_t rBSecondStage, const Bool_t deltaBSecondStage, const Bool_t gammaSecondStage, const Bool_t rDSecondStage, const Bool_t deltaDSecondStage, const Bool_t useGlobalGamma, const Bool_t useGlobalADSPars) : LauAbsCoeffSet{ compName }, decayType_{ decayType }, useGlobalGamma_{ useGlobalGamma }, useGlobalADSPars_{ useGlobalADSPars }, acp_{ "ACP", 0.0, -1.0, 1.0 } { // All of the possible D decay types need these two parameters x_ = std::make_unique("X", x, minRealImagPart_, maxRealImagPart_, xFixed); y_ = std::make_unique("Y", y, minRealImagPart_, maxRealImagPart_, yFixed); // if we're using a global gamma, create it if it doesn't already exist then set gamma_ to point to it // otherwise create our individual copy of gamma if (useGlobalGamma_) { if (!gammaGlobal_) { gammaGlobal_ = std::make_shared("gamma", gamma, minPhase_, maxPhase_, gammaFixed); gamma_ = gammaGlobal_; } else { gamma_.reset( gammaGlobal_->createClone() ); } } else { gamma_ = std::make_shared("gamma", gamma, minPhase_, maxPhase_, gammaFixed); } if (gammaSecondStage && !gammaFixed) { gamma_->secondStage(kTRUE); gamma_->initValue(0.0); } // which of the other parameter we need depends on the D-decay type if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { rB_ = std::make_unique("rB", rB, minMagnitude_, maxMagnitude_, rBFixed); deltaB_ = std::make_unique("deltaB", deltaB, minPhase_, maxPhase_, deltaBFixed); if (rBSecondStage && !rBFixed) { rB_->secondStage(kTRUE); rB_->initValue(0.0); } if (deltaBSecondStage && !deltaBFixed) { deltaB_->secondStage(kTRUE); deltaB_->initValue(0.0); } } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { if (useGlobalADSPars_) { if ( !rDGlobal_ ) { rDGlobal_ = std::make_shared("rD", rD, minMagnitude_, maxMagnitude_, rDFixed); deltaDGlobal_ = std::make_shared("deltaD", deltaD, minPhase_, maxPhase_, deltaDFixed); rD_ = rDGlobal_; deltaD_ = deltaDGlobal_; } else { rD_.reset( rDGlobal_->createClone() ); deltaD_.reset( deltaDGlobal_->createClone() ); } } else { rD_ = std::make_shared("rD", rD, minMagnitude_, maxMagnitude_, rDFixed); deltaD_ = std::make_shared("deltaD", deltaD, minPhase_, maxPhase_, deltaDFixed); } if (rDSecondStage && !rDFixed) { rD_->secondStage(kTRUE); rD_->initValue(0.0); } if (deltaDSecondStage && !deltaDFixed) { deltaD_->secondStage(kTRUE); deltaD_->initValue(0.0); } } } LauPolarGammaCPCoeffSet::LauPolarGammaCPCoeffSet(const LauPolarGammaCPCoeffSet& rhs, const CloneOption cloneOption, const Double_t constFactor, const nlohmann::json& coeffInfo) : LauAbsCoeffSet{ rhs.name(), rhs.baseName(), &rhs, cloneOption, constFactor }, decayType_{ rhs.decayType_ }, useGlobalGamma_{ rhs.useGlobalGamma_ }, useGlobalADSPars_{ rhs.useGlobalADSPars_ }, nonCPPart_{ rhs.nonCPPart_ }, cpPart_{ rhs.cpPart_ }, cpAntiPart_{ rhs.cpAntiPart_ }, particleCoeff_{ rhs.particleCoeff_ }, antiparticleCoeff_{ rhs.antiparticleCoeff_ }, acp_{ rhs.acp_ } { using LauJsonTools::JsonType; using LauJsonTools::getValue; using LauJsonTools::getOptionalValue; if ( cloneOption == CloneOption::All || cloneOption == CloneOption::TieRealPart ) { x_.reset( rhs.x_->createClone(constFactor) ); } else { const auto xVal { getOptionalValue( coeffInfo, "X", JsonType::Number ).value_or( rhs.x_->value() ) }; const auto xFixed { getOptionalValue( coeffInfo, "XFixed", JsonType::Boolean ).value_or( rhs.x_->fixed() ) }; x_ = std::make_unique("X", xVal, minRealImagPart_, maxRealImagPart_, xFixed); if ( getOptionalValue( coeffInfo, "XBlind", JsonType::Boolean ).value_or( kFALSE ) ) { const auto blindingString { getValue( coeffInfo, "XBlindingString" ) }; const auto blindingWidth { getValue( coeffInfo, "XBlindingWidth" ) }; x_->blindParameter( blindingString, blindingWidth ); } else if ( rhs.x_->blind() ) { const LauBlind* blinder { rhs.x_->blinder() }; x_->blindParameter( blinder->blindingString(), blinder->blindingWidth() ); } } if ( cloneOption == CloneOption::All || cloneOption == CloneOption::TieImagPart ) { y_.reset( rhs.y_->createClone(constFactor) ); } else { const auto yVal { getOptionalValue( coeffInfo, "Y", JsonType::Number ).value_or( rhs.y_->value() ) }; const auto yFixed { getOptionalValue( coeffInfo, "YFixed", JsonType::Boolean ).value_or( rhs.y_->fixed() ) }; y_ = std::make_unique("Y", yVal, minRealImagPart_, maxRealImagPart_, yFixed); if ( getOptionalValue( coeffInfo, "YBlind", JsonType::Boolean ).value_or( kFALSE ) ) { const auto blindingString { getValue( coeffInfo, "YBlindingString" ) }; const auto blindingWidth { getValue( coeffInfo, "YBlindingWidth" ) }; y_->blindParameter( blindingString, blindingWidth ); } else if ( rhs.y_->blind() ) { const LauBlind* blinder { rhs.y_->blinder() }; y_->blindParameter( blinder->blindingString(), blinder->blindingWidth() ); } } if ( cloneOption == CloneOption::All || cloneOption == CloneOption::TieCPPars ) { gamma_.reset( rhs.gamma_->createClone(constFactor) ); if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { rB_.reset( rhs.rB_->createClone(constFactor) ); deltaB_.reset( rhs.deltaB_->createClone(constFactor) ); } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { rD_.reset( rhs.rD_->createClone(constFactor) ); deltaD_.reset( rhs.deltaD_->createClone(constFactor) ); } } else { if (useGlobalGamma_) { gamma_.reset( gammaGlobal_->createClone() ); } else { const auto gammaVal { getOptionalValue( coeffInfo, "gamma", JsonType::Number ).value_or( rhs.gamma_->value() ) }; const auto gammaFixed { getOptionalValue( coeffInfo, "gammaFixed", JsonType::Boolean ).value_or( rhs.gamma_->fixed() ) }; const auto gammaSecondStage { getOptionalValue( coeffInfo, "gammaSecondStage", JsonType::Boolean ).value_or( rhs.gamma_->secondStage() ) }; gamma_ = std::make_shared("gamma", gammaVal, minPhase_, maxPhase_, gammaFixed); if ( gammaSecondStage && !gammaFixed ) { gamma_->secondStage(kTRUE); gamma_->initValue(0.0); } if ( getOptionalValue( coeffInfo, "gammaBlind", JsonType::Boolean ).value_or( kFALSE ) ) { const auto blindingString { getValue( coeffInfo, "gammaBlindingString" ) }; const auto blindingWidth { getValue( coeffInfo, "gammaBlindingWidth" ) }; gamma_->blindParameter( blindingString, blindingWidth ); } else if ( rhs.gamma_->blind() ) { const LauBlind* blinder { rhs.gamma_->blinder() }; gamma_->blindParameter( blinder->blindingString(), blinder->blindingWidth() ); } } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { const auto rBVal { getOptionalValue( coeffInfo, "rB", JsonType::Number ).value_or( rhs.rB_->value() ) }; const auto rBFixed { getOptionalValue( coeffInfo, "rBFixed", JsonType::Boolean ).value_or( rhs.rB_->fixed() ) }; const auto rBSecondStage { getOptionalValue( coeffInfo, "rBSecondStage", JsonType::Boolean ).value_or( rhs.rB_->secondStage() ) }; rB_ = std::make_unique("rB", rBVal, minMagnitude_, maxMagnitude_, rBFixed); if ( rBSecondStage && !rBFixed ) { rB_->secondStage(kTRUE); rB_->initValue(0.0); } if ( getOptionalValue( coeffInfo, "rBBlind", JsonType::Boolean ).value_or( kFALSE ) ) { const auto blindingString { getValue( coeffInfo, "rBBlindingString" ) }; const auto blindingWidth { getValue( coeffInfo, "rBBlindingWidth" ) }; rB_->blindParameter( blindingString, blindingWidth ); } else if ( rhs.rB_->blind() ) { const LauBlind* blinder { rhs.rB_->blinder() }; rB_->blindParameter( blinder->blindingString(), blinder->blindingWidth() ); } const auto deltaBVal { getOptionalValue( coeffInfo, "deltaB", JsonType::Number ).value_or( rhs.deltaB_->value() ) }; const auto deltaBFixed { getOptionalValue( coeffInfo, "deltaBFixed", JsonType::Boolean ).value_or( rhs.deltaB_->fixed() ) }; const auto deltaBSecondStage { getOptionalValue( coeffInfo, "deltaBSecondStage", JsonType::Boolean ).value_or( rhs.deltaB_->secondStage() ) }; deltaB_ = std::make_unique("deltaB", deltaBVal, minPhase_, maxPhase_, deltaBFixed); if ( deltaBSecondStage && !deltaBFixed ) { deltaB_->secondStage(kTRUE); deltaB_->initValue(0.0); } if ( getOptionalValue( coeffInfo, "deltaBBlind", JsonType::Boolean ).value_or( kFALSE ) ) { const auto blindingString { getValue( coeffInfo, "deltaBBlindingString" ) }; const auto blindingWidth { getValue( coeffInfo, "deltaBBlindingWidth" ) }; deltaB_->blindParameter( blindingString, blindingWidth ); } else if ( rhs.deltaB_->blind() ) { const LauBlind* blinder { rhs.deltaB_->blinder() }; deltaB_->blindParameter( blinder->blindingString(), blinder->blindingWidth() ); } } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { if ( useGlobalADSPars_ ) { rD_.reset( rDGlobal_->createClone() ); deltaD_.reset( deltaDGlobal_->createClone() ); } else { const auto rDVal { getOptionalValue( coeffInfo, "rD", JsonType::Number ).value_or( rhs.rD_->value() ) }; const auto rDFixed { getOptionalValue( coeffInfo, "rDFixed", JsonType::Boolean ).value_or( rhs.rD_->fixed() ) }; const auto rDSecondStage { getOptionalValue( coeffInfo, "rDSecondStage", JsonType::Boolean ).value_or( rhs.rD_->secondStage() ) }; rD_ = std::make_unique("rD", rDVal, minMagnitude_, maxMagnitude_, rDFixed); if ( rDSecondStage && !rDFixed ) { rD_->secondStage(kTRUE); rD_->initValue(0.0); } if ( getOptionalValue( coeffInfo, "rDBlind", JsonType::Boolean ).value_or( kFALSE ) ) { const auto blindingString { getValue( coeffInfo, "rDBlindingString" ) }; const auto blindingWidth { getValue( coeffInfo, "rDBlindingWidth" ) }; rD_->blindParameter( blindingString, blindingWidth ); } else if ( rhs.rD_->blind() ) { const LauBlind* blinder { rhs.rD_->blinder() }; rD_->blindParameter( blinder->blindingString(), blinder->blindingWidth() ); } const auto deltaDVal { getOptionalValue( coeffInfo, "deltaD", JsonType::Number ).value_or( rhs.deltaD_->value() ) }; const auto deltaDFixed { getOptionalValue( coeffInfo, "deltaDFixed", JsonType::Boolean ).value_or( rhs.deltaD_->fixed() ) }; const auto deltaDSecondStage { getOptionalValue( coeffInfo, "deltaDSecondStage", JsonType::Boolean ).value_or( rhs.deltaD_->secondStage() ) }; deltaD_ = std::make_unique("deltaD", deltaDVal, minPhase_, maxPhase_, deltaDFixed); if ( deltaDSecondStage && !deltaDFixed ) { deltaD_->secondStage(kTRUE); deltaD_->initValue(0.0); } if ( getOptionalValue( coeffInfo, "deltaDBlind", JsonType::Boolean ).value_or( kFALSE ) ) { const auto blindingString { getValue( coeffInfo, "deltaDBlindingString" ) }; const auto blindingWidth { getValue( coeffInfo, "deltaDBlindingWidth" ) }; deltaD_->blindParameter( blindingString, blindingWidth ); } else if ( rhs.deltaD_->blind() ) { const LauBlind* blinder { rhs.deltaD_->blinder() }; deltaD_->blindParameter( blinder->blindingString(), blinder->blindingWidth() ); } } } } } void LauPolarGammaCPCoeffSet::adjustName(LauParameter& par, const TString& oldBaseName) { if ( ( &par == gamma_.get() && useGlobalGamma_ ) || ( &par == rD_.get() && useGlobalADSPars_ ) || ( &par == deltaD_.get() && useGlobalADSPars_ ) ) { // for global parameters we do not want to adjust their names return; } else { LauAbsCoeffSet::adjustName(par,oldBaseName); } } std::vector LauPolarGammaCPCoeffSet::getParameters() { std::vector pars; pars.reserve(7); pars.push_back(x_.get()); pars.push_back(y_.get()); pars.push_back(gamma_.get()); if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { pars.push_back(rB_.get()); pars.push_back(deltaB_.get()); } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { pars.push_back(rD_.get()); pars.push_back(deltaD_.get()); } return pars; } std::vector LauPolarGammaCPCoeffSet::getParameters() const { std::vector pars; pars.reserve(7); pars.push_back(x_.get()); pars.push_back(y_.get()); pars.push_back(gamma_.get()); if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { pars.push_back(rB_.get()); pars.push_back(deltaB_.get()); } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { pars.push_back(rD_.get()); pars.push_back(deltaD_.get()); } return pars; } std::vector LauPolarGammaCPCoeffSet::getParNames() const { std::vector pars; pars.reserve(7); pars.push_back("X"); pars.push_back("Y"); pars.push_back("gamma"); if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { pars.push_back("rB"); pars.push_back("deltaB"); } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { pars.push_back("rD"); pars.push_back("deltaD"); } return pars; } void LauPolarGammaCPCoeffSet::printParValues() const { std::cout<<"INFO in LauPolarGammaCPCoeffSet::printParValues : Component \""<name()<<"\" has "; std::cout<<"X = "<value()<<",\t"; std::cout<<"Y = "<value()<<",\t"; if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { std::cout<<"rB = "<value()<<",\t"; std::cout<<"deltaB = "<value()<<",\t"; } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { std::cout<<"rD = "<value()<<",\t"; std::cout<<"deltaD = "<value()<<",\t"; } std::cout<<"gamma = "<value()<<"."<name() }; resName = resName.ReplaceAll("_", "\\_"); stream<value()); stream<<" \\pm "; print.printFormat(stream, x_->error()); stream<<"$ & $"; print.printFormat(stream, y_->value()); stream<<" \\pm "; print.printFormat(stream, y_->error()); stream<<"$ & $"; if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { print.printFormat(stream, rB_->value()); stream<<" \\pm "; print.printFormat(stream, rB_->error()); stream<<"$ & $"; print.printFormat(stream, deltaB_->value()); stream<<" \\pm "; print.printFormat(stream, deltaB_->error()); stream<<"$ & $"; } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { print.printFormat(stream, rD_->value()); stream<<" \\pm "; print.printFormat(stream, rD_->error()); stream<<"$ & $"; print.printFormat(stream, deltaD_->value()); stream<<" \\pm "; print.printFormat(stream, deltaD_->error()); stream<<"$ & $"; } print.printFormat(stream, gamma_->value()); stream<<" \\pm "; print.printFormat(stream, gamma_->error()); stream<<"$ \\\\"<fixed() == kFALSE) { // Choose a value for "X" between -3.0 and 3.0 const Double_t value { LauAbsCoeffSet::getRandomiser()->Rndm()*6.0 - 3.0 }; x_->initValue(value); x_->value(value); } if (y_->fixed() == kFALSE) { // Choose a value for "Y" between -3.0 and 3.0 const Double_t value { LauAbsCoeffSet::getRandomiser()->Rndm()*6.0 - 3.0 }; y_->initValue(value); y_->value(value); } if (gamma_->fixed() == kFALSE && gamma_->secondStage() == kFALSE) { // Choose a value for "gamma" between +-pi const Double_t value { LauAbsCoeffSet::getRandomiser()->Rndm()*LauConstants::twoPi - LauConstants::pi }; gamma_->initValue(value); gamma_->value(value); } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { if (rB_->fixed() == kFALSE && rB_->secondStage() == kFALSE) { // Choose a value for "rB" between 0.0 and 2.0 const Double_t value { LauAbsCoeffSet::getRandomiser()->Rndm()*2.0 }; rB_->initValue(value); rB_->value(value); } if (deltaB_->fixed() == kFALSE && deltaB_->secondStage() == kFALSE) { // Choose a value for "deltaB" between +- pi const Double_t value { LauAbsCoeffSet::getRandomiser()->Rndm()*LauConstants::twoPi - LauConstants::pi }; deltaB_->initValue(value); deltaB_->value(value); } } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { if (rD_->fixed() == kFALSE && rD_->secondStage() == kFALSE) { // Choose a value for "rD" between 0.0 and 2.0 const Double_t value { LauAbsCoeffSet::getRandomiser()->Rndm()*2.0 }; rD_->initValue(value); rD_->value(value); } if (deltaD_->fixed() == kFALSE && deltaD_->secondStage() == kFALSE) { // Choose a value for "deltaD" between +- pi const Double_t value { LauAbsCoeffSet::getRandomiser()->Rndm()*LauConstants::twoPi - LauConstants::pi }; deltaD_->initValue(value); deltaD_->value(value); } } } void LauPolarGammaCPCoeffSet::finaliseValues() { // retrieve the current values from the parameters Double_t gammaVal { gamma_->value() }; Double_t rBVal { 0.0 }; Double_t deltaBVal { 0.0 }; Double_t genDeltaB { 0.0 }; Double_t rDVal { 0.0 }; Double_t deltaDVal { 0.0 }; Double_t genDeltaD { 0.0 }; if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { rBVal = rB_->value(); deltaBVal = deltaB_->value(); genDeltaB = deltaB_->genValue(); } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { rDVal = rD_->value(); deltaDVal = deltaD_->value(); genDeltaD = deltaD_->genValue(); } // Check whether we have a negative magnitude. // If so make it positive and add pi to the phases. if (rBVal < 0.0) { rBVal *= -1.0; deltaBVal += LauConstants::pi; } if (rDVal < 0.0) { rDVal *= -1.0; deltaDVal += LauConstants::pi; } // Check now whether the phases lie in the right range (-pi to pi). Bool_t deltaBWithinRange{kFALSE}; Bool_t deltaDWithinRange{kFALSE}; Bool_t gammaWithinRange{kFALSE}; while ( deltaBWithinRange == kFALSE ) { if (deltaBVal > -LauConstants::pi && deltaBVal <= LauConstants::pi) { deltaBWithinRange = kTRUE; } else { // Not within the specified range if (deltaBVal > LauConstants::pi) { deltaBVal -= LauConstants::twoPi; } else if (deltaBVal <= -LauConstants::pi) { deltaBVal += LauConstants::twoPi; } } } while ( deltaDWithinRange == kFALSE ) { if (deltaDVal > -LauConstants::pi && deltaDVal <= LauConstants::pi) { deltaDWithinRange = kTRUE; } else { // Not within the specified range if (deltaDVal > LauConstants::pi) { deltaDVal -= LauConstants::twoPi; } else if (deltaDVal <= -LauConstants::pi) { deltaDVal += LauConstants::twoPi; } } } while ( gammaWithinRange == kFALSE ) { if (gammaVal > -LauConstants::pi && gammaVal <= LauConstants::pi) { gammaWithinRange = kTRUE; } else { // Not within the specified range if (gammaVal > LauConstants::pi) { gammaVal -= LauConstants::twoPi; } else if (gammaVal <= -LauConstants::pi) { gammaVal += LauConstants::twoPi; } } } // To resolve the two-fold ambiguity in gamma and deltaB we require gamma to be in the range 0-pi if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { if (gammaVal < 0.0) { if (deltaBVal <= 0.0) { gammaVal += LauConstants::pi; deltaBVal += LauConstants::pi; } else { gammaVal += LauConstants::pi; deltaBVal -= LauConstants::pi; } } } // A further problem can occur when the generated phase is close to -pi or pi. // The phase can wrap over to the other end of the scale - // this leads to artificially large pulls so we wrap it back. Double_t diff { deltaBVal - genDeltaB }; if (diff > LauConstants::pi) { deltaBVal -= LauConstants::twoPi; } else if (diff < -LauConstants::pi) { deltaBVal += LauConstants::twoPi; } diff = deltaDVal - genDeltaD; if (diff > LauConstants::pi) { deltaDVal -= LauConstants::twoPi; } else if (diff < -LauConstants::pi) { deltaDVal += LauConstants::twoPi; } // finally store the new values in the parameters // and update the pulls gamma_->value(gammaVal); gamma_->updatePull(); if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::GLW_CPOdd || decayType_ == DecayType::GLW_CPEven ) { rB_->value(rBVal); rB_->updatePull(); deltaB_->value(deltaBVal); deltaB_->updatePull(); } if ( decayType_ == DecayType::ADS_Favoured || decayType_ == DecayType::ADS_Suppressed || decayType_ == DecayType::ADS_Favoured_btouOnly ) { rD_->value(rDVal); rD_->updatePull(); deltaD_->value(deltaDVal); deltaD_->updatePull(); } } const LauComplex& LauPolarGammaCPCoeffSet::particleCoeff() { this->updateAmplitudes(); return particleCoeff_; } const LauComplex& LauPolarGammaCPCoeffSet::antiparticleCoeff() { this->updateAmplitudes(); return antiparticleCoeff_; } void LauPolarGammaCPCoeffSet::updateAmplitudes() { nonCPPart_.setRealImagPart( x_->unblindValue(), y_->unblindValue() ); const Double_t gammaVal { gamma_->unblindValue() }; switch ( decayType_ ) { case DecayType::GLW_CPOdd : { const Double_t rBVal { rB_->unblindValue() }; const Double_t deltaBVal { deltaB_->unblindValue() }; cpPart_.setRealImagPart( 1.0 - rBVal*TMath::Cos(deltaBVal + gammaVal), -rBVal*TMath::Sin(deltaBVal + gammaVal) ); cpAntiPart_.setRealImagPart( 1.0 - rBVal*TMath::Cos(deltaBVal - gammaVal), -rBVal*TMath::Sin(deltaBVal - gammaVal) ); break; } case DecayType::GLW_CPEven : { const Double_t rBVal { rB_->unblindValue() }; const Double_t deltaBVal { deltaB_->unblindValue() }; cpPart_.setRealImagPart( 1.0 + rBVal*TMath::Cos(deltaBVal + gammaVal), rBVal*TMath::Sin(deltaBVal + gammaVal) ); cpAntiPart_.setRealImagPart( 1.0 + rBVal*TMath::Cos(deltaBVal - gammaVal), rBVal*TMath::Sin(deltaBVal - gammaVal) ); break; } case DecayType::ADS_Favoured : { const Double_t rBVal { rB_->unblindValue() }; const Double_t deltaBVal { deltaB_->unblindValue() }; const Double_t rDVal { rD_->unblindValue() }; const Double_t deltaDVal { deltaD_->unblindValue() }; cpPart_.setRealImagPart( 1.0 + rBVal*rDVal*TMath::Cos(deltaBVal - deltaDVal + gammaVal), rBVal*rDVal*TMath::Sin(deltaBVal - deltaDVal + gammaVal) ); cpAntiPart_.setRealImagPart( 1.0 + rBVal*rDVal*TMath::Cos(deltaBVal - deltaDVal - gammaVal), rBVal*rDVal*TMath::Sin(deltaBVal - deltaDVal - gammaVal) ); break; } case DecayType::ADS_Suppressed : { const Double_t rBVal { rB_->unblindValue() }; const Double_t deltaBVal { deltaB_->unblindValue() }; const Double_t rDVal { rD_->unblindValue() }; const Double_t deltaDVal { deltaD_->unblindValue() }; cpPart_.setRealImagPart( rDVal*TMath::Cos(-deltaDVal) + rBVal*TMath::Cos(deltaBVal + gammaVal), rDVal*TMath::Sin(-deltaDVal) + rBVal*TMath::Sin(deltaBVal + gammaVal) ); cpAntiPart_.setRealImagPart( rDVal*TMath::Cos(-deltaDVal) + rBVal*TMath::Cos(deltaBVal - gammaVal), rDVal*TMath::Sin(-deltaDVal) + rBVal*TMath::Sin(deltaBVal - gammaVal) ); break; } case DecayType::GLW_CPOdd_btouOnly : nonCPPart_.rescale(-1.0); cpPart_.setRealImagPart( 1.0 * TMath::Cos( gammaVal ), 1.0 * TMath::Sin( gammaVal ) ); cpAntiPart_.setRealImagPart( 1.0 * TMath::Cos( -gammaVal ), 1.0 * TMath::Sin( -gammaVal ) ); break; case DecayType::GLW_CPEven_btouOnly : cpPart_.setRealImagPart( 1.0 * TMath::Cos( gammaVal ), 1.0 * TMath::Sin( gammaVal ) ); cpAntiPart_.setRealImagPart( 1.0 * TMath::Cos( -gammaVal ), 1.0 * TMath::Sin( -gammaVal ) ); break; case DecayType::ADS_Favoured_btouOnly : { const Double_t rDVal { rD_->unblindValue() }; const Double_t deltaDVal { deltaD_->unblindValue() }; cpPart_.setRealImagPart( rDVal * TMath::Cos( -deltaDVal + gammaVal ), rDVal * TMath::Sin( -deltaDVal + gammaVal ) ); cpAntiPart_.setRealImagPart( rDVal * TMath::Cos( -deltaDVal - gammaVal ), rDVal * TMath::Sin( -deltaDVal - gammaVal ) ); break; } case DecayType::ADS_Suppressed_btouOnly : cpPart_.setRealImagPart( 1.0 * TMath::Cos( gammaVal ), 1.0 * TMath::Sin( gammaVal ) ); cpAntiPart_.setRealImagPart( 1.0 * TMath::Cos( -gammaVal ), 1.0 * TMath::Sin( -gammaVal ) ); break; } particleCoeff_ = nonCPPart_ * cpPart_; antiparticleCoeff_ = nonCPPart_ * cpAntiPart_; } void LauPolarGammaCPCoeffSet::setCoeffValues( const LauComplex&, const LauComplex&, Bool_t ) { std::cerr << "ERROR in LauPolarGammaCPCoeffSet::setCoeffValues : Method not supported by this class - too many parameters" << std::endl; } LauParameter LauPolarGammaCPCoeffSet::acp() { // set the name const TString parName{ this->baseName() + "_ACP" }; acp_.name(parName); // work out the ACP value LauComplex nonCPPart{ x_->value(), y_->value() }; LauComplex cpPart; LauComplex cpAntiPart; const Double_t gammaVal { gamma_->value() }; switch ( decayType_ ) { case DecayType::GLW_CPOdd : { const Double_t rBVal { rB_->value() }; const Double_t deltaBVal { deltaB_->value() }; cpPart.setRealImagPart( 1.0 - rBVal*TMath::Cos(deltaBVal + gammaVal), -rBVal*TMath::Sin(deltaBVal + gammaVal) ); cpAntiPart.setRealImagPart( 1.0 - rBVal*TMath::Cos(deltaBVal - gammaVal), -rBVal*TMath::Sin(deltaBVal - gammaVal) ); break; } case DecayType::GLW_CPEven : { const Double_t rBVal { rB_->value() }; const Double_t deltaBVal { deltaB_->value() }; cpPart.setRealImagPart( 1.0 + rBVal*TMath::Cos(deltaBVal + gammaVal), rBVal*TMath::Sin(deltaBVal + gammaVal) ); cpAntiPart.setRealImagPart( 1.0 + rBVal*TMath::Cos(deltaBVal - gammaVal), rBVal*TMath::Sin(deltaBVal - gammaVal) ); break; } case DecayType::ADS_Favoured : { const Double_t rBVal { rB_->value() }; const Double_t deltaBVal { deltaB_->value() }; const Double_t rDVal { rD_->value() }; const Double_t deltaDVal { deltaD_->value() }; cpPart.setRealImagPart( 1.0 + rBVal*rDVal*TMath::Cos(deltaBVal - deltaDVal + gammaVal), rBVal*rDVal*TMath::Sin(deltaBVal - deltaDVal + gammaVal) ); cpAntiPart.setRealImagPart( 1.0 + rBVal*rDVal*TMath::Cos(deltaBVal - deltaDVal - gammaVal), rBVal*rDVal*TMath::Sin(deltaBVal - deltaDVal - gammaVal) ); break; } case DecayType::ADS_Suppressed : { const Double_t rBVal { rB_->value() }; const Double_t deltaBVal { deltaB_->value() }; const Double_t rDVal { rD_->value() }; const Double_t deltaDVal { deltaD_->value() }; cpPart.setRealImagPart( rDVal*TMath::Cos(-deltaDVal) + rBVal*TMath::Cos(deltaBVal + gammaVal), rDVal*TMath::Sin(-deltaDVal) + rBVal*TMath::Sin(deltaBVal + gammaVal) ); cpAntiPart.setRealImagPart( rDVal*TMath::Cos(-deltaDVal) + rBVal*TMath::Cos(deltaBVal - gammaVal), rDVal*TMath::Sin(-deltaDVal) + rBVal*TMath::Sin(deltaBVal - gammaVal) ); break; } case DecayType::GLW_CPOdd_btouOnly : nonCPPart.rescale(-1.0); cpPart.setRealImagPart( 1.0 * TMath::Cos( gammaVal ), 1.0 * TMath::Sin( gammaVal ) ); cpAntiPart.setRealImagPart( 1.0 * TMath::Cos( -gammaVal ), 1.0 * TMath::Sin( -gammaVal ) ); break; case DecayType::GLW_CPEven_btouOnly : cpPart.setRealImagPart( 1.0 * TMath::Cos( gammaVal ), 1.0 * TMath::Sin( gammaVal ) ); cpAntiPart.setRealImagPart( 1.0 * TMath::Cos( -gammaVal ), 1.0 * TMath::Sin( -gammaVal ) ); break; case DecayType::ADS_Favoured_btouOnly : { const Double_t rDVal { rD_->value() }; const Double_t deltaDVal { deltaD_->value() }; cpPart.setRealImagPart( rDVal * TMath::Cos( -deltaDVal + gammaVal ), rDVal * TMath::Sin( -deltaDVal + gammaVal ) ); cpAntiPart.setRealImagPart( rDVal * TMath::Cos( -deltaDVal - gammaVal ), rDVal * TMath::Sin( -deltaDVal - gammaVal ) ); break; } case DecayType::ADS_Suppressed_btouOnly : cpPart.setRealImagPart( 1.0 * TMath::Cos( gammaVal ), 1.0 * TMath::Sin( gammaVal ) ); cpAntiPart.setRealImagPart( 1.0 * TMath::Cos( -gammaVal ), 1.0 * TMath::Sin( -gammaVal ) ); break; } const LauComplex partCoeff { nonCPPart * cpPart }; const LauComplex antiCoeff { nonCPPart * cpAntiPart }; const Double_t numer { antiCoeff.abs2() - partCoeff.abs2() }; const Double_t denom { antiCoeff.abs2() + partCoeff.abs2() }; const Double_t value { numer/denom }; // is it fixed? const Bool_t fixed { gamma_->fixed() }; acp_.fixed(fixed); // we can't work out the error without the covariance matrix const Double_t error{0.0}; // set the value and error acp_.valueAndErrors(value,error); return acp_; } LauPolarGammaCPCoeffSet* LauPolarGammaCPCoeffSet::createClone_impl(const TString& newName, const CloneOption cloneOption, const Double_t constFactor, const nlohmann::json& coeffInfo) const { if ( ! ( cloneOption == CloneOption::All || cloneOption == CloneOption::TieRealPart || cloneOption == CloneOption::TieImagPart || cloneOption == CloneOption::TieCPPars ) ) { std::cerr << "ERROR in LauPolarGammaCPCoeffSet::createClone : Invalid clone option" << std::endl; return nullptr; } auto clone = new LauPolarGammaCPCoeffSet{ *this, cloneOption, constFactor, coeffInfo }; clone->name( newName ); return clone; } -std::ostream& operator<<( std::ostream& os, const LauPolarGammaCPCoeffSet::DecayType type ) -{ - using DecayType = LauPolarGammaCPCoeffSet::DecayType; - - switch ( type ) { - case DecayType::GLW_CPOdd : - os << "GLW_CPOdd"; - break; - case DecayType::GLW_CPEven : - os << "GLW_CPEven"; - break; - case DecayType::ADS_Favoured : - os << "ADS_Favoured"; - break; - case DecayType::ADS_Suppressed : - os << "ADS_Suppressed"; - break; - case DecayType::GLW_CPOdd_btouOnly : - os << "GLW_CPOdd_btouOnly"; - break; - case DecayType::GLW_CPEven_btouOnly : - os << "GLW_CPEven_btouOnly"; - break; - case DecayType::ADS_Favoured_btouOnly : - os << "ADS_Favoured_btouOnly"; - break; - case DecayType::ADS_Suppressed_btouOnly : - os << "ADS_Suppressed_btouOnly"; - break; - } - - return os; -} - void LauPolarGammaCPCoeffSet::serialiseToJson( nlohmann::json& j ) const { // Call the base class method to do most of the work LauAbsCoeffSet::serialiseToJson(j); const LauPolarGammaCPCoeffSet::DecayType decayType { this->decayType() }; j["decayType"] = decayType; j["useGlobalGamma"] = this->useGlobalGamma(); j["useGlobalADSPars"] = this->useGlobalADSPars(); if ( this->useGlobalGamma() && gamma_->clone() ) { j["gamma"] = gamma_->value(); j["gammaFixed"] = gamma_->fixed(); j["gammaSecondStage"] = gamma_->secondStage(); } if ( this->useGlobalADSPars() && rD_ && rD_->clone() ) { j["rD"] = rD_->value(); j["rDFixed"] = rD_->fixed(); j["rDSecondStage"] = rD_->secondStage(); } if ( this->useGlobalADSPars() && deltaD_ && deltaD_->clone() ) { j["deltaD"] = deltaD_->value(); j["deltaDFixed"] = deltaD_->fixed(); j["deltaDSecondStage"] = deltaD_->secondStage(); } } //! \cond DOXYGEN_IGNORE LauPolarGammaCPCoeffSet nlohmann::adl_serializer::from_json(const json& j) { using LauJsonTools::JsonType; using LauJsonTools::getValue; using LauJsonTools::getOptionalValue; using DecayType = LauPolarGammaCPCoeffSet::DecayType; const auto type { getValue( j, "type" ) }; if ( type != LauCoeffType::PolarGammaCP ) { throw LauWrongCoeffType("Wrong coefficient type given to construct LauPolarGammaCPCoeffSet"); } const auto clone { getValue( j, "clone" ) }; if ( clone ) { throw LauClonedCoeff{"Cannot build a cloned LauPolarGammaCPCoeffSet standalone"}; } const auto decayType { getValue( j, "decayType" ) }; std::vector mandatoryElements { std::make_pair("X", JsonType::Number), std::make_pair("XFixed", JsonType::Boolean), std::make_pair("Y", JsonType::Number), std::make_pair("YFixed", JsonType::Boolean), std::make_pair("gamma", JsonType::Number), std::make_pair("gammaFixed", JsonType::Boolean) }; if ( decayType == DecayType::ADS_Favoured || decayType == DecayType::ADS_Suppressed || decayType == DecayType::GLW_CPOdd || decayType == DecayType::GLW_CPEven ) { mandatoryElements.push_back( std::make_pair( "rB", JsonType::Number ) ); mandatoryElements.push_back( std::make_pair( "rBFixed", JsonType::Boolean ) ); mandatoryElements.push_back( std::make_pair( "deltaB", JsonType::Number ) ); mandatoryElements.push_back( std::make_pair( "deltaBFixed", JsonType::Boolean ) ); } if ( decayType == DecayType::ADS_Favoured || decayType == DecayType::ADS_Suppressed || decayType == DecayType::ADS_Favoured_btouOnly ) { mandatoryElements.push_back( std::make_pair( "rD", JsonType::Number ) ); mandatoryElements.push_back( std::make_pair( "rDFixed", JsonType::Boolean ) ); mandatoryElements.push_back( std::make_pair( "deltaD", JsonType::Number ) ); mandatoryElements.push_back( std::make_pair( "deltaDFixed", JsonType::Boolean ) ); } if ( ! LauJsonTools::checkObjectElements( j, mandatoryElements ) ) { throw LauJsonTools::MissingJsonElement{"Missing elements needed to construct LauPolarGammaCPCoeffSet"}; } const auto name { getValue( j, "name" ) }; const auto useGlobalGamma { getOptionalValue( j, "useGlobalGamma", JsonType::Boolean ).value_or( kFALSE ) }; const auto useGlobalADSPars { getOptionalValue( j, "useGlobalADSPars", JsonType::Boolean ).value_or( kFALSE ) }; const auto x { getValue( j, "X" ) }; const auto xFixed { getValue( j, "XFixed" ) }; const auto y { getValue( j, "Y" ) }; const auto yFixed { getValue( j, "YFixed" ) }; const auto gamma { getValue( j, "gamma" ) }; const auto gammaFixed { getValue( j, "gammaFixed" ) }; const auto gammaSecondStage { getOptionalValue( j, "gammaSecondStage", JsonType::Boolean ).value_or( kFALSE ) }; Double_t rB{0.0}; Bool_t rBFixed{kTRUE}; Bool_t rBSecondStage{kFALSE}; Double_t deltaB{0.0}; Bool_t deltaBFixed{kTRUE}; Bool_t deltaBSecondStage{kFALSE}; Double_t rD{0.0}; Bool_t rDFixed{kTRUE}; Bool_t rDSecondStage{kFALSE}; Double_t deltaD{0.0}; Bool_t deltaDFixed{kTRUE}; Bool_t deltaDSecondStage{kFALSE}; if ( decayType == DecayType::ADS_Favoured || decayType == DecayType::ADS_Suppressed || decayType == DecayType::GLW_CPOdd || decayType == DecayType::GLW_CPEven ) { rB = getValue( j, "rB" ); rBFixed = getValue( j, "rBFixed" ); rBSecondStage = getOptionalValue( j, "rBSecondStage", JsonType::Boolean ).value_or(kFALSE); deltaB = getValue( j, "deltaB" ); deltaBFixed = getValue( j, "deltaBFixed" ); deltaBSecondStage = getOptionalValue( j, "deltaBSecondStage", JsonType::Boolean ).value_or(kFALSE); } if ( decayType == DecayType::ADS_Favoured || decayType == DecayType::ADS_Suppressed || decayType == DecayType::ADS_Favoured_btouOnly ) { rD = getValue( j, "rD" ); rDFixed = getValue( j, "rDFixed" ); rDSecondStage = getOptionalValue( j, "rDSecondStage", JsonType::Boolean ).value_or(kFALSE); deltaD = getValue( j, "deltaD" ); deltaDFixed = getValue( j, "deltaDFixed" ); deltaDSecondStage = getOptionalValue( j, "deltaDSecondStage", JsonType::Boolean ).value_or(kFALSE); } LauPolarGammaCPCoeffSet coeff{ name, decayType, x, y, rB, deltaB, gamma, rD, deltaD, xFixed, yFixed, rBFixed, deltaBFixed, gammaFixed, rDFixed, deltaDFixed, rBSecondStage, deltaBSecondStage, gammaSecondStage, rDSecondStage, deltaDSecondStage, useGlobalGamma, useGlobalADSPars }; coeff.applyBlinding( j ); return coeff; } //! \endcond