From 411559acdc2f154e6e2a0a6d279f21eb56a64a61 Mon Sep 17 00:00:00 2001 From: Dave Casper <dcasper@uci.edu> Date: Wed, 8 Dec 2021 13:23:51 -0800 Subject: [PATCH] Fix integer overflow in persistent classes --- .../src/CaloHitCollectionCnv.cxx | 8 +- .../src/CaloHitCollectionCnv.h | 6 +- .../CaloHits/CaloHitCollectionCnv_p1a.h | 41 +++ .../CaloHits/CaloHitCollection_p1a.h | 59 +++ .../CaloSimEventTPCnvDict.h | 2 + .../FaserCaloSimEventTPCnv/selection.xml | 2 + .../src/CaloHits/CaloHitCollectionCnv_p1a.cxx | 339 ++++++++++++++++++ .../src/NeutrinoHitCollectionCnv.cxx | 9 +- .../src/NeutrinoHitCollectionCnv.h | 8 +- .../NeutrinoHitCollectionCnv_p1a.h | 41 +++ .../NeutrinoHits/NeutrinoHitCollection_p1a.h | 57 +++ .../NeutrinoSimEventTPCnvDict.h | 3 + .../NeutrinoSimEventTPCnv/selection.xml | 1 + .../NeutrinoHitCollectionCnv_p1a.cxx | 334 +++++++++++++++++ 14 files changed, 900 insertions(+), 10 deletions(-) create mode 100644 Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h create mode 100644 Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h create mode 100644 Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1a.cxx create mode 100644 Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h create mode 100644 Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h create mode 100644 Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.cxx diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.cxx b/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.cxx index 2ac860d86..6abec9240 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.cxx +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.cxx @@ -18,12 +18,16 @@ CaloHitCollection_PERS* CaloHitCollectionCnv::createPersistent(CaloHitCollection CaloHitCollection* CaloHitCollectionCnv::createTransient() { MsgStream mlog(msgSvc(), "CaloHitCollectionConverter" ); CaloHitCollectionCnv_p1 converter_p1; + CaloHitCollectionCnv_p1a converter_p1a; static const pool::Guid p1_guid("134E8045-AB99-43EF-9AD1-324C48830B64"); - // static const pool::Guid p1_guid("B2573A16-4B46-4E1E-98E3-F93421680779"); + static const pool::Guid p1a_guid("02C108EE-0AD9-4444-83BD-D5273FCDEF6F"); CaloHitCollection *trans_cont(0); - if( this->compareClassGuid(p1_guid)) { + if( this->compareClassGuid(p1a_guid)) { + std::unique_ptr< CaloHitCollection_p1a > col_vect( this->poolReadObject< CaloHitCollection_p1a >() ); + trans_cont = converter_p1a.createTransient( col_vect.get(), mlog ); + } else if( this->compareClassGuid(p1_guid)) { std::unique_ptr< CaloHitCollection_p1 > col_vect( this->poolReadObject< CaloHitCollection_p1 >() ); trans_cont = converter_p1.createTransient( col_vect.get(), mlog ); } else { diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.h b/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.h index b46894c5f..1de7cc3e0 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.h +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventAthenaPool/src/CaloHitCollectionCnv.h @@ -8,12 +8,14 @@ #include "FaserCaloSimEvent/CaloHitCollection.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h" #include "AthenaPoolCnvSvc/T_AthenaPoolCustomCnv.h" // Gaudi #include "GaudiKernel/MsgStream.h" // typedef to the latest persistent version -typedef CaloHitCollection_p1 CaloHitCollection_PERS; -typedef CaloHitCollectionCnv_p1 CaloHitCollectionCnv_PERS; +typedef CaloHitCollection_p1a CaloHitCollection_PERS; +typedef CaloHitCollectionCnv_p1a CaloHitCollectionCnv_PERS; class CaloHitCollectionCnv : public T_AthenaPoolCustomCnv<CaloHitCollection, CaloHitCollection_PERS > { friend class CnvFactory<CaloHitCollectionCnv>; diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h new file mode 100644 index 000000000..80534aae7 --- /dev/null +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CALOHITCOLLECTIONCNV_P1A_H +#define CALOHITCOLLECTIONCNV_P1A_H + +// CaloHitCollectionCnv_p1, T/P separation of Calo Hits +// author D.Costanzo <davide.costanzo@cern.ch> +// author O.Arnaez <olivier.arnaez@cern.ch> + +#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h" +#include "FaserCaloSimEvent/CaloHitCollection.h" +#include "CaloHitCollection_p1a.h" + + +class CaloHitCollectionCnv_p1a : public T_AthenaPoolTPCnvBase<CaloHitCollection, CaloHitCollection_p1a> +{ + public: + + CaloHitCollectionCnv_p1a() {}; + + virtual CaloHitCollection* createTransient(const CaloHitCollection_p1a* persObj, MsgStream &log); + + virtual void persToTrans(const CaloHitCollection_p1a* persCont, + CaloHitCollection* transCont, + MsgStream &log) ; + virtual void transToPers(const CaloHitCollection* transCont, + CaloHitCollection_p1a* persCont, + MsgStream &log) ; + + private: + + static const double m_persEneUnit; + static const double m_persLenUnit; + static const double m_persAngUnit; + static const double m_2bHalfMaximum; + static const int m_2bMaximum; +}; + +#endif diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h new file mode 100644 index 000000000..7dc511d9d --- /dev/null +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CALOHITCOLLECTION_P1A_H +#define CALOHITCOLLECTION_P1A_H + +/* + +Authors: Davide Costanzo Rob Duxfield +Modified for FASER by D. Casper - change internal unsigned short counters to unsigned long +p2, p3, etc reserved for possible future ATLAS changes + +*/ + +#include <vector> +#include <string> + +class CaloHitCollection_p1a +{ + public: +/// Default constructor + CaloHitCollection_p1a (); + //private: + + std::vector<float> m_hit1_meanTime; // 1 element per string + std::vector<float> m_hit1_x0; // + std::vector<float> m_hit1_y0; // + std::vector<float> m_hit1_z0; // + std::vector<float> m_hit1_theta; // + std::vector<float> m_hit1_phi; // + std::vector<unsigned long> m_nHits; // + + std::vector<unsigned short> m_hitEne_2b; // 1 element per hit + std::vector<unsigned short> m_hitLength_2b; // + + std::vector<unsigned short> m_dTheta; // 1 element per hit except for first hit in string + std::vector<unsigned short> m_dPhi; // + + std::vector<float> m_hitEne_4b; // 1 element per hit with m_hitEne_2b[i] == 2**16 + + std::vector<float> m_hitLength_4b; // 1 element per hit with m_hitLength_2b[i] == 2**16 + + std::vector<unsigned long> m_barcode; + std::vector<unsigned long> m_mcEvtIndex; + std::vector<char> m_evtColl; + std::vector<unsigned long> m_nBC; + + std::vector<unsigned long> m_id; + std::vector<unsigned long> m_nId; +}; + + +// inlines + +inline +CaloHitCollection_p1a::CaloHitCollection_p1a () {} + +#endif diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloSimEventTPCnvDict.h b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloSimEventTPCnvDict.h index 80937ffc8..de24c20ac 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloSimEventTPCnvDict.h +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/CaloSimEventTPCnvDict.h @@ -15,6 +15,8 @@ #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCnv_p1.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h" #include "FaserCaloSimEventTPCnv/CaloHits/CaloHit_p1.h" #endif // CALOEVENTTPCNV_CALOSIMEVENTTPCNVDICT_H diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/selection.xml b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/selection.xml index d73b5ce1a..e90551988 100644 --- a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/selection.xml +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/FaserCaloSimEventTPCnv/selection.xml @@ -4,4 +4,6 @@ <class name="CaloHit_p1" /> <class name="std::vector<CaloHit_p1>" /> <class name="CaloHitCollection_p1" id="134E8045-AB99-43EF-9AD1-324C48830B64" /> + <class name="CaloHitCollection_p1a" id="02C108EE-0AD9-4444-83BD-D5273FCDEF6F" /> + </lcgdict> diff --git a/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1a.cxx b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1a.cxx new file mode 100644 index 000000000..d1d6ec53b --- /dev/null +++ b/Calorimeter/CaloEventCnv/FaserCaloSimEventTPCnv/src/CaloHits/CaloHitCollectionCnv_p1a.cxx @@ -0,0 +1,339 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "FaserCaloSimEvent/CaloHit.h" +#include "FaserCaloSimEvent/CaloHitCollection.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollection_p1a.h" +#include "FaserCaloSimEventTPCnv/CaloHits/CaloHitCollectionCnv_p1a.h" +#include "GeneratorObjects/HepMcParticleLink.h" + +#include <cmath> + +//CLHEP +#include "CLHEP/Geometry/Point3D.h" +// Gaudi +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + +// Athena +#include "AthenaKernel/ExtendedEventContext.h" +#include "StoreGate/StoreGateSvc.h" + +// * * * stolen from eflowRec * * * // +inline double phicorr(double a) +{ + if (a <= -M_PI) + { + return a+(2*M_PI*floor(-(a-M_PI)/(2*M_PI))); + } + else if (a > M_PI) + { + return a-(2*M_PI*floor((a+M_PI)/(2*M_PI))); + } + else + { + return a; + } +} + +// * * * stolen from eflowRec * * * // +inline double cycle(double a, double b) +{ + double del = b-a; + if (del > M_PI) + { + return a+2.0*M_PI; + } + else if (del < -M_PI) + { + return a-2.0*M_PI; + } + else + { + return a; + } +} + + +const double CaloHitCollectionCnv_p1a::m_persEneUnit = 1.0e-5; +const double CaloHitCollectionCnv_p1a::m_persLenUnit = 1.0e-5; +const double CaloHitCollectionCnv_p1a::m_persAngUnit = 1.0e-5; +const double CaloHitCollectionCnv_p1a::m_2bHalfMaximum = pow(2.0, 15.0); +const int CaloHitCollectionCnv_p1a::m_2bMaximum = (unsigned short)(-1); + + +void CaloHitCollectionCnv_p1a::transToPers(const CaloHitCollection* transCont, CaloHitCollection_p1a* persCont, MsgStream &log) +{ + // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and + // persistifies the end point of each hit plus the start point of the first hit in each string. + // + // Further compression is achieved by optimising the storage of the position vectors:- start (x,y,z) and (theta,phi) of + // first hit are stored as floats, (delta_theta,delta_phi) relative to the fisrst hit are stored as 2 byte numbers and + // used to specify the hit direction. All hit lengths are stored as 2 byte numbers. + // + // Additional savings are achieved by storing the energy loss for each hit as a 2 byte number and only storing the mean + // time of the first hit per string. + // + // See http://indico.cern.ch/getFile.py/access?contribId=11&resId=2&materialId=slides&confId=30893 for more info. + + static const double dRcut = 1.0e-7; + static const double dTcut = 1.0; + + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); + const HepMcParticleLink * lastLink=nullptr; + int lastId = -1; + double stringFirstTheta = 0.0; + double stringFirstPhi = 0.0; + double lastT = 0.0; + double persSumE = 0.0; + double transSumE = 0.0; + unsigned int idx = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + unsigned int endHit = 0; + HepGeom::Point3D<double> lastTransEnd(0.0, 0.0, 0.0); + HepGeom::Point3D<double> lastPersEnd(0.0, 0.0, 0.0); + + for (CaloHitCollection::const_iterator it = transCont->begin(); it != transCont->end(); ++it) { + + CaloHitCollection::const_iterator siHit = it; + + + if ( !lastLink || (siHit->particleLink() != *lastLink) ) { + + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode + + lastLink = &(siHit->particleLink()); + persCont->m_barcode.push_back(lastLink->barcode()); + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); + persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); + + if (idx > 0) { + persCont->m_nBC.push_back(idx - endBC); + endBC = idx; + } + } + + if ( (int)siHit->identify() != lastId ) { + + // store id once for set of consecutive hits with same barcode + + lastId = siHit->identify(); + persCont->m_id.push_back(lastId); + + if (idx > 0) { + persCont->m_nId.push_back(idx - endId); + endId = idx; + } + } + + HepGeom::Point3D<double> st = siHit->localStartPosition(); + HepGeom::Point3D<double> en = siHit->localEndPosition(); + + const double dx = st.x() - lastTransEnd.x(); + const double dy = st.y() - lastTransEnd.y(); + const double dz = st.z() - lastTransEnd.z(); + const double t = siHit->meanTime(); + + const double dRLast = sqrt(dx * dx + dy * dy + dz * dz); // dR between end of previous hit and start of current one + const double dTLast = fabs(t - lastT); + + CLHEP::Hep3Vector direction(0.0, 0.0, 0.0); + double theta = 0.0; + double phi = 0.0; + bool startNewString = false; + + if (dRLast < dRcut && dTLast < dTcut) { + + // hit is part of existing string + + direction = CLHEP::Hep3Vector( en.x() - lastPersEnd.x(), en.y() - lastPersEnd.y(), en.z() - lastPersEnd.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + const int dTheta_2b = (int)( (theta - stringFirstTheta) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + const int dPhi_2b = (int)( (cycle(phi, stringFirstPhi) - stringFirstPhi) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + + if ( dTheta_2b < m_2bMaximum && dTheta_2b >= 0 && dPhi_2b < m_2bMaximum && dPhi_2b >= 0) { + persCont->m_dTheta.push_back(dTheta_2b); + persCont->m_dPhi.push_back(dPhi_2b); + theta = stringFirstTheta + ( (double)dTheta_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = stringFirstPhi + ( (double)dPhi_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = phicorr(phi); + } + else { + startNewString = true; + } + } + + if (startNewString || dRLast >= dRcut || dTLast >= dTcut) { + + // begin new hit string + + direction = CLHEP::Hep3Vector( en.x() - st.x(), en.y() - st.y(), en.z() - st.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + persCont->m_hit1_meanTime.push_back(t); + persCont->m_hit1_x0.push_back(st.x()); + persCont->m_hit1_y0.push_back(st.y()); + persCont->m_hit1_z0.push_back(st.z()); + persCont->m_hit1_theta.push_back(theta); + persCont->m_hit1_phi.push_back(phi); + + lastPersEnd = HepGeom::Point3D<double>(st.x(), st.y(), st.z()); + + stringFirstTheta = theta; + stringFirstPhi = phi; + + if (idx > 0) { + persCont->m_nHits.push_back(idx - endHit); + endHit = idx; + } + } + + lastTransEnd = HepGeom::Point3D<double>(en.x(), en.y(), en.z()); + transSumE += siHit->energyLoss(); + + const int eneLoss_2b = (int)((transSumE - persSumE) / m_persEneUnit + 0.5); // calculated to allow recovery sum over + // whole hit string to chosen precision + + const int hitLength_2b = (int)(direction.mag() / m_persLenUnit + 0.5); // calculated to give the correct position to + // the chosen precision, NOT the length of the + // hit (small difference in practice). + double eneLoss = 0.0; + + if (eneLoss_2b >= m_2bMaximum) { + eneLoss = siHit->energyLoss(); + persCont->m_hitEne_2b.push_back(m_2bMaximum); + persCont->m_hitEne_4b.push_back(eneLoss); + } + else { + eneLoss = eneLoss_2b * m_persEneUnit; + persCont->m_hitEne_2b.push_back(eneLoss_2b); + } + + double length = 0.0; + + if (hitLength_2b >= m_2bMaximum) { + length = direction.mag(); + persCont->m_hitLength_2b.push_back(m_2bMaximum); + persCont->m_hitLength_4b.push_back(direction.mag()); + } + else { + length = hitLength_2b * m_persLenUnit; + persCont->m_hitLength_2b.push_back(hitLength_2b); + } + + CLHEP::Hep3Vector persDir(length, 0.0, 0.0); + persDir.setTheta(theta); + persDir.setPhi(phi); + + lastPersEnd = (CLHEP::Hep3Vector)lastPersEnd + persDir; + persSumE += eneLoss; + lastT = t; + + ++idx; + } + + persCont->m_nBC.push_back(idx - endBC); + persCont->m_nId.push_back(idx - endId); + persCont->m_nHits.push_back(idx - endHit); +} + + +CaloHitCollection* CaloHitCollectionCnv_p1a::createTransient(const CaloHitCollection_p1a* persObj, MsgStream &log) { + for (size_t i = 0; i < persObj->m_evtColl.size(); i++) + { + if (persObj->m_evtColl[i] != 'a') + log << MSG::ALWAYS << "Corrupted in createTransient: " << persObj->m_evtColl[i] << endmsg; + } + std::unique_ptr<CaloHitCollection> trans(std::make_unique<CaloHitCollection>("DefaultCollectionName",persObj->m_nHits.size())); + persToTrans(persObj, trans.get(), log); + return(trans.release()); +} + + +void CaloHitCollectionCnv_p1a::persToTrans(const CaloHitCollection_p1a* persCont, CaloHitCollection* transCont, MsgStream &/*log*/) +{ + const EventContext& ctx = Gaudi::Hive::currentContext(); + + unsigned int hitCount = 0; + unsigned int angleCount = 0; + unsigned int idxBC = 0; + unsigned int idxId = 0; + unsigned int idxEne4b = 0; + unsigned int idxLen4b = 0; + unsigned int endHit = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + + + for (unsigned int i = 0; i < persCont->m_nHits.size(); i++) { + + if (persCont->m_nHits[i]) { + const unsigned int start = endHit; + endHit += persCont->m_nHits[i]; + + const double t0 = persCont->m_hit1_meanTime[i]; + const double theta0 = persCont->m_hit1_theta[i]; + const double phi0 = persCont->m_hit1_phi[i]; + HepGeom::Point3D<double> endLast(persCont->m_hit1_x0[i], persCont->m_hit1_y0[i], persCont->m_hit1_z0[i]); + + for (unsigned int j = start; j < endHit; j++) { + if (j >= endBC + persCont->m_nBC[idxBC]) + endBC += persCont->m_nBC[idxBC++]; + + if (j >= endId + persCont->m_nId[idxId]) + endId += persCont->m_nId[idxId++]; + + const double eneLoss_2b = persCont->m_hitEne_2b[hitCount]; + const double hitLength_2b = persCont->m_hitLength_2b[hitCount]; + + const double eneLoss = (eneLoss_2b < m_2bMaximum) ? eneLoss_2b * m_persEneUnit : persCont->m_hitEne_4b[idxEne4b++]; + const double length = (hitLength_2b < m_2bMaximum) ? hitLength_2b * m_persLenUnit : persCont->m_hitLength_4b[idxLen4b++]; + + const double dTheta = (j > start) ? ((double)persCont->m_dTheta[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + const double dPhi = (j > start) ? ((double)persCont->m_dPhi[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + + const double meanTime = t0; + const double theta = theta0 + dTheta; + const double phi = phicorr(phi0 + dPhi); + + CLHEP::Hep3Vector r(length, 0.0, 0.0); + r.setTheta(theta); + r.setPhi(phi); + + HepGeom::Point3D<double> endThis( endLast + r ); + + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); + transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); + + endLast = endThis; + + ++hitCount; + if (j > start) ++angleCount; + } + } + } +} diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx index 36ff6569e..715a49b37 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.cxx @@ -4,6 +4,7 @@ #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h" #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h" #include "NeutrinoHitCollectionCnv.h" @@ -18,12 +19,16 @@ NeutrinoHitCollection_PERS* NeutrinoHitCollectionCnv::createPersistent(NeutrinoH NeutrinoHitCollection* NeutrinoHitCollectionCnv::createTransient() { MsgStream mlog(msgSvc(), "NeutrinoHitCollectionConverter" ); NeutrinoHitCollectionCnv_p1 converter_p1; + NeutrinoHitCollectionCnv_p1a converter_p1a; static const pool::Guid p1_guid("2CA7AF71-1494-4378-BED4-AFB5C54398AA"); - // static const pool::Guid p1_guid("B2573A16-4B46-4E1E-98E3-F93421680779"); + static const pool::Guid p1a_guid("0A3CD37D-64CE-405D-98CF-595D678B14B7"); NeutrinoHitCollection *trans_cont(0); - if( this->compareClassGuid(p1_guid)) { + if( this->compareClassGuid(p1a_guid)) { + std::unique_ptr< NeutrinoHitCollection_p1a > col_vect( this->poolReadObject< NeutrinoHitCollection_p1a >() ); + trans_cont = converter_p1a.createTransient( col_vect.get(), mlog ); + } else if( this->compareClassGuid(p1_guid)) { std::unique_ptr< NeutrinoHitCollection_p1 > col_vect( this->poolReadObject< NeutrinoHitCollection_p1 >() ); trans_cont = converter_p1.createTransient( col_vect.get(), mlog ); } else { diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h index 5ccd3e1bb..a8158c01a 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventAthenaPool/src/NeutrinoHitCollectionCnv.h @@ -6,14 +6,14 @@ #define NEUTRINOHITCOLLECTIONCNV #include "NeutrinoSimEvent/NeutrinoHitCollection.h" -#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h" -#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h" #include "AthenaPoolCnvSvc/T_AthenaPoolCustomCnv.h" // Gaudi #include "GaudiKernel/MsgStream.h" // typedef to the latest persistent version -typedef NeutrinoHitCollection_p1 NeutrinoHitCollection_PERS; -typedef NeutrinoHitCollectionCnv_p1 NeutrinoHitCollectionCnv_PERS; +typedef NeutrinoHitCollection_p1a NeutrinoHitCollection_PERS; +typedef NeutrinoHitCollectionCnv_p1a NeutrinoHitCollectionCnv_PERS; class NeutrinoHitCollectionCnv : public T_AthenaPoolCustomCnv<NeutrinoHitCollection, NeutrinoHitCollection_PERS > { friend class CnvFactory<NeutrinoHitCollectionCnv>; diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h new file mode 100644 index 000000000..5666f66e7 --- /dev/null +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef NEUTRINOHITCOLLECTIONCNV_P1A_H +#define NEUTRINOHITCOLLECTIONCNV_P1A_H + +// NeutrinoHitCollectionCnv_p1a, T/P separation of Neutrino Hits +// author D.Costanzo <davide.costanzo@cern.ch> +// author O.Arnaez <olivier.arnaez@cern.ch> + +#include "AthenaPoolCnvSvc/T_AthenaPoolTPConverter.h" +#include "NeutrinoSimEvent/NeutrinoHitCollection.h" +#include "NeutrinoHitCollection_p1a.h" + + +class NeutrinoHitCollectionCnv_p1a : public T_AthenaPoolTPCnvBase<NeutrinoHitCollection, NeutrinoHitCollection_p1a> +{ + public: + + NeutrinoHitCollectionCnv_p1a() {}; + + virtual NeutrinoHitCollection* createTransient(const NeutrinoHitCollection_p1a* persObj, MsgStream &log); + + virtual void persToTrans(const NeutrinoHitCollection_p1a* persCont, + NeutrinoHitCollection* transCont, + MsgStream &log) ; + virtual void transToPers(const NeutrinoHitCollection* transCont, + NeutrinoHitCollection_p1a* persCont, + MsgStream &log) ; + + private: + + static const double m_persEneUnit; + static const double m_persLenUnit; + static const double m_persAngUnit; + static const double m_2bHalfMaximum; + static const int m_2bMaximum; +}; + +#endif diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h new file mode 100644 index 000000000..639ff9840 --- /dev/null +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef NEUTRINOHITCOLLECTION_P1A_H +#define NEUTRINOHITCOLLECTION_P1A_H + +/* + +Authors: Davide Costanzo Rob Duxfield + +*/ + +#include <vector> +#include <string> + +class NeutrinoHitCollection_p1a +{ + public: +/// Default constructor + NeutrinoHitCollection_p1a (); + //private: + + std::vector<float> m_hit1_meanTime; // 1 element per string + std::vector<float> m_hit1_x0; // + std::vector<float> m_hit1_y0; // + std::vector<float> m_hit1_z0; // + std::vector<float> m_hit1_theta; // + std::vector<float> m_hit1_phi; // + std::vector<unsigned long> m_nHits; // + + std::vector<unsigned short> m_hitEne_2b; // 1 element per hit + std::vector<unsigned short> m_hitLength_2b; // + + std::vector<unsigned short> m_dTheta; // 1 element per hit except for first hit in string + std::vector<unsigned short> m_dPhi; // + + std::vector<float> m_hitEne_4b; // 1 element per hit with m_hitEne_2b[i] == 2**16 + + std::vector<float> m_hitLength_4b; // 1 element per hit with m_hitLength_2b[i] == 2**16 + + std::vector<unsigned long> m_barcode; + std::vector<unsigned short> m_mcEvtIndex; + std::vector<char> m_evtColl; + std::vector<unsigned long> m_nBC; + + std::vector<unsigned long> m_id; + std::vector<unsigned long> m_nId; +}; + + +// inlines + +inline +NeutrinoHitCollection_p1a::NeutrinoHitCollection_p1a () {} + +#endif diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h index 064ad71ac..15b7afc5b 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnvDict.h @@ -15,6 +15,9 @@ #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCnv_p1.h" #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1.h" #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h" + #include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHit_p1.h" #endif // NEUTRINOEVENTTPCNV_NEUTRINOSIMEVENTTPCNVDICT_H diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml index 6808c217a..3332a0a0c 100644 --- a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/NeutrinoSimEventTPCnv/selection.xml @@ -4,4 +4,5 @@ <class name="NeutrinoHit_p1" /> <class name="std::vector<NeutrinoHit_p1>" /> <class name="NeutrinoHitCollection_p1" id="2CA7AF71-1494-4378-BED4-AFB5C54398AA" /> + <class name="NeutrinoHitCollection_p1a" id="0A3CD37D-64CE-405D-98CF-595D678B14B7" /> </lcgdict> diff --git a/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.cxx b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.cxx new file mode 100644 index 000000000..6ef0bb107 --- /dev/null +++ b/Neutrino/NeutrinoEventCnv/NeutrinoSimEventTPCnv/src/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.cxx @@ -0,0 +1,334 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "NeutrinoSimEvent/NeutrinoHit.h" +#include "NeutrinoSimEvent/NeutrinoHitCollection.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollection_p1a.h" +#include "NeutrinoSimEventTPCnv/NeutrinoHits/NeutrinoHitCollectionCnv_p1a.h" +#include "GeneratorObjects/HepMcParticleLink.h" + +#include <cmath> + +//CLHEP +#include "CLHEP/Geometry/Point3D.h" +// Gaudi +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/ThreadLocalContext.h" + +// Athena +#include "AthenaKernel/ExtendedEventContext.h" +#include "StoreGate/StoreGateSvc.h" + +// * * * stolen from eflowRec * * * // +inline double phicorr(double a) +{ + if (a <= -M_PI) + { + return a+(2*M_PI*floor(-(a-M_PI)/(2*M_PI))); + } + else if (a > M_PI) + { + return a-(2*M_PI*floor((a+M_PI)/(2*M_PI))); + } + else + { + return a; + } +} + +// * * * stolen from eflowRec * * * // +inline double cycle(double a, double b) +{ + double del = b-a; + if (del > M_PI) + { + return a+2.0*M_PI; + } + else if (del < -M_PI) + { + return a-2.0*M_PI; + } + else + { + return a; + } +} + + +const double NeutrinoHitCollectionCnv_p1a::m_persEneUnit = 1.0e-5; +const double NeutrinoHitCollectionCnv_p1a::m_persLenUnit = 1.0e-5; +const double NeutrinoHitCollectionCnv_p1a::m_persAngUnit = 1.0e-5; +const double NeutrinoHitCollectionCnv_p1a::m_2bHalfMaximum = pow(2.0, 15.0); +const int NeutrinoHitCollectionCnv_p1a::m_2bMaximum = (unsigned short)(-1); + + +void NeutrinoHitCollectionCnv_p1a::transToPers(const NeutrinoHitCollection* transCont, NeutrinoHitCollection_p1a* persCont, MsgStream &log) +{ + // Finds hits belonging to a "string" (in which the end point of one hit is the same as the start point of the next) and + // persistifies the end point of each hit plus the start point of the first hit in each string. + // + // Further compression is achieved by optimising the storage of the position vectors:- start (x,y,z) and (theta,phi) of + // first hit are stored as floats, (delta_theta,delta_phi) relative to the fisrst hit are stored as 2 byte numbers and + // used to specify the hit direction. All hit lengths are stored as 2 byte numbers. + // + // Additional savings are achieved by storing the energy loss for each hit as a 2 byte number and only storing the mean + // time of the first hit per string. + // + // See http://indico.cern.ch/getFile.py/access?contribId=11&resId=2&materialId=slides&confId=30893 for more info. + + static const double dRcut = 1.0e-7; + static const double dTcut = 1.0; + + const EventContext& ctx = Gaudi::Hive::currentContext(); + const IProxyDict* proxy = Atlas::getExtendedEventContext(ctx).proxy(); + const HepMcParticleLink * lastLink=nullptr; + int lastId = -1; + double stringFirstTheta = 0.0; + double stringFirstPhi = 0.0; + double lastT = 0.0; + double persSumE = 0.0; + double transSumE = 0.0; + unsigned int idx = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + unsigned int endHit = 0; + HepGeom::Point3D<double> lastTransEnd(0.0, 0.0, 0.0); + HepGeom::Point3D<double> lastPersEnd(0.0, 0.0, 0.0); + + for (NeutrinoHitCollection::const_iterator it = transCont->begin(); it != transCont->end(); ++it) { + + NeutrinoHitCollection::const_iterator siHit = it; + + + if ( !lastLink || (siHit->particleLink() != *lastLink) ) { + + // store barcode once for set of consecutive hits with same barcode + + lastLink = &(siHit->particleLink()); + persCont->m_barcode.push_back(lastLink->barcode()); + unsigned short index{0}; + const HepMcParticleLink::index_type position = + HepMcParticleLink::getEventPositionInCollection(lastLink->eventIndex(), + lastLink->getEventCollection(), + proxy).at(0); + if (position!=0) { + index = lastLink->eventIndex(); + if(lastLink->eventIndex()!=static_cast<HepMcParticleLink::index_type>(index)) { + log << MSG::WARNING << "Attempting to persistify an eventIndex larger than max unsigned short!" << endmsg; + } + } + persCont->m_mcEvtIndex.push_back(index); + persCont->m_evtColl.push_back(lastLink->getEventCollectionAsChar()); + + if (idx > 0) { + persCont->m_nBC.push_back(idx - endBC); + endBC = idx; + } + } + + if ( (int)siHit->identify() != lastId ) { + + // store barcode, eventIndex and McEventCollection once for set of consecutive hits with same barcode + + lastId = siHit->identify(); + persCont->m_id.push_back(lastId); + + if (idx > 0) { + persCont->m_nId.push_back(idx - endId); + endId = idx; + } + } + + HepGeom::Point3D<double> st = siHit->localStartPosition(); + HepGeom::Point3D<double> en = siHit->localEndPosition(); + + const double dx = st.x() - lastTransEnd.x(); + const double dy = st.y() - lastTransEnd.y(); + const double dz = st.z() - lastTransEnd.z(); + const double t = siHit->meanTime(); + + const double dRLast = sqrt(dx * dx + dy * dy + dz * dz); // dR between end of previous hit and start of current one + const double dTLast = fabs(t - lastT); + + CLHEP::Hep3Vector direction(0.0, 0.0, 0.0); + double theta = 0.0; + double phi = 0.0; + bool startNewString = false; + + if (dRLast < dRcut && dTLast < dTcut) { + + // hit is part of existing string + + direction = CLHEP::Hep3Vector( en.x() - lastPersEnd.x(), en.y() - lastPersEnd.y(), en.z() - lastPersEnd.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + const int dTheta_2b = (int)( (theta - stringFirstTheta) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + const int dPhi_2b = (int)( (cycle(phi, stringFirstPhi) - stringFirstPhi) / m_persAngUnit + m_2bHalfMaximum + 0.5 ); + + if ( dTheta_2b < m_2bMaximum && dTheta_2b >= 0 && dPhi_2b < m_2bMaximum && dPhi_2b >= 0) { + persCont->m_dTheta.push_back(dTheta_2b); + persCont->m_dPhi.push_back(dPhi_2b); + theta = stringFirstTheta + ( (double)dTheta_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = stringFirstPhi + ( (double)dPhi_2b - m_2bHalfMaximum ) * m_persAngUnit; + phi = phicorr(phi); + } + else { + startNewString = true; + } + } + + if (startNewString || dRLast >= dRcut || dTLast >= dTcut) { + + // begin new hit string + + direction = CLHEP::Hep3Vector( en.x() - st.x(), en.y() - st.y(), en.z() - st.z() ); + + theta = direction.theta(); + phi = phicorr( direction.phi() ); + + persCont->m_hit1_meanTime.push_back(t); + persCont->m_hit1_x0.push_back(st.x()); + persCont->m_hit1_y0.push_back(st.y()); + persCont->m_hit1_z0.push_back(st.z()); + persCont->m_hit1_theta.push_back(theta); + persCont->m_hit1_phi.push_back(phi); + + lastPersEnd = HepGeom::Point3D<double>(st.x(), st.y(), st.z()); + + stringFirstTheta = theta; + stringFirstPhi = phi; + + if (idx > 0) { + persCont->m_nHits.push_back(idx - endHit); + endHit = idx; + } + } + + lastTransEnd = HepGeom::Point3D<double>(en.x(), en.y(), en.z()); + transSumE += siHit->energyLoss(); + + const int eneLoss_2b = (int)((transSumE - persSumE) / m_persEneUnit + 0.5); // calculated to allow recovery sum over + // whole hit string to chosen precision + + const int hitLength_2b = (int)(direction.mag() / m_persLenUnit + 0.5); // calculated to give the correct position to + // the chosen precision, NOT the length of the + // hit (small difference in practice). + double eneLoss = 0.0; + + if (eneLoss_2b >= m_2bMaximum) { + eneLoss = siHit->energyLoss(); + persCont->m_hitEne_2b.push_back(m_2bMaximum); + persCont->m_hitEne_4b.push_back(eneLoss); + } + else { + eneLoss = eneLoss_2b * m_persEneUnit; + persCont->m_hitEne_2b.push_back(eneLoss_2b); + } + + double length = 0.0; + + if (hitLength_2b >= m_2bMaximum) { + length = direction.mag(); + persCont->m_hitLength_2b.push_back(m_2bMaximum); + persCont->m_hitLength_4b.push_back(direction.mag()); + } + else { + length = hitLength_2b * m_persLenUnit; + persCont->m_hitLength_2b.push_back(hitLength_2b); + } + + CLHEP::Hep3Vector persDir(length, 0.0, 0.0); + persDir.setTheta(theta); + persDir.setPhi(phi); + + lastPersEnd = (CLHEP::Hep3Vector)lastPersEnd + persDir; + persSumE += eneLoss; + lastT = t; + + ++idx; + } + + persCont->m_nBC.push_back(idx - endBC); + persCont->m_nId.push_back(idx - endId); + persCont->m_nHits.push_back(idx - endHit); +} + + +NeutrinoHitCollection* NeutrinoHitCollectionCnv_p1a::createTransient(const NeutrinoHitCollection_p1a* persObj, MsgStream &log) { + std::unique_ptr<NeutrinoHitCollection> trans(std::make_unique<NeutrinoHitCollection>("DefaultCollectionName",persObj->m_nHits.size())); + persToTrans(persObj, trans.get(), log); + return(trans.release()); +} + + +void NeutrinoHitCollectionCnv_p1a::persToTrans(const NeutrinoHitCollection_p1a* persCont, NeutrinoHitCollection* transCont, MsgStream &/*log*/) +{ + const EventContext& ctx = Gaudi::Hive::currentContext(); + + unsigned int hitCount = 0; + unsigned int angleCount = 0; + unsigned int idxBC = 0; + unsigned int idxId = 0; + unsigned int idxEne4b = 0; + unsigned int idxLen4b = 0; + unsigned int endHit = 0; + unsigned int endBC = 0; + unsigned int endId = 0; + + for (unsigned int i = 0; i < persCont->m_nHits.size(); i++) { + + if (persCont->m_nHits[i]) { + + const unsigned int start = endHit; + endHit += persCont->m_nHits[i]; + + const double t0 = persCont->m_hit1_meanTime[i]; + const double theta0 = persCont->m_hit1_theta[i]; + const double phi0 = persCont->m_hit1_phi[i]; + HepGeom::Point3D<double> endLast(persCont->m_hit1_x0[i], persCont->m_hit1_y0[i], persCont->m_hit1_z0[i]); + + for (unsigned int j = start; j < endHit; j++) { + + if (j >= endBC + persCont->m_nBC[idxBC]) + endBC += persCont->m_nBC[idxBC++]; + + if (j >= endId + persCont->m_nId[idxId]) + endId += persCont->m_nId[idxId++]; + + const double eneLoss_2b = persCont->m_hitEne_2b[hitCount]; + const double hitLength_2b = persCont->m_hitLength_2b[hitCount]; + + const double eneLoss = (eneLoss_2b < m_2bMaximum) ? eneLoss_2b * m_persEneUnit : persCont->m_hitEne_4b[idxEne4b++]; + const double length = (hitLength_2b < m_2bMaximum) ? hitLength_2b * m_persLenUnit : persCont->m_hitLength_4b[idxLen4b++]; + + const double dTheta = (j > start) ? ((double)persCont->m_dTheta[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + const double dPhi = (j > start) ? ((double)persCont->m_dPhi[angleCount] - m_2bHalfMaximum) * m_persAngUnit : 0.0; + + const double meanTime = t0; + const double theta = theta0 + dTheta; + const double phi = phicorr(phi0 + dPhi); + + CLHEP::Hep3Vector r(length, 0.0, 0.0); + r.setTheta(theta); + r.setPhi(phi); + + HepGeom::Point3D<double> endThis( endLast + r ); + + HepMcParticleLink::PositionFlag flag = HepMcParticleLink::IS_INDEX; + if (persCont->m_mcEvtIndex[idxBC] == 0) { + flag = HepMcParticleLink::IS_POSITION; + } + HepMcParticleLink partLink( persCont->m_barcode[idxBC], persCont->m_mcEvtIndex[idxBC], HepMcParticleLink::ExtendedBarCode::eventCollectionFromChar(persCont->m_evtColl[idxBC]), flag, ctx ); + transCont->Emplace( endLast, endThis, eneLoss, meanTime, partLink, persCont->m_id[idxId]); + + endLast = endThis; + + ++hitCount; + if (j > start) ++angleCount; + } + } + } +} -- GitLab