8#include <svd/modules/svdBackground/SVDBackgroundModule.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 <svd/dataobjects/SVDSimHit.h>
20#include <svd/dataobjects/SVDTrueHit.h>
21#include <svd/dataobjects/SVDShaperDigit.h>
22#include <svd/dataobjects/SVDCluster.h>
23#include <svd/dataobjects/SVDEnergyDepositionEvent.h>
24#include <svd/dataobjects/SVDNeutronFluxEvent.h>
25#include <svd/dataobjects/SVDOccupancyEvent.h>
30#include <boost/format.hpp>
32#include <Math/Vector3D.h>
42double eToADU(
double charge)
44 double minADC = -96000;
45 double maxADC = 288000;
46 double unitADC = (maxADC - minADC) / 1024.0;
47 return round(std::min(maxADC, std::max(minADC, charge)) / unitADC);
61 Module(), m_outputDirectoryName(
""),
62 m_doseReportingLevel(c_reportNTuple),
63 m_nfluxReportingLevel(c_reportNTuple),
64 m_occupancyReportingLevel(c_reportNTuple),
65 m_componentName(
""), m_componentTime(0),
66 m_triggerWidth(5), m_acceptanceWidth(2.5),
67 m_nielNeutrons(new
TNiel(c_niel_neutronFile)),
68 m_nielProtons(new
TNiel(c_niel_protonFile)),
69 m_nielPions(new
TNiel(c_niel_pionFile)),
70 m_nielElectrons(new
TNiel(c_niel_electronFile))
80 "A hit is accepted if arrived within +/- accpetanceWidth * RMS(hit time - trigger time) of trigger; in ns",
m_acceptanceWidth);
91 static ROOT::Math::XYZVector result(0, 0, 0);
94 result = info.pointToGlobal(local);
100 static ROOT::Math::XYZVector result(0, 0, 0);
103 result = info.vectorToGlobal(local);
122 RelationArray relDigitsMCParticles(storeDigits, storeMCParticles);
124 RelationArray relMCParticlesTrueHits(storeMCParticles, storeTrueHits);
125 RelationArray relTrueHitsSimHits(storeTrueHits, storeSimHits);
181 double currentComponentTime = storeBgMetaData->getRealTime();
183 B2FATAL(
"Mismatch in component times:\n"
185 <<
"Background file: " << currentComponentTime);
187 VxdID currentSensorID(0);
188 double currentSensorThickness(0);
189 double currentSensorArea(0);
193 B2DEBUG(100,
"Expo and dose");
194 currentSensorID.
setID(0);
195 double currentSensorMass(0);
197 for (
const SVDSimHit& hit : storeSimHits) {
199 VxdID sensorID = hit.getSensorID();
200 if (sensorID != currentSensorID) {
201 currentSensorID = sensorID;
209 (hitEnergy /
Unit::J) / (currentSensorMass / 1000) * (
c_smy / currentComponentTime);
211 m_sensorData[currentSensorID].m_expo += hitEnergy / currentSensorArea / (currentComponentTime /
Unit::s);
213 const ROOT::Math::XYZVector localPos = hit.getPosIn();
214 const ROOT::Math::XYZVector globalPos =
pointToGlobal(currentSensorID, localPos);
215 float globalPosXYZ[3];
216 globalPos.GetCoordinates(globalPosXYZ);
219 hit.getPDGcode(), hit.getGlobalTime(),
220 localPos.X(), localPos.Y(), globalPosXYZ, hitEnergy,
221 (hitEnergy /
Unit::J) / (currentSensorMass / 1000) / (currentComponentTime /
Unit::s),
222 (hitEnergy /
Unit::J) / currentSensorArea / (currentComponentTime /
Unit::s)
230 B2DEBUG(100,
"Neutron flux");
231 currentSensorID.
setID(0);
233 VxdID sensorID = hit.getSensorID();
235 if (sensorID != currentSensorID) {
236 currentSensorID = sensorID;
242 ROOT::Math::XYZVector entryPos(hit.getEntryU(), hit.getEntryV(), hit.getEntryW());
243 ROOT::Math::XYZVector exitPos(hit.getExitU(), hit.getExitV(), hit.getExitW());
244 double stepLength = (exitPos - entryPos).
R();
250 double minDistance = 1.0e10;
251 for (
const SVDSimHit& related : storeSimHits) {
252 double distance = (entryPos - related.getPosIn()).
R();
253 if (distance < minDistance) {
254 minDistance = distance;
260 B2WARNING(
"No related SVDSimHit found");
267 ROOT::Math::XYZVector hitMomentum(hit.getMomentum());
268 hitMomentum.SetX(std::isfinite(hitMomentum.X()) ? hitMomentum.X() : 0.0);
269 hitMomentum.SetY(std::isfinite(hitMomentum.Y()) ? hitMomentum.Y() : 0.0);
270 hitMomentum.SetZ(std::isfinite(hitMomentum.Z()) ? hitMomentum.Z() : 0.0);
272 double kineticEnergy(0.0);
273 double nielWeight(0.0);
276 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
281 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
286 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
291 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
296 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
300 nielWeight = std::isfinite(nielWeight) ? nielWeight : 0.0;
301 m_sensorData[currentSensorID].m_neutronFlux += nielWeight * stepLength / currentSensorThickness / currentSensorArea /
302 currentComponentTime *
c_smy;
306 ROOT::Math::XYZVector localPos(hit.getU(), hit.getV(), hit.getW());
307 const ROOT::Math::XYZVector globalPos =
pointToGlobal(currentSensorID, localPos);
308 float globalPosXYZ[3];
309 globalPos.GetCoordinates(globalPosXYZ);
310 ROOT::Math::XYZVector localMom = hit.getMomentum();
311 const ROOT::Math::XYZVector globalMom =
vectorToGlobal(currentSensorID, localMom);
312 float globalMomXYZ[3];
313 globalMom.GetCoordinates(globalMomXYZ);
317 hit.getU(), hit.getV(), globalPosXYZ, globalMomXYZ, kineticEnergy,
318 stepLength, nielWeight,
319 stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime /
Unit::s),
320 nielWeight * stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime /
Unit::s)
328 B2DEBUG(100,
"Fired strips");
329 currentSensorID.
setID(0);
330 double currentSensorUCut = 0;
331 double currentSensorVCut = 0;
333 std::map<VxdID, std::multiset<unsigned short> > firedStrips;
337 VxdID sensorID = digit.getSensorID();
338 if (sensorID != currentSensorID) {
339 currentSensorID = sensorID;
341 currentSensorUCut = eToADU(3.0 * info.getElectronicNoiseU());
342 currentSensorVCut = eToADU(3.0 * info.getElectronicNoiseV());
344 B2DEBUG(30,
"MaxCharge: " << digit.getMaxADCCounts() <<
" threshold: " << (digit.isUStrip() ? currentSensorUCut :
346 if (digit.getMaxADCCounts() < (digit.isUStrip() ? currentSensorUCut : currentSensorVCut))
continue;
347 B2DEBUG(30,
"Passed.");
349 VxdID writeID(sensorID);
350 if (digit.isUStrip())
354 firedStrips[writeID].insert(digit.getCellID());
357 for (
auto idAndSet : firedStrips) {
358 bool isUStrip = (idAndSet.first.getSegmentNumber() == 0);
359 VxdID sensorID = idAndSet.first;
362 int nFired_APV = idAndSet.second.size();
364 for (
auto it = idAndSet.second.begin();
365 it != idAndSet.second.end();
366 it = idAndSet.second.upper_bound(*it)) nFired++;
367 double fired = nFired / (currentComponentTime /
Unit::s) / sensorArea;
393 B2DEBUG(100,
"Occupancy");
394 currentSensorID.
setID(0);
395 double currentNoiseU = 0;
396 double currentNoiseV = 0;
399 for (
auto cluster : storeClsuters) {
400 VxdID sensorID = cluster.getSensorID();
401 if (currentSensorID != sensorID) {
402 currentSensorID = sensorID;
404 currentNoiseU = eToADU(info.getElectronicNoiseU());
405 currentNoiseV = eToADU(info.getElectronicNoiseV());
406 nStripsU = info.getUCells();
407 nStripsV = info.getVCells();
409 bool isU = cluster.isUCluster();
410 double snr = (isU) ? cluster.getCharge() / currentNoiseU : cluster.getCharge() / currentNoiseV;
411 int nStrips = (isU) ? nStripsU : nStripsV;
412 double tau_error = 45 / snr *
Unit::ns;
415 double w_acceptance = tau_acceptance / currentComponentTime;
417 double occupancy = 1.0 / nStrips * cluster.getSize();
419 m_sensorData[sensorID].m_occupancyU += w_acceptance * occupancy;
420 m_sensorData[sensorID].m_occupancyU_APV += w_acceptance_APV * occupancy;
422 m_sensorData[sensorID].m_occupancyV += w_acceptance * occupancy;
423 m_sensorData[sensorID].m_occupancyV_APV += w_acceptance_APV * occupancy;
429 cluster.isUCluster(), cluster.getPosition(), cluster.getSize(),
430 cluster.getCharge(), snr, w_acceptance, w_acceptance * occupancy,
431 w_acceptance_APV * occupancy
448 outfile.open(outfileName.c_str(), ios::out | ios::trunc);
449 outfile <<
"component_name\t"
450 <<
"component_time\t"
463 <<
"occupancy_u_APV\t"
469 << componentTime <<
"\t"
470 << vxdSensor.first.getLayerNumber() <<
"\t"
471 << vxdSensor.first.getLadderNumber() <<
"\t"
472 << vxdSensor.first.getSensorNumber() <<
"\t"
473 << vxdSensor.second.m_dose <<
"\t"
474 << vxdSensor.second.m_expo <<
"\t"
475 << vxdSensor.second.m_neutronFlux <<
"\t"
476 << vxdSensor.second.m_firedU <<
"\t"
477 << vxdSensor.second.m_firedV <<
"\t"
478 << vxdSensor.second.m_firedU_t <<
"\t"
479 << vxdSensor.second.m_firedV_t <<
"\t"
480 << vxdSensor.second.m_occupancyU <<
"\t"
481 << vxdSensor.second.m_occupancyV <<
"\t"
482 << vxdSensor.second.m_occupancyU_APV <<
"\t"
483 << vxdSensor.second.m_occupancyV_APV
static const ParticleType neutron
neutron particle
static const ParticleType pi0
neutral pion particle
static const ChargedStable pion
charged pion particle
static const double electronMass
electron mass
static const double neutronMass
neutron mass
static const ChargedStable proton
proton particle
static const double ehEnergy
Energy needed to create an electron-hole pair in Si at std.
static const double protonMass
proton mass
static const ParticleType photon
photon particle
static const double pi0Mass
neutral pion mass
static const ChargedStable electron
electron particle
@ c_Persistent
Object is available during entire execution time.
void setDescription(const std::string &description)
Sets the description of the module.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Low-level class to create/modify relations between StoreArrays.
The SVD ShaperDigit class.
Class SVDSimHit - Geant4 simulated hit for the SVD.
Class SVDTrueHit - Records of tracks that either enter or leave the sensitive volume.
static const unsigned short c_reportNTuple
Summary and NTuple.
std::string m_storeFileMetaDataName
Name of the persistent FileMetaData object.
double m_triggerWidth
RMS of trigger time measurement.
unsigned short m_nfluxReportingLevel
0 - no data, 1 - summary only, 2 - ntuple
const ROOT::Math::XYZVector & vectorToGlobal(VxdID sensorID, const ROOT::Math::XYZVector &local)
Convert local vector coordinates to global.
const ROOT::Math::XYZVector & pointToGlobal(VxdID sensorID, const ROOT::Math::XYZVector &local)
Convert local sensor coordinates to global.
std::string m_storeEnergyDepositsName
SVDEnergyDepositEvents StoreArray name.
const double c_smy
Seconds in snowmass year.
const SVD::SensorInfo & getInfo(VxdID sensorID) const
This is a shortcut to getting SVD::SensorInfo from the GeoCache.
unsigned short m_doseReportingLevel
0 - no data, 1 - summary only, 2 - ntuple
std::string m_storeOccupancyEventsName
SVDOccupancyEvents 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
SVDTrueHitsToSVDSimHits RelationArray name.
std::string m_relDigitsMCParticlesName
StoreArray name of SVDDigits to MCParticles relation.
double m_acceptanceWidth
A hit is accepted if arrived within +/- m_acceptanceWidth * RMS(hit time - trigger time).
virtual void event() override
Event processing.
virtual ~SVDBackgroundModule()
Destructor.
double getSensorMass(VxdID sensorID) const
Return mass of the sensor with the given sensor ID.
static const unsigned short c_reportNone
No reporting.
virtual void endRun() override
End-of-run tasks.
std::string m_storeNeutronFluxesName
SVDNeutronFluxEvents StoreArray name.
std::string m_storeTrueHitsName
SVDTrueHits 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.
double getSensorThickness(VxdID sensorID) const
Return thickness of the sensor with the given sensor ID.
std::unique_ptr< TNiel > m_nielPions
Pointer to Niel table for pions.
virtual void beginRun() override
Start-of-run initializations.
SVDBackgroundModule()
Constructor.
std::string m_storeBgMetaDataName
Name of the persistent BackgroundMetaDta object.
double getSensorArea(VxdID sensorID) const
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
SVDDigits StoreArray name.
std::string m_storeClustersName
SVDClusters StoreArray name.
std::unique_ptr< TNiel > m_nielElectrons
Pointer to Niel table for electrons.
const double c_APVCycleTime
APV cycle time.
std::string m_relParticlesTrueHitsName
MCParticlesToSVDTrueHits RelationArray name.
std::string m_componentName
Name of the current component.
double m_componentTime
Time of current component.
unsigned short m_occupancyReportingLevel
0 - no data, 1 - summary only, 2 - ntuple
std::string m_storeSimHitsName
SVDSimHits StoreArray name.
std::string m_relDigitsTrueHitsName
StoreArray name of SVDDigits to SVDTrueHits relation.
Specific implementation of SensorInfo for SVD Sensors which provides additional sensor specific infor...
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.
T * appendNew()
Construct a new T object at the end of the array.
Type-safe access to single objects in the data store.
static const double us
[microsecond]
static const double J
[joule]
static const double MeV
[megaelectronvolt]
static const double ns
Standard of [time].
static const double s
[second]
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.
void setSegmentNumber(baseType segment)
Set the sensor segment.
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.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
double sqrt(double a)
sqrt for double
Namespace to encapsulate code needed for simulation and reconstrucion of the SVD.
Abstract base class for different kinds of events.