ATLAS Offline Software
Loading...
Searching...
No Matches
LArPileUpTool.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// +==========================================================================+
6// + +
7// + Authors .......: G.Unal +
8// + migrate LAr digitization to PileUpTool framework +
9// +==========================================================================+
10//
11
12#include "LArPileUpTool.h"
13
15
17#include "CLHEP/Random/RandGaussZiggurat.h"
25#include "LArSimEvent/LArHit.h"
28
30#include "CLHEP/Random/RandomEngine.h"
31
32#include <CLHEP/Random/Randomize.h>
33
34#include <utility>
35
36using CLHEP::RandFlat;
37using CLHEP::RandGaussZiggurat;
38
39LArPileUpTool::LArPileUpTool(const std::string& type, const std::string& name, const IInterface* parent) :
40 PileUpToolBase(type, name, parent) {
41}
42
43
45
47
48 //
49 // ........ Check for inconsistent configuration
50 //
52 ATH_MSG_FATAL("Adding noise to hard-scatter Hits is not supported for Data Overlay! Fix your configuration. Bailing out.");
53 return StatusCode::FAILURE;
54 }
56 ATH_MSG_FATAL("MC overlay. Need to switch back on noise only to emulate extra noise for cells with different gains! Fix your configuration. Bailing out.");
57 return StatusCode::FAILURE;
58 }
59 if (m_RndmEvtOverlay && !m_PileUp) {
60 ATH_MSG_FATAL("If RndmEvtOverlay==True then PileUp must also be True. Fix your configuration. Bailing out.");
61 return StatusCode::FAILURE;
62 }
64 ATH_MSG_FATAL("If PileUp==False then OnlyUserContainerName must also be False. Fix your configuration. Bailing out.");
65 return StatusCode::FAILURE;
66 }
67 //
68 // ........ print random event overlay flag
69 //
70 if (m_RndmEvtOverlay) {
71 ATH_MSG_INFO(" pileup and/or noise added by overlaying digits of random events");
72 if (m_isMcOverlay) {
73 ATH_MSG_INFO(" random events are from MC ");
74 } else {
75 ATH_MSG_INFO(" random events are from data ");
76 }
77 } else {
78 ATH_MSG_INFO(" No overlay of random events");
79 }
80
82 ATH_CHECK(m_mergeSvc.retrieve());
83 ATH_MSG_INFO("PileUpMergeSvc successfully initialized");
84 }
85
86 //
87 // ......... print the noise flag
88 //
89 if (m_NoiseOnOff) {
90 ATH_MSG_INFO(" Electronic noise will be added in each cell ");
91 } else {
92 ATH_MSG_INFO(" No electronic noise added.");
93
94 // not useful (see MakeDigit), but in case of...
95 m_NoiseInEMB = false;
96 m_NoiseInEMEC = false;
97 m_NoiseInHEC = false;
98 m_NoiseInFCAL = false;
99 }
100 //
101 // ............ print cross-talk configuration
102 //
103 if (m_CrossTalk) {
104 ATH_MSG_INFO(" Cross-talk in EM barrel will be taken into account : ");
105 ATH_MSG_INFO(" Cross talk strip strip included ");
107 ATH_MSG_INFO(" Cross talk strip-2nd strip included ");
108 ATH_MSG_INFO(" Cross talk strip middle included ");
110 ATH_MSG_INFO(" Cross talk strip middle included ");
112 ATH_MSG_INFO(" Cross talk middle middle included");
113 } else {
114 ATH_MSG_INFO(" no Cross-Talk simulated");
115 }
116
119 } else {
120 if (m_useLArHitFloat) {
122 } else {
124 }
125 }
126 ATH_MSG_DEBUG("Input objects in these containers : '" << m_hitContainerNames << "'");
127
128 // Initialize ReadHandleKey
132
134 ATH_CHECK(m_mcEventColl.initialize(m_Windows));
135
136
137 ATH_CHECK(m_caloMgrKey.initialize());
138
139 // retrieve ID helpers
140 ATH_CHECK(detStore()->retrieve(m_calocell_id, "CaloCell_ID"));
141
142 const CaloIdManager* caloIdMgr = nullptr;
143 StatusCode sc = detStore()->retrieve(caloIdMgr);
144 if (sc.isFailure()) {
145 ATH_MSG_ERROR(" Unable to retrieve CaloIdManager from DetectoreStore");
146 return StatusCode::FAILURE;
147 }
148 m_larem_id = caloIdMgr->getEM_ID();
149 m_larhec_id = caloIdMgr->getHEC_ID();
150 m_larfcal_id = caloIdMgr->getFCAL_ID();
151
152 sc = detStore()->retrieve(m_laronline_id);
153 if (sc.isFailure()) {
154 ATH_MSG_ERROR(" Unable to retrieve LArOnlineId from DetectoreStore");
155 return StatusCode::FAILURE;
156 }
157
158 ATH_CHECK(m_rndmGenSvc.retrieve());
159
160 // register data handle for conditions data
161
162 ATH_CHECK(m_xtalkKey.initialize());
163
164 ATH_CHECK(m_cablingKey.initialize());
165
166 ATH_CHECK(m_hitMapKey.initialize());
168
169 ATH_MSG_DEBUG("Initialization completed successfully");
170
171 return StatusCode::SUCCESS;
172}
173// ----------------------------------------------------------------------------------------------------------------------------------
174
175StatusCode LArPileUpTool::prepareEvent(const EventContext& ctx, unsigned int /*nInputEvents */)
176{
177
178 //Clear per-event data:
179 m_data.m_energySum.clear();
180 m_data.m_energySum_DigiHSTruth.clear();
181 m_data.m_hitmap=nullptr;
182 m_data.m_hitmap_DigiHSTruth=nullptr;
183 m_data.m_trigtime=0;
184 m_data.m_weights=nullptr;
185
187 auto* cabling=*cablingHdl;
188 if(!cabling) {
189 ATH_MSG_ERROR("Failed to retrieve LAr Cabling map with key " << m_cablingKey.key() );
190 return StatusCode::FAILURE;
191 }
193 const CaloDetDescrManager* caloDDMgr = *caloMgrHandle;
194 auto hitmap=SG::makeHandle(m_hitMapKey, ctx);
195 auto hitMapPtr=std::make_unique<LArHitEMap>(cabling,m_calocell_id,caloDDMgr,m_RndmEvtOverlay);
196 ATH_CHECK(hitmap.record(std::move(hitMapPtr)));
197 m_data.m_hitmap=hitmap.ptr();
198 ATH_MSG_DEBUG(" Number of created cells in Map " << hitmap->GetNbCells());
199 if (!m_useMBTime) m_data.m_energySum.assign(m_data.m_hitmap->GetNbCells(),0.);
200
201
202 if (m_doDigiTruth) {
203 auto hitmap_DigiHSTruth=SG::makeHandle(m_hitMapKey_DigiHSTruth, ctx);
204 auto hitMapPtr=std::make_unique<LArHitEMap>(cabling,m_calocell_id,caloDDMgr,m_RndmEvtOverlay);
205 ATH_CHECK(hitmap_DigiHSTruth.record(std::move(hitMapPtr)));
206 m_data.m_hitmap_DigiHSTruth=hitmap_DigiHSTruth.ptr();
207 if (!m_useMBTime) m_data.m_energySum_DigiHSTruth.assign(m_data.m_hitmap_DigiHSTruth->GetNbCells(),0.);
208 }
209 // get the trigger time if requested
210 m_data.m_trigtime=0;
211 if (m_useTriggerTime) {
213 m_data.m_trigtime = cosTimeHdl->time();
214 ATH_MSG_DEBUG(" Trigger time used : " << m_data.m_trigtime);
215 }
216
217 ATHRNG::RNGWrapper* rngWrapper = m_rndmGenSvc->getEngine(this, m_randomStreamName);
219 rngWrapper->setSeedLegacy( m_randomStreamName, ctx, m_randomSeedOffset, seedingmode );
220 // add random phase (i.e subtract it from trigtime)
221 if (m_addPhase) {
222 m_data.m_trigtime -= (m_phaseMin + (m_phaseMax-m_phaseMin)*RandFlat::shoot(rngWrapper->getEngine(ctx)) );
223 }
224
225 if (m_Windows) {
226 ATH_MSG_DEBUG(" redefine windows list ");
228 const McEventCollection* mcCollptr=mcColl.cptr();
229 if ( evtStore()->retrieve(mcCollptr).isFailure() ) {
230 ATH_MSG_WARNING ("LArHitEMap:cannot retrieve McEventCollection (keyless)");
231 }
232
233 m_data.m_hitmap->BuildWindows(mcCollptr, m_WindowsEtaSize, m_WindowsPhiSize, m_WindowsPtCut);
234 if (m_doDigiTruth) {
235 m_data.m_hitmap_DigiHSTruth->BuildWindows(mcCollptr, m_WindowsEtaSize, m_WindowsPhiSize, m_WindowsPtCut);
236 }
237 }
238
239 return StatusCode::SUCCESS;
240}
241
242
243//----------------------------------------------------------------------------------------------------------------------------
244
245StatusCode LArPileUpTool::processBunchXing(int bunchXing, SubEventIterator bSubEvents, SubEventIterator eSubEvents) {
246
247 ATH_MSG_VERBOSE("processBunchXing()");
248 float tbunch = (float)(bunchXing);
249 const EventContext& ctx = Gaudi::Hive::currentContext();
251 m_data.m_weights = *weightHdl;
252
253 SubEventIterator iEvt(bSubEvents);
254 while (iEvt != eSubEvents) {
255
256 // do we deal with the MC signal event ?
257 bool isSignal = ((iEvt->type() == xAOD::EventInfo_v1::PileUpType::Signal) || m_RndmEvtOverlay);
258
259 // fill LArHits in map
260 if (this->fillMapFromHit(iEvt, tbunch, isSignal, m_data).isFailure()) {
261
262 ATH_MSG_ERROR(" cannot fill map from hits ");
263 return StatusCode::FAILURE;
264 }
265
266 // store digits from randoms for overlay
267 if (m_RndmEvtOverlay) {
268 const LArDigitContainer* rndm_digit_container;
269 if (m_mergeSvc->retrieveSingleSubEvtData(m_inputDigitContainerKey.key(), rndm_digit_container, bunchXing, iEvt).isSuccess()) {
270 int ndigit = 0;
271 for (const LArDigit* digit : *rndm_digit_container) {
272 if (m_data.m_hitmap->AddDigit(digit))
273 ndigit++;
274 }
275 ATH_MSG_INFO(" Number of digits stored for RndmEvt Overlay " << ndigit);
276 }
277 }
278
279 ++iEvt;
280 }
281
282 if (!m_useMBTime) {
283 if (!this->fillMapfromSum(tbunch, m_data)) {
284 ATH_MSG_ERROR(" error in FillMapFromSum ");
285 return StatusCode::FAILURE;
286 }
287 }
288
289 return StatusCode::SUCCESS;
290}
291
292// ---------------------------------------------------------------------------------------------------------------------------------
293
294StatusCode LArPileUpTool::processAllSubEvents(const EventContext& ctx) {
295 return const_cast<const LArPileUpTool*>(this)->processAllSubEvents(ctx); //refer to const-version
296}
297
298StatusCode LArPileUpTool::processAllSubEvents(const EventContext& ctx) const {
299
300
302
304 if(!cablingHdl.isValid()) {
305 ATH_MSG_ERROR("Failed to retrieve LAr Cabling map with key " << m_cablingKey.key() );
306 return StatusCode::FAILURE;
307 }
308 const LArOnOffIdMapping* cabling=*cablingHdl;
310 const CaloDetDescrManager* caloDDMgr = *caloMgrHandle;
311
312
314 auto hitMapPtr=std::make_unique<LArHitEMap>(cabling,m_calocell_id,caloDDMgr,m_RndmEvtOverlay);
315 ATH_CHECK(hitmap.record(std::move(hitMapPtr)));
316 data.m_hitmap=hitmap.ptr();
317 ATH_MSG_DEBUG(" Number of created cells in Map " << hitmap->GetNbCells());
318
319 if (!m_useMBTime) data.m_energySum.assign(hitmap->GetNbCells(),0.);
320
321
322 if (m_doDigiTruth) {
323 SG::WriteHandle<LArHitEMap> hitmap_DigiHSTruth;
324 hitmap_DigiHSTruth=SG::makeHandle(m_hitMapKey_DigiHSTruth, ctx);
325 auto hitMapPtr=std::make_unique<LArHitEMap>(cabling,m_calocell_id,caloDDMgr,m_RndmEvtOverlay);
326 ATH_CHECK(hitmap_DigiHSTruth.record(std::move(hitMapPtr)));
327 if (!m_useMBTime) data.m_energySum_DigiHSTruth.assign(hitmap_DigiHSTruth->GetNbCells(),0.);
328 data.m_hitmap_DigiHSTruth=hitmap_DigiHSTruth.ptr();
329 }
330
331 // get the trigger time if requested
332
333 data.m_trigtime=0;
334 if (m_useTriggerTime) {
336 data.m_trigtime = cosTimeHdl->time();
337 ATH_MSG_DEBUG(" Trigger time used : " << m_data.m_trigtime);
338 }
339
340 ATHRNG::RNGWrapper* rngWrapper = m_rndmGenSvc->getEngine(this, m_randomStreamName);
342 rngWrapper->setSeedLegacy( m_randomStreamName, ctx, m_randomSeedOffset, seedingmode );
343
344 // add random phase (i.e subtract it from trigtime)
345 if (m_addPhase) {
346 data.m_trigtime -= (m_phaseMin + (m_phaseMax-m_phaseMin)*RandFlat::shoot(rngWrapper->getEngine(ctx)) );
347 }
348
349 if (m_Windows) {
350 ATH_MSG_DEBUG(" redefine windows list ");
352 const McEventCollection* mcCollptr=mcColl.cptr();
353 data.m_hitmap->BuildWindows(mcCollptr,
356 if(m_doDigiTruth) {
357 data.m_hitmap_DigiHSTruth->BuildWindows(mcCollptr,
359 }
360
361 }
362
363 //
364 // ....... create the LAr Digit Container
365 //
366
367 if (m_CrossTalk) {
369 data.m_weights=weightHdl.cptr();
370 }
371
373 auto hitVectorHandles = m_hitContainerKeys.makeHandles(ctx);
374 for (auto & inputHits : hitVectorHandles) {
375 if (!inputHits.isValid()) {
376 ATH_MSG_ERROR("Input LAr hit container is missing!");
377 return StatusCode::FAILURE;
378 }
379 bool isSignal(true);
380 double SubEvtTimOffset(0.0);
381 double timeCurrBunch=-9999999.;
382 for (const LArHit* hit : *inputHits) {
383 float energy = (float) (hit->energy());
384 float time;
385 if (m_ignoreTime && isSignal) time=0.;
386 else time = (float) (SubEvtTimOffset+ hit->time() - data.m_trigtime);
387 Identifier cellId = hit->cellID();
388 if (!m_useMBTime) {
389 if (std::fabs(SubEvtTimOffset-timeCurrBunch)>1.) {
390 if (timeCurrBunch>-9999.) {
391 if (!this->fillMapfromSum(timeCurrBunch,data)) {
392 ATH_MSG_ERROR(" error in FillMapFromSum ");
393 return(StatusCode::FAILURE);
394 }
395 }
396 timeCurrBunch = SubEvtTimOffset;
397 }
398 }
399 if (this->AddHit(cellId,energy,time,isSignal,data).isFailure()) return StatusCode::FAILURE;
400 } // End of loop over LArHitContainer
401 } // End of loop over SG::ReadHandles
402 }
403
404 if (!m_PileUp) {
405 float time=0.;
406 if (this->fillMapFromHit(ctx, time,true,data).isFailure()) {
407 ATH_MSG_ERROR("error in fillMapFromHit");
408 return StatusCode::FAILURE;
409 }
410 }
411
412 else {
413
414 for (const std::string& containerName : m_hitContainerNames) {
415
416 ATH_MSG_DEBUG(" pileUpOld asking for: " << containerName);
417
418 double timeCurrBunch=-9999999.;
419
420 if (!m_useLArHitFloat) {
422 TimedHitContList hitContList;
423 //
424 // retrieve list of pairs (time,container) from PileUp service
425
426 if (!(m_mergeSvc->retrieveSubEvtsData(containerName
427 ,hitContList).isSuccess()) && hitContList.empty()) {
428 ATH_MSG_ERROR("Could not fill TimedHitContList");
429 return StatusCode::FAILURE;
430 }
431
432 // loop over this list
433 TimedHitContList::iterator iFirstCont(hitContList.begin());
434 TimedHitContList::iterator iEndCont(hitContList.end());
435 if(m_RndmEvtOverlay) {
436 iEndCont = iFirstCont ;
437 ATH_MSG_DEBUG(" random event overlay mode : only time 0 read ");
438 ++iEndCont ;
439 }
440 double SubEvtTimOffset;
441 while (iFirstCont != iEndCont) {
442 // get time for this subevent
443 // new coding of time information (January 05)
444 bool isSignal = ( iFirstCont == hitContList.begin());
445 const PileUpTimeEventIndex* time_evt = &(iFirstCont->first);
446 SubEvtTimOffset = time_evt->time();
447 // get LArHitContainer for this subevent
448 const LArHitContainer& firstCont = *(iFirstCont->second);
449 // Loop over cells in this LArHitContainer
450 for (const LArHit* hit : firstCont) {
451 float energy = (float) (hit->energy());
452 float time;
453 if (m_ignoreTime && isSignal) time=0.;
454 else time = (float) (SubEvtTimOffset+ hit->time() - data.m_trigtime);
455 Identifier cellId = hit->cellID();
456
457 if (!m_useMBTime) {
458 if (std::fabs(SubEvtTimOffset-timeCurrBunch)>1.) {
459 if (timeCurrBunch>-9999.) {
460 if (!this->fillMapfromSum(timeCurrBunch,data)) {
461 ATH_MSG_ERROR(" error in FillMapFromSum ");
462 return(StatusCode::FAILURE);
463 }
464 }
465 timeCurrBunch = SubEvtTimOffset;
466 }
467 }
468 if (this->AddHit(cellId,energy,time,isSignal,data).isFailure()) return StatusCode::FAILURE;
469 } // loop over hits
470 ++iFirstCont;
471 } // loop over subevent list
472 }
473
474 else {
475
477 TimedHitContList hitContList;
478 //
479 // retrieve list of pairs (time,container) from PileUp service
480
481 if (!(m_mergeSvc->retrieveSubEvtsData(containerName
482 ,hitContList).isSuccess()) && hitContList.empty()) {
483 ATH_MSG_ERROR("Could not fill TimedHitContList");
484 return StatusCode::FAILURE;
485 }
486
487 // loop over this list
488 TimedHitContList::iterator iFirstCont(hitContList.begin());
489 TimedHitContList::iterator iEndCont(hitContList.end());
490 if(m_RndmEvtOverlay) {
491 iEndCont = iFirstCont ;
492 ATH_MSG_DEBUG("random event overlay mode : only time 0 read ");
493 ++iEndCont ;
494 }
495 double SubEvtTimOffset;
496 while (iFirstCont != iEndCont) {
497 bool isSignal = ( iFirstCont == hitContList.begin());
498 // get time for this subevent
499 // new coding of time information (January 05)
500 const PileUpTimeEventIndex* time_evt = &(iFirstCont->first);
501 SubEvtTimOffset = time_evt->time();
502 // get LArHitContainer for this subevent
503 const LArHitFloatContainer& firstCont = *(iFirstCont->second);
504 // Loop over cells in this LArHitContainer
505 for (const LArHitFloat& hit : firstCont) {
506 float energy = (float)( hit.energy());
507 float time;
508 if (m_ignoreTime && isSignal) time=0.;
509 else time = (float) (SubEvtTimOffset+ hit.time() - data.m_trigtime);
510 Identifier cellId = hit.cellID();
511
512 if (!m_useMBTime) {
513 if (std::fabs(SubEvtTimOffset-timeCurrBunch)>1.) {
514 if (timeCurrBunch>-9999.) {
515 if (!this->fillMapfromSum(timeCurrBunch,data)) {
516 ATH_MSG_ERROR(" error in FillMapFromSum ");
517 return(StatusCode::FAILURE);
518 }
519 }
520 timeCurrBunch = SubEvtTimOffset;
521 }
522 }
523 if (this->AddHit(cellId,energy,time,isSignal,data).isFailure()) return StatusCode::FAILURE;
524 } // loop over hits
525 ++iFirstCont;
526 } // loop over subevent list
527
528 } // LArHitFloat vs LArHit useage
529
530 if (!m_useMBTime) {
531 if (!this->fillMapfromSum(timeCurrBunch,data)) {
532 ATH_MSG_ERROR(" error in FillMapFromSum ");
533 return(StatusCode::FAILURE);
534 }
535 }
536
537 } // loop over containers
538
539 // get digits for random overlay
541 {
543 {
545 if (!digitCollection.isValid()) {
546 ATH_MSG_ERROR("Could not get LArDigitContainer container " << digitCollection.name() << " from store " << digitCollection.store());
547 return StatusCode::FAILURE;
548 }
549
550 ATH_MSG_DEBUG("LArDigitContainer found with " << digitCollection->size() << " digits");
551
552 size_t ndigit{};
553 for (const LArDigit* digit : *digitCollection) {
554 if (hitmap->AddDigit(digit)) ndigit++;
555 }
556 ATH_MSG_DEBUG(" Number of digits stored for RndmEvt Overlay " << ndigit);
557 }
558 else
559 {
560 typedef PileUpMergeSvc::TimedList<LArDigitContainer>::type TimedDigitContList ;
561 LArDigitContainer::const_iterator rndm_digititer_begin ;
562 LArDigitContainer::const_iterator rndm_digititer_end ;
563 LArDigitContainer::const_iterator rndm_digititer ;
564
565
566 TimedDigitContList digitContList;
567 if (!(m_mergeSvc->retrieveSubEvtsData(m_inputDigitContainerKey.key(),
568 digitContList).isSuccess()) || digitContList.empty())
569 {
570 ATH_MSG_ERROR("Cannot retrieve LArDigitContainer for random event overlay or empty Container");
571 ATH_MSG_ERROR("Random Digit Key= " << m_inputDigitContainerKey.key() << ",size=" << digitContList.size());
572 return StatusCode::FAILURE ;
573 }
574 TimedDigitContList::iterator iTzeroDigitCont(digitContList.begin()) ;
575 double SubEvtTimOffset;
576 // get time for this subevent
577 const PileUpTimeEventIndex* time_evt = &(iTzeroDigitCont->first);
578 SubEvtTimOffset = time_evt->time();
579 ATH_MSG_DEBUG(" Subevt time : " << SubEvtTimOffset);
580 const LArDigitContainer& rndm_digit_container = *(iTzeroDigitCont->second);
581 int ndigit=0;
582 for (const LArDigit* digit : rndm_digit_container) {
583 if (hitmap->AddDigit(digit)) ndigit++;
584 }
585 ATH_MSG_INFO(" Number of digits stored for RndmEvt Overlay " << ndigit);
586 }
587 }
588
589 } // if pileup
590
591 return StatusCode::SUCCESS;
592
593}
594
595// ============================================================================================
596
597StatusCode LArPileUpTool::fillMapFromHit(const EventContext& ctx, float bunchTime, bool isSignal, perEventData_t& data) const
598{
599 if (m_useLArHitFloat) {
600 auto hitVectorHandles = m_hitFloatContainerKeys.makeHandles(ctx);
601 for (auto & hit_container : hitVectorHandles) {
602 if (hit_container.isValid()) {
603 for (const LArHitFloat& hit : *hit_container)
604 {
605 Identifier cellId = hit.cellID();
606 float energy = (float) hit.energy();
607 float time;
608 if (m_ignoreTime) time=0.;
609 else time = (float) (hit.time() - data.m_trigtime);
610 time = time + bunchTime;
611 if (this->AddHit(cellId,energy,time,isSignal,data).isFailure()) return StatusCode::FAILURE;
612 }
613 }
614 else {
615 if (isSignal) {
616 ATH_MSG_WARNING(" LAr HitFloat container not found for signal event key " << hit_container.key());
617 }
618 }
619 }
620 }
621 else {
622 auto hitVectorHandles = m_hitContainerKeys.makeHandles(ctx);
623 for (auto & hit_container : hitVectorHandles) {
624 if (hit_container.isValid()) {
625 for (const LArHit* hit : *hit_container)
626 {
627 Identifier cellId = hit->cellID();
628 float energy = (float) hit->energy();
629 float time;
630 if (m_ignoreTime) time=0.;
631 else time = (float) (hit->time() - data.m_trigtime);
632 time = time + bunchTime;
633 if (this->AddHit(cellId,energy,time,isSignal,data).isFailure()) return StatusCode::FAILURE;
634 }
635 }
636 else {
637 if (isSignal) {
638 ATH_MSG_WARNING(" LAr Hit container not found for signal event key " << hit_container.key());
639 }
640 }
641 }
642 } // end loop over containers
643
644 return StatusCode::SUCCESS;
645}
646
647// ============================================================================================
648StatusCode LArPileUpTool::fillMapFromHit(SubEventIterator iEvt, float bunchTime, bool isSignal, perEventData_t& data) const
649{
650 for (const std::string& containerName : m_hitContainerNames) {
651
652 //
653 // ..... Get the pointer to the Hit Container from StoreGate through the merge service
654 //
655
656 ATH_MSG_DEBUG(" fillMapFromHit: asking for: " << containerName);
657
658 if (m_useLArHitFloat) {
659
660 const LArHitFloatContainer * hit_container;
661
662 if (!(m_mergeSvc->retrieveSingleSubEvtData(containerName, hit_container, bunchTime,
663 iEvt).isSuccess())){
664 ATH_MSG_ERROR(" LAr Hit container not found for event key " << containerName);
665 return StatusCode::FAILURE;
666 }
667
668 for (const LArHitFloat& hit : *hit_container){
669
670 Identifier cellId = hit.cellID();
671 float energy = (float) hit.energy();
672 float time;
673 if (m_ignoreTime) time=0.;
674 else time = (float) (hit.time() - data.m_trigtime);
675 time = time + bunchTime;
676
677 if (this->AddHit(cellId,energy,time,isSignal,data).isFailure()) return StatusCode::FAILURE;
678 }
679 }
680 else {
681
682 const LArHitContainer * hit_container;
683
684 if (!(m_mergeSvc->retrieveSingleSubEvtData(containerName, hit_container, bunchTime,
685 iEvt).isSuccess())){
686 ATH_MSG_ERROR(" LAr Hit container not found for event key " << containerName);
687 return StatusCode::FAILURE;
688 }
689
691 for(hititer=hit_container->begin();
692 hititer != hit_container->end();++hititer)
693 {
694 Identifier cellId = (*hititer)->cellID();
695 float energy = (float) (*hititer)->energy();
696 float time;
697 if (m_ignoreTime) time=0.;
698 else time = (float) ((*hititer)->time() - data.m_trigtime);
699 time = time + bunchTime;
700
701 if (this->AddHit(cellId,energy,time,isSignal,data).isFailure()) return StatusCode::FAILURE;
702 }
703 }
704 } // end loop over containers
705
706 return StatusCode::SUCCESS;
707}
708
709// ----------------------------------------------------------------------------------------------------------------------
710
711StatusCode LArPileUpTool::AddHit(const Identifier cellId, const float energy, const float time, const bool isSignal, perEventData_t& data) const
712{
713
714 // remove pathological energies...
715 if (std::fabs(energy)>1e+9) {
716 ATH_MSG_WARNING(" Pathological energy ignored Id= "<< m_larem_id->show_to_string(cellId) << " energy= " << energy );
717 return StatusCode::SUCCESS;
718 }
719
720#ifndef NDEBUG
721 ATH_MSG_DEBUG(" Found hit Id= "<< m_larem_id->show_to_string(cellId)<< " energy= " << energy << "(MeV) time= " << time << "(ns)");
722#endif
723
724 IdentifierHash idHash=m_calocell_id->calo_cell_hash(cellId);
725
726// simulation of cross talk if requested (EM barrel + EndCap)
727 if (m_CrossTalk && isSignal && m_calocell_id->is_em(cellId))
728 {
729 std::vector<IdentifierHash> neighbourList;
730 std::vector<float> energyList;
731 //bool dump=false;
732 //if (energy>200. || m_larem_id->sampling(cellId)==3) dump=true;
733 //if(dump) std::cout << " Input cell energy " << m_larem_id->show_to_string(cellId) << " " << energy << std::endl;
734 this->cross_talk(idHash,cellId,energy, //FIXME -> Needs to work with full hash!
735 neighbourList,energyList, *data.m_weights);
736 //if(dump) std::cout <<" After cross-talk " ;
737 for (unsigned int icell=0;icell<neighbourList.size();icell++)
738 {
739 //unsigned int index=neighbourList[icell];
740 //Turn sub-calo hash in neighbour list into global calo-cell hash:
741 const auto subCalo = m_calocell_id->sub_calo(cellId);
742 if (subCalo == CaloCell_Base_ID::NOT_VALID){
743 ATH_MSG_ERROR("subCalo value is invalid in LArPileUpTool::AddHit");
744 return StatusCode::FAILURE;
745 }
746 const IdentifierHash index=m_calocell_id->calo_cell_hash(subCalo,neighbourList[icell]);
747 float e = energyList[icell];
748 //Identifier id2=m_larem_id->channel_id(neighbourList[icell]);
749 //if(dump) std::cout << "Cell/E " << m_larem_id->show_to_string(id2) << " " << e << " ";
750 if ( !data.m_hitmap->AddEnergy(index,e,time) )
751 {
752 ATH_MSG_ERROR(" Cell " << m_larem_id->show_to_string(cellId) << " could not add the energy= " << energy << " (GeV)");
753 return(StatusCode::FAILURE);
754 }
755 if ( m_doDigiTruth){
756 if(!data.m_hitmap_DigiHSTruth->AddEnergy(index,e,time) ) {
757 ATH_MSG_ERROR(" Cell " << m_larem_id->show_to_string(cellId) << " could not add the energy= " << energy << " (GeV)");
758 return(StatusCode::FAILURE);
759 }
760 }
761 }
762 //if (dump) std::cout << std::endl;
763 }
764 else // no cross-talk simulated
765 {
766 if (isSignal || m_useMBTime)
767 {
768 if ( !data.m_hitmap->AddEnergy(idHash,energy,time) )
769 {
770 ATH_MSG_ERROR(" Cell " << m_larem_id->show_to_string(cellId) << " could not add the energy= " << energy << " (GeV)");
771 return(StatusCode::FAILURE);
772 }
773 if ( m_doDigiTruth){
774 if(!data.m_hitmap_DigiHSTruth->AddEnergy(idHash,energy,time) ) {
775 ATH_MSG_ERROR(" Cell " << m_larem_id->show_to_string(cellId) << " could not add the energy= " << energy << " (GeV)");
776 return(StatusCode::FAILURE);
777 }
778 }
779 }
780 else
781 {
782 if (idHash<data.m_energySum.size()) data.m_energySum[idHash] += energy;
783 }
784 } // end if cross-talk
785 return StatusCode::SUCCESS;
786}
787
788// -------------------------------------------------------------------------------------------------------------------------------------
789
791 const Identifier& cellId,
792 const float& energy,
793 std::vector<IdentifierHash>& neighbourList,
794 std::vector<float>& energyList,
795 const LArXTalkWeightGlobal& weights) const
796{
797 neighbourList.clear();
798 energyList.clear();
799 int result=0;
800 neighbourList.reserve(8);
801 energyList.reserve(8);
802
803
804 int ibec = abs(m_larem_id->barrel_ec(cellId)); // 1 barrel 2 EC OW 3 EC IW
805 int sampling = m_larem_id->sampling(cellId);
806 int eta = m_larem_id->eta(cellId);
807 int region = m_larem_id->region(cellId);
808 float fcr=0,e,er;
809 float fcr2=0.;
810 std::vector<IdentifierHash> tmpList;
811
812 er=energy; // total energy of hit to be spread among channels
813
814// cross-talk in strips
815 if ((ibec==1 && sampling == 1 && region == 0)
816 || (ibec==2 && sampling ==1) )
817 {
818
819 if (ibec==1) fcr2 = weights.get_xtalk(LArXTalkWeightGlobal::TWOSTRIP,eta);
820 if (ibec==2) fcr2 = weights.get_xtalk(LArXTalkWeightGlobal::TWOSTRIP_EC,region,eta);
821
822// next in eta
823 if ( (ibec==1 && eta !=447) || (ibec==2 && (eta!=3 || region !=5)) )
824 {
825 result=m_larem_id->get_neighbours(hashId,
827 if(ibec==1) fcr = weights.get_xtalk(LArXTalkWeightGlobal::STRIP,eta+1)*m_scaleStripXtalk;
828 if(ibec==2) fcr = weights.get_xtalk(LArXTalkWeightGlobal::STRIP_EC,region,eta+1)*m_scaleStripXtalk;
829
830 if (result==0) {
831 if (tmpList.size() == 1) {
832 e=energy*fcr;
833 er=er-e;
834 neighbourList.push_back(tmpList[0]);
835 energyList.push_back(e);
836
837// second neighbor cross-talk
838 if (( (ibec==1 && eta !=446)
839 ||(ibec==2 && (eta!=2 || region !=5)) ) && m_CrossTalk2Strip) {
840 std::vector<IdentifierHash> tmpList2;
841 result = m_larem_id->get_neighbours(tmpList[0],LArNeighbours::nextInEta,tmpList2);
842 if (result==0) {
843 if (tmpList2.size()==1) {
844 e=energy*fcr2;
845 er=er-e;
846 neighbourList.push_back(tmpList2[0]);
847 energyList.push_back(e);
848 }
849 }
850 }
851
852 }
853 }
854 }
855// prev in eta (if possible)
856 if ( (ibec==1 && eta >1) || (ibec==2 && (eta !=0 || region !=0)) )
857 {
858 result=m_larem_id->get_neighbours(hashId,
860 if(ibec==1) fcr = weights.get_xtalk(LArXTalkWeightGlobal::STRIP,eta)*m_scaleStripXtalk;
861 if(ibec==2) fcr = weights.get_xtalk(LArXTalkWeightGlobal::STRIP_EC,region,eta)*m_scaleStripXtalk;
862 if (result==0 ) {
863 if (tmpList.size() == 1) {
864 e=energy*fcr;
865 er=er-e;
866 neighbourList.push_back(tmpList[0]);
867 energyList.push_back(e);
868
869// second neighbor cross-talk
870 if (( (ibec==1 && eta !=2)
871 ||(ibec==2 && (eta!=1 || region !=0)) ) && m_CrossTalk2Strip) {
872 std::vector<IdentifierHash> tmpList2;
873 result = m_larem_id->get_neighbours(tmpList[0],LArNeighbours::prevInEta,tmpList2);
874 if (result==0) {
875 if (tmpList2.size()==1) {
876 e=energy*fcr2;
877 er=er-e;
878 neighbourList.push_back(tmpList2[0]);
879 energyList.push_back(e);
880 }
881 }
882 }
883
884 }
885 }
886 }
887 }
888
889// cross-talk strip to middle
891 if ((ibec==1 && sampling==1 && region==0)
892 || (ibec==2 && sampling==1) )
893 {
895 if (ibec==2) fcr = weights.get_xtalk(LArXTalkWeightGlobal::STRIPMIDDLE_EC,region,eta)*m_scaleStripMiddle;
896
897 if (ibec==1) fcr = fcr*2.; // 8 strips for 4 middle cells
898 if (ibec==2) {
899 if (region==0) fcr=fcr/4.; // 1 strip for 4 middle cells
900 if (region==1) fcr=fcr/4.; // 1 strip for 4 middle cells
901 if (region==2) fcr=fcr*2.; // 8 strips for 4 middle cells
902 if (region==3) fcr=fcr*1.5; // 6 strips for 4 middle cells
903 // (region 4: 4strips for 4 middle cells)
904 if (region==5) fcr=fcr/4.; // 1 strip for 4 middle cells
905 }
906
907 // next sampling (should have only one cell)
908 result = m_larem_id->get_neighbours(hashId, LArNeighbours::nextInSamp,tmpList);
909 if (result==0) {
910 e=energy*fcr;
911 for (unsigned int ii=0;ii<tmpList.size();ii++) {
912 er = er-e;
913 neighbourList.push_back(tmpList[ii]);
914 energyList.push_back(e);
915 }
916 }
917 }
918
919// cross-talk middle to strip
920 if ((ibec==1 && sampling==2 && region==0)
921 || (ibec==2 && sampling==2) )
922 {
923 // previous sampling, expect 8 channels in middle for barrel, varing number in end-cap
924 result = m_larem_id->get_neighbours(hashId,
926 if (result==0) {
927 for (unsigned int ii=0;ii<tmpList.size();ii++) {
928 Identifier stripId = m_larem_id->channel_id(tmpList[ii]);
929 if (m_larem_id->sampling(stripId)==1) {
930 neighbourList.push_back(tmpList[ii]);
931 int eta2 = m_larem_id->eta(stripId);
932 int region2 = m_larem_id->region(stripId);
933 if (ibec==1) fcr=weights.get_xtalk(LArXTalkWeightGlobal::STRIPMIDDLE,eta2)*m_scaleStripMiddle;
934 if (ibec==2) fcr=weights.get_xtalk(LArXTalkWeightGlobal::STRIPMIDDLE_EC,region2,eta2)*m_scaleStripMiddle;
935 e=energy*fcr;
936 er=er-e;
937 energyList.push_back(e);
938 }
939 }
940 }
941 }
942 } // strip middle crosstalk
943
944// cross-talk middle to middle
945 if (m_CrossTalkMiddle) {
946 if ((ibec==1 && sampling==2 && region==0 ) ||
947 (ibec==2 && sampling==2 && region==1)) {
948
949 // fmiddle1 crosstalk to eta-1
950 // fmiddle2 crosstalk to eta+1
951 float fmiddle1=0.;
952 float fmiddle2=0.;
953 if (ibec==1) {
956 }
957 if (ibec==2) {
960 }
961
962 // next in eta
963 if ( (ibec==1 && eta<55) || (ibec==2 && eta <42) ) {
964 result=m_larem_id->get_neighbours(hashId,
966 if (result==0) {
967 if (tmpList.size() == 1) {
968 e=energy*fmiddle2;
969 er=er-e;
970 neighbourList.push_back(tmpList[0]);
971 energyList.push_back(e);
972 }
973 }
974 }
975 // previous in eta
976 if ( (ibec==1 && eta>0) || (ibec==2 && eta >0) ) {
977 result=m_larem_id->get_neighbours(hashId,
979 if (result==0) {
980 if (tmpList.size() == 1) {
981 e=energy*fmiddle1;
982 er=er-e;
983 neighbourList.push_back(tmpList[0]);
984 energyList.push_back(e);
985 }
986 }
987 }
988 }
989 }
990
991// cross-talk in middle to back
992 if ( (ibec==1 && sampling ==2 && region == 0 )
993 || (ibec==2 && sampling ==2 && region ==1 && eta > 2) // no sampling 3 before 1.5
994 || (ibec==3 && sampling ==1) ) // inner wheel
995 {
996 if (ibec==1) {
998 } else if(ibec==2) {
1000 } else if(ibec==3) {
1001 fcr = weights.get_xtalk(LArXTalkWeightGlobal::MIDDLEBACK_ECIW,eta); // same size of middle and back in IW
1002 }
1003// next sampling
1004 result=m_larem_id->get_neighbours(hashId,
1006 if (result==0) {
1007 if (tmpList.size() == 1) {
1008 e=energy*fcr;
1009 er=er-e;
1010 neighbourList.push_back(tmpList[0]);
1011 energyList.push_back(e);
1012 }
1013 }
1014 }
1015
1016// cross-talk back to middle
1017 if ( (ibec==1 && sampling == 3 && region == 0 )
1018 ||(ibec==2 && sampling ==3)
1019 ||(ibec==3 && sampling ==2) )
1020 {
1021 if (ibec==1) {
1022 // eta2 = eta for middle layer cells
1023 int eta2=2*eta;
1024 fcr=0.5*(weights.get_xtalk(LArXTalkWeightGlobal::MIDDLEBACK,eta2)+weights.get_xtalk(LArXTalkWeightGlobal::MIDDLEBACK,eta2+1));
1025 } else if(ibec==2) {
1026 int eta2=3+2*eta;
1028 } else if(ibec==3) {
1030 }
1031// previous sampling, expect two channels in middle for barrel + OW, one for IW
1032 result = m_larem_id->get_neighbours(hashId,
1034 if (result==0) {
1035 if ((ibec==1 || ibec==2) && tmpList.size() == 2) {
1036 fcr=fcr/2.;
1037 e=energy*fcr;
1038 er=er-2.*e;
1039 neighbourList.push_back(tmpList[0]);
1040 neighbourList.push_back(tmpList[1]);
1041 energyList.push_back(e);
1042 energyList.push_back(e);
1043 }
1044 if (ibec==1 && tmpList.size()==1) {
1045 e=energy*fcr;
1046 er=er-e;
1047 neighbourList.push_back(tmpList[0]);
1048 energyList.push_back(e);
1049 }
1050 if (ibec==3 && tmpList.size() ==1) {
1051 e=energy*fcr;
1052 er=er-e;
1053 neighbourList.push_back(tmpList[0]);
1054 energyList.push_back(e);
1055 }
1056 }
1057 }
1058
1059// remaining energy in original cell
1060 neighbourList.push_back(hashId);
1061 energyList.push_back(er);
1062
1063}
1064
1065// ----------------------------------------------------------------------------------------------------------------------------------
1066
1067
1068//
1069// take accumulated energy in cell vector for a given bunch time and push that in the hit map
1070
1072
1073 for (unsigned int i=0;i<data.m_energySum.size();i++) {
1074 float e = data.m_energySum[i];
1075 if (e>1e-6) {
1076 if (!data.m_hitmap->AddEnergy(i,e,bunchTime)) return false;
1077 }
1078 data.m_energySum[i]=0.;
1079 }
1080 if(m_doDigiTruth){
1081 for (unsigned int i=0;i<data.m_energySum_DigiHSTruth.size();i++) {
1082 float e = data.m_energySum_DigiHSTruth[i];
1083 if (e>1e-6) {
1084 if (!data.m_hitmap_DigiHSTruth->AddEnergy(i,e,bunchTime)) return false;
1085 }
1086 data.m_energySum_DigiHSTruth[i]=0.;
1087 }
1088 }
1089
1090 return true;
1091}
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
std::vector< xAOD::EventInfo::SubEvent >::const_iterator SubEventIterator
Definition IPileUpTool.h:22
interface to a tool that returns the time offset of the current trigger.
static Double_t sc
A wrapper class for event-slot-local random engines.
Definition RNGWrapper.h:56
SeedingOptionType
Options for seeding option=0 is setSeed as in MC20 option=1 is setSeedLegacy as in MC16 option=2 is s...
Definition RNGWrapper.h:97
void setSeedLegacy(const std::string &algName, size_t slot, uint64_t ev, uint64_t run, uint64_t offset, SeedingOptionType seeding, EventContext::ContextEvt_t evt=EventContext::INVALID_CONTEXT_EVT)
Set the random seed using a string (e.g.
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:134
boost::transform_iterator< make_const, typename CONT::const_iterator > const_iterator
const_iterator end() const
const_iterator begin() const
This class provides the client interface for accessing the detector description information common to...
This class initializes the Calo (LAr and Tile) offline identifiers.
const LArHEC_ID * getHEC_ID(void) const
const LArFCAL_ID * getFCAL_ID(void) const
const LArEM_ID * getEM_ID(void) const
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
This is a "hash" representation of an Identifier.
Container class for LArDigit.
Liquid Argon digit base class.
Definition LArDigit.h:25
Hit collection.
Container for LArHitFloat.
Class to store hit energy and time in LAr cell from G4 simulation.
Definition LArHitFloat.h:18
Class to store hit energy and time in LAr cell from G4 simulation.
Definition LArHit.h:25
Gaudi::Property< bool > m_NoiseOnOff
Gaudi::Property< bool > m_useLArHitFloat
Gaudi::Property< bool > m_CrossTalkMiddle
Gaudi::Property< float > m_scaleStripMiddle
Gaudi::Property< bool > m_useMBTime
Gaudi::Property< float > m_WindowsPhiSize
Gaudi::Property< bool > m_CrossTalk2Strip
const CaloCell_ID * m_calocell_id
virtual StatusCode initialize() override final
const LArFCAL_ID * m_larfcal_id
std::vector< std::string > m_hitContainerNames
Gaudi::Property< bool > m_ignoreTime
Gaudi::Property< float > m_phaseMin
SG::ReadHandleKey< CosTrigTime > m_timeKey
SG::WriteHandleKey< LArHitEMap > m_hitMapKey_DigiHSTruth
Gaudi::Property< bool > m_isMcOverlay
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKey
Gaudi::Property< bool > m_NoiseInEMB
Gaudi::Property< bool > m_CrossTalkStripMiddle
Gaudi::Property< bool > m_NoiseInEMEC
Gaudi::Property< float > m_WindowsEtaSize
Gaudi::Property< bool > m_doDigiTruth
bool fillMapfromSum(float bunchTime, perEventData_t &data) const
SG::ReadHandleKeyArray< LArHitFloatContainer > m_hitFloatContainerKeys
Gaudi::Property< bool > m_NoiseInFCAL
Gaudi::Property< float > m_scaleStripXtalk
Gaudi::Property< float > m_WindowsPtCut
Gaudi::Property< bool > m_RndmEvtOverlay
LArPileUpTool(const std::string &type, const std::string &name, const IInterface *parent)
SG::ReadHandleKey< LArDigitContainer > m_inputDigitContainerKey
StringArrayProperty m_inputKeys
Gaudi::Property< float > m_phaseMax
StatusCode fillMapFromHit(const EventContext &ctx, float tbunch, bool isSignal, perEventData_t &data) const
SG::ReadHandleKey< McEventCollection > m_mcEventColl
ServiceHandle< PileUpMergeSvc > m_mergeSvc
Gaudi::Property< bool > m_addPhase
virtual StatusCode processAllSubEvents(const EventContext &ctx) override final
SG::ReadCondHandleKey< CaloDetDescrManager > m_caloMgrKey
Gaudi::Property< uint32_t > m_randomSeedOffset
virtual StatusCode prepareEvent(const EventContext &ctx, unsigned int nInputEvents) override final
Gaudi::Property< bool > m_useLegacyRandomSeeds
const LArOnlineID * m_laronline_id
SG::ReadCondHandleKey< LArXTalkWeightGlobal > m_xtalkKey
StatusCode AddHit(const Identifier cellId, const float energy, const float time, const bool iSignal, perEventData_t &data) const
void cross_talk(const IdentifierHash &idHash, const Identifier &cellId, const float &energy, std::vector< IdentifierHash > &neighbourList, std::vector< float > &energyList, const LArXTalkWeightGlobal &weights) const
Gaudi::Property< bool > m_onlyUseContainerName
Gaudi::Property< bool > m_useTriggerTime
const LArEM_ID * m_larem_id
Gaudi::Property< bool > m_PileUp
SG::WriteHandleKey< LArHitEMap > m_hitMapKey
Gaudi::Property< bool > m_NoiseInHEC
Gaudi::Property< float > m_scaleMiddleXtalk
const LArHEC_ID * m_larhec_id
SG::ReadHandleKeyArray< LArHitContainer > m_hitContainerKeys
ServiceHandle< IAthRNGSvc > m_rndmGenSvc
virtual StatusCode processBunchXing(int bunchXing, SubEventIterator bSubEvents, SubEventIterator eSubEvents) override final
perEventData_t m_data
Gaudi::Property< bool > m_Windows
Gaudi::Property< bool > m_CrossTalk
Gaudi::Property< std::string > m_randomStreamName
This defines the McEventCollection, which is really just an ObjectVector of McEvent objectsFile: Gene...
PileUpToolBase(const std::string &type, const std::string &name, const IInterface *parent)
const_pointer_type cptr()
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
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.
pointer_type ptr()
Dereference the pointer.
@ Signal
The signal event.
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Definition index.py:1
std::list< value_t > type
type of the collection of timed data object
a struct encapsulating the identifier of a pile-up event
time_type time() const
bunch xing time in ns