Belle II Software development
PXDBackgroundModule.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#include <pxd/modules/pxdBackground/PXDBackgroundModule.h>
9
10#include <framework/datastore/DataStore.h>
11#include <framework/datastore/StoreObjPtr.h>
12#include <framework/datastore/StoreArray.h>
13#include <framework/datastore/RelationArray.h>
14
15#include <framework/dataobjects/FileMetaData.h>
16#include <framework/dataobjects/BackgroundMetaData.h>
17#include <framework/gearbox/Const.h>
18#include <mdst/dataobjects/MCParticle.h>
19#include <pxd/dataobjects/PXDSimHit.h>
20#include <pxd/dataobjects/PXDTrueHit.h>
21#include <pxd/dataobjects/PXDDigit.h>
22#include <pxd/dataobjects/PXDCluster.h>
23#include <pxd/dataobjects/PXDEnergyDepositionEvent.h>
24#include <pxd/dataobjects/PXDNeutronFluxEvent.h>
25#include <pxd/dataobjects/PXDOccupancyEvent.h>
26#include <cmath>
27#include <fstream>
28#include <boost/format.hpp>
29
30using namespace std;
31using boost::format;
32using namespace Belle2;
33using namespace Belle2::PXD;
34
35
36
37//-----------------------------------------------------------------
38// Register the Module
39//-----------------------------------------------------------------
40REG_MODULE(PXDBackground);
41
42
43//-----------------------------------------------------------------
44// Implementation
45//-----------------------------------------------------------------
46
57{
58 //Set module properties
59 setDescription("PXD background module");
60 setPropertyFlags(c_ParallelProcessingCertified); // specify this flag if you need parallel processing
61 // FIXME: This information can in principle be extracted from bg files, though not trivially.
62 addParam("componentName", m_componentName, "Background component name to process", m_componentName);
63 addParam("componentTime", m_componentTime, "Background component time", m_componentTime);
64 addParam("integrationTime", m_integrationTime, "PXD integration time", m_integrationTime);
65 addParam("doseReportingLevel", m_doseReportingLevel, "0 - no data, 1 - summary only, 2 - summary + ntuple", m_doseReportingLevel);
66 addParam("nfluxReportingLevel", m_nfluxReportingLevel, "0 - no data, 1 - summary only, 2 - summary + ntuple",
68 addParam("occupancyReportingLevel", m_occupancyReportingLevel, "0 - no data, 1 - summary only, 2 - summary + ntuple",
70 addParam("outputDirectory", m_outputDirectoryName, "Name of output directory", m_outputDirectoryName);
71}
72
73const ROOT::Math::XYZVector& PXDBackgroundModule::pointToGlobal(VxdID sensorID, const ROOT::Math::XYZVector& local)
74{
75 static ROOT::Math::XYZVector result(0, 0, 0);
76
77 const PXD::SensorInfo& info = getInfo(sensorID);
78 result = info.pointToGlobal(local);
79 return result;
80}
81
82const ROOT::Math::XYZVector& PXDBackgroundModule::vectorToGlobal(VxdID sensorID, const ROOT::Math::XYZVector& local)
83{
84 static ROOT::Math::XYZVector result(0, 0, 0);
85
86 const PXD::SensorInfo& info = getInfo(sensorID);
87 result = info.vectorToGlobal(local);
88 return result;
89}
90
94
96{
97 //Register collections
105
106 RelationArray relDigitsMCParticles(storeDigits, storeMCParticles);
107 RelationArray relDigitsTrueHits(storeDigits, storeTrueHits);
108 RelationArray relMCParticlesTrueHits(storeMCParticles, storeTrueHits);
109 RelationArray relTrueHitsSimHits(storeTrueHits, storeSimHits);
110
111 // Add two new StoreArrays
113 storeEnergyDeposits.registerInDataStore();
115 storeNeutronFluxes.registerInDataStore();
117 storeOccupancyEvents.registerInDataStore();
118
119 //Store names to speed up creation later
120 m_storeFileMetaDataName = storeFileMetaData.getName();
121 m_storeBgMetaDataName = storeBgMetaData.getName();
122 m_storeMCParticlesName = storeMCParticles.getName();
123 m_storeSimHitsName = storeSimHits.getName();
124 m_storeTrueHitsName = storeTrueHits.getName();
125 m_storeDigitsName = storeDigits.getName();
126 m_relDigitsMCParticlesName = relDigitsMCParticles.getName();
127 m_relDigitsTrueHitsName = relDigitsTrueHits.getName();
128 m_relParticlesTrueHitsName = relMCParticlesTrueHits.getName();
129 m_relTrueHitsSimHitsName = relTrueHitsSimHits.getName();
130 m_storeEnergyDepositsName = storeEnergyDeposits.getName();
131 m_storeNeutronFluxesName = storeNeutronFluxes.getName();
132
135}
136
138{
139 //Register collections
142 const StoreArray<MCParticle> storeMCParticles(m_storeMCParticlesName);
143 const StoreArray<PXDSimHit> storeSimHits(m_storeSimHitsName);
144 const StoreArray<PXDTrueHit> storeTrueHits(m_storeTrueHitsName);
145 const StoreArray<PXDDigit> storeDigits(m_storeDigitsName);
146 const StoreArray<PXDCluster> storeClsuters(m_storeClustersName);
147
148 // Add two new StoreArrays
152
153 // Relations
154 RelationArray relDigitsMCParticles(storeDigits, storeMCParticles, m_relDigitsMCParticlesName);
155 RelationArray relDigitsTrueHits(storeDigits, storeTrueHits, m_relDigitsTrueHitsName);
156 RelationArray relTrueHitsSimHits(storeTrueHits, storeSimHits, m_relTrueHitsSimHitsName);
157 RelationArray relTrueHitsMCParticles(storeMCParticles, storeTrueHits, m_relParticlesTrueHitsName);
158
159 // unsigned long numberOfEvents = storeFileMetaData->getNEvents();
160 double currentComponentTime = storeBgMetaData->getRealTime();
161 if (currentComponentTime != m_componentTime)
162 B2FATAL("Mismatch in component times:\n"
163 << "Steering file: " << m_componentTime << "\n"
164 << "Background file: " << currentComponentTime);
165
166 VxdID currentSensorID(0);
167 double currentSensorThickness(0);
168 double currentSensorArea(0);
169
170 // Exposition and dose
172 B2DEBUG(100, "Expo and dose");
173 currentSensorID.setID(0);
174 double currentSensorMass(0);
175 for (const PXDSimHit& hit : storeSimHits) {
176 // Update if we have a new sensor
177 VxdID sensorID = hit.getSensorID();
178 if (sensorID != currentSensorID) {
179 currentSensorID = sensorID;
180 currentSensorThickness = getSensorThickness(currentSensorID);
181 currentSensorMass = getSensorMass(currentSensorID);
182 currentSensorArea = getSensorArea(currentSensorID);
183 }
184 double hitEnergy = hit.getElectrons() * Const::ehEnergy;
185 // Dose in Gy/smy, normalize by sensor mass
186 m_sensorData[currentSensorID].m_dose +=
187 (hitEnergy / Unit::J) / (currentSensorMass / 1000) * (c_smy / currentComponentTime);
188 // Exposition in GeV/cm2/s
189 m_sensorData[currentSensorID].m_expo += hitEnergy / currentSensorArea / (currentComponentTime / Unit::s);
191 const ROOT::Math::XYZVector localPos = hit.getPosIn();
192 const ROOT::Math::XYZVector globalPos = pointToGlobal(currentSensorID, localPos);
193 float globalPosXYZ[3];
194 globalPos.GetCoordinates(globalPosXYZ);
195 storeEnergyDeposits.appendNew(
196 sensorID.getLayerNumber(), sensorID.getLadderNumber(), sensorID.getSensorNumber(),
197 hit.getPDGcode(), hit.getGlobalTime(),
198 localPos.X(), localPos.Y(), globalPosXYZ, hitEnergy,
199 (hitEnergy / Unit::J) / (currentSensorMass / 1000) / (currentComponentTime / Unit::s),
200 (hitEnergy / Unit::J) / currentSensorArea / (currentComponentTime / Unit::s)
201 );
202 }
203 }
204 }
205
206 // Neutron flux
208 B2DEBUG(100, "Neutron flux");
209 currentSensorID.setID(0);
210 for (const PXDTrueHit& hit : storeTrueHits) {
211 VxdID sensorID = hit.getSensorID();
212 // Update if we are on a new sensor
213 if (sensorID != currentSensorID) {
214 currentSensorID = sensorID;
215 currentSensorThickness = getSensorThickness(currentSensorID);
216 currentSensorArea = getSensorArea(currentSensorID);
217 }
218 // J(TrueHit) = abs(step)/thickness * correctionFactor;
219 ROOT::Math::XYZVector entryPos(hit.getEntryU(), hit.getEntryV(), hit.getEntryW());
220 ROOT::Math::XYZVector exitPos(hit.getExitU(), hit.getExitV(), hit.getExitW());
221 double stepLength = (exitPos - entryPos).R();
222 // Identify what particle we've got. We need type and kinetic energy.
223 // TODO: TrueHit must carry pdg or SimHit must carry energy.
224 // NOTE: MCParticles may get remapped, then SimHits still carry correct pdg.
225 const PXDSimHit* simhit = hit.getRelatedTo<PXDSimHit>();
226 if (!simhit) { //either something is very wrong, or we just don't have the relation. Try to find an appropriate SimHit manually.
227 double minDistance = 1.0e10;
228 for (const PXDSimHit& related : storeSimHits) {
229 double distance = (entryPos - related.getPosIn()).R();
230 if (distance < minDistance) {
231 minDistance = distance;
232 simhit = &related;
233 }
234 }
235 }
236 if (!simhit) {
237 B2WARNING("No related PXDSimHit found");
238 continue; //skip this true hit if the simhit is still null after setting it manually
239 }
240 // FIXME: Is there a difference between positrons and electrons wrt. NIEL?
241 // We fill neutronFluxBars with summary NIEL deposit for all kinds of particles by layer and component.
242 // Fluency plots are by component and are deposition histograms for a particular type of particle and compoonent.
243 // Special treatment of corrupt p's in TrueHits:
244 ROOT::Math::XYZVector hitMomentum(hit.getMomentum());
245 hitMomentum.SetX(std::isfinite(hitMomentum.X()) ? hitMomentum.X() : 0.0);
246 hitMomentum.SetY(std::isfinite(hitMomentum.Y()) ? hitMomentum.Y() : 0.0);
247 hitMomentum.SetZ(std::isfinite(hitMomentum.Z()) ? hitMomentum.Z() : 0.0);
248 int pdg = abs(simhit->getPDGcode());
249 double kineticEnergy(0.0);
250 double nielWeight(0.0);
251 if (pdg == Const::neutron.getPDGCode()) {
252 double m0 = Const::neutronMass;
253 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
254 nielWeight = m_nielNeutrons->getNielFactor(kineticEnergy / Unit::MeV);
255 }
256 if (pdg == Const::proton.getPDGCode()) {
257 double m0 = Const::protonMass;
258 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
259 nielWeight = m_nielProtons->getNielFactor(kineticEnergy / Unit::MeV);
260 }
261 if (pdg == Const::pi0.getPDGCode() || pdg == Const::pion.getPDGCode()) {
262 double m0 = Const::pi0Mass;
263 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
264 nielWeight = m_nielPions->getNielFactor(kineticEnergy / Unit::MeV);
265 }
266 if (pdg == Const::electron.getPDGCode()) {
267 double m0 = Const::electronMass;
268 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
269 nielWeight = m_nielElectrons->getNielFactor(kineticEnergy / Unit::MeV);
270 }
271 if (pdg == Const::photon.getPDGCode()) {
272 double m0 = 0.0;
273 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
274 }
275
276 // Only set weight for supported particles
277 nielWeight = std::isfinite(nielWeight) ? nielWeight : 0.0;
278 m_sensorData[currentSensorID].m_neutronFlux += nielWeight * stepLength / currentSensorThickness / currentSensorArea /
279 currentComponentTime * c_smy;
280
281 // Store data in a PXDNeutronFluxEvent object
283 ROOT::Math::XYZVector localPos(hit.getU(), hit.getV(), hit.getW());
284 const ROOT::Math::XYZVector globalPos = pointToGlobal(currentSensorID, localPos);
285 float globalPosXYZ[3];
286 globalPos.GetCoordinates(globalPosXYZ);
287 ROOT::Math::XYZVector localMom = hit.getMomentum();
288 const ROOT::Math::XYZVector globalMom = vectorToGlobal(currentSensorID, localMom);
289 float globalMomXYZ[3];
290 globalMom.GetCoordinates(globalMomXYZ);
291 storeNeutronFluxes.appendNew(
292 sensorID.getLayerNumber(), sensorID.getLadderNumber(), sensorID.getSensorNumber(),
293 simhit->getPDGcode(), simhit->getGlobalTime(),
294 hit.getU(), hit.getV(), globalPosXYZ, globalMomXYZ, kineticEnergy,
295 stepLength, nielWeight,
296 stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime / Unit::s),
297 nielWeight * stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime / Unit::s)
298 );
299 }
300 }
301 }
302
303 // Occupancy
305 B2DEBUG(100, "Fired pixels");
306 currentSensorID.setID(0);
307 double currentSensorCut = 0;
308 // Store fired pixels: count number of digits over threshold
309 std::map<VxdID, std::vector<float> > firedPixels;
310 for (const PXDDigit& storeDigit : storeDigits) {
311 // Filter out digits with signals below zero-suppression threshold
312 // ARE THERE SUCH DIGITS?
313 VxdID sensorID = storeDigit.getSensorID();
314 if (sensorID != currentSensorID) {
315 currentSensorID = sensorID;
316 auto info = getInfo(sensorID);
317 currentSensorCut = info.getChargeThreshold();
318 }
319 B2DEBUG(30, "Digit charge: " << storeDigit.getCharge() << " threshold: " << currentSensorCut);
320 if (storeDigit.getCharge() < currentSensorCut) continue;
321 B2DEBUG(30, "Passed.");
322 firedPixels[sensorID].push_back(storeDigit.getCharge());
323 }
324 // Process the map
325 for (auto idAndSet : firedPixels) {
326 VxdID sensorID = idAndSet.first;
327 double sensorArea = getSensorArea(sensorID);
328 int nFired = idAndSet.second.size();
329 double fired = nFired / (currentComponentTime / Unit::s) / sensorArea;
330 m_sensorData[sensorID].m_fired += fired;
331 }
332
333 B2DEBUG(100, "Occupancy");
334 currentSensorID.setID(0);
335 int nPixels = 0;
336 for (auto cluster : storeClsuters) {
337 VxdID sensorID = cluster.getSensorID();
338 if (currentSensorID != sensorID) {
339 currentSensorID = sensorID;
340 auto info = getInfo(sensorID);
341 nPixels = info.getUCells() * info.getVCells();
342 }
343
344 double w_acceptance = m_integrationTime / currentComponentTime;
345 double occupancy = 1.0 / nPixels * cluster.getSize();
346 m_sensorData[sensorID].m_occupancy += w_acceptance * occupancy;
347
349 storeOccupancyEvents.appendNew(
350 sensorID.getLayerNumber(), sensorID.getLadderNumber(),
351 sensorID.getSensorNumber(),
352 cluster.getU(), cluster.getV(), cluster.getSize(),
353 cluster.getCharge(), occupancy
354 );
355 }
356 }
357 }
358}
359
360
362{
363 // Write out m_data
364 ofstream outfile;
365 string outfileName(m_outputDirectoryName + m_componentName + "_summary.txt");
366 outfile.open(outfileName.c_str(), ios::out | ios::trunc);
367 outfile << "component_name\t"
368 << "component_time\t"
369 << "layer\t"
370 << "ladder\t"
371 << "sensor\t"
372 << "dose\t"
373 << "expo\t"
374 << "neutronFlux\t"
375 << "fired\t"
376 << "occupancy"
377 << endl;
378 double componentTime = m_componentTime / Unit::us;
379 for (auto vxdSensor : m_sensorData) {
380 outfile << m_componentName << "\t"
381 << componentTime << "\t"
382 << vxdSensor.first.getLayerNumber() << "\t"
383 << vxdSensor.first.getLadderNumber() << "\t"
384 << vxdSensor.first.getSensorNumber() << "\t"
385 << vxdSensor.second.m_dose << "\t"
386 << vxdSensor.second.m_expo << "\t"
387 << vxdSensor.second.m_neutronFlux << "\t"
388 << vxdSensor.second.m_fired << "\t"
389 << vxdSensor.second.m_occupancy
390 << endl;
391 }
392 outfile << endl;
393}
double R
typedef autogenerated by FFTW
static const ParticleType neutron
neutron particle
Definition Const.h:676
static const ParticleType pi0
neutral pion particle
Definition Const.h:675
static const ChargedStable pion
charged pion particle
Definition Const.h:662
static const double electronMass
electron mass
Definition Const.h:686
static const double neutronMass
neutron mass
Definition Const.h:693
static const ChargedStable proton
proton particle
Definition Const.h:664
static const double ehEnergy
Energy needed to create an electron-hole pair in Si at std.
Definition Const.h:698
static const double protonMass
proton mass
Definition Const.h:690
static const ParticleType photon
photon particle
Definition Const.h:674
static const double pi0Mass
neutral pion mass
Definition Const.h:692
static const ChargedStable electron
electron particle
Definition Const.h:660
@ c_Persistent
Object is available during entire execution time.
Definition DataStore.h:60
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
Module()
Constructor.
Definition Module.cc:30
@ 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
The PXD digit class.
Definition PXDDigit.h:27
Class PXDSimHit - Geant4 simulated hit for the PXD.
Definition PXDSimHit.h:24
Class PXDTrueHit - Records of tracks that either enter or leave the sensitive volume.
Definition PXDTrueHit.h:31
static const unsigned short c_reportNTuple
Summary and NTuple.
std::string m_storeFileMetaDataName
Name of the persistent FileMetaData object.
unsigned short m_nfluxReportingLevel
0 - no data, 1 - summary only, 2 - ntuple
static const ROOT::Math::XYZVector & vectorToGlobal(VxdID sensorID, const ROOT::Math::XYZVector &local)
Convert local vector coordinates to global.
static const ROOT::Math::XYZVector & pointToGlobal(VxdID sensorID, const ROOT::Math::XYZVector &local)
Convert local sensor coordinates to global.
std::string m_storeEnergyDepositsName
PXDEnergyDepositEvents StoreArray name.
const double c_smy
Seconds in snowmass year.
unsigned short m_doseReportingLevel
0 - no data, 1 - summary only, 2 - ntuple
std::string m_storeOccupancyEventsName
PXDOccupancyEvents StoreArray name.
std::map< VxdID, SensorData > m_sensorData
Struct to hold sensor-wise background data.
virtual void initialize() override
Initialize module.
std::string m_relTrueHitsSimHitsName
PXDTrueHitsToPXDSimHits RelationArray name.
double m_integrationTime
Integration time of PXD.
std::string m_relDigitsMCParticlesName
StoreArray name of PXDDigits to MCParticles relation.
const std::string c_niel_neutronFile
NIEL-correction file for neutrons.
virtual void event() override
Event processing.
double getSensorMass(VxdID sensorID) const
Return mass of the sensor with the given sensor ID.
static const unsigned short c_reportNone
No reporting.
static const PXD::SensorInfo & getInfo(const VxdID &sensorID)
This is a shortcut to getting PXD::SensorInfo from the GeoCache.
std::string m_storeNeutronFluxesName
PXDNeutronFluxEvents StoreArray name.
std::string m_storeTrueHitsName
PXDTrueHits StoreArray name.
virtual void terminate() override
Final summary and cleanup.
std::unique_ptr< TNiel > m_nielNeutrons
Pointer to Niel table for neutrons.
std::string m_storeMCParticlesName
MCParticles StoreArray name.
std::unique_ptr< TNiel > m_nielProtons
Pointer to Niel table for protons.
std::unique_ptr< TNiel > m_nielPions
Pointer to Niel table for pions.
const std::string c_niel_electronFile
NIEL-correction file for electrons.
std::string m_storeBgMetaDataName
Name of the persistent BackgroundMetaDta object.
static double getSensorArea(VxdID sensorID)
Return area of the sensor with the given sensor ID.
std::string m_outputDirectoryName
Path to directory where output data will be stored.
std::string m_storeDigitsName
PXDDigits StoreArray name.
std::string m_storeClustersName
PXDClusters StoreArray name.
static double getSensorThickness(VxdID sensorID)
Return thickness of the sensor with the given sensor ID.
std::unique_ptr< TNiel > m_nielElectrons
Pointer to Niel table for electrons.
const std::string c_niel_protonFile
NIEL-correction file for protons.
virtual ~PXDBackgroundModule() override
Destructor.
const std::string c_niel_pionFile
NIEL-correction file for pions.
std::string m_relParticlesTrueHitsName
MCParticlesToPXDTrueHits RelationArray name.
std::string m_componentName
Name of the current bg component.
double m_componentTime
Time of current component.
unsigned short m_occupancyReportingLevel
0 - no data, 1 - summary only, 2 - ntuple
std::string m_storeSimHitsName
PXDSimHits StoreArray name.
std::string m_relDigitsTrueHitsName
StoreArray name of PXDDigits to PXDTrueHits relation.
Specific implementation of SensorInfo for PXD Sensors which provides additional pixel specific inform...
Definition SensorInfo.h:23
Low-level class to create/modify relations between StoreArrays.
TO * getRelatedTo(const std::string &name="", const std::string &namedRelation="") const
Get the object to which this object has a relation.
const std::string & getName() const
Return name under which the object is saved in the DataStore.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
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:247
Type-safe access to single objects in the data store.
Definition StoreObjPtr.h:96
static const double us
[microsecond]
Definition Unit.h:97
static const double J
[joule]
Definition Unit.h:116
static const double MeV
[megaelectronvolt]
Definition Unit.h:114
static const double s
[second]
Definition Unit.h:95
float getGlobalTime() const override
Return the time of the electron deposition.
Definition VXDSimHit.h:76
int getPDGcode() const
Return the PDG code of the particle causing the electron deposition.
Definition VXDSimHit.h:66
Class to uniquely identify a any structure of the PXD and SVD.
Definition VxdID.h:32
baseType getSensorNumber() const
Get the sensor id.
Definition VxdID.h:99
void setID(baseType id)
Set the unique id.
Definition VxdID.h:104
baseType getLadderNumber() const
Get the ladder id.
Definition VxdID.h:97
baseType getLayerNumber() const
Get the layer id.
Definition VxdID.h:95
TNiel - the class providing values for NIEL factors.
Definition niel_fun.h:17
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:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
Namespace to encapsulate code needed for simulation and reconstrucion of the PXD.
Abstract base class for different kinds of events.
STL namespace.