Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • rrabadan/LHCb
  • talin/LHCb
  • imjelde/LHCb
  • mstahl/LHCb
  • padeken/LHCb
  • mimazure/LHCb
  • roiser/LHCb
  • conrad/LHCb
  • kklimasz/LHCb
  • rcurrie/LHCb
  • wkrzemie/LHCb
  • fkeizer/LHCb
  • valassi/LHCb
  • hschrein/LHCb
  • anstahll/LHCb
  • jonrob/LHCb
  • graven/LHCb
  • clemenci/LHCb
  • chaen/LHCb
  • sstahl/LHCb
  • lhcb/LHCb
21 results
Show changes
Commits on Source (65)
Showing
with 610 additions and 433 deletions
......@@ -46,14 +46,13 @@ namespace LHCb::Calo::Interfaces {
virtual hypoPairStruct getElectronBrem( LHCb::ProtoParticle const& proto ) const = 0;
virtual State caloState( ProtoParticle const& proto, IGeometryInfo const& geometry ) const = 0;
virtual State closestState( ProtoParticle const& proto, IGeometryInfo const& geometry ) const = 0;
virtual Momentum bremMomentum( ProtoParticle const& proto ) const = 0;
virtual std::optional<double> caloTrajectoryL( ProtoParticle const& proto, IGeometryInfo const& geometry,
CaloPlane::Plane refPlane = CaloPlane::ShowerMax ) const = 0;
virtual State caloState( const DeCalorimeter& detCalo, ProtoParticle const& proto,
IGeometryInfo const& geometry ) const = 0;
virtual Momentum bremMomentum( ProtoParticle const& proto ) const = 0;
// interface that does not require ProtoParticle or Hypo, just basic track and cluster...
virtual State caloState( const LHCb::Track&, IGeometryInfo const& geometry ) const = 0;
virtual State caloState( const DeCalorimeter& detCalo, const LHCb::Track&,
IGeometryInfo const& geometry ) const = 0;
// functions implemented in terms of other functions...
double eOverP( ProtoParticle const& proto ) const {
......
......@@ -40,8 +40,6 @@ struct ICaloElectron : public extend_interfaces<IPart2Calo> {
virtual LHCb::Calo::Momentum bremCaloMomentum() = 0;
using ITrack2Calo::closestState;
virtual LHCb::State closestState( std::string toWhat = "hypo" ) = 0;
virtual double caloTrajectoryZ( CaloPlane::Plane refPlane = CaloPlane::ShowerMax, std::string toWhat = "hypo" ) = 0;
virtual double caloTrajectoryL( CaloPlane::Plane refPlane = CaloPlane::ShowerMax, std::string toWhat = "hypo" ) = 0;
};
......@@ -124,28 +124,15 @@ for report in ["Dec", "Sel"]:
"OutputHlt" + report + "ReportsLocation":
hltname + "/" + report + "Reports"
},
properties={"SourceID": hltname},
properties={
"SourceID": hltname,
"DecoderMapping": "TCKANNSvc"
},
conf=DecoderDB)
if report == "Sel":
dec.Outputs[
"OutputHltObjectSummariesLocation"] = hltname + "/SelReports/Candidates"
#Vertex Decoder
for hltname in ["Hlt1", "Hlt2"]:
Decoder(
"HltVertexReportsDecoder/" + hltname + "VertexReportsDecoder",
active=True,
banks=["HltVertexReports"],
inputs={"RawEventLocations": None},
outputs={
"OutputHltVertexReportsLocations": [
hltname + "/VertexReports/PV3D",
hltname + "/VertexReports/ProtoPV3D"
]
},
properties={"SourceID": hltname},
conf=DecoderDB)
#is a Routing bits filter really a decoder? it doesn't create output...
Decoder(
"HltRoutingBitsFilter",
......
......@@ -13,6 +13,7 @@
|-histo_file = '' (default: '')
|-input_files = ['root://eoslhcb.cern.ch//eos/lhcb/wg/rta/WP6/Allen/digi_input/upgrade-magup-sim10aU1-minbias/Digi-00151659_00000001_dddb-20220705_sim-20220705-vc-mu100.digi']
| (default: [])
|-input_manifest_file = '' (default: '')
|-input_raw_format = 0.5 (default: 0.5)
|-input_type = 'ROOT' (default: '')
|-lines_maker = None
......@@ -25,13 +26,13 @@
|-ntuple_file = '' (default: '')
|-output_file = '' (default: '')
|-output_level = 3 (default: 3)
|-output_manifest_file = '' (default: '')
|-output_type = '' (default: '')
|-phoenix_filename = '' (default: '')
|-print_freq = 10000 (default: 10000)
|-python_logging_level = 20 (default: 20)
|-scheduler_legacy_mode = True (default: True)
|-simulation = True (default: True)
|-tck = 0 (default: 0)
|-use_iosvc = False (default: False)
| (default: '')
\----- (End of User ApplicationOptions/ApplicationOptions) -----------------------------------------
......
......@@ -18,7 +18,6 @@
#include "Event/PackedCaloDigit.h"
#include "Event/PackedCaloHypo.h"
#include "Event/PackedCluster.h"
#include "Event/PackedData.h"
#include "Event/PackedDataBuffer.h"
#include "Event/PackedDecReport.h"
#include "Event/PackedFlavourTag.h"
......
......@@ -9,32 +9,12 @@
* or submit itself to any jurisdiction. *
\*****************************************************************************/
#pragma once
#include "Event/RawBank.h"
#include "GaudiKernel/StatusCode.h"
#include <iomanip>
#include <string>
namespace LHCb::Hlt::PackedData {
enum HeaderIDs { kVersionNumber = 2 };
/// Bit masks in the SourceID word
enum struct SourceIDMasks : uint16_t { PartID = 0x00FF, Reserved = 0x1F00, Compression = 0xE000 };
template <SourceIDMasks m>
uint16_t extract( uint16_t i ) {
auto s = __builtin_ctz( static_cast<unsigned>( m ) );
return ( i & static_cast<unsigned>( m ) ) >> s;
}
template <SourceIDMasks m>
uint16_t shift( uint16_t i ) {
auto s = __builtin_ctz( static_cast<unsigned>( m ) );
uint16_t v = ( i << s ) & static_cast<unsigned>( m );
assert( extract<m>( v ) == i );
return v;
}
/// Compression algorithms -- note: these values are written to the RawBank, so have to remain stable
/// hence we do _not_ use native ROOT values, which could change between ROOT versions...
enum struct Compression { NoCompression = 0, ZLIB = 1, LZMA = 2, LZ4 = 3, ZSTD = 4 };
......@@ -60,7 +40,7 @@ namespace LHCb::Hlt::PackedData {
inline StatusCode parse( Compression& c, std::string in ) {
auto sv = std::string_view( in );
if ( !sv.empty() && ( sv.front() == '\'' || sv.front() == '\"' ) && sv.front() == sv.back() ) {
if ( sv.size() > 1 && ( sv.front() == '\'' || sv.front() == '\"' ) && sv.front() == sv.back() ) {
sv.remove_prefix( 1 );
sv.remove_suffix( 1 );
};
......@@ -72,11 +52,4 @@ namespace LHCb::Hlt::PackedData {
return StatusCode::SUCCESS;
}
/// Return the part ID from the SourceID word
inline std::uint32_t partID( RawBank const& b ) { return extract<SourceIDMasks::PartID>( b.sourceID() ); }
/// Return the compression from the SourceID word
inline Compression compression( RawBank const& b ) {
return static_cast<Compression>( extract<SourceIDMasks::Compression>( b.sourceID() ) );
}
} // namespace LHCb::Hlt::PackedData
......@@ -11,6 +11,7 @@
#pragma once
#include "Compression.h"
#include "Event/PackedData.h"
#include "Kernel/STLExtensions.h"
#include "RVersion.h"
#include <algorithm>
#include <cstdint>
......@@ -68,6 +69,7 @@ namespace LHCb::Hlt::PackedData {
class ByteBuffer {
public:
using buffer_type = std::vector<std::byte>;
using buffer_view = span<std::byte const>;
/// Return the current position in the buffer.
std::size_t pos() const { return m_pos; }
......@@ -81,7 +83,7 @@ namespace LHCb::Hlt::PackedData {
/// Reset the position to zero without clearing the buffer
void reset() { m_pos = 0; }
/// Initialize from an existing buffer and reset position to zero.
bool init( const buffer_type& data, bool compressed = false );
bool init( buffer_view data, bool compressed = false );
/// Return the internal buffer.
const buffer_type& buffer() const { return m_buffer; }
/// Return the size of the internal buffer.
......@@ -143,11 +145,11 @@ namespace LHCb::Hlt::PackedData {
m_pos += x.size();
}
/// Take requested part of the buffer
LHCb::span<std::byte const> subspan( size_t offset, size_t size = gsl::dynamic_extent ) const {
ByteBuffer::buffer_view subspan( size_t offset, size_t size = gsl::dynamic_extent ) const {
return LHCb::span{m_buffer}.subspan( offset, size );
}
/// Add sub span of a buffer to a new buffer
void assign( LHCb::span<std::byte const> data ) {
void assign( ByteBuffer::buffer_view data ) {
m_buffer.assign( data.begin(), data.end() );
m_pos = 0;
}
......@@ -262,15 +264,18 @@ namespace LHCb::Hlt::PackedData {
*/
class PackedDataOutBuffer {
public:
PackedDataOutBuffer( std::uint32_t key ) : m_key{key} {}
/// Clear the internal byte buffer.
void clear() { m_buffer.clear(); }
/// Return a reference to the internal buffer.
const std::vector<std::byte>& buffer() const { return m_buffer.buffer(); }
const ByteBuffer::buffer_type& buffer() const { return m_buffer.buffer(); }
/// Compress the buffer
bool compress( Compression compression, int level, ByteBuffer::buffer_type& output ) const {
return m_buffer.compress( compression, level, output );
}
std::uint32_t key() const { return m_key; }
/// Reserve size for the buffer
void reserve( std::size_t size ) { m_buffer.reserve( size ); }
/// Function called by serializable objects' save method.
......@@ -301,9 +306,16 @@ namespace LHCb::Hlt::PackedData {
m_buffer.write( x, pos );
}
/// Add byte buffer of a packed data buffer to another one
void addBuffer( PackedDataOutBuffer const& x ) { m_buffer.writeBuffer( x.m_buffer ); }
/// Add a byte buffer to a packed data buffer
void addBuffer( ByteBuffer const& x ) { m_buffer.writeBuffer( x ); }
void addBuffer( PackedDataOutBuffer const& x ) {
// if empty, inherit value from x. If not empty, require to be the same
if ( x.m_key != m_key ) {
if ( m_key != 0 || m_buffer.size() != 0 || m_buffer.pos() != 0 ) {
throw std::runtime_error( "PackedDataInBuffer: merging buffers with distinct keys" );
}
m_key = x.m_key;
}
m_buffer.writeBuffer( x.m_buffer );
}
/// Save a size integer.
std::pair<std::size_t, std::size_t> saveSize( std::size_t x ) { return save<uint32_t>( x ); }
/// Save a vector of scalars.
......@@ -338,7 +350,8 @@ namespace LHCb::Hlt::PackedData {
}
private:
ByteBuffer m_buffer; ///< Internal byte buffer
std::uint32_t m_key = 0u; ///< key used to encode, and thus required, to decode stored strings
ByteBuffer m_buffer; ///< Internal byte buffer
};
/** @class PackedDataInBuffer PackedDataBuffer.h
......@@ -349,19 +362,10 @@ namespace LHCb::Hlt::PackedData {
*/
class PackedDataInBuffer {
public:
/// Return whether the end of buffer was reached.
bool eof() const { return m_buffer.eof(); }
/// Skip a number of bytes from the buffer.
void skip( std::size_t n ) { m_buffer.readNull( n ); }
/// Initialize from an existing byte buffer.
bool init( const ByteBuffer::buffer_type& data, bool compressed = false ) {
return m_buffer.init( data, compressed );
}
bool init( const ByteBuffer& buffer, bool compressed = false ) {
return m_buffer.init( buffer.buffer(), compressed );
}
PackedDataInBuffer( std::uint32_t key = 0 ) : m_key{key} {}
/// Initialize from an existing header and byte buffer.
void init( const ObjectHeader header, const ByteBuffer::buffer_type& data ) {
PackedDataInBuffer( const ObjectHeader header, ByteBuffer::buffer_view data, std::uint32_t key ) {
m_key = key;
m_buffer.clear();
m_buffer.write( header.classID );
m_buffer.write( header.locationID );
......@@ -370,8 +374,25 @@ namespace LHCb::Hlt::PackedData {
for ( auto d : data ) m_buffer.write( d );
m_buffer.reset();
}
/// init a byte buffer from a subset of another packed data buffer
PackedDataInBuffer( PackedDataInBuffer const& x, std::size_t pos, std::size_t size = -1 ) {
m_key = x.m_key;
m_buffer.assign(
x.m_buffer.subspan( pos, size == static_cast<std::size_t>( -1 ) ? x.m_buffer.pos() - pos : size ) );
}
/// Return whether the end of buffer was reached.
bool eof() const { return m_buffer.eof(); }
/// Skip a number of bytes from the buffer.
void skip( std::size_t n ) { m_buffer.readNull( n ); }
/// Initialize from an existing byte buffer.
bool init( ByteBuffer::buffer_view data, bool compressed = false ) { return m_buffer.init( data, compressed ); }
bool init( const ByteBuffer& buffer, bool compressed = false ) {
return m_buffer.init( buffer.buffer(), compressed );
}
std::uint32_t key() const { return m_key; }
/// Return a reference to the internal buffer.
const ByteBuffer& buffer() const { return m_buffer; }
const ByteBuffer& buffer() const& { return m_buffer; }
ByteBuffer buffer() && { return std::move( m_buffer ); }
/// Clear the internal byte buffer.
void clear() { m_buffer.clear(); }
/// Function called by serializable objects' load method.
......@@ -418,12 +439,6 @@ namespace LHCb::Hlt::PackedData {
return x;
}
/// Add a byte buffer of a packed data buffer to another one at a given position
void addBuffer( PackedDataInBuffer const& x, std::uint32_t p ) {
return m_buffer.assign( x.m_buffer.subspan( p, x.m_buffer.pos() - p ) );
}
/// Add a byte buffer of a packed data buffer to another one at a given position
void addBuffer( ByteBuffer const& x, std::uint32_t p ) { return m_buffer.assign( x.subspan( p, x.pos() - p ) ); }
/// Load a scalar from a given position and return it.
template <typename T>
T loadAt( std::size_t i ) const {
......@@ -468,7 +483,50 @@ namespace LHCb::Hlt::PackedData {
}
private:
ByteBuffer m_buffer; ///< Internal byte buffer
std::uint32_t m_key = 0; ///< key used to encode, and thus required to decode stored strings
ByteBuffer m_buffer; ///< Internal byte buffer
};
class MappedInBuffers {
std::unordered_map<std::int32_t, PackedDataInBuffer> m_map; // map of locationID -> buffer:
std::uint32_t m_key = 0;
std::uint32_t m_bankversion = -1;
public:
MappedInBuffers( std::uint32_t key = 0, std::uint32_t bankversion = -1 ) : m_key{key}, m_bankversion{bankversion} {}
std::uint32_t key() const { return m_key; }
std::uint32_t bankVersion() const { return m_bankversion; }
PackedDataInBuffer const* find( std::int32_t locationID ) const {
auto i = m_map.find( locationID );
return i == m_map.end() ? nullptr : &i->second;
}
bool empty() const { return m_map.empty(); }
auto size() const { return m_map.size(); }
auto begin() const { return m_map.begin(); }
auto end() const { return m_map.end(); }
template <typename... Args>
auto try_emplace( Args&&... args ) {
auto i = m_map.try_emplace( std::forward<Args>( args )... );
if ( i.second ) {
if ( !m_key ) {
m_key = i.first->second.key();
} else if ( i.first->second.key() != m_key ) {
throw std::runtime_error( "MappedInBuffers: tried to add buffer with inconsistent key" );
}
}
return i;
}
MappedInBuffers& setBankVersion( std::uint32_t version ) {
if ( version != m_bankversion && m_bankversion != (std::uint32_t)-1 ) {
throw std::runtime_error( "MappedInBuffers: tried to change bankversion which was already set" );
}
m_bankversion = version;
return *this;
}
};
} // namespace LHCb::Hlt::PackedData
/*****************************************************************************\
* (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration *
* *
* This software is distributed under the terms of the GNU General Public *
* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". *
* *
* In applying this licence, CERN does not waive the privileges and immunities *
* granted to it by virtue of its status as an Intergovernmental Organization *
* or submit itself to any jurisdiction. *
\*****************************************************************************/
#pragma once
#include "Kernel/IANNSvc.h"
#include "LHCbAlgs/Consumer.h"
#include "Event/Particle.h"
#include "Event/PackedPartToRelatedInfoRelation.h"
#include "Event/PackedRelations.h"
#include "Event/RelatedInfoMap.h"
#include "Relations/Relation1D.h"
#include "Event/PackedDataBuffer.h"
#include "Event/StandardPacker.h"
#include "RegistryWrapper.h"
/**
* Templated base algorithm for
* Particle to Int and Particle to info relation unpacking algorithms
*
* Note that the inheritance from Consumer and the void input are misleading.
* The algorithm is reading from and writing to TES, just via Handles so that
* it can deal with non existant input and with output failures, which is not
* authorized in the functional world.
* FIXME this should not be necessary, it's mainly due to misconfigurations in
* the tests
* Additionally packing requires the data objects to be in TES before one can add links to it
* https://gitlab.cern.ch/lhcb/LHCb/-/issues/180
**/
namespace DataPacking::Buffer {
// Relation types
using Part2IntRelations = LHCb::Relation1D<LHCb::Particle, int>;
using Part2InfoRelations = LHCb::Relation1D<LHCb::Particle, LHCb::RelatedInfoMap>;
template <typename RELATION, typename PRELATION, typename FROM>
class Rel1Unpack : public LHCb::Algorithm::Consumer<void( const LHCb::Hlt::PackedData::PackedDataInBuffer& )> {
using Buffer = LHCb::Hlt::PackedData::PackedDataInBuffer;
public:
Rel1Unpack( const std::string& name, ISvcLocator* pSvcLocator )
: LHCb::Algorithm::Consumer<void( const Buffer& )>( name, pSvcLocator,
KeyValue{"InputName", "/Event/PackedRelations"} ) {}
void operator()( const Buffer& buffer ) const override {
auto* rels = m_rels.put( std::make_unique<RELATION>() );
if ( !buffer.buffer().size() ) return;
// Sadly the pack structure expects an object with a valid RegistryEntry . To be improved
auto prels = RegistryWrapper<PRELATION>( m_rels.fullKey().key() + "_Packed" );
Buffer readBuffer;
readBuffer.init( buffer.buffer(), false );
// Do the actual loading of the objects
LHCb::Hlt::PackedData::ObjectHeader header;
while ( !readBuffer.eof() ) {
Packer::io( readBuffer, header );
auto nBytesRead = readBuffer.load( *prels );
if ( nBytesRead != header.storedSize ) {
this->fatal() << "Loading of object (CLID=" << header.classID << " locationID=" << header.locationID << ") "
<< " consumed " << nBytesRead << " bytes, "
<< " but " << header.storedSize << " were stored!" << endmsg;
}
if ( this->msgLevel( MSG::DEBUG ) ) {
this->debug() << "Loading of object (CLID=" << header.classID << " locationID=" << header.locationID << ") "
<< header.storedSize << " were stored" << endmsg;
}
}
static const Gaudi::StringKey PackedObjectLocations{"PackedObjectLocations"};
for ( auto id : header.linkLocationIDs ) {
auto location = m_hltANNSvc->value( PackedObjectLocations, id );
if ( location ) {
prels->linkMgr()->addLink( location.value().first, nullptr );
} else {
m_missingLinks++;
}
}
if ( prels->data().size() ) {
rels->setVersion( prels->version() );
unpack( *rels, *prels );
}
// Count packed output
m_unpackedData += rels->relations().size();
}
void unpack( Part2IntRelations& rels, const LHCb::PackedRelations& prels ) const {
for ( const auto& prel : prels.data() ) {
for ( int kk = prel.start; prel.end > kk; ++kk ) {
int srcLink( 0 );
int srcKey( 0 );
int destLink( 0 );
int destKey( 0 );
StandardPacker::indexAndKey64( prels.sources()[kk], srcLink, srcKey );
StandardPacker::indexAndKey64( prels.dests()[kk], destLink, destKey );
DataObject* fp = nullptr;
this->evtSvc()->retrieveObject( prels.linkMgr()->link( srcLink )->path(), fp ).ignore();
auto* from = static_cast<FROM*>( fp );
if ( !from ) {
this->warning() << "Source location " << prels.linkMgr()->link( srcLink )->path()
<< " not persisted, skip the relation." << endmsg;
continue;
}
typename RELATION::From f = from->object( srcKey );
typename RELATION::To t = (int)prels.dests()[kk];
StatusCode sc = rels.relate( f, t );
if ( !sc )
this->warning() << "Something went wrong with relation unpacking "
<< "sourceKey " << srcKey << " sourceLink " << srcLink << "destKey " << destKey
<< " destLink " << destLink << endmsg;
}
}
}
void unpack( Part2InfoRelations& rels, const LHCb::PackedRelatedInfoRelations& prels ) const {
for ( const auto& prel : prels.containers() ) {
for ( unsigned int kk = prel.first; prel.last > kk; ++kk ) {
const auto& rel = prels.relations()[kk];
int srcLink( 0 );
int srcKey( 0 );
StandardPacker::indexAndKey64( rel.reference, srcLink, srcKey );
DataObject* fp = nullptr;
this->evtSvc()->retrieveObject( prels.linkMgr()->link( srcLink )->path(), fp ).ignore();
auto* from = static_cast<FROM*>( fp );
if ( !from ) {
this->warning() << "Source location " << prels.linkMgr()->link( srcLink )->path()
<< " not persisted, skip the relation." << endmsg;
continue;
}
typename RELATION::From f = from->object( srcKey );
LHCb::RelatedInfoMap t;
t.reserve( rel.last - rel.first );
for ( const auto& jj : Packer::subrange( prels.info(), rel.first, rel.last ) ) { t.insert( jj ); }
StatusCode sc = rels.relate( f, t );
if ( !sc )
this->warning() << "Something went wrong with relation unpacking "
<< "sourceKey " << srcKey << " sourceLink " << srcLink << endmsg;
}
}
}
private:
ServiceHandle<IANNSvc> m_hltANNSvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve DecReport IDs"};
DataObjectWriteHandle<RELATION> m_rels{this, "OutputName", ""};
mutable Gaudi::Accumulators::StatCounter<> m_unpackedData{this, "# PackedData"};
mutable Gaudi::Accumulators::StatCounter<> m_missingLinks{this, "# Missing Link Locations"};
};
} // namespace DataPacking::Buffer
......@@ -11,7 +11,7 @@
#pragma once
#include "Event/PackedDataBuffer.h"
#include "Kernel/IANNSvc.h"
#include "Kernel/IIndexedANNSvc.h"
#include "LHCbAlgs/Producer.h"
#include "RegistryWrapper.h"
......@@ -32,6 +32,7 @@
namespace DataPacking::Buffer {
using Producer = LHCb::Algorithm::Producer<LHCb::Hlt::PackedData::PackedDataOutBuffer()>;
inline const Gaudi::StringKey PackedObjectLocations{"PackedObjectLocations"};
template <class PACKER>
class Pack final : public Producer {
......@@ -45,14 +46,19 @@ namespace DataPacking::Buffer {
Buffer operator()() const override {
if ( !m_data.exist() ) {
auto const* data = m_data.getIfExists();
m_nbInputFound += ( data != nullptr );
if ( !data ) {
if ( this->msgLevel( MSG::DEBUG ) ) this->debug() << "Input location " << m_data << " doesn't exist." << endmsg;
return {};
return {0};
}
auto const* data = m_data.get();
if ( data->size() == 0 ) {
if ( this->msgLevel( MSG::DEBUG ) ) this->debug() << "Input location " << m_data << " empty." << endmsg;
return {};
// if ( data->size() == 0 ) {
// if ( this->msgLevel( MSG::DEBUG ) ) this->debug() << "Input location " << m_data << " empty." << endmsg;
// return {0};
//}
if ( m_encodingKey == 0 ) {
throw GaudiException( "encoding key is zero", __PRETTY_FUNCTION__, StatusCode::FAILURE );
++m_zero_key;
}
// Sadly the pack structure expects an object with a valid registry entry. To be improved
......@@ -69,36 +75,41 @@ namespace DataPacking::Buffer {
m_nbPackedData += pdata->data().size();
// reserve some space for data, this should be tuned
Buffer buffer;
Buffer buffer( m_encodingKey );
buffer.reserve( pdata->data().size() );
static const Gaudi::StringKey PackedObjectLocations{"PackedObjectLocations"};
auto locationID = m_hltANNSvc->value( PackedObjectLocations, outputLocation() );
auto classID = pdata->clID();
const auto& map = m_annsvc->s2i( m_encodingKey, PackedObjectLocations );
auto iloc = map.find( m_data.fullKey().key() );
if ( iloc == map.end() ) {
error() << "could not locate packedobjectlocation " << m_data.fullKey().key() << " in table with key "
<< m_encodingKey.value() << endmsg;
throw GaudiException( "unknown location", __PRETTY_FUNCTION__, StatusCode::FAILURE );
}
auto locationID = iloc->second;
buffer.save<uint32_t>( classID );
buffer.save<int32_t>( locationID->second );
buffer.save<uint32_t>( pdata->clID() );
buffer.save<int32_t>( locationID );
auto* linkMgr = pdata->linkMgr();
unsigned int nlinks = linkMgr->size();
if ( this->msgLevel( MSG::DEBUG ) ) {
this->debug() << "Packed version " << (unsigned int)pdata->version() << endmsg;
this->debug() << "packed data type " << System::typeinfoName( typeid( *pdata ) ) << endmsg;
this->debug() << "data location " << locationID->first << endmsg;
this->debug() << "data location " << outputLocation() << endmsg;
this->debug() << "packed data size " << pdata->data().size() << endmsg;
this->debug() << "classID " << classID << " locationID " << locationID->second << " nlinks " << nlinks
<< endmsg;
this->debug() << "classID " << pdata->clID() << " locationID " << locationID << " nlinks " << nlinks << endmsg;
}
buffer.saveSize( nlinks );
for ( unsigned int id = 0; id < nlinks; ++id ) {
auto location = linkMgr->link( id )->path();
if ( location[0] != '/' ) { location = "/Event/" + location; }
auto packedLocation = m_containerMap.find( location );
if ( packedLocation != end( m_containerMap ) ) { location = packedLocation->second; }
auto linkID = m_hltANNSvc->value( PackedObjectLocations, location );
buffer.save<int32_t>( linkID->second );
if ( !location.empty() && location.front() != '/' ) { location = "/Event/" + location; }
auto iloc = map.find( location );
if ( iloc == map.end() ) {
error() << "could not locate referred location " << location << " originally: " << linkMgr->link( id )->path()
<< " in table with key " << m_encodingKey.value() << endmsg;
throw GaudiException( "unknown location", __PRETTY_FUNCTION__, StatusCode::FAILURE );
}
buffer.save<int32_t>( iloc->second );
}
// Reserve bytes for the size of the object
......@@ -146,22 +157,27 @@ namespace DataPacking::Buffer {
}
private:
ServiceHandle<IANNSvc> m_hltANNSvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve PackedObjectLocations"};
ServiceHandle<IIndexedANNSvc> m_annsvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve PackedObjectLocations"};
DataObjectReadHandle<typename PACKER::DataVector> m_data{this, "InputName", PACKER::unpackedLocation()};
Gaudi::Property<unsigned int> m_encodingKey{this, "EncodingKey", 0u};
Gaudi::Property<unsigned short int> m_packingVersion{
this, "PackingVersion", (unsigned short int)PACKER::PackedDataVector::defaultPackingVersion(),
"Packing version number"};
Gaudi::Property<bool> m_enableCheck{this, "EnableCheck", false};
// Mapping of reconstruction object to their location after packing
Gaudi::Property<std::map<std::string, std::string>> m_containerMap{this, "ContainerMap"};
mutable Gaudi::Accumulators::BinomialCounter<> m_nbInputFound{this, "input found"};
mutable Gaudi::Accumulators::StatCounter<> m_nbPackedData{this, "# PackedData"};
mutable Gaudi::Accumulators::MsgCounter<MSG::ERROR> m_unregisterError{
this, "Problem unregistering data in PackerBaseAlg", 10};
mutable Gaudi::Accumulators::MsgCounter<MSG::WARNING> m_zero_key{
this,
"Encoding key is zero -- this implies explicit configuration of decoding will be required.. make sure you know "
"how to do this, and will have the required configuration setup",
10};
};
} // namespace DataPacking::Buffer
......@@ -66,15 +66,16 @@ namespace DataPacking::Buffer {
Buffer operator()() const override {
if ( !m_rels.exist() ) {
auto const* rels = m_rels.getIfExists();
m_nbInputFound += ( rels != nullptr );
if ( !rels ) {
if ( this->msgLevel( MSG::DEBUG ) ) this->debug() << "Input location " << m_rels << " doesn't exist." << endmsg;
return {};
return {0};
}
auto const* rels = m_rels.get();
if ( !rels->relations().size() ) {
if ( this->msgLevel( MSG::DEBUG ) ) this->debug() << "Relations empty " << endmsg;
return {};
return {0};
}
// FIXME This (temporary) TES usage should not be needed
......@@ -96,14 +97,22 @@ namespace DataPacking::Buffer {
}
// reserve some space for data, this should be tuned
Buffer buffer;
Buffer buffer{m_encodingKey};
buffer.reserve( prels->data().size() );
static const Gaudi::StringKey PackedObjectLocations{"PackedObjectLocations"};
auto locationID = m_hltANNSvc->value( PackedObjectLocations, outputLocation() );
auto classID = prels->clID();
if ( m_encodingKey == 0 ) ++m_zero_key;
const auto& map = m_annsvc->s2i( m_encodingKey, PackedObjectLocations );
auto iloc = map.find( m_rels.fullKey().key() );
if ( iloc == map.end() ) {
error() << "could not locate packedobjectlocation " << m_rels.fullKey().key() << " in table with key "
<< m_encodingKey.value() << endmsg;
throw GaudiException( "unknown location", __PRETTY_FUNCTION__, StatusCode::FAILURE );
}
auto locationID = iloc->second;
auto classID = prels->clID();
buffer.save<uint32_t>( classID );
buffer.save<int32_t>( locationID->second );
buffer.save<int32_t>( locationID );
auto* linkMgr = prels->linkMgr();
unsigned int nlinks = linkMgr->size();
......@@ -112,11 +121,13 @@ namespace DataPacking::Buffer {
for ( unsigned int id = 0; id < nlinks; ++id ) {
auto location = linkMgr->link( id )->path();
if ( location[0] != '/' ) { location = "/Event/" + location; }
auto packedLocation = m_containerMap.find( location );
if ( packedLocation != end( m_containerMap ) ) { location = packedLocation->second; }
auto linkID = m_hltANNSvc->value( PackedObjectLocations, location );
buffer.save<int32_t>( linkID->second );
auto iloc = map.find( location );
if ( iloc == map.end() ) {
error() << "could not locate referred location " << location << " originally: " << linkMgr->link( id )->path()
<< " in table with key " << m_encodingKey.value() << endmsg;
throw GaudiException( "unknown location", __PRETTY_FUNCTION__, StatusCode::FAILURE );
}
buffer.save<int32_t>( iloc->second );
}
// Reserve bytes for the size of the object
......@@ -280,7 +291,7 @@ namespace DataPacking::Buffer {
private:
DataObjectReadHandle<RELATION> m_rels{this, "InputName", "/Event/PackedRelations"};
ServiceHandle<IANNSvc> m_hltANNSvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve PackdObjectLocations"};
ServiceHandle<IIndexedANNSvc> m_annsvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve PackdObjectLocations"};
/// Related Info Packer
const LHCb::RelatedInfoRelationsPacker m_rInfoPacker{this};
......@@ -288,10 +299,15 @@ namespace DataPacking::Buffer {
// Should add some packing checks, this is here only to make configuration happy for now
Gaudi::Property<bool> m_enableCheck{this, "EnableCheck", false};
// Mapping of reconstruction object to their location after packing
Gaudi::Property<std::map<std::string, std::string>> m_containerMap{this, "ContainerMap"};
Gaudi::Property<unsigned int> m_encodingKey{this, "EncodingKey", 0u};
mutable Gaudi::Accumulators::StatCounter<> m_nbPackedData{this, "# PackedData"};
mutable Gaudi::Accumulators::BinomialCounter<> m_nbInputFound{this, "input found"};
mutable Gaudi::Accumulators::StatCounter<> m_nbPackedData{this, "# PackedData"};
mutable Gaudi::Accumulators::MsgCounter<MSG::WARNING> m_zero_key{
this,
"Encoding key is zero -- this implies explicit configuration of decoding will be required.. make sure you know "
"how to do this, and will have the required configuration setup",
10};
};
} // namespace DataPacking::Buffer
......@@ -10,7 +10,7 @@
\*****************************************************************************/
#pragma once
#include "Kernel/IANNSvc.h"
#include "Kernel/IIndexedANNSvc.h"
#include "LHCbAlgs/Consumer.h"
#include "Event/MCParticle.h"
......@@ -18,6 +18,9 @@
#include "Event/ProtoParticle.h"
#include "Event/RecVertex.h"
#include "Event/PackedPartToRelatedInfoRelation.h"
#include "Event/RelatedInfoMap.h"
#include "Event/PackedRelations.h"
#include "Relations/Relation1D.h"
#include "Relations/RelationWeighted1D.h"
......@@ -25,6 +28,7 @@
#include "Event/PackedDataBuffer.h"
#include "Event/StandardPacker.h"
#include "RawbankV2Compatibility.h"
#include "RegistryWrapper.h"
/**
......@@ -43,24 +47,50 @@
namespace DataPacking::Buffer {
template <typename RELATION, typename PRELATION, typename FROM, typename TO>
class Rel2Unpack : public LHCb::Algorithm::Consumer<void( const LHCb::Hlt::PackedData::PackedDataInBuffer& )> {
// Relation types
using Part2IntRelations = LHCb::Relation1D<LHCb::Particle, int>;
using Part2InfoRelations = LHCb::Relation1D<LHCb::Particle, LHCb::RelatedInfoMap>;
template <typename RELATION, typename PRELATION, typename FROM, typename TO = void>
class RelUnpack : public LHCb::Algorithm::Consumer<void( const LHCb::Hlt::PackedData::MappedInBuffers& )> {
using Buffer = LHCb::Hlt::PackedData::PackedDataInBuffer;
public:
Rel2Unpack( const std::string& name, ISvcLocator* pSvcLocator )
: LHCb::Algorithm::Consumer<void( const Buffer& )>( name, pSvcLocator,
KeyValue{"InputName", "/Event/PackedRelations"} ) {}
RelUnpack( const std::string& name, ISvcLocator* pSvcLocator )
: LHCb::Algorithm::Consumer<void( const LHCb::Hlt::PackedData::MappedInBuffers& )>(
name, pSvcLocator, KeyValue{"InputName", "/Event/DAQ/MappedDstData"} ) {}
void operator()( const Buffer& buffer ) const override {
void operator()( const LHCb::Hlt::PackedData::MappedInBuffers& buffers ) const override {
auto* rels = m_rels.put( std::make_unique<RELATION>() );
if ( buffers.empty() ) {
++m_no_buffers;
return;
}
if ( !buffer.buffer().size() ) return;
const Gaudi::StringKey PackedObjectLocations{"PackedObjectLocations"};
Buffer readBuffer;
readBuffer.init( buffer.buffer(), false );
const auto& s2i = m_annsvc->s2i( buffers.key(), PackedObjectLocations );
auto j = buffers.bankVersion() < 3
? std::find_if( s2i.begin(), s2i.end(),
v2_compatibility::match_first_with_missing_p_after_slash( m_rels.fullKey().key() ) )
: s2i.find( m_rels.fullKey().key() );
if ( j == s2i.end() ) {
// FIXME: requires ref update ++m_unknown;
return;
}
auto* rels = m_rels.put( std::make_unique<RELATION>() );
const auto* buffer = buffers.find( j->second );
if ( !buffer ) {
// FIXME: requires ref update ++m_absent;
return;
}
if ( buffer->buffer().size() == 0 ) return;
Buffer readBuffer{*buffer}; // TODO: avoid copying just because 'pos' gets updated -- allow a 'shallow' emphemeral
// version which allows reading
// Sadly the pack structure expects an object with a valid RegEntry. To be improved
auto prels = RegistryWrapper<PRELATION>( m_rels.fullKey().key() + "_Packed" );
......@@ -90,13 +120,12 @@ namespace DataPacking::Buffer {
<< endmsg;
}
}
static const Gaudi::StringKey PackedObjectLocations{"PackedObjectLocations"};
assert( buffers.key() == readBuffer.key() );
const auto& map = m_annsvc->i2s( readBuffer.key(), PackedObjectLocations );
for ( auto id : header.linkLocationIDs ) {
auto location = m_hltANNSvc->value( PackedObjectLocations, id );
if ( location ) {
prels->linkMgr()->addLink( location.value().first, nullptr );
auto location = map.find( id );
if ( location != end( map ) ) {
prels->linkMgr()->addLink( location->second, nullptr );
} else {
m_missingLinks++;
}
......@@ -104,14 +133,19 @@ namespace DataPacking::Buffer {
if ( prels->data().size() ) {
rels->setVersion( prels->version() );
unpack( *rels, *prels );
if constexpr ( std::is_void<TO>::value )
unpack1d( *rels, *prels );
else
unpack2d( *rels, *prels );
}
// Count packed output
m_unpackedData += rels->relations().size();
}
void unpack( RELATION& rels, const PRELATION& prels ) const {
// Relations between two containers
void unpack2d( RELATION& rels, const PRELATION& prels ) const {
for ( const auto& prel : prels.data() ) {
for ( int kk = prel.start; prel.end > kk; ++kk ) {
......@@ -143,15 +177,14 @@ namespace DataPacking::Buffer {
continue;
}
typename RELATION::From f = from->object( srcKey );
typename RELATION::To t = to->object( destKey );
auto f = from->object( srcKey );
auto t = to->object( destKey );
StatusCode sc;
// only weighted relations have weights
if constexpr ( std::is_same_v<PRELATION, LHCb::PackedWeightedRelations> ) {
typename RELATION::Weight wgt = prels.weights()[kk];
sc = rels.relate( f, t, wgt );
sc = rels.relate( f, t, prels.weights()[kk] );
} else {
sc = rels.relate( f, t );
}
......@@ -176,13 +209,95 @@ namespace DataPacking::Buffer {
}
}
// relation between particles and ints
void unpack1d( Part2IntRelations& rels, const LHCb::PackedRelations& prels ) const {
for ( const auto& prel : prels.data() ) {
for ( int kk = prel.start; prel.end > kk; ++kk ) {
int srcLink( 0 );
int srcKey( 0 );
int destLink( 0 );
int destKey( 0 );
StandardPacker::indexAndKey64( prels.sources()[kk], srcLink, srcKey );
StandardPacker::indexAndKey64( prels.dests()[kk], destLink, destKey );
DataObject* fp = nullptr;
this->evtSvc()->retrieveObject( prels.linkMgr()->link( srcLink )->path(), fp ).ignore();
auto* from = static_cast<FROM*>( fp );
if ( !from ) {
this->warning() << "Source location " << prels.linkMgr()->link( srcLink )->path()
<< " not persisted, skip the relation." << endmsg;
continue;
}
auto f = from->object( srcKey );
auto t = (int)prels.dests()[kk];
StatusCode sc = rels.relate( f, t );
if ( !sc )
this->warning() << "Something went wrong with relation unpacking "
<< "sourceKey " << srcKey << " sourceLink " << srcLink << "destKey " << destKey
<< " destLink " << destLink << endmsg;
}
}
}
// Relation between particles and related info
void unpack1d( Part2InfoRelations& rels, const LHCb::PackedRelatedInfoRelations& prels ) const {
for ( const auto& prel : prels.containers() ) {
for ( unsigned int kk = prel.first; prel.last > kk; ++kk ) {
const auto& rel = prels.relations()[kk];
int srcLink( 0 );
int srcKey( 0 );
StandardPacker::indexAndKey64( rel.reference, srcLink, srcKey );
DataObject* fp = nullptr;
this->evtSvc()->retrieveObject( prels.linkMgr()->link( srcLink )->path(), fp ).ignore();
auto* from = static_cast<FROM*>( fp );
if ( !from ) {
this->warning() << "Source location " << prels.linkMgr()->link( srcLink )->path()
<< " not persisted, skip the relation." << endmsg;
continue;
}
auto f = from->object( srcKey );
LHCb::RelatedInfoMap t;
t.reserve( rel.last - rel.first );
for ( const auto& jj : Packer::subrange( prels.info(), rel.first, rel.last ) ) { t.insert( jj ); }
StatusCode sc = rels.relate( f, t );
if ( !sc )
this->warning() << "Something went wrong with relation unpacking "
<< "sourceKey " << srcKey << " sourceLink " << srcLink << endmsg;
}
}
}
private:
ServiceHandle<IANNSvc> m_hltANNSvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve DecReport IDs"};
ServiceHandle<IIndexedANNSvc> m_annsvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve DecReport IDs"};
DataObjectWriteHandle<RELATION> m_rels{this, "OutputName", ""};
mutable Gaudi::Accumulators::StatCounter<> m_unpackedData{this, "# PackedData"};
mutable Gaudi::Accumulators::MsgCounter<MSG::ERROR> m_unknown{
this, "Requested output is not known for the given input stream - not creating output"};
mutable Gaudi::Accumulators::MsgCounter<MSG::WARNING> m_absent{
this, "Requested output is known, but not present in packed data - creating empty container"};
mutable Gaudi::Accumulators::MsgCounter<MSG::ERROR> m_no_buffers{
this, "Input has empty map of buffers -- can not do anything at this point. Verify HltPackedBufferDecoder "
"configuration"};
mutable Gaudi::Accumulators::StatCounter<> m_unpackedData{this, "# PackedData"};
mutable Gaudi::Accumulators::StatCounter<> m_missingLinks{this, "# Missing Link Locations"};
};
......
......@@ -11,8 +11,9 @@
#pragma once
#include "Event/PackedDataBuffer.h"
#include "Kernel/IANNSvc.h"
#include "Kernel/IIndexedANNSvc.h"
#include "LHCbAlgs/Consumer.h"
#include "RawbankV2Compatibility.h"
#include "RegistryWrapper.h"
/**
......@@ -30,24 +31,36 @@
**/
namespace DataPacking::Buffer {
namespace {
static const Gaudi::StringKey PackedObjectLocations{"PackedObjectLocations"};
}
template <class PACKER>
class Unpack final : public LHCb::Algorithm::Consumer<void()> {
class Unpack final : public LHCb::Algorithm::Consumer<void( LHCb::Hlt::PackedData::MappedInBuffers const& )> {
using Buffer = LHCb::Hlt::PackedData::PackedDataInBuffer;
public:
using Consumer::Consumer;
Unpack( const std::string& name, ISvcLocator* pSvcLocator )
: Consumer{name, pSvcLocator, {"InputName", "/Event/DAQ/MappedDstData"}} {}
StatusCode initialize() override;
void operator()() const override;
void operator()( LHCb::Hlt::PackedData::MappedInBuffers const& ) const override;
private:
ServiceHandle<IANNSvc> m_hltANNSvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve DecReport IDs"};
DataObjectReadHandle<Buffer> m_buffer{this, "InputName", PACKER::packedLocation()};
ServiceHandle<IIndexedANNSvc> m_hltANNSvc{this, "ANNSvc", "HltANNSvc", "Service to resolve location IDs"};
DataObjectWriteHandle<typename PACKER::DataVector> m_data{this, "OutputName", PACKER::unpackedLocation()};
mutable Gaudi::Accumulators::MsgCounter<MSG::ERROR> m_inconsistentSize{this,
"Size read does not match size expected"};
mutable Gaudi::Accumulators::MsgCounter<MSG::ERROR> m_unknown{
this, "Requested output is not known for the given input stream - not creating output"};
mutable Gaudi::Accumulators::MsgCounter<MSG::WARNING> m_absent{
this, "Requested output is known, but not present in packed data - creating empty container"};
mutable Gaudi::Accumulators::MsgCounter<MSG::ERROR> m_no_buffers{
this, "Input has empty map of buffers -- can not do anything at this point. Verify HltPackedBufferDecoder "
"configuration"};
mutable Gaudi::Accumulators::StatCounter<> m_unpackedData{this, "# PackedData"};
mutable Gaudi::Accumulators::StatCounter<> m_missingLinks{this, "# Missing Link Locations"};
};
......@@ -56,25 +69,48 @@ namespace DataPacking::Buffer {
StatusCode Unpack<PACKER>::initialize() {
return Consumer::initialize().andThen( [&] {
if ( this->msgLevel( MSG::DEBUG ) )
this->debug() << "Input " << m_buffer.fullKey() << " Output " << m_data.fullKey() << "" << endmsg;
this->debug() << "Input " << inputLocation() << " Output " << m_data.fullKey() << "" << endmsg;
} );
}
template <class PACKER>
void Unpack<PACKER>::operator()() const {
void Unpack<PACKER>::operator()( LHCb::Hlt::PackedData::MappedInBuffers const& buffers ) const {
if ( buffers.empty() ) {
++m_no_buffers;
return;
}
const auto& s2i = m_hltANNSvc->s2i( buffers.key(), PackedObjectLocations );
auto j = buffers.bankVersion() < 3
? std::find_if( s2i.begin(), s2i.end(),
v2_compatibility::match_first_with_missing_p_after_slash( m_data.fullKey().key() ) )
: s2i.find( m_data.fullKey().key() );
if ( j == s2i.end() ) {
// FIXME: requires update of refs... ++m_unknown;
return;
}
// unfortunately, the output data must be on the TES prior to filling it with data
// as it needs a valid `registry entry` (which it obtains when it is added to the TES)
// for the unpacking to work...
auto* data = m_data.put( std::make_unique<typename PACKER::DataVector>() );
const auto* buffer = buffers.find( j->second );
if ( !buffer ) {
// FIXME: requires update of refs... ++m_absent;
return;
}
if ( buffer->buffer().size() == 0 ) return;
const PACKER packer( this );
const auto buffer = m_buffer.get();
if ( !buffer or !buffer->buffer().size() ) return;
// Sadly the pack structure expects data with valid Registry. To be improved
auto pdata = RegistryWrapper<typename PACKER::PackedDataVector>( m_data.fullKey().key() + "_Packed" );
LHCb::Hlt::PackedData::ObjectHeader header;
Buffer readBuffer;
readBuffer.init( buffer->buffer(), false );
Buffer readBuffer{*buffer}; // TODO: allow for emphemeral 'view' for reading without copying just to update 'pos'
while ( !readBuffer.eof() ) {
readBuffer.load( header.classID );
......@@ -85,6 +121,7 @@ namespace DataPacking::Buffer {
auto nBytesRead = readBuffer.load( *pdata );
if ( nBytesRead != header.storedSize ) {
++m_inconsistentSize;
this->fatal() << "Loading of object (CLID=" << header.classID << " locationID=" << header.locationID << ") "
<< " consumed " << nBytesRead << " bytes, "
<< " but " << header.storedSize << " were stored!" << endmsg;
......@@ -97,12 +134,12 @@ namespace DataPacking::Buffer {
}
}
static const Gaudi::StringKey PackedObjectLocations{"PackedObjectLocations"};
assert( buffers.key() == readBuffer.key() );
const auto& map = m_hltANNSvc->i2s( readBuffer.key(), PackedObjectLocations );
for ( auto id : header.linkLocationIDs ) {
auto location = m_hltANNSvc->value( PackedObjectLocations, id );
if ( location ) {
pdata->linkMgr()->addLink( location.value().first, nullptr );
auto location = map.find( id );
if ( location != end( map ) ) {
pdata->linkMgr()->addLink( location->second, nullptr );
} else {
m_missingLinks++;
}
......@@ -112,12 +149,13 @@ namespace DataPacking::Buffer {
data->setVersion( pdata->version() );
packer.unpack( *pdata, *data );
if ( this->msgLevel( MSG::DEBUG ) ) {
this->debug() << "Created " << data->size() << " data objects from " << m_buffer << endmsg;
this->debug() << "data type " << System::typeinfoName( typeid( data ) ) << endmsg;
this->debug() << "packed data type " << System::typeinfoName( typeid( pdata ) ) << endmsg;
this->debug() << " Packed Data Version = " << (unsigned int)pdata->version() << endmsg;
this->debug() << " Packed Packing Version = " << (unsigned int)pdata->packingVersion() << endmsg;
this->debug() << " Unpacked Data Version = " << (unsigned int)data->version() << endmsg;
this->debug() << "Created " << data->size() << " data objects for " << m_data.fullKey() << " from "
<< inputLocation() << endmsg;
this->debug() << " Output data type " << System::typeinfoName( typeid( *data ) ) << endmsg;
this->debug() << " Packed data type " << System::typeinfoName( typeid( *pdata ) ) << endmsg;
this->debug() << " Packed data Version = " << (unsigned int)pdata->version() << endmsg;
this->debug() << " Packed packing version = " << (unsigned int)pdata->packingVersion() << endmsg;
this->debug() << " Output data Version = " << (unsigned int)data->version() << endmsg;
}
}
......
......@@ -22,7 +22,8 @@
#include "GaudiKernel/DataObjectHandle.h"
#include "Event/PackedDataBuffer.h"
#include "Kernel/IANNSvc.h"
#include "Kernel/IIndexedANNSvc.h"
#include "RawbankV2Compatibility.h"
#include "RegistryWrapper.h"
namespace DataPacking::Buffer {
......@@ -32,43 +33,64 @@ namespace DataPacking::Buffer {
*
* Note that the inheritance from Consumer is misleading. The algorithm is
* writing to TES, just via a Handle so that it can do it at the begining of
* the operator(), as cross pointers are used in the TES and requires this.
* the operator(), as rebuilding pointers from persistency requires objects
* to be in the TES _prior_ to adding their content
*/
static const Gaudi::StringKey PackedObjectLocations{"PackedObjectLocations"};
struct ProtoParticleUnpacker
: LHCb::Algorithm::Consumer<void( DetectorElement const& ),
: LHCb::Algorithm::Consumer<void( LHCb::Hlt::PackedData::MappedInBuffers const&, DetectorElement const& ),
LHCb::DetDesc::usesBaseAndConditions<FixTESPath<Gaudi::Algorithm>, DetectorElement>> {
ProtoParticleUnpacker( const std::string& name, ISvcLocator* pSvcLocator )
: Consumer{name, pSvcLocator, {KeyValue{"StandardGeometryTop", LHCb::standard_geometry_top}}} {}
void operator()( DetectorElement const& ) const override;
: Consumer{name,
pSvcLocator,
{{"InputName", LHCb::PackedProtoParticleLocation::Charged},
{"StandardGeometryTop", LHCb::standard_geometry_top}}} {}
ServiceHandle<IANNSvc> m_hltANNSvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve DecReport IDs"};
void operator()( LHCb::Hlt::PackedData::MappedInBuffers const&, DetectorElement const& ) const override;
DataObjectWriteHandle<LHCb::ProtoParticles> m_protos{this, "OutputName", LHCb::ProtoParticleLocation::Charged};
DataObjectReadHandle<LHCb::Hlt::PackedData::PackedDataInBuffer> m_buffer{
this, "InputName", LHCb::PackedProtoParticleLocation::Charged};
ServiceHandle<IIndexedANNSvc> m_annsvc{this, "ANNSvc", "HltANNSvc", "Service to retrieve DecReport IDs"};
ToolHandleArray<LHCb::Rec::Interfaces::IProtoParticles> m_addInfo{this, "AddInfo", {}};
};
void ProtoParticleUnpacker::operator()( DetectorElement const& lhcb ) const {
void ProtoParticleUnpacker::operator()( LHCb::Hlt::PackedData::MappedInBuffers const& buffers,
DetectorElement const& lhcb ) const {
if ( buffers.empty() ) {
error() << "empty buffer is an error" << endmsg;
// ++m_something;
return;
}
auto* data = m_protos.put( std::make_unique<LHCb::ProtoParticles>() );
const auto& s2i = m_annsvc->s2i( buffers.key(), PackedObjectLocations );
auto const buffer = m_buffer.get();
if ( !buffer or !buffer->buffer().size() ) return;
auto j = buffers.bankVersion() < 3
? std::find_if( s2i.begin(), s2i.end(),
v2_compatibility::match_first_with_missing_p_after_slash( m_protos.fullKey().key() ) )
: s2i.find( m_protos.fullKey().key() );
if ( j == s2i.end() ) {
throw GaudiException{"Could not find entry for requested output " + m_protos.fullKey().key(), __PRETTY_FUNCTION__,
StatusCode::FAILURE};
}
auto* data = m_protos.put( std::make_unique<LHCb::ProtoParticles>() );
const auto* buffer = buffers.find( j->second );
if ( !buffer || !buffer->buffer().size() ) return;
// Sadly the pack structure expects an object with a valid RegEntry. To be improved
auto pdata = RegistryWrapper<LHCb::PackedProtoParticles>( m_protos.fullKey().key() + "_Packed" );
if ( msgLevel( MSG::DEBUG ) )
this->debug() << "Unpacking ProtoParticles from " << m_buffer << " to " << m_protos << endmsg;
this->debug() << "Unpacking ProtoParticles from " << inputLocation() << " to " << m_protos << endmsg;
std::vector<int32_t> linkLocationIDs;
LHCb::Hlt::PackedData::PackedDataInBuffer readBuffer = *buffer;
LHCb::Hlt::PackedData::PackedDataInBuffer readBuffer{*buffer};
const LHCb::ProtoParticlePacker packer( this );
// Do the actual loading of the objects
......@@ -91,10 +113,13 @@ namespace DataPacking::Buffer {
<< "and " << header.linkLocationIDs.size() << " links were stored!" << endmsg;
}
assert( readBuffer.key() == buffers.key() );
const auto& map = m_annsvc->i2s( readBuffer.key(), PackedObjectLocations );
for ( auto id : header.linkLocationIDs ) {
auto location = m_hltANNSvc->value( PackedObjectLocations, id );
if ( location ) {
pdata->linkMgr()->addLink( location.value().first, nullptr );
auto location = map.find( id );
if ( location != end( map ) ) {
pdata->linkMgr()->addLink( location->second, nullptr );
} else {
this->warning() << " could not find the location for link id " << id << endmsg;
}
......
/*****************************************************************************\
* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration *
* (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration *
* *
* This software is distributed under the terms of the GNU General Public *
* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". *
......@@ -8,38 +8,21 @@
* granted to it by virtue of its status as an Intergovernmental Organization *
* or submit itself to any jurisdiction. *
\*****************************************************************************/
#include "ANNSvc.h"
#include <functional>
#include <string>
#pragma once
#include <algorithm>
#include <iterator>
#include <string_view>
class HltANNSvc : public ANNSvc {
public:
HltANNSvc( const std::string& name, ISvcLocator* svcLocator )
: ANNSvc( name, svcLocator,
{{"Hlt1SelectionID"},
{"Hlt2SelectionID"},
{"SpruceSelectionID"},
{"InfoID"},
{"RoutingBits"},
{"RelInfoLocations"},
{"PackedObjectLocations"},
{"PackedObjectTypes"}} ) {}
using ANNSvc::handleUndefined;
std::optional<minor_value_type> handleUndefined( const major_key_type& major,
const std::string& minor ) const override;
private:
Gaudi::Property<bool> m_allowUndefined{this, "allowUndefined", true,
"do we allow undefined, on-demand generated, key/value pairs?"};
};
DECLARE_COMPONENT( HltANNSvc )
std::optional<IANNSvc::minor_value_type> HltANNSvc::handleUndefined( const major_key_type& major,
const std::string& minor ) const {
if ( !m_allowUndefined ) return {};
static const std::hash<std::string> hasher;
debug() << "handleUndefined called for " << major << " : " << minor << " --> " << hasher( minor ) << endmsg;
return minor_value_type( minor, hasher( minor ) );
}
namespace DataPacking::Buffer::v2_compatibility {
inline auto match_first_with_missing_p_after_slash( std::string_view k ) {
return [=]( const auto& i ) {
// for 'v2' banks, the id stored is the '/p' version of the name
// but here we want the actual (target) name...
if ( i.first.size() != k.size() + 1 ) return false;
auto [m, n] = std::mismatch( k.begin(), k.end(), i.first.begin() );
if ( n == i.first.end() || *n != 'p' ) return false;
if ( n == i.first.begin() || *std::prev( n ) != '/' ) return false;
return std::mismatch( m, k.end(), std::next( n ) ).first == k.end();
};
}
} // namespace DataPacking::Buffer::v2_compatibility
......@@ -9,8 +9,7 @@
* or submit itself to any jurisdiction. *
\*****************************************************************************/
#include "Buffer1RelationUnpackerBaseAlg.h"
#include "Buffer2RelationUnpackerBaseAlg.h"
#include "BufferRelationUnpackerBaseAlg.h"
#include "BufferUnpackerBaseAlg.h"
#include "UnpackerBaseAlg.h"
......@@ -89,20 +88,20 @@ DECLARE_COMPONENT_WITH_ID( DataPacking::Buffer::Unpack<LHCb::RecSummaryPacker>,
// ProtoParticleUnpacker is not templated, because it needs an additional function.
// Relation packers
using P2VRELATION = DataPacking::Buffer::Rel2Unpack<LHCb::Relation1D<LHCb::Particle, LHCb::VertexBase>,
LHCb::PackedRelations, LHCb::Particles, LHCb::RecVertices>;
using P2MCPRELATION = DataPacking::Buffer::Rel2Unpack<LHCb::Relation1D<LHCb::Particle, LHCb::MCParticle>,
LHCb::PackedRelations, LHCb::Particles, LHCb::MCParticles>;
using P2VRELATION = DataPacking::Buffer::RelUnpack<LHCb::Relation1D<LHCb::Particle, LHCb::VertexBase>,
LHCb::PackedRelations, LHCb::Particles, LHCb::RecVertices>;
using P2MCPRELATION = DataPacking::Buffer::RelUnpack<LHCb::Relation1D<LHCb::Particle, LHCb::MCParticle>,
LHCb::PackedRelations, LHCb::Particles, LHCb::MCParticles>;
using PP2MCPRELATION =
DataPacking::Buffer::Rel2Unpack<LHCb::RelationWeighted1D<LHCb::ProtoParticle, LHCb::MCParticle, double>,
LHCb::PackedWeightedRelations, LHCb::ProtoParticles, LHCb::MCParticles>;
DataPacking::Buffer::RelUnpack<LHCb::RelationWeighted1D<LHCb::ProtoParticle, LHCb::MCParticle, double>,
LHCb::PackedWeightedRelations, LHCb::ProtoParticles, LHCb::MCParticles>;
using P2IntRELATION =
DataPacking::Buffer::Rel1Unpack<LHCb::Relation1D<LHCb::Particle, int>, LHCb::PackedRelations, LHCb::Particles>;
DataPacking::Buffer::RelUnpack<LHCb::Relation1D<LHCb::Particle, int>, LHCb::PackedRelations, LHCb::Particles>;
using P2InfoRELATION = DataPacking::Buffer::Rel1Unpack<LHCb::Relation1D<LHCb::Particle, LHCb::RelatedInfoMap>,
LHCb::PackedRelatedInfoRelations, LHCb::Particles>;
using P2InfoRELATION = DataPacking::Buffer::RelUnpack<LHCb::Relation1D<LHCb::Particle, LHCb::RelatedInfoMap>,
LHCb::PackedRelatedInfoRelations, LHCb::Particles>;
DECLARE_COMPONENT_WITH_ID( P2VRELATION, "P2VRelationUnpacker" )
DECLARE_COMPONENT_WITH_ID( P2MCPRELATION, "P2MCPRelationUnpacker" )
......
......@@ -35,10 +35,11 @@ namespace LHCb::Hlt::PackedData {
return output_size > 0;
}
bool ByteBuffer::init( const buffer_type& data, bool compressed ) {
bool ByteBuffer::init( buffer_view data, bool compressed ) {
m_pos = 0;
if ( !compressed ) {
m_buffer = data;
assert( m_buffer.data() != data.data() );
m_buffer.assign( data.begin(), data.end() );
return true;
}
if ( data.size() < 9 ) {
......
......@@ -26,7 +26,6 @@ def parse_args():
)
parser.add_argument(
"options",
type=OptionsLoader,
help="YAML data to populate the Application.Options object with. "
"Multiple files can merged using 'file1.yaml+file2.yaml'.")
parser.add_argument("extra_args", nargs="*")
......@@ -45,8 +44,9 @@ def parse_args():
help=argparse.SUPPRESS
# "Name of the Gaudi application to use, primarily needed for Online."
)
args = parser.parse_args()
return main(**vars(args))
kwargs = vars(parser.parse_args())
kwargs["options"] = OptionsLoader(kwargs["function"], kwargs["options"])
return main(**kwargs)
if __name__ == "__main__":
......
......@@ -32,17 +32,19 @@ environment variable. If required ``OVERRIDE_LBEXEC_APP`` can be passed to
override which application is loaded. This is used by projects created by
lb-dev where the value of ``GAUDIAPPNAME`` is ``${PROJECT_NAME}Dev``.
"""
import difflib
import ast
import difflib
import inspect
import os
import re
import shlex
import sys
import traceback
from importlib import import_module
from importlib.machinery import SourceFileLoader
from pathlib import Path
from types import TracebackType
from typing import Optional
from types import ModuleType
from typing import Optional, Callable, get_type_hints
import click
import pydantic
......@@ -64,10 +66,11 @@ class FunctionLoader:
_suggest_spec_fix(spec, spec)
sys.exit(1)
# Import the module
sys.path.insert(0, os.getcwd())
# Import the module, ensuring sys.path behaves the same way as
# "python my_script.py" and is always restored to it's original value
path_backup = sys.path
try:
module = import_module(self.module_name)
module = self.__load_module()
except Exception as e:
if isinstance(e, ModuleNotFoundError) and Path(
self.module_name).is_file():
......@@ -76,7 +79,7 @@ class FunctionLoader:
action_msg = f"import {self.module_name!r}"
_raise_user_exception(e, action_msg, self)
finally:
sys.path.pop(0)
sys.path = path_backup
# Get the function
try:
......@@ -87,6 +90,25 @@ class FunctionLoader:
_suggest_module_fix(self.spec, self.module_name, function_names)
sys.exit(1)
def __load_module(self) -> ModuleType:
if self.module_name.endswith(".py"):
module_path = Path(self.module_name)
if module_path.is_file():
self.module_name = module_path.with_suffix("").name
sys.path = [module_path.parent] + sys.path[1:]
return SourceFileLoader(self.module_name,
str(module_path)).load_module()
if "/" in self.module_name:
log_error(
f"{self.module_name} looks like a filename but it doesn't exist"
)
sys.exit(1)
log_warn(
f"{self.module_name} doesn't exist, assuming it's a Python module"
)
sys.path = [os.getcwd()] + sys.path[1:]
return import_module(self.module_name)
def __call__(self, options: OptionsBase,
*extra_args: list[str]) -> ComponentConfig:
"""Run the user provided function and validate the result"""
......@@ -105,41 +127,65 @@ class FunctionLoader:
return config
@property
def OptionsClass(self) -> type[OptionsBase]:
"""Return the Options class used by the function"""
valid_types = (inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.POSITIONAL_OR_KEYWORD)
positional_param_names = [
n for n, p in inspect.signature(self._function).parameters.items()
if p.kind in valid_types
]
if len(positional_param_names) == 0:
raise TypeError(
f"{self.spec} must accept one or more positional argument(s)")
type_hints = get_type_hints(self._function)
options_arg = positional_param_names[0]
if options_arg not in type_hints:
log_error(f"Failed to find an options type hint for {self.spec}")
_make_type_hint_suggestion(self._function, options_arg)
sys.exit(1)
OptionsClass = type_hints[options_arg]
if not issubclass(OptionsClass, OptionsBase):
log_error(
f"OptionsClass for {self.spec} should inherit from OptionsBase"
)
sys.exit(1)
return OptionsClass
def OptionsLoader(options_spec: str) -> OptionsBase:
"""Convert a '+' separated list of paths to an Application.Options object."""
# Import the Options object from the current application
app_name = os.environ.get("OVERRIDE_LBEXEC_APP",
os.environ.get("GAUDIAPPNAME"))
if not app_name:
log_error("GAUDIAPPNAME is not set in environment!")
sys.exit(1)
# There is no LHCb import but we want it to be usable lbexec for merging
if app_name == "LHCb":
app_name = "GaudiConf.LbExec"
app = import_module(app_name)
Options = getattr(app, "Options", None)
if not Options:
log_error(f"{app_name} doesn't support lbexec")
sys.exit(1)
# Load and merge the various input YAML files
options = {}
for options_yaml in map(Path, re.split(r'(?<!\\)\+', options_spec)):
if not options_yaml.is_file():
log_error(f"{options_yaml} does not exist")
sys.exit(1)
options_data = yaml.safe_load(options_yaml.read_text())
if not isinstance(options_data, dict):
def OptionsLoader(function: FunctionLoader, options_spec: str) -> OptionsBase:
"""Convert a '+' separated list of paths to an Application.Options object."""
if options_spec.endswith((".yaml", ".yml", ".json")):
# Load and merge the various input YAML files
options = {}
for options_yaml in map(Path, re.split(r'(?<!\\)\+', options_spec)):
if not options_yaml.is_file():
log_error(f"{options_yaml} does not exist")
sys.exit(1)
options_data = yaml.safe_load(options_yaml.read_text())
if not isinstance(options_data, dict):
log_error(
f"{options_yaml} should contain a mapping but got {options_data!r}"
)
sys.exit(1)
options.update(options_data)
elif ":" in options_spec:
if options_spec.startswith(":"):
options_spec = function.spec.split(":", 1)[0] + options_spec
# HACK: Abuse the FunctionLoader class to load the options
options = FunctionLoader(options_spec)._function
if not isinstance(options, dict):
log_error(
f"{options_yaml} should contain a mapping but got {options_data!r}"
f"{options_spec} should point to a mapping but got {options!r}"
)
sys.exit(1)
options.update(options_data)
else:
raise NotImplementedError(f"Unrecognised {options_spec!r}")
# Parse the merged YAML
try:
return Options.parse_obj(options)
return function.OptionsClass.parse_obj(options)
except pydantic.ValidationError as e:
errors = e.errors()
log_error(f"Failed to validate options! Found {len(errors)} errors:")
......@@ -147,7 +193,9 @@ def OptionsLoader(options_spec: str) -> OptionsBase:
extra_msg = ""
if error["type"] == "value_error.extra" and len(error["loc"]) == 1:
suggestions = difflib.get_close_matches(
error["loc"][0], Options.schema()["properties"], n=1)
error["loc"][0],
function.OptionsClass.schema()["properties"],
n=1)
if suggestions:
extra_msg = click.style(
f"Did you mean {suggestions[0]!r}?", fg="green")
......@@ -165,10 +213,45 @@ def log_info(message):
click.echo(click.style("INFO: ", fg="green") + message, err=True)
def log_warn(message):
click.echo(click.style("WARN: ", fg="yellow") + message, err=True)
def log_error(message):
click.echo(click.style("ERROR: ", fg="red") + message, err=True)
def _make_type_hint_suggestion(function: Callable, options_arg: str) -> str:
# Try to guess what the application name should be
app_name = os.environ.get("GAUDIAPPNAME", "!!!ADD_APP_NAME_HERE!!!")
# There is no LHCb import but we want it to be usable lbexec for merging
if app_name == "LHCb":
app_name = "GaudiConf.LbExec"
original = inspect.getsource(function).split("\n")[0]
# Try to guess how the Python code should look
sig = inspect.signature(function)
parameter_fixed = sig.parameters[options_arg].replace(
annotation="to-be-replaced!")
sig_fixed = sig.replace(
parameters=[parameter_fixed] + list(sig.parameters.values())[1:])
fixed = original.replace(
str(sig),
str(sig_fixed).replace("'to-be-replaced!'", "Options"))
# If the code is unchanged something went wrong
if fixed == original:
log_error("Failed to generate corrected Python code")
else:
log_error("*** You probably need to replace:")
log_error(original)
log_error("*** with:")
log_error(f"from {app_name} import Options")
log_error("")
log_error(fixed)
source_file = inspect.getsourcefile(function)
_, lineno = inspect.getsourcelines(function)
log_error(f"*** in {source_file}:{lineno}")
def _suggest_spec_fix(spec, module_name: str, func_name: Optional[str] = None):
if os.path.isfile(module_name):
filename = Path(module_name).absolute().relative_to(Path.cwd())
......@@ -205,7 +288,7 @@ def _guess_function_names(module_name: str,
def _suggest_module_fix(spec: str, module_name: str,
function_names: list[str]):
log_error(f"There seems to be an issue with your funcion specification.")
log_error("There seems to be an issue with your funcion specification.")
if function_names:
click.echo("Did you mean one of these:\n", err=True)
for maybe_function in function_names:
......
......@@ -48,6 +48,7 @@ class Options(BaseModel):
input_files: list[str] = []
input_type: FileFormats = FileFormats.NONE
input_raw_format: float = 0.5
input_manifest_file: Optional[str] = None
xml_file_catalog: Optional[str] = None
evt_max: int = -1
first_evt: int = 0
......@@ -56,6 +57,7 @@ class Options(BaseModel):
"""Output"""
output_file: Optional[str] = None
output_type: FileFormats = FileFormats.ROOT
output_manifest_file: Optional[str] = None
compression: Optional[constr(regex=r'^(ZLIB|LZMA|LZ4|ZSTD):\d+$')] = None
histo_file: Optional[str] = None
ntuple_file: Optional[str] = None
......
......@@ -8,17 +8,30 @@
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
def do_nothing(options):
from GaudiConf.LbExec import Options
options_data = {
"data_type": "Upgrade",
"simulation": True,
"dddb_tag": "dddb-20210617",
"conddb_tag": "sim-20210617-vc-md100",
"output_file": "spruce_passthrough2.dst",
"output_type": "ROOT",
"evt_max": 0
}
def do_nothing(options: Options):
from PyConf.application import configure_input
return configure_input(options)
def bad_function(options):
def bad_function(options: Options):
raise TypeError("Something is wrong")
def execption_with_chain(options):
def execption_with_chain(options: Options):
try:
try:
raise Exception("Exception 1")
......@@ -28,15 +41,15 @@ def execption_with_chain(options):
raise Exception("Exception 3")
def return_none(options):
def return_none(options: Options):
return None
def do_something_2022(options):
def do_something_2022(options: Options):
return do_nothing(None)
def do_something_2023(options, *args):
def do_something_2023(options: Options, *args):
return do_nothing(None)
......@@ -46,3 +59,11 @@ def do_something_2024(arg1, arg2):
def wrong_args():
return do_nothing(None)
def no_type_hint(options):
return do_nothing(options)
def bad_type_hint(options: int):
return do_nothing(options)