diff --git a/inc/LauAbsCoeffSet.hh b/inc/LauAbsCoeffSet.hh index e417f0b..b34052b 100644 --- a/inc/LauAbsCoeffSet.hh +++ b/inc/LauAbsCoeffSet.hh @@ -1,517 +1,541 @@ /* 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 #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 /*! - \param [in] coeffs the collection of coefficients to be written out + \param [in] coeffs the collection of coefficients to be written out (the collection should contain either smart or raw pointers to LauAbsCoeffSet or derived types) \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) */ - static void writeToJson( const std::vector>& coeffs, const TString& fileName, const TString& elementName = "", const bool append = false, const int indent = 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, { {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, { {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 DOXYGEN_IGNORE #endif diff --git a/src/LauAbsCoeffSet.cc b/src/LauAbsCoeffSet.cc index 75f5ed0..cc7dcde 100644 --- a/src/LauAbsCoeffSet.cc +++ b/src/LauAbsCoeffSet.cc @@ -1,482 +1,462 @@ /* 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::to_json : 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; } -void LauAbsCoeffSet::writeToJson( const std::vector>& 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; - } -} - 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; }