Forked from
atlas / athena
113493 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
SCT_PrepDataToxAOD.cxx 19.43 KiB
/*
Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
*/
///////////////////////////////////////////////////////////////////
// SCT_PrepDataToxAOD.cxx
// Implementation file for class SCT_PrepDataToxAOD
///////////////////////////////////////////////////////////////////
#include "SCT_PrepDataToxAOD.h"
#include "xAODTracking/TrackMeasurementValidationAuxContainer.h"
#include "Identifier/Identifier.h"
#include "InDetIdentifier/SCT_ID.h"
#include "InDetRawData/SCT_RDO_Collection.h"
#include "HepMC/GenParticle.h"
#include "InDetSimEvent/SiHit.h"
#include "CLHEP/Geometry/Point3D.h"
#include "StoreGate/ReadHandle.h"
#include "StoreGate/WriteHandle.h"
#define AUXDATA(OBJ, TYP, NAME) \
static const SG::AuxElement::Accessor<TYP> acc_##NAME (#NAME); acc_##NAME(*(OBJ))
/////////////////////////////////////////////////////////////////////
//
// Constructor with parameters:
//
/////////////////////////////////////////////////////////////////////
SCT_PrepDataToxAOD::SCT_PrepDataToxAOD(const std::string &name, ISvcLocator *pSvcLocator) :
AthAlgorithm(name,pSvcLocator),
m_SCTHelper{nullptr},
m_firstEventWarnings{true}
{
}
/////////////////////////////////////////////////////////////////////
//
// Initialize method:
//
/////////////////////////////////////////////////////////////////////
StatusCode SCT_PrepDataToxAOD::initialize()
{
CHECK ( detStore()->retrieve(m_SCTHelper, "SCT_ID") );
//make sure we don't write what we don't have
if (not m_useTruthInfo.value()) {
m_writeSDOs.set(false);
m_writeSiHits.set(false);
}
ATH_CHECK( m_clustercontainer.initialize() );
ATH_CHECK( m_SDOcontainer.initialize(m_writeSDOs.value()) );
ATH_CHECK( m_sihitContainer.initialize(m_writeSiHits.value()) );
ATH_CHECK( m_multiTruth.initialize(m_useTruthInfo.value()) );
ATH_CHECK( m_rdoContainer.initialize(m_writeRDOinformation.value()) );
ATH_CHECK( m_xAodContainer.initialize() );
ATH_CHECK( m_xAodOffset.initialize() );
ATH_CHECK( m_SCTDetEleCollKey.initialize() );
return StatusCode::SUCCESS;
}
/////////////////////////////////////////////////////////////////////
//
// Execute method:
//
/////////////////////////////////////////////////////////////////////
StatusCode SCT_PrepDataToxAOD::execute()
{
// the cluster ambiguity map
std::map< Identifier, const SCT_RDORawData* > idToRAWDataMap;
if (m_writeRDOinformation.value()) {
SG::ReadHandle<SCT_RDO_Container> rdoContainer(m_rdoContainer);
if (rdoContainer.isValid()) {
// get all the RIO_Collections in the container
for (const auto& collection: *rdoContainer) {
//get all the RDOs in the collection
for (const auto& rdo : *collection) {
if (rdo==nullptr) {
ATH_MSG_WARNING( "Null SCT RDO. Skipping it");
continue;
}
Identifier rdoId = rdo->identify();
idToRAWDataMap.insert( std::pair< Identifier, const SCT_RDORawData*>( rdoId, rdo ) );
} // collection
} // Have container;
} else if ( m_firstEventWarnings ) {
ATH_MSG_WARNING( "Failed to retrieve SCT RDO container" );
}
}
ATH_MSG_DEBUG("Size of RDO map is "<<idToRAWDataMap.size());
// Mandatory. This is needed and required if this algorithm is scheduled.
SG::ReadHandle<InDet::SCT_ClusterContainer> sctClusterContainer(m_clustercontainer);
if (not sctClusterContainer.isValid()) {
ATH_MSG_FATAL("Cannot retrieve SCT PrepDataContainer " << m_clustercontainer.key());
return StatusCode::FAILURE;
}
// Create the xAOD container and its auxiliary store:
SG::WriteHandle<xAOD::TrackMeasurementValidationContainer> xaod(m_xAodContainer);
ATH_CHECK( xaod.record(std::make_unique<xAOD::TrackMeasurementValidationContainer>(),
std::make_unique<xAOD::TrackMeasurementValidationAuxContainer>()) );
SG::WriteHandle<std::vector<unsigned int> > offsets(m_xAodOffset);
ATH_CHECK( offsets.record(std::make_unique<std::vector<unsigned int> >( m_SCTHelper->wafer_hash_max(), 0 )) );
// Loop over the container
unsigned int counter(0);
for (const auto& clusterCollection : *sctClusterContainer) {
//Fill Offset container
(*offsets)[clusterCollection->identifyHash()] = counter;
// skip empty collections
if (clusterCollection->empty()) continue;
// loop over collection and convert to xAOD
for (const InDet::SCT_Cluster* prd : *clusterCollection) {
++counter;
Identifier clusterId = prd->identify();
if (not clusterId.is_valid()) {
ATH_MSG_WARNING("SCT cluster identifier is not valid!");
}
// create and add xAOD object
xAOD::TrackMeasurementValidation* xprd = new xAOD::TrackMeasurementValidation();
xaod->push_back(xprd);
//Set Identifier
xprd->setIdentifier( clusterId.get_compact() );
//Set Global Position
Amg::Vector3D gpos = prd->globalPosition();
xprd->setGlobalPosition(gpos.x(),gpos.y(),gpos.z());
//Set Local Position
const Amg::Vector2D& locpos = prd->localPosition();
float locY(0.);
float locX = locpos.x();
if (not (std::isinf(locpos.y()) or std::isnan(locpos.y()))) {
if (locpos.y()>=1e-07) locY=locpos.y();
} else {
locY = -9999.;
}
// Set local error matrix
xprd->setLocalPosition(locX,locY);
const Amg::MatrixX& localCov = prd->localCovariance();
if (localCov.size() == 1) {
xprd->setLocalPositionError( localCov(0,0), 0., 0. );
} else if (localCov.size() == 4) {
xprd->setLocalPositionError( localCov(0,0), localCov(1,1), localCov(0,1) );
} else {
xprd->setLocalPositionError(0.,0.,0.);
}
// Set vector of hit identifiers
std::vector< uint64_t > rdoIdentifierList;
for (const auto &hitIdentifier : prd->rdoList()) {
rdoIdentifierList.push_back( hitIdentifier.get_compact() );
}
xprd->setRdoIdentifierList(rdoIdentifierList);
//Add SCT specific information
const InDet::SiWidth cw = prd->width();
AUXDATA(xprd, int, SiWidth) = (int)cw.colRow()[0];
AUXDATA(xprd, int, hitsInThirdTimeBin) = (int)(prd->hitsInThirdTimeBin());
AUXDATA(xprd, int, bec) = m_SCTHelper->barrel_ec(clusterId) ;
AUXDATA(xprd, int, layer) = m_SCTHelper->layer_disk(clusterId) ;
AUXDATA(xprd, int, phi_module) = m_SCTHelper->phi_module(clusterId) ;
AUXDATA(xprd, int, eta_module) = m_SCTHelper->eta_module(clusterId) ;
AUXDATA(xprd, int, side) = m_SCTHelper->side(clusterId) ;
// Add the Detector element ID -- not sure if needed as we have the informations above
const InDetDD::SiDetectorElement* de = prd->detectorElement();
uint64_t detElementId(0);
if (de) {
Identifier detId = de->identify();
if ( detId.is_valid() ) {
detElementId = detId.get_compact();
}
}
AUXDATA(xprd, uint64_t, detectorElementID) = detElementId;
//Add details about the individual hits
if (m_writeRDOinformation.value()) {
addRDOInformation(xprd, prd, idToRAWDataMap);
}
// Use the MultiTruth Collection to get a list of all true particle contributing to the cluster
if (m_useTruthInfo.value()) {
SG::ReadHandle<PRD_MultiTruthCollection> prdmtColl(m_multiTruth);
if (prdmtColl.isValid()) {
std::vector<int> barcodes;
//std::pair<PRD_MultiTruthCollection::const_iterator,PRD_MultiTruthCollection::const_iterator>;
auto range = prdmtColl->equal_range(clusterId);
for (auto i = range.first; i != range.second; ++i) {
barcodes.push_back( i->second.barcode() );
}
AUXDATA(xprd, std::vector<int> , truth_barcode) = barcodes;
}
}
// Use the SDO Collection to get a list of all true particle contributing to the cluster per readout element
// Also get the energy deposited by each true particle per readout element
if (m_writeSDOs.value()) {
SG::ReadHandle<InDetSimDataCollection> sdoCollection(m_SDOcontainer);
if (sdoCollection.isValid()) {
addSDOInformation( xprd, prd, &*sdoCollection);
}
}
// Now Get the most detailed truth from the SiHits
// Note that this could get really slow if there are a lot of hits and clusters
if (m_writeSiHits.value()) {
SG::ReadHandle<SiHitCollection> sihitCollection(m_sihitContainer);
if (sihitCollection.isValid()) {
addSiHitInformation( xprd, prd, &*sihitCollection);
}
}
}
}
ATH_MSG_DEBUG( " recorded SCT_PrepData objects: size " << xaod->size() );
m_firstEventWarnings = false; //disable one-time warnings
return StatusCode::SUCCESS;
}
void SCT_PrepDataToxAOD::addSDOInformation( xAOD::TrackMeasurementValidation* xprd,
const InDet::SCT_Cluster* prd,
const InDetSimDataCollection* sdoCollection ) const
{
std::vector<int> sdo_word;
std::vector< std::vector< int > > sdo_depositsBarcode;
std::vector< std::vector< float > > sdo_depositsEnergy;
// find hit
for (const auto &hitIdentifier : prd->rdoList()) {
auto pos = sdoCollection->find(hitIdentifier);
if (pos != sdoCollection->end()) {
sdo_word.push_back( pos->second.word() ) ;
std::vector< int > sdoDepBC;
std::vector< float > sdoDepEnergy;
for (auto deposit : pos->second.getdeposits()) {
if (deposit.first) {
sdoDepBC.push_back( deposit.first->barcode());
} else {
sdoDepBC.push_back( -1 );
}
sdoDepEnergy.push_back( deposit.second );
ATH_MSG_DEBUG(" SDO Energy Deposit " << deposit.second ) ;
}
sdo_depositsBarcode.push_back( sdoDepBC );
sdo_depositsEnergy.push_back( sdoDepEnergy );
}
}
AUXDATA(xprd, std::vector<int> , sdo_words) = sdo_word;
AUXDATA(xprd, std::vector< std::vector<int> > , sdo_depositsBarcode) = sdo_depositsBarcode;
AUXDATA(xprd, std::vector< std::vector<float> > , sdo_depositsEnergy) = sdo_depositsEnergy;
}
void SCT_PrepDataToxAOD::addSiHitInformation( xAOD::TrackMeasurementValidation* xprd,
const InDet::SCT_Cluster* prd,
const SiHitCollection* sihitCollection) const
{
std::vector<SiHit> matchingHits = findAllHitsCompatibleWithCluster( prd, sihitCollection );
int numHits = matchingHits.size();
std::vector<float> sihit_energyDeposit(numHits,0);
std::vector<float> sihit_meanTime(numHits,0);
std::vector<int> sihit_barcode(numHits,0);
std::vector<float> sihit_startPosX(numHits,0);
std::vector<float> sihit_startPosY(numHits,0);
std::vector<float> sihit_startPosZ(numHits,0);
std::vector<float> sihit_endPosX(numHits,0);
std::vector<float> sihit_endPosY(numHits,0);
std::vector<float> sihit_endPosZ(numHits,0);
int hitNumber(0);
const InDetDD::SiDetectorElement* de = prd->detectorElement();
if (de) {
for (auto sihit : matchingHits) {
sihit_energyDeposit[hitNumber] = sihit.energyLoss() ;
sihit_meanTime[hitNumber] = sihit.meanTime() ;
sihit_barcode[hitNumber] = sihit.particleLink().barcode() ;
// Convert Simulation frame into reco frame
const HepGeom::Point3D<double>& startPos=sihit.localStartPosition();
Amg::Vector2D pos= de->hitLocalToLocal( startPos.z(), startPos.y() );
sihit_startPosX[hitNumber] = pos[0];
sihit_startPosY[hitNumber] = pos[1];
sihit_startPosZ[hitNumber] = startPos.x();
const HepGeom::Point3D<double>& endPos=sihit.localEndPosition();
pos= de->hitLocalToLocal( endPos.z(), endPos.y() );
sihit_endPosX[hitNumber] = pos[0];
sihit_endPosY[hitNumber] = pos[1];
sihit_endPosZ[hitNumber] = endPos.x();
++hitNumber;
}
}
AUXDATA(xprd, std::vector<float> , sihit_energyDeposit) = sihit_energyDeposit;
AUXDATA(xprd, std::vector<float> , sihit_meanTime) = sihit_meanTime;
AUXDATA(xprd, std::vector<int> , sihit_barcode) = sihit_barcode;
AUXDATA(xprd, std::vector<float> , sihit_startPosX) = sihit_startPosX;
AUXDATA(xprd, std::vector<float> , sihit_startPosY) = sihit_startPosY;
AUXDATA(xprd, std::vector<float> , sihit_startPosZ) = sihit_startPosZ;
AUXDATA(xprd, std::vector<float> , sihit_endPosX) = sihit_endPosX;
AUXDATA(xprd, std::vector<float> , sihit_endPosY) = sihit_endPosY;
AUXDATA(xprd, std::vector<float> , sihit_endPosZ) = sihit_endPosZ;
}
std::vector<SiHit> SCT_PrepDataToxAOD::findAllHitsCompatibleWithCluster( const InDet::SCT_Cluster* prd,
const SiHitCollection* collection) const
{
ATH_MSG_VERBOSE( "Got " << collection->size() << " SiHits to look through" );
std::vector<SiHit> matchingHits;
// Check if we have detector element -- needed to find the local position of the SiHits
const InDetDD::SiDetectorElement* de = prd->detectorElement();
if (de==nullptr) return matchingHits;
std::vector<const SiHit* > multiMatchingHits;
for ( const auto& siHit : *collection) {
// Check if it is a SCT hit
if (not siHit.isSCT()) continue;
//Check if it is on the correct module
Identifier clusterId = prd->identify();
if (m_SCTHelper->barrel_ec(clusterId) != siHit.getBarrelEndcap() or
m_SCTHelper->layer_disk(clusterId)!= siHit.getLayerDisk() or
m_SCTHelper->phi_module(clusterId)!= siHit.getPhiModule() or
m_SCTHelper->eta_module(clusterId)!= siHit.getEtaModule() or
m_SCTHelper->side(clusterId) != siHit.getSide() ) {
continue;
}
// Now we have all hits in the module that match lets check to see if they match the cluster
// Must be within +/- 1 hits of any hit in the cluster to be included
ATH_MSG_DEBUG("Hit is on the same module");
HepGeom::Point3D<double> averagePosition = siHit.localStartPosition() + siHit.localEndPosition();
averagePosition *= 0.5;
Amg::Vector2D pos = de->hitLocalToLocal( averagePosition.z(), averagePosition.y() );
InDetDD::SiCellId diode = de->cellIdOfPosition(pos);
for (const auto &hitIdentifier : prd->rdoList()) {
//if ( abs( int(diode.etaIndex()) - m_SCTHelper->eta_index( hitIdentifier ) ) <=1 )
//if ( abs( int(diode.phiIndex() - m_SCTHelper->phi_index( hitIdentifier ) ) <=1 )
ATH_MSG_DEBUG("Truth Strip " << diode.phiIndex() << " Cluster Strip " << m_SCTHelper->strip( hitIdentifier ) );
if ( abs( int(diode.phiIndex()) - m_SCTHelper->strip( hitIdentifier ) ) <=1) {
multiMatchingHits.push_back(&siHit);
break;
}
}
}
//Now we will now make 1 SiHit for each true particle if the SiHits "touch" other
std::vector<const SiHit* >::iterator siHitIter = multiMatchingHits.begin();
std::vector<const SiHit* >::iterator siHitIter2 = multiMatchingHits.begin();
ATH_MSG_DEBUG( "Found " << multiMatchingHits.size() << " SiHit " );
for ( ; siHitIter != multiMatchingHits.end(); siHitIter++) {
const SiHit* lowestXPos = *siHitIter;
const SiHit* highestXPos = *siHitIter;
// We will merge these hits
std::vector<const SiHit* > ajoiningHits;
ajoiningHits.push_back( *siHitIter );
siHitIter2 = siHitIter+1;
while ( siHitIter2 != multiMatchingHits.end() ) {
// Need to come from the same truth particle
if ((*siHitIter)->particleLink().barcode() != (*siHitIter2)->particleLink().barcode() ) {
++siHitIter2;
continue;
}
// Check to see if the SiHits are compatible with each other.
if (fabs((highestXPos->localEndPosition().x()-(*siHitIter2)->localStartPosition().x()))<0.00005 and
fabs((highestXPos->localEndPosition().y()-(*siHitIter2)->localStartPosition().y()))<0.00005 and
fabs((highestXPos->localEndPosition().z()-(*siHitIter2)->localStartPosition().z()))<0.00005 ) {
highestXPos = *siHitIter2;
ajoiningHits.push_back( *siHitIter2 );
// Dont use hit more than once
siHitIter2 = multiMatchingHits.erase( siHitIter2 );
} else if (fabs((lowestXPos->localStartPosition().x()-(*siHitIter2)->localEndPosition().x()))<0.00005 and
fabs((lowestXPos->localStartPosition().y()-(*siHitIter2)->localEndPosition().y()))<0.00005 and
fabs((lowestXPos->localStartPosition().z()-(*siHitIter2)->localEndPosition().z()))<0.00005) {
lowestXPos = *siHitIter2;
ajoiningHits.push_back( *siHitIter2 );
// Dont use hit more than once
siHitIter2 = multiMatchingHits.erase( siHitIter2 );
} else {
++siHitIter2;
}
}
if (ajoiningHits.size() == 0) {
ATH_MSG_WARNING("This should really never happen");
continue;
} else if (ajoiningHits.size() == 1) {
// Copy Si Hit ready to return
matchingHits.push_back( *ajoiningHits[0] );
continue;
} else {
// Build new SiHit and merge information together.
ATH_MSG_DEBUG("Merging " << ajoiningHits.size() << " SiHits together." );
float energyDep(0.);
float time(0.);
for (auto& siHit : ajoiningHits) {
energyDep += siHit->energyLoss();
time += siHit->meanTime();
}
time /= (float)ajoiningHits.size();
matchingHits.push_back( SiHit(lowestXPos->localStartPosition(),
highestXPos->localEndPosition(),
energyDep,
time,
(*siHitIter)->particleLink().barcode(),
1, // 0 for pixel 1 for SCT
(*siHitIter)->getBarrelEndcap(),
(*siHitIter)->getLayerDisk(),
(*siHitIter)->getEtaModule(),
(*siHitIter)->getPhiModule(),
(*siHitIter)->getSide() ) );
}
}
return matchingHits;
}
void SCT_PrepDataToxAOD::addRDOInformation(xAOD::TrackMeasurementValidation* xprd,
const InDet::SCT_Cluster* prd,
const std::map<Identifier, const SCT_RDORawData*>& idToRAWDataMap) const {
std::vector<int> strip;
std::vector<int> timebin;
std::vector<int> groupsize;
for (const auto &hitIdentifier : prd->rdoList()) {
auto result = idToRAWDataMap.find(hitIdentifier);
if (result != idToRAWDataMap.end() ) {
const SCT_RDORawData *sctRdo = result->second;
const SCT3_RawData* rdo3 = dynamic_cast<const SCT3_RawData*>(sctRdo);
int tbin(-1);
int gs(-1);
if (rdo3!=0) {
tbin = rdo3->getTimeBin();
gs = rdo3->getGroupSize();
}
timebin.push_back( tbin);
groupsize.push_back( gs);
strip.push_back(m_SCTHelper->strip(sctRdo->identify()));
} else {
timebin.push_back( -1 );
strip.push_back( -1 );
groupsize.push_back( -1 );
}
}
AUXDATA(xprd, std::vector<int> , rdo_strip) = strip;
AUXDATA(xprd, std::vector<int> , rdo_timebin) = timebin;
AUXDATA(xprd, std::vector<int> , rdo_groupsize) = groupsize;
}
/////////////////////////////////////////////////////////////////////
//
// Finalize method:
//
/////////////////////////////////////////////////////////////////////
StatusCode SCT_PrepDataToxAOD::finalize()
{
return StatusCode::SUCCESS;
}