diff --git a/Associators/Associators/Associators/Detail/Mixin.h b/Associators/Associators/Associators/Detail/Mixin.h new file mode 100644 index 0000000000000000000000000000000000000000..607e322370ca4b25bf226297b10c0c283f4d6b86 --- /dev/null +++ b/Associators/Associators/Associators/Detail/Mixin.h @@ -0,0 +1,73 @@ +#ifndef LINKERMIXIN_H +#define LINKERMIXIN_H + +#include <GaudiKernel/LinkManager.h> +#include <GaudiKernel/ContainedObject.h> +#include <Event/LinksByKey.h> + +#include "OutputLinks.h" +#include <Associators/InputLinks.h> + +namespace { + struct DefaultType {}; +} + +namespace Detail { + +template <typename Source> +class LinkerMixin { +public: + + static std::string location(const std::string& location) + { + return "Link/" + (location.compare(0,7,"/Event/") == 0 ? location.substr(7) + : location); + } + + // Bit of a trick here with enable if: if Target is specified, + // so it's not DefaultType, we assume that the user wants + // to use the given types for Source and Target + template <typename Src, typename Target = DefaultType, + typename std::enable_if<!std::is_same<DefaultType, Target>::value, Target>::type* = nullptr> + InputLinks<Src, Target> inputLinks(const LHCb::LinksByKey& links) const + { + return InputLinks<Src, Target>{links}; + } + + // Bit of a trick here with enable if: if Target is not specified, + // so it's DefaultType, we assume that the user wants Source to be + // ContainedObject and Targe to be Target, the remaining parameter + // is therefore taken to be the target type. + template <typename Src, typename Target = DefaultType, + typename std::enable_if<std::is_same<DefaultType, Target>::value, Target>::type* = nullptr> + InputLinks<ContainedObject, Src> inputLinks(const LHCb::LinksByKey& links) const + { + return InputLinks<ContainedObject, Src>{links}; + } + + // Bit of a trick here with enable if: if Target is not specified, + // so it's DefaultType, we assume that the user wants Src to be + // ContainedObject and Target to be Target, the remaining template + // parameter (Src) is therefore taken to be the target type. + template <typename Src, typename Target = DefaultType, + typename std::enable_if<std::is_same<DefaultType, Target>::value, Target>::type* = nullptr> + Detail::OutputLinks<Source, Src> outputLinks() const + { + return Detail::OutputLinks<Source, Src>{}; + } + + // Bit of a trick here with enable if: if Target is specified, so + // it's not DefaultType, we assume that the user wants to use the + // given types. + template <typename Src, typename Target = DefaultType, + typename std::enable_if<!std::is_same<DefaultType, Target>::value, Target>::type* = nullptr> + Detail::OutputLinks<Src, Target> outputLinks() const + { + return Detail::OutputLinks<Src, Target>{}; + } + +}; + +} + +#endif diff --git a/Associators/Associators/Associators/Detail/OutputLinks.h b/Associators/Associators/Associators/Detail/OutputLinks.h new file mode 100644 index 0000000000000000000000000000000000000000..e5dd6806f67087089fe952d50d44d02b58a7d88d --- /dev/null +++ b/Associators/Associators/Associators/Detail/OutputLinks.h @@ -0,0 +1,64 @@ +#ifndef LINKERDETAILS_OUTPUTLINKS_H +#define LINKERDETAILS_OUTPUTLINKS_H + +#include <Event/LinksByKey.h> + +namespace Detail { + +template <typename Source, typename Target> +class OutputLinks final { +public: + + OutputLinks() + { + m_links.setTargetClassID(Target::classID()); + m_links.setSourceClassID(Source::classID()); + } + + operator LHCb::LinksByKey() { + // This is horrible, but needed because the copy constructor of + // DataObject creates a new (and empty) LinkManager. The + // existing move constructor moves the linkmanager, which would + // work, expect the using auto conversion twice would result in + // undefined behaviour. So, create a copy, insert all the links + // it's and then return it. + LHCb::LinksByKey r{m_links}; + for (long linkID = 0; linkID != m_links.linkMgr()->size(); ++ linkID) { + auto link = m_links.linkMgr()->link(linkID); + r.linkMgr()->addLink(link->path(), link->object()); + } + return r; + } + + const LHCb::LinksByKey& links() const { return m_links; } + + void reset() { m_links.reset(); } + + void link(const Source* source, const Target* dest, double weight = 1.) + { + if (!source || !dest) return; + + m_links.addReference(source->index(), m_links.linkID(source->parent()), + dest->index(), m_links.linkID(dest->parent()), + weight); + } + + void link(int key, const Target* dest, double weight = 1.) + { + if (!dest) return; + + m_links.addReference(key, -1, dest->index(), m_links.linkID(dest->parent()), weight); + } + + void setIncreasingWeight() { m_links.setIncreasing(); } + void setDecreasingWeight() { m_links.setDecreasing(); } + +private: + + LHCb::LinksByKey m_links; + +}; + +} + +#endif diff --git a/Associators/Associators/Associators/InputLinks.h b/Associators/Associators/Associators/InputLinks.h new file mode 100644 index 0000000000000000000000000000000000000000..8adac3fd966fa616de3455f552d0606d6780d8ad --- /dev/null +++ b/Associators/Associators/Associators/InputLinks.h @@ -0,0 +1,133 @@ +#ifndef LINKERDETAILS_H +#define LINKERDETAILS_H + +#include <iostream> +#include <type_traits> + +#include <GaudiKernel/LinkManager.h> +#include <GaudiKernel/GaudiException.h> +#include <GaudiKernel/IRegistry.h> +#include <Event/LinksByKey.h> +#include <Relations/RelationWeighted2D.h> + +// template <class Source, class Targed, class Enabled = void> +// class InputLinks {}; + +namespace { + + template <typename Source> + struct GetObject + { + const Source* operator()(const LHCb::LinksByKey& links, + const int linkID, int index) const + { + if (linkID != -1) { + LinkManager::Link* link = links.linkMgr()->link(linkID); + ObjectContainerBase* parent = dynamic_cast<ObjectContainerBase*>(link->object()); + return parent ? static_cast<const Source*>(parent->containedObject(index)) + : nullptr; + } else { + return nullptr; + } + } + }; +} + +template <class Source, class Target> +class InputLinks { +public: + + using Relations = LHCb::RelationWeighted2D<Source, Target, double>; + using KeyRelations = LHCb::RelationWeighted2D<unsigned int, Target, double>; + + /// Standard constructor + InputLinks(const LHCb::LinksByKey& links) + { + //== Check proper template, only if specified. + if (links.sourceClassID() != Source::classID() && + CLID_ContainedObject != Source::classID()) { + std::ostringstream message; + message << "Incompatible Source type; template classID is " + << Source::classID() << " expected " << links.sourceClassID(); + throw GaudiException(message.str(), "LinkedTo", StatusCode::FAILURE); + } + if (links.targetClassID() != Target::classID()) { + std::ostringstream message; + message << "Incompatible Target type; template classID is " << Target::classID() + << " expected " << links.targetClassID(); + throw GaudiException(message.str(), "LinkedTo", StatusCode::FAILURE); + } + + // Very ugly, but there seems to be no way around the loading here. + const_cast<LHCb::LinksByKey&>(links).resolveLinks(links.registry()->dataSvc()); + + // Fill the relations table by looping over the links. The + // keyIndex in the LinksByKey contains pairs of source index and + // reference index. The reference at reference index contains + // the link ID of the source and target containers, the index of + // the target and the weight. The source and target objects can + // be obtained by getting container from the link manager and + // then the object at the respective indices. + const auto& refs = links.linkReference(); + + int srcKey = 0; + int refIndex = 0; + + for (const auto& entry : links.keyIndex()) { + std::tie(srcKey, refIndex) = entry; + const auto& ref = refs[refIndex]; + const auto target = GetObject<Target>{}(links, ref.linkID(), ref.objectKey()); + if (ref.srcLinkID() != -1) { + const Source* source = GetObject<Source>{}(links, ref.srcLinkID(), srcKey); + m_relations.i_push(source, target, ref.weight()); + } else { + m_keyRelations.i_push(srcKey, target, ref.weight()); + } + } + m_relations.i_sort(); + m_keyRelations.i_sort(); + }; + + typename LHCb::RelationWeighted2D<unsigned int, Target, double>::Range from(unsigned int key) const + { + auto range = m_keyRelations.relations(key); + return range; + } + + typename LHCb::RelationWeighted2D<Source, Target, double>::Range from(const Source* source) const + { + return m_relations.relations(source); + } + + template <typename Object, typename std::enable_if<(!std::is_same<Source, Object>::value + && std::is_same<ContainedObject, Object>::value) + || (!std::is_same<ContainedObject, Object>::value + && std::is_same<Source, Object>::value)>::type> + typename LHCb::RelationWeighted2D<Source, Target, double>::Range from(const Object* source) const + { + return m_relations.relations(static_cast<const Source*>(source)); + } + + typename LHCb::RelationWeighted2D<Source, Target, double>::Range to(const Target* target) const + { + return m_relations.inverse().relations(target); + } + + typename LHCb::RelationWeighted2D<Source, Target, double>::Range relations() const + { + return m_relations; + } + + typename LHCb::RelationWeighted2D<unsigned int, Target, double>::Range keyRelations() const + { + return m_keyRelations; + } + +private: + + Relations m_relations; + KeyRelations m_keyRelations; + +}; + +#endif diff --git a/Associators/Associators/Associators/Linker.h b/Associators/Associators/Associators/Linker.h new file mode 100644 index 0000000000000000000000000000000000000000..28635822ab2d5996f9c8153a22efd318ecf3d54e --- /dev/null +++ b/Associators/Associators/Associators/Linker.h @@ -0,0 +1,64 @@ +#ifndef LINKER_H +#define LINKER_H + +#include <GaudiKernel/KeyedContainer.h> +#include <GaudiAlg/Transformer.h> +#include <Event/LinksByKey.h> + +#include "Detail/Mixin.h" + +namespace Gaudi { +namespace Functional { + +template <typename Signature, typename Traits_ = Traits::useDefaults> class Linker; + +// A base class to link reconstructed objects to MC objects to easy +// the transition from LinkerWithKey to a future event model for the +// MC. +// NOTE: Several different object containers are used by recontructed +// and MC objects, such as KeyedContainer and ObjectVector, these do +// not contain the same public typedefs, so some specialization tricks +// are needed to get access to the target and source types. +template <class Out, + template <typename, typename...> class SourceContainer, typename Source, typename... SourceContainerArgs, + typename... ExtraIn, typename Traits_> +class Linker<Out(const SourceContainer<Source, SourceContainerArgs...>&, const ExtraIn&...), Traits_> +: public Detail::LinkerMixin<Source>, + public Transformer<Out(const SourceContainer<Source, SourceContainerArgs...>&, const ExtraIn&...), Traits_> +{ +public: + + // Forwarding contructor saves a lot of hassle + using Transformer<Out(const SourceContainer<Source, SourceContainerArgs...>&, const ExtraIn&...), + Traits_>::Transformer; + +}; + +template <typename Signature, typename Traits_ = Traits::useDefaults> class MultiLinker; + +// A base class to link reconstructed objects to MC objects to easy +// the transition from LinkerWithKey to a future event model for the +// MC. +// NOTE: Several different object containers are used by recontructed +// and MC objects, such as KeyedContainer and ObjectVector, these do +// not contain the same public typedefs, so some specialization tricks +// are needed to get access to the target and source types. +template <typename... Out, + template <typename, typename...> class SourceContainer, typename Source, typename... SourceContainerArgs, + typename... ExtraIn, typename Traits_> +class MultiLinker<std::tuple<Out...>(const SourceContainer<Source, SourceContainerArgs...>&, const ExtraIn&...), Traits_> +: public Detail::LinkerMixin<Source>, + public MultiTransformer<std::tuple<Out...>(const SourceContainer<Source, SourceContainerArgs...>&, const ExtraIn&...), Traits_> +{ +public: + + // Forwarding contructor saves a lot of hassle + using MultiTransformer<std::tuple<Out...>(const SourceContainer<Source, SourceContainerArgs...>&, const ExtraIn&...), + Traits_>::MultiTransformer; + +}; + +} +} + +#endif diff --git a/Associators/Associators/CMakeLists.txt b/Associators/Associators/CMakeLists.txt index 27ddcc8770ac1105baea287e53e7b38202043982..c992797369c87ea412138968f6f8a135e1adf279 100644 --- a/Associators/Associators/CMakeLists.txt +++ b/Associators/Associators/CMakeLists.txt @@ -5,13 +5,17 @@ gaudi_subdir(Associators v3r9p1) gaudi_depends_on_subdirs(Event/LinkerEvent Event/MCEvent + Kernel/Relations GaudiAlg) find_package(Boost) find_package(ROOT) include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}) +gaudi_install_headers(Associators) + gaudi_add_module(Associators src/*.cpp LINK_LIBRARIES LinkerEvent MCEvent GaudiAlgLib) +gaudi_install_python_modules() diff --git a/Associators/Associators/python/Associators/__init__.py b/Associators/Associators/python/Associators/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c05d3f9218e89309dec12155aeed65874f289cd5 --- /dev/null +++ b/Associators/Associators/python/Associators/__init__.py @@ -0,0 +1,5 @@ +import cppyy +cppyy.gbl.gSystem.Load("libGaudiKernel.so") +cppyy.gbl.gSystem.Load("libLinkerEvent.so") +cppyy.gbl.gInterpreter.Declare("#include <Associators/InputLinks.h>") +InputLinks = cppyy.gbl.InputLinks diff --git a/VP/VPAssociators/src/VPClusterLinker.cpp b/VP/VPAssociators/src/VPClusterLinker.cpp old mode 100755 new mode 100644 diff --git a/VP/VPAssociators/src/VPClusterLinker.h b/VP/VPAssociators/src/VPClusterLinker.h old mode 100755 new mode 100644