diff --git a/.ci/build_docs.sh b/.ci/build_docs.sh new file mode 100644 index 00000000000..9a8453ba881 --- /dev/null +++ b/.ci/build_docs.sh @@ -0,0 +1,111 @@ +#!/bin/sh +################################################################################ +# Title : generateDocumentationAndDeploy.sh +# Date created : 2016/02/22 +# Notes : +__AUTHOR__="Jeroen de Bruijn" +# Preconditions: +# - Packages doxygen doxygen-doc doxygen-latex doxygen-gui graphviz +# must be installed. +# - Doxygen configuration file must have the destination directory empty and +# source code directory with a $(TRAVIS_BUILD_DIR) prefix. +# - An gh-pages branch should already exist. See below for mor info on hoe to +# create a gh-pages branch. +# +# Required global variables: +# - TRAVIS_BUILD_NUMBER : The number of the current build. +# - TRAVIS_COMMIT : The commit that the current build is testing. +# - DOXYFILE : The Doxygen configuration file. +# - TRAVIS_REPO_SLUG : The username / reponame for the repository. +# - GH_REPO_TOKEN : Secure token to the github repository. +# +# For information on how to encrypt variables for Travis CI please go to +# https://docs.travis-ci.com/user/environment-variables/#Encrypted-Variables +# or https://gist.github.com/vidavidorra/7ed6166a46c537d3cbd2 +# For information on how to create a clean gh-pages branch from the master +# branch, please go to https://gist.github.com/vidavidorra/846a2fc7dd51f4fe56a0 +# +# This script will generate Doxygen documentation and push the documentation to +# the gh-pages branch of a repository specified by GH_REPO_REF. +# Before this script is used there should already be a gh-pages branch in the +# repository. +# +################################################################################ + +################################################################################ +##### Setup this script and get the current gh-pages branch. ##### +if [[ $TRAVIS_OS_NAME == "osx" ]]; then return ; fi + +echo 'Setting up the script...' +# Exit with nonzero exit code if anything fails +set -e + +GH_REPO_ORG=`echo $TRAVIS_REPO_SLUG | cut -d "/" -f 1` +GH_REPO_NAME=`echo $TRAVIS_REPO_SLUG | cut -d "/" -f 2` +GH_REPO_REF="github.com/$GH_REPO_ORG/$GH_REPO_NAME.git" + +# Create a clean working directory for this script. +# Get the current gh-pages branch +cd doc +git clone -b gh-pages https://git@$GH_REPO_REF html +cd html + +##### Configure git. +# Set the push default to simple i.e. push only the current branch. +git config --global push.default simple +# Pretend to be an user called Travis CI. +git config user.name "Travis CI" +git config user.email "travis@travis-ci.org" + +# Remove everything currently in the gh-pages branch. +# GitHub is smart enough to know which files have changed and which files have +# stayed the same and will only update the changed files. So the gh-pages branch +# can be safely cleaned, and it is sure that everything pushed later is the new +# documentation. +rm -rf * + +# Need to create a .nojekyll file to allow filenames starting with an underscore +# to be seen on the gh-pages site. Therefore creating an empty .nojekyll file. +# Presumably this is only needed when the SHORT_NAMES option in Doxygen is set +# to NO, which it is by default. So creating the file just in case. +echo "" > .nojekyll + +################################################################################ +##### Generate the Doxygen code documentation and log the output. ##### +echo 'Generating Doxygen code documentation...' +# Redirect both stderr and stdout to the log file AND the console. +cd .. + +doxygen --version + +doxygen $DOXYFILE 2>&1 | tee doxygen.log + +################################################################################ +##### Upload the documentation to the gh-pages branch of the repository. ##### +# Only upload if Doxygen successfully created the documentation. +# Check this by verifying that the html directory and the file html/index.html +# both exist. This is a good indication that Doxygen did it's work. +if [ -d "html" ] && [ -f "html/index.html" ]; then + + cd html + echo 'Uploading documentation to the gh-pages branch...' + # Add everything in this directory (the Doxygen code documentation) to the + # gh-pages branch. + # GitHub is smart enough to know which files have changed and which files have + # stayed the same and will only update the changed files. + git add --all + + # Commit the added files with a title and description containing the Travis CI + # build number and the GitHub commit reference that issued this build. + git commit -m "Deploy code docs to GitHub Pages Travis build: ${TRAVIS_BUILD_NUMBER}" -m "Commit: ${TRAVIS_COMMIT}" + + # Force push to the remote gh-pages branch. + # The ouput is redirected to /dev/null to hide any sensitive credential data + # that might otherwise be exposed. + git push --force "https://${GH_REPO_TOKEN}@${GH_REPO_REF}" > /dev/null 2>&1 +else + echo '' >&2 + echo 'Warning: No documentation (html) files have been found!' >&2 + echo 'Warning: Not going to push the documentation to GitHub!' >&2 + exit 1 +fi diff --git a/.ci/build_root.sh b/.ci/build_root.sh new file mode 100755 index 00000000000..865eb1eec92 --- /dev/null +++ b/.ci/build_root.sh @@ -0,0 +1,19 @@ +pushd $DEPS_DIR +set -evx + +os=$1 +if [[ $os == "osx" ]] ; then + wget -nv http://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda_${os}.sh +elif [[ $os == "linux" ]] ; then + wget -nv http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda_${os}.sh +fi + +bash miniconda_${os}.sh -b -p $DEPS_DIR/miniconda +export PATH="$DEPS_DIR/miniconda/bin:$PATH" +hash -r +conda config --add channels conda-forge + +conda create --yes -n env_${os} root doxygen -c conda-forge + +set +evx +popd diff --git a/.ci/build_root_linux.sh b/.ci/build_root_linux.sh new file mode 100755 index 00000000000..6c184476362 --- /dev/null +++ b/.ci/build_root_linux.sh @@ -0,0 +1,20 @@ +pushd $DEPS_DIR + +if [[ $1 == "osx" ]] ; then + wget -nv http://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda.sh +elif [[ $1 == "linux" ]] ; then + wget -nv http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh +fi + +bash miniconda.sh -b -p $DEPS_DIR/miniconda +export PATH="$DEPS_DIR/miniconda/bin:$PATH" +hash -r +conda config --add channels conda-forge +conda config --set channel_priority strict + +# conda install --quiet --yes -c conda-forge/label/gcc8 root_base doxygen +conda create --quiet --yes -n my_root_env root doxygen zstd=1.3.7 -c conda-forge +# conda init bash +# source "$DEPS_DIR/miniconda/bin/thisroot.sh" +# export CXX="$DEPS_DIR/miniconda/bin/g++" +popd diff --git a/.ci/build_root_osx.sh b/.ci/build_root_osx.sh new file mode 100644 index 00000000000..33d47b5f33f --- /dev/null +++ b/.ci/build_root_osx.sh @@ -0,0 +1,17 @@ +pushd $DEPS_DIR + +wget -nv https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O ~/miniconda.sh +bash ~/miniconda.sh -b -p $DEPS_DIR/miniconda +export PATH="$DEPS_DIR/miniconda/bin:$PATH" +hash -r +conda config --add channels conda-forge +conda install --quiet --yes -c conda-forge root +. $DEPS_DIR/miniconda/etc/profile.d/conda.sh +conda activate root +# . "/home/tim/miniconda/etc/profile.d/conda.sh" +# else +# export PATH="/home/tim/miniconda/bin:$PATH" + +# source "$DEPS_DIR/miniconda/bin/thisroot.sh" +popd + diff --git a/.ci/travis_linux.sh b/.ci/travis_linux.sh new file mode 100755 index 00000000000..e63c2fbfd9d --- /dev/null +++ b/.ci/travis_linux.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -evx +# from https://stackoverflow.com/questions/55342122/conda-activate-on-travis-ci +export PATH="$DEPS_DIR/miniconda/bin:$PATH" +. $(conda info --root)/etc/profile.d/conda.sh +conda activate env_${TRAVIS_OS_NAME} + +echo -en 'travis_fold:start:script.build\\r' +echo "Building..." +echo "Building under OS: $TRAVIS_OS_NAME, CXX =$CXX" +echo "Directories: DEPS_DIR=$DEPS_DIR; TRAVIS_BUILD_DIR=$TRAVIS_BUILD_DIR" +mkdir -p build +cd build +cmake .. -DENABLE_INSTALL=0 +cmake --build . -- -j2 + +set +evx + +cd .. + +./build/bin/AmpGen.exe options/example_b2kstarll.opt --CompilerWrapper::Verbose --nEvents 10000 + diff --git a/.ci/travis_osx.sh b/.ci/travis_osx.sh new file mode 100644 index 00000000000..133a2d1d8a1 --- /dev/null +++ b/.ci/travis_osx.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +. $(conda info --root)/etc/profile.d/conda.sh +conda activate env_${TRAVIS_OS_NAME} + +echo -en 'travis_fold:start:script.build\\r' +echo "Building..." +echo "Building under OS: $TRAVIS_OS_NAME" + +mkdir -p build +cd build +echo "CMake-ing, CXX = $CXX" +cmake .. -DCMAKE_CXX_COMPILER=clang -DUSE_SIMD=0 -DUSE_OPENMP=0 -DENABLE_INSTALL=0 +echo "Building ..." +cmake --build . -- -j2 +cd .. +echo "Running test job ..." +./build/bin/AmpGen.exe options/example_b2kstarll.opt --CompilerWrapper::Verbose --nEvents 10000 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index eada0860293..00000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,20 +0,0 @@ -image: alpine:latest - -pages: - stage: deploy - script: - - apk update && apk add doxygen && apk add graphviz - - apk add ghostscript - - mkdir build - - cd doc - - doxygen doxyfile - - cd ../ - - mv build/html/ public - - cp doc/customdoxygen.css public/ - - mkdir public/figs/ - - cp doc/figs/*.png public/figs/. - artifacts: - paths: - - public - only: - - master diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000..84c3110f45f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,51 @@ +language: cpp + +matrix: + include: + - os: osx + osx_image: xcode10.1 + compiler: clang + addons: + homebrew: + packages: + - libomp + - os: linux + env: + - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" + + + +cache: + ccache: true + apt: true + directories: + - "${TRAVIS_BUILD_DIR}/deps/root" + - "${TRAVIS_BUILD_DIR}/deps/doxygen" + +# Blacklist +branches: + except: + - gh-pages + +# Environment variables +env: + global: + - GH_REPO_NAME: AmpGen + - DOXYFILE: $TRAVIS_BUILD_DIR/doc/doxyfile + - GH_REPO_REF: github.com/GooFit/AmpGen.git + - DEPS_DIR: "${TRAVIS_BUILD_DIR}/deps" + +before_install: + - eval "${MATRIX_EVAL}" + - chmod +x .ci/build_root.sh + - source .ci/build_root.sh ${TRAVIS_OS_NAME} + +# Build your code e.g. by calling make +script: + - chmod +x .ci/travis_${TRAVIS_OS_NAME}.sh + - source .ci/travis_${TRAVIS_OS_NAME}.sh + +# Generate and deploy documentation +after_success: + - chmod +x .ci/build_docs.sh + - source .ci/build_docs.sh diff --git a/AmpGen/ASTResolver.h b/AmpGen/ASTResolver.h index 9513347ac84..1fc44234816 100644 --- a/AmpGen/ASTResolver.h +++ b/AmpGen/ASTResolver.h @@ -17,54 +17,60 @@ namespace AmpGen { class MinuitParameter; class MinuitParameterSet; class MinuitParameterLink; - /// \class ASTResolver - /// Traverses trees in IExpression::resolveDependencies() - /// to keep track of the dependencies of the tree - /// such as sub-trees, external parameters and the event type map. + /** @ingroup ExpressionEngine class ASTResolver + @brief (Internal) class to aide in the resolution of the dependencies of expression trees. + + Traverses trees in IExpression::resolve() to keep track of the dependencies of the tree + such as sub-trees, external parameters and the mapping between particle kinematics and the + event vector. + */ class ASTResolver { public: - ASTResolver(const std::map& evtMap = {} , const MinuitParameterSet* mps = nullptr ); - bool hasSubExpressions() const; - void reduceSubTrees(); - void cleanup(); - void getOrderedSubExpressions( Expression& expression, std::vector>& dependentSubexpressions ); + ASTResolver(const std::map& evtMap = {} , const MinuitParameterSet* mps = nullptr ); + std::vector> getOrderedSubExpressions( const Expression& expression); template void resolve( const TYPE& obj ){} template size_t addCacheFunction( const std::string& name, const ARGS&... args ) { auto it = m_cacheFunctions.find(name); if( it != m_cacheFunctions.end() ) return it->second->address(); - auto cacheFunction = std::make_shared(nParameters, args... ); + auto cacheFunction = std::make_shared(m_nParameters, name, args... ); m_cacheFunctions[name] = cacheFunction; - nParameters += cacheFunction->size(); - return nParameters - cacheFunction->size(); + m_nParameters += cacheFunction->size(); + return m_nParameters - cacheFunction->size(); } - size_t nParams() const { return nParameters ; } - bool enableCuda() const { return enable_cuda ; } - bool enableCompileConstants() const { return enable_compileTimeConstants ;} + size_t nParams() const { return m_nParameters ; } + bool enableCuda() const { return m_enable_cuda ; } + bool enableAVX() const { return m_enable_avx; } + bool enableCompileConstants() const { return m_enable_compileTimeConstants ;} + void setEnableAVX(){ m_enable_avx = true ; } std::map> cacheFunctions() const; void addResolvedParameter(const IExpression* param, const std::string& thing); void addResolvedParameter(const IExpression* param, const size_t& address, const size_t& arg=0); std::string resolvedParameter( const IExpression* param ) const; + + void clear(); + std::map parameters() const { return m_resolvedParameters; } private: - std::map m_resolvedParameters; - std::map> m_cacheFunctions; - std::map evtMap; /// event specification - std::map parameterMapping; /// Mapping of parameters to compile parameters - const MinuitParameterSet* mps; /// Set of MinuitParameters - std::map tempTrees; /// temporary store of sub-trees for performing cse reduction - std::map subTrees; /// Unordered sub-trees - unsigned int nParameters; /// Number of parameters - bool enable_cuda; /// flag to generate CUDA code <> - bool enable_compileTimeConstants; /// flag to enable compile time constants <> - + std::map m_resolvedParameters; /// Map of parameters that have been resolved + std::map> m_cacheFunctions; /// Container of functions for calculating function cache + std::map m_evtMap; /// Event specification + std::map m_parameterMapping; /// Mapping of parameters to compile parameters + const MinuitParameterSet* m_mps; /// Set of MinuitParameters + std::map m_tempTrees; /// temporary store of sub-trees for performing cse reduction + unsigned int m_nParameters; /// Number of parameters + bool m_enable_cuda {false}; /// flag to generate CUDA code <> + bool m_enable_compileTimeConstants {false}; /// flag to enable compile time constants <> + bool m_enable_avx {false}; /// flag to generate code using AVX instructions <> + bool m_check_hashes {false}; /// flag to check that hashes are unique }; template <> void ASTResolver::resolve( const Parameter& obj ); template <> void ASTResolver::resolve ( const SubTree & obj ); template <> void ASTResolver::resolve ( const Spline & obj ); template <> void ASTResolver::resolve( const MinuitParameterLink& obj ); + template <> void ASTResolver::resolve( const LambdaExpression& obj); } diff --git a/AmpGen/AddCPConjugate.h b/AmpGen/AddCPConjugate.h new file mode 100644 index 00000000000..40bb9011540 --- /dev/null +++ b/AmpGen/AddCPConjugate.h @@ -0,0 +1,6 @@ + +namespace AmpGen { + class MinuitParameterSet; + + void AddCPConjugate(MinuitParameterSet&); +} diff --git a/AmpGen/AmplitudeRules.h b/AmpGen/AmplitudeRules.h index a3b53f6c6fa..57e30519d34 100644 --- a/AmpGen/AmplitudeRules.h +++ b/AmpGen/AmplitudeRules.h @@ -13,105 +13,120 @@ #include "AmpGen/CompiledExpression.h" #include "AmpGen/Event.h" #include "AmpGen/Particle.h" +#include "AmpGen/ExpressionParser.h" +#if ENABLE_AVX + #include "AmpGen/EventListSIMD.h" +#endif namespace AmpGen { - class AmplitudeRules; class MinuitParameter; + class MinuitExpression; class MinuitParameterSet; - class CouplingConstant; - class AmplitudeRule + class Coupling { public: - AmplitudeRule( const std::string& reName, const std::map& mapping ); + Coupling(MinuitParameter* re, MinuitParameter* im); + Coupling(MinuitExpression* expression); std::string name() const { return m_name; } std::string head() const { return m_particle.name(); } std::string prefix() const { return m_prefix; } EventType eventType() const; - friend class CouplingConstant; - friend class AmplitudeRules; - + MinuitParameter* x() const { return m_re; } + MinuitParameter* y() const { return m_im; } + complex_t operator()() const; + Expression to_expression() const; + const Particle& particle() const { return m_particle ; } + bool isCartesian() const { return m_isCartesian; } private: - std::string m_prefix; - std::string m_name; - MinuitParameter* m_re; - MinuitParameter* m_im; - bool m_isGood; - Particle m_particle; + std::string m_prefix = {""}; + std::string m_name = {""}; + MinuitParameter* m_re = {nullptr}; + MinuitParameter* m_im = {nullptr}; + MinuitExpression* m_expr = {nullptr}; + Particle m_particle; + bool m_isCartesian = {true}; + double m_sf = {1}; }; - class AmplitudeRules - { - public: - AmplitudeRules() = default; - AmplitudeRules( const MinuitParameterSet& mps ); - std::vector rulesForDecay(const std::string& head, const std::string& prefix=""); - bool hasDecay( const std::string& head ); - std::map> rules(); - std::vector> getMatchingRules( - const EventType& type, const std::string& prefix ); - std::vector processesThatProduce(const Particle& particle) const; - private: - std::map> m_rules; - }; - - class CouplingConstant + class TotalCoupling { public: - CouplingConstant() = default; - CouplingConstant( const CouplingConstant& other, const AmplitudeRule& pA); - CouplingConstant( const AmplitudeRule& pA); + TotalCoupling() = default; + TotalCoupling( const TotalCoupling& other, const Coupling& pA); + TotalCoupling( const Coupling& pA); std::complex operator()() const; Expression to_expression() const; void print() const; - std::pair operator[]( const size_t& index ) { return couplings[index]; } + Coupling operator[]( const size_t& index ) { return couplings[index]; } bool isFixed() const; bool contains( const std::string& name ) const; - void changeSign(); - std::vector> couplings; + size_t size() const { return couplings.size(); } + std::vector::const_iterator begin() const { return couplings.begin() ; } + std::vector::const_iterator end() const { return couplings.end() ; } + private: + std::vector couplings; + }; + + class AmplitudeRules + { + public: + AmplitudeRules() = default; + AmplitudeRules( const MinuitParameterSet& mps ); + std::vector rulesForDecay(const std::string& head, const std::string& prefix=""); + bool hasDecay( const std::string& head ); + const std::map>& rules() const; + std::vector> getMatchingRules( + const EventType& type, const std::string& prefix="" ); + std::vector processesThatProduce(const Particle& particle) const; private: - bool isCartesian = {true}; - double sf = {1}; + std::map> m_rules; }; - template struct TransitionMatrix + template struct TransitionMatrix : public CompiledExpression { + using amp_type = CompiledExpression; TransitionMatrix() = default; TransitionMatrix(const Particle& dt, - const CouplingConstant& coupling, - const CompiledExpression & pdf) : + const TotalCoupling& coupling, + const amp_type& amp) : + amp_type(amp), decayTree(dt), - coupling(coupling), - pdf(pdf) {} + coupling(coupling) {} - TransitionMatrix(Particle& dt, - const CouplingConstant& coupling, + TransitionMatrix(const Particle& dt, + const TotalCoupling& coupling, const MinuitParameterSet& mps, - const std::map& evtFormat, + const std::map& evtFormat, const bool& debugThis=false) : + amp_type(Particle(dt).getExpression(debugThis ? &db : nullptr ), dt.decayDescriptor(), evtFormat, db, &mps ), decayTree(dt), - coupling(coupling) - { - DebugSymbols db; - auto expression = dt.getExpression(debugThis ? &db : nullptr); - pdf = CompiledExpression - (expression, dt.decayDescriptor(), evtFormat, debugThis ? db : DebugSymbols(), &mps ); - } + coupling(coupling) {} - const RT operator()(const Event& event) const { return pdf(event.address() ); } + #if ENABLE_AVX + const RT operator()(const Event& event) const { return amp_type::operator()(EventListSIMD::makeEvent(event).data()); } + void debug( const Event& event ) const { amp_type::debug(EventListSIMD::makeEvent(event).data() ) ; } + + #else + const RT operator()(const Event& event) const { return amp_type::operator()(event.address()) ; } + void debug( const Event& event ) const { amp_type::debug(event.address()) ; } + #endif + template auto operator()(arg_types... args ) const { return amp_type::operator()(args...) ; } + + const RT operator()(const float_v* t) const { return amp_type::operator()(t) ; } + void debug( const float_v* t ) const { amp_type::debug(t) ; } const std::string decayDescriptor() const { return decayTree.decayDescriptor() ; } Particle decayTree; - CouplingConstant coupling; + TotalCoupling coupling; complex_t coefficient; - CompiledExpression pdf; - size_t addressData = {999}; + DebugSymbols db; + bool workToDo = {false}; }; - template - std::vector processIndex(const std::vector>& tm, const std::string& label) + template std::vector processIndex(const std::vector>& tm, const std::string& label) { std::vector indices; for ( size_t i = 0; i < tm.size(); ++i ) { @@ -120,8 +135,7 @@ namespace AmpGen return indices; } - template - size_t findIndex(const std::vector>& tm, const std::string& decayDescriptor) + template size_t findIndex(const std::vector>& tm, const std::string& decayDescriptor) { for ( size_t i = 0; i < tm.size(); ++i ) { if ( tm[i].decayDescriptor() == decayDescriptor ) return i; @@ -139,7 +153,54 @@ namespace AmpGen } return rt; } + + template <> struct TransitionMatrix : public CompiledExpression + { + using amp_type = CompiledExpression; + TransitionMatrix() = default; + TransitionMatrix(const Particle& dt, + const TotalCoupling& coupling, + const amp_type& amp) : + amp_type(amp), + decayTree(dt), + coupling(coupling) {} + + TransitionMatrix(const Particle& dt, + const TotalCoupling& coupling, + const MinuitParameterSet& mps, + const std::map& evtFormat, + const bool& debugThis=false) : + amp_type(Particle(dt).getExpression(debugThis ? &db : nullptr ), dt.decayDescriptor(), evtFormat, db, &mps ), + decayTree(dt), + coupling(coupling) + { use_rto();} + + const std::vector operator()(const Event& event) const + { + std::vector rt(size); + #if ENABLE_AVX + amp_type::operator()(rt.data(), 1, externBuffer().data(), EventListSIMD::makeEvent(event).data()); + #else + amp_type::operator()(rt.data(), 1, externBuffer().data(), event.address()); + #endif + return rt; + } + template auto operator()(arg_types... args ) const { return amp_type::operator()(args...) ; } + #if ENABLE_AVX + void debug( const Event& event ) const { amp_type::debug(EventListSIMD::makeEvent(event).data() ) ; } + #else + void debug( const Event& event ) const { amp_type::debug(event.address()) ; } + #endif + const std::string decayDescriptor() const { return decayTree.decayDescriptor() ; } + Particle decayTree; + TotalCoupling coupling; + complex_t coefficient; + DebugSymbols db; + bool workToDo = {false}; + unsigned size = {0}; + }; + } // namespace AmpGen #endif diff --git a/AmpGen/ArgumentPack.h b/AmpGen/ArgumentPack.h index 90b66758d0f..a9e745a7750 100644 --- a/AmpGen/ArgumentPack.h +++ b/AmpGen/ArgumentPack.h @@ -7,94 +7,94 @@ #include #include - namespace AmpGen { + #define DECLARE_ARGUMENT(X, Y) \ + struct X : public AmpGen::Argument { \ + template \ + explicit X(Z val = Z()) : AmpGen::Argument(val){} \ + X() : AmpGen::Argument(){} \ + } + /** @class IArgument + @brief Virtual base class for arguments + Named arguments to functions (python-style) are given a virtual base class such + that they can be stored into an argument pack. Relies on runtime polymorphism + and should be kept away from any code that has to be fast. + */ struct IArgument { - virtual ~IArgument() = default; + virtual ~IArgument() = default; }; + /** @class Argument - Structure to flexibly pass blocks of "Named" parameters to functions, to - approximate the behaviour of python's named arguments. - Typical usage is for constructors with variable arguments, such as - to read data from the disk. The interface for the user is typically - \code{cpp} - EventList events("files.root", - type, - GetGenPDF(true), - WeightBranch("eventWeight"), - Branches({"K_PX","K_PY",...})); - \endcode - Internally these arguments are used to construct an ArgumentPack, and then read out - using getArg, so for this example: - \code{cpp} - auto pdfSize = args.getArg().val; - auto filter = args.getArg().val; - auto getGenPdf = args.getArg(true).val; - auto weightBranch = args.getArg().val; - auto branches = args.getArg().val; - auto applySym = args.getArg().val; - auto entryList = args.getArg().val; - \endcode - @tparam: TYPE type of the argument, such as a string, a number, a bool etc. - */ - template struct Argument : public IArgument + @brief Structure to pass "named" parameters to functions. + Structure to flexibly pass blocks of "Named" parameters to functions, to + approximate the behaviour of Python's named arguments. + Typical usage is for constructors with variable arguments, such as + to read data from the disk. The interface for the user is typically + \code{cpp} + EventList events("files.root", + type, + GetGenPDF(true), + WeightBranch("eventWeight"), + Branches({"K_PX","K_PY",...})); + \endcode + Internally these arguments are used to construct an ArgumentPack, and then read out + using getArg, so for this example: + \code{cpp} + auto pdfSize = args.getArg().val; + auto filter = args.getArg().val; + auto getGenPdf = args.getArg(true).val; + auto weightBranch = args.getArg().val; + auto branches = args.getArg().val; + auto applySym = args.getArg().val; + auto entryList = args.getArg().val; + \endcode + @tparam TYPE Type of the argument, such as a string, a number, a bool etc. + */ + template + struct Argument : public IArgument { - Argument( const TYPE& x = TYPE() ) : val( x ) {} + template + explicit Argument( T x ) : val(x) {} + Argument() = default; operator TYPE() const { return val; } - TYPE val; - }; - - template struct ArgumentPtr : public IArgument - { - ArgumentPtr( TYPE* x = nullptr ) : val( x ) {} - TYPE* val; - }; - - struct File : public IArgument - { - std::string name; - std::ios_base::openmode mode; - File( const std::string& name = "", const std::ios_base::openmode& mode = std::ios_base::in ) - : name( name ), mode( mode ){}; + TYPE val = { TYPE() }; }; + /** @class ArgumentPack + @brief Container for a set of arguments + Contains a set of arguments packed from a variadic constructor, that can + then be unpacked in the call site of the function where the named arguments + are required, as per the description in Argument. + */ class ArgumentPack { public: - template - ArgumentPack( const ARGS&... args ) + template + explicit ArgumentPack( const ARGS&... args ) { std::tuple argTuple( args... ); - for_each( argTuple, [this]( auto& f ) { m_parameters.emplace_back( makeShared( f ) ); } ); + for_each(argTuple, [this](const auto& f){ this->addArgument(f) ; } ); } - template - ARG getArg( const ARG& default_argument = ARG() ) const + template arg_type* get() const + { + for( const auto& param : m_parameters ) { - for ( auto& param : m_parameters ) { - auto ptr = dynamic_cast( param.get() ); - if ( ptr != nullptr ) return *ptr; - } - return default_argument; + auto ptr = dynamic_cast(param.get()); + if( ptr != nullptr ) return ptr; } + return nullptr; + } + template + arg_type getArg( const default_arg_type& default_argument = default_arg_type() ) const + { + auto p = get(); + return p == nullptr ? arg_type(default_argument) : *p; + } private: std::vector> m_parameters; + template void addArgument( const T& f ){ m_parameters.emplace_back( std::make_shared(f) ) ; } }; -#define DECLARE_ARGUMENT( X, Y ) \ - struct X : public AmpGen::Argument { \ - X( const Y& val = Y() ) : AmpGen::Argument( val ){}; \ - } - -#define DECLARE_ARGUMENT_PTR( X, Y ) \ - struct X : public AmpGen::ArgumentPtr { \ - X( Y* val = nullptr ) : AmpGen::ArgumentPtr( val ){}; \ - } - -#define DECLARE_ARGUMENT_DEFAULT( X, Y, Z ) \ - struct X : public AmpGen::Argument { \ - X( const Y& val = Z ) : AmpGen::Argument( val ){}; \ - } - } // namespace AmpGen #endif diff --git a/AmpGen/Array.h b/AmpGen/Array.h index 92aeae0310e..312cd465e08 100644 --- a/AmpGen/Array.h +++ b/AmpGen/Array.h @@ -15,22 +15,27 @@ namespace AmpGen { class ASTResolver; - + + /** @ingroup ExpressionEngine class Array + @brief Expression for a fixed size array of values. + Expression for an array, i.e. a set of values with an index. + Can be used to return an expression from the array, which is resolved at (second) compile time. + */ class Array : public IExpression { public: Array( const Expression& top, const size_t& size, const Expression& address = 0 ); std::string to_string(const ASTResolver* resolver=nullptr) const override ; - void resolve( ASTResolver& resolver ) override; + void resolve( ASTResolver& resolver ) const override; operator Expression(); complex_t operator()() const override; Expression operator[]( const Expression& address ) const; Expression top() const { return m_top ; } - + unsigned size() const { return m_size; } private: Expression m_top; Expression m_address; - size_t m_size; + unsigned m_size; }; } // namespace AmpGen diff --git a/AmpGen/BinDT.h b/AmpGen/BinDT.h index 20b00c73ecb..386c55a6cad 100644 --- a/AmpGen/BinDT.h +++ b/AmpGen/BinDT.h @@ -15,31 +15,23 @@ #include #include "AmpGen/ArgumentPack.h" -#include "AmpGen/EventList.h" #include "AmpGen/MsgService.h" #include "AmpGen/Types.h" +#include "AmpGen/EventList.h" namespace AmpGen { class Event; - #define PACKET_SIZE 22 DECLARE_ARGUMENT(MaxDepth, size_t ); DECLARE_ARGUMENT(MinEvents, size_t ); DECLARE_ARGUMENT(Dim, size_t ); - DECLARE_ARGUMENT_PTR( Stream, std::ifstream ); - DECLARE_ARGUMENT_DEFAULT( Functor, std::function( const Event& )>, nullptr ); + DECLARE_ARGUMENT(Functor, std::function( const Event& )>); + DECLARE_ARGUMENT(File, std::string); class BinDT { public: - struct AddressCompressor - { - AddressCompressor() = default; - uint32_t operator[]( const void* ptr ); - uint32_t counter = {0}; - std::map elements; - }; class EndNode; class INode @@ -77,7 +69,9 @@ namespace AmpGen void serialize( std::ostream& stream ) const override; void setChildren( std::shared_ptr l, std::shared_ptr r ); void visit( const std::function& visit_function ) override; + friend class BinDT; + private : std::shared_ptr m_left; std::shared_ptr m_right; @@ -95,62 +89,65 @@ namespace AmpGen { m_top = makeNodes( addr ); } - template - BinDT( const EventList& events, const ARGS&... args ) : BinDT( ArgumentPack( args... ) ) + template BinDT( const EventList& events, const ARGS&... args ) : BinDT(ArgumentPack(args...) ) + { + m_top = makeNodes( events.begin(), events.end() ); + } + template BinDT( const iterator_type& begin, + const iterator_type& end, const ARGS&... args ) : BinDT(ArgumentPack( args... ) ) { - std::vector data( m_dim * events.size() ); - std::vector addresses( events.size() ); - size_t counter = 0; - for ( auto& evt : events ) { - auto val = m_functors( evt ); - for ( unsigned int i = 0; i < m_dim; ++i ) data[m_dim * counter + i] = val[i]; - addresses[counter] = &( data[m_dim * counter] ); - counter++; - } - INFO( "Making nodes" ); - m_top = makeNodes( addresses ); + m_top = makeNodes(begin, end ); } - BinDT( const ArgumentPack& args ); + explicit BinDT( const ArgumentPack& args ); + BinDT( const EventList& events, const ArgumentPack& args ); BinDT() = default; std::shared_ptr top() { return m_top; } - double nnUniformity( std::vector evts, const unsigned int& index ) const; unsigned int getBinNumber( const Event& evt ) const; unsigned int getBinNumber( const double* evt ) const; unsigned int getBin( const Event& evt ) const; unsigned int getBin( const double* evt ) const; unsigned int size() const; void readFromStream( std::istream& stream ); - void readFromBinary( std::ifstream& stream ); void serialize( std::ofstream& output ); void serialize( const std::string& filename ); - void writeToBinary( std::ofstream& file ); - void setQueueOrdering( const std::vector& queueOrdering ){ m_queueOrdering = queueOrdering ; } + void setQueueOrdering( const std::vector& queueOrdering ){ m_queueOrdering = queueOrdering ; } std::vector>& nodes() { return m_endNodes; } const std::vector>& const_nodes() const { return m_endNodes; } std::vector>::iterator begin() { return m_endNodes.begin(); } std::vector>::iterator end() { return m_endNodes.end(); } std::function( const Event& )> makeDefaultFunctors(); - void refreshQueue( const std::vector& evts, std::queue& indexQueue, - const unsigned int& depth ); - std::shared_ptr makeNodes( std::vector evts, std::queue indexQueue, - const unsigned int& depth ); - std::shared_ptr makeNodes( std::vector evts ); - std::shared_ptr makeNodes( std::vector source, std::vector target ); - - std::shared_ptr makeNodes( std::vector source, std::vector target, - std::queue indexQueue, const unsigned int& depth ); - void setFunctor( const std::function( const Event& )>& functors ) { m_functors = functors; } - + void refreshQueue(const std::vector&, std::queue&, const unsigned&); + template + std::shared_ptr makeNodes(const iterator_type& begin, const iterator_type& end) + { + std::vector data( m_dim * (end-begin) ); + std::vector addresses( end-begin ); + size_t counter = 0; + for ( auto evt = begin; evt != end; ++evt ) + { + auto val = m_functors( *evt ); + for ( unsigned int i = 0; i < m_dim; ++i ) data[m_dim * counter + i] = val[i]; + addresses[counter] = &( data[m_dim * counter] ); + counter++; + } + return makeNodes( addresses ); + } + std::shared_ptr makeNodes(const std::vector&, std::queue, const unsigned&); + std::shared_ptr makeNodes(const std::vector&); + std::shared_ptr makeNodes(const std::vector&, const std::vector&); + std::shared_ptr makeNodes(std::vector, std::vector, std::queue, const unsigned&); + void setFunctor(const std::function( const Event& )>& functors) { m_functors = functors; } private: - std::shared_ptr m_top; - unsigned int m_dim; - std::vector> m_endNodes; - std::function( const Event& )> m_functors; - unsigned int m_minEvents; - unsigned int m_maxDepth; - std::vector m_queueOrdering; + std::shared_ptr m_top = {nullptr}; + unsigned m_dim = {0}; + unsigned m_minEvents = {0}; + unsigned m_maxDepth = {0}; + std::vector m_queueOrdering = {}; + std::vector> m_endNodes = {}; + std::function(const Event&)> m_functors = {}; double getBestPost(const std::vector& source, const std::vector& target, int index, bool verbose = false ); }; diff --git a/AmpGen/CacheTransfer.h b/AmpGen/CacheTransfer.h index 5be2ef201fa..67bcd1e0f95 100644 --- a/AmpGen/CacheTransfer.h +++ b/AmpGen/CacheTransfer.h @@ -3,41 +3,60 @@ #include #include +#include +#include namespace AmpGen { class CompiledExpressionBase; class MinuitParameter; + class LambdaExpression; class CacheTransfer { - protected: - unsigned int m_address; - double m_value; - size_t m_size; public: CacheTransfer(); - CacheTransfer( const unsigned int& address, const double& value, const size_t& size=1); + CacheTransfer( const size_t& address, const std::string& name, const double& value=0, const size_t& size=1); virtual ~CacheTransfer() = default; + + size_t address() const { return m_address ; } + virtual void transfer( CompiledExpressionBase* destination ); - virtual void print() const; - virtual unsigned int address() const { return m_address ; } - virtual unsigned int size() const { return m_size ; } + virtual void print() const; + virtual size_t size() const { return m_size ; } + + protected: + size_t m_address = {0}; + size_t m_size = {0}; + double m_value = {0}; + std::string m_name = {""}; }; class ParameterTransfer : public CacheTransfer { - protected: - unsigned int m_address; - AmpGen::MinuitParameter* m_source; - - public: - ParameterTransfer( const unsigned int& address, AmpGen::MinuitParameter* source ); - virtual ~ParameterTransfer() = default; - void transfer( CompiledExpressionBase* destination ) override; - void print() const override; - unsigned int address() const override { return m_address ; } - unsigned int size() const override { return 1 ; } + public: + ParameterTransfer( const size_t& address, const std::string& name, MinuitParameter* source ); + virtual ~ParameterTransfer() = default; + + size_t size() const override { return 1 ; } + + void transfer( CompiledExpressionBase* destination ) override; + void print() const override; + + protected: + MinuitParameter* m_source = {nullptr}; + }; + class LambdaTransfer : public CacheTransfer + { + public: + LambdaTransfer( const size_t& address, const std::string& name, const LambdaExpression* source ); + + size_t size() const override { return 1 ; } + + void transfer( CompiledExpressionBase* destination ) override; + void print() const override; + + std::function m_function; }; } // namespace AmpGen diff --git a/AmpGen/Chi2Estimator.h b/AmpGen/Chi2Estimator.h index 9102cbdb7dc..ea92e4d09de 100644 --- a/AmpGen/Chi2Estimator.h +++ b/AmpGen/Chi2Estimator.h @@ -7,24 +7,38 @@ #include "AmpGen/BinDT.h" +#if ENABLE_AVX +#include "AmpGen/EventListSIMD.h" +#else +#include "AmpGen/EventList.h" +#endif + + namespace AmpGen { - class EventList; class EventType; class Event; class Chi2Estimator { - public: - Chi2Estimator( const EventList& dataEvents, const EventList& mcEvents, - const std::function& fcn, const unsigned int& minEvents = 10 ); + #if ENABLE_AVX + typedef EventListSIMD EventList_type; + #else + typedef EventList EventList_type; + #endif + public: + template + Chi2Estimator( const EventList_type& dataEvents, const EventList_type& mcEvents, + const std::function& fcn, + const argument_types&... args ) : m_binning(dataEvents.begin(), dataEvents.end(), ArgumentPack(args...) ) + { + doChi2(dataEvents, mcEvents, fcn); + } - Chi2Estimator( const EventList& dataEvents, const EventList& mcEvents, - const std::function& fcn, const std::string& filename ); double chi2() const; double nBins() const; void writeBinningToFile( const std::string& filename ); - void doChi2( const EventList& dataEvents, const EventList& mcEvents, + void doChi2( const EventList_type& dataEvents, const EventList_type& mcEvents, const std::function& fcn ); private: double m_chi2; diff --git a/AmpGen/CoherenceFactor.h b/AmpGen/CoherenceFactor.h deleted file mode 100644 index de7638f058b..00000000000 --- a/AmpGen/CoherenceFactor.h +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef AMPGEN_COHERENCEFACTOR_H -#define AMPGEN_COHERENCEFACTOR_H -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AmpGen/BinDT.h" -#include "AmpGen/EventList.h" -#include "AmpGen/EventType.h" -#include "AmpGen/CoherentSum.h" -#include "AmpGen/Integrator.h" -#include "AmpGen/MsgService.h" -#include "AmpGen/Utilities.h" -#include "AmpGen/Types.h" - -namespace AmpGen -{ - class Event; - - struct CoherenceEvent { - std::array values; - complex_t amp1; - complex_t amp2; - real_t weight; - uint64_t flag; - }; - - struct CoherenceCalculator { - CoherentSum* m_pdf1; - CoherentSum* m_pdf2; - Bilinears R; - Bilinears N1; - Bilinears N2; - real_t rTransform; - real_t phiTransform; - CoherenceCalculator() = default; - CoherenceCalculator( CoherentSum* pdf1, CoherentSum* pdf2 ) - : m_pdf1( pdf1 ) - , m_pdf2( pdf2 ) - , R( m_pdf1->size(), m_pdf2->size() ) - , N1( m_pdf1->size(), m_pdf1->size() ) - , N2( m_pdf2->size(), m_pdf2->size() ) - , rTransform( 1 ) - , phiTransform( 0 ) - { - } - - void setTransform( const real_t& rT, const real_t& pT ) - { - rTransform = rT; - phiTransform = pT; - } - real_t getN2() const - { - real_t accN2 = 0; - for ( unsigned int i = 0; i < m_pdf2->size(); ++i ) { - accN2 += std::norm( ( *m_pdf2 )[i].coefficient ) * std::abs( N2.get( i, i ) ); - for ( unsigned int j = i + 1; j < m_pdf2->size(); ++j ) { - accN2 += - 2 * std::real( ( *m_pdf2 )[i].coefficient * std::conj( ( *m_pdf2 )[j].coefficient ) * N2.get( i, j ) ); - } - } - return accN2; - } - - real_t getN1() const - { - real_t accN1 = 0; - for ( unsigned int i = 0; i < m_pdf1->size(); ++i ) { - accN1 += std::norm( ( *m_pdf1 )[i].coefficient ) * std::abs( N1.get( i, i ) ); - for ( unsigned int j = i + 1; j < m_pdf1->size(); ++j ) { - accN1 += - 2 * std::real( ( *m_pdf1 )[i].coefficient * std::conj( ( *m_pdf1 )[j].coefficient ) * N1.get( i, j ) ); - } - } - return accN1 * rTransform * rTransform; - } - - complex_t getVal() - { - complex_t accR( 0, 0 ); - m_pdf1->transferParameters(); - m_pdf2->transferParameters(); - for ( unsigned int i = 0; i < m_pdf1->size(); ++i ) { - for ( unsigned int j = 0; j < m_pdf2->size(); ++j ) { - accR += ( *m_pdf1 )[i].coefficient * std::conj( ( *m_pdf2 )[j].coefficient ) * R.get( i, j ); - } - } - return complex_t( cos( phiTransform ), sin( phiTransform ) ) * rTransform * accR / - sqrt( getN1() * getN2() ); - } - }; - - struct HadronicParameters { - - HadronicParameters( const real_t& _R, const real_t& _d, const real_t& k1 ); - HadronicParameters( const real_t& _R, const real_t& _d, const real_t& k1, const real_t& k2 ); - HadronicParameters() : n1( 0 ), n2( 0 ), wt(0), coherence( 0, 0 ), nFills( 0 ), id( 0 ), binID( 0 ) {} - - real_t n1; - real_t n2; - real_t wt; - complex_t coherence; - unsigned int nFills; - unsigned int id; - unsigned int binID; - real_t I1() const { return n1 / wt ; } - real_t I2() const { return n2 / wt ; } - real_t d() const { return std::arg( coherence ); } - real_t R() const { return std::abs( getCoherence() ); } - real_t r() const { return sqrt( n1 / n2 ); } - complex_t getCoherence() const { return coherence / ( wt * sqrt( I1() * I2() ) ) ; } - void scale_p1( const real_t& sf ); - void scale_p2( const real_t& sf ); - void rotate( const real_t& angle ); - void clear(); - - void add( const complex_t& f1, const complex_t& f2, const real_t& weight = 1 ); - - HadronicParameters operator+=( const HadronicParameters& other ); - HadronicParameters operator-=( const HadronicParameters& other ); - - std::string to_string() const; - }; - - HadronicParameters operator+( const HadronicParameters& a, const HadronicParameters& b ); - class CoherenceFactor - { - private: - HadronicParameters m_global; - real_t m_globalPhase; - real_t m_globalR; - CoherentSum* m_pdf1; - CoherentSum* m_pdf2; - BinDT m_voxels; - std::vector m_paramsPerVoxel; - std::map m_nodeID2Bin; - unsigned int m_nBins; - - CoherenceCalculator m_calc; - EventList* m_data; - EventType m_type; - - void MakeEventDeltaPlots(const std::vector& events ); - public: - BinDT& getDT() { return m_voxels; } - real_t phase(); - real_t getR(); - std::vector getNumberOfEventsInEachBin( const EventList& events ) const; - HadronicParameters calculateGlobalCoherence( EventList* data = nullptr ); - void writeToFile( const std::string& filename ); - - HadronicParameters getVal() const; - CoherenceFactor( const std::string& filename ); - CoherenceFactor(); - CoherenceFactor( CoherentSum* pdf1, CoherentSum* pdf2, EventList* data = nullptr ); - - CoherenceFactor( CoherentSum* pdf1, CoherentSum* pdf2, const EventType& type ); - - void makeCoherentMapping( const unsigned int& nBins, - const std::function( const Event& )>& functors = nullptr, - const size_t& maxDepth = 20, const size_t& minPop = 50, - const std::function& flagFunctor = nullptr, - const bool& refreshEvents = true ); - void makeCoherentMapping( const unsigned int& nBins, const BinDT& binDT ); - - void groupByStrongPhase( const std::vector& coherenceEvents = {}, const bool& recalculateVoxels =true ); - - void readBinsFromFile( const std::string& binName ); /// - unsigned int getBinNumber( const Event& event ) const; - real_t operator()(); - void testCoherenceFactor() const; - - std::vector getCoherenceFactors() const; - std::vector getCoherenceFactorsFast() const; - std::vector coherenceFactorsPerVoxel() const { return m_paramsPerVoxel; } - - void calculateNorms(); - void calculateCoherenceFactorsPerVoxel(); - void calculateCoherenceFactorsPerVoxel( const std::vector& dtEvents ); - - void setGlobals( const real_t& globalPhase, const real_t& globalR ) - { - m_globalR = globalR; - m_globalPhase = globalPhase; - } - void setBinOfNode( const unsigned int& nodeID, const unsigned int& bin ) { m_nodeID2Bin[nodeID] = bin; } - }; -} // namespace AmpGen - -#endif diff --git a/AmpGen/CoherentSum.h b/AmpGen/CoherentSum.h index 6321ac1ec65..22863b73f68 100644 --- a/AmpGen/CoherentSum.h +++ b/AmpGen/CoherentSum.h @@ -1,5 +1,5 @@ -#ifndef AMPGEN_FASTCOHERENTSUM_H -#define AMPGEN_FASTCOHERENTSUM_H +#ifndef AMPGEN_COHERENTSUM_H +#define AMPGEN_COHERENTSUM_H #include #include @@ -13,90 +13,118 @@ #include "AmpGen/AmplitudeRules.h" #include "AmpGen/CompiledExpression.h" #include "AmpGen/EventList.h" +#include "AmpGen/EventListSIMD.h" #include "AmpGen/EventType.h" #include "AmpGen/Integrator.h" #include "AmpGen/Types.h" #include "AmpGen/Event.h" - +#include "AmpGen/Projection.h" +#include "AmpGen/MinuitParameter.h" +#include "AmpGen/Store.h" +#include "AmpGen/KeyedFunctors.h" namespace AmpGen { class LinearErrorPropagator; - class MinuitParameter; class MinuitParameterSet; class FitFraction; class Particle; + /** @class CoherentSum + @brief A coherent sum of amplitudes + + An coherent sum of resonant contributions, where at a position in phase-space @f$\psi@f$, + the (unnormalised) probability density is given by + @f[ + \mathcal{P}(\psi) = \left| \sum_{i} g_i \mathcal{A}_i(\psi) \right|^2, + @f] + where @f$\mathcal{P}(\psi)@f$ is the probability, @f$g_i@f$ is the coupling to an isobar channel, + and @f$\mathcal{A}_i(\psi)@f$ is the amplitude of the ith channel. + */ class CoherentSum { public: + #if ENABLE_AVX + using EventList_type = EventListSIMD; + #else + using EventList_type = EventList; + #endif CoherentSum(); CoherentSum( const EventType& type, const AmpGen::MinuitParameterSet& mps, const std::string& prefix = "" ); virtual ~CoherentSum() = default; - AmplitudeRules protoAmplitudes() { return m_protoAmplitudes; } + AmplitudeRules protoAmplitudes() { return m_rules; } std::string prefix() const { return m_prefix; } - TransitionMatrix operator[]( const size_t& index ) { return m_matrixElements[index]; } - const TransitionMatrix operator[]( const size_t& index ) const { return m_matrixElements[index]; } - size_t size() const { return m_matrixElements.size(); } - - real_t getWeight() const { return m_weight; } - real_t operator()( const Event& evt ) const { return prob( evt ); } - real_t prob( const Event& evt ) const { return m_weight * std::norm( getVal( evt ) ) / m_norm; } - real_t prob_unnormalised( const Event& evt ) const { return std::norm( getVal( evt ) ); } - real_t norm( const Bilinears& norms ) const; + auto operator[]( const size_t& index ) { return m_matrixElements[index]; } + auto operator[]( const size_t& index ) const { return m_matrixElements[index]; } + size_t size() const { return m_matrixElements.size(); } + real_t getWeight() const { return m_weight; } + real_t norm( const Bilinears& norms ) const; real_t norm() const; real_t getNorm( const Bilinears& normalisations ); - real_t get_norm() const { return m_norm ; } - complex_t norm( const unsigned int& x, const unsigned int& y ) const; + complex_t norm( const size_t& x, const size_t& y ) const; complex_t getVal( const Event& evt ) const; - complex_t getVal( const Event& evt, const std::vector& cacheAddresses ) const; - complex_t getValNoCache( const Event& evt ) const; - + complex_t getValNoCache( const Event& evt ) const; + void transferParameters(); void prepare(); void printVal( const Event& evt ); - void updateNorms( const std::vector& changedPdfIndices ); - void setWeight( const double& weight ) { m_weight = weight; } - void setWeight( MinuitParameter* param ) { m_weightParam = param; } + void updateNorms(); + void setWeight( MinuitProxy param ) { m_weight = param; } void makeTotalExpression(); void reset( bool resetEvents = false ); - void setEvents( EventList& list ); - void setMC( EventList& sim ); - void PConjugate(); + void setEvents( const EventList_type& list ); + void setMC( const EventList_type& sim ); + #if ENABLE_AVX + void setEvents( const EventList& list) { + WARNING("Setting events from a AoS container, will need to make a copy"); + m_ownEvents = true; setEvents( *(new EventListSIMD(list)) ) ; } + void setMC ( const EventList& list) { + WARNING("Setting integration events from a AoS container, will need to make a copy"); + setMC( *(new EventListSIMD(list)) ) ; } + double operator()(const double*, const unsigned) const; + #endif + + float_v operator()(const float_v*, const unsigned) const; + real_t operator()(const Event& evt ) const { return m_weight*std::norm(getVal(evt))/m_norm; } + void debug( const Event& evt, const std::string& nameMustContain=""); void generateSourceCode( const std::string& fname, const double& normalisation = 1, bool add_mt = false ); - void resync(); - std::vector cacheAddresses( const EventList& evts ) const; std::vector fitFractions( const LinearErrorPropagator& linProp ); - std::vector> matrixElements() const { return m_matrixElements; } + auto matrixElements() const { return m_matrixElements; } std::map> getGroupedAmplitudes(); Bilinears norms() const { return m_normalisations ; } - + + std::function evaluator(const EventList_type* = nullptr) const; + KeyedFunctors componentEvaluator(const EventList_type* = nullptr) const; + EventType eventType() const { return m_evtType; } protected: - std::vector> m_matrixElements; ///< Vector of (expanded) matrix elements - Bilinears m_normalisations; ///< Normalisation integrals - AmplitudeRules m_protoAmplitudes; ///< Proto amplitudes from user rule-set - Integrator<10> m_integrator; ///< Integral dispatch tool (with default unroll = 10) - TransitionMatrix m_total; ///< Total Matrix Element - EventList* m_events = {nullptr}; ///< Data events to evaluate PDF on - EventType m_evtType; ///< Final state for this amplitude - MinuitParameter* m_weightParam = {nullptr}; ///< Weight parameter (i.e. the normalised yield) - size_t m_prepareCalls = {0}; ///< Number of times prepare has been called - size_t m_lastPrint = {0}; ///< Last time verbose PDF info was printed - size_t m_printFreq = {0}; ///< Frequency to print verbose PDF info - double m_weight = {1}; ///< Weight number (i.e. the normalised yield) - double m_norm = {0}; ///< Normalisation integral - bool m_isConstant = {false}; ///< Flag for a constant PDF - bool m_dbThis = {false}; ///< Flag to generate amplitude level debugging - bool m_verbosity = {false}; ///< Flag for verbose printing - std::string m_objCache = {""}; ///< Directory that contains (cached) amplitude objects - std::string m_prefix = {""}; ///< Prefix for matrix elements - void addMatrixElement( std::pair& particleWithCoupling, const MinuitParameterSet& mps ); - bool isFixedPDF(const MinuitParameterSet& mps) const; + std::vector> m_matrixElements; ///< Vector of matrix elements + Bilinears m_normalisations; ///< Normalisation integrals + AmplitudeRules m_rules; ///< Ruleset for the selected transition. + + Integrator m_integrator; ///< Tool to calculate integrals + const EventList_type* m_events = {nullptr}; ///< Data events to evaluate PDF on + Store m_cache; ///< Store of intermediate values for the PDF calculation + + bool m_ownEvents = {false}; ///< Flag as to whether events are owned by this PDF or not + EventType m_evtType; ///< Final state for this amplitude + size_t m_prepareCalls = {0}; ///< Number of times prepare has been called + size_t m_lastPrint = {0}; ///< Last time verbose PDF info was printed + size_t m_printFreq = {0}; ///< Frequency to print verbose PDF info + MinuitProxy m_weight = {nullptr, 1}; ///< Weight (i.e. the normalised yield) + double m_norm = {1}; ///< Normalisation integral + bool m_isConstant = {false}; ///< Flag for a constant PDF + bool m_dbThis = {false}; ///< Flag to generate amplitude level debugging + bool m_verbosity = {false}; ///< Flag for verbose printing + std::string m_objCache = {""}; ///< Directory that contains (cached) amplitude objects + std::string m_prefix = {""}; ///< Prefix for matrix elements + const MinuitParameterSet* m_mps = {nullptr}; + + void addMatrixElement( std::pair& particleWithCoupling, const MinuitParameterSet& mps ); }; } // namespace AmpGen diff --git a/AmpGen/CompiledExpression.h b/AmpGen/CompiledExpression.h index 94f0e08dfea..cd0cf58e4ed 100644 --- a/AmpGen/CompiledExpression.h +++ b/AmpGen/CompiledExpression.h @@ -9,231 +9,264 @@ #include "AmpGen/MsgService.h" #include "AmpGen/Utilities.h" #include "AmpGen/Types.h" - +#include "AmpGen/simd/utils.h" +#include "AmpGen/Tensor.h" +#include "AmpGen/ArgumentPack.h" #include #include #include +#include namespace AmpGen { /* @class CompiledExpression - @tparam RETURN_TYPE The type that is returned this compiled expression, + @tparam ret_type The type that is returned this compiled expression, usually this is a std::complex, but in principal support also exists for computing coupled channel propagators (i.e. returning array types) */ + + + + namespace detail { + template struct size_of { static constexpr unsigned value = sizeof(T); }; + template <> struct size_of { static constexpr unsigned value = 0; } ; + } + DECLARE_ARGUMENT(disableBatch, bool); + + template class CompiledExpression; + - template - class CompiledExpression : public CompiledExpressionBase - { - - private: - DynamicFCN m_fcn; - DynamicFCN>>( ARGS... )> m_fdb; - std::vector m_externals; - bool m_hasExternalsChanged; - - public: - - CompiledExpression( const Expression& expression, - const std::string& name, - const std::map& evtMapping = - std::map(), - const DebugSymbols& db = {}, - const MinuitParameterSet* mps = nullptr ) - : CompiledExpressionBase( expression, name, db, evtMapping ), - m_hasExternalsChanged( false ) + template + class CompiledExpression : public CompiledExpressionBase { - resolve(mps); - } - CompiledExpression( const std::string& name = "" ) : CompiledExpressionBase( name ) {}; - std::vector externBuffer() const { return m_externals ; } - std::string returnTypename() const override { return typeof(); } - std::string fcnSignature() const override - { - std::string signature; - auto argTypes = typelist(); - for( unsigned int i = 0 ; i < argTypes.size(); ++i ) - { - signature += argTypes[i] + " x"+std::to_string(i) ; - if( i != argTypes.size() - 1 ) signature += ", "; - } - return signature; - } - std::string args() const override - { - std::string signature; - auto argTypes = typelist(); - for( unsigned int i = 0 ; i < argTypes.size(); ++i ) - { - signature += " x"+std::to_string(i) ; - if( i != argTypes.size() - 1 ) signature += ", "; - } - return signature; - } + private: + DynamicFCN m_fcn; + DynamicFCN m_batchFcn; + DynamicFCN>(arg_types...)> m_fdb; + std::vector m_externals = {}; + bool m_hasExternalsChanged = {false}; + + public: + typedef ret_type return_type; + unsigned m_outputSize = {0}; - void resolve( const MinuitParameterSet* mps=nullptr ) - { - CompiledExpressionBase::resolve(mps); - } - void setExternals( const std::vector& external ) { m_externals = external; } + template + CompiledExpression( const Expression& expression, const std::string& name, const namedArgs&... args ) : CompiledExpressionBase(expression, name) + { + const MinuitParameterSet* mps = nullptr; + auto process_argument = [this, &mps]( const auto& arg ) mutable + { + if constexpr( std::is_convertible::value ) this->m_db = arg; + else if constexpr( std::is_convertible>::value ) this->m_evtMap = arg; + else if constexpr( std::is_convertible::value ) this->m_enableBatch = false; + else if constexpr( std::is_convertible::value ) mps = arg; + else if constexpr( std::is_convertible::value ) mps = arg; + else if constexpr( std::is_convertible::value ) mps = &arg; + else ERROR("Unrecognised argument: " << type_string(arg) ); + }; + for_each( std::tuple(args...), process_argument); + DEBUG("Made expression: " << m_name << " " << progName() << " " << mps << " batch enabled ? " << this->m_enableBatch ); + #ifndef _OPENMP + this->m_enableBatch = false; + #endif + resolve(mps); + if constexpr(std::is_same::value ) + { + typedef typename std::remove_pointer>::type zt; + m_outputSize = detail::size_of::value; + DEBUG( "one element: " << m_outputSize << type_string() ); + if( is(expression) ) m_outputSize *= cast(expression).tensor().size(); + } + else m_outputSize = detail::size_of::value; + } - unsigned int getNParams() const { return m_externals.size(); } - - void print() const override - { - INFO( "Name = " << name() ); - INFO( "Hash = " << hash() ); - INFO( "IsReady? = " << isReady() << " IsLinked? " << (m_fcn.isLinked() ) ); - INFO( "args = ["<< vectorToString( m_externals, ", ") <<"]"); - for( auto& c : m_cacheTransfers ){ c->print() ; } - } + CompiledExpression( const std::string& name = "" ) : CompiledExpressionBase( name ) { m_outputSize = detail::size_of::value; }; + std::vector externBuffer() const { return m_externals ; } + std::string returnTypename() const override { return type_string(); } + std::string fcnSignature() const override + { + return CompiledExpressionBase::fcnSignature(typelist(), use_rto()); + } + bool use_rto() const override { + return std::is_same::value; + } + std::string args() const override + { + std::string signature; + auto argTypes = typelist(); + for( unsigned int i = 0 ; i < argTypes.size(); ++i ) + { + signature += " x"+std::to_string(i) ; + if( i != argTypes.size() - 1 ) signature += ", "; + } + return signature; + } - void setExternal( const double& value, const unsigned int& address ) override - { - DEBUG( "Setting external " << address << " / " << m_externals.size() << " to value = " << value << " ; current = " << m_externals[address] ); - if ( m_externals[address] == value ) return; - m_externals[address] = value; - m_hasExternalsChanged = true; - } - void resizeExternalCache(const size_t& N ) override { - if( m_externals.size() < N ){ - m_externals.resize(N); - } - } - bool hasExternalsChanged() { return m_hasExternalsChanged; } - void resetExternals() { m_hasExternalsChanged = false; } + void resolve( const MinuitParameterSet* mps=nullptr ) + { + CompiledExpressionBase::resolve(mps); + } + void setExternals( const std::vector& external ) { m_externals = external; } - Expression& expression() { return m_obj; } - void compileDetails( std::ostream& stream ) const - { - stream << "extern \"C\" int " << progName() << "_pSize () {\n" - << " return " << m_externals.size() << ";\n"; - stream << "}\n"; - - stream << "extern \"C\" double " << progName() << "_pVal (int n) {\n"; - for ( size_t i = 0; i < m_externals.size(); i++ ) - stream << " if(n == " << i << ") return " << m_externals.at( i ) << ";\n"; - stream << " return 0;\n}\n"; - } + unsigned int getNParams() const { return m_externals.size(); } - void compileWithParameters( std::ostream& stream ) const - { - DEBUG( "Compiling " << name() << " = " << hash() ); - // Avoid a warning about std::complex not being C compatible (it is) - stream << "#pragma clang diagnostic push\n" - << "#pragma clang diagnostic ignored \"-Wreturn-type-c-linkage\"\n"; - stream << "extern \"C\" " << returnTypename() << " " << progName() << "_wParams" - << "( const double*__restrict__ E ){" << std::endl; - stream << " double externalParameters [] = {"; - if ( m_externals.size() != 0 ) { - for ( unsigned int i = 0; i < m_externals.size() - 1; ++i ) { - stream << m_externals[i] << ", " ; - } - stream << m_externals[m_externals.size() - 1] << " }; " << std::endl; - } else stream << "0};" << std::endl; - stream << " return " << progName() << "( externalParameters, E ); // E is P \n}\n"; - stream << "#pragma clang diagnostic pop\n\n" << std::endl; - } + void print() const override + { + INFO( "Name = " << name() ); + INFO( "Hash = " << hash() ); + INFO( "IsReady? = " << isReady() << " IsLinked? " << (m_fcn.isLinked() ) ); + INFO( "args = ["<< vectorToString( m_externals, ", ") <<"]"); + std::vector ordered_cache_functors; + for( const auto& c : m_cacheTransfers ) ordered_cache_functors.push_back( c.get() ); + std::sort( ordered_cache_functors.begin(), + ordered_cache_functors.end(), + [](auto& c1, auto& c2 ) { return c1->address() < c2->address() ; } ); + for( auto& c : ordered_cache_functors ) c->print() ; + } - bool isReady() const override { return (m_readyFlag != nullptr && m_readyFlag->get() ) && m_fcn.isLinked(); } - bool isLinked() const { return m_fcn.isLinked() ; } - size_t returnTypeSize() const override { return sizeof( RETURN_TYPE ); } - - template < class T > - RETURN_TYPE operator()( const T* event ) const - { - return m_fcn( (const double*)( &( m_externals[0] ) ), event ); - } - RETURN_TYPE operator()( const ARGS&... args ) const - { - return m_fcn( args... ); - } + void setExternal( const double& value, const unsigned int& address ) override + { + DEBUG( "Setting external " << address << " / " << m_externals.size() << " to value = " << value << " ; current = " << m_externals[address] ); + if ( m_externals[address] == value ) return; + m_externals[address] = value; + m_hasExternalsChanged = true; + } + void resizeExternalCache(const size_t& N ) override + { + if( m_externals.size() < N ) m_externals.resize(N); + } + bool hasExternalsChanged() { return m_hasExternalsChanged; } + void resetExternals() { m_hasExternalsChanged = false; } + + Expression& expression() { return m_obj; } + + void compileDetails( std::ostream& stream ) const + { + stream << "extern \"C\" int " << progName() << "_pSize () {\n" + << " return " << m_externals.size() << ";\n"; + stream << "}\n"; + + stream << "extern \"C\" double " << progName() << "_pVal (int n) {\n"; + for ( size_t i = 0; i < m_externals.size(); i++ ) + stream << " if(n == " << i << ") return " << m_externals.at( i ) << ";\n"; + stream << " return 0;\n}\n"; + } + void compileBatch( std::ostream& stream ) const override + { + stream << "#include \n"; + stream << "extern \"C\" void " << progName() + << "_batch("; + stream << " const size_t& N, " + << " const size_t& eventSize, " + << " const size_t& cacheSize, "; + stream << type_string() << " * rt, "; + stream << CompiledExpressionBase::fcnSignature(typelist(), use_rto(), false) << ") {\n"; + stream << "#pragma omp parallel for\n"; + stream << "for( size_t i = 0; i < N/" << utils::size::value << "; ++i ){\n"; + if( use_rto() ) stream << progName() + "( r + cacheSize * i, s, x0, x1 + i * eventSize);"; + else stream << " rt[cacheSize*i] = " << progName() + "( x0, x1 + i * eventSize);"; + stream << "}\n}"; + } + + void compileWithParameters( std::ostream& stream ) const + { + DEBUG( "Compiling " << name() << " = " << hash() ); + stream << "extern \"C\" " << returnTypename() << " " << progName() << "_wParams" + << "( const double*__restrict__ E ){" << std::endl; + stream << " double externalParameters [] = {" << + (m_externals.size() == 0 ? "0" : vectorToString(m_externals,", ", [](auto& line){ return std::to_string(line); }) ) <<"};\n" ; + stream << " return " << progName() << "( externalParameters, E ); // E is P \n}\n"; + } - void debug( const double* event ) const + bool isReady() const override { return m_fcn.isLinked(); } + bool isLinked() const { return m_fcn.isLinked() ; } + + unsigned returnTypeSize() const override { return m_outputSize; } + + template < typename T > + ret_type operator()( const T* event ) const + { + return m_fcn( m_externals.data(), event ); + } + ret_type operator()( const arg_types&... args ) const + { + return m_fcn( args... ); + } + template void batch( batch_arg_types... args ) const { + m_batchFcn(args...); + } + + template < typename T> void debug( const T* event ) const + { + if ( !m_fcn.isLinked() ) { + FATAL( "Function " << name() << " not linked" ); + } + if ( !m_fdb.isLinked() ) { + FATAL( "Function" << name() << " debugging symbols not linked" ); + } + std::vector> debug_results; + if constexpr(std::is_same::value) debug_results = m_fdb( nullptr, 0, &( m_externals[0] ), event ); + else debug_results = m_fdb( &(m_externals[0]), event); + for( auto& debug_result : debug_results ){ + auto val = debug_result.second; + auto label = debug_result.first; + if( utils::all_of(val.real(), -999.) ) std::cout << bold_on << std::setw(50) << std::left << label << bold_off << std::endl; + else if( utils::all_of(val.imag(), 0.) ) std::cout << " " << std::setw(50) << std::left << label << " = " << val.real() << std::endl; + else + std::cout << " " << std::setw(50) << std::left << label << " = " << val << std::endl; + } + } + + bool link( void* handle ) override + { + const std::string symbol = progName() ; + bool status = true; + status &= m_fcn.set(handle, symbol, true); + status &= m_db.size() == 0 || m_fdb.set(handle, symbol + "_DB"); + status &= !m_enableBatch || m_batchFcn.set(handle, symbol + "_batch"); + return status; + } + bool link( const std::string& handle ) override + { + return link( dlopen( handle.c_str(), RTLD_NOW ) ); + }; + std::string arg_type(const unsigned& i ) const override + { + return typelist()[i]; + } + }; + + template + CompiledExpression + make_rto_expression( const Expression& expression, const std::string& name , const bool& verbose=false) { - if ( !m_fcn.isLinked() ) { - ERROR( "Function " << name() << " not linked" ); - } - if ( !m_fdb.isLinked() ) { - ERROR( "Function" << name() << " debugging symbols not linked" ); - } - auto debug_results = m_fdb( &( m_externals[0] ), event ); - for( auto& debug_result : debug_results ){ - auto val = debug_result.second; - auto label = debug_result.first; - if( std::real(val) == -999. ) std::cout << bold_on << std::setw(50) << std::left << label << bold_off << std::endl; - else if( std::imag(val) == 0 ) std::cout << " " << std::setw(50) << std::left << label << " = " << std::real(val) << std::endl; - else std::cout << " " << std::setw(50) << std::left << label << " = " << val << std::endl; - } + CompiledExpression rt(expression,name); + rt.compile(); + rt.prepare(); + return rt; } - bool link( void* handle ) override + template CompiledExpression + make_expression( const Expression& expression, const std::string& name , const bool& verbose=false) { - const std::string symbol = progName() ; - if ( m_fcn.set( handle, symbol ) == 0 ) { - ERROR( dlerror() ); - ERROR( name() << " (symbol = " << symbol << ") linking fails" ); - return false; - } - if ( m_db.size() ==0 ) return true; - if ( m_fdb.set( handle, progName() + "_DB" ) == 0 ) { - ERROR( "Linking of " << name() << " symbol = " << symbol << ") for debugging fails" ); - return false; - } - return true; + CompiledExpression rt(expression,name); + rt.compile(); + rt.prepare(); + return rt; } - bool link( const std::string& handle ) override + template + CompiledExpression + make_expression( const Expression& expression, + const std::string& name, + const arg_types&... args) { - DEBUG( "Linking " << name() << ( m_db.size() !=0 ? " (debugging)" : "" ) << " hash = " << hash() ); - const std::string symbol = progName(); - if ( m_fcn.set( handle, symbol ) == 0 ) { - ERROR( "Function not linked: " << name() << " (sym="<< symbol << ")" ); - return false; - } - if ( m_db.size() ==0 ) return true; - const std::string dbsymbol = symbol + "_DB"; - if ( m_fdb.set( handle, dbsymbol ) == 0 ) { - ERROR( "Linking of " << name() << " symbol = " << dbsymbol << ")" ); - return false; - } - return true; + CompiledExpression rt(expression,name,args...); + rt.compile(); + rt.prepare(); + return rt; } - }; - - template - CompiledExpression - make_expression( const Expression& expression, const std::string& name , const bool& verbose=false) - { - CompiledExpression rt(expression,name); - rt.compile("", true); - rt.prepare(); - return rt; - } - template - CompiledExpression - make_expression( const Expression& expression, - const std::string& name, - const MinuitParameterSet& mps ) - { - CompiledExpression rt(expression,name,{},{},&mps); - rt.compile("", true); - rt.prepare(); - return rt; - } - template - CompiledExpression - make_expression( const Expression& expression, - const std::string& name, - const std::map & evtMap, - const MinuitParameterSet& mps ) - { - CompiledExpression rt(expression,name,evtMap,{},&mps); - rt.compile("", true); - rt.prepare(); - return rt; - } + } // namespace AmpGen diff --git a/AmpGen/CompiledExpressionBase.h b/AmpGen/CompiledExpressionBase.h index 5051ae3b5bd..8e2820f82c8 100644 --- a/AmpGen/CompiledExpressionBase.h +++ b/AmpGen/CompiledExpressionBase.h @@ -18,10 +18,9 @@ namespace AmpGen class CacheTransfer; std::string programatic_name( std::string s ); - + class ASTResolver; class MinuitParameter; class MinuitParameterSet; - class ASTResolver; /** @class CompiledExpressionBase * Base class for compiled expressions, i.e. expressions that are (almost) ready to be evaluated. @@ -31,44 +30,50 @@ namespace AmpGen */ class CompiledExpressionBase { - protected: - Expression m_obj; - std::string m_name; - std::string m_progName; - DebugSymbols m_db; - std::map m_evtMap; - std::shared_future* m_readyFlag = {nullptr}; - std::vector> m_dependentSubexpressions; - std::vector> m_debugSubexpressions; - std::vector> m_cacheTransfers; - ASTResolver* m_resolver = {nullptr}; public: + CompiledExpressionBase(); + CompiledExpressionBase( const std::string& name ); CompiledExpressionBase( const Expression& expression, const std::string& name, const DebugSymbols& db=DebugSymbols(), - const std::map& evtMapping = {} ); - CompiledExpressionBase( const std::string& name ); - CompiledExpressionBase() = default; + const std::map& evtMapping = {} ); void resolve(const MinuitParameterSet* mps = nullptr); void prepare(); - void compile(const std::string& fname="", const bool& wait = false ); + void compile(const std::string& fname=""); + virtual void compileBatch( std::ostream& stream ) const = 0; void to_stream( std::ostream& stream ) const; unsigned int hash() const; std::string name() const; std::string progName() const; - virtual bool link( void* handle ) = 0; - virtual bool link( const std::string& handle ) = 0; - virtual void setExternal( const double& value, const unsigned int& address ) = 0; - virtual void resizeExternalCache( const size_t& N ) = 0; + virtual bool link( void*) = 0; + virtual bool link( const std::string&) = 0; + virtual void setExternal(const double&, const unsigned&) = 0; + virtual void resizeExternalCache(const size_t&) = 0; virtual bool isReady() const = 0; virtual std::string returnTypename() const = 0; virtual std::string fcnSignature() const = 0; virtual std::string args() const = 0; virtual void print() const = 0; - virtual ~CompiledExpressionBase() = default; - virtual size_t returnTypeSize() const = 0; - + virtual ~CompiledExpressionBase(); + virtual unsigned returnTypeSize() const = 0; + static std::string fcnSignature(const std::vector&, bool=false, bool=true); + virtual bool use_rto() const = 0; + Expression expression() const { return m_obj; } + void enableBatch() { m_enableBatch = true ; } + virtual std::string arg_type( const unsigned& counter) const =0; + protected: + Expression m_obj; + std::string m_name; + std::string m_progName; + DebugSymbols m_db; + std::map m_evtMap; + std::vector> m_dependentSubexpressions; + std::vector> m_debugSubexpressions; + std::vector> m_cacheTransfers; + std::shared_ptr m_resolver; + std::vector m_additionalHeaders; + bool m_enableBatch = {true}; private: void addDebug( std::ostream& stream ) const; void addDependentExpressions( std::ostream& stream, size_t& sizeOfStream ) const; diff --git a/AmpGen/CompilerWrapper.h b/AmpGen/CompilerWrapper.h index 258a80952de..a7f20be2439 100644 --- a/AmpGen/CompilerWrapper.h +++ b/AmpGen/CompilerWrapper.h @@ -14,18 +14,21 @@ namespace AmpGen class CompilerWrapper { public: - CompilerWrapper( const bool& verbose=false); + explicit CompilerWrapper( const bool& verbose=false); void generateSource( const CompiledExpressionBase& expression, const std::string& fname); bool compile( CompiledExpressionBase& expression, const std::string& fname=""); bool compile( std::vector& expression, const std::string& fname=""); void compileSource(const std::string& fname, const std::string& oname ); void setVerbose() { m_verbose = true ; } void preamble(std::ostream& os ) const ; + void addHeader(const std::string& include ) { m_includes.push_back(include); } + private: - std::vector m_includes; + std::vector m_includes = {"array","complex","math.h","vector"}; bool m_verbose; std::string m_cxx; std::string generateFilename(); + bool isClang() const; }; } // namespace AmpGen #endif diff --git a/AmpGen/CoupledChannel.h b/AmpGen/CoupledChannel.h index e72e1e8a68d..f9837963538 100644 --- a/AmpGen/CoupledChannel.h +++ b/AmpGen/CoupledChannel.h @@ -2,5 +2,11 @@ #include "AmpGen/Particle.h" namespace AmpGen { + + namespace Lineshape { + /** @ingroup Lineshapes class CoupledChannel + @brief Description of a resonance that decays to multiple two and three-body final states. */ + DECLARE_LINESHAPE( CoupledChannel ); + } Expression phaseSpace(const Expression& s, const Particle& p, const size_t& l); } diff --git a/AmpGen/DalitzIntegrator.h b/AmpGen/DalitzIntegrator.h index 31c09622e26..06bbdb144df 100644 --- a/AmpGen/DalitzIntegrator.h +++ b/AmpGen/DalitzIntegrator.h @@ -32,18 +32,8 @@ namespace AmpGen DalitzIntegrator( const double& s0, const double& s1, const double& s2, const double& s3); - template - double integrate( FCN fcn, const double& s) const - { - double event[12]; - for(size_t i = 0; i < 12; ++i) event[i] = 0; - TF2 f( "fcn", [&]( double* x, double* p ) { - sqCo pos = {x[0], x[1]}; - setEvent( pos, event, s); - return J(pos, s) * std::real( fcn(event) ); }, 0, 1, 0, 1, 0 ); - return integrate_internal(f) / s; - } - + template double integrate( FCN fcn, const double& s) const; + template double integrate( FCN fcn ) const { return integrate( fcn, m_s0 ); @@ -80,6 +70,18 @@ namespace AmpGen double integrate_internal( TF2& fcn ) const ; }; + template + double DalitzIntegrator::integrate( FCN fcn, const double& s) const + { + double event[12]; + for(size_t i = 0; i < 12; ++i) event[i] = 0; + TF2 f( "fcn", [&]( double* x, double* p ) { + sqCo pos = {x[0], x[1]}; + setEvent( pos, event, s); + return J(pos, s) * std::real( fcn(event) ); }, 0, 1, 0, 1, 0 ); + return integrate_internal(f) / s; + } + } // namespace AmpGen #endif diff --git a/AmpGen/DiracMatrices.h b/AmpGen/DiracMatrices.h index 69ce55aaf25..7e646e323b4 100644 --- a/AmpGen/DiracMatrices.h +++ b/AmpGen/DiracMatrices.h @@ -12,7 +12,9 @@ namespace AmpGen extern const Expression Z; extern const std::array Gamma; extern const std::array Sigma; + extern const std::array Sigma4; extern const std::array S03; + extern const std::array SU3; } // namespace AmpGen #endif diff --git a/AmpGen/DynamicFCN.h b/AmpGen/DynamicFCN.h index d8758b29c90..59157e5c7b7 100644 --- a/AmpGen/DynamicFCN.h +++ b/AmpGen/DynamicFCN.h @@ -50,11 +50,12 @@ namespace AmpGen } return set(m_handle,name); } - bool set( void* handle, const std::string& name ) + bool set( void* handle, const std::string& name, bool isFatal = false) { m_fcn = (RETURN_TYPE( * )( IN_TYPES... ))dlsym( handle, name.c_str() ); if ( m_fcn == nullptr ) { - ERROR( dlerror() ); + if( !isFatal ) ERROR( "Failed to link: " << name << " error: " << dlerror() ); + else FATAL("Failed to link: " << name << " error: " << dlerror() ); return false; } return true; diff --git a/AmpGen/ErrorPropagator.h b/AmpGen/ErrorPropagator.h index 7470162c0dc..1178c74badb 100644 --- a/AmpGen/ErrorPropagator.h +++ b/AmpGen/ErrorPropagator.h @@ -27,99 +27,34 @@ class TRandom3; namespace AmpGen { class MinuitParameterSet; - /// \class LinearErrorPropagator - /// Propagates uncertainties on functors using either a MinuitParameterSet (thus assuming a diagonal covariance matrix) - /// or with a set of parameters and a covariance matrix (i.e. the product of a fit). - /// Can be used for calculating the uncertainties on observables such as Fit fractions, - /// or for producing uncertainty bands in predictions on figures. - /// Usage is - + /** @class LinearErrorPropagator + Propagates uncertainties on functors using either a MinuitParameterSet (thus assuming a diagonal covariance matrix) + or with a set of parameters and a covariance matrix (i.e. the product of a fit). + Can be used for calculating the uncertainties on observables such as Fit fractions, + or for producing uncertainty bands in predictions on figures. + Usage is + */ class LinearErrorPropagator { public: ///< Constructor for LinearErrorPropagator taking a vector of free parameters, assumes a diagonal covariance matrix taking the parameter uncertainties. - LinearErrorPropagator( const std::vector& params ); + explicit LinearErrorPropagator( const std::vector& params ); ///< Constructor for LinearErrorPropagator, taking a MinuitParameterSet as argument, assumes a diagonal coviarance matrix using the uncertainties on parameters. - LinearErrorPropagator( const MinuitParameterSet& params ); - + explicit LinearErrorPropagator( const MinuitParameterSet& params ); ///< Constructor for LinearErrorPropagator, taking a covariance matrix and a vector parameters - LinearErrorPropagator( const TMatrixD& reducedCovarianceMatrix, - const std::vector& params ); + LinearErrorPropagator( const TMatrixD& reducedCovarianceMatrix, const std::vector& params ); ///< Calculates the uncertainty on functor fcn. template double operator()( FCN fcn ) const { - return getError( fcn ); + return getError( std::function(fcn) ); } ///< Calculates the error on functor fcn (should take no arguments and return a double). - template double getError( FCN fcn ) const - { - unsigned int N = m_cov.GetNrows(); - TVectorD errorVec( N ); - for ( unsigned int i = 0; i < N; ++i ) { - DEBUG( "Perturbing parameter: [" << m_parameters[i]->name() << "] " << startingValue << " by " - << sqrt( m_cov( i, i ) ) << " " << m_parameters[i] ); - errorVec(i) = derivative(fcn,i); - fcn(); - } - return sqrt( errorVec * ( m_cov * errorVec ) ); - } - - ///< Calculate the uncertainties on a functor that returns an array of doubles of size RANK, used for propagating the uncertainties on figures. - template std::array getVectorError( FCN fcn ) const - { - unsigned int N = m_cov.GetNrows(); - std::array errorVec; - for ( unsigned int i = 0; i < RANK; ++i ) errorVec[i].ResizeTo( N ); - for ( unsigned int i = 0; i < N; ++i ) { - double startingValue = m_parameters[i]->mean(); - double error = sqrt( m_cov( i, i ) ); - double min = m_parameters[i]->mean() - error; - double max = m_parameters[i]->mean() + error; - DEBUG( "Perturbing parameter: " << m_parameters[i]->name() << " -> [" << min << ", " << max << "]" ); - - m_parameters[i]->setCurrentFitVal( max ); - auto plus_variation = fcn(); - m_parameters[i]->setCurrentFitVal( min ); - auto minus_variation = fcn(); - m_parameters[i]->setCurrentFitVal( startingValue ); - for ( size_t j = 0; j < RANK; ++j ) { - errorVec[j]( i ) = ( plus_variation[j] - minus_variation[j] ) / ( 2 * error ); - } - } - fcn(); - std::array rt; - for ( unsigned int j = 0; j < RANK; ++j ) rt[j] = sqrt( errorVec[j] * ( m_cov * errorVec[j] ) ); - return rt; - } + double getError( const std::function& fcn ) const; ///< Calculate the uncertainties on a functor that returns a vector of size RANK. - template std::vector getVectorError( FCN fcn, size_t RANK ) const - { - unsigned int N = m_cov.GetNrows(); - std::vector errorVec( RANK, TVectorD( N ) ); - for ( unsigned int i = 0; i < N; ++i ) { - double startingValue = m_parameters[i]->mean(); - double error = sqrt( m_cov( i, i ) ); - double min = m_parameters[i]->mean() - error; - double max = m_parameters[i]->mean() + error; - DEBUG( "Perturbing parameter: " << m_parameters[i]->name() << " -> [" << min << ", " << max << "]" ); - - m_parameters[i]->setCurrentFitVal( max ); - auto plus_variation = fcn(); - m_parameters[i]->setCurrentFitVal( min ); - auto minus_variation = fcn(); - m_parameters[i]->setCurrentFitVal( startingValue ); - for ( size_t j = 0; j < RANK; ++j ) { - errorVec[j]( i ) = ( plus_variation[j] - minus_variation[j] ) / ( 2 * error ); - } - } - fcn(); - std::vector rt( RANK, 0 ); - for ( unsigned int j = 0; j < RANK; ++j ) rt[j] = sqrt( errorVec[j] * ( m_cov * errorVec[j] ) ); - return rt; - } + std::vector getVectorError( const std::function(void)>& fcn, size_t RANK ) const; /// Calculate the variance-covariance matrix of functor set functions. std::vector combinationWeights( const std::vector>& functions ); diff --git a/AmpGen/Event.h b/AmpGen/Event.h index 36c269c7404..5e420599f1b 100644 --- a/AmpGen/Event.h +++ b/AmpGen/Event.h @@ -13,63 +13,53 @@ namespace AmpGen { /** @class Event @brief Encapsulates the final state particles of a single event - Encapsulates the final state particles of a single event, or candidate in the language of proton-proton collisions. Typically will store (i) the event kinematics, i.e. four-momenta, (ii). a cache of complex numbers that contain intermediate calculations of the amplitude, (iii). the weight of the given event/candidate, (iv). The probability that the event was generated with, in the case of a simulated event */ + Encapsulates the final state particles of a single event, or candidate in the language of proton-proton collisions. Typically will store (i) the event kinematics, i.e. four-momenta, (ii). the weight of the given event/candidate, (iii). The probability that the event was generated with, in the case of a simulated event */ class Event { public: + Event () = default; + Event( const unsigned& N ); + Event( const real_t* data, const unsigned& N ); - Event( const size_t& N, const size_t& cacheSize=0 ); - Event( const real_t* data, const size_t& N, const size_t& cacheSize=0); - - void set( const size_t& i, const std::vector& p ); - void set( const size_t& i, const real_t* p ); + void set( const unsigned& i, const std::vector& p ); + void set( const unsigned& i, const real_t* p ); void set( const real_t* evt ); - void set( const size_t& i, const real_t& p ) ; + void set( const unsigned& i, const real_t& p ) ; void swap( const unsigned int& i , const unsigned int& j ); - void setCache(const complex_t& value, const size_t& pos) ; - template void setCache( const std::array& value, const size_t& pos ) - { - std::memmove( m_cache.data() + pos, value.data(), sizeof(std::array) ); - } - void setCache( const std::vector& value, const size_t& pos ); - void resizeCache( const unsigned int& new_size ); - size_t size() const { return m_event.size(); } - - real_t* pWeight() { return &(m_weight); } - real_t* pGenPdf() { return &m_genPdf; } - const real_t* address(const unsigned int ref=0 ) const { return &(m_event[ref]); } - real_t* address(const unsigned int& ref=0) { return &(m_event[ref]); } + unsigned size() const { return m_event.size(); } - unsigned int cacheSize() const { return m_cache.size(); } - real_t weight() const { return m_weight; } - real_t genPdf() const { return m_genPdf; } - real_t operator[](const unsigned int& i) const { return m_event[i]; } - real_t& operator[](const unsigned int& i) { return m_event[i]; } - operator const real_t*() const { return &(m_event[0]); } - operator real_t*() { return &(m_event[0]); } + real_t* pWeight() { return &(m_weight); } + real_t* pGenPdf() { return &m_genPdf; } + const real_t* address(const unsigned& ref=0) const { return &(m_event[ref]); } + real_t* address(const unsigned& ref=0) { return &(m_event[ref]); } - const complex_t& getCache(const unsigned int& pos) const { return m_cache[pos]; } - const complex_t* getCachePtr(const unsigned int& pos=0) const { return &(m_cache[0]) + pos; } + real_t weight() const { return m_weight; } + real_t genPdf() const { return m_genPdf; } + real_t operator[](const unsigned& i) const { return m_event[i]; } + real_t& operator[](const unsigned& i) { return m_event[i]; } + operator const real_t*() const { return &(m_event[0]); } + operator real_t*() { return &(m_event[0]); } void setWeight( const real_t& weight ){ m_weight = weight ; } void setGenPdf( const real_t& genPdf ){ m_genPdf = genPdf ; } void extendEvent(const real_t& value) { m_event.push_back( value ); } void print() const; - void printCache() const; - - real_t s( const size_t& index) const ; - real_t s( const size_t& index1, const size_t& index2 ) const ; - real_t s( const size_t& index1, const size_t& index2, const size_t& index3 ) const; - real_t s( const std::vector& indices ) const ; + // void printCache() const; + void setIndex(const unsigned& index){ m_index = index; } + unsigned index() const { return m_index; } + real_t s( const unsigned& index) const ; + real_t s( const unsigned& index1, const unsigned& index2 ) const ; + real_t s( const unsigned& index1, const unsigned& index2, const unsigned& index3 ) const; + real_t s( const std::vector& indices ) const ; + void reorder( const std::vector& addresses); private: std::vector m_event; - std::vector m_cache; real_t m_genPdf = {1}; real_t m_weight = {1}; - - inline real_t get(const size_t& index ) const { return m_event[index]; }; + unsigned m_index = {0}; + inline real_t get(const unsigned& index ) const { return m_event[index]; }; }; } diff --git a/AmpGen/EventList.h b/AmpGen/EventList.h index c0800963a5e..8495845e2dc 100644 --- a/AmpGen/EventList.h +++ b/AmpGen/EventList.h @@ -7,6 +7,8 @@ #include "AmpGen/Event.h" #include "AmpGen/Projection.h" #include "AmpGen/Utilities.h" +#include "AmpGen/MetaUtils.h" +#include "AmpGen/Units.h" #include #include @@ -18,31 +20,33 @@ #include #include -#ifdef __USE_OPENMP__ -#include +#ifdef _OPENMP + #include #endif namespace AmpGen { - DECLARE_ARGUMENT_DEFAULT( Bins, size_t, 100 ); - + namespace PlotOptions { DECLARE_ARGUMENT(Bins, size_t); } class CompiledExpressionBase; class EventList { private: std::vector m_data = {}; EventType m_eventType = {}; - std::map m_pdfIndex = {}; std::map m_extensions = {}; - double m_norm = {0}; - size_t m_lastCachePosition = {0}; + public: + typedef Event value_type; EventList() = default; EventList( const EventType& type ); template < class ... ARGS > EventList( const std::string& fname, const EventType& evtType, const ARGS&... args ) : EventList(evtType) { loadFromFile( fname, ArgumentPack(args...) ); } + template < class ... ARGS > EventList( const std::string& fname, const ARGS&... args ) : EventList() + { + loadFromFile( fname, ArgumentPack(args...) ); + } template < class ... ARGS > EventList( const std::vector& fname, const EventType& evtType, const ARGS&... args ) : EventList(evtType) { for( auto& f : fname ) loadFromFile( f, ArgumentPack(args...) ); @@ -51,8 +55,7 @@ namespace AmpGen { loadFromTree( tree, ArgumentPack(args...) ); } - - void resetCache(); + const EventList& store() const { return *this;} std::vector::reverse_iterator rbegin() { return m_data.rbegin(); } std::vector::reverse_iterator rend() { return m_data.rend(); } std::vector::iterator begin() { return m_data.begin(); } @@ -66,118 +69,95 @@ namespace AmpGen EventType eventType() const { return m_eventType; } const Event& at( const size_t& pos ) const { return m_data[pos]; } size_t size() const { return m_data.size(); } + size_t aligned_size() const { return m_data.size() ; } + size_t nBlocks() const { return m_data.size() ; } double integral() const; - double norm(); - - void reserve( const size_t& size ) { m_data.reserve( size ); } - void push_back( const Event& evt ) { m_data.push_back( evt ); } + const double* block(const unsigned pos) const { return m_data[pos].address(); } + real_t weight( const size_t& pos) const { return m_data[pos].weight(); } + real_t genPDF( const size_t& pos) const { return m_data[pos].genPdf(); } + unsigned key(const std::string& key) const + { + auto it = m_extensions.find(key); + if( it == m_extensions.end() ) return m_data[0].size() - 1; + return it->second; + } + void reserve( const size_t& size ); + void resize ( const size_t& size ); + void push_back( const Event& evt ); + void emplace_back( const Event& evt); void setEventType( const EventType& type ) { m_eventType = type; } void add( const EventList& evts ); void loadFromTree( TTree* tree, const ArgumentPack& args ); void loadFromFile( const std::string& fname, const ArgumentPack& args ); - void printCacheInfo( const unsigned int& nEvt = 0 ); void clear(); - void erase( const std::vector::iterator& begin, const std::vector::iterator& end ); - - TTree* tree( const std::string& name, const std::vector& extraBranches = {} ); - - size_t getCacheIndex( const CompiledExpressionBase& PDF, bool& status ) const; - size_t getCacheIndex( const CompiledExpressionBase& PDF ) const; - template - size_t registerExpression(const T& expression, const size_t& size_of=0) - { - auto key = FNV1a_hash( expression.name() ); - auto pdfIndex = m_pdfIndex.find( key ); - if ( pdfIndex != m_pdfIndex.end() ) { - return pdfIndex->second; - } else { - size_t size = m_lastCachePosition; - size_t expression_size = size_of == 0 ? - expression.returnTypeSize() / sizeof(complex_t) : size_of; - if ( size >= at( 0 ).cacheSize() ) { - WARNING("Cache index " << size << " exceeds cache size = " - << at(0).cacheSize() << " resizing to " - << size + expression_size ); - - for (auto& evt : *this) evt.resizeCache( size + expression_size ); - } - m_pdfIndex[key] = m_lastCachePosition; - m_lastCachePosition += expression_size; - return size; - } - } - - template - unsigned int extendEvent( const std::string& name, FUNCTOR func ) + void setWeight( const unsigned int& pos, const double& w, const double&g=+1) { - unsigned int index = this->begin()->size(); - for ( auto& evt : *this ) evt.extendEvent(func(evt)); - m_extensions[name] = index; - return index; - } - - template - void updateCache( const FCN& fcn, const size_t& index ) - { - #pragma omp parallel for - for ( unsigned int i = 0; i < size(); ++i ) { - ( *this )[i].setCache(fcn(getEvent(i)), index); - } + m_data[pos].setWeight(w); + m_data[pos].setGenPdf(g); } + void erase( const std::vector::iterator& begin, const std::vector::iterator& end ); - TH2D* makeProjection( const Projection2D& projection, const ArgumentPack& args ); + TTree* tree( const std::string& name, const std::vector& extraBranches = {} ) const; + + TH1D* makeProjection(const Projection& projection , const ArgumentPack& args = ArgumentPack()) const; + TH2D* makeProjection(const Projection2D& projection, const ArgumentPack& args = ArgumentPack()) const; std::vector makeProjections( const std::vector& projections, const ArgumentPack& args ); - template - std::vector makeDefaultProjections( const ARGS&... args ) + template std::vector makeDefaultProjections( const ARGS&... args ) { auto argPack = ArgumentPack( args... ); - size_t nBins = argPack.getArg(100); + size_t nBins = argPack.getArg(100); auto proj = eventType().defaultProjections(nBins); return makeProjections( proj , argPack ); } - template - std::vector makeProjections( const std::vector& projections, const ARGS&... args ) + + template std::vector makeProjections( const std::vector& projections, const ARGS&... args ) { return makeProjections( projections, ArgumentPack( args... ) ); } - template - TH1D* makeProjection( const Projection& projection, const ARGS&... args ) + + template , ArgumentPack>::value > > + TH1D* makeProjection( const Projection& projection, const ARGS&... args ) const { return makeProjection( projection, ArgumentPack(args...) ); } - TH1D* makeProjection( const Projection& projection, const ArgumentPack& args ); - - template + + template , ArgumentPack>::value > > TH2D* makeProjection( const Projection2D& projection, const ARGS&... args ) { return makeProjection( projection, ArgumentPack(args...) ); } - template - EventList& transform( FCN&& fcn ) + + template EventList& transform( functor&& fcn ) { for ( auto& event : m_data ) fcn( event ); return *this; } - template - void filter( FCN&& fcn ){ - size_t currentSize = size(); + + template void filter( functor&& fcn ) + { + unsigned currentSize = size(); m_data.erase( std::remove_if( m_data.begin(), m_data.end(), fcn ) , m_data.end() ); - INFO("Filter removes: " << currentSize - size() << " / " << currentSize << " events"); + INFO("Filter retains " << size() << " / " << currentSize << " events"); + } + + template unsigned count( functor&& fcn ) const + { + return std::count_if( std::begin(*this), std::end(*this), fcn ); } - }; - DECLARE_ARGUMENT( LineColor, int ); - DECLARE_ARGUMENT( DrawStyle, std::string ); - DECLARE_ARGUMENT( Selection, std::function ); - DECLARE_ARGUMENT( WeightFunction, std::function ); - DECLARE_ARGUMENT( Branches, std::vector ); - DECLARE_ARGUMENT( EntryList, std::vector ); - DECLARE_ARGUMENT_DEFAULT(GetGenPdf, bool, false ); - DECLARE_ARGUMENT_DEFAULT(CacheSize, size_t , 0 ); - DECLARE_ARGUMENT_DEFAULT(Filter, std::string , ""); - DECLARE_ARGUMENT_DEFAULT(WeightBranch, std::string, "" ); - DECLARE_ARGUMENT_DEFAULT(ApplySym, bool, 0 ); - DECLARE_ARGUMENT_DEFAULT(Prefix, std::string, "" ); + }; + DECLARE_ARGUMENT(Branches, std::vector); /// Branch names containing kinematic information + DECLARE_ARGUMENT(ExtraBranches, std::vector); /// additional information about the event to include + DECLARE_ARGUMENT(IdBranches, std::vector); /// Branches containing PID information, used if the names of particles are incorrect (looking at you, DTF) + DECLARE_ARGUMENT(EntryList, std::vector); + DECLARE_ARGUMENT(GetGenPdf, bool); + DECLARE_ARGUMENT(Filter, std::string); + DECLARE_ARGUMENT(WeightBranch, std::string); + DECLARE_ARGUMENT(ApplySym, bool); + DECLARE_ARGUMENT(WeightFunction, std::function); + DECLARE_ARGUMENT(InputUnits, AmpGen::Units); } // namespace AmpGen #endif diff --git a/AmpGen/EventListSIMD.h b/AmpGen/EventListSIMD.h new file mode 100644 index 00000000000..487f7898cef --- /dev/null +++ b/AmpGen/EventListSIMD.h @@ -0,0 +1,148 @@ +#ifndef AMPGEN_EVENTLIST2_H +#define AMPGEN_EVENTLIST2_H + +#include "AmpGen/ArgumentPack.h" +#include "AmpGen/EventType.h" +#include "AmpGen/MsgService.h" +#include "AmpGen/Event.h" +#include "AmpGen/Projection.h" +#include "AmpGen/Utilities.h" +#include "AmpGen/MetaUtils.h" +#include "AmpGen/EventList.h" +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef _OPENMP + #include +#endif + +#include "AmpGen/simd/iterator.h" +#include "AmpGen/simd/utils.h" +#include "AmpGen/Store.h" + +namespace AmpGen +{ + class CompiledExpressionBase; + class EventListSIMD + { + private: + Store m_data {}; + std::vector m_weights {}; + std::vector m_genPDF {}; + EventType m_eventType {}; + public: + typedef Event value_type; + EventListSIMD() = default; + EventListSIMD( const EventType& type ); + template < class ... ARGS > EventListSIMD( const std::string& fname, const EventType& evtType, const ARGS&... args ) : EventListSIMD(evtType) + { + loadFromFile( fname, ArgumentPack(args...) ); + } + template < class ... ARGS > EventListSIMD( const std::string& fname, const ARGS&... args ) : EventListSIMD() + { + loadFromFile( fname, ArgumentPack(args...) ); + } + template < class ... ARGS > EventListSIMD( const std::vector& fname, const EventType& evtType, const ARGS&... args ) : EventListSIMD(evtType) + { + for( auto& f : fname ) loadFromFile( f, ArgumentPack(args...) ); + } + template < class ... ARGS > EventListSIMD( TTree* tree, const EventType& evtType, const ARGS&... args ) : EventListSIMD(evtType) + { + loadFromTree( tree, ArgumentPack(args...) ); + } + EventListSIMD( const EventList& other ); + const float_v* data() const { return m_data.data(); } + operator Store () const { return m_data ; } + const auto& store() const { return m_data; } + const Event at(const unsigned& p) const { return EventListSIMD::operator[](p) ; } + const float_v* block(const unsigned& p) const { return m_data.data() + p * m_data.nFields(); } + float_v* block(const unsigned& p) { return m_data.data() + p * m_data.nFields(); } + float_v weight(const unsigned& p) const { return m_weights[p]; } + float_v genPDF(const unsigned& p) const { return m_genPDF[p]; } + + void setWeight( const unsigned& block, const float_v& w, const float_v& g=1.f) + { + m_weights[block] = w; + m_genPDF[block] = g; + } + void resize( const unsigned nEvents ) + { + m_data = Store( nEvents, m_eventType.eventSize() ); + m_weights.resize( aligned_size(), 1.f); + m_genPDF.resize( aligned_size(), 1.f ); + } + const Event operator[]( const size_t&) const; + std::array::value> scatter(unsigned) const; + void gather(const std::array::value>&, unsigned); + auto begin() const { return make_scatter_iterator::value>(0,this); } + auto end() const { return make_scatter_iterator::value>(size(), (const EventListSIMD*)(nullptr) ); } + auto begin() { return make_scatter_iterator::value, true>(0, this); } + auto end() { return make_scatter_iterator::value, true>(size(), (EventListSIMD*)(nullptr) ); } + EventType eventType() const { return m_eventType; } + size_t aligned_size() const { return m_data.aligned_size(); } + double integral() const; + size_t eventSize() const { return m_data.nFields(); } + size_t size() const { return m_data.size(); } + size_t nBlocks() const { return m_data.nBlocks(); } + void setEventType( const EventType& type ) { m_eventType = type; } + void add( const EventListSIMD& evts ); + void loadFromTree( TTree* tree, const ArgumentPack& args ); + void loadFromFile( const std::string& fname, const ArgumentPack& args ); + void clear(); + + TTree* tree( const std::string& name, const std::vector& extraBranches = {} ) const; + + + TH1D* makeProjection(const Projection& projection , const ArgumentPack& args = ArgumentPack()) const; + TH2D* makeProjection(const Projection2D& projection, const ArgumentPack& args = ArgumentPack()) const; + std::vector makeProjections( const std::vector& projections, const ArgumentPack& args ); + + template std::vector makeDefaultProjections( const ARGS&... args ) + { + auto argPack = ArgumentPack( args... ); + size_t nBins = argPack.getArg(100); + auto proj = eventType().defaultProjections(nBins); + return makeProjections( proj , argPack ); + } + + template std::vector makeProjections( const std::vector& projections, const ARGS&... args ) + { + return makeProjections( projections, ArgumentPack( args... ) ); + } + + template , ArgumentPack>::value > > + TH1D* makeProjection( const Projection& projection, const ARGS&... args ) const + { + return makeProjection( projection, ArgumentPack(args...) ); + } + + template , ArgumentPack>::value > > + TH2D* makeProjection( const Projection2D& projection, const ARGS&... args ) + { + return makeProjection( projection, ArgumentPack(args...) ); + } + + template EventListSIMD& transform( functor&& fcn ) + { + for ( auto& event : *this ) fcn( event ); + return *this; + } + static std::vector makeEvent( const Event& event ) + { + std::vector rt( event.size() ); + for( unsigned i = 0 ; i != event.size(); ++i ) rt[i] = event[i]; + return rt; + } + }; + +} // namespace AmpGen +#endif diff --git a/AmpGen/EventType.h b/AmpGen/EventType.h index 21ec4cb6ec4..191cf35f976 100644 --- a/AmpGen/EventType.h +++ b/AmpGen/EventType.h @@ -9,57 +9,78 @@ namespace AmpGen { - class Projection; - class Event; + class Projection; + class Event; /**@class EventType - * Deals with final state configuration of events, - * specifically dealing with the ordering of particles in trees. + Deals with final state configuration of events, + specifically dealing with the ordering of particles in trees. */ + class EventType; + std::ostream& operator<<( std::ostream& os, const EventType& type ); class EventType { - private: - std::string m_mother; ///< name of decaying particle - double m_motherMass; ///< mass of decaying particle - std::vector m_particleNames; ///< names of decay products - std::vector m_particleNamesPickled; ///< names of decay product pickled for ROOT - std::vector m_particleMasses; ///< masses of decay products - bool m_timeDependent; - std::vector m_eventTypeExtensions; ///< extended event data - std::pair m_dim; ///< Rank of the relevant transition matrix - public: - EventType() = default; - EventType( const std::vector&, const bool& isTD = false ); - std::map getEventFormat( const bool& outputNames = false ) const; - - std::pair minmax( const std::vector& indices, bool isGeV = false ) const; - std::vector> getBosePairs() const; - std::vector masses() const; - std::string mother() const; - double mass( const size_t& index ) const; - double motherMass() const; - std::vector finalStates() const; - bool isTimeDependent() const; - size_t eventSize() const; - size_t size() const; - size_t dof() const; - std::string operator[]( const size_t& index ) const; + public: + /// Default constructor + EventType() = default; + + /// Takes a list of particles, beginning with the head of the decay and + /// then then final state particles, and a flag as to whether to include time dependence. + EventType( const std::vector&, const bool& isTD = false ); + + /// Returns the CP-conjugated event type. Can also require that only the initial/ + /// final state is conjugated. By default, conjugates both. + EventType conj( const bool& headOnly = 0, const bool& dontConjHead = 0 ) const; + + /// Returns the event format, that matches between expressions and the names used in Particle. + std::map getEventFormat( const bool& outputNames = false ) const; + + /// Counts the number of particles in this event type with + /// the same name as the index'th name. + std::pair count(const unsigned& index) const; + std::pair minmax( const std::vector& indices) const; + std::vector masses() const; + std::string mother() const; + double mass( const unsigned& index ) const; + double motherMass() const; + std::vector finalStates() const; + bool isTimeDependent() const; + unsigned eventSize() const; + unsigned size() const; + unsigned dof() const; + std::string operator[]( const unsigned& index ) const; + std::string decayDescriptor() const; + std::string label( const unsigned& index, bool isRoot = true ) const; + std::string label( const std::vector& index, bool isRoot = true ) const; + std::vector defaultProjections(const unsigned& nBins=100) const; + Projection projection(const unsigned& nBins, const std::vector& indices, const std::string& observable = "mass2") const; - std::string label( const size_t& index, bool isRoot = true ) const; - std::string label( const std::vector& index, bool isRoot = true ) const; - std::vector defaultProjections(const size_t& nBins) const; - Projection projection(const size_t& nBins, const std::vector& indices) const; + bool operator==( const EventType& other ) const; + bool has( const std::string& name ) const; - bool operator==( const EventType& other ) const; - bool has( const std::string& name ) const; - EventType conj( const bool& headOnly = 0, const bool& dontConjHead = 0 ) const; - - void setMotherMass( const double& mass ){ m_motherMass = mass ; } - void extendEventType( const std::string& branch ); - std::function symmetriser() const; - std::pair dim() const; ///< calculates the number of spin indices accociated with the initial and final state, i.e. the rank of the relevant transition matrix. + void extendEventType( const std::string& branch ); + + /// Functor to randomly symmetrise data of this event type, using the Fisher-Yates shuffle. + std::function symmetriser() const; + std::function& ids)> automaticOrdering() const; + + /// Calculates the number of spin indices associated with the initial and final state, i.e. the rank of the relevant transition matrix. + std::pair dim() const; + + friend std::ostream& AmpGen::operator<<( std::ostream& os, const EventType& type ); + + private: + std::string m_mother; ///< name of decaying particle + double m_motherMass; ///< mass of decaying particle + std::vector m_particleNames; ///< names of decay products + std::vector m_particleNamesPickled; ///< names of decay product pickled for ROOT + std::vector m_particleMasses; ///< masses of decay products + std::vector m_ignore; ///< Flag to ignore particle when reading events, for invisible or tags + bool m_timeDependent; ///< Flag to include a decay time as the last element in the event vector + std::vector m_eventTypeExtensions; ///< extended event data + std::pair m_dim; ///< Rank of the relevant transition matrix + bool m_alt_part_names; ///< alternative naming in ouput tree (e.g. Xi- pi+ pi+ becomes Xim pip0 pip1 rather than _1_Xi# _2_pi~ _3_pi~) }; - std::ostream& operator<<( std::ostream& os, const EventType& type ); } // namespace AmpGen #endif diff --git a/AmpGen/Expression.h b/AmpGen/Expression.h index 9198ff061b8..f48312d89f2 100644 --- a/AmpGen/Expression.h +++ b/AmpGen/Expression.h @@ -57,12 +57,17 @@ complex_t X::operator()() const { return F( m_expression() ); } \ std::string X::to_string(const ASTResolver* resolver) const { return std::string(#F)+"("+ m_expression.to_string(resolver)+")";} +#define DEFINE_UNARY_OPERATOR_NO_RESOLVER( X, F ) \ + X::X( const AmpGen::Expression& expression) : IUnaryExpression(expression) {} \ + X::operator Expression() const { return Expression( std::make_shared(*this) ) ; } \ + complex_t X::operator()() const { return F( m_expression() ); } + /// @ingroup ExpressionEngine macro DECLARE_UNARY_OPERATOR /// Macro to declare a unary operator, \ref ExpressionEngine "see IUnaryExpression" #define DECLARE_UNARY_OPERATOR( X ) \ class X : public IUnaryExpression { \ public: \ - X( const Expression& other ); \ + explicit X( const Expression& other ); \ virtual std::string to_string(const ASTResolver* resolver=nullptr) const override; \ virtual Expression d() const override; \ operator Expression() const; \ @@ -114,7 +119,7 @@ namespace AmpGen /// Resolve the dependencies of a tree using an ASTResolver, /// which keeps track of parameters, dependent sub-trees, etc. /// \param resolver resolver object to use - virtual void resolve( ASTResolver& resolver ) = 0; + virtual void resolve( ASTResolver& resolver ) const = 0; /// virtual descructor virtual ~IExpression() = default; /// Evaluate the expression using the tree, @@ -134,11 +139,11 @@ namespace AmpGen ~Expression() = default; std::string to_string(const ASTResolver* resolver=nullptr) const; IExpression* get() const; - void resolve( ASTResolver& resolver ); - Expression operator+=( const Expression& other ) const; - Expression operator*=( const Expression& other ) const; - Expression operator-=( const Expression& other ) const; - Expression operator/=( const Expression& other ) const; + void resolve( ASTResolver& resolver ) const; + Expression operator+=( const Expression& other ); + Expression operator*=( const Expression& other ); + Expression operator-=( const Expression& other ); + Expression operator/=( const Expression& other ); Expression operator-() const; complex_t operator()() const; @@ -157,7 +162,7 @@ namespace AmpGen Constant( const complex_t& value ) : m_value(value) {} std::string to_string(const ASTResolver* resolver=nullptr) const override; - void resolve( ASTResolver& resolver ) override; + void resolve( ASTResolver& resolver ) const override; operator Expression() const; complex_t operator()() const override { return m_value; } private: @@ -173,13 +178,12 @@ namespace AmpGen such as cache states, but this currently requires manually specifying the argument ordering. */ class Parameter : public IExpression { public: - Parameter( const std::string& name = "", - const double& defaultValue = 0 , - const bool& resolved = false, - const unsigned int& fromArg = 0 ); + Parameter(const std::string& name = "", + const double& defaultValue = 0 , + const bool& resolved = false); std::string to_string(const ASTResolver* resolver = nullptr) const override; - void resolve( ASTResolver& resolver ) override; - operator Expression() const; + void resolve( ASTResolver& resolver ) const override; + virtual operator Expression() const; complex_t operator()() const override { return complex_t( m_defaultValue, 0 ); } std::string name() const { return m_name; } const double& defaultValue() const { return m_defaultValue ; } @@ -189,9 +193,34 @@ namespace AmpGen std::string m_name; double m_defaultValue; bool m_resolved; - unsigned int m_fromArg; }; + class ComplexParameter : public IExpression { + public: + ComplexParameter( const Parameter& real, const Parameter& imag ); + std::string to_string(const ASTResolver* resolver = nullptr ) const override; + void resolve( ASTResolver& resolver ) const override; + operator Expression() const ; + complex_t operator()() const override; + private: + Parameter m_real; + Parameter m_imag; + }; + /** @ingroup ExpressionEngine class LambdaExpression + @brief Parameter that the value of which is given by some arbitrary C++ function + */ + class LambdaExpression : public IExpression { + public: + template + LambdaExpression( const function_type& function) : m_function(function), m_name(type_string()) {} + std::string to_string(const ASTResolver* resolver = nullptr) const override; + void resolve( ASTResolver& resolver) const override; + operator Expression() const; + complex_t operator()() const override; + std::function m_function; + std::string m_name; + }; + /** @ingroup ExpressionEngine class Ternary @brief Evaluates the ternary operator. @@ -199,12 +228,14 @@ namespace AmpGen \code{.cpp} return a ? b : c \endcode */ - struct Ternary : public IExpression { + class Ternary : public IExpression { + public: Ternary( const Expression& cond, const Expression& v1, const Expression& v2 ); std::string to_string(const ASTResolver* resolver = nullptr ) const override; - void resolve( ASTResolver& resolver ) override; + void resolve( ASTResolver& resolver ) const override; operator Expression() const ; complex_t operator()() const override { return std::real(m_cond()) ? m_v1() : m_v2(); } + private: Expression m_cond; Expression m_v1; Expression m_v2; @@ -214,11 +245,12 @@ namespace AmpGen struct SubTree : public IExpression { SubTree( const Expression& other ) ; std::string to_string(const ASTResolver* resolver = nullptr ) const override ; - void resolve( ASTResolver& resolver ) override; + void resolve( ASTResolver& resolver ) const override; operator Expression() const ; complex_t operator()() const override { return m_expression(); } uint64_t key() const; void setKey( const size_t& new_key ); + Expression expression() const { return m_expression; } Expression m_expression; uint64_t m_key; }; @@ -226,7 +258,7 @@ namespace AmpGen struct Function : public IExpression { Function( const std::string& name, const std::vector& args ) ; std::string to_string(const ASTResolver* resolver = nullptr ) const override ; - void resolve( ASTResolver& resolver ) override; + void resolve( ASTResolver& resolver ) const override; operator Expression() const ; complex_t operator()() const override { return 0; } std::string m_name; @@ -238,7 +270,7 @@ namespace AmpGen class IBinaryExpression : public IExpression { public: IBinaryExpression( const Expression& l, const Expression& r ) : lval( l ), rval( r ){}; - void resolve( ASTResolver& resolver ) override; + void resolve( ASTResolver& resolver ) const override; complex_t operator()() const override = 0; Expression l() const { return lval ; } Expression r() const { return rval ; } @@ -278,10 +310,22 @@ namespace AmpGen /// @ingroup ExpressionEngine class GreaterThan /// @brief Binary expression that returns \f$l > r\f$ DECLARE_BINARY_OPERATOR( GreaterThan ); + + /// @ingroup ExpressionEngine class LessThanEqualTo + /// @brief Binary expression that returns \f$l < r\f$ + DECLARE_BINARY_OPERATOR( LessThanEqualTo ); + /// @ingroup ExpressionEngine class GreaterThanEqualTo + /// @brief Binary expression that returns \f$l > r\f$ + DECLARE_BINARY_OPERATOR( GreaterThanEqualTo ); + /// @ingroup ExpressionEngine class And /// @brief Binary expression that returns \f$l \wedge r\f$ DECLARE_BINARY_OPERATOR( And ); + + /// @ingroup ExpressionEngine class Or + /// @brief Binary expression that returns \f$l \wedge r\f$ + DECLARE_BINARY_OPERATOR( Or ); DECLARE_BINARY_OPERATOR( Equal ); DECLARE_BINARY_OPERATOR( ATan2 ); @@ -290,7 +334,7 @@ namespace AmpGen class IUnaryExpression : public IExpression { public: IUnaryExpression( const Expression& other ) : m_expression( other ){}; - void resolve( ASTResolver& resolver ) override; + void resolve( ASTResolver& resolver ) const override; complex_t operator()() const override = 0; virtual Expression d() const = 0; Expression arg() const { return m_expression ;} @@ -348,7 +392,6 @@ namespace AmpGen /// @ingroup ExpressionEngine struct ACos /// @brief Unary expression that returns \f$\cos^{-1}(z)\f$ DECLARE_UNARY_OPERATOR( ACos ); - /// @ingroup ExpressionEngine struct ATan /// @brief Unary expression that returns \f$\tan^{-1}(z)\f$ DECLARE_UNARY_OPERATOR( ATan ); @@ -363,6 +406,8 @@ namespace AmpGen Expression operator<( const Expression& A, const Expression& B ); Expression operator>( const Expression& A, const Expression& B ); + Expression operator<=( const Expression& A, const Expression& B ); + Expression operator>=( const Expression& A, const Expression& B ); Expression operator+( const Expression& A, const Expression& B ); Expression operator-( const Expression& A, const Expression& B ); @@ -388,6 +433,7 @@ namespace AmpGen Expression operator/( const T& A, const Expression& B ){ return Constant(A) / B; } Expression operator&&( const Expression& A, const Expression& B ); + Expression operator||( const Expression& A, const Expression& B ); Expression operator==( const Expression& A, const Expression& B ); Expression operator==( const Expression& A, const double& B ); Expression operator==( const double& A, const Expression& B ); @@ -412,7 +458,6 @@ namespace AmpGen Expression exp( const Expression& expression ); Expression log( const Expression& expression ); Expression atan2( const Expression& y, const Expression& x); - } template < class T > bool is( const Expression& expression ){ diff --git a/AmpGen/ExpressionParser.h b/AmpGen/ExpressionParser.h index 5f18e924dc0..6becfbf086d 100644 --- a/AmpGen/ExpressionParser.h +++ b/AmpGen/ExpressionParser.h @@ -1,4 +1,5 @@ #ifndef AMPGEN_EXPRESSIONPARSER_H +#define AMPGEN_EXPRESSIONPARSER_H 1 #include #include @@ -9,31 +10,36 @@ #include "AmpGen/Expression.h" #include "AmpGen/Types.h" +#include "AmpGen/enum.h" namespace AmpGen { class ASTResolver; class MinuitParameter; class MinuitParameterSet; - + + declare_enum(coordinateType, cartesian, polar) + declare_enum(angType, deg, rad) + class MinuitParameterLink : public IExpression { public: - MinuitParameterLink( MinuitParameter* param ) ; + explicit MinuitParameterLink( MinuitParameter* param ) ; std::string to_string(const ASTResolver* resolver=nullptr) const override ; - void resolve( ASTResolver& resolver ) override ; + void resolve( ASTResolver& resolver ) const override ; complex_t operator()() const override ; operator Expression() const ; std::string name() const; + const MinuitParameter& param() const; private: MinuitParameter* m_parameter; }; class ExpressionPack : public IExpression { public: - ExpressionPack( const std::vector& expressions ){ m_expressions = expressions ; } + explicit ExpressionPack( const std::vector& expressions ): m_expressions(expressions) {} ExpressionPack( const Expression& A, const Expression& B ); std::string to_string(const ASTResolver* resolver=nullptr) const override; - void resolve( ASTResolver& resolver ) override; + void resolve( ASTResolver& resolver ) const override; complex_t operator()() const override; operator Expression() const ; private: @@ -60,27 +66,30 @@ namespace AmpGen } void add_binary( const std::string& name, binaryFCN op ) { m_binaryFunctions.emplace_back( name, op ); } - void setMPS( MinuitParameterSet* mps ) { m_mps = mps; } - static Expression Parse( const std::string& str ); + static Expression parse( const std::string& str, const MinuitParameterSet* mps=nullptr ); + static Expression parse(std::vector::const_iterator begin, + std::vector::const_iterator end , + const MinuitParameterSet* mps = nullptr ); static ExpressionParser* gExpressionParser; static ExpressionParser* getMe() { if ( !gExpressionParser ) gExpressionParser = new ExpressionParser(); return gExpressionParser; } - private: ExpressionParser(); - Expression processEndPoint( const std::string& name ); - Expression parseTokens( const std::vector& tokens ); + Expression processEndPoint( const std::string& name, const MinuitParameterSet* mps = nullptr ); + Expression parseTokens( std::vector::const_iterator begin, std::vector::const_iterator end , const MinuitParameterSet* mps = nullptr ); void processBinaryOperators( std::vector& opCodes, std::vector& expressions ); void processUnaryOperators( std::vector& opCodes, std::vector& expressions ); - MinuitParameterSet* m_mps; std::map m_unaryFunctions; std::vector> m_binaryFunctions; + bool m_isCartesian = {true}; + double m_sf = {1}; + }; } // namespace AmpGen diff --git a/AmpGen/Factory.h b/AmpGen/Factory.h index 0a76926c6e4..3323914be87 100644 --- a/AmpGen/Factory.h +++ b/AmpGen/Factory.h @@ -34,7 +34,7 @@ namespace AmpGen auto ptrToStatic = getMe(); auto raw_base = ptrToStatic->m_terms.find( type ); if ( raw_base == ptrToStatic->m_terms.end() ) { - if ( !quiet ) ERROR( type << " not found in Factory<" << typeof() << typeof() << " >" ); + if ( !quiet ) ERROR( type << " not found in Factory<" << type_string() << type_string() << " >" ); return nullptr; } auto objectToReturn = raw_base->second->create(); diff --git a/AmpGen/FastDT.h b/AmpGen/FastDT.h index 37158765c53..14f2953e4ae 100644 --- a/AmpGen/FastDT.h +++ b/AmpGen/FastDT.h @@ -24,14 +24,14 @@ namespace AmpGen { { public: struct Node { - unsigned int index; - int left; - int right; - double cutValue; + unsigned index; + unsigned left; + unsigned right; + double cutValue; Node(){}; - Node(const unsigned int& index, - const int& left, - const int& right, + Node(const unsigned& index, + const unsigned& left, + const unsigned& right, const double& cutValue) : index(index), left(left), right(right), cutValue(cutValue) {}; }; FastDT() = default; @@ -41,8 +41,8 @@ namespace AmpGen { std::vector m_nodes; std::function(const Event&)> m_functors; std::queue m_queueOrdering; - size_t m_dim; - size_t m_minEvents; + size_t m_dim = {0}; + size_t m_minEvents = {0}; size_t m_maxDepth = {0}; int m_endNodeCounter = {0}; int makeNodes(std::vector& evts, std::queue indexQueue, const size_t& depth); diff --git a/AmpGen/FitFraction.h b/AmpGen/FitFraction.h index 29142f17bdc..88efd3af8c5 100644 --- a/AmpGen/FitFraction.h +++ b/AmpGen/FitFraction.h @@ -7,17 +7,17 @@ #include #include "AmpGen/Types.h" #include "AmpGen/ErrorPropagator.h" +#include "AmpGen/AmplitudeRules.h" namespace AmpGen { class EventType; class Particle; - class FitFraction { public: - FitFraction(const std::string& line, const AmpGen::EventType& evtType); + FitFraction(const std::string& line); FitFraction(const std::string& name, const double& frac, const double& err); FitFraction() = default; @@ -25,13 +25,13 @@ namespace AmpGen double val() const; double err() const; std::string name() const; - std::shared_ptr particle() const; private: std::string m_name; double m_value; double m_error; }; + bool operator <(const FitFraction& lhs, const FitFraction& rhs); bool operator >(const FitFraction& lhs, const FitFraction& rhs); bool operator ==(const FitFraction& lhs, const FitFraction& rhs); @@ -60,7 +60,8 @@ namespace AmpGen pdf(pdf), normSet(normSet), recalculateIntegrals(recalculateIntegrals) {} - std::vector operator()(){ + std::vector operator()() + { if ( recalculateIntegrals ) pdf->prepare(); else pdf->transferParameters(); std::vector rv; @@ -82,14 +83,14 @@ namespace AmpGen } return std::real(sum); } - real_t getVal( const size_t& index ) const { + real_t getVal( const size_t& index, const bool& getImaginaryPart = false) const { complex_t sum = 0; for ( auto& i : calculators[index].i ) { for ( auto& j : calculators[index].j ) { sum += (*pdf)[i].coefficient * std::conj( (*pdf)[j].coefficient ) * ( j >= i ? pdf->norm(i, j) : std::conj(pdf->norm(j,i)) ); } } - return std::real(sum) / norm(); + return (getImaginaryPart ? std::imag(sum) : std::real(sum) ) / norm(); } std::vector operator()(const std::string& name, const LinearErrorPropagator& linProp ) { diff --git a/AmpGen/FitResult.h b/AmpGen/FitResult.h index a518679836c..932eab0f979 100644 --- a/AmpGen/FitResult.h +++ b/AmpGen/FitResult.h @@ -2,8 +2,8 @@ #define AMPGEN_FITRESULT_H #include "TMatrixD.h" +#include "TClass.h" -#include "AmpGen/EventType.h" #include "AmpGen/FitFraction.h" #include "AmpGen/MinuitParameter.h" #include "AmpGen/Utilities.h" @@ -15,75 +15,64 @@ namespace AmpGen class FitResult { - private: - double m_chi2; - double m_LL; - double m_nBins; - double m_nParam; - int m_status; - EventType m_eventType; - std::map m_observables; - std::vector m_fitFractions; - TMatrixD m_covarianceMatrix; - std::shared_ptr m_mps; - bool m_fitted; - std::map m_covMapping; - - std::string getLastLine( std::ifstream& in ) const; - void addToParameters( const std::string& line ); - void addToObservables( const std::string& line ); - void setFitQuality( const std::string& line ); - public: - FitResult( const FitResult& other ); + ~FitResult(){}; + FitResult(); + explicit FitResult( const FitResult& other ); + explicit FitResult( const std::string& filename ); + explicit FitResult( const Minimiser& mini ); + FitResult( MinuitParameterSet& mps, const TMatrixD& covMini ); void addObservable( const std::string& name, const double& F ); - FitResult( const Minimiser& mini ); - FitResult( const MinuitParameterSet& mps, const TMatrixD& covMini ); - - FitResult( const std::string& filename, const EventType& evtType = EventType() ); - FitResult() : m_chi2( 0 ), m_LL( -999 ), m_nBins( 0 ), m_nParam( 0 ), m_status( -1 ), m_fitted( 0 ) {} - - bool readFile( const std::string& fname ); + void addChi2( const double& chi2, const double& nBins ); + void addFractions( const std::vector& fractions ); + void addFraction( const std::string& name, const double& frac, const double& err ); + void setCov( const size_t& x, const size_t& y, const double& F ); void writeToFile( const std::string& fname ); + void clearFitFractions(); - double chi2() const { return m_chi2; } - double LL() const { return m_LL; } - int status() const { return m_status; } - int nParam() const { return m_nParam; } - int nBins() const { return m_nBins; } + bool readFile( const std::string& fname ); - EventType eventType() const { return m_eventType; } - std::map observables() const { return m_observables; } - std::vector fitFractions() const { return m_fitFractions; } - std::shared_ptr mps() const { return m_mps; } + double chi2() const; + double LL() const; + double dof() const; + double cov(const size_t& x, const size_t& y ) const; + double cov(const std::string& x, const std::string& y ) const; + double correlation( const std::string& x, const std::string& y ) const; + + int status() const; + int nParam() const; + int nBins() const; - double dof() const { return m_nBins - m_nParam - 1; } - std::vector getParameters() const; - std::vector getFitFractions() const { return m_fitFractions; } - MinuitParameterSet* MPS() const { return &( *m_mps ); } - TMatrixD cov() const { return m_covarianceMatrix; } - double cov( const size_t& x, const size_t& y ) const { return m_covarianceMatrix( x, y ); } + std::map observables() const; + MinuitParameterSet* mps() const; + std::vector fitFractions() const; + std::vector parameters() const; + std::vector floating(const bool& extended = false) const; + TMatrixD cov() const; + void print() const; - std::vector getFloating( const bool& extended = false ) const; TMatrixD getReducedCovariance( const bool& extended = false ) const; LinearErrorPropagator getErrorPropagator( const bool& extended = false ) const; - void addChi2( const double& chi2, const double& nBins ); - void addFractions( const std::vector& fractions ); - void addFraction( const std::string& name, const double& frac, const double& err ) - { - m_fitFractions.emplace_back( name, frac, err ); - } - void clearFitFractions() { m_fitFractions.clear(); } - void setCov( const size_t& x, const size_t& y, const double& F ) { m_covarianceMatrix( x, y ) = F; } - double correlation( const std::string& x, const std::string& y ) - { - auto ix = m_covMapping[x]; - auto iy = m_covMapping[y]; - return m_covarianceMatrix( ix, iy ) / sqrt( m_covarianceMatrix( ix, ix ) * m_covarianceMatrix( iy, iy ) ); - } + + private: + MinuitParameterSet* m_mps = {nullptr}; + double m_chi2 = {0}; + double m_LL = {-999}; + double m_nBins = {0}; + double m_nParam = {0}; + int m_status = {-1}; + bool m_fitted = {false}; + std::map m_observables; + std::vector m_fitFractions; + TMatrixD m_covarianceMatrix; + std::map m_covMapping; + + void addToParameters( const std::string& line ); + void addToObservables( const std::string& line ); + void setFitQuality( const std::string& line ); }; } // namespace AmpGen diff --git a/AmpGen/Generator.h b/AmpGen/Generator.h index 9f146fd8e2e..5fafd74a841 100644 --- a/AmpGen/Generator.h +++ b/AmpGen/Generator.h @@ -5,148 +5,172 @@ #include "AmpGen/EventType.h" #include "AmpGen/PhaseSpace.h" #include "AmpGen/Utilities.h" +#include "AmpGen/ProfileClock.h" +#include "AmpGen/ProgressBar.h" +#include "AmpGen/NamedParameter.h" +#include "AmpGen/MetaUtils.h" namespace AmpGen { - template - class Generator - { - private: - EventType m_eventType; - PHASESPACE m_gps; - unsigned int m_generatorBlock = {5000000}; - TRandom* m_rnd = {gRandom}; - bool m_normalise = {true}; - - public: - template - Generator( const ARGS&... args ) - : m_gps(args...) - { - m_eventType = m_gps.eventType(); - setRandom( m_rnd ); - } - PHASESPACE phsp() { return m_gps; } - void setRandom( TRandom* rand ) - { - m_rnd = rand; - m_gps.setRandom( m_rnd ); - } - void fillEventListPhaseSpace( EventList& list, const unsigned int& N, unsigned int cacheSize = 0 ) - { - fillEventListPhaseSpace( list, N, cacheSize, []( const Event& evt ) { return 1; } ); - } - void setBlockSize( const size_t& blockSize ) { m_generatorBlock = blockSize; } - void setNormFlag( const bool& normSetting ) { m_normalise = normSetting; } - - template - void fillEventListPhaseSpace( EventList& list, const unsigned int& N, const unsigned int& cacheSize, HARD_CUT cut ) + template + class Generator { - unsigned int rejected = 0; - #ifdef DEBUGLEVEL - auto t_start = std::chrono::high_resolution_clock::now(); - #endif - list.reserve( N ); - while( list.size() < N ){ - Event newEvent = m_gps.makeEvent( cacheSize ); - newEvent.setWeight( 1 ); - if ( cut( newEvent ) ) list.push_back( newEvent ); - else rejected ++; - } - #ifdef DEBUGLEVEL - auto t_end = std::chrono::high_resolution_clock::now(); - double time = std::chrono::duration( t_end - t_start ).count(); - #endif - DEBUG( "Stage 1 efficiency = " << 100. * list.size() / ( list.size() + rejected ) << "%, yield = " << list.size() - << " time = " << time ); - } - template - void fillEventList( PDF& pdf, EventList& list, const unsigned int& N ) - { - fillEventList( pdf, list, N, []( const Event& evt ) { return 1; } ); - } + private: + EventType m_eventType; + phaseSpace_t m_gps; + size_t m_generatorBlock = {5000000}; + TRandom* m_rnd = {gRandom}; + bool m_normalise = {true}; - template - void fillEventList( PDF& pdf, EventList& list, const unsigned int& N, HARD_CUT cut ) - { - if ( m_rnd == nullptr ) { - ERROR( "Random generator not set!" ); - return; - } - double normalisationConstant = m_normalise ? 0 : 1; - unsigned int size0 = list.size(); - auto tStartTotal = std::chrono::high_resolution_clock::now(); - pdf.reset( true ); - while ( list.size() - size0 < N ) { - auto t_start = std::chrono::high_resolution_clock::now(); - EventList mc( m_eventType ); - fillEventListPhaseSpace( mc, m_generatorBlock, pdf.size(), cut ); - - pdf.setEvents( mc ); - pdf.prepare(); + public: + template explicit Generator( const ARGS&... args ) : m_gps(args...) + { + m_eventType = m_gps.eventType(); + setRandom( m_rnd ); + DEBUG("Creating generator, using: " << type_string() << " and internal store type: " << type_string() ); + } + + phaseSpace_t phsp() { return m_gps; } + + void setRandom( TRandom* rand ) + { + m_rnd = rand; + m_gps.setRandom( m_rnd ); + } + void setBlockSize( const size_t& blockSize ) { m_generatorBlock = blockSize; } + void setNormFlag( const bool& normSetting ) { m_normalise = normSetting; } - if ( normalisationConstant == 0 ) { - double max = 0; - for ( auto& evt : mc ) { - double value = pdf.prob_unnormalised( evt ); + template void fillEventListPhaseSpace( eventListInternal_t& events, const size_t& N, [[maybe_unused]] cut_t cut = nullptr) + { + events.resize(N); + auto it = events.begin(); + while( it != events.end() ) + { + *it = m_gps.makeEvent(); + if constexpr( ! std::is_same::value ) + { + if( ! cut(*it ) ) continue; + } + if constexpr( std::is_same::value ) it->setIndex( it - events.begin() ); + ++it; + } + } + template void fillEventList( pdf_t& pdf, eventList_t& list, const size_t& N ) + { + fillEventList( pdf, list, N, nullptr); + } + template double getMax(const pdf_t& pdf, const eventListInternal_t& events) const + { + auto max = 0.; + for ( const auto& evt : events ) + { + auto value = pdf(evt) / evt.genPdf(); if ( value > max ) max = value; } - normalisationConstant = max * 1.5; - INFO( "Setting normalisation constant = " << normalisationConstant ); + DEBUG( "Returning normalisation constant = " << max * 1.5 ); + return max; } - unsigned int previousSize = list.size(); - for ( auto& evt : mc ) { - double value = pdf.prob_unnormalised( evt ); - if ( value > normalisationConstant ) { - WARNING( "PDF value exceeds norm value: " << value << " " << normalisationConstant ); - } - if ( value > normalisationConstant * m_rnd->Rndm() ) { - evt.setGenPdf( value ); - list.push_back( evt ); + template void fillEventList( pdf_t& pdf, eventList_t& list, const size_t& N, cut_t cut ) + { + if ( m_rnd == nullptr ) + { + ERROR( "Random generator not set!" ); + return; } - if ( list.size() - size0 == N ) break; + double maxProb = m_normalise ? 0 : 1; + auto size0 = list.size(); + double totalGenerated = 0; + pdf.reset( true ); + ProgressBar pb(60, detail::trimmedString(__PRETTY_FUNCTION__) ); + ProfileClock t_phsp, t_eval, t_acceptReject, t_total; + std::vector efficiencyReport(m_generatorBlock,false); + bool accept_all = NamedParameter("AcceptAll",false); + eventListInternal_t mc( m_eventType ); + while ( list.size() - size0 < N ) { + t_phsp.start(); + fillEventListPhaseSpace(mc, m_generatorBlock, cut); + t_phsp.stop(); + t_eval.start(); + pdf.setEvents( mc ); + pdf.prepare(); + maxProb = maxProb == 0 ? 1.5 * getMax(pdf, mc) : maxProb; + auto previousSize = list.size(); + #ifdef _OPENMP + #pragma omp parallel for + #endif + for ( size_t block=0; block < mc.nBlocks(); ++block ) + mc.setWeight(block, 1.0, pdf(mc.block(block), block) / mc.genPDF(block)); + t_eval.stop(); + t_acceptReject.start(); + totalGenerated += mc.size(); + for(const auto& event : mc) + { + if ( event.genPdf() > maxProb ) { + std::cout << std::endl; + WARNING( "PDF value exceeds norm value: " << event.genPdf() << " > " << maxProb ); +// pdf.debug( event ); + } + if ( accept_all || event.genPdf() > maxProb * m_rnd->Rndm() ){ + list.push_back(event); + efficiencyReport[event.index()] = true; + } + else efficiencyReport[event.index()] = false; + if ( list.size() - size0 == N ) break; + } + t_acceptReject.stop(); + + // m_gps.provideEfficiencyReport( efficiencyReport ); + double efficiency = 100. * ( list.size() - previousSize ) / (double)m_generatorBlock; + pb.print( double(list.size()) / double(N), " ε[gen] = " + mysprintf("%.4f",efficiency) + "% , " + std::to_string(int(t_total.count()/1000.)) + " seconds" ); + if ( list.size() == previousSize ) { + ERROR( "No events generated, PDF: " << type_string() << " is likely to be malformed" ); + break; + } + } + pb.finish(); + t_total.stop(); + INFO("Generated " << N << " events in " << t_total << " ms"); + INFO("Generating phase space : " << t_phsp << " ms"); + INFO("Evaluating PDF : " << t_eval << " ms"); + INFO("Accept/reject : " << t_acceptReject << " ms"); + INFO("Efficiency = " << double(N) * 100. / totalGenerated << " %"); } - auto t_end = std::chrono::high_resolution_clock::now(); - // double time = std::chrono::duration(t_end-t_stage2).count() ; - double timeTotal = std::chrono::duration( t_end - t_start ).count(); - INFO( "Generator Efficiency = " << 100. * ( list.size() - previousSize ) / (double)m_generatorBlock - << "% integrated yield = " << list.size() << ", time = " << timeTotal << "ms" ); - if ( list.size() == previousSize ) { - ERROR( "No events generated, PDF: " << typeof() << " is likely to be malformed" ); - break; + template ::value>::type> + EventList generate(pdf_t& pdf, const size_t& nEvents ) + { + EventList evts( m_eventType ); + fillEventList( pdf, evts, nEvents ); + return evts; + } + EventList generate(const size_t& nEvents) + { + EventList evts( m_eventType ); + fillEventListPhaseSpace( evts, nEvents); + return evts; } - } - double time = - std::chrono::duration( std::chrono::high_resolution_clock::now() - tStartTotal ).count(); - INFO( "Generated " << N << " events in " << time << " ms" ); - } - template - EventList generate( PDF& pdf, const unsigned int& nEvents ) - { - EventList evts( m_eventType ); - fillEventList( pdf, evts, nEvents ); - return evts; - } - EventList generate( const unsigned int& nEvents, const size_t& cacheSize=0 ) - { - EventList evts( m_eventType ); - fillEventListPhaseSpace( evts, nEvents, cacheSize ); - return evts; - } + }; - }; - template - class PDFWrapper { - FCN m_fcn; + template class PDFWrapper + { public: - void prepare(){}; - void setEvents( AmpGen::EventList& evts ){}; - double prob_unnormalised( const AmpGen::Event& evt ) const { return m_fcn(evt); } - PDFWrapper( const FCN& fcn ) : m_fcn(fcn) {} - size_t size() const { return 0; } - void reset( const bool& flag = false ){}; + void prepare(){}; + void setEvents( AmpGen::EventList& /*evts*/ ){}; + double prob_unnormalised( const AmpGen::Event& evt ) const { return m_fcn(evt); } + explicit PDFWrapper( const FCN& fcn ) : m_fcn(fcn) {} + size_t size() const { return 0; } + void reset( const bool& /*flag*/ = false ){}; + + private: + FCN m_fcn; }; + + template PDFWrapper make_pdf(const FCN& fcn){ return PDFWrapper(fcn) ; } + + /** @function PyGenerate + + Wrapper around the a phase space generator from a stringy event type to be used with python / numpy. + */ extern "C" void PyGenerate( const char* eventType, double* out, const unsigned int size ); } // namespace AmpGen #endif diff --git a/AmpGen/IncoherentSum.h b/AmpGen/IncoherentSum.h index c4c32bb6b16..589c6760057 100644 --- a/AmpGen/IncoherentSum.h +++ b/AmpGen/IncoherentSum.h @@ -1,5 +1,5 @@ -#ifndef AMPGEN_FASTINCOHERENTSUM_H -#define AMPGEN_FASTINCOHERENTSUM_H +#ifndef AMPGEN_INCOHERENTSUM_H +#define AMPGEN_INCOHERENTSUM_H #include #include @@ -19,22 +19,47 @@ namespace AmpGen class FitFraction; class LinearErrorPropagator; class MinuitParameterSet; - + + /** @class IncoherentSum + @brief An incoherent sum of resonances, traditionally considered as an approximate background model. + An incoherent sum of resonant contributions, where at a positiion in phase-space @f$\psi@f$, + the (unnormalised) probability density is given by + @f[ + \mathcal{P}(\psi) = \sum_{i} \left| g_i \mathcal{A}_i(\psi) \right|^2, + @f] + where @f$\mathcal{P}(\psi)@f$ is the probability, @f$g_i@f$ is the coupling to an isobar channel, + and @f$\mathcal{A}_i(\psi)@f$ is the amplitude of the ith channel. + I dont know whats going on? + */ class IncoherentSum : public CoherentSum { public: - IncoherentSum( const EventType& finalStates, const AmpGen::MinuitParameterSet& mps, const std::string& prefix = "Inco" ); + /** Constructs an incoherentSum from the type of event this is expected to describe, + and a set of parameters that are expected to be able to describe it. + @param eventType The type of event that this PDF should describe + @param mps The parameter set of couplings, masses, etc. + @param prefix Prefix required for the ``head'' decays for this event type. */ + IncoherentSum(const EventType& eventType, const AmpGen::MinuitParameterSet& mps, const std::string& prefix = "Inco"); + + /// Evaluates the normalised probability for an event. + real_t prob( const Event& evt ) const; + real_t operator()(const Event& evt) const { return prob(evt) ; } - double getVal( const Event& evt ) const; - double operator()( const Event& evt ) const; - double prob( const Event& evt ) const; - double prob_unnormalised( const Event& evt ) const; - void prepare(); - double norm() const; + /// Calculates the unnormalised probability for an event. + real_t prob_unnormalised( const Event& evt ) const; + + /** Returns the normalisation for this PDF, given by + @f[ + \mathcal{N} = \int d\psi \varepsilon(\psi) \mathcal{P}(\psi) \approx \sum_i \frac{\mathcal{P}(\psi_i)}{\mathcal{P}^\prime(\psi_i)} + @f] + where the sum is over a simulated sample, generated with PDF @f$\mathcal{P}^\prime(\psi)@f$. */ + real_t norm() const; complex_t norm(const size_t& i, const size_t& j){ return i==j ? m_normalisations.get(i, 0) : 0; } complex_t norm(const size_t& i) { return m_normalisations.get(i, 0); } - double norm( const Bilinears& norms ) const; + real_t norm( const Bilinears& norms ) const; std::vector fitFractions( const LinearErrorPropagator& linProp ); + + void prepare(); }; } // namespace AmpGen diff --git a/AmpGen/Integrator.h b/AmpGen/Integrator.h index b9e4f5b024e..df48b7a763d 100644 --- a/AmpGen/Integrator.h +++ b/AmpGen/Integrator.h @@ -5,15 +5,74 @@ #include "AmpGen/EventList.h" #include #include - -/* - * Calculates Bilinears A_i A_j^* integrated over the phase-space. - * Integrates in blocks of (i,j) such that integrals can be queued and evaluated in blocks - * to optimise cache throughput. - */ +#include "AmpGen/simd/utils.h" +#include "AmpGen/Store.h" +#include "AmpGen/EventListSIMD.h" +#include "AmpGen/EventList.h" namespace AmpGen -{ +{ + class Integrator + { + struct QueuedIntegral + { + QueuedIntegral() = default; + QueuedIntegral(complex_t* result, const unsigned& i, const unsigned& j) + : result(result), i(i), j(j) {} + complex_t* result = {nullptr}; + unsigned i = {0}; + unsigned j = {0}; + }; + public: + Integrator() = default; + + template Integrator( const EventList_type* events, const std::vector& expressions ={}, const size_t& size_of =0) : m_events(events) + { + if( events == nullptr ) { + WARNING("No events specified, returning"); + return; + } + m_cache = Store(events->size(), expressions); + m_weight.resize( events->nBlocks() ); + float_v norm_acc = 0.; + for( size_t i = 0 ; i < events->nBlocks(); ++i ) + { + m_weight[i] = events->weight(i) / events->genPDF(i); + norm_acc += m_weight[i]; + } + m_norm = utils::sum_elements(norm_acc); + } + + bool isReady() const; + void queueIntegral( complex_t* result, const unsigned& i, const unsigned& j ); + void flush(); + + template return_type get( const unsigned& index, const unsigned& evt ) const ; + template unsigned getCacheIndex( const T& t ) const { return m_cache.find(t) ; } + double norm() const { return m_norm; } + + template void updateCache(const T& expression) + { + #if ENABLE_AVX + if( m_events != nullptr ) m_cache.update( static_cast(m_events)->store(), expression ); + #else + if( m_events != nullptr ) m_cache.update( static_cast(m_events)->store(), expression ); + #endif + } + template const T* events() const { return static_cast(m_events) ; } + + const Store& cache() const { return m_cache; } + private: + static constexpr size_t N = {8}; ///unroll factor + size_t m_counter = {0}; /// + std::array m_integrals; + const void* m_events = {nullptr}; + std::vector m_weight; + Store m_cache; + double m_norm = {0}; + void integrateBlock(); + }; + class Bilinears { private: @@ -25,9 +84,8 @@ namespace AmpGen public: Bilinears( const size_t& r = 0, const size_t& c = 0 ); complex_t get(const size_t& x, const size_t& y) const; - template - complex_t get(const size_t& x, const size_t& y, T* integ = nullptr, const size_t& kx=0, const size_t& ky=0){ - if( integ != nullptr ) integ->queueIntegral(kx, ky, &norms[x*cols+y]); + complex_t get(const size_t& x, const size_t& y, Integrator* integ = nullptr, const size_t& kx=0, const size_t& ky=0){ + if( integ != nullptr ) integ->queueIntegral(&norms[x*cols+y], kx, ky ); /// will return the wrong answer for now, but queues for later.. return norms[x*cols+y]; } @@ -40,232 +98,5 @@ namespace AmpGen void resize(const size_t& r, const size_t& c = 1 ); }; - template - struct Integral { - typedef std::function TransferFCN; - size_t i = {0}; - size_t j = {0}; - TransferFCN transfer; - Integral() = default; - Integral(const size_t& i, const size_t& j, TransferFCN t) : i(i), j(j), transfer(t) {} - }; - - template - class Integrator - { - private: - typedef const complex_t& arg; - typedef std::function TransferFCN; - size_t m_counter = {0}; - std::array, NROLL> m_integrals; - EventList* m_events = {nullptr}; - void calculate() - { - integrateBlock(); - m_counter = 0; - } - void integrateBlock() - { - real_t re[NROLL] = {0}; - real_t im[NROLL] = {0}; - #pragma omp parallel for reduction( +: re, im ) - for ( size_t i = 0; i < m_events->size(); ++i ) { - auto& evt = ( *m_events )[i]; - real_t w = evt.weight() / evt.genPdf(); - for ( size_t roll = 0; roll < NROLL; ++roll ) { - auto c = evt.getCache(m_integrals[roll].i) * std::conj(evt.getCache(m_integrals[roll].j)); - re[roll] += w * std::real(c); - im[roll] += w * std::imag(c); - } - } - real_t nv = m_events->norm(); - for ( size_t j = 0; j < m_counter; ++j ) - m_integrals[j].transfer( complex_t( re[j], im[j] ) / nv ); - } - public: - Integrator( EventList* events = nullptr ) : m_events( events ){} - - double sampleNorm() { return m_events->norm(); } - bool isReady() const { return m_events != nullptr ; } - const EventList& events() const { return *m_events ; } - template - void addIntegral( const T1& f1, const T2& f2, const TransferFCN& tFunc ) - { - addIntegralKeyed( m_events->getCacheIndex(f1), m_events->getCacheIndex(f2), tFunc ); - } - void queueIntegral(const size_t& i, const size_t& j, complex_t* result){ - addIntegralKeyed(i, j, [result](arg& val){ *result = val ; } ); - } - void queueIntegral(const size_t& c1, - const size_t& c2, - const size_t& i, - const size_t& j, - Bilinears* out, - const bool& sim = true ) - { - if( out->workToDo(i,j) ){ - if( sim ) - addIntegralKeyed( c1, c2, [out,i,j]( arg& val ){ - out->set(i,j,val); - if( i != j ) out->set(j,i, std::conj(val) ); } ); - else - addIntegralKeyed( c1, c2, [out,i,j]( arg& val ){ out->set(i,j,val); } ); - } - } - void addIntegralKeyed( const size_t& c1, const size_t& c2, const TransferFCN& tFunc ) - { - m_integrals[m_counter++] = Integral(c1,c2,tFunc); - if ( m_counter == NROLL ) calculate(); - } - - void flush() - { - if ( m_counter == 0 ) return; - calculate(); - } - template - void prepareExpression( const EXPRESSION& expression, const size_t& size_of = 0 ) - { - if( m_events == nullptr ) return; - auto index = m_events->registerExpression( expression , size_of ); - m_events->updateCache( expression, index ); - } - }; - - template - class BinnedIntegrator - { - private: - typedef const std::vector>& arg; - typedef std::function TransferFCN; - - size_t m_counter = {0}; - std::vector m_view = {0}; - std::vector m_slice = {0}; - std::array, NROLL> m_integrals; - EventList* m_events = {nullptr}; - void calculate() - { - integrateBlock(); - m_counter = 0; - } - void integrateBlock() - { - double re[( NBINS + 1 ) * NROLL] = {0}; - double im[( NBINS + 1 ) * NROLL] = {0}; - auto ij = [&]( const Event& evt, const unsigned int& i, const unsigned int& j ) { - return evt.getCache( i ) * std::conj( evt.getCache( j ) ); - }; - if ( m_slice.size() == 0 ) { - #pragma omp parallel for reduction( + : re, im ) - for ( unsigned int i = 0; i < m_events->size(); ++i ) { - auto& evt = ( *m_events )[i]; - size_t binNo = m_view[i]; - double w = evt.weight() / evt.genPdf(); - for ( unsigned int roll = 0; roll < NROLL; ++roll ) { - auto c = ij( evt, m_integrals[roll].i, m_integrals[roll].j ); - DEBUG( "pos = " << roll * NBINS + binNo << " val = " << w * c ); - re[roll * NBINS + binNo] += w * std::real( c ); - im[roll * NBINS + binNo] += w * std::imag( c ); - } - } - } else { - #pragma omp parallel for reduction( + : re, im ) - for ( unsigned int i = 0; i < m_slice.size(); ++i ) { - auto& evt = ( *m_events )[m_slice[i]]; - size_t binNo = m_view[i]; - double w = evt.weight() / evt.genPdf(); - for ( unsigned int roll = 0; roll < NROLL; ++roll ) { - auto c = ij( evt, m_integrals[roll].i, m_integrals[roll].j ); - re[roll * NBINS + binNo] += w * std::real( c ); - im[roll * NBINS + binNo] += w * std::imag( c ); - } - } - } - double nv = m_events->norm(); - for ( size_t thisIntegral = 0; thisIntegral < m_counter; ++thisIntegral ) { - std::vector> tmpBins( NBINS ); - size_t offset = thisIntegral * NBINS; - for ( size_t nBin = 0; nBin < NBINS; ++nBin ) - tmpBins[nBin] = std::complex( re[offset + nBin], im[offset + nBin] ) / nv; - m_integrals[thisIntegral].transfer( tmpBins ); - } - } - public: - BinnedIntegrator( EventList* events = nullptr ) : m_events( events ) {} - void setView( const std::function& binNumber ) - { - if ( m_slice.size() == 0 ) { - if ( m_view.size() != m_events->size() ) m_view.resize( m_events->size() ); - for ( unsigned int i = 0; i < m_events->size(); ++i ) { - - m_view[i] = binNumber( ( *m_events )[i] ); - - if ( m_view[i] >= NBINS ) { - m_view[i] = NBINS; - WARNING( "Event " << m_slice[i] << " bin number = " << m_view[i] << " is out of range!" ); - } - } - } else { - if ( m_view.size() != m_slice.size() ) m_view.resize( m_slice.size() ); - for ( unsigned int i = 0; i < m_slice.size(); ++i ) { - m_view[i] = binNumber( ( *m_events )[m_slice[i]] ); - if ( m_view[i] >= NBINS ) { - m_view[i] = NBINS; - WARNING( "Event " << m_slice[i] << " bin number = " << m_view[i] << " is out of range!" ); - } - } - } - } - void setSlice( const std::function& sliceFunction ) - { - if ( m_slice.size() != 0 ) m_slice.clear(); - for ( unsigned int i = 0; i < m_events->size(); ++i ) - if ( sliceFunction( ( *m_events )[i] ) ) m_slice.push_back( i ); - } - - template - void addIntegral( const T1& f1, const T2& f2, const TransferFCN& tFunc ) - { - m_integrals[m_counter++] = Integral( m_events->getCacheIndex( f1 ), m_events->getCacheIndex( f2 ), tFunc ); - if ( m_counter == NROLL ) calculate(); - } - void flush() - { - if ( m_counter == 0 ) return; - calculate(); - } - template - void update( FCN& fcn, std::array& normalisations ) - { - auto mE = fcn.matrixElements(); - auto size = mE.size(); - std::vector toUpdate; - std::vector integralHasChanged( size * size ); - for ( size_t x = 0; x < size; ++x ) { - auto& pdf = mE[x].pdf; - pdf.prepare(); - if ( !pdf.hasExternalsChanged() ) continue; - m_events->updateCache( pdf, m_events->getCacheIndex( pdf ) ); - toUpdate.push_back( x ); - } - for ( auto& i : toUpdate ) { - DEBUG( "Updating: " << mE[i].decayTree->uniqueString() ); - for ( unsigned int j = 0; j < size; ++j ) { - if ( integralHasChanged[i * size + j] ) continue; - integralHasChanged[i * size + j] = true; - integralHasChanged[j * size + i] = true; - - addIntegral( mE[i].pdf, mE[j].pdf, - [i, j, &normalisations]( const auto& val ) { - for ( unsigned int bin = 0; bin < NBINS; ++bin ) { - normalisations[bin].set( i, j, val[bin] ); - if ( i != j ) normalisations[bin].set( j, i, std::conj( val[bin] ) ); - } - } ); - } - } - } - }; } // namespace AmpGen #endif diff --git a/AmpGen/KeyedFunctors.h b/AmpGen/KeyedFunctors.h new file mode 100644 index 00000000000..c1c9fa7654a --- /dev/null +++ b/AmpGen/KeyedFunctors.h @@ -0,0 +1,31 @@ +#ifndef AMPGEN_LITESPAN_H +#define AMPGEN_LITESPAN_H + +#include "AmpGen/MsgService.h" +#include "AmpGen/Utilities.h" + +namespace AmpGen { + template struct KeyedFunctors; + + template struct KeyedFunctors + { + std::vector > functors; + std::vector keys; + std::vector titles; + template void add(const functor_type& functor, const std::string& key, const std::string& title="") + { + functors.push_back(functor); + keys.push_back(key); + titles.push_back(title); + } + std::vector operator()( arg_types... arg ) const + { + std::vector rt; + for( auto& f : functors ) rt.push_back( f(arg...) ); + return rt; + } + }; + +} + +#endif diff --git a/AmpGen/Kinematics.h b/AmpGen/Kinematics.h index 6385fe8230e..a86ebb8e6e4 100644 --- a/AmpGen/Kinematics.h +++ b/AmpGen/Kinematics.h @@ -23,15 +23,15 @@ namespace AmpGen */ class HelicityCosine { public: - HelicityCosine(const std::vector& p1, const std::vector& p2, - const std::vector& pR); + HelicityCosine(const std::vector& p1, const std::vector& p2, + const std::vector& pR); - HelicityCosine(const size_t& i, const size_t& j, const std::vector& pR); + HelicityCosine(const unsigned& i, const unsigned& j, const std::vector& pR); double operator()( std::vector::iterator evt ) const; double operator()( const Event& evt ) const; private: - std::vector _i, _j, _pR; + std::vector _i, _j, _pR; }; /** @ingroup Kin class MomentumTransfer @@ -39,13 +39,13 @@ namespace AmpGen */ class MomentumTransfer { public: - MomentumTransfer( const std::vector& _p1, const std::vector& _p2 ); + MomentumTransfer( const std::vector& _p1, const std::vector& _p2 ); double operator()( const Event& evt ) const; private: double Q2( const double& s, const double& s1, const double& s2 ) const; - std::vector p1; - std::vector p2; - std::vector s; + std::vector p1; + std::vector p2; + std::vector s; }; /** @ingroup Kin function acoplanarity @@ -79,12 +79,12 @@ namespace AmpGen /** @ingroup Kin function pFromEvent @brief Helper function to extract a TLorentzVector of the ith decay product from an AmpGen::Event. */ - TLorentzVector pFromEvent( const Event& evt, const size_t& ref ); + TLorentzVector pFromEvent( const Event& evt, const unsigned& ref ); /** @ingroup Kin function pFromEvent @brief Helper function to extract a TLorentzVector of the sum of {2} decay product from an AmpGen::Event. */ - TLorentzVector pFromEvent( const Event& evt, const std::vector& ref ); + TLorentzVector pFromEvent( const Event& evt, const std::vector& ref ); } // namespace AmpGen #endif diff --git a/AmpGen/Lineshapes.h b/AmpGen/Lineshapes.h index 9d4648251ce..cf9a57b7309 100644 --- a/AmpGen/Lineshapes.h +++ b/AmpGen/Lineshapes.h @@ -10,6 +10,8 @@ #include "AmpGen/Factory.h" #include "AmpGen/MsgService.h" #include "AmpGen/Tensor.h" +#include "AmpGen/Particle.h" + /** @defgroup Lineshapes Lineshapes @brief Lineshapes are semi-empirical complex functions for describing the propagation and decay of short-lived resonances. @@ -39,7 +41,7 @@ */ #define DECLARE_LINESHAPE( X ) \ - class X : public AmpGen::ILineshape { \ + class X : public AmpGen::Lineshape::Base { \ static std::string _id; \ public: \ X(){ DEBUG("Constructing lineshape") ;} \ @@ -47,50 +49,36 @@ const AmpGen::Expression& s2, const std::string& particleName, \ const unsigned int& L, const std::string& lineshapeModifier, \ AmpGen::DebugSymbols* dbexpressions = 0) const override; \ - AmpGen::Expression get(const AmpGen::Expression& s, const std::vector& p, \ - const std::string& particleName, \ - const unsigned int& L, const std::string& lineshapeModifier, \ + AmpGen::Expression get(const AmpGen::Particle& p, \ + const std::string& lineshapeModifier, \ AmpGen::DebugSymbols* dbexpressions = nullptr ) const override; \ } #define DEFINE_LINESHAPE( X ) \ - REGISTER_WITH_KEY( ILineshape, Lineshape::X, #X, std::string ); \ - AmpGen::Expression Lineshape::X::get( const AmpGen::Expression& s, const std::vector& p, \ - const std::string& particleName, \ - const unsigned int& L, const std::string& lineshapeModifier, \ + REGISTER_WITH_KEY( Lineshape::Base, Lineshape::X, #X, std::string ); \ + AmpGen::Expression Lineshape::X::get( const AmpGen::Particle& p, \ + const std::string& lineshapeModifier, \ AmpGen::DebugSymbols* dbexpressions ) const { return \ - get(s, dot(p[0],p[0]), dot(p[1],p[1]), \ - particleName, L, lineshapeModifier, dbexpressions) ;} \ + get(p.massSq(), p.daughter(0)->massSq(), p.daughter(1)->massSq(), \ + p.name(), p.L(), lineshapeModifier, dbexpressions) ;} \ AmpGen::Expression Lineshape::X::get( const AmpGen::Expression& s, const AmpGen::Expression& s1, \ const AmpGen::Expression& s2, const std::string& particleName, \ const unsigned int& L, const std::string& lineshapeModifier, \ AmpGen::DebugSymbols* dbexpressions ) const #define DEFINE_GENERIC_SHAPE( X ) \ - REGISTER_WITH_KEY( ILineshape, Lineshape::X, #X, std::string ); \ + REGISTER_WITH_KEY( Lineshape::Base, Lineshape::X, #X, std::string ); \ AmpGen::Expression Lineshape::X::get( const AmpGen::Expression& s, const AmpGen::Expression& s1, \ const AmpGen::Expression& s2, const std::string& particleName, \ const unsigned int& L, const std::string& lineshapeModifier, \ AmpGen::DebugSymbols* dbexpressions ) const { return 0;} \ - AmpGen::Expression Lineshape::X::get( const AmpGen::Expression& s, const std::vector& p, \ - const std::string& particleName, \ - const unsigned int& L, const std::string& lineshapeModifier, \ + AmpGen::Expression Lineshape::X::get( const AmpGen::Particle& p, \ + const std::string& lineshapeModifier, \ AmpGen::DebugSymbols* dbexpressions ) const namespace AmpGen { - class ILineshape { - public: - virtual ~ILineshape() = default; - virtual Expression get( const Expression& s, const Expression& s1, const Expression& s2, - const std::string& particleName, const unsigned int& L, - const std::string& lineshapeModifier, DebugSymbols* dbexpressions = nullptr ) const = 0; - - virtual Expression get( const Expression& s, const std::vector& p, const std::string& particleName, - const unsigned int& L, const std::string& lineshapeModifier, - AmpGen::DebugSymbols* dbexpressions = nullptr ) const = 0; - ILineshape* create() { return this; } - }; + class Particle; // forward definitions /** @ingroup Lineshapes namespace Lineshape Namespace that contains all lineshapes, i.e. propagators for describing amplitudes and phases for resonances (and nonresonant) contributions to a total amplitude. @@ -98,16 +86,27 @@ namespace AmpGen namespace Lineshape { - class Factory : public AmpGen::Factory + class Base { + public: + virtual ~Base() = default; + virtual Expression get( const Expression& s, const Expression& s1, const Expression& s2, + const std::string& particleName, const unsigned& L, + const std::string& lineshapeModifier, DebugSymbols* dbexpressions = nullptr ) const = 0; + virtual Expression get( const AmpGen::Particle& p, + const std::string& lineshapeModifier, + AmpGen::DebugSymbols* dbexpressions = nullptr ) const = 0; + Base* create() { return this; } + }; + + class Factory : public AmpGen::Factory { public: static Expression get(const std::string& lineshape, const Expression& s, const Expression& s1, - const Expression& s2, const std::string& particleName, const unsigned int& L, + const Expression& s2, const std::string& particleName, const unsigned& L, std::vector>* dbexpressions = nullptr ); static Expression get(const std::string& lineshape, - const Expression& s, - const std::vector& p, const std::string& particleName, - const unsigned int& L, AmpGen::DebugSymbols* dbexpressions ); + const Particle& p, + AmpGen::DebugSymbols* dbexpressions ); static bool isLineshape( const std::string& lineshape ); }; @@ -134,7 +133,7 @@ namespace AmpGen @f$r@f$ | particleName_radius | Hadronic radius for Blatt-Weisskopf form-factor (defaults to 1.5GeV for light resonances, 3.5GeV for charm) BL : Use Blatt-Weisskopf factors normalised at @f$ \sqrt{s}=m @f$ (by default, normalised at @f$\sqrt{s}=0@f$) - \image html BW_combined.png "Modulus and phase of the Relativistic Breit-Wigner propagator, for @f$l={0,4}@f$, using the mass and nominal width of the @f$\rho@f$ meson" + \image html BW_combined.png "Modulus and phase of the Relativistic Breit-Wigner propagator, for orbital momentum up-to four, using the mass and nominal width of the rho meson." */ DECLARE_LINESHAPE( BW ); @@ -152,7 +151,16 @@ namespace AmpGen @f$\Gamma_0@f$ | particleName_width | Breit-Wigner width, defined as the width of resonance at the Breit-Wigner mass */ DECLARE_LINESHAPE( SBW ); - /// Non-relativistic Breit-Wigner lineshape + + /** @ingroup Lineshapes class NonRelBW + @brief Nonrelativistic Breit-Wigner lineshape + + Non-relativistic Breit-Wigner lineshape, given by + + @f[ + \mathcal{A}(s) = \sqrt{ \frac{ \Gamma_0 }{ 2 \pi } } \left( \sqrt{s} - m_0 - i \Gamma_0 /2 \right)^{-1} + @f] + */ DECLARE_LINESHAPE( NonRelBW ); /** @ingroup Lineshapes class GounarisSakurai @@ -180,8 +188,90 @@ namespace AmpGen */ DECLARE_LINESHAPE( GounarisSakurai ); - /// Description of the \f$ K\pi \f$ S-wave, based on the fits to scattering data. + /** @ingroup Lineshapes class LASS + @brief Description of the @f$ K\pi @f$ S-wave, based on the fits to scattering data. + The LASS parameterisation of the @f$ K\pi @f$ S-wave is derived from fits to ~ elastic @f$ K \pi @f$ scattering data, which is approximately up to the @f$ K \eta^\prime @f$ threshold. + In this regime, unitarity implies that phases, rather than amplitudes should be summed. + In this context, a slow varying nonresonant phase, + @f[ + \tan(\phi_{NR}) = \frac{2 a q}{2 + arq^2}, + @f] + where @f$a, r@f$ are parameters determined from scattering data, is added to the phase shift of a Breit-Wigner, + @f[ + \tan(\phi_{BW}) = \frac{m\Gamma(s)}{m^2 -s }, + @f] + normally associated to the @f$ K^*(1430)^{0} @f$ resonance. + The total amplitude is therefore: + @f[ + \mathcal{A}(s) = \frac{2 a \sqrt{s} }{ 2 + arq^2 - 2iaq} + \frac{2+arq^2 + 2iaq}{2+arq^2 - 2iaq }\mathcal{A}_{BW}(s) = \mathcal{A}_{NR}(s) + \mathcal{A}^{\prime}_{BW}(s). + @f] + As this expression somewhat resembles the sum of a Breit-Wigner with a slowly varying nonresonant component, the two parts are sometimes split apart with an additional production amplitude placed on one or the other. + These can be accessed separately using the modifiers LASS.BW and LASS.NR, and given independent coupling constants. From the user interface: + \code{.cpp} + K*(1430)bar0[LASS.NR]{K-,pi+} 0 2.0 0.1 0 -90 0.1 + K*(1430)bar0[LASS.BW]{K-,pi+} 0 1.5 0.1 0 20 0.1 + \endcode + Corresponds to the overall lineshape: + @f[ + \mathcal{A}(s) + = \left(\texttt{K*(1430)bar0[LASS.NR]{K-,pi+}}\right) \mathcal{A}_{NR}(s) + + \left(\texttt{K*(1430)bar0[LASS.BW]{K-,pi+}}\right) \mathcal{A}^{\prime}_{BW}(s) + = 2.0 e^{-90^\mathrm{o}} \mathcal{A}_{NR}(s) + 1.5 e^{-20^\mathrm{o}} \mathcal{A}^{\prime}_{BW}(s). + @f] + An alternative way to introduce a different coupling between the two components is to fix one coupling and to introduce an additional production coupling. + In the user interface, this might for example in @f$ D^{0} \to K^{-} \pi^{+} \pi^{0} @f$ decays: + \code{.cpp} + D0{K*(1430)bar0,pi0} 0 1.3 0.0 0 15 0.1 + K*(1430)bar0[LASS.NR]{K-,pi+} 0 2.0 0.1 0 -90 0.1 + K*(1430)bar0[LASS.BW]{K-,pi+} 2 1.0 0.0 0 0 0.0 + \endcode + Then the lineshape with production couplings will be: + @f[ + \mathcal{A}(s) + = \left(\texttt{D0{K*(1430)bar0,pi0}}\right)\left( + = \left(\texttt{K*(1430)bar0[LASS.NR]{K-,pi+}}\right) \mathcal{A}_{NR}(s) + + \mathcal{A}^{\prime}_{BW}(s) \right) + = 1.3 e^{15^\mathrm{o}} \left( 2.0 e^{-90^\mathrm{o}} \mathcal{A}_{NR}(s) + \mathcal{A}^{\prime}_{BW}(s) \right). + @f] + + Parameter | User name | Description + -----------------------|--------------------------------------|------------------------------------------------------------------------ + @f$m@f$ | particleName_mass | Breit-Wigner mass of the resonant component, defined as energy at which the self-energy of the resonance is purely imaginary (defaults to value in PDG)
+ @f$\Gamma_0@f$ | particleName_width | Breit-Wigner width of the resonant component, defined as the width of resonance at the Breit-Wigner mass
+ @f$a@f$ | LASS::a | Scattering length of the nonresonant component, defaults to @f$2.07\mathrm{G\kern -0.1em eV}^{-1}@f$ + @f$r@f$ | LASS::r | Effective interaction length of the nonresonant component, defaults to @f$3.32\mathrm{G\kern -0.1em eV}^{-1}@f$ + */ DECLARE_LINESHAPE( LASS ); + /** @ingroup Lineshapes class GLASS + @brief Generalised description of the @f$ K\pi@f$ S-wave, taken from BABAR / BELLE analysis of @f$ D^{0} \to K_{S}^{0} \pi^{+} \pi^{-} @f$ https://journals.aps.org/prd/pdf/10.1103/PhysRevD.98.112012 + + Alternative parameterisation of the @f$ K \pi @f$ S-wave taken from the BABAR/BELLE analysis of @f$ D^{0} \to K_{S}^{0} \pi^{+} \pi^{-} @f$ https://journals.aps.org/prd/pdf/10.1103/PhysRevD.98.112012. + It introduces four additional parameters, two amplitudes and two phases, and is written + @f[ + \mathcal{A}(s) = R\sin\delta_R e^{i(\delta_R + 2\delta_F)} + F\sin\delta_F e^{i\delta_F} + @f] + where + @f[ + \delta_R = \phi_R + \tan^{-1}\left(\frac{m\Gamma(s)}{m^2 -s }\right) + @f] + and + @f[ + \delta_F = \phi_F + \tan^{-1}\left(\frac{2 a q}{2 + arq^2}\right), + @f] + that is, the 'resonant' and 'nonresonant' phases of the LASS formulation with additional 'proudction' phases @f$ \phi_R @f$ and @f$\phi_F @f$, and production couplings @f$R, F@f$. One of the production couplings can typically be fixed to 1, normally the resonant coupling, @f$R @f$. + + Parameter | Interface parameter name | Description + -----------------------|--------------------------------------|------------------------------------------------------------------------ + @f$m@f$ | particleName_mass | Breit-Wigner mass of the resonant component, defined as energy at which the self-energy of the resonance is purely imaginary (defaults to value in PDG)
+ @f$\Gamma_0@f$ | particleName_width | Breit-Wigner width of the resonant component, defined as the width of resonance at the Breit-Wigner mass
+ @f$a@f$ | particleName::GLASS::a | Scattering length of the nonresonant component, defaults to @f$2.07\mathrm{G\kern -0.1em eV}^{-1}@f$ + @f$r@f$ | particleName::GLASS::r | Effective interaction length of the nonresonant component, defaults to @f$3.32\mathrm{G\kern -0.1em eV}^{-1}@f$ + @f$\phi_R@f$ | particleName::GLASS::phiR | Additional production phase of the resonant component, defaults to @f$0^{\mathrm{o}}@f$, measured in degrees. + @f$\phi_F@f$ | particleName::GLASS::phiF | Additional production phase of the nonresonant component, defaults to @f$0^{\mathrm{o}}@f$, measured in degrees. + @f$R@f$ | particleName::GLASS::R | Additional production coupling of the resonant component, defaults to @f$1@f$. + @f$F@f$ | particleName::GLASS::F | Additional production coupling of the nonresonant component, defaults to @f$1@f$. + */ + DECLARE_LINESHAPE(GLASS); /** @ingroup Lineshapes class Flatte @brief Lineshape to describe resonances with coupled channels such as @f$f_{0}(980)^{0} / a_{0}(980) @f$. @@ -195,17 +285,20 @@ namespace AmpGen @f] where the running width is given by @f[ - \Gamma(s) = g_{\pi\pi} \left( \Lambda^{1/2}(s,m_{\pi}^2,m_{\pi}^2) + \frac{g_{KK}}{g_{\pi\pi}} \Lambda^{1/2}(s,m_K^2, m_K^2) \right) + \Gamma(s) = \frac{ g_{\pi\pi} }{s} \left( \Lambda^{1/2}(s,m_{\pi}^2,m_{\pi}^2) + \frac{g_{KK}}{g_{\pi\pi}} \Lambda^{1/2}(s,m_K^2, m_K^2) \right) @f] or @f[ - \Gamma(s) = g_{\pi\eta} \left( \Lambda^{1/2}(s,m_{\pi}^2,m_{\eta}^2) + \frac{g_{KK}}{g_{\pi\eta}} \Lambda^{1/2}(s,m_K^2, m_K^2) \right) + \Gamma(s) = \frac{ g_{\pi\eta}}{s} \left( \Lambda^{1/2}(s,m_{\pi}^2,m_{\eta}^2) + \frac{g_{KK}}{g_{\pi\eta}} \Lambda^{1/2}(s,m_K^2, m_K^2) \right) @f] for the @f$f_0(980)^{0}@f$ and the @f$a_0(980)^{0}@f$, respectively. */ DECLARE_LINESHAPE( Flatte ); DECLARE_LINESHAPE( Bugg ); + DECLARE_LINESHAPE( Kappa ); + DECLARE_LINESHAPE( Dabba ); + DECLARE_LINESHAPE( Isotensor ); /// Exponential form-factor of type \f$ e^{ - q^2 R^2 } \f$ @@ -215,14 +308,14 @@ namespace AmpGen /** @ingroup Lineshapes class Gaussian @brief Gaussian shape for (relatively) long lived states that are limited by experimental resolution, rather than natural width. - @detail The gaussian lineshape has the form + The gaussian lineshape has the form @f[ \mathcal{A}(s) = e^{ -(s-\mu)^2 / 2\sigma^2 }, @f] which is potentially useful for fitting very long-lived contributions that are essentially limited by the experimental resolution, rather than the natural lifetime. This type of parameterisation will assess contributions from interference incorrectly. - Parameter | User name | Description + Parameter | Interface parameter name | Description -----------------------|--------------------------------------|------------------------------------------------------------------------ @f$\mu@f$ | lineshapeModifier_mean | Mean of the gaussian distribution. @f$\sigma@f$ | lineshapeModifier_sigma | Width of the gaussian distribution. @@ -232,23 +325,14 @@ namespace AmpGen /** @ingroup Lineshapes class Poly * @brief Polynominal shape \f$ \mathcal{A}(s) = \sum^n_i c_i s^{i} \f$ where the sum is to lineshapeModifier::Degree, and the free parameters of the shape are lineshapeModifier_ci */ + DECLARE_LINESHAPE( EXPNR ); + DECLARE_LINESHAPE( PolyNR ); + + /** @ingroup Lineshapes class PolyNR + * @brief Polynominal shape \f$ \mathcal{A}(s) = \sqrt{ \sum_{ij} c_{ij} s^{i} (s^\prime)^{j} } \f$ where the sum is to lineshapeModifier::Degree, and the free parameters of the shape are lineshapeModifier_cij + */ DECLARE_LINESHAPE( Poly ); - /** @ingroup Lineshapes class kMatrix - @brief Anisovich-Sarantsev Isoscalar K-matrix from https://arxiv.org/abs/hep-ph/0204328 - - Describes the isoscalar @f$ \pi\pi, KK, 4\pi \eta\eta, \eta\eta^\prime@f$ S-wave in terms of a five-by-five K-matrix and corresponding P-vector couplings. - Includes a large number of parameters that can be fixed from the above publication. - These parameters can be found in the options directory, which in turn can be includes in the fit by adding - - \code{cpp} - Import $AMPGENROOT/options/kMatrix.opt - \endcode - - to the user configuration file. - */ - DECLARE_LINESHAPE( kMatrix ); - /** @ingroup Lineshapes class FOCUS * @brief K matrix amplitudes used for I=1/2 and I=3/2 in the description of the \f$ K\pi \f$ S-wave in the analysis of @f$ D^{+}\rightarrow K^{-}\pi^{+}\pi^{+}@f$ https://arxiv.org/abs/0705.2248 */ @@ -257,17 +341,6 @@ namespace AmpGen /// I=1/2 and I=3/2 K Matrices used in the description of the \f$ K\pi\f$ S-wave in the analysis of @f$\eta_{c}\rightarrow K^{+} K^{-} \pi^{0}@f$ https://arxiv.org/abs/1701.04881 DECLARE_LINESHAPE( PALANO ); - /** @ingroup Lineshapes class ObelixRho - * @brief Amplitude to describe the vector-isovector system, otherwise known as the @f$ \rho @f$ mesons. WARNING untested. - - Vector-Isovector amplitude @f$(I=1, J=1)@f$ using a K-matrix to describe the @f$\pi\pi, KK, \pi\pi\pi\pi @f$ channels using three poles, commonly associated with - the @f$ \rho(770), \rho(1450), \rho(1900) @f$ resonances. - */ - DECLARE_LINESHAPE( ObelixRho ); - - /// K matrix to describe \f$K_1(1270) / K_1(1400)\f$. WARNING incompleted. - DECLARE_LINESHAPE( AxialKaon ); - /** @ingroup Lineshapes class kMatrixSimple @brief Simple and flexible K matrix that implements a variable number of scalar channels and poles. Flexible K matrix implementation that accepts a variable number of scalar channels and pole terms. @@ -286,7 +359,7 @@ namespace AmpGen @f] where @f$a_n@f$ is the value of the function evaluated at the @f$ n @f$ knot and the other polynomial coefficients are determined by imposing continuity and differentiability. - Parameter | User name | Description + Parameter | Interface parameter name | Description -----------------------|--------------------------------------|------------------------------------------------------------------------ @f$\mathcal{R}(a_j)@f$ | particleName::Spline::Re::j | The real value of the lineshape evaluated at the @f$ j @f$th knot. @f$\mathcal{I}(a_j)@f$ | particleName::Spline::Im::j | The imaginary value of the lineshape evaluated at the @f$ j @f$th knot. @@ -301,10 +374,6 @@ namespace AmpGen DECLARE_LINESHAPE( DecaySpline ); DECLARE_LINESHAPE( InelasticSpline ); - /** @ingroup Lineshapes class CoupledChannel - @brief Description of a resonance that decays to multiple two and three-body final states. - */ - DECLARE_LINESHAPE( CoupledChannel ); /** @ingroup Lineshapes class GenericKmatrix @brief Implementation of a generic K-matrix */ @@ -323,6 +392,19 @@ namespace AmpGen */ DECLARE_LINESHAPE( EtaDalitz ); + /** @ingroup Lineshapes class TD + @brief (Linear) time dependence + + ''Lineshape'' that gives a linear time-dependence for use in time-dependent generation / fitting. + @f[ + \mathcal{A}(t) = \frac{t}{2\tau}, + @f] + where @f$\tau@f$ is the proper decay time. + + */ + DECLARE_LINESHAPE( TD ); + + DECLARE_LINESHAPE( Photon ); } // namespace Lineshape Expression Q2( const Expression& Msq, const Expression& M1sq, const Expression& M2sq ); @@ -338,11 +420,10 @@ namespace AmpGen Expression pol( const AmpGen::Expression& X, const std::vector& p ); - std::vector parameterVector( const std::string& name, const unsigned int& nParam ); + std::vector parameterVector(const std::string& name, const size_t& nParam); Expression width( const Expression& s, const Expression& s1, const Expression& s2, const Expression& mass, const Expression& width, const Expression& radius, unsigned int L, DebugSymbols* dbexpressions = nullptr ); - } // namespace AmpGen #endif diff --git a/AmpGen/MetaUtils.h b/AmpGen/MetaUtils.h index 4d436d436fb..3c985be4daa 100644 --- a/AmpGen/MetaUtils.h +++ b/AmpGen/MetaUtils.h @@ -6,14 +6,16 @@ #include #include #include +#include namespace AmpGen { - /** Utility classes for (library) compile-level metaprogramming, such as identifying the types of - * arguments for generating source code, compile-time unrolling of tuples and loops, and identifying if a class can be constructed in different ways. + /** Utility classes for compile-time metaprogramming, such as identifying the types of + arguments for generating source code, compile-time unrolling of tuples and loops, + and identifying if a class can be constructed in different ways. */ - - template std::string typeof() + + template std::string type_string() { int status = 0; std::string name = abi::__cxa_demangle( typeid( TYPE ).name(), nullptr, nullptr, &status ); @@ -23,22 +25,40 @@ namespace AmpGen return name; } - template std::string typeof( TYPE t ) { return typeof(); } + template std::string type_string( const TYPE& t ) { return type_string(); } + + namespace detail { + template struct zeroType { typedef T type; }; + } + template using nthType = typename std::tuple_element>::type; + + template using zeroType = typename detail::zeroType::type; template - typename std::enable_if::type + typename std::enable_if_t for_each( std::tuple&, FuncT ){} template - inline typename std::enable_if < I::type for_each( std::tuple& t, FuncT f ) + inline typename std::enable_if_t< I for_each( std::tuple& t, FuncT f ) { f( std::get( t ) ); for_each( t, f ); } + template + void for_each_sequence( iterator begin, iterator end, transform_types... transforms) + { + for_each( std::tuple(transforms...), [&](auto& transform){ std::for_each( begin, end, transform ); } ); + } + + template + typename std::enable_if_t + for_each( const std::tuple&, FuncT ){} - template std::shared_ptr makeShared( const TYPE& obj ) + template + inline typename std::enable_if_t< I for_each( const std::tuple& t, FuncT f ) { - return std::make_shared( obj ); + f( std::get( t ) ); + for_each( t, f ); } template ::value && (false == std::is_same::value); } + template std::vector typelist() { std::vector< std::string > rt; - if( typeof() != "void" ) { - rt.emplace_back( typeof() ); + if( type_string() != "void" ) { + rt.emplace_back( type_string() ); auto rtp = typelist(); - for( auto& r : rtp ) rt.emplace_back( r ); + std::copy( rtp.begin(), rtp.end(), std::back_inserter(rt) ); } return rt; } template struct isTuple: std::false_type {}; - template struct isTuple>: std::true_type {}; + template struct isVector : std::false_type {}; + template struct isVector> : std::true_type {}; + + + #define def_has_function(function_name) \ + template \ + struct has_##function_name { \ + template static auto test(int) -> decltype(std::declval().function_name() == 1, std::true_type()); \ + template static std::false_type test(...); \ + static constexpr bool value = std::is_same(0)), std::true_type>::value; \ + } + } // namespace AmpGen #endif diff --git a/AmpGen/Minimiser.h b/AmpGen/Minimiser.h index 815235b1e28..736380d6588 100644 --- a/AmpGen/Minimiser.h +++ b/AmpGen/Minimiser.h @@ -9,15 +9,18 @@ #include #include "TMatrixTSym.h" +#include "AmpGen/MetaUtils.h" +/** @cond PRIVATE */ namespace ROOT { - namespace Math + namespace Minuit2 { - class Minimizer; + class Minuit2Minimizer; } } class TGraph; +/** @endcode */ namespace AmpGen { @@ -28,14 +31,24 @@ namespace AmpGen class Minimiser { + private: + def_has_function(getVal); + public: - template + template void setFunction( TYPE& fcn ) + { + if constexpr( has_getVal::value ) m_theFunction = [&fcn]() { return fcn.getVal(); }; + else m_theFunction = fcn; + } + + template Minimiser(TYPE& fitFunction, MinuitParameterSet* mps) : m_parSet(mps) { - m_theFunction = [&fitFunction]() { return fitFunction.getVal(); }; + setFunction(fitFunction); prepare(); } + Minimiser(std::function& fitFunction, MinuitParameterSet* mps) : m_parSet(mps), m_theFunction(fitFunction) @@ -46,11 +59,9 @@ namespace AmpGen unsigned int nPars() const; void prepare(); + void gradientTest(); bool doFit(); - void GradientTest(); - TGraph* scan( MinuitParameter* param, const double& min, const double& max, const double& step ); - void addExtendedTerm( IExtendLikelihood* term ); TMatrixTSym covMatrix() const; TMatrixTSym covMatrixFull() const; @@ -58,21 +69,19 @@ namespace AmpGen double FCN() const; MinuitParameterSet* parSet() const; int status() const; - ROOT::Math::Minimizer* minimiserInternal(); - + ROOT::Minuit2::Minuit2Minimizer* minimiserInternal(); private: - void print( const double& LL ); - MinuitParameterSet* m_parSet = {nullptr}; + MinuitParameterSet* m_parSet = {nullptr}; std::function m_theFunction; - ROOT::Math::Minimizer* m_minimiser = {nullptr}; - std::vector m_covMatrix = {0}; - std::vector m_mapping; + ROOT::Minuit2::Minuit2Minimizer* m_minimiser = {nullptr}; + std::vector m_covMatrix = {0}; + std::vector m_mapping = {}; + int m_status = {0}; + unsigned m_nParams = {0}; + unsigned m_printLevel = {0}; + double m_ll_zero = {0}; + bool m_normalise = {false}; std::vector m_extendedTerms; - int m_status = {0}; - unsigned int m_nParams = {0}; - unsigned int m_lastPrint = {0}; - unsigned int m_printLevel = {0}; - }; } // namespace AmpGen #endif diff --git a/AmpGen/MinuitExpression.h b/AmpGen/MinuitExpression.h index 377dd01de6d..159abc5e0d8 100644 --- a/AmpGen/MinuitExpression.h +++ b/AmpGen/MinuitExpression.h @@ -14,20 +14,16 @@ namespace AmpGen class MinuitExpression : public MinuitParameter { + public: + MinuitExpression(const std::vector& tokens, MinuitParameterSet* mps ); + MinuitExpression(const std::string& name, const Expression& expression); + double mean() const override; + complex_t getVal() const; + Expression expression() const { return m_expression; } + operator double() const override; + ~MinuitExpression() override; private: Expression m_expression; - bool m_isGood; - - public: - MinuitExpression( const std::vector& tokens, MinuitParameterSet* mps ); - - double getVal() const { return std::real( m_expression() ); } - operator double() const override { return getVal(); } - - ~MinuitExpression() override = default; - - double mean() const override { return getVal(); } - bool isGood() const { return m_isGood; } }; } // namespace AmpGen diff --git a/AmpGen/MinuitParameter.h b/AmpGen/MinuitParameter.h index 0aa2c51d678..7d79369bd0d 100644 --- a/AmpGen/MinuitParameter.h +++ b/AmpGen/MinuitParameter.h @@ -5,23 +5,25 @@ #include #include +#include "AmpGen/enum.h" namespace AmpGen { class MinuitParameterSet; - + declare_enum( Flag, Free, Hide, Fix, CompileTimeConstant) class MinuitParameter { public: - enum Flag { Float, Hide, Fix, CompileTimeConstant }; - + MinuitParameter() = default; - MinuitParameter(const std::string& name, const Flag& iFixInit, const double& mean, const double& step, + MinuitParameter(const std::string& name, const Flag& flag, const double& mean, const double& step, + const double& min = 0, const double& max = 0 ); + MinuitParameter(const std::string& name, const double& mean, const double& step, const double& min = 0, const double& max = 0 ); - Flag iFixInit() const; - bool hidden() const; - bool fixed(); + Flag flag() const; + bool isFixed() const; + bool isFree() const; const std::string& name() const; double meanInit() const; @@ -33,7 +35,7 @@ namespace AmpGen double errNeg() const; double* vp() { return &m_meanResult ; } - void setInit( const double& init ); + void setInit( const double& init, const double& step=-1 ); void setStepInit( const double& si ); void setFree() ; void scaleStep( const double& sf ); @@ -42,7 +44,6 @@ namespace AmpGen void setLimits( const double& min, const double& max ); void setResult( double fitMean, double fitErr, double fitErrPos, double fitErrNeg ); void resetToInit(); - void print( std::ostream& os = std::cout ) const; void setName( const std::string& name ); virtual double mean() const; virtual operator double() const { return m_meanResult; } @@ -50,7 +51,7 @@ namespace AmpGen friend class MinuitParameterSet; private: - Flag m_iFixInit; + Flag m_flag; std::string m_name; double m_meanInit; double m_stepInit; @@ -64,18 +65,18 @@ namespace AmpGen class MinuitProxy { - double m_value; - MinuitParameter* m_parameter; - public: - void update() { m_value = m_parameter->mean(); } + void update() { if(m_parameter != nullptr ) m_value = m_parameter->mean(); } MinuitParameter* ptr() { return m_parameter; } - operator double() const { return m_parameter->mean(); } - double getFast() const { return m_value ; } - MinuitProxy( MinuitParameter* param = nullptr ) : m_parameter( param ) { if( m_parameter != nullptr ) update(); } + operator double() const { return m_value; } + MinuitProxy(MinuitParameter* param = nullptr, const double& value=0) : m_parameter(param), m_value(value) { update(); } MinuitParameter* operator->() { return m_parameter; } const MinuitParameter* operator->() const { return m_parameter; } + private: + MinuitParameter* m_parameter{nullptr}; + double m_value; }; + std::ostream& operator<<( std::ostream& os, const MinuitParameter& type ); } // namespace AmpGen #endif diff --git a/AmpGen/MinuitParameterSet.h b/AmpGen/MinuitParameterSet.h index 272b556c7fc..13b79a00caf 100644 --- a/AmpGen/MinuitParameterSet.h +++ b/AmpGen/MinuitParameterSet.h @@ -17,69 +17,53 @@ namespace AmpGen class MinuitParameterSet { public: + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + MinuitParameterSet(); - MinuitParameterSet( const MinuitParameterSet& other ); - ~MinuitParameterSet(); + explicit MinuitParameterSet(const std::vector& params ); - MinuitParameterSet getFloating(); + MinuitParameterSet( const MinuitParameterSet& other ) = delete; + ~MinuitParameterSet(); // = default; + + // MinuitParameterSet getFloating(); bool add( MinuitParameter* parPtr ); - MinuitParameter* add( const std::string& name, const unsigned int& flag, const double& mean, const double& sigma, - const double& min = 0, const double& max = 0 ); + MinuitParameter* add(const std::string& name, const Flag& flag, const double& mean, const double& sigma, const double& min = 0, const double& max = 0 ); bool unregister( MinuitParameter* patPtr ); - MinuitParameter* addOrGet( const std::string& name, const unsigned int& flag, const double& mean, - const double& sigma, const double& min = 0, const double& max = 0 ); + MinuitParameter* addOrGet(const std::string& name, const Flag& flag, const double& mean, + const double& sigma, const double& min = 0, const double& max = 0 ); void loadFromStream(); void loadFromFile( const std::string& name ); void resetToInit(); - unsigned int size() const; - - MinuitParameter* getParPtr( unsigned int i ) const; - - std::map& map() { return _keyAccess; } - const std::map& const_map() const { return _keyAccess; } - std::vector::const_iterator cbegin() const { return _parPtrList.cbegin(); } - std::vector::const_iterator cend() const { return _parPtrList.cend(); } - - std::vector parPtrs() { return _parPtrList; } - std::vector::iterator begin() { return _parPtrList.begin(); } - std::vector::iterator end() { return _parPtrList.end(); } - std::vector::const_iterator begin() const { return _parPtrList.cbegin(); } - std::vector::const_iterator end() const { return _parPtrList.cend(); } - - void deleteListAndObjects(); - void deleteListKeepObjects(); - void print( std::ostream& os = std::cout ) const; void printVariable( std::ostream& os = std::cout ) const; - void set( const MinuitParameterSet& mps ); + bool rename(const std::string& name, const std::string& new_name); + unsigned int size() const; + + const_iterator cbegin() const; + const_iterator cend() const; + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + MinuitParameter* at( const std::string& key ); + MinuitParameter* at( const size_t& index ) const; MinuitParameter* operator[]( const std::string& key ); MinuitParameter* operator[]( const std::string& key ) const; - MinuitParameter* operator[]( const unsigned int& key ); - MinuitParameter* find( const std::string& key ) const - { - auto it = _keyAccess.find(key); - return it == _keyAccess.end() ? nullptr : it->second; - } - double operator()( const std::string& name ) - { - if ( _keyAccess.find( name ) == _keyAccess.end() ) { - std::cout << "Cannot find parameter " << name << std::endl; - } - return _keyAccess[name]->mean(); - } + MinuitParameter* operator[]( const size_t& key ); + MinuitParameter* find( const std::string& key ) const; + double operator()( const std::string& name ); private: void tryParameter( const std::vector& line ); void tryAlias( const std::vector& line ); - std::vector _parPtrList; - std::vector _aliasList; - std::map _keyAccess; bool addToEnd( MinuitParameter* parPtr ); - + + std::vector m_parameters; + std::map m_keyAccess; }; - } // namespace AmpGen #endif // diff --git a/AmpGen/MsgService.h b/AmpGen/MsgService.h index 6e00b5d814e..3d91b75d63f 100644 --- a/AmpGen/MsgService.h +++ b/AmpGen/MsgService.h @@ -1,90 +1,97 @@ #ifndef AMPGEN_MSGSERVICE_H #define AMPGEN_MSGSERVICE_H -/* - MsgService Header - -Defines coloured and organised output macro streams using __PRETTY_FUNCTION__ - INFO() - info level messages, always displayed - ERROR() - error level messages, always displayed - FATAL() - error message that throws the process, always displayed - WARNING() - warning level messages, can be switched with the WARNINGLEVEL flag - DEBUG() - debug level messages, can be switched with the DEBUGLEVEL flag - */ +/** @defgroup msgService Messaging and logging + MsgService Header + Defines coloured and organised output macro streams using __PRETTY_FUNCTION__ + INFO() - info level messages, always displayed + ERROR() - error level messages, always displayed + FATAL() - error message that throws the process, always displayed + WARNING() - warning level messages, can be switched with the WARNINGLEVEL flag + DEBUG() - debug level messages, can be switched with the DEBUGLEVEL flag + */ #include #include #include +#include #define WARNINGLEVEL 1 -//#define DEBUGLEVEL 0 -//#define TRACELEVEL 0 -#define FCNNAMELENGTH 45 -inline std::string trimmedString( std::string thing, const unsigned int& length = FCNNAMELENGTH ) -{ - size_t pos2=0; - do { - pos2 = thing.find( "AmpGen::" ); - if ( pos2 != std::string::npos ) thing = thing.replace( pos2, 8, "" ); - } while( pos2 != std::string::npos ); - - pos2 = thing.find( "std::" ); - if ( pos2 != std::string::npos ) thing.replace( pos2, 5, "" ); - - pos2 = thing.find( "virtual " ); - if ( pos2 != std::string::npos ) thing = thing.replace( pos2, 8, "" ); - - size_t pos = thing.find( "(" ); - - if ( pos != std::string::npos ) { - return pos < length ? thing.substr( 0, pos ) : thing.substr( 0, length ); +namespace AmpGen { + namespace detail { + constexpr static int FCNNAMELENGTH = 45; + + inline std::string trimmedString( std::string thing, const unsigned int& length = FCNNAMELENGTH ) + { + size_t pos2=0; + do { + pos2 = thing.find( "AmpGen::" ); + if ( pos2 != std::string::npos ) thing = thing.replace( pos2, 8, "" ); + } while( pos2 != std::string::npos ); + + pos2 = thing.find( "std::" ); + if ( pos2 != std::string::npos ) thing.replace( pos2, 5, "" ); + + pos2 = thing.find( "virtual " ); + if ( pos2 != std::string::npos ) thing = thing.replace( pos2, 8, "" ); + + size_t pos = thing.find( "(" ); + + if ( pos != std::string::npos ) { + return pos < length ? thing.substr( 0, pos ) : thing.substr( 0, length ); + } + return thing.size() < length ? thing : thing.substr( 0, length ) + "..."; + } + inline std::ostream& labelled_stream(const std::string& function_name) + { + return std::cout << "\033[2;34m" << std::left << std::setw(FCNNAMELENGTH) << trimmedString(function_name) << " INFO " << "\033[0m"; + } + template struct debug_type : std::false_type {}; } - return thing.size() < length ? thing : thing.substr( 0, length ) + "..."; - if ( thing.size() < length ) return thing; } +#define ENABLE_DEBUG(X) \ + namespace AmpGen { namespace detail { template <> struct debug_type : std::true_type {}; } } -#ifdef DEBUGLEVEL -#define DEBUG( X ) \ - std::cout << "\033[2;32m" << std::left << std::setw( FCNNAMELENGTH ) << trimmedString( __PRETTY_FUNCTION__ ) \ -<< " DEBUG " \ -<< "\033[0m" << X << std::endl -#else -#define DEBUG( X ) -#endif +/// @ingroup msgService macro DEBUG +/// Used for printing verbose debugging messages, only if DEBUGLEVEL is defined. +#define DEBUG( X ) { \ + if constexpr( AmpGen::detail::debug_type::type>::value ) { \ + std::cout << "\033[2;32m" << std::left << std::setw( AmpGen::detail::FCNNAMELENGTH ) << AmpGen::detail::trimmedString(__PRETTY_FUNCTION__) \ + << " DEBUG " \ + << "\033[0m" << X << " " << std::endl; } } -#define INFO( X ) \ - std::cout << "\033[2;34m" << std::left << std::setw( FCNNAMELENGTH ) << trimmedString( __PRETTY_FUNCTION__ ) \ -<< " INFO " \ -<< "\033[0m" << X << std::endl +/// @ingroup msgService macro INFO +/// Used for printing information messages, and will always be printed. +#define INFO( X ) \ + AmpGen::detail::labelled_stream(__PRETTY_FUNCTION__) << X << std::endl +/// @ingroup msgService macro ERROR +/// Used for printing errors messages, and will always be printed. #define ERROR( X ) \ - std::cout << "\033[1;31m" << std::left << std::setw( FCNNAMELENGTH ) << trimmedString( __PRETTY_FUNCTION__ ) \ -<< " ERROR " \ -<< "\033[0m" << X << std::endl + std::cout << "\033[1;31m" << std::left << std::setw( AmpGen::detail::FCNNAMELENGTH ) << AmpGen::detail::trimmedString( __PRETTY_FUNCTION__ ) \ + << " ERROR " \ + << "\033[0m" << X << std::endl +/// @ingroup msgService macro FATAL +/// Used for printing fatal errors messages, and will always be printed and will terminate the process afterwards. #define FATAL( X ) \ - { std::cout << "\033[1;31m" << std::left << std::setw( FCNNAMELENGTH ) << trimmedString( __PRETTY_FUNCTION__ ) \ -<< " FATAL " \ -<< "\033[0m" << X << std::endl; \ -throw std::runtime_error( trimmedString( __PRETTY_FUNCTION__)+ " FATAL" ) ;} +{ std::cout << "\033[1;31m" << std::left << std::setw( AmpGen::detail::FCNNAMELENGTH ) << AmpGen::detail::trimmedString( __PRETTY_FUNCTION__ ) \ + << " FATAL " \ + << "\033[0m" << X << std::endl; \ + throw std::runtime_error( AmpGen::detail::trimmedString( __PRETTY_FUNCTION__)+ " FATAL" ) ;} + +/// @ingroup msgService macro FATAL +/// Used for printing warning messages, can be switched off using WARNINGLEVEL. These messages are often harmless, but sometimes not! #ifdef WARNINGLEVEL #define WARNING( X ) \ - std::cout << "\033[1;35m" << std::left << std::setw( FCNNAMELENGTH ) << trimmedString( __PRETTY_FUNCTION__ ) \ -<< " WARNING " \ -<< "\033[0m" << X << std::endl + std::cout << "\033[1;35m" << std::left << std::setw( AmpGen::detail::FCNNAMELENGTH ) << AmpGen::detail::trimmedString( __PRETTY_FUNCTION__ ) \ + << " WARNING " \ + << "\033[0m" << X << std::endl #else #define WARNING( X ) #endif -#ifdef TRACELEVEL -#define TRACE( X ) \ - std::cout << "\033[1;36m" << std::left << std::setw( FCNNAMELENGTH ) << trimmedString( __PRETTY_FUNCTION__ ) \ -<< " TRACE " \ -<< "\033[0m" << X << std::endl -#else -#define TRACE( X ) -#endif - #endif diff --git a/AmpGen/NamedParameter.h b/AmpGen/NamedParameter.h index 18b993f5eb0..8c5a1264385 100644 --- a/AmpGen/NamedParameter.h +++ b/AmpGen/NamedParameter.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "AmpGen/MsgService.h" #include "AmpGen/OptionsParser.h" @@ -20,13 +21,20 @@ namespace AmpGen { + /** @class NamedParameter + @brief A parameter with value specified by the user at runtime, either in an options file or via the command line + + Stores a vector of values for a parameter. + @tparam T the type of this named parameter, i.e. strings, or numbers or bools etc. + + */ template class NamedParameter { protected: - std::string m_name; - std::string m_helpString; - std::vector m_valueArray; + std::string m_name; /// < Name of this parameter + std::string m_helpString; /// < The helper string for this parameter, printed if the flag --help is used. + std::vector m_valueArray; /// < The value (array) of this parameter. bool setFromOptionsParser() { @@ -59,29 +67,6 @@ namespace AmpGen if ( OptionsParser::printHelp() ) help(def); DEBUG( *this ); } - /* - template - NamedParameter( const std::string& name, const T& def, const ARGS&... args ) : - m_name(name) - { - setVal( def ); - setFromOptionsParser(); - auto arg_pack = ArgumentPack(args...); - auto acceptedValues = arg_pack.getArg>().val; - m_helpString = arg_pack.getArg().val; - - if( acceptedValues.size() != 0 ){ - bool isAcceptedValue = false; - for( auto& v : acceptedValues ) if( m_valueArray[0] == v ) isAcceptedValue = true; - if( !isAcceptedValue ){ - ERROR( "Argument: " << name << " is not in [" << italic_on << vectorToString( acceptedValues, ", ") << italic_off <<"]" ); - } - } - if ( OptionsParser::printHelp() ) help(def); - DEBUG( *this ); - } - */ - NamedParameter(const std::string& name, const std::vector& defVec, const std::string& helpString="") : m_name(name), m_helpString(helpString) @@ -90,10 +75,8 @@ namespace AmpGen setFromOptionsParser(); if ( OptionsParser::printHelp() ) help( defVec.size() > 0 ? defVec[0] : T() ); } - void help(const T& def){ - std::map< std::string, std::string > aliases; - std::string type = typeof(); + std::string type = type_string(); if( type == "std::__cxx11::basic_string, std::allocator >" ) type = "string"; std::cout << " " << bold_on << std::left << std::setw(27) << m_name << bold_off << std::setw(20) << "[" + type + "]" ; @@ -123,6 +106,8 @@ namespace AmpGen operator T() const { return getVal(); } operator T() { return getVal(); } + template bool operator==(const G& other) const { return getVal() == other; } + template bool operator!=(const G& other) const { return getVal() != other; } const std::vector& getVector() const { return m_valueArray; } void setVal( const T& val, int i = 0 ) @@ -163,24 +148,30 @@ namespace AmpGen return return_container; } }; - template - std::ostream& operator<<( std::ostream& os, const NamedParameter& np ); - - std::string optionalHelpString(const std::string& header, const std::vector>& args); + template std::ostream& operator<<( std::ostream& os, const NamedParameter& np ); + template std::string optionalHelpString(const std::string& header, const T&... args); } - template std::ostream& AmpGen::operator<<( std::ostream& os, const AmpGen::NamedParameter& np ) { os << np.name() ; for ( size_t i = 0; i < np.size(); i++ ) { if( i == 0 ) os << " = "; - os << np.getVal( i ); + os << np.getVal(i); if ( i != np.size() ) os << " "; } return os; } +template std::string AmpGen::optionalHelpString(const std::string& header, const T&... args ) +{ + std::stringstream rt; + rt << header; + for_each( std::make_tuple(args...), [&rt](const auto& f) mutable { + rt << "\n\033[3m " << f.first << "\033[0m: " << f.second; + }); + return rt.str(); +} + #endif -// diff --git a/AmpGen/OptionsParser.h b/AmpGen/OptionsParser.h index c1bd3449a15..ec9dc04832d 100644 --- a/AmpGen/OptionsParser.h +++ b/AmpGen/OptionsParser.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace AmpGen { @@ -17,26 +18,29 @@ namespace AmpGen static OptionsParser* getMe(); static bool printHelp(); - static void setArgs( int argc, char** argv ); + static void setArgs( int argc, char** argv, const std::string& description="" ); static void setArg( const std::string& arg ); + void setQuiet(); void addArg( const std::string& arg ); - void setCommandLineArgs( int argc, char** argv ); + void setCommandLineArgs( int argc, char** argv, const std::string& description =""); void import( const std::string& fName ); iterator find( const std::string& name ); iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; - private: std::map> m_parsedLines; - bool m_printHelp; + std::map)> > m_keywords; + bool m_printHelp = {false}; + bool m_quiet = {false}; static OptionsParser* gOptionsParser; OptionsParser(); bool ignoreThisLine( const std::string& line ); void readStream( std::istream& is ); std::vector makeParsedStrings( const std::string& line, int& braceDepth ) const; + void addArg(const std::vector& tokens ); }; } // namespace AmpGen #endif diff --git a/AmpGen/Pade.h b/AmpGen/Pade.h new file mode 100644 index 00000000000..2b3c7d90d3d --- /dev/null +++ b/AmpGen/Pade.h @@ -0,0 +1,56 @@ +#ifndef AMPGEN_PADE_H +#define AMPGEN_PADE_H + +#include +#include +#include + +namespace AmpGen { + enum Strategy { linear, quadratic, cubic, quartic }; + namespace detail { + std::vector solve_pade(const std::function& fcn, + const double& min, + const double& max, + const unsigned& N, + const Strategy& strat = Strategy::linear); + } + + template class Pade + { + public: + Pade(const std::function& fcn, + const double& min, + const double& max, + const Strategy& strat = Strategy::linear) : + m_function(fcn), min(min),max(max) + { + auto r = detail::solve_pade(fcn, min, max, N, strat ); + for(unsigned i = 0; i <= N; ++i ) co_f[i] = r[i]; + for(unsigned i = 0; i < N; ++i ) co_g[i] = r[i+(N+1)]; + range = 1./(max-min); + } + T operator()(const T& s) + { + T x = (s-min)*range; + T f = 0; + T g = 1; + T acc = 1; + for(unsigned i = 0; i < N; ++i){ + f += co_f[i] * acc; + acc *= x; + g += co_g[i] * acc; + } + return (f + co_f[N]*acc)/g; + } + + private: + std::function m_function; + std::array co_f; + std::array co_g; + T min; + T max; + T range; + }; +} + +#endif diff --git a/AmpGen/Particle.h b/AmpGen/Particle.h index 2b0306fc9da..4b9fc065585 100644 --- a/AmpGen/Particle.h +++ b/AmpGen/Particle.h @@ -26,7 +26,8 @@ namespace stdx { #include "AmpGen/Expression.h" #include "AmpGen/Tensor.h" #include "AmpGen/QuarkContent.h" - +#include "AmpGen/NamedParameter.h" +#include "AmpGen/enum.h" namespace AmpGen { /** @class Particle @@ -61,18 +62,19 @@ namespace AmpGen These will be denoted by the use of [] braces, so for example \code{cpp} - Delta(1232)++{p+,pi+} - Delta(1232)++[D]{p+,pi+} + a(1)(1260)+{rho(770)0,pi+} + a(1)(1260)+[D]{rho(770)0,pi+} \endcode - correspond to the S-wave and D-wave decays of the @f$\Delta(1232)^{++}@f$ baryon. + correspond to the S-wave and D-wave decays of the @f$a(1)(1260)^{+}@f$ meson. As a rule, the lowest orbital state permitted by the relevant conservation laws of the decay is used if the orbital state is not specified, so the conservation of angular momentum, and the conservation of parity if the decay proceeds via the strong or electromagnetic force. The modifier syntax is also used to specify a different choice of lineshape for the resonance. For example, a common parameterisation for the @f$\rho(770)@f$ meson is the Gounaris-Sakurai propagator, - which accounts for dispersive corrections to the @f$I=1@f$ dipion scattering. In this example + which accounts for dispersive corrections to the @f$I=1@f$ dipion system. + In this example \code{cpp} rho(770)0[GounarisSakurai]{pi+,pi-} @@ -93,168 +95,172 @@ namespace AmpGen Similar to other components of AmpGen, Particles will rarely be constructed in the C++ context, and will instead be instantiated dynamically at runtime from a user supplied options file. */ class ParticleProperties; - //struct zFrame { - // /// Frame where parent is at rest, particle 0 is along the z-axis - // Tensor operator(const std::vector& indices)() const - // { - // - // } - //}; + + declare_enum( spinFormalism, Covariant, Canonical ) + declare_enum( spinBasis , Dirac , Weyl ) class Particle { - private: - const ParticleProperties* m_props; ///< Particle Properties from the PDG - std::string m_name = {""}; ///< Name of the particle - std::string m_lineshape = {"BW"}; ///< Propagator to use - std::string m_uniqueString = {""}; ///< Unique string of particle tree - int m_parity = {0}; ///< Intrinsic parity of particle - int m_polState = {0}; ///< polarisation state - unsigned int m_index = {999}; ///< Index, for constructing four-momenta - unsigned int m_originalIndex = {999}; ///< Starting index, used in Bose-symmetrisation - unsigned int m_orbital = {0}; ///< Orbital angular momentum between daughters - unsigned int m_spinConfigurationNumber = {0}; ///< Spin configuration quantum number 'S' - unsigned int m_minL = {0}; ///< Minimum orbital angular momentum - bool m_isHead = {true}; ///< Flag that particle is head of decay chain - bool m_isStateGood = {true}; ///< Flag to check the decay is well-formed - bool m_usesDefaultLineshape = {false}; ///< Flag to check if default shape is used - std::vector> m_daughters; ///< Array of daughter particles - std::vector m_modifiers; ///< Additional modifiers for amplitude - std::string m_spinFormalism = {""}; ///< Spin formalism to use for this particle (global) - std::string m_spinBasis = {""}; ///< Basis to use for external polarisations (global) - std::string m_defaultModifier = {""}; ///< Default Modifier to use (global) - - void pdgLookup(); ///< Lookup information from the PDG database (using ParticlePropertiesList) - bool hasModifier( const std::string& modifier ) const; ///< Check if this particle has a given modifier - std::string modifierString() const; ///< Re-generate modifier string used to create particle - std::string makeUniqueString(); ///< Generate the decay descriptor for this decay. - void sortDaughters(); ///< Recursively order the particle's decay products. public: - /// @constructor default constructor + /// Default Constructor Particle(); - /// @constructor Constructor that takes a pair of other particles (i.e. this particle's decay products) as arguments and looks up the properties of this particle using the particle name. + /// Constructor that takes a pair of other particles (i.e. this particle's decay products) as arguments and looks up the properties of this particle using the particle name. Particle( const std::string& name, const Particle& p1, const Particle& p2 ); - /// @constructor Constructor that takes a pair of other particles (i.e. this particle's decay products) as arguments and looks up the properties of this particle using the PDG MC ID. + /// Constructor that takes a pair of other particles (i.e. this particle's decay products) as arguments and looks up the properties of this particle using the PDG MC ID. Particle( const int& pdg_id, const Particle& p1, const Particle& p2 ); - /// @constructor Constructor by name and with an index to match to the event type + /// Constructor by name and with an index to match to the event type Particle( const std::string& name, const unsigned int& index ); - /// @constructor Constructor that takes a decay descriptor as an argument and a list of final state particles to match to the event type. Constructs the entire decay tree. + /// Constructor that takes a decay descriptor as an argument and a list of final state particles to match to the event type. Constructs the entire decay tree. Particle( const std::string& decayString, const std::vector& finalStates = {}, const bool& orderDaughters = true ); + /// (Quasi) Constructor that returns the (quasi)CP conjugated amplitude. The full behaviour of the amplitude is made more complicated by the ordering convention. + Particle conj(bool invertHead = true, bool reorder = true); + + /// CP conjugate this particle // + + void conjThis(); + + static bool isValidDecayDescriptor( const std::string& decayDescriptor ); + /// Set the orbital quantum number 'L' for this decay. void setOrbital( const unsigned int& orbital ); + + /// Set the lineshape for the decay of this particle. void setLineshape( const std::string& lineshape ); + + /// Set the index'th daughter of this to particle. void setDaughter( const Particle& particle, const unsigned int& index ); - void setTop( bool state = true ); + + /// Set the parent particle for this particle + void setParent( const Particle* particle ); + + /// Set the index of this particle, i.e. where it is positioned in the event data structure. void setIndex( const unsigned int& index, const bool& setOri = false ); + /// Remove all of the decay products of this particle + void clearDecayProducts(); + + /// Add some modifier to the particle, such as a lineshape or a different spin state void addModifier( const std::string& mod ); + + /// Parse some set of modifiers, delimited with semicolons. void parseModifier( const std::string& mod ); + + /// Set some particle ordering of the decay products of this particle, mostly used internally by the symmetrisation void setOrdering( const std::vector& ordering ); + + /// Set the particle name + void setName(const std::string& name); + + /// Add a decay product void addDaughter( const std::shared_ptr& particle ); + + /// Set the polarisation state of this particle, which is twice the projection of the spin along the quantisation axis. void setPolarisationState( const int& state ); - std::pair orbitalRange( const bool& converseParity = true ) const; ///< Range of possible orbital angular momenta between decay products + void setPolarisationState( const std::vector& state); + + /// Returns the range of orbital angular momentum between the decay products + std::pair orbitalRange( const bool& converseParity = true ) const; + + /// Returns the set of possible spin-orbit couplings allowed by conservation of angular momentum, and if specified parity std::vector> spinOrbitCouplings( const bool& conserveParity = true ) const; + + /// Return the additional optional attribute keyed by variable key stdx::optional attribute(const std::string& key) const; + + /// Return the particleProperties object for this particle const ParticleProperties* props() const; - QuarkContent quarks() const; - QuarkContent daughterQuarks() const; - int parity() const; - int finalStateParity() const; - int polState() const; - int conjugate( bool invertHead = false , bool reorder = true); - double mass() const; - double spin() const; - double S() const; - bool isHead() const; - bool isWeakDecay() const; - bool isStateGood() const; - bool isStable() const; - bool isQuasiStable() const; - bool conservesParity( unsigned int L = 0 ) const; - bool checkExists() const; - - unsigned int orbital() const; - unsigned int index() const; - unsigned int originalIndex() const; - - /// @function Name of the decaying particle. - std::string name() const; - - /// @function Name of the propagator to use for the decay of this particle. - std::string lineshape() const; - - /// @function Name of the (spin)vertex to use for the decay of this particle - std::string vertexName() const; - - /// @function The unique string (i.e. decay descriptor) that identifies this decay / - /// can be parsed to generate the decay tree. - std::string uniqueString() const; - /// @function The descriptor that describes this decay / - /// that can be parsed to generate the decay tree and uniquely identify it. - std::string decayDescriptor() const; + QuarkContent quarks() const; ///< Return the quarks of this particle + + QuarkContent daughterQuarks() const; ///< Returns the quark content of the sum of the decay products of this particle + + int parity() const; ///< Returns the parity of this particle + int finalStateParity() const; ///< Returns the parity of the final state of this particle + + int polState() const; ///< Returns the polarisation state, i.e. twice the projection of the spin along the quantisation axis, of this particle. + int CP() const; ///< Returns the CP of this decay. + int C() const; ///< Returns the C quantum number for this decay + double mass() const; ///< Returns the (PDG) mass of the particle + double spin() const; ///< Returns the spin of the particle + double S() const; ///< Returns the spin configuration of the decay products of the particle + unsigned L() const; ///< Returns the orbital angular + + bool isHead() const; ///< Returns whether if this particle is the head of the decay, i.e. has no parent + bool isWeakDecay() const; ///< Returns whether is this particle decays weakly or not + bool isStateGood() const; ///< Returns whether this particle, and its decays have been configured correctly + bool isStable() const; ///< Check whether this particle is stable, has any decay products. + bool isQuasiStable() const; ///< Check whether the particle is quasi-stable, i.e. may have some appreciable flight distance + bool conservesParity( unsigned int L = 0 ) const; ///< Check whether the decay of this particle with angular momentum L conserves parity or not + + unsigned index() const; ///< Returns the current index of the particle in event data structure. Can differ from the original index due to symmetrisation + unsigned originalIndex() const; ///< Returns the original index of the particle + std::string name() const; ///< Name of the decaying particle. + std::string lineshape() const; ///< Name of the propagator to use for the decay of this particle. + + std::string uniqueString() const; ///< Returns the unique string (i.e. decay descriptor) that identifies this decay, which can be parsed to generate the decay tree. + std::string decayDescriptor() const;///< Returns the unique string (i.e. decay descriptor) that identifies this decay, which can be parsed to generate the decay tree. - /// @function The string that describes the spin/orbital topology of this decay, + /// The string that describes the spin/orbital topology of this decay, /// i.e. replacing specific particle names with their spins. std::string topologicalString() const; - /// @function The string that describes the spin/orbit configuration of this decay. + /// The string that describes the spin/orbit configuration of this decay. std::string orbitalString() const; - /// @function Decay descriptor formatted as LaTeX for this decay. + /// Decay descriptor formatted as LaTeX for this decay. std::string texLabel( const bool& printHead = false, const bool& recurse=true ) const; - /// @function Returns the ``quasi'' CP Quantum number for this decay - int quasiCP() const; - - /// @function Return the eventType for this decay (i.e. the initial and final state particles) + /// Return the eventType for this decay (i.e. the initial and final state particles) EventType eventType() const; - /// @function Returns the indexth decay product of this particle + /// Returns the indexth decay product of this particle std::shared_ptr daughter( const size_t& index ); - /// @function Returns in indexth decay product of this particle (as constant) + /// Returns in indexth decay product of this particle (as constant) std::shared_ptr daughter( const size_t& index ) const; + + /// Returns in indexth decay product of this particle (as constant) + std::shared_ptr daughter(const std::string& name, const int& maxDepth=-1) const; - /// @function Vector of decay products of this particle + /// Vector of decay products of this particle std::vector> daughters() const; - /// @function Get orderings of the final state that are identical to each other, i.e. those that only differ by exchanging identical particles. + /// Get orderings of the final state that are identical to each other, i.e. those that only differ by exchanging identical particles. std::vector> identicalDaughterOrderings() const; - /// @function Returns the final state particles for this decay process. + /// Returns the final state particles for this decay process. std::vector> getFinalStateParticles( const bool& sort = true ) const; - /// @function Calculate the particle tree only including quasi-stable processes, + /// Calculate the particle tree only including quasi-stable processes, /// i.e. only includes states with lifetimes > ParticleProperties::qsThreshold (default ~ 1 KeV ) Particle quasiStableTree() const; - /// @function Calculates the momentum sum of the decay products + /// Calculates the momentum sum of the decay products Tensor P() const; - /// @function Calculates the momentum difference between the decay products (only well defined for quasi two-body processes ) + /// Calculates the momentum difference between the decay products (only well defined for quasi two-body processes ) Tensor Q() const; - /// @function Calculates the spin tensor or generalised current for this particle + /// Calculates the spin tensor or generalised current for this particle Tensor spinTensor( DebugSymbols* db = nullptr ) const; - /// @function Calculates the polarisation vector / spinor etc. of this particle, used for the initial/final state particles + /// Calculates the polarisation vector / spinor etc. of this particle, used for the initial/final state particles Tensor externalSpinTensor(const int& polState, DebugSymbols* db = nullptr) const; - /// @function Calculates the invariant mass-squared of the mass of this particle + /// Calculates the invariant mass-squared of the mass of this particle Expression massSq() const; - /// @function Calculates the lineshape / propagator for this particle. + /// Calculates the lineshape / propagator for this particle. Expression propagator( DebugSymbols* db = nullptr ) const; - /// @function Calculates the total expression for this particle, including symmetrisation and the current polarisation state - Expression getExpression( DebugSymbols* db = nullptr, const unsigned int& index = 0 ); + /// Calculates the total expression for this particle, including symmetrisation and the current polarisation state + Expression getExpression( DebugSymbols* db = nullptr, const std::vector& = {} ); - /// @function Calculate the transition matrix for this decay + /// Calculate the transition matrix for this decay Tensor transitionMatrix( DebugSymbols* db = nullptr ); bool operator<( const Particle& other ); bool operator>( const Particle& other ); @@ -267,9 +273,44 @@ namespace AmpGen DifferentOrbital = ( 1<<3 ), DifferentPolarisation = ( 1<<4 ) }; - /// @function matches Check the matching between two decay chains, according to the MatchState enum. + /// matches Check the matching between two decay chains, according to the MatchState enum. unsigned int matches( const Particle& other ) const; + std::string makeUniqueString(); ///< Generate the decay descriptor for this decay. + + private: + std::string m_name = {""}; ///< Name of the particle + const ParticleProperties* m_props = {nullptr}; ///< Particle Properties from the PDG + std::string m_lineshape = {"BW"}; ///< Propagator to use + std::string m_uniqueString = {""}; ///< Unique string of particle tree + int m_parity = {0}; ///< Intrinsic parity of particle + int m_polState = {0}; ///< Projection of the spin along the quantisation axis, i.e. 'z' + unsigned m_index = {999}; ///< Index, for constructing four-momenta + unsigned m_originalIndex = {999}; ///< Starting index, used in Bose-symmetrisation + unsigned m_orbital = {0}; ///< Orbital angular momentum between daughters + unsigned m_spinConfigurationNumber = {0}; ///< Spin configuration quantum number 'S' + unsigned m_minL = {0}; ///< Minimum orbital angular momentum + bool m_usesDefaultLineshape = {false}; ///< Flag to check if default shape is used + bool m_isStateGood = {true}; ///< Flag to check the decay is well-formed + std::vector> m_daughters; ///< Array of daughter particles + std::vector m_modifiers; ///< Additional modifiers for amplitude + const Particle* m_parent = {nullptr}; ///< Pointer to the parent particle of this particle + void pdgLookup(); ///< Lookup information from the PDG database (using ParticlePropertiesList) + bool hasModifier( const std::string& modifier ) const; ///< Check if this particle has a given modifier + std::string modifierString() const; ///< Re-generate modifier string used to create particle + void sortDaughters(); ///< Recursively order the particle's decay products. + + NamedParameter m_spinFormalism = {"Particle::SpinFormalism" ,spinFormalism::Covariant, + optionalHelpString("Formalism to use for spin calculations", + std::make_pair("Covariant", "[default] Covariant Tensor, based on Rarita-Schwinger constraints on the allowed covariant wavefunctions.") + , std::make_pair("Canonical", "Canonical formulation, based on rotational properties of wavefunctions, i.e. Wigner D-matrices and Clebsch-Gordan for (L,S) expansion.") ) }; + + NamedParameter m_spinBasis = {"Particle::SpinBasis", spinBasis::Dirac, + optionalHelpString("Basis to use for calculating external polarisation tensors / spinors.", + std::make_pair("Dirac", "[default] Quantises along the z-axis") + , std::make_pair("Weyl", "Quantises along the direction of motion") )}; + NamedParameter m_defaultModifier = {"Particle::DefaultModifier","", "Default modifier to use for lineshapes, for example to use normalised vs unnormalised Blatt-Weisskopf factors."}; }; + std::ostream& operator<<( std::ostream& os, const Particle& particle ); } // namespace AmpGen #endif diff --git a/AmpGen/ParticleProperties.h b/AmpGen/ParticleProperties.h index 02766797f00..df8e000bfe3 100644 --- a/AmpGen/ParticleProperties.h +++ b/AmpGen/ParticleProperties.h @@ -11,96 +11,103 @@ namespace AmpGen { - class ParticleProperties - { - private: - double m_mass; ///< mass [MeV] - double m_mErrPlus; ///< +ve mass error [MeV] - double m_mErrMinus; ///< -ve mass error [MeV] - double m_width; ///< width [MeV] - double m_wErrPlus; ///< +ve width error [MeV] - double m_wErrMinus; ///< -ve width error [MeV] - double m_Radius; ///< hadronic radius - int m_Gparity; ///< G-parity - int m_Parity; ///< Parity - int m_Cparity; ///< Charge 'parity' - int m_pdgID; ///< PDG id - int m_Rexist; ///< likelihood of existence, baryons only - int m_charge; ///< electrical charge - int m_twoSpin; ///< twice the spin - std::string m_Isospin; ///< isospin - std::string m_JtotalSpin; ///< total spin - std::string m_name; ///< particle name - std::string m_quarks; ///< quark string - std::string m_texName; ///< latex label of particle - std::string m_chargeString; ///< string for particle charge - char m_Aformat; ///< anti-particle format character - char m_status; ///< status (estalished or not etc) - QuarkContent m_netQuarkContent; - bool m_isValid; - - void setRadius(); + /** @class ParticleProperties + @brief Class that contains the PDG properties (mass, width, charges, etc.) for a single particle species, + + Stores the information for a single particle species, the mass, the width, spin, various charges. + The data is typically loaded from ParticlePropertiesList, which loads from the PDG provided + \code{cpp} + mass_width.cvs + \endcode + See that more details. + */ - void antiQuarks(); - void antiQuarkContent(); - void antiCharge(); - int chargeFromString( const std::string& ch, bool& status ) const; - public: - double mass() const { return m_mass * MeV; } ///< returns mass of particle in MeV - double mErrPlus() const { return m_mErrPlus * MeV; } ///< returns +ve uncertainty on particle mass in MeV - double mErrMinus() const { return m_mErrMinus * MeV; } ///< returns -ve uncertainty on particle mass in MeV - double width() const { return m_width * MeV; } ///< returns width of particle in MeV - double wErrPlus() const { return m_wErrPlus * MeV; } ///< returns +ve uncertainty on particle width in MeV - double wErrMinus() const { return m_wErrMinus * MeV; } ///< returns -ve uncertainty on particle width in MeV - double radius() const; + class ParticleProperties + { + public: + explicit ParticleProperties( const std::string& pdg_string = "" ); ///< Constructor from a string formatted by the PDG convention. + double mass() const { return m_mass * MeV; } ///< Returns mass of particle in MeV + double mErrPlus() const { return m_mErrPlus * MeV; } ///< Returns +ve uncertainty on particle mass in MeV + double mErrMinus() const { return m_mErrMinus * MeV; } ///< Returns -ve uncertainty on particle mass in MeV + double width() const { return m_width * MeV; } ///< Returns width of particle in MeV + double wErrPlus() const { return m_wErrPlus * MeV; } ///< Returns +ve uncertainty on particle width in MeV + double wErrMinus() const { return m_wErrMinus * MeV; } ///< Returns -ve uncertainty on particle width in MeV + double radius() const; ///< Returns the effective interaction radius of the particle, i.e. for the Blatt-Weisskopf factors + double lifetime() const; ///< Returns the lifetime of the particle in ns - int G() const { return m_Gparity; } - int P() const { return m_Parity; } - int C() const { return m_Cparity; } - int R() const { return m_Rexist; } - int pdgID() const { return m_pdgID; } - int twoSpin() const { return m_twoSpin ; } - std::string I() const { return m_Isospin; } - std::string J() const { return m_JtotalSpin; } - int charge() const { return m_charge; } - std::string label() const { return m_texName; } - std::string quarks() const { return m_quarks; } - std::string name() const; - std::string chargeString() const { return m_chargeString; } - std::string spinName() const; + int G() const { return m_Gparity; } ///< Returns the G-parity of the particle + int P() const { return m_parity; } ///< Returns the parity of the particle + int C() const { return m_Cparity; } ///< Returns the C-parity of the particle + int R() const { return m_Rexist; } ///< Returns the R-parity of the particle + int pdgID() const { return m_pdgID; } ///< Returns the PDG id of the particle. + int twoSpin() const { return m_twoSpin; } ///< Returns twice the spin of the particle + int charge() const { return m_charge; } ///< Returns the (electrical) charge of the particle + char S() const { return m_status; } ///< Returns the existence status of the particle, i.e. whether it is confirmed by multiple experiments + std::string I() const { return m_isospin; } ///< Returns the isospin of the particle as a string. + std::string J() const; + std::string label() const { return m_texName; } ///< Returns the LaTeX formatted label for the particle + std::string name() const; ///< Returns the particle name + std::string spinName() const; ///< Returns the name of the particles spin. + bool isValid() const { return m_isValid; } ///< Check if the particle properties have been configured correctly + bool hasDistinctAnti() const; ///< Check if the particle has a distinct antiparticle + bool isNonResonant() const; ///< Check is this is a nonresonant `quasi-particle' + bool isFermion() const; ///< Check if the particle is a fermion, i.e. if the spin 1/2, 3/2, ... + bool isBoson() const; ///< Check if the particle is a boson, i.e. if the spin 0, 1, 2... + bool isNeutrino() const; ///< Check if the particle is a neutrino - char S() const { return m_status; } - void setLabel( const std::string& label ) { m_texName = label; } - void setName( const std::string& name ) { m_name = name; } - const QuarkContent& netQuarkContent() const { return m_netQuarkContent; } - - bool isValid() const { return m_isValid; } + bool isPhoton() const; ///< Check if the particle is a photon + void setProperty(const std::string& key, const std::string& value); ///< set a propery of a particle by key + const QuarkContent& quarkContent() const { return m_quarkContent; } ///< Returns the particle's quark content - bool hasDistinctAnti() const; - bool barred() const; - bool isItsOwnAnti() const { return !hasDistinctAnti(); } + void setLabel( const std::string& label ) { m_texName = label; } ///< Set the LaTeX label of the particle + void setName( const std::string& name ) { + m_customName = true; + m_name = name; } ///< Set the name of the particle - ParticleProperties( const std::string& pdg_string = "" ); + void print( std::ostream& out = std::cout ) const; - void print( std::ostream& out = std::cout ) const; + bool operator==( const ParticleProperties& rhs ) const; + bool operator< ( const ParticleProperties& rhs ) const; + bool operator> ( const ParticleProperties& rhs ) const; + bool operator<=( const ParticleProperties& rhs ) const; + bool operator>=( const ParticleProperties& rhs ) const; - bool operator==( const ParticleProperties& rhs ) const; - bool operator< ( const ParticleProperties& rhs ) const; - bool operator> ( const ParticleProperties& rhs ) const; - bool operator<=( const ParticleProperties& rhs ) const; - bool operator>=( const ParticleProperties& rhs ) const; + bool antiThis(); ///< Change this particle to its antiparticle + ParticleProperties anti() const; ///< Return the antiparticle of this particle - bool antiThis(); - ParticleProperties anti() const; + static const ParticleProperties* get( const std::string& name, const bool& quiet=false ); - bool isNonResonant() const; - bool isFermion() const ; - bool isBoson() const; - static const ParticleProperties* get( const std::string& name, const bool& quiet=false ); + private: + double m_mass{0}; ///< mass [GeV] + double m_mErrPlus{0}; ///< +ve mass error [GeV] + double m_mErrMinus{0}; ///< -ve mass error [GeV] + double m_width{0}; ///< width [GeV] + double m_wErrPlus{0}; ///< +ve width error [GeV] + double m_wErrMinus{0}; ///< -ve width error [GeV] + double m_radius{0}; ///< hadronic radius + int m_Gparity{0}; ///< G-parity + int m_parity{0}; ///< Parity + int m_Cparity{0}; ///< Charge 'parity' + int m_pdgID{0}; ///< PDG id + int m_Rexist{0}; ///< likelihood of existence, baryons only + int m_charge{0}; ///< electrical charge + int m_twoSpin{0}; ///< twice the spin + std::string m_isospin{""}; ///< isospin + std::string m_name{""}; ///< particle name + std::string m_texName{""}; ///< latex label of particle + std::string m_chargeString{""}; ///< string for particle charge + char m_Aformat; ///< anti-particle format character + char m_status; ///< status (estalished or not etc) + QuarkContent m_quarkContent; ///< The quark content of the state (uD, uud etc.) + bool m_isValid; ///< Flag to check whether the ParticleProperties have configured correctly + bool m_customName = {false}; ///< Flag to make custom name + void antiQuarks(); + void antiCharge(); + int chargeFromString( const std::string& ch, bool& status ) const; }; -} // namespace AmpGen -std::ostream& operator<<( std::ostream& out, const AmpGen::ParticleProperties& pp ); + std::ostream& operator<<( std::ostream& out, const AmpGen::ParticleProperties& pp ); +} #endif // diff --git a/AmpGen/ParticlePropertiesList.h b/AmpGen/ParticlePropertiesList.h index 0256ff3ca4d..289ccd8343d 100644 --- a/AmpGen/ParticlePropertiesList.h +++ b/AmpGen/ParticlePropertiesList.h @@ -24,7 +24,7 @@ namespace AmpGen std::map m_byID; double m_quasiStableThreshold; - ParticlePropertiesList( const std::string& fname_in = "mass_width.csv" ); + explicit ParticlePropertiesList( const std::string& fname_in = "mass_width.csv" ); protected: const std::vector dirList() const; @@ -48,6 +48,7 @@ namespace AmpGen void print( std::ostream& out = std::cout ) const; bool readLatexLabels( const std::string& name ); void makeMappings(); + void addParticle(const std::vector& properties ); }; std::ostream& operator<<( std::ostream& out, const ParticlePropertiesList& ppl ); } // namespace AmpGen diff --git a/AmpGen/PhaseSpace.h b/AmpGen/PhaseSpace.h index 090badfc489..2d3f37257d6 100644 --- a/AmpGen/PhaseSpace.h +++ b/AmpGen/PhaseSpace.h @@ -10,38 +10,39 @@ namespace AmpGen { - /**@class PhaseSpace - * Phase-space generator taken from the ROOT routine, from Rene Brun and Valerio Filippini, - * which was originally based on the GENBOD routine of CERNLIB with - * modifications such that unweighted events are generated, - * which saves a large amount of CPU. Further modified to remove the dependencies on TLorentzVector - * and to only use the AmpGen::Event classes, and to add the option to include a time dependence. + /** @class PhaseSpace + Phase-space generator taken from the ROOT routine, from Rene Brun and Valerio Filippini, + which was originally based on the GENBOD routine of CERNLIB with + modifications such that unweighted events are generated, + which saves a large amount of CPU. Further modified to remove the dependencies on TLorentzVector + and to only use the AmpGen::Event classes, and to add the option to include a time dependence. */ + class Particle; class PhaseSpace { public: - PhaseSpace() = default; - PhaseSpace( const EventType& type, TRandom* rand = gRandom ); - ~PhaseSpace() = default; + PhaseSpace() = default; ///< Empty constructor + explicit PhaseSpace(const EventType& type, TRandom* rand = gRandom); ///< Construct a phase space generator from an EventType + explicit PhaseSpace(const Particle& type, TRandom* rand = gRandom); ///< Construct a phase space generator from a Particle - bool setDecay( const double& m0, const std::vector& mass ); - void setRandom( TRandom* rand ) { m_rand = rand; } - size_t size() const { return m_nt; } - AmpGen::Event makeEvent( const size_t& cacheSize = 0 ); - AmpGen::EventType eventType() const; + bool setDecay( const double& m0, const std::vector& mass ); ///< Set the parameters of this phase space generator + void setRandom( TRandom* rand ) { m_rand = rand; } ///< Set the random number used by this phase space generator + size_t size() const { return m_nt; } ///< Return the number of decay products + Event makeEvent(); ///< Make an event in this phase space. + EventType eventType() const; ///< Returns the EventType that this phase space is generating + void provideEfficiencyReport(const std::vector& report){} private: - unsigned int m_nt = {0}; // number of decay particles - double m_mass[18] = {0}; // masses of particles - double m_teCmTm = {0}; // total energy in the C.M. minus the total mass - double m_wtMax = {0}; // maximum weight - double m_decayTime = {0}; // decay time - TRandom* m_rand = {nullptr}; // Random number generator - EventType m_type; // EventType to generate + size_t m_nt = {0}; ///< Number of particles in the final state + double m_mass[18] = {0}; ///< Masses of particles in the final state + double m_teCmTm = {0}; ///< Total energy in the rest frame minus the total mass + double m_wtMax = {0}; ///< Maximum weight of an event + double m_decayTime = {0}; ///< Proper decay time of the particle + TRandom* m_rand = {nullptr}; ///< Random number generator + EventType m_type; ///< EventType to generate - double rndm() { return m_rand->Rndm(); } - double q(double a, double b, double c) const; + double q(double a, double b, double c) const; ///< Breakup momentum of a particle with mass a decaying to decay products with masses b and c. }; } // namespace AmpGen #endif diff --git a/AmpGen/Plots.h b/AmpGen/Plots.h deleted file mode 100644 index 7135c708329..00000000000 --- a/AmpGen/Plots.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef AMPGEN_PLOTS_H -#define AMPGEN_PLOTS_H -#include "AmpGen/ErrorPropagator.h" -#include "AmpGen/EventList.h" -#include "AmpGen/CoherentSum.h" -#include "AmpGen/IncoherentSum.h" -#include "AmpGen/Integrator.h" -#include "AmpGen/MinuitParameterSet.h" -#include "AmpGen/Projection.h" -#include "AmpGen/Utilities.h" -#include "AmpGen/EventList.h" - -#include "TFile.h" -#include "TH1D.h" -#include "TH2D.h" -#include - -namespace AmpGen -{ - void perAmplitudePlot(const EventList& evts, const Projection& projection, const CoherentSum& pdf); - - template - std::array getNorms( CoherentSum& fcn, BinnedIntegrator& bid ) - { - - std::array normalisations; - for ( unsigned int i = 0; i < NBINS; ++i ) normalisations[i] = Bilinears( fcn.size(), fcn.size() ); - - for ( unsigned int i = 0; i < fcn.size(); ++i ) { - for ( unsigned int j = i; j < fcn.size(); ++j ) { - bid.addIntegral( fcn[i].pdf, fcn[j].pdf, [i, j, &normalisations]( const auto& val ) { - for ( unsigned int bin = 0; bin < NBINS; ++bin ) { - normalisations[bin].set( i, j, val[bin] ); - if ( i != j ) normalisations[bin].set( j, i, std::conj( val[bin] ) ); - } - } ); - } - } - bid.flush(); - return normalisations; - } - - template - std::array getNorms( IncoherentSum& fcn, BinnedIntegrator& bid ) - { - std::array normalisations; - for ( unsigned int i = 0; i < NBINS; ++i ) normalisations[i] = Bilinears( fcn.size(), fcn.size() ); - for ( unsigned int i = 0; i < fcn.size(); ++i ) { - bid.addIntegral( fcn[i].pdf, fcn[i].pdf, [i, &normalisations]( const auto& val ) { - for ( unsigned int bin = 0; bin < NBINS; ++bin ) normalisations[bin].set( i, 0, val[bin] ); - } ); - } - bid.flush(); - return normalisations; - } - - template - TH1D* plotWithError( EventList& events, FCN& fcn, const Projection& projection, const std::string& prefix, - LinearErrorPropagator& linProp, const std::function& selection = nullptr ) - { - BinnedIntegrator bid( &events ); - if ( selection != nullptr ) bid.setSlice( selection ); - bid.setView( projection.binFunctor() ); - TH1D* plot = projection.plot(); - plot->SetName( ( prefix + plot->GetName() ).c_str() ); - auto normalisations = getNorms( fcn, bid ); - - auto vectorBinFunctor = [&normalisations, &fcn, &bid] { - fcn.transferParameters(); - bid.update( fcn, normalisations ); - std::array values; - double total = 0; - for ( size_t bin = 0; bin < NBINS; ++bin ) { - values[bin] = fcn.norm( normalisations[bin] ); - total += values[bin]; - } - for ( size_t bin = 0; bin < NBINS; ++bin ) values[bin] /= total; - return values; - }; - auto values = vectorBinFunctor(); - auto errors = linProp.getVectorError( vectorBinFunctor ); - for ( size_t bin = 0; bin < NBINS; ++bin ) { - plot->SetBinContent( bin + 1, values[bin] ); - plot->SetBinError( bin + 1, errors[bin] ); - } - return plot; - } - - - template - std::vector bandPlot( EventList& events, const std::string& prefix, FCN& fcn, LinearErrorPropagator& linProp ) - { - std::vector plots; - auto axes = events.eventType().defaultProjections( NBINS ); - for ( auto& proj : axes ) { - INFO( "Making plot:" << proj.name() ); - plots.push_back( plotWithError( events, fcn, proj, prefix, linProp ) ); - } - return plots; - } -} // namespace AmpGen - -#endif diff --git a/AmpGen/PolarisedSum.h b/AmpGen/PolarisedSum.h index e9f7cf9225e..c6aec002e18 100644 --- a/AmpGen/PolarisedSum.h +++ b/AmpGen/PolarisedSum.h @@ -19,13 +19,14 @@ #include "AmpGen/CoherentSum.h" #include "AmpGen/Expression.h" #include "AmpGen/Tensor.h" +#include "AmpGen/MinuitParameter.h" + #include "TMatrixD.h" namespace AmpGen { class LinearErrorPropagator; - class MinuitParameter; class MinuitParameterSet; class FitFraction; class Event; @@ -35,53 +36,68 @@ namespace AmpGen class PolarisedSum { public: - PolarisedSum( const EventType& eventType, AmpGen::MinuitParameterSet& mps, const std::string& prefix="" ); + #if ENABLE_AVX + using EventList_type = EventListSIMD; + #else + using EventList_type = EventList; + #endif + + PolarisedSum() = default; + PolarisedSum(const EventType&, MinuitParameterSet&, const std::vector& = {}); void prepare(); - void setEvents( AmpGen::EventList& events ); - void setMC( AmpGen::EventList& events ); - void reset( const bool& flag = false ); - void debug(const AmpGen::Event& event ); + void setEvents(EventList_type&); + void setMC(EventList_type&); + #if ENABLE_AVX + void setEvents(EventList& evts){ m_ownEvents = true; setEvents( *new EventList_type(evts)) ; }; + void setMC(EventList& evts){ setMC( *new EventList_type(evts)) ; }; + double operator()(const double*, const unsigned) const; + #endif + float_v operator()(const float_v*, const unsigned) const; + real_t operator()(const Event& evt) const; + void reset(const bool& = false); + void debug(const Event&); void debug_norm(); - void setWeight( MinuitParameter* param ); + void setWeight(MinuitProxy); double getWeight() const; - void calculateNorms(const std::vector& hasChanged); - void generateSourceCode( const std::string& fname, const double& normalisation = 1, bool add_mt = false ); - void build_probunnormalised(); - Expression probExpression( const Tensor& T_matrix, const std::vector& p ) const; - size_t size() const ; + void updateNorms(); + void generateSourceCode(const std::string&, const double& = 1, bool = false); + Expression probExpression(const Tensor&, const std::vector&, DebugSymbols* = nullptr) const; + size_t size() const; real_t norm() const; - complex_t norm(const size_t& i, const size_t& j, Integrator<18>* integ = nullptr ); - real_t operator()(const AmpGen::Event& event) const { return prob_unnormalised(event) ;} - real_t prob_unnormalised( const AmpGen::Event& evt ) const; - real_t prob(const AmpGen::Event& evt ) const ; - real_t getValNoCache( const AmpGen::Event& evt ) ; - std::vector fitFractions( const LinearErrorPropagator& prop ); - std::vector>> matrixElements() const; + complex_t norm(const size_t&, const size_t&, Integrator* = nullptr); + real_t getValNoCache(const Event&) const; + std::vector fitFractions(const LinearErrorPropagator&); + std::vector> matrixElements() const; void transferParameters(); - Tensor transitionMatrix(); - TransitionMatrix> operator[](const size_t& i) const { return m_matrixElements[i] ; } - + Tensor transitionMatrix() const; + const TransitionMatrix& operator[](const size_t& i) const { return m_matrixElements[i] ; } + std::function evaluator(const EventList_type* = nullptr) const; + KeyedFunctors componentEvaluator(const EventList_type* = nullptr) const; + EventType eventType() const{ return m_eventType; } private: size_t m_nCalls = {0}; real_t m_norm = {1}; - EventList* m_events = {nullptr}; - MinuitParameter* m_weightParam = {nullptr}; - const MinuitParameterSet* m_mps = {nullptr}; - double m_weight = {1}; + EventList_type* m_events = {nullptr}; + Store m_cache = {}; + Store m_pdfCache = {}; + bool m_ownEvents = {false}; + MinuitParameterSet* m_mps = {nullptr}; + MinuitProxy m_weight = {nullptr,1}; std::vector m_pVector = {}; bool m_verbosity = {0}; - Integrator<18> m_integrator; + bool m_debug = {0}; + Integrator m_integrator; std::vector m_norms; - std::vector> m_polStates; EventType m_eventType; std::string m_prefix = ""; - std::vector m_psi; + std::vector m_rho; std::vector m_integIndex; - std::vector>> m_matrixElements; - CompiledExpression m_probExpression; AmplitudeRules m_rules; - std::vector> polarisationOuterProduct( const std::vector>& A, const std::vector& B ) const; - std::vector polarisations( const std::string& name ) const ; + std::pair m_dim; + std::vector> m_matrixElements; + CompiledExpression m_probExpression; + std::vector> indexProduct(const std::vector>&, const std::vector&) const; + std::vector polarisations(const std::string&) const ; }; } // namespace AmpGen diff --git a/AmpGen/ProfileClock.h b/AmpGen/ProfileClock.h index 008b834cad1..8810c325663 100644 --- a/AmpGen/ProfileClock.h +++ b/AmpGen/ProfileClock.h @@ -1,24 +1,67 @@ #ifndef AMPGEN_PROFILECLOCK_H #define AMPGEN_PROFILECLOCK_H 1 #include +#include #include "AmpGen/MsgService.h" #include "AmpGen/Utilities.h" namespace AmpGen{ struct ProfileClock { - std::chrono::time_point t_start; - std::chrono::time_point t_end; - ProfileClock() : t_start( std::chrono::high_resolution_clock::now()) {} - void stop(){ t_end = std::chrono::high_resolution_clock::now() ; } - operator double() const { return std::chrono::duration( t_end - t_start ).count() ; } ; + std::chrono::time_point t_start; + std::chrono::time_point t_end; + double t_duration = {0}; + + ProfileClock() : t_start(std::chrono::high_resolution_clock::now()) {} + void stop() + { + t_end = std::chrono::high_resolution_clock::now() ; + t_duration += std::chrono::duration( t_end - t_start ).count(); + } + double count() const + { + auto now = std::chrono::high_resolution_clock::now() ; + return std::chrono::duration(now - t_start ).count(); + } + void start(){ t_start = std::chrono::high_resolution_clock::now() ; } + operator double() const { return t_duration; } ; }; template - double Profile( const FCN& fcn ){ + double Profile( const FCN& fcn, const std::string& name ="" ){ ProfileClock t; for( size_t i = 0 ; i < N; ++i ) fcn(); t.stop(); - INFO( typeof() << " " << t/double(N) << "[ms] per iteration" ); + INFO( (name == "" ? type_string() : name ) << " " << t/double(N) << "[ms] per iteration" ); + return t; + } + template + double ProfileWithStat( const FCN& fcn, const std::string& name ="" ){ + double t = 0; + double t2 = 0; + double tmin = 1e9; + double tmax = 0; + for( size_t i = 0 ; i < N; ++i ){ + ProfileClock pi; + fcn(); + pi.stop(); + t += pi; + t2 += pi*pi; + tmin = pi < tmin ? pi : tmin; + tmax = pi > tmax ? pi : tmax; + } + t /= double(N); + t2 = std::sqrt( t2 / double(N) - t*t); + INFO( (name == "" ? type_string() : name ) << " " << t << " ± " << t2 << "[ms] per iteration << [" << tmin << ", " << tmax << "]" ); + return t; + } + + template + double Profile2( const FCN& fcn ){ + ProfileClock t; + auto z = 0 ; + for( size_t i = 0 ; i < N; ++i ) z += fcn(); + t.stop(); + INFO( type_string() << " " << t/double(N) << "[ms] per iteration; " << z ); return t; } } diff --git a/AmpGen/ProgressBar.h b/AmpGen/ProgressBar.h new file mode 100644 index 00000000000..258fe5f9202 --- /dev/null +++ b/AmpGen/ProgressBar.h @@ -0,0 +1,21 @@ +#ifndef AMPGEN_PROGRESSBAR_H +#define AMPGEN_PROGRESSBAR_H + +#include +namespace AmpGen { + class ProgressBar { + public: + ProgressBar(const size_t& width, const std::string& context); + ~ProgressBar(); + void print(const double& percentage, const std::string& message=""); + void finish(); + private: + size_t m_width; + int m_lastPercent; + std::string m_context; + std::string m_lastMessage = {""}; + bool m_finished = {false}; + }; +} + +#endif diff --git a/AmpGen/Projection.h b/AmpGen/Projection.h index ad77e66c683..ce91ffb9e1e 100644 --- a/AmpGen/Projection.h +++ b/AmpGen/Projection.h @@ -8,43 +8,67 @@ #include "TH1D.h" #include "TH2D.h" -#include "AmpGen/Event.h" +#include "THStack.h" -class TH1D; -class TH2D; +#include "AmpGen/ArgumentPack.h" +#include "AmpGen/Types.h" +#include "AmpGen/KeyedFunctors.h" namespace AmpGen { class Projection2D; class Event; + class EventList; class Projection { - friend class Projection2D; - private: - std::function m_func; - std::string m_name; - std::string m_xAxisTitle; - std::string m_units; - size_t m_nBins; - double m_min; - double m_max; - double m_width; + using keyedFunctors = KeyedFunctors; public: - const std::string name() const ; - double operator()( const Event& evt ) const ; - template + Projection(); + template Projection( const FCN& fcn, const std::string& name, const std::string& xAxisTitle, const size_t& nBins, const double& min, const double& max, const std::string& units = "" ) : Projection( std::function< double( const Event& )>( fcn ), name, xAxisTitle, nBins, min, max, units ) {} - Projection( const std::function& fcn, const std::string& name, - const std::string& xAxisTitle, const size_t& nBins, const double& min, const double& max, - const std::string& units = "" ); + Projection( const std::function& fcn, const std::string& name, + const std::string& xAxisTitle, const size_t& nBins, const double& min, const double& max, + const std::string& units = "" ); + const std::string name() const; + template TH1D* operator()(const eventlist_type& evts, const ARGS... args) const + { + return projInternal(evts, ArgumentPack(args...) ); + } + template std::tuple, THStack*> operator()(const eventlist_type& evts, + const keyedFunctors& weightFunction, const ARGS... args ) const + { + return projInternal(evts, weightFunction, ArgumentPack(args...) ); + } + + double operator()( const Event& evt ) const; + + TH1D* plot(const std::string& prefix="") const; - TH1D* plot(const std::string& prefix="") const; + std::function binFunctor() const; + void setRange( const double& min, const double& max ) + { + m_min = min; + m_max = max; + m_width = (m_max-m_min)/double(m_nBins); + } - std::function binFunctor() const; - void setRange( const double& min, const double& max ){ m_min = (min); m_max = (max) ; } + friend class Projection2D; + /// private: + template + TH1D* projInternal(const eventlist_type&, const ArgumentPack&) const; + template + std::tuple, THStack*> projInternal(const eventlist_type&, const keyedFunctors&, const ArgumentPack&) const; + std::function m_func; + std::string m_name = {""}; + std::string m_xAxisTitle = {""}; + std::string m_units = {""}; + size_t m_nBins = {0}; + double m_min = {0}; + double m_max = {0}; + double m_width = {0}; }; class Projection2D @@ -60,7 +84,15 @@ namespace AmpGen std::pair operator()( const Event& evt ) const; }; - + namespace PlotOptions { + DECLARE_ARGUMENT(LineColor , int); + DECLARE_ARGUMENT(DrawStyle , std::string); + DECLARE_ARGUMENT(Selection , std::function); + DECLARE_ARGUMENT(Prefix , std::string); + DECLARE_ARGUMENT(Norm , double); + DECLARE_ARGUMENT(AddTo , THStack*); + DECLARE_ARGUMENT(AutoWrite , bool); + } } // namespace AmpGen #endif diff --git a/AmpGen/QuarkContent.h b/AmpGen/QuarkContent.h index 17d4feb7ab7..061750ba6df 100644 --- a/AmpGen/QuarkContent.h +++ b/AmpGen/QuarkContent.h @@ -17,9 +17,8 @@ namespace AmpGen std::array m_quarks; public: QuarkState(); - QuarkState( const std::string& str ); + explicit QuarkState( const std::string& str ); void antiThis(); - void initFromString( const std::string& str ); char nameFromPosition( int i ) const; int positionFromName( char c ) const; bool isVacuum() const; @@ -28,8 +27,9 @@ namespace AmpGen QuarkState& operator-=( const QuarkState& rhs ); QuarkState operator+ ( const QuarkState& rhs ) const; QuarkState operator- ( const QuarkState& rhs ) const; - bool operator==( const QuarkState& rhs ) const; - int operator[]( const size_t& index ) const; + bool operator==( const QuarkState& rhs ) const; + bool operator!=( const QuarkState& rhs ) const; + int operator[]( const size_t& index ) const; }; class QuarkContent @@ -38,9 +38,8 @@ namespace AmpGen std::vector m_quarks; public: QuarkContent(); - QuarkContent( const std::string& str ){ initFromString(str); } + explicit QuarkContent( const std::string& str ); void antiThis(); - void initFromString( const std::string& str ); void print( std::ostream& os = std::cout ) const; size_t size() const; bool compatible( const QuarkContent& other ) const; @@ -50,8 +49,8 @@ namespace AmpGen QuarkContent operator- ( const QuarkContent& rhs ) const; bool operator==( const QuarkContent& rhs ) const; bool operator!=( const QuarkContent& rhs ) const; - QuarkState operator[]( const size_t& index) const; - std::vector quarks() const; + QuarkState operator[]( const size_t& index) const; + const std::vector& quarks() const; }; std::ostream& operator<<( std::ostream& st, const QuarkState& qc ); std::ostream& operator<<( std::ostream& st, const QuarkContent& qc ); diff --git a/AmpGen/RecursivePhaseSpace.h b/AmpGen/RecursivePhaseSpace.h index 073a21ae7d7..bf71534a906 100644 --- a/AmpGen/RecursivePhaseSpace.h +++ b/AmpGen/RecursivePhaseSpace.h @@ -21,35 +21,43 @@ namespace AmpGen { class Particle; class Event; - + /** @class RecursivePhaseSpace + @brief Generator of events with more complex topologies. + @decription Generates events in the phase space of a decay with one-or-more quasistable products + that are further decayed, where these quasistable products are suitably long-lived + that their propagators can be assumed to be delta-functions, i.e. particles such as + @f$ \Lambda^0 , {K_\rm{S}}^0 @f$ etc. Such a process has a natural factorisation into + each of these steps. For each of the decays of a quasistable particle, the PhaseSpace + generator is used, which is itself based heavily on TGenPhaseSpace. + */ class RecursivePhaseSpace { private: struct Node { - std::string name; - int sink = {-1}; + std::string name = {""}; + int sink = {-1}; std::shared_ptr decayProds = {nullptr}; - Node( const std::string& _name ) : name( _name ) {}; + explicit Node( const std::string& _name ) : name( _name ) {}; }; public: - RecursivePhaseSpace(const EventType& type); + explicit RecursivePhaseSpace(const EventType& type); RecursivePhaseSpace(const Particle& decayChain, const EventType& type, TRandom* rndm = gRandom); std::vector getFinalStates(); void print( const size_t& offset = 0 ) const; void setRandom( TRandom* rand ); - AmpGen::Event makeEvent( const size_t& cacheSize = 0 ); + Event makeEvent(); size_t size() const; EventType eventType() const ; + void provideEfficiencyReport(const std::vector& report){} private: PhaseSpace m_phsp; - unsigned int m_totalSize; - std::string m_name; + unsigned m_totalSize = {0}; + std::string m_name = {""}; EventType m_eventType; std::vector m_nodes; - }; } // namespace AmpGen diff --git a/AmpGen/SimPDF.h b/AmpGen/SimPDF.h index ba46838a76b..ad47ef00d64 100644 --- a/AmpGen/SimPDF.h +++ b/AmpGen/SimPDF.h @@ -7,23 +7,25 @@ namespace AmpGen { class SimFit { - std::vector> m_pdfs; + public: + SimFit() = default; + double getVal() + { + double LL = 0; + for ( auto& pdf : m_pdfs ) LL += pdf(); + return LL; + } - public: - SimFit() {} - double getVal() - { - double LL = 0; - for ( auto& pdf : m_pdfs ) LL += pdf(); - return LL; - } + template + void add( PDF& pdf ) + { + INFO( "Adding " << &pdf << " to sim fit" ); + m_pdfs.emplace_back( [&pdf]() -> double { return pdf.getVal(); } ); + } + + private: + std::vector> m_pdfs; - template - void add( PDF& pdf ) - { - INFO( "Adding " << &pdf << " to sim fit" ); - m_pdfs.emplace_back( [&pdf]() -> double { return pdf.getVal(); } ); - } }; } // namespace AmpGen diff --git a/AmpGen/Simplify.h b/AmpGen/Simplify.h index 5ecdc59be87..882d081ac9f 100644 --- a/AmpGen/Simplify.h +++ b/AmpGen/Simplify.h @@ -8,6 +8,9 @@ #include "AmpGen/Expression.h" namespace AmpGen { + + Expression Simplify(const Expression& expression ); + class NormalOrderedExpression { public: struct Term { @@ -31,7 +34,6 @@ namespace AmpGen { std::vector m_terms; bool m_expandSubTrees; }; - Expression Simplify(const Expression& expression ); } #endif diff --git a/AmpGen/Spline.h b/AmpGen/Spline.h index bed74747e21..3556e80b823 100644 --- a/AmpGen/Spline.h +++ b/AmpGen/Spline.h @@ -12,7 +12,6 @@ #include "AmpGen/Expression.h" #include "AmpGen/CacheTransfer.h" #include "AmpGen/Types.h" -#include "TMatrixDUtilsfwd.h" #include "TMatrixTBase.h" #include "TMatrixD.h" @@ -24,54 +23,50 @@ namespace AmpGen{ class SplineTransfer : public CacheTransfer { - private: - TMatrixD m_transferMatrix; - std::vector m_parameters; - unsigned int m_nKnots; - double m_min; - double m_max; - unsigned int m_address; + public: + SplineTransfer(); + SplineTransfer( const SplineTransfer& other ); + SplineTransfer( const size_t& address, const std::string& name, const unsigned int& N, const double& min, const double& max ); + void transfer( CompiledExpressionBase* destination ) override; + bool isConfigured(); + void set( const unsigned int& N, AmpGen::MinuitParameter* f ); + void set( const unsigned int& N, const double& value ); + void print() const override; + size_t size() const override { return 2*m_nKnots; } - public: - SplineTransfer(); - SplineTransfer( const SplineTransfer& other ); - SplineTransfer( const unsigned int& address, const unsigned int& N, const double& min, const double& max ); - void transfer( CompiledExpressionBase* destination ) override; + private: + TMatrixD m_transferMatrix; + std::vector m_parameters; + size_t m_nKnots; + double m_min; + double m_max; + }; - bool isConfigured(); + class Spline : public IExpression { + public: + Spline( const std::string& name, + const size_t& nKnots, + const double& min, + const double& max ); - void set( const unsigned int& N, AmpGen::MinuitParameter* f ); - void set( const unsigned int& N, const double& value ); + Spline( const Spline& spline, const Expression& x, DebugSymbols* db =nullptr ); + void resolve( ASTResolver& resolver ) const override ; + std::string to_string(const ASTResolver* resolver=nullptr) const override; + operator Expression() ; + complex_t operator()() const override ; + Expression operator()( const Expression& x, DebugSymbols* db); + Expression eval(DebugSymbols* db=nullptr) const ; - void setAddress( const unsigned int& address ); - void print() const override; - unsigned int address() const override { return m_address ; } - unsigned int size() const override { return 2*m_nKnots ; } - }; - - struct Spline : public IExpression { - Array m_points; - std::string m_name; - size_t m_nKnots; - double m_min; - double m_max; - Expression m_x; - Expression m_eval; - Spline( const std::string& name, - const size_t& nKnots, - const double& min, - const double& max ); - - Spline( const Spline& spline, const Expression& x ); - void resolve( ASTResolver& resolver ) override ; - std::string to_string(const ASTResolver* resolver=nullptr) const override; - operator Expression() ; - complex_t operator()() const override ; - Expression operator()( const Expression& x ); - Expression eval() const ; + Array m_points; + std::string m_name; + size_t m_nKnots; + double m_min; + double m_max; + Expression m_x; + Expression m_eval; }; Expression getSpline( const std::string& name, const AmpGen::Expression& x, const std::string& arrayName, - AmpGen::DebugSymbols* dbexpressions = nullptr, const bool& continueSpline = false ); + AmpGen::DebugSymbols* dbexpressions = nullptr, const bool& continueSpline = false ); } #endif diff --git a/AmpGen/Store.h b/AmpGen/Store.h new file mode 100644 index 00000000000..92bad6b08b8 --- /dev/null +++ b/AmpGen/Store.h @@ -0,0 +1,178 @@ +#ifndef AMPGEN_STORE_H +#define AMPGEN_STORE_H + +#include "AmpGen/simd/utils.h" +#include "AmpGen/EventList.h" +#ifdef _OPENMP +#include +#endif + +namespace AmpGen { + + enum Alignment { + SoA, AoS + }; + + template class Store + { + public: + Store( const size_t& nEntries=0, const size_t& nFields=0) : + m_nEntries(nEntries), + m_nBlocks(utils::aligned_size( nEntries ) / utils::size::value ), + m_nFields(nFields), + m_store(m_nBlocks * m_nFields) {} + + template + void addFunctor( const functor_type& functor ) + { + if( m_index.count(functor.name()) == 0 ) + { + auto vsize = functor.returnTypeSize() / sizeof(stored_type); + DEBUG("Registering: " << functor.name() << " field = " << m_nFields << " " << functor.returnTypeSize() << " / " << sizeof(stored_type) ); + m_index[ functor.name() ] = std::make_pair(m_nFields, vsize); + m_nFields += vsize; + } + } + template void allocate( const size_t& nEntries, const std::vector& functors) + { + for(const auto& functor : functors) addFunctor( functor ); + m_nEntries = nEntries; + m_nBlocks = utils::aligned_size(nEntries)/utils::size::value; + m_store.resize(m_nBlocks * m_nFields); + } + template ::value>::type > + void allocate( const size_t& nEntries, const functor_type& functor) + { + addFunctor(functor); + m_nEntries = nEntries; + m_nBlocks = utils::aligned_size(nEntries)/utils::size::value; + m_store.resize(m_nBlocks * m_nFields); + } + + template Store( const size_t& nEntries, const std::vector& functors) + { + allocate(nEntries, functors); + } + template ::value>::type> + Store( const size_t& nEntries, const functor_type& functor) + { + allocate( nEntries, {functor}); + } + + inline stored_type operator[]( const size_t& index ) const { return m_store[index]; } + inline stored_type& operator[]( const size_t& index ) { return m_store[index]; } + template unsigned find( const T& t ) const { return m_index.find( t.name() )->second.first; } + + inline size_t size() const { return m_nEntries; } + inline size_t nBlocks() const { return m_nBlocks; } + inline size_t nFields() const { return m_nFields; } + inline size_t aligned_size() const { return m_nBlocks * utils::size::value ; } + inline const stored_type& operator()(const size_t& index, const size_t& field) const + { + if constexpr( align == Alignment::SoA ) return m_store[ field * m_nBlocks + index] ; + else return m_store[index*m_nFields+field]; + } + template + inline const return_type get(const size_t& index, const size_t& field ) const + { + return utils::at( operator()( index / utils::size::value, field ), index % utils::size::value ); + } + inline const stored_type* data() const { return m_store.data(); } + inline stored_type* data() { return m_store.data() ;} + inline stored_type& operator()(const size_t& index, const size_t& field) + { + if constexpr( align == Alignment::SoA ) return m_store[ field * m_nBlocks + index] ; + else return m_store[index*m_nFields+field]; + } + + void resize(const size_t& nEntries, const size_t& nFields ) + { + m_nEntries = nEntries; + m_nBlocks = utils::aligned_size(nEntries)/utils::size::value; + m_nFields = nFields; + m_store.resize(m_nBlocks * m_nFields); + m_index.clear(); + } + void clear() { m_store.clear(); m_index.clear() ; } + void store( const size_t& event0, const size_t& index0, const stored_type* item, const unsigned N = 1 ) + { + if constexpr( align == Alignment::AoS ) + std::memcpy( &(*this)(event0, index0) , item, N * sizeof( stored_type ) ); + else + { + for( unsigned i = 0 ; i != N ; ++i ) (*this)(event0, index0 +i ) = item[i]; + } + } + + template void update(const Store& is, const functor_type& fcn) + { + auto f = m_index.find( fcn.name() ); + if( f == m_index.end() ) FATAL("Expression: " << fcn.name() << " is not registed"); + auto [p0, s] = f->second; + DEBUG("Updating: " << fcn.name() << " index = " << p0 << " size_of = " << s << " on store: " << is.size() << " blocks = " << is.nBlocks() << " fields = " << is.nFields () ); + if constexpr( align == Alignment::AoS ) + { + if constexpr( std::is_same< typename functor_type::return_type, void >::value ) + fcn.batch(aligned_size(), is.nFields(), m_nFields, nullptr, m_store.data() + p0, 1, fcn.externBuffer().data(), is.data()); + if constexpr( ! std::is_same< typename functor_type::return_type, void >::value ) + fcn.batch(aligned_size(), is.nFields(), m_nFields , m_store.data() + p0 , fcn.externBuffer().data(), is.data()); + } + else + { + if constexpr( std::is_same< typename functor_type::return_type, void >::value) + fcn.batch(aligned_size(), is.nFields(), 1, nullptr, m_store.data() + p0*m_nBlocks, m_nBlocks, fcn.externBuffer().data(), is.data() ); + else + fcn.batch(aligned_size(), is.nFields(), 1 , m_store.data() + p0*m_nBlocks , fcn.externBuffer().data(), is.data() ); + } + } + template void update( const EventList& events, const functor_type& fcn ) + { + auto f = m_index.find( fcn.name() ); + if( f == m_index.end() ) FATAL("Expression: " << fcn.name() << " is not registed"); + //auto& [p0, s] = f->second; /// bug in the C++ standard. Such fun. + auto p0 = f->second.first; + auto s = f->second.second; + DEBUG("Updating: " << fcn.name() << " index = " << p0 << " size_of = " << s << " on store: " << size() << " blocks = " << nBlocks() << " fields = " << nFields () ); + + if constexpr( std::is_same< typename functor_type::return_type, void >::value ) + { + + #ifdef _OPENMP + #pragma omp parallel for + #endif + for ( size_t evt = 0; evt < events.size(); ++evt ) + { + std::vector buffer(s); + fcn(buffer.data(), 1, fcn.externBuffer().data(), events[evt].address() ); + store(evt, p0, buffer.data(), s ); + } + } + else { + #ifdef _OPENMP + #pragma omp parallel for + #endif + for ( size_t evt = 0; evt < events.size(); ++evt ) + { + auto tmp = fcn( events[evt].address() ); + store( evt, p0, &tmp, s); + } + } + } + + private: + size_t m_nEntries{0}; /// Number of entries, i.e. number of events + size_t m_nBlocks {0}; /// Number of blocks, i.e. number of entries aligned to the size, divided by block size. + size_t m_nFields {0}; /// Number of fields per entry + std::vector m_store; + std::map> m_index; + }; +} +#if DEBUG_LEVEL ==1 +using aos_store = AmpGen::Store; +using soa_store = AmpGen::Store; + +ENABLE_DEBUG(aos_store) +ENABLE_DEBUG(soa_store) +#endif + +#endif diff --git a/AmpGen/SumPDF.h b/AmpGen/SumPDF.h index 2cdcea39e62..832d5d68860 100644 --- a/AmpGen/SumPDF.h +++ b/AmpGen/SumPDF.h @@ -1,74 +1,159 @@ #ifndef AMPGEN_SUMPDF_H #define AMPGEN_SUMPDF_H -#include "AmpGen/EventList.h" #include "AmpGen/IExtendLikelihood.h" #include "AmpGen/MetaUtils.h" #include "AmpGen/MsgService.h" #include "AmpGen/ProfileClock.h" - +#include "AmpGen/KeyedFunctors.h" #include -/* A SumPDF is the log-likelihood of the form - -2*LL(event) = -2*log( Sum( i, P_i(event) ) ) - Where P_i are some probability density functions - The sum is variadically unrolled at compile time, i.e. the wrapper - is the same for 1..N pdfs. The unrolling should be properly inlined, - hence N can be reasonably large with out afflicting either - compile time or binary size. - */ + +#if ENABLE_AVX + #include "AmpGen/simd/utils.h" +#endif namespace AmpGen { - template + class EventList; + class EventListSIMD; + /** @class SumPDF + @brief A pdf that contains one or more terms. + + A pdf with a probability of the form + @f[ + P(\psi) = \sum_{j} \mathcal{P}_j (\psi), + @f] + where @f$ \mathcal{P}_j(\psi) @f$ are some normalised probability density functions + as a function of position in the phase space @f$ \psi @f$ + , and the sum is over the different terms, typically a signal term and then a number of background terms. + The pdf is also equipped with a log-likelihood of the form: + @f[ + -2 \mathcal{L} = - 2 \sum_{i} \log \left( \sum_{j} \mathcal{P}_j \left(\psi_i\right) \right) + @f] + and the sum over @f$ i @f$ is over some dataset. + This combined functionality is largely historical and the two roles should be separated at some point in the future. + The sum is variadically unrolled at compile time, i.e. the wrapper + is the same for 1..N pdfs. The unrolling should be properly inlined, + hence N can be reasonably large with out afflicting either + compile time or binary size. It isn't primarily used as PDF, as its primary function is + as a likelihood via function getVal(). + Typically constructed using either the make_pdf helper function or make_likelihood helper function. */ + template class SumPDF { + private: + typedef typename eventListType::value_type eventValueType; ///< The value type stored in the eventListType + std::tuple m_pdfs; ///< The tuple of probability density functions + const eventListType* m_events = {nullptr}; ///< The event list to evaluate likelihoods on + public: - SumPDF( const TYPES&... _pdfs ) : m_pdfs( std::tuple( _pdfs... ) ) {} - std::tuple m_pdfs; - EventList* m_events; + /// Default Constructor + SumPDF() = default; + + /// Constructor from a set of PDF functions + SumPDF( const pdfTypes&... pdfs ) : m_pdfs( std::tuple( pdfs... ) ) {} + + /// Returns negative twice the log-likelihood for this PDF and the given dataset. - std::tuple pdfs() const { return m_pdfs; } - double getVal() { -// ProfileClock pc; - double LL = 0; - for_each( m_pdfs, []( auto& f ) { f.prepare(); } ); -// pc.stop(); -// ProfileClock eval; - #pragma omp parallel for reduction( +: LL ) - for ( unsigned int i = 0; i < m_events->size(); ++i ) { - auto prob = ((*this))(( *m_events)[i] ); - LL += log(prob); + if constexpr( std::is_same::value ) + { + double LL = 0; + for_each( m_pdfs, []( auto& f ) { f.prepare(); } ); + #pragma omp parallel for reduction( +: LL ) + for ( unsigned int i = 0; i < m_events->size(); ++i ) { + auto prob = ((*this))(( *m_events)[i] ); + auto w = (*m_events)[i].weight(); + LL += w*log(prob); + } + return -2 * LL; } -// eval.stop(); -// std::cout << "t [prepare] = " << pc << "; t[eval] = " << eval << "ms" << std::endl; - return -2 * LL; + #if ENABLE_AVX + if constexpr( std::is_same::value ) + { + float_v LL = 0.f; + for_each( m_pdfs, []( auto& f ) { f.prepare(); } ); + #pragma omp parallel for reduction( +: LL ) + for ( size_t block = 0; block < m_events->nBlocks(); ++block ) + { + LL += m_events->weight(block) * AVX::log(this->operator()(m_events->block(block), block)); + } + return -2 * utils::sum_elements(LL); + } + #endif + } + /// Returns the probability for the given event. + float_v operator()( const float_v* evt , const unsigned block) + { + float_v prob = 0.f; + for_each( this->m_pdfs, [&prob, &evt,block]( const auto& f ) { prob += f(evt, block); } ); + return prob; } - double operator()( const Event& evt ) + /// Returns the probability for the given event. + double operator()( const eventValueType& evt ) { double prob = 0; - for_each( this->m_pdfs, [&prob, &evt]( auto& f ) { prob += f.prob( evt ); } ); + for_each( this->m_pdfs, [&prob, &evt]( const auto& f ) { prob += f(evt); } ); return prob; } - void setEvents( EventList& events ) + + /// Sets the events to be summed over in the likelihood + void setEvents( eventListType& events ) { m_events = &events; for_each( m_pdfs, [&events]( auto& f ) { f.setEvents( events ); } ); } - template - void forEach( const FCN& fcn ) - { - for_each( m_pdfs, fcn ); + /// Returns the number of PDFs contained by this function + std::size_t nPDFs() const { return sizeof...(pdfTypes); } + + /// Returns the tuple of PDFs used by this function + std::tuple pdfs() const { return m_pdfs; } + + std::function evaluator(const eventListType* events) const + { + std::vector values( events->size() ); + for_each( this->m_pdfs, [events, &values](const auto& pdf ) mutable { + auto eval = pdf.evaluator(events); + for( unsigned i = 0; i != events->size(); ++i ) values[i] += eval( events->at(i) ); + } ); + return arrayToFunctor(values); + } + KeyedFunctors componentEvaluator(const eventListType* events) const + { + KeyedFunctors view; + for_each( this->m_pdfs, [&view, &events]( const auto& pdf) mutable { + auto eval = pdf.evaluator(events); + view.add([eval](const auto& event){ return eval(event) ; } , type_string(pdf), "" ); + } ); + return view; } - std::size_t nPDFs() { return sizeof...( TYPES ); } }; - template - auto make_pdf( PDFS&&... pdfs ) + /** @function make_pdf + + Usage is + \code{cpp} + auto pdf = make_pdf( signal, bkg1, ... ); + \endcode + which returns a PDF that is the sum of the signal and bkg1 etc. The sum is also equipped with a likelihood, which can be used by setting + the data for the PDF. + Therefore, named SumPDF, it is useful to use this function to get a likelihood for a PDF containing a single term (i.e. signal or background only). + */ + template + auto make_pdf( pdfTypes&&... pdfs ) + { + //return SumPDF( std::forward( pdfs )... ); + return SumPDF( pdfs... ); + } + + template + auto make_likelihood( eventListType& events, pdfTypes&&... pdfs ) { - return SumPDF( std::forward( pdfs )... ); + auto rt = SumPDF( std::forward( pdfs )... ); + rt.setEvents(events); + return rt; } } // namespace AmpGen diff --git a/AmpGen/Tensor.h b/AmpGen/Tensor.h index f79646e9c1e..d5a13ca827a 100644 --- a/AmpGen/Tensor.h +++ b/AmpGen/Tensor.h @@ -15,11 +15,11 @@ #include "AmpGen/Types.h" #define ADD_DEBUG_TENSOR( X, Y ) \ - if ( Y != nullptr ) for( size_t i = 0 ; i < X.size(); ++i ) \ - Y->emplace_back( std::string(#X) + Tensor::coordinates_to_string( X.coords(i) ) , X[i] ); + if ( Y != nullptr ) for( unsigned i = 0 ; i < Tensor(X).size(); ++i ) \ + Y->emplace_back( std::string(#X) + Tensor::coordinates_to_string( Tensor(X).coords(i) ) , Tensor(X)[i] ); #define ADD_DEBUG_TENSOR_NAMED( X, Y, Z ) \ - if ( Y != nullptr ) for( size_t i = 0 ; i < X.size(); ++i ) \ + if ( Y != nullptr ) for( unsigned i = 0 ; i < X.size(); ++i ) \ Y->emplace_back( Z + Tensor::coordinates_to_string( X.coords(i) ) , X[i] ); namespace AmpGen @@ -34,52 +34,51 @@ namespace AmpGen private: std::shared_ptr m_ptr; bool m_isUpper; - std::string name; public: bool operator==( const Tensor::Index& other ) const { return m_ptr.get() == other.m_ptr.get(); } bool operator!=( const Tensor::Index& other ) const { return m_ptr.get() != other.m_ptr.get(); } bool isUpper() const { return m_isUpper; }; - Index( bool isUpper = false ) : m_ptr( new int() ), m_isUpper( isUpper ) {} + explicit Index( bool isUpper = false ) : m_ptr( new int() ), m_isUpper( isUpper ) {} Index( const std::shared_ptr& index, bool isUpper = false ) : m_ptr( index ), m_isUpper( isUpper ) {} Index operator-() const { return Index( m_ptr, !m_isUpper ); } friend std::ostream& operator <<( std::ostream& out, const Index& index ); }; Tensor(); - Tensor(const std::vector& elements); - Tensor(const std::vector& dim); + explicit Tensor(const std::vector& elements); + explicit Tensor(const std::vector& dim); template Tensor(const std::initializer_list& elements, - const std::vector& dim) : m_dim(dim) + const std::vector& dim) : m_dim(dim) { setupCoordinates(); for ( auto& x : elements ) append( x ); } template Tensor(const std::vector& elements, - const std::vector& dim) : m_dim(dim) + const std::vector& dim) : m_dim(dim) { setupCoordinates(); for ( auto& x : elements ) append( x ); } /// Low level access of elements, either by coordinates or by index /// - Expression& operator[]( const size_t& i ); - Expression& operator[]( const std::vector& co ); - const Expression& operator[]( const size_t& i ) const; - const Expression& operator[]( const std::vector& co ) const; + Expression& operator[]( const unsigned& i ); + Expression& operator[]( const std::vector& co ); + const Expression& operator[]( const unsigned& i ) const; + const Expression& operator[]( const std::vector& co ) const; - Expression get( const size_t& co ); - Expression get( const size_t& co ) const; - Expression get( const std::vector& _co ) const; + Expression get( const unsigned& co ); + Expression get( const unsigned& co ) const; + Expression get( const std::vector& _co ) const; /// TensorProxy access to class members /// High level access is done via these commands, i.e. () operators - Expression& operator()( const size_t& a ) { return Tensor::operator[]( {a} ) ; } - Expression& operator()( const size_t& a, const size_t& b) { return Tensor::operator[]( {a,b} ) ; } - const Expression operator()( const size_t& a ) const { return Tensor::operator[]( {a} ) ; } - const Expression& operator()( const size_t& a, const size_t& b) const { return Tensor::operator[]( {a,b} ) ; } + Expression& operator()( const unsigned& a ) { return Tensor::operator[]( {a} ) ; } + Expression& operator()( const unsigned& a, const unsigned& b) { return Tensor::operator[]( {a,b} ) ; } + const Expression operator()( const unsigned& a ) const { return Tensor::operator[]( {a} ) ; } + const Expression& operator()( const unsigned& a, const unsigned& b) const { return Tensor::operator[]( {a,b} ) ; } TensorProxy operator()( const Tensor::Index& a ) const; TensorProxy operator()( const Tensor::Index& a, const Tensor::Index& b ) const; @@ -91,57 +90,54 @@ namespace AmpGen Tensor operator-() const; void st(const bool simplify=false); - bool rankMatches( const Tensor& other ); - void imposeSymmetry( size_t indexA, size_t indexB); - void imposeSymmetry( std::vector indices ); + void imposeSymmetry( unsigned indexA, unsigned indexB); + void imposeSymmetry( std::vector indices ); Tensor Invert() const; std::string to_string(const ASTResolver* resolver=nullptr) const ; - int metricSgn( const std::vector& coordinates ) const; - int metricSgn( const size_t& index ) const; + int metricSgn( const std::vector& coordinates ) const; + int metricSgn( const unsigned& index ) const; void append( const Expression& expression ); void append( const real_t& value ); void append( const complex_t& value ); void append( const std::string& value ); void setupCoordinates(); - size_t nDim() const; - size_t rank() const; - size_t size() const; - size_t index( const std::vector& _co ) const; - size_t symmetrisedIndex( const std::vector& _co ) const; - size_t nElements() const; + unsigned nDim() const; + unsigned rank() const; + unsigned size() const; + unsigned index( const std::vector& _co ) const; + unsigned symmetrisedIndex( const std::vector& _co ) const; + unsigned nElements() const; - const std::vector coords( const size_t& index ) const; - const std::vector& dims() const { return m_dim; } + const std::vector coords( const unsigned& index ) const; + const std::vector& dims() const { return m_dim; } const std::string dimString() const ; void print(const bool& eval = false) const; - const std::vector& uniqueElements() const { - return m_uniqueElements; - } + const std::vector& uniqueElements() const { return m_uniqueElements; } void operator+=( const Tensor& rhs ); void operator-=( const Tensor& rhs ); Tensor conjugate() const; - static std::vector index_to_coordinates( const size_t& index, const std::vector& dim ); - static size_t coordinates_to_index( const std::vector& coords, const std::vector& dim ); - static std::string coordinates_to_string( const std::vector& coordinates ); + static std::vector index_to_coordinates( const unsigned& index, const std::vector& dim ); + static unsigned coordinates_to_index( const std::vector& coords, const std::vector& dim ); + static std::string coordinates_to_string( const std::vector& coordinates ); template - static std::vector dim( const ARGS&... args ){ - std::vector rt; + static std::vector dim( const ARGS&... args ){ + std::vector rt; auto up = std::tuple(args...); - for_each(up, [&rt]( auto& f ) { rt.emplace_back(f); } ); + for_each(up, [&rt]( const unsigned& f ) { rt.emplace_back(f); } ); return rt; - } + } private: - std::vector m_dim; - std::vector m_symmetrisedCoordinates; - std::vector m_uniqueElements; + std::vector m_dim; + std::vector m_symmetrisedCoordinates; + std::vector m_uniqueElements; std::vector m_elements; }; @@ -173,39 +169,39 @@ namespace AmpGen public: TensorExpression( const Tensor& tensor ); std::string to_string(const ASTResolver* resolver) const override; - void resolve( ASTResolver& resolver ) override; + void resolve( ASTResolver& resolver ) const override; complex_t operator()() const override; operator Expression() const; - + Tensor tensor() const { return m_tensor;} private: Tensor m_tensor; }; - Tensor operator+( const Tensor& t1, const Tensor& t2 ); - Tensor operator-( const Tensor& t1, const Tensor& t2 ); - Tensor operator/( const Tensor& t1, const Expression& t2 ); - Tensor operator*( const Expression& t1, const Tensor& t2 ); - Tensor operator*( const Tensor& t1, const Expression& t2 ); + Tensor operator+(const Tensor&, const Tensor&); + Tensor operator-(const Tensor&, const Tensor&); + Tensor operator/(const Tensor&, const Expression&); + Tensor operator*(const Expression&, const Tensor&); + Tensor operator*(const Tensor&, const Expression&); - Tensor operator/( const Tensor& t1, const double& t2 ); - Tensor operator*( const double& t1, const Tensor& t2 ); - Tensor operator*( const Tensor& t1, const double& t2 ); + Tensor operator/(const Tensor&, const double&); + Tensor operator*(const double&, const Tensor&); + Tensor operator*(const Tensor&, const double&); - TensorProxy operator*( const TensorProxy& t1, const TensorProxy& t2 ); - TensorProxy operator+( const TensorProxy& t1, const TensorProxy& t2 ); - TensorProxy operator-( const TensorProxy& t1, const TensorProxy& t2 ); + TensorProxy operator*(const TensorProxy&, const TensorProxy&); + TensorProxy operator+(const TensorProxy&, const TensorProxy&); + TensorProxy operator-(const TensorProxy&, const TensorProxy&); - TensorProxy operator/( const TensorProxy& t1, const Expression& t2 ); - TensorProxy operator*( const Expression& t1, const TensorProxy& t2 ); - TensorProxy operator*( const TensorProxy& t1, const Expression& t2 ); + TensorProxy operator/(const TensorProxy&, const Expression& ); + TensorProxy operator*(const Expression& , const TensorProxy&); + TensorProxy operator*(const TensorProxy&, const Expression& ); - TensorProxy operator/( const TensorProxy& t1, const double& t2 ); - TensorProxy operator*( const double& t1, const TensorProxy& t2 ); - TensorProxy operator*( const TensorProxy& t1, const double& t2 ); + TensorProxy operator/(const TensorProxy&, const double&); + TensorProxy operator*(const double& , const TensorProxy&); + TensorProxy operator*(const TensorProxy&, const double&); - Tensor Identity( const size_t& rank = 4 ); + Tensor Identity( const unsigned& rank = 4 ); - const Tensor LeviCivita( const size_t& rank = 4); + const Tensor LeviCivita( const unsigned& rank = 4); Expression dot( const Tensor& A, const Tensor& B ); std::ostream& operator <<( std::ostream& out, const Tensor::Index& index ); diff --git a/AmpGen/ThreadPool.h b/AmpGen/ThreadPool.h index 7604c971ddb..589a06e1422 100644 --- a/AmpGen/ThreadPool.h +++ b/AmpGen/ThreadPool.h @@ -3,8 +3,8 @@ /* @class ThreadPool ThreadPool.h AmpGen/ThreadPool.h * Thread pool implementation taken from https://github.com/progschj/ThreadPool - * Modified to allow explicit clearing of queues. - * A single static thread pool exists that can be used as a sceduler. + * Modified to allow explicit clearing of queues, and to make + * the constructor explicit * * Copyright (c) 2012 Jakob Progsch, Václav Zeman * @@ -48,27 +48,12 @@ namespace AmpGen class ThreadPool { public: - static size_t nThreads; - + explicit ThreadPool(const size_t& nt); ~ThreadPool(); - - template static auto schedule( F&& f, Args&&... args ) -> std::future::type> - { - return getMe()->enqueue( f, args... ); - } - template auto enqueue(F&& f, Args&&... args) -> std::future::type>; - - ThreadPool(const size_t& nt); void waitForStoppedThreads(); + private: - static ThreadPool* gThreadPool; - static ThreadPool* getMe() - { - if ( !gThreadPool ) - gThreadPool = new ThreadPool(ThreadPool::nThreads); - return gThreadPool; - } std::vector m_workers; std::queue> m_tasks; std::mutex m_queue_mutex; diff --git a/AmpGen/ThreeBodyCalculators.h b/AmpGen/ThreeBodyCalculators.h index 4ff024ede6a..d7b24724dd4 100644 --- a/AmpGen/ThreeBodyCalculators.h +++ b/AmpGen/ThreeBodyCalculators.h @@ -10,7 +10,6 @@ class TGraph; namespace AmpGen { - class MinuitParameterSet; class ThreeBodyCalculator @@ -19,12 +18,12 @@ namespace AmpGen struct PartialWidth { CoherentSum fcs; DalitzIntegrator integrator; - CompiledExpression< std::complex, const real_t*, const real_t* > totalWidth; + CompiledExpression totalWidth; EventType type; - std::vector, const real_t*, const real_t*>> partialWidths; + std::vector> partialWidths; double getWidth( const double& m ); PartialWidth( const EventType& type, MinuitParameterSet& mps ); - Expression spinAverageMatrixElement( const std::vector>>& elements, + Expression spinAverageMatrixElement( const std::vector >& elements, DebugSymbols* msym ); }; Expression calculateSAME( const std::string& particle ); diff --git a/AmpGen/Transform.h b/AmpGen/Transform.h index 576e56e987c..1c703a7b056 100644 --- a/AmpGen/Transform.h +++ b/AmpGen/Transform.h @@ -41,13 +41,16 @@ namespace AmpGen { class TransformSequence { public: - TransformSequence() = default; + TransformSequence(); + TransformSequence( const Transform& transform ); + TransformSequence( const TransformSequence& t1, const TransformSequence& t2); + TransformSequence( const Transform& t1, const Transform& t2); TransformSequence inverse() const; - Tensor operator()( const Transform::Representation& repr ) const; + Tensor operator()( const Transform::Representation& repr ) const ; Tensor operator()( const Tensor& tensor, const Transform::Representation& repr=Transform::Representation::Vector ) const; - void add( const Transform& transform ); - void add( const TransformSequence& transform ); + void push_back( const Transform& transform ); + void push_back( const TransformSequence& transform ); void stepThrough( const Tensor& tensor, const Transform::Representation& repr = Transform::Representation::Vector ); @@ -58,9 +61,14 @@ namespace AmpGen { std::vector::const_iterator end() const { return m_transforms.cend(); } std::vector::iterator begin() { return m_transforms.begin(); } std::vector::iterator end() { return m_transforms.end(); } + unsigned size() const { return m_transforms.size(); } + private: + void buildCache(); std::vector m_transforms; + std::array m_cache; }; + } #endif diff --git a/AmpGen/TreePhaseSpace.h b/AmpGen/TreePhaseSpace.h new file mode 100644 index 00000000000..3c708882f5d --- /dev/null +++ b/AmpGen/TreePhaseSpace.h @@ -0,0 +1,100 @@ +#ifndef AMPGEN_TREEPHASESPACE_H +#define AMPGEN_TREEPHASESPACE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AmpGen/EventType.h" +#include "AmpGen/PhaseSpace.h" +#include "AmpGen/Particle.h" + +#include +#include + +namespace AmpGen +{ + class Particle; + class Event; + /** @class TreePhaseSpace + @brief Generator of events where the phase space is decomposed into a series of subtrees. + @decription Generates events using the decomposition of the phase space + into a series of two-body phase spaces, where the invariant mass of the two-body space + can be generated according to, for example, a simplified Breit-Wigner model. + This can then be used to generate a more complex model using accept-reject, which + allows for a much more efficient generation of narrow peaks. + + Currently, each of the available channels is given the same weight relative to phase space, + ideally feedback could be given from the generator phase to focus on the more efficient channels, + i.e. those that have larger contributions to the full amplitude. + */ + class TreePhaseSpace + { + + public: + struct Vertex + { + enum Type { BW, Flat, Stable, QuasiStable}; + Vertex() = default; + Vertex(const Particle& particle, const double& min); + Vertex(const Particle& particle, const double& min, const double& max); + double p() const; + double weight() const; + double genPdf(const Event& event) const; + void generate(); + void print(const unsigned& offset = 0) const; + void place(Event& event); + Event event(const unsigned& eventSize); + void generateFullEvent(); + void setRhoMax(); + void setRandom(TRandom3* rnd); + static Vertex make(const Particle& particle, Vertex* parent = nullptr); + Particle particle; + double min = {0}; + double max = {0}; + double phiMin = {0}; + double phiMax = {0}; + Type type = {Type::BW}; + unsigned index = {999}; + double bwMass = {0}; + double bwWidth = {0}; + double s = {0}; + std::shared_ptr left = {nullptr}; + std::shared_ptr right = {nullptr}; + TRandom3* rand = {nullptr}; + std::vector indices; + TLorentzVector mom; + bool isMultiBody = {false}; + PhaseSpace phsp; /// multibody phase to resort to for non two-body decomposition; + }; + + explicit TreePhaseSpace(const EventType& type); + TreePhaseSpace(const Particle& decayChain, const EventType& type, TRandom* rndm = nullptr ); + TreePhaseSpace(const std::vector& decayChains, const EventType& type, TRandom* rndm = nullptr); + + void setRandom( TRandom* rand ); + Event makeEvent(); + size_t size() const; + EventType eventType() const ; + double genPdf( const Event& event) const ; + const Vertex& operator[](const unsigned i) const { return m_top[i]; } + + void provideEfficiencyReport(const std::vector& report); + private: + std::vector m_top; + TRandom3* m_rand = {nullptr}; + EventType m_type; ///< EventType to generate + std::discrete_distribution<> m_dice; ///< + std::vector m_weights; + std::vector m_generatorRecord; + std::mt19937 m_gen; + }; +} // namespace AmpGen + +#endif diff --git a/AmpGen/TreeReader.h b/AmpGen/TreeReader.h index a71f97d752d..86bea94c1e7 100644 --- a/AmpGen/TreeReader.h +++ b/AmpGen/TreeReader.h @@ -5,115 +5,106 @@ #include "TLeaf.h" #include "TTree.h" #include - +#include "AmpGen/MetaUtils.h" namespace AmpGen { - template - class TreeReader - { - private: - struct IReadBranch { - std::string name; - IReadBranch( const std::string& name = "" ) : name( name ) {} - virtual void* address() const = 0; - virtual void transfer() = 0; - virtual ~IReadBranch() = default; - }; - - template struct ReadBranch : public IReadBranch { - InputType thing; - OutputType* output; - void* address() const override { return (void*)&thing; } - ReadBranch( const std::string& name, OutputType* outputBranch ) : IReadBranch( name ), output( outputBranch ) {} - void transfer() override { *output = thing; } - }; - - template struct ReinterpretBranch : public IReadBranch { - InputType thing; - OutputType* output; - void* address() const override { return (void*)&thing; } - ReinterpretBranch( const std::string& name, OutputType* outputBranch ) : IReadBranch( name ), output( outputBranch ) {} - void transfer() override { *output = reinterpret_cast(thing); } - }; - - struct Branch { - OutputType* value; - Branch() : value( new OutputType() ) {} - ~Branch() { delete value; } - operator OutputType() const { return *value; } - operator OutputType&() { return *value; } - OutputType* operator&() { return value; } - }; + class TreeReader + { + private: + struct IReadBranch { + std::string name; + IReadBranch( const std::string& name = "" ) : name( name ) {} + virtual void* address() const = 0; + virtual void transfer() = 0; + virtual ~IReadBranch() = default; + }; - struct Iterator { - size_t m_position; - TreeReader* m_parent; - Iterator( const size_t& pos, TreeReader* parent ) : m_position( pos ), m_parent( parent ) {} - Iterator& operator++() - { - m_position++; - m_parent->getEntry( m_position ); - return *this; - } - bool operator==( const Iterator& rhs ) const { return m_position == rhs.m_position; } - bool operator!=( const Iterator& rhs ) const { return m_position != rhs.m_position; } - size_t operator*() const { return m_position; } - }; - TTree* tree; - bool ready; - std::vector branches; + template struct ReadBranch : public IReadBranch + { + InputType thing; + OutputType* output; + void* address() const override { return (void*)&thing; } + ReadBranch( const std::string& name, OutputType* outputBranch ) : IReadBranch( name ), output( outputBranch ) {} + void transfer() override { *output = thing; } + }; - public: - TreeReader( TTree* tree ) : tree( tree ) {} - void setBranch( const std::string& name, OutputType* ptr ) + template struct ReinterpretBranch : public IReadBranch + { + InputType thing; + OutputType* output; + void* address() const override { return (void*)&thing; } + ReinterpretBranch( const std::string& name, OutputType* outputBranch ) : IReadBranch( name ), output( outputBranch ) {} + void transfer() override { *output = reinterpret_cast(thing); } + }; + struct Iterator { + size_t m_position; + TreeReader* m_parent; + Iterator( const size_t& pos, TreeReader* parent ) : m_position( pos ), m_parent( parent ) {} + Iterator& operator++() { - IReadBranch* new_branch = nullptr; - TLeaf* leaf = tree->GetLeaf( name.c_str() ); - if( leaf == nullptr ){ - ERROR( "Leaf: " << name << " not found"); - return; - } - std::string branchType = leaf->GetTypeName(); - if( branchType == "Double_t" ) new_branch = new ReadBranch( name, ptr ); - if( branchType == "Float_t" ) new_branch = new ReadBranch( name, ptr ); - if( branchType == "Bool_t" ) new_branch = new ReadBranch( name, ptr ); - if( branchType == "Int_t" ) new_branch = new ReadBranch( name, ptr ); - if( branchType == "UInt_t" ) new_branch = new ReadBranch( name, ptr ); - if( branchType == "ULong64_t") new_branch = new ReadBranch( name, ptr ); - if( new_branch == nullptr ){ - ERROR( "Branch type:" << branchType << " not recognised" ); - return; - } - ready = false; - branches.push_back( new_branch ); + m_position++; + m_parent->getEntry( m_position ); + return *this; } - Branch bind( const std::string& name ) - { - Branch rt; - setBranch( name, &rt ); - return rt; + bool operator==( const Iterator& rhs ) const { return m_position == rhs.m_position; } + bool operator!=( const Iterator& rhs ) const { return m_position != rhs.m_position; } + size_t operator*() const { return m_position; } + unsigned pos() const { return m_position; } + }; + TTree* m_tree = {nullptr}; + bool m_ready = {false}; + std::vector m_branches = {}; + std::vector m_entryList = {}; + public: + template struct Proxy + { + OutputType* data; + Proxy() : data( new OutputType() ) {} + operator OutputType() const { return *data; } + ~Proxy(){ delete data ; } + }; + explicit TreeReader( TTree* tree ); + template Proxy make_proxy( const std::string& name ) + { + Proxy rt; + setBranch( name, rt.data ); + return rt; + } + template void setBranch( const std::string& name, OutputType& thing ) { + setBranch(name,&thing) ; } + template void setBranch( const std::string& name, OutputType* ptr ) + { + IReadBranch* new_branch = nullptr; + TLeaf* leaf = m_tree->GetLeaf( name.c_str() ); + if( leaf == nullptr ){ + ERROR( "Leaf: " << name << " not found"); + return; } - void getEntry( const unsigned int& entry ) - { - if ( !ready ) prepare(); - tree->GetEntry( entry ); - for ( auto& branch : branches ) branch->transfer(); - } - void prepare() - { - for ( auto& branch : branches ) { - tree->SetBranchStatus( branch->name.c_str(), "1" ); - tree->SetBranchAddress( branch->name.c_str(), branch->address() ); - } - ready = true; - } - ~TreeReader() - { - for ( auto& branch : branches ) delete branch; + std::string branchType = leaf->GetTypeName(); + if( branchType == "Double_t" ) new_branch = new ReadBranch( name, ptr ); + if( branchType == "Float_t" ) new_branch = new ReadBranch( name, ptr ); + if( branchType == "Bool_t" ) new_branch = new ReadBranch( name, ptr ); + if( branchType == "Int_t" ) new_branch = new ReadBranch( name, ptr ); + if( branchType == "UInt_t" ) new_branch = new ReadBranch( name, ptr ); + if( branchType == "ULong64_t") new_branch = new ReadBranch( name, ptr ); + if( new_branch == nullptr ){ + ERROR( "Branch type:" << branchType << " not recognised" ); + return; } - Iterator begin() { return Iterator( 0, this ); } - Iterator end() { return Iterator( tree->GetEntries(), this ); } - }; + DEBUG("Making branch with properties: [name = " << name << ", input type = " << branchType << " output type = " << type_string() << "]" ); + m_ready = false; + m_branches.push_back( new_branch ); + } + void setEntryList( const std::vector& entryList ); + void unsetEntryList(); + void getEntry( const unsigned int& entry ); + void prepare(); + size_t nEntries() const; + ~TreeReader(); + Iterator begin(); + Iterator end(); + }; +// ENABLE_DEBUG(TreeReader); } // namespace AmpGen #endif diff --git a/AmpGen/Units.h b/AmpGen/Units.h index fc9db3fddd2..00b40c2ccf5 100644 --- a/AmpGen/Units.h +++ b/AmpGen/Units.h @@ -1,10 +1,25 @@ #ifndef AMPGEN_UNITS_H #define AMPGEN_UNITS_H 1 +#include "AmpGen/enum.h" namespace AmpGen { + static const double TeV = 1000; static const double GeV = 1; static const double MeV = 0.001; static const double KeV = 0.001*0.001; + static const double eV = 0.001*0.001*0.001; + + static const double ms = 1000*1000; + static const double us = 1000; + static const double ns = 1; + static const double ps = 0.001; + static const double fs = 0.001*0.001; + + static const double mm = 1.0; + static const double um = 0.001; + static const double nm = 0.001*0.001; + declare_enum( Units, TeV, GeV, MeV, KeV, eV, ms, us, ns, ps, fs ) + double to_double(const Units& unit ); } #endif diff --git a/AmpGen/Utilities.h b/AmpGen/Utilities.h index 90d8f335854..213591f10a9 100644 --- a/AmpGen/Utilities.h +++ b/AmpGen/Utilities.h @@ -12,52 +12,38 @@ #include #include #include +#ifdef _OPENMP #include +#endif #include "AmpGen/MsgService.h" #include "AmpGen/MetaUtils.h" -namespace AmpGen { - template - static bool isIn( const std::vector& container, const T& obj ) - { - for ( auto& it : container ) - if ( obj == it ) return true; - return false; - } - - template - static bool isIn( const std::vector& container, const B& obj, F f ) - { - for ( auto& it : container ) - if ( f( it, obj ) ) return true; - return false; - } - template - std::string vectorToString( const std::vector& obj, const std::string& delim = "" ) +namespace AmpGen { + template + std::string vectorToString( iterator_type begin, + iterator_type end, + const std::string& delim, + functor_type fcn ) { - std::string returnValue; std::stringstream ss; - if( obj.size() == 0 ) return ""; - for ( unsigned int i = 0 ; i < obj.size()-1; ++i ) - ss << obj[i] << delim; - ss << obj[obj.size()-1]; + if( begin == end ) return ""; + for ( auto it = begin; it != end-1; ++it) + ss << fcn(*it) << delim; + ss << fcn(*(end-1)); return ss.str(); } - template - std::string vectorToString( const std::vector& obj, const std::string& delim="", const F& functor =[](auto& f){ return f ; } ) + template > + std::string vectorToString( const container_type& obj, const std::string& delim = "", const functor_type& f = [](const auto& arg){ return arg; }) { - std::string returnValue; - std::stringstream ss; - if( obj.size() == 0 ) return ""; - for ( unsigned int i = 0 ; i < obj.size()-1; ++i ) - ss << functor(obj[i]) << delim; - ss << functor(obj[obj.size()-1]); - return ss.str(); + return vectorToString( std::begin(obj), std::end(obj), delim, f); } - template std::vector> nCr( const T& n, const T& r ) + template std::vector> nCr( const T& n, const T& r ) { std::vector mask( n ); std::vector> combinations; @@ -82,6 +68,7 @@ namespace AmpGen { size_t find_next_of( const std::string& input, const std::vector& patterns, const size_t& begin = 0 ); std::string replaceAll( const std::string& input, const std::string& toReplace, const std::string& replaceWith ); + std::string replaceAll( const std::string& input, const std::vector>& rules ); unsigned int FNV1a_hash( const std::string& toHash ); @@ -96,13 +83,13 @@ namespace AmpGen { std::string numberWithError( const double& number, const double& error, const unsigned int& nDigits ); - template - RETURN_TYPE lexical_cast( const std::string& word, bool& status ) + template + return_type lexical_cast( const std::string& word, bool& status ) { - WARNING( "Only use specialised versions of this template (word = " << word << ", type = " << AmpGen::typeof() + WARNING( "Only use specialised versions of this template (word = " << word << ", type = " << AmpGen::type_string() << ") " ); status = 0; - return RETURN_TYPE(); + return return_type(); } template @@ -111,7 +98,7 @@ namespace AmpGen { auto size = std::snprintf(nullptr, 0, format.c_str(), std::forward(args)...); std::string output(size+1,'\0'); std::sprintf(&output[0],format.c_str(), std::forward(args)...); - return output; + return output.substr(0, output.size()-1); } @@ -124,13 +111,14 @@ namespace AmpGen { template <> unsigned long int lexical_cast( const std::string& word, bool& status ); template <> long int lexical_cast( const std::string& word, bool& status ); - template - void processFile( const std::string& filename, FCN&& toDo, const char ignoreLinesThatBeginWith = '#' ) + template + void processFile( const std::string& filename, functor_type&& toDo, const char ignoreLinesThatBeginWith = '#' ) { std::string tmp; std::ifstream inFile( filename.c_str() ); while ( inFile.good() ) { std::getline( inFile, tmp ); + tmp.erase( std::remove_if( tmp.begin(), tmp.end(), [](const char c){ return c == '\r'; }), tmp.end() ); if ( tmp.size() == 0 || tmp[0] == ignoreLinesThatBeginWith ) continue; toDo( tmp ); } @@ -169,12 +157,19 @@ namespace AmpGen { { auto total = init; auto size = end-begin; + #ifdef _OPENMP #pragma omp parallel for reduction( +: total ) + #endif for( int it = 0; it < size; ++it ){ total += f(*(begin+it)); } return total; } + template std::function + arrayToFunctor( const std::vector& values) + { + return [values](const contained_type& event) -> return_type {return *(values.data() + event.index()); }; + } template void parallel_sort(iterator begin, @@ -191,14 +186,14 @@ namespace AmpGen { bool isDir( const std::string& fname ); bool fileExists( const std::string& name ); - std::vector getListOfFiles( const std::string& directory, std::string patternString = "" ); + std::vector getListOfFiles(const std::string& directory, const std::string& patternString = ""); void printSplash(); void printReleaseNotes(const std::string& fname); std::string ltrim( std::string s ); std::string rtrim( std::string s ); - std::string trim( std::string s ); + std::string trim( const std::string& s ); std::string expandGlobals( std::string path ); std::ostream& bold_on( std::ostream& ); diff --git a/AmpGen/Version.h.in b/AmpGen/Version.h.in index 9adbb1f3413..d80b4640bbf 100644 --- a/AmpGen/Version.h.in +++ b/AmpGen/Version.h.in @@ -1,2 +1,3 @@ -#define AMPGEN_VERSION_MAJOR @AmpGen_VERSION_MAJOR@ -#define AMPGEN_VERSION_MINOR @AmpGen_VERSION_MINOR@ +#define AMPGEN_MAJOR_VERSION @AmpGen_VERSION_MAJOR@ +#define AMPGEN_MINOR_VERSION @AmpGen_VERSION_MINOR@ + diff --git a/AmpGen/Vertex.h b/AmpGen/Vertex.h index fb2cd7636c3..850bfdbc4c3 100644 --- a/AmpGen/Vertex.h +++ b/AmpGen/Vertex.h @@ -24,31 +24,31 @@ * Macro to declare a vertex */ #define DECLARE_VERTEX(NAME) \ - struct NAME : public VertexBase { \ + struct NAME : public Base { \ NAME(){ DEBUG("Constructing vertex"); } \ - virtual Tensor operator()( const Tensor& P, const Tensor& Q, const Tensor& V1, const Tensor& V2, DebugSymbols* db = 0 ) override; \ + virtual Tensor operator()(const Tensor& P, const Tensor& Q, const Tensor& V1, const Tensor& V2, DebugSymbols* db = 0 ) override; \ static std::string _id; \ } #define DEFINE_VERTEX(VERTEX) \ - REGISTER_WITH_KEY( Vertex::VertexBase, Vertex::VERTEX, #VERTEX, std::string ); \ + REGISTER_WITH_KEY( Vertex::Base, Vertex::VERTEX, #VERTEX, std::string ); \ Tensor Vertex::VERTEX::operator()( const Tensor& P, const Tensor& Q, const Tensor& V1, const Tensor& V2, DebugSymbols* db ) namespace AmpGen { /** @ingroup Vertices namespace Vertex - Namespace that contains the base class for vertices, VertexBase, as well as the implementations + Namespace that contains the base class for vertices, Vertex::Base, as well as the implementations of specific spin couplings and some helper functions such as the orbital operators. */ namespace Vertex { - /** @ingroup Vertices class VertexBase + /** @ingroup Vertices class Base @brief Base class for all spin vertices. Virtual base class from which all the other vertices derive, in essence this is just a named function pointer that can create a pointer to itself, i.e. such that it can be constructed using a Factory. */ - struct VertexBase { + struct Base { /** Calculate the generalised current for this decay process, as a function of: @param P The momentum of the decaying particle @@ -64,8 +64,8 @@ namespace AmpGen const AmpGen::Tensor& V2, AmpGen::DebugSymbols* db = nullptr ) = 0; - virtual ~VertexBase() = default; - VertexBase* create() { return this; } + virtual ~Base() = default; + Base* create() { return this; } }; /// \ingroup Vertices class S_SS_S /// \brief \f$ S = S_1 S_2 \f$ @@ -106,6 +106,7 @@ namespace AmpGen /// \ingroup Vertices class S_TT_S /// \brief \f$ S = T_1^{\mu\nu} T_{2\mu\nu}\f$ DECLARE_VERTEX( S_TT_S ); + /// @ingroup Vertices class V_SS_P /// @brief @f$ V^{\mu} = L^{\mu} S_1 S_2 @f$ @@ -120,11 +121,28 @@ namespace AmpGen DECLARE_VERTEX( V_TS_P ); DECLARE_VERTEX( V_TS_D ); + DECLARE_VERTEX( V_VV_S ); + DECLARE_VERTEX( V_VV_P ); + DECLARE_VERTEX( V_VV_P1 ); + DECLARE_VERTEX( V_VV_P2 ); + DECLARE_VERTEX( V_VV_D ); + DECLARE_VERTEX( V_VV_D2 ); + DECLARE_VERTEX( T_VS_D ); DECLARE_VERTEX( T_VS_P ); DECLARE_VERTEX( T_SS_D ); DECLARE_VERTEX( T_TS_D ); DECLARE_VERTEX( T_TS_S ); + + DECLARE_VERTEX( T_VV_S ); + DECLARE_VERTEX( T_VV_P ); + //DECLARE_VERTEX( T_VV_P2 ); + DECLARE_VERTEX( T_VV_D ); + //DECLARE_VERTEX( T_VV_D1 ); + //DECLARE_VERTEX( T_VV_D2 ); + + DECLARE_VERTEX( S_HS_F ); + DECLARE_VERTEX( H_SS_F ); DECLARE_VERTEX( f_fS_S ); DECLARE_VERTEX( f_fS_S1 ); @@ -138,6 +156,12 @@ namespace AmpGen DECLARE_VERTEX( f_Vf_P2 ); DECLARE_VERTEX( f_Vf_P3 ); + DECLARE_VERTEX( f_fS_SL ); + DECLARE_VERTEX( f_fS_SR ); + + DECLARE_VERTEX( f_Vf_SL ); + DECLARE_VERTEX( f_Vf_SR ); + DECLARE_VERTEX( f_Vf_D ); DECLARE_VERTEX( f_Vf_D1 ); @@ -151,9 +175,11 @@ namespace AmpGen DECLARE_VERTEX( S_ff_S ); DECLARE_VERTEX( S_ff_S1 ); - DECLARE_VERTEX( V_ff_P ); - DECLARE_VERTEX( V_ff_P1 ); - class Factory : public AmpGen::Factory + DECLARE_VERTEX( V_ff_S ); + DECLARE_VERTEX( V_ff_S1 ); + DECLARE_VERTEX( V_ff_PL ); + DECLARE_VERTEX( V_ff_PR ); + class Factory : public AmpGen::Factory { public: static Tensor getSpinFactor( const Tensor& P, const Tensor& Q, const Tensor& V1, const Tensor& V2, @@ -164,14 +190,44 @@ namespace AmpGen }; } // namespace Vertex - /// \ingroup Vertices function Orbital_PWave - /// Helper function that computes the L=1 orbital momentum operator, i.e. - /// \f$ L_{\mu} = q_{\mu} - \frac{p_{\nu}q^{\nu} p_{\mu} }{ p_{\alpha} p^{\alpha}} \f$ - Tensor Orbital_PWave( const Tensor& A, const Tensor& B ); - Tensor Orbital_DWave( const Tensor& A, const Tensor& B ); - Tensor Spin1Projector( const Tensor& A ); - Tensor Spin2Projector( const Tensor& A ); - + /** @ingroup Vertices function Orbital_PWave + @brief Helper function that computes the @f$L=1@f$ orbital momentum operator. + Helper function that computes the @f$L=1@f$ orbital momentum operator, which is given by + @f[ L_{\mu} = q_{\mu} - p_{\mu} \frac{p_{\nu}q^{\nu}}{ p^2 }, @f] + where @f$ p @f$ is total momentum and @f$ q @f$ is the momentum difference between + the two particles in the state. + */ + Tensor Orbital_PWave(const Tensor& p, const Tensor& q); + + /** @ingroup Vertices function Orbital_DWave + @brief Helper function that computes the @f$L=2@f$ orbital momentum operator. + Helper function that computes the @f$L=2@f$ orbital momentum operator, which is given by + @f[ L_{\mu\nu} = L_{\mu}L_{\nu} - \frac{L^2}{3} S_{\mu\nu}, @f] + where @f$ L_{\mu} @f$ is the Orbital_PWave operator and @f$ S_{\mu\nu} @f$ is the + Spin1Projector. */ + Tensor Orbital_DWave(const Tensor& p, const Tensor& q); + Tensor Orbital_FWave(const Tensor& p, const Tensor& q); + + /** @ingroup Vertices function Spin1Projector + @brief Helper function that computes the projection operator onto a spin one state. + Helper function that projects some lorentz object onto the momentum @f$p_\mu @f$ of state, + and is given by + @f[ S_{\mu\nu} = g_{\mu\nu} - \frac{p_{\mu}p_{\nu}}{p^2}. @f] */ + Tensor Spin1Projector(const Tensor& p); + + /** @ingroup Vertices function Spin2Projector + @brief Helper function that computes the projection operator onto a spin one state. + Helper function that projects some lorentz object onto the momentum @f$p_\mu @f$ of state, + and is given by + @f[ S_{\mu\nu\alpha\beta} = \frac{1}{2}\left( S_{\mu\alpha} S_{\nu\beta} + S_{\mu\beta}S_{\nu\alpha} \right) - \frac{1}{3} S_{\mu\nu} S_{\alpha\beta}, @f] + where @f$ S_{\mu\nu} @f$ is the spin-one projection operator (see Spin1Projector). */ + Tensor Spin2Projector(const Tensor& p); + + /** @ingroup Vertices function Spin1hProjector + @brief Helper function that projects a spinor. + Helper function that projects out a spin-half state + @f[ S_{ab} = \frac{1}{2m}\left( {p\!\!\!/} + m I \right) @f] + */ Tensor Spin1hProjector( const Tensor& B ); Tensor Spin3hProjector( const Tensor& A ); diff --git a/AmpGen/Wigner.h b/AmpGen/Wigner.h index be44e8a08b5..01a3792ec63 100644 --- a/AmpGen/Wigner.h +++ b/AmpGen/Wigner.h @@ -6,50 +6,55 @@ #include "AmpGen/Transform.h" namespace AmpGen { -class Particle; + class Particle; + using TransformCache = std::map; Expression wigner_d( const Expression& cb, const double& j, const double& m, const double& n ); - Expression wigner_D( const Tensor& P, const double& J, const double& lA, const double& lB, DebugSymbols* db , const std::string& name = ""); - + Expression wigner_D( const std::pair& P, const double& J, const double& lA, const double& lB, DebugSymbols* db); /** @ingroup Vertices function CG Calculates the Clebsch-Gordan coefficient for (j1 m1 j2 m2 | J M), the expansion coefficients in */ double CG( const double& j1, - const double& m1, - const double& j2, - const double& m2, - const double& J, - const double& M ); + const double& m1, + const double& j2, + const double& m2, + const double& J, + const double& M ); - /** @ingroup Vertices function helicityTransformMatrix - Generates a helicity transform tensor (matrix) that aligns tensor P (four-vector) to the +/- ve z-axis, then boosts to the rest frame. + /** @ingroup Vertices function wickTransform + Generates a wick transform sequence that aligns tensor P (four-vector) to the +/- ve z-axis, then boosts to the rest frame. The mass may be seperately specified. The parameter ve specifies whether the initial Euler rotation is to the +/- z-axis. In the case where ve =-1, a second rotation is applied about the x-axis that aligns P to the +ve z-axis. This ensures that singly and doubly primed helicity frames remain orthonormal. */ - TransformSequence helicityTransformMatrix( const Tensor& P, const Expression& M, const int& ve =1, const bool& handleZeroCase = false ); - - Expression helicityAmplitude( const Particle& particle, const TransformSequence& parentFrame, const double& Mz, DebugSymbols* db , const int sgn=1); + TransformSequence wickTransform(const Tensor& P, const Particle& p, const int& ve =1, DebugSymbols* db = nullptr ); + Expression helicityAmplitude(const Particle& particle, + const TransformSequence& parentFrame, + const double& Mz, + DebugSymbols* db , + const int sgn=1, + TransformCache* cacheptr = nullptr); Tensor basisSpinor(const int& polState, const int& id); + Tensor basisVector(const int& polState); struct LS { - double factor; - double cg1; - double cg2; - double p; - double m1; - double m2; + double factor = {1}; + double cg1 = {0}; + double cg2 = {0}; + double p = {0}; + double m1 = {0}; + double m2 = {0}; }; - + std::vector calculate_recoupling_constants( - const double& J, - const double& M, - const double& L, - const double& S, - const double& j1, - const double& j2 ); + const double& J, + const double& M, + const double& L, + const double& S, + const double& j1, + const double& j2 ); } #endif diff --git a/AmpGen/enum.h b/AmpGen/enum.h new file mode 100644 index 00000000000..ba526c714b1 --- /dev/null +++ b/AmpGen/enum.h @@ -0,0 +1,71 @@ +#ifndef AMPGEN_ENUM_H +#define AMPGEN_ENUM_H 1 +#include "AmpGen/MsgService.h" +#include "AmpGen/Utilities.h" + +#define declare_enum(name, ...) \ +enum class name {__VA_ARGS__, Invalid}; \ +template <> name parse(const std::string& word); \ +template <> std::string to_string( const name& enumItem ); \ +std::ostream& operator<<( std::ostream& os, const name& np); + +#define complete_enum(name, ...) \ +template <> name parse(const std::string& word){ constexpr auto args = #__VA_ARGS__; return AmpGen::detail::parse(word, args); } \ +template <> std::string to_string( const name& enumItem ){ constexpr auto args = #__VA_ARGS__; return AmpGen::detail::to_string(enumItem, args) ; } \ +template <> name lexical_cast(const std::string& word, bool& /*status*/){ return parse(word); } \ +std::ostream& operator<<(std::ostream& os, const name& np){ return os << to_string(np);} + +#define make_enum(name, ...) \ +enum class name {__VA_ARGS__, Invalid}; \ +template <> name parse(const std::string& word){ constexpr auto args = #__VA_ARGS__; return AmpGen::detail::parse(word, args); } \ +template <> std::string to_string( const name& enumItem ){ constexpr auto args = #__VA_ARGS__; return AmpGen::detail::to_string(enumItem, args) ; } \ +template <> name lexical_cast(const std::string& word, bool& /*status*/){ return parse(word); } \ +std::ostream& operator<<(std::ostream& os, const name& np){ return os << to_string(np);} + +namespace AmpGen { + template T parse( const std::string& word ){ return T(); } + template std::string to_string( const T& enumItem ){ return ""; } + + namespace detail { + template T parse(const std::string& word, const char* args) + { + char* p; + auto number = strtoul( word.c_str(), &p, 10 ); + if( *p == 0 ) return T(number); + unsigned counter = 0; + unsigned begin = 0; + unsigned end = 0; + auto compare = [](const char* word, const char* otherWord, const unsigned& nChar) + { + for( size_t x = 0; x != nChar ; ++x) if( word[x] != otherWord[x] ) return false; + return true; + }; + bool found = false; + while( args[begin] != '\0' ) + { + while( args[begin] == ' ' ) begin++; + for( end=begin; args[end] != '\0'; end++ ) if( args[end] == ',' ) break; + if( compare( word.c_str(), args + begin , end-begin ) ) { found = true; break; } + begin = end+1; + counter++; + if( args[end] == '\0' ) break; + } + if(!found) return T::Invalid; + return T(counter); + } + template std::string to_string(const T& enumItem, const char* args) + { + unsigned counter = 0; + unsigned sBegin = 0; + unsigned sLength = 0; + for( ; args[sBegin] != '\0' && counter != unsigned(enumItem); sBegin++ ) + { + if( args[sBegin] == ',' ) counter++; + } + while( args[sBegin] == ' ') sBegin++; + for(; args[sLength + sBegin] != '\0' ; ++sLength ) if( args[sBegin + sLength] == ',') break; + return std::string(args).substr(sBegin, sLength); + } + } +} +#endif diff --git a/AmpGen/gsl_wrapper.h b/AmpGen/gsl_wrapper.h new file mode 100644 index 00000000000..57228b24f7f --- /dev/null +++ b/AmpGen/gsl_wrapper.h @@ -0,0 +1,56 @@ + +#include + +namespace AmpGen { + template double integrate_1d( const function_type& fcn, const double& min, const double& max, gsl_integration_workspace* ws = nullptr) + { + gsl_integration_workspace* w = (ws == nullptr) ? gsl_integration_workspace_alloc (1000) : ws; + double result = 0; + double error = 0; + gsl_function F; + F.function = [](double x, void* p) -> double { return (*static_cast(p))(x); }; + F.params = const_cast(&fcn); + gsl_integration_qags (&F, min, max, 0, 1e-5, 1000, w, &result, &error); + if( ws == nullptr ) gsl_integration_workspace_free (w); + return result; + } + template double integrate_1d_inf( const function_type& fcn, gsl_integration_workspace* ws = nullptr) + { + gsl_integration_workspace* w = (ws == nullptr) ? gsl_integration_workspace_alloc (1000) : ws; + double result = 0; + double error = 0; + gsl_function F; + F.function = [](double x, void* p) -> double { return (*static_cast(p))(x); }; + F.params = const_cast(&fcn); + gsl_integration_qagi(&F, 0, 1e-5, 1000, w, &result, &error); + if( ws == nullptr ) gsl_integration_workspace_free (w); + std::cout << result << " +/- " << error << std::endl; + return result; + } + + + template double integrate_2d( const function_type& fcn, const double& x1, const double& x2, const double& y1, const double& y2) + { + gsl_integration_workspace* w1 = gsl_integration_workspace_alloc (1000); + auto outer = [fcn, &x1, &x2, &w1](const double& y) + { + auto inner = [fcn, &y](const double& x){ return fcn(x,y); }; + return integrate_1d(inner, x1,x2, w1); + }; + auto r = integrate_1d( outer, y1, y2); + gsl_integration_workspace_free (w1); + return r; + } + template double integrate_1d_cauchy( const function_type& fcn, const double& x0, const double& min, const double& max, gsl_integration_workspace* ws = nullptr) + { + gsl_integration_workspace* w = (ws == nullptr) ? gsl_integration_workspace_alloc (1000) : ws; + double result = 0; + double error = 0; + gsl_function F; + F.function = [](double x, void* p) -> double { return (*static_cast(p))(x); }; + F.params = const_cast(&fcn); + gsl_integration_qawc(&F, min, max, x0, 0, 1e-5, 1000, w, &result, &error); + if( ws == nullptr ) gsl_integration_workspace_free (w); + return result; + } +} diff --git a/AmpGen/kMatrix.h b/AmpGen/kMatrix.h index ae4165af1fc..c7cbcb1ce9b 100644 --- a/AmpGen/kMatrix.h +++ b/AmpGen/kMatrix.h @@ -3,9 +3,28 @@ #include "AmpGen/Expression.h" #include "AmpGen/Tensor.h" +#include "AmpGen/Lineshapes.h" namespace AmpGen { + namespace Lineshape { + + /** @ingroup Lineshapes class kMatrix + @brief Anisovich-Sarantsev Isoscalar K-matrix from https://arxiv.org/abs/hep-ph/0204328 + + Describes the isoscalar @f$ \pi\pi, KK, 4\pi \eta\eta, \eta\eta^\prime@f$ S-wave in terms of a five-by-five K-matrix and corresponding P-vector couplings. + Includes a large number of parameters that can be fixed from the above publication. + These parameters can be found in the options directory, which in turn can be includes in the fit by adding + + \code{cpp} + Import $AMPGENROOT/options/kMatrix.opt + \endcode + + to the user configuration file. + */ + DECLARE_LINESHAPE( kMatrix ); + } + struct poleConfig { Expression s; std::vector couplings; @@ -18,11 +37,11 @@ namespace AmpGen couplings.push_back( coupling ); bl_factors.push_back( bl_factor ); } - const Expression coupling(const size_t& i) const { return couplings[i] * bl_factors[i]; } - const Expression g(const size_t& i) const { return couplings[i]; } + const Expression coupling(const unsigned& i) const { return couplings[i] * bl_factors[i]; } + const Expression g(const unsigned& i) const { return couplings[i]; } }; - Tensor constructKMatrix(const Expression& s, const size_t& nChannels, + Tensor constructKMatrix(const Expression& s, const unsigned& nChannels, const std::vector& poleConfigs); Expression phsp_twoBody( const Expression& s, const double& m0, const double& m1 ); @@ -32,9 +51,7 @@ namespace AmpGen std::vector paramVector( const std::string& name, const unsigned int& nParam ); - Tensor getPropagator(const Tensor& kMatrix, const std::vector& phaseSpace); - - + Tensor getPropagator(const Tensor& kMatrix, const std::vector& phaseSpace, DebugSymbols* db=nullptr); } // namespace AmpGen #endif /* end of include guard: AMPGEN_KMATRIX_H */ diff --git a/AmpGen/simd/avx2d_types.h b/AmpGen/simd/avx2d_types.h new file mode 100644 index 00000000000..e3e0349d7fb --- /dev/null +++ b/AmpGen/simd/avx2d_types.h @@ -0,0 +1,217 @@ +#ifndef AMPGEN_AVXd_TYPES +#define AMPGEN_AVXd_TYPES 1 + +#include +#include +#include +#include +#ifdef _OPENMP +#include +#endif +#include + +#if USE_MVEC +extern "C" void _ZGVdN4vvv_sincos(__m256d x, __m256i ptrs, __m256i ptrc); +#endif + +#if USE_MVEC +#define libmvec_alias( function_name) \ + extern "C" __m256d _ZGVcN4v_##function_name(__m256d x); \ + inline real_v function_name( const real_v& v ){ return _ZGVcN4v_##function_name (v) ; } +#else +#define libmvec_alias( F ) \ + inline real_v F( const real_v& v ){ auto arr = v.to_array(); return real_v( std::F(arr[0]), std::F(arr[1]), std::F(arr[2]), std::F(arr[3])) ; } +#endif + +namespace AmpGen { + namespace AVX2d { + + struct real_v { + __m256d data; + static constexpr unsigned size = 4; + typedef double scalar_type; + real_v() = default; + real_v(__m256d data ) : data(data) {} + real_v(const double& f ) : data( _mm256_set1_pd( f )) {} + real_v(const double& x0, const double& x1, const double& x2, const double& x3 ) + { + data = _mm256_set_pd(x3,x2,x1,x0); + } + real_v(const double* f ) : data( _mm256_loadu_pd( f ) ) {} + real_v(const std::array f ) : data( _mm256_loadu_pd( f.data() ) ) {} + void store( double* ptr ) const { _mm256_storeu_pd( ptr, data ); } + std::array to_array() const { std::array b; store( &b[0] ); return b; } + double at(const unsigned i) const { return to_array()[i] ; } + operator __m256d() const { return data ; } + }; + + inline real_v operator+( const real_v& lhs, const real_v& rhs ) { return _mm256_add_pd(lhs, rhs); } + inline real_v operator-( const real_v& lhs, const real_v& rhs ) { return _mm256_sub_pd(lhs, rhs); } + inline real_v operator*( const real_v& lhs, const real_v& rhs ) { return _mm256_mul_pd(lhs, rhs); } + inline real_v operator/( const real_v& lhs, const real_v& rhs ) { return _mm256_div_pd(lhs, rhs); } + inline real_v operator-( const real_v& x ) { return -1.f * x; } + inline real_v operator&( const real_v& lhs, const real_v& rhs ) { return _mm256_and_pd( lhs, rhs ); } + inline real_v operator|( const real_v& lhs, const real_v& rhs ) { return _mm256_or_pd( lhs, rhs ); } + inline real_v operator^( const real_v& lhs, const real_v& rhs ) { return _mm256_xor_pd( lhs, rhs ); } + inline real_v operator+=(real_v& lhs, const real_v& rhs ){ lhs = lhs + rhs; return lhs; } + inline real_v operator-=(real_v& lhs, const real_v& rhs ){ lhs = lhs - rhs; return lhs; } + inline real_v operator*=(real_v& lhs, const real_v& rhs ){ lhs = lhs * rhs; return lhs; } + inline real_v operator/=(real_v& lhs, const real_v& rhs ){ lhs = lhs / rhs; return lhs; } + inline real_v operator&&( const real_v& lhs, const real_v& rhs ) { return _mm256_and_pd( lhs, rhs ); } + inline real_v operator||( const real_v& lhs, const real_v& rhs ) { return _mm256_or_pd( lhs, rhs ); } + inline real_v operator!( const real_v& x ) { return x ^ _mm256_castsi256_pd( _mm256_set1_epi32( -1 ) ); } + inline real_v operator<( const real_v& lhs, const real_v& rhs ) { return _mm256_cmp_pd( lhs, rhs, _CMP_LT_OS ); } + inline real_v operator>( const real_v& lhs, const real_v& rhs ) { return _mm256_cmp_pd( lhs, rhs, _CMP_GT_OS ); } + inline real_v operator<=( const real_v& lhs, const real_v& rhs ) { return _mm256_cmp_pd( lhs, rhs, _CMP_LE_OS ); } + inline real_v operator>=( const real_v& lhs, const real_v& rhs ) { return _mm256_cmp_pd( lhs, rhs, _CMP_GE_OS ); } + inline real_v operator==( const real_v& lhs, const real_v& rhs ){ return _mm256_cmp_pd( lhs, rhs, _CMP_EQ_OS ); } + inline real_v sqrt( const real_v& v ) { return _mm256_sqrt_pd(v); } + inline real_v abs ( const real_v& v ) { return _mm256_andnot_pd(_mm256_set1_pd(-0.), v); } + libmvec_alias( sin ) + libmvec_alias( cos ) + libmvec_alias( exp ) + libmvec_alias( log ) + //inline real_v log( const real_v& v ){ auto arr = v.to_array(); return real_v( std::log(arr[0]), std::log(arr[1]), std::log(arr[2]), std::log(arr[3])) ; } + inline void sincos( const real_v& v, real_v& s, real_v& c ) + { +#if USE_MVEC + __m256i sp = _mm256_add_epi64(_mm256_set1_epi64x((uint64_t)&s),_mm256_set_epi64x(24,16,8,0)); + __m256i cp = _mm256_add_epi64(_mm256_set1_epi64x((uint64_t)&c),_mm256_set_epi64x(24,16,8,0)); + _ZGVdN4vvv_sincos(v,sp,cp); +#else + s = sin(v); + c = cos(v); +#endif + } + inline std::pair sincos( const real_v& v ) + { + std::pair rt; + sincos( v, rt.first, rt.second ); + return rt; + } + inline real_v tan( const real_v& v ) + { + auto [s,c] = sincos( v ); + return s / c ; + } + + inline real_v select(const real_v& mask, const real_v& a, const real_v& b ) { return _mm256_blendv_pd( b, a, mask ); } + inline real_v select(const bool& mask , const real_v& a, const real_v& b ) { return mask ? a : b; } + inline real_v sign ( const real_v& v){ return select( v > 0., +1., -1. ); } + inline real_v atan2( const real_v& y, const real_v& x ){ + std::array bx{x.to_array()}, by{y.to_array()}; + return real_v ( + std::atan2( by[0], bx[0]) + , std::atan2( by[1], bx[1]) + , std::atan2( by[2], bx[2]) + , std::atan2( by[3], bx[3]) ); + } + inline __m256i udouble_to_uint( const real_v& x ) + { + auto xr = _mm256_round_pd(x, _MM_FROUND_TO_NEG_INF); + // based on: https://stackoverflow.com/questions/41144668/how-to-efficiently-perform-double-int64-conversions-with-sse-avx + return _mm256_sub_epi64(_mm256_castpd_si256(_mm256_add_pd(xr, _mm256_set1_pd(0x0018000000000000))), + _mm256_castpd_si256(_mm256_set1_pd(0x0018000000000000))); + } + inline real_v gather( const double* base_addr, const real_v& offsets) + { + return _mm256_i64gather_pd(base_addr, udouble_to_uint(offsets),sizeof(double)); + } + + inline real_v fmadd( const real_v& a, const real_v& b, const real_v& c ) + { + return _mm256_fmadd_pd(a, b, c); + } + inline real_v remainder( const real_v& a, const real_v& b ){ return a - real_v(_mm256_round_pd(a/b, _MM_FROUND_TO_NEG_INF)) * b; } + inline real_v fmod( const real_v& a, const real_v& b ) + { + auto r = remainder( abs(a), abs(b) ); + return select( a > 0., r, -r ); + } + + struct complex_v { + real_v re; + real_v im; + typedef std::complex scalar_type; + static constexpr unsigned size = 4; + + real_v real() const { return re; } + real_v imag() const { return im; } + real_v norm() const { return re*re + im *im ; } + complex_v() = default; + complex_v( const real_v& re, const real_v& im) : re(re), im(im) {} + complex_v( const float& re, const float& im) : re(re), im(im) {} + complex_v( const std::complex& f ) : re( f.real() ), im( f.imag() ) {} + complex_v( const std::complex& f ) : re( f.real() ), im( f.imag() ) {} + complex_v( const std::complex* arr ) : + re ( arr[0].real(), arr[1].real(), arr[2].real(), arr[3].real() ), + im ( arr[0].imag(), arr[1].imag(), arr[2].imag(), arr[3].imag() ){} + explicit complex_v( const real_v& arg ) : re(arg) {}; + explicit complex_v( const double& arg ) : re(arg) {}; + const std::complex at(const unsigned i) const { return std::complex(re.to_array()[i], im.to_array()[i]) ; } + void store( double* sre, double* sim ){ re.store(sre); im.store(sim); } + void store( scalar_type* r ) const { + auto re_arr = re.to_array(); + auto im_arr = im.to_array(); + for( unsigned i = 0 ; i != re_arr.size(); ++i ) r[i] = scalar_type( re_arr[i], im_arr[i] ); + } + auto to_array() const + { + std::array rt; + store( rt.data() ); + return rt; + } + }; + + inline std::ostream& operator<<( std::ostream& os, const real_v& obj ) { + auto buffer = obj.to_array(); + for( unsigned i = 0 ; i != 4; ++i ) os << buffer[i] << " "; + return os; + } + inline real_v real(const complex_v& arg ){ return arg.re ; } + inline real_v imag(const complex_v& arg ){ return arg.im ; } + inline complex_v conj(const complex_v& arg ){ return complex_v(arg.re, -arg.im) ; } + inline real_v conj(const real_v& arg ){ return arg ; } + inline complex_v operator+( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re + rhs, lhs.im); } + inline complex_v operator-( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re - rhs, lhs.im); } + inline complex_v operator*( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re*rhs, lhs.im*rhs); } + inline complex_v operator/( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re/rhs, lhs.im/rhs); } + inline complex_v operator+( const real_v& lhs, const complex_v& rhs ) { return complex_v(lhs + rhs.re, rhs.im); } + inline complex_v operator-( const real_v& lhs, const complex_v& rhs ) { return complex_v(lhs - rhs.re, - rhs.im); } + inline complex_v operator*( const real_v& lhs, const complex_v& rhs ) { return complex_v(lhs*rhs.re, lhs*rhs.im); } + inline complex_v operator/( const real_v& lhs, const complex_v& rhs ) { return complex_v( lhs * rhs.re , -lhs *rhs.im) / (rhs.re * rhs.re + rhs.im * rhs.im ); } + inline complex_v operator+( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re + rhs.re, lhs.im + rhs.im); } + inline complex_v operator-( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re - rhs.re, lhs.im - rhs.im); } + inline complex_v operator*( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re*rhs.re - lhs.im*rhs.im, lhs.re*rhs.im + lhs.im*rhs.re); } + inline complex_v operator/( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re*rhs.re + lhs.im*rhs.im, -lhs.re*rhs.im + lhs.im*rhs.re) / (rhs.re * rhs.re + rhs.im * rhs.im ); } + inline complex_v operator-( const complex_v& x ) { return -1.f * x; } + inline real_v abs( const complex_v& v ) { return sqrt( v.re * v.re + v.im * v.im ) ; } + inline real_v norm( const complex_v& v ) { return ( v.re * v.re + v.im * v.im ) ; } + inline complex_v select(const real_v& mask, const complex_v& a, const complex_v& b ) { return complex_v( select(mask, a.re, b.re), select(mask, a.im, b.im ) ) ; } + inline complex_v select(const real_v& mask, const real_v& a, const complex_v& b ) { return complex_v( select(mask, a , b.re), select(mask, 0.f, b.im) ); } + inline complex_v select(const real_v& mask, const complex_v& a, const real_v& b ) { return complex_v( select(mask, a.re, b ) , select(mask, a.im, 0.f) ); } + inline complex_v select(const bool& mask , const complex_v& a, const complex_v& b ) { return mask ? a : b; } + inline complex_v exp( const complex_v& v ){ + auto [s,c] = sincos( v.im); + return exp(v.re) * complex_v(c, s); + } + inline complex_v sqrt( const complex_v& v ) + { + auto r = abs(v); + return complex_v ( sqrt( 0.5 * (r + v.re) ), sign(v.im) * sqrt( 0.5*( r - v.re ) ) ); + } + inline complex_v log( const complex_v& v ) + { + return complex_v( 0.5 * log( v.norm() ) , atan2(v.im, v.re) ); + } + + inline std::ostream& operator<<( std::ostream& os, const complex_v& obj ) { return os << "( "<< obj.re << ") (" << obj.im << ")"; } + #pragma omp declare reduction(+: real_v: \ + omp_out = omp_out + omp_in) + #pragma omp declare reduction(+: complex_v: \ + omp_out = omp_out + omp_in) + + } +} + +#endif diff --git a/AmpGen/simd/avx2f_types.h b/AmpGen/simd/avx2f_types.h new file mode 100644 index 00000000000..66a91df9431 --- /dev/null +++ b/AmpGen/simd/avx2f_types.h @@ -0,0 +1,204 @@ +#ifndef AMPGEN_AVX_TYPES +#define AMPGEN_AVX_TYPES 1 + +#include +#include +#include +#include +#include + +#if USE_MVEC +extern "C" void _ZGVdN8vvv_sincos(__m256 x, __m256i ptrs, __m256i ptrc); +#endif + +#if USE_MVEC +#define libmvec_alias( function_name) \ + extern "C" __m256 _ZGVcN8v_##function_name(__m256 x); \ + inline real_v function_name( const real_v& v ){ return _ZGVcN8v_##function_name (v) ; } +#else +#define libmvec_alias( F ) \ + inline real_v F( const real_v& v ){ auto arr = v.to_array(); return real_v( \ + std::F(arr[0]), std::F(arr[1]), std::F(arr[2]), std::F(arr[3]), \ + std::F(arr[4]), std::F(arr[5]), std::F(arr[6]), std::F(arr[7]) ) ; } +#endif + +namespace AmpGen { + namespace AVX2f { + struct real_v { + __m256 data; + static constexpr unsigned size = 8 ; + typedef float scalar_type; + real_v() = default; + real_v(__m256 data ) : data(data) {} + real_v(const float& f ) : data( _mm256_set1_ps(f) ) {} + real_v(const double& f ) : data( _mm256_set1_ps( float(f) )) {} + real_v(const float* f ) : data( _mm256_loadu_ps( f ) ) {} + real_v(const float& x0, const float& x1, const float& x2, const float& x3, + const float& x4, const float& x5, const float& x6, const float& x7) + { + data = _mm256_set_ps(x7,x6,x5,x4,x3,x2,x1,x0); + } + + void store( float* ptr ) const { _mm256_storeu_ps( ptr, data ); } + std::array to_array() const { std::array b; store( &b[0] ); return b; } + float at(const unsigned i) const { return to_array()[i] ; } + operator __m256() const { return data ; } + }; + + inline real_v operator+( const real_v& lhs, const real_v& rhs ) { return _mm256_add_ps(lhs, rhs); } + inline real_v operator-( const real_v& lhs, const real_v& rhs ) { return _mm256_sub_ps(lhs, rhs); } + inline real_v operator*( const real_v& lhs, const real_v& rhs ) { return _mm256_mul_ps(lhs, rhs); } + inline real_v operator/( const real_v& lhs, const real_v& rhs ) { return _mm256_div_ps(lhs, rhs); } + inline real_v operator-( const real_v& x ) { return -1.f * x; } + inline real_v operator&( const real_v& lhs, const real_v& rhs ) { return _mm256_and_ps( lhs, rhs ); } + inline real_v operator|( const real_v& lhs, const real_v& rhs ) { return _mm256_or_ps( lhs, rhs ); } + inline real_v operator^( const real_v& lhs, const real_v& rhs ) { return _mm256_xor_ps( lhs, rhs ); } + inline real_v operator+=(real_v& lhs, const real_v& rhs ){ lhs = lhs + rhs; return lhs; } + inline real_v operator-=(real_v& lhs, const real_v& rhs ){ lhs = lhs - rhs; return lhs; } + inline real_v operator*=(real_v& lhs, const real_v& rhs ){ lhs = lhs * rhs; return lhs; } + inline real_v operator/=(real_v& lhs, const real_v& rhs ){ lhs = lhs / rhs; return lhs; } + inline real_v operator&&( const real_v& lhs, const real_v& rhs ) { return _mm256_and_ps( lhs, rhs ); } + inline real_v operator||( const real_v& lhs, const real_v& rhs ) { return _mm256_or_ps( lhs, rhs ); } + inline real_v operator!( const real_v& x ) { return x ^ _mm256_castsi256_ps( _mm256_set1_epi32( -1 ) ); } + inline real_v operator<( const real_v& lhs, const real_v& rhs ) { return _mm256_cmp_ps( lhs, rhs, _CMP_LT_OS ); } + inline real_v operator>( const real_v& lhs, const real_v& rhs ) { return _mm256_cmp_ps( lhs, rhs, _CMP_GT_OS ); } + inline real_v operator<( const real_v& lhs, const real_v& rhs ) { return _mm256_cmp_ps( lhs, rhs, _CMP_LE_OS ); } + inline real_v operator>( const real_v& lhs, const real_v& rhs ) { return _mm256_cmp_ps( lhs, rhs, _CMP_GE_OS ); } + inline real_v operator==( const real_v& lhs, const real_v& rhs ){ return _mm256_cmp_ps( lhs, rhs, _CMP_EQ_OS ); } + inline real_v sqrt( const real_v& v ) { return _mm256_sqrt_ps(v); } + libmvec_alias(sin) + libmvec_alias(cos) + libmvec_alias(exp) + libmvec_alias(log) + + inline void sincos( const real_v& v, real_v& s, real_v& c ) + { +#if USE_MVEC + __m256i sp = _mm256_add_epi64(_mm256_set1_epi32x((uint64_t)&s),_mm256_set_epi32x(28,24,20,16,12,8,4,0)); + __m256i cp = _mm256_add_epi64(_mm256_set1_epi32x((uint64_t)&c),_mm256_set_epi32x(28,24,20,16,12,8,4,0)); + _ZGVdN8vvv_sincos(v,sp,cp); +#else + s = sin(v); + c = cos(v); +#endif + } + inline std::pair sincos( const real_v& v ) + { + std::pair rt; + sincos( v, rt.first, rt.second ); + return rt; + } + inline real_v tan( const real_v& v ) + { + auto [s,c] = sincos( v ); + return s / c ; + } + + + + inline real_v abs ( const real_v& v ) { return v & _mm256_castsi256_ps( _mm256_set1_epi32( 0x7FFFFFFF ) ); } + inline real_v select(const real_v& mask, const real_v& a, const real_v& b ) { return _mm256_blendv_ps( b, a, mask ); } + inline real_v select(const bool& mask , const real_v& a, const real_v& b ) { return mask ? a : b; } + inline real_v atan2( const real_v& y, const real_v& x ){ + std::array bx{x.to_array()}, by{y.to_array()}, rt; + for( unsigned i = 0 ; i != 8 ; ++i ) rt[i] = std::atan2( by[i] , bx[i] ); + return real_v (rt.data() ); + } +// inline real_v gather( const double* base_addr, const real_v& offsets) +// { +// auto addr_avx =_mm256_cvtps_epi32(offsets); +// std::array addr; +// _mm256_storeu_ps( addr.data(), _mm256_cvtps_epi32(offsets) ); +// return real_v( +// base_addr[addr[0]], base_addr[addr[1]],base_addr[addr[2]],base_addr[addr[3]], +// base_addr[addr[4]], base_addr[addr[5]],base_addr[addr[6]],base_addr[addr[7]] ); +// +// //return _mm256_i32gather_ps(base_addr, _mm256_cvtps_epi32(offsets),sizeof(double)); +// } + + inline real_v fmadd( const real_v& a, const real_v& b, const real_v& c ) + { + return _mm256_fmadd_ps(a, b, c); + } + inline real_v remainder( const real_v& a, const real_v& b ){ return a - real_v(_mm256_round_ps(a/b, _MM_FROUND_TO_NEG_INF)) * b; } + inline real_v fmod( const real_v& a, const real_v& b ) + { + auto r = remainder( abs(a), abs(b) ); + return select( a > 0., r, -r ); + } + struct complex_v { + real_v re; + real_v im; + typedef std::complex scalar_type; + static constexpr unsigned size = 8 ; + + real_v real() const { return re; } + real_v imag() const { return im; } + real_v norm() const { return re*re + im *im ; } + complex_v() = default; + complex_v( const real_v& re, const real_v& im) : re(re), im(im) {} + complex_v( const float& re, const float& im) : re(re), im(im) {} + complex_v( const std::complex& f ) : re( f.real() ), im( f.imag() ) {} + complex_v( const std::complex& f ) : re( f.real() ), im( f.imag() ) {} + + const std::complex at(const unsigned i) const { return std::complex(re.to_array()[i], im.to_array()[i]) ; } + void store( float* sre, float* sim ) const { re.store(sre); im.store(sim); } + void store( std::complex* r ) const { + auto re_arr = re.to_array(); + auto im_arr = im.to_array(); + for( unsigned i = 0 ; i != re_arr.size(); ++i ) r[i] = std::complex( re_arr[i], im_arr[i] ); + } + auto to_array() const + { + std::array rt; + store( rt.data() ); + return rt; + } + }; + + inline std::ostream& operator<<( std::ostream& os, const real_v& obj ) { + auto buffer = obj.to_array(); + for( unsigned i = 0 ; i != 8; ++i ) os << buffer[i] << " "; + return os; + } + inline real_v real(const complex_v& arg ){ return arg.re ; } + inline real_v imag(const complex_v& arg ){ return arg.im ; } + inline complex_v conj(const complex_v& arg ){ return complex_v(arg.re, -arg.im) ; } + inline real_v conj(const real_v& arg ){ return arg ; } + inline complex_v operator+( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re + rhs, lhs.im); } + inline complex_v operator-( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re - rhs, lhs.im); } + inline complex_v operator*( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re*rhs, lhs.im*rhs); } + inline complex_v operator/( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re/rhs, lhs.im/rhs); } + inline complex_v operator+( const real_v& lhs, const complex_v& rhs ) { return complex_v(lhs + rhs.re, rhs.im); } + inline complex_v operator-( const real_v& lhs, const complex_v& rhs ) { return complex_v(lhs - rhs.re, - rhs.im); } + inline complex_v operator*( const real_v& lhs, const complex_v& rhs ) { return complex_v(lhs*rhs.re, lhs*rhs.im); } + inline complex_v operator/( const real_v& lhs, const complex_v& rhs ) { return complex_v( lhs * rhs.re , -lhs *rhs.im) / (rhs.re * rhs.re + rhs.im * rhs.im ); } + inline complex_v operator+( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re + rhs.re, lhs.im + rhs.im); } + inline complex_v operator-( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re - rhs.re, lhs.im - rhs.im); } + inline complex_v operator*( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re*rhs.re - lhs.im*rhs.im, lhs.re*rhs.im + lhs.im*rhs.re); } + inline complex_v operator/( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re*rhs.re + lhs.im*rhs.im, -lhs.re*rhs.im + lhs.im*rhs.re) / (rhs.re * rhs.re + rhs.im * rhs.im ); } + inline complex_v operator-( const complex_v& x ) { return -1.f * x; } + inline real_v abs( const complex_v& v ) { return sqrt( v.re * v.re + v.im * v.im ) ; } + inline real_v norm( const complex_v& v ) { return ( v.re * v.re + v.im * v.im ) ; } + inline complex_v select(const real_v& mask, const complex_v& a, const complex_v& b ) { return complex_v( _mm256_blendv_ps( b.re, a.re, mask ), _mm256_blendv_ps( b.im, a.im, mask ) ); } + inline complex_v select(const real_v& mask, const real_v& a, const complex_v& b ) { return complex_v( _mm256_blendv_ps( b.re, a , mask ), _mm256_blendv_ps( b.im, real_v(0.f), mask ) ); } + inline complex_v select(const real_v& mask, const complex_v& a, const real_v& b ) { return complex_v( _mm256_blendv_ps( b, a.re, mask ), _mm256_blendv_ps( real_v(0.f), a.im, mask ) ); } + inline complex_v select(const bool& mask , const complex_v& a, const complex_v& b ) { return mask ? a : b; } + inline complex_v exp( const complex_v& v ){ + auto [s,c] = sincos( v.im ); + return exp( v.re ) * complex_v(c, s); + } + inline complex_v log( const complex_v& v ) + { + return complex_v( 0.5 * log( v.norm() ) , atan2(v.im, v.re) ); + } + inline std::ostream& operator<<( std::ostream& os, const complex_v& obj ) { return os << "( "<< obj.re << ") (" << obj.im << ")"; } + #pragma omp declare reduction(+: real_v: \ + omp_out = omp_out + omp_in) + #pragma omp declare reduction(+: complex_v: \ + omp_out = omp_out + omp_in) + + } +} + +#endif diff --git a/AmpGen/simd/avx512d_types.h b/AmpGen/simd/avx512d_types.h new file mode 100644 index 00000000000..36d9695af77 --- /dev/null +++ b/AmpGen/simd/avx512d_types.h @@ -0,0 +1,213 @@ +#ifndef AMPGEN_AVXd_TYPES +#define AMPGEN_AVXd_TYPES 1 + +#include +#include +#include +#include +#include + +namespace AmpGen { + namespace AVX512d { + #define stl_fallback( x ) \ + inline real_v x( const real_v& v ){ auto a = v.to_array(); return real_v( std::x(a[0]), std::x(a[1]), std::x(a[2]), std::x(a[3]), std::x(a[4]), std::x(a[5]), std::x(a[6]), std::x(a[7]) ) ; } + + struct real_v { + __m512d data; + static constexpr unsigned size = 8; + typedef double scalar_type; + real_v() = default; + real_v(__m512d data ) : data(data) {} + real_v(const double& f ) : data( _mm512_set1_pd( f )) {} + real_v( + const double& x0, const double& x1, const double& x2, const double& x3, + const double& x4, const double& x5, const double& x6, const double& x7) + { + double tmp[8] = {x0,x1,x2,x3,x4,x5,x6,x7}; + data = _mm512_loadu_pd(tmp); + } + real_v(const double* f ) : data( _mm512_loadu_pd( f ) ) {} + void store( double* ptr ) const { _mm512_storeu_pd( ptr, data ); } + std::array to_array() const { std::array b; store( &b[0] ); return b; } + double at(const unsigned i) const { return to_array()[i] ; } + operator __m512d() const { return data ; } + }; + + inline real_v operator+( const real_v& lhs, const real_v& rhs ) { return _mm512_add_pd(lhs, rhs); } + inline real_v operator-( const real_v& lhs, const real_v& rhs ) { return _mm512_sub_pd(lhs, rhs); } + inline real_v operator*( const real_v& lhs, const real_v& rhs ) { return _mm512_mul_pd(lhs, rhs); } + inline real_v operator/( const real_v& lhs, const real_v& rhs ) { return _mm512_div_pd(lhs, rhs); } + inline real_v operator-( const real_v& x ) { return -1.f * x; } + inline real_v operator&( const real_v& lhs, const real_v& rhs ) { return _mm512_and_pd( lhs, rhs ); } + inline real_v operator|( const real_v& lhs, const real_v& rhs ) { return _mm512_or_pd( lhs, rhs ); } + inline real_v operator^( const real_v& lhs, const real_v& rhs ) { return _mm512_xor_pd( lhs, rhs ); } + inline real_v operator+=(real_v& lhs, const real_v& rhs ){ lhs = lhs + rhs; return lhs; } + inline real_v operator-=(real_v& lhs, const real_v& rhs ){ lhs = lhs - rhs; return lhs; } + inline real_v operator*=(real_v& lhs, const real_v& rhs ){ lhs = lhs * rhs; return lhs; } + inline real_v operator/=(real_v& lhs, const real_v& rhs ){ lhs = lhs / rhs; return lhs; } + inline real_v operator&&( const real_v& lhs, const real_v& rhs ) { return _mm512_and_pd( lhs, rhs ); } + inline real_v operator||( const real_v& lhs, const real_v& rhs ) { return _mm512_or_pd( lhs, rhs ); } + inline real_v operator!( const real_v& x ) { return x ^ _mm512_castsi512_pd( _mm512_set1_epi32( -1 ) ); } + inline __mmask8 operator<( const real_v& lhs, const real_v& rhs ) { return _mm512_cmp_pd_mask( lhs, rhs, _CMP_LT_OS ); } + inline __mmask8 operator>( const real_v& lhs, const real_v& rhs ) { return _mm512_cmp_pd_mask( lhs, rhs, _CMP_GT_OS ); } + inline __mmask8 operator==( const real_v& lhs, const real_v& rhs ){ return _mm512_cmp_pd_mask( lhs, rhs, _CMP_EQ_OS ); } + inline real_v sqrt( const real_v& v ) { return _mm512_sqrt_pd(v); } + inline real_v abs ( const real_v& v ) { return _mm512_andnot_pd(_mm512_set1_pd(-0.), v); } + // inline real_v sin( const real_v& v ) { return sin512_pd(v) ; } + // inline real_v cos( const real_v& v ) { return cos512_pd(v) ; } + // inline real_v tan( const real_v& v ) { real_v s; real_v c; sincos512_pd(v, (__m512*)&s, (__m512*)&c) ; return s/c; } + // inline real_v exp( const real_v& v ) { return exp512_ps(v) ; } + inline real_v select(const __mmask8& mask, const real_v& a, const real_v& b ) { return _mm512_mask_mov_pd( b, mask, a ); } + inline real_v select(const bool& mask , const real_v& a, const real_v& b ) { return mask ? a : b; } + inline real_v sign ( const real_v& v){ return select( v > 0., +1., -1. ); } + inline real_v atan2( const real_v& y, const real_v& x ){ + std::array bx{x.to_array()}, by{y.to_array()}; + return real_v ( + std::atan2(by[0], bx[0]) , std::atan2( by[1], bx[1]), std::atan2( by[2], bx[2]), std::atan2( by[3], bx[3]) , + std::atan2(by[4], bx[4]) , std::atan2( by[5], bx[5]), std::atan2( by[6], bx[6]), std::atan2( by[7], bx[7]) ); + } + inline __m512i double_to_int( const real_v& x ) + { + auto xr = _mm512_roundscale_pd(x, _MM_FROUND_TO_ZERO); + // based on: https://stackoverflow.com/questions/41144668/how-to-efficiently-perform-double-int64-conversions-with-sse-avx + return _mm512_sub_epi64(_mm512_castpd_si512(_mm512_add_pd(xr, _mm512_set1_pd(0x0018000000000000))), + _mm512_castpd_si512(_mm512_set1_pd(0x0018000000000000))); + } + inline real_v gather( const double* base_addr, const real_v& offsets) + { + return _mm512_i64gather_pd(double_to_int(offsets), base_addr, sizeof(double)); + } + + inline void frexp(const real_v& value, real_v& mant, real_v& exponent) + { + auto arg_as_int = _mm512_castpd_si512(value); + static const real_v offset(4503599627370496.0 + 1022.0); // 2^52 + 1022.0 + static const __m512i pow2_52_i = _mm512_set1_epi64(0x4330000000000000); // *reinterpret_cast(&pow2_52_d); + auto b = _mm512_srl_epi64(arg_as_int, _mm_cvtsi32_si128(52)); + auto c = _mm512_or_si512( b , pow2_52_i); + exponent = real_v( _mm512_castsi512_pd(c) ) - offset; + mant = _mm512_castsi512_pd(_mm512_or_si512(_mm512_and_si512 (arg_as_int, _mm512_set1_epi64(0x000FFFFFFFFFFFFFll) ), _mm512_set1_epi64(0x3FE0000000000000ll))); + } + + inline real_v fmadd( const real_v& a, const real_v& b, const real_v& c ) + { + return _mm512_fmadd_pd(a, b, c); + } + inline real_v log(const real_v& arg) + { + static const real_v corr = 0.693147180559945286226764; + static const real_v CL15 = 0.148197055177935105296783; + static const real_v CL13 = 0.153108178020442575739679; + static const real_v CL11 = 0.181837339521549679055568; + static const real_v CL9 = 0.22222194152736701733275; + static const real_v CL7 = 0.285714288030134544449368; + static const real_v CL5 = 0.399999999989941956712869; + static const real_v CL3 = 0.666666666666685503450651; + static const real_v CL1 = 2.0; + real_v mant, exponent; + frexp(arg, mant, exponent); + auto x = (mant - 1.) / (mant + 1.); + auto x2 = x * x; + auto p = fmadd(CL15, x2, CL13); + p = fmadd(p, x2, CL11); + p = fmadd(p, x2, CL9); + p = fmadd(p, x2, CL7); + p = fmadd(p, x2, CL5); + p = fmadd(p, x2, CL3); + p = fmadd(p, x2, CL1); + p = fmadd(p, x, corr * exponent); + return p; + } + stl_fallback( exp ) + stl_fallback( tan ) + stl_fallback( sin ) + stl_fallback( cos ) + inline real_v remainder( const real_v& a, const real_v& b ){ return a - real_v(_mm512_roundscale_pd(a/b, _MM_FROUND_TO_NEG_INF)) * b; } + inline real_v fmod( const real_v& a, const real_v& b ) + { + auto r = remainder( abs(a), abs(b) ); + return select( a > 0., r, -r ); + } + + struct complex_v { + real_v re; + real_v im; + static constexpr unsigned size = 8; + typedef std::complex scalar_type; + + real_v real() const { return re; } + real_v imag() const { return im; } + real_v norm() const { return re*re + im *im ; } + complex_v() = default; + complex_v( const real_v& re, const real_v& im) : re(re), im(im) {} + complex_v( const float& re, const float& im) : re(re), im(im) {} + complex_v( const std::complex& f ) : re( f.real() ), im( f.imag() ) {} + complex_v( const std::complex& f ) : re( f.real() ), im( f.imag() ) {} + explicit complex_v( const real_v& arg ) : re(arg) {}; + explicit complex_v( const double& arg ) : re(arg) {}; + const std::complex at(const unsigned i) const { return std::complex(re.to_array()[i], im.to_array()[i]) ; } + void store( double* sre, double* sim ){ re.store(sre); im.store(sim); } + void store( scalar_type* r ) const { + auto re_arr = re.to_array(); + auto im_arr = im.to_array(); + for( unsigned i = 0 ; i != re_arr.size(); ++i ) r[i] = scalar_type( re_arr[i], im_arr[i] ); + } + auto to_array() const + { + std::array rt; + store( rt.data() ); + return rt; + } + }; + + inline std::ostream& operator<<( std::ostream& os, const real_v& obj ) { + auto buffer = obj.to_array(); + for( unsigned i = 0 ; i != 8; ++i ) os << buffer[i] << " "; + return os; + } + inline real_v real(const complex_v& arg ){ return arg.re ; } + inline real_v imag(const complex_v& arg ){ return arg.im ; } + inline complex_v conj(const complex_v& arg ){ return complex_v(arg.re, -arg.im) ; } + inline real_v conj(const real_v& arg ){ return arg ; } + inline complex_v operator+( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re + rhs, lhs.im); } + inline complex_v operator-( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re - rhs, lhs.im); } + inline complex_v operator*( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re*rhs, lhs.im*rhs); } + inline complex_v operator/( const complex_v& lhs, const real_v& rhs ) { return complex_v(lhs.re/rhs, lhs.im/rhs); } + inline complex_v operator+( const real_v& lhs, const complex_v& rhs ) { return complex_v(lhs + rhs.re, rhs.im); } + inline complex_v operator-( const real_v& lhs, const complex_v& rhs ) { return complex_v(lhs - rhs.re, - rhs.im); } + inline complex_v operator*( const real_v& lhs, const complex_v& rhs ) { return complex_v(lhs*rhs.re, lhs*rhs.im); } + inline complex_v operator/( const real_v& lhs, const complex_v& rhs ) { return complex_v( lhs * rhs.re , -lhs *rhs.im) / (rhs.re * rhs.re + rhs.im * rhs.im ); } + inline complex_v operator+( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re + rhs.re, lhs.im + rhs.im); } + inline complex_v operator-( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re - rhs.re, lhs.im - rhs.im); } + inline complex_v operator*( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re*rhs.re - lhs.im*rhs.im, lhs.re*rhs.im + lhs.im*rhs.re); } + inline complex_v operator/( const complex_v& lhs, const complex_v& rhs ) { return complex_v(lhs.re*rhs.re + lhs.im*rhs.im, -lhs.re*rhs.im + lhs.im*rhs.re) / (rhs.re * rhs.re + rhs.im * rhs.im ); } + inline complex_v operator-( const complex_v& x ) { return -1.f * x; } + inline real_v abs( const complex_v& v ) { return sqrt( v.re * v.re + v.im * v.im ) ; } + inline real_v norm( const complex_v& v ) { return ( v.re * v.re + v.im * v.im ) ; } + inline complex_v select(const __mmask8& mask, const complex_v& a, const complex_v& b ) { return complex_v( select(mask, a.re, b.re), select(mask, a.im, b.im ) ) ; } + inline complex_v select(const __mmask8& mask, const real_v& a, const complex_v& b ) { return complex_v( select(mask, a , b.re), select(mask, 0.f, b.im) ); } + inline complex_v select(const __mmask8& mask, const complex_v& a, const real_v& b ) { return complex_v( select(mask, a.re, b ) , select(mask, a.im, 0.f) ); } + inline complex_v select(const bool& mask , const complex_v& a, const complex_v& b ) { return mask ? a : b; } + inline complex_v exp( const complex_v& v ){ + return exp( v.re) * complex_v( cos( v.im ), sin( v.im ) ); + } + inline complex_v sqrt( const complex_v& v ) + { + auto r = abs(v); + return complex_v ( sqrt( 0.5 * (r + v.re) ), sign(v.im) * sqrt( 0.5*( r - v.re ) ) ); + } + inline complex_v log( const complex_v& v ) + { + return complex_v( log( v.re ) , atan2(v.im, v.re) ); + } + + inline std::ostream& operator<<( std::ostream& os, const complex_v& obj ) { return os << "( "<< obj.re << ") (" << obj.im << ")"; } + #pragma omp declare reduction(+: real_v: \ + omp_out = omp_out + omp_in) + #pragma omp declare reduction(+: complex_v: \ + omp_out = omp_out + omp_in) + + } +} + +#endif diff --git a/AmpGen/simd/iterator.h b/AmpGen/simd/iterator.h new file mode 100644 index 00000000000..3949a0a44ea --- /dev/null +++ b/AmpGen/simd/iterator.h @@ -0,0 +1,45 @@ +#include + +namespace AmpGen { + template class scatter_iterator + { + store_type* m_store; + std::array m_buffer; + size_t m_pos{0}; + public: + int pos() const { return m_pos ; } + scatter_iterator( const size_t& pos, store_type* store ) : + m_store(store), + m_pos(pos) { + if( m_store != nullptr && pos < m_store->aligned_size()) m_buffer = m_store->scatter(pos / simd_size ); + } + stored_type* operator->() const { return &( m_buffer )[m_pos % simd_size]; } + stored_type operator*() const { return m_buffer [m_pos % simd_size]; } + stored_type& operator*() { return m_buffer [m_pos % simd_size]; } + scatter_iterator& operator++() + { + m_pos++; + if ( m_pos % simd_size == 0 ) + { + if constexpr(modifiable == true ) m_store->gather(m_buffer, (m_pos-1) / simd_size); + m_buffer = m_store->scatter( m_pos ); + } + return *this; + } + ~scatter_iterator() + { + if constexpr(modifiable == true) + { + if(m_store != nullptr && m_pos % simd_size != 0 ){ + m_store->gather(m_buffer, m_pos/simd_size); + } + } + } + bool operator==( const scatter_iterator& rhs ) const { return m_pos == rhs.m_pos ; } + bool operator!=( const scatter_iterator& rhs ) const { return m_pos != rhs.m_pos ; } + friend int operator-( const scatter_iterator& lhs, const scatter_iterator& rhs) { return lhs.pos() - rhs.pos() ; } + }; + template + auto make_scatter_iterator( const unsigned& pos, store_type* store) { + return scatter_iterator(pos, store) ; } +} diff --git a/AmpGen/simd/utils.h b/AmpGen/simd/utils.h new file mode 100644 index 00000000000..12c0ecf6c51 --- /dev/null +++ b/AmpGen/simd/utils.h @@ -0,0 +1,112 @@ +#ifndef AMPGEN_SIMD_UTILS_H +#define AMPGEN_SIMD_UTILS_H + +#include +#include + +#if ENABLE_AVX512 + #include "AmpGen/simd/avx512d_types.h" +#elif ENABLE_AVX2d + #include "AmpGen/simd/avx2d_types.h" +#elif ENABLE_AVX2f + #include "AmpGen/simd/avx2f_types.h" +#endif + + + +namespace AmpGen { +#if ENABLE_AVX512 + namespace AVX = AVX512d; +#elif ENABLE_AVX2d + namespace AVX = AVX2d; +#elif ENABLE_AVX2f + namespace AVX = AVX2f; +#endif + +#if ENABLE_AVX + using float_v = AVX::real_v; + using complex_v = AVX::complex_v; +#else + using float_v = double; + using complex_v = std::complex; +#endif + + namespace utils { + + template struct is_vector_type : std::false_type {}; + template struct size { static constexpr unsigned value = 1; } ; +#if ENABLE_AVX + template <> struct is_vector_type : std::true_type {}; + template <> struct is_vector_type : std::true_type {}; + template <> struct size { static constexpr unsigned value = AVX::complex_v::size; }; + template <> struct size { static constexpr unsigned value = AVX::complex_v::size; }; +#endif + template simd_type gather( + const container_type& container, const functor_type& functor, unsigned offset=0, typename simd_type::scalar_type df =0.) + { + std::array rv; + if( df == 0. ) + for( unsigned k = 0 ; k != simd_type::size; ++k ) rv[k] = offset + k < container.size() ? functor(container[offset+k]) : functor(container[container.size()-1]); + else + for( unsigned k = 0 ; k != simd_type::size; ++k ) rv[k] = offset + k < container.size() ? functor(container[offset+k]) : df; + return simd_type( rv.data() ); + } + + template size_t aligned_size( const size_t& unaligned_size ) { + return size::value * unsigned ( 1 + (unaligned_size -1 ) / size::value ); + } + template auto sum_elements( const simd_type& obj ) + { + if constexpr ( is_vector_type::value ) + { + auto arr = obj.to_array(); + auto rt = arr[0]; + for( unsigned i = 1 ; i != size::value; ++i ) rt = rt + arr[i]; + return rt; + } + else return obj; + } + template bool all_of( const simd_type& obj, const value_type& v ) + { + if constexpr( size::value == 1 ) return obj == v; + if constexpr( size::value == 4 ) return _mm256_movemask_pd( obj == v ) == 0xF; + if constexpr( size::value == 8 ) return _mm256_movemask_ps( obj == v ) == 0xFF; + return false; + } + template bool all_of( const simd_type& obj) + { + if constexpr( ! is_vector_type::value ) return obj; + else return _mm256_movemask_pd( obj ) == 0xF; + } + template auto get( vtype v ) + { + if constexpr ( is_vector_type::value ) return v.at(p); + if constexpr ( ! is_vector_type::value ) return v; + } + template < class vtype> auto at( vtype v, const unsigned p=0 ) + { + if constexpr ( is_vector_type::value ) return v.at(p); + if constexpr ( ! is_vector_type::value ) return v; + } + template auto norm( const ctype& v ) + { + #if ENABLE_AVX + if constexpr( is_vector_type::value ) return AVX::norm(v); + #endif + if constexpr( ! is_vector_type::value ) return std::norm(v); + } + template void store( store_type* container, const type& v) + { + if constexpr( is_vector_type::value ) + { + auto arr = v.to_array(); + for( unsigned k = 0 ; k != utils::size::value; ++k ) container[k] = arr[k]; + } + else { + *container = v; + } + } + } +} + +#endif diff --git a/AmpGenConfig.cmake.in b/AmpGenConfig.cmake.in new file mode 100644 index 00000000000..01d34c5eeec --- /dev/null +++ b/AmpGenConfig.cmake.in @@ -0,0 +1,18 @@ +# - Config file for the AmpGen package +# It defines the following variables +# AMPGEN_INCLUDE_DIRS - include directories for AmpGen +# AMPGEN_LIBRARIES - libraries to link against +# AMPGEN_EXECUTABLE - the bar executable + +# Compute paths +get_filename_component(AMPGEN_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +set(AMPGEN_INCLUDE_DIRS "@PROJECT_SOURCE_DIR@") +set(USE_OPENMP "@USE_OPENMP@") +# Our library dependencies (contains definitions for IMPORTED targets) +if(NOT TARGET AmpGen AND NOT AmpGen_BINARY_DIR) + include("@CMAKE_BINARY_DIR@/AmpGenTargets.cmake") +endif() + +# These are IMPORTED targets created by FooBarTargets.cmake +set(AMPGEN_LIBRARIES AmpGen) + diff --git a/CMakeLists.txt b/CMakeLists.txt index 63017dab540..1cea6e70ded 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,33 +2,281 @@ # Package: AmpGen ################################################################################ -# Support standalone build -if(COMMAND gaudi_subdir) - gaudi_subdir(AmpGen v1r1) - - find_package(ROOT COMPONENTS RIO Hist Matrix Graf Minuit2 Tree MathMore MathCore Physics) - find_package(TBB REQUIRED) - find_package(GSL REQUIRED) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp -Wno-unused-parameter -ldl") - set(AmpGen_VERSION_MAJOR "1") - set(AmpGen_VERSION_MINOR "1") - set(AMPGEN_CXX ${CMAKE_CXX_COMPILER} CACHE FILEPATH "This should be the path to compiler (use which c++ for macOS)" ) - configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/AmpGen/Version.h.in" "${CMAKE_CURRENT_SOURCE_DIR}/AmpGen/Version.h") - gaudi_add_library(AmpGen - src/*.cpp - src/Lineshapes/*.cpp - NO_PUBLIC_HEADERS - INCLUDE_DIRS ROOT - LINK_LIBRARIES ROOT TBB GSL) - target_compile_definitions(AmpGen PUBLIC "AMPGEN_CXX=\"${AMPGEN_CXX}\"") - foreach(app Generator Fitter ConvertToSourceCode) - gaudi_add_executable(${app} apps/${app}.cpp - LINK_LIBRARIES AmpGen) - endforeach() +cmake_minimum_required(VERSION 3.9...3.15) + +if(${CMAKE_VERSION} VERSION_LESS 3.12) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +endif() + +project(AmpGen LANGUAGES CXX VERSION 2.1) + +set(AMPGEN_CXX ${CMAKE_CXX_COMPILER} CACHE FILEPATH "This should be the path to compiler (use which c++ for macOS)" ) + +file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/CMakeLists.txt" LOC_PATH) +if(EXISTS "${LOC_PATH}") + message(FATAL_ERROR "You cannot build in a source directory (or any directory with a CMakeLists.txt file). Please make a build subdirectory. Feel free to remove CMakeCache.txt and CMakeFiles.") +endif() + +file(GLOB_RECURSE AMPGEN_SRC src/*) +file(GLOB_RECURSE AMPGEN_HDR AmpGen/*) + +set(CMAKE_CXX_STANDARD "17" CACHE STRING "CMAKE_CXX_STANDARD") +set(USE_SIMD "AVX2d" CACHE STRING "USE_SIMD") # AVX instruction set + precision to use +set(USE_OPENMP TRUE CACHE BOOL "USE_OPENMP") # flag to use openmp for threading +set(USE_MVEC TRUE CACHE BOOL "USE_MVEC") # flag to use vector math library mvec +set(ENABLE_FITTING TRUE CACHE BOOL "ENABLE_FITTING") # flag to enable fitting (requires Minuit2) +set(ENABLE_TESTS TRUE CACHE BOOL "ENABLE_TESTS") # flag to build unit tests +set(BUILTIN_GSL TRUE CACHE BOOL "BUILTIN_GSL") # flag to use ROOT's builtin GSL +set(ENABLE_INSTALL TRUE CACHE BOOL "ENABLE_INSTALL") # flag to enable installs (switched off to make Travis happier) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin") +set(CMAKE_TEST_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/test") + +include(CMakeDependentOption) +include(CMakePrintHelpers) +include(GNUInstallDirs) + +option(AMPGEN_DEBUG "AmpGen Debug printout") +option(AMPGEN_TRACE "AmpGen Trace printout") + +configure_file ("${PROJECT_SOURCE_DIR}/AmpGen/Version.h.in" "${CMAKE_BINARY_DIR}/AmpGenVersion.h") + +add_library(${PROJECT_NAME} SHARED ${AMPGEN_SRC} ${AMPGEN_HDR}) +add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) + +if(NOT DEFINED ROOT_LIBRARIES) + if(DEFINED ENV{ROOTSYS}) + list(APPEND CMAKE_MODULE_PATH "$ENV{ROOTSYS}/etc/cmake/") + endif() + find_package(ROOT COMPONENTS Matrix MathMore MathCore Gpad Tree Graf) +else() + string( REPLACE ":" " " ROOT_LIBRARIES ${ROOT_LIBRARIES}) + separate_arguments(ROOT_LIBRARIES) +endif() + +if( NOT BUILTIN_GSL OR DEFINED GSL_LIBRARIES ) + if( NOT DEFINED GSL_LIBRARIES ) + find_package(GSL) + else() + string( REPLACE ":" " " GSL_LIBRARIES ${GSL_LIBRARIES}) + separate_arguments(GSL_LIBRARIES) + endif() +endif() + +if( USE_OPENMP ) + find_package(OpenMP) +endif() + +# Default build type from the Kitware Blog +set(default_build_type "Release") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +target_include_directories(AmpGen PUBLIC $ $ ) + +target_include_directories(AmpGen PUBLIC ${ROOT_INCLUDE_DIRS} ) + +target_link_libraries(AmpGen PUBLIC -lm "${ROOT_LIBRARIES}" ${CMAKE_DL_LIBS} "${GSL_LIBRARIES}" ) + +find_library(libmvec mvec) + +if ( USE_MVEC AND libmvec ) + message( STATUS "Using libmvec for vectorised math operations") + target_link_libraries(AmpGen PUBLIC mvec) + target_compile_definitions(AmpGen PUBLIC "USE_MVEC=1") +else() + message( STATUS "Warning: libmvec not found, with use scalar math where necessary.") + target_compile_definitions(AmpGen PUBLIC "USE_MVEC=0") +endif() + +if( ENABLE_FITTING ) + if( ( NOT TARGET ROOT::Minuit2 AND NOT TARGET Minuit2 ) OR "${extern_minuit2}" ) + message( STATUS "Use external Minuit2") + add_subdirectory("extern/Minuit2") + set_target_properties(Minuit2 PROPERTIES FOLDER extern) + target_compile_options(Minuit2 PUBLIC -fPIC -Wno-suggest-override) + set_target_properties(Minuit2Math PROPERTIES FOLDER extern) + add_library(ROOT::Minuit2 ALIAS Minuit2) + target_include_directories( AmpGen PUBLIC "${CMAKE_SOURCE_DIR}/extern/Minuit2/inc/") + else() + message( STATUS "Use ROOT::Minuit2") + endif() + if ( TARGET Minuit2 AND NOT TARGET ROOT::Minuit2 ) + find_package( ROOT CONFIG REQUIRED COMPONENTS Minuit2) + add_library(ROOT::Minuit2 ALIAS Minuit2) + endif() + target_link_libraries(AmpGen PUBLIC ROOT::Minuit2 ) +else() + message(STATUS "Disable fitting") +endif() + + +if( USE_OPENMP ) + target_compile_definitions(AmpGen PUBLIC "USE_OPENMP=1") + if(OpenMP_FOUND OR OpenMP_CXX_FOUND) + if(NOT TARGET OpenMP::OpenMP_CXX) + add_library(OpenMP::OpenMP_CXX IMPORTED INTERFACE) + set_property(TARGET OpenMP::OpenMP_CXX PROPERTY INTERFACE_COMPILE_OPTIONS ${OpenMP_CXX_FLAGS}) + set_property(TARGET OpenMP::OpenMP_CXX PROPERTY INTERFACE_LINK_LIBRARIES ${OpenMP_CXX_FLAGS}) + if(CMAKE_VERSION VERSION_LESS 3.4) + set_property(TARGET OpenMP::OpenMP_CXX APPEND PROPERTY INTERFACE_LINK_LIBRARIES -pthread) + else() + find_package(Threads REQUIRED) + set_property(TARGET OpenMP::OpenMP_CXX APPEND PROPERTY INTERFACE_LINK_LIBRARIES Threads::Threads) + endif() + endif() + target_link_libraries(AmpGen PUBLIC OpenMP::OpenMP_CXX) + else() + message(STATUS "OpenMP not found for CXX, you might have forgotten lb-run ROOT bash or CXX=`which g++` in CERN stack") + endif() +else() + target_compile_definitions(AmpGen PUBLIC "USE_OPENMP=0") +endif() + +if( DEFINED TBB_LIBRARIES ) + target_link_libraries(AmpGen PUBLIC ${TBB_LIBRARIES}) +endif() + +# Default to XROOTD only if on CMT system. Can be overridden with -DAMPGEN_XROOTD=ON +if(DEFINED ENV{CMTCONFIG}) + set(AMPGEN_XROOTD_DEFAULT ON) +else() + set(AMPGEN_XROOTD_DEFAULT OFF) +endif() + +cmake_dependent_option(AMPGEN_XROOTD "Turn on XROOTD discovery" ON "AMPGEN_XROOTD_DEFAULT" OFF) + +if(AMPGEN_XROOTD) + find_library(XROOTD_LIB NAMES libXrdCl.so + HINTS "/cvmfs/lhcb.cern.ch/lib/lcg/releases/LCG_89/xrootd/4.6.0/$ENV{CMTCONFIG}/lib64") + target_link_libraries(AmpGen PUBLIC ${XROOTD_LIB}) +endif() + +target_compile_definitions(AmpGen PRIVATE + "AMPGENROOT_CMAKE=\"${CMAKE_BINARY_DIR}/bin\"" + "AMPGENROOT=\"${PROJECT_SOURCE_DIR}\"" + "AMPGEN_CXX=\"${AMPGEN_CXX}\"" + $<$:DEBUGLEVEL=1> + $<$:TRACELEVEL=1>) + + +target_compile_options(AmpGen + INTERFACE + -Wall -Wextra -Wpedantic -g3 + -Wno-unused-parameter + -Wno-unknown-pragmas + $<$:-O3>) + +if ( ${USE_SIMD} MATCHES "AVX2d" ) + message(STATUS "Enabling AVX2 [double precision]") + target_compile_definitions(AmpGen PUBLIC "ENABLE_AVX=1" "ENABLE_AVX2d=1") + target_compile_options(AmpGen PUBLIC -march=native -ftree-vectorize -mavx2 -ffast-math -DHAVE_AVX2_INSTRUCTIONS) +elseif ( ${USE_SIMD} MATCHES "AVX2f" ) + message(STATUS "Enabling AVX2 [single precision]") + target_compile_definitions(AmpGen PUBLIC "ENABLE_AVX=1" "ENABLE_AVX2f=1") + target_compile_options(AmpGen PUBLIC -march=native -ftree-vectorize -mavx2 -ffast-math -DHAVE_AVX2_INSTRUCTIONS) +elseif ( ${USE_SIMD} MATCHES "AVX512d" ) + message(STATUS "Enabling AVX2 [double precision]") + target_compile_definitions(AmpGen PUBLIC "ENABLE_AVX=1" "ENABLE_AVX512=1") + target_compile_options(AmpGen PUBLIC -march=native -ftree-vectorize -mavx512f -ffast-math -DHAVE_AVX512_INSTRUCTIONS) +else() + target_compile_definitions(AmpGen PUBLIC "ENABLE_AVX=0") + target_compile_options(AmpGen PUBLIC -march=x86-64) + message(STATUS "SIMD disabled, resorting to scalar build : ${USE_SIMD}") +endif() + +if(${CMAKE_CXX_COMPILER_ID} MATCHES "AppleClang" OR + ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" ) + target_compile_options(AmpGen PUBLIC -mfma) +endif() + +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "AppleClang" ) + target_link_libraries(AmpGen PUBLIC stdc++ ) + message(STATUS "Using OSX specific flags: -lm -lstdc++ -lSystem") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lm -lstdc++ -lSystem") +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + target_link_libraries(AmpGen PUBLIC stdc++) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lm -lstdc++") else() - cmake_minimum_required(VERSION 3.3) - project(AmpGen LANGUAGES CXX VERSION 1.1) - include(Standalone.cmake) + target_compile_options(AmpGen PUBLIC -Wno-suggest-override) +endif() + +# build the applications and examples + +file(GLOB_RECURSE applications apps/*.cpp examples/*.cpp ) +foreach( file ${applications} ) + get_filename_component( Executable ${file} NAME_WE ) + add_executable(${Executable}.exe ${file}) + target_compile_options(${Executable}.exe PUBLIC -g3 -Ofast) + target_link_libraries(${Executable}.exe PUBLIC AmpGen ) + target_include_directories(${Executable}.exe PRIVATE ${ROOT_INCLUDE_DIRS}) +endforeach() + +# symlink the options files (so as there is the mass_width etc.) to the build directory, and also the release notes +file(GLOB_RECURSE options_files options/*.*) +execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin") +foreach(file ${options_files}) + get_filename_component(OptionFile "${file}" NAME) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${file}" "${CMAKE_BINARY_DIR}/bin/${OptionFile}") +endforeach() +execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_SOURCE_DIR}/doc/release.notes" "${CMAKE_BINARY_DIR}/bin/release.notes") + +if( ENABLE_TESTS ) + enable_testing() + set(Boost_NO_BOOST_CMAKE ON) + add_subdirectory(test) +endif() + + +# stuff related to export, install and version tagging + +include(CMakePackageConfigHelpers) +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/AmpGenVersion.cmake VERSION ${PACKAGE_VERSION} COMPATIBILITY AnyNewerVersion) + +set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) +set(LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}) +set(DATA_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/AmpGen) + +configure_package_config_file(AmpGenConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/AmpGenConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/AmpGen/cmake + PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR DATA_INSTALL_DIR + ) + +if( ENABLE_INSTALL ) + install( FILES ${CMAKE_CURRENT_BINARY_DIR}/AmpGenConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/AmpGenVersion.cmake + DESTINATION ${CMAKE_INSTALL_DATADIR}/AmpGen/cmake) + + install( + TARGETS ${PROJECT_NAME} + EXPORT AmpGenTargets + LIBRARY DESTINATION lib + PUBLIC_HEADER DESTINATION AmpGen + ) + + install( + TARGETS AmpGen.exe + DESTINATION bin + ) + + install(EXPORT "AmpGenTargets" + NAMESPACE "AmpGen::" + DESTINATION ${CMAKE_INSTALL_DATADIR}/AmpGen/cmake + ) + + export( TARGETS AmpGen NAMESPACE AmpGen:: FILE AmpGenTargets.cmake ) + set(CMAKE_EXPORT_PACKAGE_REGISTRY ON) + export(PACKAGE AmpGen) endif() diff --git a/README.md b/README.md index d6277d15b6e..75c5c8cee01 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,66 @@ + + +[![Build Status][travis-badge]][travis-link] +[![License: LGPL v3][license-badge]](./LICENSE) +

- +

AmpGen is a library and set of applications for fitting and generating multi-body particle decays using the isobar model. It developed out of the MINT project used in the fitting of three and four-body pseudoscalar decays by the CLEO-c and LHCb colloborations. The library can handle the fitting and generation of a wide variety of final states, including those involving fermions and photons, as well as polarised initial states. -Source code for the evaluation of amplitudes is dynamically generated by a custom engine, JIT compiled and dynamically linked to the user programme at runtime, which results in high flexibility and performance. +Source code for the evaluation of amplitudes is dynamically generated by a custom engine, JIT compiled and dynamically linked to the user programme at runtime, which results in high flexibility and performance. -## Table of Contents +## Table of Contents * [Getting Started](#getting-started) * [Applications](#applications) * [Examples](#examples) * [Advanced](#advanced) -* [API documentation](https://tevans1260.gitlab.io/AmpGen/) +* [API documentation](https://goofit.github.io/AmpGen/) * [Acknowledgements](#acknowledgements) ## Getting started - ### Installation #### Getting the source Clone with git ``` -git clone http://gitlab.com/tevans1260/AmpGen.git --recursive +git clone http://github.com/GooFit/AmpGen/ --recursive ``` -There is at the time of writing only a master branch (FIXME) + ##### Build requirements: -* cmake >= 3.11.0 -* C++ compiler with CXX standard >= 14 (gcc >= 4.9.3, clang ~ 5). +* cmake >= 3.11.0 +* C++ compiler with CXX standard >= 14 (gcc >= 4.9.3, clang ~ 5). Defaults to Cxx17 (enable cxx14 with cmake flag `-DCMAKE_CXX_STANDARD=14` ) * ROOT >= 6 with MathMore - To (re)configure root with these options, use the additional command line options `-Dcxx14 -Dmathmore=ON` when configuring the installation of ROOT. + To (re)configure root with these options, use the additional command line options `-Dcxx14 -Dmathmore=ON` when configuring the installation of ROOT. ##### Optional: -* boost >= 1.67.0 for unit tests -* xROOTd for network file access +* boost >= 1.67.0 for unit tests +* xROOTd for network file access * OpenMP for multithreading -* ROOT >= 6 with MathMore and Minuit2 enabled. The external version of Minuit2 provided as an external package of GooFit is used if the ROOT version is not unavailable. - To (re)configure root with these options, use the additional command line options `-Dcxx14 -Dminuit2=ON -Dmathmore=ON` when configuring the installation of ROOT. +* ROOT >= 6 with MathMore and Minuit2 enabled. The external version of Minuit2 provided as an external package of GooFit is used if the ROOT version is not unavailable. + To (re)configure root with these options, use the additional command line options `-Dcxx14 -Dminuit2=ON -Dmathmore=ON` when configuring the installation of ROOT. #### Building -The configuration of the AmpGen build is performed by cmake. -It is recommended to use a build directory to keep the source tree clean. +The configuration of the AmpGen build is performed by cmake. +It is recommended to use a build directory to keep the source tree clean. ```shell mkdir build cd build cmake .. -make +make +make install #optional# ``` This will build the shared library, several standalone test applications, and a set of unit tests. #### Usage with ROOT -The library can be used interactively in conjunction with the ROOT C++ interpreter by adding the following lines -to the users root login script +The library can be used interactively in conjunction with the ROOT C++ interpreter by adding the following lines +to the users root login script -``` +```c++ gSystem->Load("path_to_ampgen/build/lib/libAmpGen.so"); gROOT->ProcessLine(".include path_to_ampgen"); ``` @@ -64,159 +69,245 @@ You can also build AmpGen with LLVM. The only change you might want when using A is to specifically specify the location of the build tool for AmpGen's JIT: ```shell --DAMPGEN_CXX=$(which c++) +-DAMPGEN_CXX=\$(which c++) ``` -##### CentOS7 +##### LXPLUS -In order to build stand-alone on CentOS7, you will need a valid development environment; the following line will work: +A valid development environment is required to build the library on LXPLUS and similar. The easiest way to provide this is via cvmfs views where available, as this provides the necessary versions of gcc in addition to the ROOT libraries in a coherent manner, which can be used as -```shell -lb-run ROOT $SHELL +```` +source /cvmfs/sft.cern.ch/lcg/views/setupViews.sh LCG_94python3 x86_64-centos7-gcc8-opt +```` + +The LCG versions and binary tag may need to be updated over time. + +Several examples of usages of the library are included in apps and examples directories and are built alongside the library. All standalone programs can accept both options files and command line arguments. Also supported is the `--help` option to print instructions for key arguments to the program. + +#### Using SIMD instructions. + +AmpGen (v > 2.0) can be setup to generate vectorised code for faster evaluation of amplitudes / computation of integrals on compatible hardware. Such extensions can be enabled by setting the providing the flag +``` +-DUSE_SIMD=AVX2d ``` -Several examples of usages of the library are included in the apps directory and are -built alongside the library. -All standalone programs can accept both options files and command line arguments. -They also support `--help` to print help for key arguments to the program. -This will also run the program, as arguments can be defined throughout each of the programs rather than all defined at the beginning. +to cmake. This tells AmpGen that code should be generated using the AVX2 instruction set using double precision. Single precision is also supported, but not recommended for fitting. The support for SIMD instructions is often limited on batch systems, and therefore it is often useful to also have a build with these instruction switched off, which can be done using -### Options files and decay descriptors +``` +-DUSE_SIMD=0 +``` + +### Options files and decay descriptors -Options files will generally contain the description of one or more particle decays, -as well as other settings such as input/output locations, global flags such as -whether complex numbers should be interpreted as cartesian or polar, and other parameters -such as the masses and widths of particles is these differ from those given in the PDG. - -A minimal example options file for the generator application could contain: +Options files will generally contain the description of one or more particle decays, as well as other settings such as input/output locations, global flags such as whether complex numbers should be interpreted as cartesian or polar, and other parameters such as the masses and widths of particles is these differ from those given in the PDG. + +A minimal example options file for the generator application could contain: ``` EventType D0 K+ pi- pi- pi+ -# Real / Amplitude | Imaginary / Phase +# Real / Amplitude | Imaginary / Phase # Fix? Value Step | Fix? Value Step D0{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}} 2 1 0 2 0 0 ``` -The EventType specifies the initial and final states requested by the user. -This gives the ordering of particles used in input data, in output code, and used in internal computations. -This also defines how the amplitude source code must be interfaced with external packages, i.e. MC generators such as EvtGen. +The EventType specifies the initial and final states requested by the user. This gives the ordering of particles used in input data, in output code, and used in internal computations. This also defines how the amplitude source code must be interfaced with external packages, i.e. MC generators such as EvtGen. The decay products of a particle are enclosed within curly braces, for example ``` K*(892)0{K+,pi-} ``` -describes an excited vector kaon decaying into a charged kaon and pion. -For more details about the API for describing particle decays, see [AmpGen::Particle](https://tevans1260.gitlab.io/AmpGen/de/dd7/class_amp_gen_1_1_particle.html). -The other numbers on the lines that describe the decays parameterise the coupling to this channel, -either in terms of real and imaginary parts or an amplitude and a phase. -Each parameter is specified in terms of three numbers: the _fix_ flag, the initial value, and the step size. -The possible options for the _fix_ flag are: +describes an excited vector kaon decaying into a charged kaon and pion. For more details about the API for describing particle decays, see [AmpGen::Particle](https://goofit.github.io/AmpGen/de/dd7/class_amp_gen_1_1_particle.html) The other numbers on the lines that describe the decays parameterise the coupling to this channel, +either in terms of real and imaginary parts or an amplitude and a phase. Each parameter is specified in terms of three numbers: the _fix_ flag, the initial value, and the step size. +The possible options for the _fix_ flag are: + * Free (fix=0) and a step size of not 0. * Fixed (fix=2, for historical reasons) -* Compile-Time-Constant (fix=3) which indicates that the parameter should be treated as a (JIT) compile time constant, which in some cases allows for more aggressive optimisations to be performed. +* Compile-Time-Constant (fix=3) which indicates that the parameter should be treated as a (JIT) compile time constant, which in some cases allows for more aggressive optimisations to be performed. -These options can be used in the Generator application, which is described below. +These options can be used in the AmpGen application, which is described below. Decays can either be specified fully inline, as above, or split into multiple steps, which is useful for treating the so called _cascade_ decays, an example of which is shown below. ``` D0{K(1)(1270)+,pi-} 0 1 0.1 0 0 0.1 - +Type K(1)(1270)+{rho(770)0{pi+,pi-},K+} 2 1 0 2 0 0 K(1)(1270)+{K*(892)0{K+,pi-},pi+} 0 1 0.1 0 0 0.1 ``` -The production/decay couplings of the K(1270) resonance are now defined in terms of the coupling to the rho(770),K+ channel, -which can be useful in making comparisons between different production modes of a resonance. -Additional care must be taken in such a case to not introduce redundant degrees of freedom. +The production/decay couplings of the resonance are now defined in terms of the coupling to the channel, which can be useful in making comparisons between different production modes of a resonance. Additional care must be taken in such a case so as not to introduce redundant degrees of freedom. -Configuration can be split over multiple files by the using _Import_ keyword, for example, to import the parameters for the isoscalar K-matrix, the line +Configuration can be split over multiple files by the using _Import_ keyword, for example, to import the parameters for the parameters associated with the isoscalar K-matrix, the line ``` -Import $AMPGENROOT/options/kMatrix.opt +Import \$AMPGENROOT/options/kMatrix.opt ``` -can be added to options file. Multiple user configuration files can also be specified by including multiple files on the command line. + +can be added to options file. Multiple user configuration files can also be specified by including multiple files on the command line. + +#### PDF Types + +AmpGen supports several different types of probability density functions (PDFs), which are detailed in this section. + +##### CoherentSum + +The most common type of PDF is the CoherentSum. In this case, the total amplitude is given by the sum of amplitudes, weighted by complex coefficients. At a position in the phase space , the transition amplitude is given by: + + + +and the corresponding probability density is proportional to . The CoherentSum is the default amplitude in many cases, and is used to describe the decay of a single, (pseudo)scalar particle to two or more (pseudo)scalar decay products. + +##### PolarisedSum + +The initial and/or final state(s) may also carry spin, in which case the spin states must also be summed. The transition matrix can be written in the isobar model as + + , + +where and label the initial and final states, respectively. As these states are in principal observables, the indices related to spin must be summed incoherently. The probability density function in this case is therefore given by + + , + +where is the relevant density matrix for the initial state, which is given by 1 for a scalar initial state. For a spin- state, the density matrix can be parameterised in terms of a polarisation vector and the Pauli matrices , and is given by: + + + +For a spin-1 initial state, the density matrix is parameterised in terms of the Gell-Mann matrices, , as + + , + +where now the polarisation 'vector' has 8 components. + +##### IncoherentSum + +An alternative model is the IncoherentSum, which may be useful to describe the probability density of a background contribution that contains incoherent sources with several different resonances. Generally, such models are only useful for relatively small backgrounds in relatively pure samples, as in general background contributions cannot be described with such a simple parameterisation. In this case, the probability is given by an incoherent sum of amplitudes: + + ## Applications -This section details the prebuilt command line applications that use the AmpGen library for some common functionality, such as generating Toy Monte Carlo samples -and debugging amplitudes. + +This section details the prebuilt command line applications that use the AmpGen library for some common functionality, such as generating Toy Monte Carlo samples and debugging amplitudes. ### Table of contents -* [Generator](#generator) +* [AmpGen](#AmpGen) * [Debugger](#debugger) -* [ConvertToSourceCode](#converttosourcecode) +* [LibDiff](#LibDiff) +* [DataConverter](#DataConverter) -### Generator +### AmpGen -The standalone generator for models can be used as +The standalone generator (named AmpGen) is used as: ```shell -Generator MyOpts.opt --nEvents=10000 --Output=output.root +AmpGen.exe MyOpts.opt --nEvents=10000 --Output=output.root ``` -Which generates 10000 events of the model described in MyOpts.opt and saves them to output.root. -The output should include a tree (DalitzEventList) of candidates with the full four-vectors, as well as one- and two-dimensional projections, an example of which is shown below: +where MyOpts.opt contains the options described in the previous section that describe the decay the user wishes to generate, and the optional arguments `nEvents` and `Output` given the number of events requested and the output file, respectively. The full list of application specific arguments can be obtained by: -![s01](doc/figs/s01.png) +```bash +AmpGen.exe --help +``` -In particular, the tree indicates the way in which data is by default loaded into the _Event_ / _EventList_ class. +The output includes a tree (DalitzEventList) of candidates with the full four-vectors, as well as one- and two-dimensional projections, an example of which is shown below: -### Debugger +

+ +

-The debugger application is a tool for producing verbose information debugging for amplitudes and models. It is used on an options file as -``` -./Debugger MyOpts.opt +Several models for different decays published by the LHCb collaboration are included in the options directory, in addition to several other decay modes to demonstrate different features. These options often do not include EventTypes so as they can be included as part of a larger decay chain if required. For example, to generate toy decays, the type of the events requested must also be specified: + +```shell +AmpGen.exe options/D02Kpipipi.opt --EventType "D0 K- pi+ pi+ pi-" --nEvents 1000000 ``` -which calculates each amplitude at a randomly generated point in phase space, as well as calculating the total amplitude accounting for complex -couplings. Also computed is the amplitude for the P conjugate event. A more useful application is the _verbose_ debugging mode which can be -activated by + +The standalone generator can also be used to only produce the source code that evaluates the amplitude, to be used by other generators such as EvtGen. In this case, the PDF is automatically normalised such that . The code can be generated and compiled into a shared library as follows +```shell +AmpGen.exe MyOpts.opt --Output=MyModel.cpp --SourceOnly +g++ -Ofast -shared -rdynamic --std=c++14 -fPIC MyModel.cpp -o MyModel.so ``` -./Debugger MyOpts.opt --CoherentSum::Debug +Decays can also be specified entirely on the command line in order to quickly study the distributions of different decay modes. For example, to generate a sample of 10000 decays, + +```shell +AmpGen.exe --Decay "Lambda(b)0{p+,K*(892)bar-{K-,pi0}}" --nEvents 10000 --Type PolarisedSum ``` -which produces a large number of intermediate steps in the calculation of each amplitude, which are added to the calculation using the -ADD_DEBUG and ADD_DEBUG_TENSOR macros in the code generation. For example, in src/Lineshapes/BW.cpp. -### ConvertToSourceCode +The flag `Type` is used to specify that the initial and/or final states includes at least one particle carrying spin, and thus polarisation must be taken into account. The output is both the full event kinematics, as well as projections of the different invariant masses shown below: + +

+

+ + +
+

+ +#### Phase space generators + +Generating events consists of two phases. Firstly, the kinematics of candidates are generated according to some distribution, by default uniform in the phase space. The target distribution, , is then obtained using the accept-reject method. A candidate generated at position in the phase space is retained on the condition that + + , + +where is the largest possible value of , and is a random number uniformly drawn between 0 and 1. + +​ The generation can be made more efficient by making the first step produce candidates that are distributed more closely to the full distribution than the uniform phase space. In particular, this is relevant for producing very narrow structures such as the resonance efficiently. To use this option, the flag `PhaseSpace` should be set to the value `TreePhaseSpace`. For example, to generate a sample of decays: -This produces source code to evaluate the PDF, and normalises for use with other generators such as EvtGen, i.e. P(max) < 1. This can be used as ```shell -./ConvertToSourceCode MyOpts.opt --Output=MyFile.cpp +AmpGen.exe --Decay "Lambda(b)0{J/psi0{mu+,mu-},Lambda(1405)0{p+,pi-}}" --nEvents 1000000 --Type PolarisedSum --PhaseSpace TreePhaseSpace ``` -This can then be a compiled to a shared library using -```shell -g++ -Ofast -shared -rdynamic --std=c++14 -fPIC MyFile.cpp -o MyFile.so + +Two example projections are shown below, of the dimuon invariant mass with essentially no width, which would be virtually impossible to generate with a uniform distribution and the naive accept-reject method, and the combined mass of the dimuon with the proton from the decay: + +

+

+ + +
+

+ +### Debugger + +The debugger application is a tool for producing verbose information debugging for amplitudes and models. It is used on an options file as + ``` +Debugger.exe MyOpts.opt +``` +which calculates each amplitude at a randomly generated point in phase space, as well as calculating the total amplitude accounting for complex couplings. + +A more useful application is the _verbose_ debugging mode which can be activated by + +``` +Debugger.exe MyOpts.opt --CoherentSum::Debug +``` +which produces a large number of intermediate steps in the calculation of each amplitude, which are added to the calculation using the ADD_DEBUG and ADD_DEBUG_TENSOR macros in the code generation. For example, in src/Lineshapes/BW.cpp. +If the model is a PolarisedSum, i.e. handles spin in the initial/final state, the flag PolarisedSum::Debug should be used instead of CoherentSum::Debug. + +### LibDiff +### DataConvertor ## Examples ### SignalOnlyFitter -An example fitter is provided in _examples/SignalOnlyFitter.cpp_, which as the name suggests only has a single signal component in the fit. -The free parameters of the fit are specified in the same way as the Generator, -with the additional relevant slots being _DataSample_ which specifies the signal sample to fit, -which is presumed to already have the selection applied, and _Branches_ which takes a list of branch names, -and defaults to the format used by the Generator etc. More details can be found with -``` -SignalOnlyFitter --help +An example fitter is provided in _examples/SignalOnlyFitter.cpp_, which as the name suggests only has a single signal component in the fit. The free parameters of the fit are specified in the same way as the Generator, with the additional relevant slots being _DataSample_ which specifies the signal sample to fit, which is presumed to already have the selection applied, and _Branches_ which takes a list of branch names, and defaults to the format used by the Generator. More details can be found with +```shell +SignalOnlyFitter.exe --help ``` For example, the fitter can be used to fit a toy MC sample generated by the generator by running: -``` -Generator MyOpts.opt --nEvents 100000 -SignalOnlyFitter MyOpts.opt --DataSample Generate_Output.root +```shell +AmpGen.exe MyOpts.opt --nEvents 100000 +SignalOnlyFitter.exe MyOpts.opt --DataSample Generate_Output.root ``` -## Advanced +## Advanced -This section contains miscellaneous details on more advanced functionality, including using python bindings and alternative parameterisation of the spin factors. +This section contains miscellaneous details on more advanced functionality, including using python bindings and alternative parameterisations of the spin factors. ### Table of contents * [Python Bindings](#python-bindings) * [Particle Properties and Lineshape parameters](#particle-properties-and-lineshape-parameters) * [Fit parameters and expressions](#fit-parameters-and-expressions) * [Spin Formalisms](#spin-formalisms) - +* [Quasiparticles](#quasiparticles) ### Python Bindings Models built into a shared library can be used in python using the following flags into ConvertToSourceCode: -```shell -./ConvertToSourceCode MyOpts.opt --Output=MyFile.cpp --OutputEvents=events.csv --IncludePythonBindings +```shell +./AmpGen.exe MyOpts.opt --Output=MyFile.cpp --SourceOnly --OutputEvents=events.csv --IncludePythonBindings ``` -where normalisation events are also output for testing purposes in events.csv. +where normalisation events are also output for testing purposes in events.csv. This can then be used with the python bindings in ampgen.py: ```python from ampgen import FixedLib @@ -232,51 +323,46 @@ fcn2 = data.apply(model.FCN, axis=1) ``` ### Particle Properties and Lineshape parameters -The particles available and their default properties can be found in *options/mass\_width.csv* using the MC format of the 2008 PDG. -Additional pseudoparticles, such as nonresonant states and terms for use in conjunction with K-matrices are defined by *options/MintDalitzSpecialParticles.csv*. -Any additional user defined particles should be added here. -For the default lineshape (the relavistic Breit-Wigner or BW), there are three parameters: The mass, the width and the Blatt-Weisskopf radius. -These default to their PDG values, but can be overridden in the options file with parameters: *particleName*\_mass, *particleName*\_width, *particleName*\_radius. -So if the K(1270)+ mass was allowed to vary, the line: +The particles available and their default properties can be found in *options/mass\_width.csv* using the MC format of the 2008 PDG. Additional pseudoparticles, such as nonresonant states and terms for use in conjunction with K-matrices are defined by *options/MintDalitzSpecialParticles.csv*. Any additional user defined particles should be added here. For the default lineshape (the relavistic Breit-Wigner or BW), there are three parameters: The mass, the width and the Blatt-Weisskopf radius. These default to their PDG values, but can be overridden in the options file with parameters: *particleName*\_mass, *particleName*\_width, *particleName*\_radius. To vary the mass of the meson, the line: ``` -K(1270)+_mass 0 1.270 0.01 +K(1)(1270)+_mass 0 1.270 0.01 ``` -could be added to the user configuration. -Other lineshapes may define other parameters, for example channel couplings or pole masses in the case of the K-matrices, which can be set or varied in a similar manner. +could be added to the user configuration. +Other lineshapes may define other parameters, for example channel couplings or pole masses in the case of the K-matrices, can be set or varied in a similar manner. ### Fit parameters and expressions -Parameters can either be specified by three parameters, in the case of a scalar parameter such as a mass or a width, or with six parameters in the case of a complex parameter such as a coupling. -Upper and lower bounds on parameters can also be set by specifying a parameter with five parameters or ten parameters for a scalar or complex, respectively. -For example, if we wished to vary the K(1)(1270)+ mass in the above example, but restricting the allowed values in the range \[0.0,2.0\] GeV: +Parameters can either be specified by three parameters, in the case of a scalar parameter such as a mass or a width, or with six parameters in the case of a complex parameter such as a coupling. +Upper and lower bounds on parameters can also be set by specifying a parameter with five parameters or ten parameters for a scalar or complex, respectively. +For example, if we wished to vary the mass of the meson in the above example, but restricting the allowed values in the range : ``` K(1)(1270)+_mass 0 1.27 0.01 0.0 2.0 ``` -(Scalar) parameters can also be related to each other via simple expressions, although the implementation of this is rather unreliable so should be used with caution. -Suppose for example we have K(1)(1270)+ and K(1)(1270)bar- in the same fit (for example, for D-\>KKpipi) -The properties of one can be allowed to vary, for example the K(1)(1270)+, and the other fixed to the same value, using: +Parameters can also be related to each other via expressions, +Suppose for example we have and in the same fit (for example, in ) +The properties of one can be allowed to vary, for example the , and the other fixed to the same value, using: ``` -K(1)(1270)+_mass 0 1.27 0.01 0.0 2.0 -K(1)(1270)bar-_mass = K(1)(1270)+_mass +K(1)(1270)+_mass 0 1.27 0.01 0.0 2.0 +K(1)(1270)bar-_mass = K(1)(1270)+_mass ``` -Due to the abundance of **odd** glyphs such as brackets and +/- in parameter names, parameter expressions are white space delimited and somewhat sensitive to bracket usage. +Parameter expressions are whitespace delimited due to the abundance of **odd** glyphs such as brackets and +/- in the names of parameters. +Expressions support the binary operations , as well as common unary functions such as sqrt, trigonometric functions etc. ### Spin Formalisms -AmpGen implements both the covariant tensor (or Rarita-Schwinger) and canonical helicity formalism for describing the angular momentum component of decays. -Both formalisms refer to states of well-defined orbital angular momentum, as opposed to the helicity states, as the states with well-defined orbital angular momentum have a straightforward parity and momentum dependences. -The default formalism is the covariant tensor formalism, but this can be switched to the canonical formalism changing the flag +AmpGen implements both the covariant tensor (or Rarita-Schwinger) and canonical helicity formalism for describing the angular momentum component of decays. +Both formalisms refer to states of well-defined orbital angular momentum, as opposed to the helicity states, as the states with well-defined orbital angular momentum have a straightforward parity and momentum dependences. +The default formalism is the covariant tensor formalism, but this can be switched to the canonical formalism changing the flag ``` -Particle::SpinFormalism Canonical ## default = Covariant +Particle::SpinFormalism Canonical ``` -in the options file. -The spin formalism for an individual decay chain can be specified by changing the attribute SpinFormalism in the decay descriptor. For example, +in the options file. +The spin formalism for an individual decay chain can be specified by changing the attribute SpinFormalism in the decay descriptor. For example, ``` D0[SpinFormalism=Canonical]{K*(892)bar0,rho(770)0} ``` -selects the S-wave of the K*, rho system. The user can also specify systems of helicity couplings in the canonical formalism, using the attribute _helAmp_. -For example, suppose the transversity amplitudes were used rather than the canonical, then the user can specify +selects the S-wave of the system. The user can also specify systems of helicity couplings in the canonical formalism, using the attribute _helAmp_. For example, suppose the transversity amplitudes were used rather than the canonical, then the user can specify ``` D0[SpinFormalism=Canonical;helAmp=Long]{K*(892)bar0,rho(770)0} D0[SpinFormalism=Canonical;helAmp=t1]{K*(892)bar0,rho(770)0} @@ -298,17 +384,42 @@ t2 { -0.707106781 -1 -1 } ``` -That is specified as sets of three numbers, firstly the coupling, and then the two particle helicities. So in this example, the longitudinal amplitude is the 00 helicity state, while the two transverse amplitudes and the sum and difference of the two other helicity amplitudes. +That is specified as sets of three numbers, firstly the coupling, and then the two particle helicities. So in this example, the longitudinal amplitude is the helicity state, while the two transverse amplitudes and the sum and difference of the two other helicity amplitudes. + +### Quasiparticles +Quasiparticles are fictional decaying particles that can be implemented in the decay chain for a variety of different purposes. The original use case was to group some amplitudes with the same quantum numbers with couplings that want to be factorised. +For example, for the -wave, the K matrix description may be used. The coupling from the initial state may be written as + +``` +D0{K0S0,NonResS0} ... +``` +The quasiparticle _NonResS0_ can then be decayed to the final state via the K matrix lineshape(s) +``` +NonResS0[kMatrix.pole.0]{pi+,pi-} ... +NonResS0[kMatrix.pole.1]{pi+,pi-} ... +... +``` +where each of the .X is one of the terms of the (pole) production vector. +In this example, an equivalent formulation would be +``` +D0{K0S0,NonResS0[kMatrix.pole.0]{pi+,pi-}} ... +D0{K0S0,NonResS0[kMatrix.pole.1]{pi+,pi-}} ... +... +``` ## Acknowledgements The development of this software has been supported by the National Science Foundation under grant PHY-1414736 and through a subcontract under Cooperative Agreement OAC-1836650. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the developers and do not necessarily reflect the views of the National Science Foundation.

- - - + + +

+[travis-badge]: https://travis-ci.org/GooFit/AmpGen.svg?branch=master +[license-badge]: https://img.shields.io/badge/License-GPL%20v2-blue.svg +[travis-link]: https://travis-ci.org/GooFit/AmpGen + diff --git a/README.tex.md b/README.tex.md new file mode 100644 index 00000000000..4ebda4aca94 --- /dev/null +++ b/README.tex.md @@ -0,0 +1,427 @@ + + +[![Build Status][travis-badge]][travis-link] +[![License: LGPL v3][license-badge]](./LICENSE) + +

+ +

+AmpGen is a library and set of applications for fitting and generating multi-body particle decays using the isobar model. +It developed out of the MINT project used in the fitting of three and four-body pseudoscalar decays by the CLEO-c and LHCb colloborations. The library can handle the fitting and generation of a wide variety of final states, including those involving fermions and photons, as well as polarised initial states. + +Source code for the evaluation of amplitudes is dynamically generated by a custom engine, JIT compiled and dynamically linked to the user programme at runtime, which results in high flexibility and performance. + +## Table of Contents +* [Getting Started](#getting-started) +* [Applications](#applications) +* [Examples](#examples) +* [Advanced](#advanced) +* [API documentation](https://goofit.github.io/AmpGen/) +* [Acknowledgements](#acknowledgements) + +## Getting started +### Installation +#### Getting the source +Clone with git +``` +git clone http://github.com/GooFit/AmpGen/ --recursive +``` + + +##### Build requirements: +* cmake >= 3.11.0 +* C++ compiler with CXX standard >= 14 (gcc >= 4.9.3, clang ~ 5). + Defaults to Cxx17 (enable cxx14 with cmake flag `-DCMAKE_CXX_STANDARD=14` ) +* ROOT >= 6 with MathMore + To (re)configure root with these options, use the additional command line options `-Dcxx14 -Dmathmore=ON` when configuring the installation of ROOT. + +##### Optional: +* boost >= 1.67.0 for unit tests +* xROOTd for network file access +* OpenMP for multithreading +* ROOT >= 6 with MathMore and Minuit2 enabled. The external version of Minuit2 provided as an external package of GooFit is used if the ROOT version is not unavailable. + To (re)configure root with these options, use the additional command line options `-Dcxx14 -Dminuit2=ON -Dmathmore=ON` when configuring the installation of ROOT. + +#### Building +The configuration of the AmpGen build is performed by cmake. +It is recommended to use a build directory to keep the source tree clean. + +```shell +mkdir build +cd build +cmake .. +make +make install #optional# +``` +This will build the shared library, several standalone test applications, and a set of unit tests. + +#### Usage with ROOT + +The library can be used interactively in conjunction with the ROOT C++ interpreter by adding the following lines +to the users root login script + +```c++ + gSystem->Load("path_to_ampgen/build/lib/libAmpGen.so"); + gROOT->ProcessLine(".include path_to_ampgen"); +``` +##### LLVM +You can also build AmpGen with LLVM. The only change you might want when using Apple LLVM +is to specifically specify the location of the build tool for AmpGen's JIT: + +```shell +-DAMPGEN_CXX=\$(which c++) +``` + +##### LXPLUS + +A valid development environment is required to build the library on LXPLUS and similar. The easiest way to provide this is via cvmfs views where available, as this provides the necessary versions of gcc in addition to the ROOT libraries in a coherent manner, which can be used as + +```` +source /cvmfs/sft.cern.ch/lcg/views/setupViews.sh LCG_94python3 x86_64-centos7-gcc8-opt +```` + +The LCG versions and binary tag may need to be updated over time. + +Several examples of usages of the library are included in apps and examples directories and are built alongside the library. All standalone programs can accept both options files and command line arguments. Also supported is the `--help` option to print instructions for key arguments to the program. + +#### Using SIMD instructions. + +AmpGen (v > 2.0) can be setup to generate vectorised code for faster evaluation of amplitudes / computation of integrals on compatible hardware. Such extensions can be enabled by setting the providing the flag +``` +-DUSE_SIMD=AVX2d +``` +to cmake. This tells AmpGen that code should be generated using the AVX2 instruction set using double precision. Single precision is also supported, but not recommended for fitting. The support for SIMD instructions is often limited on batch systems, and therefore it is often useful to also have a build with these instruction switched off, which can be done using + +``` +-DUSE_SIMD=0 +``` + +### Options files and decay descriptors + +Options files will generally contain the description of one or more particle decays, as well as other settings such as input/output locations, global flags such as whether complex numbers should be interpreted as cartesian or polar, and other parameters such as the masses and widths of particles is these differ from those given in the PDG. + +A minimal example options file for the generator application could contain: +``` +EventType D0 K+ pi- pi- pi+ +# Real / Amplitude | Imaginary / Phase +# Fix? Value Step | Fix? Value Step +D0{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}} 2 1 0 2 0 0 +``` +The EventType specifies the initial and final states requested by the user. This gives the ordering of particles used in input data, in output code, and used in internal computations. This also defines how the amplitude source code must be interfaced with external packages, i.e. MC generators such as EvtGen. + +The decay products of a particle are enclosed within curly braces, for example +``` +K*(892)0{K+,pi-} +``` +describes an excited vector kaon decaying into a charged kaon and pion. For more details about the API for describing particle decays, see [AmpGen::Particle](https://goofit.github.io/AmpGen/de/dd7/class_amp_gen_1_1_particle.html) The other numbers on the lines that describe the decays parameterise the coupling to this channel, +either in terms of real and imaginary parts or an amplitude and a phase. Each parameter is specified in terms of three numbers: the _fix_ flag, the initial value, and the step size. +The possible options for the _fix_ flag are: + +* Free (fix=0) and a step size of not 0. +* Fixed (fix=2, for historical reasons) +* Compile-Time-Constant (fix=3) which indicates that the parameter should be treated as a (JIT) compile time constant, which in some cases allows for more aggressive optimisations to be performed. + +These options can be used in the AmpGen application, which is described below. + +Decays can either be specified fully inline, as above, or split into multiple steps, which is useful for treating the so called _cascade_ decays, an example of which is shown below. +``` +D0{K(1)(1270)+,pi-} 0 1 0.1 0 0 0.1 +Type +K(1)(1270)+{rho(770)0{pi+,pi-},K+} 2 1 0 2 0 0 +K(1)(1270)+{K*(892)0{K+,pi-},pi+} 0 1 0.1 0 0 0.1 +``` +The production/decay couplings of the $K_1(1270)^+$ resonance are now defined in terms of the coupling to the $\rho(770)^0 K^+$ channel, which can be useful in making comparisons between different production modes of a resonance. Additional care must be taken in such a case so as not to introduce redundant degrees of freedom. + +Configuration can be split over multiple files by the using _Import_ keyword, for example, to import the parameters for the parameters associated with the isoscalar K-matrix, the line +``` +Import \$AMPGENROOT/options/kMatrix.opt +``` + +can be added to options file. Multiple user configuration files can also be specified by including multiple files on the command line. + +#### PDF Types + +AmpGen supports several different types of probability density functions (PDFs), which are detailed in this section. + +##### CoherentSum + +The most common type of PDF is the CoherentSum. In this case, the total amplitude is given by the sum of amplitudes, weighted by complex coefficients. At a position in the phase space $\mathbf{x}$, the transition amplitude $\mathcal{T}$ is given by: + +$\mathcal{T}(\mathbf{x}) = \sum_{k} g_k A_k (\mathbf{x})$ + +and the corresponding probability density is proportional to $\mathcal{P}(\mathbf{x})\propto \left|\mathcal{T}(\mathbf{x})\right|^2$. The CoherentSum is the default amplitude in many cases, and is used to describe the decay of a single, (pseudo)scalar particle to two or more (pseudo)scalar decay products. + +##### PolarisedSum + +The initial and/or final state(s) may also carry spin, in which case the spin states must also be summed. The transition matrix can be written in the isobar model as + +$\mathcal{T}_{if} = \sum_k g_k \mathcal{T}^{k}_{if}(\mathbf{x})$, + +where $i$ and $f$ label the initial and final states, respectively. As these states are in principal observables, the indices related to spin must be summed incoherently. The probability density function in this case is therefore given by + +$\mathcal{P}(\mathbf{x}) = \sum_{if} \hat{\rho}_{ij} T_{if}(\mathbf{x}) T^{*}_{jf}(\mathbf{x}) $, + +where $\hat{\rho}$ is the relevant density matrix for the initial state, which is given by 1 for a scalar initial state. For a spin-$\frac{1}{2}$ state, the density matrix can be parameterised in terms of a polarisation vector $p_i$ and the Pauli matrices $\sigma_i$, and is given by: + +$\hat{\rho} = I + \sigma_i p_i$ + +For a spin-1 initial state, the density matrix is parameterised in terms of the Gell-Mann matrices, $\lambda_k$, as + +$\hat{\rho} = I + \lambda_k p_k$, + +where now the polarisation 'vector' $p_k$ has 8 components. + +##### IncoherentSum + +An alternative model is the IncoherentSum, which may be useful to describe the probability density of a background contribution that contains incoherent sources with several different resonances. Generally, such models are only useful for relatively small backgrounds in relatively pure samples, as in general background contributions cannot be described with such a simple parameterisation. In this case, the probability is given by an incoherent sum of amplitudes: + +$\mathcal{P}(\mathbf{x}) = \sum_k g_k^2 \left| A_k \right|^2 $ + +## Applications + +This section details the prebuilt command line applications that use the AmpGen library for some common functionality, such as generating Toy Monte Carlo samples and debugging amplitudes. + +### Table of contents +* [AmpGen](#AmpGen) +* [Debugger](#debugger) +* [LibDiff](#LibDiff) +* [DataConverter](#DataConverter) + +### AmpGen + +The standalone generator (named AmpGen) is used as: + +```shell +AmpGen.exe MyOpts.opt --nEvents=10000 --Output=output.root +``` + +where MyOpts.opt contains the options described in the previous section that describe the decay the user wishes to generate, and the optional arguments `nEvents` and `Output` given the number of events requested and the output file, respectively. The full list of application specific arguments can be obtained by: + +```bash +AmpGen.exe --help +``` + +The output includes a tree (DalitzEventList) of candidates with the full four-vectors, as well as one- and two-dimensional projections, an example of which is shown below: + +

+ +

+ + +Several models for different $D^0$ decays published by the LHCb collaboration are included in the options directory, in addition to several other decay modes to demonstrate different features. These options often do not include EventTypes so as they can be included as part of a larger decay chain if required. For example, to generate $10^6$ toy $\Dz\to\Km\pip\pip\pim$ decays, the type of the events requested must also be specified: + +```shell +AmpGen.exe options/D02Kpipipi.opt --EventType "D0 K- pi+ pi+ pi-" --nEvents 1000000 +``` + +The standalone generator can also be used to only produce the source code that evaluates the amplitude, to be used by other generators such as EvtGen. In this case, the PDF is automatically normalised such that $\mathcal{P}_{\text{max}} < 1$ . The code can be generated and compiled into a shared library as follows +```shell +AmpGen.exe MyOpts.opt --Output=MyModel.cpp --SourceOnly +g++ -Ofast -shared -rdynamic --std=c++14 -fPIC MyModel.cpp -o MyModel.so +``` +Decays can also be specified entirely on the command line in order to quickly study the distributions of different decay modes. For example, to generate a sample of 10000 $\Lambda_b \to p K^{*-}$ decays, + +```shell +AmpGen.exe --Decay "Lambda(b)0{p+,K*(892)bar-{K-,pi0}}" --nEvents 10000 --Type PolarisedSum +``` + +The flag `Type` is used to specify that the initial and/or final states includes at least one particle carrying spin, and thus polarisation must be taken into account. The output is both the full event kinematics, as well as projections of the different invariant masses shown below: + +

+

+ + +
+

+ + +#### Phase space generators + +Generating events consists of two phases. Firstly, the kinematics of candidates are generated according to some distribution, by default uniform in the phase space. The target distribution, $\mathcal{P}(\mathbf{x})$ , is then obtained using the accept-reject method. A candidate generated at position $\mathbf{x}$ in the phase space is retained on the condition that + + $\mathcal{P}(\mathbf{x}) > \mathcal{P}_{\text{max}} \times \texttt{Uniform}(0,1) $, + +where $\mathcal{P}_{\text{max}}$ is the largest possible value of $\mathcal{P}(\mathbf{x})$ , and $\texttt{Uniform}(0,1)$ is a random number uniformly drawn between 0 and 1. + +​ The generation can be made more efficient by making the first step produce candidates that are distributed more closely to the full distribution than the uniform phase space. In particular, this is relevant for producing very narrow structures such as the $J/\psi$ resonance efficiently. To use this option, the flag `PhaseSpace` should be set to the value `TreePhaseSpace`. For example, to generate a sample of $10^6$ $\Lambda_b^0 \to J/\psi \left[\mu^+\mu^-\right]\Lambda(1405)^0 \left[p^+ \pi^-\right]$ decays: + +```shell +AmpGen.exe --Decay "Lambda(b)0{J/psi0{mu+,mu-},Lambda(1405)0{p+,pi-}}" --nEvents 1000000 --Type PolarisedSum --PhaseSpace TreePhaseSpace +``` + +Two example projections are shown below, of the dimuon invariant mass with essentially no width, which would be virtually impossible to generate with a uniform distribution and the naive accept-reject method, and the combined mass of the dimuon with the proton from the $\Lambda(1405)^0$ decay: + +

+

+ + +
+

+ + +### Debugger + +The debugger application is a tool for producing verbose information debugging for amplitudes and models. It is used on an options file as + +``` +Debugger.exe MyOpts.opt +``` +which calculates each amplitude at a randomly generated point in phase space, as well as calculating the total amplitude accounting for complex couplings. + +A more useful application is the _verbose_ debugging mode which can be activated by + +``` +Debugger.exe MyOpts.opt --CoherentSum::Debug +``` +which produces a large number of intermediate steps in the calculation of each amplitude, which are added to the calculation using the ADD_DEBUG and ADD_DEBUG_TENSOR macros in the code generation. For example, in src/Lineshapes/BW.cpp. +If the model is a PolarisedSum, i.e. handles spin in the initial/final state, the flag PolarisedSum::Debug should be used instead of CoherentSum::Debug. + +### LibDiff + +### DataConvertor + +## Examples + +### SignalOnlyFitter + +An example fitter is provided in _examples/SignalOnlyFitter.cpp_, which as the name suggests only has a single signal component in the fit. The free parameters of the fit are specified in the same way as the Generator, with the additional relevant slots being _DataSample_ which specifies the signal sample to fit, which is presumed to already have the selection applied, and _Branches_ which takes a list of branch names, and defaults to the format used by the Generator. More details can be found with +```shell +SignalOnlyFitter.exe --help +``` +For example, the fitter can be used to fit a toy MC sample generated by the generator by running: +```shell +AmpGen.exe MyOpts.opt --nEvents 100000 +SignalOnlyFitter.exe MyOpts.opt --DataSample Generate_Output.root +``` + +## Advanced + +This section contains miscellaneous details on more advanced functionality, including using python bindings and alternative parameterisations of the spin factors. + +### Table of contents +* [Python Bindings](#python-bindings) +* [Particle Properties and Lineshape parameters](#particle-properties-and-lineshape-parameters) +* [Fit parameters and expressions](#fit-parameters-and-expressions) +* [Spin Formalisms](#spin-formalisms) +* [Quasiparticles](#quasiparticles) + +### Python Bindings +Models built into a shared library can be used in python using the following flags into ConvertToSourceCode: +```shell +./AmpGen.exe MyOpts.opt --Output=MyFile.cpp --SourceOnly --OutputEvents=events.csv --IncludePythonBindings +``` +where normalisation events are also output for testing purposes in events.csv. +This can then be used with the python bindings in ampgen.py: +```python +from ampgen import FixedLib +model = FixedLib('MyModel.so') +print(model.matrix_elements[0]) # Print first matrix element + +import pandas as pd +data = pd.read_csv('events.csv', nrows=100_000) +fcn1 = model.FCN_all(data) + +# or, a bit slower, but just to show flexibility: +fcn2 = data.apply(model.FCN, axis=1) +``` + +### Particle Properties and Lineshape parameters +The particles available and their default properties can be found in *options/mass\_width.csv* using the MC format of the 2008 PDG. Additional pseudoparticles, such as nonresonant states and terms for use in conjunction with K-matrices are defined by *options/MintDalitzSpecialParticles.csv*. Any additional user defined particles should be added here. For the default lineshape (the relavistic Breit-Wigner or BW), there are three parameters: The mass, the width and the Blatt-Weisskopf radius. These default to their PDG values, but can be overridden in the options file with parameters: *particleName*\_mass, *particleName*\_width, *particleName*\_radius. To vary the mass of the $K_1(1270)^+$ meson, the line: +``` +K(1)(1270)+_mass 0 1.270 0.01 +``` +could be added to the user configuration. +Other lineshapes may define other parameters, for example channel couplings or pole masses in the case of the K-matrices, can be set or varied in a similar manner. + +### Fit parameters and expressions + +Parameters can either be specified by three parameters, in the case of a scalar parameter such as a mass or a width, or with six parameters in the case of a complex parameter such as a coupling. +Upper and lower bounds on parameters can also be set by specifying a parameter with five parameters or ten parameters for a scalar or complex, respectively. +For example, if we wished to vary the mass of the $K_1(1270)^+$ meson in the above example, but restricting the allowed values in the range $[0.0,2.0]\,\mathrm{GeV}$: +``` +K(1)(1270)+_mass 0 1.27 0.01 0.0 2.0 +``` + +Parameters can also be related to each other via expressions, +Suppose for example we have $K_1(1270)^+$ and $K_1(1270)^-$ in the same fit (for example, in $D^0 \to K^- K^+ \pi^- \pi^+$) +The properties of one can be allowed to vary, for example the $K_1(1270)^+$, and the other fixed to the same value, using: +``` +K(1)(1270)+_mass 0 1.27 0.01 0.0 2.0 +K(1)(1270)bar-_mass = K(1)(1270)+_mass +``` +Parameter expressions are whitespace delimited due to the abundance of **odd** glyphs such as brackets and +/- in the names of parameters. +Expressions support the binary operations $(+,-,/,* )$, as well as common unary functions such as sqrt, trigonometric functions etc. + +### Spin Formalisms + +AmpGen implements both the covariant tensor (or Rarita-Schwinger) and canonical helicity formalism for describing the angular momentum component of decays. +Both formalisms refer to states of well-defined orbital angular momentum, as opposed to the helicity states, as the states with well-defined orbital angular momentum have a straightforward parity and momentum dependences. +The default formalism is the covariant tensor formalism, but this can be switched to the canonical formalism changing the flag +``` +Particle::SpinFormalism Canonical +``` +in the options file. +The spin formalism for an individual decay chain can be specified by changing the attribute SpinFormalism in the decay descriptor. For example, +``` +D0[SpinFormalism=Canonical]{K*(892)bar0,rho(770)0} +``` +selects the S-wave of the $K^* \rho$ system. The user can also specify systems of helicity couplings in the canonical formalism, using the attribute _helAmp_. For example, suppose the transversity amplitudes were used rather than the canonical, then the user can specify +``` +D0[SpinFormalism=Canonical;helAmp=Long]{K*(892)bar0,rho(770)0} +D0[SpinFormalism=Canonical;helAmp=t1]{K*(892)bar0,rho(770)0} +D0[SpinFormalism=Canonical;helAmp=t2]{K*(892)bar0,rho(770)0} +``` +For the longitudinal and two transverse amplitudes. These must then be defined by the user in terms of the helicity amplitudes in the following structure: +``` +Long { + 1.0 0 0 +} + +t1 { + 0.707106781 +1 +1 + 0.707106781 -1 -1 +} + +t2 { + 0.707106781 +1 +1 + -0.707106781 -1 -1 +} +``` +That is specified as sets of three numbers, firstly the coupling, and then the two particle helicities. So in this example, the longitudinal amplitude is the $00$ helicity state, while the two transverse amplitudes and the sum and difference of the two other helicity amplitudes. + +### Quasiparticles + +Quasiparticles are fictional decaying particles that can be implemented in the decay chain for a variety of different purposes. The original use case was to group some amplitudes with the same quantum numbers with couplings that want to be factorised. +For example, for the $I=0$ $S$-wave, the K matrix description may be used. The coupling from the initial state may be written as + +``` +D0{K0S0,NonResS0} ... +``` +The quasiparticle _NonResS0_ can then be decayed to the final state via the K matrix lineshape(s) +``` +NonResS0[kMatrix.pole.0]{pi+,pi-} ... +NonResS0[kMatrix.pole.1]{pi+,pi-} ... +... +``` +where each of the .X is one of the terms of the (pole) production vector. +In this example, an equivalent formulation would be +``` +D0{K0S0,NonResS0[kMatrix.pole.0]{pi+,pi-}} ... +D0{K0S0,NonResS0[kMatrix.pole.1]{pi+,pi-}} ... +... +``` + +## Acknowledgements +The development of this software has been supported by the National Science Foundation under grant PHY-1414736 and through a subcontract under Cooperative Agreement OAC-1836650. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the developers and do not necessarily reflect the views of the National Science Foundation. + +

+

+ + + +
+

+ +[travis-badge]: https://travis-ci.org/GooFit/AmpGen.svg?branch=master +[license-badge]: https://img.shields.io/badge/License-GPL%20v2-blue.svg +[travis-link]: https://travis-ci.org/GooFit/AmpGen diff --git a/Standalone.cmake b/Standalone.cmake deleted file mode 100644 index e3b6e0ecad2..00000000000 --- a/Standalone.cmake +++ /dev/null @@ -1,180 +0,0 @@ -set(AMPGEN_CXX ${CMAKE_CXX_COMPILER} CACHE FILEPATH "This should be the path to compiler (use which c++ for macOS)" ) - -file(GLOB_RECURSE AMPGEN_SRC src/*) -file(GLOB_RECURSE AMPGEN_HDR AmpGen/*) - - -if( NOT "${CMAKE_CXX_STANDARD}" ) - set(CMAKE_CXX_STANDARD 14) -endif() - -set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin") -set(CMAKE_TEST_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/test") - -include(CMakeDependentOption) -include(CMakePrintHelpers) - -option(AMPGEN_DEBUG "AmpGen Debug printout") -option(AMPGEN_TRACE "AmpGen Trace printout") - -configure_file ("${PROJECT_SOURCE_DIR}/AmpGen/Version.h.in" "${PROJECT_SOURCE_DIR}/AmpGen/Version.h") - -add_library(AmpGen SHARED ${AMPGEN_SRC} ${AMPGEN_HDR}) - -if(DEFINED ENV{ROOTSYS}) - list(APPEND CMAKE_MODULE_PATH "$ENV{ROOTSYS}/etc/cmake/") -endif() - -find_package(ROOT CONFIG REQUIRED COMPONENTS Matrix MathMore MathCore Gpad Tree Graf) -find_package(OpenMP) - -cmake_print_variables(CMAKE_SOURCE_DIR) - -# Default build type from the Kitware Blog -set(default_build_type "Release") -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to '${default_build_type}' as none was specified.") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE - STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Release" "MinSizeRel" "RelWithDebInfo") -endif() - -message( STATUS "ROOT_INCLUDE_DIRS = ${ROOT_INCLUDE_DIRS}") - -target_include_directories(AmpGen PUBLIC "${CMAKE_SOURCE_DIR}") - -target_include_directories(AmpGen SYSTEM PUBLIC "${ROOT_INCLUDE_DIRS}") - -target_link_libraries(AmpGen PUBLIC ${ROOT_LIBRARIES} ${CMAKE_DL_LIBS}) - -if( ( NOT TARGET ROOT::Minuit2 AND NOT TARGET Minuit2 ) OR "${extern_minuit2}" ) - message( STATUS "Use external Minuit2") - add_subdirectory("extern/Minuit2") - set_target_properties(Minuit2 PROPERTIES FOLDER extern) - target_compile_options(Minuit2 PUBLIC -fPIC -Wno-suggest-override) - set_target_properties(Minuit2Math PROPERTIES FOLDER extern) - add_library(ROOT::Minuit2 ALIAS Minuit2) - target_include_directories( AmpGen PUBLIC "${CMAKE_SOURCE_DIR}/extern/Minuit2/inc/") -else() - message( STATUS "Use ROOT::Minuit2") -endif() -if ( TARGET Minuit2 AND NOT TARGET ROOT::Minuit2 ) - find_package( ROOT CONFIG REQUIRED COMPONENTS Minuit2) - add_library(ROOT::Minuit2 ALIAS Minuit2) -endif() - -target_link_libraries(AmpGen PUBLIC ROOT::Minuit2 ) - - -if(OpenMP_FOUND OR OpenMP_CXX_FOUND) - if(NOT TARGET OpenMP::OpenMP_CXX) - add_library(OpenMP::OpenMP_CXX IMPORTED INTERFACE) - set_property(TARGET OpenMP::OpenMP_CXX PROPERTY INTERFACE_COMPILE_OPTIONS ${OpenMP_CXX_FLAGS}) - set_property(TARGET OpenMP::OpenMP_CXX PROPERTY INTERFACE_LINK_LIBRARIES ${OpenMP_CXX_FLAGS}) - if(CMAKE_VERSION VERSION_LESS 3.4) - set_property(TARGET OpenMP::OpenMP_CXX APPEND PROPERTY INTERFACE_LINK_LIBRARIES -pthread) - else() - find_package(Threads REQUIRED) - set_property(TARGET OpenMP::OpenMP_CXX APPEND PROPERTY INTERFACE_LINK_LIBRARIES Threads::Threads) - endif() - endif() - target_link_libraries(AmpGen PUBLIC OpenMP::OpenMP_CXX) -else() - message(STATUS "OpenMP not found for CXX, you might have forgotten lb-run ROOT bash or CXX=`which g++` in CERN stack") -endif() - -# Default to XROOTD only if on CMT system. Can be overridden with -DAMPGEN_XROOTD=ON -if(DEFINED ENV{CMTCONFIG}) - set(AMPGEN_XROOTD_DEFAULT ON) -else() - set(AMPGEN_XROOTD_DEFAULT OFF) -endif() - -cmake_dependent_option(AMPGEN_XROOTD "Turn on XROOTD discovery" ON "AMPGEN_XROOTD_DEFAULT" OFF) - -if(AMPGEN_XROOTD) - find_library(XROOTD_LIB NAMES libXrdCl.so - HINTS "/cvmfs/lhcb.cern.ch/lib/lcg/releases/LCG_89/xrootd/4.6.0/$ENV{CMTCONFIG}/lib64") - target_link_libraries(AmpGen PUBLIC ${XROOTD_LIB}) -endif() - -target_compile_definitions(AmpGen - PUBLIC - "AMPGENROOT_CMAKE=\"${CMAKE_BINARY_DIR}/bin\"" - "AMPGEN_CXX=\"${AMPGEN_CXX}\"" - $<$:DEBUGLEVEL=1> - $<$:TRACELEVEL=1>) - -target_compile_options(AmpGen - PUBLIC - -Wall -Wextra -Wpedantic -g3 - -Wno-unused-parameter - -Wno-unknown-pragmas - -Wnon-virtual-dtor - -Woverloaded-virtual - $<$:-Ofast>) - -if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lm -lstdc++") -else() - target_compile_options(AmpGen PUBLIC -Wsuggest-override) -endif() - -file(GLOB_RECURSE applications apps/*.cpp ) -file(GLOB_RECURSE examples examples/*.cpp ) - -foreach( file ${applications} ) - get_filename_component( Executable ${file} NAME_WE ) - cmake_print_variables(Executable) - add_executable(${Executable} ${file}) - target_compile_options(${Executable} PUBLIC -g3 -Ofast) - target_link_libraries(${Executable} PUBLIC AmpGen) -endforeach() - -foreach( file ${examples} ) - get_filename_component( Executable ${file} NAME_WE ) - cmake_print_variables(Executable) - add_executable(${Executable} ${file}) - target_link_libraries(${Executable} PUBLIC AmpGen) -endforeach() - -file(GLOB_RECURSE options_files options/*.*) -execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin") -foreach(file ${options_files}) - get_filename_component(OptionFile "${file}" NAME) - cmake_print_variables(OptionFile) - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${file}" "${CMAKE_BINARY_DIR}/bin/${OptionFile}") -endforeach() - -enable_testing() -find_package(Boost 1.67.0 COMPONENTS unit_test_framework) -if ( Boost_FOUND ) - include_directories (${Boost_INCLUDE_DIRS}) - - file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test/*.cpp) - - foreach(testSrc ${TEST_SRCS}) - get_filename_component(testName ${testSrc} NAME_WE) - add_executable(${testName} ${testSrc}) - set_target_properties(${testName} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_TEST_OUTPUT_DIRECTORY}" - RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_TEST_OUTPUT_DIRECTORY}" - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_TEST_OUTPUT_DIRECTORY}" - EXECUTABLE_OUTPUT_DIRECTORY "${CMAKE_TEST_OUTPUT_DIRECTORY}" - ) - target_link_libraries(${testName} ${Boost_LIBRARIES} AmpGen) - add_test(NAME ${testName} WORKING_DIRECTORY ${CMAKE_TEST_OUTPUT_DIRECTORY} COMMAND ${CMAKE_TEST_OUTPUT_DIRECTORY}/${testName} ) - endforeach(testSrc) -else() - message( WARNING "Warning: Boost (version >=1.67.0) required to build unit tests\n") -endif() - diff --git a/apps/AmpGen.cpp b/apps/AmpGen.cpp new file mode 100644 index 00000000000..4beaba2169c --- /dev/null +++ b/apps/AmpGen.cpp @@ -0,0 +1,287 @@ +#include +#include +#include +#include +#include + +#include "TFile.h" +#include "TRandom3.h" +#include "TTree.h" + +#ifdef _OPENMP +#include +#include +#endif + +#include "AmpGen/DynamicFCN.h" +#include "AmpGen/EventList.h" +#include "AmpGen/MsgService.h" +#include "AmpGen/Particle.h" +#include "AmpGen/RecursivePhaseSpace.h" +#include "AmpGen/Utilities.h" +#include "AmpGen/EventType.h" +#include "AmpGen/CoherentSum.h" +#include "AmpGen/Generator.h" +#include "AmpGen/MinuitParameterSet.h" +#include "AmpGen/NamedParameter.h" +#include "AmpGen/PolarisedSum.h" +#include "AmpGen/OptionsParser.h" +#include "AmpGen/TreePhaseSpace.h" +#include "AmpGen/enum.h" +#include "AmpGen/ParticlePropertiesList.h" +#include "AmpGen/AddCPConjugate.h" + +#if ENABLE_AVX + #include "AmpGen/EventListSIMD.h" + using EventList_t = AmpGen::EventListSIMD; +#else + #include "AmpGen/EventList.h" + using EventList_t = AmpGen::EventList; +#endif + +using namespace AmpGen; + +namespace AmpGen { + make_enum(pdfTypes, CoherentSum, PolarisedSum, FixedLib) + make_enum(phspTypes, PhaseSpace, RecursivePhaseSpace, TreePhaseSpace) +} + +struct FixedLibPDF +{ + void* lib = {nullptr}; + DynamicFCN PDF; + void debug( const Event& event) {}; + void prepare(){}; + void setEvents( AmpGen::EventList& evts ){}; + void setEvents( AmpGen::EventListSIMD& evts ){}; + double operator()( const AmpGen::Event& evt ) const { return PDF( evt, 1 ); } + double operator()( const double* evt, const unsigned& index ) + { + return PDF(evt, 1 ); + } + FixedLibPDF( const std::string& lib ) + { + void* handle = dlopen( lib.c_str(), RTLD_NOW ); + if ( handle == nullptr ) ERROR( dlerror() ); + PDF = DynamicFCN( handle, "FCN" ); + } + size_t size() { return 0; } + void reset( const bool& flag = false ){}; +}; + +template void generateSource(T& pdf, const std::string& sourceFile, MinuitParameterSet& mps) +{ + bool normalise = NamedParameter("Normalise",true); + double safetyFactor = NamedParameter( "SafetyFactor", 3 ); + int seed = NamedParameter("Seed", 1); + size_t nEvents = NamedParameter( "NormEvents", 1000000 ); + + TRandom3 rnd(seed); + + Generator phsp(pdf.eventType()); + phsp.setRandom(&rnd); + EventList normEvents = phsp.generate(nEvents); + if constexpr( std::is_same::value ) pdf.prepare(); + + double norm = 1; + if( normalise ){ + double pMax = 0; + for ( auto& evt : normEvents ) + { + if constexpr ( std::is_same::value ) + { + double px, py, pz; + rnd.Sphere(px,py,pz, rnd.Uniform(0,1)); + mps["Px"]->setCurrentFitVal(px); + mps["Py"]->setCurrentFitVal(py); + mps["Pz"]->setCurrentFitVal(pz); + pdf.transferParameters(); + } + double n = 0; + if constexpr ( std::is_same::value ) n = std::norm( pdf.getValNoCache(evt) ); + if constexpr ( std::is_same::value ) n = pdf.getValNoCache(evt); + if ( n > pMax ) pMax = n; + } + norm = pMax * safetyFactor ; + INFO( "Making binary with " << pMax << " x safety factor = " << safetyFactor ); + } + mps.resetToInit(); + pdf.generateSourceCode( sourceFile, norm, true ); +} + + +template Particle getTopology(const pdf_t& pdf) +{ + if constexpr( std::is_same::value ) + { + FATAL("Cannot deduce decay topology from a compiled library, check generator options"); + } + else return pdf.matrixElements()[0].decayTree.quasiStableTree(); +} + +template std::vector getDecayChains( const pdf_t& pdf ) +{ + if constexpr( std::is_same::value ) + { + FATAL("Cannot deduce decay topology from a compiled library, check generator options"); + } + else { + std::vector channels; + for( auto& chain : pdf.matrixElements() ) channels.push_back( chain.decayTree ); + return channels; + } +} + + +template void generateEvents( EventList& events + , pdf_t& pdf + , const phspTypes& phsp_type + , const size_t& nEvents + , const size_t& blockSize + , TRandom* rndm + , const bool& normalise = true ) +{ + if constexpr( std::is_same::value ) + { + Generator signalGenerator(events.eventType(), rndm); + signalGenerator.setBlockSize(blockSize); + signalGenerator.setNormFlag(normalise); + signalGenerator.fillEventList(pdf, events, nEvents ); + } + else { + if( phsp_type == phspTypes::PhaseSpace ) + { + Generator signalGenerator(events.eventType(), rndm); + signalGenerator.setBlockSize(blockSize); + signalGenerator.setNormFlag(normalise); + signalGenerator.fillEventList(pdf, events, nEvents ); + } + else if( phsp_type == phspTypes::RecursivePhaseSpace ) + { + Generator signalGenerator( getTopology(pdf), events.eventType(), rndm ); + signalGenerator.setBlockSize(blockSize); + signalGenerator.setNormFlag(normalise); + signalGenerator.fillEventList(pdf, events, nEvents); + } + else if( phsp_type == phspTypes::TreePhaseSpace ) + { + Generator signalGenerator(getDecayChains(pdf), events.eventType(), rndm); + signalGenerator.setBlockSize(blockSize); + signalGenerator.setNormFlag(normalise); + signalGenerator.fillEventList(pdf, events, nEvents ); + } + else { + FATAL("Phase space configuration: " << phsp_type << " is not supported"); + } + } +} + + + +int main( int argc, char** argv ) +{ + OptionsParser::setArgs( argc, argv ); + + size_t nEvents = NamedParameter ("nEvents" , 1, "Total number of events to generate" ); + size_t blockSize = NamedParameter ("BlockSize", 5000000, "Number of events to generate per block" ); + int seed = NamedParameter ("Seed" , 0, "Random seed used in event Generation" ); + std::string outfile = NamedParameter("Output" , "Generate_Output.root" , "Name of output file" ); + auto pdfType = NamedParameter( "Type", pdfTypes::CoherentSum, optionalHelpString("Type of PDF to use:", + std::make_pair(pdfTypes::CoherentSum , "Describes decays of a (pseudo)scalar particle to N pseudoscalars") + , std::make_pair(pdfTypes::PolarisedSum, "Describes the decay of a particle with spin to N particles carrying spin.") + , std::make_pair(pdfTypes::FixedLib , "PDF to describe a decay from a precompiled library, such as those provided to GAUSS.") ) ); + auto phspType = NamedParameter( "PhaseSpace", phspTypes::PhaseSpace, optionalHelpString("Phase-space generator to use:", + std::make_pair(phspTypes::PhaseSpace , "Phase space generation based on Raubold-Lynch algorithm (recommended).\0") + , std::make_pair(phspTypes::TreePhaseSpace , "Divides the phase-space into a series of quasi two-body phase-spaces for efficiently generating narrow states.\0") + , std::make_pair(phspTypes::RecursivePhaseSpace, "Includes possible quasi-stable particles and the phase spaces of their decay products, such as Λ baryons.\0") ) ); + std::string lib = NamedParameter("Library","","Name of library to use for a fixed library generation"); + size_t nBins = NamedParameter ("nBins" ,100, "Number of bins for monitoring plots." ); + bool sourceOnly = NamedParameter ("SourceOnly",false, "Flag to only generate the source code, but not produce any events"); + #ifdef _OPENMP + unsigned int concurentThreadsSupported = std::thread::hardware_concurrency(); + unsigned int nCores = NamedParameter( "nCores", concurentThreadsSupported, "Number of cores to use (OpenMP only)" ); + omp_set_num_threads( nCores ); + omp_set_dynamic( 0 ); + #endif + + TRandom3 rand; + rand.SetSeed( seed + 934534 ); + + MinuitParameterSet MPS; + MPS.loadFromStream(); + + EventType eventType; + std::string decay = NamedParameter("Decay","","Single decay written on the command line"); + if( decay != "" ) + { + Particle p(decay); + eventType = p.eventType(); + MPS.add(p.decayDescriptor()+"_Re", Flag::Fix, 1., 0); + MPS.add(p.decayDescriptor()+"_Im", Flag::Fix, 0., 0); + } + else eventType = EventType( NamedParameter( "EventType" , "", "EventType to generate, in the format: \033[3m parent daughter1 daughter2 ... \033[0m" ).getVector(), + NamedParameter( "GenerateTimeDependent", false , "Flag to include possible time dependence of the amplitude") ); + + bool conj = NamedParameter("Conj",false, "Flag to generate the CP conjugate amplitude under the assumption of CP conservation"); + bool add_cp_conjugate = NamedParameter("AddConj",false, "Flag to add all of the CP conjugate amplitudes, under the assumption of CP conservation"); + if ( conj ) eventType = eventType.conj(); + if( conj || add_cp_conjugate ) AddCPConjugate(MPS); + + if( OptionsParser::printHelp() ) return 0; + + INFO("Writing output: " << outfile ); + #ifdef _OPENMP + INFO("Using: " << nCores << " / " << concurentThreadsSupported << " threads" ); + #endif + + if( sourceOnly ) + { + if ( pdfType == pdfTypes::CoherentSum ) + { + CoherentSum pdf( eventType, MPS); + generateSource(pdf, outfile, MPS); + } + else if ( pdfType == pdfTypes::PolarisedSum ) + { + PolarisedSum pdf(eventType, MPS); + generateSource(pdf, outfile, MPS); + } + return 0; + } + INFO("Generating time-dependence? " << eventType.isTimeDependent() ); + EventList accepted( eventType ); + + INFO("Generating events with type = " << eventType ); + + if ( pdfType == pdfTypes::CoherentSum ){ + CoherentSum pdf( eventType, MPS); + generateEvents(accepted, pdf, phspType , nEvents, blockSize, &rand ); + } + else if ( pdfType == pdfTypes::PolarisedSum ){ + PolarisedSum pdf(eventType, MPS); + generateEvents( accepted, pdf, phspType, nEvents, blockSize, &rand ); + } + else if ( pdfType == pdfTypes::FixedLib ){ + FixedLibPDF pdf(lib); + generateEvents( accepted, pdf, phspType, nEvents, blockSize, &rand, false ); + } + else { + FATAL("Did not recognise configuration: " << pdfType ); + } + if( accepted.size() == 0 ) return -1; + TFile* f = TFile::Open( outfile.c_str(), "RECREATE" ); + accepted.tree( "DalitzEventList" )->Write(); + auto plots = accepted.makeDefaultProjections(PlotOptions::Bins(nBins), PlotOptions::LineColor(kBlack)); + for ( auto& plot : plots ) plot->Write(); + if( NamedParameter("plots_2d",true) == true ){ + auto proj = eventType.defaultProjections(nBins); + for( size_t i = 0 ; i < proj.size(); ++i ){ + for( size_t j = i+1 ; j < proj.size(); ++j ){ + accepted.makeProjection( Projection2D(proj[i], proj[j]), PlotOptions::LineColor(kBlack) )->Write(); + } + } + } + INFO( "Writing output file " ); + + f->Close(); +} diff --git a/apps/ConvertToSourceCode.cpp b/apps/ConvertToSourceCode.cpp deleted file mode 100644 index 72783952716..00000000000 --- a/apps/ConvertToSourceCode.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include -#include -#include - -#include "AmpGen/EventList.h" -#include "AmpGen/EventType.h" -#include "AmpGen/CoherentSum.h" -#include "AmpGen/PolarisedSum.h" -#include "AmpGen/Generator.h" -#include "AmpGen/MinuitParameterSet.h" -#include "AmpGen/NamedParameter.h" -#include "AmpGen/PhaseSpace.h" -#include "AmpGen/Utilities.h" -#include "AmpGen/ThreadPool.h" -#include "AmpGen/Particle.h" -#include "TRandom3.h" - -using namespace AmpGen; - -template -void create_integration_tests(T& pdf, - const EventType& type, - const MinuitParameterSet& mps, - const std::vector& testEvents, - const std::string& sourceFile) -{ - auto stringify = [](const std::string arg ){ return "\"" + arg + "\"" ; }; - std::ofstream unit_tests; - unit_tests.open(split( sourceFile, '.')[0] + "_test.cpp"); - unit_tests << "#define BOOST_TEST_DYN_LINK" << std::endl; - unit_tests << "#define BOOST_TEST_MODULE amp" << std::endl; - unit_tests << "#include " << std::endl; - unit_tests << "#include \"AmpGen/Particle.h\"" << std::endl; - unit_tests << "#include \"AmpGen/CompiledExpression.h\"" << std::endl; - unit_tests << "#include \"AmpGen/EventType.h\"" << std::endl; - unit_tests << "#include \"AmpGen/MinuitParameterSet.h\"" << std::endl; - unit_tests << "#include \"AmpGen/OptionsParser.h\"" << std::endl; - unit_tests << "using namespace AmpGen;" << std::endl; - - unit_tests << "void setupOptions(){" << std::endl; - for( auto& p : *OptionsParser::getMe() ) - { - unit_tests << " OptionsParser::setArg( \"" << vectorToString(p.second," ") <<"\");"<< std::endl; - } - unit_tests << "\n}\n" << std::endl; - - for( auto& mE : pdf.matrixElements() ){ - auto value = mE.pdf(testEvents[0].address()); - unit_tests << "BOOST_AUTO_TEST_CASE( " << mE.pdf.progName() + "_test){" << std::endl; - unit_tests << " EventType type({" << stringify(type.mother()) << ", " << vectorToString( type.finalStates(), ", ", stringify ) << "});" << std::endl; - unit_tests << " Particle p("<(p.getExpression(), p.decayDescriptor(), type.getEventFormat(), mps);" << std::endl; - unit_tests << " auto eval = expr(event);" << std::endl; - unit_tests << " BOOST_TEST( std::real(eval) == " << std::real(value)<< ", boost::test_tools::tolerance(1e-6)) ;" << std::endl; - unit_tests << " BOOST_TEST( std::imag(eval) == " << std::imag(value)<< ", boost::test_tools::tolerance(1e-6)) ;" << std::endl; - unit_tests << "}\n\n"; - } - unit_tests.close(); -} - - -template void generate_source(T& pdf, EventList& normEvents, const std::string& sourceFile, MinuitParameterSet& mps, const double& sf) -{ - bool normalise = NamedParameter("Normalise",true); - std::string type = NamedParameter( "Type", "CoherentSum" ); - - double norm = 1; - if( normalise ){ - double pMax = 0 ; - pdf.setEvents( normEvents ); - pdf.prepare(); - for ( auto& evt : normEvents ) { - if( type == "PolarisedSum" ){ - double px, py, pz; - gRandom->Sphere(px,py,pz, gRandom->Uniform(0,1)); - mps["Px"]->setCurrentFitVal(px); - mps["Py"]->setCurrentFitVal(py); - mps["Pz"]->setCurrentFitVal(pz); - pdf.transferParameters(); - } - double n = pdf.prob_unnormalised( evt ); - if ( n > pMax ) pMax = n; - } - norm = pMax * sf ; - INFO( "Making binary with " << pMax << " x safety factor = " << sf ); - } - mps.resetToInit(); - pdf.generateSourceCode( sourceFile, norm, true ); -} - -int main( int argc, char** argv ) -{ - OptionsParser::setArgs( argc, argv ); - std::vector oEventType = NamedParameter( "EventType" ).getVector(); - std::string sourceFile = NamedParameter( "Output" , "output.cpp" ); - std::string type = NamedParameter( "Type", "CoherentSum" ); - std::string outputPS = NamedParameter( "OutputEvents", "" ); - unsigned int NormEvents = NamedParameter( "NormEvents", 1000000 ); - double safetyFactor = NamedParameter( "SafefyFactor", 3 ); - - EventType eventType( oEventType ); - - AmpGen::MinuitParameterSet MPS; // - MPS.loadFromStream(); - Generator phsp( eventType ); - TRandom3 rnd; - - gRandom = &rnd; - phsp.setRandom( &rnd ); - - EventList phspEvents( oEventType ); - phsp.fillEventListPhaseSpace( phspEvents, NormEvents ); - - if( type == "CoherentSum" ){ - CoherentSum sig( eventType, MPS, "" ); - generate_source( sig, phspEvents, sourceFile, MPS, safetyFactor ); - create_integration_tests(sig, eventType, MPS, {phspEvents[15]}, sourceFile ); - } - if( type == "PolarisedSum" ){ - PolarisedSum sig( eventType, MPS ); - generate_source( sig, phspEvents, sourceFile, MPS, safetyFactor ); - } - if ( outputPS != "" ) { - std::ofstream ofile( outputPS ); - ofile << "0x,0y,0z,0t,1x,1y,1z,1t,2x,2y,2z,2t,3x,3y,3z,3t\n"; - for ( auto& event : phspEvents ) { - for ( size_t i = 0; i < event.size(); i++ ) ofile << ( i == 0 ? "" : "," ) << event[i]; - ofile << "\n"; - } - } -} diff --git a/apps/DataConverter.cpp b/apps/DataConverter.cpp index 815e824599e..bde9ca91297 100644 --- a/apps/DataConverter.cpp +++ b/apps/DataConverter.cpp @@ -18,7 +18,7 @@ #include "AmpGen/NamedParameter.h" #include "AmpGen/Utilities.h" #include "AmpGen/Projection.h" - +#include "AmpGen/TreeReader.h" #include "TEventList.h" #include "TFile.h" #include "TH1.h" @@ -36,11 +36,10 @@ void invertParity( Event& event, const size_t& nParticles=0) } } - int main( int argc, char* argv[] ) { OptionsParser::setArgs( argc, argv ); - std::string inputFilename = NamedParameter("Input" , "", "Input ROOT file" ); + std::string inputFilename = NamedParameter("Input" , "", "Input ROOT file(s)" ); std::string treeName = NamedParameter("Tree" , "", "Input ROOT tree." ); std::string outputFilename = NamedParameter("Output" , "", "Output ROOT file" ); std::string pdfLibrary = NamedParameter("PdfLibrary", "", "PDF Library that used to generate this sample for MC reweighting (MC only)" ); @@ -49,10 +48,15 @@ int main( int argc, char* argv[] ) std::vector particles = NamedParameter("ParticleNames" , std::vector() ).getVector(); std::vector monitorBranches = NamedParameter("Monitors" , std::vector() ).getVector(); std::vector branchFormat = NamedParameter("BranchFormat" , std::vector() ).getVector(); - bool usePIDCalib = NamedParameter("usePIDCalib" , false ); - bool rejectMultipleCandidates = NamedParameter("rejectMultipleCandidates", true ); - std::string cuts = vectorToString( NamedParameter("Cut","").getVector() , " && "); + std::vector friends = NamedParameter("Friends" , std::vector() ).getVector(); + std::vector idBranches = NamedParameter("IdBranches" , std::vector() ).getVector(); + bool usePIDCalib = NamedParameter("usePIDCalib" , false); + bool rejectMultipleCandidates = NamedParameter("rejectMultipleCandidates", true ); + auto cuts = NamedParameter("Cut","").getVector(); EventType evtType( NamedParameter( "EventType" ).getVector() ); + + std::vector branches; + for( auto& particle : particles ) for(auto& bf : branchFormat) branches.push_back( mysprintf(bf, particle.c_str())); INFO( "Reading file " << inputFilename ); INFO( "Outputting file: " << outputFilename); @@ -61,8 +65,11 @@ int main( int argc, char* argv[] ) TTree* in_tree = (TTree*)f->Get( treeName.c_str() ); in_tree->SetBranchStatus( "*", 1 ); + for( auto& frie : friends ){ + auto tokens = split( frie, ':'); + in_tree->AddFriend( tokens[1].c_str(), tokens[0].c_str() ); + } - INFO( "Using cut = " << cuts ); if(inputFilename == "") FATAL("No input specified in options" ); if(treeName == "") FATAL("No tree specified in options" ); @@ -71,19 +78,16 @@ int main( int argc, char* argv[] ) if(in_tree == nullptr ) FATAL(treeName + " not found" ); INFO( "Got tree " << inputFilename << ":" << treeName ); - - in_tree->Draw( ">>elist", cuts.c_str() ); + std::string cut = ""; + for( auto& i : cuts ) cut += i; + INFO( "Using cut = " << cut ); + + in_tree->Draw( ">>elist", cut.c_str() ); TEventList* elist = (TEventList*)gDirectory->Get( "elist" ); INFO( "Total efficiency = " << elist->GetN() / (double)in_tree->GetEntries() ); std::vector eventsToTake; - std::vector branches; - for( auto& particle : particles ) { - for(size_t i = 0 ; i < 4; ++i ) branches.push_back( mysprintf(branchFormat[i], particle.c_str())); - } - for(auto& branch : monitorBranches) branches.push_back( branch ); - if ( rejectMultipleCandidates ) { ULong64_t totCandidate; ULong64_t eventNumber; @@ -125,7 +129,13 @@ int main( int argc, char* argv[] ) } } - EventList evts( in_tree, evtType, Branches(branches), EntryList(eventsToTake), GetGenPdf(false)); + EventList evts( in_tree, evtType, Branches(branches), + EntryList(eventsToTake), + GetGenPdf(false), + ApplySym(true) , + ExtraBranches(monitorBranches), + IdBranches(idBranches), + InputUnits(Units::MeV) ); INFO( "Branches = ["<< vectorToString(branches, ", " ) << "]" ); @@ -133,14 +143,14 @@ int main( int argc, char* argv[] ) INFO("Constructing eventList"); if ( motherID != "" ) { + bool neg = motherID[0] == '-'; INFO( "Converting " << evtType.mother() << " " << eventsToTake.size() << " " << evts.size() ); - in_tree->SetBranchStatus( "*", 0 ); + TreeReader tr( in_tree ); int id = 0; - in_tree->SetBranchStatus( motherID.c_str() ); - in_tree->SetBranchAddress( motherID.c_str(), &id ); + tr.setBranch( neg ? motherID.substr(1, motherID.size() -1 ) : motherID, & id ); for ( unsigned int i = 0; i < eventsToTake.size(); ++i ) { - in_tree->GetEntry( eventsToTake[i] ); - if ( id < 0 ) invertParity( evts[i] , evtType.size() ); + tr.getEntry(eventsToTake[i] ); + if ( neg ? id > 0 : id < 0 ) invertParity( evts[i] , evtType.size() ); } } @@ -177,18 +187,11 @@ int main( int argc, char* argv[] ) evts[i].setWeight( weight ); } } - evts.transform( [=](auto& event){ for( size_t i = 0 ; i < 4*evtType.size(); ++i ) event[i] /= 1000. ; } ); - if ( pdfLibrary != "" ) { INFO( "Setting generator level PDF from " << pdfLibrary ); - void* handle = dlopen( pdfLibrary.c_str(), RTLD_NOW ); - if ( handle == nullptr ) dlerror(); - - DynamicFCN fcn( handle, "FCN" ); + DynamicFCN fcn( pdfLibrary, "FCN" ); for ( unsigned int i = 0; i < evts.size(); ++i ) { - if ( i % 500000 == 0 ) { - INFO( "Set for " << i << " events" ); - } + if ( i % 500000 == 0 ) INFO( "Set for " << i << " events" ); evts[i].setGenPdf( fcn( (const real_t*)(evts[i]), 1 ) ); } } @@ -202,10 +205,15 @@ int main( int argc, char* argv[] ) INFO("Closing file..."); outputFile->Close(); TFile* outputPlotFile = TFile::Open( plotsName.c_str(), "RECREATE" ); - auto plots = evts.makeDefaultProjections(); - for ( auto& plot : plots ) { - INFO( "Writing plot " << plot->GetName() << " to file" ); - plot->Write(); + auto projections = evtType.defaultProjections(); + for ( auto& p : projections ) { + p( evts ) -> Write(); + // p( evts, WeightFunction([](auto& evt){ return 1; }), PlotOptions::Prefix("noweight") )->Write(); + } + for( unsigned i = 0 ; i != evtType.size(); ++i ) + { + Projection p( [i](auto& event){ return sqrt( event.s(i) ); }, "m_"+std::to_string(i), "m_"+std::to_string(i), 100, 0, 2.5 ); + p(evts)->Write(); } outputPlotFile->Close(); } diff --git a/apps/Debugger.cpp b/apps/Debugger.cpp index 411d1dc3fb7..35f65cccd0e 100644 --- a/apps/Debugger.cpp +++ b/apps/Debugger.cpp @@ -20,6 +20,7 @@ #include "AmpGen/ParticlePropertiesList.h" #include "AmpGen/Utilities.h" #include "TRandom3.h" +#include "AmpGen/AddCPConjugate.h" #ifdef _OPENMP #include @@ -33,6 +34,7 @@ #include "AmpGen/NamedParameter.h" #include "AmpGen/PolarisedSum.h" + using namespace AmpGen; void invertParity( Event& event, const size_t& nParticles) @@ -45,71 +47,21 @@ void invertParity( Event& event, const size_t& nParticles) } } -int invert_parameter( AmpGen::MinuitParameter* param, MinuitParameterSet& mps ) -{ - const std::string name = param->name(); - size_t pos = 0; - std::string prefix = ""; - std::string new_name = name; - int sgn = 1; - if ( name.find( "::" ) != std::string::npos ) { - pos = name.find( "::" ); - auto props = AmpGen::ParticlePropertiesList::get( name.substr( 0, pos ), true ); - if ( props != nullptr ) new_name = props->anti().name() + name.substr( pos ); - } else { - auto tokens = split( name, '_' ); - std::string reOrIm = *tokens.rbegin(); - std::string prefix = ""; - std::string name = tokens[0]; - if ( tokens.size() == 3 ) { - prefix = tokens[0]; - name = tokens[1]; - } - if ( reOrIm == "Re" || reOrIm == "Im" ) { - std::vector final_state_ordering; - AmpGen::Particle test( name, final_state_ordering ); - sgn = test.conjugate( true ); - if ( reOrIm == "Re" ) sgn = 1; - new_name = ( prefix != "" ? prefix + "_" : "" ) + test.uniqueString() + "_" + reOrIm; - } else if ( tokens.size() == 2 ) { - auto props = AmpGen::ParticlePropertiesList::get( name ); - if ( props != nullptr ) new_name = props->anti().name() + "_" + tokens[1]; - } - } - DEBUG( param->name() << " → " << new_name << " sgn = " << sgn ); - mps.map().erase( param->name() ); - param->setName( new_name ); - mps.map().emplace( param->name(), param ); - if ( sgn == -1 ) param->setCurrentFitVal( param->mean() + M_PI ); - return sgn; -} - -template void print( const Event& event, const MatrixElements& matrixElements, bool verbose ) -{ - for ( auto& mE : matrixElements ) { - INFO( mE.decayDescriptor() << " " << mE.coupling() ); - auto terms = mE.coupling.couplings; - if ( verbose ) { - for ( auto& term : terms ) { - INFO( "--> " << term.first->name() << " = (" << term.first->mean() * cos( term.second->mean() ) << " + i " << term.first->mean() * sin( term.second->mean() ) << ")" ); - } - mE.pdf.debug( event ); - } - } -} - template < class FCN > void debug( FCN& sig, EventList& accepted, bool verbose, TRandom3* rndm, MinuitParameterSet& mps ){ INFO("Debugging: "); + unsigned eventToDebug = 0; sig.setEvents( accepted ); sig.prepare(); - sig.debug( accepted[0] ); - accepted[0].print(); - if( verbose ) print( accepted[0], sig.matrixElements(), verbose ); - invertParity(accepted[0], accepted.eventType().size() ); - accepted[0].print(); + sig.debug( accepted[eventToDebug] ); + accepted[eventToDebug].print(); +// if( verbose ) print( accepted[0], sig.matrixElements(), verbose ); + for( unsigned int i = 0 ; i != accepted.size(); ++i ) + invertParity(accepted[i], accepted.eventType().size() ); + accepted[eventToDebug].print(); sig.reset(); + sig.setEvents(accepted); sig.prepare(); - sig.debug( accepted[0] ); + sig.debug( accepted[eventToDebug] ); } int main( int argc, char** argv ) @@ -119,16 +71,20 @@ int main( int argc, char** argv ) int seed = NamedParameter( "Seed", 156 ); TRandom3* rndm = new TRandom3( seed ); - EventType eventType( NamedParameter( "EventType" ).getVector() ); + EventType eventType( NamedParameter( "EventType" , "", "EventType to generate, in the format: \033[3m parent daughter1 daughter2 ... \033[0m" ).getVector(), + NamedParameter( "GenerateTimeDependent", false , "Flag to include possible time dependence of the amplitude") ); bool verbose = NamedParameter("CoherentSum::Debug", 0 ) || NamedParameter("PolarisedSum::Debug", 0 ); INFO("Using verbose mode: " << verbose ); AmpGen::MinuitParameterSet MPS; MPS.loadFromStream(); - if ( NamedParameter( "conj", false ) == true ) { - eventType = eventType.conj( false ); - for ( auto& param : MPS ) invert_parameter( param, MPS ); + + if ( NamedParameter( "conj", false ) == true ) + { + eventType = eventType.conj(); + INFO( eventType ); + AddCPConjugate(MPS); } INFO( "EventType = " << eventType ); @@ -136,13 +92,17 @@ int main( int argc, char** argv ) EventList accepted = infile == "" ? EventList( eventType ) : EventList( infile, eventType ); std::string input_units = NamedParameter("Units","GeV"); - if( input_units == "MeV" && infile != "") accepted.transform([](auto& event){ for( int i = 0;i<16;++i) event[i]/=1000; } ); + if( input_units == "MeV" && infile != "") accepted.transform([](auto& event){ for( unsigned i = 0;i< event.size();++i) event[i]/=1000; } ); if( infile == "" ){ - Event evt = PhaseSpace( eventType, rndm ).makeEvent(); - accepted.push_back(evt); + for( unsigned i = 0 ; i != 16; ++i ){ + Event evt = PhaseSpace( eventType, rndm ).makeEvent(); + evt.setIndex(i); + accepted.push_back(evt); + } } - accepted[0].print(); - + std::vector event = NamedParameter("Event",0).getVector(); + if( event.size() != 1 ) accepted[0].set( event.data() ); + std::string type = NamedParameter("Type","CoherentSum"); if( type == "PolarisedSum") @@ -158,7 +118,7 @@ int main( int argc, char** argv ) { CoherentSum sig(eventType, MPS); debug(sig, accepted, verbose, rndm, MPS); - print(accepted[0], sig.matrixElements() , false); + // print(accepted[0], sig.matrixElements() , false); INFO( "A(x) = " << sig.getValNoCache( accepted[0] ) ); } else { diff --git a/apps/Fitter.cpp b/apps/Fitter.cpp index 406c20071ee..52ef74f1ad1 100644 --- a/apps/Fitter.cpp +++ b/apps/Fitter.cpp @@ -10,7 +10,6 @@ #include #include "AmpGen/Chi2Estimator.h" -#include "AmpGen/CoherenceFactor.h" #include "AmpGen/ErrorPropagator.h" #include "AmpGen/EventList.h" #include "AmpGen/EventType.h" @@ -29,13 +28,20 @@ #include "AmpGen/ThreeBodyCalculators.h" #include "AmpGen/Utilities.h" #include "AmpGen/Generator.h" -#include "AmpGen/Plots.h" #ifdef _OPENMP #include #include #endif +#if ENABLE_AVX2 + #include "AmpGen/EventListSIMD.h" + using EventList_type = AmpGen::EventListSIMD; +#else + #include "AmpGen/EventList.h" + using EventList_type = AmpGen::EventList; +#endif + #include "TFile.h" #include "TRandom3.h" @@ -52,25 +58,13 @@ std::vector threeBodyCalculators( MinuitParameterSet& mps ) void randomizeStartingPoint( MinuitParameterSet& MPS, TRandom3& rand, bool SplineOnly = false ) { double range = 5; - for ( unsigned int i = 0; i < MPS.size(); ++i ) { - auto param = MPS.getParPtr( i ); - if ( param->iFixInit() == 0 ) { - if ( SplineOnly && param->name().find( "::Spline::" ) == std::string::npos ) continue; - range = param->maxInit() - param->minInit(); - MPS.getParPtr( i )->setInit( range * rand.Rndm() + param->meanInit() ); - MPS.getParPtr( i )->print(); - std::cout << std::endl; - } - } -} - -unsigned int count_amplitudes( const AmpGen::MinuitParameterSet& mps ) -{ - unsigned int counter = 0; - for ( auto param = mps.cbegin(); param != mps.cend(); ++param ) { - if ( ( *param )->name().find( "_Re" ) != std::string::npos ) counter++; + for (auto& param : MPS) { + if ( ! param->isFree() == 0 ) continue; + if ( SplineOnly && param->name().find( "::Spline::" ) == std::string::npos ) continue; + range = param->maxInit() - param->minInit(); + param->setInit( range * rand.Rndm() + param->meanInit() ); + std::cout << *param << std::endl; } - return counter; } template @@ -93,11 +87,9 @@ void addExtendedTerms( Minimiser& mini, SIGPDF& pdf, MinuitParameterSet& mps ) template FitResult* doFit( PDF&& pdf, EventList& data, EventList& mc, MinuitParameterSet& MPS ) { - INFO( "Type = " << typeof() ); - + INFO( "Type = " << type_string() ); auto time_wall = std::chrono::high_resolution_clock::now(); auto time = std::clock(); - pdf.setEvents( data ); Minimiser mini( pdf, &MPS ); @@ -112,11 +104,10 @@ FitResult* doFit( PDF&& pdf, EventList& data, EventList& mc, MinuitParameterSet& std::vector slowParamPtrs; if ( nIterations != 0 ) { for ( auto& param : SlowParams ) { - auto mps_map = MPS.map(); - auto it = mps_map.find( param ); - if ( it != mps_map.end() ) { - slowParamPtrs.push_back( it->second ); - it->second->fix(); + auto it = MPS.find( param ); + if ( it != nullptr ) { + slowParamPtrs.push_back( it ); + it->fix(); } else { WARNING( "Trying to release non-existent parameter: " << param ); } @@ -138,13 +129,9 @@ FitResult* doFit( PDF&& pdf, EventList& data, EventList& mc, MinuitParameterSet& auto ep = fr->getErrorPropagator(); unsigned int counter = 1; - for_each( pdf.m_pdfs, [&]( auto& f ) { - std::function FCN_sig = - [&](const Event& evt){ return f.prob_unnormalised(evt) ; }; + for_each( pdf.pdfs(), [&]( auto& f ) { auto tStartIntegral2 = std::chrono::high_resolution_clock::now(); - auto mc_plot3 = mc.makeProjections( mc.eventType().defaultProjections(100), WeightFunction(f), Prefix("tMC_Category"+std::to_string(counter) ) ); - - // auto mc_plot3 = bandPlot<100>( mc, "tMC_Category" + std::to_string( counter ) + "_", f, ep ); + auto mc_plot3 = mc.makeProjections( mc.eventType().defaultProjections(100), WeightFunction(f), PlotOptions::Prefix("tMC_Category"+std::to_string(counter) ) ); auto tEndIntegral2 = std::chrono::high_resolution_clock::now(); double t2 = std::chrono::duration( tEndIntegral2 - tStartIntegral2 ).count(); INFO( "Time for plots = " << t2 ); @@ -156,7 +143,7 @@ FitResult* doFit( PDF&& pdf, EventList& data, EventList& mc, MinuitParameterSet& counter++; } ); } - Chi2Estimator chi2( data, mc, pdf, 15 ); + Chi2Estimator chi2( data, mc, pdf, MinEvents(15) ); fr->addChi2( chi2.chi2(), chi2.nBins() ); auto twall_end = std::chrono::high_resolution_clock::now(); @@ -209,7 +196,7 @@ int main( int argc, char* argv[] ) if ( perturb ) { for ( auto& param : MPS ) { - if ( param->iFixInit() != 0 ) continue; + if ( !param->isFree() ) continue; param->setCurrentFitVal( rndm.Gaus( param->mean(), param->err() ) ); } } @@ -230,14 +217,16 @@ int main( int argc, char* argv[] ) const std::string cut = NamedParameter( "Cut", "1" ); const std::string simCut = NamedParameter( "SimCut", "1" ); bool BAR = NamedParameter("Bar",false); - size_t defaultCacheSize = count_amplitudes( MPS ); - - EventList events( dataFile, !BAR ? evtType : evtType.conj() , CacheSize(defaultCacheSize), Filter(cut) ); - EventList eventsMC = mcFile == "" ? EventList( evtType) : EventList( mcFile, !BAR ? evtType : evtType.conj() , CacheSize(defaultCacheSize), Filter(simCut) ) ; - auto scale_transform = [](auto& event){ for( size_t x = 0 ; x < event.size(); ++x ) event[x] /= 1000.; }; - INFO("Changing units from MeV -> GeV"); - events.transform( scale_transform ); - eventsMC.transform( scale_transform ); + + EventList events( dataFile, !BAR ? evtType : evtType.conj() , Filter(cut) ); + EventList eventsMC = mcFile == "" ? EventList( evtType) : EventList( mcFile, !BAR ? evtType : evtType.conj(), Filter(simCut) ) ; + + auto scale_transform = [](auto& event){ for( size_t x = 0 ; x < event.size(); ++x ) event[x] /= 1000.; }; + if( NamedParameter("Units", "GeV").getVal() == "MeV") { + INFO("Changing units from MeV -> GeV"); + events.transform( scale_transform ); + } + eventsMC.transform( scale_transform ); INFO( "Data events: " << events.size() ); INFO( "MC events : " << eventsMC.size() ); @@ -286,7 +275,7 @@ int main( int argc, char* argv[] ) fr->writeToFile( logFile ); output->cd(); - auto plots = events.makeDefaultProjections( Prefix( "Data_" ), Bins( NBins ) ); + auto plots = events.makeDefaultProjections( PlotOptions::Prefix( "Data_" ), PlotOptions::Bins( NBins ) ); for ( auto& plot : plots ) plot->Write(); output->Write(); diff --git a/apps/Generator.cpp b/apps/Generator.cpp deleted file mode 100644 index a80592dfa41..00000000000 --- a/apps/Generator.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include -#include -#include -#include - -#include "TFile.h" -#include "TRandom3.h" -#include "TTree.h" - -#ifdef _OPENMP -#include -#include -#endif - -#include "AmpGen/DynamicFCN.h" -#include "AmpGen/EventList.h" -#include "AmpGen/MsgService.h" -#include "AmpGen/Particle.h" -#include "AmpGen/RecursivePhaseSpace.h" -#include "AmpGen/Utilities.h" -#include "AmpGen/EventType.h" -#include "AmpGen/CoherentSum.h" -#include "AmpGen/Generator.h" -#include "AmpGen/MinuitParameterSet.h" -#include "AmpGen/NamedParameter.h" -#include "AmpGen/PolarisedSum.h" -#include "AmpGen/OptionsParser.h" - -using namespace AmpGen; - -struct FixedLibPDF { - void* lib; - AmpGen::DynamicFCN PDF; - - void prepare(){}; - void setEvents( AmpGen::EventList& evts ){}; - double prob_unnormalised( const AmpGen::Event& evt ) const { return PDF( evt, 1 ); } - FixedLibPDF( const std::string& lib ) - { - void* handle = dlopen( lib.c_str(), RTLD_NOW ); - if ( handle == nullptr ) ERROR( dlerror() ); - PDF = AmpGen::DynamicFCN( handle, "FCN" ); - } - size_t size() { return 0; } - void reset( const bool& flag = false ){}; -}; - -template - void GenerateEvents( EventList& events - , PDF_TYPE& pdf - , PRIOR_TYPE& prior - , const size_t& nEvents - , const size_t& blockSize - , TRandom* rndm ) -{ - Generator signalGenerator( prior ); - signalGenerator.setRandom( rndm); - signalGenerator.setBlockSize( blockSize ); - signalGenerator.fillEventList( pdf, events, nEvents ); -} - -int main( int argc, char** argv ) -{ - OptionsParser::setArgs( argc, argv ); - - size_t nEvents = NamedParameter ("nEvents" , 1, "Total number of events to generate" ); - size_t blockSize = NamedParameter ("BlockSize", 100000, "Number of events to generate per block" ); - int seed = NamedParameter ("Seed" , 0, "Random seed used in event Generation" ); - std::string outfile = NamedParameter("Output" , "Generate_Output.root" , "Name of output file" ); - - std::string gen_type = NamedParameter( "Type", "CoherentSum", optionalHelpString("Generator configuration to use:", - { {"CoherentSum", "Full phase-space generator with (pseudo)scalar amplitude"} - , {"PolarisedSum", "Full phase-space generator with particles carrying spin in the initial/final states"} - , {"FixedLib", "Full phase-space generator with an amplitude from a precompiled library"} - , {"RGenerator", "Recursive phase-space generator for intermediate (quasi)stable states such as the D-mesons"} } ) ); - - std::string lib = NamedParameter("Library","","Name of library to use for a fixed library generation"); - size_t nBins = NamedParameter ("nBins" ,100, "Number of bins for monitoring plots." ); - - #ifdef _OPENMP - unsigned int concurentThreadsSupported = std::thread::hardware_concurrency(); - unsigned int nCores = NamedParameter( "nCores", concurentThreadsSupported, "Number of cores to use (OpenMP only)" ); - omp_set_num_threads( nCores ); - omp_set_dynamic( 0 ); - #endif - - TRandom3 rand; - rand.SetSeed( seed + 934534 ); - - MinuitParameterSet MPS; - MPS.loadFromStream(); - - Particle p; - - EventType eventType( NamedParameter( "EventType" , "", "EventType to generate, in the format: \033[3m parent daughter1 daughter2 ... \033[0m" ).getVector(), - NamedParameter( "GenerateTimeDependent", false , "Flag to include possible time dependence of the amplitude") ); - - EventList accepted( eventType ); - - INFO("Generating events with type = " << eventType ); - - if ( gen_type == "CoherentSum" ) { - CoherentSum sig( eventType, MPS ); - PhaseSpace phsp(eventType,&rand); - GenerateEvents( accepted, sig, phsp , nEvents, blockSize, &rand ); - } - else if ( gen_type == "PolarisedSum" ){ - PolarisedSum sig( eventType, MPS ); - RecursivePhaseSpace phsp( sig.matrixElements()[0].decayTree.quasiStableTree() , eventType, &rand ); - GenerateEvents( accepted, sig, phsp, nEvents, blockSize, &rand ); - } - else if ( gen_type == "RGenerator" ) { - CoherentSum sig( eventType, MPS, "" ); - Generator signalGenerator( sig[0].decayTree.quasiStableTree(), eventType ); - signalGenerator.setRandom( &rand ); - signalGenerator.fillEventList( sig, accepted, nEvents ); - } - else if ( gen_type == "FixedLib" ) { - Generator<> signalGenerator( eventType ); - signalGenerator.setRandom( &rand ); - signalGenerator.setBlockSize( blockSize ); - signalGenerator.setNormFlag( false ); - FixedLibPDF pdf( lib ); - signalGenerator.fillEventList( pdf, accepted, nEvents ); - } - else { - ERROR("Did not recognise configuration: " << gen_type ); - } - if( accepted.size() == 0 ) return -1; - TFile* f = TFile::Open( outfile.c_str(), "RECREATE" ); - accepted.tree( "DalitzEventList" )->Write(); - auto plots = accepted.makeDefaultProjections(Bins(nBins), LineColor(kBlack)); - for ( auto& plot : plots ) plot->Write(); - if( NamedParameter("plots_2d",true) == true ){ - auto proj = eventType.defaultProjections(nBins); - INFO("Making 2D projections..."); - for( size_t i = 0 ; i < proj.size(); ++i ){ - for( size_t j = i+1 ; j < proj.size(); ++j ){ - - accepted.makeProjection( Projection2D(proj[i],proj[j] ) )->Write(); - } - } - } - - INFO( "Writing output file " ); - - f->Close(); -} diff --git a/apps/LibDiff.cpp b/apps/LibDiff.cpp new file mode 100644 index 00000000000..344f87b20ea --- /dev/null +++ b/apps/LibDiff.cpp @@ -0,0 +1,121 @@ +#include "AmpGen/PhaseSpace.h" +#include "AmpGen/DynamicFCN.h" +#include "AmpGen/Utilities.h" +#include "AmpGen/OptionsParser.h" +#include "AmpGen/NamedParameter.h" + +using namespace AmpGen; + +std::vector cmd( const std::string& command ){ + std::vector output; + FILE* proc = popen(command.c_str(), "r"); + char buf[4096]; + while (!feof(proc) && fgets(buf, sizeof(buf), proc)) output.push_back(buf); + pclose(proc); + return output; +} + +struct Counter { + int pass {0}; + int total{0}; + Counter() = default; + Counter( const bool& pass ) : pass(pass), total(1) {} + Counter( const double& a, const double& b, const std::string& name, const double& tolerance ); + Counter( const complex_t& a, const complex_t& b, const std::string& name, const double& tolerance ); + Counter(const std::vector& a, const std::vector& b, const std::string& name, const double& tolerance); + void operator+=( const Counter& other ) + { + this->pass += other.pass; + this->total += other.total; + } + +}; + +Counter::Counter(const double& a, const double& b, const std::string& name, const double& tolerance) +{ + double diff = std::abs(a-b); + total = 1; + if( diff > std::abs(tolerance) ){ + ERROR( name << " (" << a << " " << b << ") = " << diff << " > " << tolerance); + pass = 0; + } + else pass =1; + DEBUG( name << " (" << a << " " << b << ") = " << diff << " > " << tolerance); +} + +Counter::Counter(const complex_t& a, const complex_t& b, const std::string& name, const double& tolerance) +{ + double diff_re = std::abs(std::real(a)-std::real(b)); + double diff_im = std::abs(std::imag(a)-std::imag(b)); + total =1; + if( diff_re > std::abs(tolerance) || diff_im > std::abs(tolerance) ){ + ERROR( name << " (" << a << " " << b << ") = " << diff_re << ", " << diff_im << " > " << tolerance); + pass =0; + } + else pass = 1; + DEBUG( name << " (" << a << " " << b << ") = " << diff_re << ", " << diff_im << " < " << tolerance); +} + +Counter::Counter(const std::vector& a, const std::vector& b, const std::string& name, const double& tolerance) +{ + total = a.size(); + for( size_t i = 0 ; i < a.size(); ++i ){ + double diff_re = std::abs(std::real(a[i])-std::real(b[i])); + double diff_im = std::abs(std::imag(a[i])-std::imag(b[i])); + if( diff_re > std::abs(tolerance) || diff_im > std::abs(tolerance) ){ + ERROR( name << " (" << a[i] << " " << b[i] << ") = " << diff_re << ", " << diff_im << " > " << tolerance); + } + else pass++; + DEBUG( name << " (" << a[i] << " " << b[i] << ") = " << diff_re << ", " << diff_im << " > " << tolerance); + } +} + +int main( int argc, char** argv ) +{ + std::string modelName = argv[1]; + OptionsParser::getMe()->setQuiet(); + OptionsParser::setArgs( argc, argv ); + PhaseSpace phsp( EventType(NamedParameter("EventType", "").getVector()) ); + auto event = phsp.makeEvent(); + auto event2 = phsp.makeEvent(); + std::string lib = NamedParameter("Lib",""); + std::string refLib = NamedParameter("RefLib",""); + std::string type = NamedParameter("Type","CoherentSum"); + Counter total; + + auto ftable = cmd("nm " + refLib + "| grep __wParams"); + if( type == "CoherentSum"){ + auto f1 = DynamicFCN(lib, "AMP"); + auto f2 = DynamicFCN(refLib, "AMP"); + total += Counter(f1(event,+1), f2(event,+1), modelName + " fcn(x)", 10e-6 ); + total += Counter(f1(event,-1), f2(event,-1), modelName + " fcn(Px)", 10e-6); + for( auto& line : ftable ) + { + auto i = trim( split(line,' ')[2] ); + auto f = DynamicFCN(lib, i ); + auto g = DynamicFCN(refLib, i ); + if( !f.isLinked() || !g.isLinked() ) total += false ; + else total += Counter( f(event), g(event), i, 10e-6); + } + } + if( type == "PolarisedSum"){ + auto f1 = DynamicFCN(lib , "FCN_extPol"); + auto f2 = DynamicFCN(refLib, "FCN_extPol"); + total += Counter(f1(event,+1,0,0,0), f2(event,+1,0,0,0), modelName + " fcn(x)" , 1e-6); + total += Counter(f1(event,-1,0,0,0), f2(event,-1,0,0,0), modelName + " fcn(Px)", 1e-6); + for( auto& line : ftable ){ + auto i = trim( split(line,' ')[2] ); + auto a1 = DynamicFCN(const double*)>(lib , i ); + auto a2 = DynamicFCN(const double*)>(refLib, i ); + if( ! a1.isLinked() || ! a2.isLinked() ) total += false; + else { + auto pass = Counter(a1(event), a2(event), i, 10e-6); + total += pass; + } + } + } + if(total.pass == total.total) + INFO("Library: " << modelName << " matches [passed = " << total.pass << " / " << total.total << "]" ); + else + ERROR("Library: " << modelName << " does not match [passed = " << total.pass << " / " << total.total << "]" ); +} diff --git a/doc/doxyfile b/doc/doxyfile index 851d07e57da..f9b12378de2 100644 --- a/doc/doxyfile +++ b/doc/doxyfile @@ -33,14 +33,13 @@ DOXYFILE_ENCODING = UTF-8 # The default value is: My Project. PROJECT_NAME = "AmpGen" -PROJECT_NUMBER = 1.1 +PROJECT_NUMBER = 1.2 PROJECT_BRIEF = PROJECT_LOGO = "figs/logo_small.png" -OUTPUT_DIRECTORY = "../build/" LAYOUT_FILE = "DoxygenLayout.xml" HTML_EXTRA_STYLESHEET = "customdoxygen.css" -INPUT = "../AmpGen" "../README.md" -USE_MDFILE_AS_MAINPAGE = "../README.md" +INPUT = "../AmpGen" "../README.tex.md" +USE_MDFILE_AS_MAINPAGE = "../README.tex.md" IMAGE_PATH = "figs/" # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- @@ -1248,7 +1247,7 @@ MAN_LINKS = NO # captures the structure of the code including all documentation. # The default value is: NO. -GENERATE_XML = NO +GENERATE_XML = YES # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of diff --git a/doc/figs/k3pi_s01.svg b/doc/figs/k3pi_s01.svg new file mode 100644 index 00000000000..8aa81f430ac --- /dev/null +++ b/doc/figs/k3pi_s01.svg @@ -0,0 +1,593 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/lb2jspiL_s01.svg b/doc/figs/lb2jspiL_s01.svg new file mode 100644 index 00000000000..6e9f53f0acd --- /dev/null +++ b/doc/figs/lb2jspiL_s01.svg @@ -0,0 +1,544 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/lb2jspiL_s012.svg b/doc/figs/lb2jspiL_s012.svg new file mode 100644 index 00000000000..d0c6dcf3164 --- /dev/null +++ b/doc/figs/lb2jspiL_s012.svg @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/lb2pKpi_s01.svg b/doc/figs/lb2pKpi_s01.svg new file mode 100644 index 00000000000..dfd139bd86e --- /dev/null +++ b/doc/figs/lb2pKpi_s01.svg @@ -0,0 +1,594 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/lb2pKpi_s02.svg b/doc/figs/lb2pKpi_s02.svg new file mode 100644 index 00000000000..d8c6194511e --- /dev/null +++ b/doc/figs/lb2pKpi_s02.svg @@ -0,0 +1,713 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/lb2pKpi_s12.svg b/doc/figs/lb2pKpi_s12.svg new file mode 100644 index 00000000000..364f6647442 --- /dev/null +++ b/doc/figs/lb2pKpi_s12.svg @@ -0,0 +1,715 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/s12.svg b/doc/figs/s12.svg new file mode 100644 index 00000000000..364f6647442 --- /dev/null +++ b/doc/figs/s12.svg @@ -0,0 +1,715 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig0.svg b/doc/figs/tex/fig0.svg new file mode 100644 index 00000000000..cd6a77bec58 --- /dev/null +++ b/doc/figs/tex/fig0.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig1.svg b/doc/figs/tex/fig1.svg new file mode 100644 index 00000000000..6f3f59ddf13 --- /dev/null +++ b/doc/figs/tex/fig1.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig10.svg b/doc/figs/tex/fig10.svg new file mode 100644 index 00000000000..b3c7c57fb17 --- /dev/null +++ b/doc/figs/tex/fig10.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig11.svg b/doc/figs/tex/fig11.svg new file mode 100644 index 00000000000..430714dc97d --- /dev/null +++ b/doc/figs/tex/fig11.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig12.svg b/doc/figs/tex/fig12.svg new file mode 100644 index 00000000000..9c2658ab34c --- /dev/null +++ b/doc/figs/tex/fig12.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig13.svg b/doc/figs/tex/fig13.svg new file mode 100644 index 00000000000..4772cdbc29a --- /dev/null +++ b/doc/figs/tex/fig13.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig14.svg b/doc/figs/tex/fig14.svg new file mode 100644 index 00000000000..53f2dc72ac6 --- /dev/null +++ b/doc/figs/tex/fig14.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig15.svg b/doc/figs/tex/fig15.svg new file mode 100644 index 00000000000..d107ae8333f --- /dev/null +++ b/doc/figs/tex/fig15.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig16.svg b/doc/figs/tex/fig16.svg new file mode 100644 index 00000000000..30e7319ca92 --- /dev/null +++ b/doc/figs/tex/fig16.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig17.svg b/doc/figs/tex/fig17.svg new file mode 100644 index 00000000000..e06cb3fea26 --- /dev/null +++ b/doc/figs/tex/fig17.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig18.svg b/doc/figs/tex/fig18.svg new file mode 100644 index 00000000000..2c2621e562f --- /dev/null +++ b/doc/figs/tex/fig18.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig19.svg b/doc/figs/tex/fig19.svg new file mode 100644 index 00000000000..c4756c76dc2 --- /dev/null +++ b/doc/figs/tex/fig19.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig2.svg b/doc/figs/tex/fig2.svg new file mode 100644 index 00000000000..1d0aad29aeb --- /dev/null +++ b/doc/figs/tex/fig2.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig20.svg b/doc/figs/tex/fig20.svg new file mode 100644 index 00000000000..1bc66dad39a --- /dev/null +++ b/doc/figs/tex/fig20.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig21.svg b/doc/figs/tex/fig21.svg new file mode 100644 index 00000000000..9d2d8902ad9 --- /dev/null +++ b/doc/figs/tex/fig21.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig22.svg b/doc/figs/tex/fig22.svg new file mode 100644 index 00000000000..7d96049e8cc --- /dev/null +++ b/doc/figs/tex/fig22.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig23.svg b/doc/figs/tex/fig23.svg new file mode 100644 index 00000000000..64b0735b240 --- /dev/null +++ b/doc/figs/tex/fig23.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig24.svg b/doc/figs/tex/fig24.svg new file mode 100644 index 00000000000..203e006c887 --- /dev/null +++ b/doc/figs/tex/fig24.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig25.svg b/doc/figs/tex/fig25.svg new file mode 100644 index 00000000000..1d0aad29aeb --- /dev/null +++ b/doc/figs/tex/fig25.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig26.svg b/doc/figs/tex/fig26.svg new file mode 100644 index 00000000000..7d652ec63a2 --- /dev/null +++ b/doc/figs/tex/fig26.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig27.svg b/doc/figs/tex/fig27.svg new file mode 100644 index 00000000000..219c86f4c1a --- /dev/null +++ b/doc/figs/tex/fig27.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig28.svg b/doc/figs/tex/fig28.svg new file mode 100644 index 00000000000..203e006c887 --- /dev/null +++ b/doc/figs/tex/fig28.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig29.svg b/doc/figs/tex/fig29.svg new file mode 100644 index 00000000000..c1b4811dcda --- /dev/null +++ b/doc/figs/tex/fig29.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig3.svg b/doc/figs/tex/fig3.svg new file mode 100644 index 00000000000..74395b91b9f --- /dev/null +++ b/doc/figs/tex/fig3.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig30.svg b/doc/figs/tex/fig30.svg new file mode 100644 index 00000000000..fae269e3c3d --- /dev/null +++ b/doc/figs/tex/fig30.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig31.svg b/doc/figs/tex/fig31.svg new file mode 100644 index 00000000000..1bc66dad39a --- /dev/null +++ b/doc/figs/tex/fig31.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig32.svg b/doc/figs/tex/fig32.svg new file mode 100644 index 00000000000..e7d8901dec9 --- /dev/null +++ b/doc/figs/tex/fig32.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig33.svg b/doc/figs/tex/fig33.svg new file mode 100644 index 00000000000..237a622257f --- /dev/null +++ b/doc/figs/tex/fig33.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig34.svg b/doc/figs/tex/fig34.svg new file mode 100644 index 00000000000..cd6a77bec58 --- /dev/null +++ b/doc/figs/tex/fig34.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig35.svg b/doc/figs/tex/fig35.svg new file mode 100644 index 00000000000..cd6a77bec58 --- /dev/null +++ b/doc/figs/tex/fig35.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig36.svg b/doc/figs/tex/fig36.svg new file mode 100644 index 00000000000..b3116a75348 --- /dev/null +++ b/doc/figs/tex/fig36.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig37.svg b/doc/figs/tex/fig37.svg new file mode 100644 index 00000000000..cd6a77bec58 --- /dev/null +++ b/doc/figs/tex/fig37.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig38.svg b/doc/figs/tex/fig38.svg new file mode 100644 index 00000000000..60c45e30ba3 --- /dev/null +++ b/doc/figs/tex/fig38.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig39.svg b/doc/figs/tex/fig39.svg new file mode 100644 index 00000000000..2b237e03225 --- /dev/null +++ b/doc/figs/tex/fig39.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig4.svg b/doc/figs/tex/fig4.svg new file mode 100644 index 00000000000..50106b737b3 --- /dev/null +++ b/doc/figs/tex/fig4.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig40.svg b/doc/figs/tex/fig40.svg new file mode 100644 index 00000000000..cd6a77bec58 --- /dev/null +++ b/doc/figs/tex/fig40.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig41.svg b/doc/figs/tex/fig41.svg new file mode 100644 index 00000000000..f2a072cea11 --- /dev/null +++ b/doc/figs/tex/fig41.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig42.svg b/doc/figs/tex/fig42.svg new file mode 100644 index 00000000000..8be51763347 --- /dev/null +++ b/doc/figs/tex/fig42.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig43.svg b/doc/figs/tex/fig43.svg new file mode 100644 index 00000000000..f2c928f67e8 --- /dev/null +++ b/doc/figs/tex/fig43.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig44.svg b/doc/figs/tex/fig44.svg new file mode 100644 index 00000000000..c63d8cd345a --- /dev/null +++ b/doc/figs/tex/fig44.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig45.svg b/doc/figs/tex/fig45.svg new file mode 100644 index 00000000000..58c801d5579 --- /dev/null +++ b/doc/figs/tex/fig45.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig5.svg b/doc/figs/tex/fig5.svg new file mode 100644 index 00000000000..285012c74e7 --- /dev/null +++ b/doc/figs/tex/fig5.svg @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig6.svg b/doc/figs/tex/fig6.svg new file mode 100644 index 00000000000..d996c971647 --- /dev/null +++ b/doc/figs/tex/fig6.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig7.svg b/doc/figs/tex/fig7.svg new file mode 100644 index 00000000000..c5c6dacc2ec --- /dev/null +++ b/doc/figs/tex/fig7.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig8.svg b/doc/figs/tex/fig8.svg new file mode 100644 index 00000000000..1f058383058 --- /dev/null +++ b/doc/figs/tex/fig8.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figs/tex/fig9.svg b/doc/figs/tex/fig9.svg new file mode 100644 index 00000000000..1b49bbf978b --- /dev/null +++ b/doc/figs/tex/fig9.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/release.notes b/doc/release.notes index 08a6f9a3dd8..cd850f12407 100644 --- a/doc/release.notes +++ b/doc/release.notes @@ -1,8 +1,24 @@ -!----------------------------------------------------------------------------- -! Package : Gen/AmpGen -! Responsible : Tim Evans -! Purpose : -!----------------------------------------------------------------------------- +!=================== AmpGen v2r1 2020-28-10 ================== + - Improved cmake configuration to allow installation + - Consolidation of Generator and ConvertToSourceCode to single executable 'AmpGen' +!=================== AmpGen v2r0 2020-25-04 ================== + - Refactored caching logic away from being computations being stored with event data. + - Support for AVX2 for amplitude evaluation / integration single/double precision. + - Updated plotting for making component amplitude plots. + - Better thread safety of integration should improve fit stability. + - Add GenericKmatrix lineshape for handling ... Generic K-matrices (L=0 only) +!=================== AmpGen v1r2 2019-11-12 ================== + - New phase space Generator TreePhaseSpace for producing narrow resonances. + - Improved handling of CP conjugated amplitudes. + - Add vertices f_fS_S{L,R} f_Vf_S{L,R} for couplings with well-defined chirality. + - Add initial states with ill-defined flavour to PolarisedSum +!=================== AmpGen v1r2 2019-08-13 ================== + - Tagged to match results in Gauss/LbAmpGen v49r14+ + - Improved thread support for CoherentSum + - Add examples/QcGenerator for Ψ(3770) decays +! 2019-05-29 - Tim Evans + - Updated ExpressionParser with improved stability. + - Removed unused / untested lineshapes AxialKaon and ObelixRho !=================== AmpGen v1r1 2019-03-22 ================== ! 2019-03-22 - Tim Evans - Added support for fitting more general final states, i.e. with multiple fermions, photons etc. @@ -19,8 +35,6 @@ !============================================================= ! 2016-09-06 - Tim Evans - First import of source, apps, headers - - ! 2016-09-02 - Tim Evans - Empty structure for the package !============================================================= diff --git a/examples/BaryonFitter.cpp b/examples/BaryonFitter.cpp new file mode 100644 index 00000000000..a4657e804bb --- /dev/null +++ b/examples/BaryonFitter.cpp @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AmpGen/Chi2Estimator.h" +#include "AmpGen/ErrorPropagator.h" +#if ENABLE_AVX + #include "AmpGen/EventListSIMD.h" + using EventList_type = AmpGen::EventListSIMD; +#else + #include "AmpGen/EventList.h" + using EventList_type = AmpGen::EventList; +#endif +#include "AmpGen/EventType.h" +#include "AmpGen/Factory.h" +#include "AmpGen/RecursivePhaseSpace.h" +#include "AmpGen/FitResult.h" +#include "AmpGen/IExtendLikelihood.h" +#include "AmpGen/Minimiser.h" +#include "AmpGen/MinuitParameter.h" +#include "AmpGen/MinuitParameterSet.h" +#include "AmpGen/MsgService.h" +#include "AmpGen/NamedParameter.h" +#include "AmpGen/SumPDF.h" +#include "AmpGen/ThreeBodyCalculators.h" +#include "AmpGen/Utilities.h" +#include "AmpGen/Generator.h" +#include "AmpGen/PolarisedSum.h" +#include "AmpGen/Kinematics.h" + +#ifdef _OPENMP + #include + #include +#endif + +using namespace AmpGen; + +void randomizeStartingPoint( MinuitParameterSet& mps, TRandom3& rand) +{ + for (auto& param : mps) { + if ( ! param->isFree() || param->name() == "Px" || param->name() == "Py" || param->name() == "Pz" ) continue; + double min = param->minInit(); + double max = param->maxInit(); + double new_value = rand.Uniform(param->mean()-param->stepInit(),param->mean()+param->stepInit()); + if( min != 0 && max != 0 ) + new_value = rand.Uniform(min,max); + param->setInit( new_value ); + param->setCurrentFitVal( new_value ); + INFO( param->name() << " = " << param->mean() << " " << param->stepInit() ); + } +} + +template +FitResult* doFit( PDF&& pdf, EventList_type& data, EventList_type& mc, MinuitParameterSet& MPS ) +{ + auto time_wall = std::chrono::high_resolution_clock::now(); + auto time = std::clock(); + + pdf.setEvents( data ); + + /* Minimiser is a general interface to Minuit1/Minuit2, + that is constructed from an object that defines an operator() that returns a double + (i.e. the likielihood, and a set of MinuitParameters. */ + Minimiser mini( pdf, &MPS ); + mini.doFit(); + FitResult* fr = new FitResult(mini); + + /* Estimate the chi2 using an adaptive / decision tree based binning, + down to a minimum bin population of 15, and add it to the output.*/ + //if(data.eventType().size() < 5){ + // Chi2Estimator chi2( data, mc, pdf, 15 ); + // //chi2.writeBinningToFile("chi2_binning.txt"); + // fr->addChi2( chi2.chi2(), chi2.nBins() ); + //} + + auto twall_end = std::chrono::high_resolution_clock::now(); + double time_cpu = ( std::clock() - time ) / (double)CLOCKS_PER_SEC; + double tWall = std::chrono::duration( twall_end - time_wall ).count(); + INFO( "Wall time = " << tWall / 1000. ); + INFO( "CPU time = " << time_cpu ); + fr->print(); + + /* Save weighted data and norm MC for the different components in the PDF, i.e. the signal and backgrounds. + The structure assumed the PDF is some SumPDF. */ + unsigned int counter = 1; + for_each(pdf.pdfs(), [&]( auto& f ){ + mc.transform([&f](auto& mcevt){mcevt.setWeight(f.getValNoCache(mcevt)*mcevt.weight()/mcevt.genPdf());}).tree(counter>1?"MCt"+std::to_string(counter):"MCt")->Write(); + data.tree(counter>1?"t"+std::to_string(counter):"t")->Write(); + counter++; + } ); + + return fr; +} + +void invertParity( Event& event, const size_t& nParticles=0) +{ + for( size_t i = 0 ; i < nParticles; ++i ) + { + event[4*i + 0] = -event[4*i+0]; + event[4*i + 1] = -event[4*i+1]; + event[4*i + 2] = -event[4*i+2]; + } +} + +int main( int argc, char* argv[] ) +{ + gErrorIgnoreLevel = 1001; + + OptionsParser::setArgs( argc, argv ); + + const std::vector dataFile = NamedParameter("DataSample","").getVector(); + const std::string simFile = NamedParameter("SimFile", "" , "Name of file containing simulated sample for using in MC integration"); + const std::string logFile = NamedParameter("LogFile","Fitter.log"); + const std::string plotFile = NamedParameter("Plots","plots.root"); + const std::string prefix = NamedParameter("PlotPrefix",""); + const std::string idbranch = NamedParameter("IDBranch",""); + const std::string mcidbranch = NamedParameter("MCIDBranch",""); + const std::string weight_branch = NamedParameter("WeightBranch","","Name of branch containing event weights."); + const std::string mc_weight_branch = NamedParameter("MCWeightBranch","","Name of branch containing event weights."); + + const auto nev_MC = NamedParameter("NEventsMC", 8e6, "Number of MC events for normalization."); + auto bNames = NamedParameter("Branches", std::vector(), + "List of branch names, assumed to be \033[3m daughter1_px ... daughter1_E, daughter2_px ... \033[0m" ).getVector(); + auto MCbNames = NamedParameter("MCBranches", std::vector(), + "List of branch names, assumed to be \033[3m daughter1_px ... daughter1_E, daughter2_px ... \033[0m" ).getVector(); + auto pNames = NamedParameter("EventType" , "" + , "EventType to fit, in the format: \033[3m parent daughter1 daughter2 ... \033[0m" ).getVector(); + +#if ENABLE_AVX + if(!idbranch.empty() || !weight_branch.empty() || !mcidbranch.empty() || !mc_weight_branch.empty()){ + ERROR("Vectorized version currently not supported when adding extra branches"); + return 1; + } +#endif + +#ifdef _OPENMP + unsigned int concurentThreadsSupported = std::thread::hardware_concurrency(); + unsigned int nThreads = NamedParameter( "nCores", concurentThreadsSupported ); + omp_set_num_threads( nThreads ); + INFO( "Setting " << nThreads << " fixed threads for OpenMP" ); + omp_set_dynamic( 0 ); +#endif + + + /* A MinuitParameterSet is (unsurprisingly) a set of fit parameters, and can be loaded from + the parsed options. For historical reasons, this is referred to as loading it from a "Stream" */ + MinuitParameterSet MPS; + MPS.loadFromStream(); + TRandom3 rndm = TRandom3( NamedParameter("Seed", 1 ) ) ; + if( NamedParameter("RandomizeStartingPoint",false) ) randomizeStartingPoint(MPS,rndm ); + + /* An EventType specifies the initial and final state particles as a vector that will be described by the fit. + It is typically loaded from the interface parameter EventType. */ + EventType evtType(pNames); + + /* A CoherentSum is the typical amplitude to be used, that is some sum over quasi two-body contributions + weighted by an appropriate complex amplitude. The CoherentSum is generated from the couplings described + by a set of parameters (in a MinuitParameterSet), and an EventType, which matches these parameters + to a given final state and a set of data. A common set of rules can be matched to multiple final states, + i.e. to facilitate the analysis of coupled channels. */ + PolarisedSum sig(evtType, MPS); + + /* Events are read in from ROOT files. If only the filename and the event type are specified, + the file is assumed to be in the specific format that is defined by the event type, + unless the branches to load are specified in the user options */ + EventList_type events(dataFile, evtType, Branches(bNames), GetGenPdf(false), WeightBranch(weight_branch), ExtraBranches(std::vector{idbranch}) ); + + /* Generate events to normalise the PDF with. This can also be loaded from a file, + which will be the case when efficiency variations are included. */ + EventList_type eventsMC = simFile == "" + ? EventList_type(Generator(sig.matrixElements()[0].decayTree.quasiStableTree(), events.eventType(), &rndm).generate(nev_MC)) + : EventList_type(simFile, evtType, Branches(MCbNames), WeightBranch(mc_weight_branch), ExtraBranches(std::vector{mcidbranch})); + + /* Transform data if we have an ID brach. That branch indicates that we operate on a sample with particles+antiparticles mixed. + The transformation also includes boosting to the restframe of the head of the decay chain. + TODO: There might be situations where you want to separate both transformations */ + auto const n_final_state_particles = evtType.size(); + std::vector daughters_as_ints(n_final_state_particles); + std::iota (daughters_as_ints.begin(), daughters_as_ints.end(), 0u); + auto frame_transform = [&evtType, &daughters_as_ints, &n_final_state_particles](auto& event){ + TVector3 pBeam(0,0,1); + if( event[event.size()-1] < 0 ){ + invertParity( event, n_final_state_particles); + pBeam = -pBeam; + } + TLorentzVector pP = pFromEvent(event,daughters_as_ints); + //if( pP.P() < 10e-5) return; + TVector3 pZ = pP.Vect(); + rotateBasis( event, (pBeam.Cross(pZ) ).Cross(pZ), pBeam.Cross(pZ), pZ ); + boost( event, {0, 0, -1}, pP.P()/pP.E() ); + }; + + + for( auto& event : events ) + if( event[event.size()-1] < 0 ){ + event.print(); + break; + } + events.transform( frame_transform ); + for( auto& event : events ) + if( event[event.size()-1] < 0 ){//E if there's no ID branch + event.print(); + break; + } + for( auto& event : eventsMC ) + if( event[event.size()-1] < 0 ){ + event.print(); + break; + } + eventsMC.transform( frame_transform ); + for( auto& event : eventsMC ) + if( event[event.size()-1] < 0 ){//E if there's no ID branch + event.print(); + break; + } + sig.setMC(eventsMC); + sig.setEvents(events); + + TFile* output = TFile::Open( plotFile.c_str(), "RECREATE" ); + output->cd(); + auto fr = doFit(make_pdf(sig), events, eventsMC, MPS); + + auto ff = sig.fitFractions( fr->getErrorPropagator() ); + fr->addFractions(ff); + fr->writeToFile( logFile ); + output->Close(); + return 0; +} diff --git a/examples/FitHyperonParameters.cpp b/examples/FitHyperonParameters.cpp new file mode 100644 index 00000000000..ccb856cfe76 --- /dev/null +++ b/examples/FitHyperonParameters.cpp @@ -0,0 +1,22 @@ +#include "AmpGen/MinuitParameterSet.h" +#include "AmpGen/Minimiser.h" +#include "AmpGen/NamedParameter.h" + +using namespace AmpGen; + +int main( int argc, char* argv[] ){ + OptionsParser::setArgs( argc, argv ); + MinuitParameterSet mps; + mps.add("gRe",AmpGen::Flag::Free,0,0.1,-10,10); + mps.add("gIm",AmpGen::Flag::Free,0,0.1,-10,10); + const auto alpha_measured = NamedParameter("alpha", 0.75); + const auto phi_measured = NamedParameter("phi", -6.5); + const auto alpha_error = NamedParameter("alpha_error", 0.012); + const auto phi_error = NamedParameter("phi_error", 3.5); + std::function f = [&mps, &alpha_measured, &alpha_error, &phi_measured, &phi_error]() -> double { + auto alpha_pred = 2.*mps[0]->mean()/(1.+mps[0]->mean()*mps[0]->mean()+mps[1]->mean()*mps[1]->mean()); + auto phi_pred = 180.*atan(2.*mps[1]->mean()/(1.-(mps[0]->mean()*mps[0]->mean()+mps[1]->mean()*mps[1]->mean())))/M_PI; + return pow((alpha_measured-alpha_pred)/alpha_error,2.)+pow((phi_measured-phi_pred)/phi_error,2.); + }; + Minimiser(f, &mps).doFit(); +} diff --git a/examples/FitterWithPolarisation.cpp b/examples/FitterWithPolarisation.cpp index 25aad8ae32a..bc36c2ac700 100644 --- a/examples/FitterWithPolarisation.cpp +++ b/examples/FitterWithPolarisation.cpp @@ -9,6 +9,7 @@ #include #include "AmpGen/Chi2Estimator.h" +#include "AmpGen/RecursivePhaseSpace.h" #include "AmpGen/EventList.h" #include "AmpGen/EventType.h" #include "AmpGen/CoherentSum.h" @@ -32,10 +33,23 @@ #include #include +#if ENABLE_AVX + #include "AmpGen/EventListSIMD.h" + using EventList_type = AmpGen::EventListSIMD; +#else + #include "AmpGen/EventList.h" + using EventList_type = AmpGen::EventList; +#endif + using namespace AmpGen; +template Particle getTopology(const pdf_t& pdf) +{ + return pdf.matrixElements()[0].decayTree.quasiStableTree(); +} + template -FitResult* doFit( PDF&& pdf, EventList& data, EventList& mc, MinuitParameterSet& MPS ); +FitResult* doFit( PDF&& pdf, EventList_type& data, EventList_type& mc, MinuitParameterSet& MPS ); int main( int argc, char* argv[] ) { @@ -50,7 +64,7 @@ int main( int argc, char* argv[] ) std::string dataFile = NamedParameter("DataSample", "" , "Name of file containing data sample to fit." ); std::string logFile = NamedParameter("LogFile" , "Fitter.log", "Name of the output log file"); std::string plotFile = NamedParameter("Plots" , "plots.root", "Name of the output plot file"); - + std::string simFile = NamedParameter("SgIntegratorFname", "" , "Name of file containing simulated sample for using in MC integration"); auto bNames = NamedParameter("Branches", std::vector() ,"List of branch names, assumed to be \033[3m daughter1_px ... daughter1_E, daughter2_px ... \033[0m" ).getVector(); @@ -60,9 +74,7 @@ int main( int argc, char* argv[] ) if( dataFile == "" ) FATAL("Must specify input with option " << italic_on << "DataSample" << italic_off ); if( pNames.size() == 0 ) FATAL("Must specify event type with option " << italic_on << " EventType" << italic_off); - [[maybe_unused]] - size_t nThreads = NamedParameter ("nCores" , 8 , "Number of threads to use" ); - size_t seed = NamedParameter ("Seed" , 0 , "Random seed used" ); + size_t seed = NamedParameter ("Seed" , 1 , "Random seed used" ); TRandom3 rndm; rndm.SetSeed( seed ); @@ -71,6 +83,7 @@ int main( int argc, char* argv[] ) INFO("LogFile: " << logFile << "; Plots: " << plotFile ); #ifdef _OPENMP + size_t nThreads = NamedParameter ("nCores" , 8 , "Number of threads to use" ); omp_set_num_threads( nThreads ); INFO( "Setting " << nThreads << " fixed threads for OpenMP" ); omp_set_dynamic( 0 ); @@ -80,6 +93,7 @@ int main( int argc, char* argv[] ) the parsed options. For historical reasons, this is referred to as loading it from a "Stream" */ MinuitParameterSet MPS; MPS.loadFromStream(); + // for( auto& p : MPS ) if( p->flag() == Flag::Free ) p->setResult( gRandom->Gaus( p->mean(), p->err() ), p->err(), 0,0 ); /* An EventType specifies the initial and final state particles as a vector that will be described by the fit. It is typically loaded from the interface parameter EventType. */ @@ -95,12 +109,14 @@ int main( int argc, char* argv[] ) /* Events are read in from ROOT files. If only the filename and the event type are specified, the file is assumed to be in the specific format that is defined by the event type, unless the branches to load are specified in the user options */ - EventList events(dataFile, evtType, Branches(bNames), GetGenPdf(false) ); + EventList_type events(dataFile, evtType, Branches(bNames), GetGenPdf(false) ); /* Generate events to normalise the PDF with. This can also be loaded from a file, which will be the case when efficiency variations are included. Default number of normalisation events - is 5 million. */ - EventList eventsMC = Generator<>(evtType, &rndm).generate(5e6); + is 2 million. */ + Generator signalGenerator( getTopology(sig), events.eventType(), &rndm ); + auto events_l = signalGenerator.generate(1e6); + EventList_type eventsMC = simFile == "" ? EventList_type(events_l) : EventList_type(simFile, evtType); sig.setMC( eventsMC ); @@ -108,27 +124,21 @@ int main( int argc, char* argv[] ) /* Do the fit and return the fit results, which can be written to the log and contains the covariance matrix, fit parameters, and other observables such as fit fractions */ - FitResult* fr = doFit(make_pdf(sig), events, eventsMC, MPS ); + FitResult* fr = doFit(make_pdf(sig), events, eventsMC, MPS ); /* Calculate the `fit fractions` using the signal model and the error propagator (i.e. fit results + covariance matrix) of the fit result, and write them to a file. */ auto fitFractions = sig.fitFractions( fr->getErrorPropagator() ); - + + INFO("Adding fraction to file..."); fr->addFractions( fitFractions ); - fr->writeToFile( logFile ); - output->cd(); - - /* Write out the data plots. This also shows the first example of the named arguments - to functions, emulating python's behaviour in this area */ - - auto plots = events.makeDefaultProjections(Prefix("Data"), Bins(100)); - for ( auto& plot : plots ) plot->Write(); - + INFO("Writing file ... "); + fr->writeToFile( logFile ); output->Close(); } template -FitResult* doFit( PDF&& pdf, EventList& data, EventList& mc, MinuitParameterSet& MPS ) +FitResult* doFit( PDF&& pdf, EventList_type& data, EventList_type& mc, MinuitParameterSet& MPS ) { auto time_wall = std::chrono::high_resolution_clock::now(); auto time = std::clock(); @@ -144,28 +154,29 @@ FitResult* doFit( PDF&& pdf, EventList& data, EventList& mc, MinuitParameterSet& /* Make the plots for the different components in the PDF, i.e. the signal and backgrounds. The structure assumed the PDF is some SumPDF. */ - unsigned int counter = 1; - for_each(pdf.m_pdfs, [&]( auto& f ){ -// std::function FCN_sig = [&](const Event& evt){ return f.prob_unnormalised(evt) ; }; - auto mc_plot3 = mc.makeDefaultProjections(WeightFunction(f), Prefix("Model_cat"+std::to_string(counter))); - for( auto& plot : mc_plot3 ) - { - plot->Scale( ( data.integral() * f.getWeight() ) / plot->Integral() ); - plot->Write(); - } - counter++; - } ); /* Estimate the chi2 using an adaptive / decision tree based binning, down to a minimum bin population of 15, and add it to the output. */ - Chi2Estimator chi2( data, mc, pdf, 15 ); - chi2.writeBinningToFile("chi2_binning.txt"); - fr->addChi2( chi2.chi2(), chi2.nBins() ); + // Chi2Estimator chi2( data, mc, pdf, 15 ); + // chi2.writeBinningToFile("chi2_binning.txt"); + // fr->addChi2( chi2.chi2(), chi2.nBins() ); auto twall_end = std::chrono::high_resolution_clock::now(); double time_cpu = ( std::clock() - time ) / (double)CLOCKS_PER_SEC; double tWall = std::chrono::duration( twall_end - time_wall ).count(); INFO( "Wall time = " << tWall / 1000. ); INFO( "CPU time = " << time_cpu ); + auto evaluator = pdf.componentEvaluator(&mc); + auto projections = data.eventType().defaultProjections(100); + + /* Write out the data plots. This also shows the first example of the named arguments + to functions, emulating python's behaviour in this area */ + auto evaluator_per_component = std::get<0>( pdf.pdfs() ).componentEvaluator(); + for( const auto& proj : projections ) + { + proj(mc, evaluator, PlotOptions::Norm(data.size()), PlotOptions::AutoWrite() ); + proj(mc, evaluator_per_component, PlotOptions::Prefix("amp"), PlotOptions::Norm(data.size()), PlotOptions::AutoWrite() ); + proj(data, PlotOptions::Prefix("Data") )->Write(); + } fr->print(); return fr; } diff --git a/examples/QcGenerator.cpp b/examples/QcGenerator.cpp new file mode 100644 index 00000000000..7a410e5ab45 --- /dev/null +++ b/examples/QcGenerator.cpp @@ -0,0 +1,447 @@ +#include "AmpGen/CoherentSum.h" +#include "AmpGen/Generator.h" +#include "AmpGen/EventType.h" +#include "AmpGen/NamedParameter.h" +#include "AmpGen/Kinematics.h" +#include "AmpGen/OptionsParser.h" +#include "AmpGen/ProfileClock.h" +#include "AmpGen/ParticlePropertiesList.h" +#include "AmpGen/MinuitParameterSet.h" +#include "AmpGen/AddCPConjugate.h" +#include +#include +#include +#ifdef _OPENMP +#include +#include +#endif + +using namespace AmpGen; +using namespace std::complex_literals; + +class FixedLibPdf +{ + public: + FixedLibPdf() = default; + FixedLibPdf(const EventType& type, MinuitParameterSet& mps) : + FixedLibPdf(NamedParameter(type.decayDescriptor()+"::lib").getVal()) + { + INFO("Constructing: " << type << " flib = " <( handle, "AMP" ); + } + void prepare(){}; + void setEvents( AmpGen::EventList& evts ){}; + double prob_unnormalised( const AmpGen::Event& evt ) const { return std::norm(getValNoCache(evt)); } + complex_t getValNoCache( const AmpGen::Event& evt ) const { return amp(evt,+1); } + size_t size() { return 0; } + void reset( const bool& flag = false ){}; + private: + AmpGen::DynamicFCN amp; +}; + +struct DTEvent +{ + AmpGen::Event signal; + AmpGen::Event tag; + double prob; + DTEvent() : signal(0,0), tag(0,0) {}; + DTEvent( const AmpGen::Event& signal, const AmpGen::Event& tag ) : signal(signal), tag(tag) {}; + void set( const AmpGen::Event& s1, const AmpGen::Event& s2 ) { signal.set(s1); tag.set(s2); }; + void invertParity(){ + for( size_t i = 0 ; i < signal.size(); ++i ) if( i % 4 != 3 ) signal[i] *= -1; + for( size_t i = 0 ; i < tag.size(); ++i ) if( i % 4 != 3 ) tag[i] *= -1; + } +}; + +struct DTEventList : public std::vector +{ + AmpGen::EventType m_sigType; + AmpGen::EventType m_tagType; + DTEventList( const AmpGen::EventType& signal, const AmpGen::EventType& tag ) : m_sigType(signal), m_tagType(tag) {} + std::string particleName(const AmpGen::EventType& type, const size_t& j); + TTree* tree(const std::string& name); +}; + +class DTYieldCalculator { + public: + DTYieldCalculator(const double& productionCrossSection = 3260) : + productionCrossSection(productionCrossSection){} + + double operator()(const double& lumi, + const AmpGen::EventType& t_signal, + const AmpGen::EventType& t_tag, + const bool& print = false); + double bf( const AmpGen::EventType& type ) const; + private: + double productionCrossSection; + std::map getKeyed( const std::string& name ); + std::map branchingRatios = {getKeyed("BranchingRatios")}; + std::map efficiencies = {getKeyed("Efficiencies")}; +}; + +template struct normalised_pdf { + PDF pdf; + complex_t norm; + normalised_pdf() = default; + normalised_pdf(const EventType& type, MinuitParameterSet& mps, const DTYieldCalculator& yc) : pdf(type, mps) + { + ProfileClock pc; + auto normEvents = Generator(type).generate(1e6); + double n =0; + pdf.prepare(); + #pragma omp parallel for reduction(+:n) + for(size_t i =0; imean() * M_PI/180. ); + pc.stop(); + INFO(type << " Time to construct: " << pc << "[ms], norm = " << norm << " " << type_string() ); + } + complex_t operator()(const Event& event){ return norm * pdf.getValNoCache(event); } +}; + +struct ModelStore { + MinuitParameterSet* mps; + DTYieldCalculator yieldCalculator; + std::map> genericModels; + std::map> flibModels; + ModelStore(MinuitParameterSet* mps, const DTYieldCalculator& yc) : mps(mps), yieldCalculator(yc) {} + template normalised_pdf& get(const EventType& type, std::map>& container) + { + auto key = type.decayDescriptor(); + if( container.count(key) == 0 ) + container[key] = normalised_pdf(type, *mps, yieldCalculator); + return container[key]; + } + template normalised_pdf& find(const EventType& type); +}; + +template class Psi3770 { + private: + EventType m_signalType; + EventType m_tagType; + normalised_pdf& m_signal; + normalised_pdf& m_signalBar; + normalised_pdf& m_tag; + normalised_pdf& m_tagBar; + PhaseSpace m_signalPhsp; + PhaseSpace m_tagPhsp; + PhaseSpace m_headPhsp; + bool m_printed = {false}; + bool m_ignoreQc = {NamedParameter("IgnoreQC",false)}; + size_t m_blockSize = {1000000}; + public: + template std::tuple + z(T& t1, T& t2, const EventType& type) const + { + double n1(0), n2(0), zR(0), zI(0); + auto normEvents = Generator(type).generate(m_blockSize); + #pragma omp parallel for reduction(+:zR,zI,n1,n2) + for(size_t i = 0; i < m_blockSize; ++i){ + auto p1 = t1(normEvents[i]); + auto p2 = t2(normEvents[i]); + auto f = p2 * std::conj(p1); + zR += std::real(f); + zI += std::imag(f); + n1 += std::norm(p1); + n2 += std::norm(p2); + } + complex_t z2(zR,zI); + auto arg = std::arg(z2); + return std::make_tuple( std::abs(z2/sqrt(n1*n2)), 180 * ( arg > 0 ? arg : 2*M_PI+arg) /M_PI, sqrt(n1/n2) ); + } + Psi3770(ModelStore& models, + const EventType& signalType, + const EventType& tagType) : + m_signalType(signalType) , + m_tagType (tagType) , + m_signal (models.find(m_signalType)), + m_signalBar (models.find(m_signalType.conj(true))), + m_tag (models.find(m_tagType)) , + m_tagBar (models.find(m_tagType.conj(true))) , + m_signalPhsp(m_signalType ) , + m_tagPhsp (m_tagType ) , + m_headPhsp (EventType({"psi(3770)0","D0","Dbar0"})) + { + INFO("Type = " << m_signalType << " x " << m_tagType.conj(true) << "] - [" << m_signalType.conj(true) << " x " << m_tagType << "]"); + auto z1 = z(m_signal, m_signalBar, m_signalType); + auto z2 = z(m_tag , m_tagBar , m_tagType); + INFO( "Signal: R = " << round(std::get<0>(z1),5) << "; δ = " << round(std::get<1>(z1),3) << "° ; r = " << round(std::get<2>(z1),5) ); + INFO( "Tag : R = " << round(std::get<0>(z2),5) << "; δ = " << round(std::get<1>(z2),3) << "° ; r = " << round(std::get<2>(z2),5) ); + } + complex_t operator()(const DTEvent& event ) const { return operator()( event.signal, event.tag ); } + complex_t operator()(const Event& signal, const Event& tag) const { return m_signal(signal)*m_tagBar(tag) - m_signalBar(signal) * m_tag(tag); } + double P(const DTEvent& event) const { return m_ignoreQc ? prob_noQC(event) : std::norm(operator()(event)); } + double prob_noQC (const DTEvent& event) const { return std::norm(m_signal(event.signal)*m_tagBar(event.tag)) + std::norm(m_signalBar(event.signal)*m_tag(event.tag)); } + DTEvent generatePhaseSpace() { return DTEvent( m_signalPhsp.makeEvent(), m_tagPhsp.makeEvent() ); } + DTEventList generate( const size_t& N ) + { + DTEventList output( m_signalType, m_tagType ); + ProgressBar pb(60, detail::trimmedString(__PRETTY_FUNCTION__)); + auto tStartTotal = std::chrono::high_resolution_clock::now(); + int currentSize = 0; + double norm = -1; + while( output.size() < N ){ + auto events = generatePHSP(m_blockSize); + if(norm == -1 ){ + for(auto& event : events) if(event.prob > norm ) norm = event.prob; + norm *= 1.5; + INFO("Calculated normalisation of PDF = " << norm ); + } + for( auto& event : events ){ + if( event.prob > norm * gRandom->Uniform() ) output.push_back( event ); + if( output.size() >= N ) break ; + } + double efficiency = 100 * double(output.size() - currentSize )/double(m_blockSize); + double time = std::chrono::duration( std::chrono::high_resolution_clock::now() - tStartTotal ).count(); + pb.print( double(output.size()) / double(N), " ε[gen] = " + mysprintf("%.2f",efficiency) + "% , " + std::to_string(int(time/1000.)) + " seconds" ); + currentSize = output.size(); + } + auto psi_q = PhaseSpace(m_headPhsp); + auto beta = [](const Event& event, const size_t&j){ return sqrt( event[4*j+0]*event[4*j+0] + event[4*j+1]*event[4*j+1] + event[4*j+2]*event[4*j+2] )/event[4*j+3] ; }; + auto p = [](const Event& event, const size_t&j){ return std::make_tuple(event[4*j+0], event[4*j+1], event[4*j+2]); }; + for( auto& event : output ){ + auto psi_event = psi_q.makeEvent(); + boost( event.signal, p(psi_event,0), beta(psi_event,0)); + boost( event.tag , p(psi_event,1), beta(psi_event,1)); + } + double time = std::chrono::duration( std::chrono::high_resolution_clock::now() - tStartTotal ).count(); + pb.finish(); + INFO("Requested: " << N << " events t=" << time/1000 << "[ms]"); + return output; + } + DTEventList generatePHSP(const size_t& N, const bool& eval=true){ + DTEventList output( m_signalType, m_tagType ); + for(size_t x = 0 ; x < m_blockSize; ++x) output.emplace_back( generatePhaseSpace() ); +#pragma omp parallel for + for(size_t i = 0 ; i < m_blockSize; ++i ) output[i].prob = P(output[i]); + return output; + } + double rho() { + if( m_ignoreQc ) return 1; + double withQC=0; + double withoutQC =0; + DTEventList evts = generatePHSP(m_blockSize, false); +#pragma omp parallel for reduction(+:withQC,withoutQC) + for( size_t x = 0; x("nCores" , hwt , "Number of threads to use"); + double luminosity = NamedParameter("Luminosity" , 818.3 , "Luminosity to generate. Defaults to CLEO-c integrated luminosity."); + size_t nEvents = NamedParameter("nEvents" , 0 , "Can also generate a fixed number of events per tag, if unspecified use the CLEO-c integrated luminosity."); + size_t seed = NamedParameter("Seed" , 0 , "Random seed to use."); + bool poissonYield = NamedParameter("PoissonYield", true , "Flag to include Poisson fluctuations in expected yields (only if nEvents is not specified)"); + double crossSection = NamedParameter("CrossSection", 3.26 * 1000 , "Cross section for e⁺e⁻ → Ψ(3770) → DD'"); + std::string output = NamedParameter("Output" , "ToyMC.root", "File containing output events"); + auto pNames = NamedParameter("EventType" , "" + , "EventType to generate, in the format: \033[3m parent daughter1 daughter2 ... \033[0m" ).getVector(); + auto tags = NamedParameter("TagTypes" , std::string(), "Vector of opposite side tags to generate, in the format \033[3m outputTreeName decayDescriptor \033[0m.").getVector(); + + gRandom = new TRandom3(seed); +#ifdef _OPENMP + omp_set_num_threads( nThreads ); + INFO("Setting " << nThreads << " fixed threads for OpenMP"); + omp_set_dynamic(0); +#endif + MinuitParameterSet MPS; + MPS.loadFromStream(); + AddCPConjugate(MPS); + EventType signalType( pNames ); + TFile* f = TFile::Open( output.c_str() ,"RECREATE"); + auto yc = DTYieldCalculator(crossSection); + if( nEvents == 0 ) + INFO("Generating events using PDG/efficiencies with luminosity = " << luminosity << " pb⁻¹; σ = " << crossSection << " pb" ); + else INFO("Generating " << nEvents << " per sample"); + ModelStore models(&MPS, yc); + for( auto& tag : tags ){ + auto tokens = split(tag, ' '); + auto tagParticle = Particle(tokens[1], {}, false); + EventType type = tagParticle.eventType(); + double yield_noQC = yc(luminosity,signalType,type,true); + std::string flib = NamedParameter( type.decayDescriptor() +"::lib", ""); + if( flib == "" ){ + auto generator = Psi3770(models, signalType, type); + double rho = generator.rho(); + double yield = nEvents; + if( nEvents == 0 && poissonYield ) yield = gRandom->Poisson(yield_noQC*rho); + if( nEvents == 0 && !poissonYield ) yield = yield_noQC*rho; + INFO( "Tag = " << type << " Expected Yield [incoherent] = " << yield_noQC << " rho = " << rho << " requested = " << yield ); + generator.generate(yield).tree(tokens[0])->Write(); + } + else { + auto generator = Psi3770(models, signalType, type); + double rho = generator.rho(); + double yield = nEvents; + if( nEvents == 0 && poissonYield ) yield = gRandom->Poisson(yield_noQC*rho); + if( nEvents == 0 && !poissonYield ) yield = yield_noQC*rho; + INFO( "Tag = " << type << " Expected Yield [incoherent] = " << yield_noQC << " rho = " << rho << " requested = " << yield ); + generator.generate(yield).tree(tokens[0])->Write(); + } + } + f->Close(); + auto twall_end = std::chrono::high_resolution_clock::now(); + double time_cpu = ( std::clock() - time ) / (double)CLOCKS_PER_SEC; + double tWall = std::chrono::duration( twall_end - time_wall ).count(); + INFO( "Wall time = " << tWall / 1000. ); + INFO( "CPU time = " << time_cpu ); +} + +void add_CP_conjugate( MinuitParameterSet& mps ) +{ + std::vector tmp; + for( auto& param : mps ){ + const std::string name = param->name(); + size_t pos=0; + std::string new_name = name; + int sgn=1; + if( name.find("::") != std::string::npos ){ + pos = name.find("::"); + auto props = AmpGen::ParticlePropertiesList::get( name.substr(0,pos), true ); + if( props != 0 ) new_name = props->anti().name() + name.substr(pos); + } + else { + auto tokens=split(name,'_'); + std::string reOrIm = *tokens.rbegin(); + std::string pname = tokens[0]; + if ( reOrIm == "Re" || reOrIm == "Im" ){ + auto p = Particle( pname ).conj(); + sgn = reOrIm == "Re" ? p.CP() : 1; + new_name = p.uniqueString() +"_"+reOrIm; + } + else if( tokens.size() == 2 ) { + auto props = AmpGen::ParticlePropertiesList::get( name ); + if( props != 0 ) new_name = props->anti().name() + "_" + tokens[1]; + } + } + if( mps.find( new_name ) == nullptr ){ + tmp.push_back( new MinuitParameter(new_name, Flag::Free, sgn * param->mean(), param->err(), 0, 0)); + } + } + for( auto& p : tmp ) mps.add( p ); +} + +std::map DTYieldCalculator::getKeyed(const std::string& name) +{ + std::vector things = AmpGen::NamedParameter(name).getVector(); + std::map< std::string , double > branchingRatios; + for( auto& thing : things ){ + auto tokens = AmpGen::split( thing, ' ' ); + AmpGen::Particle p(tokens[0]); + branchingRatios[p.uniqueString()] = stod(tokens[1]); + branchingRatios[p.conj().uniqueString()] = stod(tokens[1]); + } + return branchingRatios; +} + +double DTYieldCalculator::operator()(const double& lumi, + const AmpGen::EventType& t_signal, + const AmpGen::EventType& t_tag, + const bool& print){ + auto statisticalFactor = 2; + if( t_signal == t_tag || t_signal == t_tag.conj(false,true) ) statisticalFactor = 1; + auto signal = AmpGen::Particle(t_signal.decayDescriptor()).uniqueString(); + auto tag = AmpGen::Particle(t_tag.decayDescriptor()).uniqueString(); + auto signalBar = AmpGen::replaceAll( signal, "D0", "Dbar0"); + auto tagBar = AmpGen::replaceAll( tag, "D0", "Dbar0"); + auto eff = [this](const std::string& tag) -> double { auto it = efficiencies.find(tag); + if( it == efficiencies.end() ){ + WARNING("Efficiency for final state: " << tag << " not found"); + return 1; + } + return it->second; + }; + double efficiency = eff(signal) * eff(tag); + double br = branchingRatios[signal] * branchingRatios[tagBar] + branchingRatios[signalBar] * branchingRatios[tag]; + double totalDDbar = lumi * productionCrossSection; + if( print ){ + INFO("Expected yield for final state: " << t_signal << " vs " << t_tag ); + INFO("Total DDbar = " << totalDDbar ); + INFO("Efficiency = " << efficiency ); + INFO("BR = " << branchingRatios[signal] <<" x " << branchingRatios[tagBar] + << " + " << branchingRatios[signalBar] << " x " << branchingRatios[tag] + << " = " << br ); + INFO("Total = " << statisticalFactor * totalDDbar * efficiency * br ); + } + return statisticalFactor * totalDDbar * efficiency * br; +} + +double DTYieldCalculator::bf( const AmpGen::EventType& type ) const { + auto p = AmpGen::Particle( type.decayDescriptor() ); + auto it = branchingRatios.find(p.decayDescriptor()); + if( it != branchingRatios.end() ) return it->second; + else { + ERROR("Tag: " << p.decayDescriptor() << " not found in branching ratios"); + return 0; + } +} +std::string DTEventList::particleName(const AmpGen::EventType& type, const size_t& j) +{ + auto count = type.count(j); + if( count.second == 1 ) return programatic_name(type[j]); + return programatic_name(type[j])+std::to_string(count.first); +} + +TTree* DTEventList::tree(const std::string& name) +{ + DTEvent tmp(at(0).signal, at(0).tag); + std::vector id_sig(m_sigType.size()), + ids_sig(m_sigType.size()), + id_tag(m_tagType.size()), + ids_tag(m_tagType.size()); + + TTree* outputTree = new TTree(name.c_str(),name.c_str()); + for(size_t i = 0 ; i < m_sigType.size(); ++i ) + { + outputTree->Branch((particleName(m_sigType, i)+"_PX").c_str(), &tmp.signal[4*i+0]); + outputTree->Branch((particleName(m_sigType, i)+"_PY").c_str(), &tmp.signal[4*i+1]); + outputTree->Branch((particleName(m_sigType, i)+"_PZ").c_str(), &tmp.signal[4*i+2]); + outputTree->Branch((particleName(m_sigType, i)+"_E").c_str(), &tmp.signal[4*i+3]); + outputTree->Branch((particleName(m_sigType, i)+"_ID").c_str(), &id_sig[i]); + ids_sig[i] = ParticlePropertiesList::get( m_sigType[i] )->pdgID(); + } + for(size_t i = 0 ; i < m_tagType.size(); ++i ) + { + outputTree->Branch(("Tag_"+particleName(m_tagType, i)+"_PX").c_str(), &tmp.tag[4*i+0]); + outputTree->Branch(("Tag_"+particleName(m_tagType, i)+"_PY").c_str(), &tmp.tag[4*i+1]); + outputTree->Branch(("Tag_"+particleName(m_tagType, i)+"_PZ").c_str(), &tmp.tag[4*i+2]); + outputTree->Branch(("Tag_"+particleName(m_tagType, i)+"_E").c_str(), &tmp.tag[4*i+3]); + outputTree->Branch(("Tag_"+particleName(m_tagType, i)+"_ID").c_str(), &id_tag[i]); + ids_tag[i] = ParticlePropertiesList::get( m_tagType[i] )->pdgID(); + } + bool sym = NamedParameter("symmetrise",true); + for( auto& evt: *this ){ + bool swap = sym && ( gRandom->Uniform() > 0.5 ); + tmp.set(evt.signal, evt.tag); + if( swap ) tmp.invertParity(); + for(size_t i=0; i != m_sigType.size(); ++i) + id_sig[i] = swap ? -ids_sig[i] : ids_sig[i]; + for(size_t i=0; i != m_tagType.size(); ++i) + id_tag[i] = swap ? -ids_tag[i] : ids_tag[i]; + outputTree->Fill(); + } + + return outputTree; +} + +template <> normalised_pdf& ModelStore::find(const EventType& type){ return get(type, genericModels); } +template <> normalised_pdf& ModelStore::find(const EventType& type){ return get(type, flibModels); } + diff --git a/examples/SignalOnlyFitter.cpp b/examples/SignalOnlyFitter.cpp index b7b1cafcbf7..611ae7dd6da 100644 --- a/examples/SignalOnlyFitter.cpp +++ b/examples/SignalOnlyFitter.cpp @@ -9,7 +9,6 @@ #include #include "AmpGen/Chi2Estimator.h" -#include "AmpGen/EventList.h" #include "AmpGen/EventType.h" #include "AmpGen/CoherentSum.h" #include "AmpGen/IncoherentSum.h" @@ -27,14 +26,21 @@ #include #endif +#if ENABLE_AVX + #include "AmpGen/EventListSIMD.h" + using EventList_type = AmpGen::EventListSIMD; +#else + #include "AmpGen/EventList.h" + using EventList_type = AmpGen::EventList; +#endif + #include #include #include using namespace AmpGen; -template -FitResult* doFit( PDF&& pdf, EventList& data, EventList& mc, MinuitParameterSet& MPS ); +template FitResult* doFit( PDF&& pdf, EventList_type& data, EventList_type& mc, MinuitParameterSet& MPS ); int main( int argc, char* argv[] ) { @@ -47,6 +53,7 @@ int main( int argc, char* argv[] ) then the default value, and then the help string that will be printed if --h is specified as an option. */ std::string dataFile = NamedParameter("DataSample", "" , "Name of file containing data sample to fit." ); + std::string intFile = NamedParameter("IntegrationSample","" , "Name of file containing events to use for MC integration."); std::string logFile = NamedParameter("LogFile" , "Fitter.log", "Name of the output log file"); std::string plotFile = NamedParameter("Plots" , "plots.root", "Name of the output plot file"); @@ -56,13 +63,13 @@ int main( int argc, char* argv[] ) auto pNames = NamedParameter("EventType" , "" , "EventType to fit, in the format: \033[3m parent daughter1 daughter2 ... \033[0m" ).getVector(); - if( dataFile == "" ) FATAL("Must specify input with option " << italic_on << "DataSample" << italic_off ); - if( pNames.size() == 0 ) FATAL("Must specify event type with option " << italic_on << " EventType" << italic_off); - [[maybe_unused]] size_t nThreads = NamedParameter ("nCores" , 8 , "Number of threads to use" ); size_t seed = NamedParameter ("Seed" , 0 , "Random seed used" ); - + + if( dataFile == "" ) FATAL("Must specify input with option " << italic_on << "DataSample" << italic_off ); + if( pNames.size() == 0 ) FATAL("Must specify event type with option " << italic_on << " EventType" << italic_off); + TRandom3 rndm; rndm.SetSeed( seed ); gRandom = &rndm; @@ -83,23 +90,26 @@ int main( int argc, char* argv[] ) /* An EventType specifies the initial and final state particles as a vector that will be described by the fit. It is typically loaded from the interface parameter EventType. */ EventType evtType(pNames); - /* A CoherentSum is the typical amplitude to be used, that is some sum over quasi two-body contributions weighted by an appropriate complex amplitude. The CoherentSum is generated from the couplings described by a set of parameters (in a MinuitParameterSet), and an EventType, which matches these parameters to a given final state and a set of data. A common set of rules can be matched to multiple final states, - i.e. to facilitate the analysis of coupled channels. */ + i.e. to facilitate the analysis of coupled channels. + The CoherentSum is only appropriate for decays involving only (pseudo)scalars in the inital / final state, + otherwise the sum must also be over initial / final spin states. In this case, as PolarisedSum should be used. + See FitterWithPolarisation for an example of this use case. + */ CoherentSum sig(evtType, MPS); /* Events are read in from ROOT files. If only the filename and the event type are specified, the file is assumed to be in the specific format that is defined by the event type, unless the branches to load are specified in the user options */ - EventList events(dataFile, evtType, Branches(bNames), GetGenPdf(false) ); + EventList_type events(dataFile, evtType, Branches(bNames), GetGenPdf(false) ); /* Generate events to normalise the PDF with. This can also be loaded from a file, which will be the case when efficiency variations are included. Default number of normalisation events is 5 million. */ - EventList eventsMC = Generator<>(evtType, &rndm).generate(5e6); + EventList_type eventsMC = intFile == "" ? Generator<>(evtType, &rndm).generate(2.5e6) : EventList_type(intFile, evtType, GetGenPdf(true)); sig.setMC( eventsMC ); @@ -107,7 +117,7 @@ int main( int argc, char* argv[] ) /* Do the fit and return the fit results, which can be written to the log and contains the covariance matrix, fit parameters, and other observables such as fit fractions */ - FitResult* fr = doFit(make_pdf(sig), events, eventsMC, MPS ); + FitResult* fr = doFit(make_likelihood(events, sig), events, eventsMC, MPS ); /* Calculate the `fit fractions` using the signal model and the error propagator (i.e. fit results + covariance matrix) of the fit result, and write them to a file. */ @@ -115,57 +125,46 @@ int main( int argc, char* argv[] ) fr->addFractions( fitFractions ); fr->writeToFile( logFile ); - output->cd(); - /* Write out the data plots. This also shows the first example of the named arguments - to functions, emulating python's behaviour in this area */ - - auto plots = events.makeDefaultProjections(Prefix("Data"), Bins(100)); - for ( auto& plot : plots ) plot->Write(); - output->Close(); } -template -FitResult* doFit( PDF&& pdf, EventList& data, EventList& mc, MinuitParameterSet& MPS ) +template +FitResult* doFit( likelihoodType&& likelihood, EventList_type& data, EventList_type& mc, MinuitParameterSet& MPS ) { auto time_wall = std::chrono::high_resolution_clock::now(); auto time = std::clock(); - - pdf.setEvents( data ); - /* Minimiser is a general interface to Minuit1/Minuit2, that is constructed from an object that defines an operator() that returns a double (i.e. the likielihood, and a set of MinuitParameters. */ - Minimiser mini( pdf, &MPS ); + Minimiser mini( likelihood, &MPS ); mini.doFit(); FitResult* fr = new FitResult(mini); - - /* Make the plots for the different components in the PDF, i.e. the signal and backgrounds. - The structure assumed the PDF is some SumPDF. */ - unsigned int counter = 1; - for_each(pdf.m_pdfs, [&]( auto& f ){ - std::function FCN_sig = [&](const Event& evt){ return f.prob_unnormalised(evt) ; }; - auto mc_plot3 = mc.makeDefaultProjections(WeightFunction(f), Prefix("Model_cat"+std::to_string(counter))); - for( auto& plot : mc_plot3 ) - { - plot->Scale( ( data.integral() * f.getWeight() ) / plot->Integral() ); - plot->Write(); - } - counter++; - } ); - - /* Estimate the chi2 using an adaptive / decision tree based binning, - down to a minimum bin population of 15, and add it to the output. */ - Chi2Estimator chi2( data, mc, pdf, 15 ); - chi2.writeBinningToFile("chi2_binning.txt"); - fr->addChi2( chi2.chi2(), chi2.nBins() ); auto twall_end = std::chrono::high_resolution_clock::now(); double time_cpu = ( std::clock() - time ) / (double)CLOCKS_PER_SEC; double tWall = std::chrono::duration( twall_end - time_wall ).count(); INFO( "Wall time = " << tWall / 1000. ); INFO( "CPU time = " << time_cpu ); + + /* Estimate the chi2 using an adaptive / decision tree based binning, + down to a minimum bin population of 15, and add it to the output. */ + + Chi2Estimator chi2( data, mc, likelihood.evaluator(&mc), MinEvents(15), Dim(data.eventType().dof()) ); + chi2.writeBinningToFile("chi2_binning.txt"); + fr->addChi2( chi2.chi2(), chi2.nBins() ); fr->print(); + + /* Make the plots for the different components in the PDF, i.e. the signal and backgrounds. + The structure assumed the PDF is some SumPDF. */ + auto evaluator = likelihood.componentEvaluator(&mc); + auto evaluator_per_component = std::get<0>( likelihood.pdfs() ).componentEvaluator(&mc); + auto projections = data.eventType().defaultProjections(100); + for( const auto& proj : projections ) + { + proj(mc, evaluator, PlotOptions::Norm(data.size()), PlotOptions::AutoWrite() ); + proj(mc, evaluator_per_component, PlotOptions::Prefix("amp"), PlotOptions::Norm(data.size()), PlotOptions::AutoWrite() ); + proj(data, PlotOptions::Prefix("Data") )->Write(); + } return fr; } diff --git a/examples/SimFit.cpp b/examples/SimFit.cpp new file mode 100644 index 00000000000..95345cd2797 --- /dev/null +++ b/examples/SimFit.cpp @@ -0,0 +1,98 @@ +#include "AmpGen/Particle.h" +#include "AmpGen/CoherentSum.h" +#include "AmpGen/MsgService.h" +#include "AmpGen/SumPDF.h" +#include "AmpGen/FitResult.h" +#include "AmpGen/IExtendLikelihood.h" +#include "AmpGen/Minimiser.h" +#include "AmpGen/NamedParameter.h" +#include "AmpGen/Utilities.h" +#include "AmpGen/MinuitParameterSet.h" +#include "AmpGen/SimPDF.h" +#include "AmpGen/Kinematics.h" +#include "AmpGen/Generator.h" +#include "AmpGen/PolarisedSum.h" +#include "AmpGen/AddCPConjugate.h" +#ifdef _OPENMP + #include +#endif +#if ENABLE_AVX + #include "AmpGen/EventListSIMD.h" + using EventList_type = AmpGen::EventListSIMD; +#else + #include "AmpGen/EventList.h" + using EventList_type = AmpGen::EventList; +#endif + +#include "TRandom3.h" +#include "TFile.h" +#include "TTree.h" + +using namespace AmpGen; + +int main(int argc , char* argv[] ){ + OptionsParser::setArgs( argc, argv ); + + const auto datasets = NamedParameter("Datasets","", + "List of data/simulated samples to fit, in the format \ + \033[3m data[0] sim[0] data[1] sim[1] ... \033[0m. \nIf a simulated sample is specified FLAT, uniformly generated phase-space events are used for integrals ").getVector(); + + const std::string logFile = NamedParameter("LogFile" , "Fitter.log", + "Name of the output log file"); + + const std::string plotFile = NamedParameter("Plots" , "plots.root", + "Name of the output plot file"); + + const bool add_conj = NamedParameter("AddConj", false ); + + std::vector data; + std::vector mcs; + + #ifdef _OPENMP + size_t hwThreads = std::thread::hardware_concurrency(); + size_t usThreads = NamedParameter( "nCores", hwThreads, "Number of cores to use (OpenMP only)" ); + INFO("Using: " << usThreads << " / " << hwThreads << " threads" ); + omp_set_num_threads(usThreads); + omp_set_dynamic(0); + #endif + + INFO("Output : " << logFile << " plots = " << plotFile ); + + for(size_t i=0;i < datasets.size() ; i+=2 ){ + data.emplace_back( datasets[i] ); + if( datasets[i+1] == "FLAT" ) mcs.emplace_back(Generator<>(data.rbegin()->eventType() ).generate(1e6)); + else mcs.emplace_back( datasets[i+1], data.rbegin()->eventType(), GetGenPdf(true) ); + } + + std::vector fcs(data.size()); + std::vector> pdfs; + + pdfs.reserve(data.size()); + + SimFit totalLL; + MinuitParameterSet mps; + mps.loadFromStream(); + if( add_conj ) AddCPConjugate(mps); + for(size_t i = 0; i < data.size(); ++i){ + fcs[i] = PolarisedSum(data[i].eventType(), mps); + pdfs.emplace_back( make_pdf(fcs[i]) ); + pdfs[i].setEvents(data[i]); + auto& mc = mcs[i]; + for_each( pdfs[i].pdfs(), [&mc](auto& pdf){pdf.setMC(mc);}); + totalLL.add( pdfs[i] ); + } + Minimiser mini( totalLL, &mps ); + mini.doFit(); + FitResult(mini).writeToFile("Fitter.log"); + TFile* output_plots = TFile::Open( plotFile.c_str(), "RECREATE"); + for( size_t i = 0 ; i < data.size(); ++i ) + { + INFO("Making figures for sample: " << i << " ..."); + for( auto proj : data[i].eventType().defaultProjections() ) + { + proj(data[i], PlotOptions::Prefix("Data"+std::to_string(i)), PlotOptions::AutoWrite() ); + proj(mcs[i] , pdfs[i].componentEvaluator(&mcs[i]), PlotOptions::Prefix("pdf"+std::to_string(i)), PlotOptions::Norm(data.size()), PlotOptions::AutoWrite() ); + } + } + output_plots->Close(); +} diff --git a/examples/qc_options_example.opt b/examples/qc_options_example.opt new file mode 100644 index 00000000000..c2c8578d973 --- /dev/null +++ b/examples/qc_options_example.opt @@ -0,0 +1,47 @@ + +EventType D0 K+ pi- pi- pi+ + +TagTypes { "KK D0{K+,K-}" + "KPi D0{K-,pi+}" + "KsPi0 D0{K0S0,pi0}" + "PiK D0{K+,pi-}" + "PiKPiPi D0{K+,pi-,pi-,pi+}" + "KPiPiPi D0{K-,pi+,pi+,pi-}" + } + +Efficiencies { + "D0{K+,K-} 0.57" + "D0{K0S0,pi0} 0.31" + "D0{pi+,pi-} 0.71" + "D0{K-,pi+,pi+,pi-} 0.46" + "D0{K+,pi-,pi-,pi+} 0.46" + "D0{K-,pi+} 0.60" + "D0{K+,pi-} 0.60" +} + +BranchingRatios { + "D0{K+,K-} 0.003970" + "D0{K0S0,pi0} 0.011900" + "D0{pi+,pi-} 0.001407" + "D0{K-,pi+,pi+,pi-} 0.0811" + "D0{K+,pi-,pi-,pi+} 0.000245" + "D0{K-,pi+} 0.0389" + "D0{K+,pi-} 0.0001366" +} + +Import $AMPGENROOT/options/D02piKpipi.opt + +D0{K+,K-} 2 1 0 2 0 0 +Dbar0{K+,K-} 2 1 0 2 0 0 + +D0{pi+,pi-} 2 1 0 2 0 0 +Dbar0{pi+,pi-} 2 1 0 2 0 0 + +D0{K0S0,pi0} 2 1 0 2 0 0 +Dbar0{K0S0,pi0} 2 1 0 2 180 0 + +D0{K-,pi+} 2 1 0 2 0.0 0 +Dbar0{K-,pi+} 2 1 0 2 -191.8 0 + +D0{K+,pi-,pi-,pi+}::strongPhase 2 -130.0 0 #overall phase shift to add to the D0->K+,pi-,pi-,pi+ +Dbar0{K-,pi+,pi+,pi-}::strongPhase = D0{K+,pi-,pi-,pi+}::strongPhase diff --git a/options/D02Kpipipi.opt b/options/D02Kpipipi.opt index 5fe22c2017d..b4c83e6ab98 100644 --- a/options/D02Kpipipi.opt +++ b/options/D02Kpipipi.opt @@ -1,4 +1,5 @@ # Description of CF amplitude D0 -> K-,pi+,pi+,pi- +EventType D0 K- pi+ pi+ pi- Import $AMPGENROOT/options/kMatrix.opt a(1)(1260)-::Spline 40 0.18412 1.9 diff --git a/options/D02piKpipi.opt b/options/D02piKpipi.opt index b81c4db0536..189951d7289 100644 --- a/options/D02piKpipi.opt +++ b/options/D02piKpipi.opt @@ -1,21 +1,24 @@ # Description of DCS amplitude D0 -> K+,pi-,pi-,pi+ - Import $AMPGENROOT/options/Dbar02piKpipi.opt #necessary for K1 couplings / shape parameters -D0_radius 2 3.7559 0 -D0{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}} 0 0.205 0.019 0 -8.5 4.7 -D0[P]{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}} 0 0.390 0.002 0 -91.4 0.4 -D0[D]{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}} 2 1.000 0.000 2 0.0 0.0 -D0{rho(1450)0{pi+,pi-},K*(892)0{K+,pi-}} 0 0.541 0.042 0 -21.8 6.5 +CouplingConstant::Coordinates polar +CouplingConstant::AngularUnits deg +CoherentSum::Verbosity 0 + +D0_radius 2 3.7559 0 +D0{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}} 2 0.205 0.019 2 -8.5 4.7 +D0[P]{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}} 2 0.390 0.002 2 -91.4 0.4 +D0[D]{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}} 2 1.000 0.000 2 0.0 0.0 +D0{rho(1450)0{pi+,pi-},K*(892)0{K+,pi-}} 2 0.541 0.042 2 -21.8 6.5 # There is an additional relative phase of 180 degrees here w.r.t # what is written in the paper, due to a slightly different convention # in how the K(1) couplings have been defined. -D0{K(1)(1270)+,pi-} 0 0.653 0.040 0 69.3 5.1 -D0{K(1)(1400)+{K*(892)0{K+,pi-},pi+},pi-} 0 0.560 0.037 0 29.8 4.2 -D0{KPi40,PiPi40} 2 1.000 0.000 2 0.0 0.0 -KPi40[FOCUS.Kpi]{K+,pi-} 2 1.000 0.000 2 0.0 0.0 -KPi40[FOCUS.I32]{K+,pi-} 0 0.686 0.010 0 -149.4 4.3 -PiPi40[kMatrix.pole.1]{pi+,pi-} 0 0.438 0.009 0 -132.4 6.5 -PiPi40[kMatrix.prod.0]{pi+,pi-} 0 0.050 0.001 0 74.8 7.5 +D0{K(1)(1270)+,pi-} 2 0.653 0.040 2 69.3 5.1 +D0{K(1)(1400)+{K*(892)0{K+,pi-},pi+},pi-} 2 0.560 0.037 2 29.8 4.2 +D0{KPi40,PiPi40} 2 1.000 0.000 2 0.0 0.0 +KPi40[FOCUS.Kpi]{K+,pi-} 2 1.000 0.000 2 0.0 0.0 +KPi40[FOCUS.I32]{K+,pi-} 2 0.686 0.010 2 -149.4 4.3 +PiPi40[kMatrix.pole.1]{pi+,pi-} 2 0.438 0.009 2 -132.4 6.5 +PiPi40[kMatrix.prod.0]{pi+,pi-} 2 0.050 0.001 2 74.8 7.5 diff --git a/options/Dbar02piKpipi.opt b/options/Dbar02piKpipi.opt index 6e254ae3811..b3ee7777480 100644 --- a/options/Dbar02piKpipi.opt +++ b/options/Dbar02piKpipi.opt @@ -46,8 +46,8 @@ PiPi20[kMatrix.pole.1]{pi+,pi-} PiPi20[kMatrix.pole.0]{pi+,pi-} 2 0.291 0.007 2 165.8 1.3 PiPi20[kMatrix.prod.0]{pi+,pi-} 2 0.117 0.002 2 170.5 1.2 a(1)(1260)-[D;GSpline.EFF]{rho(770)0{pi+,pi-},pi-} 2 0.582 0.011 2 -152.8 1.2 -a(1)(1260)-_mass 2 1.19505 0.00105 2 -a(1)(1260)-_radius 2 1.70000 0.00000 2 +a(1)(1260)-_mass 2 1.19505 0.00105 +a(1)(1260)-_radius 2 1.70000 0.00000 a(1)(1260)-_width 2 0.42201 0.00210 K(1)(1270)+[GSpline.EFF]{rho(770)0{pi+,pi-},K+} 2 1.000 0.000 2 0.0 0.0 K(1)(1270)+[GSpline.EFF]{rho(1450)0{pi+,pi-},K+} 2 2.016 0.026 2 -119.5 0.9 diff --git a/options/FitterExample.opt b/options/FitterExample.opt index feeb9f67ece..7446b538bf3 100644 --- a/options/FitterExample.opt +++ b/options/FitterExample.opt @@ -106,58 +106,3 @@ a(1)(1260)+::Spline::Gamma::30 2 1.17885 0 a(1)(1260)+::Spline::Gamma::31 2 1.21615 0 a(1)(1260)+::Spline::Gamma::32 2 1.25246 0 a(1)(1260)+::Spline::Gamma::33 2 1.28789 0 - -#K(1)(1270)bar-_mass 0 1270 1 1000 1500 -#K(1)(1270)bar-_width 0 90 1 50 200 -# -#gLASS::F 0 1.0 1.34906e-01 -#gLASS::R 2 1.00000e+00 0 -#gLASS::a 2 0.224 3.46447e-03 -#gLASS::phiF 0 0.0 2.45733e-01 -#gLASS::phiR 0 0.0 3.14745e-02 -#gLASS::r 2 -15.01 1.49288e-01 -# -#K(1)(1270)bar-::Spline::Min 0.613246 -#K(1)(1270)bar-::Spline::Max 2.95978 -#K(1)(1270)bar-::Spline::N 40 -#K(1)(1270)bar-::Spline::Gamma::0 2 0.000162404 0 -#K(1)(1270)bar-::Spline::Gamma::1 2 0.00386694 0 -#K(1)(1270)bar-::Spline::Gamma::2 2 0.0128833 0 -#K(1)(1270)bar-::Spline::Gamma::3 2 0.0276225 0 -#K(1)(1270)bar-::Spline::Gamma::4 2 0.048283 0 -#K(1)(1270)bar-::Spline::Gamma::5 2 0.0748626 0 -#K(1)(1270)bar-::Spline::Gamma::6 2 0.107234 0 -#K(1)(1270)bar-::Spline::Gamma::7 2 0.145263 0 -#K(1)(1270)bar-::Spline::Gamma::8 2 0.188929 0 -#K(1)(1270)bar-::Spline::Gamma::9 2 0.238422 0 -#K(1)(1270)bar-::Spline::Gamma::10 2 0.294211 0 -#K(1)(1270)bar-::Spline::Gamma::11 2 0.357122 0 -#K(1)(1270)bar-::Spline::Gamma::12 2 0.428445 0 -#K(1)(1270)bar-::Spline::Gamma::13 2 0.510093 0 -#K(1)(1270)bar-::Spline::Gamma::14 2 0.604757 0 -#K(1)(1270)bar-::Spline::Gamma::15 2 0.715757 0 -#K(1)(1270)bar-::Spline::Gamma::16 2 0.845719 0 -#K(1)(1270)bar-::Spline::Gamma::17 2 0.993541 0 -#K(1)(1270)bar-::Spline::Gamma::18 2 1.15281 0 -#K(1)(1270)bar-::Spline::Gamma::19 2 1.31566 0 -#K(1)(1270)bar-::Spline::Gamma::20 2 1.47718 0 -#K(1)(1270)bar-::Spline::Gamma::21 2 1.63572 0 -#K(1)(1270)bar-::Spline::Gamma::22 2 1.79135 0 -#K(1)(1270)bar-::Spline::Gamma::23 2 1.94481 0 -#K(1)(1270)bar-::Spline::Gamma::24 2 2.09696 0 -#K(1)(1270)bar-::Spline::Gamma::25 2 2.24862 0 -#K(1)(1270)bar-::Spline::Gamma::26 2 2.40051 0 -#K(1)(1270)bar-::Spline::Gamma::27 2 2.55328 0 -#K(1)(1270)bar-::Spline::Gamma::28 2 2.70744 0 -#K(1)(1270)bar-::Spline::Gamma::29 2 2.86345 0 -#K(1)(1270)bar-::Spline::Gamma::30 2 3.02171 0 -#K(1)(1270)bar-::Spline::Gamma::31 2 3.18254 0 -#K(1)(1270)bar-::Spline::Gamma::32 2 3.34625 0 -#K(1)(1270)bar-::Spline::Gamma::33 2 3.51307 0 -#K(1)(1270)bar-::Spline::Gamma::34 2 3.68324 0 -#K(1)(1270)bar-::Spline::Gamma::35 2 3.85695 0 -#K(1)(1270)bar-::Spline::Gamma::36 2 4.03437 0 -#K(1)(1270)bar-::Spline::Gamma::37 2 4.21566 0 -#K(1)(1270)bar-::Spline::Gamma::38 2 4.40095 0 -#K(1)(1270)bar-::Spline::Gamma::39 2 4.59036 0 -# diff --git a/options/MintDalitzSpecialParticles.csv b/options/MintDalitzSpecialParticles.csv index 5d07dfbf05b..6565871935b 100644 --- a/options/MintDalitzSpecialParticles.csv +++ b/options/MintDalitzSpecialParticles.csv @@ -14,35 +14,41 @@ 9.990E+03 ,1.0E+00,1.0E+00,9.9E+09 ,1.0E+00,1.0E+00,0 , ,1/2 ,+, ,F, 9988, 0,4,R,NonRes1p ,?? 9.990E+03 ,1.0E+00,1.0E+00,9.9E+09 ,1.0E+00,1.0E+00,0 , ,3/2 ,-, ,F, 9989, 0,4,R,NonRes3m ,?? 9.990E+03 ,1.0E+00,1.0E+00,9.9E+09 ,1.0E+00,1.0E+00,0 , ,3/2 ,+, ,F, 9910, 0,4,R,NonRes3p ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998100, 0, ,R,PiPi0 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998101, 0, ,R,PiPi1 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998102, 0, ,R,PiPi2 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998103, 0, ,R,PiPi3 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998104, 0, ,R,PiPi4 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998105, 0, ,R,PiPi5 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998106, 0, ,R,PiPi6 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+,F, 998110, 0, ,R,KPi0 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+,F, 998111, 0, ,R,KPi1 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+,F, 998112, 0, ,R,KPi2 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+,F, 998113, 0, ,R,KPi3 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+,F, 998114, 0, ,R,KPi4 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+,F, 998115, 0, ,R,KPi5 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+,F, 998116, 0, ,R,KPi6 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+,F, 998117, 0, ,R,KPi7 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998120, 0, ,R,KK0 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998121, 0, ,R,KK1 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998122, 0, ,R,KK2 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998123, 0, ,R,KK3 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998124, 0, ,R,KK4 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998125, 0, ,R,KK5 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, , 998126, 0, ,R,KK6 ,x(uU+dD)+y(sS) -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998130, 0, ,R,rhoOmega0 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998131, 0, ,R,rhoOmega1 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998132, 0, ,R,rhoOmega2 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998133, 0, ,R,rhoOmega3 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998134, 0, ,R,rhoOmega4 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998135, 0, ,R,rhoOmega5 ,?? -9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,1 ,-,-, , 998136, 0, ,R,rhoOmega6 ,?? +9.970E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998100, 0, ,R,PiPi0 ,x(uU+dD)+y(sS) +9.970E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998101, 0, ,R,PiPi1 ,x(uU+dD)+y(sS) +9.970E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998102, 0, ,R,PiPi2 ,x(uU+dD)+y(sS) +9.970E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998103, 0, ,R,PiPi3 ,x(uU+dD)+y(sS) +9.970E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998104, 0, ,R,PiPi4 ,x(uU+dD)+y(sS) +9.970E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998105, 0, ,R,PiPi5 ,x(uU+dD)+y(sS) +9.970E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998106, 0, ,R,PiPi6 ,x(uU+dD)+y(sS) +9.980E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,0 ,+,+,F, 998110, 0, ,R,KPi0 ,?? +9.980E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,0 ,+,+,F, 998111, 0, ,R,KPi1 ,?? +9.980E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,0 ,+,+,F, 998112, 0, ,R,KPi2 ,?? +9.980E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,0 ,+,+,F, 998113, 0, ,R,KPi3 ,?? +9.980E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,0 ,+,+,F, 998114, 0, ,R,KPi4 ,?? +9.980E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,0 ,+,+,F, 998115, 0, ,R,KPi5 ,?? +9.980E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,0 ,+,+,F, 998116, 0, ,R,KPi6 ,?? +9.980E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2,+,0 ,+,+,F, 998117, 0, ,R,KPi7 ,?? +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998120, 0, ,R,KK0 ,x(uU+dD)+y(sS) +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998121, 0, ,R,KK1 ,x(uU+dD)+y(sS) +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998122, 0, ,R,KK2 ,x(uU+dD)+y(sS) +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998123, 0, ,R,KK3 ,x(uU+dD)+y(sS) +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998124, 0, ,R,KK4 ,x(uU+dD)+y(sS) +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998125, 0, ,R,KK5 ,x(uU+dD)+y(sS) +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,0 ,+,0 ,+, , , 998126, 0, ,R,KK6 ,x(uU+dD)+y(sS) +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1 ,+,1 ,-,-, , 998130, 0, ,R,rhoOmega0 ,?? +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1 ,+,1 ,-,-, , 998131, 0, ,R,rhoOmega1 ,?? +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1 ,+,1 ,-,-, , 998132, 0, ,R,rhoOmega2 ,?? +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1 ,+,1 ,-,-, , 998133, 0, ,R,rhoOmega3 ,?? +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1 ,+,1 ,-,-, , 998134, 0, ,R,rhoOmega4 ,?? +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1 ,+,1 ,-,-, , 998135, 0, ,R,rhoOmega5 ,?? +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1 ,+,1 ,-,-, , 998136, 0, ,R,rhoOmega6 ,?? 1.272E+03 ,7.0E+00,7.0E+00,9.0E+01 ,2.0E+01,2.0E+01,1/2, ,1 ,+, ,F, 998200, +, ,R,Ka ,uS 1.272E+03 ,7.0E+00,7.0E+00,9.0E+01 ,2.0E+01,2.0E+01,1/2, ,1 ,+, ,F, 998201, +, ,R,Kb ,uS +1.86484E+03 ,1.7E-01,1.7E-01,1.605E-09 ,6.0E-12,6.0E-12,1/2, ,0 ,-, ,F, 998421, 0, ,R,D~ ,cU +3.8948E+03 ,1.1E-02,1.1E-02,2.96E+00 ,2.1E-03,2.1E-03,1 ,+,1 ,+,-, , 999443, 0, ,R,Z(c)(3900) ,cCuU +3.8948E+03 ,1.1E-02,1.1E-02,2.96E+00 ,2.1E-03,2.1E-03,1 ,+,1 ,+,-, , 999444, +, ,R,Z(c)(3900) ,cCuD +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1 , ,1/2 ,-, ,F, , 0,3,R,LambdaEta ,uds +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2, ,1/2 ,-, ,F, , -,3,R,XiPi ,dss +9.990E+03 ,1.0E+01,1.0E+01,9.9E+09 ,3.0E+01,3.0E+01,1/2, ,1/2 ,-, ,F, , 0,3,R,XiPi ,uss *** diff --git a/options/example_glass.opt b/options/example_glass.opt new file mode 100644 index 00000000000..69babd9d999 --- /dev/null +++ b/options/example_glass.opt @@ -0,0 +1,24 @@ +EventType D0 K0S0 pi+ pi- + +D0{K(0)*(1430)+[GLASS]{K0S0,pi+},pi-} 2 1 0 2 0 0 + +K(0)*(1430)+::GLASS::a 0 0.113 0.006 +K(0)*(1430)+::GLASS::r 0 -33.800 1.800 +K(0)*(1430)+::GLASS::R 2 1.000 0.000 +K(0)*(1430)+::GLASS::F 0 0.960 0.007 +K(0)*(1430)+::GLASS::phiR 0 -109.700 2.600 +K(0)*(1430)+::GLASS::phiF 0 0.100 0.300 + +# K(0)*(1430)+::GLASS::a 0 2.070 0.006 +# K(0)*(1430)+::GLASS::r 0 3.320 1.800 +# K(0)*(1430)+::GLASS::R 2 1.000 0.000 +# K(0)*(1430)+::GLASS::F 0 1.000 0.007 +# K(0)*(1430)+::GLASS::phiR 0 0.000 2.600 +# K(0)*(1430)+::GLASS::phiF 0 0.000 0.300 + +K(0)*(1430)bar-::GLASS::a = K(0)*(1430)+::GLASS::a +K(0)*(1430)bar-::GLASS::r = K(0)*(1430)+::GLASS::r +K(0)*(1430)bar-::GLASS::R = K(0)*(1430)+::GLASS::R +K(0)*(1430)bar-::GLASS::F = K(0)*(1430)+::GLASS::F +K(0)*(1430)bar-::GLASS::phiR = K(0)*(1430)+::GLASS::phiR +K(0)*(1430)bar-::GLASS::phiF = K(0)*(1430)+::GLASS::phiF diff --git a/options/mass_width.csv b/options/mass_width.csv index 6f6050db895..7d502d48324 100644 --- a/options/mass_width.csv +++ b/options/mass_width.csv @@ -16,7 +16,7 @@ * A1. read table into any spreadsheet or database program that accepts a comma-separated format * A2. For example, in EXCEL, open a blank workbook and import this file as external data, * comma-delimited, starting the import at row 100, which contains column header names. -* B1. In a FORTRAN program, ignore documentation lines that begin with "*" and process data lines using +* B1. In a FORTRAN program, ignore documentation lines that begin with '*' and process data lines using * FORMAT (BN, E14.0, 1X, 2(E7.0, 1X), E12.0, 1X, 2(E7.0, 1X), A3, 1X, A1, 1X, A4, 1X, 3(A1, 1X), A7, 1X, A4, 1X, 2(A1, 1X), A17, 1X, A) * B2. WARNING. MINUS VALUE OF ERROR means its absence! * B3. columns contents Fortran I/O @@ -51,7 +51,7 @@ * with ascii name formed by concatenation of the name shown below with charge * ( e- <--> e+, pi+ <--> pi-, K+ <--> K-, W+ <--> W- ). * A = F - particle that has anti-particle partner different from particle -* with ascii name formed by concatenation of the name shown below with string "bar" and charge +* with ascii name formed by concatenation of the name shown below with string 'bar' and charge * by the rule (nu(e) <--> nubar(e), p <--> pbar, Delta++ <--> Deltabar--) * A = blank - particle that coincide with its antiparticle (gamma, pi0, eta). * 85 comma (1X) @@ -59,7 +59,7 @@ * The number used in the PDG Monte Carlo numbering scheme (see RPP). * Only particles are shown in this table and they are given positive ID numbers. * For antiparticles, change the ID to negative. Thus pi- has code -211. -* The ID has up to 7 digits. See RPP "Monte Carlo particle numbering scheme" +* The ID has up to 7 digits. See RPP 'Monte Carlo particle numbering scheme' * for details. * 94 comma (1X) * 95 - 99 charge (A4) @@ -81,7 +81,7 @@ * space even though they are well established. * S - The particle is omitted from the particle properties Summary Tables * because it is not well established. -* F - Special case: "Further mesons", see RPP , these states are in the RPP +* F - Special case: 'Further mesons', see RPP , these states are in the RPP * database but are poorly established or observed by a single group and thus * need confirmation. If used, these should be referred to the original publication. * For these states we list a single line without charge and with C-parity, if known, @@ -91,10 +91,10 @@ * 105 -122 particle name (A17) * 123 comma (1X) * 124 -139 Quark contents (A) -* Note: capital letters represents anti-quarks, "qQ" stands for light quark, light +* Note: capital letters represents anti-quarks, 'qQ' stands for light quark, light * anti-quark pair with unknown wave functions. * x, y - wave function coefficients, see RPP 'Quark Model' Review -* p, q - CP violation parameters, See. RPP "CP violation in KL Decays" review. +* p, q - CP violation parameters, See. RPP 'CP violation in KL Decays' review. * * *MASS(MeV) ,Err+ ,Err- ,WIDTH(MeV) ,Err+ ,Err- ,I ,G,J ,P,C,A,PDG-MC ,Chrg,R,S,Name ,Quarks @@ -104,9 +104,9 @@ 5.10998910E-01,1.3E-08,1.3E-08,0.0E+00 ,0.0E+00,0.0E+00, , ,1/2 ,+, ,B, 11, -, ,R,e , 1.05658367E+02,4.0E-06,4.0E-06,3.015937E-16,2.9E-21,2.9E-21, , ,1/2 ,+, ,B, 13, -, ,R,mu , 1.77684E+03 ,1.7E-01,1.7E-01,2.280E-09 ,8.0E-12,8.0E-12, , ,1/2 ,+, ,B, 15, -, ,R,tau , -0.0E+00 ,0.0E+00,0.0E+00,0.0E+00 ,0.0E+00,0.0E+00,<2 , ,1/2 ,+, ,F, 12, 0, ,R,nu_e , -0.0E+00 ,0.0E+00,0.0E+00,0.0E+00 ,0.0E+00,0.0E+00,<2 , ,1/2 ,+, ,F, 14, 0, ,R,nu_mu , -0.0E+00 ,0.0E+00,0.0E+00,0.0E+00 ,0.0E+00,0.0E+00,<2 , ,1/2 ,+, ,F, 16, 0, ,R,nu_tau , +0.0E+00 ,0.0E+00,0.0E+00,0.0E+00 ,0.0E+00,0.0E+00,<2 , ,1/2 ,+, ,F, 12, 0, ,R,nue , +0.0E+00 ,0.0E+00,0.0E+00,0.0E+00 ,0.0E+00,0.0E+00,<2 , ,1/2 ,+, ,F, 14, 0, ,R,numu , +0.0E+00 ,0.0E+00,0.0E+00,0.0E+00 ,0.0E+00,0.0E+00,<2 , ,1/2 ,+, ,F, 16, 0, ,R,nutau , 2.4E+00 ,9.0E-01,9.0E-01,-1 ,-1 ,-1 ,1/2, ,1/2 ,+, ,F, 2,+2/3, ,R,u ,u 4.8E+00 ,1.2E+00,1.2E+00,-1 ,-1 ,-1 ,1/2, ,1/2 ,+, ,F, 1,-1/3, ,R,d ,d 1.04E+02 ,2.6E+01,3.4E+01,-1 ,-1 ,-1 ,0 , ,1/2 ,+, ,F, 3,-1/3, ,R,s ,s @@ -118,12 +118,12 @@ 5.47853E+02 ,2.4E-02,2.4E-02,1.30E-03 ,7.0E-05,7.0E-05,0 ,+,0 ,-,+, , 221, 0, ,R,eta ,x(uU+dD)+y(sS) 8.0E+02 ,4.0E+02,4.0E+02,8.0E+02 ,2.0E+02,2.0E+02,0 ,+,0 ,+,+, ,9000221, 0, ,R,f(0)(600) ,Maybe non-qQ 7.7549E+02 ,3.4E-01,3.4E-01,1.4940E+02 ,1.0E+00,1.0E+00,1 ,+,1 ,-, ,B, 213, +, ,R,rho(770) ,uD -7.7549E+02 ,3.4E-01,3.4E-01,1.4940E+02 ,1.0E+00,1.0E+00,1 ,+,1 ,-,-,B, 113, 0, ,R,rho(770) ,(uU-dD)/sqrt(2) +7.7549E+02 ,3.4E-01,3.4E-01,1.4940E+02 ,1.0E+00,1.0E+00,1 ,+,1 ,-,-, , 113, 0, ,R,rho(770) ,(uU-dD)/sqrt(2) 7.8265E+02 ,1.2E-01,1.2E-01,8.49E+00 ,8.0E-02,8.0E-02,0 ,-,1 ,-,-, , 223, 0, ,R,omega(782) ,x(uU+dD)+y(sS) 9.5766E+02 ,2.4E-01,2.4E-01,2.05E-01 ,1.5E-02,1.5E-02,0 ,+,0 ,-,+, , 331, 0, ,R,eta'(958) ,x(uU+dD)+y(sS) 9.800E+02 ,1.0E+01,1.0E+01,7.0E+01 ,3.0E+01,3.0E+01,0 ,+,0 ,+,+, ,9010221, 0, ,R,f(0)(980) ,Maybe non-qQ 9.847E+02 ,1.2E+00,1.2E+00,7.5E+01 ,2.5E+01,2.5E+01,1 ,-,0 ,+, ,B,9000211, +, ,R,a(0)(980) ,Maybe non-qQ -9.847E+02 ,1.2E+00,1.2E+00,7.5E+01 ,2.5E+01,2.5E+01,1 ,-,0 ,+,+,B,9000111, 0, ,R,a(0)(980) ,Maybe non-qQ +9.847E+02 ,1.2E+00,1.2E+00,7.5E+01 ,2.5E+01,2.5E+01,1 ,-,0 ,+,+, ,9000111, 0, ,R,a(0)(980) ,Maybe non-qQ 1.019455E+03 ,2.0E-02,2.0E-02,4.26E+00 ,4.0E-02,4.0E-02,0 ,-,1 ,-,-, , 333, 0, ,R,phi(1020) ,x(uU+dD)+y(sS) 1.170E+03 ,2.0E+01,2.0E+01,3.6E+02 ,4.0E+01,4.0E+01,0 ,-,1 ,+,-, , 10223, 0, ,R,h(1)(1170) ,x(uU+dD)+y(sS) 1.2295E+03 ,3.2E+00,3.2E+00,1.42E+02 ,9.0E+00,9.0E+00,1 ,+,1 ,+, ,B, 10213, +, ,R,b(1)(1235) ,uD @@ -134,9 +134,9 @@ 1.2818E+03 ,6.0E-01,6.0E-01,2.43E+01 ,1.1E+00,1.1E+00,0 ,+,1 ,+,+, , 20223, 0, ,R,f(1)(1285) ,x(uU+dD)+y(sS) 1.294E+03 ,4.0E+00,4.0E+00,5.5E+01 ,5.0E+00,5.0E+00,0 ,+,0 ,-,+, , 100221, 0, ,R,eta(1295) ,x(uU+dD)+y(sS) 1.300E+03 ,1.0E+02,1.0E+02,4.0E+02 ,2.0E+02,2.0E+02,1 ,-,0 ,-, ,B, 100211, +, ,R,pi(1300) ,uD -1.300E+03 ,1.0E+02,1.0E+02,4.0E+02 ,2.0E+02,2.0E+02,1 ,-,0 ,-,+,B, 100111, 0, ,R,pi(1300) ,(uU-dD)/sqrt(2) +1.300E+03 ,1.0E+02,1.0E+02,4.0E+02 ,2.0E+02,2.0E+02,1 ,-,0 ,-,+, , 100111, 0, ,R,pi(1300) ,(uU-dD)/sqrt(2) 1.3183E+03 ,6.0E-01,6.0E-01,1.07E+02 ,5.0E+00,5.0E+00,1 ,-,2 ,+, ,B, 215, +, ,R,a(2)(1320) ,uD -1.3183E+03 ,6.0E-01,6.0E-01,1.07E+02 ,5.0E+00,5.0E+00,1 ,-,2 ,+,+,B, 115, 0, ,R,a(2)(1320) ,(uU-dD)/sqrt(2) +1.3183E+03 ,6.0E-01,6.0E-01,1.07E+02 ,5.0E+00,5.0E+00,1 ,-,2 ,+,+, , 115, 0, ,R,a(2)(1320) ,(uU-dD)/sqrt(2) 1.35E+03 ,1.5E+02,1.5E+02,3.5E+02 ,1.5E+02,1.5E+02,0 ,+,0 ,+,+, , 30221, 0, ,R,f(0)(1370) ,x(uU+dD)+y(sS) 1.386E+03 ,1.9E+01,1.9E+01,9.1E+01 ,3.0E+01,3.0E+01,? ,-,1 ,+,-, , 10333, 0, ,S,h(1)(1380) ,x(uU+dD)+y(sS) 1.351E+03 ,3.0E+01,3.0E+01,3.1E+02 ,4.0E+01,4.0E+01,1 ,-,1 ,-, , ,9000213, +, ,R,pi(1)(1400) ,Maybe non-qQ @@ -146,9 +146,9 @@ 1.425E+03 ,2.5E+01,2.5E+01,2.15E+02 ,3.5E+01,3.5E+01,0 ,-,1 ,-,-, , 100223, 0, ,R,omega(1420) ,x(uU+dD)+y(sS) 1.453E+03 ,4.0E+00,4.0E+00,1.3E+01 ,5.0E+00,5.0E+00,0 ,+,2 ,+,+, ,9000225, 0, ,S,f(2)(1430) ,x(uU+dD)+y(sS) 1.474E+03 ,1.9E+01,1.9E+01,2.65E+02 ,1.3E+01,1.3E+01,1 ,-,0 ,+, ,B, 10211, +, ,R,a(0)(1450) ,uD -1.474E+03 ,1.9E+01,1.9E+01,2.65E+02 ,1.3E+01,1.3E+01,1 ,-,0 ,+,+,B, 10111, 0, ,R,a(0)(1450) ,(uU-dD)/sqrt(2) +1.474E+03 ,1.9E+01,1.9E+01,2.65E+02 ,1.3E+01,1.3E+01,1 ,-,0 ,+,+, , 10111, 0, ,R,a(0)(1450) ,(uU-dD)/sqrt(2) 1.465E+03 ,2.5E+01,2.5E+01,4.0E+02 ,6.0E+01,6.0E+01,1 ,+,1 ,-, ,B, 100213, +, ,R,rho(1450) ,uD -1.465E+03 ,2.5E+01,2.5E+01,4.0E+02 ,6.0E+01,6.0E+01,1 ,+,1 ,-,-,B, 100113, 0, ,R,rho(1450) ,(uU-dD)/sqrt(2) +1.465E+03 ,2.5E+01,2.5E+01,4.0E+02 ,6.0E+01,6.0E+01,1 ,+,1 ,-,-, , 100113, 0, ,R,rho(1450) ,(uU-dD)/sqrt(2) 1.476E+03 ,4.0E+00,4.0E+00,8.5E+01 ,9.0E+00,9.0E+00,0 ,+,0 ,-,+, , 100331, 0, ,R,eta(1475) ,x(uU+dD)+y(sS) 1.505E+03 ,6.0E+00,6.0E+00,1.09E+02 ,7.0E+00,7.0E+00,0 ,+,0 ,+,+, ,9030221, 0, ,R,f(0)(1500) ,Maybe non-qQ 1.518E+03 ,5.0E+00,5.0E+00,7.3E+01 ,2.5E+01,2.5E+01,0 ,+,1 ,+,+, ,9000223, 0, ,S,f(1)(1510) ,x(uU+dD)+y(sS) @@ -159,61 +159,61 @@ 1.662E+03 ,1.5E+01,1.1E+01,2.3E+02 ,5.0E+01,5.0E+01,1 ,-,1 ,-, , ,9010213, +, ,R,pi(1)(1600) ,Maybe non-qQ 1.662E+03 ,1.5E+01,1.1E+01,2.3E+02 ,5.0E+01,5.0E+01,1 ,-,1 ,-,+, ,9010113, 0, ,R,pi(1)(1600) ,Maybe non-qQ 1.647E+03 ,2.2E+01,2.2E+01,2.54E+02 ,2.7E+01,2.7E+01,1 ,-,1 ,+, ,B,9020213, +, ,S,a(1)(1640) ,uD -1.647E+03 ,2.2E+01,2.2E+01,2.54E+02 ,2.7E+01,2.7E+01,1 ,-,1 ,+,+,B,9020113, 0, ,S,a(1)(1640) ,(uU-dD)/sqrt(2) +1.647E+03 ,2.2E+01,2.2E+01,2.54E+02 ,2.7E+01,2.7E+01,1 ,-,1 ,+,+, ,9020113, 0, ,S,a(1)(1640) ,(uU-dD)/sqrt(2) 1.639E+03 ,6.0E+00,6.0E+00,9.9E+01 ,6.0E+01,4.0E+01,0 ,+,2 ,+,+, ,9020225, 0, ,S,f(2)(1640) ,x(uU+dD)+y(sS) 1.617E+03 ,5.0E+00,5.0E+00,1.81E+02 ,1.1E+01,1.1E+01,0 ,+,2 ,-,+, , 10225, 0, ,R,eta(2)(1645) ,x(uU+dD)+y(sS) 1.670E+03 ,3.0E+01,3.0E+01,3.15E+02 ,3.5E+01,3.5E+01,0 ,-,1 ,-,-, , 30223, 0, ,R,omega(1650) ,x(uU+dD)+y(sS) 1.667E+03 ,4.0E+00,4.0E+00,1.680E+02 ,1.0E+01,1.0E+01,0 ,-,3 ,-,-, , 227, 0, ,R,omega(3)(1670) ,x(uU+dD)+y(sS) 1.6724E+03 ,3.2E+00,3.2E+00,2.59E+02 ,9.0E+00,9.0E+00,1 ,-,2 ,-, ,B, 10215, +, ,R,pi(2)(1670) ,uD -1.6724E+03 ,3.2E+00,3.2E+00,2.59E+02 ,9.0E+00,9.0E+00,1 ,-,2 ,-,+,B, 10115, 0, ,R,pi(2)(1670) ,(uU-dD)/sqrt(2) +1.6724E+03 ,3.2E+00,3.2E+00,2.59E+02 ,9.0E+00,9.0E+00,1 ,-,2 ,-,+, , 10115, 0, ,R,pi(2)(1670) ,(uU-dD)/sqrt(2) 1.680E+03 ,2.0E+01,2.0E+01,1.5E+02 ,5.0E+01,5.0E+01,0 ,-,1 ,-,-, , 100333, 0, ,R,phi(1680) ,x(uU+dD)+y(sS) 1.6888E+03 ,2.1E+00,2.1E+00,1.610E+02 ,1.0E+01,1.0E+01,1 ,+,3 ,-, ,B, 217, +, ,R,rho(3)(1690) ,uD -1.6888E+03 ,2.1E+00,2.1E+00,1.610E+02 ,1.0E+01,1.0E+01,1 ,+,3 ,-,-,B, 117, 0, ,R,rho(3)(1690) ,(uU-dD)/sqrt(2) +1.6888E+03 ,2.1E+00,2.1E+00,1.610E+02 ,1.0E+01,1.0E+01,1 ,+,3 ,-,-, , 117, 0, ,R,rho(3)(1690) ,(uU-dD)/sqrt(2) 1.720E+03 ,2.0E+01,2.0E+01,2.50E+02 ,1.0E+02,1.0E+02,1 ,+,1 ,-, ,B, 30213, +, ,R,rho(1700) ,uD -1.720E+03 ,2.0E+01,2.0E+01,2.50E+02 ,1.0E+02,1.0E+02,1 ,+,1 ,-,-,B, 30113, 0, ,R,rho(1700) ,(uU-dD)/sqrt(2) +1.720E+03 ,2.0E+01,2.0E+01,2.50E+02 ,1.0E+02,1.0E+02,1 ,+,1 ,-,-, , 30113, 0, ,R,rho(1700) ,(uU-dD)/sqrt(2) 1.732E+03 ,1.6E+01,1.6E+01,1.9E+02 ,4.0E+01,4.0E+01,1 ,-,2 ,+, ,B, 100215, +, ,S,a(2)(1700) ,uD -1.732E+03 ,1.6E+01,1.6E+01,1.9E+02 ,4.0E+01,4.0E+01,1 ,-,2 ,+,+,B, 100115, 0, ,S,a(2)(1700) ,(uU-dD)/sqrt(2) +1.732E+03 ,1.6E+01,1.6E+01,1.9E+02 ,4.0E+01,4.0E+01,1 ,-,2 ,+,+, , 100115, 0, ,S,a(2)(1700) ,(uU-dD)/sqrt(2) 1.724E+03 ,7.0E+00,7.0E+00,1.37E+02 ,8.0E+00,8.0E+00,0 ,+,0 ,+,+, , 10331, 0, ,R,f(0)(1710) ,x(uU+dD)+y(sS) 1.756E+03 ,9.0E+00,9.0E+00,9.6E+01 ,7.0E+01,7.0E+01,0 ,+,0 ,-,+, ,9040221, 0, ,S,eta(1760) ,x(uU+dD)+y(sS) 1.816E+03 ,1.4E+01,1.4E+01,2.08E+02 ,1.2E+01,1.2E+01,1 ,-,0 ,-, ,B,9010211, +, ,R,pi(1800) ,uD -1.816E+03 ,1.4E+01,1.4E+01,2.08E+02 ,1.2E+01,1.2E+01,1 ,-,0 ,-,+,B,9010111, 0, ,R,pi(1800) ,(uU-dD)/sqrt(2) +1.816E+03 ,1.4E+01,1.4E+01,2.08E+02 ,1.2E+01,1.2E+01,1 ,-,0 ,-,+, ,9010111, 0, ,R,pi(1800) ,(uU-dD)/sqrt(2) 1.815E+03 ,1.2E+01,1.2E+01,1.97E+02 ,2.2E+01,2.2E+01,0 ,+,2 ,+,+, ,9030225, 0, ,S,f(2)(1810) ,x(uU+dD)+y(sS) 1.834E+03 ,7.0E+00,7.0E+00,6.8E+01 ,2.2E+01,2.2E+01,? ,?,? ,-,+, , , 0, ,S,X(1835) ,x(uU+dD)+y(sS) 1.854E+03 ,7.0E+00,7.0E+00,8.7E+01 ,2.8E+01,2.3E+01,0 ,-,3 ,-,-, , 337, 0, ,R,phi(3)(1850) ,x(uU+dD)+y(sS) 1.842E+03 ,8.0E+00,8.0E+00,2.25E+02 ,1.4E+01,1.4E+01,0 ,+,2 ,-,+, , 10335, 0, ,S,eta(2)(1870) ,x(uU+dD)+y(sS) 1.895E+03 ,1.6E+01,1.6E+01,2.35E+02 ,3.4E+01,3.4E+01,1 ,-,2 ,-,+, , , 0, ,R,pi(2)(1880) ,x(uU+dD)+y(sS) 1.909E+03 ,3.0E+01,3.0E+01,4.8E+01 ,1.7E+01,1.7E+01,1 ,+,1 ,-, ,B,9030213, +, ,S,rho(1900) ,uD -1.909E+03 ,3.0E+01,3.0E+01,4.8E+01 ,1.7E+01,1.7E+01,1 ,+,1 ,-,-,B,9030113, 0, ,S,rho(1900) ,(uU-dD)/sqrt(2) +1.909E+03 ,3.0E+01,3.0E+01,4.8E+01 ,1.7E+01,1.7E+01,1 ,+,1 ,-,-, ,9030113, 0, ,S,rho(1900) ,(uU-dD)/sqrt(2) 1.903E+03 ,9.0E+00,9.0E+00,1.96E+02 ,3.1E+01,3.1E+01,0 ,+,2 ,+,+, ,9040225, 0, ,S,f(2)(1910) ,x(uU+dD)+y(sS) 1.944E+03 ,1.2E+01,1.2E+01,4.72E+02 ,1.8E+01,1.8E+01,0 ,+,2 ,+,+, ,9050225, 0, ,R,f(2)(1950) ,x(uU+dD)+y(sS) 1.982E+03 ,1.4E+01,1.4E+01,1.88E+02 ,2.4E+01,2.4E+01,1 ,+,3 ,-, ,B,9000217, +, ,S,rho(3)(1990) ,uD -1.982E+03 ,1.4E+01,1.4E+01,1.88E+02 ,2.4E+01,2.4E+01,1 ,+,3 ,-,-,B,9000117, 0, ,S,rho(3)(1990) ,(uU-dD)/sqrt(2) +1.982E+03 ,1.4E+01,1.4E+01,1.88E+02 ,2.4E+01,2.4E+01,1 ,+,3 ,-,-, ,9000117, 0, ,S,rho(3)(1990) ,(uU-dD)/sqrt(2) 2.01E+03 ,6.0E+01,8.0E+01,2.0E+02 ,6.0E+01,6.0E+01,0 ,+,2 ,+,+, ,9060225, 0, ,R,f(2)(2010) ,x(uU+dD)+y(sS) 1.992E+03 ,1.6E+01,1.6E+01,4.4E+02 ,6.0E+01,6.0E+01,0 ,+,0 ,+,+, ,9050221, 0, ,S,f(0)(2020) ,x(uU+dD)+y(sS) 2.0010E+03 ,1.0E+01,1.0E+01,3.13E+02 ,3.1E+01,3.1E+01,1 ,-,4 ,+, ,B, 219, +, ,R,a(4)(2040) ,uD -2.0010E+03 ,1.0E+01,1.0E+01,3.13E+02 ,3.1E+01,3.1E+01,1 ,-,4 ,+,+,B, 119, 0, ,R,a(4)(2040) ,(uU-dD)/sqrt(2) +2.0010E+03 ,1.0E+01,1.0E+01,3.13E+02 ,3.1E+01,3.1E+01,1 ,-,4 ,+,+, , 119, 0, ,R,a(4)(2040) ,(uU-dD)/sqrt(2) 2.018E+03 ,1.1E+01,1.1E+01,2.37E+02 ,1.8E+01,1.8E+01,0 ,+,4 ,+,+, , 229, 0, ,R,f(4)(2050) ,x(uU+dD)+y(sS) 2.090E+03 ,2.9E+01,2.9E+01,6.2E+02 ,5.0E+01,5.0E+01,1 ,-,2 ,-, ,B,9000215, +, ,S,pi(2)(2100) ,uD -2.090E+03 ,2.9E+01,2.9E+01,6.2E+02 ,5.0E+01,5.0E+01,1 ,-,2 ,-,+,B,9000115, 0, ,S,pi(2)(2100) ,(uU-dD)/sqrt(2) +2.090E+03 ,2.9E+01,2.9E+01,6.2E+02 ,5.0E+01,5.0E+01,1 ,-,2 ,-,+, ,9000115, 0, ,S,pi(2)(2100) ,(uU-dD)/sqrt(2) 2.103E+03 ,8.0E+00,8.0E+00,2.09E+02 ,1.9E+01,1.9E+01,0 ,+,0 ,+,+, ,9060221, 0, ,S,f(0)(2100) ,x(uU+dD)+y(sS) 2.156E+03 ,1.1E+01,1.1E+01,1.67E+02 ,3.0E+01,3.0E+01,0 ,+,2 ,+,+, ,9070225, 0, ,S,f(2)(2150) ,x(uU+dD)+y(sS) 2.149E+03 ,1.7E+01,1.7E+01,3.6E+02 ,4.0E+01,4.0E+01,1 ,+,1 ,-, ,B,9040213, +, ,S,rho(2150) ,uD -2.149E+03 ,1.7E+01,1.7E+01,3.6E+02 ,4.0E+01,4.0E+01,1 ,+,1 ,-,-,B,9040113, 0, ,S,rho(2150) ,(uU-dD)/sqrt(2) +2.149E+03 ,1.7E+01,1.7E+01,3.6E+02 ,4.0E+01,4.0E+01,1 ,+,1 ,-,-, ,9040113, 0, ,S,rho(2150) ,(uU-dD)/sqrt(2) 2.175E+03 ,1.5E+01,1.5E+01,6.1E+01 ,1.8E+01,1.8E+01,0 ,-,1 ,-, ,B, , +, ,S,phi(2170) ,uD -2.175E+03 ,1.5E+01,1.5E+01,6.1E+01 ,1.8E+01,1.8E+01,0 ,-,1 ,-,-,B, , 0, ,S,phi(2170) ,(uU-dD)/sqrt(2) +2.175E+03 ,1.5E+01,1.5E+01,6.1E+01 ,1.8E+01,1.8E+01,0 ,-,1 ,-,-, , , 0, ,S,phi(2170) ,(uU-dD)/sqrt(2) 2.189E+03 ,1.3E+01,1.3E+01,2.4E+02 ,5.0E+01,5.0E+01,0 ,+,0 ,+,+, ,9070221, 0, ,S,f(0)(2200) ,x(uU+dD)+y(sS) 2.2311E+03 ,3.5E+00,3.5E+00,2.3E+01 ,8.0E+00,7.0E+00,0 ,+,2 ,+,+, ,9000229, 0, ,S,f(J)(2220) ,x(uU+dD)+y(sS) 2.220E+03 ,1.8E+01,1.8E+01,1.5E+02 ,3.1E+02,8.0E+01,0 ,+,0 ,-,+, ,9080221, 0, ,S,eta(2225) ,x(uU+dD)+y(sS) 2.260E+03 ,2.0E+01,2.0E+01,1.60E+02 ,2.5E+01,2.5E+01,1 ,+,3 ,-, ,B,9010217, +, ,S,rho(3)(2250) ,uD -2.260E+03 ,2.0E+01,2.0E+01,1.60E+02 ,2.5E+01,2.5E+01,1 ,+,3 ,-,-,B,9010117, 0, ,S,rho(3)(2250) ,(uU-dD)/sqrt(2) +2.260E+03 ,2.0E+01,2.0E+01,1.60E+02 ,2.5E+01,2.5E+01,1 ,+,3 ,-,-, ,9010117, 0, ,S,rho(3)(2250) ,(uU-dD)/sqrt(2) 2.297E+03 ,2.8E+01,2.8E+01,1.5E+02 ,4.0E+01,4.0E+01,0 ,+,2 ,+,+, ,9080225, 0, ,R,f(2)(2300) ,x(uU+dD)+y(sS) 2.32E+03 ,6.0E+01,6.0E+01,2.5E+02 ,8.0E+01,8.0E+01,0 ,+,4 ,+,+, ,9010229, 0, ,S,f(4)(2300) ,x(uU+dD)+y(sS) 2.314E+03 ,2.5E+01,2.5E+01,1.44E+02 ,2.0E+01,2.0E+01,0 ,+,0 ,+,+, ,9090221, 0, ,S,f(0)(2330) ,x(uU+dD)+y(sS) 2.34E+03 ,6.0E+01,6.0E+01,3.2E+02 ,8.0E+01,7.0E+01,0 ,+,2 ,+,+, ,9090225, 0, ,R,f(2)(2340) ,x(uU+dD)+y(sS) 2.330E+03 ,3.5E+01,3.5E+01,4.00E+02 ,1.0E+02,1.0E+02,1 ,+,5 ,-, ,B, , +, ,S,rho(5)(2350) ,uD -2.330E+03 ,3.5E+01,3.5E+01,4.00E+02 ,1.0E+02,1.0E+02,1 ,+,5 ,-,-,B, , 0, ,S,rho(5)(2350) ,(uU+dD)/sqrt(2) +2.330E+03 ,3.5E+01,3.5E+01,4.00E+02 ,1.0E+02,1.0E+02,1 ,+,5 ,-,-, , , 0, ,S,rho(5)(2350) ,(uU+dD)/sqrt(2) 2.45E+03 ,1.3E+02,1.3E+02,4.0E+02 ,2.5E+02,2.5E+02,1 ,-,6 ,+, ,B, , +, ,S,a(6)(2450) ,uD -2.45E+03 ,1.3E+02,1.3E+02,4.0E+02 ,2.5E+02,2.5E+02,1 ,-,6 ,+,+,B, , 0, ,S,a(6)(2450) ,(uU+dD)/sqrt(2) +2.45E+03 ,1.3E+02,1.3E+02,4.0E+02 ,2.5E+02,2.5E+02,1 ,-,6 ,+,+, , , 0, ,S,a(6)(2450) ,(uU+dD)/sqrt(2) 2.46E+03 ,5.0E+01,5.0E+01,2.6E+02 ,4.0E+01,4.0E+01,0 ,+,6 ,+,+, , , 0, ,S,f(6)(2510) ,x(uU+dD)+y(sS) 1.0724E+03 ,8.0E-01,8.0E-01,3.50E+00 ,1.5E+00,1.0E+00,? ,?,0 ,+,+, , , 0, ,F,X(1070) ,?? 1.107E+03 ,4.0E+00,4.0E+00,1.11E+02 ,1.7E+01,1.7E+01,0 ,+,? ,+,+, , , 0, ,F,X(1110) ,?? @@ -316,8 +316,8 @@ 3.350E+03 ,2.2E+01,2.8E+01,7.0E+01 ,6.0E+01,5.0E+01,? ,?,? ,?,?, , , 0, ,F,X(3350) ,?? 4.93677E+02 ,1.6E-02,1.6E-02,5.352E-14 ,9.0E-17,9.0E-17,1/2, ,0 ,-, ,B, 321, +, ,R,K ,uS 4.97614E+02 ,2.4E-02,2.4E-02,-1 ,-1 ,-1 ,1/2, ,0 ,-, ,F, 311, 0, ,R,K ,dS -4.97614E+02 ,2.4E-02,2.4E-02,7.397E-12 ,4.0E-15,4.0E-15,1/2, ,0 ,-, , , 310, 0, ,R,K0S ,p(dS)+q(Ds) -4.97614E+02 ,2.4E-02,2.4E-02,1.295E-14 ,5.0E-17,5.0E-17,1/2, ,0 ,-, , , 130, 0, ,R,K0L ,p(dS)-q(Ds) +4.97614E+02 ,2.4E-02,2.4E-02,7.397E-12 ,4.0E-15,4.0E-15,1/2, ,0 ,-,-, , 310, 0, ,R,K0S ,p(dS)+q(Ds) +4.97614E+02 ,2.4E-02,2.4E-02,1.295E-14 ,5.0E-17,5.0E-17,1/2, ,0 ,-,+, , 130, 0, ,R,K0L ,p(dS)-q(Ds) 6.7E+02 ,4.0E+01,4.0E+01,5.50E+02 ,3.4E+01,3.4E+01,1/2, ,0 ,+, ,F,9000321, +, ,S,K(0)*(800) ,uS 6.7E+02 ,4.0E+01,4.0E+01,5.50E+02 ,3.4E+01,3.4E+01,1/2, ,0 ,+, ,F,9000311, 0, ,S,K(0)*(800) ,dS 8.9166E+02 ,2.6E-01,2.6E-01,5.08E+01 ,9.0E-01,9.0E-01,1/2, ,1 ,-, ,F, 323, +, ,R,K*(892) ,uS @@ -367,22 +367,22 @@ 3.054E+03 ,1.1E+01,1.1E+01,4.2E+01 ,1.6E+01,1.6E+01,? ,?,? ,?,?, , , 0, ,S,K(3100) ,Maybe non-qQ 1.86962E+03 ,2.0E-01,2.0E-01,6.329E-10 ,4.0E-12,4.0E-12,1/2, ,0 ,-, ,B, 411, +, ,R,D ,cD 1.86484E+03 ,1.7E-01,1.7E-01,1.605E-09 ,6.0E-12,6.0E-12,1/2, ,0 ,-, ,F, 421, 0, ,R,D ,cU -2.00697E+03 ,1.9E-01,1.9E-01,2.1 ,-1 ,-1 ,1/2, ,1 ,-, ,F, 423, 0, ,R,D*(2007) ,cU +2.00697E+03 ,1.9E-01,1.9E-01,9.6E-02 ,-1 ,-1 ,1/2, ,1 ,-, ,F, 423, 0, ,R,D*(2007) ,cU 2.01027E+03 ,1.7E-01,1.7E-01,9.6E-02 ,2.2E-02,2.2E-02,1/2, ,1 ,-, ,B, 413, +, ,R,D*(2010) ,cD -2.35E+03 ,5.0E+01,5.0E+01,2.6E+02 ,5.0E+01,5.0E+01,1/2, ,0 ,+, ,F, 10421, 0, ,S,D(0)*(2400) ,cU -2.40E+03 ,4.0E+01,4.0E+01,2.8E+02 ,4.0E+01,4.0E+01,1/2, ,0 ,+, ,F, 10411, +, ,S,D(0)*(2400) ,cD +2.30E+03 ,1.9E+01,1.9E+01,2.74E+02 ,4.0E+01,4.0E+01,1/2, ,0 ,+, ,F, 10421, 0, ,S,D(0)*(2300) ,cU +2.349E+03 ,7.0E+00,7.0E+00,2.21E+02 ,1.8E+01,1.8E+01,1/2, ,0 ,+, ,F, 10411, +, ,S,D(0)*(2300) ,cD 2.4223E+03 ,1.3E+00,1.3E+00,2.04E+01 ,1.7E+00,1.7E+00,1/2, ,1 ,+, ,F, 10423, 0, ,R,D(1)(2420) ,cU 2.4234E+03 ,3.1E+00,3.1E+00,2.5E+01 ,6.0E+00,6.0E+00,1/2, ,? ,?, ,B, 10413, +, ,S,D(1)(2420) ,cD 2.43E+03 ,4.0E+01,4.0E+01,3.8E+02 ,1.3E+02,1.1E+02,1/2, ,1 ,+, ,F, 20423, 0, ,S,D(1)(2430) ,cU -2.4611E+03 ,1.6E+00,1.6E+00,4.3E+01 ,4.0E+00,4.0E+00,1/2, ,2 ,+, ,F, 425, 0, ,R,D(2)*(2460) ,cU -2.4601E+03 ,2.6E+00,3.5E+00,3.7E+01 ,6.0E+00,6.0E+00,1/2, ,2 ,+, ,B, 415, +, ,R,D(2)*(2460) ,cD +2.4607E+03 ,0.4E+00,0.4E+00,4.75E+01 ,1.1E+00,1.1E+00,1/2, ,2 ,+, ,F, 425, 0, ,R,D(2)*(2460) ,cU +2.4654E+03 ,1.3E+00,1.3E+00,4.67E+01 ,1.2E+00,1.2E+00,1/2, ,2 ,+, ,B, 415, +, ,R,D(2)*(2460) ,cD 2.637E+03 ,6.0E+00,6.0E+00,15 ,-1 ,-1 ,1/2, ,? ,?, ,F, , +, ,S,D*(2640) ,cD 1.96849E+03 ,3.4E-01,3.4E-01,1.325E-09 ,1.9E-11,1.9E-11,0 , ,0 ,-, ,B, 431, +, ,R,D(s) ,cS -2.1123E+03 ,5.0E-01,5.0E-01,-1 ,-1 ,-1 ,0 , ,? ,?, ,B, 433, +, ,R,D(s)* ,cS +2.1123E+03 ,5.0E-01,5.0E-01,1.0E-01 ,-1 ,-1 ,0 , ,1 ,-, ,B, 433, +, ,R,D(s)* ,cS 2.3178E+03 ,6.0E-01,6.0E-01,10 ,-1 ,-1 ,0 , ,0 ,+, ,B, 10431, +, ,R,D(s0)*(2317) ,cS 2.4596E+03 ,6.0E-01,6.0E-01,6.3 ,-1 ,-1 ,0 , ,1 ,+, ,B, 20433, +, ,R,D(s1)(2460) ,cS 2.5354E+03 ,6.0E-01,6.0E-01,2.5 ,-1 ,-1 ,0 , ,1 ,+, ,B, 10433, +, ,R,D(s1)(2536) ,cS -2.5726E+03 ,9.0E-01,9.0E-01,2.0E+01 ,5.0E+00,5.0E+00,0 , ,? ,?, ,B, 435, +, ,R,D(s2)(2573) ,cS +2.5726E+03 ,9.0E-01,9.0E-01,2.0E+01 ,5.0E+00,5.0E+00,0 , ,2 ,+, ,B, 435, +, ,R,D(s2)(2573) ,cS 2.690E+03 ,7.0E+00,7.0E+00,1.10E+02 ,2.7E+01,2.7E+01,0 , ,1 ,-, ,B, , +, ,S,D(s1)(2700) ,cS 5.27915E+03 ,3.1E-01,3.1E-01,4.045E-10 ,2.7E-12,2.7E-12,1/2, ,0 ,-, ,B, 521, +, ,R,B ,uB 5.27953E+03 ,3.3E-01,3.3E-01,4.331E-10 ,2.5E-12,2.5E-12,1/2, ,0 ,-, ,F, 511, 0, ,R,B ,dB @@ -409,7 +409,7 @@ 3.637E+03 ,4.0E+00,4.0E+00,1.4E+01 ,7.0E+00,7.0E+00,0 ,+,0 ,-,+, , 100441, 0, ,R,eta(c)(2S) ,cC 3.68609E+03 ,4.0E-02,4.0E-02,3.17E-01 ,9.0E-03,9.0E-03,0 ,-,1 ,-,-, , 100443, 0, ,R,psi(2S) ,cC 3.77292E+03 ,3.5E-01,3.5E-01,2.730E+01 ,1.0E+00,1.0E+00,0 ,-,1 ,-,-, , 30443, 0, ,R,psi(3770) ,cC -3.8722E+03 ,8.0E-01,8.0E-01,3.0E+00 ,2.1E+00,1.7E+00,0 ,?,1 ,?,+, ,9930443, 0, ,R,X(3872) ,cC +3.8722E+03 ,8.0E-01,8.0E-01,3.0E+00 ,2.1E+00,1.7E+00,0 ,+,1 ,+,+, ,9930443, 0, ,R,X(3872) ,cC 3.929E+03 ,5.0E+00,5.0E+00,2.90E+01 ,1.0E+01,1.0E+01,0 ,+,2 ,+,+, , 100445, 0, ,S,chi(c2)(2P) ,cC 3.943E+03 ,8.0E+00,8.0E+00,52 ,-1 ,-1 ,? ,?,? ,?,?, , , 0, ,S,X(3940) ,cC 3.943E+03 ,1.7E+01,1.7E+01,8.7E+01 ,3.4E+01,3.4E+01,? ,?,? ,?,?, , , 0, ,S,X(3945) ,cC @@ -578,15 +578,15 @@ 2.342E+03 ,3.0E+01,3.0E+01,1.6E+02 ,4.0E+01,4.0E+01,0 , ,3/2 ,-, ,F, , 0,1,S,Lambda(2325) ,uds 2.3500E+03 ,2.0E+01,1.0E+01,1.5E+02 ,1.0E+02,5.0E+01,0 , ,9/2 ,+, ,F, , 0,3,D,Lambda(2350) ,uds 2.530E+03 ,2.5E+01,2.5E+01,150 ,-1 ,-1 ,0 , ,? ,?, ,F, , 0,2,S,Lambda(2585) ,uds -1.18937E+03 ,7.0E-02,7.0E-02,8.264E-12 ,2.7E-14,2.7E-14,1 , ,1/2 ,+, ,F, 3222, +,4,R,Sigma(P11) ,uus -1.192642E+03 ,2.4E-02,2.4E-02,9.0E-03 ,8.0E-04,8.0E-04,1 , ,1/2 ,+, ,F, 3212, 0,4,R,Sigma(P11) ,uds -1.197449E+03 ,3.0E-02,3.0E-02,4.480E-12 ,3.3E-14,3.3E-14,1 , ,1/2 ,+, ,F, 3112, -,4,R,Sigma(P11) ,dds +1.18937E+03 ,7.0E-02,7.0E-02,8.264E-12 ,2.7E-14,2.7E-14,1 , ,1/2 ,+, ,F, 3222, +,4,R,Sigma ,uus +1.192642E+03 ,2.4E-02,2.4E-02,9.0E-03 ,8.0E-04,8.0E-04,1 , ,1/2 ,+, ,F, 3212, 0,4,R,Sigma ,uds +1.197449E+03 ,3.0E-02,3.0E-02,4.480E-12 ,3.3E-14,3.3E-14,1 , ,1/2 ,+, ,F, 3112, -,4,R,Sigma ,dds 1.3828E+03 ,4.0E-01,4.0E-01,3.58E+01 ,8.0E-01,8.0E-01,1 , ,3/2 ,+, ,F, 3224, +,4,R,Sigma(1385) ,uus 1.38370E+03 ,1.0E+00,1.0E+00,3.6E+01 ,5.0E+00,5.0E+00,1 , ,3/2 ,+, ,F, 3214, 0,4,R,Sigma(1385) ,uds 1.3872E+03 ,5.0E-01,5.0E-01,3.94E+01 ,2.1E+00,2.1E+00,1 , ,3/2 ,+, ,F, 3114, -,4,R,Sigma(1385) ,dds -1.480E+03 ,1.5E+01,1.5E+01,6.0E+01 ,1.5E+01,1.5E+01,1 , ,? ,?, ,F, , +,1,S,Sigma(1480) ,uus -1.480E+03 ,1.5E+01,1.5E+01,6.0E+01 ,1.5E+01,1.5E+01,1 , ,? ,?, ,F, , 0,1,S,Sigma(1480) ,uds -1.480E+03 ,1.5E+01,1.5E+01,6.0E+01 ,1.5E+01,1.5E+01,1 , ,? ,?, ,F, , -,1,S,Sigma(1480) ,dds +1.480E+03 ,1.5E+01,1.5E+01,6.0E+01 ,1.5E+01,1.5E+01,1 , ,1/2 ,+, ,F, , +,1,S,Sigma(1480) ,uus +1.480E+03 ,1.5E+01,1.5E+01,6.0E+01 ,1.5E+01,1.5E+01,1 , ,1/2 ,+, ,F, , 0,1,S,Sigma(1480) ,uds +1.480E+03 ,1.5E+01,1.5E+01,6.0E+01 ,1.5E+01,1.5E+01,1 , ,1/2 ,+, ,F, , -,1,S,Sigma(1480) ,dds 1.572E+03 ,4.0E+00,4.0E+00,7.9E+01 ,3.0E+01,3.0E+01,1 , ,? ,?, ,F, , +,2,S,Sigma(1560) ,uus 1.572E+03 ,4.0E+00,4.0E+00,7.9E+01 ,3.0E+01,3.0E+01,1 , ,? ,?, ,F, , 0,2,S,Sigma(1560) ,uds 1.572E+03 ,4.0E+00,4.0E+00,7.9E+01 ,3.0E+01,3.0E+01,1 , ,? ,?, ,F, , -,2,S,Sigma(1560) ,dds @@ -666,16 +666,16 @@ 1.32171E+03 ,7.0E-02,7.0E-02,4.04E-12 ,4.0E-14,4.0E-14,1/2, ,1/2 ,+, ,F, 3312, -,4,R,Xi ,dss 1.53180E+03 ,3.2E-01,3.2E-01,9.1E+00 ,5.0E-01,5.0E-01,1/2, ,3/2 ,+, ,F, 3324, 0,4,R,Xi(1530) ,uss 1.5350E+03 ,6.0E-01,6.0E-01,9.9E+00 ,1.7E+00,1.9E+00,1/2, ,3/2 ,+, ,F, 3314, -,4,R,Xi(1530) ,dss -1.6240E+03 ,3.0E+00,3.0E+00,22.5 ,-1 ,-1 ,1/2, ,? ,?, ,F, , 0,1,S,Xi(1620) ,uss -1.6240E+03 ,3.0E+00,3.0E+00,22.5 ,-1 ,-1 ,1/2, ,? ,?, ,F, , -,1,S,Xi(1620) ,dss -1.6900E+03 ,1.0E+01,1.0E+01,-1 ,-1 ,-1 ,1/2, ,? ,?, ,F, , 0,3,D,Xi(1690) ,uss -1.6900E+03 ,1.0E+01,1.0E+01,-1 ,-1 ,-1 ,1/2, ,? ,?, ,F, , -,3,D,Xi(1690) ,dss +1.6240E+03 ,3.0E+00,3.0E+00,22.5 ,-1 ,-1 ,1/2, ,1/2 ,-, ,F, , 0,1,S,Xi(1620) ,uss +1.6240E+03 ,3.0E+00,3.0E+00,22.5 ,-1 ,-1 ,1/2, ,1/2 ,-, ,F, , -,1,S,Xi(1620) ,dss +1.6900E+03 ,1.0E+01,1.0E+01,-1 ,-1 ,-1 ,1/2, ,1/2 ,-, ,F, , 0,3,D,Xi(1690) ,uss +1.6900E+03 ,1.0E+01,1.0E+01,-1 ,-1 ,-1 ,1/2, ,1/2 ,-, ,F, , -,3,D,Xi(1690) ,dss 1.823E+03 ,5.0E+00,5.0E+00,2.40E+01 ,1.5E+01,1.0E+01,1/2, ,3/2 ,-, ,F, 13324, 0,3,D,Xi(1820) ,uss 1.823E+03 ,5.0E+00,5.0E+00,2.40E+01 ,1.5E+01,1.0E+01,1/2, ,3/2 ,-, ,F, 13314, -,3,D,Xi(1820) ,dss -1.950E+03 ,1.5E+01,1.5E+01,6.0E+01 ,2.0E+01,2.0E+01,1/2, ,? ,?, ,F, , 0,3,D,Xi(1950) ,uss -1.950E+03 ,1.5E+01,1.5E+01,6.0E+01 ,2.0E+01,2.0E+01,1/2, ,? ,?, ,F, , -,3,D,Xi(1950) ,dss -2.025E+03 ,5.0E+00,5.0E+00,2.0E+01 ,1.5E+01,5.0E+00,1/2, ,>3/2,?, ,F, , 0,3,D,Xi(2030) ,uss -2.025E+03 ,5.0E+00,5.0E+00,2.0E+01 ,1.5E+01,5.0E+00,1/2, ,>3/2,?, ,F, , -,3,D,Xi(2030) ,dss +1.950E+03 ,1.5E+01,1.5E+01,6.0E+01 ,2.0E+01,2.0E+01,1/2, ,5/2 ,-, ,F, , 0,3,D,Xi(1950) ,uss +1.950E+03 ,1.5E+01,1.5E+01,6.0E+01 ,2.0E+01,2.0E+01,1/2, ,5/2 ,-, ,F, , -,3,D,Xi(1950) ,dss +2.025E+03 ,5.0E+00,5.0E+00,2.0E+01 ,1.5E+01,5.0E+00,1/2, ,3/2 ,+, ,F, , 0,3,D,Xi(2030) ,uss +2.025E+03 ,5.0E+00,5.0E+00,2.0E+01 ,1.5E+01,5.0E+00,1/2, ,3/2 ,+, ,F, , -,3,D,Xi(2030) ,dss 2.137E+03 ,4.0E+00,4.0E+00,20 ,-1 ,-1 ,1/2, ,? ,?, ,F, , 0,1,S,Xi(2120) ,uss 2.137E+03 ,4.0E+00,4.0E+00,20 ,-1 ,-1 ,1/2, ,? ,?, ,F, , -,1,S,Xi(2120) ,dss 2.189E+03 ,7.0E+00,7.0E+00,4.6E+01 ,2.7E+01,2.7E+01,1/2, ,? ,?, ,F, , 0,2,S,Xi(2250) ,uss @@ -721,6 +721,7 @@ 3.1229E+03 ,1.3E+00,1.3E+00,4.0E+00 ,4.0E+00,4.0E+00,? , ,? ,?, ,F, , +,1,S,Xi(c)(3123) ,usc 2.6975E+03 ,2.6E+00,2.6E+00,9.6E-09 ,1.7E-09,1.7E-09,0 , ,1/2 ,+, ,F, 4332, 0,3,R,Omega(c) ,ssc 2.7683E+03 ,3.0E+00,3.0E+00,-1 ,-1 ,-1 ,0 , ,3/2 ,+, ,F, 4334, 0,3,R,Omega(c)(2770) ,ssc +3.0004E+03 ,0.2E+00,0.2E+00,4.5E+00 ,0.7E+00,0.7E+00,0 , ,1/2 ,+, ,F, , 0,3,R,Omega(c)(3000) ,ssc 3.5189E+03 ,9.0E-01,9.0E-01,2.0079E-08 ,-1 ,-1 ,? , ,? ,?, ,F, 4422, ++,1,S,Xi(cc) ,ucc 3.5189E+03 ,9.0E-01,9.0E-01,2.0079E-08 ,-1 ,-1 ,? , ,? ,?, ,F, 4412, +,1,S,Xi(cc) ,dcc 5.6202E+03 ,1.6E+00,1.6E+00,4.79E-10 ,1.7E-11,1.7E-11,0 , ,1/2 ,+, ,F, 5122, 0,3,R,Lambda(b) ,udb @@ -732,4 +733,4 @@ 5.8364E+03 ,2.8E+00,2.8E+00,-1 ,-1 ,-1 ,1 , ,3/2 ,+, ,F, 5114, -,3,R,Sigma(b)* ,ddb 5.7924E+03 ,3.0E+00,3.0E+00,1.42E-12 ,2.8E-13,2.4E-13,1/2, ,1/2 ,+, ,F, 5232, -,3,R,Xi(b) ,dsb 5.7924E+03 ,3.0E+00,3.0E+00,4.7E-10 ,9.0E-11,8.0E-11,1/2, ,1/2 ,+, ,F, 5132, 0,3,R,Xi(b) ,usb - +6.0461E+03 ,1.7E+00,1.7E+00,4.7E-10 ,9.0E-11,8.0E-11,1/2, ,1/2 ,+, ,F, 5334, -,3,R,Omega(b) ,ssb diff --git a/options/pdgID_to_latex.dat b/options/pdgID_to_latex.dat index 6c72b3250ee..86724739cc1 100644 --- a/options/pdgID_to_latex.dat +++ b/options/pdgID_to_latex.dat @@ -296,6 +296,7 @@ 3334 \Omega^{-} \Omega^{+} 4332 \Omega_{c}^{0} \Omega_{c}^{0} 4334 \Omega_{c}^{*0} \Omega_{c}^{*0} +5334 \Omega_{b}^{-} \Omega_{b}^{+} 9981 0^{+} 0^{+} 9983 1^{+} 1^{+} 9985 2^{+} 2^{+} diff --git a/options/run_lbAmpGen_tests.sh b/options/run_lbAmpGen_tests.sh new file mode 100755 index 00000000000..0e1ea585131 --- /dev/null +++ b/options/run_lbAmpGen_tests.sh @@ -0,0 +1,22 @@ +branch=mstahl_AmpGen + +tmp_dir=$(mktemp -d -t ci-XXXXXXXXXX) +echo "TMPDIR=$tmp_dir" +cd $tmp_dir + +wget https://gitlab.cern.ch/lhcb/Gauss/-/archive/$branch/Gauss-${branch}.zip?path=Gen/LbAmpGen -O LbAmpGen.zip >> /dev/null +unzip LbAmpGen.zip >> /dev/null +top=Gauss-$branch-Gen-LbAmpGen + +for model in $top/Gen/LbAmpGen/models/*.opt ; do + filename=$(basename $model) + without_ext=${filename%.*} + if [ $without_ext == "DtoKpipipi_v1" ] || + [ $without_ext == "DtopiKpipi_v1" ] || + [ $without_ext == "DtoKKpipi_v1" ] ; then continue ; fi # these are old models that kept for backwards compatability, dont expect to be able reproduce exactly + mkdir -p build/$without_ext + $AMPGENROOT/build/bin/ConvertToSourceCode $model --Output build/$without_ext/new.cpp >> /dev/null + g++ -Ofast -shared -rdynamic --std=c++11 -fPIC build/$without_ext/new.cpp -o build/$without_ext/new.so + g++ -Ofast -shared -rdynamic --std=c++11 -fPIC $top/Gen/LbAmpGen/src/${without_ext}.cpp -o build/$without_ext/gaussUpdate.so + $AMPGENROOT/build/bin/lib_diff $model --Lib=build/$without_ext/new.so --RefLib=build/$without_ext/gaussUpdate.so +done diff --git a/src/ASTResolver.cpp b/src/ASTResolver.cpp index 0275b1b0bf2..b1366d6ba5e 100644 --- a/src/ASTResolver.cpp +++ b/src/ASTResolver.cpp @@ -12,100 +12,94 @@ using namespace AmpGen; -ASTResolver::ASTResolver(const std::map& evtMap, +ASTResolver::ASTResolver(const std::map& evtMap, const MinuitParameterSet* mps ) : - evtMap(evtMap), - mps(mps), - nParameters(0) + m_evtMap(evtMap), + m_mps(mps), + m_nParameters(0) { - enable_cuda = NamedParameter("UseCUDA",false); - enable_compileTimeConstants = NamedParameter("ASTResolver::CompileTimeConstants",false); + m_enable_cuda = NamedParameter("UseCUDA",false); + m_enable_compileTimeConstants = NamedParameter("ASTResolver::CompileTimeConstants", false); + m_check_hashes = NamedParameter("ASTResolver::CheckHashes", false ); } -bool ASTResolver::hasSubExpressions() const -{ - return subTrees.size() != 0; -} - -void ASTResolver::reduceSubTrees() -{ - subTrees.clear(); - for( auto& t : tempTrees ){ - auto expr = t.first->m_expression; - uint64_t key = t.first->key(); - if( subTrees.count( key ) == 0 ){ - subTrees[ key ] = t.first->m_expression ; - } - } - tempTrees.clear(); -} - -void ASTResolver::getOrderedSubExpressions( - Expression& expression, - std::vector< std::pair< uint64_t,Expression>>& dependentSubexpressions ) +std::vector> ASTResolver::getOrderedSubExpressions( const Expression& expression ) { + std::vector> subexpressions; expression.resolve( *this ); - std::map< uint64_t , size_t> used_functions; - for( size_t i = 0 ; i < dependentSubexpressions.size(); ++i ) - used_functions[ dependentSubexpressions[i].first ] = i; + std::map used_functions; + std::map subTrees; do { - reduceSubTrees(); - for( auto& expression : subTrees ) { - expression.second.resolve( *this ); - auto stack_pos = used_functions.find( expression.first ); + subTrees.clear(); + for( auto& [t, s] : m_tempTrees ) + { + uint64_t key = s->key(); + if( subTrees.count( key ) == 0 ) subTrees[ key ] = s->expression(); + // else if( m_check_hashes && t.first->m_expression.to_string() != subTrees[key].to_string() ) + // { + // WARNING("Hash collision between in key = " << key << " other key = " << FNV1a_hash( subTrees[key].to_string() ) ); + // } + } + m_tempTrees.clear(); + for( auto& [key,expression] : subTrees ){ + expression.resolve( *this ); + auto stack_pos = used_functions.find(key); if ( stack_pos == used_functions.end() ) { - dependentSubexpressions.emplace_back( expression.first , expression.second ); - used_functions[expression.first] = dependentSubexpressions.size() - 1; + subexpressions.emplace_back(key , expression ); + used_functions[key] = subexpressions.size() - 1; continue; } - unsigned int oldPos = stack_pos->second; - auto it = dependentSubexpressions.begin() + oldPos; - if ( it == dependentSubexpressions.end() - 1 ) continue; - - std::rotate( it, it + 1, dependentSubexpressions.end() ); - + auto oldPos = stack_pos->second; + auto it = subexpressions.begin() + oldPos; + if ( it == subexpressions.end() - 1 ) continue; + std::rotate( it, it + 1, subexpressions.end() ); for ( auto uf = used_functions.begin(); uf != used_functions.end(); ++uf ) { if ( uf->second >= oldPos ) uf->second = uf->second - 1; } - used_functions[expression.first] = dependentSubexpressions.size() - 1; + used_functions[key] = subexpressions.size() - 1; } - } while ( hasSubExpressions() ); - std::reverse( dependentSubexpressions.begin(), dependentSubexpressions.end() ); + } while ( subTrees.size() !=0 ); + std::reverse( subexpressions.begin(), subexpressions.end() ); + return subexpressions; } template <> void ASTResolver::resolve( const SubTree& subTree ) { - if( tempTrees.count( &subTree ) != 0 ) return; - tempTrees[&subTree] = 1; + auto ptr = subTree.expression().get(); + if( m_tempTrees.count(ptr) != 0 ) return; + else { + ptr->resolve( *this ); + m_tempTrees[ptr] = &subTree; + } } template <> void ASTResolver::resolve( const Spline& spline ) { if( m_resolvedParameters.count( &spline) != 0 ) return ; - auto address = addCacheFunction(spline.m_name,spline.m_nKnots,spline.m_min,spline.m_max); + auto address = addCacheFunction(spline.m_name, spline.m_nKnots, spline.m_min, spline.m_max); addResolvedParameter( &spline, address ); addResolvedParameter( spline.m_points.top().get(), address ); auto splineTransfer = dynamic_cast( m_cacheFunctions[spline.m_name].get() ); - if( mps == nullptr ) ERROR("Fix me!"); + if( m_mps == nullptr ) ERROR("Fix me: Spline parameters must come from a ParameterSet"); for( unsigned int i = 0 ; i < spline.m_nKnots; ++i ) - splineTransfer->set(i, mps->find(spline.m_name+"::"+std::to_string(i)) ); + splineTransfer->set(i, m_mps->find(spline.m_name+"::"+std::to_string(i)) ); } template <> void ASTResolver::resolve( const Parameter& parameter ) { if( m_resolvedParameters.count(¶meter) != 0 || parameter.isResolved() ) return; - auto res = evtMap.find(parameter.name()); - if( res != evtMap.end() ){ - if( enable_cuda ) { + auto res = m_evtMap.find(parameter.name()); + if( res != m_evtMap.end() ){ + if( m_enable_cuda ) { size_t t = res->second; std::string it = ""; - if( t % 3 == 0 ) it = "x"; - if( t % 3 == 1 ) it = "y"; - if( t % 3 == 2 ) it = "z"; + if( t % 3 == 0 ) it = ".x"; + if( t % 3 == 1 ) it = ".y"; + if( t % 3 == 2 ) it = ".z"; int stg = t/3; std::string nTimesStg = "+"+std::to_string(stg) +"*N"; if( stg == 0 ) nTimesStg = ""; - if( stg == 1 ) nTimesStg = "N"; + if( stg == 1 ) nTimesStg = "+N"; addResolvedParameter( ¶meter, "x1[i"+nTimesStg+"]" +it ); } else { @@ -113,18 +107,17 @@ template <> void ASTResolver::resolve( const Parameter& parameter ) } return; } - else if( mps != nullptr ){ - auto it = mps->find(parameter.name()); + else if( m_mps != nullptr ){ + auto it = m_mps->find(parameter.name()); if( it != nullptr ){ - if( enable_compileTimeConstants && - it->iFixInit() == MinuitParameter::Flag::CompileTimeConstant ){ - addResolvedParameter( ¶meter, std::to_string(it->mean()) ); + if( m_enable_compileTimeConstants && it->flag() == Flag::CompileTimeConstant ){ + addResolvedParameter( ¶meter, "("+std::to_string(it->mean()) +")" ); } else addResolvedParameter( ¶meter, addCacheFunction( parameter.name(), it ) ); return; } } - else if( enable_compileTimeConstants ){ + else if( m_enable_compileTimeConstants ){ addResolvedParameter( ¶meter, std::to_string( parameter.defaultValue() ) ); return; } @@ -135,10 +128,16 @@ template <> void ASTResolver::resolve( const Parameter& parameter ) template <> void ASTResolver::resolve(const MinuitParameterLink& parameter) { if( m_resolvedParameters.count(¶meter) != 0 ) return; - if( mps == nullptr ) return; - auto it = mps->find(parameter.name()); + if( m_mps == nullptr ) return; + auto it = m_mps->find(parameter.name()); if( it == nullptr ) return; - addResolvedParameter(¶meter, addCacheFunction( parameter.name(),it)); + addResolvedParameter(¶meter, addCacheFunction(parameter.name(), it)); +} + +template <> void ASTResolver::resolve( const LambdaExpression& obj) +{ + if( m_resolvedParameters.count(&obj) != 0 ) return; + addResolvedParameter(&obj, addCacheFunction( "lxpr_" + std::to_string(m_nParameters), &obj)); } std::map> ASTResolver::cacheFunctions() const @@ -161,8 +160,16 @@ std::string ASTResolver::resolvedParameter( const IExpression* param ) const auto it = m_resolvedParameters.find(param); if( it != m_resolvedParameters.end() ) return it->second; else { - ERROR( "Parameter cannot be resolved" << param ); + ERROR( "Parameter cannot be resolved: [" << this << "]" << param ); return ""; } } +void ASTResolver::clear() +{ + m_resolvedParameters.clear(); + m_cacheFunctions.clear(); + m_parameterMapping.clear(); + m_tempTrees.clear(); + m_nParameters = 0; +} diff --git a/src/AddCPConjugate.cpp b/src/AddCPConjugate.cpp new file mode 100644 index 00000000000..fea88b44661 --- /dev/null +++ b/src/AddCPConjugate.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include "AmpGen/AddCPConjugate.h" +#include "AmpGen/MinuitParameterSet.h" +#include "AmpGen/NamedParameter.h" +#include "AmpGen/ExpressionParser.h" +#include "AmpGen/MinuitExpression.h" +#include "AmpGen/Particle.h" +#include "AmpGen/ParticlePropertiesList.h" + +using namespace AmpGen; + +void AmpGen::AddCPConjugate( MinuitParameterSet& mps ) +{ + std::vector tmp; + std::string cartOrPolar = NamedParameter("CouplingConstant::Coordinates" ,"cartesian"); + for( auto& param : mps ){ + const std::string name = param->name(); + size_t pos=0; + std::string new_name = name; + int sgn=1; + if( name.find("::") != std::string::npos ){ + pos = name.find("::"); + auto props = AmpGen::ParticlePropertiesList::get( name.substr(0,pos), true ); + if( props != 0 ) new_name = props->anti().name() + name.substr(pos); + } + else { + auto tokens=split(name,'_'); + std::string reOrIm = *tokens.rbegin(); + std::string name = tokens[0]; + if ( reOrIm == "Re" || reOrIm == "Im" ){ + Particle test = Particle(name).conj(); + if( cartOrPolar == "polar" ) sgn = reOrIm == "Re" ? test.CP() : 1; + if( cartOrPolar == "cartesian" ) sgn = test.CP(); + new_name = test.uniqueString() +"_"+reOrIm; + } + else if( tokens.size() == 2 ) { + auto props = AmpGen::ParticlePropertiesList::get(name, true); + if( props != 0 ) new_name = props->anti().name() + "_" + tokens[1]; + } + } + if( mps.find( new_name ) == nullptr ) + { + tmp.push_back( new MinuitExpression(new_name, sgn * MinuitParameterLink(param) )) ; + } + } + for( auto& p : tmp ) mps.add( p ); +} diff --git a/src/AmplitudeRules.cpp b/src/AmplitudeRules.cpp index 11be23a6451..b3d56e136a4 100644 --- a/src/AmplitudeRules.cpp +++ b/src/AmplitudeRules.cpp @@ -5,8 +5,10 @@ #include #include #include +#include #include "AmpGen/MinuitParameter.h" +#include "AmpGen/MinuitExpression.h" #include "AmpGen/MinuitParameterSet.h" #include "AmpGen/MsgService.h" #include "AmpGen/Particle.h" @@ -14,67 +16,77 @@ #include "AmpGen/NamedParameter.h" using namespace AmpGen; +using namespace std::complex_literals; -AmplitudeRule::AmplitudeRule( const std::string& reName, - const std::map& mapping ) +Coupling::Coupling(MinuitParameter* re, MinuitParameter* im) : + m_re(re), + m_im(im) { - auto tokens = split( reName, '_' ); + auto tokens = split( re->name(), '_' ); if ( tokens.size() == 3 ) { m_prefix = tokens[0]; m_name = tokens[1]; - auto ire = mapping.find( reName ); - auto iim = mapping.find( tokens[0] + "_" + tokens[1] + "_Im" ); - if ( iim == mapping.end() ) { - ERROR( "Well-formed coupling not identified for:" << reName ); - return; - } - m_re = ire->second; - m_im = iim->second; - m_isGood = true; - } else if ( tokens.size() == 2 ) { - m_prefix = ""; m_name = tokens[0]; - auto ire = mapping.find( reName ); - auto iim = mapping.find( tokens[0] + "_Im" ); - if ( iim == mapping.end() ) { - ERROR( "Well-formed coupling not identified for:" << reName ); - return; - } - m_re = ire->second; - m_im = iim->second; - m_isGood = true; - } else { - ERROR( "Too many tokens! " ); - m_isGood = false; } - if ( m_isGood ) { - size_t pos = find_next_of( m_name, {"[", "{"} ); - if ( pos == std::string::npos ) - { - ERROR( "Does not seem to be well formed decay descriptor [" << reName << "]" ); - m_isGood = false; - } + else { + ERROR("Ill-formed decay descriptor: " << m_name ); } m_particle = Particle(m_name); + coordinateType coord = NamedParameter("CouplingConstant::Coordinates", coordinateType::cartesian); + angType degOrRad = NamedParameter("CouplingConstant::AngularUnits" , angType::rad); + m_isCartesian = true; + + if( coord == coordinateType::polar ) m_isCartesian = false; + + if ( coord == coordinateType::Invalid){ + FATAL("Coordinates for coupling constants must be either cartesian or polar"); + } + if ( degOrRad == angType::deg) m_sf = M_PI / 180; + + if ( degOrRad == angType::Invalid ){ + FATAL("TotalCoupling::AngularUnits must be either rad or deg"); + } } +Coupling::Coupling(MinuitExpression* expression) : + m_name(expression->name()), + m_expr(expression), + m_particle(m_name){} + AmplitudeRules::AmplitudeRules( const MinuitParameterSet& mps ) { - for ( auto& o : mps.const_map() ) { - if ( o.first.find( "_Re" ) == std::string::npos ) continue; - AmplitudeRule pAmp( o.first, mps.const_map() ); - if ( pAmp.m_isGood ) m_rules[pAmp.m_particle.name()].push_back( pAmp ); + for ( auto& it_re : mps ) { + auto& name = it_re->name(); + DEBUG("Attempting to parse: " << it_re->name() ); + if ( name.find("_Re") != std::string::npos ){ + auto it_im = mps.find(replaceAll( name, "_Re","_Im") ); + if( it_im == nullptr ){ + ERROR("Cannot find matching imaginary part / phase for: " << it_re->name() ); + continue; + } + if( ! Particle::isValidDecayDescriptor( name.substr(0, name.find("_Re") ) ) ) continue; + Coupling p(it_re, it_im); + m_rules[p.head()].emplace_back(p); + } + else if( name.find("_Im") == std::string::npos ){ + bool isCoupling = Particle::isValidDecayDescriptor( it_re->name() ); + if( isCoupling ){ + MinuitExpression* expression = dynamic_cast( it_re ); + DEBUG("Constructing: " << expression << " " << it_re->name() ); + if( expression != nullptr ){ + Coupling p(expression); + m_rules[p.head()].emplace_back(p); + } + } + } } } -CouplingConstant::CouplingConstant( const CouplingConstant& other, - const AmplitudeRule& pA) : - couplings(other.couplings ), - isCartesian(other.isCartesian), - sf(other.sf) +TotalCoupling::TotalCoupling(const TotalCoupling& other, const Coupling& pA) : + couplings(other.couplings) { - couplings.emplace_back( pA.m_re, pA.m_im ); + couplings.emplace_back(pA); } @@ -83,106 +95,78 @@ bool AmplitudeRules::hasDecay(const std::string& head) return m_rules.find(head) != m_rules.end(); } -std::vector AmplitudeRules::rulesForDecay(const std::string& head, const std::string& prefix) +std::vector AmplitudeRules::rulesForDecay(const std::string& head, const std::string& prefix) { - if(!hasDecay(head)) return std::vector(); + if(!hasDecay(head)) return std::vector(); if( prefix == "" )return m_rules[head]; - std::vector rt = m_rules[head]; - rt.erase( std::remove_if( std::begin(rt), std::end(rt), [&prefix](auto& p){ return p.prefix() != prefix; } ) ); + std::vector rt = m_rules[head]; + rt.erase( std::remove_if( std::begin(rt), std::end(rt), [&prefix](auto& p){ return p.prefix() != prefix; } ), rt.end() ); return rt; } -std::map> AmplitudeRules::rules() +const std::map>& AmplitudeRules::rules() const { return m_rules; } -EventType AmplitudeRule::eventType() const +EventType Coupling::eventType() const { Particle particle( m_name ); - std::vector particleNames; - particleNames.push_back( particle.name() ); + std::vector particleNames = { particle.name() }; std::vector> fs = particle.getFinalStateParticles(); std::stable_sort( fs.begin(), fs.end(), []( auto& A, auto& B ) { return *A < *B; } ); - for( auto& f : fs ) particleNames.push_back( f->name() ); + std::transform( fs.begin(), fs.end(), std::back_inserter(particleNames), [](auto& p ) -> std::string { return p->name() ; } ); return EventType( particleNames ); } -CouplingConstant::CouplingConstant(const AmplitudeRule& pA) +TotalCoupling::TotalCoupling(const Coupling& pA) { - couplings.emplace_back( std::make_pair(pA.m_re,pA.m_im) ); - std::string cartOrPolar = NamedParameter("CouplingConstant::Coordinates" ,"cartesian"); - std::string degOrRad = NamedParameter("CouplingConstant::AngularUnits","rad"); - if( cartOrPolar == "polar" ){ - isCartesian = false; - } - else if ( cartOrPolar != "cartesian" ){ - FATAL("Coordinates for coupling constants must be either cartesian or polar"); - } - if ( degOrRad == "deg") sf = M_PI / 180; - else if ( degOrRad != "rad"){ - FATAL("CouplingConstant::AngularUnits must be either rad or deg"); - } + couplings.emplace_back(pA); } -std::complex CouplingConstant::operator()() const +std::complex Coupling::operator()() const { - std::complex F( 1, 0 ); - if ( isCartesian ) - for( auto& p : couplings ) F *= complex_t( p.first->mean() , p.second->mean() ); - else - for( auto& p : couplings ) F *= p.first->mean() * complex_t( cos( sf * p.second->mean() ), sin( sf * p.second->mean() ) ); - return F; + return m_expr != nullptr ? m_expr->getVal() : ( m_isCartesian ? complex_t( m_re->mean(), m_im->mean() ) : m_re->mean() * exp( 1i* m_sf * m_im->mean() ) ); } -Expression CouplingConstant::to_expression() const +Expression Coupling::to_expression() const { - Expression J = Constant(0,1); - if ( isCartesian ) { - Expression total = 1; - for ( auto& p : couplings ) { - total = total * ( Parameter( p.first->name() ) + J * Parameter( p.second->name() ) ); - } - return total; - } else { - Expression angle = 0; - Expression amp = 1; - for ( auto& p : couplings ) { - angle = angle + Parameter( p.second->name() ); - amp = amp * Parameter( p.first->name() ); - } - return amp * ( Cos( sf * angle ) + J * Sin( sf * angle ) ); - } + return m_expr != nullptr ? m_expr->expression() : ( m_isCartesian ? ComplexParameter(Parameter(m_re->name()), Parameter(m_im->name())) : Parameter( m_re->name() ) * fcn::exp( 1i * m_sf * Parameter(m_im->name()) ) ); } -void CouplingConstant::print() const +std::complex TotalCoupling::operator()() const { - INFO( couplings[0].first->name() << " (" << isCartesian << ") = " << ( *this )() ); - if ( isCartesian ) - for ( auto& coupling : couplings ) INFO( coupling.first->name() + " i " + coupling.second->name() ); - else - for ( auto& coupling : couplings ) INFO( coupling.first->name() << " x exp(i" << coupling.second->name() ); + return std::accumulate( couplings.begin(), couplings.end(), complex_t(1,0), [](auto& prod, auto& coupling ){ return prod * coupling() ; } ); } -std::vector< std::pair > AmplitudeRules::getMatchingRules( - const EventType& type, const std::string& prefix ){ +Expression TotalCoupling::to_expression() const +{ + return std::accumulate( couplings.begin(), couplings.end(), Expression(1), [](auto& prod, auto& coupling ){ return prod * coupling.to_expression(); } ); +} - auto rules = rulesForDecay( type.mother() ); - std::vector> rt; +void TotalCoupling::print() const +{ + INFO( this->operator()() << " -> " ); + for( const auto& coupling :*this ) INFO( coupling.to_expression() << " = " << coupling() ); +} +std::vector> AmplitudeRules::getMatchingRules(const EventType& type, const std::string& prefix ) +{ + auto rules = rulesForDecay( type.mother() ); + std::vector> rt; for ( auto& rule : rules ) { if ( rule.prefix() != prefix ) continue; - std::vector> tmpParticles; + std::vector> tmpParticles; auto fs = type.finalStates(); - tmpParticles.emplace_back( Particle( rule.name(), fs ), CouplingConstant(rule) ); + tmpParticles.emplace_back( Particle( rule.name(), fs ), TotalCoupling(rule) ); do { - std::vector> newTmpParticles; - for ( auto& particleWithCouplingConstant : tmpParticles ) { - auto protoParticle = particleWithCouplingConstant.first; - auto coupling = particleWithCouplingConstant.second; + std::vector> newTmpParticles; + for ( auto& particleWithTotalCoupling : tmpParticles ) { + auto protoParticle = particleWithTotalCoupling.first; + auto coupling = particleWithTotalCoupling.second; auto protoFinalStates = protoParticle.getFinalStateParticles(); if ( protoFinalStates.size() == type.size() ) { - rt.emplace_back( particleWithCouplingConstant ); + rt.emplace_back( particleWithTotalCoupling ); continue; } std::string nameToExpand = protoParticle.uniqueString(); @@ -192,7 +176,7 @@ std::vector< std::pair > AmplitudeRules::getMatchin for ( auto& subTree : expandedRules ) { auto expanded_amplitude = replaceAll( nameToExpand, ifs->name(), subTree.name() ); auto fs2 = type.finalStates(); - newTmpParticles.emplace_back( Particle( expanded_amplitude, fs2 ), CouplingConstant( coupling, subTree) ); + newTmpParticles.emplace_back( Particle( expanded_amplitude, fs2 ), TotalCoupling( coupling, subTree) ); } break; // we should only break if there are rules to be expanded ... } @@ -200,26 +184,23 @@ std::vector< std::pair > AmplitudeRules::getMatchin tmpParticles = newTmpParticles; } while ( tmpParticles.size() != 0 ); } + rt.erase( std::remove_if( std::begin(rt), std::end(rt), [](auto& p){ return !p.first.isStateGood(); } ), rt.end() ); + auto end = std::end(rt); + for (auto it = rt.begin(); it != end; ++it) { + auto dd = it->first.decayDescriptor(); + end = std::remove_if(it + 1, end, [dd](auto p){ return p.first.decayDescriptor() == dd;} ); + } + rt.erase(end, rt.end()); return rt; } -bool CouplingConstant::isFixed() const -{ - for( auto& c : couplings ) - if( c.first->iFixInit() == 0 or c.second->iFixInit() == 0 ) return false; - return true; -} - -bool CouplingConstant::contains( const std::string& label ) const +bool TotalCoupling::isFixed() const { - for ( auto& reAndIm : couplings ) - if ( reAndIm.first->name().find( label ) != std::string::npos ) return true; - return false; + return std::all_of(begin(), end(), [](auto& c){ return c.x()->isFixed() && c.y()->isFixed() ; } ); } -void CouplingConstant::changeSign() +bool TotalCoupling::contains( const std::string& label ) const { - auto& top_coupling = *couplings.begin(); - if( isCartesian ) top_coupling.first->setCurrentFitVal( top_coupling.first->mean() * -1. ); + return std::any_of(begin(), end(), [&label](auto& c){ return c.name().find(label) != std::string::npos ; } ); } diff --git a/src/Array.cpp b/src/Array.cpp index c24cc378388..faaedacbf52 100644 --- a/src/Array.cpp +++ b/src/Array.cpp @@ -19,19 +19,13 @@ Array::Array( const Expression& top, std::string Array::to_string(const ASTResolver* resolver) const { auto head = m_top.to_string(resolver); - if( is(m_address) ) - return head+"["+ std::to_string(int(std::real(m_address()))) +"]"; - auto offset = m_address.to_string(resolver); - auto pos = head.find_last_of("]"); - if( pos != std::string::npos ){ - auto st1 = head.substr(0,pos); - auto st2 = head.substr(pos,head.size() - pos ); - return st1 + "+int("+offset+")" + st2; - } - else return head +"[ int("+offset+")]"; + auto offset = Ternary( m_address >= 0 && m_address < m_size, m_address, 0.).to_string(resolver); + if( resolver != nullptr && resolver->enableAVX() ) return " gather( &(" + head + "), " + offset + ")"; + if( head.find("[") == std::string::npos ) return head + "[int("+offset+")]"; + else return " * ( & (" + head + ") + int("+offset+") )"; } -void Array::resolve( ASTResolver& resolver ) +void Array::resolve( ASTResolver& resolver ) const { m_top.resolve( resolver ); m_address.resolve( resolver ); diff --git a/src/BinDT.cpp b/src/BinDT.cpp index b1b13adf8a3..24a62280198 100644 --- a/src/BinDT.cpp +++ b/src/BinDT.cpp @@ -15,7 +15,7 @@ using namespace AmpGen; -double nearestNeighbourVariance(std::vector evts, const size_t& index) +double nearestNeighbourVariance( std::vector evts, const size_t& index) { auto dist = [&index](const double* x, const double* y){ return fabs( *(x+index) -*(y+index)) ;}; auto dist2 = [&index](const double* x, const double* y){ return ( *(x+index) -*(y+index))*( *(x+index) - *(y+index) ) ;}; @@ -69,25 +69,6 @@ unsigned int BinDT::getBinNumber( const double* evt ) const { return ( *m_top )( unsigned int BinDT::size() const { return m_endNodes.size(); } -namespace AmpGen -{ - struct PackedDecision { - uint8_t header; // = 2 bytes - uint8_t index; // = 8 bytes - uint32_t address; // = 2 + 4 bytes - uint32_t left; // = 18 - uint32_t right; // = 24 bytes - double cutVal; // = 14 bytes - }; - struct PackedNode { - uint8_t header; - uint8_t packingBit[1]; - uint32_t address; - uint32_t binNumber; - uint32_t voxNumber; - uint16_t packingBits[3]; - }; -} // namespace AmpGen std::function( const Event& )> BinDT::makeDefaultFunctors() { if ( m_dim == 5 ) { @@ -99,7 +80,7 @@ std::function( const Event& )> BinDT::makeDefaultFunctors() DEBUG( "Problem has 2 d.o.f.s -> using Dalitz coordinates" ); return []( const Event& evt ) -> std::vector { return {evt.s( 0, 1 ), evt.s( 1, 2 )}; }; } - DEBUG( "No functors found for dim = " << m_dim ); + ERROR( "No default functors found for dim = " << m_dim ); return nullptr; } @@ -109,19 +90,18 @@ BinDT::BinDT( const ArgumentPack& args ) m_maxDepth = args.getArg( 999 ); m_dim = args.getArg( 5 ); m_functors = args.getArg( makeDefaultFunctors() ).val; - std::ifstream* stream = args.getArg().val; - auto fname = args.getArg(); - if ( stream != nullptr && stream->is_open() ) { - readFromBinary( *stream ); - } else if ( fname.name != "" ) { - std::ifstream stream( fname.name, fname.mode | std::ios::in ); - if ( fname.mode & std::ios::binary ) - readFromBinary( stream ); - else - readFromStream( stream ); + auto fname = args.getArg("").val; + if ( fname != "" ) { + auto stream = std::ifstream(fname); + readFromStream(stream); } } +BinDT::BinDT( const EventList& events, const ArgumentPack& args ) : BinDT(args) +{ + makeNodes( events.begin(), events.end() ); +} + void BinDT::readFromStream( std::istream& stream ) { std::map>> nodes; @@ -159,79 +139,6 @@ void BinDT::readFromStream( std::istream& stream ) } } -void BinDT::readFromBinary( std::ifstream& stream ) -{ - std::map> nodes; - std::map> fti; - char buffer[PACKET_SIZE]; // 24 byte word for the nodes // - size_t edc = 0; - while ( stream.read( buffer, PACKET_SIZE ) ) { - if ( ( uint8_t( buffer[0] ) ) == 0xAA ) { - PackedDecision pd; - memcpy( &pd, buffer, PACKET_SIZE ); - nodes.emplace( pd.address, std::make_shared( pd.index, pd.cutVal ) ); - DEBUG( "header = " << std::hex << (uint8_t)pd.header << std::dec << " index = " << pd.index - << " cut-val = " << pd.cutVal << " left-node = " << pd.left << " right-node=" << std::hex - << pd.right << " " << std::dec << sizeof( PackedDecision ) << " " << PACKET_SIZE ); - fti[pd.address] = std::make_pair( pd.left, pd.right ); - } else if ( uint8_t( buffer[0] ) == 0xBB ) { - edc++; - PackedNode pd; - memcpy( &pd, buffer, PACKET_SIZE ); - nodes.emplace( pd.address, std::make_shared( pd.voxNumber, pd.binNumber ) ); - } else { - ERROR( "Packet header: " << std::hex << uint8_t( buffer[0] ) << " not recognised" ); - } - if ( nodes.size() == 1 ) m_top = nodes.begin()->second; - } - INFO( "Read: " << nodes.size() << " nodes from binary file, now re-establishing tree structure; EndNodes=" << edc ); - - for ( auto& node : nodes ) { - Decision* node_ptr = dynamic_cast( node.second.get() ); - if ( node_ptr == nullptr ) continue; - auto child_nodes = fti.find( node.first ); - if ( child_nodes == fti.end() ) { - ERROR( "Child nodes not found!" ); - } - auto pL = nodes.find( child_nodes->second.first ); - auto pR = nodes.find( child_nodes->second.second ); - if ( pL == nodes.end() || pR == nodes.end() ) { - ERROR( "Nodes for " << node_ptr << " not found! success counter " - << " " << child_nodes->second.first << " " << child_nodes->second.second ); - } else { - node_ptr->setChildren( pL->second, pR->second ); - } - } -} - -void BinDT::writeToBinary( std::ofstream& stream ) -{ - AddressCompressor counter; - m_top->visit( [&stream, &counter]( const INode* node ) { - std::array word; - const BinDT::Decision* decision = dynamic_cast( node ); - if ( decision != nullptr ) { - PackedDecision pd; - pd.header = 0xAA; - pd.address = counter[decision]; // uint32_t ( 0xFFFFFFFF & (uint64_t)this ); - pd.index = decision->m_index; - pd.cutVal = decision->m_value; - pd.left = counter[decision->m_left.get()]; // (uint32_t)m_left.get(); - pd.right = counter[decision->m_right.get()]; // (uint32_t)m_right.get(); - memcpy( word.data(), &pd, PACKET_SIZE ); - } else if ( dynamic_cast( node ) != nullptr ) { - const BinDT::EndNode* endNode = dynamic_cast( node ); - PackedNode pd; - pd.header = 0xBB; - pd.address = counter[endNode]; - pd.binNumber = endNode->m_binNumber; - pd.voxNumber = endNode->m_voxNumber; - memcpy( word.data(), &pd, PACKET_SIZE ); - } - stream.write( (char*)( &word ), sizeof( word ) ); - } ); -} - void BinDT::serialize( std::ofstream& output ) { output << std::setprecision( 17 ); @@ -247,7 +154,7 @@ void BinDT::serialize( const std::string& filename ) output.close(); } -std::shared_ptr BinDT::makeNodes( std::vector evts ) +std::shared_ptr BinDT::makeNodes( const std::vector& evts ) { INFO( "Making nodes" ); std::queue iq; @@ -260,8 +167,7 @@ std::shared_ptr BinDT::makeNodes( std::vector evts ) return node; } -std::shared_ptr BinDT::makeNodes( std::vector evts, std::queue indexQueue, - const unsigned int& depth ) +std::shared_ptr BinDT::makeNodes( const std::vector& evts, std::queue indexQueue, const unsigned& depth ) { unsigned int index = indexQueue.front(); DEBUG( "Depth = " << depth << " nodes = " << m_endNodes.size() << " maxDepth = " << m_maxDepth @@ -282,7 +188,7 @@ std::shared_ptr BinDT::makeNodes( std::vector evts, std:: return node; } -std::shared_ptr BinDT::makeNodes( std::vector source, std::vector target ) +std::shared_ptr BinDT::makeNodes( const std::vector& source, const std::vector& target ) { std::queue iq; refreshQueue( source, iq, 0 ); @@ -440,17 +346,6 @@ void BinDT::Decision::setChildren( std::shared_ptr l, std::shared_ptrm_parent = this; } -uint32_t BinDT::AddressCompressor::operator[]( const void* ptr ) -{ - auto it = elements.find( ptr ); - if ( it != elements.end() ) - return it->second; - else { - elements[ptr] = counter++; - return elements[ptr]; - } -} - BinDT::EndNode::EndNode( const unsigned int& no, const unsigned int& binNumber ) : m_voxNumber( no ), m_binNumber( binNumber ) {} @@ -464,7 +359,6 @@ void BinDT::EndNode::serialize( std::ostream& stream ) const const BinDT::EndNode* BinDT::Decision::operator()( const double* evt ) const { -// INFO( m_index << " " << m_value << " " << *(evt+m_index)); return *( evt + m_index ) < m_value ? ( *m_right )( evt ) : ( *m_left )( evt ); } @@ -474,3 +368,4 @@ void BinDT::Decision::visit( const std::function& visit_fun m_left->visit( visit_function ); m_right->visit( visit_function ); } + diff --git a/src/BinaryExpression.cpp b/src/BinaryExpression.cpp index eeb1c5e2d3a..9416412a7ab 100644 --- a/src/BinaryExpression.cpp +++ b/src/BinaryExpression.cpp @@ -18,6 +18,9 @@ DEFINE_BINARY_OPERATOR( Equal ) DEFINE_BINARY_OPERATOR( Pow ) DEFINE_BINARY_OPERATOR( Fmod ) DEFINE_BINARY_OPERATOR( ATan2 ) +DEFINE_BINARY_OPERATOR( GreaterThanEqualTo ) +DEFINE_BINARY_OPERATOR( LessThanEqualTo ) +DEFINE_BINARY_OPERATOR( Or ) template < class condition > std::string bracketed( const Expression& expression, condition&& use_brackets, const ASTResolver* resolver=nullptr ){ @@ -31,15 +34,21 @@ complex_t Divide::operator()() const { return lval() / rval(); } complex_t And::operator()() const { return complex_t(std::real(lval()) && std::real(rval()),0); } complex_t GreaterThan::operator()() const { return complex_t(std::real(lval()) > std::real(rval()) ,0); } complex_t LessThan::operator()() const { return complex_t(std::real(lval()) < std::real(rval()) ,0); } +complex_t GreaterThanEqualTo::operator()() const { return complex_t(std::real(lval()) >= std::real(rval()) ,0); } +complex_t LessThanEqualTo::operator()() const { return complex_t(std::real(lval()) <= std::real(rval()) ,0); } complex_t Pow::operator()() const { return pow( lval(), rval() ); } complex_t Fmod::operator()() const { return 0; } complex_t Equal::operator()() const { return lval() == rval() ; } +complex_t Or::operator()() const { return std::real(lval()) || std::real(rval()) ; } complex_t ATan2::operator()() const { return atan2( std::real(lval() ), std::real(rval() ) ); } -std::string Sum::to_string(const ASTResolver* resolver) const { +std::string Sum::to_string(const ASTResolver* resolver) const +{ return lval.to_string(resolver) + " + " + rval.to_string(resolver) ; } -std::string Sub::to_string(const ASTResolver* resolver) const { + +std::string Sub::to_string(const ASTResolver* resolver) const +{ return lval.to_string(resolver) + "-" + bracketed( rval, [](auto& expression){ return is(expression) || is(expression) ; } , resolver ) ; } std::string Equal::to_string(const ASTResolver* resolver) const { return "(" + lval.to_string(resolver) + " == "+ rval.to_string(resolver) +")"; } @@ -60,11 +69,14 @@ std::string Divide::to_string(const ASTResolver* resolver) const { std::string LessThan::to_string(const ASTResolver* resolver) const { return "(" + lval.to_string(resolver) + "<" + rval.to_string(resolver) +")"; } std::string GreaterThan::to_string(const ASTResolver* resolver) const { return "(" + lval.to_string(resolver) + ">" + rval.to_string(resolver) +")"; } std::string And::to_string(const ASTResolver* resolver) const { return "(" + lval.to_string(resolver) + "&&" + rval.to_string(resolver) +")"; } +std::string LessThanEqualTo::to_string(const ASTResolver* resolver) const { return "(" + lval.to_string(resolver) + "<=" + rval.to_string(resolver) +")"; } +std::string GreaterThanEqualTo::to_string(const ASTResolver* resolver) const { return "(" + lval.to_string(resolver) + ">=" + rval.to_string(resolver) +")"; } +std::string Or::to_string(const ASTResolver* resolver) const { return "(" + lval.to_string(resolver) + "||" + rval.to_string(resolver) +")"; } std::string Pow::to_string(const ASTResolver* resolver) const { return "pow(" + lval.to_string(resolver) + ", " + rval.to_string(resolver) +")"; } std::string Fmod::to_string(const ASTResolver* resolver) const { return "fmod(" + lval.to_string(resolver) + "," + rval.to_string(resolver) +")"; } std::string ATan2::to_string( const ASTResolver* resolver) const { return "atan2("+ lval.to_string(resolver) + "," + rval.to_string(resolver) +")"; } -void IBinaryExpression::resolve( ASTResolver& resolver ) +void IBinaryExpression::resolve( ASTResolver& resolver ) const { lval.resolve( resolver ); rval.resolve( resolver ); diff --git a/src/CacheTransfer.cpp b/src/CacheTransfer.cpp index 04f9edae16b..625ccc8ca1c 100644 --- a/src/CacheTransfer.cpp +++ b/src/CacheTransfer.cpp @@ -9,25 +9,56 @@ using namespace AmpGen; -CacheTransfer::CacheTransfer( const unsigned int& address, const double& value, const size_t& size ) : - m_address(address), m_value(value), m_size(size) {} +CacheTransfer::CacheTransfer() = default; + +CacheTransfer::CacheTransfer( const size_t& address, const std::string& name, const double& value, const size_t& size ) : + m_address(address), + m_size(size), + m_value(value), + m_name(name) +{ +} void CacheTransfer::transfer( CompiledExpressionBase* destination ) { destination->setExternal(m_value, m_address); } -void CacheTransfer::print() const { INFO( m_address << " " << m_value ) ; } + +void CacheTransfer::print() const +{ + INFO( m_address << " " << m_value << " " << m_name ) ; +} void ParameterTransfer::transfer( CompiledExpressionBase* destination ) { destination->setExternal( m_source->mean(), m_address ); } -CacheTransfer::CacheTransfer() : m_address( 0 ), m_value( 0 ) {} +ParameterTransfer::ParameterTransfer(const size_t& address, const std::string& name, MinuitParameter* source ) + : CacheTransfer(address, name, source->mean(), 1), + m_source( source ) +{ +} + +void ParameterTransfer::print() const +{ + INFO( "Source: " << m_source->name() << " address = " << m_address << " value = " << m_source->mean() ); +} + + +LambdaTransfer::LambdaTransfer(const size_t& address, const std::string& name, const LambdaExpression* source ) + : CacheTransfer(address, name, source->m_function(), 1), + m_function(source->m_function) +{ +} + +void LambdaTransfer::transfer( CompiledExpressionBase* destination ) +{ + destination->setExternal( m_function(), m_address ); +} -ParameterTransfer::ParameterTransfer( const unsigned int& address, MinuitParameter* source ) - : m_address( address ), m_source( source ) +void LambdaTransfer::print() const { + INFO( m_name << " = " << m_function() << " address = " << m_address ); } -void ParameterTransfer::print() const { std::cout << this << " " << m_source->name() << " " << m_address << std::endl; INFO( "Source: " << m_source->name() << " address = " << m_address ); } diff --git a/src/Chi2Estimator.cpp b/src/Chi2Estimator.cpp index 58047ad5c4c..6c5ee020aef 100644 --- a/src/Chi2Estimator.cpp +++ b/src/Chi2Estimator.cpp @@ -6,9 +6,9 @@ #include "AmpGen/ArgumentPack.h" #include "AmpGen/EventType.h" #include "AmpGen/MsgService.h" -#include "AmpGen/EventList.h" #include "AmpGen/Event.h" + using namespace AmpGen; struct Moment { @@ -33,26 +33,11 @@ struct Moment { double var() { return N == 0 ? 0 : xx; } }; -Chi2Estimator::Chi2Estimator( const EventList& dataEvents, const EventList& mcEvents, - const std::function& fcn, const unsigned int& minEvents ) : - m_binning( dataEvents, MinEvents( minEvents ), Dim( dataEvents.eventType().dof() ) ) -{ - doChi2( dataEvents, mcEvents, fcn ); -} - -Chi2Estimator::Chi2Estimator( const EventList& dataEvents, const EventList& mcEvents, - const std::function& fcn, const std::string& filename ) : - m_binning( File( filename ) ) -{ - doChi2( dataEvents, mcEvents, fcn ); -} - - double Chi2Estimator::chi2() const { return m_chi2; } double Chi2Estimator::nBins() const { return m_nBins; } void Chi2Estimator::writeBinningToFile( const std::string& filename ) { m_binning.serialize( filename ); } -void Chi2Estimator::doChi2( const EventList& dataEvents, const EventList& mcEvents, +void Chi2Estimator::doChi2( const EventList_type& dataEvents, const EventList_type& mcEvents, const std::function& fcn ) { std::vector data( m_binning.size() ); @@ -63,7 +48,7 @@ void Chi2Estimator::doChi2( const EventList& dataEvents, const EventList& mcEv unsigned int j = 0; double total_data_weight = 0; double total_int_weight = 0; - for ( auto& d : dataEvents ) { + for ( const auto& d : dataEvents ) { if ( j % 1000000 == 0 && j != 0 ) INFO( "Binned " << j << " data events" ); double w = d.weight(); data[m_binning.getBinNumber( d )].add( d.weight() ); @@ -71,10 +56,11 @@ void Chi2Estimator::doChi2( const EventList& dataEvents, const EventList& mcEv j++; } j = 0; - for ( auto& evt : mcEvents ) { + for ( auto& evt : mcEvents ) + { if ( j % 1000000 == 0 && j != 0 ) INFO( "Binned " << j << " sim. events" ); double w = fcn( evt ) * evt.weight() / evt.genPdf(); - mc[m_binning.getBinNumber( evt )].add( w ); + mc[m_binning.getBinNumber(evt)].add( w ); total_int_weight += w; j++; } @@ -90,3 +76,5 @@ void Chi2Estimator::doChi2( const EventList& dataEvents, const EventList& mcEv m_nBins = m_binning.size(); } + + diff --git a/src/CoherenceFactor.cpp b/src/CoherenceFactor.cpp deleted file mode 100644 index 1da28335737..00000000000 --- a/src/CoherenceFactor.cpp +++ /dev/null @@ -1,551 +0,0 @@ -#include "AmpGen/CoherenceFactor.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AmpGen/ArgumentPack.h" -#include "AmpGen/DynamicContainer.h" -#include "AmpGen/Generator.h" -#include "AmpGen/Integrator.h" -#include "AmpGen/MsgService.h" -#include "AmpGen/PhaseSpace.h" -#include "AmpGen/NamedParameter.h" -#include "AmpGen/CompiledExpression.h" -#include "AmpGen/Event.h" -#include "AmpGen/Utilities.h" -#include "TH1.h" - -using namespace AmpGen; - -void HadronicParameters::scale_p1( const real_t& sf ) -{ - n1 /= sf; - coherence /= sqrt( sf ); -} -void HadronicParameters::scale_p2( const real_t& sf ) -{ - n2 /= sf; - coherence /= sqrt( sf ); -} - -void HadronicParameters::rotate( const real_t& angle ) -{ - coherence *= complex_t( cos( angle ), sin( angle ) ); -} - -void HadronicParameters::clear() -{ - n1 = 0; - n2 = 0; - nFills = 0; - id = 0; - wt = 0; - coherence = complex_t( 0, 0 ); -} - -void HadronicParameters::add( const complex_t& f1, - const complex_t& f2, - const real_t& weight ) -{ - n1 += weight * std::norm( f1 ); - n2 += weight * std::norm( f2 ); - wt += weight; - coherence += weight * std::conj(f1) * f2 ; - nFills++; -} - -HadronicParameters::HadronicParameters( const real_t& _R, const real_t& _d, const real_t& k1 ) : - n1(k1*k1), - n2(1), - wt(1), - coherence(k1*_R*cos( M_PI*_d/180.), k1*_R*sin(M_PI*_d/180.)) {} - -HadronicParameters::HadronicParameters( const real_t& _R, const real_t& _d, const real_t& k1, const real_t& k2 ) - : n1( k1 ), - n2( k2 ), - wt(1), - coherence( sqrt( k1 * k2 ) * _R * cos( _d ), sqrt( k1 * k2 ) * _R * sin( _d ) ) {} - -HadronicParameters HadronicParameters::operator+=( const HadronicParameters& other ) -{ - n1 += other.n1; - n2 += other.n2; - coherence += other.coherence; - nFills += other.nFills; - wt += other.wt; - return *this; -} - -HadronicParameters HadronicParameters::operator-=( const HadronicParameters& other ) -{ - n1 -= other.n1; - n2 -= other.n2; - coherence -= other.coherence; - nFills -= other.nFills; - wt -= other.wt; - return *this; -} -HadronicParameters AmpGen::operator+( const HadronicParameters& a, const HadronicParameters& b ) -{ - HadronicParameters hp; - hp.wt = a.wt + b.wt; - hp.n1 = a.n1 + b.n1 ; - hp.n2 = a.n2 + b.n2 ; - hp.coherence = a.coherence + b.coherence ; - hp.nFills = a.nFills + b.nFills; - return hp; -} - -std::string HadronicParameters::to_string() const -{ - auto c = getCoherence(); - std::string total = "R = " + round( R() , 3 ) + " δ = " + round( 180 * d() / M_PI, 2 ) + - " r = " + round( r(), 4 ) + " K = " + round( I1() , 6 ) + " K' = " + round( I2(), 6 ) + " N = " + - std::to_string( wt ) + " ci = " + std::to_string( std::real( c ) ) + " si = " + - std::to_string( std::imag( c ) ) ; - return total; -} - -void CoherenceFactor::makeCoherentMapping( const unsigned int& nBins, - const std::function( const Event& )>& functors, - const size_t& maxDepth, - const size_t& minPop, - const std::function& flagFunctor, - const bool& refreshEvents ) -{ - m_nBins = nBins; - - if ( m_data != nullptr ) { - m_voxels = BinDT( *m_data, Functor( functors ), MinEvents( minPop ) ); - return; - } - if( !refreshEvents ){ - groupByStrongPhase({},false); - return; - } - - size_t population = pow( 2, maxDepth ) * 1.2 * minPop; /// 20 % safety factor /// - Generator<> phsp( m_type ); - phsp.setRandom( new TRandom3() ); - size_t counter = 0; - int otherCounter = 0; - size_t blockSize = 1 * pow( 10, 5 ); - auto makeEvents = [&]( EventList& eventList ) { - bool useFlatEvents = NamedParameter ("CoherenceFactor::FlatEvents",true); - if( useFlatEvents ) phsp.fillEventListPhaseSpace( eventList, blockSize, 0); - else phsp.fillEventList( *m_pdf2, eventList, blockSize ); - - eventList.resetCache(); - - m_pdf1->reset( true ); - m_pdf2->reset( true ); - m_pdf1->setEvents( eventList ); - m_pdf2->setEvents( eventList ); - m_pdf1->prepare(); - m_pdf2->prepare(); - counter += blockSize; - INFO( "Generated: " << counter << " DT events (out of " << population - << " requested); [evt counter=" << otherCounter << "]" ); - }; - DynamicContainer dlist( population, makeEvents ); - std::vector DTevents( population ); - std::vector addresses; - std::vector addresses_veto; - for ( auto evt : dlist ) { - auto& te = DTevents[otherCounter++]; - te.weight = 1./evt.genPdf(); - te.amp1 = m_pdf1->getVal( evt ); - te.amp2 = m_pdf2->getVal( evt ); - auto coords = functors( evt ); - for ( unsigned int i = 0; i < 5; ++i ) - te.values[i] = coords[i]; - if ( flagFunctor != nullptr && flagFunctor( evt ) ) { - te.flag = true; - addresses_veto.push_back( te.values.data() ); - } else { - addresses.push_back( te.values.data() ); - } - } - m_voxels = BinDT( addresses, Functor( functors ), MaxDepth( maxDepth ), MinEvents( minPop ) ); - - INFO( "Generated " << dlist.size() - << " events; entries per node = " << real_t( dlist.size() ) / real_t( m_voxels.nodes().size() ) ); - groupByStrongPhase( DTevents , true ); -} - -void CoherenceFactor::makeCoherentMapping( const unsigned int& nBins, const BinDT& binDT ) -{ - m_voxels = binDT; - m_nBins = nBins; - groupByStrongPhase(); -} - -void CoherenceFactor::calculateCoherenceFactorsPerVoxel() -{ - m_paramsPerVoxel.clear(); - m_paramsPerVoxel.resize( m_voxels.size() + 1 ); - for ( unsigned int i = 0; i < m_paramsPerVoxel.size(); ++i ) m_paramsPerVoxel[i].id = i; - auto pdf1CacheMap = m_pdf1->cacheAddresses( *m_data ); - auto pdf2CacheMap = m_pdf2->cacheAddresses( *m_data ); - - TH1D* deltaPhaseWeightPdf1 = new TH1D( "deltaPhi1","",100,-180,180); - TH1D* deltaPhaseWeightPdf2 = new TH1D( "deltaPhi2","",100,-180,180); - TH1D* deltaPhaseNoWeight = new TH1D( "deltaPhase0","",100,-180,180); - for ( auto& evt : *m_data ) { - int binNumber = m_voxels.getBinNumber( evt ); - real_t w = evt.weight() / evt.genPdf(); - complex_t p1 = m_pdf1->getVal( evt, pdf1CacheMap ); - complex_t p2 = m_pdf2->getVal( evt, pdf2CacheMap ); - real_t arg = std::arg( p1* std::conj(p2 ) ); - deltaPhaseWeightPdf1->Fill( arg * 180 / M_PI, std::abs(p1) ); - deltaPhaseWeightPdf2->Fill( arg * 180 / M_PI, std::abs(p2) ); - deltaPhaseNoWeight->Fill( arg * 180 / M_PI, 1 ); - m_paramsPerVoxel[binNumber].add( p1, p2, w ); - } - deltaPhaseWeightPdf1->Write(); - deltaPhaseWeightPdf2->Write(); - deltaPhaseNoWeight->Write(); -} - -void CoherenceFactor::calculateCoherenceFactorsPerVoxel( const std::vector& dtEvents ) -{ - m_paramsPerVoxel.clear(); - m_paramsPerVoxel.resize( m_voxels.size() + 1 ); - INFO( "h-Voxels = " << m_voxels.size() << " associating with ids" ); - for ( unsigned int i = 0; i < m_paramsPerVoxel.size(); ++i ) m_paramsPerVoxel[i].id = i; - - TH1D* deltaPhaseNoWeight = new TH1D( "deltaPhi0","",100,-180,180); - TH1D* deltaPhaseWeightVN = new TH1D( "deltaVPhiN","",100,-180,180); - TH1D* weight = new TH1D("weight","",100,0,100); - - HadronicParameters hG; - for ( auto& evt : dtEvents ) { - unsigned int binNumber = evt.flag ? m_voxels.size() : m_voxels.getBinNumber( evt.values.data() ); - DEBUG( "BinNumber: " << binNumber << " pos = {" << evt.values[0] << "," << evt.values[1] << "," << evt.values[2] - << "," << evt.values[3] << "," << evt.values[4] << "}" ); - real_t arg = std::arg( std::conj(evt.amp1) * evt.amp2 ); - deltaPhaseNoWeight->Fill( arg * 180 / M_PI, 1 ); - weight->Fill( evt.weight ); - m_paramsPerVoxel[binNumber].add( evt.amp1, evt.amp2, evt.weight ); - hG.add( evt.amp1, evt.amp2, evt.weight ); - } - INFO( hG.to_string() ); - for( auto& v : m_paramsPerVoxel ) deltaPhaseWeightVN->Fill( v.d()*180/M_PI, 1 ); - deltaPhaseNoWeight->Write(); - deltaPhaseWeightVN->Write(); - weight->Write(); -} - -void CoherenceFactor::groupByStrongPhase( const std::vector& coherenceEvent, const bool& recalculateVoxels ) -{ - if( recalculateVoxels ){ - if ( m_data != nullptr ) - calculateCoherenceFactorsPerVoxel(); - else - calculateCoherenceFactorsPerVoxel( coherenceEvent ); - } - INFO( "Got " << m_voxels.size() << " voxels" ); - HadronicParameters global_hp; - for ( auto& h : m_paramsPerVoxel ) global_hp += h; - - INFO( "Global parameters = " << global_hp.to_string() ); - real_t phiTransform = m_globalPhase - global_hp.d(); - real_t rTransform = m_globalR * m_globalR * global_hp.n2 / global_hp.n1; - - INFO( "Global rotation = " << phiTransform * 180 / M_PI ); - for ( auto& h : m_paramsPerVoxel ) { - h.scale_p1( 1. / rTransform ); - h.rotate( phiTransform ); - } - INFO( "Transform = " << sqrt( rTransform ) << " ; phi = " << phiTransform ); - - HadronicParameters global_hp_new = std::accumulate( m_paramsPerVoxel.begin(), m_paramsPerVoxel.end() - 1, HadronicParameters() ); - INFO( global_hp_new.to_string() ); - std::sort( m_paramsPerVoxel.begin(), m_paramsPerVoxel.end() - 1, []( auto& b1, auto& b2 ) { return b1.d() < b2.d(); } ); - - real_t norm_target = global_hp_new.wt / real_t( m_nBins ); - unsigned int currentBin = 0; - std::vector> binLimits; - binLimits.emplace_back( -M_PI, 0 ); - INFO( "Normalisation-per-bin = " << norm_target << " i1 = " << global_hp_new.I1() ); - auto currentBinLimits = binLimits.rbegin(); - HadronicParameters hp_accumulator, glob_vox_test; - - for( auto ihp = m_paramsPerVoxel.begin(); ihp != m_paramsPerVoxel.end() - 1; ++ihp ) { - ihp->binID = currentBin; - m_nodeID2Bin[ihp->id] = currentBin; - hp_accumulator += *ihp; - if ( hp_accumulator.wt > norm_target ) { - currentBinLimits->second = ihp->d(); - currentBin++; - binLimits.emplace_back( ihp->d(), 0 ); - currentBinLimits = binLimits.rbegin(); - glob_vox_test += hp_accumulator; - hp_accumulator.clear(); - } - } - INFO("Generated: " << currentBin << " bins"); - glob_vox_test += hp_accumulator; - m_paramsPerVoxel.rbegin()->binID = m_nBins; // allocate veto bin /// - // for( auto& bin : m_para - // INFO( "[ " << currentBin + 1 << " ] " << hp_test.to_string() ); - INFO( "[ VETO ] " << m_paramsPerVoxel.rbegin()->to_string() ); - INFO( "[ NO VETO ] " << glob_vox_test.to_string() ); - - glob_vox_test += *m_paramsPerVoxel.rbegin(); - INFO( "[SUM VOXELS] " << global_hp_new.to_string() ); - INFO( "[SUM BINS ] " << glob_vox_test.to_string() ); - if( recalculateVoxels && m_data == nullptr ) MakeEventDeltaPlots( coherenceEvent ); - // for ( auto& limits : binLimits ) { - // INFO( "Bin Limits [" << limits.first << ", " << limits.second << "]" ); - // } -} - -void CoherenceFactor::MakeEventDeltaPlots( const std::vector& events ) { - - std::vector plots; - for(size_t i = 0 ; i < m_nBins ; ++i ) - plots.push_back( new TH1D( ("Bin_"+std::to_string(i)+"_deltaPhi").c_str(),0,100,-180,180) ); - for( auto& event : events ){ - unsigned int voxNumber = event.flag ? m_voxels.size() : m_voxels.getBinNumber( event.values.data() ); - real_t arg = std::arg( std::conj(event.amp1) * event.amp2 ); - auto binNumber = m_nodeID2Bin[ voxNumber ]; - if( ! event.flag ) plots[binNumber]->Fill( arg*180/M_PI ); - } - for( auto& plot : plots ) plot->Write(); -} - - - -void CoherenceFactor::testCoherenceFactor() const -{ - - BinnedIntegrator<8> bid( m_data ); - bid.setView( [this]( auto& evt ) { return this->getBinNumber( evt ); } ); - std::vector calcs( 8, CoherenceCalculator( m_pdf1, m_pdf2 ) ); - - size_t PDF1_size = m_pdf1->size(); - size_t PDF2_size = m_pdf2->size(); - for ( unsigned int i = 0; i < PDF1_size; ++i ) { - for ( unsigned int j = 0; j < PDF2_size; ++j ) { - bid.addIntegral( ( *m_pdf1 )[i].pdf, ( *m_pdf2 )[j].pdf, [i, j, &calcs]( const auto& val ) { - for ( unsigned int bin = 0; bin < 8; ++bin ) calcs[bin].R.set( i, j, val[bin] ); - } ); - } - } - for ( unsigned int i = 0; i < PDF1_size; ++i ) { - for ( unsigned int j = i; j < PDF1_size; ++j ) { - bid.addIntegral( ( *m_pdf1 )[i].pdf, ( *m_pdf1 )[j].pdf, [i, j, &calcs]( const auto& val ) { - for ( unsigned int bin = 0; bin < 8; ++bin ) { - calcs[bin].N1.set( i, j, val[bin] ); - if ( i != j ) calcs[bin].N1.set( j, i, std::conj( val[bin] ) ); - } - } ); - } - } - for ( unsigned int i = 0; i < PDF2_size; ++i ) { - for ( unsigned int j = i; j < PDF2_size; ++j ) { - bid.addIntegral( ( *m_pdf2 )[i].pdf, ( *m_pdf2 )[j].pdf, [i, j, &calcs]( const auto& val ) { - for ( unsigned int bin = 0; bin < 8; ++bin ) { - calcs[bin].N2.set( i, j, val[bin] ); - if ( i != j ) calcs[bin].N2.set( j, i, std::conj( val[bin] ) ); - } - } ); - } - } - bid.flush(); - - for ( unsigned int i = 0; i < 8; ++i ) { - complex_t VALUE = calcs[i].getVal(); - INFO( "Bin [" << i + 1 << "] R=" << std::abs( VALUE ) << " d= " << 180 * std::arg( VALUE ) / M_PI - << " N1= " << calcs[i].getN1() << " N2= " << calcs[i].getN2() ); - } -} - -std::vector CoherenceFactor::getCoherenceFactors() const -{ - std::vector R( m_nBins + 1 ); - HadronicParameters RG; - auto pdf1CacheMap = m_pdf1->cacheAddresses( *m_data ); - auto pdf2CacheMap = m_pdf2->cacheAddresses( *m_data ); - for ( auto& evt : *m_data ) { - unsigned int binNumber = getBinNumber( evt ); - real_t w = evt.weight() / evt.genPdf(); - complex_t p1 = m_pdf1->getVal( evt, pdf1CacheMap ); - complex_t p2 = m_pdf2->getVal( evt, pdf2CacheMap ); - R[binNumber].add( p1, p2, w ); - RG.add( p1, p2, w ); - } - real_t phiTransform = m_globalPhase - std::arg( RG.coherence ); - real_t rTransform = m_globalR * m_globalR * RG.n2 / RG.n1; - for ( auto& h : R ) { - h.scale_p1( 1. / rTransform ); - h.rotate( phiTransform ); - } - INFO( RG.to_string() ); - return R; -} - -std::vector CoherenceFactor::getCoherenceFactorsFast() const -{ - - std::vector coherence_factors( m_nBins + 1 ); - for ( auto hp = m_paramsPerVoxel.begin(); hp != m_paramsPerVoxel.end() - 1; ++hp ) { - coherence_factors[hp->binID] += *hp; - } - coherence_factors[m_nBins] = *m_paramsPerVoxel.rbegin(); - return coherence_factors; -} - -std::vector CoherenceFactor::getNumberOfEventsInEachBin( const EventList& events ) const -{ - - std::vector counter( m_nBins + 1, 0 ); - for ( auto& event : events ) { - counter[getBinNumber( event )]++; - } - return counter; -} - -CoherenceFactor::CoherenceFactor( const std::string& filename ) { readBinsFromFile( filename ); } - -void CoherenceFactor::readBinsFromFile( const std::string& binName ) -{ - INFO( "Reading file = " << binName ); - m_voxels = BinDT( File( binName ) ); - m_nBins = 0; - for ( auto& node : m_voxels.nodes() ) { - m_nodeID2Bin[node->voxNumber()] = node->binNumber(); - if ( node->binNumber() != 999 && node->binNumber() >= m_nBins ) m_nBins = node->binNumber() + 1; - } - INFO( "Got " << m_nBins << " coherent bins and " << m_voxels.size() << " voxels" ); -} - -real_t CoherenceFactor::phase() { return std::arg( m_global.getCoherence() ); } -real_t CoherenceFactor::getR() { return std::abs( m_global.getCoherence() ); } - -HadronicParameters CoherenceFactor::calculateGlobalCoherence( EventList* _data ) -{ - m_global.clear(); - bool freshData = false; - if ( _data == nullptr ) { - _data = new EventList( m_type ); - PhaseSpace phsp( m_type ); - phsp.setRandom( new TRandom3() ); - for ( unsigned int i = 0; i < 1e6; ++i ) _data->push_back( phsp.makeEvent( m_pdf1->size() + m_pdf2->size() ) ); - freshData = true; - } - m_pdf1->setMC( *_data ); - m_pdf2->setMC( *_data ); - m_pdf1->prepare(); - m_pdf2->prepare(); - auto pdf1CacheMap = m_pdf1->cacheAddresses( *_data ); - auto pdf2CacheMap = m_pdf2->cacheAddresses( *_data ); - for ( unsigned int i = 0; i < _data->size(); ++i ) { - const Event& evt = ( *_data )[i]; - real_t w = evt.weight() / evt.genPdf(); - complex_t pdf1 = m_pdf1->getVal( evt, pdf1CacheMap ); - complex_t pdf2 = m_pdf2->getVal( evt, pdf2CacheMap ); - m_global.add( pdf1, pdf2, w ); - } - - if ( freshData ) delete _data; - return m_global; -} - -void CoherenceFactor::writeToFile( const std::string& filename ) -{ - auto endNodes = m_voxels.nodes(); - for ( auto& node : endNodes ) { - node->setBinNumber( m_nodeID2Bin[node->voxNumber()] ); - } - m_voxels.serialize( filename ); -} - -HadronicParameters CoherenceFactor::getVal() const { return m_global; } -CoherenceFactor::CoherenceFactor() = default; - -CoherenceFactor::CoherenceFactor( CoherentSum* pdf1, CoherentSum* pdf2, EventList* data ) - : m_pdf1( pdf1 ), m_pdf2( pdf2 ), m_calc( pdf1, pdf2 ), m_data( data ) -{ - if ( m_data != nullptr ) { - calculateGlobalCoherence( m_data ); - calculateNorms(); - m_type = m_data->eventType(); - } -} - -CoherenceFactor::CoherenceFactor( CoherentSum* pdf1, CoherentSum* pdf2, const EventType& type ) - : m_pdf1( pdf1 ), m_pdf2( pdf2 ), m_calc( pdf1, pdf2 ), m_data( nullptr ), m_type( type ) -{ -} - -void CoherenceFactor::calculateNorms() -{ - Integrator<10> id( m_data ); - for ( unsigned int i = 0; i < m_pdf1->size(); ++i ) { - for ( unsigned int j = 0; j < m_pdf2->size(); ++j ) { - id.addIntegral( ( *m_pdf1 )[i].pdf, ( *m_pdf2 )[j].pdf, - [i, j, this]( const complex_t& val ) { this->m_calc.R.set( i, j, val ); } ); - } - } - - for ( unsigned int i = 0; i < m_pdf1->size(); ++i ) { - for ( unsigned int j = i; j < m_pdf1->size(); ++j ) { - id.addIntegral( ( *m_pdf1 )[i].pdf, ( *m_pdf1 )[j].pdf, [i, j, this]( const complex_t& val ) { - this->m_calc.N1.set( i, j, val ); - if ( i != j ) this->m_calc.N1.set( j, i, std::conj( val ) ); - } ); - } - } - - for ( unsigned int i = 0; i < m_pdf2->size(); ++i ) { - for ( unsigned int j = i; j < m_pdf2->size(); ++j ) { - id.addIntegral( ( *m_pdf2 )[i].pdf, ( *m_pdf2 )[j].pdf, [i, j, this]( const complex_t& val ) { - this->m_calc.N2.set( i, j, val ); - if ( i != j ) this->m_calc.N2.set( j, i, std::conj( val ) ); - } ); - } - } - - id.flush(); -} - -std::vector CoherentSum::cacheAddresses( const EventList& evts ) const -{ - std::vector addresses; - for ( auto& mE : m_matrixElements ) { - addresses.push_back( evts.getCacheIndex( mE.pdf ) ); - } - return addresses; -} - -complex_t CoherentSum::getVal( const Event& evt ) const -{ - complex_t value( 0., 0. ); - for ( auto& mE : m_matrixElements ) { - value += mE.coefficient * evt.getCache( mE.addressData ); - } - return value; -} - -complex_t CoherentSum::getVal( const Event& evt, const std::vector& cacheAddresses ) const -{ - complex_t value( 0., 0. ); - for ( unsigned int i = 0; i < m_matrixElements.size(); ++i ) - value += m_matrixElements[i].coefficient * evt.getCache( cacheAddresses[i] ); - return value; -} - -unsigned int CoherenceFactor::getBinNumber( const Event& event ) const -{ - int voxelID = m_voxels.getBinNumber( event ); - return voxelID == -1 ? m_nBins : m_nodeID2Bin.find( voxelID )->second; -} -real_t CoherenceFactor::operator()() { return std::abs( m_calc.getVal() ); } diff --git a/src/CoherentSum.cpp b/src/CoherentSum.cpp index 6acaf88989b..0465febdbf2 100644 --- a/src/CoherentSum.cpp +++ b/src/CoherentSum.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "AmpGen/CompiledExpression.h" #include "AmpGen/ErrorPropagator.h" @@ -24,128 +25,113 @@ #include "AmpGen/CompilerWrapper.h" #include "AmpGen/ThreadPool.h" #include "AmpGen/ProfileClock.h" +#include "AmpGen/simd/utils.h" -#ifdef __USE_OPENMP__ +#ifdef _OPENMP #include #endif using namespace AmpGen; +CoherentSum::CoherentSum() = default; CoherentSum::CoherentSum( const EventType& type, const MinuitParameterSet& mps, const std::string& prefix ) - : m_protoAmplitudes( mps ) - , m_evtType( type ) - , m_printFreq(NamedParameter( "CoherentSum::PrintFrequency", 100) ) - , m_dbThis (NamedParameter( "CoherentSum::Debug" , false)) - , m_verbosity(NamedParameter( "CoherentSum::Verbosity" , 0) ) - , m_objCache (NamedParameter("CoherentSum::ObjectCache" ,"") ) - , m_prefix( prefix ) + : m_rules (mps) + , m_evtType (type) + , m_printFreq(NamedParameter( "CoherentSum::PrintFrequency", 100) ) + , m_dbThis (NamedParameter( "CoherentSum::Debug" , false)) + , m_verbosity(NamedParameter( "CoherentSum::Verbosity" , 0) ) + , m_objCache (NamedParameter("CoherentSum::ObjectCache" ,"") ) + , m_prefix (prefix) + , m_mps(&mps) { - auto amplitudes = m_protoAmplitudes.getMatchingRules( m_evtType, prefix); - for( auto& amp : amplitudes ) addMatrixElement( amp, mps ); - m_isConstant = isFixedPDF(mps); - m_normalisations.resize( m_matrixElements.size(), m_matrixElements.size() ); - ThreadPool tp(8); - for( auto& mE: m_matrixElements ) - tp.enqueue( [&]{ CompilerWrapper().compile( mE.pdf, this->m_objCache); } ); -} - -void CoherentSum::addMatrixElement( std::pair& particleWithCouplingConstant, const MinuitParameterSet& mps ) -{ - auto& protoParticle = particleWithCouplingConstant.first; - auto& coupling = particleWithCouplingConstant.second; - if ( !protoParticle.isStateGood() ) return; - const std::string name = protoParticle.uniqueString(); - DebugSymbols dbExpressions; - INFO( name ); - for ( auto& mE : m_matrixElements ) { - if ( name == mE.decayTree.uniqueString() ) return; + auto amplitudes = m_rules.getMatchingRules( m_evtType, prefix); + if( amplitudes.size() == 0 ){ + WARNING("The defined amplitudes don't seem to be able to be able to generate eventType: " << type); + } + for( auto& amp : amplitudes ) INFO( amp.first.decayDescriptor() ); + m_matrixElements.resize( amplitudes.size() ); + m_normalisations.resize( m_matrixElements.size(), m_matrixElements.size() ); + size_t nThreads = NamedParameter ("nCores" , std::thread::hardware_concurrency(), "Number of threads to use" ); + ThreadPool tp(nThreads); + for(size_t i = 0; i < m_matrixElements.size(); ++i){ + tp.enqueue( [i,this,&mps,&litudes]{ + auto& [p, c] = amplitudes[i]; + DebugSymbols db; + m_matrixElements[i] = + TransitionMatrix(p, c, + CompiledExpression( p.getExpression(m_dbThis ? &db : nullptr), p.decayDescriptor(), + this->m_evtType.getEventFormat(), db, &mps ) ); + CompilerWrapper().compile( m_matrixElements[i], this->m_objCache); + } ); } - m_matrixElements.emplace_back(protoParticle, coupling, mps, m_evtType.getEventFormat(), m_dbThis); } void CoherentSum::prepare() { - if ( m_weightParam != nullptr ) m_weight = m_weightParam->mean(); - if ( m_isConstant && m_prepareCalls != 0 ) return; transferParameters(); - - std::vector changedPdfIndices; ProfileClock clockEval; - bool printed = false; - - for ( unsigned int i = 0; i < m_matrixElements.size(); ++i ) { - auto& pdf = m_matrixElements[i].pdf; - pdf.prepare(); - if ( m_prepareCalls != 0 && !pdf.hasExternalsChanged() ) continue; - ProfileClock clockThisElement; - if ( m_events != nullptr ) { - if ( m_matrixElements[i].addressData == 999 ) - m_matrixElements[i].addressData = m_events->registerExpression( pdf ); - m_events->updateCache( pdf, m_matrixElements[i].addressData ); - } - else if ( i == 0 && m_verbosity ) WARNING( "No data events specified for " << this ); - clockThisElement.stop(); - if ( m_verbosity && ( m_prepareCalls > m_lastPrint + m_printFreq || m_prepareCalls == 0 ) ) { - INFO( pdf.name() << " (t = " << clockThisElement << " ms, nCalls = " << m_prepareCalls << ", events = " << m_events->size() << ")" ); - printed = true; - } - changedPdfIndices.push_back(i); - pdf.resetExternals(); + for (auto& t : m_matrixElements ) { + t.prepare(); + if ( m_prepareCalls != 0 && !t.hasExternalsChanged() ) continue; + if ( m_events != nullptr ) m_cache.update(m_events->store(), t ); + m_integrator.updateCache(t); + t.resetExternals(); + t.workToDo = true; } clockEval.stop(); ProfileClock clockIntegral; - if ( m_integrator.isReady()) updateNorms( changedPdfIndices ); + if (m_integrator.isReady()) updateNorms(); else if ( m_verbosity ) WARNING( "No simulated sample specified for " << this ); - - m_norm = norm(); - if ( m_verbosity && printed ) { - clockIntegral.stop(); + clockIntegral.stop(); + if ( m_verbosity && m_prepareCalls % 100 == 0 ) { INFO( "Time Performance: " << "Eval = " << clockEval << " ms" << ", Integral = " << clockIntegral << " ms" << ", Total = " << clockEval + clockIntegral << " ms; normalisation = " << m_norm ); m_lastPrint = m_prepareCalls; } + for( auto& t : m_matrixElements ) t.workToDo = false; m_prepareCalls++; } -void CoherentSum::updateNorms( const std::vector& changedPdfIndices ) +void CoherentSum::updateNorms() { - for ( auto& i : changedPdfIndices ) m_integrator.prepareExpression( m_matrixElements[i].pdf ); - std::vector cacheIndex; - for( auto& m : m_matrixElements ) - cacheIndex.push_back( m_integrator.events().getCacheIndex( m.pdf ) ); - for ( auto& i : changedPdfIndices ) - for ( size_t j = 0; j < size(); ++j ) - m_integrator.queueIntegral( cacheIndex[i], cacheIndex[j] ,i, j, &m_normalisations ); + if(std::any_of(m_matrixElements.begin(),m_matrixElements.end(), [](auto& me){ return me.workToDo; } )) + { + for ( unsigned i = 0; i != m_matrixElements.size(); ++i ) + for ( size_t j = i; j < size(); ++j ){ + if( m_matrixElements[i].workToDo || m_matrixElements[j].workToDo ) + m_normalisations.get(i, j, &m_integrator, i, j); + } + } m_integrator.flush(); m_normalisations.resetCalculateFlags(); + m_norm = norm(); } void CoherentSum::debug( const Event& evt, const std::string& nameMustContain ) { prepare(); - for ( auto& pdf : m_matrixElements ) pdf.pdf.resetExternals(); - if ( nameMustContain == "" ) - for ( auto& pdf : m_matrixElements ) { - auto A = pdf(evt); - INFO( std::setw(70) << pdf.decayTree.uniqueString() << " A = [ " - << std::real(A) << " " << std::imag(A) << " ] g = [ " - << std::real(pdf.coupling()) << " " << std::imag(pdf.coupling()) << " ]" ); - if( m_dbThis ) pdf.pdf.debug( evt ); - } - else - for ( auto& pdf : m_matrixElements ) - if ( pdf.pdf.name().find( nameMustContain ) != std::string::npos ) pdf.pdf.debug( evt ); + INFO("Weight = " << evt.weight() << " genPDF = " << evt.genPdf() ); - INFO( "Pdf = " << prob_unnormalised( evt ) ); + for ( auto& me : m_matrixElements ) { + auto A = me(evt); + INFO( std::setw(70) << me.decayTree.uniqueString() + << " A = [ " << utils::get<0>(A.real()) << " " << utils::get<0>(A.imag()) + << " ] g = [ "<< me.coupling().real() << " " << me.coupling().imag() << " ] " + << m_cache( evt.index(), std::distance(&m_matrixElements[0], &me ) ) + << me.decayTree.CP() ); + } + if( m_dbThis ) for ( auto& me : m_matrixElements ) me.debug( evt) ; + INFO( "A(x) = " << getVal(evt) << " without cache: " << getValNoCache(evt) ); } std::vector CoherentSum::fitFractions(const LinearErrorPropagator& linProp) { + prepare(); bool recomputeIntegrals = NamedParameter("CoherentSum::RecomputeIntegrals", false ); std::vector outputFractions; - for(auto& rule : m_protoAmplitudes.rules()) + for(auto& rule : m_rules.rules()) { FitFractionCalculator pCalc(this, findIndices(m_matrixElements, rule.first), recomputeIntegrals); for(auto& process : rule.second) @@ -157,17 +143,17 @@ std::vector CoherentSum::fitFractions(const LinearErrorPropagator& } if( pCalc.calculators.size() == 0 ) continue; auto fractions = pCalc(rule.first, linProp); - for( auto& f : fractions ) outputFractions.emplace_back(f); + std::transform( fractions.begin(), fractions.end(), std::back_inserter(outputFractions),[](auto& p){ return p;} ); }; - auto ffForHead = m_protoAmplitudes.rulesForDecay(m_evtType.mother(), m_prefix); + auto ffForHead = m_rules.rulesForDecay(m_evtType.mother(), m_prefix); FitFractionCalculator iCalc(this, findIndices(m_matrixElements, m_evtType.mother()), recomputeIntegrals); for ( size_t i = 0; i < ffForHead.size(); ++i ) { for ( size_t j = i + 1; j < ffForHead.size(); ++j ) { iCalc.emplace_back(ffForHead[i].name() + "x" + ffForHead[j].name(), - processIndex(m_matrixElements, ffForHead[i].name()), - processIndex(m_matrixElements, ffForHead[j].name()) ); + processIndex(m_matrixElements, ffForHead[i].name()), + processIndex(m_matrixElements, ffForHead[j].name()) ); } } std::vector interferenceFractions = iCalc(m_evtType.mother()+"_interference",linProp); @@ -176,7 +162,7 @@ std::vector CoherentSum::fitFractions(const LinearErrorPropagator& return outputFractions; } -void CoherentSum::generateSourceCode( const std::string& fname, const double& normalisation, bool add_mt ) +void CoherentSum::generateSourceCode(const std::string& fname, const double& normalisation, bool add_mt) { std::ofstream stream( fname ); transferParameters(); @@ -186,32 +172,34 @@ void CoherentSum::generateSourceCode( const std::string& fname, const double& no stream << "#include \n"; if ( add_mt ) stream << "#include \n"; bool includePythonBindings = NamedParameter("CoherentSum::IncludePythonBindings",false); - bool enableCuda = NamedParameter("CoherentSum::EnableCuda",false); for ( auto& p : m_matrixElements ){ - stream << p.pdf << std::endl; - if( ! enableCuda ) p.pdf.compileWithParameters( stream ); - if( includePythonBindings ) p.pdf.compileDetails( stream ); + auto expr = CompiledExpression( + p.expression(), + p.decayDescriptor(), + m_evtType.getEventFormat(), DebugSymbols(), disableBatch(), m_mps ); + expr.prepare(); + stream << expr << std::endl; + expr.compileWithParameters( stream ); + if( includePythonBindings ) p.compileDetails( stream ); } - Expression event = Parameter("x0",0,true,0); - Expression pa = Parameter("double(x1)",0,true,0); + Expression event = Parameter("x0",0,true); + Expression pa = Parameter("double(x1)",0,true); Expression amplitude; for( unsigned int i = 0 ; i < size(); ++i ){ auto& p = m_matrixElements[i]; - Expression this_amplitude = p.coupling() * Function( programatic_name( p.pdf.name() ) + "_wParams", {event} ); + Expression this_amplitude = p.coupling() * Function( programatic_name( p.name() ) + "_wParams", {event} ); amplitude = amplitude + ( p.decayTree.finalStateParity() == 1 ? 1 : pa ) * this_amplitude; } - if( !enableCuda ){ - stream << CompiledExpression< std::complex, const double*, int>( amplitude , "AMP" ) << std::endl; - stream << CompiledExpression< double, const double*, int>(fcn::norm(amplitude) / normalisation, "FCN" ) << std::endl; - } + stream << CompiledExpression(const double*, const int&)>( amplitude , "AMP", disableBatch() ) << std::endl; + stream << CompiledExpression(fcn::norm(amplitude) / normalisation, "FCN", disableBatch() ) << std::endl; if( includePythonBindings ){ - stream << CompiledExpression< unsigned int >( m_matrixElements.size(), "matrix_elements_n" ) << std::endl; - stream << CompiledExpression< double > ( normalisation, "normalization") << std::endl; + stream << CompiledExpression( m_matrixElements.size(), "matrix_elements_n" ) << std::endl; + stream << CompiledExpression( normalisation, "normalization") << std::endl; stream << "extern \"C\" const char* matrix_elements(int n) {\n"; for ( size_t i = 0; i < m_matrixElements.size(); i++ ) { - stream << " if(n ==" << i << ") return \"" << m_matrixElements.at(i).pdf.progName() << "\" ;\n"; + stream << " if(n ==" << i << ") return \"" << m_matrixElements.at(i).progName() << "\" ;\n"; } stream << " return 0;\n}\n"; stream << "extern \"C\" void FCN_all(double* out, double* events, unsigned int size, int parity, double* amps){\n"; @@ -233,25 +221,10 @@ void CoherentSum::generateSourceCode( const std::string& fname, const double& no int parity = p.decayTree.finalStateParity(); if ( parity == -1 ) stream << "double(parity) * "; stream << "std::complex(amps[" << i * 2 << "],amps[" << i * 2 + 1 << "]) * "; - stream << programatic_name( p.pdf.name() )<< "_wParams( E )"; + stream << programatic_name( p.name() )<< "_wParams( E )"; stream << ( i == size() - 1 ? ";" : " +" ) << "\n"; } stream << " out[i] = std::norm(amplitude) / " << normalisation << ";\n }\n}\n"; - stream << "extern \"C\" void FCN_mt(double* out, double* events, unsigned int size, int parity, double* amps){\n"; - stream << " unsigned int n = std::thread::hardware_concurrency();\n"; - stream << " unsigned int batch_size = size / n;\n"; - stream << " std::vector threads;\n"; - stream << " for(size_t i=0; im_events )[0].size() - << ", len, parity, amps);\n"; - stream << " }\n"; - stream << " for(auto &thread : threads)\n"; - stream << " thread.join();\n"; - stream << "}\n\n"; stream << "extern \"C\" double coefficients( int n, int which, int parity){\n"; for ( size_t i = 0; i < size(); i++ ) { @@ -267,49 +240,40 @@ void CoherentSum::generateSourceCode( const std::string& fname, const double& no stream.close(); } -bool CoherentSum::isFixedPDF(const MinuitParameterSet& mps) const -{ - for ( auto& matrixElement : m_matrixElements ) { - if( ! matrixElement.coupling.isFixed() ) return false; - } - return true; -} - -void CoherentSum::PConjugate() -{ - for ( auto& matrixElement : m_matrixElements ) { - if ( matrixElement.decayTree.finalStateParity() == -1 ) matrixElement.coupling.changeSign(); - } -} - complex_t CoherentSum::getValNoCache( const Event& evt ) const { - return std::accumulate( m_matrixElements.begin(), - m_matrixElements.end(), - complex_t(0,0), - [&evt]( auto& a, auto& b ){ return a + b.coefficient * b(evt);} ); + return utils::get<0>( complex_v(std::accumulate( m_matrixElements.begin(), + m_matrixElements.end(), + complex_v(0,0), + [&evt]( const auto& a, const auto& b ){ return a + b.coefficient * b(evt);} )) ); } void CoherentSum::reset( bool resetEvents ) { m_prepareCalls = 0; m_lastPrint = 0; - for ( auto& mE : m_matrixElements ) mE.addressData = 999; - if ( resetEvents ) m_events = nullptr; + if ( resetEvents ){ + m_events = nullptr; + m_integrator = Integrator(); + } } -void CoherentSum::setEvents( EventList& list ) +void CoherentSum::setEvents( const EventList_type& list ) { - if ( m_verbosity ) INFO( "Setting events to size = " << list.size() << " for " << this ); + DEBUG( "Setting event list with:" << list.size() << " events for " << this ); reset(); + for( auto& me : m_matrixElements ){ DEBUG("Registering: " << me.name() ) ; } + if( m_ownEvents && m_events != nullptr ) delete m_events; m_events = &list; + m_cache . allocate( m_events->size(), m_matrixElements ); } -void CoherentSum::setMC( EventList& sim ) + +void CoherentSum::setMC( const EventList_type& sim ) { - if ( m_verbosity ) INFO( "Setting MC = " << &sim << " for " << this ); + if ( m_verbosity ) INFO( "Setting norm. event list with:" << sim.size() << " events for " << this ); reset(); - m_integrator = Integrator<10>(&sim); + m_integrator = Integrator( &sim, m_matrixElements ); } real_t CoherentSum::norm() const @@ -322,16 +286,15 @@ real_t CoherentSum::norm(const Bilinears& norms) const complex_t acc(0, 0); for ( size_t i = 0; i < size(); ++i ) { for ( size_t j = 0; j < size(); ++j ) { - auto val = norms.get(i, j) - * m_matrixElements[i].coefficient - * std::conj(m_matrixElements[j].coefficient); - acc += val; + acc += m_matrixElements[i].coefficient + * std::conj(m_matrixElements[j].coefficient) + * ( i > j ? std::conj(norm(j,i)) : norm(i,j) ); } } return acc.real(); } -complex_t CoherentSum::norm(const unsigned int& x, const unsigned int& y) const +complex_t CoherentSum::norm(const size_t& x, const size_t& y) const { return m_normalisations.get(x, y); } @@ -339,18 +302,101 @@ complex_t CoherentSum::norm(const unsigned int& x, const unsigned int& y) const void CoherentSum::transferParameters() { for ( auto& mE : m_matrixElements ) mE.coefficient = mE.coupling(); + m_weight.update(); } void CoherentSum::printVal(const Event& evt) { for ( auto& mE : m_matrixElements ) { - unsigned int address = mE.addressData; - std::cout << mE.decayTree.decayDescriptor() << " = " << mE.coefficient << " x " << evt.getCache( address ) + unsigned int address = std::distance( &mE , &m_matrixElements[0] ); + std::cout << mE.decayTree.decayDescriptor() << " = " << mE.coefficient << " x " << m_cache( evt.index() / utils::size::value, address ) << " address = " << address << " " << mE( evt ) << std::endl; - if( mE.coupling.couplings.size() != 1 ){ + if( mE.coupling.size() != 1 ){ std::cout << "CouplingConstants: " << std::endl; mE.coupling.print(); std::cout << "================================" << std::endl; } } } + +complex_t CoherentSum::getVal( const Event& evt ) const +{ + complex_v value( 0., 0. ); + for (unsigned int i = 0 ; i != m_matrixElements.size(); ++i ) { + value = value + m_matrixElements[i].coefficient * m_cache(evt.index() / utils::size::value, i ); + } +#if ENABLE_AVX + return value.at(evt.index() % utils::size::value ); +#else + return value; +#endif +} + +float_v CoherentSum::operator()( const float_v* /*evt*/, const unsigned block ) const +{ + complex_v value( 0., 0. ); + for ( const auto& mE : m_matrixElements ) + { + unsigned address = &mE - &m_matrixElements[0]; + value = value + mE.coefficient * m_cache(block, address); + } + return (m_weight/m_norm ) * utils::norm(value); +} + +#if ENABLE_AVX +double CoherentSum::operator()( const double* /*evt*/, const unsigned block ) const +{ + return operator()((const float_v*)nullptr, block / utils::size::value ).at( block % utils::size::value ); +} +#endif + +std::function CoherentSum::evaluator(const EventList_type* ievents) const +{ + auto events = ievents == nullptr ? m_integrator.events() : ievents; + Store store( events->size(), m_matrixElements); + for( auto& me : m_matrixElements ) store.update(events->store(), me ); + + std::vector values( events->aligned_size() ); + #ifdef _OPENMP + #pragma omp parallel for + #endif + for( unsigned int block = 0 ; block < events->nBlocks(); ++block ) + { + complex_v amp(0.,0.); + for( unsigned j = 0 ; j != m_matrixElements.size(); ++j ) + amp = amp + m_matrixElements[j].coefficient * store(block, j); + utils::store( values.data() + block * utils::size::value, (m_weight/m_norm) * utils::norm(amp) ); + } + return arrayToFunctor(values); +} + +KeyedFunctors CoherentSum::componentEvaluator(const EventList_type* ievents) const +{ + using store_t = Store; + auto events = ievents == nullptr ? m_integrator.events() : ievents; + KeyedFunctors rt; + std::shared_ptr cache; + if( events != m_integrator.events() ) + { + cache = std::make_shared(events->size(), m_matrixElements); + for( auto& me : m_matrixElements ) const_cast(cache.get())->update(events->store(), me); + } + else cache = std::shared_ptr( & m_integrator.cache(), [](const store_t* t){} ); + /// this little slice of weirdness allows either a new cache to be instantiated, or one to just get a pointer to the one used for the integration. + + for( unsigned i = 0 ; i != m_matrixElements.size(); ++i ) + { + for( unsigned j = i ; j != m_matrixElements.size(); ++j ) + { + auto mi = m_matrixElements[i]; + auto mj = m_matrixElements[j]; + auto ci = this->m_matrixElements[i].coefficient; + auto cj = this->m_matrixElements[j].coefficient; + double s = (i==j) ? 1 : 2 ; + auto name = programatic_name(mi.decayTree.decayDescriptor()) + "_" + programatic_name( mj.decayTree.decayDescriptor() ); + auto functor = [ci,cj,i,j,s, cache](const Event& event){ return s * std::real( ci * cache->get( event.index(), i ) * std::conj( cj * cache->get( event.index(), j ) ) ) ;}; + rt.add(functor, name, ""); + } + } + return rt; +} diff --git a/src/CompiledExpressionBase.cpp b/src/CompiledExpressionBase.cpp index c4e70d99b86..ac2bf0c7524 100644 --- a/src/CompiledExpressionBase.cpp +++ b/src/CompiledExpressionBase.cpp @@ -11,9 +11,29 @@ #include "AmpGen/ThreadPool.h" #include "AmpGen/CompilerWrapper.h" #include "AmpGen/ASTResolver.h" - +#include "AmpGen/ProfileClock.h" +#include "AmpGen/Tensor.h" +#include "AmpGen/simd/utils.h" using namespace AmpGen; +CompiledExpressionBase::CompiledExpressionBase() = default; + +CompiledExpressionBase::CompiledExpressionBase( const std::string& name ) : + m_name( name ), + m_progName( programatic_name(name) ) {} + +CompiledExpressionBase::CompiledExpressionBase( const Expression& expression, + const std::string& name, + const DebugSymbols& db, + const std::map& evtMapping ) : + m_obj( expression ), + m_name( name ), + m_progName( programatic_name(name) ), + m_db(db), + m_evtMap(evtMapping) {} + +CompiledExpressionBase::~CompiledExpressionBase() {} + std::string AmpGen::programatic_name( std::string s ) { std::replace( s.begin(), s.end(), '-', 'm' ); @@ -28,12 +48,18 @@ std::string AmpGen::programatic_name( std::string s ) void CompiledExpressionBase::resolve(const MinuitParameterSet* mps) { - if( m_resolver != nullptr ) delete m_resolver ; - m_resolver = new ASTResolver( m_evtMap, mps ); - m_resolver->getOrderedSubExpressions( m_obj, m_dependentSubexpressions ); - for ( auto& sym : m_db ){ - sym.second.resolve( *m_resolver ); - m_resolver->getOrderedSubExpressions( sym.second, m_debugSubexpressions ); + if( m_resolver == nullptr ) m_resolver = std::make_shared( m_evtMap, mps ); + if( fcnSignature().find("AVX") != std::string::npos ) { + m_resolver->setEnableAVX(); + enableBatch(); + } + m_dependentSubexpressions = m_resolver->getOrderedSubExpressions( m_obj ); + for ( auto& sym : m_db ){ + auto expressions_for_this = m_resolver->getOrderedSubExpressions( sym.second); + for( auto& it : expressions_for_this ){ + auto is_same = [&it](const auto& jt){ return it.first == jt.first ; }; + if( !std::any_of( m_debugSubexpressions.begin(), m_debugSubexpressions.end(), is_same) ) m_debugSubexpressions.push_back( it ); + } } m_cacheTransfers.clear(); for( auto& expression : m_resolver->cacheFunctions() ) @@ -42,22 +68,6 @@ void CompiledExpressionBase::resolve(const MinuitParameterSet* mps) prepare(); } -CompiledExpressionBase::CompiledExpressionBase( const Expression& expression, - const std::string& name, - const DebugSymbols& db, - const std::map& evtMapping ) - : m_obj( expression ), - m_name( name ), - m_progName( programatic_name(name) ), - m_db(db), - m_evtMap(evtMapping), - m_readyFlag(nullptr) {} - -CompiledExpressionBase::CompiledExpressionBase( const std::string& name ) - : m_name( name ), - m_progName( programatic_name(name) ), - m_readyFlag(nullptr) {} - std::string CompiledExpressionBase::name() const { return m_name; } std::string CompiledExpressionBase::progName() const { return m_progName; } unsigned int CompiledExpressionBase::hash() const { return FNV1a_hash(m_name); } @@ -70,7 +80,7 @@ void CompiledExpressionBase::prepare() void CompiledExpressionBase::addDependentExpressions( std::ostream& stream, size_t& sizeOfStream ) const { for ( auto& dep : m_dependentSubexpressions ) { - std::string rt = "auto v" + std::to_string(dep.first) + " = " + dep.second.to_string(m_resolver) +";"; + std::string rt = " auto v" + std::to_string(dep.first) + " = " + dep.second.to_string(m_resolver.get()) +";"; stream << rt << "\n"; sizeOfStream += sizeof(char) * rt.size(); /// bytes /// } @@ -80,35 +90,40 @@ void CompiledExpressionBase::to_stream( std::ostream& stream ) const { if( m_db.size() !=0 ) stream << "#include\n"; stream << "extern \"C\" const char* " << progName() << "_name() { return \"" << m_name << "\"; } \n"; - bool enable_cuda = NamedParameter("EnableCUDA",false); - - size_t sizeOfStream = 0; - if( !enable_cuda ){ - // Avoid a warning about std::complex not being C compatible (it is) - stream << "#pragma clang diagnostic push\n" - << "#pragma clang diagnostic ignored \"-Wreturn-type-c-linkage\"\n"; - + bool enable_cuda = NamedParameter("UseCUDA",false); + size_t sizeOfStream = 0; + if( use_rto() ) + { + + stream << "extern \"C\" " << returnTypename() << " " << progName() << "(" << fcnSignature() << "){\n"; + addDependentExpressions( stream , sizeOfStream );\ + std::string return_type = arg_type(0); + return_type = return_type.substr(0,return_type.size()-1); + if( is(m_obj) == false ){ + stream << "*r = " << return_type << "(" << m_obj.to_string(m_resolver.get()) << ");\n"; + stream << "}\n"; + } + else { + auto as_tensor = cast(m_obj).tensor(); + + for(unsigned j=0; j != as_tensor.size(); ++j ) + stream << "r[s * "<< j<<"] = " << return_type << "(" << as_tensor[j].to_string(m_resolver.get()) << ");\n"; + stream << "}\n"; + } + } + else if( !enable_cuda ){ stream << "extern \"C\" " << returnTypename() << " " << progName() << "(" << fcnSignature() << "){\n"; addDependentExpressions( stream , sizeOfStream ); - std::string objString = m_obj.to_string(m_resolver); - stream << "return " << objString << ";\n}\n"; + stream << "return " << m_obj.to_string(m_resolver.get()) << ";\n}\n"; } else { - std::string rt_cpp = returnTypename(); - std::string rt_cuda = ""; - if( rt_cpp == "double" || rt_cpp == "float" || rt_cpp == "real_t" ) - rt_cuda = "float* r, const int N"; - if( rt_cpp == "std::complex" || rt_cpp == "std::complex" || rt_cpp == "complex_t" ) - rt_cuda = "ampgen_cuda::complex_t* r, const int N"; - stream << "__global__ void " << progName() << "( " << rt_cuda << ", const float_t* x0, const float3* x1){\n"; + stream << "__global__ void " << progName() << "( " << returnTypename() + "* r, const int N, " << fcnSignature() << "){\n"; stream << " int i = blockIdx.x * blockDim.x + threadIdx.x;\n"; addDependentExpressions( stream, sizeOfStream); - std::string objString = m_obj.to_string(m_resolver); - stream << " r[i] = " << objString << ";\n}\n"; + stream << " r[i] = " << m_obj.to_string(m_resolver.get()) << ";\n}\n"; } - if( NamedParameter("IncludePythonBindings", false) == true ){ - stream << "#pragma clang diagnostic pop\n\n"; + if( NamedParameter("IncludePythonBindings", false) == true && returnTypename().find("complex") != std::string::npos ){ stream << "extern \"C\" void " << progName() << "_c" << "(double *real, double *imag, " << fcnSignature() << "){\n"; stream << " auto val = " << progName() << "(" << args() << ") ;\n"; stream << " *real = val.real();\n"; @@ -116,6 +131,7 @@ void CompiledExpressionBase::to_stream( std::ostream& stream ) const stream << "}\n"; } if ( m_db.size() != 0 ) addDebug( stream ); + if( m_enableBatch ) compileBatch(stream); } std::ostream& AmpGen::operator<<( std::ostream& os, const CompiledExpressionBase& expression ) @@ -124,25 +140,18 @@ std::ostream& AmpGen::operator<<( std::ostream& os, const CompiledExpressionBase return os; } -void CompiledExpressionBase::compile(const std::string& fname, const bool& wait ) +void CompiledExpressionBase::compile(const std::string& fname) { - if(!wait){ - m_readyFlag = new std::shared_future( ThreadPool::schedule([this,fname](){ - CompilerWrapper().compile(*this,fname); - return true;} ) ); - } - else { - CompilerWrapper(false).compile(*this,fname ); - } + CompilerWrapper(false).compile(*this,fname ); } void CompiledExpressionBase::addDebug( std::ostream& stream ) const { stream << "#include\n"; - stream << "extern \"C\" std::vector>> " + stream << "extern \"C\" std::vector() << " >> " << m_progName << "_DB(" << fcnSignature() << "){\n"; for ( auto& dep : m_debugSubexpressions ) { - std::string rt = "auto v" + std::to_string(dep.first) + " = " + dep.second.to_string(m_resolver) +";"; + std::string rt = "auto v" + std::to_string(dep.first) + " = " + dep.second.to_string(m_resolver.get()) +";"; stream << rt << "\n"; } stream << "return {"; @@ -150,8 +159,16 @@ void CompiledExpressionBase::addDebug( std::ostream& stream ) const std::string comma = (i!=m_db.size()-1)?", " :"};\n}\n"; const auto expression = m_db[i].second; stream << std::endl << "{\"" << m_db[i].first << "\","; - if ( expression.to_string(m_resolver) != "NULL" ) - stream << expression.to_string(m_resolver) << "}" << comma; - else stream << "-999}" << comma ; + if ( expression.to_string(m_resolver.get()) != "NULL" ) + stream << type_string() << "("<< expression.to_string(m_resolver.get()) << ")}" << comma; + else stream << type_string() << "(-999.,0.)}" << comma ; } } + +std::string CompiledExpressionBase::fcnSignature(const std::vector& argList, bool rto, bool includeStagger) +{ + unsigned counter=0; + auto fcn = [counter](const auto& str) mutable {return str + " x"+std::to_string(counter++); }; + if( rto ) return argList[0] + " r, " + argList[1] + " s, " + vectorToString( argList.begin()+2, argList.end(), ", ", fcn ); + return vectorToString( argList.begin(), argList.end(), ", ", fcn); +} diff --git a/src/CompilerWrapper.cpp b/src/CompilerWrapper.cpp index ff8bc927fc0..da79239729a 100644 --- a/src/CompilerWrapper.cpp +++ b/src/CompilerWrapper.cpp @@ -18,30 +18,45 @@ #include "AmpGen/MsgService.h" #include "AmpGen/Utilities.h" #include "AmpGen/CompiledExpressionBase.h" -#include "AmpGen/Version.h" +#include "AmpGenVersion.h" using namespace AmpGen; +#ifdef AMPGEN_CXX +#pragma message "Using c++ compiler: " AMPGEN_CXX " for JIT" +#pragma message "Using AMPGENROOT: " AMPGENROOT +#pragma message "Using AMPGENROOT_CMAKE: " AMPGENROOT_CMAKE +#else +#pragma warning "No AMPGEN_CXX for JIT set" +#endif -CompilerWrapper::CompilerWrapper( const bool& verbose ) : - m_includes( {"array", "complex", "math.h", "vector"} ), - m_verbose(verbose) +CompilerWrapper::CompilerWrapper( const bool& verbose ) : + m_verbose(verbose), + m_cxx(getenv("AMPGEN_CXX") != nullptr ? std::string( getenv( "AMPGEN_CXX" ) ) : "") { - m_cxx = getenv("CXX") != nullptr ? std::string( getenv( "CXX" ) ) : ""; if ( m_cxx == "" ) { #ifdef AMPGEN_CXX if( m_verbose ) - INFO( "Using original compiler; set global variable CXX if another needed: " << AMPGEN_CXX ); + INFO( "Global variable AMPGEN_CXX is undefined, using compiler variable AMPGEN_CXX: " << AMPGEN_CXX ); m_cxx = AMPGEN_CXX; #else - ERROR( "No configured compiler; set global variable CXX" ); + m_cxx = getenv("AMPGEN_CXX") != nullptr ? std::string( getenv( "AMPGEN_CXX" ) ) : ""; + if( m_cxx == "" ) ERROR( "No configured compiler; set global variable AMPGEN_CXX" ); #endif } + else { + if( m_verbose ) + INFO( "Global variable CXX is defined: " << m_cxx << "; AMPGEN_CXX is ignored" ); // to use AMPGEN_CXX, unset CXX + } } void CompilerWrapper::generateSource( const CompiledExpressionBase& expression, const std::string& filename ) { std::ofstream output( filename ); for ( auto& include : m_includes ) output << "#include <" << include << ">\n"; + if( expression.fcnSignature().find("AVX2d") != std::string::npos ) output << "#include \"AmpGen/simd/avx2d_types.h\"\n; using namespace AmpGen::AVX2d;\n" ; + else if( expression.fcnSignature().find("AVX2f") != std::string::npos ) output << "#include \"AmpGen/simd/avx2f_types.h\"\n; using namespace AmpGen::AVX2f;\n;" ; + else if( expression.fcnSignature().find("AVX512d") != std::string::npos ) output << "#include \"AmpGen/simd/avx512d_types.h\"\n; using namespace AmpGen::AVX512d;\n;" ; + else if( expression.fcnSignature().find("AVX512") != std::string::npos ) output << "#include \"AmpGen/simd/avx512_types.h\"\n; using namespace AmpGen::AVX512;\n;" ; output << expression << std::endl; output.close(); } @@ -53,6 +68,7 @@ std::string CompilerWrapper::generateFilename() if ( status == -1 ) { ERROR( "Failed to generate temporary filename " << status ); } + std::remove( buffer ); return buffer; } @@ -102,7 +118,6 @@ bool CompilerWrapper::compile( std::vector& expressions for ( auto& include : m_includes ) output << "#include <" << include << ">\n"; for ( auto& expression : expressions ) output << *expression << std::endl; output.close(); - compileSource( cname, oname ); for( auto& expression : expressions ) expression->link( oname ); auto twall_end = std::chrono::high_resolution_clock::now(); @@ -111,23 +126,52 @@ bool CompilerWrapper::compile( std::vector& expressions return true; } -std::string get_cpp_version(){ +bool CompilerWrapper::isClang() const +{ + return m_cxx.find("clang") != std::string::npos || m_cxx.find("llvm-g++") != std::string::npos; +} + +std::string get_cpp_version() +{ if( __cplusplus >= 201703L ) return "c++17"; if( __cplusplus >= 201402L ) return "c++14"; if( __cplusplus >= 201103L ) return "c++11"; else return ""; } + void CompilerWrapper::compileSource( const std::string& fname, const std::string& oname ) { using namespace std::chrono_literals; std::vector compile_flags = NamedParameter("CompilerWrapper::Flags", - {"-Ofast", "--std="+get_cpp_version(),"-march=native"} ); + {"-Ofast", "--std="+get_cpp_version()}); + + #if ENABLE_AVX + compile_flags.push_back("-march=native"); + compile_flags.push_back( std::string("-I") + AMPGENROOT) ; + #endif + #if ENABLE_AVX2d + compile_flags.push_back("-mavx2"); + compile_flags.push_back("-DHAVE_AVX2_INSTRUCTIONS"); + #endif + #if USE_OPENMP + compile_flags.push_back("-fopenmp"); + #endif std::vector argp = { m_cxx.c_str(), "-shared", "-rdynamic", "-fPIC"}; - for( auto& flag : compile_flags ) argp.push_back( flag.c_str() ); + std::transform( compile_flags.begin(), compile_flags.end(), std::back_inserter(argp), [](const auto& flag ){return flag.c_str() ; } ); + if(isClang()) + { + argp.push_back( "-Wno-return-type-c-linkage"); + #if __APPLE__ + argp.push_back("-lstdc++"); + #endif + #if USE_OPENMP + argp.push_back("-fopenmp=libiomp5"); + #endif + } argp.push_back( fname.c_str() ); argp.push_back( "-o"); @@ -144,7 +188,7 @@ void CompilerWrapper::compileSource( const std::string& fname, const std::string if( childPID == 0 ) { execv( argp[0], const_cast( &argp[0] ) ); - perror( "execl()" ); + perror( "execv() in ../src/CompilerWrapper.cpp" ); // add "CompilerWrapper::Verbose true" to .opt file to diagnose exit( 0 ); } int status = 0; @@ -156,7 +200,7 @@ void CompilerWrapper::preamble( std::ostream& os ) const time_t now = time(0); char* dt = ctime(&now); os << "/** Generated by " << getenv("USER") << " on " << dt ; - os << " AmpGen v" << AMPGEN_VERSION_MAJOR << "." << AMPGEN_VERSION_MINOR << '\n'; + os << " AmpGen v" << AMPGEN_MAJOR_VERSION << "." << AMPGEN_MINOR_VERSION << '\n'; #if defined(__clang__) os << " clang v" << __clang_major__ << "." << __clang_minor__ << "." << __clang_patchlevel__; #elif defined(__ICC) || defined(__INTEL_COMPILER) @@ -166,6 +210,5 @@ void CompilerWrapper::preamble( std::ostream& os ) const #endif os << '\n'; os << "*/\n"; - for ( auto& include : m_includes ) os << "#include <" << include << ">\n"; } diff --git a/src/DalitzIntegrator.cpp b/src/DalitzIntegrator.cpp index e06568ba8f2..aab7a7f8cd3 100644 --- a/src/DalitzIntegrator.cpp +++ b/src/DalitzIntegrator.cpp @@ -38,7 +38,12 @@ double DalitzIntegrator::sqDp1( const Event& evt ) const TLorentzVector p2( ( evt.address( 4 ) ) ); TLorentzVector p3( ( evt.address( 8 ) ) ); TLorentzVector pA = p1 + p2; - return acos( 2 * ( pA.Mag() - m_min ) / ( m_max - m_min ) - 1 ) / M_PI; + auto arg = 2 * ( pA.Mag() - m_min ) / ( m_max - m_min ) - 1; + if( arg > 1 || arg < -1 ){ + ERROR("Argument: " << arg << " is out-of-bounds"); + return -1; + } + return acos(arg)/M_PI; } double DalitzIntegrator::sqDp2( const Event& evt ) const { @@ -169,14 +174,11 @@ TH2D* DalitzIntegrator::makePlot( const std::function& fc const std::string& name, const size_t& nSamples ) { auto plot = projection.plot(); - double event[12]; - for ( unsigned int i = 0; i < 12; ++i ) event[i] = 0; - Event evtCache( 12 ); + Event event( 12 ); for ( unsigned int i = 0; i < nSamples; ++i ) { sqCo pos = {gRandom->Uniform(), gRandom->Uniform()}; setEvent( pos, event ); - evtCache.set( event ); - auto obs_cos = projection( evtCache ); + auto obs_cos = projection( event ); plot->Fill( obs_cos.first, obs_cos.second, J( pos ) * fcn( event ) ); } return plot; @@ -191,6 +193,5 @@ double DalitzIntegrator::integrate_internal( TF2& fcn ) const ig.SetRelTolerance( 0.000001 ); double xmin[] = {0, 0}; double xmax[] = {1, 1}; - double v = ig.Integral( xmin, xmax ); - return v ; + return ig.Integral(xmin,xmax); } diff --git a/src/DiracMatrices.cpp b/src/DiracMatrices.cpp index 338dacbe399..a17c6d64ebe 100644 --- a/src/DiracMatrices.cpp +++ b/src/DiracMatrices.cpp @@ -11,46 +11,43 @@ using namespace AmpGen; extern const AmpGen::Expression AmpGen::I = Constant(0, 1); extern const AmpGen::Expression AmpGen::Z = Constant(0); -extern const std::array AmpGen::Gamma ( { - Tensor ({ 0, 0, 0, 1, - 0, 0, 1, 0, - 0,-1, 0, 0, - -1, 0, 0, 0} , {4, 4}), - Tensor ({ Z, Z, Z,-I, - Z, Z, I, Z, - Z, I, Z, Z, - -I, Z, Z, Z} , {4, 4}), - Tensor ({ 0, 0, 1, 0, - 0, 0, 0,-1, - -1, 0, 0, 0, - 0, 1, 0, 0} , {4, 4}), - Tensor ({ 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0,-1, 0, - 0, 0, 0,-1} , {4, 4}), - Tensor ({ 0, 0, 1, 0, - 0, 0, 0, 1, - 1, 0, 0, 0, - 0, 1, 0, 0} , {4, 4})} ); - -extern const std::array AmpGen::Sigma ( - { - Tensor({0,1,1,0},{2,2}), - Tensor({Z,-I, - I,Z},{2,2}), - Tensor({1,0,0,-1},{2,2}) - } ); +extern const std::array AmpGen::Gamma( { + Tensor({ 0, 0, 0, 1, 0, 0, 1, 0, 0,-1, 0, 0,-1, 0, 0, 0}, Tensor::dim(4,4)), + Tensor({ Z, Z, Z,-I, Z, Z, I, Z, Z, I, Z, Z,-I, Z, Z, Z}, Tensor::dim(4,4)), + Tensor({ 0, 0, 1, 0, 0, 0, 0,-1,-1, 0, 0, 0, 0, 1, 0, 0}, Tensor::dim(4,4)), + Tensor({ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0,-1}, Tensor::dim(4,4)), + Tensor({ 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0}, Tensor::dim(4,4))} ); + +extern const std::array AmpGen::Sigma( { + Tensor({ 0, 1, 1, 0}, Tensor::dim(2,2)), + Tensor({ Z,-I, I, Z}, Tensor::dim(2,2)), + Tensor({ 1, 0, 0,-1}, Tensor::dim(2,2))} ); + +extern const std::array AmpGen::Sigma4( { + Tensor({ 0, 1, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 1, 0 }, Tensor::dim(4,4)), + Tensor({ Z,-I, Z, Z, + I, Z, Z, Z, + Z, Z, Z, -I, + Z, Z, I, Z }, Tensor::dim(4,4)), + Tensor({ 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, -1 }, Tensor::dim(4,4))} ); extern const std::array AmpGen::S03 ( { - Tensor ({ 0, 0, 0, 0, - 0, 0,-1, 0, - 0, 1, 0, 0, - 0, 0, 0, 0 } , Tensor::dim(4,4) ), - Tensor ({ 0, 0, 1, 0, - 0, 0, 0, 0, - -1, 0, 0, 0, - 0, 0, 0, 0 } , Tensor::dim(4,4) ), - Tensor ({ 0,-1, 0, 0, - 1, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 } , Tensor::dim(4,4) ) } ); + Tensor({ 0, 0, 0, 0, 0, 0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, Tensor::dim(4,4) ), + Tensor({ 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, Tensor::dim(4,4) ), + Tensor({ 0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, Tensor::dim(4,4) ) } ); + +extern const std::array AmpGen::SU3 ( { + Tensor({ 0, 1, 0, 1, 0, 0, 0, 0, 0}, Tensor::dim(3,3)), + Tensor({ Z,-I, Z, I, Z, Z, Z, Z, Z}, Tensor::dim(3,3)), + Tensor({ 1, 0, 0, 0,-1, 0, 0, 0, 0}, Tensor::dim(3,3)), + Tensor({ 0, 0, 1, 0, 0, 0, 1, 0, 0}, Tensor::dim(3,3)), + Tensor({ Z, Z,-I, Z, Z, Z, I, Z, Z}, Tensor::dim(3,3)), + Tensor({ 0, 0, 0, 0, 0, 1, 0, 1, 0}, Tensor::dim(3,3)), + Tensor({ Z, Z, Z, Z, Z,-I, Z, I, Z}, Tensor::dim(3,3)), + Tensor({ 1./sqrt(3), 0., 0., 0.,1./sqrt(3.), 0., 0., 0., -2./sqrt(3.)}, Tensor::dim(3,3)) }); diff --git a/src/ErrorPropagator.cpp b/src/ErrorPropagator.cpp index 3c62fdbb804..815b50e577a 100644 --- a/src/ErrorPropagator.cpp +++ b/src/ErrorPropagator.cpp @@ -11,7 +11,6 @@ using namespace AmpGen; GaussErrorPropagator::GaussErrorPropagator( const TMatrixD& reducedCovariance, const std::vector& params, TRandom3* rnd ) : m_parameters( params ), m_rand( rnd ), m_decomposedCholesky( params.size(), params.size() ) { - for ( size_t x = 0; x < params.size(); ++x ) { auto p = params[x]; INFO( p->name() << " " << p->mean() << " +/- " << sqrt( reducedCovariance( x, x ) ) ); @@ -20,7 +19,12 @@ GaussErrorPropagator::GaussErrorPropagator( const TMatrixD& reducedCovariance, c TDecompChol decomposed( reducedCovariance ); decomposed.Decompose(); m_decomposedCholesky = decomposed.GetU(); - transpose(); + /// transpose the cholesky matrix + for ( int i = 0; i < m_decomposedCholesky.GetNrows(); ++i ) { + for ( int j = i + 1; j < m_decomposedCholesky.GetNrows(); ++j ){ + std::swap( m_decomposedCholesky(i, j), m_decomposedCholesky(j, i) ); + } + } } void GaussErrorPropagator::perturb() @@ -40,16 +44,6 @@ void GaussErrorPropagator::reset() for ( unsigned int j = 0; j < m_parameters.size(); ++j ) m_parameters[j]->setCurrentFitVal( m_startingValues[j] ); } -void GaussErrorPropagator::transpose() -{ - for ( int i = 0; i < m_decomposedCholesky.GetNrows(); ++i ) { - for ( int j = i + 1; j < m_decomposedCholesky.GetNrows(); ++j ) { - double tmp = m_decomposedCholesky( j, i ); - m_decomposedCholesky( j, i ) = m_decomposedCholesky( i, j ); - m_decomposedCholesky( i, j ) = tmp; - } - } -} LinearErrorPropagator::LinearErrorPropagator( const TMatrixD& reducedCovarianceMatrix, const std::vector& params ) : m_cov( reducedCovarianceMatrix ), m_parameters( params ) @@ -59,8 +53,7 @@ LinearErrorPropagator::LinearErrorPropagator( const TMatrixD& reducedCovarianceM LinearErrorPropagator::LinearErrorPropagator( const std::vector& params ) { for( auto& param : params ){ - if( param->iFixInit() != MinuitParameter::Float ) continue; - if( param->err() == 0 ) continue; + if( !param->isFree() || param->err() == 0 ) continue; m_parameters.push_back( param ); } m_cov.ResizeTo( m_parameters.size(), m_parameters.size() ); @@ -70,11 +63,9 @@ LinearErrorPropagator::LinearErrorPropagator( const std::vectoriFixInit() != MinuitParameter::Float ) continue; - if( param->err() == 0 ) continue; - m_parameters.push_back( param ); + for(auto& param : mps){ + if( ! param->isFree() || param->err() == 0 ) continue; + m_parameters.push_back(param); } m_cov.ResizeTo( m_parameters.size(), m_parameters.size() ); for( size_t i = 0 ; i < m_parameters.size(); ++i ) @@ -83,11 +74,9 @@ LinearErrorPropagator::LinearErrorPropagator( const MinuitParameterSet& mps ) void LinearErrorPropagator::add( const LinearErrorPropagator& p2 ) { - size_t superSet = size(); size_t oldSize = size(); auto p1_pMap = posMap(); - std::vector props( p2.size() ); for ( size_t x = 0; x != p2.size(); ++x ) { auto it = p1_pMap.find( p2.params()[x]->name() ); @@ -97,14 +86,11 @@ void LinearErrorPropagator::add( const LinearErrorPropagator& p2 ) } else props[x] = it->second; } - TMatrixD old_cov = m_cov; if ( superSet != oldSize ) m_cov.ResizeTo( superSet, superSet ); - for ( size_t x = 0; x != oldSize; ++x ) { for ( size_t y = 0; y != oldSize; ++y ) m_cov( x, y ) = old_cov( x, y ); } - auto p2_cov = p2.cov(); for ( size_t x = 0; x < p2.size(); ++x ) { for ( size_t y = 0; y < p2.size(); ++y ) { @@ -115,6 +101,46 @@ void LinearErrorPropagator::add( const LinearErrorPropagator& p2 ) } } +double LinearErrorPropagator::getError( const std::function& fcn ) const +{ + unsigned int N = m_cov.GetNrows(); + TVectorD errorVec( N ); + for ( unsigned int i = 0; i < N; ++i ) { + DEBUG( "Perturbing parameter: [" << m_parameters[i]->name() << "] " << m_parameters[i]->mean() << " by " + << sqrt( m_cov( i, i ) ) << " " << m_parameters[i] ); + errorVec(i) = derivative(fcn,i); + fcn(); + } + return sqrt( errorVec * ( m_cov * errorVec ) ); +} + +std::vector LinearErrorPropagator::getVectorError( const std::function(void)>& fcn, size_t RANK ) const +{ + unsigned int N = m_cov.GetNrows(); + std::vector errorVec( RANK, TVectorD( N ) ); + for ( unsigned int i = 0; i < N; ++i ) { + double startingValue = m_parameters[i]->mean(); + double error = sqrt( m_cov( i, i ) ); + double min = m_parameters[i]->mean() - error; + double max = m_parameters[i]->mean() + error; + DEBUG( "Perturbing parameter: " << m_parameters[i]->name() << " -> [" << min << ", " << max << "]" ); + + m_parameters[i]->setCurrentFitVal( max ); + auto plus_variation = fcn(); + m_parameters[i]->setCurrentFitVal( min ); + auto minus_variation = fcn(); + m_parameters[i]->setCurrentFitVal( startingValue ); + for ( size_t j = 0; j < RANK; ++j ) { + errorVec[j]( i ) = ( plus_variation[j] - minus_variation[j] ) / ( 2 * error ); + } + } + fcn(); + std::vector rt( RANK, 0 ); + for ( unsigned int j = 0; j < RANK; ++j ) rt[j] = sqrt( errorVec[j] * ( m_cov * errorVec[j] ) ); + return rt; +} + + void LinearErrorPropagator::reset() { for ( int x = 0; x < m_cov.GetNrows(); ++x ) { diff --git a/src/Event.cpp b/src/Event.cpp index 483267fb15f..04043c21503 100644 --- a/src/Event.cpp +++ b/src/Event.cpp @@ -1,4 +1,4 @@ -#include + #include #include #include @@ -10,18 +10,15 @@ using namespace AmpGen; -Event::Event( const size_t& N, const size_t& cacheSize) : - m_event(N), - m_cache(cacheSize) { - } +Event::Event( const unsigned& N) : + m_event(N) {} -Event::Event( const real_t* data, const size_t& N, const size_t& cacheSize) : - m_event(data, data+N), - m_cache(cacheSize) { - } +Event::Event( const real_t* data, const unsigned& N) : + m_event(data, data+N) {} void Event::print() const { - for( unsigned int i = 0 ; i< m_event.size()/4 ; ++i ){ + unsigned nParticles = m_event.size()/4; + for( unsigned i = 0 ; i < nParticles; ++i ){ double px = m_event[4*i+0]; double py = m_event[4*i+1]; double pz = m_event[4*i+2]; @@ -29,22 +26,25 @@ void Event::print() const { double s = pE*pE - px*px -py*py -pz*pz; INFO( "P["<(std::string("")).val; + auto getGenPdf = args.getArg(false).val; + auto weightBranch = args.getArg(std::string("")).val; auto branches = args.getArg().val; - auto applySym = args.getArg().val; + auto extraBranches= args.getArg().val; + auto applySym = args.getArg(false).val; auto entryList = args.getArg().val; auto eventFormat = m_eventType.getEventFormat( true ); - - Event temp( branches.size() == 0 ? eventFormat.size() : branches.size() , pdfSize ); + auto inputUnits = args.getArg(Units::GeV); + auto idBranches = args.getArg({}).val; + Event temp( eventFormat.size() + extraBranches.size()); temp.setWeight( 1 ); temp.setGenPdf( 1 ); tree->SetBranchStatus( "*", 0 ); - - TreeReader tr( tree ); - if( branches.size() != 0 ){ - INFO("Branches = [" << vectorToString(branches, ", ") << "]" ); - for ( auto branch = branches.begin(); branch != branches.end(); ++branch ) { - unsigned int pos = std::distance( branches.begin(), branch ); - tr.setBranch( *branch, &(temp[pos]) ); - if( pos >= eventFormat.size() ){ - INFO("Specifiying event extension: " << *branch << " " << pos << " " << eventFormat.size() ); - m_extensions[ *branch ] = pos; - } + TreeReader tr( tree ); + bool hasEnergy = branches.size() == 0 || branches.size() == 4 * m_eventType.size(); // if the energy of the particle has been explicitly specified // + std::vector ids( m_eventType.size() ); + if( branches.size() != 0 ) + { + DEBUG("Branches = [" << vectorToString(branches, ", ") << "]" ); + for (unsigned p = 0 ; p != branches.size(); ++p ) + { + auto pos = hasEnergy ? p : 4 * int(p/3) + p % 3 ; + DEBUG("Setting branch: " << branches[p] << " pos: " << pos << " fmt = " << inv_map( eventFormat, pos, "NOT FOUND" ) << " has energy? " << hasEnergy ); + tr.setBranch( branches[p], &(temp[pos]) ); } - } - else { - for ( auto& branch : eventFormat ){ - tr.setBranch( branch.first, &(temp[branch.second]) ); + if( idBranches.size() != 0 ) + { + if( idBranches.size() != m_eventType.size() ) FATAL("Number of ID branches should be number of final state particles"); + for( int i = 0; i != ids.size(); ++i ) tr.setBranch( idBranches[i], ids.data() + i); } } + else for ( auto& branch : eventFormat ) tr.setBranch( branch.first, &(temp[branch.second]) ); + auto pos = eventFormat.size(); + for( const auto& branch : extraBranches ){ + tr.setBranch( branch, &(temp[pos]) ); + m_extensions[branch] = pos++; + } if( getGenPdf ) tr.setBranch( "genPdf", temp.pGenPdf() ); if( weightBranch != "" ) tr.setBranch( weightBranch, temp.pWeight() ); if( filter != "" ){ @@ -100,22 +118,29 @@ void EventList::loadFromTree( TTree* tree, const ArgumentPack& args ) for( int i = 0 ; i < evtList->GetN(); ++i ) entryList.push_back( evtList->GetEntry(i) ); } - bool hasEventList = entryList.size() != 0; - unsigned int nEvents = hasEventList ? entryList.size() : tree->GetEntries(); - m_data.reserve( nEvents ); + if( entryList.size() != 0 ) tr.setEntryList( entryList ); + m_data.reserve( tr.nEntries() ); auto symmetriser = m_eventType.symmetriser(); - for ( unsigned int evt = 0; evt < nEvents; ++evt ) { - tr.getEntry( hasEventList ? entryList[evt] : evt ); - if( applySym ) symmetriser( temp ); - m_data.push_back( temp ); + auto automaticOrdering = m_eventType.automaticOrdering(); + for (const auto& evt : tr) { + if( inputUnits != Units::GeV ) for( unsigned k = 0; k != eventFormat.size(); ++k ) temp[k] *= to_double(inputUnits); + if( idBranches.size() != 0 && !automaticOrdering(temp, ids) ) WARNING("Failed to order event: " << evt ); + if( applySym ) symmetriser(temp); + if( ! hasEnergy ){ + for( unsigned int k = 0 ; k != m_eventType.size(); ++k ) + temp[4*k + 3] = sqrt( m_eventType.mass(k) * m_eventType.mass(k) + temp[4*k+0]*temp[4*k+0] + temp[4*k+1]*temp[4*k+1] + temp[4*k+2]*temp[4*k+2] ); + } + push_back( temp ); } read_time.stop(); INFO("Time to read tree = " << read_time << "[ms]; nEntries = " << size() ); } -TTree* EventList::tree( const std::string& name, const std::vector& extraBranches ) +TTree* EventList::tree( const std::string& name, const std::vector& extraBranches ) const { - TTree* outputTree = new TTree( name.c_str(), name.c_str() ); + std::string title = m_eventType.mother(); + for( unsigned i = 0 ; i != m_eventType.size(); ++i ) title += " " + m_eventType[i]; + TTree* outputTree = new TTree( name.c_str(), title.c_str() ); if ( size() == 0 ) { ERROR( "Trying to output empty tree" ); return nullptr; @@ -124,15 +149,11 @@ TTree* EventList::tree( const std::string& name, const std::vector& double genPdf = 1; double weight = 1; auto format = m_eventType.getEventFormat( true ); - for ( auto& f : format ){ - outputTree->Branch( f.first.c_str(), tmp.address( f.second ) ); - } - for ( auto& f : m_extensions ){ - outputTree->Branch( f.first.c_str(), tmp.address( f.second ) ); - } + for ( const auto& f : format ) outputTree->Branch( f.first.c_str(), tmp.address( f.second ) ); + for ( const auto& f : m_extensions ) outputTree->Branch( f.first.c_str(), tmp.address( f.second ) ); outputTree->Branch( "genPdf", &genPdf ); outputTree->Branch( "weight", &weight ); - for ( auto& evt : *this ) { + for ( const auto& evt : *this ) { tmp = evt; genPdf = evt.genPdf(); weight = evt.weight(); @@ -144,21 +165,17 @@ TTree* EventList::tree( const std::string& name, const std::vector& std::vector EventList::makeProjections( const std::vector& projections, const ArgumentPack& args ) { std::vector plots; - for ( auto& proj : projections ) { - TH1D* plot = makeProjection(proj, args ); - DEBUG("Made plot ... " << plot->GetName() ); - plots.push_back( plot ); - } + for ( const auto& proj : projections ) plots.push_back( makeProjection(proj, args) ); return plots; } -TH1D* EventList::makeProjection( const Projection& projection, const ArgumentPack& args ) +TH1D* EventList::makeProjection( const Projection& projection, const ArgumentPack& args ) const { - auto selection = args.getArg().val; + auto selection = args.getArg().val; auto weightFunction = args.getArg().val; - std::string prefix = args.getArg(); + std::string prefix = args.getArg(std::string("")); auto plot = projection.plot(prefix); - plot->SetLineColor(args.getArg(kBlack).val); + plot->SetLineColor(args.getArg(kBlack).val); plot->SetMarkerSize(0); for( auto& evt : m_data ){ if( selection != nullptr && !selection(evt) ) continue; @@ -169,11 +186,11 @@ TH1D* EventList::makeProjection( const Projection& projection, const ArgumentPac return plot; } -TH2D* EventList::makeProjection( const Projection2D& projection, const ArgumentPack& args ) +TH2D* EventList::makeProjection( const Projection2D& projection, const ArgumentPack& args ) const { - auto selection = args.getArg().val; + auto selection = args.getArg().val; auto weightFunction = args.getArg().val; - std::string prefix = args.getArg().val; + std::string prefix = args.getArg().val; auto plot = projection.plot(prefix); for ( auto& evt : m_data ){ if ( selection != nullptr && !selection(evt) ) continue; @@ -183,72 +200,46 @@ TH2D* EventList::makeProjection( const Projection2D& projection, const ArgumentP return plot; } -void EventList::printCacheInfo( const unsigned int& nEvt ) +double EventList::integral() const { - for ( auto& ind : m_pdfIndex ) { - INFO( "Cache[" << ind.second << "] = " << ind.first << " = " << at( nEvt ).getCache( ind.second ) ); - } + return std::accumulate( std::begin(*this), std::end(*this), 0, [](double rv, const auto& evt){ return rv + evt.weight(); } ); } -size_t EventList::getCacheIndex( const CompiledExpressionBase& PDF ) const +void EventList::add( const EventList& evts ) { - auto pdfIndex = m_pdfIndex.find( FNV1a_hash( PDF.name() ) ); - if ( pdfIndex != m_pdfIndex.end() ) - return pdfIndex->second; - else - ERROR( "FATAL: PDF Index for " << PDF.name() << " not found" ); - return 999; + for ( auto& evt : evts ) push_back( evt ); } -size_t EventList::getCacheIndex( const CompiledExpressionBase& PDF, bool& isRegistered ) const -{ - auto pdfIndex = m_pdfIndex.find( FNV1a_hash( PDF.name() ) ); - if ( pdfIndex != m_pdfIndex.end() ) { - isRegistered = true; - return pdfIndex->second; - } - isRegistered = false; - return 999; +void EventList::clear() +{ + m_data.clear(); } -void EventList::resetCache() +void EventList::erase(const std::vector::iterator& begin, + const std::vector::iterator& end) { - m_pdfIndex.clear(); - for ( auto evt = begin(); evt != end(); ++evt ) evt->resizeCache( 0 ); - m_lastCachePosition = 0; + m_data.erase( begin, end ); } -double EventList::integral() const -{ - double integral = 0; - for ( auto& evt : *this ) { - integral += evt.weight(); - } - return integral; -} -void EventList::add( const EventList& evts ) -{ - resetCache(); - WARNING( "Adding event lists invalidates cache state" ); - for ( auto& evt : evts ) { - m_data.push_back( evt ); - rbegin()->resizeCache( 0 ); - } -} -double EventList::norm() -{ - if ( m_norm == 0 ) { - double totalWeight = 0; -#pragma omp parallel for reduction( + : totalWeight ) - for ( unsigned int i = 0; i < size(); ++i ) totalWeight += ( *this )[i].weight() / ( *this )[i].genPdf(); - m_norm = totalWeight; - } - return m_norm; +void EventList::reserve( const size_t& size ) +{ + m_data.reserve( size ); } +void EventList::resize ( const size_t& size ) +{ + m_data.resize(size); + for( unsigned int i = 0 ; i != size; ++i ) m_data[i].setIndex(i) ; +} -void EventList::clear() { m_data.clear(); } -void EventList::erase( const std::vector::iterator& begin, const std::vector::iterator& end ) -{ - m_data.erase( begin, end ); +void EventList::push_back( const Event& evt ) +{ + m_data.push_back( evt ); + m_data.rbegin()->setIndex(m_data.size()-1); +} + +void EventList::emplace_back( const Event& evt) +{ + m_data.emplace_back(evt) ; + m_data.rbegin()->setIndex(m_data.size()-1); } diff --git a/src/EventListSIMD.cpp b/src/EventListSIMD.cpp new file mode 100644 index 00000000000..cd6b6873e6b --- /dev/null +++ b/src/EventListSIMD.cpp @@ -0,0 +1,251 @@ +#if ENABLE_AVX + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AmpGen/ArgumentPack.h" +#include "AmpGen/CompiledExpressionBase.h" +#include "AmpGen/EventListSIMD.h" +#include "AmpGen/EventType.h" +#include "AmpGen/MsgService.h" +#include "AmpGen/Projection.h" +#include "AmpGen/TreeReader.h" +#include "AmpGen/Utilities.h" +#include "AmpGen/Event.h" +#include "AmpGen/Types.h" +#include "AmpGen/ProfileClock.h" +#include "AmpGen/simd/utils.h" +using namespace AmpGen; + +// ENABLE_DEBUG(EventListSIMD) + +EventListSIMD::EventListSIMD( const EventType& type ) : + m_data(0, type.eventSize() ), + m_eventType( type ) {} + +void EventListSIMD::loadFromFile( const std::string& fname, const ArgumentPack& args ) +{ + auto current_file = gFile; + auto tokens = split( fname, ':'); + TTree* tree = nullptr; + if( fname == "" ) FATAL("Filename must be specified to load data"); + if( tokens.size() == 2 ){ + gFile = TFile::Open( tokens[0].c_str(), "READ"); + if( gFile == nullptr ) FATAL("Failed to load file: " << tokens[0] ); + tree = (TTree*)gFile->Get( tokens[1].c_str() ); + } + else { + gFile = TFile::Open( fname.c_str(), "READ"); + if( gFile == nullptr ) FATAL("Failed to load file: " << tokens[0] ); + if( tree == nullptr ) tree = (TTree*)gFile->Get("EventList"); + tree = (TTree*)gFile->Get("DalitzEventList"); + } + if( tree == nullptr ) FATAL( "Failed to load tree from file: " << fname ); + loadFromTree( tree, args ); + gFile->Close(); + gFile = current_file; +} + +void EventListSIMD::loadFromTree( TTree* tree, const ArgumentPack& args ) +{ + ProfileClock read_time; + if( m_eventType.size() == 0 ){ + auto tokens = split( tree->GetTitle(), ' '); + if( tokens.size() != 1 ) setEventType( EventType( tokens ) ); + INFO("Attempted automatic deduction of eventType: " << m_eventType ); + } + auto filter = args.getArg(std::string("")).val; + auto getGenPdf = args.getArg(false).val; + auto weightBranch = args.getArg(std::string("")).val; + auto branches = args.getArg().val; + auto applySym = args.getArg(false).val; + auto entryList = args.getArg().val; + auto eventFormat = m_eventType.getEventFormat( true ); + + Event temp( branches.size() == 0 ? eventFormat.size() : branches.size()); + temp.setWeight( 1 ); + temp.setGenPdf( 1 ); + tree->SetBranchStatus( "*", 0 ); + + TreeReader tr( tree ); + if( branches.size() != 0 ){ + INFO("Branches = [" << vectorToString(branches, ", ") << "]" ); + for ( auto branch = branches.begin(); branch != branches.end(); ++branch ) { + unsigned int pos = std::distance( branches.begin(), branch ); + tr.setBranch( *branch, &(temp[pos]) ); + } + } + else { + for ( auto& branch : eventFormat ){ + tr.setBranch( branch.first, &(temp[branch.second]) ); + } + } + if( getGenPdf ) tr.setBranch( "genPdf", temp.pGenPdf() ); + if( weightBranch != "" ) tr.setBranch( weightBranch, temp.pWeight() ); + if( filter != "" ){ + if( entryList.size() != 0 ){ + WARNING("Specified entry list and filter, will overwrite list with specified selection"); + } + tr.prepare(); + tree->Draw(">>evtList", filter.c_str() ); + TEventList* evtList = (TEventList*)gDirectory->Get("evtList"); + for( int i = 0 ; i < evtList->GetN(); ++i ) entryList.push_back( evtList->GetEntry(i) ); + } + bool hasEventList = entryList.size() != 0; + size_t nEvents = hasEventList ? entryList.size() : tree->GetEntries(); + std::array buffer; + + resize( nEvents ); + auto symmetriser = m_eventType.symmetriser(); + for ( unsigned int block = 0; block < m_data.nBlocks(); ++block ) + { + for( unsigned k = 0 ; k != float_v::size; ++k ) + { + auto evt = k + block * float_v::size; + if(evt < m_data.size() ) + { + tr.getEntry( hasEventList ? entryList[evt] : evt ); + if( applySym ) symmetriser( temp ); + buffer[k] = temp; + } + else buffer[k].setWeight(0); + } + gather( buffer, block ); + } + read_time.stop(); + INFO("Time to read tree = " << read_time << "[ms]; nEntries = " << size() ); +} + + +EventListSIMD::EventListSIMD( const EventList& other ) : EventListSIMD( other.eventType() ) +{ + resize( other.size() ); + for( unsigned block = 0 ; block != m_data.nBlocks(); block++ ) + { + for( unsigned j = 0 ; j != m_data.nFields(); ++j ) + m_data(block, j) = utils::gather(other, [j](auto& event){ return event[j]; } , block * float_v::size ); + m_weights[block] = utils::gather(other, [](auto& event){ return event.weight(); }, block * float_v::size, 0); + m_genPDF [block] = utils::gather(other, [](auto& event){ return event.genPdf(); }, block * float_v::size, 1); + } +} + + + +TTree* EventListSIMD::tree( const std::string& name, const std::vector& extraBranches ) const +{ + std::string title = m_eventType.mother(); + for( unsigned i = 0 ; i != m_eventType.size(); ++i ) title += " " + m_eventType[i]; + TTree* outputTree = new TTree( name.c_str(), title.c_str() ); + if ( size() == 0 ) { + ERROR( "Trying to output empty tree" ); + return nullptr; + } + Event tmp = *( begin() ); + double genPdf = 1; + double weight = 1; + auto format = m_eventType.getEventFormat( true ); + + for ( const auto& f : format ) outputTree->Branch( f.first.c_str(), tmp.address( f.second ) ); + // for ( const auto& f : m_extensions ) outputTree->Branch( f.first.c_str(), tmp.address( f.second ) ); + + outputTree->Branch( "genPdf", &genPdf ); + outputTree->Branch( "weight", &weight ); + for ( const auto& evt : *this ) { + tmp = evt; + genPdf = evt.genPdf(); + weight = evt.weight(); + outputTree->Fill(); + } + return outputTree; +} + +std::vector EventListSIMD::makeProjections( const std::vector& projections, const ArgumentPack& args ) +{ + std::vector plots; + for ( const auto& proj : projections ) plots.push_back( proj(*this,args) ); + return plots; +} + +TH1D* EventListSIMD::makeProjection( const Projection& projection, const ArgumentPack& args ) const +{ + return projection(*this, args); + +} +TH2D* EventListSIMD::makeProjection( const Projection2D& projection, const ArgumentPack& args ) const +{ + auto selection = args.getArg().val; + auto weightFunction = args.getArg().val; + std::string prefix = args.getArg().val; + auto plot = projection.plot(prefix); + for ( const auto evt : *this ){ + if ( selection != nullptr && !selection(evt) ) continue; + auto pos = projection(evt); + plot->Fill( pos.first, pos.second, evt.weight() * ( weightFunction == nullptr ? 1 : weightFunction(evt) / evt.genPdf() ) ); + } + return plot; +} + + +void EventListSIMD::clear() +{ + m_data.clear(); +} + +const Event EventListSIMD::operator[]( const size_t& pos ) const +{ + unsigned nEvents = size(); + unsigned p = pos / float_v::size; + unsigned q = pos % float_v::size; + Event tempEvent( eventSize() ); + for( unsigned i = 0 ; i != tempEvent.size(); ++i ) + tempEvent[i] = m_data(p, i).at(q); + tempEvent.setWeight( m_weights[p].at(q) ); + tempEvent.setGenPdf( m_genPDF[p].at(q) ); + tempEvent.setIndex( pos ); + return tempEvent; +} + +std::array EventListSIMD::scatter( unsigned pos ) const +{ + unsigned p = pos / float_v::size; + std::array rt; + auto vw = m_weights[p].to_array(); + auto vg = m_genPDF[p].to_array(); + for( unsigned evt = 0 ; evt != float_v::size; ++evt ){ + rt[evt] = Event( m_data.nFields() ); + rt[evt].setWeight(vw[evt]); + rt[evt].setGenPdf(vg[evt]); + rt[evt].setIndex(evt + pos); + } + for( unsigned field = 0 ; field != m_data.nFields(); ++field){ + auto v = m_data(p, field).to_array(); + for( unsigned evt = 0; evt != float_v::size; ++evt ) rt[evt][field] = v[evt]; + } + return rt; +} + +void EventListSIMD::gather( const std::array& data, unsigned pos ) +{ + for( unsigned field = 0; field != m_data.nFields(); ++field ) + m_data(pos, field) = utils::gather(data, [field](auto& event){ return event[field]; } ); + m_weights[pos] = utils::gather(data, [](auto& event){ return event.weight() ; } ); + m_genPDF[pos] = utils::gather(data, [](auto& event){ return event.genPdf(); } ); +} + +#endif diff --git a/src/EventType.cpp b/src/EventType.cpp index 8ee8d7d9faa..06e3e1f33f6 100644 --- a/src/EventType.cpp +++ b/src/EventType.cpp @@ -20,18 +20,22 @@ #include "AmpGen/Utilities.h" #include "AmpGen/Units.h" #include "AmpGen/Event.h" +#include "AmpGen/OptionsParser.h" using namespace AmpGen; std::string convertTeXtoROOT(std::string input); EventType::EventType( const std::vector& particleNames, const bool& isTD ) : m_timeDependent( isTD ) -{ +{ + if ( OptionsParser::printHelp() ) return; + if ( particleNames.size() < 3 ) { // Mother plus two daughters minimum required ERROR( "Not enough particles in event type: " << particleNames[0] << " size = " << particleNames.size() ); throw std::runtime_error( "Not enough particles listed in particle names! Was it defined?" ); } m_mother = particleNames.at(0); - for ( unsigned int i = 1; i < particleNames.size(); ++i ) m_particleNames.push_back( particleNames[i] ); + m_alt_part_names = NamedParameter("EventType::AlternativeParticleNames", false ); + auto motherProperties = ParticlePropertiesList::get( m_mother ); if ( motherProperties != nullptr ) m_motherMass = motherProperties->mass(); @@ -39,15 +43,27 @@ EventType::EventType( const std::vector& particleNames, const bool& ERROR( "Particle not found: " << m_mother ); return; } - for ( auto& particle : m_particleNames ) { - auto prop = ParticlePropertiesList::get( particle ); + + m_ignore.resize(particleNames.size()-1,false); + for ( auto it = particleNames.begin()+1; it != particleNames.end(); ++it ) + { + if( *it->begin() == '{' && *it->rbegin() == '}' ) + { + m_particleNames.push_back( it->substr(1, it->size() -2 ) ); + } + else m_particleNames.push_back( *it ); + + auto prop = ParticlePropertiesList::get( *m_particleNames.rbegin() ); if ( prop != nullptr ) m_particleMasses.push_back( prop->mass() ); else { - ERROR( "Particle not found: " << particle ); + FATAL( "Particle not found: " << *m_particleNames.rbegin() ); return; } - m_particleNamesPickled.push_back( replaceAll( replaceAll( particle, "+", "~" ), "-", "#" ) ); + if(m_alt_part_names) + m_particleNamesPickled.push_back( replaceAll( *m_particleNames.rbegin(), {{"+","p"},{"-","m"},{"(",""},{")",""}})); + else + m_particleNamesPickled.push_back( replaceAll( *m_particleNames.rbegin(), {{"+","~"},{"-","#"},{"(",""},{")",""}})); } DEBUG( m_mother << " = " << m_motherMass << " -> " ); for ( unsigned int i = 0; i < m_particleNames.size(); ++i ) { @@ -61,64 +77,80 @@ EventType::EventType( const std::vector& particleNames, const bool& for( auto& p : m_particleNames ) m_dim.second *= dimOfParticle(p); } -std::map EventType::getEventFormat( const bool& outputNames ) const +std::map EventType::getEventFormat( const bool& outputNames ) const { - std::map returnValue; + std::map returnValue; bool include_energy = NamedParameter("EventType::IncludeEnergy", true ); - size_t s = include_energy ? 4 : 3; + unsigned s = include_energy ? 4 : 3; for ( unsigned int ip = 0; ip < size(); ++ip ) { - std::string stub = - outputNames ? "_" + std::to_string( ip + 1 ) + "_" + m_particleNamesPickled[ip] : std::to_string( ip ); + std::string parsed_name; + if(m_alt_part_names) + //check if there are multiple identical particles + if(std::count(m_particleNamesPickled.begin(),m_particleNamesPickled.end(),m_particleNamesPickled[ip]) > 1) + //if yes, append an index + parsed_name = m_particleNamesPickled[ip] + + std::to_string(std::count(m_particleNamesPickled.begin(),m_particleNamesPickled.begin()+ip, m_particleNamesPickled[ip])); + else // just take the already chosen name + parsed_name = m_particleNamesPickled[ip]; + else + parsed_name = "_" + std::to_string( ip + 1 ) + "_" + m_particleNamesPickled[ip]; + std::string stub = outputNames ? parsed_name : std::to_string( ip ); if( include_energy ) returnValue[stub + "_E"] = s * ip + 3; returnValue[stub + "_Px"] = s * ip + 0; returnValue[stub + "_Py"] = s * ip + 1; returnValue[stub + "_Pz"] = s * ip + 2; } - if ( m_timeDependent ) returnValue[m_mother + "_ctau"] = 4 * size(); + if ( m_timeDependent ) returnValue[m_mother + "_decayTime"] = 4 * size(); for( auto& extend : m_eventTypeExtensions ) returnValue[extend] = returnValue.size(); return returnValue; } -void EventType::extendEventType( const std::string& branch ) +void EventType::extendEventType( const std::string& branch ) { m_eventTypeExtensions.push_back(branch); } -std::pair EventType::minmax( const std::vector& indices, bool isGeV ) const +std::pair EventType::minmax( const std::vector& indices) const { - std::vector ivec( size() ); + std::vector ivec( size() ); std::iota( ivec.begin(), ivec.end(), 0 ); - double min( 0 ); - double max( motherMass() ); - for ( auto& x : indices ) min += mass( x ); + double min = 0 ; + for( auto& i : indices ) min += mass(i); + double max = motherMass(); for ( auto& x : ivec ) if ( std::find( indices.begin(), indices.end(), x ) == indices.end() ) max -= mass( x ); - return std::pair( min * min / GeV, max * max / GeV ); + return std::pair(min, max); } - -std::vector> EventType::getBosePairs() const +std::pair EventType::count(const unsigned& index) const { - std::map> particleOrdering; - for ( unsigned int i = 0; i < m_particleNames.size(); ++i ) particleOrdering[m_particleNames[i]].push_back( i ); - std::vector> orderings; - for ( auto& im : particleOrdering ) - if ( im.second.size() != 1 ) orderings.push_back( im.second ); - return orderings; + if( index >= size() ){ + ERROR("Looking for matching particles to index = " << index << " > size of eventType"); + return std::pair(0, 0); + } + std::pair rt(0,0); + for( unsigned j = 0 ; j < size(); ++j ){ + if( EventType::operator[](j) == EventType::operator[](index) ){ + rt.second++; + if( j < index ) rt.first++; + } + } + return rt; } + std::vector EventType::finalStates() const { return m_particleNames; } std::vector EventType::masses() const { return m_particleMasses; } -size_t EventType::size() const { return m_particleNames.size(); } -double EventType::mass( const size_t& index ) const { return m_particleMasses[index]; } +unsigned EventType::size() const { return m_particleNames.size(); } +double EventType::mass( const unsigned& index ) const { return m_particleMasses[index]; } double EventType::motherMass() const { return m_motherMass; } std::string EventType::mother() const { return m_mother; } -std::string EventType::operator[]( const size_t& index ) const { return m_particleNames[index]; } -std::string EventType::label( const size_t& index, bool isRoot ) const +std::string EventType::operator[]( const unsigned& index ) const { return m_particleNames[index]; } +std::string EventType::label( const unsigned& index, bool isRoot ) const { const std::string label = ParticlePropertiesList::get( m_particleNames[index] )->label(); return isRoot ? convertTeXtoROOT( label ) : label; } -std::string EventType::label( const std::vector& index, bool isRoot ) const +std::string EventType::label( const std::vector& index, bool isRoot ) const { std::string thing = ""; for ( auto& x : index ) { @@ -131,53 +163,47 @@ EventType EventType::conj( const bool& headOnly, const bool& dontConjHead ) cons { std::vector type; type.push_back( dontConjHead ? m_mother : ParticlePropertiesList::get( m_mother )->anti().name() ); - - for ( auto& x : m_particleNames ) type.push_back( headOnly ? x : ParticlePropertiesList::get( x )->anti().name() ); + std::transform( m_particleNames.begin(), m_particleNames.end(), std::back_inserter(type), + [&](auto& x){ return headOnly ? x : ParticlePropertiesList::get(x)->anti().name() ; } ); return EventType( type ); } -std::vector EventType::defaultProjections(const size_t& nBins) const +std::vector EventType::defaultProjections(const unsigned& nBins) const { - bool useRootLabelling = NamedParameter( "EventType::UseRootTEX", false ); std::string defaultObservable = NamedParameter( "EventType::Observable", "mass2"); - - std::vector axes; - std::string gevcccc = useRootLabelling ? "GeV^{2}/c^{4}" : "\\mathrm{GeV}^{2}/c^{4}"; - std::string gevcc = useRootLabelling ? "GeV/c^{2}" : "\\mathrm{GeV}/c^{2}"; - for ( size_t r = 2; r < size(); ++r ) { /// loop over sizes /// - std::vector> combR = nCr( size(), r ); - for ( auto& indices : combR ) { - auto mm = minmax( indices, true ); - if( defaultObservable == "mass2" ) - axes.emplace_back( [indices]( const Event& evt ) { return evt.s( indices ); }, - "s" + vectorToString( indices ), - "s_{" + label( indices, useRootLabelling ) + "}", nBins, - ( mm.first - 0.05 ) , ( mm.second + 0.05 ) , gevcccc ); - else if( defaultObservable == "mass" ) - axes.emplace_back( [indices]( const Event& evt ) { return sqrt( evt.s( indices ) ); }, - "m" + vectorToString( indices ), - "m_{" + label( indices, useRootLabelling ) + "}", nBins, - sqrt( mm.first - 0.05 ) , sqrt( mm.second + 0.05 ) , gevcc ); - } + std::vector projections; + for ( unsigned r = 2; r < size(); ++r ) { /// loop over sizes /// + std::vector> combR = nCr( size(), r ); + std::transform( combR.begin(), combR.end(), std::back_inserter(projections), + [&](auto& index){ return this->projection(nBins, index, defaultObservable ); } ); } - return axes; + return projections; } -Projection EventType::projection(const size_t& nBins, const std::vector& indices) const +Projection EventType::projection(const unsigned& nBins, const std::vector& indices, const std::string& observable) const { - auto mm = minmax( indices, true ); - std::string gevcccc = "\\mathrm{GeV}^{2}/c^{4}"; - return Projection( [indices]( const Event& evt ) { return evt.s( indices ); }, - "s" + vectorToString(indices), - "s_{" + label(indices, false) + "}\\, \\left[" + gevcccc + "\\right]", nBins, - ( mm.first - 0.05 ) , ( mm.second + 0.05 ) , gevcccc ); + bool useRootLabelling = NamedParameter("EventType::UseRootTEX", false ); + auto mm = minmax(indices); + std::string gevcccc = useRootLabelling ? "GeV^{2}/c^{4}" : "\\mathrm{GeV}^{2}/c^{4}"; + std::string gevcc = useRootLabelling ? "GeV/c^{2}" : "\\mathrm{GeV}/c^{2}"; + if( observable == "mass2" ) + return Projection( [indices]( const Event& evt ) { return evt.s( indices ); }, + "s" + vectorToString( indices ), + "s_{" + label( indices ) + "}", nBins, + ( mm.first * mm.first - 0.05 ) , ( mm.second * mm.second + 0.05 ) , gevcccc ); + else if( observable == "mass" ){ + return Projection( [indices]( const Event& evt ) { return sqrt( evt.s( indices ) ); }, + "m" + vectorToString( indices ), + "m_{" + label( indices ) + "}", nBins, + mm.first > 0.05 ? mm.first - 0.05 :0 , mm.second + 0.05, gevcc ); + } + return Projection(); } bool EventType::operator==( const EventType& other ) const { if ( m_mother != other.mother() || size() != other.size() ) return false; - - for ( size_t i = 0; i < m_particleNames.size(); ++i ) { + for ( unsigned i = 0; i < m_particleNames.size(); ++i ) { if ( m_particleNames[i] != other[i] ) return false; } return true; @@ -189,11 +215,17 @@ std::ostream& AmpGen::operator<<( std::ostream& os, const EventType& type ) return os; } -size_t EventType::dof() const { return 3 * size() - 7; } +unsigned EventType::dof() const { return 3 * size() - 7; } std::function EventType::symmetriser() const { - auto shuffles = getBosePairs(); + std::map> particleOrdering; + for ( unsigned i = 0; i < m_particleNames.size(); ++i ) + particleOrdering[m_particleNames[i]].push_back( i ); + std::vector> shuffles; + for ( auto& im : particleOrdering ) + if ( im.second.size() != 1 ) shuffles.push_back( im.second ); + int seed = NamedParameter( "EventType::SymmetriserSeed", 12 ); std::mt19937 rng( seed ); for ( auto& shuffle : shuffles ) { @@ -201,7 +233,7 @@ std::function EventType::symmetriser() const for ( auto& s : shuffle ) shuffle_string += std::to_string( s ) + " "; DEBUG( "Shuffle = " << shuffle_string ); } - auto fcn = [shuffles, rng]( auto& event ) mutable -> void { + return [shuffles, rng]( auto& event ) mutable -> void { for ( auto shuffled : shuffles ) { for ( unsigned int index = 0; index < shuffled.size(); ++index ) { unsigned int j = std::uniform_int_distribution( 0, index )( rng ); @@ -211,21 +243,57 @@ std::function EventType::symmetriser() const } } }; - return fcn; } +std::function&)> EventType::automaticOrdering() const +{ + std::vector ids; + for( unsigned i = 0 ; i != m_particleNames.size(); ++i ) ids.push_back( ParticleProperties::get(m_particleNames[i])->pdgID() ); + auto matches = [](const auto& c1, const auto& c2 , unsigned sgn = +1) + { + std::vector used( c1.size(), false ); + for(unsigned i = 0; i != c1.size(); ++i ) + { + for( unsigned j = 0; j != c2.size(); ++j ) + { + if( c1[i] == sgn * c2[j] && ! used[j] ) used[j] = true; + } + } + return std::all_of( std::begin(used), std::end(used), [](auto b) { return b; } ) ; + }; + + return [ids, matches](auto& event, const auto& actual_ids) -> bool { + std::vector new_addresses( ids.size(), 999 ); + int sgn = +1; + if( matches(ids, actual_ids ) ) sgn = +1; + else if( matches(ids, actual_ids, -1 ) ) sgn = -1; + else { ERROR("Ids: " << vectorToString(actual_ids, " ") << " do not match either particle or antiparticle ["<< vectorToString(ids, " ") << "]" ); + return false; + } + + for( unsigned i = 0 ; i != ids.size(); ++i ) + { + for( unsigned j = 0 ; j != actual_ids.size(); ++j ) + { + if( actual_ids[j] == sgn * ids[i] && new_addresses[j]==999 ){ new_addresses[j] = i; break ; } + } + } + event.reorder( new_addresses ); + return true; + }; +} + + bool EventType::has( const std::string& name ) const { - for ( auto& it : m_particleNames ) - if ( it == name ) return true; - return false; + return std::any_of( m_particleNames.begin(), m_particleNames.end(), [&name](auto& it) { return it == name ; } ); } bool EventType::isTimeDependent() const { return m_timeDependent; } -size_t EventType::eventSize() const { return 4 * size() + m_timeDependent; } +unsigned EventType::eventSize() const { return 4 * size() + m_timeDependent; } -std::pair EventType::dim() const { return m_dim; } +std::pair EventType::dim() const { return m_dim; } std::string convertTeXtoROOT( std::string input ) { @@ -237,3 +305,7 @@ std::string convertTeXtoROOT( std::string input ) return input; } +std::string EventType::decayDescriptor() const +{ + return mother()+"{" + vectorToString(m_particleNames,",") +"}" ; +} diff --git a/src/Expression.cpp b/src/Expression.cpp index 0b11d8ca339..930bfb13822 100644 --- a/src/Expression.cpp +++ b/src/Expression.cpp @@ -15,14 +15,19 @@ #include "AmpGen/MetaUtils.h" #include "AmpGen/MsgService.h" #include "AmpGen/Types.h" - +#include "AmpGen/simd/utils.h" +#include "AmpGen/CompiledExpressionBase.h" using namespace AmpGen; +using namespace AmpGen::fcn; +using namespace std::complex_literals; -DEFINE_CAST( Constant ) -DEFINE_CAST( Parameter ) -DEFINE_CAST( SubTree ) -DEFINE_CAST( Ternary ) -DEFINE_CAST( Function ) +DEFINE_CAST(Constant ) +DEFINE_CAST(Parameter ) +DEFINE_CAST(SubTree ) +DEFINE_CAST(Ternary ) +DEFINE_CAST(Function ) +DEFINE_CAST(ComplexParameter); +DEFINE_CAST(LambdaExpression); Expression::Expression( const std::shared_ptr& expression ) : m_expression( expression ) {} @@ -49,13 +54,18 @@ bool isZero( const complex_t& A ){ std::string Constant::to_string(const ASTResolver* resolver) const { auto rounded_string = [](const double& val ){ - std::string str = std::to_string (val); - str.erase ( str.find_last_not_of('0') + 1, std::string::npos ); - return str; + std::string str = mysprintf("%g", val); + return str.find(".") != std::string::npos or str.find("e") != std::string::npos ? str : str + "."; }; - std::string complex_type_string = resolver != nullptr && resolver->enableCuda() ? "ampgen_cuda::complex_t" : typeof() ; - return std::imag( m_value ) == 0 ? "(" + rounded_string(std::real(m_value)) +")" : - complex_type_string +"("+rounded_string(std::real(m_value))+","+rounded_string(std::imag(m_value))+")"; + std::string complex_type = type_string(); + std::string literalSuffix = ""; + if( resolver != nullptr && (resolver->enableCuda() || resolver->enableAVX()) ) + { + literalSuffix = "f"; + complex_type = type_string(); + } + return std::imag(m_value) == 0 ? "(" + rounded_string(std::real(m_value)) +literalSuffix + ")" : + complex_type +"("+rounded_string(std::real(m_value))+literalSuffix+","+rounded_string(std::imag(m_value))+literalSuffix+")"; } Expression simplify_constant_addition( const Constant& constant, const Expression& expression ) @@ -147,16 +157,8 @@ Expression AmpGen::operator/( const Expression& A, const Expression& B ) if( is( as_prod.l() ) ) return ( Constant( 1./as_prod.l()() ) * A )/ as_prod.r(); if( is( as_prod.r() ) ) return ( Constant( 1./as_prod.r()() ) * A )/ as_prod.l(); } -// else if( is(A) ) { -// auto A_divide = cast(A); -// if( is(B) ){ -// auto B_divide = cast(B); -// return Divide( A_divide.l() * B_divide.r() , ( A_divide.r() * B_divide.l() ) ); -// } -// return A_divide.l() * B / A_divide.r() ; -// } else if( is(B) ) return ( A * cast(B).r() ) / cast(B).l(); - else if( is(B) ) return ( A * fcn::isqrt( cast(B).arg() ) ); +// else if( is(B) ) return ( A / fcn::sqrt( cast(B).arg() ) ); return Expression( Divide( A, B ) ); } Expression AmpGen::operator&&( const Expression& A, const Expression& B ) { return Expression( And( A, B ) ); } @@ -165,12 +167,14 @@ Expression AmpGen::operator==( const Expression& A, const Expression& B ){ retur Expression AmpGen::operator==( const double& A, const Expression& B ){ return Constant(A) == B ; } Expression AmpGen::operator==( const Expression& A, const double& B ){ return A == Constant(B) ; } -Parameter::Parameter( const std::string& name, const double& defaultValue, const bool& resolved, - const unsigned int& fromArg ) +Expression AmpGen::operator||( const Expression& A, const Expression& B){ return Expression( Or(A,B)) ; } +Expression AmpGen::operator<=( const Expression& A, const Expression& B ){ return LessThanEqualTo(A,B) ; } +Expression AmpGen::operator>=( const Expression& A, const Expression& B ){ return GreaterThanEqualTo(A,B) ; } + +Parameter::Parameter( const std::string& name, const double& defaultValue, const bool& resolved) : m_name( name ) , m_defaultValue( defaultValue ) , m_resolved( resolved ) - , m_fromArg( fromArg ) { } @@ -187,21 +191,21 @@ Expression AmpGen::operator>( const Expression& A, const Expression& B ) { retur Expression Expression::operator-() const { return Constant( -1. ) * m_expression; } -Expression Expression::operator+=( const Expression& other ) const { return *this + other ; } -Expression Expression::operator-=( const Expression& other ) const { return *this - other ; } -Expression Expression::operator*=( const Expression& other ) const { return *this * other ; } -Expression Expression::operator/=( const Expression& other ) const { return *this / other; } +Expression Expression::operator+=(const Expression& other) { *this = *this + other; return *this; } +Expression Expression::operator-=(const Expression& other) { *this = *this - other; return *this; } +Expression Expression::operator*=(const Expression& other) { *this = *this * other; return *this; } +Expression Expression::operator/=(const Expression& other) { *this = *this / other; return *this; } std::ostream& AmpGen::operator<<( std::ostream& os, const Expression& expression ) { return os << expression.to_string() ; } Expression::Expression( const double& value ) : m_expression( std::make_shared( value ) ) {} Expression::Expression( const complex_t& value ) : m_expression( std::make_shared( value ) ) {} Expression::Expression() : m_expression( std::make_shared( 0. ) ) {} -void Expression::resolve( ASTResolver& resolver ) { m_expression->resolve( resolver ); } +void Expression::resolve( ASTResolver& resolver ) const { m_expression->resolve( resolver ); } -void Constant::resolve( ASTResolver& resolver ) {} +void Constant::resolve( ASTResolver& resolver ) const {} -void Parameter::resolve( ASTResolver& resolver ) +void Parameter::resolve( ASTResolver& resolver ) const { if( !m_resolved ) resolver.resolve(*this); } @@ -212,10 +216,12 @@ Ternary::Ternary( const Expression& cond, const Expression& v1, const Expression } std::string Ternary::to_string(const ASTResolver* resolver) const { - return "(" + m_cond.to_string(resolver) + "?" + m_v1.to_string(resolver) + ":" + m_v2.to_string(resolver) + ")"; + return resolver != nullptr && resolver->enableAVX() ? "select(" + m_cond.to_string(resolver) + ", " + + m_v1.to_string(resolver) + ", " + m_v2.to_string(resolver) +")" + : "(" + m_cond.to_string(resolver) + "?" + m_v1.to_string(resolver) + ":" + m_v2.to_string(resolver) + ")"; } -void Ternary::resolve( ASTResolver& resolver ) +void Ternary::resolve( ASTResolver& resolver ) const { m_cond.resolve( resolver ); m_v1.resolve( resolver ); @@ -238,17 +244,16 @@ std::string Function::to_string(const ASTResolver* resolver) const { for( auto& arg : m_args ) rt += arg.to_string(resolver) + ", "; return rt.substr(0,rt.size()-2) + ")"; } -void Function::resolve( ASTResolver& resolver ) {} +void Function::resolve( ASTResolver& resolver ) const {} std::string SubTree::to_string(const ASTResolver* /*resolver*/) const { return "v"+ std::to_string(key()); } -void SubTree::resolve( ASTResolver& resolver ) +void SubTree::resolve( ASTResolver& resolver ) const { resolver.resolve( *this ); - m_expression.resolve( resolver ); } Expression AmpGen::make_cse( const Expression& A , bool simplify ) @@ -304,7 +309,7 @@ Expression AmpGen::fcn::complex_sqrt( const Expression& expression ) { if( is(expression ) ) return sqrt( expression() ); auto st = make_cse(expression); - return Ternary( st > 0, Sqrt(st), Constant(0,1)*Sqrt(-st) ); + return Ternary( st > 0, Sqrt(st), 1i*Sqrt(-st) ); } Expression AmpGen::fcn::isqrt( const Expression& expression ) @@ -319,3 +324,41 @@ Expression AmpGen::fcn::fpow( const Expression& x, const int& n){ for( int y=0;y(); + if( resolver != nullptr && (resolver->enableCuda() || resolver->enableAVX()) ) complex_type = type_string(); + return complex_type + "(" + m_real.to_string(resolver) + ", " + m_imag.to_string(resolver) +")"; +} + +void ComplexParameter::resolve( ASTResolver& resolver ) const +{ + m_real.resolve(resolver); + m_imag.resolve(resolver); +} + +complex_t ComplexParameter::operator()() const +{ + return m_real() + 1i * m_imag(); +} + +std::string LambdaExpression::to_string(const ASTResolver* resolver) const +{ + return resolver == nullptr ?programatic_name(m_name) : resolver->resolvedParameter(this); +} + +complex_t LambdaExpression::operator()() const +{ + return m_function(); +} + +void LambdaExpression::resolve(ASTResolver& resolver) const { + resolver.resolve(*this); +} + + + diff --git a/src/ExpressionParser.cpp b/src/ExpressionParser.cpp index 172281e7251..4c9c2cba2b8 100644 --- a/src/ExpressionParser.cpp +++ b/src/ExpressionParser.cpp @@ -9,16 +9,26 @@ #include "AmpGen/Utilities.h" #include "AmpGen/MinuitParameter.h" #include "AmpGen/ASTResolver.h" +#include "AmpGen/enum.h" +#include "AmpGen/NamedParameter.h" +#include "AmpGen/Tensor.h" using namespace AmpGen; +using namespace std::complex_literals; DEFINE_CAST( MinuitParameterLink ) DEFINE_CAST( ExpressionPack ) +namespace AmpGen +{ + complete_enum(coordinateType, cartesian, polar) + complete_enum(angType, deg, rad) +} + void ExpressionParser::processBinaryOperators( std::vector& opCodes, std::vector& expressions ) { for ( auto& fcn : m_binaryFunctions ) { - for ( int pos = 0; pos < (int)opCodes.size(); ++pos ) { + for ( int pos = 0; pos < int(opCodes.size()); ++pos ) { if ( opCodes[pos] != fcn.first ) continue; expressions[pos] = fcn.second( expressions[pos], expressions[pos + 1] ); expressions.erase( expressions.begin() + pos + 1 ); @@ -30,7 +40,7 @@ void ExpressionParser::processBinaryOperators( std::vector& opCodes void ExpressionParser::processUnaryOperators( std::vector& opCodes, std::vector& expressions ) { - for ( int pos = 0; pos < (int)opCodes.size(); ++pos ) { + for ( int pos = 0; pos < int(opCodes.size()); ++pos ) { auto fcn = m_unaryFunctions.find( opCodes[pos] ); DEBUG( " op = " << opCodes[pos] << " pos = " << pos ); if ( fcn == m_unaryFunctions.end() ) continue; @@ -40,40 +50,99 @@ void ExpressionParser::processUnaryOperators( std::vector& opCodes, } } -Expression ExpressionParser::parseTokens( const std::vector& tokens ) +using iterator = std::vector::const_iterator; + +template iterator findMatchingBracket(iterator begin, iterator end ) { - int nOpenedBrackets = 0; - std::vector> expressions; - expressions.push_back( std::vector() ); - for ( auto iToken = tokens.begin(); iToken != tokens.end(); ++iToken ) { - auto& token = *iToken; - expressions.rbegin()->push_back( token ); - if ( token == "(" ) nOpenedBrackets++; - if ( token == ")" ) nOpenedBrackets--; - if ( nOpenedBrackets == 0 && iToken != tokens.end() - 1 ) expressions.push_back( std::vector() ); + int openedBrackets = 1; + if( begin + 1 >= end ) return end; + for( auto it = begin+1; it != end; ++it ) + { + openedBrackets += ( it->at(0) == open) -( it->at(0) == close ); + if( openedBrackets == 0 ) return it; } - for ( auto& eC : expressions ) { - if ( eC.size() > 2 && *eC.begin() == "(" && *eC.rbegin() == ")" ) { - eC.erase( eC.end() - 1 ); - eC.erase( eC.begin() ); + for( auto it = begin; it != end; ++it ) + { + std::cout << *it << " "; + } + std::cout << std::endl; + FATAL("Unmatched brace in expression, " << open << " " << close); + return end; +} + +/// divides strings by a delimiter, allowing for bracketing rules +std::vector< std::pair > split_it( iterator begin, iterator end, const std::string& delimiter) +{ + std::vector> rt; + rt.emplace_back(begin, nullptr); + int b1l = 0; + int b2l = 0; + for( auto it = begin; it != end-1; ++it ) + { + b1l += ( it->at(0) == '(') - (it->at(0) == ')'); + b2l += ( it->at(0) == '{') - (it->at(0) == '}'); + if( *it == delimiter && b1l == 0 && b2l == 0 ) + { + rt.rbegin()->second = it; + // INFO( *it << " " << std::distance( begin, rt.rbegin()->first) << " " << std::distance( begin, rt.rbegin()->second) ); + rt.emplace_back( it+1, nullptr ); } } - if ( expressions.size() == 1 ) return processEndPoint( expressions[0][0] ); + rt.rbegin()->second = end; + return rt; +} + +std::string merge( iterator begin, iterator end) +{ + std::string total = ""; + for( auto it = begin; it != end; ++it ) total += *it + " "; + return total; +} +Expression ExpressionParser::parseTokens(std::vector::const_iterator begin, + std::vector::const_iterator end, + const MinuitParameterSet* mps ) +{ std::vector opCodes; - std::vector parsedExpressions; - for ( size_t pos = 0; pos < expressions.size(); pos++ ) { - if ( pos % 2 == expressions.size() % 2 ) - opCodes.push_back( expressions[pos][0] ); - else - parsedExpressions.push_back( parseTokens( expressions[pos] ) ); + std::vector expressions; + for( auto it = begin; it != end; ++it ) + { + if( it->at(0) == '(' ){ + auto begin_2 = it; + auto end_2 = findMatchingBracket<'(',')'>(it, end); + expressions.emplace_back( parseTokens(begin_2+1, end_2, mps) ); + it = end_2; + } + else if ( it->at(0) == '{' ) + { + auto begin_2 = it; + auto end_2 = findMatchingBracket<'{','}'>(it, end); + auto divided = split_it( begin_2+1, end_2, ","); + Tensor v( std::vector{static_cast(divided.size())} ); + for( unsigned int i = 0 ; i != divided.size(); ++i ) + { + v[i] = parseTokens( divided[i].first, divided[i].second, mps); + } + DEBUG( "Adding tensor: " << v.to_string() ); + expressions.emplace_back(TensorExpression(v)); + it = end_2; + } + else { + auto f = std::find_if(m_binaryFunctions.begin(), m_binaryFunctions.end(), [it](auto& jt){ return jt.first == *it; } ); + if( f != m_binaryFunctions.end() || m_unaryFunctions.count(*it) ) opCodes.push_back(*it); + else expressions.push_back( processEndPoint( *it , mps ) ); + } } - processUnaryOperators( opCodes, parsedExpressions ); - processBinaryOperators( opCodes, parsedExpressions ); - return parsedExpressions[0]; + DEBUG( "nExpressions = " << expressions.size() << " nOpCodes = " << opCodes.size() << " " << vectorToString( opCodes, " " ) ); + processUnaryOperators( opCodes, expressions ); + processBinaryOperators( opCodes, expressions ); + if( expressions.size() != 1 ){ + ERROR("Could not process expression: n = " << expressions.size() << " " << merge(begin, end) ); + } + return expressions[0]; } -ExpressionParser::ExpressionParser() : m_mps( nullptr ) +ExpressionParser::ExpressionParser() { add_unary( "sin" ); /// "function" operator ordering is irrelevant add_unary( "cos" ); @@ -86,62 +155,99 @@ ExpressionParser::ExpressionParser() : m_mps( nullptr ) add_unary( "sqrt" ); add_unary( "exp" ); add_unary( "log" ); + add_unary("real"); + add_unary("imag"); + add_unary("abs"); + + add_binary( "^" , [](auto& A, auto& B ) { return fcn::pow(A,B); } ); + add_binary( "/" , [](auto& A, auto& B ) { return A / B; } ); + add_binary( "*" , [](auto& A, auto& B ) { return A * B; } ); + add_binary( "-" , [](auto& A, auto& B ) { return A - B; } ); + add_binary( "+" , [](auto& A, auto& B ) { return A + B; } ); + add_binary( ">" , [](auto& A, auto& B ) { return A > B; } ); + add_binary( "<" , [](auto& A, auto& B ) { return A < B; } ); + add_binary( "&&", [](auto& A, auto& B ) { return A && B; } ); + add_binary( "," , [](auto& A, auto& B ) { return ExpressionPack( A, B ); } ); + + coordinateType coord = NamedParameter("CouplingConstant::Coordinates", coordinateType::cartesian); + angType degOrRad = NamedParameter("CouplingConstant::AngularUnits", angType::rad); + m_isCartesian = true; + if( coord == coordinateType::polar ) m_isCartesian = false; + else if ( coord != coordinateType::cartesian){ + FATAL("Coordinates for coupling constants must be either cartesian or polar"); + } + if ( degOrRad == angType::deg) m_sf = M_PI / 180; + else if ( degOrRad != angType::rad){ + FATAL("CouplingConstant::AngularUnits must be either rad or deg"); + } - add_binary( "/", []( auto& A, auto& B ) { return A / B; } ); /// operator ordering here matters! - add_binary( "*", []( auto& A, auto& B ) { return A * B; } ); - add_binary( "+", []( auto& A, auto& B ) { return A + B; } ); - add_binary( "-", []( auto& A, auto& B ) { return A - B; } ); - add_binary( ">", []( auto& A, auto& B ) { return A > B; } ); - add_binary( "<", []( auto& A, auto& B ) { return A < B; } ); - add_binary( "&&", []( auto& A, auto& B ) { return A && B; } ); - add_binary( ",", []( auto& A, auto& B ) { return ExpressionPack( A, B ); } ); } -Expression ExpressionParser::Parse( const std::string& str ) { return getMe()->parseTokens( split( str, ' ' ) ); } +Expression ExpressionParser::parse( + std::vector::const_iterator begin, + std::vector::const_iterator end, + const MinuitParameterSet* mps ) { + return getMe()->parseTokens(begin, end, mps ); +} +Expression ExpressionParser::parse( + const std::string& expr, + const MinuitParameterSet* mps ) { + auto tokens = split( expr , ' ' ); + return getMe()->parseTokens(tokens.cbegin(), tokens.cend() , mps ); +} + ExpressionParser* ExpressionParser::gExpressionParser = nullptr; -Expression ExpressionParser::processEndPoint( const std::string& name ) +Expression ExpressionParser::processEndPoint( const std::string& name, const MinuitParameterSet* mps ) { bool status = true; double value = lexical_cast( name, status ); - if ( status == true ) return Constant( value ); - if ( name == "PI" ) return Constant( M_PI ); - if ( name == "pi" ) return Constant( M_PI ); - if ( name == "e" ) return Constant( std::exp(1) ); - if ( name == "I" ) return Constant( 0, 1 ); - if ( name == "i" ) return Constant( 0, 1 ); - - if ( m_mps != nullptr ) { - auto map = m_mps->map(); - auto it = map.find( name ); - if ( it != map.end() ) - return MinuitParameterLink( it->second ); - else { - WARNING( "Token not understood: " << name << " [map size = " << map.size() << "]" ); - for ( auto& ip : map ) INFO( "map entry = " << ip.first ); + if ( status == true ) return value; + if ( name == "PI" || name == "pi" || name == "M_PI" ) return M_PI; + if ( name == "e" ) return std::exp(1); + if ( name == "I" || name == "i" ) return complex_t( 0, 1 ); + if ( mps != nullptr ) { + auto it = mps->find(name); + if ( it != nullptr ) return MinuitParameterLink( it ); + else if ( mps->find(name+"_Re") != nullptr && mps->find(name+"_Im") != nullptr ) { + if( m_isCartesian ) return MinuitParameterLink( mps->find(name+"_Re") ) + 1i * MinuitParameterLink( mps->find(name+"_Im") ); + else return MinuitParameterLink( mps->find(name+"_Re") ) * fcn::exp( m_sf * 1i *MinuitParameterLink( mps->find(name+"_Im") ) ); + } + else { + WARNING( "Token not understood: " << name << " [map size = " << mps->size() << "]" ); } } return Parameter( name, 0, true ); } MinuitParameterLink::MinuitParameterLink( MinuitParameter* param ) : m_parameter( param ) {} + std::string MinuitParameterLink::to_string(const ASTResolver* resolver) const { - return resolver == nullptr ? m_parameter->name() : resolver->resolvedParameter(this); + if( resolver == nullptr ) return m_parameter->name(); + if( resolver->enableCompileConstants() && m_parameter != nullptr && m_parameter->flag () == Flag::CompileTimeConstant ) + return std::to_string( m_parameter->mean() ); + return resolver->resolvedParameter(this); } std::string MinuitParameterLink::name() const { return m_parameter->name(); } -void MinuitParameterLink::resolve( ASTResolver& resolver ) +void MinuitParameterLink::resolve( ASTResolver& resolver ) const { - resolver.resolve(*this); + if( m_parameter->flag() != Flag::CompileTimeConstant ) resolver.resolve(*this); } -complex_t MinuitParameterLink::operator()() const { +complex_t MinuitParameterLink::operator()() const +{ if( m_parameter == nullptr ) ERROR("Parameter does not have end-point"); - return m_parameter->mean(); } + return m_parameter->mean(); +} + +const MinuitParameter& MinuitParameterLink::param() const { + return *m_parameter ; +} ExpressionPack::ExpressionPack( const Expression& A, const Expression& B ) { @@ -156,6 +262,7 @@ ExpressionPack::ExpressionPack( const Expression& A, const Expression& B ) } else m_expressions.push_back( B ); } + std::string ExpressionPack::to_string(const ASTResolver* resolver) const { std::string rt = ""; @@ -165,7 +272,7 @@ std::string ExpressionPack::to_string(const ASTResolver* resolver) const return rt.substr( 0, rt.length() - 2 ); } -void ExpressionPack::resolve( ASTResolver& resolver ) +void ExpressionPack::resolve( ASTResolver& resolver ) const { for ( auto& expr : m_expressions ) expr.resolve( resolver ); } diff --git a/src/FastDT.cpp b/src/FastDT.cpp index f5dc428b2a8..9d2a068917c 100644 --- a/src/FastDT.cpp +++ b/src/FastDT.cpp @@ -4,6 +4,10 @@ using namespace AmpGen; +FastDT::FastDT( const std::string& fname ){ + //std::ifstream s(fname); +} + int FastDT::findNode( const double* event ) { int address = m_nodes.size()-1; @@ -16,9 +20,6 @@ int FastDT::findNode( const double* event ) return m_nodes[address].left; } -FastDT::FastDT( const std::string& fname ){ - std::ifstream s(fname); -} double nnVariance(std::vector& evts, const size_t& index) { diff --git a/src/FitFraction.cpp b/src/FitFraction.cpp index 8ad62890824..f064e2d7750 100644 --- a/src/FitFraction.cpp +++ b/src/FitFraction.cpp @@ -11,19 +11,14 @@ using namespace AmpGen; -FitFraction::FitFraction( const std::string& line, const EventType& evtType ) +FitFraction::FitFraction( const std::string& line ) { auto tokens = split( line, ' ' ); m_name = tokens[1]; m_value = stod( tokens[2] ); m_error = stod( tokens[3] ); - if ( evtType.size() != 0 ) { - std::vector finalStates = evtType.finalStates(); - } } -std::shared_ptr FitFraction::particle() const { return std::make_shared( m_name ); } - FitFraction::FitFraction( const std::string& name, const double& frac, const double& err ) : m_name( name ), m_value( frac ), m_error( err ) { diff --git a/src/FitResult.cpp b/src/FitResult.cpp index dfd54c36dc0..1e30bed851e 100644 --- a/src/FitResult.cpp +++ b/src/FitResult.cpp @@ -23,58 +23,78 @@ using namespace AmpGen; -FitResult::FitResult( const std::string& filename, const EventType& evtType ) +FitResult::FitResult() = default; + +FitResult::FitResult( const FitResult& other ) + : m_mps( other.mps() ) + , m_chi2( other.chi2() ) + , m_LL( other.LL() ) + , m_nBins( other.nBins() ) + , m_nParam( other.nParam() ) + , m_status( other.status() ) + , m_observables( other.observables() ) + , m_fitFractions( other.fitFractions() ) + , m_covarianceMatrix(other.cov()) { - m_eventType = evtType; - m_fitted = readFile( filename ); } -std::string FitResult::getLastLine( std::ifstream& in ) const +FitResult::FitResult( const std::string& filename ) : + m_mps( new MinuitParameterSet() ) { - std::string line; - while ( in >> std::ws && std::getline( in, line ) ) - ; - return line; + m_fitted = readFile( filename ); } -bool FitResult::readFile( const std::string& fname ) +FitResult::FitResult( const Minimiser& mini ) + : m_mps ( mini.parSet() ) + , m_LL ( mini.FCN() ) + , m_nParam( 0 ) + , m_status( mini.status() ) + , m_covarianceMatrix( mini.covMatrixFull() ) { + for (size_t i = 0; i < m_mps->size(); ++i ) { + if ( m_mps->at(i)->isFree() ) m_nParam++; + m_covMapping[ m_mps->at(i)->name() ] = i; + } +} + +FitResult::FitResult( MinuitParameterSet& mps, const TMatrixD& covMini ) : m_mps(&mps) { - std::ifstream CHECK( fname ); - if ( !CHECK.is_open() || CHECK.peek() == std::ifstream::traits_type::eof() ) { - return false; + if ( int( mps.size() ) != covMini.GetNcols() ) { + ERROR( "Minuit parameter set size does not match covariance matrix size!" ); } - if ( getLastLine( CHECK ) != "End Log" ) { - ERROR( "File not properly close " << fname ); - return false; + m_covarianceMatrix.ResizeTo( covMini.GetNcols(), covMini.GetNrows() ); + m_covarianceMatrix = covMini; + for (size_t i = 0; i < m_mps->size(); ++i ) { + if ( m_mps->at(i)->isFree()) m_nParam++; } - CHECK.close(); +} - // auto lines = vectorFromFile( fname ); +bool FitResult::readFile( const std::string& fname ) +{ + std::ifstream checkIsClosed( fname ); + if ( !checkIsClosed.is_open() + || checkIsClosed.peek() == std::ifstream::traits_type::eof() ) return false; + checkIsClosed.close(); + auto lines = vectorFromFile(fname); + if( *lines.rbegin() != "End Log" ){ + ERROR("File not properly closed: " << *lines.rbegin() ); + return false; + } std::vector parameterLines; - - processFile( fname, [this, ¶meterLines]( auto& line ) { + for( auto& line : lines ){ const std::string name = split( line, ' ' )[0]; - if ( name == "Parameter" ) - parameterLines.push_back( line ); - else if ( name == "FitQuality" ) - this->setFitQuality( line ); - else if ( name == "FitFraction" ) - this->m_fitFractions.emplace_back( line, m_eventType ); - else if ( name == "Observable" ) - this->addToObservables( line ); - } ); - - unsigned int nParameters = parameterLines.size(); - + if ( name == "Parameter" ) parameterLines.push_back( line ); + else if ( name == "FitQuality" ) this->setFitQuality( line ); + else if ( name == "FitFraction" ) this->m_fitFractions.emplace_back(line); + else if ( name == "Observable" ) this->addToObservables( line ); + } + size_t nParameters = parameterLines.size(); m_covarianceMatrix.ResizeTo( parameterLines.size(), parameterLines.size() ); - m_mps = std::make_shared(); - for ( unsigned int i = 0; i < nParameters; ++i ) { + for (size_t i = 0; i < nParameters; ++i ) { auto tokens = split( parameterLines[i], ' ' ); m_covMapping[tokens[1]] = i; - m_mps->add( new MinuitParameter( tokens[1], MinuitParameter::Flag(stoi( tokens[2] ) ), stod( tokens[3] ), stod( tokens[4] ), 0, 0 ) ); - for ( unsigned int j = 0; j < nParameters; ++j ) m_covarianceMatrix( i, j ) = stod( tokens[5 + j] ); + m_mps->add( new MinuitParameter( tokens[1], parse(tokens[2]), stod( tokens[3] ), stod( tokens[4] ), 0, 0 ) ); + for (size_t j = 0; j < nParameters; ++j ) m_covarianceMatrix( i, j ) = stod( tokens[5 + j] ); } - return true; } @@ -83,8 +103,8 @@ void FitResult::setFitQuality( const std::string& line ) auto tokens = split( line, ' ' ); bool status=true; if( tokens.size() != 6 ){ - WARNING("Cannot pass FitQuality line: " << line ); - return; + WARNING("Cannot pass FitQuality line: " << line ); + return; } m_chi2 = lexical_cast( tokens[1] , status ); m_nBins = lexical_cast( tokens[2] , status ); @@ -92,6 +112,7 @@ void FitResult::setFitQuality( const std::string& line ) m_LL = lexical_cast( tokens[4] , status ); m_status = lexical_cast ( tokens[5] , status ); } + void FitResult::addToObservables( const std::string& line ) { auto tokens = split( line, ' ' ); @@ -104,55 +125,22 @@ void FitResult::writeToFile( const std::string& fname ) { std::ofstream outlog; outlog.open( fname ); - - for ( int i = 0; i < m_covarianceMatrix.GetNrows(); ++i ) { - auto param = m_mps->getParPtr( i ); + for (size_t i = 0; i < (size_t)m_covarianceMatrix.GetNrows(); ++i ) { + auto param = m_mps->at(i); outlog << "Parameter" - << " " << param->name() << " " << param->iFixInit() << " " << param->mean() << " " - << m_mps->getParPtr( i )->err() << " "; - for ( int j = 0; j < m_covarianceMatrix.GetNcols(); ++j ) outlog << m_covarianceMatrix[i][j] << " "; + << " " << param->name() << " " << to_string(param->flag()) << " " << param->mean() << " " + << ( param->isFree() ? m_mps->at(i)->err() : 0 ) << " "; + for (size_t j = 0; j < (size_t)m_covarianceMatrix.GetNcols(); ++j ) outlog << m_covarianceMatrix[i][j] << " "; outlog << std::endl; } outlog << std::setprecision( 8 ); - outlog << "FitQuality " << m_chi2 << " " << m_nBins << " " << m_nParam << " " << m_LL << " " << m_status << "\n"; - for ( auto& p : m_fitFractions ) { - outlog << "FitFraction " << p.name() << " " << p.val() << " " << p.err() << "\n"; - } - for ( auto& ob : m_observables ) { - outlog << "Observable " << ob.first << " " << ob.second << "\n"; - } + outlog << "FitQuality " << m_chi2 << " " << m_nBins << " " << m_nParam << " " << m_LL << " " << m_status << "\n"; + for ( auto& f : m_fitFractions ) outlog << "FitFraction " << f.name() << " " << f.val() << " " << f.err() << "\n"; + for ( auto& o : m_observables ) outlog << "Observable " << o.first << " " << o.second << "\n"; outlog << "End Log\n"; outlog.close(); } -FitResult::FitResult( const Minimiser& mini ) -{ - m_mps = std::make_shared( *mini.parSet() ); - m_LL = mini.FCN(); - auto M = mini.covMatrixFull(); - m_covarianceMatrix.ResizeTo( M.GetNcols(), M.GetNrows() ); - m_covarianceMatrix = M; - m_status = mini.status(); - m_nParam = 0; - for ( unsigned int i = 0; i < m_mps->size(); ++i ) { - if ( m_mps->getParPtr( i )->iFixInit() == 0 ) m_nParam++; - m_covMapping[ m_mps->getParPtr(i)->name() ] = i; - } -} - -FitResult::FitResult( const MinuitParameterSet& mps, const TMatrixD& covMini ) : FitResult() -{ - m_mps = std::make_shared( mps ); - if ( int( mps.size() ) != covMini.GetNcols() ) { - ERROR( "Minuit parameter set size does not match covariance matrix size!" ); - } - m_covarianceMatrix.ResizeTo( covMini.GetNcols(), covMini.GetNrows() ); - m_covarianceMatrix = covMini; - for ( unsigned int i = 0; i < m_mps->size(); ++i ) { - if ( m_mps->getParPtr( i )->iFixInit() == 0 ) m_nParam++; - } -} - void FitResult::print() const { INFO( "Chi2 per bin = " << m_chi2 / m_nBins ); @@ -161,56 +149,33 @@ void FitResult::print() const INFO( "Fit Status = " << m_status ); } -FitResult::FitResult( const FitResult& other ) - : m_chi2( other.chi2() ) - , m_LL( other.LL() ) - , m_nBins( other.nBins() ) - , m_nParam( other.nParam() ) - , m_status( other.status() ) - , m_eventType( other.eventType() ) - , m_observables( other.observables() ) - , m_fitFractions( other.fitFractions() ) - , m_mps( std::make_shared( *other.mps() ) ) -{ - m_covarianceMatrix.ResizeTo( other.cov().GetNrows(), other.cov().GetNcols() ); - m_covarianceMatrix = other.cov(); -} - -std::vector FitResult::getParameters() const +std::vector FitResult::parameters() const { - std::vector params; - for ( auto& param : *m_mps ) params.push_back( param ); + std::vector params( m_mps->size() ); + std::copy( m_mps->begin(), m_mps->end(), params.begin() ); return params; } -std::vector FitResult::getFloating( const bool& extended ) const +std::vector FitResult::floating( const bool& extended ) const { std::vector floating; for ( auto& param : *m_mps ) { - if ( ( param->iFixInit() == 0 || extended ) && param->err() > 1e-6 ) floating.push_back( param ); - } - /* - if( extended ){ - DEBUG("Got extended error propagator:"); - for( auto& param : floating ){ - INFO( param->name() ); - } + if ( ( param->isFree() || extended ) && param->err() > 1e-6 ) floating.push_back( param ); } - */ return floating; } TMatrixD FitResult::getReducedCovariance( const bool& extended ) const { std::vector floating_indices; - for ( unsigned int i = 0; i < m_mps->size(); ++i ) { - auto param = m_mps->getParPtr( i ); - if ( ( param->iFixInit() == 0 || extended ) && param->err() > 1e-6 ) floating_indices.push_back( i ); + for (size_t i = 0; i < m_mps->size(); ++i ) { + auto param = m_mps->at(i); + if ( ( param->isFree() || extended ) && param->err() > 1e-6 ) floating_indices.push_back( i ); } TMatrixD reducedCov( floating_indices.size(), floating_indices.size() ); if ( int( floating_indices.size() ) > m_covarianceMatrix.GetNrows() ) { ERROR( "Looking for more floating indices than real indices: " << m_covarianceMatrix.GetNrows() << " " - << floating_indices.size() ); + << floating_indices.size() ); return reducedCov; } for ( unsigned int i = 0; i < floating_indices.size(); ++i ) { @@ -223,7 +188,7 @@ TMatrixD FitResult::getReducedCovariance( const bool& extended ) const LinearErrorPropagator FitResult::getErrorPropagator( const bool& extended ) const { - return LinearErrorPropagator( getReducedCovariance( extended ), getFloating( extended ) ); + return LinearErrorPropagator( getReducedCovariance( extended ), floating( extended ) ); } void FitResult::addChi2( const double& chi2, const double& nBins ) @@ -232,4 +197,39 @@ void FitResult::addChi2( const double& chi2, const double& nBins ) m_nBins = nBins; } -void FitResult::addFractions( const std::vector& fractions ) { m_fitFractions = fractions; } +void FitResult::addFractions( const std::vector& fractions ) +{ + m_fitFractions = fractions; +} + +double FitResult::chi2() const { return m_chi2; } +double FitResult::LL() const { return m_LL; } +int FitResult::status() const { return m_status; } +int FitResult::nParam() const { return m_nParam; } +int FitResult::nBins() const { return m_nBins; } + +std::map FitResult::observables() const { return m_observables; } +MinuitParameterSet* FitResult::mps() const { return m_mps; } + +double FitResult::dof() const { return m_nBins - m_nParam - 1; } +std::vector FitResult::fitFractions() const { return m_fitFractions; } +TMatrixD FitResult::cov() const { return m_covarianceMatrix; } +double FitResult::cov( const size_t& x, const size_t& y ) const { return m_covarianceMatrix( x, y ); } +double FitResult::cov( const std::string& x, const std::string& y ) const { return m_covarianceMatrix( m_covMapping.at(x), m_covMapping.at(y) ); } + +void FitResult::addFraction( const std::string& name, const double& frac, const double& err ) +{ + m_fitFractions.emplace_back( name, frac, err ); +} +void FitResult::clearFitFractions() { m_fitFractions.clear(); } +void FitResult::setCov( const size_t& x, const size_t& y, const double& F ) { m_covarianceMatrix( x, y ) = F; } +double FitResult::correlation( const std::string& x, const std::string& y ) const +{ + auto tx = m_covMapping.find(x); + auto ty = m_covMapping.find(y); + if( tx == m_covMapping.end() || ty == m_covMapping.end() ){ + ERROR("Parameter not found: " << x << ", " << y ); + return -1; + } + return cov(tx->second, ty->second)/sqrt(cov(tx->second, tx->second)*cov(ty->second, ty->second)); +} diff --git a/src/Generator.cpp b/src/Generator.cpp index a18115b9b1b..30d30eb4f47 100644 --- a/src/Generator.cpp +++ b/src/Generator.cpp @@ -8,9 +8,10 @@ extern "C" void AmpGen::PyGenerate(const char* eventType, double* out, const uns EventType type( split( std::string(eventType),' ') ); INFO( type << " generating: " ); auto phsp = Generator(type, new TRandom3() ); - auto events = phsp.generate( size,0 ); + auto events = phsp.generate( size ); for( size_t i = 0 ; i < events.size(); ++i ){ for( size_t j = 0 ; j < events[i].size(); ++j) out[events[i].size() * i + j] = events[i][j]; } } + diff --git a/src/IncoherentSum.cpp b/src/IncoherentSum.cpp index 1df5e034969..2a75ae3ca1f 100644 --- a/src/IncoherentSum.cpp +++ b/src/IncoherentSum.cpp @@ -39,30 +39,24 @@ double IncoherentSum::norm( const Bilinears& norms ) const void IncoherentSum::prepare() { - if ( m_weightParam != nullptr ) m_weight = m_weightParam->mean(); - + /* if ( m_isConstant && m_prepareCalls != 0 ) return; - transferParameters(); for ( auto& mE : m_matrixElements ) { - auto& pdf = mE.pdf; - pdf.prepare(); - if ( m_prepareCalls != 0 && !pdf.hasExternalsChanged() ) continue; - + auto& amp = mE.amp; + amp.prepare(); + if ( m_prepareCalls != 0 && !amp.hasExternalsChanged() ) continue; if ( m_prepareCalls == 0 && m_events != nullptr ) - mE.addressData = m_events->registerExpression( pdf ); - - if ( m_events != nullptr ) m_events->updateCache( pdf, mE.addressData ); - if ( m_prepareCalls == 0 && m_integrator.isReady() ){ - m_integrator.prepareExpression( pdf ); - } - INFO( mE.addressData << " " << m_events->at(0).getCache(mE.addressData) ); - pdf.resetExternals(); + mE.addressData = m_events->registerExpression( amp ); +// if ( m_events != nullptr ) m_events->updateCache( amp, mE.addressData ); + // if ( m_prepareCalls == 0 && m_integrator.isReady() ){ + // m_integrator.prepareExpression( amp ); + // } + amp.resetExternals(); } if( m_prepareCalls == 0 ){ for( size_t i = 0 ; i < m_matrixElements.size(); ++i ){ - auto& mE = m_matrixElements[i]; - auto index = m_integrator.events().getCacheIndex( mE.pdf ); + auto index = m_integrator.events().getCacheIndex( m_matrixElements[i].amp ); m_integrator.queueIntegral( index, index, i, 0, &m_normalisations, false); } m_integrator.flush(); @@ -70,6 +64,7 @@ void IncoherentSum::prepare() m_prepareCalls++; m_norm = norm(); INFO( "norm = " << m_norm << " weight = " << m_weight ); + */ } std::vector IncoherentSum::fitFractions( const LinearErrorPropagator& linProp ) @@ -83,17 +78,17 @@ std::vector IncoherentSum::fitFractions( const LinearErrorPropagato for ( auto& p : outputFractions ) INFO(p); return outputFractions; } -double IncoherentSum::getVal( const Event& evt ) const -{ + +double IncoherentSum::prob( const Event& evt ) const +{ + return m_weight * prob_unnormalised(evt) / m_norm; +} + +double IncoherentSum::prob_unnormalised( const Event& evt ) const +{ double value( 0. ); - for ( auto& mE : m_matrixElements ) { - value += std::norm( mE.coefficient * evt.getCache( mE.addressData ) ); - } + //for ( auto& mE : m_matrixElements ) { + // value += std::norm( mE.coefficient * m_events->cache(evt.index(), mE.addressData ) ); + //} return value; } -double IncoherentSum::operator()( const Event& evt ) const { return prob( evt ); } -double IncoherentSum::prob( const Event& evt ) const -{ - return m_weight * getVal( evt ) / m_norm; -} -double IncoherentSum::prob_unnormalised( const Event& evt ) const { return getVal( evt ); } diff --git a/src/Integrator.cpp b/src/Integrator.cpp index e51f3d6639f..3736ef37a5d 100644 --- a/src/Integrator.cpp +++ b/src/Integrator.cpp @@ -33,3 +33,52 @@ void Bilinears::resize( const size_t& r, const size_t& c) calculate[i] = true; } } + +void Integrator::integrateBlock() +{ + #pragma omp parallel for + for ( size_t roll = 0; roll < m_counter; ++roll ) { + float_v re( 0.f ); + float_v im( 0.f ); + auto b1 = m_cache.data() + m_integrals[roll].i * m_cache.nBlocks(); + auto b2 = m_cache.data() + m_integrals[roll].j * m_cache.nBlocks(); + for ( size_t i = 0; i < m_cache.nBlocks(); ++i ) { + auto c = b1[i] * conj(b2[i]); + #if ENABLE_AVX + re = fmadd( m_weight[i], real(c), re ); + im = fmadd( m_weight[i], imag(c), im ); + #else + re = re + m_weight[i] * real(c); + im = im + m_weight[i] * imag(c); + #endif + } + *m_integrals[roll].result = complex_t(utils::sum_elements( complex_v(re, im) )) / m_norm; + } + m_counter = 0; +} + +bool Integrator::isReady() const { return m_events != nullptr; } + +void Integrator::queueIntegral(complex_t* result, const unsigned& i, const unsigned& j) +{ + m_integrals[m_counter++] = QueuedIntegral(result, i, j ); + if( m_counter == N ) integrateBlock(); +} + +void Integrator::flush() +{ + if ( m_counter == 0 ) return; + integrateBlock(); +} + +#if ENABLE_AVX2 +template <> complex_t Integrator::get( const unsigned& index, const unsigned& evt ) const +{ + return utils::at( m_cache( evt/utils::size::value, index), evt % utils::size::value ); +} +#endif + +template <> complex_v Integrator::get( const unsigned& index, const unsigned& evt ) const +{ + return m_cache(evt, index); +} diff --git a/src/Kinematics.cpp b/src/Kinematics.cpp index ba9239d1150..8446b000063 100644 --- a/src/Kinematics.cpp +++ b/src/Kinematics.cpp @@ -11,7 +11,7 @@ using namespace AmpGen; -MomentumTransfer::MomentumTransfer( const std::vector& _p1, const std::vector& _p2 ) +MomentumTransfer::MomentumTransfer( const std::vector& _p1, const std::vector& _p2 ) : p1( _p1 ), p2( _p2 ) { for ( auto& p : p1 ) s.push_back( p ); @@ -30,13 +30,13 @@ double MomentumTransfer::Q2( const double& s, const double& s1, const double& s2 return s / 4. - ( s1 + s2 ) / 2. + ( s1 - s2 ) * ( s1 - s2 ) / ( 4 * s ); } -HelicityCosine::HelicityCosine( const std::vector& p1, const std::vector& p2, - const std::vector& pR ) +HelicityCosine::HelicityCosine( const std::vector& p1, const std::vector& p2, + const std::vector& pR ) : _i( p1 ), _j( p2 ), _pR( pR ) { } -HelicityCosine::HelicityCosine( const size_t& i, const size_t& j, const std::vector& pR ) +HelicityCosine::HelicityCosine( const unsigned& i, const unsigned& j, const std::vector& pR ) : _i( 1, i ), _j( 1, j ), _pR( pR ) { } @@ -50,12 +50,12 @@ double HelicityCosine::operator()( const Event& evt ) const return dotProduct(pi, pj, PR) / sqrt( dotProduct( pi, pi, PR ) * dotProduct( pj, pj, PR ) ); } -TLorentzVector AmpGen::pFromEvent( const Event& evt, const size_t& ref ) +TLorentzVector AmpGen::pFromEvent( const Event& evt, const unsigned& ref ) { return TLorentzVector( evt.address( 4 * ref ) ); } -TLorentzVector AmpGen::pFromEvent( const Event& evt, const std::vector& ref ) +TLorentzVector AmpGen::pFromEvent( const Event& evt, const std::vector& ref ) { double px( 0 ), py( 0 ), pz( 0 ), pE( 0 ); for ( auto& r : ref ) { @@ -144,7 +144,7 @@ void AmpGen::boost( Event& evt, const std::tuple& n, con double nz = std::get<2>( n ); double norm = sqrt( nx * nx + ny * ny + nz * nz ); - for ( size_t i = 0; i < evt.size() / 4; ++i ) { + for ( unsigned i = 0; i < evt.size() / 4; ++i ) { double nv = evt[4 * i] * nx + evt[4 * i + 1] * ny + evt[4 * i + 2] * nz; evt[4*i+0] += ( (gamma-1) * nv / norm + gamma * evt[4*i+3] * v ) * nx / norm; evt[4*i+1] += ( (gamma-1) * nv / norm + gamma * evt[4*i+3] * v ) * ny / norm; @@ -155,13 +155,11 @@ void AmpGen::boost( Event& evt, const std::tuple& n, con void AmpGen::rotate( Event& evt, const std::tuple& n, const double& v ) { - double nx = std::get<0>( n ); - double ny = std::get<1>( n ); - double nz = std::get<2>( n ); + auto& [nx,ny,nz ] = n; double cv = cos(v); double sv = sin(v); double norm = sqrt( nx * nx + ny * ny + nz * nz ); - for( size_t i = 0 ; i < evt.size()/4;++i){ + for( unsigned i = 0 ; i < evt.size()/4;++i){ double ix = evt[ 4*i+0]; double iy = evt[ 4*i+1]; double iz = evt[ 4*i+2]; @@ -174,7 +172,7 @@ void AmpGen::rotate( Event& evt, const std::tuple& n, cons void AmpGen::rotateBasis( Event& evt, const TVector3& p1, const TVector3& p2, const TVector3& p3 ) { - for(size_t i = 0 ; i < evt.size()/4;++i) + for(unsigned i = 0 ; i < evt.size()/4;++i) { double ex = evt[4*i+0]; double ey = evt[4*i+1]; diff --git a/src/Lineshapes.cpp b/src/Lineshapes.cpp index 4215758bbb9..7406c7d21db 100644 --- a/src/Lineshapes.cpp +++ b/src/Lineshapes.cpp @@ -23,8 +23,10 @@ Expression AmpGen::kFactor( const Expression& mass, const Expression& width, Deb return sqrt(k); } -Expression AmpGen::BlattWeisskopf_Norm( const Expression& z, const Expression& z0, unsigned int L ) +Expression AmpGen::BlattWeisskopf_Norm( const Expression& ze, const Expression& z0e, unsigned int L ) { + auto z = make_cse(ze); + auto z0 = make_cse(z0e); switch( L ) { case 0: return 1; case 1: return (1+z0) / (1+z); @@ -37,8 +39,9 @@ Expression AmpGen::BlattWeisskopf_Norm( const Expression& z, const Expression& z } } -Expression AmpGen::BlattWeisskopf( const Expression& z, unsigned int L ) +Expression AmpGen::BlattWeisskopf( const Expression& ze, unsigned int L ) { + auto z = make_cse(ze); switch( L ) { case 0: return 1; case 1: return 2 *fpow(z,1) / (1+z); @@ -63,11 +66,11 @@ Expression AmpGen::BL( const Expression& s, return sqrt( BlattWeisskopf( q2 * radius * radius, L ) / BlattWeisskopf( q20 * radius * radius, L ) ); } -std::vector AmpGen::parameterVector( const std::string& name, const unsigned int& nParam ) +std::vector AmpGen::parameterVector( const std::string& name, const size_t& nParam ) { std::vector returnVector; - for ( unsigned int i = 0; i < nParam; ++i ) - returnVector.push_back( Parameter( name + std::to_string( i ) ) ); + for (size_t i = 0; i != nParam; ++i ) + returnVector.emplace_back(Parameter(name + std::to_string(i))); return returnVector; } @@ -75,27 +78,19 @@ Expression AmpGen::width( const Expression& s, const Expression& s1, const Expre const Expression& width, const Expression& radius, unsigned int L, DebugSymbols* dbexpressions ) { - auto q2v = make_cse( Q2(s,s1,s2) ); + auto q2v = make_cse( Q2(s,s1,s2) ); const Expression q2 = Ternary( q2v > 0, q2v, 0 ); - const Expression q20 = Abs( Q2( mass * mass, s1, s2 ) ); + const Expression q20 = abs( Q2( mass * mass, s1, s2 ) ); Expression BF = BlattWeisskopf_Norm( q2 * radius * radius, q20 * radius * radius, L ); - Expression qr = sqrt( q2 / q20 ) * fpow( q2/q20, L ); - - const Expression mreco = isqrt( s ); - const Expression mr = mass * mreco; + auto q2r = make_cse(q2 / q20); ADD_DEBUG(q2 , dbexpressions); ADD_DEBUG(q20 , dbexpressions); ADD_DEBUG(sqrt(q2/q20) , dbexpressions); ADD_DEBUG(BF , dbexpressions); - ADD_DEBUG(qr , dbexpressions); - ADD_DEBUG(mr , dbexpressions); - ADD_DEBUG(qr*mr , dbexpressions); - ADD_DEBUG(sqrt(q2)/mreco, dbexpressions); - ADD_DEBUG(sqrt(q20)/mass, dbexpressions); - ADD_DEBUG(width*BF*qr*mr, dbexpressions); - - return width * BF * qr * mr; + const auto rt = make_cse( width * BF * mass * sqrt( q2r / s ) * fpow( q2r, L ) ); + ADD_DEBUG(rt, dbexpressions); + return rt; } bool Lineshape::Factory::isLineshape( const std::string& lineshape ) @@ -103,9 +98,9 @@ bool Lineshape::Factory::isLineshape( const std::string& lineshape ) size_t pos = lineshape.find( "." ); if ( pos == std::string::npos ) - return AmpGen::Factory::get(lineshape, true) != nullptr; + return AmpGen::Factory::get(lineshape, true) != nullptr; else - return AmpGen::Factory::get(lineshape.substr(0, pos), true ) != nullptr; + return AmpGen::Factory::get(lineshape.substr(0, pos), true ) != nullptr; } Expression Lineshape::Factory::get( const std::string& lineshape, const Expression& s, const Expression& s1, @@ -115,26 +110,25 @@ Expression Lineshape::Factory::get( const std::string& lineshape, const Expressi size_t pos = lineshape.find( "." ); if ( pos == std::string::npos ) { - auto it = AmpGen::Factory::get( lineshape ); + auto it = AmpGen::Factory::get( lineshape ); if ( !it ) ERROR( "Lineshape : " << lineshape << " not found" ); return it->get( s, s1, s2, particleName, L, "", dbexpressions ); } else { - return AmpGen::Factory::get(lineshape.substr(0, pos))->get( s, s1, s2, particleName, L, lineshape.substr( pos + 1 ), dbexpressions ); + return AmpGen::Factory::get(lineshape.substr(0, pos))->get( s, s1, s2, particleName, L, lineshape.substr( pos + 1 ), dbexpressions ); } } -Expression Lineshape::Factory::get(const std::string& lineshape, const Expression& s, const std::vector& p, - const std::string& particleName, const unsigned int& L, +Expression Lineshape::Factory::get(const std::string& lineshape, const AmpGen::Particle& p, DebugSymbols* dbexpressions ) { size_t pos = lineshape.find( "." ); if ( pos == std::string::npos ) { - auto it = AmpGen::Factory::get( lineshape ); + auto it = AmpGen::Factory::get( lineshape ); if ( !it ) ERROR( "Lineshape : " << lineshape << " not found" ); - return it->get(s, p, particleName, L, "", dbexpressions ); + return it->get(p, "", dbexpressions ); } else { - return AmpGen::Factory::get( lineshape.substr( 0, pos ) )->get(s, p, particleName, L, lineshape.substr( pos + 1 ), dbexpressions ); + return AmpGen::Factory::get( lineshape.substr( 0, pos ) )->get(p, lineshape.substr( pos + 1 ), dbexpressions ); } } @@ -143,8 +137,8 @@ Expression AmpGen::pol( const Expression& X, const std::vector& p ) Expression F = 0; Expression L = 1; for ( auto& ip : p ) { - F = F + ip * L; - L = L * X; + F += ip * L; + L *= X; } return F; } diff --git a/src/Lineshapes/AxialKaon.cpp b/src/Lineshapes/AxialKaon.cpp deleted file mode 100644 index eebc035edc6..00000000000 --- a/src/Lineshapes/AxialKaon.cpp +++ /dev/null @@ -1,62 +0,0 @@ - -#include -#include -#include - -#include "AmpGen/Lineshapes.h" -#include "AmpGen/kMatrix.h" -#include "AmpGen/Spline.h" -#include "AmpGen/Expression.h" -#include "AmpGen/Factory.h" -#include "AmpGen/Tensor.h" -#include "AmpGen/Utilities.h" - -using namespace AmpGen; - -DEFINE_LINESHAPE( AxialKaon ) -{ - ERROR("This lineshape does not work as intended, should not be used"); -/* - - Spline rho_Krho("rho_Krho",20, 0.597247, 5, - {5.35636e-23, 0.000210696, 0.00208479, 0.00993997, 0.0415061, 0.120885, 0.196599, 0.256062, 0.304949, 0.34693, 0.384132, 0.417868, 0.448995, 0.478101, 0.505606, 0.531815, 0.556963, 0.581226, 0.604745, 0.627631}); - - Spline rho_Kstpi("rho_Kspi",20,0.597247, 5, - {6.29163e-23, 0.000390208, 0.0161092, 0.0855491, 0.128145, 0.159565, 0.184867, 0.20627, 0.224985, 0.241753, 0.257056, 0.271229, 0.284507, 0.297066, 0.309035, 0.320516, 0.331588, 0.342313, 0.35274, 0.362912} ); - - Spline rho_KstpiD("rho_KspiD",20,0.597247, 5, - {6.29163e-23, 0.000390208, 0.0161092, 0.0855491, 0.128145, 0.159565, 0.184867, 0.20627, 0.224985, 0.241753, 0.257056, 0.271229, 0.284507, 0.297066, 0.309035, 0.320516, 0.331588, 0.342313, 0.35274, 0.362912} ); - - Spline rho_KSpi("rho_KSpi",20,0.597247, 5, - {5.58343e-23, 0.000178087, 0.00132915, 0.00423057, 0.00963868, 0.0185276, 0.0324146, 0.053891, 0.0870863, 0.13619, 0.202066, 0.282239, 0.373053, 0.470919, 0.572771, 0.67618, 0.779316, 0.880855, 0.979877, 1.07577}); - - - std::vector phaseSpace = { rho_Krho(s), rho_Kstpi(s), rho_KstpiD(s), rho_KSpi(s) }; - - std::vector< std::string > channels = {"Krho","Kspi","KspiD","KSpi"}; - unsigned int nPoles = 2; - std::vector poleConfigs; - for( unsigned int pole=1;pole <= nPoles; ++pole ) - { - std::string stub = "AxialKaon_p"+std::to_string(pole)+"_"; - Expression mass = Parameter( stub + "mass" ); - poleConfig p( mass * mass ); - for ( unsigned int ch = 0; ch < 4; ++ch ) p.add( Parameter( stub + channels[ch] ) ); - poleConfigs.push_back( p ); - } - auto kMatrix = constructKMatrix( s, 4, poleConfigs ); - - Tensor F = getPropagator( kMatrix, phaseSpace ); - - auto tokens = split( lineshapeModifier, '.' ); - unsigned int pTerm = stoi(tokens[0]); - unsigned int channel = stoi(tokens[1]); - auto pole = poleConfigs[pTerm]; - Expression M = 0; - for ( unsigned int i = 0; i < pole.couplings.size(); ++i ) { - M = M + F[{channel, i}] * pole.couplings[i]; - } - return SubTree( M / ( pole.s - s ) ); - */ - return 0; -} diff --git a/src/Lineshapes/BW.cpp b/src/Lineshapes/BW.cpp index a58c2cfe665..3b2468100b6 100644 --- a/src/Lineshapes/BW.cpp +++ b/src/Lineshapes/BW.cpp @@ -6,6 +6,7 @@ #include "AmpGen/Lineshapes.h" #include "AmpGen/ParticleProperties.h" #include "AmpGen/ParticlePropertiesList.h" +#include "AmpGen/Particle.h" using namespace AmpGen; using namespace AmpGen::fcn; @@ -15,17 +16,20 @@ DEFINE_LINESHAPE( FormFactor ) { auto props = ParticlePropertiesList::get( particleName ); Expression radius = Parameter( particleName + "_radius", props->radius() ); - + Expression mass = Parameter( particleName + "_mass" , props->mass() ); const Expression q2 = make_cse( Q2( s, s1, s2 ) ); + const Expression q20 = make_cse( Q2( mass*mass, s1, s2 ) ); int Lp = L; if( lineshapeModifier == "L0" ) Lp = 0; if( lineshapeModifier == "L1" ) Lp = 1; if( lineshapeModifier == "L2" ) Lp = 2; if( lineshapeModifier == "L3" ) Lp = 3; - const Expression FormFactor = lineshapeModifier.find("BL") == std::string::npos ? - sqrt( BlattWeisskopf_Norm( q2 * radius * radius, 0, Lp ) ) : - sqrt( BlattWeisskopf(q2*radius*radius, Lp ) ); + Expression FormFactor = sqrt( BlattWeisskopf_Norm( q2 * radius * radius, 0, Lp ) ); + if ( lineshapeModifier == "BL" ) FormFactor = sqrt( BlattWeisskopf( q2 * radius * radius, Lp ) ); + if ( lineshapeModifier == "NFF" ) FormFactor = 1; + if ( lineshapeModifier == "BELLE2018" ) FormFactor = sqrt( BlattWeisskopf_Norm( q2 * radius * radius, q20 * radius * radius, Lp ) ); + if( L != 0 ){ ADD_DEBUG( q2 , dbexpressions ); ADD_DEBUG( radius , dbexpressions ); @@ -62,19 +66,23 @@ DEFINE_LINESHAPE( BW ) const Expression& radius = Parameter( particleName + "_radius", props->radius() ); const Expression q2 = make_cse( Abs(Q2( s_cse, s1, s2 ) ) ) ; const Expression q20 = make_cse( Abs(Q2( mass * mass, s1, s2 )) ); - Expression FormFactor = sqrt( BlattWeisskopf_Norm( q2 * radius * radius, 0, L ) ); - if ( lineshapeModifier == "BL" ) FormFactor = sqrt( BlattWeisskopf( q2 * radius * radius, L ) ); + Expression FormFactor = sqrt( BlattWeisskopf_Norm( q2 * radius * radius, 0, L ) ); + if ( lineshapeModifier == "BL" ) FormFactor = sqrt( BlattWeisskopf( q2 * radius * radius, L ) ); + if ( lineshapeModifier == "BELLE2018" ) FormFactor = sqrt( BlattWeisskopf_Norm( q2 * radius * radius, q20 * radius * radius, L ) ); + if ( lineshapeModifier == "NFF") FormFactor = 1; Expression runningWidth = width( s_cse, s1, s2, mass, width0, radius, L, dbexpressions ); const Expression BW = FormFactor / ( mass * mass - s_cse -1i * mass * runningWidth ); const Expression kf = kFactor( mass, width0, dbexpressions ); + ADD_DEBUG( s_cse, dbexpressions ); + ADD_DEBUG( s1, dbexpressions ); + ADD_DEBUG( s2, dbexpressions ); ADD_DEBUG( FormFactor, dbexpressions ); ADD_DEBUG( runningWidth, dbexpressions ); ADD_DEBUG( BW, dbexpressions ); ADD_DEBUG( kf, dbexpressions ); - return kf * BW; + return lineshapeModifier == "BELLE2018" ? BW : kf*BW; } - DEFINE_LINESHAPE( SBW ) { auto props = ParticlePropertiesList::get( particleName ); diff --git a/src/Lineshapes/Bugg.cpp b/src/Lineshapes/Bugg.cpp index c3612d3fec7..cac67e5b0b8 100644 --- a/src/Lineshapes/Bugg.cpp +++ b/src/Lineshapes/Bugg.cpp @@ -43,7 +43,7 @@ Expression Gamma_4pi( const Expression& s, const Expression& m0, const Expressio DEFINE_LINESHAPE( Bugg ) { - Expression M = Parameter( "Bugg::M", 0.935 ); + Expression M = Parameter( "Bugg::M", 0.953 ); Expression b1 = Parameter( "Bugg::b1", 1.302 ); Expression b2 = Parameter( "Bugg::b2", 0.340 ); Expression A = Parameter( "Bugg::A", 2.426 ); @@ -97,3 +97,56 @@ DEFINE_LINESHAPE( Bugg ) ADD_DEBUG( rho_4pi( s, lambda_4pi, s0_4pi ), dbexpressions ); return lineshapeModifier == "Az" ? BW * ( s - sA ) * g1sg : BW; } + +DEFINE_LINESHAPE( Kappa ) +{ + Expression M = Parameter( "Kappa::M", 3.3 ); + Expression b1 = Parameter( "Kappa::b1", 24.49 ); + Expression b2 = Parameter( "Kappa::b2", 0. ); + Expression A = Parameter( "Kappa::A", 2.5 ); + Constant mPiPlus( 0.139570 ); + Constant mKPlus( 0.493677 ); + Expression J = Constant(0,1); + Expression sA = Parameter( "Kappa::sA", 1.) * (mKPlus*mKPlus - 0.5 * mPiPlus * mPiPlus); + + Expression g1sg = M * ( b1 + b2 * s ) * Exp( -( s - M * M ) / A ); + Expression adlerZero = ( s - sA ) / ( M * M - sA ); + Expression Gamma_tot = g1sg * adlerZero * rho_2(s,(mPiPlus+mKPlus)*(mPiPlus+mKPlus)/4.); + + Expression iBW = M * M - s - J * Gamma_tot; + + Expression BW = 1. / iBW; + ADD_DEBUG( M, dbexpressions ); + ADD_DEBUG( g1sg, dbexpressions ); + ADD_DEBUG( sA, dbexpressions ); + ADD_DEBUG( adlerZero, dbexpressions ); + ADD_DEBUG( Gamma_tot, dbexpressions ); + ADD_DEBUG( s, dbexpressions ); + ADD_DEBUG( iBW, dbexpressions ); + return lineshapeModifier == "Az" ? BW * ( s - sA ) * g1sg : BW; +} + +DEFINE_LINESHAPE( Dabba ) +{ + Expression b = Parameter( "Dabba::b", 24.49 ); + Expression alpha = Parameter( "Dabba::alpha", 0.1 ); + Expression beta = Parameter( "Dabba::beta", 0.1 ); + Constant mPiPlus( 0.139570 ); + Constant mDPlus( 1.86965 ); + Expression J = Constant(0,1); + Expression sA = Parameter( "Dabba::sA", 1.) * (mDPlus*mDPlus - 0.5 * mPiPlus * mPiPlus); + + Expression s0 = (mDPlus+mPiPlus)*(mDPlus+mPiPlus); + Expression term1 = beta * (s-s0); + Expression term2 = b * rho_2(s,s0/4.) * (s-sA) * Exp( - alpha * ( s - s0) ); + + Expression iBW = 1 - term1 - J * term2; + + Expression BW = 1. / iBW; + ADD_DEBUG( s0, dbexpressions ); + ADD_DEBUG( term1, dbexpressions ); + ADD_DEBUG( term2, dbexpressions ); + ADD_DEBUG( iBW, dbexpressions ); + return BW; +} + diff --git a/src/Lineshapes/CoupledChannel.cpp b/src/Lineshapes/CoupledChannel.cpp index 0ee3ad024e6..a6715dd9212 100644 --- a/src/Lineshapes/CoupledChannel.cpp +++ b/src/Lineshapes/CoupledChannel.cpp @@ -11,6 +11,9 @@ using namespace AmpGen; using namespace AmpGen::fcn; +using namespace std::complex_literals; + +// ENABLE_DEBUG( Lineshape::CoupledChannel ); Expression H(const Expression& x, const Expression& y, @@ -74,12 +77,28 @@ Expression AmpGen::phaseSpace(const Expression& s, const Particle& p, const size const Expression radius = Parameter(p.name() + "_radius", p.props()->radius()); return rho_twoBody(s, s1, s2) * BlattWeisskopf(k2p*radius*radius, l); } - if( phsp_parameterisation == std::string("arXiv.0707.3596") ){ + else if( phsp_parameterisation == std::string("arXiv.0707.3596") ){ INFO("Got AS parametrisation"); - Expression E = 1; - // return 2*fpow(k2,l)*complex_sqrt(k2) * E * 2 / ((1.5+k2p) * sqrt(s) ); return 2 * complex_sqrt(k2/s); } + else if( phsp_parameterisation == std::string("CM") ) + { + if( l != 0 ){ + WARNING("Chew-Mandelstam only implemented for l=0"); + } + auto m1 = p.daughter(0)->mass(); + auto m2 = p.daughter(1)->mass(); + Expression s1 = m1*m1; + Expression s2 = m2*m2; + Expression sT = (m1+m2)*(m1+m2); + Expression q2 = (s*s + s1*s1 + s2*s2 - 2*s*s1 - 2*s*s2 - 2*s1*s2)/(4*s); + auto q = fcn::complex_sqrt(q2); + auto arg = (s1 + s2 - s + 2*fcn::sqrt(s) * q )/ (2*m1*m2); + return (2.*q * fcn::log(arg) / fcn::sqrt(s) - (s1-s2)*( 1./s - 1./sT ) * fcn::log(m1/m2) ) / ( 16.i * M_PI * M_PI ); + } + else { + FATAL("Parametrisation: " << *phsp_parameterisation << " not found"); + } } if( fs.size() == 3 && ! p.daughter(0)->isStable() ) return rho_threeBody( s, *p.daughter(0), *p.daughter(1) ); if( fs.size() == 3 && ! p.daughter(1)->isStable() ) return rho_threeBody( s, *p.daughter(1), *p.daughter(0) ); @@ -100,13 +119,13 @@ DEFINE_LINESHAPE( CoupledChannel ) ADD_DEBUG( s , dbexpressions ); for( size_t i = 0 ; i < channels.size(); i+=2 ){ Particle p( channels[i] ); - INFO( "Adding channel ... " << p.uniqueString() << " coupling = " << NamedParameter( channels[i+1] ) ); + DEBUG( "Adding channel ... " << p.uniqueString() << " coupling = " << NamedParameter( channels[i+1] ) ); Expression coupling = Parameter(channels[i+1], 0); - totalWidth = totalWidth + coupling * phaseSpace(s , p, p.orbital()); - totalWidthAtPole = totalWidthAtPole + coupling * phaseSpace(mass*mass, p, p.orbital()); + totalWidth = totalWidth + coupling * phaseSpace(s , p, p.L()); + totalWidthAtPole = totalWidthAtPole + coupling * phaseSpace(mass*mass, p, p.L()); ADD_DEBUG(coupling, dbexpressions); - ADD_DEBUG(phaseSpace(s,p,p.orbital() ), dbexpressions); - ADD_DEBUG(phaseSpace(mass*mass,p,p.orbital() ), dbexpressions); + ADD_DEBUG(phaseSpace(s,p,p.L() ), dbexpressions); + ADD_DEBUG(phaseSpace(mass*mass,p,p.L() ), dbexpressions); } ADD_DEBUG(totalWidth, dbexpressions); ADD_DEBUG(totalWidthAtPole, dbexpressions); diff --git a/src/Lineshapes/EtaDalitz.cpp b/src/Lineshapes/EtaDalitz.cpp index f7d7a525774..b43d691f5c0 100644 --- a/src/Lineshapes/EtaDalitz.cpp +++ b/src/Lineshapes/EtaDalitz.cpp @@ -12,13 +12,14 @@ using namespace AmpGen::fcn; DEFINE_GENERIC_SHAPE( EtaDalitz ) { - WARNING("Empirical expression; eta0[EtaDalitz.NonRelBW]{pi+,pi-,pi0} with pi0 in the 3rd order."); - Tensor P( Tensor::dim(4) ); - for ( auto& ip : p ) P = P + ip; + auto pp = *p.daughter("pi+"); + auto pm = *p.daughter("pi-"); + auto p0 = *p.daughter("pi0"); + auto P = p.P(); - Expression T0 = sqrt( dot( p[0], P ) * dot( p[0], P ) / dot( P, P ) ) - sqrt( dot( p[0], p[0] ) ); - Expression T1 = sqrt( dot( p[1], P ) * dot( p[1], P ) / dot( P, P ) ) - sqrt( dot( p[1], p[1] ) ); - Expression T2 = sqrt( dot( p[2], P ) * dot( p[2], P ) / dot( P, P ) ) - sqrt( dot( p[2], p[2] ) ); + Expression T0 = dot(pp.P(), P) - p.mass() * pp.mass(); + Expression T1 = dot(pm.P(), P) - p.mass() * pm.mass(); + Expression T2 = dot(p0.P(), P) - p.mass() * p0.mass(); Expression Q = T0 + T1 + T2; Expression y = 3.0 * T2 / Q - 1.0; @@ -26,7 +27,7 @@ DEFINE_GENERIC_SHAPE( EtaDalitz ) Expression amp = Ternary( z > 0.0, sqrt(z), 1 ); if ( lineshapeModifier != "" ){ - amp = amp * Lineshape::Factory::get(lineshapeModifier, s, p, particleName, L, dbexpressions); + amp = amp * Lineshape::Factory::get(lineshapeModifier, p, dbexpressions); } return amp; } diff --git a/src/Lineshapes/Flatte.cpp b/src/Lineshapes/Flatte.cpp index 220cdfc1f47..06827969cbf 100644 --- a/src/Lineshapes/Flatte.cpp +++ b/src/Lineshapes/Flatte.cpp @@ -10,12 +10,12 @@ using namespace std::complex_literals; Expression aSqrtTerm( const Expression& s, const Expression& m0 ) { Expression a2 = 1.0 - ( 4 * m0 * m0 ) / s; - return Ternary( a2 > Constant( 0 ), sqrt( a2 ), Constant( 0 ) ); + return Ternary( a2 > 0., sqrt( a2 ), Constant( 0 ) ); } Expression fSqrtTerm( const Expression& s, const Expression& m0 ) { - return complex_sqrt( 1.0 - ( 4 * m0 * m0 ) / s ); + return complex_sqrt( 1.0 - 4*m0*m0/ s ); } DEFINE_LINESHAPE( Flatte ) { diff --git a/src/Lineshapes/GLASS.cpp b/src/Lineshapes/GLASS.cpp new file mode 100644 index 00000000000..3fb68ec8929 --- /dev/null +++ b/src/Lineshapes/GLASS.cpp @@ -0,0 +1,43 @@ +#include + +#include "AmpGen/Expression.h" +#include "AmpGen/Factory.h" +#include "AmpGen/Lineshapes.h" +#include "AmpGen/ParticleProperties.h" +#include "AmpGen/ParticlePropertiesList.h" +#include "AmpGen/Units.h" + +using namespace AmpGen; +using namespace AmpGen::fcn; + +DEFINE_LINESHAPE( GLASS ) +{ + const auto props = ParticlePropertiesList::get( particleName ); + const auto mass = Parameter( particleName + "_mass", props->mass() ); + const auto width0 = Parameter( particleName + "_width", props->width() ); + const auto s0 = mass*mass; + const auto a = Parameter( particleName + "::GLASS::a", 2.07 ); + const auto r = Parameter( particleName + "::GLASS::r", 3.32 ); + const auto phiR = Parameter( particleName + "::GLASS::phiR", 0.00 ); + const auto phiF = Parameter( particleName + "::GLASS::phiF", 0.00 ); + const auto R = Parameter( particleName + "::GLASS::R", 1.00 ); + const auto F = Parameter( particleName + "::GLASS::F", 1.00 ); + const auto q2 = Q2(s, s1, s2); + const auto q20 = Q2(s0, s1, s2); + const auto q = safe_sqrt( q2 ); + const auto i = Constant(0,1); + const auto width = width0 * mass * sqrt( q2 / ( q20 * s ) ); + const auto rbw = s0 * width0 /(sqrt(q20) * (mass*mass - s - i*mass*width )); + const auto den = ( 1.0 + 0.5*r*a*q2 - i * a * q); + const auto resTerm = R * exp( i*(phiR + 2*phiF) ) * rbw * ( 1.0 + 0.5*r*a*q2 + i * a * q ); + const auto nrTerm = F * exp( i*phiF ) * ( a * q * cos(phiF) + ( 1.0 + 0.5 * r * a * q2 ) * sin(phiF)) * sqrt(s) / q; + const auto total = (nrTerm + resTerm)/den; + + ADD_DEBUG(width , dbexpressions); + ADD_DEBUG(rbw , dbexpressions); + ADD_DEBUG(den , dbexpressions); + ADD_DEBUG(resTerm/den, dbexpressions); + ADD_DEBUG(nrTerm/den , dbexpressions); + ADD_DEBUG(total , dbexpressions); + return total; +} diff --git a/src/Lineshapes/GenericKmatrix.cpp b/src/Lineshapes/GenericKmatrix.cpp index 179c64ba17d..b66cbe9cda7 100644 --- a/src/Lineshapes/GenericKmatrix.cpp +++ b/src/Lineshapes/GenericKmatrix.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "AmpGen/Expression.h" #include "AmpGen/Factory.h" @@ -16,87 +17,118 @@ #include "AmpGen/Utilities.h" #include "AmpGen/kMatrix.h" #include "AmpGen/CoupledChannel.h" +#include "AmpGen/enum.h" using namespace AmpGen; -using namespace AmpGen::fcn; +using namespace AmpGen::fcn; +namespace AmpGen{ make_enum(PA_TYPE, PVec, QVec); } DEFINE_LINESHAPE(GenericKmatrix) { - auto props = ParticlePropertiesList::get( particleName ); - Expression mass = Parameter( particleName + "_mass", props->mass() ); - INFO( "kMatrix modifier " << lineshapeModifier << " particle = " << particleName ); - auto tokens = split(lineshapeModifier, '.' ); - DEBUG("kMatrix modifier = " << lineshapeModifier << " nTokens = " << tokens.size() ); - size_t nPoles = NamedParameter( lineshapeModifier + "::kMatrix::nPoles"); - auto channels = NamedParameter(lineshapeModifier + "::kMatrix::channels").getVector(); - size_t nChannels = channels.size(); - std::vector phsps; - std::vector bw_phase_space; - auto s0 = mass*mass; + auto props = ParticlePropertiesList::get( particleName ); + Expression mass = Parameter( particleName + "_mass", props->mass() ); + unsigned nPoles = NamedParameter(particleName+"::kMatrix::nPoles"); + auto channels = NamedParameter(particleName+"::kMatrix::channels").getVector(); + auto const pa_type = NamedParameter(particleName+"::kMatrix::production_amplitude",PA_TYPE::PVec); + auto nChannels = channels.size(); + auto s0 = mass*mass; + std::vector phsps, bw_phase_space; ADD_DEBUG(s, dbexpressions ); ADD_DEBUG(s0, dbexpressions ); - INFO("Initialising K-matrix with : " << nChannels); - for( size_t i = 0 ; i < channels.size(); i+=1 ){ - Particle p( channels[i] ); + INFO("Initialising K-matrix with [nChannels = " << nChannels << ", nPoles = " << nPoles << "]"); + //phase-space + for( unsigned i = 0 ; i < channels.size(); i+=1 ){ + Particle p( channels[i] ); INFO( p.decayDescriptor() ); - Expression sf = Parameter( lineshapeModifier + "::phsp::sf::"+std::to_string(i+1), 1); - phsps.emplace_back( sf * phaseSpace(s, p, p.orbital() ) ); - bw_phase_space.emplace_back( sf * phaseSpace(s0, p, p.orbital() ) ); - ADD_DEBUG( *phsps.rbegin(), dbexpressions); - ADD_DEBUG( phaseSpace(s0,p,p.orbital()), dbexpressions ); + phsps.emplace_back( phaseSpace(s, p, p.L() ) ); + bw_phase_space.emplace_back( phaseSpace(s0, p, p.L() ) ); + if( dbexpressions != nullptr ) dbexpressions->emplace_back("phsp_"+p.decayDescriptor(), *phsps.rbegin() ); //ADD_DEBUG( *phsps.rbegin(), dbexpressions); +// ADD_DEBUG( phaseSpace(s0,p,p.L()), dbexpressions ); } - Tensor non_resonant( Tensor::dim(nChannels, nChannels) ); + //pole configuration for kMatrix (see e.g. eq. (48.25) in http://pdg.lbl.gov/2019/reviews/rpp2019-rev-resonances.pdf) std::vector poleConfigs; - for (size_t pole = 1; pole <= nPoles; ++pole ){ - std::string stub = lineshapeModifier + "::pole::" + std::to_string(pole); + for (unsigned pole = 1; pole <= nPoles; ++pole ){ + std::string stub = particleName+"::pole::" + std::to_string(pole); Expression mass = Parameter(stub + "::mass"); + DEBUG( "Will link to parameter: " << stub + "::mass"); poleConfig thisPole(mass*mass); if( dbexpressions != nullptr ) dbexpressions->emplace_back(stub+"::mass", mass); Expression bw_width = 0; Expression bw_width0 = 0; - for (size_t channel = 1; channel <= nChannels; ++channel ) - { + for (unsigned channel = 1; channel <= nChannels; ++channel ){ Expression g = Parameter(stub+"::g::"+std::to_string(channel)); + DEBUG("Will link to parameter: " << stub+"::g::"+std::to_string(channel) ); thisPole.add(g, 1); - if( dbexpressions != nullptr ){ - dbexpressions->emplace_back( stub+"::g::"+std::to_string(channel), g); - } + if(dbexpressions != nullptr) dbexpressions->emplace_back( stub+"::g::"+std::to_string(channel), g); bw_width = bw_width + g*g*phsps[channel-1] / mass; bw_width0 = bw_width0 + g*g*bw_phase_space[channel-1] / mass; } - for( size_t channel = 1 ; channel <= nChannels; ++channel ){ - Expression g = Parameter(stub+"::g::"+std::to_string(channel)); - Expression BR = g*g*bw_phase_space[channel-1] / ( mass * bw_width0 ); - ADD_DEBUG( BR, dbexpressions ); + if( dbexpressions != nullptr ){ + for( unsigned channel = 1 ; channel <= nChannels; ++channel ){ + Expression g = Parameter(stub+"::g::"+std::to_string(channel)); + Expression BR = g*g*bw_phase_space[channel-1] / ( mass * bw_width0 ); + ADD_DEBUG( BR, dbexpressions ); + } + ADD_DEBUG(bw_width, dbexpressions); + ADD_DEBUG(bw_width0, dbexpressions); } - ADD_DEBUG(bw_width, dbexpressions); - ADD_DEBUG(bw_width0, dbexpressions); poleConfigs.push_back(thisPole); } - for(size_t ch1 = 1; ch1 <= nChannels; ++ch1){ - for( size_t ch2 = 1; ch2 <= nChannels; ++ch2 ){ + //add non-resonant term to kMatrix (eq. (48.25) in http://pdg.lbl.gov/2019/reviews/rpp2019-rev-resonances.pdf) + Tensor non_resonant( Tensor::dim(nChannels, nChannels) ); + for(unsigned ch1 = 1; ch1 <= nChannels; ++ch1){ + for( unsigned ch2 = 1; ch2 <= nChannels; ++ch2 ){ auto c1 = std::to_string(ch1); - auto c2 = std::to_string(ch2); + auto c2 = std::to_string(ch2); if( ch1 > ch2 ) std::swap(c1,c2); - std::string nrShape = NamedParameter(lineshapeModifier +"::"+c1+"::"+c2+"::nrShape", "flat"); - Expression f1 = Parameter(lineshapeModifier+"::f1::"+c1+"::"+c2, 0); + std::string nrShape = NamedParameter(particleName+"::"+c1+"::"+c2+"::nrShape", "flat"); + Expression f1 = Parameter(particleName+"::f1::"+c1+"::"+c2, 0); if( nrShape == "flat") non_resonant[{ch1-1,ch2-1}] = f1; - else if( nrShape == "pole"){ - Expression f2 = Parameter(lineshapeModifier+"::f2::"+c1+"::"+c2, 0); - Expression s0 = Parameter(lineshapeModifier+"::s0::"+c1+"::"+c2, 0); + else if( nrShape == "pole"){ + Expression f2 = Parameter(particleName+"::f2::"+c1+"::"+c2, 0); + Expression s0 = Parameter(particleName+"::s0::"+c1+"::"+c2, 0); non_resonant[{ch1-1,ch2-1}] = (f1 + f2*sqrt(s)) / (s-s0); } - else WARNING("Unknown shape: " << nrShape); + else WARNING("Unknown shape: " << nrShape); } } + Tensor kMatrix = constructKMatrix(s, nChannels, poleConfigs); - ADD_DEBUG_TENSOR(kMatrix , dbexpressions); - kMatrix = kMatrix + non_resonant; + ADD_DEBUG_TENSOR(kMatrix, dbexpressions); + kMatrix = kMatrix + non_resonant; Tensor propagator = getPropagator(kMatrix, phsps); ADD_DEBUG_TENSOR(non_resonant, dbexpressions); - Expression M; - for(size_t i = 0 ; i < nChannels; ++i) M = M + kMatrix[{i,0}] * propagator[{0,i}]; - return M ; // * phsps[0]; + + //we have all ingredients to build the production amplitude now + //follow https://doi.org/10.1007/s1010502a0002 eqns (9)-(13) modulo the Adler zero term (which is argued away in a fuzzy manner by citing a private communication) + if(pa_type==PA_TYPE::PVec){ + std::vector P(nChannels,0), a(nChannels,0), phi(nChannels,0);//the P-vector, a and phi coefficients + Expression s_0 = Parameter(particleName+"::s0"); + Expression F_0 = 0;//the object we'll return later: the production amplitude in the 0th channel + //get the coefficients first + for(unsigned k = 0 ; k < nChannels; ++k) a[k] = Parameter(particleName+"::a::"+std::to_string(k+1)); + //now start loop to calculate the production amplitude + for(unsigned k = 0 ; k < nChannels; ++k){ + for(unsigned alpha = 0; alpha < nPoles; ++alpha){ + Expression beta = 0; + for(unsigned q = 0 ; q < nChannels; ++q){ + beta += a[q] * poleConfigs[alpha].couplings[q]; + phi[k] += a[q] * non_resonant[{k,q}]; + } + P[k] += (beta * poleConfigs[alpha].couplings[k])/(poleConfigs[alpha].s - s) + phi[k] * (1.+s_0)/(s-s_0); + } + F_0 += propagator[{0,k}] * P[k]; + } + //TODO: implement higher orbital angular momentum + return F_0; + } + else if(pa_type==PA_TYPE::QVec){ + INFO("Using Q-vector approach to build the production amplitude"); + Expression M; + for(unsigned i = 0 ; i < nChannels; ++i) M = M + kMatrix[{i,0}] * propagator[{0,i}]; + return M ; // * phsps[0]; + } + else throw std::runtime_error("This shouldn't happen. Currently supported types: P-vector approach (PA_TYPE::PVec) and Q-vector approach (PA_TYPE::QVec)"); } diff --git a/src/Lineshapes/GounarisSakurai.cpp b/src/Lineshapes/GounarisSakurai.cpp index 43a664952b9..ddad835df4c 100644 --- a/src/Lineshapes/GounarisSakurai.cpp +++ b/src/Lineshapes/GounarisSakurai.cpp @@ -35,7 +35,7 @@ DEFINE_LINESHAPE( GounarisSakurai ) Expression mass = Parameter( particleName + "_mass", props->mass() ); Expression radius = Parameter( particleName + "_radius", props->radius() ); Expression width0 = Parameter( particleName + "_width", props->width() ); - + Expression s0 = mass * mass; Expression t1 = 2 * s0 * q2(s) * q(s) *logTerm(s)/(sqrt(s)*fpow(q(s0),3)); @@ -43,12 +43,31 @@ DEFINE_LINESHAPE( GounarisSakurai ) Expression t3 = (s0-s)/q(s0); Expression M2 = s0 + width0 * (t1 + t2 + t3 )/M_PI; - - Expression D = M2 - 1i*mass*width(s,s1,s2,mass,width0,0,L); + bool useRadius = lineshapeModifier.find("IncludeRadiusInWidth") != std::string::npos; + bool normalisedFF = lineshapeModifier.find("BL") != std::string::npos; + Expression D = M2 - 1i*mass*width(s, s1, s2, mass, width0, useRadius ? radius : 0, L); const Expression q2 = abs( Q2( s, s1, s2 ) ); Expression FormFactor = sqrt( BlattWeisskopf_Norm( q2 * radius * radius, 0, L ) ); - if ( lineshapeModifier == "BL" ) FormFactor = sqrt( BlattWeisskopf( q2 * radius * radius, L ) ); + if ( normalisedFF ) FormFactor = sqrt( BlattWeisskopf( q2 * radius * radius, L ) ); ADD_DEBUG( FormFactor , dbexpressions); ADD_DEBUG( M2 , dbexpressions); - return kFactor( mass, width0, dbexpressions ) * FormFactor / (D-s); + ADD_DEBUG( D, dbexpressions); + Expression GS = kFactor( mass, width0, dbexpressions ) * FormFactor / (D-s); + if(lineshapeModifier.find("Omega") != std::string::npos){ + // this implements rho/omega mixing from https://arxiv.org/pdf/hep-ex/0112031.pdf + auto props_omega = ParticlePropertiesList::get("omega(782)0"); + Expression mass_omega = Parameter("omega(782)0_mass", props_omega->mass() ); + //Expression radius_omega = Parameter("omega(782)0_radius", props_omega->radius() ); + Expression width0_omega = Parameter("omega(782)0_width", props_omega->width() ); + + const Expression kF_omega = 1.;//kFactor( mass_omega, width0_omega ) ; + const Expression BW_omega = kF_omega / ( mass_omega * mass_omega - s - 1i*mass_omega * width0_omega ); + + Expression delta_Amp = Parameter( particleName + "_deltaOmegaAmp", 0.00157 ); + Expression delta_Phase = Parameter( particleName + "_deltaOmegaPhase", 12.6 ); + Expression delta = delta_Amp * exp(1i* M_PI / 180 * delta_Phase); + + return GS * (1.+s/(mass_omega*mass_omega) * delta * BW_omega); + } +return GS; } diff --git a/src/Lineshapes/Isotensor.cpp b/src/Lineshapes/Isotensor.cpp index 0d7030d7fa5..d2f2b0fa74d 100644 --- a/src/Lineshapes/Isotensor.cpp +++ b/src/Lineshapes/Isotensor.cpp @@ -1,11 +1,13 @@ #include #include +#include #include "AmpGen/Expression.h" #include "AmpGen/Factory.h" #include "AmpGen/Lineshapes.h" using namespace AmpGen; +using namespace std::complex_literals; DEFINE_LINESHAPE( Isotensor ) { @@ -23,8 +25,5 @@ DEFINE_LINESHAPE( Isotensor ) ADD_DEBUG( phaseShift, dbexpressions ); ADD_DEBUG( fcn::sqrt( s / 4 - mpi * mpi ), dbexpressions ); ADD_DEBUG( polyTerm, dbexpressions ); - Expression cos_shift = Cos( phaseShift ); - Expression sin_shift = Sin( phaseShift ); - Expression J = Constant(0,1); - return ( cos_shift + J*sin_shift - 1 ) * (-0.5 * J ); + return ( fcn::exp( 1i * phaseShift) - 1 ) / 2i; } diff --git a/src/Lineshapes/LASS.cpp b/src/Lineshapes/LASS.cpp index eae25a1eb3f..1d6acb358ef 100644 --- a/src/Lineshapes/LASS.cpp +++ b/src/Lineshapes/LASS.cpp @@ -14,7 +14,6 @@ DEFINE_LINESHAPE( LASS ) { const auto props = ParticlePropertiesList::get( particleName ); Expression mass = Parameter( particleName + "_mass", props->mass() ); - Expression radius = Parameter( particleName + "_radius", props->radius() ); Expression width0 = Parameter( particleName + "_width", props->width() ); Expression s0 = mass*mass; Expression a = Parameter( "LASS::a", 2.07 ); @@ -32,13 +31,15 @@ DEFINE_LINESHAPE( LASS ) Expression tan_phi2 = mass*gamma / (s0 - s); Expression phase = atan(tan_phi1) + atan(tan_phi2); - ADD_DEBUG(sin(phase) * exp( i * phase ) / rho, dbexpressions ); Expression bw = ( mass * width0 ) / ( rho0 * ( s0 -s -i*mass*gamma ) ); Expression nrPhaseShift = ( 2 + a * r * q2 + i * 2*a*q ) / ( 2+a*r*q2 - i*2*a*q ); Expression NR = 2*a*sqrt(s)/( 2 + a*r*q*q -2*i*a*q ); + ADD_DEBUG(s, dbexpressions ); ADD_DEBUG(nrPhaseShift*bw, dbexpressions ); ADD_DEBUG(NR, dbexpressions ); ADD_DEBUG(NR + bw*nrPhaseShift, dbexpressions ); + ADD_DEBUG(sin(phase) * exp( i * phase ) , dbexpressions ); + ADD_DEBUG(sin(phase) * exp( i * phase ) / rho, dbexpressions ); // Takes the splitting of the LASS into a "resonant" and "nonresonant" // component from Laura++, as a better implementation of the "gLASS" lineshape diff --git a/src/Lineshapes/ObelixRho.cpp b/src/Lineshapes/ObelixRho.cpp deleted file mode 100644 index 238f076cc42..00000000000 --- a/src/Lineshapes/ObelixRho.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include -#include -#include - -#include "AmpGen/Expression.h" -#include "AmpGen/Factory.h" -#include "AmpGen/Lineshapes.h" -#include "AmpGen/MsgService.h" -#include "AmpGen/ParticleProperties.h" -#include "AmpGen/Tensor.h" -#include "AmpGen/Utilities.h" - -using namespace AmpGen; - -#include "AmpGen/ParticlePropertiesList.h" -#include "AmpGen/kMatrix.h" - -DEFINE_LINESHAPE( ObelixRho ) -{ - Expression sInGeV = SubTree( s / (GeV*GeV) ); - DEBUG( "kMatrix modifier " << lineshapeModifier << " particle = " << particleName ); - auto tokens = split( lineshapeModifier, '.' ); - - DEBUG( "kMatrix modifier = " << lineshapeModifier << " nTokens = " << tokens.size() ); - unsigned int pTerm = tokens.size() > 0 ? stoi( tokens[0] ) : 999; - if ( pTerm == 999 ) { - ERROR( "Pole term not recognised: " << pTerm ); - } - - double mPiPlus( 0.139570 ); - double mKPlus( 0.493677 ); - std::vector phaseSpace = {phsp_twoBody( sInGeV, mPiPlus, mPiPlus ), phsp_fourPi( sInGeV ), - phsp_twoBody( sInGeV, mKPlus, mKPlus )}; - const unsigned int nPoles = 3; - const unsigned int nChannels = 3; - auto props = ParticlePropertiesList::get( "rho(770)0" ); - - const Expression radius = Parameter( particleName + "_radius", props->radius() ); - - std::vector poleConfigs; - - for ( unsigned int i = 1; i <= nPoles; ++i ) { - std::string stub = "rho_p" + std::to_string( i ); - Expression mRho = Parameter( ( stub + "_mass" ) ); - Expression gRho1 = Parameter( ( stub + "_pipi" ) ); - Expression gRho2 = Parameter( ( stub + "_4pi" ) ); - Expression gRho3 = Parameter( ( stub + "_KK" ) ); - poleConfig pole( mRho * mRho ); - - pole.add( gFromGamma( mRho, gRho1, phsp_twoBody( mRho * mRho, mPiPlus, mPiPlus ) ), - BL( sInGeV, mRho * mRho, mPiPlus * mPiPlus, mPiPlus * mPiPlus, radius, 1 ) ); - - pole.add( gFromGamma( mRho, gRho2, phsp_fourPi( mRho * mRho ) ) ); - - pole.add( gFromGamma( mRho, gRho3, phsp_twoBody( mRho * mRho, mKPlus, mKPlus ) ), - BL( sInGeV, mRho * mRho, mKPlus * mKPlus, mKPlus * mKPlus, radius, 1 ) ); - - poleConfigs.emplace_back( pole ); - } - - auto kMatrix = constructKMatrix( sInGeV, nChannels, poleConfigs ); - - if ( dbexpressions != nullptr ) { - for ( auto& p : poleConfigs ) { - ADD_DEBUG( p.s, dbexpressions ); - ADD_DEBUG( p.couplings[0], dbexpressions ); - ADD_DEBUG( p.couplings[1], dbexpressions ); - ADD_DEBUG( p.couplings[2], dbexpressions ); - } - ADD_DEBUG( phaseSpace[0], dbexpressions ); - ADD_DEBUG( phaseSpace[1], dbexpressions ); - ADD_DEBUG( phaseSpace[2], dbexpressions ); - for ( unsigned int i = 0; i < nChannels; ++i ) { - for ( unsigned int j = 0; j < nChannels; ++j ) { - dbexpressions->emplace_back( "K[" + std::to_string( i ) + "," + std::to_string( j ) + "]", kMatrix[{i, j}] ); - } - } - } - - Tensor propagator = getPropagator( kMatrix, phaseSpace ); - - Expression M; - - auto pole = poleConfigs[pTerm]; - const Expression q2 = Abs( Q2( s, s1, s2 ) ); - - for ( unsigned int i = 0; i < nChannels; ++i ) { - M = M + propagator[{0, i}] * pole.g( i ); - } - return SubTree( M / ( pole.s - sInGeV ) ); -} diff --git a/src/Lineshapes/Photon.cpp b/src/Lineshapes/Photon.cpp new file mode 100644 index 00000000000..4f241116a44 --- /dev/null +++ b/src/Lineshapes/Photon.cpp @@ -0,0 +1,11 @@ +#include "AmpGen/Lineshapes.h" +#include "AmpGen/ParticlePropertiesList.h" + +using namespace AmpGen; + +DEFINE_LINESHAPE( Photon ) +{ + auto props = ParticlePropertiesList::get( particleName ); + Expression mass = Parameter( particleName + "_mass", props->mass() ); + return 1. / ( s - mass*mass ); +} diff --git a/src/Lineshapes/Poly.cpp b/src/Lineshapes/Poly.cpp index 87ae781931a..5f21b6a63da 100644 --- a/src/Lineshapes/Poly.cpp +++ b/src/Lineshapes/Poly.cpp @@ -9,7 +9,10 @@ using namespace AmpGen; DEFINE_LINESHAPE( Poly ) { - unsigned int degree = NamedParameter( lineshapeModifier + "::Degree" ); - auto params = parameterVector( lineshapeModifier + "_c", degree ); + size_t degree = NamedParameter( lineshapeModifier + "::Degree" ); + auto params = parameterVector(lineshapeModifier + "_c", degree + 1); + ADD_DEBUG(s, dbexpressions); + if( dbexpressions != nullptr ) for( size_t i=0;iemplace_back( lineshapeModifier +"_c"+std::to_string(i), params[i] ); return pol(s, params); } diff --git a/src/Lineshapes/PolyNR.cpp b/src/Lineshapes/PolyNR.cpp new file mode 100644 index 00000000000..066c2abcdf4 --- /dev/null +++ b/src/Lineshapes/PolyNR.cpp @@ -0,0 +1,52 @@ +#include + +#include "AmpGen/Expression.h" +#include "AmpGen/Factory.h" +#include "AmpGen/Lineshapes.h" +#include "AmpGen/NamedParameter.h" + +using namespace AmpGen; + +DEFINE_GENERIC_SHAPE( PolyNR ) +{ + auto p0 = *p.daughter(0); + auto p1 = *p.daughter(1); + auto p2 = *p.daughter(2); + auto p01 = (p0.P() + p1.P()); + auto p02 = (p0.P() + p2.P()); + auto s01 = dot( p01, p01 ); + auto s02 = dot( p02, p02 ); + size_t degree = NamedParameter( lineshapeModifier + "::Degree" ) +1; + std::vector< std::vector > C( degree, std::vector(degree) ); + + for( size_t i = 0 ; i != degree ; ++i ) + { + for( size_t j = 0 ; j != degree ; ++j ){ + auto pname = lineshapeModifier +"_"+std::to_string(i) + "_"+std::to_string(j) ; + C[i][j] = Parameter(pname, 0); + if( dbexpressions != nullptr ) + dbexpressions->emplace_back( pname, C[i][j] ); + } + } + Expression rt; + for( size_t i = 0 ; i != degree; ++i ) + { + for( size_t j = 0 ; j != degree ; ++j ) + { + rt = rt + C[i][j] * fcn::pow(s01, i) * fcn::pow(s02, j); + } + } + return rt; +} + +DEFINE_LINESHAPE( EXPNR ) +{ + Expression alpha = Parameter( particleName + "_alpha", 0 ); + Expression beta = Parameter( particleName + "_beta", 0 ); + + const Expression BW = Exp(-alpha * s - Constant(0,1) * beta * s); + + ADD_DEBUG( BW, dbexpressions ); + return BW; +} + diff --git a/src/Lineshapes/TD.cpp b/src/Lineshapes/TD.cpp new file mode 100644 index 00000000000..6bfd744cec6 --- /dev/null +++ b/src/Lineshapes/TD.cpp @@ -0,0 +1,20 @@ +#include +#include +#include + +#include "AmpGen/Expression.h" +#include "AmpGen/Factory.h" +#include "AmpGen/Lineshapes.h" +#include "AmpGen/Tensor.h" +#include "AmpGen/ParticleProperties.h" + +using namespace AmpGen; +using namespace AmpGen::fcn; + +DEFINE_GENERIC_SHAPE( TD ) +{ + Expression tau = Parameter(p.name() +"_decayTime"); + ADD_DEBUG( tau, dbexpressions ); + ADD_DEBUG( p.props()->lifetime(), dbexpressions ); + return tau / ( 2 * p.props()->lifetime() ); +} diff --git a/src/Lineshapes/kMatrix.cpp b/src/Lineshapes/kMatrix.cpp index 073406dd3be..5fb6569a98e 100644 --- a/src/Lineshapes/kMatrix.cpp +++ b/src/Lineshapes/kMatrix.cpp @@ -24,7 +24,8 @@ Expression AmpGen::phsp_twoBody( const Expression& s, const double& m0, const do Expression AmpGen::phsp_fourPi( const Expression& s ) { - double mPiPlus( 0.139570 ); + // Parameterisation of the 4pi phase-space taken from Laura++ (https://laura.hepforge.org/ or Ref. https://arxiv.org/abs/1711.09854) + double mPiPlus = 0.139570; Expression rho_4pi = pol( s, {0.00051, -0.01933, 0.13851, -0.20840, -0.29744, 0.13655, 1.07885} ); return Ternary( s > 1, phsp_twoBody( s, 2 * mPiPlus, 2 * mPiPlus ), rho_4pi ); } @@ -39,7 +40,7 @@ Expression AmpGen::phsp_FOCUS( const Expression& s, const double& m0, const doub std::vector AmpGen::paramVector( const std::string& name, const unsigned int& nParam ) { std::vector returnVector; - for(size_t i = 0; i < nParam; ++i ) returnVector.emplace_back( name + std::to_string(i) ); + for(unsigned i = 0; i < nParam; ++i ) returnVector.emplace_back( name + std::to_string(i) ); return returnVector; } @@ -48,23 +49,24 @@ Expression AmpGen::gFromGamma( const Expression& m, const Expression& gamma, con return fcn::sqrt( m * gamma / rho ); } -Tensor AmpGen::getPropagator(const Tensor& kMatrix, const std::vector& phaseSpace) +Tensor AmpGen::getPropagator(const Tensor& kMatrix, const std::vector& phaseSpace, DebugSymbols* db ) { unsigned int nChannels = kMatrix.dims()[0]; Tensor T( Tensor::dim(nChannels, nChannels) ); - for (size_t i = 0; i < nChannels; ++i ) { - for (size_t j = 0; j < nChannels; ++j ) { + for (unsigned i = 0; i < nChannels; ++i ) { + for (unsigned j = 0; j < nChannels; ++j ) { T[{i, j}] = SubTree( ( i == j ? 1 : 0 ) - 1i * kMatrix[{i, j}] * phaseSpace[j] ); } } + ADD_DEBUG_TENSOR( T, db ); return T.Invert(); } -Tensor AmpGen::constructKMatrix(const Expression& this_s, const size_t& nChannels, const std::vector& poleConfigs) +Tensor AmpGen::constructKMatrix(const Expression& this_s, const unsigned& nChannels, const std::vector& poleConfigs) { Tensor kMatrix( Tensor::dim(nChannels, nChannels)); - for ( size_t i = 0; i < nChannels; ++i ) { - for ( size_t j = 0; j < nChannels; ++j ) { + for ( unsigned i = 0; i < nChannels; ++i ) { + for ( unsigned j = 0; j < nChannels; ++j ) { Expression sumOverPoles = 0; for ( auto& pole : poleConfigs ) { Expression term = ( pole.couplings[i] * pole.couplings[j] ) / ( pole.s - this_s ); @@ -91,7 +93,7 @@ DEFINE_LINESHAPE( kMatrix ) double mPiPlus = 0.139570; double mKPlus = 0.493677; double mEta = 0.547862; - double mEtap = 0.96778; + double mEtap = 0.967780; Expression sA0 = Parameter( "sA0", -0.15 ); Expression sA = Parameter( "sA", 1.0 ); @@ -100,11 +102,11 @@ DEFINE_LINESHAPE( kMatrix ) std::vector fScatt = paramVector( "f_scatt", nChannels ); std::vector poleConfigs; - + bool addImaginaryMass = NamedParameter("kMatrix::fp", true ); for ( unsigned int pole = 1; pole <= nPoles; ++pole ) { std::string stub = "IS_p" + std::to_string( pole ) + "_"; Expression mass = Parameter( stub + "mass" ); - poleConfig p( mass * mass ); + poleConfig p( mass * mass + addImaginaryMass * (1i)*(1.e-6) ); /// add a tiny imaginary part to the mass to avoid floating point errors // for ( unsigned int ch = 0; ch < nChannels; ++ch ) p.add( Parameter( stub + channels[ch] ) ); poleConfigs.push_back( p ); } @@ -117,7 +119,7 @@ DEFINE_LINESHAPE( kMatrix ) auto kMatrix = constructKMatrix( sInGeV, 5, poleConfigs); Tensor scattPart( Tensor::dim(5,5) ); - for(size_t i = 0; i < 5;++i){ + for(unsigned i = 0; i < 5;++i){ scattPart(i,0) = fScatt[i]*( 1 - s0_scatt )/( s - s0_scatt ); scattPart(0,i) = fScatt[i]*( 1 - s0_scatt )/( s - s0_scatt ); } @@ -128,7 +130,7 @@ DEFINE_LINESHAPE( kMatrix ) Expression adlerTerm = SubTree( ( 1. - sA0 ) * ( sInGeV - sA * mPiPlus * mPiPlus / 2 ) / ( sInGeV - sA0 ) ); kMatrix = adlerTerm * kMatrix; - Tensor F = getPropagator(kMatrix, phaseSpace); + Tensor F = getPropagator(kMatrix, phaseSpace, dbexpressions); if ( dbexpressions != nullptr ) { for ( auto& p : poleConfigs ) { @@ -146,6 +148,7 @@ DEFINE_LINESHAPE( kMatrix ) ADD_DEBUG( sA0, dbexpressions ); ADD_DEBUG( adlerTerm, dbexpressions ); ADD_DEBUG_TENSOR( kMatrix, dbexpressions ); + ADD_DEBUG_TENSOR( F, dbexpressions ); } if ( tokens[0] == "scatt" ) { @@ -181,6 +184,6 @@ DEFINE_LINESHAPE( kMatrix ) DEBUG( "Returning bkg term" ); return F[{1, pTerm}] * ( 1 - s0_prod ) / ( sInGeV - s0_prod ); } - ERROR( "Lineshape not found: " << lineshapeModifier ); + ERROR( "Modifier not found: " << lineshapeModifier << ", expecting one of {scatt, pole, poleKK, prod, prodKK}" ); return Expression( 0 ); } diff --git a/src/Minimiser.cpp b/src/Minimiser.cpp index bd92ccfbc44..b28f69fcaa5 100644 --- a/src/Minimiser.cpp +++ b/src/Minimiser.cpp @@ -8,7 +8,6 @@ #include #include - #include "AmpGen/IExtendLikelihood.h" #include "AmpGen/MinuitParameter.h" #include "AmpGen/MinuitParameterSet.h" @@ -18,34 +17,31 @@ #include "Math/Factory.h" #include "Math/Functor.h" #include "Math/Minimizer.h" +#include "AmpGen/ProfileClock.h" using namespace AmpGen; using namespace ROOT; unsigned int Minimiser::nPars() const { return m_nParams; } -void Minimiser::print( const double& LL ) -{ - INFO( "Iteration # " << m_lastPrint << " FCN = " << round( LL, 3 ) << " Edm = " << round( m_minimiser->Edm(), 3 ) - << " NCalls = " << m_minimiser->NCalls() ); -} - double Minimiser::operator()( const double* xx ) { - for ( unsigned int i = 0; i < m_mapping.size(); ++i ) { - m_parSet->getParPtr( m_mapping[i] )->setCurrentFitVal( xx[i] ); + ProfileClock callTime; + for(size_t i = 0; i < m_mapping.size(); ++i ) { + m_parSet->at( m_mapping[i] )->setCurrentFitVal( xx[i] ); } - double LL = m_theFunction(); - for ( auto& extendTerm : m_extendedTerms ) { - LL -= 2 * extendTerm->getVal(); - } - return LL; + double LL = m_theFunction() ; + for ( auto& extendTerm : m_extendedTerms ) LL -= 2 * extendTerm->getVal(); + callTime.stop(); + return LL - m_ll_zero; } -void Minimiser::GradientTest() +double Minimiser::FCN() const { return m_theFunction(); } + +void Minimiser::gradientTest() { - for ( unsigned int i = 0; i < m_mapping.size(); ++i ) { - auto parameter = m_parSet->getParPtr( m_mapping[i] ); + for (size_t i = 0; i < m_mapping.size(); ++i) { + auto parameter = m_parSet->at( m_mapping[i] ); double m = parameter->mean(); parameter->setCurrentFitVal( parameter->meanInit() + parameter->stepInit() ); double vp = FCN(); @@ -59,38 +55,34 @@ void Minimiser::GradientTest() parameter->setCurrentFitVal( m ); } } -double Minimiser::FCN() const { return m_theFunction(); } void Minimiser::prepare() { std::string algorithm = NamedParameter( "Minimiser::Algorithm", "Hesse"); size_t maxCalls = NamedParameter( "Minimiser::MaxCalls" , 100000); - double tolerance = NamedParameter( "Minimiser::Tolerance" , 0.01); + double tolerance = NamedParameter( "Minimiser::Tolerance" , 1.0); m_printLevel = NamedParameter( "Minimiser::PrintLevel", 4); + m_normalise = NamedParameter( "Minimiser::Normalise",false); if ( m_minimiser != nullptr ) delete m_minimiser; m_minimiser = new Minuit2::Minuit2Minimizer(algorithm.c_str() ); DEBUG( "Error definition = " << m_minimiser->ErrorDef() ); m_minimiser->SetMaxFunctionCalls( maxCalls ); m_minimiser->SetMaxIterations( 100000 ); m_minimiser->SetTolerance( tolerance ); +// m_minimiser->SetStrategy( 3 ); + // m_minimiser->SetPrecision(std::numeric_limits::epsilon()); m_minimiser->SetPrintLevel( m_printLevel ); m_mapping.clear(); m_covMatrix.clear(); - for(size_t i = 0 ; i < m_parSet->size(); ++i) + for(size_t i = 0 ; i < m_parSet->size(); ++i) { - auto par = m_parSet->getParPtr(i); - if ( par->iFixInit() != 0 ) continue; + auto par = m_parSet->at(i); + if ( ! par->isFree() ) continue; m_minimiser->SetVariable(m_mapping.size(), par->name(), par->mean(), par->stepInit()); - if ( par->minInit() != 0 || par->maxInit() != 0 ) + if ( par->minInit() != 0 || par->maxInit() != 0 ) m_minimiser->SetVariableLimits( m_mapping.size(), par->minInit(), par->maxInit() ); m_mapping.push_back(i); - if ( m_printLevel != 0 ) { - INFO( "Parameter: " << std::left << std::setw(60) << par->name() << " = " - << std::right << std::setw(12) << par->mean() << " ± " - << std::left << std::setw(12) << par->stepInit() - << ( ( par->minInit() != 0 || par->maxInit() != 0 ) ? - ("["+ std::to_string(par->minInit()) + ", " + std::to_string(par->maxInit() ) ) + "]" : "" ) ); - } + if ( m_printLevel != 0 ) INFO( *par ); } m_nParams = m_mapping.size(); m_covMatrix.resize( m_nParams * m_nParams, 0 ); @@ -98,19 +90,18 @@ void Minimiser::prepare() bool Minimiser::doFit() { - m_lastPrint = 999; + if( m_normalise ) m_ll_zero = m_theFunction(); ROOT::Math::Functor f( *this, m_nParams ); - for ( unsigned int i = 0; i < m_mapping.size(); ++i ) { - MinuitParameter* par = m_parSet->getParPtr( m_mapping[i] ); + for (size_t i = 0; i < m_mapping.size(); ++i ) { + MinuitParameter* par = m_parSet->at( m_mapping[i] ); m_minimiser->SetVariable( i, par->name(), par->mean(), par->stepInit() ); if ( par->minInit() != 0 || par->maxInit() != 0 ) m_minimiser->SetVariableLimits( i, par->minInit(), par->maxInit() ); } - m_minimiser->SetFunction( f ); m_minimiser->Minimize(); - for ( unsigned int i = 0; i < m_nParams; ++i ) { - auto par = m_parSet->getParPtr( m_mapping[i] ); + for (size_t i = 0; i < m_nParams; ++i ) { + auto par = m_parSet->at( m_mapping[i] ); double error = *( m_minimiser->Errors() + i ); par->setResult( *( m_minimiser->X() + i ), error, error, error ); for ( unsigned int j = 0; j < m_nParams; ++j ) { @@ -118,6 +109,21 @@ bool Minimiser::doFit() } } m_status = m_minimiser->Status(); + if(NamedParameter("Minimiser::RunMinos",false)){ + for( unsigned i = 0 ; i != m_nParams; ++i ){ + double low = 0; + double high = 0; + int status = 0; + m_minimiser->GetMinosError(i, low, high, status); + auto param = m_parSet->at( m_mapping[i] ); + param->setResult( *param, param->err(), low, high ); + } + for( unsigned i = 0 ; i != m_nParams; ++i ) + { + auto param = m_parSet->at( m_mapping[i] ); + INFO( param->name() << " " << param->mean() << " " << param->errPos() << " " << param->errNeg() ); + } + } return 1; } @@ -162,8 +168,9 @@ TMatrixTSym Minimiser::covMatrixFull() const MinuitParameterSet* Minimiser::parSet() const { return m_parSet; } void Minimiser::addExtendedTerm( IExtendLikelihood* m_term ) -{ - m_extendedTerms.push_back( m_term ); +{ + m_extendedTerms.push_back( m_term ); } -ROOT::Math::Minimizer* Minimiser::minimiserInternal() { return m_minimiser; } +ROOT::Minuit2::Minuit2Minimizer* Minimiser::minimiserInternal() { return m_minimiser; } + diff --git a/src/MinuitExpression.cpp b/src/MinuitExpression.cpp index 1625781e92f..d9f1c015ae1 100644 --- a/src/MinuitExpression.cpp +++ b/src/MinuitExpression.cpp @@ -12,9 +12,19 @@ using namespace AmpGen; MinuitExpression::MinuitExpression( const std::vector& tokens, MinuitParameterSet* mps ) { setName( tokens[0] ); - std::string total_line = ""; - for ( size_t it = 2; it != tokens.size(); ++it ) total_line += tokens[it] + " "; - ExpressionParser::getMe()->setMPS( mps ); - m_expression = ExpressionParser::Parse( total_line ); - m_isGood = true; + m_expression = ExpressionParser::parse(tokens.begin() + 2 , tokens.end() , mps ); + fix(); } + +MinuitExpression::MinuitExpression(const std::string& name, const Expression& expression) +{ + setName(name); + m_expression = expression; + fix(); +} + +double MinuitExpression::mean() const { return std::real(getVal()); } +complex_t MinuitExpression::getVal() const { return m_expression(); } +MinuitExpression::operator double() const { return std::real(getVal()); } +MinuitExpression::~MinuitExpression() = default; + diff --git a/src/MinuitParameter.cpp b/src/MinuitParameter.cpp index 8edc615e4a9..b0913ea5ae3 100644 --- a/src/MinuitParameter.cpp +++ b/src/MinuitParameter.cpp @@ -1,6 +1,7 @@ // author: Jonas Rademacker (Jonas.Rademacker@bristol.ac.uk) // status: Mon 9 Feb 2009 19:17:55 GMT #include "AmpGen/MinuitParameter.h" +#include "AmpGen/Utilities.h" #include @@ -8,28 +9,39 @@ using namespace AmpGen; -MinuitParameter::MinuitParameter( const std::string& name, const MinuitParameter::Flag& fix, const double& mean, const double& step, +namespace AmpGen { + complete_enum( Flag, Free, Hide, Fix, CompileTimeConstant, Invalid ) +} + +MinuitParameter::MinuitParameter( const std::string& name, const Flag& fix, const double& mean, const double& step, const double& mi, const double& ma ) - : m_iFixInit( fix ), m_name( name ), m_meanInit( mean ), m_stepInit( step ), m_minInit( mi ), m_maxInit( ma ) + : m_flag( fix ), m_name( name ), m_meanInit( mean ), m_stepInit( step ), m_minInit( mi ), m_maxInit( ma ) { DEBUG( "Building parameter : " << name ); resetToInit(); } -MinuitParameter::Flag MinuitParameter::iFixInit() const { return m_iFixInit; } - -double MinuitParameter::meanInit() const { return m_meanInit; } -double MinuitParameter::stepInit() const { return m_stepInit; } -double MinuitParameter::minInit() const { return m_minInit; } -double MinuitParameter::maxInit() const { return m_maxInit; } -double MinuitParameter::mean() const { return m_meanResult; } -double MinuitParameter::errPos() const { return m_errPosResult; } -double MinuitParameter::errNeg() const { return m_errNegResult; } -double MinuitParameter::err() const { return m_errResult; } - -bool MinuitParameter::fixed() { return m_iFixInit == Flag::Fix; } +MinuitParameter::MinuitParameter( const std::string& name, const double& mean, const double& step, const double& mi, const double& ma ) + : MinuitParameter(name, Flag::Free, m_meanInit, m_stepInit, m_minInit, m_maxInit ) +{ + DEBUG( "Building parameter : " << name ); + resetToInit(); +} -void MinuitParameter::fix() { m_iFixInit = Flag::Fix; } +Flag MinuitParameter::flag() const { return m_flag; } +double MinuitParameter::meanInit() const { return m_meanInit; } +double MinuitParameter::stepInit() const { return m_stepInit; } +double MinuitParameter::minInit() const { return m_minInit; } +double MinuitParameter::maxInit() const { return m_maxInit; } +double MinuitParameter::mean() const { return m_meanResult; } +double MinuitParameter::errPos() const { return m_errPosResult; } +double MinuitParameter::errNeg() const { return m_errNegResult; } +double MinuitParameter::err() const { return m_errResult; } +bool MinuitParameter::isFixed() const { return m_flag == Flag::Fix || m_flag == Flag::CompileTimeConstant; } +bool MinuitParameter::isFree() const { return m_flag == Flag::Free; } +const std::string& MinuitParameter::name() const { return m_name; } + +void MinuitParameter::fix() { m_flag = Flag::Fix; } void MinuitParameter::scaleStep( const double& sf ) { m_errResult *= sf; @@ -40,14 +52,17 @@ void MinuitParameter::setStepInit( const double& si ) m_stepInit = si; } -const std::string& MinuitParameter::name() const { return m_name; } -bool MinuitParameter::hidden() const { return m_iFixInit == 1; } -void MinuitParameter::setFree() { INFO("Setting parameter: " << m_name << " free" ) ; m_iFixInit = Flag::Float; } +void MinuitParameter::setFree() { INFO("Setting parameter: " << m_name << " free" ) ; m_flag = Flag::Free; } void MinuitParameter::setCurrentFitVal( double cfv ) { m_meanResult = cfv; } -void MinuitParameter::setInit( const double& val ) { m_meanInit = val; } +void MinuitParameter::setInit( const double& val, const double& step ) +{ + m_meanInit = val; + m_meanResult = val; + if( step != -1 ) m_stepInit = step; +} void MinuitParameter::setResult( double fitMean, double fitErr, double fitErrPos, double fitErrNeg ) { @@ -57,11 +72,6 @@ void MinuitParameter::setResult( double fitMean, double fitErr, double fitErrPos m_errNegResult = fitErrNeg; } -void MinuitParameter::print( std::ostream& os ) const -{ - os << std::left << std::setw(65) << name() << "\t" << iFixInit() << "\t" << mean() << "\t" << err() << "\t" << minInit() << "\t" << maxInit(); -} - void MinuitParameter::setName( const std::string& name ) { m_name = name; } void MinuitParameter::resetToInit() @@ -77,3 +87,13 @@ void MinuitParameter::setLimits( const double& min, const double& max ) m_minInit = min; m_maxInit = max; } + +std::ostream& AmpGen::operator<<( std::ostream& os, const MinuitParameter& par ) +{ + return os << std::left << std::setw(60) << par.name() << " = " + << std::right << std::setw(12) << par.mean() << " ± " + << std::left << std::setw(12) << par.stepInit() + << ( ( par.minInit() != 0 || par.maxInit() != 0 ) ? + ("["+ std::to_string(par.minInit()) + ", " + std::to_string(par.maxInit() ) ) + "]" : "") + << " [flag=" << to_string(par.flag()) << "]"; +} diff --git a/src/MinuitParameterSet.cpp b/src/MinuitParameterSet.cpp index 72b23ba6b77..39ed23b5433 100644 --- a/src/MinuitParameterSet.cpp +++ b/src/MinuitParameterSet.cpp @@ -21,185 +21,133 @@ using namespace AmpGen; MinuitParameterSet::MinuitParameterSet() = default; -MinuitParameterSet::MinuitParameterSet( const MinuitParameterSet& other ) - : _parPtrList( other._parPtrList ), _keyAccess( other._keyAccess ) +MinuitParameterSet::MinuitParameterSet(const std::vector& params ) { -} - -MinuitParameterSet MinuitParameterSet::getFloating() -{ - MinuitParameterSet floating; - for ( auto& param : *this ) { - if ( param->iFixInit() == MinuitParameter::Flag::Float ) floating.add(param); - } - return floating; + for( auto& param : params ) add(param); } bool MinuitParameterSet::addToEnd( MinuitParameter* parPtr ) { bool success = true; if ( nullptr == parPtr ) return false; - - _parPtrList.push_back( parPtr ); - - if ( _keyAccess.find( parPtr->name() ) != _keyAccess.end() ) { + m_parameters.push_back( parPtr ); + if ( m_keyAccess.find( parPtr->name() ) != m_keyAccess.end() ) { WARNING( "Parameter with name " << parPtr->name() << " already exists!" ); } - _keyAccess[parPtr->name()] = parPtr; + m_keyAccess[parPtr->name()] = parPtr; return success; } -MinuitParameter* MinuitParameterSet::add( const std::string& name, const unsigned int& flag, const double& mean, - const double& sigma, const double& min, const double& max ) +MinuitParameter* MinuitParameterSet::add( const std::string& name, const Flag& flag, const double& mean, + const double& sigma, const double& min, const double& max ) { - addToEnd( new MinuitParameter( name, MinuitParameter::Flag(flag), mean, sigma, min, max ) ); - return _keyAccess[name]; + addToEnd( new MinuitParameter( name, Flag(flag), mean, sigma, min, max ) ); + return m_keyAccess[name]; } bool MinuitParameterSet::add( MinuitParameter* parPtr ) { return addToEnd( parPtr ); } bool MinuitParameterSet::unregister( MinuitParameter* parPtr ) { - if ( _parPtrList.end() == std::find( _parPtrList.begin(), _parPtrList.end(), parPtr ) ) { + if ( m_parameters.end() == std::find( m_parameters.begin(), m_parameters.end(), parPtr ) ) { WARNING( "parPtr you want to unregister is not part of this list!" ); return false; } - _parPtrList.erase( remove( _parPtrList.begin(), _parPtrList.end(), parPtr ), _parPtrList.end() ); + m_parameters.erase( remove( m_parameters.begin(), m_parameters.end(), parPtr ), m_parameters.end() ); return true; } -unsigned int MinuitParameterSet::size() const { return _parPtrList.size(); } - -MinuitParameter* MinuitParameterSet::getParPtr( unsigned int i ) const -{ - if ( i >= _parPtrList.size() ) return nullptr; - return _parPtrList[i]; -} - -void MinuitParameterSet::deleteListAndObjects() -{ - for ( auto it = _parPtrList.begin(); it != _parPtrList.end(); ++it ) { - delete *it; - } - _parPtrList.clear(); -} - -void MinuitParameterSet::deleteListKeepObjects() { _parPtrList.clear(); } +unsigned int MinuitParameterSet::size() const { return m_parameters.size(); } void MinuitParameterSet::print( std::ostream& os ) const { - for ( unsigned int i = 0; i < size(); i++ ) { - if ( nullptr == getParPtr( i ) ) continue; - os << '\n'; - getParPtr( i )->print( os ); + for (size_t i = 0; i < size(); i++ ) { + os << '\n' << *m_parameters[i]; } os << '\n'; } void MinuitParameterSet::printVariable( std::ostream& os ) const { - for ( unsigned int i = 0; i < size(); i++ ) { - if ( nullptr == getParPtr( i ) ) continue; - if ( getParPtr( i )->iFixInit() == 1 ) continue; /// hide parameter - os << '\n'; - getParPtr( i )->print( os ); + for (size_t i = 0; i < size(); i++ ) { + if ( m_parameters[i]->flag() == Flag::Hide ) continue; /// hide parameter + os << '\n' << *m_parameters[i]; } } MinuitParameter* MinuitParameterSet::operator[]( const std::string& key ) { - auto it = _keyAccess.find( key ); - if ( it == _keyAccess.end() ) { + auto it = m_keyAccess.find( key ); + if ( it == m_keyAccess.end() ) { WARNING( "Parameter: " << key << " not found" ); } return it->second; } + MinuitParameter* MinuitParameterSet::operator[]( const std::string& key ) const { - auto it = _keyAccess.find( key ); - if ( it == _keyAccess.end() ) { + auto it = m_keyAccess.find( key ); + if ( it == m_keyAccess.end() ) { WARNING( "Parameter: " << key << " not found" ); } return it->second; } -MinuitParameter* MinuitParameterSet::operator[]( const unsigned int& key ) { return _parPtrList[key]; } + +MinuitParameter* MinuitParameterSet::operator[]( const size_t& key ) { return m_parameters[key]; } + MinuitParameter* MinuitParameterSet::at( const std::string& key ) { - if ( _keyAccess.count( key ) == 0 ) { + if ( m_keyAccess.count( key ) == 0 ) { ERROR( key << " not found" ); return nullptr; } else - return _keyAccess[key]; + return m_keyAccess[key]; +} + +MinuitParameter* MinuitParameterSet::at( const size_t& index ) const +{ + if( index >= m_parameters.size() ) + ERROR( "Attempting to access parameter " << index << " when only " << m_parameters.size() << " have been defined" ); + return index < m_parameters.size() ? m_parameters[index] : nullptr; } + void MinuitParameterSet::tryParameter( const std::vector& line ) { + bool status = true; if ( line.size() == 4 || line.size() == 6 ) { - bool status = true; - int flag = lexical_cast( line[1], status ); - if( flag > 3 ) return ; + bool hasLimits = line.size() == 6; double mean = lexical_cast( line[2], status ); double step = lexical_cast( line[3], status ); - double min = line.size() == 6 ? lexical_cast( line[4], status ) : 0; - double max = line.size() == 6 ? lexical_cast( line[5], status ) : 0; - - if ( status ) { - if ( OptionsParser::printHelp() ) - INFO( "MINUIT: Registered " << line[0] << " (flag " << flag << ") = " << mean << ", step=" << step << " (" - << min << "," << max << ")" ); - add( new MinuitParameter( line[0], MinuitParameter::Flag(flag), mean, step, min, max ) ); - } - return; + double min = hasLimits ? lexical_cast( line[4], status ) : 0; + double max = hasLimits ? lexical_cast( line[5], status ) : 0; + if( !status ) return; + auto flag = parse( line[1] ); + if( flag == Flag::Invalid ) return; + if ( OptionsParser::printHelp() ) + INFO( "MINUIT: Registered " << line[0] << " ( " << to_string(flag) << ") = " << mean << ", step=" << step << " ("<< min << "," << max << ")" ); + add( new MinuitParameter( line[0], flag, mean, step, min, max ) ); } - if ( line.size() == 7 ) { - - bool status = true; - int flag_re = lexical_cast( line[1], status ); + if ( line.size() == 7 || line.size() == 11 ) { + bool hasLimits = line.size() == 11; double mean_re = lexical_cast( line[2], status ); double step_re = lexical_cast( line[3], status ); - int flag_im = lexical_cast( line[4], status ); - double mean_im = lexical_cast( line[5], status ); - double step_im = lexical_cast( line[6], status ); + double min_re = hasLimits ? lexical_cast( line[4], status ) : 0; + double max_re = hasLimits ? lexical_cast( line[5], status ) : 0; + double mean_im = lexical_cast( line[5 + 2 *hasLimits], status ); + double step_im = lexical_cast( line[6 + 2 *hasLimits], status ); + double min_im = hasLimits ? lexical_cast( line[9] , status ) : 0; + double max_im = hasLimits ? lexical_cast( line[10], status ) : 0; - double min_re = 0; - double max_re = 0; - double min_im = 0; - double max_im = 0; if ( !status ) return; - - if ( NamedParameter( "MinuitParameterSet::RegulateParameters", 0 ) == 1 ) { - if ( mean_re < 0 ) { - mean_re = -mean_re; - mean_im = mean_im + M_PI; - } - mean_im = atan2( sin( mean_im ), cos( mean_im ) ); - max_re = 1000; - } + auto flag_re = parse(line[1]); + auto flag_im = parse(line[4 + 2*hasLimits]); + if( flag_re == Flag::Invalid || flag_im == Flag::Invalid ) return; if ( OptionsParser::printHelp() ) { - INFO( "MINUIT: Complex " << line[0] << "_Re (flag " << flag_re << ") = " << mean_re << ", step=" << step_re - << " (" << min_re << "," << max_re << ")" ); - INFO( "MINUIT: Complex " << line[0] << "_Im (flag " << flag_im << ") = " << mean_im << ", step=" << step_im - << " (" << min_im << "," << max_im << ")" ); + INFO( "MINUIT: Complex " << line[0] << "_Re ( " << to_string(flag_re) << ") = " << mean_re << ", step=" << step_re << " (" << min_re << "," << max_re << ")" ); + INFO( "MINUIT: Complex " << line[0] << "_Im ( " << to_string(flag_im) << ") = " << mean_im << ", step=" << step_im << " (" << min_im << "," << max_im << ")" ); } - add( new MinuitParameter( line[0] + "_Re", MinuitParameter::Flag(flag_re), mean_re, step_re, min_re, max_re ) ); - add( new MinuitParameter( line[0] + "_Im", MinuitParameter::Flag(flag_im), mean_im, step_im, min_im, max_im ) ); - } - if ( line.size() == 11 ) { - - bool status = true; - int flag_re = lexical_cast( line[1], status ); - double mean_re = lexical_cast( line[2], status ); - double step_re = lexical_cast( line[3], status ); - double min_re = lexical_cast( line[4], status ); - double max_re = lexical_cast( line[5], status ); - int flag_im = lexical_cast( line[6], status ); - double mean_im = lexical_cast( line[7], status ); - double step_im = lexical_cast( line[8], status ); - double min_im = lexical_cast( line[9], status ); - double max_im = lexical_cast( line[10], status ); - if ( !status ) return; - - add( new MinuitParameter( line[0] + "_Re", MinuitParameter::Flag(flag_re), mean_re, step_re, min_re, max_re ) ); - add( new MinuitParameter( line[0] + "_Im", MinuitParameter::Flag(flag_im), mean_im, step_im, min_im, max_im ) ); + add( new MinuitParameter( line[0] + "_Re", flag_re, mean_re, step_re, min_re, max_re ) ); + add( new MinuitParameter( line[0] + "_Im", flag_im, mean_im, step_im, min_im, max_im ) ); } } @@ -207,42 +155,29 @@ void MinuitParameterSet::tryAlias( const std::vector& line ) { if ( line.size() < 3 ) return; if ( line[1] == "=" ) { - std::string name = line[0]; - MinuitExpression* expr = new MinuitExpression( line, this ); - if ( expr->isGood() ) { - _aliasList.push_back( expr ); - _keyAccess[name] = expr; - } else { - ERROR( "Expression is ill-formed: " << line[0] ); - delete expr; - } + addToEnd( new MinuitExpression(line, this) ); } } void MinuitParameterSet::loadFromStream() { auto ppfl = OptionsParser::getMe(); - std::vector> protoAliases; - for ( auto it = ppfl->begin(); it != ppfl->end(); ++it ) { tryParameter( it->second ); if ( it->second.size() >= 3 && it->second[1] == "=" ) protoAliases.push_back( it->second ); } for ( auto& alias : protoAliases ) tryAlias( alias ); - // print(); } void MinuitParameterSet::loadFromFile( const std::string& file ) { processFile( file, [this]( auto& line ) { - this->tryParameter( split( line, {' ', '\t'} ) ); - this->tryAlias( split( line, {' ', '\t'} ) ); - } ); + this->tryParameter( split( line, {' ', '\t'} ) ); + this->tryAlias( split( line, {' ', '\t'} ) ); + } ); } -MinuitParameterSet::~MinuitParameterSet() = default; - void MinuitParameterSet::set( const MinuitParameterSet& other ) { for ( auto& param : *this ) { @@ -256,9 +191,54 @@ void MinuitParameterSet::resetToInit() for ( auto& param : *this ) param->resetToInit(); } -MinuitParameter* MinuitParameterSet::addOrGet( const std::string& name, const unsigned int& flag, const double& mean, - const double& sigma, const double& min, const double& max ) + +bool MinuitParameterSet::rename(const std::string& name, const std::string& new_name) { - if ( _keyAccess.count( name ) != 0 ) return _keyAccess[name]; + auto it = find(name); + if( it == nullptr ){ + DEBUG("Parameter: " << name << " not found"); + return false; + } + if( name == new_name ) return false; + if( find(new_name) != nullptr ){ + DEBUG("New key for " << name << " = " << new_name << " already exists"); + return false; + } + it->setName(new_name); + m_keyAccess.erase(name); + m_keyAccess.emplace(new_name, it); + return true; +} + +MinuitParameter* MinuitParameterSet::addOrGet( const std::string& name, const Flag& flag, const double& mean, + const double& sigma, const double& min, const double& max ) +{ + if ( m_keyAccess.count( name ) != 0 ) return m_keyAccess[name]; return add( name, flag, mean, sigma, min, max ); } + +MinuitParameterSet::const_iterator MinuitParameterSet::cbegin() const { return m_parameters.cbegin(); } +MinuitParameterSet::const_iterator MinuitParameterSet::cend() const { return m_parameters.cend(); } +MinuitParameterSet::iterator MinuitParameterSet::begin() { return m_parameters.begin(); } +MinuitParameterSet::iterator MinuitParameterSet::end() { return m_parameters.end(); } +MinuitParameterSet::const_iterator MinuitParameterSet::begin() const { return m_parameters.cbegin(); } +MinuitParameterSet::const_iterator MinuitParameterSet::end() const { return m_parameters.cend(); } + +MinuitParameter* MinuitParameterSet::find( const std::string& key ) const +{ + auto it = m_keyAccess.find(key); + return it == m_keyAccess.end() ? nullptr : it->second; +} + +double MinuitParameterSet::operator()( const std::string& name ) +{ + if ( m_keyAccess.find(name) == m_keyAccess.end() ) { + ERROR( "Cannot find parameter " << name ); + } + return m_keyAccess[name]->mean(); +} + +MinuitParameterSet::~MinuitParameterSet() +{ + for( auto& param : m_parameters ) if( param != nullptr ) delete param; +} diff --git a/src/NamedParameter.cpp b/src/NamedParameter.cpp index a2b7ef86db8..282581e3b75 100644 --- a/src/NamedParameter.cpp +++ b/src/NamedParameter.cpp @@ -11,12 +11,3 @@ template class AmpGen::NamedParameter; template class AmpGen::NamedParameter; template class AmpGen::NamedParameter; -std::string AmpGen::optionalHelpString(const std::string& header, const std::vector>& args ) -{ - std::string rt=header +"\n"; - for( size_t i = 0 ; i < args.size(); ++i ){ - rt += "\033[3m " + args[i].first + std::string( 25 - args[i].first.size(), ' '); - rt += "\033[0m: " + args[i].second + (i==args.size()-1 ? "" : "\n" ); - } - return rt; -} diff --git a/src/OptionsParser.cpp b/src/OptionsParser.cpp index fec4a16b21d..8702a80102d 100644 --- a/src/OptionsParser.cpp +++ b/src/OptionsParser.cpp @@ -10,30 +10,38 @@ using namespace AmpGen; -OptionsParser::OptionsParser() : m_printHelp(false) {} - OptionsParser* OptionsParser::gOptionsParser = nullptr; +OptionsParser::OptionsParser() +{ + m_keywords["Import"] = [this](const auto& tokens){ if( tokens.size() != 2 ) return; this->import(expandGlobals(tokens[1] ) ) ; }; + m_keywords["ParticleProperties"] = [](const auto& tokens){ ParticlePropertiesList::getMutable()->addParticle( tokens ); }; + m_keywords["ParticlePropertiesList::Alias"] = [](const auto& tokens){ if( tokens.size() !=3 ) return; ParticlePropertiesList::getMutable()->makeAlias( tokens[1], tokens[2] ); }; +} + OptionsParser* OptionsParser::getMe() { if( gOptionsParser == nullptr ) gOptionsParser = new OptionsParser(); return gOptionsParser; } +void OptionsParser::setQuiet(){ + m_quiet = true; +} bool OptionsParser::ignoreThisLine( const std::string& line ) { if ( line.empty() ) return true; - const char _ignoreLinesStartingWith[] = {'*', '#', '\0'}; - for ( int i = 0; _ignoreLinesStartingWith[i] != '\0'; i++ ) { - if ( line[0] == _ignoreLinesStartingWith[i] ) return true; + const char ignoreLinesStartingWith[] = {'*', '#', '\0'}; + for ( int i = 0; ignoreLinesStartingWith[i] != '\0'; i++ ) { + if ( line[0] == ignoreLinesStartingWith[i] ) return true; } return false; } -void OptionsParser::setCommandLineArgs( int argc, char** argv ) +void OptionsParser::setCommandLineArgs( int argc, char** argv, const std::string& description ) { - printSplash(); + if( !m_quiet ) printSplash(); int x = 0; while ( ++x < argc ) { std::string token = std::string( argv[x] ); @@ -54,25 +62,19 @@ void OptionsParser::setCommandLineArgs( int argc, char** argv ) x++; } } - int depth = 0 ; if( key == "help" ) m_printHelp = true; - m_parsedLines[key] = makeParsedStrings( key + " " + val, depth ); + addArg(key +" " + val); } - for( auto& line : m_parsedLines ) - { - std::string to_string = ""; - for( auto& thing : line.second ) to_string += thing + " "; - } - if( m_printHelp ){ std::cout << bold_on << "Usage: " << bold_off << argv[0] << italic_on << " options_file1.opt options_file2.opt --key1=value1 --key2=value2 ..." << italic_off << std::endl; + if( description != "") std::cout << description << std::endl; std::cout << bold_on << "Options: " << bold_off << std::endl; } } void OptionsParser::import( const std::string& fName ) { - INFO( "Importing: " << fName ); + if( !m_quiet) INFO( "Importing: " << fName ); if ( !fileExists( fName ) ) { ERROR( "Cannot find file: " << fName ); return; @@ -80,49 +82,40 @@ void OptionsParser::import( const std::string& fName ) int braceDepth = 0 ; std::vector currentTokens; processFile( fName, [this, ¤tTokens, &braceDepth]( auto& line ) { - if ( this->ignoreThisLine( line ) ) return; - auto tokens = this->makeParsedStrings( line, braceDepth ); - for ( auto& token : tokens ) currentTokens.push_back( token ); - if ( tokens.size() == 0 ) return; - std::string name = currentTokens[0]; - if ( name == "Import" && currentTokens.size() == 2 ) { - this->import( expandGlobals( tokens[1] ) ); - currentTokens.clear(); - return; - } - if ( name == "Alias" && currentTokens.size() == 3 ) { - ParticlePropertiesList::getMutable()->makeAlias( tokens[1], tokens[2] ); - currentTokens.clear(); - return; - } - if ( braceDepth == 0 ) { - if ( this->m_parsedLines.find( name ) != this->m_parsedLines.end() ) { - WARNING( "Overwriting parameter: " << name ); - } - currentTokens.erase( std::remove_if( currentTokens.begin(), currentTokens.end(), - []( const std::string& o ) { return o == "{" || o == "}"; } ), - currentTokens.end() ); - this->m_parsedLines[name] = currentTokens; - currentTokens.clear(); - } + if ( this->ignoreThisLine( line ) ) return; + auto tokens = this->makeParsedStrings( line, braceDepth ); + for ( auto& token : tokens ) currentTokens.push_back( token ); + if ( tokens.size() == 0 ) return; + std::string key = currentTokens[0]; + if ( braceDepth != 0 ) return; + if ( this->m_parsedLines.find( key ) != this->m_parsedLines.end() ) { + WARNING( "Overwriting parameter: " << key ); + } + auto isCurlyBrace = []( const std::string& o ) { return o == "{" || o == "}"; }; + currentTokens.erase( std::remove_if( currentTokens.begin(), currentTokens.end(), isCurlyBrace), currentTokens.end() ); + this->addArg( currentTokens ); + currentTokens.clear(); } ); - - } void OptionsParser::addArg( const std::string& arg ) { int bc = 0 ; - auto tokens = makeParsedStrings( arg, bc ); - auto name = tokens[0]; - m_parsedLines[name] = tokens; + addArg( makeParsedStrings( arg, bc ) ); +} + +void OptionsParser::addArg( const std::vector& tokens ) +{ + auto& key = tokens[0]; + DEBUG("Adding arg with key: " << key ); + if( m_keywords.count(key) != 0 ) m_keywords[key]( tokens ); + else m_parsedLines[key] = tokens; } std::vector OptionsParser::makeParsedStrings( const std::string& line, int& braceDepth ) const { std::string s = line; if ( s.empty() ) return {}; - s.push_back( ' ' ); // makes sure we get last element s = " " + s; // makes things easier when we start with quotes. std::string::const_iterator prev = s.begin(); @@ -158,10 +151,10 @@ std::vector OptionsParser::makeParsedStrings( const std::string& li bool OptionsParser::printHelp() { return getMe()->m_printHelp ; } -void OptionsParser::setArgs( int argc, char** argv ){ getMe()->setCommandLineArgs(argc, argv ) ; } +void OptionsParser::setArgs( int argc, char** argv , const std::string& description){ getMe()->setCommandLineArgs(argc, argv, description); } void OptionsParser::setArg( const std::string& arg ){ getMe()->addArg( arg ); } OptionsParser::iterator OptionsParser::find( const std::string& name ) { return m_parsedLines.find( name ); } -OptionsParser::iterator OptionsParser::begin() { return m_parsedLines.begin(); } -OptionsParser::iterator OptionsParser::end() { return m_parsedLines.end(); } +OptionsParser::iterator OptionsParser::begin() { return m_parsedLines.begin(); } +OptionsParser::iterator OptionsParser::end() { return m_parsedLines.end(); } OptionsParser::const_iterator OptionsParser::begin() const { return m_parsedLines.cbegin(); } -OptionsParser::const_iterator OptionsParser::end() const { return m_parsedLines.cend(); } +OptionsParser::const_iterator OptionsParser::end() const { return m_parsedLines.cend(); } diff --git a/src/Pade.cpp b/src/Pade.cpp new file mode 100644 index 00000000000..40a8e697778 --- /dev/null +++ b/src/Pade.cpp @@ -0,0 +1,30 @@ +#include "AmpGen/Pade.h" +#include "TMatrixD.h" +#include "TVectorD.h" + + +std::vector AmpGen::detail::solve_pade(const std::function& fcn, + const double& min, + const double& max, + const unsigned& N, + const AmpGen::Strategy& strat) +{ + + TMatrixD solver(2*N+1,2*N+1); + std::vector samples(2*N+1); + if( strat < 4 ){ + for(unsigned eq = 0 ; eq < 2*N+1; ++eq) + samples[eq] = pow( eq/double(2*N), strat + 1); + } + TVectorD rest(2*N+1); + for( unsigned eq = 0 ; eq < 2*N+1; ++eq ){ + rest(eq) = fcn( samples[eq]*(max-min) + min); + for(unsigned i = 0; i <= N; ++i) solver(eq,i) = pow(samples[eq],i); + for(unsigned i = 1; i <= N; ++i) solver(eq,i+N) = -rest(eq)* pow(samples[eq],i); + } + solver.Invert(); + auto r = solver * rest; + std::vector rv(2*N+1); + for(unsigned i = 0; i<2*N+1; ++i) rv[i] = r[i]; + return rv; +} diff --git a/src/Particle.cpp b/src/Particle.cpp index 900bfb04e52..5cdd8fb1ba2 100644 --- a/src/Particle.cpp +++ b/src/Particle.cpp @@ -28,49 +28,43 @@ #include "AmpGen/Types.h" using namespace AmpGen; +using namespace std::complex_literals; -Particle::Particle() -{ - m_defaultModifier = NamedParameter("Particle::DefaultModifier","", "Default modifier to use for lineshapes, for example to use normalised vs unnormalised Blatt-Weisskopf factors."); - m_spinFormalism = NamedParameter("Particle::SpinFormalism" ,"Covariant", "Spin formalism to use, can choose between Covariant and Canonical formalisms"); - m_spinBasis = NamedParameter("Particle::SpinBasis" ,"Dirac", - optionalHelpString("Basis to use for calculating external polarisation tensors / spinors.", { - {"Dirac", "Quantises along the z-axis"} - , {"Weyl" , "Quantises along the direction of motion"}} ) ); - -} +Particle::Particle() = default; -Particle::Particle( const std::string& name, const Particle& p1, const Particle& p2 ) - : Particle() +Particle::Particle( const std::string& name, const Particle& p1, const Particle& p2 ) : + m_name{name} + , m_props{ParticlePropertiesList::get(name)} + , m_daughters{ std::make_shared(p1), std::make_shared(p2) } { - m_props = ParticlePropertiesList::get( name ); - m_name = name; - m_daughters.push_back(std::make_shared(p1)); - m_daughters.push_back(std::make_shared(p2)); pdgLookup(); sortDaughters(); - for ( auto& d : m_daughters ) d->setTop( false ); + for ( auto& d : m_daughters ) d->setParent( this ); m_uniqueString = makeUniqueString(); } -Particle::Particle( const int& pdgID, const Particle& p1, const Particle& p2 ) - : Particle() -{ - m_props = ParticlePropertiesList::get( pdgID ); - m_daughters.push_back( std::make_shared( p1 ) ); - m_daughters.push_back( std::make_shared( p2 ) ); +Particle::Particle( const int& pdgID, const Particle& p1, const Particle& p2 ) : + m_props{ParticlePropertiesList::get(pdgID)} + , m_daughters{std::make_shared(p1) , std::make_shared(p2) } +{ if ( m_props != nullptr ) m_name = m_props->name(); pdgLookup(); sortDaughters(); - for ( auto& d : m_daughters ) d->setTop( false ); + for ( auto& d : m_daughters ) d->setParent( this ); + m_uniqueString = makeUniqueString(); +} + +Particle::Particle( const std::string& name, const unsigned int& index ) : + m_props{ParticlePropertiesList::get( name )} + , m_index{index} +{ + pdgLookup(); m_uniqueString = makeUniqueString(); } Particle::Particle( const std::string& decayString, const std::vector& finalStates, const bool& orderDaughters ) - : Particle() { - DEBUG( "Building particle from decay string = " << decayString ); auto items = getItems( decayString ); if ( items.size() == 0 ) { ERROR( "Failed to parse string" << decayString ); @@ -80,13 +74,15 @@ Particle::Particle( const std::string& decayString, const std::vector( items[it] ) ); - + for( auto& modifier : m_modifiers ) parseModifier( modifier ); + for( size_t it = 1; it < items.size(); ++it ){ + m_daughters.push_back( std::make_shared( items[it] ) ); + (*m_daughters.rbegin())->setParent(this); + } m_props = ParticlePropertiesList::get( m_name ); pdgLookup(); auto fs = getFinalStateParticles( false ); + DEBUG( "Building particle from decay string = " << decayString << " name = " << m_name << " "<< m_props->name() ); std::vector hasUsedFinalState( finalStates.size(), 0 ); for ( auto d : fs ) { for ( unsigned int i = 0; i < finalStates.size(); ++i ) { @@ -99,35 +95,39 @@ Particle::Particle( const std::string& decayString, const std::vectorisStateGood(); - if ( !isStateGood() ) { ERROR( "Amplitude " << decayString << " not configured correctly" ); } if ( finalStates.size() == fs.size() ) { - std::string finalStateString = ""; - for ( auto& fs : finalStates ) finalStateString += fs + " "; - for ( auto used : hasUsedFinalState ) { - m_isStateGood &= used; - } - if ( !isStateGood() ) { - DEBUG( "Amplitude " << decayString << " does not match requested event type " << finalStateString ); - } + m_isStateGood = std::all_of( hasUsedFinalState.begin(), hasUsedFinalState.end(),[](const auto& b){return b;} ); } m_uniqueString = makeUniqueString(); } -Particle::Particle( const std::string& name, const unsigned int& index ) : Particle() + +bool Particle::isValidDecayDescriptor( const std::string& decayDescriptor ) { - m_props = ParticlePropertiesList::get( name ); - m_index = index; - pdgLookup(); - for ( auto& d : m_daughters ) d->setTop( false ); - m_uniqueString = makeUniqueString(); + auto first = decayDescriptor.find("{"); + auto open = std::count(decayDescriptor.begin(), decayDescriptor.end(), '{'); + auto close = std::count(decayDescriptor.begin(), decayDescriptor.end(), '}'); + if( open == 0 || open != close || first == std::string::npos){ + if( open !=0 && open != close ) WARNING("Unmatched braces in possible decay descriptor: " << decayDescriptor); + return false; + } + auto tokens = split(decayDescriptor, {'{','}',',','_'} ); + bool valid = true; + for( auto token : tokens ) + { + auto particle_name = token.substr(0, token.find("[") ); + valid &= ParticleProperties::get( particle_name, true) != nullptr; + } + return valid; } void Particle::parseModifier( const std::string& mod ) { - if( mod.size() == 1 ) + if ( Lineshape::Factory::isLineshape(mod) ) m_lineshape = mod; + else if( mod.size() == 1 ) { DEBUG( "Modifier = " << mod ); if ( mod == "S" ) m_orbital = 0; @@ -137,41 +137,25 @@ void Particle::parseModifier( const std::string& mod ) else if ( mod == "G" ) m_orbital = 4; else if ( mod == "H" ) m_orbital = 5; else if ( mod == "I" ) m_orbital = 6; - bool status=true; - auto tmp = lexical_cast(mod,status); - if( status ) m_spinConfigurationNumber = tmp; + else { + bool status=true; + auto tmp = lexical_cast(mod,status); // this is if it is a number /// + if( status ) m_spinConfigurationNumber = tmp; + else { + m_spinConfigurationNumber = 10 + int(mod[0]); + } + } } else if ( mod.size() == 2 ) { parseModifier( mod.substr(0,1) ); parseModifier( mod.substr(1,1) ); } - else if ( Lineshape::Factory::isLineshape( mod ) ) - m_lineshape = mod; } double Particle::spin() const { return double( m_props->twoSpin() / 2. ) ; } double Particle::S() const { return m_spinConfigurationNumber ; } -std::string Particle::vertexName() const -{ - if ( m_daughters.size() != 2 ){ - WARNING("Vertices only well-defined for quasi two-body processes, check logic"); - return "ERROR"; - } - std::string orbitalString; - if( m_orbital == 0 ) orbitalString = "S"; - if( m_orbital == 1 ) orbitalString = "P"; - if( m_orbital == 2 ) orbitalString = "D"; - if( m_orbital == 3 ) orbitalString = "F"; - if( m_spinConfigurationNumber != 0 ) orbitalString += std::to_string( m_spinConfigurationNumber ); - auto vx= m_props->spinName() + "_" + - m_daughters[0]->m_props->spinName() + - m_daughters[1]->m_props->spinName() + "_" + orbitalString; - - return vx; -} - void Particle::pdgLookup() { if ( m_props == nullptr ) { @@ -179,21 +163,18 @@ void Particle::pdgLookup() return; } if ( m_lineshape == "BW" || m_usesDefaultLineshape ) { - if ( m_name.find( "NonRes" ) != std::string::npos || m_props->width() < 1e-3 ) - m_lineshape = "FormFactor"; + if ( m_name.find("NonRes") != std::string::npos || m_props->width() < ParticlePropertiesList::getMe()->quasiStableThreshold() ) m_lineshape = "FormFactor"; + if ( m_props->isPhoton() ) m_lineshape = "Photon"; m_usesDefaultLineshape = true; - } else - m_usesDefaultLineshape = false; + } + else m_usesDefaultLineshape = false; m_parity = m_props->P(); - if ( !isdigit( m_props->J()[0] ) ) { - ERROR( "Spin not recognised! : " << m_name << " J = " << m_props->J() ); - } + // if ( !isdigit( m_props->J()[0] ) ) ERROR( "Spin not recognised! : " << m_name << " J = " << m_props->J() ); if( m_defaultModifier != "" && m_lineshape.find(".") == std::string::npos ){ - m_lineshape = m_lineshape + "." + m_defaultModifier; + m_lineshape = m_lineshape + "." + m_defaultModifier.getVal(); } bool isStrong = quarks() == daughterQuarks(); - DEBUG( m_name << " is decaying via " << ( isStrong ? "strong" : "electroweak" ) << " interactions; P = " << props()->P() ); - + if( abs(m_props->pdgID()) == 24 || abs(m_props->pdgID()) == 23 ) isStrong = false; if ( m_name.find( "NonRes" ) != std::string::npos ) isStrong = true; m_minL = m_daughters.size() == 2 ? orbitalRange( isStrong ).first : 0; if ( m_daughters.size() == 2 ) { @@ -201,23 +182,31 @@ void Particle::pdgLookup() << " name = " << m_name << " d0 = " << m_daughters[0]->name() << " d1 = " << m_daughters[1]->name() ); } - if ( m_orbital == 0 ) m_orbital = m_minL; //// define in ground state unless specified /// - - for ( auto& d : m_daughters ) d->setTop( false ); + if ( m_orbital == 0 ) m_orbital = m_minL; // define in ground state unless specified + if( m_daughters.size() != 0 ){ + DEBUG( m_name << " is decaying via " << ( isStrong ? "strong" : "electroweak" ) << " interactions; P = " << props()->P() << "l = " << m_orbital ); + } + int charge = 0; + for ( auto& d : m_daughters ){ + d->setParent(this); + charge += d->props()->charge(); + } + if( m_minL == 999 ) ERROR("Decay: " << m_name << " does not appear to have an allowed spin-orbit configuration"); + if( m_daughters.size() != 0 && m_props->charge() != charge ) ERROR("Decay: " << m_name << " does not conserve (electric) charge"); } Tensor Particle::P() const { - Tensor momentum( std::vector( {0., 0., 0., 0.} ), std::vector( {4} ) ); + Tensor momentum( std::vector( {0., 0., 0., 0.} ), Tensor::dim(4) ); if ( isStable() ) { if ( m_index != 999 ) { const std::string index = std::to_string( m_index ); Tensor rt( std::vector( { - Parameter( index + "_Px", 0, false, 1 ), - Parameter( index + "_Py", 0, false, 1 ), - Parameter( index + "_Pz", 0, false, 1 ), 0 } ) , {4} ); - rt[3] = make_cse( fcn::sqrt( mass()*mass() + rt[0]*rt[0] + rt[1]*rt[1] + rt[2]*rt[2] ) ); - // Parameter( index + "_E" , 0, false, 1 )} ), + Parameter(index + "_Px"), + Parameter(index + "_Py"), + Parameter(index + "_Pz"), + Parameter(index + "_E") }) , Tensor::dim(4) ); +// rt[3] = fcn::sqrt( mass()*mass() + rt[0]*rt[0] + rt[1]*rt[1] + rt[2]*rt[2] ) ; return rt; } else ERROR( "Stable particle " << m_index << "is unindexed!" ); } @@ -239,16 +228,31 @@ Tensor Particle::Q() const std::shared_ptr Particle::daughter( const size_t& index ) { return ( m_daughters[index] ); } std::shared_ptr Particle::daughter( const size_t& index ) const { return m_daughters[index]; } +std::shared_ptr Particle::daughter( const std::string& name, const int& maxDepth ) const +{ + if( maxDepth == -1 ) + { + auto fs = getFinalStateParticles(); + for( auto& f : fs ) if( f->name() == name ) return f; + ERROR("Particle: " << name << " not found amongst decay products!"); + } + else { + for( auto& d : m_daughters ) if( d->name() == name ) return d; + ERROR("Particle: " << name << " not found amongst decay products!"); + } + return std::shared_ptr(); +} + + std::string Particle::orbitalString() const { - std::string orbital_part; - if ( m_orbital == 0 ) orbital_part = "S"; - else if ( m_orbital == 1 ) orbital_part = "P"; - else if ( m_orbital == 2 ) orbital_part = "D"; - else if ( m_orbital == 3 ) orbital_part = "F"; - else orbital_part = "X"; - if( m_spinConfigurationNumber == 0 ) return orbital_part; - else return orbital_part + std::to_string( m_spinConfigurationNumber ); + constexpr std::array orbitals = {'S','P','D','F','G','H','I'}; + std::string rt = std::string(1, orbitals[m_orbital] ); + if( m_spinConfigurationNumber != 0 ){ + if( m_spinConfigurationNumber < 10 ) rt += std::to_string( m_spinConfigurationNumber ); + else rt += char(m_spinConfigurationNumber-10); + } + return rt; } bool Particle::hasModifier( const std::string& modifier ) const @@ -275,14 +279,9 @@ std::string Particle::makeUniqueString() { std::string modifier = modifierString(); if ( m_daughters.size() != 0 ) { - std::string val = m_name + modifier + "{"; - for ( unsigned int i = 0; i < m_daughters.size(); ++i ) { - m_daughters[i]->makeUniqueString(); - val += m_daughters[i]->uniqueString() + ( i == m_daughters.size() - 1 ? "}" : "," ); - } - m_uniqueString = val; + m_uniqueString = m_props->name() + modifier + "{" + vectorToString( m_daughters, ",", [](auto& d){ return d->makeUniqueString() ;} ) +"}"; } else { - m_uniqueString = m_name + modifier ; + m_uniqueString = m_props->name() + modifier ; } return m_uniqueString; } @@ -290,7 +289,6 @@ std::string Particle::makeUniqueString() std::vector> Particle::getFinalStateParticles( const bool& sort ) const { std::vector> ffs; - for ( auto daughter : m_daughters ) { if ( daughter->isStable() ) { ffs.push_back( daughter ); @@ -313,12 +311,11 @@ Particle Particle::quasiStableTree() const { Particle returnVal( m_name ); for ( auto& d : m_daughters ) { - auto qTree = d->quasiStableTree(); - if ( d->isQuasiStable() ) { - returnVal.addDaughter( std::make_shared( qTree ) ); - } else { - for ( auto& dp : qTree.daughters() ) returnVal.addDaughter( dp ); - } + auto qTree = d->quasiStableTree(); + if( qTree.daughters().size() == 0 || (qTree.isQuasiStable() && m_daughters.size() != 1 ) ) + returnVal.addDaughter( std::make_shared(qTree) ); + else + for( auto& it : qTree.daughters() ) returnVal.addDaughter(it); } returnVal.sortDaughters(); returnVal.makeUniqueString(); @@ -333,15 +330,16 @@ Expression Particle::propagator( DebugSymbols* db ) const Expression total( 1. ); DEBUG( "Getting lineshape " << m_lineshape << " for " << m_name ); Expression s = massSq(); - if ( m_daughters.size() == 2 ) { - auto prop = Lineshape::Factory::get(m_lineshape, s, daughter(0)->massSq(), daughter(1)->massSq(), m_name, m_orbital, db); - total = total * make_cse(prop); - } - else if ( m_daughters.size() == 3 ) { - std::string shape = m_lineshape == "BW" ? "SBW" : m_lineshape; - auto prop = Lineshape::Factory::get(shape, massSq(), {daughter(0)->P(), daughter(1)->P(), daughter(2)->P()}, m_name, m_orbital, db ); - total = total * make_cse(prop); - } + Expression prop = 1; + if ( m_daughters.size() == 2 ) + prop = Lineshape::Factory::get(m_lineshape, s, daughter(0)->massSq(), daughter(1)->massSq(), m_name, m_orbital, db); + else if ( m_daughters.size() >= 3 ) + prop = Lineshape::Factory::get(m_lineshape == "BW" ? "SBW" : m_lineshape, *this, db ); + else if ( m_daughters.size() == 1 && m_lineshape != "BW" && m_lineshape != "FormFactor" ) + { + prop = Lineshape::Factory::get(m_lineshape, *this, db ); + } + total = total * make_cse(prop); for(auto& d : m_daughters) total = total*make_cse(d->propagator(db)); if(db != nullptr) db->emplace_back("A("+uniqueString()+")", total); return total; @@ -352,7 +350,8 @@ std::vector> Particle::identicalDaughterOrderings() const std::vector> orderings; auto finalStateParticles = getFinalStateParticles(); std::vector zero_perm; - for( auto& particle : finalStateParticles ) zero_perm.push_back( particle->name() ); + std::transform( finalStateParticles.begin(), finalStateParticles.end(), std::back_inserter(zero_perm), + [](auto& p ){ return p->name() ; } ); std::vector indices( finalStateParticles.size() ); std::iota(indices.begin(), indices.end(), 0); do { @@ -371,7 +370,11 @@ void Particle::setOrdering( const std::vector& ordering ) finalStateParticles[i]->setIndex( ordering[i] ); } } -void Particle::addDaughter( const std::shared_ptr& particle ) { m_daughters.push_back( particle ); } +void Particle::addDaughter( const std::shared_ptr& particle ) +{ + m_daughters.push_back( particle ); + m_uniqueString = makeUniqueString(); +} Tensor Particle::transitionMatrix( DebugSymbols* db ) { @@ -379,47 +382,46 @@ Tensor Particle::transitionMatrix( DebugSymbols* db ) return spinTensor(); } -Expression Particle::getExpression( DebugSymbols* db, const unsigned int& index ) +Expression Particle::getExpression( DebugSymbols* db, const std::vector& state) { + if( state.size() !=0 ) setPolarisationState( state ); if( db != nullptr && !isStable() ) db->emplace_back( uniqueString() , Parameter( "NULL", 0, true ) ); - auto spinFormalism = m_spinFormalism; - auto localFormalism = attribute("SpinFormalism"); - if( localFormalism != stdx::nullopt ) localFormalism = localFormalism.value(); - if( spinFormalism != "Covariant" && spinFormalism != "Canonical") - { - FATAL("Invalid value for SpinFormalism: " << spinFormalism << ", possible values are: " << italic_on << " Covariant, Canonical." << italic_off ); - } - Expression total( 0 ); + Expression total = 0; + Tensor::Index a; auto finalStateParticles = getFinalStateParticles(); auto orderings = identicalDaughterOrderings(); bool doSymmetrisation = !hasModifier("NoSym"); bool sumAmplitudes = !hasModifier("Inco"); bool includeSpin = !hasModifier("BgSpin0"); std::vector exchangeParities; - for( auto& p : finalStateParticles ) exchangeParities.push_back( p->props()->isFermion() ? -1 : 1 ); - for(auto& ordering : orderings){ + std::transform( finalStateParticles.begin(), finalStateParticles.end(), std::back_inserter(exchangeParities), + [](const auto& p){ return p->props()->isFermion() ? -1 : 1; } ); + for(const auto& ordering : orderings){ auto exchangeParity = minSwaps( ordering, exchangeParities ); - //INFO( vectorToString( ordering, ", ") << " " << exchangeParity.second ); setOrdering( ordering ); Expression spinFactor = 1; - if( includeSpin && spinFormalism == "Covariant" ){ + if( includeSpin && m_spinFormalism == spinFormalism::Covariant ){ Tensor st = spinTensor(db); if( m_props->twoSpin() == 0 ) spinFactor = st[0]; if( m_props->twoSpin() == 1 ){ Tensor is = Bar( externalSpinTensor(m_polState) ); ADD_DEBUG_TENSOR( externalSpinTensor(m_polState), db ); ADD_DEBUG_TENSOR( st, db ); - Tensor::Index a; if( st.size() != 4 ){ ERROR("Spin tensor is the wrong rank = " << st.dimString() ); spinFactor = 1; } - else { spinFactor = is(a) * st(a) ; } + else spinFactor = is(a) * st(a) ; + } + if( m_props->twoSpin() == 2 ){ + Tensor is = externalSpinTensor(m_polState).conjugate(); + ADD_DEBUG_TENSOR(is, db ); + spinFactor = dot(is,st); } } - if ( includeSpin && spinFormalism == "Canonical" ){ - spinFactor = helicityAmplitude( *this, TransformSequence(), double(polState())/2.0, db ); + if ( includeSpin && m_spinFormalism == spinFormalism::Canonical ){ + spinFactor = helicityAmplitude(*this, TransformSequence(), m_props->isBoson() ? polState() : double(polState())/2.0, db); } if( db != nullptr ){ std::string finalStateString=""; @@ -439,7 +441,14 @@ Expression Particle::getExpression( DebugSymbols* db, const unsigned int& index } ADD_DEBUG( total, db ); double nPermutations = doSymmetrisation ? orderings.size() : 1; - if ( sumAmplitudes ) return total / fcn::sqrt( nPermutations ); + if ( sumAmplitudes ) + { + if ( is(total) ){ + WARNING("Amplitude is just a constant: " << total << " may cause problems for compiler, making a little bit complex" ); + total += 1i * 0.00001; + } + return total / fcn::sqrt( nPermutations ); + } else { Expression sqrted = fcn::sqrt( total / nPermutations ); ADD_DEBUG( sqrted, db ); @@ -456,9 +465,10 @@ Tensor Particle::spinTensor( DebugSymbols* db ) const return S; } else if ( m_daughters.size() == 2 ) { + auto vname = m_props->spinName() + "_" + m_daughters[0]->m_props->spinName() + m_daughters[1]->m_props->spinName() + "_" + orbitalString(); Tensor value = Vertex::Factory::getSpinFactor( P(), Q(), - daughter(0)->spinTensor( db ), - daughter(1)->spinTensor( db ), vertexName() , db ); + daughter(0)->spinTensor(db), + daughter(1)->spinTensor(db), vname, db ); DEBUG( "Returning spin tensor" ); return value; } else if ( m_daughters.size() == 3 ) { @@ -477,103 +487,92 @@ Tensor Particle::externalSpinTensor(const int& polState, DebugSymbols* db ) cons { DEBUG("Getting final state spin tensor for: " << name() << " " << spin() ); if ( spin() == 0 ) - return Tensor( std::vector( {1.} ), std::vector( {1} ) ); + return Tensor( std::vector( {1.} ), std::vector( {1} ) ); + if( m_spinBasis == spinBasis::Dirac && ( m_props->isPhoton() || m_props->isNeutrino() ) ) + { + WARNING("Use the Weyl (helicity) basis for calculations involving photons / neutrinos, as they don't have a rest frame. This will result in ill-defined amplitudes."); + } + Tensor p = P(); - Expression pX = p.get(0) ; - Expression pY = p.get(1) ; - Expression pZ = p.get(2) ; - Expression pE = p.get(3) ; + Expression pX = p.get(0); + Expression pY = p.get(1); + Expression pZ = p.get(2); + Expression pE = p.get(3); Expression pP = fcn::sqrt( pX*pX + pY*pY + pZ*pZ ); - Expression m = fcn::sqrt( dot( p, p ) ); - complex_t I(0,1); - Expression z = pX + I*pY; - Expression zb = pX - I*pY; + Expression m = mass(); + Expression z = pX + 1i*pY; + Expression zb = pX - 1i*pY; auto id = props()->pdgID(); - if ( m_props->twoSpin() == 2 && m_spinBasis == "Weyl" ) { - Expression N = 1 / ( m * fcn::sqrt( 2 ) ); - Expression em = pE+m; - if( polState == 0 ) return Tensor( { pX*pZ/(m*em), pY*pZ/(m*em), 1. + pZ*pZ/(m*em), pZ/m } ); - if( polState == 1 ) return -N*Tensor( { m + pX*zb/em, pY*zb/em -m*I, pZ*zb, zb } ); - if( polState == -1 ) return N*Tensor( { m + pX*z/em, pY*z/em + m*I, pZ*z, z } ); - } - if( m_props->twoSpin() == 2 && m_spinBasis == "Dirac" ){ - Expression invPT2 = Ternary( pX*pX + pY*pY > 1e-6, 1./(pX*pX+pY*pY), 0 ); - if( m_props->mass() == 0 ){ - Expression N = 1./(pP*sqrt(2)); - if( polState == 1 ) return N * Tensor({ -pZ - pY*invPT2*(pP-pZ)*(pY-I*pX), - -I*pZ + pX*invPT2*(pP-pZ)*(pY-I*pX), - ( pX + I*pY), 0 } ); - if( polState == -1 ) return N * Tensor({ pZ + pY*invPT2*(pP-pZ)*(pY+I*pX), - I*pZ - pX*invPT2*(pP-pZ)*(pY+I*pX), - ( -pX + I*pY), 0 } ); - if( polState == 0 ) ERROR("Photon should does not have a rest frame, cannot be in m=0 state"); + if ( m_props->twoSpin() == 2 ) + { + if( m_spinBasis == spinBasis::Weyl ) + { + Expression N = 1./(sqrt(2)); + Expression invPT2 = make_cse(Ternary( pX*pX + pY*pY > 1e-6, 1./(pX*pX+pY*pY), 0 )); + Expression invP = make_cse(Ternary( pP > 1e-6, 1./pP,0)); + Expression pZoverP = make_cse(Ternary( pP > 1e-6, pZ/pP, 1) ); + Expression f = (pP-pZ)*invPT2; + if(polState == 1) return N * Tensor({-pZoverP + 1i*z *pY*f*invP, -1i*pZoverP - 1i*z *pX*f*invP, z*invP , 0. }); + if(polState == -1) return N * Tensor({ pZoverP + 1i*zb*pY*f*invP, -1i*pZoverP - 1i*zb*pX*f*invP,-zb*invP , 0. }); + if(polState == 0) return Tensor({pX*pE*invP/m , pY*pE*invP/m , pZoverP*pE/m, pP/m}); } - } - if( m_props->twoSpin() == 1 && m_spinBasis == "Weyl" ){ - Expression n = fcn::sqrt( 2 * pP*(pP+pZ) ); - Expression fa = fcn::sqrt( (pE + m)/(2*m) ); - Expression fb = fcn::sqrt( (pE - m)/(2*m) ); - Expression aligned = make_cse( Abs(pP + pZ) < 10e-6 ) ; - Expression xi10 = make_cse(Ternary( aligned, 1, (pP+pZ)/n )); - Expression xi11 = make_cse(Ternary( aligned, 0, z/n )); - Expression xi00 = make_cse(Ternary( aligned, 0, -zb/n )); - Expression xi01 = make_cse(Ternary( aligned, 1, (pP+pZ)/n )); - if(id > 0 && polState == 1 ) return Tensor({ fa*xi10, fa*xi11, fb*xi10, fb*xi11 } ); - if(id > 0 && polState == -1 ) return Tensor({ fa*xi00, fa*xi01, -fb*xi00, -fb*xi01 } ); - if(id < 0 && polState == 1 ) return Tensor({ fb*xi00, fb*xi01, -fa*xi00, -fa*xi01 } ); - if(id < 0 && polState == -1 ) return Tensor({ fb*xi10, fb*xi11, -fa*xi01, -fa*xi11 } ); - } - if ( m_props->twoSpin() == 1 && m_spinBasis == "Dirac" ) + if( m_spinBasis == spinBasis::Dirac ){ + Expression N = make_cse(1./(m*(pE + m))); + if( polState == 1 ) return -Tensor({1.+ z *pX*N, 1i + z*pY*N, z*pZ*N , z*m })/sqrt(2); + if( polState == -1 ) return Tensor({1.+ zb*pX*N, -1i + zb*pY*N, zb*pZ*N , zb*m })/sqrt(2); + if( polState == 0 ) return Tensor({pX*pZ*N , pY*pZ*N, 1 + pZ*pZ*N, pZ/m }); + } + } + if( m_props->twoSpin() == 1 ) { - Expression norm = make_cse( fcn::sqrt((pE+m)/(2*m) )); - if(id > 0 && polState == 1 ) return norm * Tensor({ 1 ,0 , pZ/(pE+m), z/(pE+m) }); - if(id > 0 && polState == -1 ) return norm * Tensor({ 0 ,1 , zb/(pE+m), -pZ/(pE+m) }); - if(id < 0 && polState == -1 ) return norm * Tensor({ pZ/(pE+m), z/(pE+m) , 1 ,0 }); - if(id < 0 && polState == 1 ) return norm * Tensor({ zb/(pE+m),-pZ/(pE+m) , 0 ,1 }); - } - WARNING("Spin tensors not implemented for spin J = " << m_props->twoSpin() << " / 2 m = " << m_polState << " " << m_name ); - return Tensor( std::vector( {1.} ), Tensor::dim(0) ); -} - -bool Particle::checkExists() const -{ - bool success = true; - if ( m_daughters.size() == 2 ) { - success &= Vertex::Factory::isVertex( vertexName() ); - if ( !success ) { - ERROR( uniqueString() ); - ERROR( "Spin configuration not found J = " - << spin() << " L = " << m_orbital << " l' = " << m_spinConfigurationNumber - << " s1 = " << m_daughters[0]->spin() << " s2 = " << m_daughters[1]->spin() ); + if( m_spinBasis == spinBasis::Weyl ) + { + std::array xi; + Expression n = fcn::sqrt( 2 * pP*(pP+pZ) ); + Expression aligned = make_cse( Abs(pP + pZ) < 10e-6 ) ; + xi[0] = Tensor( {make_cse( Ternary(aligned, 1, -zb/n)) , make_cse( Ternary(aligned, 0, (pP+pZ)/n ) ) }); + xi[1] = Tensor( {make_cse( Ternary(aligned, 0, (pP+pZ)/n)), make_cse(Ternary(aligned,1, z/n) ) }); + + Expression fa = m_props->isNeutrino() ? polState * fcn::sqrt(pE) : polState * fcn::sqrt( pE/m- 1 ); + Expression fb = m_props->isNeutrino() ? fcn::sqrt(pE) : fcn::sqrt( pE/m + 1 ); + int ind = (id>0 ? polState : -polState) == -1 ? 0 : 1; + + return id > 0 ? Tensor({ - fa * xi[ind][0], - fa * xi[ind][1], fb * xi[ind][0], fb * xi[ind][1] }) + : -polState * Tensor({ fb * xi[ind][0], fb * xi[ind][1], fa * xi[ind][0], fa * xi[ind][1] }); + } + if ( m_spinBasis == spinBasis::Dirac ) + { + Expression N = make_cse( fcn::sqrt((pE+m)/(2*m) )); + if(id > 0 && polState == 1 ) return N * Tensor({ 1 ,0 , pZ/(pE+m), z/(pE+m) }); + if(id > 0 && polState == -1 ) return N * Tensor({ 0 ,1 , zb/(pE+m), -pZ/(pE+m) }); + if(id < 0 && polState == -1 ) return N * Tensor({ pZ/(pE+m), z/(pE+m) , 1 ,0 }); + if(id < 0 && polState == 1 ) return N * Tensor({ zb/(pE+m),-pZ/(pE+m) , 0 ,1 }); } - success &= daughter(0)->checkExists() & daughter(1)->checkExists(); } - if ( success == false ) ERROR( uniqueString() << " is not described in IVertex" ); - return success; + std::string js = m_props->isBoson() ? std::to_string(m_props->twoSpin()/2) : std::to_string(m_props->twoSpin()) +"/2"; + WARNING("Spin tensors not implemented for spin J = " << js << "; m = " << m_polState << " " << m_name ); + return Tensor( std::vector( {1.} ), Tensor::dim(0) ); } std::pair Particle::orbitalRange( const bool& conserveParity ) const { if( m_daughters.size() == 0 ) return {0, 0}; - if( m_daughters.size() == 1 ) return {0,0}; + if( m_daughters.size() == 1 ) return {0, 0}; if( m_daughters.size() != 2 ) { ERROR( "L not well defined for nDaughters == " << m_daughters.size() ); return {999, 998}; } const int S = m_props->twoSpin(); - const int s1 = daughter( 0 )->props()->twoSpin(); - const int s2 = daughter( 1 )->props()->twoSpin(); - - int min = std::abs( S - s1 - s2 ); - if ( std::abs( S + s1 - s2 ) < min ) min = std::abs( S + s1 - s2 ); - if ( std::abs( S - s1 + s2 ) < min ) min = std::abs( S - s1 + s2 ); - int max = S + s1 + s2; - + const int s1 = daughter(0)->props()->twoSpin(); + const int s2 = daughter(1)->props()->twoSpin(); + int min = std::abs( S - s1 - s2 ); + min = std::min(min, std::abs( S + s1 - s2 )); + min = std::min(min, std::abs( S - s1 + s2 )); + int max = S + s1 + s2; min /= 2; max /= 2; DEBUG( "Range = " << min << " -> " << max << " conserving parity ? " << conserveParity << " J = " << S << " s1= " << s1 << " s2= " << s2 ); - if ( conserveParity == false ) return {min, max}; - + if ( conserveParity == false ) return {min, max}; int l = min; for ( ; l < max + 1; ++l ) if( conservesParity(l) ) break; if ( l == max + 1 ) return {999, 999}; @@ -610,13 +609,13 @@ std::string Particle::texLabel( const bool& printHead, const bool& recurse ) con const std::string rightBrace = "\\right]"; if( m_daughters.size() == 0 ) return m_props->label(); std::string val = ""; // m_props->label(); - if( !m_isHead ) val = m_props->label(); - if( printHead && m_isHead ) val = m_props->label() + "\\rightarrow "; + if( !isHead() ) val = m_props->label(); + if( printHead && isHead() ) val = m_props->label() + "\\rightarrow "; - if( m_isHead || recurse ){ - if ( !m_isHead || m_orbital != m_minL ) val += leftBrace; + if( isHead() || recurse ){ + if ( !isHead() || m_orbital != m_minL ) val += leftBrace; for( auto& prod : m_daughters ) val += prod->texLabel(false,recurse) + " "; - if ( !m_isHead || m_orbital != m_minL ) val += rightBrace; + if ( !isHead() || m_orbital != m_minL ) val += rightBrace; if ( m_orbital != m_minL ) val += "^{" + orbitalString() + "}"; } return val; @@ -624,38 +623,35 @@ std::string Particle::texLabel( const bool& printHead, const bool& recurse ) con void Particle::sortDaughters() { - std::stable_sort( m_daughters.begin(), m_daughters.end(), []( auto& A, auto& B ) { return *A < *B; } ); + bool isAntiParticle = m_props->pdgID() < 0; + if( isAntiParticle ) conjThis(); + std::stable_sort( m_daughters.begin(), m_daughters.end(), [](const auto& A, const auto& B) { return *A < *B; } ); + if( isAntiParticle ) conjThis(); + m_uniqueString = makeUniqueString(); } -int Particle::conjugate( bool invertHead , bool reorder ) +void Particle::conjThis() { - int sgn = 1; - DEBUG( "Conjugating flavour of " << m_name ); - if ( m_props == nullptr ) ERROR( "Particle properties not found for " << m_name ); - if ( ( !m_isHead || invertHead ) && m_props->hasDistinctAnti() ) { - DEBUG( "Trying to conjugate: " << m_name ); - m_props = ParticlePropertiesList::get( -m_props->pdgID() ); - m_name = m_props->name(); - m_parity = m_props->P(); - } - sgn *= pow( -1, m_orbital ); - if ( m_parity == -1 - && m_daughters.size() == 2 - && std::abs(daughter(0)->props()->pdgID()) == std::abs(daughter(1)->props()->pdgID()) - && daughter(0)->props()->pdgID() != daughter(1)->props()->pdgID() ) { - sgn *= -1; - } - for ( auto& d : m_daughters ) sgn *= d->conjugate( invertHead ); - if( reorder ) sortDaughters(); - std::string oldUniqueString = m_uniqueString; - m_uniqueString = makeUniqueString(); - DEBUG( "Conjugate : " << oldUniqueString << " to " << m_uniqueString << " sgn = " << sgn ); - return sgn; + if( m_props->hasDistinctAnti() ) + m_props = ParticlePropertiesList::get( -m_props->pdgID(), false); + for(unsigned i = 0 ; i != m_daughters.size(); ++i) m_daughters[i]->conjThis(); +} + +Particle Particle::conj( bool invertHead , bool reorder ) +{ + Particle cp(*this); + cp.clearDecayProducts(); + const ParticleProperties* p = ( !isHead() || invertHead ) && m_props->hasDistinctAnti() ? ParticlePropertiesList::get( -m_props->pdgID() ) : m_props; + cp.setName( p->name() ); + for( auto& d : m_daughters ) cp.addDaughter( std::make_shared(d->conj(invertHead,reorder)) ); + if( reorder ) cp.sortDaughters(); + cp.pdgLookup(); + return cp; } QuarkContent Particle::quarks() const { - return m_name.find("NonRes") != std::string::npos ? daughterQuarks() : m_props->netQuarkContent(); + return m_name.find("NonRes") != std::string::npos ? daughterQuarks() : m_props->quarkContent(); } QuarkContent Particle::daughterQuarks() const @@ -666,13 +662,24 @@ QuarkContent Particle::daughterQuarks() const } Expression Particle::massSq() const { return isStable() ? mass() * mass() : make_cse( dot( P(), P() ) ); } + +void Particle::clearDecayProducts() +{ + m_daughters.clear(); +} + void Particle::addModifier( const std::string& mod ) { m_modifiers.push_back( mod ); parseModifier( mod ); m_uniqueString = makeUniqueString(); } -void Particle::setTop( bool state ) { m_isHead = state; } +void Particle::setName(const std::string& name) +{ + m_name = name; + m_props = ParticlePropertiesList::get(name); + m_parity = m_props->P(); +} void Particle::setIndex( const unsigned int& index, const bool& setOri ) { m_index = index; @@ -689,35 +696,42 @@ void Particle::setLineshape( const std::string& lineshape ) m_lineshape = lineshape; m_uniqueString = makeUniqueString(); } + int Particle::finalStateParity() const { - int lpart = ( m_orbital % 2 == 0 ? 1 : -1 ); - for ( auto& d : m_daughters ) lpart *= d->parity(); - return lpart; + if( m_daughters.size() == 0) return 1; + if( m_daughters.size() == 1) return m_daughters[0]->finalStateParity(); /// forward through quasiparticles + if( m_daughters.size() == 2){ + int f = spin() - ( m_orbital + daughter(0)->spin() + daughter(1)->spin() ); + int lpart = (f % 2 == 0 ? 1 : -1); + for( auto& d : m_daughters ) lpart *= d->finalStateParity(); + return lpart; + } + WARNING("> 2 body vertices may require special considerations when conjugating, returning (-1)^J"); + return pow(-1, spin() ); } bool Particle::conservesParity( unsigned int L ) const { - return parity() == daughter( 0 )->parity() * daughter( 1 )->parity() * ( L % 2 == 0 ? 1 : -1 ); + return parity() == daughter(0)->parity() * daughter(1)->parity() * ( L % 2 == 0 ? 1 : -1 ); } std::string Particle::topologicalString() const { - std::string topo = ""; - for ( auto& d : m_daughters ) topo += d->m_props->J(); - return topo; + return std::accumulate( m_daughters.begin(), m_daughters.end(), std::string(""), [](auto& s, auto& d){ return s+d->props()->J() ; } ); } + const ParticleProperties* Particle::props() const { return m_props; } -bool Particle::isHead() const { return m_isHead; } -bool Particle::isWeakDecay() const { return quarks() == daughterQuarks(); } +bool Particle::isHead() const { return m_parent == nullptr; } +bool Particle::isWeakDecay() const { return quarks() != daughterQuarks(); } bool Particle::isStateGood() const { return m_isStateGood; } bool Particle::isStable() const { return m_daughters.size() == 0; } bool Particle::isQuasiStable() const { - return props()->width() < ParticlePropertiesList::getMe()->quasiStableThreshold(); + return props()->width() < ParticlePropertiesList::getMe()->quasiStableThreshold() && name() != "gamma0"; } -unsigned int Particle::orbital() const { return m_orbital; } +unsigned Particle::L() const { return m_orbital; } int Particle::polState() const { return m_polState; } std::string Particle::name() const { return m_name; } std::string Particle::uniqueString() const { return m_uniqueString; } @@ -733,14 +747,20 @@ void Particle::setDaughter( const Particle& particle, const unsigned int& index makeUniqueString(); } +void Particle::setParent(const Particle* ptr ) +{ + m_parent = ptr; +} + std::vector> Particle::daughters() const { return m_daughters; } + bool Particle::operator<( const Particle& other ) { - if ( spin() != other.spin() ) return spin() > other.spin(); - if ( !isStable() && other.isStable() ) return true; - if ( isStable() && !other.isStable() ) return false; - if ( mass() != other.mass() ) return mass() > other.mass(); - if ( std::abs( props()->pdgID() ) == std::abs( other.props()->pdgID() ) + if ( spin() != other.spin() ) return spin() > other.spin(); + if ( !isStable() && other.isStable() ) return true; + if ( isStable() && !other.isStable() ) return false; + if ( mass() != other.mass() ) return mass() > other.mass(); + if ( std::abs(props()->pdgID()) == std::abs(other.props()->pdgID() ) && props()->pdgID() != other.props()->pdgID() ) return props()->pdgID() > other.props()->pdgID(); if ( props()->charge() != other.props()->charge() ) return props()->charge() > other.props()->charge(); if ( props()->pdgID() != other.props()->pdgID() ) return props()->pdgID() > other.props()->pdgID(); @@ -756,7 +776,7 @@ EventType Particle::eventType() const { std::vector names = {m_name}; auto fs = getFinalStateParticles( false ); - for ( auto& p : fs ) names.push_back( p->name() ); + std::transform(fs.begin(), fs.end(), std::back_inserter(names), [](const auto& p){ return p->name(); } ); return EventType( names ); } @@ -776,6 +796,14 @@ void Particle::setPolarisationState( const int& state ) m_uniqueString = makeUniqueString(); } +void Particle::setPolarisationState( const std::vector& state ) +{ + setPolarisationState( state[0] ); + auto fs = getFinalStateParticles(); + for(size_t i = 0 ; i < fs.size(); ++i ) fs[i]->setPolarisationState( state[i+1] ); + m_uniqueString = makeUniqueString(); +} + unsigned int Particle::matches( const Particle& other ) const { unsigned int rt=0; @@ -789,7 +817,7 @@ unsigned int Particle::matches( const Particle& other ) const if( daughter_match == 0 ) return MatchState::None; rt |= daughter_match; } - if( m_orbital != other.orbital() ) rt |= MatchState::DifferentOrbital; + if( m_orbital != other.L() ) rt |= MatchState::DifferentOrbital; if( m_polState != other.polState() ) rt |= MatchState::DifferentPolarisation; if( rt == 0 ) rt = MatchState::Exact; if( rt & MatchState::Exact && rt != MatchState::Exact ) @@ -799,11 +827,16 @@ unsigned int Particle::matches( const Particle& other ) const std::string Particle::decayDescriptor() const { return m_uniqueString ; } -int Particle::quasiCP() const +int Particle::CP() const +{ + return C() * finalStateParity(); +} + +int Particle::C() const { - int prod = m_props->C() == 0 ? 1 : m_props->C(); - prod *= ( m_orbital % 2 == 0 ? 1 : -1 ); - for( auto& d : m_daughters ) prod *= d->quasiCP() ; + if( m_daughters.size() == 1 ) return m_daughters[0]->C(); + int prod = 1; + for( auto& d : m_daughters ) prod *= ( d->props()->C() == 0 ? 1 : d->props()->C() ) * d->C(); return prod; } @@ -815,3 +848,13 @@ stdx::optional Particle::attribute(const std::string& key) const } return stdx::nullopt; } + +std::ostream& AmpGen::operator<<( std::ostream& os, const Particle& particle ){ + return os << particle.decayDescriptor(); +} + +namespace AmpGen { + complete_enum( spinFormalism, Covariant, Canonical ) + complete_enum( spinBasis , Dirac , Weyl ) +} + diff --git a/src/ParticleProperties.cpp b/src/ParticleProperties.cpp index d0d67fc2906..6c0417df61a 100644 --- a/src/ParticleProperties.cpp +++ b/src/ParticleProperties.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "AmpGen/ParticlePropertiesList.h" #include "AmpGen/MsgService.h" @@ -17,9 +18,9 @@ void ParticleProperties::print( std::ostream& out ) const { out << "Mass " << mass() << " +" << mErrPlus() << " -" << mErrMinus() << "\nWidth " << width() << " +" << wErrPlus() << " -" << wErrMinus() << "\n I=" << I() << ", G=" << G() << "\n J=" << J() << ", C=" << C() << ", P=" << P() - << "\n Q = " << charge() << "\n pdgID " << pdgID() << "\n name " << name() << "\n quark content: " << quarks() - << "\n net-quark-content " << netQuarkContent() << "\n is its own antiparticle? " - << ( isItsOwnAnti() ? "yes" : "no" ) << "\n radius " << radius() * GeV << " /GeV" + << "\n Q = " << charge() << "\n pdgID " << pdgID() << "\n name " << name() + << "\n quark-content " << quarkContent() << "\n is its own antiparticle? " + << ( hasDistinctAnti() ? "no" : "yes" ) << "\n radius " << radius() * GeV << " /GeV" << "\n"; } @@ -28,14 +29,22 @@ int ParticleProperties::chargeFromString( const std::string& ch, bool& status ) if ( ch == "+" ) return 1; if ( ch == "-" ) return -1; if ( ch == " " ) return 0; - if ( ch == "0" ) return 0; - if ( ch == "++" ) return 2; + if ( ch == "0" ) return 0; + if ( ch == "++" ) return 2; if ( ch == "--" ) return -2; status = 0; return 0; } -ParticleProperties::ParticleProperties( const std::string& pdg_string ) : m_netQuarkContent() +std::string ParticleProperties::J() const +{ + if( m_twoSpin == -1 ) return "?"; + if( m_twoSpin % 2 == 0 ) return std::to_string( int(m_twoSpin/2) ); + if( m_twoSpin % 2 == 1 ) return std::to_string( int(m_twoSpin/2) ) + "/2"; + return ""; +} + +ParticleProperties::ParticleProperties( const std::string& pdg_string ) { m_isValid = false; if ( pdg_string == "" || pdg_string.empty() ) return; @@ -45,7 +54,7 @@ ParticleProperties::ParticleProperties( const std::string& pdg_string ) : m_netQ DEBUG( "Invalid line : " << pdg_string ); return; } - for ( auto& st : s ) st = trim( st ); + std::transform(s.begin(), s.end(), s.begin(), trim); bool status = 1; m_mass = lexical_cast( s[0], status ); m_mErrPlus = lexical_cast( s[1], status ); @@ -56,82 +65,42 @@ ParticleProperties::ParticleProperties( const std::string& pdg_string ) : m_netQ m_pdgID = lexical_cast( s[12], status ); m_Rexist = lexical_cast( s[14], status ); m_Gparity = chargeFromString( s[7], status ); - m_Parity = chargeFromString( s[9], status ); + m_parity = chargeFromString( s[9], status ); m_Cparity = chargeFromString( s[10], status ); m_charge = chargeFromString( s[13], status ); - m_Isospin = s[6]; - m_JtotalSpin = s[8]; + m_isospin = s[6]; m_status = s[15][0]; m_name = s[16]; - m_quarks = s[17]; - m_Aformat = s[11][0]; + m_Aformat = s[11].size() == 1 ? s[11][0] : ' '; m_chargeString = s[13]; - m_netQuarkContent.initFromString( m_quarks ); + m_quarkContent = QuarkContent( s[17] ); bool spin_status = 1; - if( m_JtotalSpin == "?" ) m_twoSpin = 0; - else if( m_JtotalSpin.find("/") != std::string::npos ){ - m_twoSpin = lexical_cast( m_JtotalSpin.substr(0, m_JtotalSpin.find("/") ) , spin_status ); + if( s[8] == "?" ) m_twoSpin = -1; + else if( s[8].find("/") != std::string::npos ){ + m_twoSpin = lexical_cast( s[8].substr(0, s[8].find("/") ) , spin_status ); } - else m_twoSpin = 2 * lexical_cast( m_JtotalSpin, spin_status ); + else m_twoSpin = 2 * lexical_cast( s[8], spin_status ); if( spin_status == 0 ){ - DEBUG("Spin of particle: " << name() << " could not be interpretted (J=" << m_JtotalSpin << ")" ); + DEBUG("Spin of particle: " << name() << " could not be interpretted (J=" << s[8] << ")" ); } - setRadius(); - m_isValid = true; -} - -void ParticleProperties::setRadius() -{ - double defaultRadius = 1.5 / GeV; // 1.5/GeV; - double defaultCharmRadius = 5.0 / GeV; + m_radius = 1.5 / GeV; bool isCharm = ( abs(pdgID()) == 421 || abs(pdgID()) == 411 || abs(pdgID()) == 431 || abs(pdgID()) == 4122 ); - m_Radius = isCharm ? defaultCharmRadius : defaultRadius; -} - -void swap_string(std::string& arg, const char a, const char b) -{ - for( auto& c : arg ) - { - if( c == a ) c = b; - else if( c == b ) c = a; - } -} - -void ParticleProperties::antiQuarks() -{ - if ( m_quarks.empty() ) return; - swapChars(m_quarks, 'U', 'u'); - swapChars(m_quarks, 'D', 'd'); - swapChars(m_quarks, 'C', 'c'); - swapChars(m_quarks, 'S', 's'); - swapChars(m_quarks, 'T', 't'); - swapChars(m_quarks, 'B', 'b'); - unsigned int pos = m_quarks.find( "SqrT" ); - if ( pos < m_quarks.size() ) { - m_quarks.replace( pos, 4, "sqrt" ); - } + if(isCharm) m_radius = 5.0 / GeV; + m_isValid = true; } -void ParticleProperties::antiQuarkContent() { m_netQuarkContent.antiThis(); } - -void ParticleProperties::antiCharge() -{ - swapChars( m_chargeString, '+', '-'); - m_charge *= -1; -} bool ParticleProperties::hasDistinctAnti() const { return !( m_Aformat == ' ' ); } -bool ParticleProperties::barred() const { return m_Aformat == 'F'; } - bool ParticleProperties::antiThis() { if ( !hasDistinctAnti() ) return false; - antiCharge(); - antiQuarks(); - antiQuarkContent(); + swapChars( m_chargeString, '+', '-'); + m_charge *= -1; + if( isFermion() ) m_parity *= -1; + m_quarkContent.antiThis(); m_pdgID *= -1; return true; } @@ -145,12 +114,19 @@ ParticleProperties ParticleProperties::anti() const std::string ParticleProperties::name() const { + if( m_customName ) return m_name; std::string fullName = m_name; if ( m_pdgID < 0 && m_Aformat == 'F' ) fullName += "bar"; fullName += m_chargeString; return fullName; } -double ParticleProperties::radius() const { return m_Radius; } +double ParticleProperties::radius() const { return m_radius; } + +double ParticleProperties::lifetime() const +{ + return 6.582119514 / ( m_width * std::pow( 10, 13 ) ); +} + bool ParticleProperties::isNonResonant() const { @@ -161,11 +137,21 @@ bool ParticleProperties::isFermion() const { return m_twoSpin % 2 == 1; } +bool ParticleProperties::isPhoton() const +{ + return m_pdgID == 22; +} + +bool ParticleProperties::isNeutrino() const +{ + return abs(m_pdgID) == 12 || abs(m_pdgID) == 14 || abs(m_pdgID) == 16; +} + bool ParticleProperties::isBoson() const { return ! isFermion(); } -std::ostream& operator<<( std::ostream& out, const ParticleProperties& pp ) +std::ostream& AmpGen::operator<<( std::ostream& out, const ParticleProperties& pp ) { pp.print( out ); return out; @@ -184,11 +170,12 @@ std::string ParticleProperties::spinName() const { if( m_twoSpin == 5 ) return "e"; if( m_twoSpin == 7 ) return "c"; } - WARNING("Spin name not implemented for " << m_JtotalSpin ); + WARNING("Spin name not implemented for " << m_twoSpin ); return "?"; } -const ParticleProperties* ParticleProperties::get( const std::string& name, const bool& quiet ){ +const ParticleProperties* ParticleProperties::get( const std::string& name, const bool& quiet ) +{ return ParticlePropertiesList::get( name, quiet ); } @@ -212,3 +199,30 @@ bool ParticleProperties::operator>( const ParticleProperties& rhs ) const { retu bool ParticleProperties::operator<=( const ParticleProperties& rhs ) const { return ( *this < rhs || *this == rhs ); } bool ParticleProperties::operator>=( const ParticleProperties& rhs ) const { return ( *this > rhs || *this == rhs ); } + +void ParticleProperties::setProperty(const std::string& key, const std::string& value) +{ + DEBUG("Setting property: " << key << " " << value ); + bool status = true; + if( key == "mass" ) m_mass = stod(value) / MeV; + else if( key == "name" ) m_name = value; + else if( key == "width" ) m_width = stod(value) / MeV; + else if( key == "spin" ) + { + bool spin_status = 1; + if( value == "?" ) m_twoSpin = 0; + else if( value.find("/") != std::string::npos ){ + m_twoSpin = lexical_cast( value.substr(0, value.find("/") ) , spin_status ); + } + else m_twoSpin = 2 * lexical_cast( value, spin_status ); + if( spin_status == 0 ){ + ERROR("Spin of particle: " << name() << " could not be interpretted (J=" << value << ")" ); + } + } + else if( key == "parity" ) m_parity = chargeFromString( value, status ); + else if( key == "charge" ) m_charge = chargeFromString( value, status ); + else if( key == "quarks" ) m_quarkContent = QuarkContent(value); + else { + ERROR("Unrecognised key: " << key ); + } +} diff --git a/src/ParticlePropertiesList.cpp b/src/ParticlePropertiesList.cpp index 68fb8c58e07..b57dccbdbb6 100644 --- a/src/ParticlePropertiesList.cpp +++ b/src/ParticlePropertiesList.cpp @@ -17,18 +17,14 @@ ParticlePropertiesList* ParticlePropertiesList::ptr = nullptr; const ParticlePropertiesList* ParticlePropertiesList::getMe() { - if(!ptr){ - ptr = new ParticlePropertiesList(); - } + if(!ptr) ptr = new ParticlePropertiesList(); if(nullptr == ptr) FATAL("Couldn't get ParticlePropertiesList (i.e. myself)" ); return ptr; } ParticlePropertiesList* ParticlePropertiesList::getMutable() { - if(!ptr){ - ptr = new ParticlePropertiesList(); - } + if(!ptr) ptr = new ParticlePropertiesList(); if(ptr == nullptr) FATAL( "Couldn't get ParticlePropertiesList (i.e. myself)" ); return ptr; } @@ -72,17 +68,13 @@ const std::vector ParticlePropertiesList::dirList() const ParticlePropertiesList::ParticlePropertiesList( const std::string& fname_in ) { - - auto _dirList = dirList(); - - for ( auto& d : _dirList ) { - if ( readLatexLabels( d + "pdgID_to_latex.dat" ) ) break; - } - for ( auto& d : _dirList ) { - if ( readFile( d + "mass_width.csv" ) ) break; - } - for ( auto& d : _dirList ) { - if ( readFile( d + "MintDalitzSpecialParticles.csv" ) ) break; + auto dl = dirList(); + bool status = true; + status &= std::any_of( dl.begin(), dl.end(), [this](auto& d){ return this->readLatexLabels(d +"pdgID_to_latex.dat") ; } ); + status &= std::any_of( dl.begin(), dl.end(), [this](auto& d){ return this->readFile(d +"mass_width.csv") ; } ); + status &= std::any_of( dl.begin(), dl.end(), [this](auto& d){ return this->readFile(d +"MintDalitzSpecialParticles.csv") ; } ); + if( !status ){ + WARNING("Failed to load full PDG configuration, beware of unexpected behaviour"); } makeMappings(); m_quasiStableThreshold = NamedParameter( "ParticleProperties::qsThreshold", KeV ); /// limit is 1 keV @@ -90,15 +82,12 @@ ParticlePropertiesList::ParticlePropertiesList( const std::string& fname_in ) bool ParticlePropertiesList::readLatexLabels( const std::string& name ) { - if ( !fileExists( name ) ) return false; - m_latexLabels.clear(); processFile( name, [this]( auto& line ) { auto tokens = split( line, ' ' ); this->m_latexLabels[stoi( tokens[0] )] = std::make_pair( tokens[1], tokens[2] ); } ); - return true; } @@ -117,7 +106,6 @@ bool ParticlePropertiesList::readFile( const std::string& name ) WARNING( line << " is not valid" ); return; } - auto label = m_latexLabels.find( P.pdgID() ); if ( label != m_latexLabels.end() ) P.setLabel( label->second.first ); m_theList.push_back( P ); @@ -157,18 +145,9 @@ const ParticleProperties* ParticlePropertiesList::find( const std::string& name, auto it = m_byName.find( name ); if ( it != m_byName.end() ) return it->second; if ( !quiet ) { - auto particleNames = ParticlePropertiesList::getMe()->getParticleNames(); - - unsigned int minDistance = 9999; - std::string suggestion = ""; - for ( auto& particle : particleNames ) { - unsigned int distance = editDistance( particle, name ); - if ( distance < minDistance ) { - suggestion = particle; - minDistance = distance; - } - } - ERROR( "Particle: " << name << " not in PDG. Did you mean " << suggestion << "?" ); + auto suggestion = std::min_element( std::begin(m_byName), std::end(m_byName), + [&name](const auto& p1, const auto& p2 ){ return editDistance(p1.first, name) < editDistance(p2.first,name); } ); + ERROR( "Particle: " << name << " not in PDG. Did you mean " << suggestion->first << "?" ); } return nullptr; } @@ -191,13 +170,13 @@ std::ostream& operator<<( std::ostream& out, const ParticlePropertiesList& ppl ) std::vector ParticlePropertiesList::getParticleNames() const { std::vector particleNames; - for ( auto& particle : m_byName ) particleNames.push_back( particle.first ); + std::transform( m_byName.begin(), m_byName.end(), std::back_inserter(particleNames), [](auto& p ) -> std::string { return p.first ; } ); return particleNames; } std::vector ParticlePropertiesList::getParticleIds() const { std::vector particleIds; - for ( auto& particle : m_byID ) particleIds.push_back( particle.first ); + std::transform( m_byID.begin(), m_byID.end(), std::back_inserter(particleIds), [](auto& p ) -> int { return p.first ; } ); return particleIds; } @@ -214,4 +193,26 @@ void ParticlePropertiesList::makeAlias( const std::string& name, const std::stri m_byName[alias] = pp; } +void ParticlePropertiesList::addParticle( const std::vector& tokens ) +{ + INFO( vectorToString(tokens, " ") ); + auto name = tokens[1]; + if( tokens.size() % 2 != 0 ) ERROR("Expecting properties as set of key value pairs"); + ParticleProperties* pp = nullptr; + if( m_byName.find( name ) != m_byName.end() ) + { + WARNING("Overwriting properties of existing particle"); + pp = m_byName[name]; + } + else { + pp = new ParticleProperties(); + pp->setProperty("name", name ); + } + for( int i = 2; i != tokens.size(); i+=2 ) + { + pp->setProperty( tokens[i], tokens[i+1] ); + } + m_byName[name] = pp; +} + double ParticlePropertiesList::quasiStableThreshold() const { return m_quasiStableThreshold; } diff --git a/src/PhaseSpace.cpp b/src/PhaseSpace.cpp index 615767d8169..7fcb9c6c201 100644 --- a/src/PhaseSpace.cpp +++ b/src/PhaseSpace.cpp @@ -10,6 +10,7 @@ #include "AmpGen/ParticlePropertiesList.h" #include "AmpGen/Types.h" #include "AmpGen/MsgService.h" +#include "AmpGen/Particle.h" #include "TRandom.h" const Int_t kMAXP = 18; @@ -20,30 +21,35 @@ PhaseSpace::PhaseSpace( const EventType& type, TRandom* rand ) : m_rand(rand), m_type(type) { setDecay( type.motherMass(), type.masses() ); - if ( type.isTimeDependent() ) - m_decayTime = 6.582119514 / ( ParticlePropertiesList::get( type.mother() )->width() * pow( 10, 13 ) ); + if ( type.isTimeDependent() ){ + INFO("Generating with time-dependence"); + m_decayTime = ParticlePropertiesList::get( type.mother() )->lifetime(); + } } +PhaseSpace::PhaseSpace( const Particle& particle, TRandom* rand ) : + PhaseSpace( particle.eventType(), rand ) {} + double PhaseSpace::q( double m, double m1, double m2 ) const { return 0.5 * sqrt( m*m - 2*m1*m1 - 2*m2*m2 + (m1*m1-m2*m2)*(m1*m1-m2*m2)/(m*m) ); } -Event PhaseSpace::makeEvent(const size_t& cacheSize) +Event PhaseSpace::makeEvent() { std::array rno; std::array pd; std::array invMas; - Event rt( 4 * m_nt, cacheSize); + Event rt(4*m_nt + m_type.isTimeDependent()); rno[0] = 0; - unsigned int n; + size_t n; double wt = m_wtMax; do { wt = m_wtMax; rno[0] = 0; - for( n = 1; n < m_nt - 1; n++ ) rno[n] = rndm(); // m_nt-2 random numbers + for( n = 1; n < m_nt - 1; n++ ) rno[n] = m_rand->Rndm(); // m_nt-2 random numbers rno[m_nt - 1] = 1; std::sort( rno.begin() + 1, rno.begin() + m_nt ); double sum = 0; @@ -55,35 +61,29 @@ Event PhaseSpace::makeEvent(const size_t& cacheSize) pd[n] = q( invMas[n + 1], invMas[n], m_mass[n + 1] ); wt *= pd[n]; } - } while ( wt < rndm() ); - - rt.set(0, { 0, pd[0], 0, sqrt( pd[0] * pd[0] + m_mass[0] * m_mass[0] )} ); - - for( unsigned int i = 1 ; i != m_nt ; ++i ){ + } while ( wt < m_rand->Rndm() ); + rt[0] = 0; + rt[1] = pd[0]; + rt[2] = 0; + rt[3] = sqrt( pd[0] * pd[0] + m_mass[0] * m_mass[0] ); + for(size_t i = 1 ; i != m_nt ; ++i ){ rt.set( i, { 0, -pd[i-1], 0, sqrt( pd[i-1] * pd[i-1] + m_mass[i] * m_mass[i] ) } ); - double cZ = 2 * rndm() - 1; + double cZ = 2 * m_rand->Rndm() - 1; double sZ = sqrt( 1 - cZ * cZ ); - double angY = 2 * M_PI * rndm(); + double angY = 2 * M_PI * m_rand->Rndm(); double cY = cos(angY); double sY = sin(angY); - for ( unsigned int j = 0; j <= i; j++ ) { + double beta = (i == m_nt-1) ? 0 : pd[i] / sqrt( pd[i] * pd[i] + invMas[i] * invMas[i] ); + double gamma = (i == m_nt-1) ? 1 : 1./sqrt( 1 - beta*beta); + for (size_t j = 0; j <= i; j++ ) { double x = rt[4*j+0]; double y = rt[4*j+1]; double z = rt[4*j+2]; - rt[4*j+0] = cZ * x - sZ * y; - rt[4*j+1] = sZ * x + cZ * y; - x = rt[4*j+0]; - rt[4*j+0] = cY * x - sY * z; - rt[4*j+2] = sY * x + cY * z; - } - if ( i == ( m_nt - 1 ) ) break; - double beta = pd[i] / sqrt( pd[i] * pd[i] + invMas[i] * invMas[i] ); - double gamma = 1./sqrt( 1 - beta*beta); - for ( unsigned int j = 0; j <= i; j++ ){ - double E = rt[4*j+3]; - double py = rt[4*j+1]; - rt[4*j+1] = gamma*( py + beta * E ); - rt[4*j+3] = gamma*( E + beta * py ); + double E = rt[4*j+3]; + rt[4*j+0] = cY * (cZ * x - sZ * y ) - sY * z; + rt[4*j+1] = gamma*( sZ * x + cZ * y + beta * E ); + rt[4*j+2] = sY * (cZ * x - sZ * y ) + cY * z; + rt[4*j+3] = gamma*( E + beta * (sZ *x + cZ*y) ); } } rt.setGenPdf( 1 ); @@ -93,10 +93,9 @@ Event PhaseSpace::makeEvent(const size_t& cacheSize) bool PhaseSpace::setDecay( const double& m0, const std::vector& mass ) { - unsigned int n; m_nt = mass.size(); m_teCmTm = m0; - for ( n = 0; n < m_nt; n++ ) { + for (size_t n = 0; n < m_nt; n++) { m_mass[n] = mass[n]; m_teCmTm -= mass[n]; } @@ -104,7 +103,7 @@ bool PhaseSpace::setDecay( const double& m0, const std::vector& mass ) double emmax = m_teCmTm + m_mass[0]; double emmin = 0; double wtmax = 1; - for ( n = 1; n < m_nt; n++ ) { + for (size_t n = 1; n < m_nt; n++) { emmin += m_mass[n - 1]; emmax += m_mass[n]; wtmax *= q( emmax, emmin, m_mass[n] ); diff --git a/src/Plots.cpp b/src/Plots.cpp deleted file mode 100644 index a3903c55a2a..00000000000 --- a/src/Plots.cpp +++ /dev/null @@ -1,71 +0,0 @@ - -#include "AmpGen/ErrorPropagator.h" -#include "AmpGen/EventList.h" -#include "AmpGen/CoherentSum.h" -#include "AmpGen/IncoherentSum.h" -#include "AmpGen/Integrator.h" -#include "AmpGen/MinuitParameterSet.h" -#include "AmpGen/Projection.h" -#include "AmpGen/Utilities.h" -#include "AmpGen/EventList.h" -#include "AmpGen/Plots.h" -#include "TFile.h" -#include "TH1D.h" -#include "TH2D.h" -#include -using namespace AmpGen; -void AmpGen::perAmplitudePlot( const EventList& evts, - const Projection& projection, - const CoherentSum& pdf ) -{ - struct PlotIJ { - unsigned int i; - unsigned int j; - TH1D* hist; - std::complex amp; - }; - - TDirectory* dir = (TDirectory*)gFile->Get( ("perAmp_"+projection.name()).c_str() ); - if( dir == nullptr ) - { - gFile->mkdir( ("perAmp_"+ projection.name() ).c_str() ); - dir = (TDirectory*)gFile->Get( ("perAmp_"+projection.name()).c_str() ); - } - dir->cd(); - - std::vector> eventData; - - std::vector tmpPlots( pdf.size() * ( pdf.size() + 1 ) / 2 ); - - unsigned int s = 0; - for ( unsigned int i = 0; i < pdf.size(); ++i ) { - - for ( unsigned int j = i; j < pdf.size(); ++j ) { - auto pdf_i = pdf[i].pdf; - auto pdf_j = pdf[j].pdf; - unsigned int index_i = evts.getCacheIndex( pdf[i].pdf ); - unsigned int index_j = evts.getCacheIndex( pdf[j].pdf ); - const std::string name = pdf_i.name() + "_" + pdf_j.name(); - tmpPlots[s].hist = projection.plot(name); - tmpPlots[s].i = index_i; - tmpPlots[s].j = index_j; - tmpPlots[s].amp = pdf[i].coupling() * std::conj( pdf[j].coupling() ); - if ( index_i != index_j ) tmpPlots[s].amp = 2.0 * tmpPlots[s].amp; - s++; - } - } - for ( auto& evt : evts ) { - double f = projection( evt ); - for ( auto& h : tmpPlots ) { - std::complex pdfValue = evt.getCache( h.i ) * std::conj( evt.getCache( h.j ) ); - double weight = std::real( h.amp * pdfValue ) * evt.weight() / evt.genPdf(); - h.hist->Fill( f, weight ); - } - } - for ( auto& h : tmpPlots ) { - h.hist->Write(); - delete h.hist; - } - dir->Write(); - gFile->cd(); -} diff --git a/src/PolarisedSum.cpp b/src/PolarisedSum.cpp index e7efc8aa0a4..c9a5b44a607 100644 --- a/src/PolarisedSum.cpp +++ b/src/PolarisedSum.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "AmpGen/CompilerWrapper.h" #include "AmpGen/NamedParameter.h" @@ -28,80 +29,125 @@ #include "AmpGen/ProfileClock.h" #include "AmpGen/DiracMatrices.h" #include "AmpGen/Simplify.h" +#include "AmpGen/enum.h" +#include "AmpGen/simd/utils.h" using namespace AmpGen; using namespace std::complex_literals; -PolarisedSum::PolarisedSum( const EventType& type, - MinuitParameterSet& mps, - const std::string& prefix ) : - m_mps(&mps), - m_eventType(type), - m_prefix(prefix) +#if DEBUGLEVEL == 1 + ENABLE_DEBUG( PolarisedSum ) +#endif + +namespace AmpGen { make_enum(spaceType, spin, flavour) } + +std::vector convertProxies(const std::vector& proxyVector, const std::function& transform) +{ + std::vector rt; + std::transform(proxyVector.begin(), proxyVector.end(), std::back_inserter(rt), transform ); + return rt; +} + +PolarisedSum::PolarisedSum(const EventType& type, + MinuitParameterSet& mps, + const std::vector& pVector) + : m_mps (&mps) + , m_pVector (pVector) + , m_verbosity (NamedParameter("PolarisedSum::Verbosity", 0 )) + , m_debug (NamedParameter("PolarisedSum::Debug" , false )) + , m_eventType (type) + , m_rules (mps) + , m_dim (m_eventType.dim()) { - bool debug = NamedParameter( "PolarisedSum::Debug" ,false ); - bool autoCompile = NamedParameter( "PolarisedSum::AutoCompile",true ); - std::string objCache = NamedParameter("PolarisedSum::ObjectCache","" ); - m_verbosity = NamedParameter( "PolarisedSum::Verbosity" ,0 ); - m_rules = AmplitudeRules(mps); - - auto proto_amplitudes = m_rules.getMatchingRules( type, prefix); - auto production_polarisations = polarisations( type.mother() ); - std::vector> allStates; - for(auto& pol : production_polarisations ) allStates.push_back({pol}); - for(size_t i = 0 ; i < type.size(); ++i ) allStates = polarisationOuterProduct( allStates, polarisations( type[i] ) ); - auto set_polarisation_state = []( auto& matrix_element, auto& polState ){ - auto fs = matrix_element.first.getFinalStateParticles(); - matrix_element.first.setPolarisationState(polState[0]); - for(size_t i = 0 ; i < fs.size(); ++i ) fs[i]->setPolarisationState( polState[i+1] ); - }; - for( auto& m : proto_amplitudes ) INFO( m.first.uniqueString() ); - for( auto& matrix_element : proto_amplitudes ){ - Tensor thisExpression( std::vector({allStates.size()}) ); - int i = 0 ; - DebugSymbols syms; - for( auto& polState : allStates ){ - set_polarisation_state( matrix_element, polState ); - thisExpression[ i++ ] = make_cse( matrix_element.first.getExpression(&syms) ); + std::string objCache = NamedParameter("PolarisedSum::ObjectCache", "" ); + spaceType stype = NamedParameter( "PolarisedSum::SpaceType" , spaceType::spin); + { + ThreadPool tp(std::thread::hardware_concurrency() ); + if( stype == spaceType::spin ) + { + auto prodPols = polarisations(m_eventType.mother()); + std::vector> polStates; + for(const auto& pol : prodPols ) polStates.push_back({pol}); + for(unsigned i = 0 ; i != type.size(); ++i ) polStates = indexProduct(polStates, polarisations( type[i] ) ); + auto protoAmps = m_rules.getMatchingRules(m_eventType); + for(const auto& m : protoAmps ) INFO( m.first.uniqueString() ); + m_matrixElements.resize( protoAmps.size() ); + for(unsigned i = 0; i < m_matrixElements.size(); ++i) + { + auto [lp, lc] = protoAmps[i]; + auto & p = lp; + auto & c = lc; + PolarisedSum* ptr = this; + tp.enqueue( [i, p=lp, c=lc, polStates, &mps, ptr] () mutable { + Tensor thisExpression( Tensor::dim(polStates.size()) ); + DebugSymbols syms; + for(unsigned j = 0; j != polStates.size(); ++j) + thisExpression[j] = make_cse( p.getExpression(j == 0 ? &syms: nullptr, polStates[j] ) ); + //thisExpression[j] = make_cse( p.getExpression(&syms, polStates[j] ) ); + ptr->m_matrixElements[i] = TransitionMatrix( + p, c, + CompiledExpression( + TensorExpression(thisExpression), p.decayDescriptor(), &mps, + ptr->m_eventType.getEventFormat(), ptr->m_debug ? syms : DebugSymbols() ) ); + + CompilerWrapper().compile( ptr->m_matrixElements[i] ); + ptr->m_matrixElements[i].size = thisExpression.size(); + }); } - CompiledExpression< std::vector , const real_t*, const real_t* > expression( - TensorExpression( thisExpression), - matrix_element.first.decayDescriptor(), - type.getEventFormat(),debug ? syms : DebugSymbols() ,&mps ); - m_matrixElements.emplace_back(matrix_element.first, matrix_element.second, expression ); - } - for( auto& polState : allStates){ - for( auto& matrix_element : proto_amplitudes ){ - set_polarisation_state( matrix_element, polState ); + } + if ( stype == spaceType::flavour ) + { + m_dim = {2,1}; + auto r1 = m_rules.getMatchingRules(m_eventType, m_prefix); + auto r2 = m_rules.getMatchingRules(m_eventType.conj(true), m_prefix); + m_matrixElements.resize( r1.size() + r2.size() ); + for(unsigned i = 0 ; i != m_matrixElements.size(); ++i) + { + tp.enqueue( [i, this, &r1, &r2] () mutable { + Tensor thisExpression( Tensor::dim(2) ); + DebugSymbols syms; + auto& [p,coupling] = i < r1.size() ? r1[i] : r2[i-r1.size()]; + thisExpression[0] = i < r1.size() ? make_cse( p.getExpression(&syms) ) : 0; + thisExpression[1] = i < r1.size() ? 0 : make_cse( p.getExpression(&syms) ); + this->m_matrixElements[i] = TransitionMatrix( + p, coupling, + CompiledExpression( + TensorExpression(thisExpression), p.decayDescriptor(), this->m_mps, + this->m_eventType.getEventFormat(), this->m_debug ? syms : DebugSymbols() ) ); + CompilerWrapper().compile( m_matrixElements[i] ); + }); } } - m_polStates = allStates; - if(autoCompile){ - ThreadPool tp(8); - for( auto& thing : m_matrixElements ) - tp.enqueue( [&]{ CompilerWrapper().compile( thing.pdf, objCache ) ;} ); } - if( mps.find("Px") == nullptr ) WARNING("Polarisation parameters not defined, defaulting to (0,0,0)"); - m_pVector = {mps.addOrGet("Px",2,0,0), mps.addOrGet("Py",2,0,0), mps.addOrGet("Pz",2,0,0)}; - auto d = m_eventType.dim(); - size_t normSize = d.second * d.first * d.first; - for(size_t i=0; i < normSize; ++i){ - m_norms.emplace_back( m_matrixElements.size(), m_matrixElements.size() ); - } + if( m_pVector.size() == 0 ) + { + auto p = [this](const std::string& name){ return this->m_mps->addOrGet(name, Flag::Fix, 0, 0); }; + if( m_dim.first == 1 ) m_pVector = {}; + else if( m_dim.first == 2 ) m_pVector = {p("Px"), p("Py"), p("Pz")}; + else if( m_dim.first == 3 ) m_pVector = {p("Px"), p("Py"), p("Pz"), p("Tyy"), p("Tzz"), p("Txy"), p("Txz"), p("Tyz")}; + } + for(size_t i=0; i < m_dim.second * m_dim.first * m_dim.first; ++i) m_norms.emplace_back( m_matrixElements.size(), m_matrixElements.size() ); + + DebugSymbols db; + auto prob = probExpression(transitionMatrix(), convertProxies(m_pVector,[](auto& p){ return Parameter(p->name());} ), m_debug ? &db : nullptr); + m_probExpression = make_expression( prob, "prob_unnormalised", m_mps, this->m_debug ? db : DebugSymbols() ); } std::vector PolarisedSum::polarisations( const std::string& name ) const { auto props = *ParticlePropertiesList::get( name ); - std::vector rt( props.twoSpin() + 1 ); - if( props.isFermion() ) return {1,-1}; - if( props.twoSpin() == 0 ) return {0}; - if( props.twoSpin() == 2 ) - return (name == "gamma0") ? std::vector({-1,1}) : std::vector({-1,0,1}) ; - else return {0}; + if( props.twoSpin() == 0 ) return {0}; // scalar + if( props.isPhoton() ) return {1,-1}; // photon + if( props.twoSpin() == 1 ) return {1,-1}; // fermion + if( props.twoSpin() == 4 ) return {-2,1,0,1,2};// tensor + if( props.twoSpin() == 2 ) return {1,0,-1}; // vector + else { + WARNING("Particle with spin: " << props.twoSpin() << "/2" << " not implemented in initial/final state"); + return {0}; + } } -std::vector> PolarisedSum::polarisationOuterProduct(const std::vector>& A, const std::vector& B ) const +std::vector> PolarisedSum::indexProduct(const std::vector>& A, const std::vector& B ) const { std::vector> rt; for( auto& iA : A ){ @@ -113,134 +159,130 @@ std::vector> PolarisedSum::polarisationOuterProduct(const std:: return rt; } -std::vector>> PolarisedSum::matrixElements() const +std::vector densityMatrix(const unsigned& dim, const std::vector& pv ) +{ + if( dim != 2 && dim != 3 ) + { + std::vector rt(dim*dim); + for( unsigned i = 0 ; i != dim; ++i ) rt[ dim*i +i ] = 1; + return rt; + } + double px = pv[0]; + double py = pv[1]; + double pz = pv[2]; + if( dim == 2 ) return {1+pz , px+1i*py, + px-1i*py, 1-pz }; + if( dim == 3 ){ + double Tyy = pv[3]; + double Tzz = pv[4]; + double Txy = pv[5]; + double Txz = pv[6]; + double Tyz = pv[7]; + return {1 + 1.5*pz + sqrt(1.5)*Tzz , sqrt(0.375)*(px+1i*py) + sqrt(3.)*(Txz+1i*Tyz), -sqrt(1.5)*( Tzz + 2.*Tyy - 2.*1i*Txy), + sqrt(0.375)*(px-1i*py) + sqrt(3)*(Txz-1i*Tyz), 1 - sqrt(6.)*Tzz , sqrt(0.375)*(px+1i*py) - sqrt(3.)*(Txz+1i*Tyz) , + -sqrt(1.500)*( Tzz + 2.*Tyy + 2.*1i*Txy) , sqrt(0.375)*(px-1i*py) - sqrt(3)*(Txz-1i*Tyz) , 1. - 1.5*pz + sqrt(1.5)*Tzz }; + } + ERROR("Density matrices not implemented for state with size="<> PolarisedSum::matrixElements() const { return m_matrixElements; } + void PolarisedSum::prepare() { - DEBUG( "Preparing: " << m_prefix << " " << m_events << " ready = " << m_integrator.isReady() ); + auto resetFlags = [](auto& t){ t.workToDo = false; t.resetExternals() ; }; + auto flagUpdate = [this](auto& t){ t.workToDo = this->m_nCalls == 0 || t.hasExternalsChanged(); }; + auto updateData = [this](auto& t) mutable { if( t.workToDo && this->m_events != nullptr ) this->m_cache.update(this->m_events->store(), t) ; }; + auto updateInteg = [this](auto& t) mutable { if( t.workToDo ) this->m_integrator.updateCache(t) ; }; + transferParameters(); - auto dim = m_eventType.dim(); - std::vector hasChanged( m_matrixElements.size(), false); - size_t nChanges = 0; - ProfileClock tEval; - size_t size_of = size() / m_matrixElements.size(); - for( size_t i = 0; i < m_matrixElements.size(); ++i ){ - ProfileClock tMEval; - auto& t = m_matrixElements[i]; - if( m_nCalls != 0 && !t.pdf.hasExternalsChanged() ) continue; - if( t.addressData == 999 ) t.addressData = m_events->registerExpression( t.pdf , dim.first * dim.second ); - m_events->updateCache(t.pdf, t.addressData); - m_integrator.prepareExpression(t.pdf, size_of); - tMEval.stop(); - t.pdf.resetExternals(); - hasChanged[i] = true; - nChanges++; - if( m_nCalls == 0 && m_integrator.isReady() ) m_integIndex.push_back( m_integrator.events().getCacheIndex( t.pdf ) ); - } - if( !m_probExpression.isLinked() ) build_probunnormalised(); - m_weight = m_weightParam == nullptr ? 1 : m_weightParam->mean(); - tEval.stop(); - ProfileClock tIntegral; - if( m_eventType.dim().first == 2 ){ - double px = m_pVector[0]; - double py = m_pVector[1]; - double pz = m_pVector[2]; - m_psi = {1+pz , px+1i*py, - px-1i*py, 1-pz }; - } - else m_psi = {1}; - if( m_integrator.isReady() ) + for_each_sequence(m_matrixElements.begin(), m_matrixElements.end(), flagUpdate, updateData, updateInteg); + if( m_integrator.isReady() ) updateNorms(); + std::for_each( m_matrixElements.begin(), m_matrixElements.end(), resetFlags ); + if constexpr( detail::debug_type::value ) { - if(nChanges != 0) calculateNorms(hasChanged); - complex_t z = 0; - for(size_t i = 0; i < m_matrixElements.size(); ++i){ - for(size_t j = i; j < m_matrixElements.size(); ++j){ - z += ((i==j) ? 1. : 2. ) * m_matrixElements[i].coupling()*std::conj(m_matrixElements[j].coupling())*norm(i,j); -// z += m_matrixElements[i].coupling()*std::conj(m_matrixElements[j].coupling())*norm(i,j); - } - } - m_norm = std::real(z); - if(m_nCalls % 100 == 0 && m_prefix == "") debug_norm(); + if( m_nCalls % 10000 == 0 ) debug_norm(); } - tIntegral.stop(); - if(m_verbosity && nChanges != 0) - INFO("Time to evaluate = " << tEval << " ms; " - << "norm = " << tIntegral << " ms; " - << "pdfs = " << nChanges); - m_nCalls++; + m_pdfCache.update(m_cache, m_probExpression); + DEBUG( "m_pdfCache[0] = " << utils::at(m_pdfCache[0],0) << " w/o caching = " << getValNoCache(m_events->at(0)) << " w = " << m_weight << " N = " << m_norm ); + m_nCalls++; } +float_v PolarisedSum::operator()( const float_v*, const unsigned index ) const +{ + return ( m_weight / m_norm ) * m_pdfCache[index]; +} + +#if ENABLE_AVX +double PolarisedSum::operator()( const double*, const unsigned index ) const +{ + return operator()((const float_v*)nullptr, index / utils::size::value ).at( index % utils::size::value ); +} +#endif + + void PolarisedSum::debug_norm() { + if( !m_integrator.isReady() ) return; double norm_slow = 0; - for( auto& evt : m_integrator.events() ) - norm_slow += evt.weight() * prob_unnormalised(evt) / evt.genPdf(); - auto evt = m_integrator.events()[0]; - INFO("Event[0]: " << prob_unnormalised(evt) << " " << getValNoCache(evt) ); - INFO("Norm : " << std::setprecision(10) - << "bilinears=" << m_norm - << "; exact=" << norm_slow / m_integrator.sampleNorm() - << "; d = " << m_norm - norm_slow / m_integrator.sampleNorm() - << "; sample=" << m_integrator.sampleNorm() ); -// for( int i = 0 ; i < m_matrixElements.size(); ++i){ -// for( int j = 0 ; j < m_matrixElements.size(); ++j){ -// INFO( "Norm(i="<( - prob, "prob_unnormalised", std::map(), {}, m_mps ); - CompilerWrapper().compile(m_probExpression); - m_probExpression.prepare(); -} - -Tensor PolarisedSum::transitionMatrix() +Tensor PolarisedSum::transitionMatrix() const { - auto dim = m_eventType.dim(); - auto size = dim.first * dim.second ; - std::vector expressions( size, 0); - for( auto& me : m_matrixElements ){ - auto coupling = me.coupling.to_expression() ; - auto cacheIndex = m_events->getCacheIndex(me.pdf); + auto size = m_dim.first * m_dim.second; + std::vector expressions(size, 0); + unsigned totalSize = 0 ; + for( const auto& me : m_matrixElements ){ + auto coupling = me.coupling.to_expression(); + // INFO( me.decayDescriptor() << " " << coupling ); + auto cacheIndex = totalSize; for( size_t i = 0 ; i < size ; ++i ){ expressions[i] = expressions[i] + coupling * Parameter( "x1["+std::to_string(cacheIndex+i)+"]",0,true); } + totalSize += size; } - Tensor T_matrix(expressions, {dim.first, dim.second}); + Tensor T_matrix(expressions, {m_dim.first, m_dim.second}); T_matrix.st(); return T_matrix; } -double PolarisedSum::prob_unnormalised( const Event& evt ) const -{ - return m_probExpression( evt.getCachePtr(0) ); +real_t PolarisedSum::operator()(const Event& evt) const +{ + return (m_weight/m_norm) * utils::at( m_pdfCache[ evt.index() / utils::size::value ], evt.index() % utils::size::value ); } double PolarisedSum::norm() const @@ -248,102 +290,126 @@ double PolarisedSum::norm() const return m_norm; } -complex_t PolarisedSum::norm(const size_t& i, const size_t& j, Integrator<18>* integ) +complex_t PolarisedSum::norm(const size_t& i, const size_t& j, Integrator* integ) { auto ai = m_integIndex[i]; auto aj = m_integIndex[j]; complex_t total = 0; - auto dim = m_eventType.dim(); - auto s1 = dim.first; - auto s2 = dim.second; + auto s1 = m_dim.first; + auto s2 = m_dim.second; for(size_t x = 0 ; x < m_norms.size(); ++x){ auto f = x % s2; auto psiIndex = (x-f) / s2; auto m2 = psiIndex % s1; auto m1 = (psiIndex-m2)/s1; - total += m_psi[psiIndex] * m_norms[x].get(i, j, integ, ai+m1*s2+f, aj+m2*s2+f); + total += m_rho[psiIndex] * m_norms[x].get(i, j, integ, ai+m1*s2+f, aj+m2*s2+f); } return total; } -void PolarisedSum::calculateNorms(const std::vector& hasChanged) +void PolarisedSum::updateNorms() { - for( size_t i = 0 ; i < m_matrixElements.size(); ++i ){ - for( size_t j = i; j < m_matrixElements.size(); ++j ){ - if( hasChanged[i] || hasChanged[j] ) norm(i, j, &m_integrator); + if(std::any_of(m_matrixElements.begin(),m_matrixElements.end(), [](auto& me){ return me.workToDo; } )){ + for( unsigned i = 0 ; i < m_matrixElements.size(); ++i ){ + for( unsigned j = i; j < m_matrixElements.size(); ++j ){ + if( m_matrixElements[i].workToDo || m_matrixElements[j].workToDo ) norm(i, j, &m_integrator); } } m_integrator.flush(); -} - -double PolarisedSum::prob(const Event& evt) const -{ - return m_weight * prob_unnormalised(evt) / m_norm; + } + complex_t z = 0; + for(size_t i = 0; i < m_matrixElements.size(); ++i){ + for(size_t j = 0; j < m_matrixElements.size(); ++j){ + z += m_matrixElements[i].coupling()*std::conj(m_matrixElements[j].coupling()) * ( i > j ? std::conj(norm(j,i)) : norm(i,j) ); + } + } + m_norm = std::real(z); } void PolarisedSum::debug(const Event& evt) { - auto dim = m_eventType.dim(); - size_t size = dim.first * dim.second; - for(auto& me : m_matrixElements) + auto tsize = m_dim.first * m_dim.second; + std::vector this_cache; + for(unsigned j = 0; j != m_matrixElements.size(); ++j) { - std::vector this_cache(0,size); - for(size_t i = 0 ; i < size; ++i ) this_cache.emplace_back( evt.getCache(me.addressData+i) ); - INFO( me.decayDescriptor() << " " << vectorToString( this_cache, " ") ); - } + for(unsigned i = 0 ; i != tsize; ++i ) this_cache.emplace_back( m_cache(evt.index() / utils::size::value, j*tsize + i) ); + INFO( m_matrixElements[j].decayDescriptor() << " " << vectorToString(this_cache, " ") ); + if( m_debug ) m_matrixElements[j].debug( evt ); + } + if( m_debug ) m_probExpression.debug(this_cache.data() ); + INFO("P(x) = " << getValNoCache(evt) << " " << operator()((const float_v*)nullptr, evt.index() / utils::size::value ) ); + INFO("Prod = [" << vectorToString(m_pVector , ", ") <<"]"); } void PolarisedSum::generateSourceCode(const std::string& fname, const double& normalisation, bool add_mt) { INFO("Generating sourceCode -> " << fname ); std::ofstream stream( fname ); - auto dim = m_eventType.dim(); - size_t size = dim.first * dim.second; + size_t size = m_dim.first * m_dim.second; CompilerWrapper().preamble( stream ); - Expression event = Parameter("x0",0,true,0); + Expression event = Parameter("x0",0,true); std::vector expressions(size); for( auto& p : m_matrixElements ){ - p.pdf.prepare(); - p.pdf.to_stream( stream ); - p.pdf.compileWithParameters( stream ); - Array z( make_cse( Function( programatic_name( p.pdf.name()) + "_wParams", {event} ) ), size ); + auto expr = CompiledExpression(const real_t*, const real_t*)>( + p.expression(), + p.decayDescriptor(), + m_eventType.getEventFormat(), DebugSymbols(), m_mps, disableBatch() ) ; + expr.prepare(); + expr.to_stream( stream ); + expr.compileWithParameters( stream ); + Array z( make_cse( Function( programatic_name( p.name()) + "_wParams", {event} ) ), size ); INFO( p.decayDescriptor() << " coupling = " << p.coupling() ); - for( unsigned int j = 0 ; j < size; ++j ){ - expressions[j] = expressions[j] + p.coupling() * z[j]; - } + for( unsigned int j = 0 ; j < size; ++j ) expressions[j] = expressions[j] + p.coupling() * z[j]; } - Tensor T_matrix( expressions, {dim.first,dim.second} ); + Tensor T_matrix( expressions, {m_dim.first, m_dim.second} ); T_matrix.st(); - auto amplitude = probExpression(T_matrix, {Constant(double(m_pVector[0])), - Constant(double(m_pVector[1])), - Constant(double(m_pVector[2]))}); - - auto amplitude_extPol = probExpression(T_matrix, {Parameter("x2",0,true), - Parameter("x3",0,true), - Parameter("x4",0,true)}); - stream << CompiledExpression Expression{ return double(proxy);} )); + auto amp_extPol = probExpression(T_matrix, {Parameter("x2",0,true), Parameter("x3",0,true), Parameter("x4",0,true)}); + stream << CompiledExpression( amplitude / normalisation, "FCN",{},{}, m_mps ) << std::endl ; + const int&)>( amp / normalisation, "FCN", m_mps, disableBatch() ) << std::endl ; - stream << CompiledExpression( amplitude_extPol / normalisation, "FCN_extPol",{},{},m_mps ) << std::endl; + const double&)>(amp_extPol / normalisation, "FCN_extPol", m_mps, disableBatch() ) << std::endl; stream.close(); } -Expression PolarisedSum::probExpression(const Tensor& T_matrix, const std::vector& p) const +Expression PolarisedSum::probExpression(const Tensor& T_matrix, const std::vector& p, DebugSymbols* db) const { Tensor T_conj = T_matrix.conjugate(); Tensor::Index a,b,c; Tensor TT = T_matrix(a,b) * T_conj(c,b); size_t it = T_matrix.dims()[0]; Tensor rho = Identity(it); - if(it == 2) rho = rho + Sigma[0] * p[0] + Sigma[1] * p[1] + Sigma[2]*p[2]; - rho.print(); - + if(it == 2) rho = rho + Sigma[0] * p[0] + Sigma[1] * p[1] + Sigma[2]*p[2]; + if(it == 3) + { + auto px = p[0]; + auto py = p[1]; + auto pz = p[2]; + auto Tyy = p[3]; + auto Tzz = p[4]; + auto Txy = p[5]; + auto Txz = p[6]; + auto Tyz = p[7]; + rho(0,0) = 1 + 1.5 * pz + sqrt(1.5)*Tzz; + rho(1,0) = sqrt(0.375)*(px+1i*py) + sqrt(3.)*(Txz+1i*Tyz); + rho(2,0) = -sqrt(1.5)*( Tzz + 2.*Tyy - 2.*1i*Txy); + rho(0,1) = sqrt(0.375)*(px-1i*py) + sqrt(3.)*(Txz-1i*Tyz); + rho(1,1) = 1 - sqrt(6.)*Tzz; + rho(2,1) = sqrt(0.375)*(px+1i*py) - sqrt(3.)*(Txz+1i*Tyz); + rho(0,2) = -sqrt(1.5)*( Tzz + 2.*Tyy + 2.*1i*Txy); + rho(1,2) = sqrt(0.375)*(px-1i*py) - sqrt(3)*(Txz-1i*Tyz); + rho(2,2) = 1. - 1.5*pz + sqrt(1.5)*Tzz; + } + ADD_DEBUG_TENSOR(T_matrix, db); + ADD_DEBUG_TENSOR(T_conj, db); + ADD_DEBUG_TENSOR(rho, db); + ADD_DEBUG_TENSOR(TT , db); Expression rt = rho(a,b) * TT(b,a); return Real(rt); } @@ -351,66 +417,131 @@ Expression PolarisedSum::probExpression(const Tensor& T_matrix, const std::vecto std::vector PolarisedSum::fitFractions(const LinearErrorPropagator& prop) { bool recomputeIntegrals = NamedParameter("PolarisedSum::RecomputeIntegrals", false ); + bool interferenceFractions = NamedParameter("PolarisedSum::InterferenceFractions", false ); std::vector outputFractions; - for(auto& rule : m_rules.rules()) + for(const auto& rule : m_rules.rules()) { FitFractionCalculator pCalc(this, findIndices(m_matrixElements, rule.first), recomputeIntegrals); - INFO("Denom = [" << vectorToString( findIndices(m_matrixElements, rule.first ) , ", " ) << "]"); - for(auto& process : rule.second) + for(const auto& process : rule.second) { if(process.head() == m_eventType.mother() && process.prefix() != m_prefix) continue; auto numeratorIndices = processIndex(m_matrixElements, process.name()); if(numeratorIndices.size() == 0 || numeratorIndices == pCalc.normSet ) continue; - INFO("Adding calculation: " << process.name() << " [" << vectorToString(numeratorIndices, ", ") << "]"); pCalc.emplace_back(process.name(), numeratorIndices); } if( pCalc.calculators.size() == 0 ) continue; auto fractions = pCalc(rule.first, prop); - for( auto& f : fractions ) outputFractions.emplace_back(f); + for( const auto& f : fractions ) outputFractions.emplace_back(f); } - auto head_rules = m_rules.rulesForDecay(m_eventType.mother(), m_prefix); - FitFractionCalculator iCalc(this, findIndices(m_matrixElements, m_eventType.mother()), recomputeIntegrals); - for(size_t i = 0 ; i < head_rules.size(); ++i) - { - auto process_i = head_rules[i]; - auto num_i = processIndex(m_matrixElements, process_i.name()); - if( num_i.size() == 0 || num_i == iCalc.normSet ) continue; - for( size_t j = i+1 ; j < head_rules.size(); ++j ){ - auto process_j = head_rules[j]; - auto num_j = processIndex(m_matrixElements, process_j.name()); - if( num_j.size() == 0 || num_j == iCalc.normSet ) continue; - iCalc.emplace_back(process_i.name() + " " + process_j.name() , num_i, num_j); + INFO("Fit fractions: "); + for(const auto& p : outputFractions) INFO(p); + + if( interferenceFractions ) + { + auto head_rules = m_rules.rulesForDecay(m_eventType.mother(), m_prefix); + FitFractionCalculator iCalc(this, findIndices(m_matrixElements, m_eventType.mother()), recomputeIntegrals); + for(size_t i = 0 ; i < head_rules.size(); ++i) + { + auto process_i = head_rules[i]; + auto num_i = processIndex(m_matrixElements, process_i.name()); + if( num_i.size() == 0 || num_i == iCalc.normSet ) continue; + for( size_t j = i+1 ; j < head_rules.size(); ++j ){ + auto process_j = head_rules[j]; + auto num_j = processIndex(m_matrixElements, process_j.name()); + if( num_j.size() == 0 || num_j == iCalc.normSet ) continue; + iCalc.emplace_back(process_i.name() + " " + process_j.name() , num_i, num_j); + } } + auto ifractions = iCalc(m_eventType.mother(), prop); + INFO("Interference fractions: "); + for( auto& f : ifractions ) INFO( FitFraction(f) ); } - auto ifractions = iCalc(m_eventType.mother(), prop); - for(auto& p : outputFractions) INFO(p); - INFO("INTERFERENCE FRACTIONS"); - for( auto& f : ifractions ) INFO( FitFraction(f) ); + INFO("Returning: " << outputFractions.size() << " fractions"); return outputFractions; } void PolarisedSum::transferParameters() { - if( m_probExpression.isLinked() ) m_probExpression.prepare(); + m_probExpression.prepare(); for(auto& me : m_matrixElements){ me.coefficient = me.coupling(); - me.pdf.prepare(); + me.prepare(); } - for(auto& p : m_pVector ) p.update(); + for(auto& p : m_pVector) p.update(); + m_weight.update(); + m_rho = densityMatrix(m_dim.first, m_pVector); } -real_t PolarisedSum::getValNoCache( const Event& evt ) +real_t PolarisedSum::getValNoCache( const Event& evt ) const { - transferParameters(); - Event copy(evt); - copy.resizeCache( size() ); - for(auto& me : m_matrixElements){ - auto values = me(copy); - copy.setCache( values , me.addressData ); + auto tsize = m_dim.first * m_dim.second; + std::vector cache( tsize * m_matrixElements.size() ); + for( unsigned i = 0 ; i != m_matrixElements.size(); ++i ){ + std::memmove( cache.data() + tsize * i , m_matrixElements[i](evt).data(), tsize * sizeof(complex_v) ); + } + return utils::get<0>(m_probExpression( cache.data() )); +} + +void PolarisedSum::setWeight( MinuitProxy param ){ m_weight = param; } +double PolarisedSum::getWeight() const { return m_weight ; } + + +std::function PolarisedSum::evaluator(const EventList_type* ievents) const +{ + auto events = ievents == nullptr ? m_integrator.events() : ievents; + Store store(events->size(), m_matrixElements); + for( auto& me : m_matrixElements ) store.update(events->store(), me ); + + std::vector values( events->aligned_size() ); + #ifdef _OPENMP + #pragma omp parallel for + #endif + for( unsigned int block = 0 ; block < events->nBlocks(); ++block ) + { + utils::store(values.data() + utils::size::value * block, (m_weight/m_norm) * m_probExpression(&store(block,0)) ); } - return m_probExpression( copy.getCachePtr() ); + return arrayToFunctor(values); } -void PolarisedSum::setWeight( MinuitParameter* param ){ m_weightParam = param ; } -double PolarisedSum::getWeight() const { return m_weightParam == nullptr ? 1.0 : m_weightParam->mean() ; } +KeyedFunctors PolarisedSum::componentEvaluator(const EventList_type* ievents) const +{ + using store_t = Store; + auto events = ievents == nullptr ? m_integrator.events() : ievents; + std::shared_ptr cache; + if( events != m_integrator.events() ) + { + cache = std::make_shared(events->size(), m_matrixElements); + for( auto& me : m_matrixElements ) const_cast(cache.get())->update(events->store(), me); + } + else cache = std::shared_ptr( & m_integrator.cache(), [](const store_t* t){} ); + + KeyedFunctors rt; + for( unsigned i = 0 ; i != m_matrixElements.size(); ++i ) + { + for( unsigned j = i ; j != m_matrixElements.size(); ++j ){ + auto mi = m_matrixElements[i]; + auto mj = m_matrixElements[j]; + auto ci = this->m_matrixElements[i].coefficient; + auto cj = this->m_matrixElements[j].coefficient; + double s = (i==j) ? 1 : 2 ; + auto name = programatic_name(mi.decayTree.decayDescriptor()) + "_" + programatic_name( mj.decayTree.decayDescriptor() ); + rt.add( [ci,cj,i,j,s, cache, this](const Event& event){ + auto [s1,s2] = this->m_dim; + auto R = s1 * s2; + complex_t total = 0; + for( unsigned x = 0; x != this->m_norms.size(); ++x ) + { + auto f = x % s2; + auto psiIndex = (x-f) / s2; + auto m2 = psiIndex % s1; + auto m1 = (psiIndex-m2)/s1; + total += this->m_rho[psiIndex] * ci * cache->get(event.index(),R * i + m1 * s2 + f) + * std::conj( cj * cache->get(event.index(),R * j + m2 * s2 + f) ); + } + return s * std::real(total); + }, name, ""); + } + } + return rt; +} diff --git a/src/ProgressBar.cpp b/src/ProgressBar.cpp new file mode 100644 index 00000000000..73e940e5855 --- /dev/null +++ b/src/ProgressBar.cpp @@ -0,0 +1,40 @@ +#include "AmpGen/ProgressBar.h" +#include "AmpGen/MsgService.h" + +#include +#include +#include +using namespace AmpGen; + +ProgressBar::ProgressBar(const size_t& width, const std::string& context) + : m_width(width), + m_lastPercent(-1), + m_context(context) {} + +ProgressBar::~ProgressBar(){ + if( !m_finished ) finish(); +} + +void ProgressBar::print(const double& percentage, const std::string& message) +{ + int lpad = int(percentage * m_width); + int val = int(percentage * 100); + if( val == m_lastPercent ) return; + m_lastPercent = val; + std::cout << "\r\033[2;34m" << std::left << std::setw( detail::FCNNAMELENGTH ) << m_context << " INFO " << "\033[0m"; + std::cout << "Completed: " << std::right << std::setw(3) << val << "% " << "["; + + // detail::labelled_stream(m_context) << "Completed: " << std::right << std::setw(3) << val << "% " << "["; + std::fill_n(std::ostream_iterator(std::cout), lpad, '|'); + std::fill_n(std::ostream_iterator(std::cout), m_width-lpad, ' '); + std::cout << "]"; + std::cout << message; + m_lastMessage = message; + fflush (stdout); +} + +void ProgressBar::finish(){ + print(1,m_lastMessage); + std::cout << std::endl; + m_finished = true; +} diff --git a/src/Projection.cpp b/src/Projection.cpp index 186b8622e9e..5856c991717 100644 --- a/src/Projection.cpp +++ b/src/Projection.cpp @@ -1,13 +1,19 @@ #include "AmpGen/Projection.h" #include "AmpGen/Utilities.h" #include "AmpGen/Event.h" +#include "AmpGen/EventList.h" +#include "AmpGen/EventListSIMD.h" #include #include "TAxis.h" #include "TH1.h" #include "TH2.h" +#include "THStack.h" using namespace AmpGen; +using namespace AmpGen::PlotOptions; + +Projection::Projection() = default; Projection::Projection( const std::function& fcn, const std::string& name, const std::string& xAxisTitle, @@ -39,12 +45,15 @@ TH1D* Projection::plot(const std::string& prefix) const { plot->GetYaxis()->SetTitleOffset(1.35); plot->SetMarkerSize(0); plot->SetMinimum(0); + + DEBUG("Returning plot: [" << m_min << " " << m_max << "] " << m_name << " " << + plot->GetXaxis()->GetBinLowEdge(1) << " " << + plot->GetXaxis()->GetBinLowEdge(1 + m_nBins) + ); return plot; } -std::function Projection::binFunctor() const { - return [this](auto& evt){ - - return int ( ( (*this)(evt) - m_min ) / m_width ) ; }; +std::function Projection::binFunctor() const { + return [this](auto& evt){ return int ( ( (*this)(evt) - m_min ) / m_width ) ;}; } TH2D* Projection2D::plot(const std::string& prefix) const { @@ -67,3 +76,103 @@ std::pair Projection2D::operator()( const Event& evt ) const return {xAxis.m_func( evt ), yAxis.m_func( evt )}; } +template <> TH1D* Projection::projInternal( const EventList& events, const ArgumentPack& args) const +{ + auto selection = args.getArg().val; + auto weightFunction = args.getArg().val; + bool autowrite = args.get() != nullptr; + std::string prefix = args.getArg(std::string("")); + auto axis = plot(prefix); + axis->SetLineColor(args.getArg(kBlack).val); + axis->SetMarkerSize(0); + for( auto& evt : events ) + { + if( selection != nullptr && !selection(evt) ) continue; + auto pos = operator()(evt); + axis->Fill( pos, evt.weight() * ( weightFunction == nullptr ? 1 : weightFunction(evt) / evt.genPdf() ) ); + } + if( selection != nullptr ) INFO("Filter efficiency = " << axis->GetEntries() << " / " << events.size() ); + if( autowrite ) axis->Write(); + return axis; +} + +template <> std::tuple, THStack*> Projection::projInternal(const EventList& events, const Projection::keyedFunctors& weightFunction, const ArgumentPack& args) const +{ + std::vector hists; + double norm_sum = args.getArg(1).val; + std::string prefix = args.getArg().val; + bool autowrite = args.get() != nullptr; + THStack* stack = args.getArg(new THStack()).val; + auto selection = args.getArg().val; + if( prefix != "" ) prefix = prefix +"_"; + for( auto& key : weightFunction.keys ) + hists.push_back( plot(prefix + key ) ); + for( const auto& evt : events ){ + if( selection != nullptr && !selection(evt) ) continue; + auto pos = operator()(evt); + auto weights = weightFunction(evt); + for( unsigned j = 0 ; j != weights.size(); ++j ) hists[j]->Fill( pos, evt.weight() * weights[j] / evt.genPdf() ); + } + std::sort( std::begin(hists), std::end(hists), [](auto& h1, auto& h2){ return h1->Integral() < h2->Integral() ; } ); + double total = std::accumulate( std::begin(hists), std::end(hists), 0.0, [](double& t, auto& h){ return t + h->Integral() ; } ); + if( total == 0 ) ERROR("Norm = " << total ); + else for( auto& h : hists ) h->Scale( norm_sum / total ); + stack->SetName( (prefix + name() + "_stack").c_str()); + for( auto& h : hists ){ + stack->Add(h, "C HIST"); + if( autowrite ) h->Write(); + } + if( autowrite ) stack->Write(); + return {hists, stack}; +} + +#if ENABLE_AVX +template <> TH1D* Projection::projInternal( const EventListSIMD& events, const ArgumentPack& args) const +{ + auto selection = args.getArg().val; + auto weightFunction = args.getArg().val; + bool autowrite = args.get() != nullptr; + std::string prefix = args.getArg(std::string("")); + auto plt = plot(prefix); + plt->SetLineColor(args.getArg(kBlack).val); + plt->SetMarkerSize(0); + for( const auto evt : events ) + { + if( selection != nullptr && !selection(evt) ) continue; + auto pos = operator()(evt); + plt->Fill( pos, evt.weight() * ( weightFunction == nullptr ? 1 : weightFunction(evt) / evt.genPdf() ) ); + } + if( autowrite ) plt->Write(); + return plt; +} + +template <> std::tuple, THStack*> Projection::projInternal(const EventListSIMD& events, const Projection::keyedFunctors& weightFunction, const ArgumentPack& args) const +{ + std::vector hists; + double norm_sum = args.getArg(1).val; + std::string prefix = args.getArg().val; + bool autowrite = args.get() != nullptr; + THStack* stack = args.getArg(new THStack()).val; + auto selection = args.getArg().val; + if( prefix != "" ) prefix = prefix +"_"; + for( auto& key : weightFunction.keys ) + hists.push_back( plot(prefix + key ) ); + for( const auto& evt : events ){ + if( selection != nullptr && !selection(evt) ) continue; + auto pos = operator()(evt); + auto weights = weightFunction(evt); + for( unsigned j = 0 ; j != weights.size(); ++j ) hists[j]->Fill( pos, evt.weight() * weights[j] / evt.genPdf() ); + } + std::sort( std::begin(hists), std::end(hists), [](auto& h1, auto& h2){ return h1->Integral() < h2->Integral() ; } ); + double total = std::accumulate( std::begin(hists), std::end(hists), 0.0, [](double& t, auto& h){ return t + h->Integral() ; } ); + if( total == 0 ) ERROR("Norm = " << total ); + else for( auto& h : hists ) h->Scale( norm_sum / total ); + stack->SetName( (prefix + name() + "_stack").c_str()); + for( auto& h : hists ){ + stack->Add(h, "C HIST"); + if( autowrite ) h->Write(); + } + if( autowrite ) stack->Write(); + return {hists, stack}; +} +#endif diff --git a/src/QuarkContent.cpp b/src/QuarkContent.cpp index d31336abae8..bb97ac0994d 100644 --- a/src/QuarkContent.cpp +++ b/src/QuarkContent.cpp @@ -15,10 +15,25 @@ std::map QuarkState::gPositions; QuarkState::QuarkState() { - for ( auto& quark : m_quarks ) quark = 0; + std::fill( m_quarks.begin(), m_quarks.end(), 0 ); initPositions(); } +QuarkContent::QuarkContent( const std::string& str ) +{ + if ( str.find( "non-qQ" ) < str.size() ) { + m_quarks.resize( 1 ); + return; + } + auto tokens = split( replaceAll( str, "sqrt", "" ), {'(', ')', '+', '-'} ); + m_quarks.clear(); + for ( auto& token : tokens ) { + QuarkState qc( token ); + if ( !qc.isVacuum() ) m_quarks.emplace_back( qc ); + } + if ( m_quarks.size() == 0 ) m_quarks.resize( 1 ); +} + QuarkState::QuarkState( const std::string& str ) : QuarkState() { for ( auto& c : str ) { auto lc = std::tolower(c); @@ -38,7 +53,7 @@ bool QuarkState::initPositions() void QuarkState::antiThis() { - for ( auto& quark : m_quarks ) quark *= -1; + std::transform( m_quarks.begin(), m_quarks.end(), m_quarks.begin(), [](const auto& quark){ return (-1)*quark ; } ); } char QuarkState::nameFromPosition( int i ) const @@ -82,16 +97,9 @@ QuarkState QuarkState::operator-( const QuarkState& rhs ) const returnVal -= rhs; return returnVal; } -std::ostream& operator<<( std::ostream& st, const QuarkState& qc ) -{ - qc.print( st ); - return st; -} bool QuarkState::isVacuum() const { - for ( auto& quark : m_quarks ) - if ( quark != 0 ) return false; - return true; + return std::all_of( m_quarks.begin(), m_quarks.end(), [](const auto& quark){ return quark == 0 ; } ); } bool QuarkState::operator==( const QuarkState& rhs ) const @@ -100,6 +108,12 @@ bool QuarkState::operator==( const QuarkState& rhs ) const if ( rhs[i] != m_quarks[i] ) return false; return true; } + +bool QuarkState::operator!=( const QuarkState& rhs ) const +{ + return !( *this == rhs ); +} + int QuarkState::operator[]( const size_t& index ) const { return m_quarks[index]; } QuarkContent::QuarkContent() : m_quarks(1) {} @@ -109,21 +123,6 @@ void QuarkContent::antiThis() for ( auto& qc : m_quarks ) qc.antiThis(); } -void QuarkContent::initFromString( const std::string& str ) -{ - if ( str.find( "non-qQ" ) < str.size() ) { - m_quarks.resize( 1 ); - return; - } - auto tokens = split( replaceAll( str, "sqrt", "" ), {'(', ')', '+', '-'} ); - m_quarks.clear(); - for ( auto& token : tokens ) { - QuarkState qc( token ); - if ( !qc.isVacuum() ) m_quarks.emplace_back( qc ); - } - if ( m_quarks.size() == 0 ) m_quarks.resize( 1 ); -} - void QuarkContent::print( std::ostream& os ) const { os << "["; @@ -177,20 +176,14 @@ QuarkContent QuarkContent::operator-( const QuarkContent& rhs ) const returnVal -= rhs; return returnVal; } -std::ostream& AmpGen::operator<<( std::ostream& st, const QuarkContent& qc ) -{ - qc.print( st ); - return st; -} bool QuarkContent::operator==( const QuarkContent& rhs ) const { - for ( auto& l : m_quarks ) { - for ( auto& r : rhs.quarks() ) { - if ( l == r ) return true; - } - } - return false; + for ( auto& qsl : m_quarks ) { + bool isSame = std::any_of( rhs.quarks().begin(), rhs.quarks().end(), [&qsl](auto& qsr){ return qsl == qsr; } ); + if( isSame ) return true; + } + return false; } bool QuarkContent::operator!=( const QuarkContent& rhs ) const @@ -205,8 +198,21 @@ QuarkState QuarkContent::operator[]( const size_t& index ) const size_t QuarkContent::size() const { return m_quarks.size(); } -std::vector QuarkContent::quarks() const +const std::vector& QuarkContent::quarks() const { return m_quarks; } + +std::ostream& AmpGen::operator<<( std::ostream& st, const QuarkContent& qc ) +{ + qc.print( st ); + return st; +} + +std::ostream& AmpGen::operator<<( std::ostream& st, const QuarkState& qc ) +{ + qc.print( st ); + return st; +} + diff --git a/src/RecursivePhaseSpace.cpp b/src/RecursivePhaseSpace.cpp index 97d7da88160..dad48e3fbde 100644 --- a/src/RecursivePhaseSpace.cpp +++ b/src/RecursivePhaseSpace.cpp @@ -40,10 +40,10 @@ RecursivePhaseSpace::RecursivePhaseSpace(const Particle& decayChain, const Event setRandom( rndm ); } -AmpGen::Event RecursivePhaseSpace::makeEvent( const size_t& cacheSize ) +AmpGen::Event RecursivePhaseSpace::makeEvent() { - AmpGen::Event evt = m_phsp.makeEvent( cacheSize ); - AmpGen::Event rt( 4 * m_eventType.size(), cacheSize ); + AmpGen::Event evt = m_phsp.makeEvent(); + AmpGen::Event rt( 4 * m_eventType.size()); for (size_t i = 0; i < m_nodes.size(); ++i ) { auto& segment = m_nodes[i]; double px = evt[4*i + 0]; @@ -58,9 +58,9 @@ AmpGen::Event RecursivePhaseSpace::makeEvent( const size_t& cacheSize ) rt[4*segment.sink + 3] = pE; } } else { - auto evtTmp = segment.decayProds->makeEvent(cacheSize); + auto evtTmp = segment.decayProds->makeEvent(); double v = sqrt( px * px + py * py + pz * pz ) / pE; - boost( evtTmp, {px, py, pz}, v ); + boost( evtTmp, std::tuple(px, py, pz), v ); for(size_t j = 0; j < rt.size(); ++j) rt[j] += evtTmp[j]; } evt.setGenPdf(1); @@ -72,8 +72,7 @@ std::vector RecursivePhaseSpace::getFinalStates() { std::vector rt; for ( auto& f : m_nodes ) { - if ( f.decayProds == nullptr ) - rt.push_back( &f ); + if ( f.decayProds == nullptr ) rt.push_back( &f ); else { auto segs = f.decayProds->getFinalStates(); for ( auto& s : segs ) rt.push_back( s ); diff --git a/src/Simplify.cpp b/src/Simplify.cpp index cb88aedd9a7..fa5c0db8081 100644 --- a/src/Simplify.cpp +++ b/src/Simplify.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "AmpGen/MsgService.h" @@ -38,8 +40,10 @@ NormalOrderedExpression::Term::Term( const Expression& expression ) : std::sort( m_terms.begin(), m_terms.end(), [](auto& t1, auto& t2 ){ return t1.second > t2.second; } ) ; - Expression t = 1; - for( auto& f : m_terms ) t = t * f.first; + Expression t = std::accumulate( m_terms.begin(), m_terms.end(), Expression(1), [](auto& A, auto& B){ return A * B.first ; } ); + // std::multiplies() ); + //Expression t = 1; + //for( auto& f : m_terms ) t = t * f.first; m_expressionAsString = ( t / m_divisor).to_string(); } diff --git a/src/Spline.cpp b/src/Spline.cpp index f92461987b6..1a1ee7b3b61 100644 --- a/src/Spline.cpp +++ b/src/Spline.cpp @@ -24,20 +24,18 @@ Spline::Spline(const std::string& name, m_min(min), m_max(max) {} -Spline::Spline(const Spline& spline, - const Expression& x ) - : +Spline::Spline(const Spline& spline, const Expression& x, DebugSymbols* db ) : m_points( spline.m_points ), m_name( spline.m_name), m_nKnots( spline.m_nKnots), m_min( spline.m_min ), m_max( spline.m_max ), m_x ( x ), - m_eval( eval() ) { - } -Expression Spline::operator()( const Expression& x ) + m_eval( eval(db) ) {} + +Expression Spline::operator()( const Expression& x, DebugSymbols* db ) { - return Spline(*this,x); + return Spline(*this,x, db); } Expression AmpGen::getSpline( const std::string& name, const Expression& x, const std::string& arrayName, @@ -56,16 +54,16 @@ Expression AmpGen::getSpline( const std::string& name, const Expression& x, cons max = NamedParameter( name + "::Spline::Max", 0. ); } std::string spline_name = name + "::Spline::"+arrayName; - return Spline( spline_name, nBins, min,max )(x); + return Spline(spline_name, nBins, min, max)(x, dbexpressions); } -Expression Spline::eval() const +Expression Spline::eval(DebugSymbols* db) const { Expression x = make_cse(m_x); double spacing = ( m_max - m_min ) / ( (double)m_nKnots - 1. ); Expression dx = Fmod( x - m_min, spacing ); Expression bin = ( x - m_min ) / spacing; - Expression continuedValue = 0; + Expression continuedValue = m_points[m_nKnots-1]; Expression returnValue = Ternary( x > m_min && x < m_max, m_points[bin] + ( ( m_points[bin + 1] - m_points[bin] ) / spacing @@ -73,6 +71,11 @@ Expression Spline::eval() const + m_points[bin+m_nKnots] * dx * dx / 2. + dx * dx * dx * ( m_points[bin+1+m_nKnots] - m_points[bin+m_nKnots] ) / ( 6. * spacing ), continuedValue ); + ADD_DEBUG(x, db ); + ADD_DEBUG(dx, db ); + ADD_DEBUG(bin, db ); + ADD_DEBUG(returnValue, db ); + ADD_DEBUG( m_points[bin], db ); return make_cse(returnValue); } @@ -80,27 +83,25 @@ void SplineTransfer::print() const { INFO( "Source: " << m_parameters[0]->name() SplineTransfer::SplineTransfer() = default; SplineTransfer::SplineTransfer( const SplineTransfer& other ) - : CacheTransfer() + : CacheTransfer(other.m_address, other.m_name, other.m_value, other.m_size) , m_transferMatrix( other.m_transferMatrix ) , m_parameters( other.m_parameters ) + , m_nKnots( other.m_nKnots ) , m_min( other.m_min ) , m_max( other.m_max ) - , m_address( other.m_address ) { } -SplineTransfer::SplineTransfer( const unsigned int& address, const unsigned int& N, const double& min, const double& max ) - : CacheTransfer() +SplineTransfer::SplineTransfer( const size_t& address, const std::string& name, const unsigned int& N, const double& min, const double& max ) + : CacheTransfer(address, name) , m_transferMatrix( TMatrixD( N - 2, N - 2 ) ) , m_parameters( N, nullptr ) , m_nKnots(N) , m_min( min ) , m_max( max ) - , m_address( address ) - { unsigned int size = N - 2; - TMatrixD M( N - 2, N - 2 ); + TMatrixD M(size, size); for ( unsigned int i = 0; i < size; ++i ) { M[i][i] = 4; if ( i != size - 1 ) { @@ -117,9 +118,7 @@ SplineTransfer::SplineTransfer( const unsigned int& address, const unsigned int& bool SplineTransfer::isConfigured() { - for ( auto& x : m_parameters ) - if ( x == nullptr ) return false; - return true; + return std::all_of( m_parameters.begin(), m_parameters.end(), [](auto& p ){ return p != nullptr ; } ); } void SplineTransfer::set( const unsigned int& N, MinuitParameter* f ) @@ -128,10 +127,9 @@ void SplineTransfer::set( const unsigned int& N, MinuitParameter* f ) } void SplineTransfer::set( const unsigned int& N, const double& value ) { - m_parameters[N] = new MinuitParameter("dumb",MinuitParameter::Fix,value,0); + m_parameters[N] = new MinuitParameter("dumb", Flag::Fix, value, 0); } -void SplineTransfer::setAddress( const unsigned int& address ) { m_address = ( address ); } void SplineTransfer::transfer( CompiledExpressionBase* destination ) { unsigned int size = m_parameters.size() - 2; @@ -154,7 +152,7 @@ void SplineTransfer::transfer( CompiledExpressionBase* destination ) } } -void Spline::resolve( ASTResolver& resolver ) +void Spline::resolve( ASTResolver& resolver ) const { resolver.resolve(*this); m_x.resolve(resolver); diff --git a/src/Tensor.cpp b/src/Tensor.cpp index b53519571b4..90ae8a46863 100644 --- a/src/Tensor.cpp +++ b/src/Tensor.cpp @@ -22,7 +22,7 @@ Tensor::Tensor() setupCoordinates(); } -Tensor::Tensor( const std::vector& dim ) +Tensor::Tensor( const std::vector& dim ) : m_dim(dim), m_elements( nElements(), Constant( 0. ) ) { @@ -30,31 +30,19 @@ Tensor::Tensor( const std::vector& dim ) } Tensor::Tensor( const std::vector& elements ) - : m_dim( std::vector( {elements.size()} ) ) + : m_dim( std::vector( {unsigned(elements.size())} ) ) { setupCoordinates(); for(auto& element : elements) append( element ); } -/* -Tensor::Tensor( const std::vector& elements ) -{ - if( elements.size() == 0 ) return Tensor(); - std::vector rank; - rank.push_back( elements.size() ); - for( auto& d : element[0].dims() ) rank.push_back( d ); - for( int i = 0 ; i < elements.size(); ++i ) - { - - } -} -*/ -Expression Tensor::get( const size_t& co ) + +Expression Tensor::get( const unsigned& co ) { if ( co >= m_elements.size() ) ERROR("Element (" + std::to_string( co ) + " ) out of range (0" << ", " << m_elements.size() << ")"); return m_elements[m_symmetrisedCoordinates[co]]; } -Expression Tensor::get( const size_t& co ) const +Expression Tensor::get( const unsigned& co ) const { if ( co >= m_elements.size() ) ERROR("Element (" + std::to_string( co ) + " ) out of range (0" << ", " << m_elements.size() << ")"); @@ -64,23 +52,22 @@ Expression Tensor::get( const size_t& co ) const std::string Tensor::to_string(const ASTResolver* resolver) const { std::string value = "{"; - for(size_t i = 0 ; i < size(); ++i) + for(unsigned i = 0 ; i < size(); ++i) { value += Tensor::operator[](i).to_string(resolver) + (i == size() -1 ? "}" : ", " ) ; } return value; } -size_t Tensor::rank() const { return m_dim.size(); } +unsigned Tensor::rank() const { return m_dim.size(); } -int Tensor::metricSgn( const std::vector& coordinates ) const +int Tensor::metricSgn( const std::vector& coordinates ) const { - int sgn = 1; - for ( auto& coord : coordinates ) sgn *= ( coord == 3 ) ? 1 : -1; - return sgn; + return std::accumulate( coordinates.begin(), coordinates.end(), 1, + [](auto& prod, auto& co){ return prod * ( ( co == 3) ? 1 : -1 ) ;} ); } -int Tensor::metricSgn( const size_t& index ) const { return metricSgn( coords( index ) ); } +int Tensor::metricSgn( const unsigned& index ) const { return metricSgn( coords( index ) ); } void Tensor::append( const Expression& expression ){ m_elements.emplace_back( expression ); } void Tensor::append( const real_t& value ) { m_elements.emplace_back( Constant( value )); } @@ -89,8 +76,7 @@ void Tensor::append( const std::string& value ) { m_elements.emplace_back( Pa void Tensor::setupCoordinates() { - int st=1; - for( auto& d : m_dim ) st *= d; + int st = std::accumulate( m_dim.begin(), m_dim.end(), 1, std::multiplies() ); DEBUG( "Setting up coordinates: " << dimString() << " coordinate mapping = " << st ); m_symmetrisedCoordinates.resize( st ); std::iota( m_symmetrisedCoordinates.begin(), m_symmetrisedCoordinates.end(), 0 ); @@ -98,11 +84,11 @@ void Tensor::setupCoordinates() std::iota( m_uniqueElements.begin(), m_uniqueElements.end(), 0 ); } -Expression Tensor::get( const std::vector& _co ) const { return ( m_elements[index( _co )] ); } +Expression Tensor::get( const std::vector& _co ) const { return ( m_elements[index( _co )] ); } -size_t Tensor::size() const { return m_elements.size(); } +unsigned Tensor::size() const { return m_elements.size(); } -size_t Tensor::index( const std::vector& _co ) const +unsigned Tensor::index( const std::vector& _co ) const { return symmetrisedIndex(_co); // auto id = Tensor::coordinates_to_index( _co, m_dim ); @@ -110,7 +96,7 @@ size_t Tensor::index( const std::vector& _co ) const // return id; } -size_t Tensor::symmetrisedIndex( const std::vector& co ) const +unsigned Tensor::symmetrisedIndex( const std::vector& co ) const { auto id = Tensor::coordinates_to_index( co, m_dim ); if( id > m_symmetrisedCoordinates.size() ){ @@ -119,29 +105,29 @@ size_t Tensor::symmetrisedIndex( const std::vector& co ) const return m_symmetrisedCoordinates[id] ; } -const std::vector Tensor::coords( const size_t& index ) const +const std::vector Tensor::coords( const unsigned& index ) const { return Tensor::index_to_coordinates( index, m_dim ); } -std::vector Tensor::index_to_coordinates( const size_t& index, const std::vector& dim ) +std::vector Tensor::index_to_coordinates( const unsigned& index, const std::vector& dim ) { - std::vector returnValue; - size_t index_temp = index; - for(size_t j = 0; j < dim.size(); ++j ) { - size_t dproduct = 1; - for(size_t i = 0; i < dim.size() - j-1; ++i ) dproduct *= dim[dim.size()-i-1]; - size_t val = ( index_temp - ( index_temp % dproduct ) ) / dproduct; + std::vector returnValue; + unsigned index_temp = index; + for(unsigned j = 0; j < dim.size(); ++j ) { + unsigned dproduct = 1; + for(unsigned i = 0; i < dim.size() - j-1; ++i ) dproduct *= dim[dim.size()-i-1]; + unsigned val = ( index_temp - ( index_temp % dproduct ) ) / dproduct; index_temp -= dproduct * val; returnValue.push_back( val ); } return returnValue; } -size_t Tensor::coordinates_to_index( const std::vector& co, const std::vector& dim ) +unsigned Tensor::coordinates_to_index( const std::vector& co, const std::vector& dim ) { - size_t index = 0; - size_t dproduct = 1; + unsigned index = 0; + unsigned dproduct = 1; for ( int i = dim.size()-1; i >= 0; --i ) { //for ( int i = 0; i < dim.size(); ++i ) { index += co[i] * dproduct; @@ -150,18 +136,14 @@ size_t Tensor::coordinates_to_index( const std::vector& co, const std::v return index; } -std::string Tensor::coordinates_to_string( const std::vector& coordinates ) +std::string Tensor::coordinates_to_string( const std::vector& coordinates ) { return "[" + vectorToString( coordinates, ", ") + "]"; } -size_t Tensor::nElements() const +unsigned Tensor::nElements() const { - size_t dim = 1; - for ( auto& d : m_dim ) { - dim *= ( d != 0 ) ? d : 1; - } - return dim; + return std::accumulate( m_dim.begin(), m_dim.end(), 1, [](auto& dim, auto& d){ return dim * ( d == 0 ? 1 : d ) ; } ); } const std::string Tensor::dimString() const { @@ -171,13 +153,13 @@ const std::string Tensor::dimString() const return str + "]"; } -size_t Tensor::nDim() const { return m_dim.size(); } +unsigned Tensor::nDim() const { return m_dim.size(); } bool Tensor::rankMatches( const Tensor& other ) { bool success = true; if ( m_dim.size() != other.m_dim.size() ) return false; - for ( size_t i = 0; i < m_dim.size(); ++i ) success &= m_dim[i] == other.m_dim[i]; + for ( unsigned i = 0; i < m_dim.size(); ++i ) success &= m_dim[i] == other.m_dim[i]; return success; } @@ -194,7 +176,7 @@ Tensor AmpGen::operator+( const Tensor& t1, const Tensor& t2 ) ERROR("Addition between tensors with different number of elements " << t1.nElements() << " " << t2.nElements()); } - for ( size_t i = 0; i < t1.nElements(); ++i ) result[i] = t1[i] + t2[i]; + for ( unsigned i = 0; i < t1.nElements(); ++i ) result[i] = t1[i] + t2[i]; return result; } @@ -212,12 +194,12 @@ Tensor AmpGen::operator-( const Tensor& t1, const Tensor& t2 ) t2.print(); ERROR("Subtraction between tensors with different number of elements " << t1.nElements() << " "<< t2.nElements()); } - for ( size_t i = 0; i < t1.nElements(); ++i ) result[i] = t1[i] - t2[i]; + for ( unsigned i = 0; i < t1.nElements(); ++i ) result[i] = t1[i] - t2[i]; return result; } void Tensor::st(const bool simplify) { - for(size_t i = 0 ; i < size(); ++i ){ + for(unsigned i = 0 ; i < size(); ++i ){ m_elements[i] = make_cse( m_elements[i], simplify ); } } @@ -225,14 +207,14 @@ void Tensor::st(const bool simplify) { Tensor Tensor::conjugate() const { Tensor copy( dims() ); - for(size_t i = 0 ; i < size(); ++i ) copy[i] = fcn::conj( get(i) ); + for(unsigned i = 0 ; i < size(); ++i ) copy[i] = fcn::conj( get(i) ); return copy; } Tensor AmpGen::operator/( const Tensor& t1, const Expression& t2 ) { Tensor result( t1.dims() ); - for (size_t i = 0; i < t1.nElements(); ++i ) result[i] = t1[i] / t2; + for (unsigned i = 0; i < t1.nElements(); ++i ) result[i] = t1[i] / t2; return result; } @@ -240,7 +222,7 @@ Tensor AmpGen::operator/( const Tensor& t1, const Expression& t2 ) Tensor AmpGen::operator*( const Expression& other, const Tensor& t1 ) { Tensor result( t1.dims() ); - for (size_t i = 0; i < t1.nElements(); ++i ) result[i] = t1[i] * other; + for (unsigned i = 0; i < t1.nElements(); ++i ) result[i] = t1[i] * other; return result; } @@ -381,10 +363,10 @@ TensorProxy Tensor::operator()( const Tensor::Index& a, const Tensor::Index& b, return TensorProxy( *this, {a, b, c, d} ); } struct contractor { - size_t i; - size_t j; + unsigned i; + unsigned j; int sgn; - contractor( const size_t& i, const size_t&j, const int& sgn) : i(i),j(j),sgn(sgn) {} + contractor( const unsigned& i, const unsigned&j, const int& sgn) : i(i),j(j),sgn(sgn) {} }; @@ -396,23 +378,23 @@ TensorProxy AmpGen::operator*( const TensorProxy& t1, const TensorProxy& t2 ) const std::vector& t1_index = t1.indices(); const std::vector& t2_index = t2.indices(); - const size_t t1_size = t1.indices().size(); - const size_t t2_size = t2.indices().size(); + const unsigned t1_size = t1.indices().size(); + const unsigned t2_size = t2.indices().size(); const Tensor& t1_tensor = t1.tensor(); const Tensor& t2_tensor = t2.tensor(); - std::vector finalTensorRank; - std::vector contractionMatrix; + std::vector finalTensorRank; + std::vector contractionMatrix; - for( size_t i = 0; i < t1_size; ++i ) + for( unsigned i = 0; i < t1_size; ++i ) { if ( std::find( t2_index.begin(), t2_index.end(), t1.indices()[i] ) == t2_index.end() ) { unsummedIndices.push_back( t1.indices()[i] ); finalTensorRank.push_back( t1_tensor.dims()[i] ); } } - for( size_t i = 0; i < t2_size; ++i ) { + for( unsigned i = 0; i < t2_size; ++i ) { auto it = std::find( t1_index.begin(), t1_index.end(), t2_index[i] ); if ( it == t1_index.end() ) { unsummedIndices.push_back( t2.indices()[i] ); @@ -423,26 +405,23 @@ TensorProxy AmpGen::operator*( const TensorProxy& t1, const TensorProxy& t2 ) t2_index[i].isUpper() != it->isUpper() ? -1 : 1 ); } } - size_t nElementsInSum = 1; + unsigned nElementsInSum = 1; for ( auto& c : contractions ){ contractionMatrix.push_back( t1_tensor.dims()[c.i] ); nElementsInSum *= t1_tensor.dims()[c.i]; } Tensor value( finalTensorRank ); - size_t nElem = value.nElements(); - DEBUG("Got " << t1_tensor.dims().size() << " x " << t2_tensor.dims().size() << " with " << contractions.size() << " contractions " << nElementsInSum); - DEBUG(t1_tensor.dimString() << " x " << t2_tensor.dimString() << " -> " << value.dimString()); - DEBUG("Contraction matrix = " << "[" << vectorToString(contractionMatrix, ", ") << "]"); + unsigned nElem = value.nElements(); - for( size_t elem = 0; elem < nElem; ++elem ) { + for( unsigned elem = 0; elem < nElem; ++elem ) { auto coords = Tensor::index_to_coordinates( elem, finalTensorRank ); - std::vector t1_coords( t1_size, 0 ); - std::vector t2_coords( t2_size, 0 ); - size_t i = 0; - size_t j = 0; + std::vector t1_coords( t1_size, 0 ); + std::vector t2_coords( t2_size, 0 ); + unsigned i = 0; + unsigned j = 0; do { - if( !isIn(contractions, i, [](const contractor& a, const size_t& b){ return a.i == b;})) { + if( std::none_of( contractions.begin(), contractions.end(), [&i](const auto& a){ return a.i == i ;} )){ t1_coords[i] = coords[j]; j++; } @@ -450,20 +429,19 @@ TensorProxy AmpGen::operator*( const TensorProxy& t1, const TensorProxy& t2 ) i = 0; j = t1_size - contractions.size(); do { - if( !isIn(contractions, i, [](const contractor& a, const size_t& b){ return a.j == b;})) { + if( std::none_of( contractions.begin(), contractions.end(), [&i](const auto& a){ return a.j == i ;} )){ t2_coords[i] = coords[j]; j++; } } while ( ++i < t2_size ); Expression elementExpression = 0; - for( unsigned int i=0; i( t1_coords.size(), 0 ); + auto t2_coords = std::vector( t1_coords.size(), 0 ); for( unsigned int j=0;j indexB ) std::swap( indexA, indexB ); - std::map< size_t, size_t > counter; - for( size_t i = 0 ; i < m_symmetrisedCoordinates.size(); ++i ){ + std::map< unsigned, unsigned > counter; + for( unsigned i = 0 ; i < m_symmetrisedCoordinates.size(); ++i ){ auto coordinates = Tensor::index_to_coordinates( i, m_dim ); /// raw coordinates of this /// if( coordinates[indexB] > coordinates[indexA] ) std::swap( coordinates[indexA], coordinates[indexB] ); @@ -548,21 +526,21 @@ void Tensor::imposeSymmetry( size_t indexA, size_t indexB) DEBUG("Imposing symmetries on " << indexA << " <--> " << indexB << " reduces size to: " << counter.size()); } -void Tensor::imposeSymmetry( std::vector indices ) +void Tensor::imposeSymmetry( std::vector indices ) { std::sort( indices.begin(), indices.end() ); - for( size_t i=0;i& co ) { return m_elements[symmetrisedIndex(co)]; } -const Expression& Tensor::operator[]( const size_t& i ) const { return m_elements[m_symmetrisedCoordinates[i]]; } -const Expression& Tensor::operator[]( const std::vector& co ) const { return m_elements[symmetrisedIndex(co)]; } +Expression& Tensor::operator[]( const unsigned& i ) { return m_elements[m_symmetrisedCoordinates[i]]; } +Expression& Tensor::operator[]( const std::vector& co ) { return m_elements[symmetrisedIndex(co)]; } +const Expression& Tensor::operator[]( const unsigned& i ) const { return m_elements[m_symmetrisedCoordinates[i]]; } +const Expression& Tensor::operator[]( const std::vector& co ) const { return m_elements[symmetrisedIndex(co)]; } TensorProxy::TensorProxy(const Tensor& tensor, const std::vector& indices) @@ -574,9 +552,9 @@ TensorProxy::TensorProxy(const Tensor& tensor, } m_indices = indices; std::vector contractions; - std::vector rt_dim; - for( size_t i = 0 ; i < indices.size(); ++i ){ - size_t j = i + 1; + std::vector rt_dim; + for( unsigned i = 0 ; i < indices.size(); ++i ){ + unsigned j = i + 1; for( ; j < indices.size(); ++j ){ if( indices[i] != indices[j] ) continue; ERROR("Tensor self-contractions not implemented yet!"); @@ -594,53 +572,52 @@ TensorProxy::TensorProxy(const Tensor& tensor, TensorProxy TensorProxy::reorder( const std::vector& indices ) { - std::vector mapping( m_indices.size() ,0 ); - for(size_t j= 0; j < indices.size(); ++j) + std::vector mapping( m_indices.size() ,0 ); + for(unsigned j= 0; j < indices.size(); ++j) { - for(size_t i = 0; i < m_indices.size(); ++i) + for(unsigned i = 0; i < m_indices.size(); ++i) { if( m_indices[j] == indices[i] ) mapping[j] = i; } } Tensor reordered( m_tensor.dims() ); - for(size_t i = 0 ; i < m_tensor.size(); ++i) + for(unsigned i = 0 ; i < m_tensor.size(); ++i) { auto coordinates = Tensor::index_to_coordinates(i,m_tensor.dims() ); - std::vector new_coordinates( m_indices.size() ); - for(size_t z = 0 ; z < m_indices.size(); ++z ) + std::vector new_coordinates( m_indices.size() ); + for(unsigned z = 0 ; z < m_indices.size(); ++z ) new_coordinates[z] = coordinates[mapping[z]]; reordered[ i ] = m_tensor[ new_coordinates ]; } return TensorProxy( reordered, indices ); } -Tensor AmpGen::Identity( const size_t& rank ) +Tensor AmpGen::Identity( const unsigned& rank ) { - Tensor id( std::vector( {rank, rank} ) ); - for (size_t i = 0; i < rank; ++i) id(i, i) = 1; + Tensor id( std::vector( {rank, rank} ) ); + for (unsigned i = 0; i < rank; ++i) id(i, i) = 1; return id; } -const Tensor AmpGen::LeviCivita( const size_t& rank ) +const Tensor AmpGen::LeviCivita( const unsigned& rank ) { - std::vector dim( rank, rank ); - std::vector indices( rank ); + std::vector dim( rank, rank ); + std::vector indices( rank ); std::iota( indices.begin(), indices.end(), 0 ); - auto permutation_sign = []( const std::vector& permutation){ + auto permutation_sign = []( const std::vector& permutation){ int product = 1; - for ( size_t i = 0; i < permutation.size() - 1; ++i ) { - for ( size_t j = i + 1; j < permutation.size(); ++j ) { + for ( unsigned i = 0; i < permutation.size() - 1; ++i ) { + for ( unsigned j = i + 1; j < permutation.size(); ++j ) { product *= ( (int)permutation[i] - (int)permutation[j] ); } } return product; }; int p0 = permutation_sign( indices ); - Tensor result( dim ); /// create tensor of rank N /// do { - size_t index = result.index( indices ); + unsigned index = result.index( indices ); result[index] = permutation_sign( indices ) / p0; } while ( std::next_permutation( indices.begin(), indices.end() ) ); return result; @@ -658,8 +635,8 @@ TensorExpression::TensorExpression( const Tensor& tensor ) : std::string TensorExpression::to_string(const ASTResolver* resolver) const { return m_tensor.to_string(resolver); } -void TensorExpression::resolve( ASTResolver& resolver ){ - for( size_t i = 0 ; i < m_tensor.size(); ++i ) m_tensor[i].resolve( resolver ); +void TensorExpression::resolve( ASTResolver& resolver ) const { + for( unsigned i = 0 ; i < m_tensor.size(); ++i ) m_tensor[i].resolve( resolver ); } complex_t TensorExpression::operator()() const { return 0 ; } diff --git a/src/ThreadPool.cpp b/src/ThreadPool.cpp index 05fa274eb37..b0489cf116c 100644 --- a/src/ThreadPool.cpp +++ b/src/ThreadPool.cpp @@ -6,10 +6,7 @@ using namespace AmpGen; -ThreadPool* ThreadPool::gThreadPool = nullptr; -size_t ThreadPool::nThreads = 10; - -ThreadPool::ThreadPool(const size_t& nt) : m_stop(false) +ThreadPool::ThreadPool(const size_t& nt) { for ( size_t i = 0; i < nt; ++i ) m_workers.emplace_back( [this] { diff --git a/src/ThreeBodyCalculators.cpp b/src/ThreeBodyCalculators.cpp index d099bb7c5ef..20c9eb69447 100644 --- a/src/ThreeBodyCalculators.cpp +++ b/src/ThreeBodyCalculators.cpp @@ -44,14 +44,9 @@ using namespace AmpGen; template double dispersive( FCN& fcn , const double& s, double min , double max ) { TF1 fcn_tf1 = TF1( "fcn_tf1",fcn, min, max, 0 ); - ROOT::Math::WrappedTF1* wf1 = new ROOT::Math::WrappedTF1( fcn_tf1 ); - ROOT::Math::GSLIntegrator ig( ROOT::Math::IntegrationOneDim::kADAPTIVE ); - ROOT::Math::IGenFunction& stupid = *( wf1->Clone() ); - ig.SetFunction( stupid ); - ig.SetRelTolerance( 0.001 ); - double rt = ig.IntegralCauchy(stupid,min,max,s); - delete wf1; - return rt; + ROOT::Math::GSLIntegrator ig(ROOT::Math::IntegrationOneDim::kADAPTIVE, 0.0001); + ig.SetFunction( ROOT::Math::WrappedTF1(fcn_tf1) ); + return ig.IntegralCauchy(min,max,s); } TGraph* ThreeBodyCalculator::runningMass( @@ -141,18 +136,18 @@ double ThreeBodyCalculator::PartialWidth::getWidth( const double& s ) } Expression ThreeBodyCalculator::PartialWidth::spinAverageMatrixElement( - const std::vector>& elements, DebugSymbols* msym ) + const std::vector>& elements, DebugSymbols* msym ) { std::vector currents; - for ( auto& element : elements ) { - Particle particle(element.decayDescriptor(), type.finalStates() ); + for ( auto& [s, c] : elements ) { + Particle particle(s.decayDescriptor(), type.finalStates() ); auto perm = particle.identicalDaughterOrderings(); for ( auto& p : perm ) { particle.setOrdering(p); particle.setLineshape( "FormFactor" ); - Expression prop = make_cse( element.coupling.to_expression() ) * make_cse( particle.propagator( msym ) ); - if ( msym != nullptr ) msym->emplace_back( element.decayTree.name() + "_g", element.coupling.to_expression() ); - if ( msym != nullptr ) msym->emplace_back( element.decayTree.name() + "_p", particle.propagator() ); + Expression prop = make_cse( c.to_expression() ) * make_cse( particle.propagator( msym ) ); + if ( msym != nullptr ) msym->emplace_back( s.name() + "_g", c.to_expression() ); + if ( msym != nullptr ) msym->emplace_back( s.name() + "_p", particle.propagator() ); Tensor zt = particle.spinTensor(msym); zt.st() ; currents.push_back( zt * prop ); @@ -169,6 +164,7 @@ Expression ThreeBodyCalculator::PartialWidth::spinAverageMatrixElement( ThreeBodyCalculator::ThreeBodyCalculator( const std::string& head, MinuitParameterSet& mps, const size_t& nKnots, const double& min, const double& max) : m_min(min), m_max(max), + m_norm(1), m_nKnots(nKnots), m_name(head), m_mps(&mps) @@ -188,9 +184,6 @@ ThreeBodyCalculator::ThreeBodyCalculator( const std::string& head, MinuitParamet finalStates.push_back( type ); } for ( auto& type : finalStates ) m_widths.emplace_back( type, mps ); - - bool isReady = true; - for( auto& width : m_widths ) isReady &= width.totalWidth.isReady(); if( nKnots != 999) setAxis( nKnots, min, max ); } @@ -210,7 +203,7 @@ void ThreeBodyCalculator::updateRunningWidth( MinuitParameterSet& mps, const dou double s = m_min + double(c) * m_step; double I = getWidth(s); const std::string knotName = m_name + "::Spline::Gamma::" + std::to_string( c ); - if ( mps.map().find( knotName ) != mps.map().end() ) mps[knotName]->setCurrentFitVal( I ); + if ( mps.find( knotName ) != nullptr ) mps[knotName]->setCurrentFitVal( I ); INFO( knotName << " = " << I ); } } @@ -233,20 +226,23 @@ TGraph* ThreeBodyCalculator::widthGraph( const double& mNorm ) return g; } -ThreeBodyCalculator::PartialWidth::PartialWidth( const EventType& evt, MinuitParameterSet& mps ) : - fcs( evt, mps, "" ) - , integrator(1, evt.mass(0)*evt.mass(0), evt.mass(1)*evt.mass(1) , evt.mass(2)*evt.mass(2) ) - , type(evt) +ThreeBodyCalculator::PartialWidth::PartialWidth( const EventType& evt, MinuitParameterSet& mps ) + : fcs( evt, mps, "" ) + , integrator(1, evt.mass(0)*evt.mass(0), evt.mass(1)*evt.mass(1) , evt.mass(2)*evt.mass(2) ) + , type(evt) { DebugSymbols msym; - Expression matrixElementTotal = spinAverageMatrixElement( fcs.matrixElements(), &msym ); + std::vector> unpacked; + for( auto& p : fcs.matrixElements() ) unpacked.emplace_back( p.decayTree, p.coupling ); + + Expression matrixElementTotal = spinAverageMatrixElement(unpacked, &msym ); std::string name = ""; auto evtFormat = evt.getEventFormat(); - for ( auto& p : fcs.matrixElements() ) { - name += p.decayDescriptor(); - partialWidths.emplace_back( spinAverageMatrixElement( {p}, &msym ), p.decayDescriptor(), evtFormat, DebugSymbols(), &mps ); + for ( auto& p : unpacked ) { + name += p.first.decayDescriptor(); + partialWidths.emplace_back( spinAverageMatrixElement( {p}, &msym ), p.first.decayDescriptor(), &mps, evtFormat); } - totalWidth = CompiledExpression< std::complex, const real_t*, const real_t* > ( matrixElementTotal, "width", evtFormat, {} , &mps ); + totalWidth = CompiledExpression< complex_t(const real_t*, const real_t*) > ( matrixElementTotal, "width", &mps, evtFormat); CompilerWrapper(true).compile( totalWidth, ""); } @@ -271,16 +267,13 @@ void ThreeBodyCalculator::makePlots(const double& mass, const size_t& x, const s { auto& sq = m_widths[0].integrator; auto& evtType = m_widths[0].type; - if( mass != -1 ) evtType.setMotherMass( mass ); auto& fcs = m_widths[0].totalWidth; auto projection_operators = evtType.defaultProjections( 500 ); int points = NamedParameter( "nPoints", 50000000 ); sq.setMother( evtType.motherMass() ); prepare(); auto fcn = [&](const double* evt) { return std::real(fcs(evt)); }; - sq.makePlot( fcn, Projection2D( projection_operators[x], projection_operators[y] ), "s01_vs_s02", points )->Write(); - } void ThreeBodyCalculator::debug( const double& m, const double& theta ) @@ -290,7 +283,7 @@ void ThreeBodyCalculator::debug( const double& m, const double& theta ) Event event(12); width.integrator.setEvent({m,theta},event); event.print(); - width.totalWidth.debug( event ); + width.totalWidth.debug( event.address() ); } } diff --git a/src/Transform.cpp b/src/Transform.cpp index c001be7ce19..812a6bef05e 100644 --- a/src/Transform.cpp +++ b/src/Transform.cpp @@ -29,11 +29,10 @@ Tensor Transform::sigma_dot_p(const Tensor& p) const Tensor Transform::J_dot_p( const Tensor& p ) const { Expression z(0); - return Tensor( - { z, -p[2], p[1] ,z - , p[2], z, -p[0] ,z - ,-p[1], p[0], z ,z - , z, z, z ,z }, Tensor::dim(4,4) ); + return Tensor( { z, -p[2], p[1] ,z + , p[2], z, -p[0] ,z + ,-p[1], p[0], z ,z + , z, z, z ,z }, Tensor::dim(4,4) ); } Tensor Transform::K_dot_p( const Tensor& p ) const @@ -65,7 +64,7 @@ Tensor Transform::boost_spinor() const return Identity(2) * fcn::sqrt(0.5*(m_arg+1)) + sigma_dot_p(m_k)*fcn::sqrt(0.5*(m_arg-1)); } -Tensor Transform::operator()(const Representation& repr) const +Tensor Transform::operator()(const Representation& repr)const { Tensor::Index m,j,k; Tensor I2 = Identity(2); @@ -97,31 +96,40 @@ Tensor Transform::operator()(const Representation& repr) const return Tensor(); } -TransformSequence TransformSequence::inverse() const +TransformSequence TransformSequence::inverse() const { TransformSequence rt; for( auto i = m_transforms.rbegin(); i != m_transforms.rend(); ++i ) - rt.add( i->inverse() ); + rt.push_back( i->inverse() ); return rt; } -Tensor TransformSequence::operator()( const Transform::Representation& repr ) const +Tensor TransformSequence::operator()( const Transform::Representation& repr ) const { - if( m_transforms.size() == 0 ){ - if( repr == Transform::Representation::Spinor ) return Identity(2); - else return Identity(4); - } - Tensor::Index a,b,c; + return m_cache[repr]; +} - Tensor rt = m_transforms[0](repr); - rt.st(); - for( size_t i = 1 ; i < m_transforms.size(); ++i ) +void TransformSequence::buildCache() +{ + for( auto repr : { Transform::Representation::Spinor, Transform::Representation::Bispinor, Transform::Representation::Vector } ) { - Tensor rti = m_transforms[i](repr); - rti.st(); - rt = rti(a,b) * rt(b,c); + if( m_transforms.size() == 0 ){ + if( repr == Transform::Representation::Spinor ) m_cache[repr] = Identity(2); + m_cache[repr] = Identity(4); + } + else { + Tensor::Index a,b,c; + Tensor rt = m_transforms[0](repr); + rt.st(); + for( size_t i = 1 ; i < m_transforms.size(); ++i ) + { + Tensor rti = m_transforms[i](repr); + rti.st(true); + rt = rti(a,b) * rt(b,c); + } + m_cache[repr] = rt; + } } - return rt; } Tensor TransformSequence::operator()( const Tensor& tensor, @@ -140,19 +148,22 @@ Tensor Transform::operator()( const Tensor& tensor, return seq(a,b)*tensor(b); } -void TransformSequence::add( const Transform& transform ) +void TransformSequence::push_back( const Transform& transform ) { m_transforms.emplace_back( transform ); + buildCache(); } -void TransformSequence::add( const TransformSequence& transform ) +void TransformSequence::push_back( const TransformSequence& transform ) { for( auto& t : transform ) m_transforms.emplace_back(t); + buildCache(); } void TransformSequence::clear() { m_transforms.clear(); + buildCache(); } void TransformSequence::stepThrough(const Tensor& tensor, @@ -167,4 +178,38 @@ void TransformSequence::stepThrough(const Tensor& tensor, } } +TransformSequence::TransformSequence( const Transform& transform ) : m_transforms{transform} { + buildCache(); +} + +TransformSequence::TransformSequence( const TransformSequence& t1, const TransformSequence& t2) { + for( const auto& t : t1 ) m_transforms.push_back(t); + for( const auto& t : t2 ) m_transforms.push_back(t); + Tensor::Index a,b,c; + + for( auto repr : { Transform::Representation::Spinor, Transform::Representation::Bispinor, Transform::Representation::Vector } ) + { + auto r1 = t1( repr ); + auto r2 = t2( repr ); + m_cache[repr] = r2(a,b) * r1(b,c); + m_cache[repr].st(); + } +} + +TransformSequence::TransformSequence( const Transform& t1, const Transform& t2) : m_transforms{t1,t2} { + Tensor::Index a,b,c; + + for( auto repr : { Transform::Representation::Spinor, Transform::Representation::Bispinor, Transform::Representation::Vector } ) + { + auto r1 = t1(repr); + auto r2 = t2(repr); + m_cache[repr] = r2(a,b) * r1(b,c); + m_cache[repr].st(); + } +} + +TransformSequence::TransformSequence() +{ + buildCache(); +} diff --git a/src/TreePhaseSpace.cpp b/src/TreePhaseSpace.cpp new file mode 100644 index 00000000000..09cc1266705 --- /dev/null +++ b/src/TreePhaseSpace.cpp @@ -0,0 +1,294 @@ +#include "AmpGen/TreePhaseSpace.h" +#include "AmpGen/MsgService.h" +#include "AmpGen/ParticleProperties.h" +#include "AmpGen/Utilities.h" +#include "TRandom.h" +#include "TRandom3.h" +#include +#include + +using namespace AmpGen; + +TreePhaseSpace::TreePhaseSpace(const Particle& decayChain, const EventType& type, TRandom* rndm) : + m_rand(rndm == nullptr ? (TRandom3*)gRandom : (TRandom3*)rndm), + m_type(type), + m_gen(1) +{ + auto orderings = decayChain.identicalDaughterOrderings(); + for( auto& ordering : orderings ) + { + Particle p = decayChain; + p.setOrdering(ordering); + m_top.push_back( Vertex::make( p) ); + m_weights.push_back(1); + } + m_dice = std::discrete_distribution<>(m_weights.begin(), m_weights.end()); + setRandom(m_rand); +} + +TreePhaseSpace::TreePhaseSpace(const std::vector& decayChains, const EventType& type, TRandom* rndm) : + m_rand(rndm == nullptr ? (TRandom3*)gRandom : (TRandom3*)rndm), + m_type(type), + m_gen(1) +{ + for( auto& decayChain : decayChains ) + { + auto orderings = decayChain.identicalDaughterOrderings(); + for( auto& ordering : orderings ) + { + Particle p = decayChain; + p.setOrdering(ordering); + m_top.push_back( Vertex::make(p) ); + m_weights.push_back(1); + } + } + setRandom(rndm); + double sum_of_weights = std::accumulate( m_weights.begin(), m_weights.end(), 0 ); + for( auto& w : m_weights ) w /= sum_of_weights; + m_dice = std::discrete_distribution<>(m_weights.begin(), m_weights.end()); +} + +Event TreePhaseSpace::makeEvent() +{ + unsigned j = 0; + double w = 0; + Event event; + do { + j = m_dice(m_gen); + if( j >= m_top.size() ) ERROR("Out of bounds: " << j << " / " << m_top.size() ); + m_top[j].generate(); + w = m_top[j].weight(); + } while ( w == 0 ); + event = m_top[j].event(m_type.size()); + event.setGenPdf( genPdf(event) / w ); + m_generatorRecord.push_back(j); + return event; +} + +void TreePhaseSpace::provideEfficiencyReport(const std::vector& report) +{ +// if( report.size() != m_generatorRecord.size() ) +// { +// WARNING("Report does not match size of generator record..."); +// return; +// } +// std::vector counters( m_top.size() ); +// std::vector totals ( m_top.size() ); +// unsigned counter = 0; +// for( unsigned i = 0 ; i != report.size(); ++i ) +// { +// counters[m_generatorRecord[i]] += report[i]; +// totals[m_generatorRecord[i]] ++; +// counter += report[i]; +// } +// for( unsigned i = 0 ; i != m_top.size(); ++i ) +// { +// INFO( m_top[i].particle.decayDescriptor() << " " << counters[i] << " / " << totals[i] ); +// m_weights[i] = double( counters[i] ) / double( counter ); +// } +// m_dice = std::discrete_distribution<>(m_weights.begin(), m_weights.end()); +// m_generatorRecord.clear(); +} + +double rho( const double& s, const double& s1, const double& s2) +{ + return sqrt( 1 - 2 * (s1+s2)/s + (s1-s2)*(s1-s2) /(s*s) ); +} + +TreePhaseSpace::Vertex::Vertex(const Particle& particle, const double& mass) + : particle(particle) + , min(mass) + , max(mass) + , type( Type::Stable ) + , index(particle.index()) + , bwMass(particle.props()->mass()) + , bwWidth(particle.props()->width()) + , s(bwMass*bwMass) +{ + if( index != 999 ) indices = {index}; +} + + +TreePhaseSpace::Vertex::Vertex(const Particle& particle, const double& min, const double& max ) + : particle(particle) + , index(particle.index()) + , bwMass(particle.props()->mass()) + , bwWidth(particle.props()->width()) + , min(min) + , max(max) + , s(bwMass*bwMass) +{ + INFO( particle << " [" << min << ", " << max << "]"); + if( particle.isStable() ) type = Type::Stable; + else if( particle.isQuasiStable() ) type = Type::QuasiStable; + else if( particle.lineshape().find("BW") != std::string::npos ){ + type = Type::BW; + phiMin = atan((min*min - bwMass*bwMass)/(bwMass*bwWidth)); + phiMax = atan((max*max - bwMass*bwMass)/(bwMass*bwWidth)); + } + else type = Type::Flat; + if( index != 999 ) indices = {index}; +} + +double TreePhaseSpace::Vertex::p() const +{ + return 0.5 * sqrt( s - 2 * (left->s+right->s) + (left->s-right->s)*(left->s-right->s)/s ); +} + +double TreePhaseSpace::Vertex::weight() const +{ + if( left == nullptr || right == nullptr ) return 1.0; + double w = sqrt(s) - sqrt(left->s) - sqrt(right->s) > 0; + if( w == 0 ) return 0; + w *= rho(s, left->s, right->s); + w *= left -> weight(); + w *= right -> weight(); + return w; +} + +double TreePhaseSpace::Vertex::genPdf(const Event& event) const +{ + if( left == nullptr || right == nullptr ) return 1; + double dp = left->genPdf(event) * right->genPdf(event); + auto st = event.s(indices); + switch( type ) { + case Type::BW : + dp *= ( bwMass* bwWidth ) /( (phiMax-phiMin) * ( (st - bwMass*bwMass)*(st-bwMass*bwMass) + bwMass*bwMass*bwWidth*bwWidth) ); + break; + case Type::Flat : + dp *= 1/(max*max -min*min); + break; + }; + return dp; +} + +void TreePhaseSpace::Vertex::generate() +{ + switch( type ) { + case Type::BW : + s = bwMass * bwMass + bwMass * bwWidth * tan( (phiMax - phiMin ) * rand->Rndm() + phiMin ); + break; + case Type::Flat : + s = (max*max-min*min)*rand->Rndm() + min; + break; + }; + if( left != nullptr ) left->generate(); + if( right != nullptr ) right->generate(); +} + +void TreePhaseSpace::Vertex::print(const unsigned& offset) const +{ + std::array vtxTypeStrings = {"BW", "Flat", "Stable", "QuasiStable"}; + INFO( std::string(offset,' ') << particle.name() << " [" << vectorToString(indices, ", ") << "] type = " << vtxTypeStrings[ type ] << " → [" << min << ", " << max << "] " << sqrt(s) ); + if( type == Type::BW ) + INFO( "phi-range : " << phiMin << " " << phiMax + << " s(min) = " << bwMass * bwMass + bwMass * bwWidth * tan(phiMin) + << " s(max) = " << bwMass * bwMass + bwMass * bwWidth * tan(phiMax) ); + if( left != nullptr ) left -> print( offset + 4 ); + if( right != nullptr ) right -> print( offset + 4 ); +} + +void TreePhaseSpace::Vertex::place(Event& event) +{ + if( index != 999 ){ + event[4*index+0] = mom[0]; + event[4*index+1] = mom[1]; + event[4*index+2] = mom[2]; + event[4*index+3] = mom[3]; + } + if( left != nullptr ) left->place(event); + if( right != nullptr ) right->place(event); +} + +Event TreePhaseSpace::Vertex::event(const unsigned& eventSize) +{ + if( isMultiBody ) return phsp.makeEvent(); + Event output(4 * eventSize); + mom.SetXYZT(0,0,0,sqrt(s)); + generateFullEvent(); + place(output); + return output; +} + +void TreePhaseSpace::Vertex::generateFullEvent() +{ + if( left == nullptr || right == nullptr ) return; + double cosTheta = 2 * rand->Rndm() - 1; + double sinTheta = sqrt( 1 - cosTheta * cosTheta ); + double angY = 2 * M_PI * rand->Rndm(); + double cosPhi = cos(angY); + double sinPhi = sin(angY); + double pf = p(); + if( std::isnan(pf) || std::isnan(s) ) + { + auto p2 = ( s - 2 * (left->s+right->s) + (left->s-right->s)*(left->s-right->s)/s ); + ERROR("Generating nan: " << pf << " " << s << " " << min << " " << max << " " << p2 << " " << left->s << " " << right->s << " w = " << weight() ); + } + left -> mom.SetXYZT( pf*sinTheta*cosPhi, pf*sinTheta*sinPhi, pf*cosTheta, sqrt(left->s + pf*pf) ); + left -> mom.Boost( mom.BoostVector() ); + left -> generateFullEvent(); + + right -> mom.SetXYZT( -pf*sinTheta*cosPhi, -pf*sinTheta*sinPhi, -pf*cosTheta, sqrt(right->s + pf*pf) ); + right -> mom.Boost( mom.BoostVector() ); + right -> generateFullEvent(); +} + +TreePhaseSpace::Vertex TreePhaseSpace::Vertex::make(const Particle& particle, TreePhaseSpace::Vertex* parent) +{ + auto decayProducts = particle.daughters(); + auto threshold = [](const Particle& particle) + { + auto d1 = particle.getFinalStateParticles(); + if( d1.size() == 0) return particle.mass(); + return std::accumulate(d1.begin(), d1.end(), 0., [](double acc, auto& p){ return acc + p->mass(); } ); + }; + if( decayProducts.size() == 1 ) return TreePhaseSpace::Vertex::make(*decayProducts[0], parent); + if( decayProducts.size() == 2 ) + { + double G = particle.isQuasiStable() ? 0 : particle.props()->width() * 10; + TreePhaseSpace::Vertex vtx = (parent == nullptr) ? TreePhaseSpace::Vertex(particle, particle.mass() - G , particle.mass() + G) : TreePhaseSpace::Vertex(); + parent = ( parent == nullptr ) ? &vtx : parent; + auto min_mass_1 = threshold(*decayProducts[0]); + auto min_mass_2 = threshold(*decayProducts[1]); + parent->left = std::make_shared(*decayProducts[0], min_mass_1, parent->max - min_mass_2); + parent->right = std::make_shared(*decayProducts[1], min_mass_2, parent->max - min_mass_1); + TreePhaseSpace::Vertex::make(*decayProducts[0], parent->left.get()); + TreePhaseSpace::Vertex::make(*decayProducts[1], parent->right.get()); + for( auto& index : parent->left ->indices ) parent->indices.push_back(index); + for( auto& index : parent->right->indices ) parent->indices.push_back(index); + return *parent; + } + return TreePhaseSpace::Vertex(); +} + +void TreePhaseSpace::setRandom( TRandom* rand ) +{ + m_rand = (TRandom3*)rand; + for( auto& channel : m_top ) channel.setRandom((TRandom3*)rand); +} + +void TreePhaseSpace::Vertex::setRandom( TRandom3* rnd ) +{ + rand = rnd; + if( left != nullptr ) left->setRandom(rnd); + if( right != nullptr ) right->setRandom(rnd); +} + +EventType TreePhaseSpace::eventType() const +{ + return m_type; +} + +double TreePhaseSpace::genPdf(const Event& event) const +{ + double genPdf = 0; + for( unsigned i = 0; i != m_top.size(); ++i ) + genPdf += m_weights[i] * m_top[i].genPdf(event); + return genPdf; +} + +size_t TreePhaseSpace::size() const +{ + return m_top.size(); +} + diff --git a/src/TreeReader.cpp b/src/TreeReader.cpp new file mode 100644 index 00000000000..42ec42513ae --- /dev/null +++ b/src/TreeReader.cpp @@ -0,0 +1,34 @@ +#include "AmpGen/TreeReader.h" +using namespace AmpGen; + +TreeReader::TreeReader( TTree* tree ) : m_tree( tree ) {} + +void TreeReader::setEntryList( const std::vector& entryList ){ m_entryList = entryList ; } + +void TreeReader::unsetEntryList(){ m_entryList.clear() ; } + +void TreeReader::getEntry( const unsigned int& entry ) +{ + if(!m_ready ) prepare(); + m_tree->GetEntry( m_entryList.size() == 0 ? entry : m_entryList[entry] ); + for ( auto& branch : m_branches ) branch->transfer(); +} + +void TreeReader::prepare() +{ + for ( auto& branch : m_branches ) { + m_tree->SetBranchStatus( branch->name.c_str(), "1" ); + m_tree->SetBranchAddress( branch->name.c_str(), branch->address() ); + } + m_ready = true; +} + +size_t TreeReader::nEntries() const { return m_entryList.size() == 0 ? m_tree->GetEntries() : m_entryList.size(); } + +TreeReader::~TreeReader() +{ + for ( auto& branch : m_branches ) delete branch; +} + +TreeReader::Iterator TreeReader::begin() { getEntry(0); return Iterator( 0, this ); } +TreeReader::Iterator TreeReader::end() { return Iterator( nEntries(), this ); } diff --git a/src/UnaryExpression.cpp b/src/UnaryExpression.cpp index 705b50a16e8..94b0d0db346 100644 --- a/src/UnaryExpression.cpp +++ b/src/UnaryExpression.cpp @@ -7,6 +7,7 @@ #include "AmpGen/Expression.h" #include "AmpGen/NamedParameter.h" #include "AmpGen/Types.h" +#include "AmpGen/ASTResolver.h" using namespace AmpGen; @@ -16,28 +17,18 @@ T rsqrt( const T& arg ){ return 1. / sqrt(arg) ; } DEFINE_UNARY_OPERATOR( Log , log ) DEFINE_UNARY_OPERATOR( Sqrt, sqrt ) DEFINE_UNARY_OPERATOR( Exp , exp ) -DEFINE_UNARY_OPERATOR( Abs , abs ) DEFINE_UNARY_OPERATOR( Sin , sin ) DEFINE_UNARY_OPERATOR( Cos , cos ) DEFINE_UNARY_OPERATOR( Tan , tan ) DEFINE_UNARY_OPERATOR( ASin, asin ) DEFINE_UNARY_OPERATOR( ACos, acos ) DEFINE_UNARY_OPERATOR( ATan, atan ) -DEFINE_UNARY_OPERATOR( Norm, std::norm ) -DEFINE_UNARY_OPERATOR( Conj, std::conj ) -DEFINE_UNARY_OPERATOR( Real, std::real ) -DEFINE_UNARY_OPERATOR( Imag, std::imag ) -//DEFINE_UNARY_OPERATOR( LGamma, std::lgamma ); - //DEFINE_UNARY_OPERATOR( ISqrt, rsqrt ) - -ISqrt::ISqrt( const Expression& expression) : IUnaryExpression(expression) {} -ISqrt::operator Expression() const { return Expression( std::make_shared(*this) ) ; } -complex_t ISqrt::operator()() const { return 1./sqrt( m_expression() ); } -std::string ISqrt::to_string(const ASTResolver* resolver) const { - return NamedParameter("enable_cuda",false) ? - "rsqrt("+m_expression.to_string(resolver)+")" : - "1./sqrt("+m_expression.to_string(resolver)+")" ; -} +DEFINE_UNARY_OPERATOR_NO_RESOLVER( Norm, std::norm ) +DEFINE_UNARY_OPERATOR_NO_RESOLVER( Real, std::real ) +DEFINE_UNARY_OPERATOR_NO_RESOLVER( Imag, std::imag ) +DEFINE_UNARY_OPERATOR_NO_RESOLVER( ISqrt, rsqrt ) +DEFINE_UNARY_OPERATOR_NO_RESOLVER( Conj, std::conj ) +DEFINE_UNARY_OPERATOR_NO_RESOLVER( Abs , std::abs ) LGamma::LGamma( const Expression& expression) : IUnaryExpression(expression) {} LGamma::operator Expression() const { return Expression( std::make_shared(*this) ) ; } @@ -46,6 +37,48 @@ std::string LGamma::to_string(const ASTResolver* resolver) const { return "std::lgamma(" + m_expression.to_string(resolver) + ")"; } +std::string ISqrt::to_string(const ASTResolver* resolver) const { + return resolver != nullptr && resolver->enableCuda() ? + "rsqrt("+m_expression.to_string(resolver)+")" : + "1./sqrt("+m_expression.to_string(resolver)+")" ; +} + +std::string Abs::to_string( const ASTResolver* resolver ) const +{ + return resolver != nullptr && resolver->enableAVX() ? + "abs(" + m_expression.to_string(resolver) +")" : + "std::abs("+m_expression.to_string(resolver) +")"; +} + +std::string Conj::to_string( const ASTResolver* resolver ) const +{ + return resolver != nullptr && resolver->enableAVX() ? + "conj(" + m_expression.to_string(resolver) +")" : + "std::conj("+m_expression.to_string(resolver) +")"; +} + +std::string Norm::to_string( const ASTResolver* resolver ) const +{ + return resolver != nullptr && resolver->enableAVX() ? + "norm(" + m_expression.to_string(resolver) +")" : + "std::norm("+m_expression.to_string(resolver) +")"; +} + +std::string Real::to_string( const ASTResolver* resolver ) const +{ + return resolver != nullptr && resolver->enableAVX() ? + "real(" + m_expression.to_string(resolver) +")" : + "std::real("+m_expression.to_string(resolver) +")"; +} + +std::string Imag::to_string( const ASTResolver* resolver ) const +{ + return resolver != nullptr && resolver->enableAVX() ? + "imag(" + m_expression.to_string(resolver) +")" : + "std::imag("+m_expression.to_string(resolver) +")"; +} + + Expression Log::d() const { return 1. / arg(); } Expression Sqrt::d() const { return 1. / ( 2 * fcn::sqrt( arg() ) ); } Expression Exp::d() const { return fcn::exp(arg()) ; } @@ -66,4 +99,4 @@ Expression Norm::d() const { return 0;} Expression Real::d() const { return 0;} Expression Imag::d() const { return 0;} Expression LGamma::d() const { return 0;} -void IUnaryExpression::resolve( ASTResolver& resolver ) { m_expression.resolve( resolver ); } +void IUnaryExpression::resolve( ASTResolver& resolver ) const { m_expression.resolve( resolver ); } diff --git a/src/Units.cpp b/src/Units.cpp new file mode 100644 index 00000000000..a252032892c --- /dev/null +++ b/src/Units.cpp @@ -0,0 +1,13 @@ + +#include "AmpGen/Units.h" +#include "AmpGen/Utilities.h" + +namespace AmpGen { + complete_enum(Units, TeV, GeV, MeV, KeV, eV, ms, us, ns, ps, fs) +} + +double AmpGen::to_double(const AmpGen::Units& unit) +{ + static const double value_table[10] = {TeV, GeV, MeV, KeV, eV, ms, us, ns, ps, fs}; + return value_table[unsigned(unit)]; +} diff --git a/src/Utilities.cpp b/src/Utilities.cpp index 8fe89b8f0a3..7f29e030160 100644 --- a/src/Utilities.cpp +++ b/src/Utilities.cpp @@ -1,5 +1,5 @@ #include "AmpGen/Utilities.h" -#include "AmpGen/Version.h" +#include "AmpGenVersion.h" #include #include #include @@ -11,19 +11,13 @@ #include #include #include - +#include #include "AmpGen/MsgService.h" std::vector AmpGen::vectorFromFile( const std::string& filename, const char ignoreLinesThatBeginWith ) { std::vector output; - std::string tmp; - std::ifstream inFile( filename.c_str() ); - while ( inFile.good() ) { - std::getline( inFile, tmp ); - if ( tmp.size() == 0 || tmp[0] == ignoreLinesThatBeginWith ) continue; - output.push_back( tmp ); - } + processFile( filename, [&output](const std::string& line) mutable -> void {output.push_back(line);} ); return output; } @@ -42,11 +36,8 @@ std::vector AmpGen::split( const std::string& s, const std::vector< { std::vector elems; std::stringstream ss( s ); - std::string strDelim = ""; + std::string strDelim = std::accumulate( delims.begin(), delims.end(), std::string("") ); std::string line; - - for ( auto& st : delims ) strDelim += st; - while ( std::getline( ss, line ) ) { std::size_t prev = 0, pos; while ( ( pos = line.find_first_of( strDelim, prev ) ) != std::string::npos ) { @@ -111,17 +102,24 @@ std::string AmpGen::replaceAll( const std::string& input, const std::string& toR return output; } +std::string AmpGen::replaceAll( const std::string& input, const std::vector>& rules ) +{ + std::string output = input; + for( auto& rule : rules ) output = replaceAll(output, rule.first, rule.second); + return output; +} + // extracts tree structures of the form X{Y,Z,A} // where Y and Z and A are also tree elements, by finding // the matching delimiter and the Z, A elements. -std::vector AmpGen::getItems( const std::string& tree, const std::vector& brackets, - const std::string& seperator ) +std::vector AmpGen::getItems( const std::string& tree, + const std::vector& brackets, + const std::string& seperator ) { auto braces = vecFindAll( tree, brackets ); /// get a vector of positions of the brackets /// if ( braces.size() % 2 != 0 ) { ERROR( "Unmatched braces in expression: " << tree << " check string: " << braces.size() ); - for ( auto& x : braces ) INFO( "char[" << x.first << "] = " << x.second ); return std::vector(); } @@ -145,11 +143,11 @@ std::vector AmpGen::getItems( const std::string& tree, const std::v std::vector daughterTrees; size_t begin_position = matched_braces.begin()->first + 1; for ( auto& comma : commas ) { - auto braces = matched_braces.begin() + 1; - for ( ; braces != matched_braces.end(); ++braces ) { - if ( comma > braces->first && comma < braces->second ) break; + auto itBrace = matched_braces.begin() + 1; + for ( ; itBrace != matched_braces.end(); ++itBrace ) { + if ( comma > itBrace->first && comma < itBrace->second ) break; } - if ( braces == matched_braces.end() ) { + if ( itBrace == matched_braces.end() ) { items.push_back( tree.substr( begin_position, comma - begin_position ) ); begin_position = comma + 1; } @@ -186,8 +184,13 @@ unsigned int AmpGen::editDistance( const std::string& s1, const std::string& s2 std::string AmpGen::round( const double& number, const unsigned int& nsf ) { double value = std::round(number * pow(10, nsf)) / pow(10, nsf); - auto r = mysprintf( ( "%." + std::to_string(nsf) + "f" ).c_str(), value ); - return r.substr(0,r.size()-1); + if( nsf != 0 ){ + auto r = mysprintf( ( "%." + std::to_string(nsf) + "f" ).c_str(), value ); + return r.substr(0,r.size()-1); + } + else { + return std::to_string( (int)value); + } } std::string AmpGen::numberWithError( const double& number, const double& error, const unsigned int& nDigits ) @@ -200,20 +203,16 @@ bool AmpGen::stringMatchesWildcard( const std::string& input, const std::string& { auto pos = wildcard_string.find( wildcard_character ); /// TEST_foobar -> *_foobar if ( wildcard_string.size() == 1 && wildcard_string[0] == wildcard_character ) { - DEBUG( "Returning true" ); return true; } if ( pos == std::string::npos ) { - DEBUG( "Returning " << input << " = " << wildcard_string << " ?" ); return input == wildcard_string; } if ( pos == wildcard_string.size() - 1 ) { - DEBUG( "Returning " << input << " contains " << wildcard_string ); return input.find( wildcard_string.substr( 0, wildcard_string.size() - 1 ) ) == 0; } else { const std::string pattern1 = wildcard_string.substr( 0, pos + 1 ); const std::string pattern2 = wildcard_string.substr( pos + 1 ); - DEBUG( "Matching " << pattern1 << " to " << input ); bool match1 = stringMatchesWildcard( input, pattern1, wildcard_character ); if ( !match1 ) return false; auto pos2 = pattern2.find( wildcard_character ); @@ -271,7 +270,7 @@ void AmpGen::printSplash() std::cout << " ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝" << std::endl; std::cout << "\033[0m\n"; std::cout << bold_on << - " version " << AMPGEN_VERSION_MAJOR << "." << AMPGEN_VERSION_MINOR << std::endl; + " version " << AMPGEN_MAJOR_VERSION << "." << AMPGEN_MINOR_VERSION << std::endl; std::cout << " build: " ; #if defined(__clang__) std::cout << "clang " << __clang_major__ << "." << __clang_minor__ << "." << __clang_patchlevel__; @@ -282,10 +281,18 @@ void AmpGen::printSplash() #elif defined(__GNUC__) || defined(__GNUG__) std::cout << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__; #endif + #if ENABLE_AVX2d + std::cout << " (avx2; double)"; + #elif ENABLE_AVX2f + std::cout << " (avx2; single)"; + #elif ENABLE_AVX512 + std::cout << " (avx512; double)"; + #endif + std::cout << " " << __DATE__ << " " << __TIME__ << bold_off << "\n\n"; - - char* AmpGenRoot = getenv("AMPGENROOT"); - if( AmpGenRoot != nullptr ) printReleaseNotes( std::string(AmpGenRoot) + "/doc/release.notes"); + #ifdef AMPGENROOT_CMAKE + printReleaseNotes( std::string(AMPGENROOT_CMAKE) + "/release.notes"); + #endif } bool AmpGen::fileExists( const std::string& name ) @@ -301,7 +308,7 @@ std::string AmpGen::rtrim( std::string s ) } // trim from both ends -std::string AmpGen::trim( std::string s ) { return ltrim( rtrim( s ) ); } +std::string AmpGen::trim( const std::string& s ) { return ltrim( rtrim( s ) ); } std::string AmpGen::ltrim( std::string s ) { @@ -315,7 +322,7 @@ std::string AmpGen::expandGlobals( std::string path ) do { pos = path.find( "$" ); if ( pos == std::string::npos ) break; - size_t end_pos = std::string::npos; + size_t end_pos; // = std::string::npos; std::string variable_name; if ( path[pos + 1] == '{' ) { end_pos = path.find( "}", pos ); @@ -324,16 +331,20 @@ std::string AmpGen::expandGlobals( std::string path ) } else { end_pos = find_next_of( path, {".", "/"}, pos ); variable_name = path.substr( pos + 1, end_pos - pos - 1 ); + end_pos--; } const char* global_var = getenv( variable_name.c_str() ); - if ( global_var == nullptr ) { + if ( variable_name == "AMPGENROOT" && global_var == nullptr ) + { + global_var = AMPGENROOT; + } + else if ( global_var == nullptr ) { ERROR( "variable " << variable_name << " not found" ); break; } std::string old_path = path; size_t len = end_pos == std::string::npos ? path.length() - pos + 1 : end_pos - pos + 1; path = path.replace( pos, len, global_var ); - DEBUG( old_path << " -> " << path ); } while ( pos != std::string::npos ); return path; @@ -345,7 +356,7 @@ bool AmpGen::isDir( const std::string& pathname ) return stat( pathname.c_str(), &sb ) == 0 && S_ISDIR( sb.st_mode ); } -std::vector AmpGen::getListOfFiles( const std::string& directory, std::string patternString ) +std::vector AmpGen::getListOfFiles( const std::string& directory, const std::string& patternString ) { std::string expanded_path = expandGlobals( directory ); std::vector files; diff --git a/src/Vertex.cpp b/src/Vertex.cpp index e788a56402a..1385fa3cca8 100644 --- a/src/Vertex.cpp +++ b/src/Vertex.cpp @@ -12,14 +12,17 @@ #include "AmpGen/Units.h" using namespace AmpGen; -//using namespace AmpGen::Vertex; -const Tensor::Index mu = Tensor::Index(); -const Tensor::Index nu = Tensor::Index(); -const Tensor::Index alpha = Tensor::Index(); -const Tensor::Index beta = Tensor::Index(); +static const Tensor::Index mu = Tensor::Index(); +static const Tensor::Index nu = Tensor::Index(); +static const Tensor::Index alpha = Tensor::Index(); +static const Tensor::Index beta = Tensor::Index(); +static const Tensor::Index a = Tensor::Index(); +static const Tensor::Index b = Tensor::Index(); +static const Tensor::Index c = Tensor::Index(); +static const Tensor::Index d = Tensor::Index(); -template <> Factory* Factory::gImpl = nullptr; +template <> Factory* Factory::gImpl = nullptr; bool Vertex::Factory::isVertex( const std::string& hash ) { return get( hash ) != nullptr; } @@ -54,35 +57,40 @@ const Tensor Metric4x4(){ return Tensor( {-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1}, {4, 4} ); } -Tensor AmpGen::Orbital_PWave( const Tensor& P, const Tensor& Q ) +Tensor AmpGen::Orbital_PWave(const Tensor& p, const Tensor& q) { - auto is = 1./make_cse( dot(P,P) ,true); - return Q - P * make_cse( dot( P, Q ) * is ); + auto is = 1./make_cse( dot(p,p) ,true); + return q - p * make_cse( dot(p, q) * is ); } -Tensor AmpGen::Orbital_DWave( const Tensor& P, const Tensor& Q ) +Tensor AmpGen::Orbital_DWave(const Tensor& p, const Tensor& q) { - Tensor::Index mu; - Tensor::Index nu; - Tensor L = Orbital_PWave( P, Q ); - Tensor f = L(mu) * L(nu) - make_cse( dot( L, L ) / 3. ) * Spin1Projector(P) ( mu, nu ); + Tensor L = Orbital_PWave(p, q); + Tensor f = L(mu) * L(nu) - make_cse( dot( L, L ) / 3. ) * Spin1Projector(p) ( mu, nu ); f.imposeSymmetry(0,1); f.st(); return f; } +Tensor AmpGen::Orbital_FWave(const Tensor& p, const Tensor& q) +{ + Tensor L = Orbital_PWave(p, q); + Tensor f = L(mu) * L(nu) * L(alpha) - make_cse( dot( L, L ) / 5. ) * ( Spin1Projector(p) ( mu, nu ) * L(alpha) + Spin1Projector(p) ( mu, alpha ) * L(nu) + Spin1Projector(p) ( alpha, nu ) * L(mu) ) ; + f.imposeSymmetry({0,1,2}); + f.st(); + return f; +} + + Tensor AmpGen::Spin1Projector( const Tensor& P ) { - Tensor::Index mu; - Tensor::Index nu; auto is = 1./make_cse( dot(P,P) , true); - return Metric4x4()(mu, nu) - P(mu) * P(nu) * is ; // / make_cse( dot(P, P) , true ); + return Metric4x4()(mu, nu) - P(mu) * P(nu) * is; } Tensor AmpGen::Spin2Projector( const Tensor& P ) { - Tensor::Index mu, nu, alpha, beta; Tensor S = Spin1Projector( P ); Tensor SP = -( 1. / 3. ) * S( mu, nu ) * S( alpha, beta ) + (1./2.) * ( S( mu, alpha ) * S( nu, beta ) + S( mu, beta ) * S( nu, alpha ) ) ; return SP; @@ -91,7 +99,6 @@ Tensor AmpGen::Spin2Projector( const Tensor& P ) Tensor AmpGen::Gamma4Vec() { - Tensor::Index a, b, mu; Tensor x( {1, 0, 0, 0}, {4} ); Tensor y( {0, 1, 0, 0}, {4} ); Tensor z( {0, 0, 1, 0}, {4} ); @@ -101,18 +108,15 @@ Tensor AmpGen::Gamma4Vec() Tensor AmpGen::slash( const Tensor& P ) { - if ( P.dims() != std::vector({4}) ) { + if ( P.dims() != std::vector({4}) ) { ERROR( "Can only compute slash operator against vector currents" ); return Tensor(); } - Tensor::Index mu, a, b; - Tensor rt = Gamma4Vec()( mu, a, b ) * P( -mu ); - return rt; + return Gamma4Vec()( mu, a, b ) * P( -mu ); } Tensor AmpGen::gamma_twiddle( const Tensor& P ) { - Tensor::Index mu, nu, a, b ; Tensor g = Gamma4Vec(); return g(nu,a,b) - P(nu) * P(mu) * g(-mu,a,b) / make_cse( dot(P,P) ); } @@ -125,7 +129,6 @@ Tensor AmpGen::Spin1hProjector( const Tensor& P ) Tensor AmpGen::Spin3hProjector( const Tensor& P ) { - Tensor::Index a,b,c, d, mu, nu; Tensor Ps = P; Ps.st(); Tensor g = gamma_twiddle(Ps); @@ -138,7 +141,6 @@ Tensor AmpGen::Spin3hProjector( const Tensor& P ) } Tensor AmpGen::Bar( const Tensor& P ){ - Tensor::Index a,b; return P.conjugate()(b) * Gamma[3](b,a); } @@ -149,9 +151,8 @@ DEFINE_VERTEX( S_VV_S1 ) { return Spin1Projector(P)(mu,nu) * V1( -mu ) * V2( -nu DEFINE_VERTEX( S_VV_D ) { - Tensor L2 = Orbital_DWave( P, Q ) / ( GeV * GeV ); - Tensor vtol = V1( mu ) * L2( -mu, -nu ) * V2( nu ); - return vtol; + Tensor L2 = Orbital_DWave(P, Q); + return V1(mu)*L2(-mu,-nu)*V2(nu); } DEFINE_VERTEX( S_VV_P ) @@ -168,14 +169,7 @@ DEFINE_VERTEX( S_VS_P ) return p_v1 * V2[0] / GeV; } -DEFINE_VERTEX( V_SS_P ) -{ - Tensor p_wave = Orbital_PWave( P, Q ); - Expression scalar_part = V1[0] * V2[0] / GeV; - Tensor L = p_wave * scalar_part; - ADD_DEBUG_TENSOR( L, db ); - return L; -} +DEFINE_VERTEX( V_SS_P ){ return Orbital_PWave(P,Q) * V1[0] * V2[0] / GeV;} DEFINE_VERTEX( V_VS_P ) { @@ -185,11 +179,7 @@ DEFINE_VERTEX( V_VS_P ) } -DEFINE_VERTEX( V_VS_S ) -{ - Tensor L = Spin1Projector(P)(mu,nu) * V1(-nu) * V2[0]; - return L; -} +DEFINE_VERTEX( V_VS_S ){ auto S = Spin1Projector(P)(mu,nu) * V1(-nu) * V2[0]; ADD_DEBUG_TENSOR(S,db); return S; } DEFINE_VERTEX( V_VS_D ) { @@ -198,6 +188,67 @@ DEFINE_VERTEX( V_VS_D ) return ( Sv( mu, nu ) * L_2_V0( -nu, -alpha ) * V1( alpha ) ) * V2[0]; } +DEFINE_VERTEX( V_VV_S ) +{ + Tensor Sv = Spin1Projector( P ); + Tensor term = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( nu )/GeV * V1( alpha ) * V2( beta ); + + return term( -mu ) * Sv(mu, nu); +} + +DEFINE_VERTEX( V_VV_P ) +{ + Tensor L = Orbital_PWave( P, Q )/GeV; + return L(mu) * dot(V1,V2); +} + +DEFINE_VERTEX( V_VV_P1 ) +{ + Tensor L = Orbital_PWave( P, Q )/GeV; + Tensor Sv = Spin1Projector( P ); + Tensor term = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( nu )/GeV * V1( alpha ) * V2( beta ); + Tensor phi_1 = term(-mu) * Sv(mu,nu); + + Tensor term2 = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( mu )/GeV * L(nu) * phi_1(alpha); + + return Sv(mu,nu) * term2(-mu); +} + +DEFINE_VERTEX( V_VV_P2 ) +{ + Tensor L = Orbital_PWave( P, Q )/GeV; + Tensor Sv1 = Spin1Projector( P ); + Tensor Sv2 = Spin2Projector( P ); + Tensor phi_2 = Sv2(-mu,-nu,alpha,beta) * V1(mu) * V2(nu); + + return Sv1(mu,nu) * L(alpha) * phi_2(-nu,-alpha); +} + +DEFINE_VERTEX( V_VV_D ) +{ + Tensor Sv = Spin1Projector( P ); + Tensor L = Orbital_DWave( P, Q )/(GeV*GeV); + + Tensor term = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( nu )/GeV * V1( alpha ) * V2( beta ); + Tensor phi_1 = term(-mu) * Sv(mu,nu); + + return Sv(mu,nu) * L(-nu,-alpha) * phi_1(alpha); +} + +DEFINE_VERTEX( V_VV_D2 ) +{ + Tensor Sv1 = Spin1Projector( P ); + Tensor Sv2 = Spin2Projector( P ); + Tensor L = Orbital_DWave( P, Q )/(GeV*GeV); + + Tensor phi_2 = Sv2(-mu,-nu,alpha,beta) * V1(mu) * V2(nu); + + Tensor term = L(mu,nu) * phi_2(alpha,-mu); + Tensor term2 = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( mu )/GeV * term(alpha,beta); + + return Sv1(mu,nu) * term2(-nu); +} + DEFINE_VERTEX( T_VS_D ) { Tensor G = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( nu ) * Q( alpha ) * V1( beta ); @@ -223,6 +274,73 @@ DEFINE_VERTEX( T_VS_P ) DEFINE_VERTEX( T_SS_D ) { return Orbital_DWave( P, Q ) * V1[0] * V2[0] / ( GeV * GeV ); } +DEFINE_VERTEX( T_VV_S ){ return Spin2Projector(P)(mu,nu,alpha,beta) * V1(-alpha) * V2(-beta); } + +DEFINE_VERTEX( T_VV_P ) +{ + Tensor Sv1 = Spin1Projector( P ); + Tensor Sv2 = Spin2Projector( P ); + Tensor L = Orbital_PWave( P, Q )/GeV; + + Tensor term = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( nu )/GeV * V1( alpha ) * V2( beta ); + Tensor phi_1 = term(-mu) * Sv1(mu,nu); + + return Sv2(mu,nu,alpha,beta) * L(-alpha) * phi_1(-beta); +} + +/* +DEFINE_VERTEX( T_VV_P2 ) +{ + // Doesnt seem to work + Tensor Sv2 = Spin2Projector( P ); + Tensor L = Orbital_PWave( P, Q )/GeV; + + Tensor phi_2 = Sv2(-mu,-nu,-alpha,-beta) * V1(mu) * V2(nu); + + Tensor term = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( mu )/GeV * L(nu); + Tensor term2 = term(-alpha,-beta) * phi_2(alpha,-mu); + + return Sv2(mu,nu,alpha,beta) * term2(-alpha,-beta); +} +*/ + +DEFINE_VERTEX( T_VV_D ){ + + Tensor Sv2 = Spin2Projector( P ); + Tensor L = Orbital_DWave( P, Q )/(GeV*GeV); + + return Sv2(mu,nu,alpha,beta) * L(-alpha,-beta) * dot(V1,V2); +} + +/* +DEFINE_VERTEX( T_VV_D1 ){ + // Doesnt seem to work + Tensor Sv1 = Spin1Projector( P ); + Tensor Sv2 = Spin2Projector( P ); + Tensor L = Orbital_DWave( P, Q )/(GeV*GeV); + + Tensor term = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( nu )/GeV * V1( alpha ) * V2( beta ); + Tensor phi_1 = term(-mu) * Sv1(mu,nu); + + Tensor term2 = LeviCivita()( -mu, -nu, -alpha, -beta ) * P( mu )/GeV * phi_1(nu); + Tensor term3 = term2(-alpha,-beta) * L(alpha,mu); + + return Sv2(mu,nu,alpha,beta) * term3(-alpha,-beta); +} +*/ +/* +DEFINE_VERTEX( T_VV_D2 ){ + // Doesnt seem to work + Tensor Sv2 = Spin2Projector( P ); + Tensor L = Orbital_DWave( P, Q )/(GeV*GeV); + + Tensor phi_2 = Sv2(-mu,-nu,alpha,beta) * V1(mu) * V2(nu); + Tensor term = L(-alpha,-beta) * phi_2(beta,mu); + + return Sv2(mu,nu,alpha,beta) * term(-alpha,-beta) ; +} +*/ + DEFINE_VERTEX( S_TV_P ) { Tensor L = Orbital_PWave( P, Q ) / GeV; @@ -258,26 +376,36 @@ DEFINE_VERTEX( V_TS_D ) return coupling( -mu, -nu ) * V1( nu, alpha ) * L( -alpha ) / ( GeV * GeV * GeV ); } +DEFINE_VERTEX( S_HS_F ) +{ + Tensor orbital = Orbital_FWave( P, Q ); + return V2[0] * Tensor( {dot( orbital, V1 ) / ( GeV * GeV * GeV)}, {1} ); +} + +DEFINE_VERTEX( H_SS_F ) { return Orbital_FWave( P, Q ) * V1[0] * V2[0] / ( GeV * GeV * GeV ); } + + + DEFINE_VERTEX( f_fS_S ) { - Tensor::Index a,b; - return Spin1hProjector(P)(a,b) * V1(b) * V2[0]; + Tensor f_fS_Sv = Spin1hProjector(P)(a,b) * V1(b) * V2[0]; + ADD_DEBUG_TENSOR( f_fS_Sv, db); + return f_fS_Sv; } + DEFINE_VERTEX( f_fS_P ) { - Tensor::Index a,b,c,d; Tensor proj = Spin1hProjector(P); Tensor L = Orbital_PWave(P,Q); - Tensor t = proj(a, b) * Gamma[4](b,c) * slash(L)(c,d) * V1(d); + ADD_DEBUG_TENSOR( P, db ); + ADD_DEBUG_TENSOR( Q, db ); ADD_DEBUG_TENSOR( L, db ); - ADD_DEBUG_TENSOR( Tensor(Gamma[4](b,c)*slash(L)(c,d)*V1(d)), db ); - ADD_DEBUG_TENSOR(t, db); + Tensor t = proj(a, b) * Gamma[4](b,c) * slash(L)(c,d) * V1(d); return t; } DEFINE_VERTEX( f_Vf_S ) { - Tensor::Index a,b,c,d; Tensor proj = Spin1hProjector(P); return proj(a, b) * Gamma[4](b,c) * gamma_twiddle(P)(mu,c,d) * V2(d) * V1(-mu); } @@ -291,7 +419,6 @@ DEFINE_VERTEX( f_Vf_P ) /// = A3 DEFINE_VERTEX( f_Vf_P1 ) //// = A6 { - Tensor::Index a,b,c,d; Tensor proj = Spin1hProjector(P); Tensor L = Orbital_PWave(P,Q); Tensor t = LeviCivita()(mu,nu,alpha,beta) * V1(-nu) * L(-alpha) * P(-beta); @@ -301,7 +428,6 @@ DEFINE_VERTEX( f_Vf_P1 ) //// = A6 DEFINE_VERTEX( f_Vf_D ) //// = A8 { - Tensor::Index a,b,c,d; Tensor proj = Spin1hProjector(P); Tensor gt = gamma_twiddle(P); Tensor L = Orbital_DWave(P,Q)(-mu,-nu) * V1(nu) / (GeV*GeV); @@ -310,28 +436,45 @@ DEFINE_VERTEX( f_Vf_D ) //// = A8 DEFINE_VERTEX( f_Vf_S1 ) { - Tensor::Index a,b,c; Tensor proj = Spin1hProjector(P); Tensor vSlash = gamma_twiddle(P)(mu,a,b) * V1(-mu); return proj( a, b ) * vSlash(b,c) * V2(c); } +DEFINE_VERTEX( f_Vf_SL ) +{ + Tensor proj = Spin1hProjector(P); + return proj(a, b) * Gamma4Vec()(mu,b,c) * ( Identity(4) - Gamma[4] )(c,d)* V2(d) * V1(-mu); +} -DEFINE_VERTEX( f_fS_S1 ) -{ - Tensor::Index a,b,c; - return Spin1hProjector(P)(a,b) * Gamma[4](b,c) * V1(c) * V2[0]; +DEFINE_VERTEX( f_Vf_SR ) +{ + Tensor proj = Spin1hProjector(P); + return proj(a, b) * Gamma4Vec()(mu,b,c) * ( Identity(4) + Gamma[4] )(c,d)* V2(d) * V1(-mu); +} + +DEFINE_VERTEX( f_fS_SL ) +{ + Tensor proj = Spin1hProjector(P); + return proj(a, b) * ( Identity(4) - Gamma[4] )(b,c)* V2(c); +} + + +DEFINE_VERTEX( f_fS_SR ) +{ + Tensor proj = Spin1hProjector(P); + return proj(a, b) * ( Identity(4) + Gamma[4] )(b,c)* V2(c); } +DEFINE_VERTEX( f_fS_S1 ){ return Spin1hProjector(P)(a,b) * Gamma[4](b,c) * V1(c) * V2[0];} + DEFINE_VERTEX( f_fS_P1 ) { - Tensor::Index a,b,c,d; return Spin1hProjector(P)(a, b) * slash(Orbital_PWave(P,Q))(b,c) * V1(c) * V2[0] / GeV; } DEFINE_VERTEX( f_Tf_P ) { - Tensor::Index a,b,c; Tensor proj = Spin1hProjector(P); Tensor T = V1; T.imposeSymmetry(0,1); @@ -347,7 +490,6 @@ DEFINE_VERTEX( f_Vf_P2 ) DEFINE_VERTEX( f_Vf_P3 ) { - Tensor::Index a,b,c; Tensor proj = Spin1hProjector(P); Tensor L = Orbital_PWave(P,Q); Tensor t = LeviCivita()(-mu,-nu,-alpha,-beta) * L(nu) * V1(alpha) * P(beta); @@ -358,7 +500,6 @@ DEFINE_VERTEX( f_Vf_P3 ) DEFINE_VERTEX( f_Vf_D1 ) { - Tensor::Index a,b,c,d; Tensor proj = Spin1hProjector(P); Tensor gt = gamma_twiddle(P); Tensor L = Orbital_DWave(P,Q)(-mu,-nu) * V1(nu) / (GeV*GeV); @@ -368,7 +509,6 @@ DEFINE_VERTEX( f_Vf_D1 ) DEFINE_VERTEX( r_fS_P ) { - Tensor::Index a,b,c,d; Tensor L = Orbital_PWave(P,Q); L.st(); Tensor F = Spin1hProjector(P); @@ -379,11 +519,11 @@ DEFINE_VERTEX( r_fS_P ) DEFINE_VERTEX( r_fS_D ) { - Tensor::Index a,b,c,d,e; + Tensor::Index e; Tensor sp = Spin3hProjector(P); Tensor L = Orbital_PWave(P,Q); Tensor F = Spin1hProjector(P); - L.st(1); + L.st(true); Expression L2 = make_cse(dot(L,L)); Tensor gt = gamma_twiddle(P); Tensor rt = ( L(mu) * F(a,b) * slash(L)(b,c) - (L2/3.) * F(a,b) * gt(mu,b,c) ) * Gamma[4](c,d) * V1(d) / (GeV*GeV); @@ -394,7 +534,6 @@ DEFINE_VERTEX( r_fS_D ) DEFINE_VERTEX( f_rS_D ) { - Tensor::Index a,b,c,d; Tensor F = Spin1hProjector(P)(a,b) * Gamma[4](b,d) * gamma_twiddle(P)(mu,d,c) @@ -407,7 +546,6 @@ DEFINE_VERTEX( f_rS_D ) DEFINE_VERTEX( f_rS_P ) { - Tensor::Index a,b,c; auto L = Orbital_PWave(P,Q); Tensor F = Spin1hProjector(P)(a,b) * V1(-mu,b) * L(mu) * V2[0] / GeV; ADD_DEBUG_TENSOR( V1, db ); @@ -419,34 +557,32 @@ DEFINE_VERTEX( f_rS_P ) DEFINE_VERTEX( f_rS_P1 ) { - Tensor::Index a,b,c; auto L = Orbital_PWave(P,Q); Tensor F = Spin1hProjector(P)(a,b) * Gamma[4](b,c) * V1(-mu,c) * L(mu) * V2[0]/ GeV; F.st(); return F; } -DEFINE_VERTEX( S_ff_S ) -{ - Tensor::Index a; - return Bar( V2 )(a) * V1(a); -} +DEFINE_VERTEX( S_ff_S ) { return Bar(V2)(a) * V1(a); } -DEFINE_VERTEX( S_ff_S1 ) -{ - Tensor::Index a,b; - return Bar( V2 )(a) * Gamma[4](a,b) * V1(b); -} +DEFINE_VERTEX( S_ff_S1 ){ return Bar(V2)(a) * Gamma[4](a,b) * V1(b); } +DEFINE_VERTEX( V_ff_S ) { return Bar(V2)(a) * Gamma4Vec()(mu,a,b) * V1(b); } -DEFINE_VERTEX( V_ff_P ) -{ - Tensor::Index a,b ; - return Bar( V2 )(a) * Gamma4Vec()(mu,a,b) * V1(b); +DEFINE_VERTEX( V_ff_S1 ){ return Bar(V2)(a) * Gamma[4](a,b) * Gamma4Vec()(mu,b,c) * V1(c); } + +DEFINE_VERTEX( V_ff_PL ) +{ + Tensor proj = Spin1Projector(P); + auto pl = 0.5 * ( Identity(4) - Gamma[4] ); + ADD_DEBUG_TENSOR( pl, db); + ADD_DEBUG_TENSOR( pl(b,c)* V2(c), db ); + return proj(mu, nu) * Bar(V1)(a) * Gamma4Vec()(-nu,a,b) * ( Identity(4) - Gamma[4] )(b,c)* V2(c); } -DEFINE_VERTEX( V_ff_P1 ) -{ - Tensor::Index a,b,c ; - return Bar( V2 )(a) * Gamma[4](a,b) * Gamma4Vec()(mu,b,c) * V1(c); +DEFINE_VERTEX( V_ff_PR ) +{ + Tensor proj = Spin1Projector(P); + ADD_DEBUG_TENSOR( (Identity(4) + Gamma[4] )(b,c)* V2(c), db ); + return proj(mu, nu) * Bar(V1)(a) * Gamma4Vec()(-nu,a,b) * ( Identity(4) + Gamma[4] )(b,c)* V2(c); } diff --git a/src/Wigner.cpp b/src/Wigner.cpp index 22dc9f5ad66..fedfc671a21 100644 --- a/src/Wigner.cpp +++ b/src/Wigner.cpp @@ -21,6 +21,7 @@ using namespace AmpGen; using namespace AmpGen::fcn; +using namespace std::complex_literals; double fact( const double& z ) { @@ -29,7 +30,7 @@ double fact( const double& z ) return f; } -double nCr_( const int& n, const int& r ){ +double binomialCoefficient( const int& n, const int& r ){ double z=1; for( int f=1; f <= r ; ++f ) z *= double(n+1-f)/double(f); return z; @@ -38,7 +39,7 @@ double nCr_( const int& n, const int& r ){ Expression expandedBinomial( const Expression& x, const unsigned int& n ) { Expression sum; - for( unsigned int k = 0 ; k <= n ; ++k ) sum = sum + nCr_(n,k) * fcn::fpow(x,k); + for( unsigned int k = 0 ; k <= n ; ++k ) sum = sum + binomialCoefficient(n,k) * fcn::fpow(x,k); return sum; } @@ -79,10 +80,8 @@ double AmpGen::CG( if( m1+m2!=M ) return 0; double f1 = (2*J+1)*fact(J+j1-j2)*fact(J-j1+j2)*fact(j1+j2-J) ; double f2 = fact(j1+m1)*fact(j1-m1)*fact(j2+m2)*fact(j2-m2)*fact(J+M)*fact(J-M); - double norm = f1 * f2 / fact(J+j1+j2+1) ; double sum = 0; - for( int nu=0; nu <= j1+j2-J ; ++nu){ double arg1 = j1+j2-J-double(nu); double arg2 = j1 -m1-double(nu); @@ -97,10 +96,10 @@ double AmpGen::CG( return sqrt(norm) * sum ; } -TransformSequence AmpGen::helicityTransformMatrix( const Tensor& P, - const Expression& mass, +TransformSequence AmpGen::wickTransform( const Tensor& P, + const Particle& particle, const int& ve, - const bool& handleZero ) + DebugSymbols* db ) { Tensor x({1,0,0}, Tensor::dim(3)); Tensor y({0,1,0}, Tensor::dim(3)); @@ -112,40 +111,46 @@ TransformSequence AmpGen::helicityTransformMatrix( const Tensor& P, Transform rot = ve == + 1 ? Transform( cos_theta, sin_phi*x - cos_phi*y, Transform::Type::Rotate) : Transform(-cos_theta, -sin_phi*x + cos_phi*y, Transform::Type::Rotate) ; -// Transform boost( P[3]/mass, (ve==+1) ? z : -z, Transform::Type::Boost ); - Transform boost( P[3]/mass, z, Transform::Type::Boost ); - TransformSequence sequence; - sequence.add( rot ); - if( ve == -1 ) sequence.add( Transform( -1, x, Transform::Type::Rotate ) ); - sequence.add( boost ) ; - return sequence; + TransformSequence sequence(rot); + if( ve == -1 ) sequence.push_back( Transform( -1, x, Transform::Type::Rotate ) ); + + if( !particle.isStable() || !( particle.props()->isPhoton() || particle.props()->isNeutrino() ) ) + { + Expression mass = fcn::sqrt( particle.massSq() ); + Transform boost( P[3]/mass, z, Transform::Type::Boost ); + return TransformSequence(sequence, boost); + } + return TransformSequence(sequence); } -Expression AmpGen::wigner_D(const Tensor& P, - const double& J, - const double& lA, - const double& lB, - DebugSymbols* db, - const std::string& name ) +std::pair angCoordinates(const Tensor& P, DebugSymbols* db) { Expression pz = make_cse( P[2] / sqrt( P[0]*P[0] + P[1] * P[1] + P[2]*P[2] ) ); Expression pt2 = make_cse( P[0]*P[0] + P[1]*P[1] ); - Expression px = P[0] / sqrt( pt2 ); - Expression py = P[1] / sqrt( pt2 ); + Expression px = P[0] / sqrt(pt2); + Expression py = P[1] / sqrt(pt2); + return {pz, make_cse(px + 1i*py)}; +} /// spherical coordinates are paramterised as {z=cos(theta), e^(iphi)}, as this avoids any trigonometric functions - Expression I(std::complex(0,1)); - auto little_d = make_cse ( wigner_d( pz, J, lA, lB ) ); +Expression AmpGen::wigner_D(const std::pair& P, + const double& J, + const double& lA, + const double& lB, + DebugSymbols* db) +{ + auto little_d = make_cse ( wigner_d( P.first, J, lA, lB ) ); if( J != 0 && db != nullptr ){ - db->emplace_back("ϕ("+name+")", atan2( py, px ) ); - db->emplace_back("θ("+name+")", pz ); + db->emplace_back("cos(θ)", P.first ); + db->emplace_back("Ω", atan2( Imag(P.second), Real(P.second) ) ); + db->emplace_back("d[" + std::to_string(J) +", " + std::to_string(lA) +", " + std::to_string(lB) +"](θ)", little_d ); db->emplace_back("D[" + std::to_string(J) +", " + std::to_string(lA) +", " + - std::to_string(lB) +"](Ω)", fpow(px+I*py,lB-lA) * little_d ); + std::to_string(lB) +"](θ, Ω)", fpow(P.second,lB-lA) * little_d ); } - return fpow( px + I * py, lB - lA ) * little_d; + return fpow( P.second, lB - lA ) * little_d; } std::vector AmpGen::calculate_recoupling_constants( @@ -173,135 +178,132 @@ std::vector AmpGen::calculate_recoupling_constants( return rt; } -/* -Tensor AmpGen::basis_spinor(const Tensor& p, const int& polState, const int& id, DebugSymbols* db ) -{ - Expression pX = p.get(0) ; - Expression pY = p.get(1) ; - Expression pZ = p.get(2) ; - Expression pE = p.get(3) ; - Expression pP = fcn::sqrt( pX*pX + pY*pY + pZ*pZ ); - Expression m = fcn::sqrt( dot( p, p ) ); - - complex_t I(0,1); - Expression z = pX + I*pY; - Expression zb = pX - I*pY; - Expression n = fcn::sqrt( 2 * pP*(pP+pZ) ); - Expression fa = fcn::sqrt( (pE + m)/(2*m) ); - Expression fb = fcn::sqrt( (pE - m)/(2*m) ); - Expression aligned = make_cse( Abs(pP + pZ) < 10e-6 ) ; - - Expression xi10 = make_cse(Ternary( aligned, 1, (pP+pZ)/n )); - Expression xi11 = make_cse(Ternary( aligned, 0, z/n )); - - Expression xi00 = make_cse(Ternary( aligned, 0, -zb/n )); - Expression xi01 = make_cse(Ternary( aligned, 1, (pP+pZ)/n )); - - if(id > 0 && polState == 1 ) return Tensor({fa*xi10, fa*xi11, fb*xi10, fb*xi11}); - if(id > 0 && polState == -1 ) return Tensor({fa*xi00, fa*xi01, -fb*xi00, -fb*xi01}); - if(id < 0 && polState == 1 ) return Tensor({fb*xi00, fb*xi01, -fa*xi00, -fa*xi01}); - if(id < 0 && polState == -1 ) return Tensor({fb*xi10, fb*xi11, -fa*xi01, -fa*xi11}); - - ERROR("Shouldn't reach here..."); - return Tensor(); -} -*/ Tensor AmpGen::basisSpinor(const int& polState, const int& id) { if(id > 0 && polState == 1 ) return Tensor({1, 0, 0, 0}, Tensor::dim(4)); if(id > 0 && polState == -1 ) return Tensor({0, 1, 0, 0}, Tensor::dim(4)); if(id < 0 && polState == 1 ) return Tensor({0, 0, 1, 0}, Tensor::dim(4)); if(id < 0 && polState == -1 ) return Tensor({0, 0, 0, 1}, Tensor::dim(4)); - ERROR("Shouldn't reach here..."); + ERROR("Shouldn't reach here..., polState = " << polState << " id = " << id ); return Tensor(); } +Tensor AmpGen::basisVector(const int& polState) +{ + double N = 1./sqrt(2); + if( polState == 0 ) return Tensor(std::vector({0., 0.,1.,0.}), Tensor::dim(4)); + if( polState == 1 ) return -N*Tensor(std::vector({1., 1i,0.,0.}), Tensor::dim(4)); + if( polState == -1 ) return N*Tensor(std::vector({1.,-1i,0.,0.}), Tensor::dim(4)); + ERROR("Shouldn't reach here..., polState = " << polState); + return Tensor(); +} std::vector userHelicityCouplings( const std::string& key ){ std::vector couplings; auto things = NamedParameter( key, 0).getVector(); - if( things.size() % 3 != 0 ) ERROR("Wrong number of tokens"); - for( size_t i = 0 ; i < things.size(); i+=3 ){ - LS coupling; - coupling.factor = things[i+0]; - coupling.m1 = things[i+1]; - coupling.m2 = things[i+2]; - couplings.push_back(coupling); - } - return couplings; + if( things.size() % 3 != 0 ) ERROR("Wrong number of tokens"); + for( size_t i = 0 ; i < things.size(); i+=3 ){ + LS coupling; + coupling.factor = things[i+0]; + coupling.m1 = things[i+1]; + coupling.m2 = things[i+2]; + couplings.push_back(coupling); + } + return couplings; } +std::string index_string(const Particle& particle) +{ + if( particle.isStable() ) return std::to_string(particle.index()); + std::string f = "{"; + for( const auto& i : particle.daughters() ) f += index_string( *i ); + return f+ "}"; +} Expression AmpGen::helicityAmplitude(const Particle& particle, const TransformSequence& parentFrame, const double& Mz, DebugSymbols* db, - int sgn ) + int sgn, + TransformCache* cachePtr ) { + if( cachePtr == nullptr ) cachePtr = new TransformCache(); if( particle.daughters().size() > 2 ) return 1; if( particle.daughters().size() == 1 ) - return helicityAmplitude( *particle.daughter(0), parentFrame, Mz, db, sgn ); - + return helicityAmplitude( *particle.daughter(0), parentFrame, Mz, db, sgn, cachePtr); Tensor::Index a,b,c; - auto myFrame = parentFrame; - if( particle.spin() == 0 ) myFrame.clear(); - Tensor pInParentFrame = parentFrame( particle.P() ); + // if( particle.props()->twoSpin() == 0 ) myFrame.clear(); + Tensor pInParentFrame = parentFrame(particle.P()); pInParentFrame.st(); - if( ! particle.isHead() ){ - auto my_sequence = helicityTransformMatrix( pInParentFrame, - fcn::sqrt(particle.massSq()), - sgn, - true ); - myFrame.add( my_sequence ); - } - if( particle.isStable() ) + auto key = index_string(particle); + if( cachePtr->count(key) == 0 ) { - if( particle.spin() == 0 ) return Mz==0; - if( particle.spin() == 0.5 ) + if( ! particle.isHead() || NamedParameter("helicityAmplitude::MovingParent", false) ) { - auto tensor = particle.externalSpinTensor(particle.polState(), db); - auto helicity_tensor = basisSpinor( 2*Mz, particle.props()->pdgID() ); - auto it = myFrame.inverse(); - auto helicity_in_frame = it( helicity_tensor, Transform::Representation::Bispinor ); - auto w = Bar(helicity_in_frame)(a) * tensor(a); - ADD_DEBUG_TENSOR( helicity_tensor, db ); - ADD_DEBUG_TENSOR( helicity_in_frame ,db); - ADD_DEBUG_TENSOR( tensor ,db ); - ADD_DEBUG(w, db); - return w; + (*cachePtr)[key] = TransformSequence(parentFrame, wickTransform(pInParentFrame, particle, sgn, db) ); } + else (*cachePtr)[key] = TransformSequence(); } + const TransformSequence& myFrame = (*cachePtr)[key]; - auto particle_couplings = particle.spinOrbitCouplings(false); - auto L = particle.orbital(); - auto& d0 = *particle.daughter(0); - auto& d1 = *particle.daughter(1); + if( particle.isStable() ) + { + if( particle.props()->twoSpin() == 0 ) return Mz==0; // a scalar + // polarisation spinor / vector etc. in the quantisation of the lab (i.e. along the z-axis or lab particle momentum) + if( particle.props()->isPhoton() && Mz == 0. ) ERROR("Photon polarisation state is wrong"); + if( particle.polState() == 0 ) ERROR("Photon external state is wrong..."); + auto labPol = particle.externalSpinTensor(particle.polState(), db); + auto inverseMyTransform = myFrame.inverse(); + if( particle.props()->twoSpin() == 1 ) // so a fermion + { + if( NamedParameter("helicityAmplitude::NoSpinAlign", false ) ) return 2*Mz == particle.polState(); + auto mzSpinor = basisSpinor( 2*Mz, particle.props()->pdgID() ); + auto mzSpinorInLab = inverseMyTransform( mzSpinor, Transform::Representation::Bispinor ); + mzSpinorInLab.st(); + ADD_DEBUG(Bar(mzSpinorInLab)(a)*labPol(a), db ); + return make_cse( Bar(mzSpinorInLab)(a)*labPol(a) ); + } + if( particle.props()->twoSpin() == 2 ) // so a spin-one boson + { + auto frameVector = basisVector(Mz); + auto labVector = inverseMyTransform( frameVector, Transform::Representation::Vector ); + return dot( labVector.conjugate(), labPol ); + } + } + auto particle_couplings = particle.spinOrbitCouplings(false); + auto L = particle.L(); + const auto& d1 = *particle.daughter(0); + const auto& d2 = *particle.daughter(1); double S = 999; if( particle.S() == 0 ){ - for( auto& l : particle_couplings ) if( l.first == L ){ S = l.second ; break; } - if( S == 999 ) ERROR("Spin orbital coupling impossible!"); + auto it = std::find_if( particle_couplings.begin(), particle_couplings.end(), [&L](auto& l){ return l.first == L; } ); + if( it != particle_couplings.end() ) S = it->second; + else ERROR("Spin orbital coupling impossible!"); } - else S = particle.S() /2.; - - auto recoupling_constants = calculate_recoupling_constants( particle.spin(), Mz, L, S, d0.spin(), d1.spin() ); + else S = particle.S()/2.; + auto recoupling_constants = calculate_recoupling_constants( particle.spin(), Mz, L, S, d1.spin(), d2.spin() ); auto mod = particle.attribute("helAmp"); - if( mod != stdx::nullopt ) recoupling_constants = userHelicityCouplings( mod.value() ); + if( mod != stdx::nullopt ) recoupling_constants = userHelicityCouplings( *mod ); if( recoupling_constants.size() == 0 ){ WARNING( particle.uniqueString() << " " << particle.spin() << " " << particle.orbitalRange(false).first << " " << particle.orbitalRange(false).second - << " transition Mz="<< Mz << " to " << d0.spin() << " x " << d0.spin() << " cannot be coupled in (LS) = " << L << ", " << S ); + << " transition Mz="<< Mz << " to " << d1.spin() << " x " << d2.spin() << " cannot be coupled in (LS) = " << L << ", " << S ); WARNING( "Possible (LS) combinations = " << vectorToString( particle_couplings, ", ", []( auto& ls ){ return "("+std::to_string(int(ls.first)) + ", " + std::to_string(ls.second) +")";} ) ); } Expression total = 0; + + auto hco = angCoordinates( myFrame(d1.P()) , db); for( auto& coupling : recoupling_constants ) { auto dm = coupling.m1 - coupling.m2; - auto term = wigner_D(myFrame(d0.P()), particle.spin(), Mz, dm,db, d0.name() ); - auto h1 = helicityAmplitude(d0, myFrame, coupling.m1, db, +1); - auto h2 = helicityAmplitude(d1, myFrame, coupling.m2, db, -1); + if( (d1.props()->isPhoton() && coupling.m1 == 0.) || + (d2.props()->isPhoton() && coupling.m2 == 0.) ) continue; + auto term = wigner_D(hco, particle.spin(), Mz, dm, db); + auto h1 = helicityAmplitude(d1, myFrame, coupling.m1, db, +1, cachePtr); + auto h2 = helicityAmplitude(d2, myFrame, coupling.m2, db, -1, cachePtr); if( db != nullptr ){ db->emplace_back( "coupling" , coupling.factor ); if( coupling.factor != 1 ) db->emplace_back( "C x DD'", coupling.factor * term * h1 * h2 ); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 00000000000..9cd5d33cf5a --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,21 @@ +find_package(Boost 1.67.0 COMPONENTS unit_test_framework) + +if ( Boost_FOUND ) + include_directories (${Boost_INCLUDE_DIRS}) + file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) + foreach(testSrc ${TEST_SRCS}) + get_filename_component(testName ${testSrc} NAME_WE) + add_executable(${testName} ${testSrc}) + set_target_properties(${testName} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_TEST_OUTPUT_DIRECTORY}" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_TEST_OUTPUT_DIRECTORY}" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_TEST_OUTPUT_DIRECTORY}" + EXECUTABLE_OUTPUT_DIRECTORY "${CMAKE_TEST_OUTPUT_DIRECTORY}" + ) + target_link_libraries(${testName} PUBLIC ${Boost_LIBRARIES} AmpGen) + add_test(NAME ${testName} WORKING_DIRECTORY ${CMAKE_TEST_OUTPUT_DIRECTORY} COMMAND ${CMAKE_TEST_OUTPUT_DIRECTORY}/${testName} ) + endforeach(testSrc) +else() + message( WARNING "Warning: Boost (version >= 1.67.0) required to build unit tests\n") +endif() diff --git a/test/test_AmplitudeRules.cpp b/test/test_AmplitudeRules.cpp new file mode 100644 index 00000000000..043950d5f9a --- /dev/null +++ b/test/test_AmplitudeRules.cpp @@ -0,0 +1,66 @@ +#define BOOST_TEST_DYN_LINK + +#define BOOST_TEST_MODULE "AmplitudeRules" + +#include +namespace utf = boost::unit_test; + +#include "AmpGen/AmplitudeRules.h" +#include "AmpGen/MinuitParameter.h" +#include "AmpGen/MinuitParameterSet.h" + +using namespace AmpGen; + +BOOST_AUTO_TEST_CASE( test_AmplitudeRule ) { + + MinuitParameter re = MinuitParameter("D0{K*(892)bar0{K-,pi+},pi0}_Re", Flag::Free,1.,0.); + MinuitParameter im = MinuitParameter("D0{K*(892)bar0{K-,pi+},pi0}_Im", Flag::Free,0.,0.); + + Coupling test(&re,&im); + + BOOST_CHECK( test.name() == "D0{K*(892)bar0{K-,pi+},pi0}" ); + BOOST_CHECK( test.head() == "D0"); + BOOST_CHECK( test.prefix() == "" ); + BOOST_CHECK( test.eventType() == EventType({"D0","K-","pi+","pi0"}) ); +} + +BOOST_AUTO_TEST_CASE( test_AmplitudeRules_constructor ){ + auto mps = MinuitParameterSet( { + new MinuitParameter("D0{K*(892)bar0,pi0}_Re", Flag::Fix,1.,0.) + , new MinuitParameter("D0{K*(892)bar0,pi0}_Im", Flag::Fix,1.,0.) + , new MinuitParameter("D0{rho(770)+,pi-}_Re" , Flag::Fix,1.,0.) + , new MinuitParameter("D0{rho(770)+,pi-}_Im" , Flag::Fix,2.,0.) + , new MinuitParameter("K*(892)bar0{K-,pi+}_Re", Flag::Free,sqrt(1./3.),0.) + , new MinuitParameter("K*(892)bar0{K-,pi+}_Im", Flag::Free,0,0.) + , new MinuitParameter("K*(892)bar0{K0,pi0}_Re", Flag::Fix,sqrt(2./3.),0.) + , new MinuitParameter("K*(892)bar0{K0,pi0}_Im", Flag::Fix,0,0.) } ); + AmplitudeRules rule_set(mps); + + BOOST_CHECK( rule_set.rules().size() == 2 ); /// number of head decays + BOOST_CHECK( rule_set.hasDecay("D0") == true ); /// has decays for D0 + BOOST_CHECK( rule_set.hasDecay("a(1)(1260)+") == false ); /// has decays for D0 +} + +BOOST_AUTO_TEST_CASE( test_couplingConstant ) +{ + auto mps = MinuitParameterSet( { + new MinuitParameter("D0{K*(892)bar0,pi0}_Re", Flag::Fix,1.,0.) + , new MinuitParameter("D0{K*(892)bar0,pi0}_Im", Flag::Fix,1.,0.) + , new MinuitParameter("D0{rho(770)+,pi-}_Re" , Flag::Fix,1.,0.) + , new MinuitParameter("D0{rho(770)+,pi-}_Im" , Flag::Fix,2.,0.) + , new MinuitParameter("K*(892)bar0{K-,pi+}_Re", Flag::Free,sqrt(1./3.),0.) + , new MinuitParameter("K*(892)bar0{K-,pi+}_Im", Flag::Free,0,0.) + , new MinuitParameter("K*(892)bar0{K0,pi0}_Re", Flag::Fix,sqrt(2./3.),0.) + , new MinuitParameter("K*(892)bar0{K0,pi0}_Im", Flag::Fix,0,0.) } ); + AmplitudeRules rule_set(mps); + auto matches = rule_set.getMatchingRules( EventType({"D0","K-","pi+","pi0"}) ); + auto matches2 = rule_set.getMatchingRules( EventType({"D0","K0","pi0","pi0"}) ); + + BOOST_TEST( std::real(matches[0].second()) == 1./sqrt(3.), boost::test_tools::tolerance(1e-10) ); + BOOST_TEST( std::imag(matches[0].second()) == 1./sqrt(3.), boost::test_tools::tolerance(1e-10) ); + BOOST_TEST( matches[0].second.isFixed() == false ); + BOOST_TEST( matches2[0].second.isFixed() == true ); + BOOST_TEST( matches[0].second.contains("K*(892)bar0{K0,pi0}") == false ); + BOOST_TEST( matches2[0].second.contains("K*(892)bar0{K0,pi0}") == true ); +} + diff --git a/test/test_ArgumentPack.cpp b/test/test_ArgumentPack.cpp index 0d529a25284..437a9fa4173 100644 --- a/test/test_ArgumentPack.cpp +++ b/test/test_ArgumentPack.cpp @@ -7,13 +7,15 @@ namespace utf = boost::unit_test; #include "AmpGen/ArgumentPack.h" -DECLARE_ARGUMENT_DEFAULT( test_argument_string, std::string, "hello world"); +DECLARE_ARGUMENT( test_argument_string, std::string); DECLARE_ARGUMENT( test_argument_double , double ); +static const test_argument_double value; + struct Mock { Mock( const AmpGen::ArgumentPack& args ){ t1 = args.getArg().val; - t2 = args.getArg().val; + t2 = args.getArg("hello world").val; } template Mock( const ARGS&... args ) : Mock( AmpGen::ArgumentPack(args...) ) {} diff --git a/test/test_Expression.cpp b/test/test_Expression.cpp index 571d4e260c9..fed4fee9396 100644 --- a/test/test_Expression.cpp +++ b/test/test_Expression.cpp @@ -6,7 +6,8 @@ namespace utf = boost::unit_test; #include "AmpGen/Expression.h" - +#include "AmpGen/CompiledExpression.h" +using namespace AmpGen; BOOST_AUTO_TEST_CASE ( sum_to_string ) { AmpGen::Parameter A("A"); @@ -42,3 +43,15 @@ BOOST_AUTO_TEST_CASE( test_composite, * utf::tolerance(1e-6) ) double value = std::real( ( A*B/( AmpGen::fcn::cos(B) * AmpGen::fcn::sqrt(A) ))() ); BOOST_TEST( value == (4*5/(cos(5)*sqrt(4))), boost::test_tools::tolerance(1e-6)) ; } + +BOOST_AUTO_TEST_CASE( lambda_expression ) +{ + double x = 5; + LambdaExpression test( [&x](){ return x; } ); + auto f = test + 7; + BOOST_CHECK( std::real(f()) == 12 ); + auto expr = make_expression( f, "test" ); + x = 12; + expr.prepare(); // update cache state + BOOST_CHECK( expr( static_cast(nullptr)) == 19 ); +} diff --git a/test/test_ExpressionParser.cpp b/test/test_ExpressionParser.cpp new file mode 100644 index 00000000000..2430f1fcda8 --- /dev/null +++ b/test/test_ExpressionParser.cpp @@ -0,0 +1,75 @@ +#define BOOST_TEST_DYN_LINK + +#define BOOST_TEST_MODULE "ExpressionParser" + +#include + +#include "AmpGen/ExpressionParser.h" +#include "AmpGen/MinuitParameterSet.h" + +namespace utf = boost::unit_test; +namespace tt = boost::test_tools; +using namespace AmpGen; + +BOOST_AUTO_TEST_CASE( simple_numericalExpressions ){ + auto test = [](const std::string& expr) -> double { return std::real( ExpressionParser::parse(expr)() ); }; + BOOST_CHECK( test("1 + 2 * 3" ) == 1 + 2 * 3 ); + BOOST_CHECK( test("4 + 2 " ) == 6 ); + BOOST_CHECK( test("3 * 6 - 7 + 2 " ) == 3 * 6 - 7 + 2 ); + BOOST_CHECK( test("6 * 2 + ( 5 - 3 ) * 3 - 8 " ) == 6 * 2 + ( 5 - 3)*3 -8 ); + BOOST_CHECK( test("( 3 + 4 ) + 7 * 2 - 1 - 9 " ) == 3 + 4 + 7 * 2 - 1 - 9); + BOOST_CHECK( test("5 - 2 + 4 * ( 8 - ( 5 + 1 ) ) + 9 " ) == 5 - 2 + 4 *( 8 - (5+1)) +9 ); + BOOST_CHECK( test("( 8 - 1 + 3 ) * 6 - ( ( 3 + 7 ) * 2 )" ) == (8-1+3)*6 - ((3+7)*2) ); +} + +BOOST_AUTO_TEST_CASE( parametericExpressions ) { + + double a = 1.0; + double b = 0.5; + double c = 4.0; + double d = 0.2; + double f = 3.13; + + MinuitParameterSet mps( { + new MinuitParameter("a", Flag::Free, a, 0.) + , new MinuitParameter("b", Flag::Free, b, 0.) + , new MinuitParameter("c", Flag::Free, c, 0.) + , new MinuitParameter("d", Flag::Free, d, 0.) + , new MinuitParameter("f", Flag::Free, f, 0.) + }); + + double pi = M_PI; + + auto test = [&mps](const std::string& expr) -> double { + std::string newLine=""; + for( auto& ch : expr ){ + if( ch == '(' || + ch == ')' || + ch == '+' || + ch == '-' || + ch == '*' || + ch == '/' || + ch == '>' || + ch == '<' || + ch == '^' ){ + newLine.push_back(' '); + newLine.push_back(ch); + newLine.push_back(' '); + } + else newLine.push_back(ch); + } + return std::real( ExpressionParser::parse(newLine, &mps)() ); }; + + BOOST_TEST( test("a+(cos(b-sin(2/a*pi))-sin(a-cos(2*b/pi)))-b") == a+(cos(b-sin(2/a*pi))-sin(a-cos(2*b/pi)))-b ); + BOOST_TEST( test("sin(a)+sin(b)") == sin(a)+sin(b) ); + BOOST_TEST( test("abs(sin(sqrt(a^2+b^2))*255)") == abs(sin(sqrt(a*a+b*b))*255) ); + BOOST_TEST( test("sqrt(a) param("test_param", 4); - BOOST_CHECK( param == 4 ); + AmpGen::NamedParameter param("test_param", 4); + BOOST_CHECK( param == unsigned(4) ); } diff --git a/test/test_Particle.cpp b/test/test_Particle.cpp new file mode 100644 index 00000000000..771aaa2cee5 --- /dev/null +++ b/test/test_Particle.cpp @@ -0,0 +1,18 @@ +#define BOOST_TEST_DYN_LINK + +#define BOOST_TEST_MODULE "Particle" + +#include +#include "AmpGen/Particle.h" + +BOOST_AUTO_TEST_CASE( Particle_quasiStableTree ) +{ + auto d1 = AmpGen::Particle("D~0{D0{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}}}"); + auto d2 = AmpGen::Particle("B+{D0{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}},K+}"); + auto d3 = AmpGen::Particle("B+{D~0{D0{K*(892)0{K+,pi-},rho(770)0{pi+,pi-}}},K+}"); + BOOST_CHECK( d1.quasiStableTree().decayDescriptor() == "D~0{K+,pi+,pi-,pi-}" ); + BOOST_CHECK( d2.quasiStableTree().decayDescriptor() == "B+{D0{K+,pi+,pi-,pi-},K+}" ); + BOOST_CHECK( d3.quasiStableTree().decayDescriptor() == "B+{D~0{K+,pi+,pi-,pi-},K+}" ); +} + + diff --git a/test/test_ParticleProperties.cpp b/test/test_ParticleProperties.cpp index 84085df71b2..010e5624c79 100644 --- a/test/test_ParticleProperties.cpp +++ b/test/test_ParticleProperties.cpp @@ -1,6 +1,6 @@ #define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE "Expression" +#define BOOST_TEST_MODULE "ParticlePropertiesList" #include #include "AmpGen/ParticlePropertiesList.h" diff --git a/test/test_QuarkContent.cpp b/test/test_QuarkContent.cpp new file mode 100644 index 00000000000..b48f3ad873e --- /dev/null +++ b/test/test_QuarkContent.cpp @@ -0,0 +1,24 @@ + +#define BOOST_TEST_DYN_LINK + +#define BOOST_TEST_MODULE "QuarkContent" + +#include +namespace utf = boost::unit_test; + +#include "AmpGen/QuarkContent.h" + +using namespace AmpGen; + +BOOST_AUTO_TEST_CASE( test_QuarkState ) { + + QuarkState uD("uD"); + QuarkState dU("dU"); + + BOOST_CHECK( uD != dU ); + + auto vu = uD + dU; + + BOOST_CHECK( vu.isVacuum()); + +} diff --git a/test/test_avx2d.cpp b/test/test_avx2d.cpp new file mode 100644 index 00000000000..049dc34b186 --- /dev/null +++ b/test/test_avx2d.cpp @@ -0,0 +1,88 @@ + +#define BOOST_TEST_DYN_LINK + +#define BOOST_TEST_MODULE "test_avx2" + +#include +namespace utf = boost::unit_test; + + +#if ENABLE_AVX2d +#include "AmpGen/simd/utils.h" + +using namespace AmpGen; +using namespace AmpGen::AVX2d; +using namespace std::complex_literals; + +#define test_simd( avx_function, scalar_function, data, tv) \ +{ auto r = avx_function( data ).to_array(); auto vals = data.to_array(); \ + for(int i =0;i!=4;++i) BOOST_TEST( r[i] == scalar_function(vals[i]), boost::test_tools::tolerance(tv) ); } + +BOOST_AUTO_TEST_CASE( test_log ) +{ + test_simd( AVX2d::log, std::log, AVX2d::real_v(0.3, 0.5, 10, 7.0), 1e-12 ); +} + +BOOST_AUTO_TEST_CASE( test_complex_log ) +{ + std::array, 4> pr = {0.3 - 3.0*1i, 0.5 - 4.0*1i, 10.+3.*1i, -4.0 + 1.0*1i}; + test_simd( AVX2d::log, std::log, AVX2d::complex_v( pr.data() ), 1e-8 ); +} + +BOOST_AUTO_TEST_CASE( test_fmod ) +{ + std::vector a = {5.1, -5.1, 5.1, -5.1}; + std::vector b = {3.0, +3.0, -3.0, -3.0}; + + AVX2d::real_v av( a.data() ); + AVX2d::real_v bv( b.data() ); + + auto modv = AVX2d::fmod(av,bv); + + auto mod = modv.to_array(); + BOOST_TEST( mod[0] == 2.1 , boost::test_tools::tolerance(1e-15)); + BOOST_TEST( mod[1] == -2.1 , boost::test_tools::tolerance(1e-15)); + BOOST_TEST( mod[2] == 2.1 , boost::test_tools::tolerance(1e-15)); + BOOST_TEST( mod[3] == -2.1 , boost::test_tools::tolerance(1e-15)); +} + +BOOST_AUTO_TEST_CASE( test_double_to_int ) +{ + std::vector a = {17.4, 19.2, 12.1, 4007.3}; + auto f = udouble_to_uint( real_v( a.data() )); + alignas(32) uint64_t t[ utils::size::value ]; + _mm256_store_si256( (__m256i*)t, f); + BOOST_TEST( t[0] == 17 ); + BOOST_TEST( t[1] == 19 ); + BOOST_TEST( t[2] == 12 ); + BOOST_TEST( t[3] == 4007 ); +} + +BOOST_AUTO_TEST_CASE( test_gather ) +{ + // 0 1 2 3 4 5 6 + std::vector data = { 15.4, 19.7, 121.8, -15.6, M_PI, sqrt(2), 5.7, 12 }; + std::vector addr = { 0.2, 5.3, 3.1, 4.1 }; + auto v = AVX2d::gather( data.data(), AVX2d::real_v(addr.data()) ).to_array(); + BOOST_TEST( v[0] == data[0] ); + BOOST_TEST( v[1] == data[5] ); + BOOST_TEST( v[2] == data[3] ); + BOOST_TEST( v[3] == data[4] ); +} + +BOOST_AUTO_TEST_CASE( test_trig ) +{ + auto data = AVX2d::real_v(0.1,0.4,-2.0,5.0); + test_simd( AVX2d::cos, std::cos, data, 1e-15); + test_simd( AVX2d::sin, std::sin, data, 1e-15); + test_simd( AVX2d::tan, std::tan, data, 1e-15); +} + +#else +BOOST_AUTO_TEST_CASE( test_dummy ) +{ + BOOST_TEST( 1 == 1 ); +} +#endif + + diff --git a/test/test_enum.cpp b/test/test_enum.cpp new file mode 100644 index 00000000000..2a3c492c275 --- /dev/null +++ b/test/test_enum.cpp @@ -0,0 +1,22 @@ + +#define BOOST_TEST_DYN_LINK + +#define BOOST_TEST_MODULE "enum" + +#include +namespace utf = boost::unit_test; + +#include "AmpGen/enum.h" + +namespace AmpGen { + make_enum( test_enum, state1, state2, state3 ) +} +using namespace AmpGen; + +BOOST_AUTO_TEST_CASE( test_enums ) +{ + BOOST_CHECK( parse ("state1") == test_enum::state1 ); + BOOST_CHECK( parse ("state2") == test_enum::state2 ); + BOOST_CHECK( parse ("state3") == test_enum::state3 ); + BOOST_CHECK( parse ("blag") == test_enum::Invalid ); +} diff --git a/test/test_phaseSpace.cpp b/test/test_phaseSpace.cpp index 4dc139124af..6bea1fd1380 100644 --- a/test/test_phaseSpace.cpp +++ b/test/test_phaseSpace.cpp @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE( phaseSpace_threeBody ) std::vector test_event = {-0.235918, -0.242689, 0.278177, 1.19862,-0.300608, -0.0584944, -0.0117436, 0.584418, 0.536526, 0.301183, -0.266434, 0.684864} ; - auto new_event = phsp.makeEvent(0); + auto new_event = phsp.makeEvent(); // auto new_event = phsp.generate(); for( int i = 0 ; i < 12 ; ++i ) diff --git a/test/test_utilities.cpp b/test/test_utilities.cpp index c52e2bcd565..0525d029c48 100644 --- a/test/test_utilities.cpp +++ b/test/test_utilities.cpp @@ -1,17 +1,23 @@ #define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE "ArgumentPack" - +#define BOOST_TEST_MODULE "Utilities" #include namespace utf = boost::unit_test; #include "AmpGen/Utilities.h" - BOOST_AUTO_TEST_CASE( test_swap_char ) { std::string test = "hello, world"; AmpGen::swapChars( test, 'h', 'w' ); - BOOST_CHECK( test == "wello, horld"); + BOOST_TEST( test == "wello, horld"); } +BOOST_AUTO_TEST_CASE( test_split ) +{ + std::string test = "hello world tokens"; + auto tokens = AmpGen::split(test,' '); + BOOST_TEST(tokens[0] == "hello"); + BOOST_TEST(tokens[1] == "world"); + BOOST_TEST(tokens[2] == "tokens"); +}