Belle II Software  release-05-01-25
PXDHitRateCounter.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2019 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Marko Staric, Benjamin Schwenker *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 // Own include
12 #include <background/modules/BeamBkgHitRateMonitor/PXDHitRateCounter.h>
13 #include <pxd/reconstruction/PXDGainCalibrator.h>
14 #include <pxd/reconstruction/PXDPixelMasker.h>
15 #include <string>
16 
17 // framework aux
18 #include <framework/logging/Logger.h>
19 
20 using namespace std;
21 
22 namespace Belle2 {
27  namespace Background {
28 
29  void PXDHitRateCounter::initialize(TTree* tree)
30  {
31  //Pointer to GeoTools instance
32  auto gTools = VXD::GeoCache::getInstance().getGeoTools();
33  if (gTools->getNumberOfPXDLayers() == 0) {
34  B2FATAL("Missing geometry for PXD.");
35  }
36 
37  m_nPXDSensors = gTools->getNumberOfPXDSensors();
38 
39  // register collection(s) as optional, your detector might be excluded in DAQ
40  m_digits.isOptional();
41 
42  // register collection(s) as optional, your detector might be excluded in DAQ
43  m_clusters.isOptional();
44 
45  string leaflist =
46  "meanOccupancies[40]/F:maxOccupancies[40]/F:doseRates[40]/F:softPhotonFluxes[40]/F:hardPhotonFluxes[40]/F:chargedFluxes[40]/F:segmentDoseRates[240]/F:segmentSoftPhotonFluxes[240]/F:segmentHardPhotonFluxes[240]/F:segmentChargedFluxes[240]/F:averageRate/F:numEvents/I:valid/O";
47 
48  // set branch address
49  tree->Branch("pxd", &m_rates, leaflist.c_str());
50 
51  // check parameters
52  if (m_integrationTime <= 0) B2FATAL("invalid integration time window for PXD: " << m_integrationTime);
53 
54  // set fractions of active channels
55  setActivePixels();
56  }
57 
58  void PXDHitRateCounter::clear()
59  {
60  m_buffer.clear();
61  }
62 
63  void PXDHitRateCounter::accumulate(unsigned timeStamp)
64  {
65  // check if data are available
66  if ((not m_digits.isValid()) or (not m_clusters.isValid())) return;
67 
68  // get buffer element
69  auto& rates = m_buffer[timeStamp];
70 
71  // increment event counter
72  rates.numEvents++;
73 
74  // accumulate hits
75  rates.averageRate += m_digits.getEntries();
76 
77  // Use the same indexing of sensors as for PXDDQM
78  auto gTools = VXD::GeoCache::getInstance().getGeoTools();
79 
80  // accumulate dose rate and event occupancy
81  float occupancies[40] = {0};
82  for (const PXDDigit& storeDigit : m_digits) {
83  VxdID sensorID = storeDigit.getSensorID();
84  int index = gTools->getPXDSensorIndex(storeDigit.getSensorID());
85  int vBin = PXD::PXDGainCalibrator::getInstance().getBinV(sensorID, storeDigit.getVCellID(), 6);
86  double ADUToEnergy = PXD::PXDGainCalibrator::getInstance().getADUToEnergy(sensorID, storeDigit.getUCellID(),
87  storeDigit.getVCellID());
88  double hitEnergy = storeDigit.getCharge() * ADUToEnergy;
89  rates.doseRates[index] += (hitEnergy / Unit::J);
90  occupancies[index] += 1.0;
91  rates.segmentDoseRates[vBin + index * 6] += (hitEnergy / Unit::J);
92  }
93 
94  for (int index = 0; index < m_nPXDSensors; index++) {
95  if (m_activePixels[index] > 0) {
96  occupancies[index] /= m_activePixels[index];
97  }
98  rates.meanOccupancies[index] += occupancies[index];
99  if (rates.maxOccupancies[index] < occupancies[index]) {
100  rates.maxOccupancies[index] = occupancies[index];
101  }
102  }
103 
104  // accumulate fluxes
105  for (const PXDCluster& cluster : m_clusters) {
106  // Update if we have a new sensor
107  VxdID sensorID = cluster.getSensorID();
108  int index = gTools->getPXDSensorIndex(sensorID);
109  auto info = getInfo(sensorID);
110 
111  auto cluster_uID = info.getUCellID(cluster.getU());
112  auto cluster_vID = info.getVCellID(cluster.getV());
113  int vBin = PXD::PXDGainCalibrator::getInstance().getBinV(sensorID, cluster_vID, 6);
114  double ADUToEnergy = PXD::PXDGainCalibrator::getInstance().getADUToEnergy(sensorID, cluster_uID, cluster_vID);
115  double clusterEnergy = cluster.getCharge() * ADUToEnergy;
116 
117  if (cluster.getSize() == 1 && clusterEnergy < 10000 * Unit::eV && clusterEnergy > 6000 * Unit::eV) {
118  rates.softPhotonFluxes[index] += 1.0;
119  rates.segmentSoftPhotonFluxes[vBin + index * 6] += 1.0;
120  } else if (cluster.getSize() == 1 && clusterEnergy > 10000 * Unit::eV) {
121  rates.hardPhotonFluxes[index] += 1.0;
122  rates.segmentHardPhotonFluxes[vBin + index * 6] += 1.0;
123  } else if (cluster.getSize() > 1 && clusterEnergy > 10000 * Unit::eV) {
124  rates.chargedFluxes[index] += 1.0;
125  rates.segmentChargedFluxes[vBin + index * 6] += 1.0;
126  }
127  }
128 
129  // set flag to true to indicate the rates are valid
130  rates.valid = true;
131  }
132 
133  void PXDHitRateCounter::normalize(unsigned timeStamp)
134  {
135  // copy buffer element
136  m_rates = m_buffer[timeStamp];
137 
138  if (not m_rates.valid) return;
139 
140  if (m_rates.numEvents == 0) return;
141 
142  // Average number of PXDDigits per 1Hz
143  m_rates.averageRate /= m_rates.numEvents;
144 
145  // Total integration time of PXD per 1Hz
146  double currentComponentTime = m_rates.numEvents * m_integrationTime;
147 
148  //Pointer to GeoTools instance
149  auto gTools = VXD::GeoCache::getInstance().getGeoTools();
150 
151  // Compute sensor level averages per 1Hz
152  for (int index = 0; index < m_nPXDSensors; index++) {
153  VxdID sensorID = gTools->getSensorIDFromPXDIndex(index);
154  auto info = getInfo(sensorID);
155  double currentSensorMass = m_activeAreas[index] * info.getThickness() * c_densitySi;
156  double currentSensorArea = m_activeAreas[index];
157 
158  m_rates.meanOccupancies[index] /= m_rates.numEvents;
159  if (currentSensorArea > 0) {
160  m_rates.doseRates[index] *= (1.0 / (currentComponentTime / Unit::s)) * (1000 / currentSensorMass);
161  m_rates.softPhotonFluxes[index] *= (1.0 / currentSensorArea) * (1.0 / (currentComponentTime / Unit::s));
162  m_rates.hardPhotonFluxes[index] *= (1.0 / currentSensorArea) * (1.0 / (currentComponentTime / Unit::s));
163  m_rates.chargedFluxes[index] *= (1.0 / currentSensorArea) * (1.0 / (currentComponentTime / Unit::s));
164 
165  // Loop over v segements
166  for (int vBin = 0; vBin < 6; ++vBin) {
167  double currentSegmentMass = m_segmentActiveAreas[vBin + index * 6] * info.getThickness() * c_densitySi;
168  double currentSegmentArea = m_segmentActiveAreas[vBin + index * 6];
169  if (currentSegmentArea > 0) {
170  m_rates.segmentDoseRates[vBin + index * 6] *= (1.0 / (currentComponentTime / Unit::s)) * (1000 / currentSegmentMass);
171  m_rates.segmentSoftPhotonFluxes[vBin + index * 6] *= (1.0 / currentSegmentArea) * (1.0 / (currentComponentTime / Unit::s));
172  m_rates.segmentHardPhotonFluxes[vBin + index * 6] *= (1.0 / currentSegmentArea) * (1.0 / (currentComponentTime / Unit::s));
173  m_rates.segmentChargedFluxes[vBin + index * 6] *= (1.0 / currentSegmentArea) * (1.0 /
174  (currentComponentTime / Unit::s));
175  }
176  }
177  }
178  }
179  }
180 
181  void PXDHitRateCounter::setActivePixels()
182  {
183  //Pointer to GeoTools instance
184  auto gTools = VXD::GeoCache::getInstance().getGeoTools();
185 
186  // Initialize active areas and active fractions for all sensors
187  for (int index = 0; index < m_nPXDSensors; index++) {
188  VxdID sensorID = gTools->getSensorIDFromPXDIndex(index);
189  auto info = getInfo(sensorID);
190 
191  // Compute nominal number of pixel per sensor
192  m_activePixels[index] = info.getUCells() * info.getVCells();
193  // Compute nominal area of sensor
194  m_activeAreas[index] = info.getWidth() * info.getLength();
195 
196  // Loop over v segements
197  for (int vBin = 0; vBin < 6; ++vBin) {
198  // Compute nominal number of pixel per segment
199  // Sgements have same number of rows, but due to pitch change a different length
200  m_segmentActivePixels[vBin + index * 6] = info.getUCells() * info.getVCells() / 6;
201  // Compute position of v segment
202  double v = info.getVCellPosition(vBin * info.getVCells() / 6);
203  // Compute nominal area of segment
204  m_segmentActiveAreas[vBin + index * 6] = info.getWidth() * info.getVPitch(v) * info.getVCells() / 6;
205  }
206 
207  if (m_maskDeadPixels) {
208  for (int ui = 0; ui < info.getUCells(); ++ui) {
209  for (int vi = 0; vi < info.getVCells(); ++vi) {
210  if (PXD::PXDPixelMasker::getInstance().pixelDead(sensorID, ui, vi)
211  || !PXD::PXDPixelMasker::getInstance().pixelOK(sensorID, ui, vi)) {
212  m_activePixels[index] -= 1;
213  m_activeAreas[index] -= info.getVPitch(info.getVCellPosition(vi)) * info.getUPitch();
214  int vBin = PXD::PXDGainCalibrator::getInstance().getBinV(sensorID, vi, 6);
215  m_segmentActivePixels[vBin + index * 6] -= 1;
216  m_segmentActiveAreas[vBin + index * 6] -= info.getVPitch(info.getVCellPosition(vi)) * info.getUPitch();
217  }
218  }
219  }
220  }
221  }
222  }
223 
224  } // Background namespace
226 } // Belle2 namespace
227 
Belle2::VxdID
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:43
Belle2::PXDDigit
The PXD digit class.
Definition: PXDDigit.h:38
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::PXDCluster
The PXD Cluster class This class stores all information about reconstructed PXD clusters The position...
Definition: PXDCluster.h:41