ATLAS Offline Software
Loading...
Searching...
No Matches
CaloCellPacker_400_500.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
11
12
14#include "CaloCompactCellTool.h"
17#include "CaloEvent/CaloCell.h"
18#include "TileEvent/TileCell.h"
23#include "GaudiKernel/SystemOfUnits.h"
24
28
29//============================================================================
30// Common methods.
31//
32
33
41 int version) const
42{
43 header.m_version = version;
44 switch (version) {
49 header.m_length = sizeof(header501)/sizeof(int);
50 break;
51
53 header.m_length = sizeof(header500)/sizeof(int);
54 break;
56 header.m_length = sizeof(header400)/sizeof(int);
57 break;
58 default:
59 std::abort();
60 }
61
62 header.m_qualy_mask = 0x8000;
63 header.m_egain_mask = 0x6000;
64 header.m_esign_mask = 0x1000;
65 // 12 bits for cbrt(|E|) and 2 ranges, one normal
66 // resolution range with upper limit 3.2 TeV and precision loss
67 // sigma_E'/E < 1.4%/sqrt(E/GeV) and one high-resolution range used
68 // whenever E < 50 GeV and the hardware gain is HIGH (HEC: MEDIUM)
69 // resulting in a precision loss of sigma_E'/E < 0.15%/sqrt(E/GeV)
70 header.m_crtae_mask = 0x0fff;
71 header.m_egain_tile_mask = 0x4000;
72 header.m_esign_tile_mask = 0x2000;
73 // 13 bits cbrt(|E|) and 2 ranges
74 // upper limit for low gain is 3.2 TeV,
75 // upper limit for high gain is 50 GeV (safety factor of ~3)
76 header.m_crtae_tile_mask = 0x1fff;
77 header.m_tsign_mask = 0x8000;
78 header.m_logat_mask = 0x7fff;
79
80 header.m_qabad = 0;
81 header.m_enlow = 0; // normal resolution LOW gain
82 header.m_enmed = 1; // normal resolution MEDIUM gain
83 header.m_enhig = 2; // normal resolution HIGH gain
84 header.m_ehhig = 3; // high resolution HIGH (HEC: MEDIUM) gain
85 header.m_glow = TileID::LOWGAIN;
86 header.m_ghigh = TileID::HIGHGAIN;
87
88 header.m_e1_norm_res = 3.2*Gaudi::Units::TeV;
89 header.m_e1_high_res = 50*Gaudi::Units::GeV;
90 header.m_high_tile = 50*Gaudi::Units::GeV;
91 header.m_low_tile = 3.2*Gaudi::Units::TeV;
92 header.m_t0 = 0.001*Gaudi::Units::ns;
93 header.m_t1 = 1250.0*Gaudi::Units::ns;
94
96}
97
98
104{
105 header.m_ncells_larem = 0;
106 header.m_ncells_larhec = 0;
107 header.m_ncells_larfcal = 0;
108 header.m_ncells_tile = 0;
109 header.m_seq_larem = 0;
110 header.m_seq_larhec = 0;
111 header.m_seq_larfcal = 0;
112 header.m_seq_tile = 0;
113 header.m_lengthProvenance = 0;
114 header.m_status = 0;
115}
116
117
124{
125 // Good quality flag.
126 pars.m_qgood = 1;
127
128 // Set up parameters for packing/unpacking the sequence header.
129 pars.m_hash_field = CaloCellPackerUtils::Bitfield (0x0003ffff);
130 pars.m_nseq_field = CaloCellPackerUtils::Bitfield (0xfffc0000);
131 pars.m_nseq_max = 0x3fff;
132
133 // Set up parameters for packing/unpacking the provenance list.
134 pars.m_prov_field = CaloCellPackerUtils::Bitfield (0xfff80000);
135 pars.m_prov_max = 0x1fff;
136 pars.m_prov_max_tile = 0x1f1f;
137
138 // Cube roots of energy ranges.
139 pars.m_cbrt_e1_norm_res = cbrt(static_cast<double>(pars.m_e1_norm_res));
140 pars.m_cbrt_e1_high_res = cbrt(static_cast<double>(pars.m_e1_high_res));
141 pars.m_cbrt_low_tile = cbrt(static_cast<double>(pars.m_low_tile));
142 pars.m_cbrt_high_tile = cbrt(static_cast<double>(pars.m_high_tile));
143
144 // Logarithms of time ranges.
145 pars.m_log_t0 = log(static_cast<double>(pars.m_t0));
146 pars.m_log_t1 = log(static_cast<double>(pars.m_t1));
147
148 // Fill in remaining bit fields.
149 pars.m_qualy_field = CaloCellPackerUtils::Bitfield (pars.m_qualy_mask);
150 pars.m_egain_field = CaloCellPackerUtils::Bitfield (pars.m_egain_mask);
151 pars.m_crtae_norm_field =
152 CaloCellPackerUtils::Floatfield2 (pars.m_crtae_mask,
153 pars.m_cbrt_e1_norm_res);
154 pars.m_crtae_high_field =
155 CaloCellPackerUtils::Floatfield2 (pars.m_crtae_mask,
156 pars.m_cbrt_e1_high_res);
157 pars.m_logat_field =
158 CaloCellPackerUtils::Floatfield (pars.m_logat_mask,
159 pars.m_log_t0, pars.m_log_t1);
160 pars.m_egain_tile_field =
161 CaloCellPackerUtils::Bitfield (pars.m_egain_tile_mask);
162 pars.m_crtae_tile_high_field =
163 CaloCellPackerUtils::Floatfield2 (pars.m_crtae_tile_mask,
164 pars.m_cbrt_high_tile);
165 pars.m_crtae_tile_low_field =
166 CaloCellPackerUtils::Floatfield2 (pars.m_crtae_tile_mask,
167 pars.m_cbrt_low_tile);
168
169 pars.m_tile_qual1_field = CaloCellPackerUtils::Bitfield (0x00ff);
170 pars.m_tile_qual2_field = CaloCellPackerUtils::Bitfield (0xff00);
171
172 // Dummy flags.
173 pars.m_lar_dummy =
174 pars.m_egain_field.in (pars.m_enhig) |
175 pars.m_qualy_field.in (pars.m_qabad) |
176 pars.m_crtae_norm_field.in (cbrt (pars.m_e1_norm_res)) |
177 pars.m_esign_mask;
178
179 pars.m_tile_dummy =
180 pars.m_egain_tile_field.in (pars.m_glow) |
181 pars.m_qualy_field.in (pars.m_qabad) |
182 pars.m_crtae_tile_high_field.in (pars.m_cbrt_high_tile) |
183 pars.m_esign_tile_mask;
184
185
186 {
187 CaloCellPackerUtils::Bitfield& elar = pars.m_crtae_norm_field;
188 pars.m_lar_dummy_subst = (pars.m_lar_dummy & ~pars.m_crtae_mask) |
189 elar.in (elar.out (pars.m_lar_dummy)-1);
190
191 CaloCellPackerUtils::Bitfield& etile = pars.m_crtae_tile_high_field;
192 pars.m_tile_dummy_subst = (pars.m_tile_dummy & ~pars.m_crtae_tile_mask) |
193 etile.in (etile.out (pars.m_tile_dummy)-1);
194 }
195}
196
197
198//============================================================================
199// Packing.
200// To ensure full inlining, don't reorder these.
201//
202
203
210inline
212 (float time,
214 const pars500& pars) const
215{
216 // We want to pack log(abs(time)).
217 float ltime = pars.m_log_t0;
218 if (time != 0)
219 ltime = log(fabs(time));
220
221 // Pack it into the bitfield.
222 CaloCompactCell::value_type data = pars.m_logat_field.in (ltime);
223
224 // Set the sign bit.
225 // Only set the sign bit if saved value is non-zero.
226 // Otherwise, it'll be read as zero regardless, and if we write
227 // again, the sign bit'll be different.
228 if ( time < 0 && data != 0 )
229 data |= pars.m_tsign_mask;
230
231 // Fill output.
232 it.set (data);
233}
234
235
243inline
245 (const CaloCell* cell,
246 CaloCell_ID::SUBCALO subcalo,
248 const pars500& pars) const
249{
250 // Get values from the cell.
251 double energy = cell->energy();
252 double time = cell->time();
253 int qualflag;
254 if( (cell->provenance() & 0x2000) == 0x2000 )
255 qualflag=pars.m_qgood;
256 else
257 qualflag=pars.m_qabad;
258
259 int gain = cell->gain();
260
261 // Figure out which gain to use.
262 // cbrt_flag is set to 1 for the high gain range (50 GeV) and 0 for
263 // the low gain range (3.2 TeV).
264 int gainflag = -999;
265 int cbrt_flag = 0;
266 switch ( gain ) {
268 gainflag = pars.m_enlow;
269 break;
271 if ( subcalo == CaloCell_ID::LARHEC &&
272 fabs(energy) < pars.m_e1_high_res )
273 {
274 gainflag = pars.m_ehhig;
275 cbrt_flag = 1;
276 }
277 else
278 gainflag = pars.m_enmed;
279 break;
281 if ( fabs(energy) < pars.m_e1_high_res &&
282 subcalo != CaloCell_ID::LARHEC )
283 {
284 gainflag = pars.m_ehhig;
285 cbrt_flag = 1;
286 }
287 else
288 gainflag = pars.m_enhig;
289 break;
290
291 default:
292 // Some invalid gain. Mark as an error.
293 gainflag = -999;
294 }
295
296 if (gainflag == -999) {
297 it.set (pars.m_lar_dummy);
298 }
299 else {
300 // Pack the energy, gain, and quality into the output word.
301 double crtae = cbrt(fabs(energy));
303 (cbrt_flag ? pars.m_crtae_high_field.in (crtae)
304 : pars.m_crtae_norm_field.in (crtae));
305
306 // Set the sign bit.
307 // Only set the sign bit if saved value is non-zero.
308 // Otherwise, it'll be read as zero regardless, and if we write
309 // again, the sign bit'll be different.
310 if (energy < 0 && data != 0)
311 data |= pars.m_esign_mask;
312
313 data |= pars.m_egain_field.in (gainflag) |
314 pars.m_qualy_field.in (qualflag);
315
316 if (data == pars.m_lar_dummy)
317 data = pars.m_lar_dummy_subst;
318
319 // Fill the output container.
320 it.set (data);
321
322 // If quality is not bad there are time and quality (chi^2) measurements.
323 if ( qualflag != pars.m_qabad){
324 pack_time (time, it, pars);
325 if (pars.m_version >= 500)
326 it.set(cell->quality());
327 }
328 }
329}
330
331
338inline
340 (const TileCell* cell,
342 const pars500& pars) const
343{
344 // Tile cells have two separate measurements to pack.
345 // Retrieve them both:
346 double ene[2] = {cell->ene1(), cell->ene2()};
347 double time[2] = {cell->time1(), cell->time2()};
348 int qbit[2] = {cell->qbit1(), cell->qbit2()};
349 int gain[2] = {cell->gain1(), cell->gain2()};
350
351 // Loop over the two measurements (PMTs).
352 // If no cell both gains are bad;
353 // if only one pmt per cell, second gain is bad.
354 bool write_qual = false;
355 for (int ipmt=0; ipmt<2; ++ipmt) {
356 // We'll set this to true if we want to write time information.
357 bool write_time = false;
358
359 // The data word we're building.
361
362 // Does this measurement exist?
363 if (gain[ipmt] == CaloGain::INVALIDGAIN) {
364 // No --- make a dummy.
365 data = pars.m_tile_dummy;
366 }
367 else {
368 // Yes --- we have a measurement. See if the quality's good.
369 // If so, then we'll want to write the time too.
370 int qualflag = pars.m_qabad;
371 if (qbit[ipmt] >= TileCell::KEEP_TIME) {
372 qualflag = pars.m_qgood;
373 write_time = true;
374 write_qual = true;
375 }
376
377 // Pack the energy, with the proper range, depending on the gain.
378 double crtae = cbrt(fabs(ene[ipmt]));
379 if (gain[ipmt] != pars.m_glow)
380 data = pars.m_crtae_tile_high_field.in (crtae);
381 else
382 data = pars.m_crtae_tile_low_field.in (crtae);
383
384 // Add the sign bit.
385 // Only set the sign bit if saved value is non-zero.
386 // Otherwise, it'll be read as zero regardless, and if we write
387 // again, the sign bit'll be different.
388 if (ene[ipmt] < 0 && data != 0)
389 data |= pars.m_esign_tile_mask;
390
391 // Add in the gain and quality.
392 data |=
393 pars.m_egain_tile_field.in (gain[ipmt]) |
394 pars.m_qualy_field.in (qualflag);
395
396 if (data == pars.m_tile_dummy)
397 data = pars.m_tile_dummy_subst;
398 }
399
400 // Fill to the output container.
401 it.set (data);
402
403 // Fill the time and quality, if needed.
404 if (write_time)
405 pack_time (time[ipmt], it, pars);
406 }
407
408 if (pars.m_version >= 502 && write_qual) {
409 it.set (cell->quality());
410 }
411}
412
413
422inline
424 (unsigned int hash,
425 unsigned int nseq,
427 CaloCell_ID::SUBCALO subcalo,
428 pars500& pars) const
429{
430 // Pack the hash code and number of cells into a bitfield.
432 pars.m_hash_field.in(hash) | pars.m_nseq_field.in(nseq);
433
434 // Write it into the output container.
435 it.set ((data>>16) & 0xffff);
436 it.set (data & 0xffff);
437
438 // Update counters.
439 switch (subcalo) {
441 pars.m_ncells_larem += nseq;
442 ++pars.m_seq_larem;
443 break;
445 pars.m_ncells_larhec += nseq;
446 ++pars.m_seq_larhec;
447 break;
449 pars.m_ncells_larfcal += nseq;
450 ++pars.m_seq_larfcal;
451 break;
453 pars.m_ncells_tile += nseq;
454 ++pars.m_seq_tile;
455 break;
456 default:
457 std::abort();
458 }
459}
460
461
471 const SG::ThinningDecisionBase* dec,
472 int version) const
473{
474 // Set up the header and derived parameters.
475 pars500 pars;
476 init_header (pars, version);
477 init_derived (pars);
478
479 std::vector<short unsigned int> vProvenance;
480
481 // Figure out an upper limit for the container size.
482 // Header, plus one word/cell for sequence, two words/cell for data,
483 // and another word/cell for provenance.
484 // Tile cells have two additional words/cell - energy and time for second PMT.
485 // Add one more to account for possible padding before the provenance info.
486 // We'll resize this down correctly when we're done.
487 unsigned int maxsize =
488 pars.m_length + 4 * cells.size() + 2 * cells.nCellsCalo (CaloCell_ID::TILE)+1;
489 packed.resize (maxsize);
490
491 // Set up for loop over cells.
492
493 // This is the output iterator, to which we write.
495 (packed.compact_begin_output (pars.m_length));
496
497 // Here we save the output iterator at the beginning of each sequence.
498 // We'll use that to go back and plug in the count when we're done.
500 (packed.compact_begin_output (pars.m_length));
501
502 // The hash of the first cell in the current sequence.
503 unsigned int seqhash = static_cast<unsigned int> (-1);
504
505 // Number of cells so far in the current sequence.
506 // 0 if not in a sequence.
507 unsigned int nseq = 0;
508
509 // The subcalorimeter code of the previous cell we looked at.
511
512 // If all the cells have provenance 0, there is nothing in the vector.
513 short unsigned int prevCellProvenance=0;
514
515 // check if it is a SuperCell
516 bool is_SC=false;
517 if (cells.size()>0){
518 // assuming no mixed SC and Cells.
519 const CaloDetDescrElement* dde = cells[0]->caloDDE();
520 const CaloCell_Base_ID* idhelper =
521 dde->descriptor()->get_calo_helper();
522 is_SC = idhelper->is_supercell(cells[0]->ID());
523 }
524
525 if (is_SC)
526 pars.m_status |= header::STATUS_IS_SUPERCELL;
527
528 // Loop over input cells.
529 for (size_t icell = 0; const CaloCell* cell : cells)
530 {
531 // Check for thinning.
532 if (dec && dec->thinned (icell++)) {
533 continue;
534 }
535
536 // Pick up values from the cell.
537 const CaloDetDescrElement* dde = cell->caloDDE();
538 unsigned int hash = dde->calo_hash();
539 CaloCell_ID::SUBCALO subcalo = dde->getSubCalo();
540
541 // Test to see if we need to start a new sequence.
542 if (// Not in a sequence now?
543 nseq == 0 ||
544 // We're at the maximum sequence length?
545 nseq >= pars.m_nseq_max ||
546 // A skip in the cell hash codes?
547 seqhash + nseq != hash ||
548 // Moving to a new subcalorimeter?
549 subcalo != prevcalo)
550 {
551 // Mark if cells aren't ordered.
552 if (prevcalo != CaloCell_ID::NOT_VALID &&
553 subcalo < prevcalo)
554 pars.m_status |= header::STATUS_UNORDERED;
555
556 // If we're already in a sequence, need to finish it.
557 if (nseq > 0)
558 finish_seq (seqhash, nseq, seqit, prevcalo, pars);
559
560 // Start a new sequence.
561 nseq = 0;
562 seqhash = hash;
563 prevcalo = subcalo;
564 // Leave space to fill in the hash/count later.
565 seqit = outit;
566 ++outit;
567 ++outit;
568 }
569
570 // Add the current cell on to sequence.
571 if (!is_SC && subcalo == CaloCell_ID::TILE) {
572 pack_tile (static_cast<const TileCell*>(cell), outit, pars);
573
574 // Check to see if the provenance changed.
575 if (version >= 502 &&
576 (cell->provenance() & pars.m_prov_max_tile) != prevCellProvenance)
577 {
578 prevCellProvenance = cell->provenance() & pars.m_prov_max_tile;
580 pars.m_hash_field.in(hash) |
581 pars.m_prov_field.in(prevCellProvenance);
582 vProvenance.push_back ((data>>16) & 0xffff);
583 vProvenance.push_back (data & 0xffff);
584 }
585 }
586 else {
587 pack_lar (cell, subcalo, outit, pars);
588
589 // Check to see if the provenance changed.
590 if (version >= 500 &&
591 (cell->provenance() & pars.m_prov_max) != prevCellProvenance)
592 {
593 prevCellProvenance = cell->provenance() & pars.m_prov_max;
595 pars.m_hash_field.in(hash) |
596 pars.m_prov_field.in(prevCellProvenance);
597 vProvenance.push_back ((data>>16) & 0xffff);
598 vProvenance.push_back (data & 0xffff);
599 }
600 }
601 ++nseq;
602 }
603
604 // Finish the last sequence.
605 if (nseq != 0)
606 finish_seq (seqhash, nseq, seqit, prevcalo, pars);
607
608 pars.m_lengthProvenance = vProvenance.size();
609
610 assert (outit.used() + pars.m_length + vProvenance.size()/2 + 1 <= maxsize);
611
612 if (pars.m_lengthProvenance > 0) {
613 // this part is making existing vector to have full number of 32 bit words.
614 int x=outit.used();
615 // dummy value of 0 is inserted
616 outit.set(0);
617 int y=outit.used();
618 // if size changed it means that vector was flat at the end and that we spoiled it.
619 // so we have to fix it.
620 if (x!=y) outit.set(0);
621 // now its surely flat.
622
623 // add provenance stuff at the end.
624 for (unsigned short & iter : vProvenance)
625 {
626 outit.set (iter);
627 }
628 }
629
630 // Now resize the container to the final size.
631 packed.resize (outit.used() + pars.m_length);
632
633 // And copy the header to the front.
634 write_header (pars, packed);
635}
636
637
643void
645 CaloCompactCellContainer& packed) const
646{
647 const int * phead = &(header.m_length);
648 std::vector<CaloCompactCellContainer::value_type>
649 vhead (phead, phead + header.m_length);
650 packed.setHeader(vhead);
651}
652
653
654
655//============================================================================
656// Unpacking.
657// To ensure full inlining, don't reorder these.
658//
659
660
667inline
670 const pars500& pars) const
671{
672 // Get the word from the input container.
674
675 // Unpack to a float.
676 int underflow;
677 double time = pars.m_logat_field.out (data, underflow);
678 if (ATH_UNLIKELY(underflow))
679 return 0;
680
681 // Exponentiate, and restore the sign.
682 // (nb. introducing `ee' helps the gcc optimizer avoid a redundant
683 // test on the underflow flag.)
684 double ee = std::exp (time);
685 if (data & pars.m_tsign_mask)
686 return -ee;
687 return ee;
688}
689
690
703inline
707 CaloCell_ID::SUBCALO subcalo,
708 LArCell* cell,
709 const pars500& pars,
710 uint16_t provenance) const
711{
712 // Get the data word from the input.
714
715 // Recognize cells filled with dummy values.
716 if (data == pars.m_lar_dummy)
717 {
718 cell->set (0, 0, 0, provenance, CaloGain::INVALIDGAIN);
719 return cell;
720 }
721
722 // Unpack the gain flag.
723 int gainflag = pars.m_egain_field.out (data);
724 int qualflag = pars.m_qualy_field.out (data);
725
727
728 // Convert to the CaloCell gain, and convert the energy back to a float
729 // using the proper range.
730 double energy;
731 if ( gainflag == pars.m_ehhig ) {
732 if ( subcalo == CaloCell_ID::LARHEC )
734 else
736 energy = pars.m_crtae_high_field.out (data);
737 }
738 else {
739 if ( gainflag == pars.m_enhig ) {
741 }
742 else if ( gainflag == pars.m_enmed ) {
744 }
745 else if ( gainflag == pars.m_enlow) {
747 }
748 energy = pars.m_crtae_norm_field.out (data);
749 }
750
751 // Now undo the cube root and apply the sign bit.
752 energy = energy*energy*energy;
753 if (data & pars.m_esign_mask)
754 energy = -energy;
755
756 // If the quality's good, then we need to unpack the time/chi2 too.
757 double time = 0;
758 uint16_t quality=0;
759 if ( qualflag != pars.m_qabad ) {
760 time = unpack_time (it, pars);
761 if (pars.m_version >= 500)
762 quality=it.next();
763 provenance = provenance | 0x2000;
764 }
765
766 // Fill the data into the cell.
767 cell->set (energy, time, quality, provenance, gain);
768
769 // Return it.
770 return cell;
771}
772
773
781inline
784 const CaloDetDescrElement* dde,
785 const pars500& pars,
786 uint16_t provenance) const
787{
788 // Loop over the two elements for the cell.
789 double ene[2];
790 double time[2];
791 int gain[2];
792 int qbit[2];
793
794 bool read_qual = false;
795
796 for (int ipmt = 0; ipmt < 2; ++ipmt) {
797 // Unpack the data word.
799
800 // Is this measurement a dummy?
801 if (data == pars.m_tile_dummy)
802 {
803 // Yeah --- fill in dummy values and skip the rest.
804 ene[ipmt] = 0;
805 gain[ipmt] = CaloGain::INVALIDGAIN;
806 qbit[ipmt] = 0;
807 if (ipmt == 1)
808 time[ipmt] = time[0];
809 else
810 time[ipmt] = 0;
811 continue;
812 }
813
814 // Get the quality and gain.
815 int qualflag = pars.m_qualy_field.out (data);
816 int gainflag = pars.m_egain_tile_field.out (data);
817
818 gain[ipmt] = gainflag;
819
820 // Unpack the energy, using the range appropriate to the gain.
821 double e;
822 if (gainflag != pars.m_glow)
823 e = pars.m_crtae_tile_high_field.out (data);
824 else
825 e = pars.m_crtae_tile_low_field.out (data);
826 ene[ipmt] = e*e*e;
827 if (data & pars.m_esign_tile_mask)
828 ene[ipmt] = -ene[ipmt];
829
830 // If the quality is good, we need to unpack the time too.
831 if (qualflag != pars.m_qabad) {
832 read_qual = true;
833 time[ipmt] = unpack_time (it, pars);
835 }
836 else {
837 time[ipmt] = 0;
838 qbit[ipmt] = TileCell::MASK_CMPC;
839 }
840 }
841
842 uint8_t qual[2];
843 if (pars.m_version >= 502) {
844 qbit[0] |= pars.m_tile_qual1_field.out (provenance);
845 qbit[1] |= pars.m_tile_qual2_field.out (provenance);
846 if (read_qual) {
847 uint16_t qualp = it.next();
848 qual[0] = pars.m_tile_qual1_field.out (qualp);
849 qual[1] = pars.m_tile_qual2_field.out (qualp);
850 } else {
851 qual[0] = ((qbit[0] & TileCell::MASK_BADCH) != 0) ? 255 : 0;
852 qual[1] = ((qbit[1] & TileCell::MASK_BADCH) != 0) ? 255 : 0;
853 }
854 }
855 else {
856 qual[0] = qual[1] = 0;
857 }
858
859 // Make the cell.
860 return TileCell (dde, ene[0], ene[1], time[0], time[1],
861 qual[0], qual[1], qbit[0], qbit[1], gain[0], gain[1]);
862}
863
864
878 (const CaloCompactCellContainer& packed,
879 const std::vector<int>& vheader,
880 CaloCellContainer& cells,
881 DataPool<LArCell>& larpool,
882 DataPool<TileCell>& tilepool) const
883{
884 // Convert the header.
885 pars500 pars;
886 pars.m_status = 0;
887 pars.m_seq_tile = 0;
888 pars.m_seq_larem = 0;
889 pars.m_seq_larhec = 0;
890 pars.m_seq_larfcal = 0;
891 pars.m_lengthProvenance = 0;
892 pars.m_ncells_tile = 0;
893 pars.m_ncells_larhec = 0;
894 pars.m_ncells_larfcal = 0;
895 pars.m_ncells_larem = 0;
896
897 {
898 const int* headerbeg = &*vheader.begin();
899 const int* headerend = headerbeg + vheader.size();
900 size_t nheader = headerend - headerbeg;
901 size_t parsize = sizeof(header) / sizeof(int);
902 size_t ncopy = std::min (nheader, parsize);
903 int* parsbeg = reinterpret_cast<int*>(&pars);
904 std::copy (headerbeg, headerbeg+ncopy, parsbeg);
905 if (nheader > parsize) {
906 // Header was longer than we expected --- there's something
907 // wrong with the data. Issue a warning.
908 REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING,
909 "CaloCellPacker_400_500 ")
910 << "Corrupted data: Compact cell header is "
911 << nheader << " words long, longer than the largest expected value of "
912 << parsize << ".";
913 }
914 else if (ncopy < parsize) {
915 // Header was shorter than we expected.
916 // It may be a previous version --- clear out the remainder of pars.
917 // TODO: Cross-check the size we got with what we expect based
918 // on the version number in the header.
919 std::fill (parsbeg + ncopy, parsbeg + parsize, 0);
920 }
921 }
922
923 // Initialize derived parameters from the header.
924 init_derived (pars);
925
926 // Bounds check on size of provenance.
927 unsigned nprov = pars.m_lengthProvenance/2;
928 if (nprov + vheader.size() > packed.getData().size()) {
929 REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING,
930 "CaloCellPacker_400_500 ")
931 << "Corrupted data: Provenance count too large "
932 << pars.m_lengthProvenance << ".";
933 pars.m_lengthProvenance = 0;
934 nprov = 0;
935 }
936
937 // need to make a new iterator and use it for provenance.
939 packed.compact_begin_input_from(pars.m_lengthProvenance/2);
940 unsigned iprov=0;
941
942 // getting starting values
943 short unsigned int currProvValue=0;
944 int nextProvHash=-1;
945 short unsigned int nextProvValue=0;
946 if (pars.m_lengthProvenance) {
947 unsigned int provhash = provIt.next();
948 provhash = (provhash<<16) | provIt.next();
949 nextProvValue = pars.m_prov_field.out (provhash);
950 nextProvHash = pars.m_hash_field.out (provhash);
951 iprov++;
952 }
953
954 bool is_SC = (pars.m_status & header::STATUS_IS_SUPERCELL);
955
956 // We need the detector description.
957 const CaloDetDescrManager_Base *ddmgr = nullptr;
958 if (is_SC){
959 SG::ReadCondHandleKey<CaloSuperCellDetDescrManager> caloSuperCellMgrKey {"CaloSuperCellDetDescrManager"};
960 StatusCode sc = caloSuperCellMgrKey.initialize();
961 if(sc.isFailure()) {
962 throw std::runtime_error("Failed to initialize ReadCondHandleKey for CaloSuperCellDetDescrManager");
963 }
964 SG::ReadCondHandle<CaloSuperCellDetDescrManager> caloSuperCellMgrHandle{caloSuperCellMgrKey};
965 ddmgr = *caloSuperCellMgrHandle;
966 }
967 else {
968 SG::ReadCondHandleKey<CaloDetDescrManager> caloMgrKey {"CaloDetDescrManager"};
969 StatusCode sc = caloMgrKey.initialize();
970 if(sc.isFailure()) {
971 throw std::runtime_error("Failed to initialize ReadCondHandleKey for CaloDetDescrManager");
972 }
973 SG::ReadCondHandle<CaloDetDescrManager> caloMgrHandle{caloMgrKey};
974 ddmgr = *caloMgrHandle;
975 }
976 const CaloCell_Base_ID *calo_id = ddmgr->getCaloCell_ID();
977
978 // Clear the output container and reserve the right number of elements.
979 cells.clear(SG::VIEW_ELEMENTS);
980 CaloCell_ID::size_type totcells =
981 pars.m_ncells_larem + pars.m_ncells_larhec +
982 pars.m_ncells_larfcal + pars.m_ncells_tile;
983 if (totcells > calo_id->calo_cell_hash_max()) {
984 REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING,
985 "CaloCellPacker_400_500 ")
986 << "Corrupted data: Too many cells " << totcells << ".";
987 totcells = calo_id->calo_cell_hash_max();
988 }
989 cells.reserve (totcells);
990
991 // Iterator for scanning the input.
993 packed.compact_begin_input();
994
995 // To test for falling off the end.
996 std::vector<CaloCompactCellContainer::value_type>::const_iterator pend =
997 packed.getData().end() - (pars.m_lengthProvenance+1)/2;
998
999 // Sum up the total number of cells/sequences over all subcalos.
1000 unsigned int ncells =
1001 pars.m_ncells_larem +
1002 pars.m_ncells_larhec +
1003 pars.m_ncells_larfcal +
1004 pars.m_ncells_tile;
1005 unsigned int nseqs =
1006 pars.m_seq_larem +
1007 pars.m_seq_larhec +
1008 pars.m_seq_larfcal +
1009 pars.m_seq_tile;
1010
1011 // Note: In the first version of the v400 packer, the sequence counts
1012 // would be left uninitialized if ncells==0.
1013 if (ncells == 0)
1014 nseqs = 0;
1015
1016 // Warn if there are too many cells/sequences.
1017 IdentifierHash hashmax = calo_id->calo_cell_hash_max();
1018 if (ncells > hashmax || nseqs > hashmax || nseqs > ncells) {
1019 REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING,
1020 "CaloCellPacker_400_500 ")
1021 << "Corrupted data: Bad counts"
1022 << ": ncells " << ncells << " nseqs " << nseqs << " hashmax " << hashmax;
1023 }
1024
1026
1027 // Loop over sequences.
1028 for (; nseqs > 0; --nseqs) {
1029
1030 // Check for overrun.
1031 if (it.base() >= pend) {
1032 REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING,
1033 "CaloCellPacker_400_500 ")
1034 << "Corrupted data: cell vector overrun.";
1035 break;
1036 }
1037
1038 // Get the starting hash code and count.
1040 unsigned int hashlength = data << 16;
1041 hashlength |= it.next();
1042
1043 unsigned int hash = pars.m_hash_field.out (hashlength);
1044 unsigned int nseq = pars.m_nseq_field.out (hashlength);
1045
1046 if (nseq > ncells || hash+nseq > hashmax)
1047 {
1048 REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING,
1049 "CaloCellPacker_400_500 ")
1050 << "Corrupted data: bad sequence. "
1051 << "nseq " << nseq << " hash " << hash << " ncells " << ncells
1052 << " hashmax " << hashmax;
1053 break;
1054 }
1055
1056 // Subcalo code for this cell.
1057 CaloCell_ID::SUBCALO subcalo =
1058 static_cast<CaloCell_ID::SUBCALO> (calo_id->sub_calo (hash));
1059
1060 // Maintain the cell container's pointers --- only if cells were ordered!
1061 if (subcalo != prevcalo) {
1062 if ((pars.m_status & header::STATUS_UNORDERED) == 0) {
1063 if (prevcalo != CaloCell_ID::NOT_VALID) {
1064 cells.updateCaloEndIterators (prevcalo, cells.size());
1065 if (subcalo < prevcalo) {
1066 REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING,
1067 "CaloCellPacker_400_500 ")
1068 << "Cells not in subcalo order; iterators will be wrong.";
1069 }
1070 }
1071 cells.updateCaloBeginIterators (subcalo, cells.size());
1072 }
1073 cells.setHasCalo (subcalo);
1074 prevcalo = subcalo;
1075 }
1076
1077 // Loop over cells in the sequence.
1078 while (nseq--) {
1079 // Find the descriptor element for this cell.
1080 const CaloDetDescrElement *dde = ddmgr->get_element(hash);
1081
1082 if (dde == nullptr) {
1083 REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING,
1084 "CaloCellPacker_400_500 ")
1085 << "Corrupted data: can't find DDE for cell with hash " << hash;
1086 }
1087
1088 // Unpack the cell.
1089 //
1090 // One point here that needs explaining.
1091 // The pack_tile method returns a TileCell by value.
1092 // Normally, this would involve a copy; however, we're careful
1093 // to allow the compiler to use the `return value optimization'
1094 // to avoid this copy. That way, we can use the TileCell constructor
1095 // directly, without having to add extra set methods (or violate
1096 // encapsulation, as the previous version of this code did).
1097 // We get a pointer to a TileCell from the data pool and
1098 // use this in a placement new to initialize a TileCell
1099 // using the value returned from unpack_tile. Due to the RVO,
1100 // the copy is avoided, and the constructor in unpack_tile
1101 // will run its constructor directly on the pointer gotten
1102 // from the pool. For this to work correctly, we rely
1103 // on the fact that TileCell has only a trivial destructor ---
1104 // thus it's safe to rerun the constructor on an object that
1105 // has already been constructed.
1106 //
1107 // You'll notice, however, that CaloCell is done differently.
1108 // CaloCell is not a simple class; it has a complicated inheritance
1109 // structure. It was found that setting up all the vtable pointers
1110 // in CaloCell was taking a considerable amount of time
1111 // (comparable to filling in the cell data). So, for CaloCell,
1112 // we instead add a couple new (inlined) set methods to fill
1113 // in the data directly, without having to redo the vtable pointers.
1114 // We split it in two, one for dde/id and the other for the cell data,
1115 // to reduce the amount of data we need to pass to unpack_lar.
1116 //
1117 // Why wasn't the same thing done for TileCell, then?
1118 // - I don't have TC rights for TileEvent, so changing that
1119 // is more of a hassle.
1120 // - There are many fewer tile cells than LAr cells.
1121 // - The TileCell constructor we use is significantly
1122 // more complicated than LArCell. We'd have to duplicate
1123 // this code. Further, this, together with the previous
1124 // point, implies that the performance implications
1125 // of rebuilding the vtable pointers is much less
1126 // for tile cells than for LAr cells.
1127
1128 // New provenance?
1129 if (hash==static_cast<unsigned int>(nextProvHash)){
1130 currProvValue = nextProvValue;
1131 if (iprov<nprov) {
1132 unsigned int provhash = provIt.next();
1133 provhash = (provhash<<16) | provIt.next();
1134 nextProvValue = pars.m_prov_field.out (provhash);
1135 nextProvHash = pars.m_hash_field.out (provhash);
1136 iprov++;
1137 } else {
1138 nextProvHash = -1;
1139 }
1140 }
1141
1142 CaloCell* cell;
1143 if (!is_SC && subcalo == CaloCell_ID::TILE)
1144 cell = new (tilepool.nextElementPtr())
1145 TileCell (unpack_tile (it,
1146 dde,
1147 pars, currProvValue));
1148 else {
1149 cell = unpack_lar (it,
1150 subcalo,
1151 larpool.nextElementPtr(),
1152 pars,
1153 currProvValue);
1154 cell->set (dde, calo_id->cell_id(hash));
1155 }
1156
1157 // Add the cell to the container.
1158 if (dde)
1159 cells.push_back (cell);
1160
1161 // Move to next cell.
1162 ++hash;
1163 }
1164 }
1165
1166 // Finish off the last iterator.
1167 if (prevcalo != CaloCell_ID::NOT_VALID)
1168 cells.updateCaloEndIterators (prevcalo, cells.size());
1169
1170 // Check that we've consumed all the data.
1171 // Note that there may be a padding word before the provenance word.
1172 if (it.base() < pend-2) {
1173 REPORT_MESSAGE_WITH_CONTEXT(MSG::WARNING,
1174 "CaloCellPacker_400_500 ")
1175 << "Corrupted data: didn't consume all packed data.";
1176 }
1177}
1178
1179
1180//============================================================================
#define ATH_UNLIKELY(x)
std::vector< Identifier > ID
Calo cell packer/unpacker v400/500.
Definition of CaloDetDescrManager.
Helpers for checking error return status codes and reporting errors.
#define REPORT_MESSAGE_WITH_CONTEXT(LVL, CONTEXT_NAME)
Report a message, with an explicitly specified context name.
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
static Double_t sc
Hold thinning decisions for one container.
#define y
#define x
Container class for CaloCell.
Helper for packing into/out of a bit field.
unsigned int out(unsigned int x) const
Extract a value from the bitfield.
unsigned int in(unsigned int x) const
Shift and mask a value into the bitfield.
Helper for packing a float into/out of a bit field, with a minimum of 0.
Helper for packing a float into/out of a bit field.
CaloCell * unpack_lar(CaloCompactCellContainer::compact_input_iterator &it, CaloCell_ID::SUBCALO subcalo, LArCell *cell, const pars500 &pars, uint16_t provenance) const
Unpack a LAr cell.
void finish_seq(unsigned int hash, unsigned int nseq, CaloCompactCellContainer::compact_output_iterator &it, CaloCell_ID::SUBCALO subcalo, pars500 &pars) const
Finish up one cell sequence.
void write_header(const header &header, CaloCompactCellContainer &packed) const
Write the header to the output container.
void pack_tile(const TileCell *cell, CaloCompactCellContainer::compact_output_iterator &it, const pars500 &pars) const
Pack one tile cell.
header501 header
The most recent header version.
void unpack(const CaloCompactCellContainer &packed, const std::vector< CaloCompactCellContainer::value_type > &vheader, CaloCellContainer &cells, DataPool< LArCell > &larpool, DataPool< TileCell > &tilepool) const
Unpack cells.
double unpack_time(CaloCompactCellContainer::compact_input_iterator &it, const pars500 &pars) const
Unpack the time word.
void pack_time(float time, CaloCompactCellContainer::compact_output_iterator &it, const pars500 &pars) const
Pack a time value.
void pack_lar(const CaloCell *cell, CaloCell_ID::SUBCALO subcalo, CaloCompactCellContainer::compact_output_iterator &it, const pars500 &pars) const
Pack one LAr cell.
void init_derived(pars500 &pars) const
Initialize the derived packing parameters from the constants in the header.
TileCell unpack_tile(CaloCompactCellContainer::compact_input_iterator &it, const CaloDetDescrElement *dde, const pars500 &pars, uint16_t provenance) const
Unpack a tile cell.
void init_header(header &header, int version) const
Initialize header with the current version of the packing parameters.
void pack(const CaloCellContainer &cells, CaloCompactCellContainer &packed, const SG::ThinningDecisionBase *dec, int version) const
Pack cells.
void clear_header(header &header) const
Clear the counters in the event header.
Helper base class for offline cell identifiers.
int sub_calo(const Identifier id) const
returns an int taken from SUBCALO enum and describing the subCalo to which the Id belongs.
size_type calo_cell_hash_max() const
cell 'global' hash table max size
bool is_supercell(const Identifier id) const
Test if the identifier represents a supercell.
Identifier cell_id(const int subCalo, const int barec_or_posneg, const int sampling_or_fcalmodule, const int region_or_dummy, const int eta, const int phi) const
Make a cell (== channel) ID from constituting fields and subCalo index; for (Mini)FCAL,...
CaloCell_Base_ID::size_type size_type
Definition CaloCell_ID.h:38
CaloCell_Base_ID::SUBCALO SUBCALO
Definition CaloCell_ID.h:50
Data object for each calorimeter readout cell.
Definition CaloCell.h:57
Simple iterator-like object for reading from the container.
CaloCompactCell::value_type next()
Return the current value and advance to the next one.
Simple iterator-like object for writing to the container.
int used() const
Return the number of underlying value_type words used.
void set(CaloCompactCell::value_type x)
Set the next value, and advance the iterator.
container class for CaloCompactCell objects
int value_type
value type for the internal data
unsigned short value_type
value type for the compact CaloCell data
This class groups all DetDescr information related to a CaloCell.
const CaloDetDescriptor * descriptor() const
cell descriptor
const CaloDetDescrElement * get_element(const Identifier &cellId) const
get element by its identifier
const CaloCell_Base_ID * getCaloCell_ID() const
get calo cell ID helper
const CaloCell_Base_ID * get_calo_helper() const
get Calo Cell ID helper
a typed memory pool that saves time spent allocation small object.
Definition DataPool.h:63
pointer nextElementPtr()
obtain the next available element in pool by pointer pool is resized if its limit has been reached On...
This is a "hash" representation of an Identifier.
Data object for LAr calorimeter readout cell.
Definition LArCell.h:53
StatusCode initialize(bool used=true)
Hold thinning decisions for one container.
bool thinned(size_t ndx) const
Return true if element ndx should be thinned.
@ KEEP_TIME
Definition TileCell.h:83
@ MASK_TIME
Definition TileCell.h:67
@ MASK_CMPC
Definition TileCell.h:66
@ MASK_BADCH
Definition TileCell.h:63
@ LARMEDIUMGAIN
Definition CaloGain.h:18
@ INVALIDGAIN
Definition CaloGain.h:18
@ LARLOWGAIN
Definition CaloGain.h:18
@ UNKNOWNGAIN
Definition CaloGain.h:21
@ LARHIGHGAIN
Definition CaloGain.h:18
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
Packing parameters header (v400).
Packing parameters header (v500).
Packing parameters header (v501).