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