Belle II Software  release-06-02-00
ARICHDigitizerModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 // Own include
9 #include <arich/modules/arichDigitizer/ARICHDigitizerModule.h>
10 
11 // Hit classes
12 #include <arich/dataobjects/ARICHSimHit.h>
13 #include <arich/dataobjects/ARICHDigit.h>
14 
15 // framework - DataStore
16 #include <framework/datastore/DataStore.h>
17 #include <framework/datastore/StoreArray.h>
18 
19 // framework aux
20 #include <framework/logging/Logger.h>
21 
22 // magnetic field manager
23 #include <framework/geometry/BFieldManager.h>
24 
25 #include <framework/dataobjects/BackgroundInfo.h>
26 
27 
28 // ROOT
29 #include <TVector2.h>
30 #include <TVector3.h>
31 #include <TRandom3.h>
32 
33 using namespace std;
34 using namespace boost;
35 
36 namespace Belle2 {
42  //-----------------------------------------------------------------
43  // Register the Module
44  //-----------------------------------------------------------------
45 
46  REG_MODULE(ARICHDigitizer)
47 
48 
49  //-----------------------------------------------------------------
50  // Implementation
51  //-----------------------------------------------------------------
52 
54  m_maxQE(0)
55  {
56 
57  // Set description()
58  setDescription("This module creates ARICHDigits from ARICHSimHits. Here spatial digitization is done, channel-by-channel QE is applied, and readout time window cut is applied.");
59 
60  // Set property flags
61  setPropertyFlags(c_ParallelProcessingCertified);
62 
63  // Add parameters
64  addParam("TimeWindow", m_timeWindow, "Readout time window width in ns", 250.0);
65  addParam("BackgroundHits", m_bkgLevel, "Number of background hits per hapd per readout (electronics noise)", 0.066);
66  addParam("MagneticFieldDistorsion", m_bdistort, "Apply image distortion due to non-perp. magnetic field", 0);
67  }
68 
69  ARICHDigitizerModule::~ARICHDigitizerModule()
70  {
71 
72  }
73 
74  void ARICHDigitizerModule::initialize()
75  {
76  // Print set parameters
77  printModuleParams();
78 
79  // QE at 400nm (3.1eV) applied in SensitiveDetector
80  m_maxQE = m_simPar->getQE(3.1);
81 
83  digits.registerInDataStore();
84 
85  m_bgOverlay = false;
86  StoreObjPtr<BackgroundInfo> bgInfo("", DataStore::c_Persistent);
87  if (bgInfo.isValid()) {
88  if (bgInfo->getMethod() == BackgroundInfo::c_Overlay) m_bgOverlay = true;
89  }
90 
91  }
92 
93  void ARICHDigitizerModule::beginRun()
94  {
95  if (m_simPar->getNBkgHits() > 0) m_bkgLevel = m_simPar->getNBkgHits();
96  }
97 
98  void ARICHDigitizerModule::event()
99  {
100 
101  // Get the collection of ARICHSimHits from the Data store.
102  //------------------------------------------------------
103  StoreArray<ARICHSimHit> arichSimHits;
104  //-----------------------------------------------------
105 
106  // Get the collection of arichDigits from the Data store,
107  // (or have one created)
108  //-----------------------------------------------------
109  StoreArray<ARICHDigit> arichDigits;
110 
111  //---------------------------------------------------------------------
112  // Convert SimHits one by one to digitizer hits.
113  //---------------------------------------------------------------------
114 
115  // We try to include the effect of opposite-polarity crosstalk among channels
116  // on each chip, which depend on number of p.e. on chip
117 
118  std::map<pair<int, int>, int> photoElectrons; // this contains number of photoelectrons falling on each channel
119  std::map<pair<int, int>, int> chipHits; // this contains number of photoelectrons on each chip
120 
121  // Get number of photon hits in this event
122  int nHits = arichSimHits.getEntries();
123 
124  // Loop over all photon hits
125  for (int iHit = 0; iHit < nHits; ++iHit) {
126 
127  ARICHSimHit* aSimHit = arichSimHits[iHit];
128 
129  // check for time window
130  double globaltime = aSimHit->getGlobalTime();
131 
132  if (globaltime < 0. || globaltime > m_timeWindow) continue;
133 
134  TVector2 locpos(aSimHit->getLocalPosition().X(), aSimHit->getLocalPosition().Y());
135 
136  // Get id of module
137  int moduleID = aSimHit->getModuleID();
138 
139  if (m_bdistort) magFieldDistorsion(locpos, moduleID);
140 
141  // skip if not active
142  if (!m_modInfo->isActive(moduleID)) continue;
143 
144  // Get id number of hit channel
145  int chX, chY;
146  m_geoPar->getHAPDGeometry().getXYChannel(locpos.X(), locpos.Y(), chX, chY);
147 
148  if (chX < 0 && chY < 0) continue;
149 
150  int asicChannel = m_chnMap->getAsicFromXY(chX, chY);
151 
152 
153  // eliminate un-active channels
154  if (asicChannel < 0 || !m_chnMask->isActive(moduleID, asicChannel)) continue;
155 
156  // apply channel dependent QE scale factor
157  //double qe_scale = 0.27 / m_maxQE;
158  //double qe_scale = m_modInfo->getChannelQE(moduleID, asicChannel) * m_simPar->getColEff() / m_maxQE; // eventually move collection efficiency to here!
159  double qe_scale = m_modInfo->getChannelQE(moduleID, asicChannel) / m_maxQE;
160 
161  if (qe_scale > 1.) B2ERROR("Channel QE is higher than QE applied in SensitiveDetector");
162  if (gRandom->Uniform(1.) > qe_scale) continue;
163 
164  // photon was converted to photoelectron
165  chipHits[make_pair(moduleID, asicChannel / 36)] += 1;
166  photoElectrons[make_pair(moduleID, asicChannel)] += 1;
167 
168  }
169 
170  // loop over produced photoelectrons. Apply suppression due to the reverse polarization crosstalk
171  // among channels on the same chip, and produce hit bitmap (4 bits).
172 
173  for (std::map<std::pair<int, int> , int>::iterator it = photoElectrons.begin(); it != photoElectrons.end(); ++it) {
174 
175  std::pair<int, int> modch = it->first;
176  double npe = double(it->second);
177 
178  // reduce efficiency
179  npe /= (1.0 + m_simPar->getChipNegativeCrosstalk() * (double(chipHits[make_pair(modch.first, modch.second / 36)]) - 1.0));
180  if (npe < 1.0 && gRandom->Uniform(1) > npe) continue;
181 
182  // Make hit bitmap (depends on number of p.e. on channel). For now bitmap is 0001 for single p.e., 0011 for 2 p.e., ...
183  // More proper implementation is to be done ...
184  uint8_t bitmap = 0;
185  for (int i = 0; i < npe; i++) {
186  bitmap |= 1 << i;
187  if (i == 3) break;
188  }
189 
190  // make new digit!
191  arichDigits.appendNew(modch.first, modch.second, bitmap);
192 
193  }
194 
195  //--- if background not overlayed add electronic noise hits
196  if (m_bgOverlay) return;
197  uint8_t bitmap = 1;
198  unsigned nSlots = m_geoPar->getDetectorPlane().getNSlots();
199  for (unsigned id = 1; id < nSlots + 1; id++) {
200  if (!m_modInfo->isActive(id)) continue;
201  int nbkg = gRandom->Poisson(m_bkgLevel);
202  for (int i = 0; i < nbkg; i++) {
203  arichDigits.appendNew(id, gRandom->Integer(144), bitmap);
204  }
205  }
206 
207  }
208 
209  void ARICHDigitizerModule::magFieldDistorsion(TVector2& hit, int copyno)
210  {
211 
212  TVector2 hitGlob;
213  double phi = m_geoPar->getDetectorPlane().getSlotPhi(copyno);
214  double r = m_geoPar->getDetectorPlane().getSlotR(copyno);
215  double z = m_geoPar->getDetectorZPosition() + m_geoPar->getHAPDGeometry().getWinThickness();
216  hitGlob.SetMagPhi(r, phi);
217  TVector2 shift = hit;
218  hitGlob += shift.Rotate(phi);
219  TVector3 Bfield = BFieldManager::getField(m_geoPar->getMasterVolume().pointToGlobal(TVector3(hitGlob.X(), hitGlob.Y(), z)));
220  double cc = m_geoPar->getHAPDGeometry().getPhotocathodeApdDistance() / abs(Bfield.Z());
221  shift.SetX(cc * Bfield.X());
222  shift.SetY(cc * Bfield.Y());
223  shift = shift.Rotate(-phi);
224  hit.SetX(hit.X() + shift.X());
225  hit.SetY(hit.Y() + shift.Y());
226  }
227 
228  void ARICHDigitizerModule::endRun()
229  {
230  }
231 
232  void ARICHDigitizerModule::terminate()
233  {
234 
235  }
236 
238 } // end Belle2 namespace
Class ARICHSimHit - Geant4 simulated hit for ARICH.
Definition: ARICHSimHit.h:29
float getGlobalTime() const override
Get global time of hit.
Definition: ARICHSimHit.h:72
int getModuleID() const
Get ID number of module that registered hit.
Definition: ARICHSimHit.h:66
TVector2 getLocalPosition() const
Get local position of hit (in module coordinates)
Definition: ARICHSimHit.h:69
Base class for Modules.
Definition: Module.h:72
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:110
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.
record to be used to store ASIC info