From 2260ab4f6c58a4bdd62c2bc56b5601e6632cad43 Mon Sep 17 00:00:00 2001
From: Pierre-Antoine Delsart <delsart@in2p3.fr>
Date: Thu, 28 May 2020 13:24:11 +0000
Subject: [PATCH] Introduce FlowElement in xAODPFlow

---
 Event/xAOD/xAODBase/xAODBase/ObjectType.h     |   1 +
 .../Root/FlowElementAuxContainer_v1.cxx       |  24 ++
 Event/xAOD/xAODPFlow/Root/FlowElement_v1.cxx  | 208 ++++++++++++++++++
 .../xAODPFlow/Root/dict/ContainerProxies.cxx  |   2 +
 Event/xAOD/xAODPFlow/xAODPFlow/FlowElement.h  |  23 ++
 .../xAODPFlow/FlowElementAuxContainer.h       |  27 +++
 .../xAODPFlow/FlowElementContainer.h          |  23 ++
 Event/xAOD/xAODPFlow/xAODPFlow/selection.xml  |  16 +-
 .../versions/FlowElementAuxContainer_v1.h     |  56 +++++
 .../versions/FlowElementContainer_v1.h        |  22 ++
 .../xAODPFlow/versions/FlowElement_v1.h       | 153 +++++++++++++
 .../xAOD/xAODPFlow/xAODPFlow/xAODPFlowDict.h  |  30 +--
 Event/xAOD/xAODPFlowAthenaPool/CMakeLists.txt |   4 +
 .../src/xAODFlowElementAuxContainerCnv.cxx    |   3 +
 .../src/xAODFlowElementAuxContainerCnv.h      |  20 ++
 .../src/xAODFlowElementContainerCnv.cxx       |   5 +
 .../src/xAODFlowElementContainerCnv.h         |  14 ++
 17 files changed, 617 insertions(+), 14 deletions(-)
 create mode 100644 Event/xAOD/xAODPFlow/Root/FlowElementAuxContainer_v1.cxx
 create mode 100644 Event/xAOD/xAODPFlow/Root/FlowElement_v1.cxx
 create mode 100644 Event/xAOD/xAODPFlow/xAODPFlow/FlowElement.h
 create mode 100644 Event/xAOD/xAODPFlow/xAODPFlow/FlowElementAuxContainer.h
 create mode 100644 Event/xAOD/xAODPFlow/xAODPFlow/FlowElementContainer.h
 create mode 100644 Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElementAuxContainer_v1.h
 create mode 100644 Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElementContainer_v1.h
 create mode 100644 Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElement_v1.h
 create mode 100644 Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementAuxContainerCnv.cxx
 create mode 100644 Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementAuxContainerCnv.h
 create mode 100644 Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementContainerCnv.cxx
 create mode 100644 Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementContainerCnv.h

diff --git a/Event/xAOD/xAODBase/xAODBase/ObjectType.h b/Event/xAOD/xAODBase/xAODBase/ObjectType.h
index 6bf91465a64..de3a8ba8372 100644
--- a/Event/xAOD/xAODBase/xAODBase/ObjectType.h
+++ b/Event/xAOD/xAODBase/xAODBase/ObjectType.h
@@ -49,6 +49,7 @@ enum ObjectType {
   Tau      = 9, ///< The object is a tau (jet)
 
   TrackCaloCluster = 10, ///< The object is a track-calo-cluster
+  FlowElement = 11, ///< The object is a track-calo-cluster
 
   // }
 
diff --git a/Event/xAOD/xAODPFlow/Root/FlowElementAuxContainer_v1.cxx b/Event/xAOD/xAODPFlow/Root/FlowElementAuxContainer_v1.cxx
new file mode 100644
index 00000000000..e162b9c0bc1
--- /dev/null
+++ b/Event/xAOD/xAODPFlow/Root/FlowElementAuxContainer_v1.cxx
@@ -0,0 +1,24 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "xAODPFlow/versions/FlowElementAuxContainer_v1.h"
+ 
+namespace xAOD {
+ 
+   FlowElementAuxContainer_v1::FlowElementAuxContainer_v1()
+      : AuxContainerBase() {
+	AUX_VARIABLE(pt);
+	AUX_VARIABLE(eta);
+	AUX_VARIABLE(phi);
+	AUX_VARIABLE(m);
+	AUX_VARIABLE(charge);
+	AUX_VARIABLE(signalType);
+	AUX_VARIABLE(vertexType);
+	AUX_VARIABLE( chargedObjectLinks );
+	AUX_VARIABLE( chargedObjectWeights );
+	AUX_VARIABLE( otherObjectLinks );
+	AUX_VARIABLE( otherObjectWeights );
+      }   
+   
+} // namespace xAOD
diff --git a/Event/xAOD/xAODPFlow/Root/FlowElement_v1.cxx b/Event/xAOD/xAODPFlow/Root/FlowElement_v1.cxx
new file mode 100644
index 00000000000..6f210f206f7
--- /dev/null
+++ b/Event/xAOD/xAODPFlow/Root/FlowElement_v1.cxx
@@ -0,0 +1,208 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// EDM include(s):
+#include "xAODCore/AuxStoreAccessorMacros.h"
+#include "AthLinks/ElementLink.h"
+
+
+// Local include(s):
+#include "xAODPFlow/versions/FlowElement_v1.h"
+
+#include "Math/Vector4D.h"
+
+using ROOT::Math::PtEtaPhiMVector ;
+
+namespace xAOD {
+
+
+  AUXSTORE_PRIMITIVE_GETTER_WITH_CAST(FlowElement_v1, float, double, pt)
+  AUXSTORE_PRIMITIVE_GETTER_WITH_CAST(FlowElement_v1, float, double, eta)
+  AUXSTORE_PRIMITIVE_GETTER_WITH_CAST(FlowElement_v1, float, double, phi)
+  AUXSTORE_PRIMITIVE_GETTER_WITH_CAST(FlowElement_v1, float, double, m)
+
+  double FlowElement_v1::e() const {
+    return PtEtaPhiMVector(pt(), eta(), phi(), m() ).E();
+  }
+
+  double FlowElement_v1::rapidity() const {
+    return PtEtaPhiMVector(pt(), eta(), phi(), m() ).Rapidity();
+  }
+
+  FlowElement_v1::FourMom_t FlowElement_v1::p4() const {
+    FourMom_t p4;
+    p4.SetPtEtaPhiE( pt(), eta(), phi(), e() );       
+    return p4;
+  }
+
+  void FlowElement_v1::setP4(float pt, float eta, float phi, float m){
+    static const Accessor< float > acc1( "pt" );     
+    acc1( *this ) = pt;     
+    static const  Accessor< float > acc2( "eta" );     
+    acc2( *this ) = eta;     
+    static const  Accessor< float > acc3( "phi" );     
+    acc3( *this ) = phi;     
+    static const  Accessor< float > acc4( "m" );     
+    acc4( *this ) = m;     
+
+  }
+
+
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER(FlowElement_v1, float, charge, setCharge) 
+  bool  FlowElement_v1::isCharged() const { return !bool( signalType()& Neutral );}
+  
+
+  
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER(FlowElement_v1, FlowElement_v1::signal_t, signalType, setSignalType) 
+  AUXSTORE_PRIMITIVE_SETTER_AND_GETTER(FlowElement_v1, FlowElement_v1::vertex_t, vertexType, setVertexType) 
+
+  bool  FlowElement_v1::isMatchedToPV(MatchedPVType vxtype) const {
+    return (vertexType()==vxtype);
+  }
+      
+
+  Type::ObjectType FlowElement_v1::type() const {
+    return Type::FlowElement;
+  }
+
+
+  
+
+  AUXSTORE_OBJECT_SETTER_AND_GETTER( FlowElement_v1, 
+				     std::vector< ElementLink< xAOD::IParticleContainer > >, 
+				     chargedObjectLinks, 
+				     setChargedObjectLinks)
+
+
+  AUXSTORE_OBJECT_GETTER( FlowElement_v1, std::vector<float>, chargedObjectWeights)
+  
+  void FlowElement_v1::setChargedObjectLinks(const std::vector<ElementLink<IParticleContainer>> & elV, const std::vector<float> & wV){
+    if(elV.size() != wV.size() ){
+      throw std::runtime_error("FlowElement::setChargedObjectLinks : Can not set vectors of links and weights with different sizes");
+    }
+    static const SG::AuxElement::Accessor< std::vector<ElementLink< xAOD::IParticleContainer >> >  accL( "chargedObjectLinks" );
+    static const SG::AuxElement::Accessor< std::vector<float> >  accW( "chargedObjectWeights" );
+    accL(*this) = elV;
+    accW(*this) = wV;    
+  }
+  
+  
+  std::vector<const xAOD::IParticle*> FlowElement_v1::chargedObjects() const {
+    const auto & elV = chargedObjectLinks();
+    std::vector<const xAOD::IParticle*> result;
+    result.reserve( elV.size() );
+    for(const auto& el: elV ){
+      result.push_back( el.isValid() ? *el : nullptr ) ; 
+    }
+    return result;
+  }
+
+  std::vector<std::pair<const xAOD::IParticle*,float> > FlowElement_v1::chargedObjectsAndWeights() const {
+
+    const auto & elV = chargedObjectLinks();
+    const std::vector<float> & wV = chargedObjectWeights();
+    std::vector< std::pair<const xAOD::IParticle*,float> > result;
+    result.reserve( elV.size() );
+    if(wV.empty()) {
+      for(const auto& el: elV ){
+	result.push_back( { el.isValid() ? *el : nullptr , 1.} ) ; 
+      }
+    } else {
+      for(size_t i=0;i<elV.size();i++){
+	const xAOD::IParticle* p = elV[i].isValid() ? *(elV[i]) : nullptr;
+	result.push_back( {p , wV[i]} ); 
+      }
+    }      
+    return result;
+  }
+
+  std::size_t FlowElement_v1::nChargedObjects() const {
+    return chargedObjectLinks().size();
+  }
+  
+  const xAOD::IParticle* FlowElement_v1::chargedObject( std::size_t i ) const{
+    const auto & elV = chargedObjectLinks();
+    // should we check if i >= size() and throw ourselves ? or trust the user ?
+    return elV[i].isValid()? *(elV[i]) : nullptr ;
+  }
+
+  std::pair<const xAOD::IParticle*, float > FlowElement_v1::chargedObjectAndWeight( std::size_t i ) const {
+    const auto & elV = chargedObjectLinks();
+    const std::vector<float> & wV = chargedObjectWeights();
+
+    if( elV[i].isValid() )  return { *(elV[i]), wV[i] } ;
+    else return {nullptr, wV[i] } ;    
+  }
+  
+
+
+  
+
+  AUXSTORE_OBJECT_SETTER_AND_GETTER( FlowElement_v1, 
+				     std::vector< ElementLink< xAOD::IParticleContainer > >, 
+				     otherObjectLinks, 
+				     setOtherObjectLinks)
+  AUXSTORE_OBJECT_GETTER( FlowElement_v1, std::vector<float>, otherObjectWeights)
+    
+  void FlowElement_v1::setOtherObjectLinks(const std::vector<ElementLink<IParticleContainer>> & elV, const std::vector<float> & wV){
+    if(elV.size() != wV.size() ){
+      throw std::runtime_error("FlowElement::setOtherObjectLinks : Can not set vectors of links and weights with different sizes");
+      return;
+    }
+    static const SG::AuxElement::Accessor< std::vector<ElementLink< xAOD::IParticleContainer > > >  accL( "otherObjectLinks" );
+    static const  SG::AuxElement::Accessor< std::vector<float>  >  accW( "otherObjectWeights" );
+    accL(*this) = elV;
+    accW(*this) = wV;    
+  }
+  
+  
+  std::vector<const xAOD::IParticle*> FlowElement_v1::otherObjects() const {
+    const auto & elV = otherObjectLinks();
+    std::vector<const xAOD::IParticle*> result;
+    result.reserve( elV.size() );
+    for(const auto& el: elV ){
+      result.push_back( el.isValid() ? *el : nullptr ) ; 
+    }
+    return result;
+  }
+
+  std::vector<std::pair<const xAOD::IParticle*,float> > FlowElement_v1::otherObjectsAndWeights() const {
+
+    const auto & elV = otherObjectLinks();
+    const std::vector<float> & wV = otherObjectWeights();
+    std::vector< std::pair<const xAOD::IParticle*,float> > result;
+    result.reserve( elV.size() );
+    if(wV.empty()) {
+      for(const auto& el: elV ){
+	result.push_back( { el.isValid() ? *el : nullptr , 1.} ) ; 
+      }
+    } else {
+      for(size_t i=0;i<elV.size();i++){
+	const xAOD::IParticle* p = elV[i].isValid() ? *(elV[i]) : nullptr;
+	result.push_back( {p , wV[i]} ); 
+      }
+    }      
+    return result;
+  }
+  
+  std::size_t FlowElement_v1::nOtherObjects() const {
+    return otherObjectLinks().size();
+  }
+
+  const xAOD::IParticle* FlowElement_v1::otherObject( std::size_t i ) const{
+    const auto & elV = otherObjectLinks();
+    // should we check if i >= size() and throw ourselves ? or trust the user ?
+    return elV[i].isValid()? *(elV[i]) : nullptr ;
+  }
+  
+  std::pair< const xAOD::IParticle*, float > FlowElement_v1::otherObjectAndWeight( std::size_t i ) const {
+    const auto & elV = otherObjectLinks();
+    const std::vector<float> & wV = otherObjectWeights();
+
+    if( elV[i].isValid() )  return { *(elV[i]), wV[i] };
+    else return {nullptr, wV[i] } ;    
+  }
+
+  
+}
diff --git a/Event/xAOD/xAODPFlow/Root/dict/ContainerProxies.cxx b/Event/xAOD/xAODPFlow/Root/dict/ContainerProxies.cxx
index 63aff550c22..88a1d7c84ff 100644
--- a/Event/xAOD/xAODPFlow/Root/dict/ContainerProxies.cxx
+++ b/Event/xAOD/xAODPFlow/Root/dict/ContainerProxies.cxx
@@ -10,7 +10,9 @@
 // Local include(s):
 #include "xAODPFlow/versions/PFOContainer_v1.h"
 #include "xAODPFlow/versions/TrackCaloClusterContainer_v1.h"
+#include "xAODPFlow/versions/FlowElementContainer_v1.h"
 
 // Set up the collection proxies:
 ADD_NS_DV_PROXY( xAOD, PFOContainer_v1 );
 ADD_NS_DV_PROXY( xAOD, TrackCaloClusterContainer_v1 );
+ADD_NS_DV_PROXY( xAOD, FlowElementContainer_v1 );
diff --git a/Event/xAOD/xAODPFlow/xAODPFlow/FlowElement.h b/Event/xAOD/xAODPFlow/xAODPFlow/FlowElement.h
new file mode 100644
index 00000000000..293a6172994
--- /dev/null
+++ b/Event/xAOD/xAODPFlow/xAODPFlow/FlowElement.h
@@ -0,0 +1,23 @@
+// this file is -*- c++ -*-
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: PFO.h 744541 2016-05-03 15:55:30Z krasznaa $
+#ifndef XAODPFLOW_FLOWELEMENT_H
+#define XAODPFLOW_FLOWELEMENT_H
+
+// Local include(s):
+#include "xAODPFlow/versions/FlowElement_v1.h"
+
+/// Namespace holding all the xAOD EDM classes
+namespace xAOD {
+  /// Definition of the current "pfo version"
+  typedef FlowElement_v1 FlowElement;
+}
+
+// Set up a CLID for the class:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::FlowElement , 25811773 , 1 )
+
+#endif // XAODPFLOW_FlowElement_H
diff --git a/Event/xAOD/xAODPFlow/xAODPFlow/FlowElementAuxContainer.h b/Event/xAOD/xAODPFlow/xAODPFlow/FlowElementAuxContainer.h
new file mode 100644
index 00000000000..21c72e3bd66
--- /dev/null
+++ b/Event/xAOD/xAODPFlow/xAODPFlow/FlowElementAuxContainer.h
@@ -0,0 +1,27 @@
+// this file is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+#ifndef XAODPFLOW_FLOWELEMENTAUXCONTAINER_H
+#define XAODPFLOW_FLOWELEMENTAUXCONTAINER_H
+
+// Local include(s):
+#include "xAODPFlow/versions/FlowElementAuxContainer_v1.h"
+
+namespace xAOD {
+   /// Definition of the current FlowElementAuxContainer_v1 auxiliary container
+   ///
+   /// All reconstruction code should attach the typedefed auxiliary
+   /// container to the xAOD::FlowElementContainer, so it will be easy to change
+   /// the container type as we get new I/O technologies for these
+   /// objects.
+   ///
+   typedef FlowElementAuxContainer_v1 FlowElementAuxContainer;
+}
+
+// Set up a CLID for the class:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::FlowElementAuxContainer , 1078624534 , 1 )
+
+#endif // XAODPFLOW_FLOWELEMENTAUXCONTAINER_H
diff --git a/Event/xAOD/xAODPFlow/xAODPFlow/FlowElementContainer.h b/Event/xAOD/xAODPFlow/xAODPFlow/FlowElementContainer.h
new file mode 100644
index 00000000000..d63b47a52ba
--- /dev/null
+++ b/Event/xAOD/xAODPFlow/xAODPFlow/FlowElementContainer.h
@@ -0,0 +1,23 @@
+//  this file is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef XAODPFLOW_FlowElementCONTAINER_H
+#define XAODPFLOW_FlowElementCONTAINER_H
+
+// Local include(s):
+#include "xAODPFlow/FlowElement.h"
+#include "xAODPFlow/versions/FlowElementContainer_v1.h"
+
+namespace xAOD {
+   /// Definition of the current "pfo container version"
+   typedef FlowElementContainer_v1 FlowElementContainer;
+}
+
+// Set up a CLID for the container:
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::FlowElementContainer , 1158384067 , 1 )
+
+#endif // XAODPFLOW_FlowElementCONTAINER_H
diff --git a/Event/xAOD/xAODPFlow/xAODPFlow/selection.xml b/Event/xAOD/xAODPFlow/xAODPFlow/selection.xml
index 3aeaf198bd1..2c6e4664db7 100644
--- a/Event/xAOD/xAODPFlow/xAODPFlow/selection.xml
+++ b/Event/xAOD/xAODPFlow/xAODPFlow/selection.xml
@@ -1,6 +1,5 @@
 <!-- Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -->
 <lcgdict>
-
    <!-- xAOD::PFO interface type(s). -->
    <class name="xAOD::PFO_v1" />
    <class name="xAOD::PFOContainer_v1"
@@ -25,6 +24,21 @@
           id="E3492C37-2469-4346-BCBA-7A18CACD46AC"/>
    <typedef name="xAOD::TrackCaloClusterAuxContainer" />
 
+
+  <!-- FlowElement interface type(s): -->
+  <class name="xAOD::FlowElement_v1" />
+  <class name="xAOD::FlowElementContainer_v1"
+         id="68F99A1F-96F4-4339-BEB7-46A6E7A5E351"/>
+
+  <typedef name="xAOD::FlowElement" />
+  <typedef name="xAOD::FlowElementContainer" />
+  
+  <!-- FlowElement interface type(s): -->
+  <class name="xAOD::FlowElementAuxContainer_v1"
+         id="5015F3F7-901A-44FD-9FF2-93EEA1DAE686"/>
+  <typedef name="xAOD::FlowElementAuxContainer" />
+   
+   
    <!-- Other type(s). -->
    <enum pattern="xAOD::PFODetails::*" />
 
diff --git a/Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElementAuxContainer_v1.h b/Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElementAuxContainer_v1.h
new file mode 100644
index 00000000000..358462b0fb8
--- /dev/null
+++ b/Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElementAuxContainer_v1.h
@@ -0,0 +1,56 @@
+// this file is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef XAODPFLOW_VERSIONS_FLOWELEMENTAUXCONTAINER_V1_H
+#define XAODPFLOW_VERSIONS_FLOWELEMENTAUXCONTAINER_V1_H
+
+
+// EDM include(s):
+#include "xAODCore/AuxContainerBase.h"
+#include "AthLinks/ElementLink.h"
+#include "xAODPFlow/FlowElement.h"
+
+namespace xAOD {
+
+
+  class FlowElementAuxContainer_v1 : public AuxContainerBase {
+
+  public:
+    /// Default constructor
+    FlowElementAuxContainer_v1();
+    ~FlowElementAuxContainer_v1() = default;
+
+  private:
+    /** Charge of FlowElement */
+    std::vector<float> charge;
+
+    std::vector<FlowElement_v1::signal_t> signalType;
+
+    std::vector<FlowElement_v1::vertex_t> vertexType;
+
+    /** 4-vector of FlowElement */
+    std::vector<float> pt;
+    std::vector<float> eta;
+    std::vector<float> phi;
+    std::vector<float> m;
+
+    /** Vectors of links to underlying objects*/
+
+    std::vector<std::vector<ElementLink<IParticleContainer> > > chargedObjectLinks;
+    std::vector<std::vector<float > >  chargedObjectWeights;
+
+    std::vector<std::vector<ElementLink<IParticleContainer> > > otherObjectLinks;
+    std::vector<std::vector<float > >  otherObjectWeights;
+
+
+  }; // class FlowElementAuxContainer_v1
+
+} // namespace xAOD
+
+#include "xAODCore/BaseInfo.h"
+SG_BASE( xAOD::FlowElementAuxContainer_v1, xAOD::AuxContainerBase );
+
+#endif // XAODPFLOW_VERSIONS_FlowElementAUXCONTAINER_V1_H
diff --git a/Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElementContainer_v1.h b/Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElementContainer_v1.h
new file mode 100644
index 00000000000..162551e7a79
--- /dev/null
+++ b/Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElementContainer_v1.h
@@ -0,0 +1,22 @@
+//  this file is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#ifndef XAODPFLOW_VERSIONS_FlowElementCONTAINER_V1_H
+#define XAODPFLOW_VERSIONS_FlowElementCONTAINER_V1_H
+
+// Core include(s):
+#include "AthContainers/DataVector.h"
+
+// Local include(s):
+#include "xAODPFlow/versions/FlowElement_v1.h"
+
+namespace xAOD {
+   /// The container is a simple typedef for now
+   typedef DataVector< xAOD::FlowElement_v1 > FlowElementContainer_v1;
+}
+
+#endif // XAODPFLOW_VERSIONS_FlowElementCONTAINER_V1_H
diff --git a/Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElement_v1.h b/Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElement_v1.h
new file mode 100644
index 00000000000..a95f1d0dcae
--- /dev/null
+++ b/Event/xAOD/xAODPFlow/xAODPFlow/versions/FlowElement_v1.h
@@ -0,0 +1,153 @@
+// this files is  -*- c++ -*-
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+#ifndef XAODPFLOW_VERSIONS_FLOWELEMENT_V1_H
+#define XAODPFLOW_VERSIONS_FLOWELEMENT_V1_H
+
+// Core include(s):
+#include "AthLinks/ElementLink.h"
+
+// xAOD include(s):
+#include "xAODBase/IParticle.h"
+#include "xAODBase/IParticleContainer.h"
+
+namespace xAOD {
+
+  /////////////////////////////////////////////////////////
+  /// A detector object made of other lower level object(s) 
+  ///
+  /// This class is intended to describe reconstruction objects coumpound of lower level detector objects.
+  /// Typically it provides links to tracks and calo clusters such as is needed for particle flow objects.
+  ///
+  /// The class is kept minimal and very generic so it can cover many use cases, including a generic type
+  /// to describe jet constituents.
+  class FlowElement_v1 : public IParticle {
+  public:
+
+    using IParticle::IParticle;
+    
+    typedef unsigned long  signal_t; // 32-bit minimum
+    typedef unsigned short vertex_t;
+    using IParticle::FourMom_t ;
+    
+    /// Enum to encode the nature of the object this FlowElement represents
+    enum SignalType { 
+		     // global characteristics
+		     Neutral      = 0x1000,
+		     Charged      = 0x2000,
+		     Combined     = 0x4000, //needed??
+
+		     // detector level signals and flow objects
+		     CaloCluster  = Neutral | 0x0100,
+		     Track        = Charged | 0x0200,
+		     Muon         = Charged | 0x0400,
+		     PFlow        = 0x0010,
+		     NeutralPFlow = Neutral | PFlow,
+		     ChargedPFlow = Charged | PFlow,
+
+		     // higher level flow objects
+		     TCC          = 0x0020,
+		     NeutralTCC   = Neutral | TCC,
+		     ChargedTCC   = Charged | TCC,
+		     UFO          = 0x0001,
+		     NeutralUFO   = Neutral | UFO,
+		     ChargedUFO   = Charged | UFO,
+
+		     // unknown
+		     Unknown      = 0x0000
+    };
+
+    /// Enum to encode high-level information on the vertex associated to this FlowElement
+    enum MatchedPVType {
+			Undefined = 0x00, HardScatter = 0x10, Pileup = 0x20, PileupSideBand = 0x21
+    };
+
+    // *************************************************
+    ///@{
+    /// kinematics (IParticle interface)
+    virtual double pt()    const override;
+    virtual double eta()   const override;
+    virtual double phi()   const override;
+    virtual double m()     const override;
+    virtual double e()     const override;
+    virtual double rapidity()     const override;
+    virtual FourMom_t p4() const override;
+    virtual Type::ObjectType type() const override ;
+    
+    void setP4(float pt, float eta, float phi, float m) ;
+    ///@}
+
+    // *************************************************
+    ///@{
+    ///Access signal type
+    signal_t signalType() const;
+    void setSignalType(signal_t t);
+    ///@}
+    
+    // *************************************************
+    ///@{
+    /// Acess  vertex types
+    bool     isMatchedToPV(MatchedPVType vxtype=HardScatter) const;
+
+    vertex_t vertexType() const;
+    void     setVertexType(vertex_t t);
+    ///@}
+    
+    // *************************************************
+    ///@{
+    ///Access charge
+    bool  isCharged() const;
+    float charge() const;
+
+    void  setCharge(float c);
+    ///@}
+
+    // *************************************************
+
+    ///@{    
+    /// Access directly the charged underlying IParticle (typically : TrackParticle)
+    /// nullptr are returned if the ElementLink to the IParticle are invalid (ex: after thinning)
+    std::vector<const xAOD::IParticle*> chargedObjects() const ;
+    std::vector<std::pair<const xAOD::IParticle*,float> > chargedObjectsAndWeights() const ;
+
+    std::size_t nChargedObjects() const ; 
+    const xAOD::IParticle* chargedObject( std::size_t i ) const;
+    std::pair< const xAOD::IParticle*, float > chargedObjectAndWeight( std::size_t i ) const;
+    ///@}
+    
+
+    ///@{    
+    /** Access to the EL.*/
+    const std::vector<ElementLink<IParticleContainer>> & chargedObjectLinks() const ;
+    const std::vector<float> & chargedObjectWeights() const ;
+    void setChargedObjectLinks(const std::vector<ElementLink<IParticleContainer>> & elV);
+    void setChargedObjectLinks(const std::vector<ElementLink<IParticleContainer>> & elV, const std::vector<float> & wV);
+    ///@}
+
+    // *************************************************
+    ///@{
+    /// Access directly the 'other' underlying IParticle (typically neutral CaloCluster)
+    /// nullptr are returned if the ElementLink to the IParticle are invalid (ex: after thinning)
+    std::vector<const xAOD::IParticle*> otherObjects() const ;
+    std::vector<std::pair<const xAOD::IParticle*,float> > otherObjectsAndWeights() const ;
+
+    std::size_t nOtherObjects() const ; 
+    const xAOD::IParticle* otherObject( std::size_t i ) const;
+    std::pair< const xAOD::IParticle*, float > otherObjectAndWeight( std::size_t i ) const;
+    ///@}
+    
+    ///@{
+    /// Access to the EL
+    const std::vector<ElementLink<IParticleContainer>>& otherObjectLinks() const ;
+    const std::vector<float>& otherObjectWeights() const ;
+
+    void setOtherObjectLinks(const std::vector<ElementLink<IParticleContainer>> & elV);
+    void setOtherObjectLinks(const std::vector<ElementLink<IParticleContainer>> & elV, const std::vector<float> & wV);
+    ///@}
+    
+  };
+
+}
+
+#endif
diff --git a/Event/xAOD/xAODPFlow/xAODPFlow/xAODPFlowDict.h b/Event/xAOD/xAODPFlow/xAODPFlow/xAODPFlowDict.h
index 1d8ff5a619c..11b944665f6 100644
--- a/Event/xAOD/xAODPFlow/xAODPFlow/xAODPFlowDict.h
+++ b/Event/xAOD/xAODPFlow/xAODPFlow/xAODPFlowDict.h
@@ -19,6 +19,8 @@
 #include "xAODPFlow/versions/TrackCaloCluster_v1.h"
 #include "xAODPFlow/versions/TrackCaloClusterContainer_v1.h"
 #include "xAODPFlow/versions/TrackCaloClusterAuxContainer_v1.h"
+#include "xAODPFlow/versions/FlowElementContainer_v1.h"
+#include "xAODPFlow/versions/FlowElementAuxContainer_v1.h"
 
 #include "xAODPFlow/PFODefs.h"
 
@@ -33,19 +35,21 @@
 // Instantiate all necessary types for the dictionary.
 namespace {
    struct GCCXML_DUMMY_INSTANTIATION_XAODFLOW {
-      // Local type(s).
-      XAOD_INSTANTIATE_NS_CONTAINER_TYPES( xAOD, PFOContainer_v1 );
-      XAOD_INSTANTIATE_NS_CONTAINER_TYPES( xAOD, TrackCaloClusterContainer_v1 );
-      // Type(s) needed for the dictionary generation to succeed.
-      XAOD_INSTANTIATE_NS_CONTAINER_TYPES( xAOD, IParticleContainer );
-      // Weird/bad types used by the PFO reconstruction as attributes on
-      // xAOD::PFO objects. :-(
-      std::pair< ElementLink< xAOD::CaloClusterContainer >, double > dummy1;
-      std::vector< std::pair< ElementLink< xAOD::CaloClusterContainer >, double > >
-         dummy2;
-      std::vector< std::vector< std::pair< ElementLink< xAOD::CaloClusterContainer >, double > > >
-         dummy3;
-      std::vector< xAOD::PFODetails::PFOLeptonType > dummy4;
+     // Local type(s).
+     XAOD_INSTANTIATE_NS_CONTAINER_TYPES( xAOD, PFOContainer_v1 );
+     XAOD_INSTANTIATE_NS_CONTAINER_TYPES( xAOD, TrackCaloClusterContainer_v1 );
+     XAOD_INSTANTIATE_NS_CONTAINER_TYPES( xAOD, FlowElementContainer_v1 );
+     // Type(s) needed for the dictionary generation to succeed.
+     XAOD_INSTANTIATE_NS_CONTAINER_TYPES( xAOD, IParticleContainer );
+     // Weird/bad types used by the PFO reconstruction as attributes on
+     // xAOD::PFO objects. :-(
+     std::pair< ElementLink< xAOD::CaloClusterContainer >, double > dummy1;
+     std::vector< std::pair< ElementLink< xAOD::CaloClusterContainer >, double > >
+     dummy2;
+     std::vector< std::vector< std::pair< ElementLink< xAOD::CaloClusterContainer >, double > > >
+     dummy3;
+     std::vector< xAOD::PFODetails::PFOLeptonType > dummy4;
+
    };
 }
 
diff --git a/Event/xAOD/xAODPFlowAthenaPool/CMakeLists.txt b/Event/xAOD/xAODPFlowAthenaPool/CMakeLists.txt
index b799b4af581..85541f56d98 100644
--- a/Event/xAOD/xAODPFlowAthenaPool/CMakeLists.txt
+++ b/Event/xAOD/xAODPFlowAthenaPool/CMakeLists.txt
@@ -9,9 +9,13 @@ atlas_add_poolcnv_library( xAODPFlowAthenaPoolPoolCnv
    FILES xAODPFlow/PFOContainer.h xAODPFlow/PFOAuxContainer.h
          xAODPFlow/TrackCaloClusterContainer.h
          xAODPFlow/TrackCaloClusterAuxContainer.h
+         xAODPFlow/FlowElementContainer.h
+         xAODPFlow/FlowElementAuxContainer.h
    TYPES_WITH_NAMESPACE xAOD::PFOContainer xAOD::PFOAuxContainer
                         xAOD::TrackCaloClusterContainer
                         xAOD::TrackCaloClusterAuxContainer
+			xAOD::FlowElementContainer
+			xAOD::FlowElementAuxContainer
    CNV_PFX xAOD
    LINK_LIBRARIES AthContainers AthenaKernel AthenaPoolCnvSvcLib
                   AthenaPoolUtilities xAODPFlow )
diff --git a/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementAuxContainerCnv.cxx b/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementAuxContainerCnv.cxx
new file mode 100644
index 00000000000..724faaa41f9
--- /dev/null
+++ b/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementAuxContainerCnv.cxx
@@ -0,0 +1,3 @@
+// Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration 
+// Dummy source file so that cmake will know that this is a custom converter.
+
diff --git a/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementAuxContainerCnv.h b/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementAuxContainerCnv.h
new file mode 100644
index 00000000000..d903ae9c85f
--- /dev/null
+++ b/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementAuxContainerCnv.h
@@ -0,0 +1,20 @@
+//  this file is -*- c++ -*-
+//
+// Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+//
+#ifndef XAODPFLOWATHENAPOOL_XAODFLOWELEMENTAUXCONTAINERCNV_H
+#define XAODPFLOWATHENAPOOL_XAODFLOWELEMENTAUXCONTAINERCNV_H
+
+// Local include(s).
+//#include "xAODFlowEmentAuxContainerCnv_v1.h"
+
+// EDM include(s).
+#include "xAODPFlow/FlowElementAuxContainer.h"
+
+// Framework include(s).
+#include "AthenaPoolCnvSvc/T_AthenaPoolAuxContainerCnv.h"
+
+// Declare the POOL converter.
+typedef T_AthenaPoolAuxContainerCnv< xAOD::FlowElementAuxContainer>   xAODFlowElementAuxContainerCnv;
+
+#endif // XAODPFLOWATHENAPOOL_XAODFLOWELEMENTAUXCONTAINERCNV_H
diff --git a/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementContainerCnv.cxx b/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementContainerCnv.cxx
new file mode 100644
index 00000000000..cabe40b8bc5
--- /dev/null
+++ b/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementContainerCnv.cxx
@@ -0,0 +1,5 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Dummy source file so that cmake will know this is a custom converter.
diff --git a/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementContainerCnv.h b/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementContainerCnv.h
new file mode 100644
index 00000000000..dc4c4db8b3c
--- /dev/null
+++ b/Event/xAOD/xAODPFlowAthenaPool/src/xAODFlowElementContainerCnv.h
@@ -0,0 +1,14 @@
+// this file is -*- c++ -*-
+/*
+Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration 
+*/ 
+
+#ifndef XAODPFLOWATHENAPOOL_XAODFLOWELEMENTCONTAINERCNV_H
+#define XAODPFLOWATHENAPOOL_XAODFLOWELEMENTCONTAINERCNV_H
+
+#include "xAODPFlow/FlowElementContainer.h"
+#include "AthenaPoolCnvSvc/T_AthenaPoolxAODCnv.h"
+
+typedef T_AthenaPoolxAODCnv<xAOD::FlowElementContainer> xAODFlowElementContainerCnv;
+
+#endif //XAODPFLOWATHENAPOOL_XAODFLOWELEMENTCONTAINERCNV_H
-- 
GitLab