diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..ce947e0 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,82 @@ +stages: + - build + - test + +variables: + LCG_VERSION: "98" + +.production_image: + variables: + LCG_OS: x86_64-centos7 + image: gitlab-registry.cern.ch/ci-tools/ci-worker:cc7 + tags: + - cvmfs + +.lcg_setup: + before_script: + - set +e && source /cvmfs/sft.cern.ch/lcg/views/setupViews.sh LCG_$LCG_VERSION $LCG_OS-$LCG_COMPILER; set -e + +.build_template: + stage: build + extends: + - .lcg_setup + script: + - mkdir install + - mkdir build && cd build + - cmake -DCMAKE_BUILD_TYPE:STRING=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/install -DEVTGEN_HEPMC3:BOOL=ON -DEVTGEN_PYTHIA:BOOL=ON -DEVTGEN_PHOTOS:BOOL=ON -DEVTGEN_TAUOLA:BOOL=ON -DEVTGEN_BUILD_TESTS:BOOL=$BUILD_TESTS $CI_PROJECT_DIR + - cmake --build . + - cmake --build . --target install + +build_clang10_opt: + variables: + LCG_COMPILER: "clang10-opt" + BUILD_TYPE: "Release" + BUILD_TESTS: "OFF" + extends: + - .production_image + - .build_template + +build_gcc10_opt: + variables: + LCG_COMPILER: "gcc10-opt" + BUILD_TYPE: "Release" + BUILD_TESTS: "OFF" + extends: + - .production_image + - .build_template + allow_failure: true + +build_gcc9_opt: + variables: + LCG_COMPILER: "gcc9-opt" + BUILD_TYPE: "Release" + BUILD_TESTS: "OFF" + extends: + - .production_image + - .build_template + +build_gcc9_dbg: + variables: + LCG_COMPILER: "gcc9-dbg" + BUILD_TYPE: "Debug" + BUILD_TESTS: "ON" + extends: + - .production_image + - .build_template + artifacts: + paths: + - install + expire_in: 1 day + +test_placeholder: + stage: test + variables: + LCG_COMPILER: "gcc9-dbg" + extends: + - .production_image + - .lcg_setup + dependencies: + - build_gcc9_dbg + script: + - cd install/share/EvtGen/test + - ./testDecayModel jsonFiles/BppmunuQCD.json diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 18ca882..05a24cc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,55 +1,60 @@ ######################################################################## # Copyright 1998-2020 CERN for the benefit of the EvtGen authors # # # # This file is part of EvtGen. # # # # EvtGen is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # EvtGen is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with EvtGen. If not, see . # ######################################################################## # the test executables require ROOT for histogramming etc. find_package(ROOT QUIET COMPONENTS Hist) +find_package(jsoncpp) if (ROOT_FOUND) add_library(root_interface INTERFACE IMPORTED) target_include_directories(root_interface INTERFACE ${ROOT_INCLUDE_DIRS}) target_link_libraries(root_interface INTERFACE ${ROOT_LIBRARIES}) # build each of the executables - foreach( test_exe evt_dalitz evtgenlhc_test1 example1 exampleWriteHepMC ) + foreach( test_exe evt_dalitz evtgenlhc_test1 example1 exampleWriteHepMC testDecayModel ) add_executable(${test_exe} ${test_exe}.cc) target_link_libraries(${test_exe} PRIVATE EvtGen) if (EVTGEN_HEPMC3) target_compile_definitions(${test_exe} PRIVATE EVTGEN_HEPMC3) endif() if( EVTGEN_PYTHIA OR EVTGEN_PHOTOS OR EVTGEN_TAUOLA ) target_compile_definitions(${test_exe} PRIVATE EVTGEN_EXTERNAL) target_link_libraries(${test_exe} PRIVATE EvtGenExternal) endif() target_link_libraries(${test_exe} PRIVATE root_interface) endforeach() + # testDecayModel needs jsoncpp as well + target_link_libraries(testDecayModel PRIVATE jsoncpp_lib) + # install the executables - install(TARGETS evt_dalitz evtgenlhc_test1 example1 exampleWriteHepMC + install(TARGETS evt_dalitz evtgenlhc_test1 example1 exampleWriteHepMC testDecayModel DESTINATION ${CMAKE_INSTALL_DATADIR}/EvtGen/test ) # install the decay files, macros, scripts, etc. install(DIRECTORY exampleFiles DESTINATION ${CMAKE_INSTALL_DATADIR}/EvtGen/test) + install(DIRECTORY jsonFiles DESTINATION ${CMAKE_INSTALL_DATADIR}/EvtGen/test) install(FILES do_tests DESTINATION ${CMAKE_INSTALL_DATADIR}/EvtGen/test PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) else() message(WARNING "Could not find ROOT, cannot build test executables") endif() diff --git a/test/jsonFiles/BdeltapmunuQCD.json b/test/jsonFiles/BdeltapmunuQCD.json new file mode 100644 index 0000000..68313b5 --- /dev/null +++ b/test/jsonFiles/BdeltapmunuQCD.json @@ -0,0 +1,17 @@ +{ + "parent" : "B-", + "daughters" : ["Delta+", "anti-p-", "mu-", "anti-nu_mu"], + "model" : "BToDiBaryonlnupQCD", + "parameters" : [67.7, -280.0, -187.3, -840.1, -10.1, -157.0, 7.0e6], + "events" : 10000, + "histograms" : [ + {"variable" : "mass", "title" : "mPP", "d1" : 1, "d2" : 2, "nbins" : 100, "xmin" : 1.5, "xmax" : 3.5}, + {"variable" : "mass", "title" : "mMuNu", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : 0.0, "xmax" : 3.5}, + {"variable" : "psumsq", "title" : "qSqMuNu", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : 0.0, "xmax" : 12.0}, + {"variable" : "coshel", "title" : "cosThetaB", "d1" : 1, "d2" : 2, "nbins" : 100, "xmin" : -1.0, "xmax" : 1.0}, + {"variable" : "coshel", "title" : "cosThetaL", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : -1.0, "xmax" : 1.0}, + {"variable" : "prob", "title" : "Prob", "d1" : 0, "d2" : 0, "nbins" : 100, "xmin" : 0.0, "xmax" : 1.0} + ], + "outfile" : "BDeltapmunuQCD.root", + "reference" : "RefBDeltapmunuQCD.root" +} diff --git a/test/jsonFiles/BppmunuQCD.json b/test/jsonFiles/BppmunuQCD.json new file mode 100644 index 0000000..2cea582 --- /dev/null +++ b/test/jsonFiles/BppmunuQCD.json @@ -0,0 +1,17 @@ +{ + "parent" : "B-", + "daughters" : ["p+", "anti-p-", "mu-", "anti-nu_mu"], + "model" : "BToDiBaryonlnupQCD", + "parameters" : [67.7, -280.0, -187.3, -840.1, -10.1, -157.0, 3.0e6], + "events" : 10000, + "histograms" : [ + {"variable" : "mass", "title" : "mPP", "d1" : 1, "d2" : 2, "nbins" : 100, "xmin" : 1.5, "xmax" : 3.5}, + {"variable" : "mass", "title" : "mMuNu", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : 0.0, "xmax" : 3.5}, + {"variable" : "psumsq", "title" : "qSqMuNu", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : 0.0, "xmax" : 12.0}, + {"variable" : "coshel", "title" : "cosThetaB", "d1" : 1, "d2" : 2, "nbins" : 100, "xmin" : -1.0, "xmax" : 1.0}, + {"variable" : "coshel", "title" : "cosThetaL", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : -1.0, "xmax" : 1.0}, + {"variable" : "prob", "title" : "Prob", "d1" : 0, "d2" : 0, "nbins" : 100, "xmin" : 0.0, "xmax" : 1.0} + ], + "outfile" : "BppmunuQCD.root", + "reference" : "RefBppmunuQCD.root" +} diff --git a/test/jsonFiles/EtaEEPiPi.json b/test/jsonFiles/EtaEEPiPi.json new file mode 100644 index 0000000..434e83d --- /dev/null +++ b/test/jsonFiles/EtaEEPiPi.json @@ -0,0 +1,18 @@ +{ + "parent" : "eta'", + "daughters" : ["e+", "e-", "pi+", "pi-"], + "model" : "ETA_LLPIPI", + "parameters" : [], + "events" : 10000, + "histograms" : [ + {"variable" : "mass", "title" : "mPiPi", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : 0.0, "xmax" : 1.0}, + {"variable" : "mass", "title" : "mLL" , "d1" : 1, "d2" : 2, "nbins" : 100, "xmin" : 0.0, "xmax" : 0.5}, + {"variable" : "mass", "title" : "mPiL1", "d1" : 1, "d2" : 4, "nbins" : 100, "xmin" : 0.0, "xmax" : 0.85}, + {"variable" : "mass", "title" : "mPiL2", "d1" : 2, "d2" : 3, "nbins" : 100, "xmin" : 0.0, "xmax" : 0.85}, + {"variable" : "coshel", "title" : "cosL", "d1" : 1, "d2" : 2, "nbins" : 100, "xmin" : -1.0, "xmax" : 1.0}, + {"variable" : "coshel", "title" : "cosPi", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : -1.0, "xmax" : 1.0}, + {"variable" : "prob", "title" : "Prob", "d1" : 0, "d2" : 0, "nbins" : 100, "xmin" : 0.0, "xmax" : 1.0} + ], + "outfile" : "EtaEEPiPi.root", + "reference" : "RefEtaEEPiPi.root" +} diff --git a/test/jsonFiles/EtaMuMuPiPi.json b/test/jsonFiles/EtaMuMuPiPi.json new file mode 100644 index 0000000..42eeffe --- /dev/null +++ b/test/jsonFiles/EtaMuMuPiPi.json @@ -0,0 +1,18 @@ +{ + "parent" : "eta'", + "daughters" : ["mu+", "mu-", "pi+", "pi-"], + "model" : "ETA_LLPIPI", + "parameters" : [], + "events" : 10000, + "histograms" : [ + {"variable" : "mass", "title" : "mPiPi", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : 0.0, "xmax" : 1.0}, + {"variable" : "mass", "title" : "mLL" , "d1" : 1, "d2" : 2, "nbins" : 100, "xmin" : 0.0, "xmax" : 0.5}, + {"variable" : "mass", "title" : "mPiL1", "d1" : 1, "d2" : 4, "nbins" : 100, "xmin" : 0.0, "xmax" : 0.85}, + {"variable" : "mass", "title" : "mPiL2", "d1" : 2, "d2" : 3, "nbins" : 100, "xmin" : 0.0, "xmax" : 0.85}, + {"variable" : "coshel", "title" : "cosL", "d1" : 1, "d2" : 2, "nbins" : 100, "xmin" : -1.0, "xmax" : 1.0}, + {"variable" : "coshel", "title" : "cosPi", "d1" : 3, "d2" : 4, "nbins" : 100, "xmin" : -1.0, "xmax" : 1.0}, + {"variable" : "prob", "title" : "Prob", "d1" : 0, "d2" : 0, "nbins" : 100, "xmin" : 0.0, "xmax" : 1.0} + ], + "outfile" : "EtaMuMuPiPi.root", + "reference" : "RefEtaMuMuPiPi.root" +} diff --git a/test/testDecayModel.cc b/test/testDecayModel.cc new file mode 100644 index 0000000..817e8c0 --- /dev/null +++ b/test/testDecayModel.cc @@ -0,0 +1,357 @@ + +/*********************************************************************** +* Copyright 1998-2020 CERN for the benefit of the EvtGen authors * +* * +* This file is part of EvtGen. * +* * +* EvtGen is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* EvtGen is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with EvtGen. If not, see . * +***********************************************************************/ + +#include "testDecayModel.hh" + +#include "EvtGen/EvtGen.hh" + +#include "EvtGenBase/EvtAbsRadCorr.hh" +#include "EvtGenBase/EvtDecayBase.hh" +#include "EvtGenBase/EvtId.hh" +#include "EvtGenBase/EvtMTRandomEngine.hh" +#include "EvtGenBase/EvtParticle.hh" +#include "EvtGenBase/EvtParticleFactory.hh" +#include "EvtGenBase/EvtPDL.hh" +#include "EvtGenBase/EvtVector4R.hh" + +#ifdef EVTGEN_EXTERNAL +#include "EvtGenExternal/EvtExternalGenList.hh" +#endif + +#include +#include +#include +#include +#include + +testDecayModel::testDecayModel( const std::string& jsonFile ) : + m_jsonFile( jsonFile ), + m_infoVect(), + m_histVect(), + m_nHistos( 0 ) +{ +} + +void testDecayModel::run() { + + Json::Value config; + std::ifstream inputStr( m_jsonFile.c_str() ); + inputStr >> config; + inputStr.close(); + + const std::string parentName = config["parent"].asString(); + + Json::Value jDaughters = config["daughters"]; + std::vector daugNames; + for ( auto daugN : jDaughters ) { + daugNames.push_back( daugN.asString() ); + } + + const std::string modelName = config["model"].asString(); + + Json::Value jParameters = config["parameters"]; + std::vector modelPars; + for ( auto par : jParameters ) { + modelPars.push_back( par.asDouble() ); + } + + // Create decay file based on json file input + const std::string decFile = createDecFile( parentName, daugNames, + modelName, modelPars ); + + int nEvents = config["events"].asInt(); + std::cout << "Number of events = " << nEvents << std::endl; + + // ROOT output file + const std::string outFileName = config["outfile"].asString(); + TFile* outFile = TFile::Open( outFileName.c_str(), "recreate" ); + + // Define histograms + defineHistos( config, outFile ); + + // Generate events and fill histograms + generateEvents( decFile, parentName, nEvents ); + + // Normalize histograms + for ( auto hist : m_histVect ) { + double area = hist->Integral(); + if ( area > 0.0 ) { hist->Scale( 1.0/area ); } + } + + // Compare with reference histograms + const std::string refFileName = config["reference"].asString(); + compareHistos( refFileName ); + + // Write output + outFile->cd(); + for ( auto hist : m_histVect ) { + hist->Write(); + } + outFile->Close(); + +} + +std::string testDecayModel::createDecFile( const std::string& parent, + const std::vector& daugNames, + const std::string& modelName, + const std::vector& parameters ) const +{ + + // Create (or overwrite) the decay file + std::string decName( modelName ); decName += ".dec"; + std::ofstream decFile; + decFile.open( decName.c_str() ); + + decFile << "Decay " << parent << std::endl; + decFile << "1.0"; + for ( auto daug : daugNames ) { + decFile << " " << daug; + } + decFile << " " << modelName; + for ( auto par : parameters ) { + decFile << " " << par; + } + decFile << ";" << std::endl; + decFile << "Enddecay" << std::endl; + decFile << "End" << std::endl; + + decFile.close(); + + return decName; + +} + +void testDecayModel::defineHistos( Json::Value& config, TFile* outFile ) { + + // Histogram information + Json::Value jHistos = config["histograms"]; + size_t nHistos = jHistos.size(); + + m_infoVect.reserve( nHistos ); + m_histVect.reserve( nHistos ); + + for ( auto hInfo : jHistos ) { + + const std::string varName = hInfo["variable"].asString(); + // Integer values that define what particles need to be used + // for invariant mass combinations or helicity angles etc + int d1 = hInfo["d1"].asInt(); + int d2 = hInfo["d2"].asInt(); + + testInfo info( varName, d1, d2 ); + m_infoVect.push_back( info ); + + const std::string varTitle = hInfo["title"].asString(); + int nBins = hInfo["nbins"].asInt(); + double xmin = hInfo["xmin"].asDouble(); + double xmax = hInfo["xmax"].asDouble(); + + TString histName( varName.c_str() ); + if ( d1 != 0 ) { histName += "_"; histName += d1; } + if ( d2 != 0 ) { histName += "_"; histName += d2; } + TH1D* hist = new TH1D( histName.Data(), varTitle.c_str(), nBins, xmin, xmax ); + hist->SetDirectory( outFile ); + m_histVect.push_back( hist ); + + } + + m_nHistos = m_histVect.size(); + +} + +void testDecayModel::generateEvents( const std::string& decFile, const std::string& parentName, + int nEvents ) { + + // Define the random number generator + auto randomEngine = std::make_unique(); + + EvtAbsRadCorr* radCorrEngine = nullptr; + std::list extraModels; + +#ifdef EVTGEN_EXTERNAL + bool convertPythiaCodes( false ); + bool useEvtGenRandom( true ); + EvtExternalGenList genList( convertPythiaCodes, "", "gamma", useEvtGenRandom ); + radCorrEngine = genList.getPhotosModel(); + extraModels = genList.getListOfModels(); +#endif + + EvtGen theGen( "../DECAY.DEC", "../evt.pdl", randomEngine.get(), + radCorrEngine, &extraModels ); + + theGen.readUDecay( decFile.c_str() ); + + // Generate the decays + EvtId parId = EvtPDL::getId( parentName.c_str() ); + for ( int i = 0; i < nEvents; i++ ) { + + if ( i%1000 == 0 ) { std::cout << "Event " << nEvents - i << std::endl; } + + // Initial 4-momentum and particle + EvtVector4R pInit( EvtPDL::getMass( parId ), 0.0, 0.0, 0.0 ); + EvtParticle* parent = EvtParticleFactory::particleFactory( parId, pInit ); + + theGen.generateDecay( parent ); + + // Store information + for ( size_t i = 0; i < m_nHistos; i++ ) { + + testInfo info = m_infoVect[i]; + double value = getValue( parent, info.getName(), info.getd1(), info.getd2() ); + + TH1D* hist = m_histVect[i]; + if ( hist ) { + hist->Fill( value ); + } + + } + + //parent->printTree(); + + // Cleanup + parent->deleteTree(); + + } + +} + +double testDecayModel::getValue( EvtParticle* parent, const std::string& varName, + const int d1, const int d2 ) const { + + double value( 0.0 ); + if ( !parent ) { return value; } + + // Daughters + const EvtParticle* par1 = d1 > 0 ? parent->getDaug( d1 - 1 ) : nullptr; + const EvtParticle* par2 = d2 > 0 ? parent->getDaug( d2 - 1 ) : nullptr; + + // 4-momenta (in parent rest frame) + const EvtVector4R p1 = par1 != nullptr ? par1->getP4() : EvtVector4R(); + const EvtVector4R p2 = par2 != nullptr ? par2->getP4() : EvtVector4R(); + + if ( !varName.compare( "mass" ) ) { + + // Invariant mass + if ( d2 != 0 ) { + // Invariant 4-mass combination of particles d1 and d2 + value = ( p1 + p2 ).mass(); + } else { + // Invariant mass of particle d1 only + value = p1.mass(); + } + + } else if ( !varName.compare( "psumsq" ) ) { + + // Invariant momentum sum squared + value = ( p1 + p2 ).mass2(); + + } else if ( !varName.compare( "pdiffsq" ) ) { + + // Invariant momentum difference squared + value = ( p1 - p2 ).mass2(); + + } else if ( !varName.compare( "mtm" ) ) { + + // Momentum of particle d1 + value = p1.d3mag(); + + } else if ( !varName.compare( "coshel" ) ) { + + // Cosine of helicity angle + + // Resonance center-of-mass system (d1 and d2) + const EvtVector4R p12 = p1 + p2; + // Boost vector + const EvtVector4R boost( p12.get( 0 ), -p12.get( 1 ), -p12.get( 2 ), -p12.get( 3 ) ); + // Momentum of particle d1 in resonance frame, p1Res + const EvtVector4R p1Res = boostTo( p1, boost ); + // Cosine of angle between p1Res and momentum of resonance in parent frame + double p1ResMag = p1Res.d3mag(); + double p12Mag = p12.d3mag(); + if ( p1ResMag > 0.0 && p12Mag > 0.0 ) { + value = p1Res.dot( p12 ) / ( p1ResMag * p12Mag ); + } + + } else if ( !varName.compare( "prob" ) ) { + + // Decay probability + double* dProb = parent->decayProb(); + if ( dProb ) { + value = *dProb; + } + + } + + return value; + +} + +void testDecayModel::compareHistos( const std::string& refFileName ) const { + + // Compare histograms with the same name, calculating the chi-squared + TFile* refFile = TFile::Open( refFileName.c_str(), "read" ); + + if ( !refFile ) { + std::cout << "Could not open reference file " << refFileName << std::endl; + return; + } + + for ( auto hist : m_histVect ) { + + const std::string histName = hist->GetName(); + // Get equivalent reference histogram + const TH1* refHist = dynamic_cast( refFile->Get ( histName.c_str() ) ); + + if ( refHist ) { + + double chiSq( 0.0 ); + int nDof( 0 ); + int iGood( 0 ); + double pValue = refHist->Chi2TestX( hist, chiSq, nDof, iGood, "WW" ); + std::cout << "Histogram " << histName << " chiSq/nDof = " + << chiSq << "/" << nDof << ", pValue = " << pValue << std::endl; + + } else { + + std::cout << "Could not find reference histogram " << histName << std::endl; + + } + + } + + refFile->Close(); + +} + +int main( int argc, char* argv[] ) { + + if ( argc != 2 ) { + std::cout << "Expecting one argument: json input file" << std::endl; + return -1; + } + + const std::string jsonFile = argv[1]; + + testDecayModel test( jsonFile ); + test.run(); + + return 0; + +} diff --git a/test/testDecayModel.hh b/test/testDecayModel.hh new file mode 100644 index 0000000..10b2196 --- /dev/null +++ b/test/testDecayModel.hh @@ -0,0 +1,87 @@ + +/*********************************************************************** +* Copyright 1998-2020 CERN for the benefit of the EvtGen authors * +* * +* This file is part of EvtGen. * +* * +* EvtGen is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* EvtGen is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with EvtGen. If not, see . * +***********************************************************************/ + +#ifndef TEST_DECAY_MODEL_HH +#define TEST_DECAY_MODEL_HH + +#include "json/json.h" + +#include "TFile.h" +#include "TH1D.h" + +#include +#include + +class EvtParticle; + +class testInfo { + + public: + testInfo( const std::string& name, int d1, int d2 ) : + m_name( name ), + m_d1( d1 ), + m_d2( d2 ) + {;} + + const std::string getName() const { return m_name; } + int getd1() const { return m_d1; } + int getd2() const { return m_d2; } + + private: + std::string m_name; + int m_d1; + int m_d2; + +}; + +class testDecayModel { + + public: + + testDecayModel( const std::string& jsonFile ); + + void run(); + + private: + + std::string createDecFile( const std::string& parent, + const std::vector& daugNames, + const std::string& model, + const std::vector& parameters ) const; + + void defineHistos( Json::Value& config, TFile* theFile ); + + void generateEvents( const std::string& decFile, const std::string& parentName, + int nEvents ); + + double getValue( EvtParticle* rootPart, const std::string& varName, + const int d1, const int d2 ) const; + + void compareHistos( const std::string& refFileName ) const; + + std::string m_jsonFile; + std::vector m_infoVect; + std::vector m_histVect; + size_t m_nHistos; + + +}; + +#endif