Belle II Software development
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 header.
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
18// framework aux
19#include <framework/logging/Logger.h>
20
21// magnetic field manager
22#include <framework/geometry/BFieldManager.h>
23
24#include <framework/dataobjects/BackgroundInfo.h>
25
26
27// ROOT
28#include <Math/Vector2D.h>
29#include <Math/Vector3D.h>
30#include <TRandom3.h>
31
32using namespace boost;
33
34namespace Belle2 {
40 //-----------------------------------------------------------------
42 //-----------------------------------------------------------------
43
44 REG_MODULE(ARICHDigitizer);
45
46
47 //-----------------------------------------------------------------
48 // Implementation
49 //-----------------------------------------------------------------
50
52 m_maxQE(0)
53 {
54
55 // Set description()
56 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.");
57
58 // Set property flags
60
61 // Add parameters
62 addParam("TimeWindow", m_timeWindow, "Readout time window width in ns", 250.0);
63 addParam("TimeWindowStart", m_timeWindowStart, "Shift of the readout time window with respect to the global zero in ns", -50.0);
64 addParam("BackgroundHits", m_bkgLevel, "Number of background hits per hapd per readout (electronics noise)", 0.066);
65 addParam("MagneticFieldDistorsion", m_bdistort, "Apply image distortion due to non-perp. magnetic field", 0);
66 }
67
69 {
70
71 }
72
74 {
75 // QE at 400nm (3.1eV) applied in SensitiveDetector
76 m_maxQE = m_simPar->getQE(3.1);
77
78 m_ARICHSimHits.isRequired();
79 m_ARICHDigits.registerInDataStore();
80
81 m_bgOverlay = false;
83 if (bgInfo.isValid()) {
84 if (bgInfo->getMethod() == BackgroundInfo::c_Overlay) m_bgOverlay = true;
85 }
86
87 }
88
90 {
91 if (m_simPar->getNBkgHits() > 0) m_bkgLevel = m_simPar->getNBkgHits();
92 }
93
95 {
96
97 //---------------------------------------------------------------------
98 // Convert SimHits one by one to digitizer hits.
99 //---------------------------------------------------------------------
100
101 // We try to include the effect of opposite-polarity crosstalk among channels
102 // on each chip, which depend on number of p.e. on chip
103
104 std::map<std::pair<int, int>, int> photoElectrons; // this contains number of photoelectrons falling on each channel
105 std::map<std::pair<int, int>, int> chipHits; // this contains number of photoelectrons on each chip
106
107 // Loop over all photon hits
108 for (const ARICHSimHit& aSimHit : m_ARICHSimHits) {
109
110 // check for time window
111 double time = aSimHit.getGlobalTime() - m_timeWindowStart;
112
113 if (time < 0 || time > m_timeWindow) continue;
114
115 ROOT::Math::XYVector locpos = aSimHit.getLocalPosition();
116
117 // Get id of module
118 int moduleID = aSimHit.getModuleID();
119
120 if (m_bdistort) magFieldDistorsion(locpos, moduleID);
121
122 // skip if not active
123 if (!m_modInfo->isActive(moduleID)) continue;
124
125 // Get id number of hit channel
126 int chX, chY;
127 m_geoPar->getHAPDGeometry().getXYChannel(locpos.X(), locpos.Y(), chX, chY);
128
129 if (chX < 0 && chY < 0) continue;
130
131 int asicChannel = m_chnMap->getAsicFromXY(chX, chY);
132
133
134 // eliminate un-active channels
135 if (asicChannel < 0 || !m_chnMask->isActive(moduleID, asicChannel)) continue;
136
137 // apply channel dependent QE scale factor
138 //double qe_scale = 0.27 / m_maxQE;
139 //double qe_scale = m_modInfo->getChannelQE(moduleID, asicChannel) * m_simPar->getColEff() / m_maxQE; // eventually move collection efficiency to here!
140 double qe_scale = m_modInfo->getChannelQE(moduleID, asicChannel) / m_maxQE;
141
142 if (qe_scale > 1.) B2ERROR("Channel QE is higher than QE applied in SensitiveDetector");
143 if (gRandom->Uniform(1.) > qe_scale) continue;
144
145 // photon was converted to photoelectron
146 chipHits[std::make_pair(moduleID, asicChannel / 36)] += 1;
147 photoElectrons[std::make_pair(moduleID, asicChannel)] += 1;
148
149 }
150
151 // loop over produced photoelectrons. Apply suppression due to the reverse polarization crosstalk
152 // among channels on the same chip, and produce hit bitmap (4 bits).
153
154 for (std::map<std::pair<int, int>, int>::iterator it = photoElectrons.begin(); it != photoElectrons.end(); ++it) {
155
156 std::pair<int, int> modch = it->first;
157 double npe = double(it->second);
158
159 // reduce efficiency
160 npe /= (1.0 + m_simPar->getChipNegativeCrosstalk() * (double(chipHits[std::make_pair(modch.first, modch.second / 36)]) - 1.0));
161 if (npe < 1.0 && gRandom->Uniform(1) > npe) continue;
162
163 // 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., ...
164 // More proper implementation is to be done ...
165 uint8_t bitmap = 0;
166 for (int i = 0; i < npe; i++) {
167 bitmap |= 1 << i;
168 if (i == 3) break;
169 }
170
171 // make new digit!
172 m_ARICHDigits.appendNew(modch.first, modch.second, bitmap);
173
174 }
175
176 //--- if background not overlayed add electronic noise hits
177 if (m_bgOverlay) return;
178 uint8_t bitmap = 1;
179 unsigned nSlots = m_geoPar->getDetectorPlane().getNSlots();
180 for (unsigned id = 1; id < nSlots + 1; id++) {
181 if (!m_modInfo->isActive(id)) continue;
182 int nbkg = gRandom->Poisson(m_bkgLevel);
183 for (int i = 0; i < nbkg; i++) {
184 m_ARICHDigits.appendNew(id, gRandom->Integer(144), bitmap);
185 }
186 }
187
188 }
189
190 void ARICHDigitizerModule::magFieldDistorsion(ROOT::Math::XYVector& hit, int copyno)
191 {
192
193 ROOT::Math::XYVector hitGlob;
194 double phi = m_geoPar->getDetectorPlane().getSlotPhi(copyno);
195 double r = m_geoPar->getDetectorPlane().getSlotR(copyno);
196 double z = m_geoPar->getDetectorZPosition() + m_geoPar->getHAPDGeometry().getWinThickness();
197 hitGlob.SetXY(r * std::cos(phi), r * std::sin(phi));
198 ROOT::Math::XYVector shift = hit;
199 shift.Rotate(phi);
200 hitGlob += shift;
201 ROOT::Math::XYZVector Bfield = BFieldManager::getField(m_geoPar->getMasterVolume().pointToGlobal(ROOT::Math::XYZVector(hitGlob.X(),
202 hitGlob.Y(), z)));
203 double cc = m_geoPar->getHAPDGeometry().getPhotocathodeApdDistance() / abs(Bfield.Z());
204 shift.SetX(cc * Bfield.X());
205 shift.SetY(cc * Bfield.Y());
206 shift.Rotate(phi);
207 hit.SetX(hit.X() + shift.X());
208 hit.SetY(hit.Y() + shift.Y());
209 }
210
212} // end Belle2 namespace
double m_maxQE
QE at 400nm (from QE curve applied in SensitveDetector)
double m_bkgLevel
Number of background hits ped hapd per readout (electronics noise)
DBObjPtr< ARICHSimulationPar > m_simPar
simulation parameters from the DB
StoreArray< ARICHSimHit > m_ARICHSimHits
StoreArray containing the ARICHSimHits.
DBObjPtr< ARICHModulesInfo > m_modInfo
information on installed modules from the DB (QEs etc.)
DBObjPtr< ARICHGeometryConfig > m_geoPar
geometry configuration parameters from the DB
bool m_bgOverlay
True if BG overlay detected.
double m_timeWindow
Readout time window width in ns.
StoreArray< ARICHDigit > m_ARICHDigits
StoreArray containing the ARICHDigits.
int m_bdistort
apply distorsion due to magnetic field
DBObjPtr< ARICHChannelMapping > m_chnMap
HAPD (x,y) to asic channel mapping.
double m_timeWindowStart
Readout time window shift w.r.t.
Class ARICHSimHit - Geant4 simulated hit for ARICH.
Definition: ARICHSimHit.h:29
@ c_Persistent
Object is available during entire execution time.
Definition: DataStore.h:60
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:111
virtual void initialize() override
Initialize the Module.
void magFieldDistorsion(ROOT::Math::XYVector &hit, int copyno)
Apply correction to hit position due to non-perpendicular component of magnetic field.
virtual void event() override
Event processor.
virtual ~ARICHDigitizerModule()
Destructor.
virtual void beginRun() override
Called when entering a new run.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
static void getField(const double *pos, double *field)
return the magnetic field at a given position.
Definition: BFieldManager.h:91
Abstract base class for different kinds of events.
record to be used to store ASIC info