-
Christopher Rob Jones authoredChristopher Rob Jones authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
RichTel40CableMapping.cpp 9.88 KiB
/*****************************************************************************\
* (c) Copyright 2000-2020 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. *
\*****************************************************************************/
// local
#include "RichFutureDAQ/RichTel40CableMapping.h"
// RICH
#include "RichUtils/RichException.h"
#include "RichUtils/ToArray.h"
#include "RichUtils/ZipRange.h"
// Gaudi
#include "Gaudi/Algorithm.h"
// Messaging
#include "RichFutureUtils/RichMessaging.h"
#define debug( ... ) \
if ( messenger() ) { ri_debug( __VA_ARGS__ ); }
#define verbo( ... ) \
if ( messenger() ) { ri_verbo( __VA_ARGS__ ); }
#define warning( ... ) \
if ( messenger() ) { ri_warning( __VA_ARGS__ ); }
#define info( ... ) \
if ( messenger() ) { ri_info( __VA_ARGS__ ); }
// boost
#include "boost/container/static_vector.hpp"
// STL
#include <algorithm>
#include <limits>
#include <string>
#include <utility>
#include <vector>
using namespace Rich::Future::DAQ;
using namespace Rich::Detector;
using namespace Rich::DAQ;
void Tel40CableMapping::fillCableMaps( const LHCb::Detector::DeLHCb&
#ifdef USE_DD4HEP
lhcb
#endif
,
const Conds& C ) {
// check status is (still) OK before continuing
if ( !isInitialised() ) { return; }
// panel data
const auto rich_types = std::array{Rich::Rich1, Rich::Rich1, Rich::Rich2, Rich::Rich2};
const auto panel_types = std::array{Rich::top, Rich::bottom, Rich::aside, Rich::cside};
// mapping version
boost::container::static_vector<int, rich_types.size()> condVers;
for ( const auto& cond : C ) {
// Access parameter, with default value 0 if missing
condVers.push_back( condition_param<int>( cond, "MappingVersion", 0 ) );
}
// Should all be the same for all panels.
if ( !condVers.empty() && std::all_of( condVers.begin(), condVers.end(),
[first = condVers.front()]( const auto& e ) { return e == first; } ) ) {
m_mappingVer = condVers.front();
} else {
setIsInitialised( false );
throw Rich::Exception( "Inconsistent mapping versions" );
}
debug( " -> Mapping Version ", m_mappingVer, endmsg );
// extract the mappings
for ( const auto&& [cond, rich, panel, name] : Ranges::ConstZip( C, rich_types, panel_types, ConditionPaths ) ) {
// Number of links for this RICH panel
const std::size_t nLinks = condition_param<int>( cond, "NumberOfLinks" );
if ( nLinks > 0 ) {
debug( " -> Found ", nLinks, " links for ", rich, " ", Rich::text( rich, panel ), endmsg );
// Load links data
const auto pmtTypes = condition_param<std::vector<std::string>>( cond, "PMTTypes" );
const auto modNames = condition_param<std::vector<std::string>>( cond, "ModuleNames" );
const auto modNums = condition_param<std::vector<int>>( cond, "ModuleNumbers" );
const auto pdmdbs = condition_param<std::vector<int>>( cond, "PDMDBNumbers" );
const auto pdmdbLinks = condition_param<std::vector<int>>( cond, "PDMDBLinks" );
const auto sourceIDs = condition_param<std::vector<int>>( cond, "Tel40SourceIDs" );
const auto connectors = condition_param<std::vector<int>>( cond, "Tel40SConnectors" );
const auto mpos = condition_param<std::vector<int>>( cond, "Tel40MPOs" );
const auto statuses = condition_param<std::vector<int>>( cond, "Tel40LinkIsActive" );
// sanity size check
if ( nLinks != pmtTypes.size() || //
nLinks != modNames.size() || //
nLinks != modNums.size() || //
nLinks != pdmdbs.size() || //
nLinks != pdmdbLinks.size() || //
nLinks != sourceIDs.size() || //
nLinks != connectors.size() || //
nLinks != mpos.size() || //
nLinks != statuses.size() ) {
setIsInitialised( false );
throw Rich::Exception( "Inconsistent data sizes for '" + name + "'" );
}
// Find Max SourceID for this RICH/Side
assert( !sourceIDs.empty() );
const SourceID maxSID( *std::max_element( sourceIDs.begin(), sourceIDs.end() ) );
// handle this silently to work around issues with older DB tags.
if ( rich != maxSID.rich() || panel != maxSID.side() ) {
setIsInitialised( false );
continue;
}
// initialise the data storage
auto& tel40CD = m_tel40ConnData.at( rich ).at( panel );
tel40CD.resize( 1 + maxSID.payload() );
verbo( " -> Reserved space for ", tel40CD.size(), " sourceIDs", endmsg );
// loop over data and fill lookup structures
for ( const auto&& [type, name, modN, pdmdb, pdmdbLink, sID, conn, mpo, status] : //
Ranges::ConstZip( pmtTypes, modNames, modNums, pdmdbs, pdmdbLinks, //
sourceIDs, connectors, mpos, statuses ) ) {
// data
assert( (std::size_t)conn <= ConnectionsPerTel40MPO );
assert( sID >= 0 && sID < std::numeric_limits<SourceID::Type>::max() );
const SourceID sourceID( sID );
assert( rich == sourceID.rich() && panel == sourceID.side() );
// connections in DB are numbered [1-12] so subtract one to convert to [0-11]
// In first (unrealistic) implementation MPO was just [1,2] for the two groups
// of 12 connections per sourceID. In the real DB they are [1,3] for the first
// SourceID per Tel40, [5,7] for the second SourceID. As we just need to know
// which of the two groups we have, map back to [1,2]
assert( 1 == mpo || 2 == mpo || 3 == mpo || 5 == mpo || 7 == mpo );
auto norm_mpo = []( const auto mpo ) {
switch ( mpo ) {
case 1:
return 1;
case 2:
return 2;
case 3:
return 2;
case 5:
return 1;
case 7:
return 2;
}
return std::numeric_limits<int>::signaling_NaN();
};
const Tel40Connector link( ( ConnectionsPerTel40MPO * ( norm_mpo( mpo ) - 1 ) ) + ( conn - 1 ) );
// PMT type
const bool isLargePMT = ( "H" == type );
// The cached RichSmartID for this entry
LHCb::RichSmartID smartID( rich, panel, LHCb::RichSmartID::MaPMTID );
smartID.setLargePMT( isLargePMT );
// Is link active. Start with value in RICH condition.
bool linkIsActive = ( 0 != status );
#ifdef USE_DD4HEP
// Use link status flag from general LHCb condition instead of from RICH condition.
const auto linksActive = lhcb.tell40link( sourceID.data() );
if ( !linksActive.has_value() ) {
warning( "Source ID '", sourceID.data(), "' is missing in LHCb Tel40 Link condition", endmsg );
} else {
// LHCb general condition has this source ID so use its value instead.
linkIsActive = linksActive.value().isEnabled( link.data() );
}
#else
// with DetDesc just use RICH value
// Eventually once DetDesc is dropped the use of the RICH status code can be dropped
// entirely both here and from the condition itself in dd4hep.
#endif
// link data struct
const Tel40LinkData linkD( name, //
smartID, //
sourceID, //
link, //
isLargePMT, //
linkIsActive, //
PDModuleNumber( modN ), //
PDMDBID( pdmdb ), //
PDMDBFrame( pdmdbLink ) );
// fill the Tel40 connection data structure
const std::size_t idx = sourceID.payload();
if ( idx >= tel40CD.size() ) {
throw Rich::Exception( "Tel40 Source ID '" + std::to_string( idx ) + "' exceeds expected range" );
}
auto& conData = tel40CD.at( idx );
assert( (std::size_t)link.data() < Tel40CableMapping::MaxConnectionsPerTel40 );
if ( conData.size() <= (std::size_t)link.data() ) { conData.resize( link.data() + 1 ); }
conData.at( link.data() ) = linkD;
if ( linkIsActive ) {
++conData.nActiveLinks;
} else {
conData.hasInactiveLinks = true;
}
verbo( " -> ", linkD, endmsg );
// fill Tel40 module data structure
auto& d = m_tel40ModuleData.at( modN ).at( pdmdb ).at( pdmdbLink );
assert( !d.isValid() ); // not yet initialised
d = std::move( linkD ); // final use of linkD so move
// fill the active links per source ID map
auto& links = m_linksPerSourceID[sourceID]; // Intentionally get-or-create here
// No entry for this link should already exist
assert( std::find( links.begin(), links.end(), link ) == links.end() );
// finally insert
links.insert( link );
}
} // nLinks > 0
} // conditions loop
}