8 #include <pxd/modules/pxdBackground/PXDBackgroundModule.h>
10 #include <framework/datastore/DataStore.h>
11 #include <framework/datastore/StoreObjPtr.h>
12 #include <framework/datastore/StoreArray.h>
13 #include <framework/datastore/RelationArray.h>
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>
28 #include <boost/format.hpp>
50 Module(), m_outputDirectoryName(""),
51 m_doseReportingLevel(c_reportNTuple),
52 m_nfluxReportingLevel(c_reportNTuple),
53 m_occupancyReportingLevel(c_reportNTuple),
54 m_componentName(""), m_componentTime(0), m_integrationTime(20),
55 m_nielNeutrons(new
TNiel(c_niel_neutronFile)),
56 m_nielProtons(new
TNiel(c_niel_protonFile)),
57 m_nielPions(new
TNiel(c_niel_pionFile)),
58 m_nielElectrons(new
TNiel(c_niel_electronFile))
61 setDescription(
"PXD background module");
62 setPropertyFlags(c_ParallelProcessingCertified);
64 addParam(
"componentName", m_componentName,
"Background component name to process", m_componentName);
65 addParam(
"componentTime", m_componentTime,
"Background component time", m_componentTime);
66 addParam(
"integrationTime", m_integrationTime,
"PXD integration time", m_integrationTime);
67 addParam(
"doseReportingLevel", m_doseReportingLevel,
"0 - no data, 1 - summary only, 2 - summary + ntuple", m_doseReportingLevel);
68 addParam(
"nfluxReportingLevel", m_nfluxReportingLevel,
"0 - no data, 1 - summary only, 2 - summary + ntuple",
69 m_nfluxReportingLevel);
70 addParam(
"occupancyReportingLevel", m_occupancyReportingLevel,
"0 - no data, 1 - summary only, 2 - summary + ntuple",
71 m_occupancyReportingLevel);
72 addParam(
"outputDirectory", m_outputDirectoryName,
"Name of output directory", m_outputDirectoryName);
75 const TVector3& PXDBackgroundModule::pointToGlobal(
VxdID sensorID,
const TVector3& local)
77 static TVector3 result(0, 0, 0);
80 result = info.pointToGlobal(local);
84 const TVector3& PXDBackgroundModule::vectorToGlobal(
VxdID sensorID,
const TVector3& local)
86 static TVector3 result(0, 0, 0);
89 result = info.vectorToGlobal(local);
93 PXDBackgroundModule::~PXDBackgroundModule()
97 void PXDBackgroundModule::initialize()
108 RelationArray relDigitsMCParticles(storeDigits, storeMCParticles);
110 RelationArray relMCParticlesTrueHits(storeMCParticles, storeTrueHits);
111 RelationArray relTrueHitsSimHits(storeTrueHits, storeSimHits);
122 m_storeFileMetaDataName = storeFileMetaData.
getName();
123 m_storeBgMetaDataName = storeBgMetaData.
getName();
124 m_storeMCParticlesName = storeMCParticles.
getName();
125 m_storeSimHitsName = storeSimHits.
getName();
126 m_storeTrueHitsName = storeTrueHits.
getName();
127 m_storeDigitsName = storeDigits.
getName();
128 m_relDigitsMCParticlesName = relDigitsMCParticles.
getName();
129 m_relDigitsTrueHitsName = relDigitsTrueHits.
getName();
130 m_relParticlesTrueHitsName = relMCParticlesTrueHits.
getName();
131 m_relTrueHitsSimHitsName = relTrueHitsSimHits.
getName();
132 m_storeEnergyDepositsName = storeEnergyDeposits.
getName();
133 m_storeNeutronFluxesName = storeNeutronFluxes.
getName();
135 m_componentTime *= Unit::us;
136 m_integrationTime *= Unit::us;
139 void PXDBackgroundModule::beginRun()
143 void PXDBackgroundModule::event()
160 RelationArray relDigitsMCParticles(storeDigits, storeMCParticles, m_relDigitsMCParticlesName);
161 RelationArray relDigitsTrueHits(storeDigits, storeTrueHits, m_relDigitsTrueHitsName);
162 RelationArray relTrueHitsSimHits(storeTrueHits, storeSimHits, m_relTrueHitsSimHitsName);
163 RelationArray relTrueHitsMCParticles(storeMCParticles, storeTrueHits, m_relParticlesTrueHitsName);
166 double currentComponentTime = storeBgMetaData->getRealTime();
167 if (currentComponentTime != m_componentTime)
168 B2FATAL(
"Mismatch in component times:\n"
169 <<
"Steering file: " << m_componentTime <<
"\n"
170 <<
"Background file: " << currentComponentTime);
172 VxdID currentSensorID(0);
173 double currentSensorThickness(0);
174 double currentSensorMass(0);
175 double currentSensorArea(0);
178 if (m_doseReportingLevel > c_reportNone) {
179 B2DEBUG(100,
"Expo and dose");
180 currentSensorID.
setID(0);
181 for (
const PXDSimHit& hit : storeSimHits) {
183 VxdID sensorID = hit.getSensorID();
184 if (sensorID != currentSensorID) {
185 currentSensorID = sensorID;
186 currentSensorThickness = getSensorThickness(currentSensorID);
187 currentSensorMass = getSensorMass(currentSensorID);
188 currentSensorArea = getSensorArea(currentSensorID);
190 double hitEnergy = hit.getElectrons() * Const::ehEnergy;
192 m_sensorData[currentSensorID].m_dose +=
193 (hitEnergy / Unit::J) / (currentSensorMass / 1000) * (c_smy / currentComponentTime);
195 m_sensorData[currentSensorID].m_expo += hitEnergy / currentSensorArea / (currentComponentTime / Unit::s);
196 if (m_doseReportingLevel == c_reportNTuple) {
197 const TVector3 localPos = hit.getPosIn();
198 const TVector3 globalPos = pointToGlobal(currentSensorID, localPos);
199 float globalPosXYZ[3];
200 globalPos.GetXYZ(globalPosXYZ);
203 hit.getPDGcode(), hit.getGlobalTime(),
204 localPos.X(), localPos.Y(), globalPosXYZ, hitEnergy,
205 (hitEnergy / Unit::J) / (currentSensorMass / 1000) / (currentComponentTime / Unit::s),
206 (hitEnergy / Unit::J) / currentSensorArea / (currentComponentTime / Unit::s)
213 if (m_nfluxReportingLevel > c_reportNone) {
214 B2DEBUG(100,
"Neutron flux");
215 currentSensorID.
setID(0);
217 VxdID sensorID = hit.getSensorID();
219 if (sensorID != currentSensorID) {
220 currentSensorID = sensorID;
221 currentSensorThickness = getSensorThickness(currentSensorID);
222 currentSensorMass = getSensorMass(currentSensorID);
223 currentSensorArea = getSensorArea(currentSensorID);
226 TVector3 entryPos(hit.getEntryU(), hit.getEntryV(), hit.getEntryW());
227 TVector3 exitPos(hit.getExitU(), hit.getExitV(), hit.getExitW());
228 double stepLength = (exitPos - entryPos).Mag();
234 double minDistance = 1.0e10;
235 for (
const PXDSimHit& related : storeSimHits) {
236 double distance = (entryPos - related.getPosIn()).Mag();
237 if (distance < minDistance) {
238 minDistance = distance;
247 TVector3 hitMomentum(hit.getMomentum());
248 hitMomentum.SetX(std::isfinite(hitMomentum.X()) ? hitMomentum.X() : 0.0);
249 hitMomentum.SetY(std::isfinite(hitMomentum.Y()) ? hitMomentum.Y() : 0.0);
250 hitMomentum.SetZ(std::isfinite(hitMomentum.Z()) ? hitMomentum.Z() : 0.0);
252 double kineticEnergy(0.0);
253 double nielWeight(0.0);
254 if (pdg == Const::neutron.getPDGCode()) {
255 double m0 = Const::neutronMass;
256 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
257 nielWeight = m_nielNeutrons->getNielFactor(kineticEnergy / Unit::MeV);
259 if (pdg == Const::proton.getPDGCode()) {
260 double m0 = Const::protonMass;
261 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
262 nielWeight = m_nielProtons->getNielFactor(kineticEnergy / Unit::MeV);
264 if (pdg == Const::pi0.getPDGCode() || pdg == Const::pion.getPDGCode()) {
265 double m0 = Const::pi0Mass;
266 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
267 nielWeight = m_nielPions->getNielFactor(kineticEnergy / Unit::MeV);
269 if (pdg == Const::electron.getPDGCode()) {
270 double m0 = Const::electronMass;
271 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
272 nielWeight = m_nielElectrons->getNielFactor(kineticEnergy / Unit::MeV);
274 if (pdg == Const::photon.getPDGCode()) {
276 kineticEnergy = sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
280 nielWeight = std::isfinite(nielWeight) ? nielWeight : 0.0;
281 m_sensorData[currentSensorID].m_neutronFlux += nielWeight * stepLength / currentSensorThickness / currentSensorArea /
282 currentComponentTime * c_smy;
285 if (m_nfluxReportingLevel == c_reportNTuple) {
286 TVector3 localPos(hit.getU(), hit.getV(), hit.getW());
287 const TVector3 globalPos = pointToGlobal(currentSensorID, localPos);
288 float globalPosXYZ[3];
289 globalPos.GetXYZ(globalPosXYZ);
290 TVector3 localMom = hit.getMomentum();
291 const TVector3 globalMom = vectorToGlobal(currentSensorID, localMom);
292 float globalMomXYZ[3];
293 globalMom.GetXYZ(globalMomXYZ);
297 hit.getU(), hit.getV(), globalPosXYZ, globalMomXYZ, kineticEnergy,
298 stepLength, nielWeight,
299 stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime / Unit::s),
300 nielWeight * stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime / Unit::s)
307 if (m_occupancyReportingLevel > c_reportNone) {
308 B2DEBUG(100,
"Fired pixels");
309 currentSensorID.
setID(0);
310 double currentSensorCut = 0;
312 std::map<VxdID, std::vector<float> > firedPixels;
313 for (
const PXDDigit& storeDigit : storeDigits) {
316 VxdID sensorID = storeDigit.getSensorID();
317 if (sensorID != currentSensorID) {
318 currentSensorID = sensorID;
319 auto info = getInfo(sensorID);
320 currentSensorCut = info.getChargeThreshold();
322 B2DEBUG(30,
"Digit charge: " << storeDigit.getCharge() <<
" threshold: " << currentSensorCut);
323 if (storeDigit.getCharge() < currentSensorCut)
continue;
324 B2DEBUG(30,
"Passed.");
325 firedPixels[sensorID].push_back(storeDigit.getCharge());
328 for (
auto idAndSet : firedPixels) {
329 VxdID sensorID = idAndSet.first;
330 double sensorArea = getSensorArea(sensorID);
331 int nFired = idAndSet.second.size();
332 double fired = nFired / (currentComponentTime / Unit::s) / sensorArea;
333 m_sensorData[sensorID].m_fired += fired;
336 B2DEBUG(100,
"Occupancy");
337 currentSensorID.
setID(0);
339 for (
auto cluster : storeClsuters) {
340 VxdID sensorID = cluster.getSensorID();
341 if (currentSensorID != sensorID) {
342 currentSensorID = sensorID;
343 auto info = getInfo(sensorID);
344 nPixels = info.getUCells() * info.getVCells();
347 double w_acceptance = m_integrationTime / currentComponentTime;
348 double occupancy = 1.0 / nPixels * cluster.getSize();
349 m_sensorData[sensorID].m_occupancy += w_acceptance * occupancy;
351 if (m_occupancyReportingLevel == c_reportNTuple) {
355 cluster.getU(), cluster.getV(), cluster.getSize(),
356 cluster.getCharge(), occupancy
363 void PXDBackgroundModule::endRun()
368 void PXDBackgroundModule::terminate()
372 string outfileName(m_outputDirectoryName + m_componentName +
"_summary.txt");
373 outfile.open(outfileName.c_str(), ios::out | ios::trunc);
374 outfile <<
"component_name\t"
375 <<
"component_time\t"
385 double componentTime = m_componentTime / Unit::us;
386 for (
auto vxdSensor : m_sensorData) {
387 outfile << m_componentName.c_str() <<
"\t"
388 << componentTime <<
"\t"
389 << vxdSensor.first.getLayerNumber() <<
"\t"
390 << vxdSensor.first.getLadderNumber() <<
"\t"
391 << vxdSensor.first.getSensorNumber() <<
"\t"
392 << vxdSensor.second.m_dose <<
"\t"
393 << vxdSensor.second.m_expo <<
"\t"
394 << vxdSensor.second.m_neutronFlux <<
"\t"
395 << vxdSensor.second.m_fired <<
"\t"
396 << vxdSensor.second.m_occupancy
Class PXDSimHit - Geant4 simulated hit for the PXD.
Class PXDTrueHit - Records of tracks that either enter or leave the sensitive volume.
Specific implementation of SensorInfo for PXD Sensors which provides additional pixel specific inform...
Low-level class to create/modify relations between StoreArrays.
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.
T * appendNew()
Construct a new T object at the end of the array.
Type-safe access to single objects in the data store.
float getGlobalTime() const override
Return the time of the electron deposition.
int getPDGcode() const
Return the PDG code of the particle causing the electron deposition.
Class to uniquely identify a any structure of the PXD and SVD.
baseType getSensorNumber() const
Get the sensor id.
void setID(baseType id)
Set the unique id.
baseType getLadderNumber() const
Get the ladder id.
baseType getLayerNumber() const
Get the layer id.
TNiel - the class providing values for NIEL factors.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Namespace to encapsulate code needed for simulation and reconstrucion of the PXD.
Abstract base class for different kinds of events.