From d965898bc8a20f590f786cb3c7c9ae248059639e Mon Sep 17 00:00:00 2001 From: Nils Krumnack <krumnack@iastate.edu> Date: Mon, 25 Jan 2021 11:52:13 -0600 Subject: [PATCH] add AnaReentrantAlgorithm Mostly a copy-and-paste of AnaAlgorithm, with cleanup and updates to inherit from AthReentrantAlgorithm. --- .../AnaAlgorithm/AnaAlgorithmDict.h | 3 + .../AnaAlgorithm/AnaReentrantAlgorithm.h | 243 ++++++++++++++++++ .../AnaReentrantAlgorithmConfig.h | 96 +++++++ .../AnaReentrantAlgorithmWrapper.h | 80 ++++++ .../AnaAlgorithm/AnaAlgorithm/Global.h | 3 + .../AnaAlgorithm/AnaAlgorithm/selection.xml | 3 + .../Root/AnaReentrantAlgorithm.cxx | 174 +++++++++++++ .../Root/AnaReentrantAlgorithmConfig.cxx | 66 +++++ .../Root/AnaReentrantAlgorithmWrapper.cxx | 138 ++++++++++ .../D3PDTools/EventLoop/EventLoop/Job.h | 1 + .../D3PDTools/EventLoop/Root/Job.cxx | 10 + .../EventLoopTest/EventLoopTestDict.h | 1 + .../EventLoopTest/UnitTestAlg6.h | 49 ++++ .../EventLoopTest/EventLoopTest/selection.xml | 1 + .../EventLoopTest/Root/UnitTestAlg6.cxx | 69 +++++ .../test/gt_AnaAlgorithmWrapper.cxx | 26 -- .../test/gt_AnaReentrantAlgorithm.cxx | 143 +++++++++++ 17 files changed, 1080 insertions(+), 26 deletions(-) create mode 100644 PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithm.h create mode 100644 PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithmConfig.h create mode 100644 PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithmWrapper.h create mode 100644 PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithm.cxx create mode 100644 PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithmConfig.cxx create mode 100644 PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithmWrapper.cxx create mode 100644 PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/UnitTestAlg6.h create mode 100644 PhysicsAnalysis/D3PDTools/EventLoopTest/Root/UnitTestAlg6.cxx delete mode 100644 PhysicsAnalysis/D3PDTools/EventLoopTest/test/gt_AnaAlgorithmWrapper.cxx create mode 100644 PhysicsAnalysis/D3PDTools/EventLoopTest/test/gt_AnaReentrantAlgorithm.cxx diff --git a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaAlgorithmDict.h b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaAlgorithmDict.h index dcd2748c0f84..7272b827d21b 100644 --- a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaAlgorithmDict.h +++ b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaAlgorithmDict.h @@ -6,9 +6,12 @@ #endif #include "AnaAlgorithm/AnaAlgorithm.h" +#include "AnaAlgorithm/AnaReentrantAlgorithm.h" #ifdef ROOTCORE #include "AnaAlgorithm/AnaAlgorithmConfig.h" #include "AnaAlgorithm/AnaAlgorithmWrapper.h" +#include "AnaAlgorithm/AnaReentrantAlgorithmConfig.h" +#include "AnaAlgorithm/AnaReentrantAlgorithmWrapper.h" #endif #endif diff --git a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithm.h b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithm.h new file mode 100644 index 000000000000..dac78f83b7bf --- /dev/null +++ b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithm.h @@ -0,0 +1,243 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ANA_ALGORITHM__ANA_REENTRANT_ALGORITHM_H +#define ANA_ALGORITHM__ANA_REENTRANT_ALGORITHM_H + +#include <AnaAlgorithm/Global.h> + +#ifdef XAOD_STANDALONE +#include <AsgTools/AsgComponent.h> +#include <AsgTools/SgTEvent.h> +#include <memory> +#include <vector> +#else +#include <AthenaBaseComps/AthReentrantAlgorithm.h> +#include <AsgMessaging/MessageCheck.h> +#endif + +class EventContext; +class ISvcLocator; + +namespace EL +{ +#ifdef XAOD_STANDALONE + class IWorker; +#endif + + /// \brief the base class for EventLoop reentrant algorithms + /// + /// Technically EventLoop doesn't use that algorithms are reentrant, + /// but when writing a dual-use algorithm it is preferable for it to + /// be reentrant in Athena, and for that it needs its own interface + /// class. + /// + /// Please note that if you use this algorithm base class you + /// absolutely must use data handles for accessing the event store. + /// While it makes zero difference in EventLoop, it doesn't work + /// otherwise in AthenaMT, which defeats the whole purpose of using + /// this class. + + class AnaReentrantAlgorithm +#ifdef XAOD_STANDALONE + : public asg::AsgComponent +#else + : public AthReentrantAlgorithm +#endif + { + // + // public interface + // + + /// \brief constructor with parameters + /// + /// This matches the Athena algorithm constructor (for dual-use + /// purposes). Within EventLoop the `pSvcLocator` will always be + /// `nullptr` (unless we ever have dual-use services). + /// + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + AnaReentrantAlgorithm (const std::string& name, + ISvcLocator* pSvcLocator); + + /// \brief standard (virtual) destructor + /// \par Guarantee + /// no-fail + public: + virtual ~AnaReentrantAlgorithm() noexcept; + + + + // + // services interface + // + +#ifdef XAOD_STANDALONE + /// \brief the filter worker interface + /// \par Guarantee + /// strong + /// \par Failures + /// no filter worker configured + /// \post result != nullptr + public: + IFilterWorker *filterWorker () const; + + + /// \brief whether the current algorithm passed its filter + /// criterion for the current event + /// \par Guarantee + /// no-fail + public: + bool filterPassed() const; + + /// \brief set the value of \ref filterPassed + /// \par Guarantee + /// no-fail + public: + void setFilterPassed (bool val_filterPassed); + + + /// \brief the worker that is controlling us (if working in + /// EventLoop) + /// \par Guarantee + /// strong + /// \par Failures + /// job not running in EventLoop + /// \post result != nullptr + public: + IWorker *wk () const; +#endif + + + + // + // virtual interface + // + + /// \brief initialize this algorithm + /// + /// Note that unlike the original EventLoop algorithms, this gets + /// called before any events are in memory (or at least it can + /// be). As such you should *not* try to access the current event + /// in here. + protected: + virtual ::StatusCode initialize (); + + /// \brief execute this algorithm + /// + /// This gets called once on every event and is where the bulk of + /// the processing ought to be happening. + protected: + virtual ::StatusCode execute (const EventContext& ctx); + + /// \brief finalize this algorithm + /// + /// This gets called after event processing has finished. The + /// last event may no longer be in memory, and the code should not + /// try to access it. + protected: + virtual ::StatusCode finalize (); + + + + // + // framework interface + // + +#ifdef XAOD_STANDALONE + /// \brief call \ref initialize + public: + ::StatusCode sysInitialize (); + + /// \brief call \ref execute + public: + ::StatusCode sysExecute (const EventContext& ctx); + + /// \brief call \ref finalize + public: + ::StatusCode sysFinalize (); + + + /// \brief get the (main) event store for this algorithm + /// + /// \par Guarantee + /// strong + /// \par Failures + /// job not configured for xAODs + /// \post result != nullptr + /// + /// \warn The user should *not* be calling this function directly, + /// ever, and it may very well disappear at any point without + /// notice, and it does *not* exist in Athena which defeats the + /// whole purpose of having a reentrant algorithm. + /// + /// It is essentially here because the stand-alone data handles + /// need it. Basically there are three solutions I considered: + /// * make it a public member function for compatibility and warn all + /// users against using it directly + /// * make it a private member function, and make all data handles + /// friends, but that would be a lot of friends + /// * change the implementation of all data handles to no longer require + /// this function, which would be quite an intrusive change + public: + asg::SgTEvent *evtStore() const; + + /// \brief set the value of \ref evtStore + /// \par Guarantee + /// strong + /// \par Failures + /// service already configured + public: + void setEvtStore (asg::SgTEvent *val_evtStore); + + /// \brief set the value of \ref filterWorker + /// \par Guarantee + /// strong + /// \par Failures + /// service already configured + public: + void setFilterWorker (IFilterWorker *val_filterWorker); + + /// \brief set the value of \ref wk + /// \par Guarantee + /// strong + /// \par Failures + /// service already configured + public: + void setWk (IWorker *val_wk); +#endif + + + + // + // private interface + // + +#ifdef XAOD_STANDALONE + /// \brief the value of \ref evtStore + private: + asg::SgTEvent *m_evtStore = nullptr; +#endif + +#ifdef XAOD_STANDALONE + /// \brief the value of \ref filterWorker + private: + IFilterWorker *m_filterWorker = nullptr; +#endif + +#ifdef XAOD_STANDALONE + /// \brief the value of \ref wk + private: + IWorker *m_wk = nullptr; +#endif + }; +} + +#endif diff --git a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithmConfig.h b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithmConfig.h new file mode 100644 index 000000000000..aba9597a4224 --- /dev/null +++ b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithmConfig.h @@ -0,0 +1,96 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef ANA_ALGORITHM__ANA_REENTRANT_ALGORITHM_CONFIG_H +#define ANA_ALGORITHM__ANA_REENTRANT_ALGORITHM_CONFIG_H + +#ifndef ROOTCORE +#error only include this header in AnalysisBase +#endif + +#include <AnaAlgorithm/Global.h> + +#include <AsgTools/AsgComponentConfig.h> + +namespace EL +{ + struct AlgorithmWorkerData; + + /// \brief an object that can create a \ref AnaReentrantAlgorithm + + class AnaReentrantAlgorithmConfig : public asg::AsgComponentConfig + { + // + // public interface + // + + /// \brief test the invariant of this object + /// \par Guarantee + /// no-fail + public: + void testInvariant () const; + + + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory I + public: + AnaReentrantAlgorithmConfig (); + + + /// \brief initializing constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + explicit AnaReentrantAlgorithmConfig (const std::string& val_typeAndName); + + + /// \brief Virtual destructor, to make PyROOT happy + /// + /// Without it ROOT 6.22+ does not allow Python classes to inherit from this + /// type. + /// + public: + virtual ~AnaReentrantAlgorithmConfig() = default; + + + /// \brief make an algorithm from this configuration + /// + /// Note that generally users won't call this function. The + /// typical workflow is to fully configure this object and then + /// hand it over to EventLoop which will take care of creating the + /// actual algorithm. + /// + /// An exception may be unit tests. If this turns out to be too + /// cumbersome for unit testing we may need to revisit it at that + /// point. For now it is unclear whether we'll even be able to do + /// algorithm unit testing either way. + /// + /// \par Guarantee + /// strong + /// \par Failures + /// configuration errors\n + /// algorithm creation/initialization errors + public: + ::StatusCode + makeAlgorithm (std::unique_ptr<AnaReentrantAlgorithm>& algorithm, + const AlgorithmWorkerData& workerData) const; + + + + // + // private interface + // + }; +} + +#endif diff --git a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithmWrapper.h b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithmWrapper.h new file mode 100644 index 000000000000..0a07964a3773 --- /dev/null +++ b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/AnaReentrantAlgorithmWrapper.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef ANA_ALGORITHM__ANA_REENTRANT_ALGORITHM_WRAPPER_H +#define ANA_ALGORITHM__ANA_REENTRANT_ALGORITHM_WRAPPER_H + +#include <AnaAlgorithm/Global.h> + +#include <AnaAlgorithm/AnaReentrantAlgorithm.h> +#include <AnaAlgorithm/AnaReentrantAlgorithmConfig.h> +#include <AnaAlgorithm/IAlgorithmWrapper.h> + +namespace EL +{ + /// \brief an \ref IAlgorithmWrapper for \ref AnaReentrantAlgorithm + + class AnaReentrantAlgorithmWrapper final : public IAlgorithmWrapper + { + public: + + /// Public Members + /// ============== + + /// \brief test the invariant of this object + void testInvariant () const; + + /// \brief standard default constructor for serialization + AnaReentrantAlgorithmWrapper () {}; + + /// \brief standard constructor + AnaReentrantAlgorithmWrapper (AnaReentrantAlgorithmConfig val_config); + + + + /// Inherited Members + /// ================= + + virtual std::string_view getName () const override; + + virtual bool hasName (const std::string& name) const override; + + virtual std::unique_ptr<IAlgorithmWrapper> makeClone() const override; + + virtual StatusCode initialize (const AlgorithmWorkerData& workerData) override; + + virtual StatusCode execute () override; + + virtual StatusCode finalize () override; + + virtual ::StatusCode fileExecute () override; + + virtual ::StatusCode beginInputFile () override; + + virtual ::StatusCode endInputFile () override; + + + + /// Private Members + /// =============== + + private: + + /// \brief the algorithm configuration + AnaReentrantAlgorithmConfig m_config; + + /// \brief the actual algorithm (once instantiated) + /// + /// Please note (and do not remove) the comment at the end of the + /// line. This specifically excludes this member from + /// serialization. + std::unique_ptr<AnaReentrantAlgorithm> m_algorithm; //! + }; +} + +#endif diff --git a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/Global.h b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/Global.h index f13ec53864e4..ae509877dda9 100644 --- a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/Global.h +++ b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/Global.h @@ -12,11 +12,14 @@ namespace EL { class AnaAlgorithm; + class AnaReentrantAlgorithm; #ifdef ROOTCORE struct AlgorithmWorkerData; class AnaAlgorithmConfig; class AnaAlgorithmWrapper; + class AnaReentrantAlgorithmConfig; + class AnaReentrantAlgorithmWrapper; class IAlgorithmWrapper; class IFilterWorker; class IHistogramWorker; diff --git a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/selection.xml b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/selection.xml index a5a5cda36bfa..0784b579a72f 100644 --- a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/selection.xml +++ b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/AnaAlgorithm/selection.xml @@ -3,6 +3,9 @@ <class name="EL::AnaAlgorithm" /> <class name="EL::AnaAlgorithmConfig" /> <class name="EL::AnaAlgorithmWrapper" /> + <class name="EL::AnaReentrantAlgorithm" /> + <class name="EL::AnaReentrantAlgorithmConfig" /> + <class name="EL::AnaReentrantAlgorithmWrapper" /> <class name="EL::IAlgorithmWrapper" /> </lcgdict> diff --git a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithm.cxx b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithm.cxx new file mode 100644 index 000000000000..a47218a346a2 --- /dev/null +++ b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithm.cxx @@ -0,0 +1,174 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <AnaAlgorithm/AnaReentrantAlgorithm.h> + +#include <AsgMessaging/MessageCheck.h> +#include <RootCoreUtils/Assert.h> +#include <stdexcept> + +#ifdef XAOD_STANDALONE +#include <AnaAlgorithm/IFilterWorker.h> +#endif + +// +// method implementations +// + +namespace EL +{ + AnaReentrantAlgorithm :: + AnaReentrantAlgorithm (const std::string& name, + [[maybe_unused]] ISvcLocator *pSvcLocator) +#ifdef XAOD_STANDALONE + : AsgComponent (name) +#else + : AthReentrantAlgorithm (name, pSvcLocator) +#endif + { + ANA_MSG_DEBUG ("AnaReentrantAlgorithm: " << name); + } + + + + AnaReentrantAlgorithm :: + ~AnaReentrantAlgorithm () noexcept + {} + + + +#ifdef XAOD_STANDALONE + bool AnaReentrantAlgorithm :: + filterPassed() const + { + return filterWorker()->filterPassed(); + } + + + + void AnaReentrantAlgorithm :: + setFilterPassed (bool val_filterPassed) + { + filterWorker()->setFilterPassed (val_filterPassed); + } + + + + IFilterWorker *AnaReentrantAlgorithm :: + filterWorker () const + { + if (!m_filterWorker) + throw std::logic_error ("no filter worker set on algorithm " + name()); + return m_filterWorker; + } + + + + IWorker *AnaReentrantAlgorithm :: + wk () const + { + if (!m_wk) + throw std::logic_error ("no worker set on algorithm " + name()); + return m_wk; + } +#endif + + + + ::StatusCode AnaReentrantAlgorithm :: + initialize () + { + return StatusCode::SUCCESS; + } + + + + ::StatusCode AnaReentrantAlgorithm :: + execute (const EventContext& /*ctx*/) + { + return StatusCode::SUCCESS; + } + + + + ::StatusCode AnaReentrantAlgorithm :: + finalize () + { + return StatusCode::SUCCESS; + } + + + +#ifdef XAOD_STANDALONE + ::StatusCode AnaReentrantAlgorithm :: + sysInitialize () + { + return initialize (); + } + + + + ::StatusCode AnaReentrantAlgorithm :: + sysExecute (const EventContext& ctx) + { + return execute (ctx); + } + + + + ::StatusCode AnaReentrantAlgorithm :: + sysFinalize () + { + return finalize (); + } + + + + asg::SgTEvent *AnaReentrantAlgorithm :: + evtStore () const + { + if (!m_evtStore) + throw std::logic_error ("no evtStore set on algorithm " + name()); + return m_evtStore; + } + + + + void AnaReentrantAlgorithm :: + setEvtStore (asg::SgTEvent *val_evtStore) + { + if (m_evtStore) + throw std::logic_error ("set evtStore twice on algorithm " + name()); + m_evtStore = val_evtStore; + } + + + + void AnaReentrantAlgorithm :: + setFilterWorker (IFilterWorker *val_filterWorker) + { + if (m_filterWorker) + throw std::logic_error ("set filter worker twice on algorithm " + name()); + m_filterWorker = val_filterWorker; + } + + + + void AnaReentrantAlgorithm :: + setWk (IWorker *val_wk) + { + if (m_wk) + throw std::logic_error ("set wk twice on algorithm " + name()); + m_wk = val_wk; + } +#endif +} diff --git a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithmConfig.cxx b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithmConfig.cxx new file mode 100644 index 000000000000..6cd45ac8d93b --- /dev/null +++ b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithmConfig.cxx @@ -0,0 +1,66 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <AnaAlgorithm/AnaReentrantAlgorithmConfig.h> + +#include <AnaAlgorithm/AnaReentrantAlgorithm.h> +#include <AnaAlgorithm/AlgorithmWorkerData.h> +#include <AnaAlgorithm/MessageCheck.h> +#include <AsgTools/AsgTool.h> +#include <RootCoreUtils/Assert.h> + +// +// method implementations +// + +namespace EL +{ + void AnaReentrantAlgorithmConfig :: + testInvariant () const + { + } + + + + AnaReentrantAlgorithmConfig :: + AnaReentrantAlgorithmConfig () + { + RCU_NEW_INVARIANT (this); + } + + + + AnaReentrantAlgorithmConfig :: + AnaReentrantAlgorithmConfig (const std::string& val_typeAndName) + : AsgComponentConfig (val_typeAndName) + { + RCU_NEW_INVARIANT (this); + } + + + + ::StatusCode AnaReentrantAlgorithmConfig :: + makeAlgorithm (std::unique_ptr<AnaReentrantAlgorithm>& algorithm, + const AlgorithmWorkerData& workerData) const + { + RCU_READ_INVARIANT (this); + using namespace msgAlgorithmConfig; + + ANA_CHECK (makeComponentExpert (algorithm, "new %1% (\"%2%\", nullptr)", true, "")); + algorithm->setFilterWorker (workerData.m_filterWorker); + algorithm->setWk (workerData.m_wk); + if (workerData.m_evtStore) + algorithm->setEvtStore (workerData.m_evtStore); + ANA_CHECK (algorithm->sysInitialize()); + return StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithmWrapper.cxx b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithmWrapper.cxx new file mode 100644 index 000000000000..d1bd7f8d878a --- /dev/null +++ b/PhysicsAnalysis/D3PDTools/AnaAlgorithm/Root/AnaReentrantAlgorithmWrapper.cxx @@ -0,0 +1,138 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <AnaAlgorithm/AnaReentrantAlgorithmWrapper.h> + +#include <AnaAlgorithm/MessageCheck.h> +#include <AsgTools/CurrentContext.h> +#include <RootCoreUtils/Assert.h> + +// +// method implementations +// + +namespace EL +{ + void AnaReentrantAlgorithmWrapper :: + testInvariant () const + { + RCU_INVARIANT (!m_config.name().empty()); + } + + + + AnaReentrantAlgorithmWrapper :: + AnaReentrantAlgorithmWrapper (AnaReentrantAlgorithmConfig val_config) + : m_config (std::move (val_config)) + { + RCU_NEW_INVARIANT (this); + } + + + + std::string_view AnaReentrantAlgorithmWrapper :: + getName () const + { + RCU_READ_INVARIANT (this); + return m_config.name(); + } + + + + bool AnaReentrantAlgorithmWrapper :: + hasName (const std::string& name) const + { + RCU_READ_INVARIANT (this); + return m_config.name() == name; + } + + + + std::unique_ptr<IAlgorithmWrapper> AnaReentrantAlgorithmWrapper :: + makeClone() const + { + RCU_READ_INVARIANT (this); + return std::make_unique<AnaReentrantAlgorithmWrapper> (m_config); + } + + + + StatusCode AnaReentrantAlgorithmWrapper :: + initialize (const AlgorithmWorkerData& workerData) + { + using namespace msgAlgorithmConfig; + RCU_CHANGE_INVARIANT (this); + if (m_config.makeAlgorithm (m_algorithm, workerData).isFailure()) + { + ANA_MSG_ERROR ("failed to create AnaReentrantAlgorithm: " << m_config.name()); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; + } + + + + StatusCode AnaReentrantAlgorithmWrapper :: + execute () + { + using namespace msgAlgorithmConfig; + RCU_READ_INVARIANT (this); + if (m_algorithm->sysExecute(Gaudi::Hive::currentContext()).isFailure()) + { + ANA_MSG_ERROR ("failed to call execute() on algorithm: " << m_config.name()); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; + } + + + + StatusCode AnaReentrantAlgorithmWrapper :: + finalize () + { + using namespace msgAlgorithmConfig; + RCU_READ_INVARIANT (this); + if (m_algorithm->sysFinalize().isFailure()) + { + ANA_MSG_ERROR ("failed to call finalize() on algorithm: " << m_config.name()); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; + } + + + + StatusCode AnaReentrantAlgorithmWrapper :: + fileExecute () + { + // no-op + return StatusCode::SUCCESS; + } + + + + StatusCode AnaReentrantAlgorithmWrapper :: + beginInputFile () + { + // no-op + return StatusCode::SUCCESS; + } + + + + ::StatusCode AnaReentrantAlgorithmWrapper :: + endInputFile () + { + // no-op + return StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/Job.h b/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/Job.h index c46cf2c5626d..50fe426a4765 100644 --- a/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/Job.h +++ b/PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/Job.h @@ -93,6 +93,7 @@ namespace EL void algsAdd (std::unique_ptr<Algorithm> val_algorithm); void algsAdd (Algorithm *alg_swallow); void algsAdd (const AnaAlgorithmConfig& config); + void algsAdd (const AnaReentrantAlgorithmConfig& config); /// \brief add a clone of the given algorithm diff --git a/PhysicsAnalysis/D3PDTools/EventLoop/Root/Job.cxx b/PhysicsAnalysis/D3PDTools/EventLoop/Root/Job.cxx index aae81d06efe2..e44cf89fde3a 100644 --- a/PhysicsAnalysis/D3PDTools/EventLoop/Root/Job.cxx +++ b/PhysicsAnalysis/D3PDTools/EventLoop/Root/Job.cxx @@ -11,6 +11,7 @@ #include <memory> #include <AnaAlgorithm/AnaAlgorithmWrapper.h> +#include <AnaAlgorithm/AnaReentrantAlgorithmWrapper.h> #include <EventLoop/MessageCheck.h> #include <EventLoop/Algorithm.h> #include <EventLoop/AlgorithmWrapper.h> @@ -264,6 +265,15 @@ namespace EL + void Job :: + algsAdd (const AnaReentrantAlgorithmConfig& config) + { + // no invariant used + algsAdd (std::make_unique<AnaReentrantAlgorithmWrapper> (config)); + } + + + void Job :: algsAddClone (const Algorithm& alg) { diff --git a/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/EventLoopTestDict.h b/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/EventLoopTestDict.h index 8dfe14a56758..9472bf63c650 100644 --- a/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/EventLoopTestDict.h +++ b/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/EventLoopTestDict.h @@ -6,5 +6,6 @@ #endif #include "EventLoopTest/UnitTestAlg5.h" +#include "EventLoopTest/UnitTestAlg6.h" #endif diff --git a/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/UnitTestAlg6.h b/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/UnitTestAlg6.h new file mode 100644 index 000000000000..3ad66ad01b01 --- /dev/null +++ b/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/UnitTestAlg6.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef EVENT_LOOP_UNIT_TEST_ALG6_H +#define EVENT_LOOP_UNIT_TEST_ALG6_H + +#include <EventLoopTest/Global.h> + +#include <AnaAlgorithm/AnaReentrantAlgorithm.h> +#include <EventLoopTest/IUnitTestTool.h> +#include <AsgTools/ToolHandle.h> + +namespace EL +{ + class UnitTestAlg6 final : public AnaReentrantAlgorithm + { + public: + UnitTestAlg6 (const std::string& name, ISvcLocator* pSvcLocator); + + public: + virtual ::StatusCode initialize () override; + + public: + virtual ::StatusCode execute (const EventContext& ctx) override; + + public: + virtual ::StatusCode finalize () override; + + + /// \brief the float property our owner sets + public: + float m_property = 0; + + /// \brief the string property our owner sets + public: + std::string m_string_property; + + /// \brief the tool handle property our owner sets + public: + ToolHandle<IUnitTestTool> m_toolHandle {"", this}; + + /// \brief whether initialize has been called + public: + bool m_wasInitialized = false; + }; +} + +#endif diff --git a/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/selection.xml b/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/selection.xml index 209766bd7235..8cd781929c2c 100644 --- a/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/selection.xml +++ b/PhysicsAnalysis/D3PDTools/EventLoopTest/EventLoopTest/selection.xml @@ -2,5 +2,6 @@ <!-- Unit test types: --> <class name="EL::UnitTestAlg5" /> + <class name="EL::UnitTestAlg6" /> </lcgdict> diff --git a/PhysicsAnalysis/D3PDTools/EventLoopTest/Root/UnitTestAlg6.cxx b/PhysicsAnalysis/D3PDTools/EventLoopTest/Root/UnitTestAlg6.cxx new file mode 100644 index 000000000000..ee9fb8cd47f7 --- /dev/null +++ b/PhysicsAnalysis/D3PDTools/EventLoopTest/Root/UnitTestAlg6.cxx @@ -0,0 +1,69 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +// +// includes +// + +#include <EventLoopTest/UnitTestAlg6.h> + +// +// method implementations +// + +namespace EL +{ + UnitTestAlg6 :: + UnitTestAlg6 (const std::string& name, ISvcLocator* pSvcLocator) + : AnaReentrantAlgorithm (name, pSvcLocator) + { + declareProperty ("property", m_property, "test property"); + declareProperty ("string_property", m_string_property, "test string property"); + declareProperty ("toolHandle", m_toolHandle, "ToolHandle property"); + } + + + + ::StatusCode UnitTestAlg6 :: + initialize () + { + if (m_wasInitialized) + { + ANA_MSG_FATAL ("initialized twice"); + return StatusCode::FAILURE; + } + + if (!m_toolHandle.empty()) + ANA_CHECK (m_toolHandle.retrieve()); + + m_wasInitialized = true; + return ::StatusCode::SUCCESS; + } + + + + ::StatusCode UnitTestAlg6 :: + execute (const EventContext& /*ctx*/) + { + if (!m_wasInitialized) + { + ANA_MSG_FATAL ("never initialized"); + return StatusCode::FAILURE; + } + return ::StatusCode::SUCCESS; + } + + + + ::StatusCode UnitTestAlg6 :: + finalize () + { + if (!m_wasInitialized) + { + ANA_MSG_FATAL ("never initialized"); + return StatusCode::FAILURE; + } + return ::StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/D3PDTools/EventLoopTest/test/gt_AnaAlgorithmWrapper.cxx b/PhysicsAnalysis/D3PDTools/EventLoopTest/test/gt_AnaAlgorithmWrapper.cxx deleted file mode 100644 index 9462707d9cba..000000000000 --- a/PhysicsAnalysis/D3PDTools/EventLoopTest/test/gt_AnaAlgorithmWrapper.cxx +++ /dev/null @@ -1,26 +0,0 @@ -/* - Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration -*/ - -/// @author Nils Krumnack - - - -// -// includes -// - -#include <EventLoop/Global.h> - -#include <RootCoreUtils/Assert.h> - -using namespace EL; - -// -// unit test -// - -int main () -{ - return 0; -} diff --git a/PhysicsAnalysis/D3PDTools/EventLoopTest/test/gt_AnaReentrantAlgorithm.cxx b/PhysicsAnalysis/D3PDTools/EventLoopTest/test/gt_AnaReentrantAlgorithm.cxx new file mode 100644 index 000000000000..3a0684628c8f --- /dev/null +++ b/PhysicsAnalysis/D3PDTools/EventLoopTest/test/gt_AnaReentrantAlgorithm.cxx @@ -0,0 +1,143 @@ +/* + Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <AnaAlgorithm/AnaReentrantAlgorithm.h> +#include <AnaAlgorithm/AnaReentrantAlgorithmConfig.h> + +#include <AnaAlgorithm/AlgorithmWorkerData.h> +#include <EventLoopTest/UnitTestAlg6.h> +#include <AsgTools/ToolHandle.h> +#include <AsgMessaging/MessageCheck.h> +#include <AsgTesting/UnitTest.h> +#include <cmath> +#include <gtest/gtest.h> + +#ifdef ROOTCORE +#include <xAODRootAccess/Init.h> +#endif + +#include <RootCoreUtils/Assert.h> + +using namespace EL; + +// +// unit test +// + +TEST (AnaReentrantAlgorithmTest, create_basic) +{ + AlgorithmWorkerData workerData; + AnaReentrantAlgorithmConfig config; + config.setName ("name"); + config.setType ("EL::AnaReentrantAlgorithm"); + std::unique_ptr<AnaReentrantAlgorithm> alg; + ASSERT_SUCCESS (config.makeAlgorithm (alg, workerData)); + ASSERT_NE (nullptr, alg.get()); + ASSERT_EQ ("name", alg->name()); +} + +TEST (AnaReentrantAlgorithmTest, newAlg) +{ + std::unique_ptr<UnitTestAlg6> alg (new UnitTestAlg6 ("name", nullptr)); +} + +TEST (AnaReentrantAlgorithmTest, create) +{ + AlgorithmWorkerData workerData; + AnaReentrantAlgorithmConfig config; + config.setName ("name"); + config.setType ("EL::UnitTestAlg6"); + std::unique_ptr<AnaReentrantAlgorithm> alg; + ASSERT_SUCCESS (config.makeAlgorithm (alg, workerData)); + ASSERT_NE (nullptr, alg.get()); + ASSERT_EQ ("name", alg->name()); +} + +TEST (AnaReentrantAlgorithmTest, setProperty_string) +{ + AlgorithmWorkerData workerData; + AnaReentrantAlgorithmConfig config; + config.setName ("name"); + config.setType ("EL::UnitTestAlg6"); + ASSERT_SUCCESS (config.setProperty ("string_property", "42")); + std::unique_ptr<AnaReentrantAlgorithm> alg; + ASSERT_SUCCESS (config.makeAlgorithm (alg, workerData)); + UnitTestAlg6 *myalg = dynamic_cast<UnitTestAlg6*>(alg.get()); + ASSERT_NE (nullptr, myalg); + ASSERT_EQ ("42", myalg->m_string_property); +} + +TEST (AnaReentrantAlgorithmTest, setProperty) +{ + AlgorithmWorkerData workerData; + AnaReentrantAlgorithmConfig config; + config.setName ("name"); + config.setType ("EL::UnitTestAlg6"); + ASSERT_SUCCESS (config.setProperty ("property", 42)); + std::unique_ptr<AnaReentrantAlgorithm> alg; + ASSERT_SUCCESS (config.makeAlgorithm (alg, workerData)); + UnitTestAlg6 *myalg = dynamic_cast<UnitTestAlg6*>(alg.get()); + ASSERT_NE (nullptr, myalg); + ASSERT_EQ (42, myalg->m_property); +} + +TEST (AnaReentrantAlgorithmTest, setOutputLevel) +{ + AlgorithmWorkerData workerData; + AnaReentrantAlgorithmConfig config; + config.setName ("name"); + config.setType ("EL::UnitTestAlg6"); + ASSERT_SUCCESS (config.setProperty ("OutputLevel", MSG::Level::VERBOSE)); + std::unique_ptr<AnaReentrantAlgorithm> alg; + ASSERT_SUCCESS (config.makeAlgorithm (alg, workerData)); + UnitTestAlg6 *myalg = dynamic_cast<UnitTestAlg6*>(alg.get()); + ASSERT_NE (nullptr, myalg); + ASSERT_EQ (MSG::Level::VERBOSE, static_cast<int>(myalg->msg().level())); +} + +TEST (AnaReentrantAlgorithmTest, setSubTool) +{ + AlgorithmWorkerData workerData; + AnaReentrantAlgorithmConfig config; + config.setName ("name"); + config.setType ("EL::UnitTestAlg6"); + ASSERT_SUCCESS (config.createPrivateTool ("toolHandle", "EL::UnitTestTool")); + ASSERT_SUCCESS (config.setProperty ("toolHandle.propertyInt", 17)); + std::unique_ptr<AnaReentrantAlgorithm> alg; + ASSERT_SUCCESS (config.makeAlgorithm (alg, workerData)); + UnitTestAlg6 *myalg = dynamic_cast<UnitTestAlg6*>(alg.get()); + ASSERT_NE (nullptr, myalg); + ASSERT_NE (nullptr, &*myalg->m_toolHandle); + ASSERT_EQ (17, myalg->m_toolHandle->getPropertyInt()); + ASSERT_EQ (nullptr, myalg->m_toolHandle->getSubtool()); +} + +TEST (AnaReentrantAlgorithmTest, setSubSubTool) +{ + AlgorithmWorkerData workerData; + AnaReentrantAlgorithmConfig config; + config.setName ("name"); + config.setType ("EL::UnitTestAlg6"); + ASSERT_SUCCESS (config.createPrivateTool ("toolHandle", "EL::UnitTestTool")); + ASSERT_SUCCESS (config.createPrivateTool ("toolHandle.subtool", "EL::UnitTestTool")); + ASSERT_SUCCESS (config.setProperty ("toolHandle.subtool.propertyInt", 17)); + std::unique_ptr<AnaReentrantAlgorithm> alg; + ASSERT_SUCCESS (config.makeAlgorithm (alg, workerData)); + UnitTestAlg6 *myalg = dynamic_cast<UnitTestAlg6*>(alg.get()); + ASSERT_NE (nullptr, myalg); + ASSERT_NE (nullptr, &*myalg->m_toolHandle); + ASSERT_EQ (0, myalg->m_toolHandle->getPropertyInt()); + ASSERT_NE (nullptr, myalg->m_toolHandle->getSubtool()); + ASSERT_EQ (17, myalg->m_toolHandle->getSubtool()->getPropertyInt()); +} + +ATLAS_GOOGLE_TEST_MAIN -- GitLab