ATLAS Offline Software
Loading...
Searching...
No Matches
BCM_DigitizationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <cmath>
6
8
11
12// CLHEP includes
13#include "CLHEP/Random/RandomEngine.h"
14#include "CLHEP/Random/RandGaussZiggurat.h"
15
19#include "xAODEventInfo/EventInfo.h" // NEW EDM
20#include "xAODEventInfo/EventAuxInfo.h" // NEW EDM
22
23//----------------------------------------------------------------------
24// Constructor with parameters:
25//----------------------------------------------------------------------
26BCM_DigitizationTool::BCM_DigitizationTool(const std::string &type, const std::string &name, const IInterface *parent) :
27 PileUpToolBase(type,name,parent)
28{
29 declareProperty("ModNoise", m_modNoise, "RMS noise averaged over modules");
30 declareProperty("ModSignal", m_modSignal, "Average MIP signal in modules");
31 declareProperty("NinoThr", m_ninoThr, "NINO threshold voltage");
32}
33
34//----------------------------------------------------------------------
35// Initialize method:
36//----------------------------------------------------------------------
38{
39 ATH_MSG_VERBOSE ( "initialize()");
40
42 ATH_CHECK(m_mergeSvc.retrieve());
43 }
44
45 // get random service
46 ATH_CHECK(m_rndmGenSvc.retrieve());
47
48 // check the input object name
49 if (m_hitsContainerKey.key().empty()) {
50 ATH_MSG_FATAL("Property InputObjectName not set !");
51 return StatusCode::FAILURE;
52 }
54 ATH_MSG_DEBUG("Input objects in container : '" << m_inputObjectName << "'");
55
56 // Initialize ReadHandleKey
57 ATH_CHECK(m_hitsContainerKey.initialize(true));
58
59 // Write handle keys
60 ATH_CHECK( m_outputKey.initialize() );
61 ATH_MSG_VERBOSE("Initialized WriteHandleKey: " << m_outputKey);
62 ATH_CHECK( m_outputSDOKey.initialize() );
63 ATH_MSG_VERBOSE("Initialized WriteHandleKey: " << m_outputSDOKey);
64
65 return StatusCode::SUCCESS;
66}
67
68//----------------------------------------------------------------------
69// createOutpuContainers method:
70//----------------------------------------------------------------------
71StatusCode BCM_DigitizationTool::createOutputContainers(const EventContext& ctx)
72{
73 // Creating output RDO container
75 ATH_CHECK(outputContainer.record(std::make_unique<BCM_RDO_Container>()));
76 if (!outputContainer.isValid()) {
77 ATH_MSG_ERROR("Could not record output BCM RDO container " << outputContainer.name() << " to store " << outputContainer.store());
78 return StatusCode::FAILURE;
79 }
80
81 ATH_MSG_DEBUG("Recorded output BCM RDO container " << outputContainer.name() << " in store " << outputContainer.store());
82 m_rdoContainer = outputContainer.ptr();
83
84 // Creating output SDO collection container
86 ATH_CHECK(outputSDOContainer.record(std::make_unique<InDetSimDataCollection>()));
87 if (!outputSDOContainer.isValid()) {
88 ATH_MSG_ERROR("Could not record output BCM SDO container " << outputSDOContainer.name() << " to store " << outputSDOContainer.store());
89 return StatusCode::FAILURE;
90 }
91
92 ATH_MSG_DEBUG("Recorded output BCM SDO container " << outputSDOContainer.name() << " in store " << outputSDOContainer.store());
93 m_simDataCollMap = outputSDOContainer.ptr();
94
95
96 // Clear G4 hit info vectors
97 for (unsigned int iMod=0; iMod<8; ++iMod) {
98 m_enerVect[iMod].clear();
99 m_timeVect[iMod].clear();
100 m_depositVect[iMod].clear();
101 }
102
103 return StatusCode::SUCCESS;
104}
105
106//----------------------------------------------------------------------
107// ProcessSiHit method:
108//----------------------------------------------------------------------
109void BCM_DigitizationTool::processSiHit(const SiHit &currentHit, double eventTime, unsigned int evtIndex, const EventContext& ctx)
110{
111 const int moduleNo = currentHit.getLayerDisk();
112 const float enerDep = computeEnergy(currentHit.energyLoss(), currentHit.localStartPosition(), currentHit.localEndPosition());
113 const float hitTime = currentHit.meanTime() + eventTime + m_timeDelay;
114 // Fill vectors with hit info
115 m_enerVect[moduleNo].push_back(enerDep);
116 m_timeVect[moduleNo].push_back(hitTime);
117 // Create new deposit and add to vector
118 const HepMcParticleLink particleLink = HepMcParticleLink::getRedirectedLink(currentHit.particleLink(), evtIndex, ctx); // This link should now correctly resolve to the TruthEvent McEventCollection in the main StoreGateSvc.
119 if (HepMC::no_truth_link(particleLink)) return;
120 m_depositVect[moduleNo].emplace_back(particleLink,currentHit.energyLoss());
121}
122
123//----------------------------------------------------------------------
124// createRDOs method:
125//----------------------------------------------------------------------
126void BCM_DigitizationTool::createRDOsAndSDOs(const EventContext& ctx)
127{
128 // Set the RNG to use for this event.
129 ATHRNG::RNGWrapper* rngWrapper = m_rndmGenSvc->getEngine(this);
130 rngWrapper->setSeed( name(), ctx );
131
132 // Digitize hit info and create RDO for each module
133 for (int iMod=0; iMod<8; ++iMod) {
134 if (!m_depositVect[iMod].empty()) m_simDataCollMap->emplace(Identifier(iMod), m_depositVect[iMod]);
135 std::vector<float> analog = createAnalog(iMod,m_enerVect[iMod],m_timeVect[iMod]);
136 addNoise(iMod,analog, rngWrapper->getEngine(ctx));
137 for (int iGain=0; iGain<2; ++iGain) {
138 std::bitset<64> digital = applyThreshold(iGain*8+iMod,analog);
139 int p1x,p1w,p2x,p2w;
140 applyFilter(digital);
141 findPulses(digital,p1x,p1w,p2x,p2w);
142 fillRDO(iGain*8+iMod,p1x,p1w,p2x,p2w);
143 }
144 }
145 }
146
147//----------------------------------------------------------------------
148// PrepareEvent method:
149//----------------------------------------------------------------------
150StatusCode BCM_DigitizationTool::prepareEvent(const EventContext& ctx, unsigned int nInputEvents)
151{
152 ATH_MSG_DEBUG ( "prepareEvent() called for " << nInputEvents << " input events" );
153
155
156 return StatusCode::SUCCESS;
157}
158
159//----------------------------------------------------------------------//
160// Digitize method: //
161//----------------------------------------------------------------------//
162StatusCode BCM_DigitizationTool::processAllSubEvents(const EventContext& ctx)
163{
164 ATH_MSG_DEBUG ( "processAllSubEvents()" );
165
167
168 // Fetch SiHitCollections for this bunch crossing
171 if (!hitCollection.isValid()) {
172 ATH_MSG_ERROR("Could not get BCM SiHitCollection container " << hitCollection.name() <<
173 " from store " << hitCollection.store());
174 return StatusCode::FAILURE;
175 }
176 const unsigned int evtIndex = 0;
177 const double time = 0.0;
178 ATH_MSG_DEBUG ( "SiHitCollection found with " << hitCollection->size() << " hits" );
179 // Read hits from this collection
180 for (const auto& siHit : *hitCollection) {
181 processSiHit(siHit, time, evtIndex, ctx);
182 }
183
184 }
185 else {
187 TimedHitCollList hitCollList;
188 if (!(m_mergeSvc->retrieveSubEvtsData(m_inputObjectName, hitCollList).isSuccess()) && hitCollList.empty()) {
189 ATH_MSG_ERROR ( "Could not fill TimedHitCollList" );
190 return StatusCode::FAILURE;
191 } else {
192 ATH_MSG_DEBUG ( hitCollList.size() << " SiHitCollections with key " << m_inputObjectName << " found" );
193 }
194
195 // Store hit info in vectors and fill SDO map
196 TimedHitCollList::iterator iColl(hitCollList.begin());
197 TimedHitCollList::iterator endColl(hitCollList.end());
198 for (; iColl != endColl; ++iColl) {
199 const SiHitCollection* tmpColl(iColl->second);
200 const unsigned int evtIndex = (iColl->first).index();
201 const double time = (iColl->first).time();
202 ATH_MSG_DEBUG ( "SiHitCollection found with " << tmpColl->size() << " hits" );
203 // Read hits from this collection
204 for (const auto& siHit : *tmpColl) {
205 processSiHit(siHit, time, evtIndex, ctx);
206 }
207 }
208 }
209
211
212 return StatusCode::SUCCESS;
213}
214
215//----------------------------------------------------------------------
216// ProcessBunchXing method:
217//----------------------------------------------------------------------
219 SubEventIterator bSubEvents,
220 SubEventIterator eSubEvents)
221{
222 const EventContext &ctx = Gaudi::Hive::currentContext();
223
224 ATH_MSG_DEBUG ( "processBunchXing() " << bunchXing );
225
226 SubEventIterator iEvt = bSubEvents;
227 for (; iEvt!=eSubEvents; ++iEvt) {
228 StoreGateSvc& seStore = *iEvt->ptr()->evtStore();
229 ATH_MSG_VERBOSE ( "SubEvt StoreGate " << seStore.name() << " :"
230 << " bunch crossing : " << bunchXing
231 << " time offset : " << iEvt->time()
232 << " event number : " << iEvt->ptr()->eventNumber()
233 << " run number : " << iEvt->ptr()->runNumber()
234 );
235 const SiHitCollection* seHitColl = nullptr;
236 CHECK(seStore.retrieve(seHitColl,m_inputObjectName));
237 ATH_MSG_DEBUG ( "SiHitCollection found with " << seHitColl->size() << " hits" );
238 SiHitCollection::const_iterator i = seHitColl->begin();
239 SiHitCollection::const_iterator e = seHitColl->end();
240 // Read hits from this collection
241 for (; i!=e; ++i) {
242 processSiHit(*i, iEvt->time(), iEvt->index(), ctx);
243 }
244 }
245
246 return StatusCode::SUCCESS;
247}
248
249//----------------------------------------------------------------------
250// MergeEvent method:
251//----------------------------------------------------------------------
252StatusCode BCM_DigitizationTool::mergeEvent(const EventContext& ctx)
253{
254 ATH_MSG_DEBUG ( "mergeEvent()" );
255
257
258 return StatusCode::SUCCESS;
259}
260
261//----------------------------------------------------------------------
262// ComputeEnergy method:
263//----------------------------------------------------------------------
264float BCM_DigitizationTool::computeEnergy(float simEner, const HepGeom::Point3D<double>& startPos, const HepGeom::Point3D<double>& endPos)
265{
266 // Initialize output energy
267 float calcEner = 0;
268 // Break hit up into 10 discrete energy deposits
269 // For each deposit, weight energy by charge collection efficiency based on position on diamond surface
270 float xStep, yStep, rStep, r0Step, effStep;
271 for (int iStep=0; iStep<10; ++iStep) {
272 xStep = startPos.x()+iStep*(endPos.x()-startPos.x())/9;
273 yStep = startPos.y()+iStep*(endPos.y()-startPos.y())/9;
274 if (xStep==0 && yStep==0) effStep = 1.;
275 else {
276 rStep = sqrt(pow(xStep,2)+pow(yStep,2));
277 r0Step = std::abs(yStep)>std::abs(xStep) ? rStep*m_effPrmDistance/std::abs(yStep) : rStep*m_effPrmDistance/std::abs(xStep);
278 effStep = 1/(1+std::exp((rStep-r0Step)/m_effPrmSharpness));
279 }
280 calcEner+= 0.1*simEner*effStep;
281 }
282 return calcEner;
283}
284
285//----------------------------------------------------------------------
286// CreateAnalog method:
287//----------------------------------------------------------------------
288std::vector<float> BCM_DigitizationTool::createAnalog(int iMod, const std::vector<float>& enerVect, const std::vector<float>& timeVect)
289{
290 std::vector<float> analog(64,0);
291 for (unsigned int iHit=0; iHit<enerVect.size(); ++iHit) {
292 float enerDep = enerVect.at(iHit);
293 float hitTime = timeVect.at(iHit);
294 int startBin = (int)(hitTime*64/25);
295 float signalMax = enerDep*m_modSignal[iMod]/m_mipDeposit;
296 float slopeup = signalMax/5; // pulse rise in 2ns ~ 5 bins @ 390ps/bin
297 float slopedown = signalMax/10; // pulse fall in 3.8ns ~ 10 bins @ 390ps/bin
298 int iBin = startBin-1;
299 float signal = 0;
300 if (iBin>=0 && startBin<64) {
301 while (signal>=0 && iBin<64) {
302 analog[iBin] += signal;
303 signal += slopeup;
304 if (iBin > startBin+4) signal -= slopeup+slopedown;
305 iBin++;
306 }
307 }
308 }
309 return analog;
310}
311
312//----------------------------------------------------------------------
313// AddNoise method:
314//----------------------------------------------------------------------
315void BCM_DigitizationTool::addNoise(int iMod, std::vector<float> &analog, CLHEP::HepRandomEngine* randomEngine)
316{
317 for (float & iBin : analog) iBin+=CLHEP::RandGaussZiggurat::shoot(randomEngine,0.,m_modNoise[iMod]);
318}
319
320//----------------------------------------------------------------------
321// ApplyThreshold method:
322//----------------------------------------------------------------------
323std::bitset<64> BCM_DigitizationTool::applyThreshold(int iChan, const std::vector<float>& analog)
324{
325 std::bitset<64> digital;
326 digital.reset();
327 float factor = iChan<8 ? 1./13 : 12./13;
328 for (int iBin=0; iBin<64; ++iBin)
329 if (analog[iBin]*factor>m_ninoThr[iChan%8]) digital.set(iBin);
330 return digital;
331}
332
333//----------------------------------------------------------------------
334// ApplyFilter method:
335//----------------------------------------------------------------------
336void BCM_DigitizationTool::applyFilter(std::bitset<64> &digital)
337{
338 // 1101, 1011 -> 1111
339 for (int iSamp=2; iSamp<63; iSamp++) {
340 if (digital[iSamp-2] && digital[iSamp-1] && !digital[iSamp] && digital[iSamp+1]) digital[iSamp] = 1;
341 if (digital[iSamp-2] && !digital[iSamp-1] && digital[iSamp] && digital[iSamp+1]) digital[iSamp-1] = 1;
342 }
343 // 010 -> 000
344 if (digital[0] && !digital[1]) digital[0] = 0;
345 for (int iSamp=1; iSamp<63; iSamp++) {
346 if (!digital[iSamp-1] && digital[iSamp] && !digital[iSamp+1]) digital[iSamp] = 0;
347 }
348 if (!digital[62] && digital[63]) digital[63] = 0;
349}
350
351//----------------------------------------------------------------------
352// FindPulses method:
353//----------------------------------------------------------------------
354void BCM_DigitizationTool::findPulses(const std::bitset<64>& digital, int &p1x, int &p1w, int &p2x, int &p2w)
355{
356 p1x = 0; p1w = 0; p2x = 0; p2w = 0;
357
358 if (!digital.count()) return; // skip if waveform is empty
359
360 bool p1done = false, p2done = false; bool ignorepulse = false;
361 if (digital[0] && digital[1]) ignorepulse = true;
362 else if (!digital[0] && digital[1] && digital[2]) p1x = 1;
363 for (int iBin=2; iBin<63; iBin++) {
364 if (!digital[iBin-2] && !digital[iBin-1] && digital[iBin] && digital[iBin+1]) { // rising edge
365 if (!p1done && !p2done) p1x = iBin;
366 else if (p1done && !p2done) p2x = iBin;
367 }
368 else if (digital[iBin-2] && digital[iBin-1] && !digital[iBin] && !digital[iBin+1]) { // falling edge
369 if (!ignorepulse) {
370 if (!p1done && !p2done) {
371 p1w = iBin - p1x;
372 p1done = true;
373 if (p1w >= 32) {
374 p2x = p1x + 31;
375 p2w = p1w - 31;
376 p2done = true;
377 p1w = 31;
378 }
379 }
380 else if (p1done && !p2done) {
381 p2w = iBin - p2x;
382 p2done = true;
383 if (p2w >= 32) p2w = 31;
384 }
385 }
386 else ignorepulse = false;
387 }
388 }
389 if (digital[61] && digital[62] && !digital[63]) {
390 if (!ignorepulse) {
391 if (!p1done && !p2done) {
392 p1w = 63 - p1x;
393 p1done = true;
394 if (p1w >= 32) {
395 p2x = p1x + 31;
396 p2w = p1w - 31;
397 p2done = true;
398 p1w = 31;
399 }
400 }
401 else if (p1done && !p2done) {
402 p2w = 63 - p2x;
403 p2done = true;
404 if (p2w >= 32) p2w = 31;
405 }
406 }
407 else ignorepulse = false;
408 }
409 else if (digital[62] && digital[63]) {
410 if (!ignorepulse) {
411 if (!p1done && !p2done) {
412 p1w = 1;
413 p1done = true;
414 if (64 - p1x >= 32) {
415 p2x = p1x + 31;
416 p2w = 1;
417 p2done = true;
418 p1w = 31;
419 }
420 }
421 else if (p1done && !p2done) {
422 p2w = 1;
423 p2done = true;
424 if (64 - p2x >= 32) p2w = 31;
425 }
426 }
427 else ignorepulse = false;
428 }
429}
430
431//----------------------------------------------------------------------
432// FillRDO method:
433//----------------------------------------------------------------------
434void BCM_DigitizationTool::fillRDO(unsigned int chan, int p1x, int p1w, int p2x, int p2w)
435{
436 BCM_RDO_Collection *RDOColl = nullptr;
437 // Check if collection for this channel already exists
438 bool collExists = false;
441 for (; it_coll!=it_collE; ++it_coll) {
442 if ((*it_coll)->getChannel()==chan) {
443 collExists = true;
444 RDOColl = *it_coll;
445 }
446 }
447 // Create the RDO collection if needed
448 if (!collExists) {
449 RDOColl = new BCM_RDO_Collection(chan);
450 // Add collection to container
451 m_rdoContainer->push_back(RDOColl);
452 }
453 // Create RDO & add it to collection
454 BCM_RawData *bcmrdo = new BCM_RawData(chan,p1x,p1w,p2x,p2w,0,0,0);
455 if (bcmrdo) RDOColl->push_back(bcmrdo);
456}
float hitTime(const AFP_SIDSimHit &hit)
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
Helpers for checking error return status codes and reporting errors.
#define CHECK(...)
Evaluate an expression and check for errors.
ATLAS-specific HepMC functions.
std::vector< xAOD::EventInfo::SubEvent >::const_iterator SubEventIterator
Definition IPileUpTool.h:22
AtlasHitsVector< SiHit > SiHitCollection
static const Attributes_t empty
constexpr int pow(int base, int exp) noexcept
A wrapper class for event-slot-local random engines.
Definition RNGWrapper.h:56
void setSeed(const std::string &algName, const EventContext &ctx)
Set the random seed using a string (e.g.
Definition RNGWrapper.h:169
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:134
CONT::const_iterator const_iterator
const_iterator begin() const
size_type size() const
const_iterator end() const
std::vector< InDetSimData::Deposit > m_depositVect[8]
Deposit vectors for SDO map.
float computeEnergy(float simEner, const HepGeom::Point3D< double > &startPos, const HepGeom::Point3D< double > &endPos)
Compute energy deposit depending on hit position.
std::vector< float > m_enerVect[8]
G4 hit energies, weighted.
std::vector< float > m_modNoise
RMS Gaussian noise.
Gaudi::Property< float > m_effPrmSharpness
std::vector< float > createAnalog(int mod, const std::vector< float > &enerVect, const std::vector< float > &timeVect)
Fill in hit pulses on analog waveform.
SG::ReadHandleKey< SiHitCollection > m_hitsContainerKey
std::bitset< 64 > applyThreshold(int chan, const std::vector< float > &analog)
Do ToT digitization.
Gaudi::Property< float > m_effPrmDistance
BCM_DigitizationTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters.
void addNoise(int mod, std::vector< float > &analog, CLHEP::HepRandomEngine *randomEngine)
Add noise to analog waveform.
StatusCode createOutputContainers(const EventContext &ctx)
Create the RDO and SDO containers.
SG::WriteHandleKey< BCM_RDO_Container > m_outputKey
virtual StatusCode mergeEvent(const EventContext &ctx) override final
InDetSimDataCollection * m_simDataCollMap
Output SDO map.
virtual StatusCode processAllSubEvents(const EventContext &ctx) override final
alternative interface which uses the PileUpMergeSvc to obtain all the required SubEvents.
std::vector< float > m_modSignal
Most probable MIP signal.
BooleanProperty m_onlyUseContainerName
SG::WriteHandleKey< InDetSimDataCollection > m_outputSDOKey
void fillRDO(unsigned int chan, int p1x, int p1w, int p2x, int p2w)
Create raw data object and put it in the container.
ServiceHandle< PileUpMergeSvc > m_mergeSvc
Gaudi::Property< float > m_mipDeposit
static void applyFilter(std::bitset< 64 > &digital)
Apply hole and spike filter to digital waveform.
virtual StatusCode prepareEvent(const EventContext &ctx, unsigned int) override final
PileUpToolBase methods.
virtual StatusCode initialize() override final
Gaudi::Property< float > m_timeDelay
void processSiHit(const SiHit &currentHit, double eventTime, unsigned int evtIndex, const EventContext &ctx)
void createRDOsAndSDOs(const EventContext &ctx)
BCM_RDO_Container * m_rdoContainer
Output RDO container.
static void findPulses(const std::bitset< 64 > &digital, int &p1x, int &p1w, int &p2x, int &p2w)
Find first two pulses on digital waveform.
std::vector< float > m_ninoThr
NINO threshold.
ServiceHandle< IAthRNGSvc > m_rndmGenSvc
Random number service.
virtual StatusCode processBunchXing(int bunchXing, SubEventIterator bSubEvents, SubEventIterator eSubEvents) override final
std::vector< float > m_timeVect[8]
G4 hit times.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
DataModel_detail::iterator< DataVector > iterator
Definition DataVector.h:842
PileUpToolBase(const std::string &type, const std::string &name, const IInterface *parent)
virtual bool isValid() override final
Can the handle be successfully dereferenced?
std::string store() const
Return the name of the store holding the object we are proxying.
const std::string & name() const
Return the StoreGate ID for the referenced object.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
pointer_type ptr()
Dereference the pointer.
Definition SiHit.h:19
double energyLoss() const
Definition SiHit.h:175
HepGeom::Point3D< double > localStartPosition() const
Definition SiHit.cxx:146
double meanTime() const
Definition SiHit.h:180
const HepMcParticleLink & particleLink() const
Definition SiHit.h:190
int getLayerDisk() const
Definition SiHit.cxx:164
HepGeom::Point3D< double > localEndPosition() const
Definition SiHit.cxx:153
The Athena Transient Store API.
StatusCode retrieve(const T *&ptr) const
Retrieve the default object into a const T*.
bool no_truth_link(const T &p)
Method to establish if a if the object is linked to something which was never saved to the HepMC Trut...
Definition index.py:1
std::list< value_t > type
type of the collection of timed data object