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;
263 ROOT::Math::XYZVector hitMomentum(hit.getMomentum());
264 hitMomentum.SetX(std::isfinite(hitMomentum.X()) ? hitMomentum.X() : 0.0);
265 hitMomentum.SetY(std::isfinite(hitMomentum.Y()) ? hitMomentum.Y() : 0.0);
266 hitMomentum.SetZ(std::isfinite(hitMomentum.Z()) ? hitMomentum.Z() : 0.0);
268 double kineticEnergy(0.0);
269 double nielWeight(0.0);
272 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
277 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
282 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
287 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
292 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
296 nielWeight = std::isfinite(nielWeight) ? nielWeight : 0.0;
297 m_sensorData[currentSensorID].m_neutronFlux += nielWeight * stepLength / currentSensorThickness / currentSensorArea /
298 currentComponentTime *
c_smy;
302 ROOT::Math::XYZVector localPos(hit.getU(), hit.getV(), hit.getW());
303 const ROOT::Math::XYZVector globalPos =
pointToGlobal(currentSensorID, localPos);
304 float globalPosXYZ[3];
305 globalPos.GetCoordinates(globalPosXYZ);
306 ROOT::Math::XYZVector localMom = hit.getMomentum();
307 const ROOT::Math::XYZVector globalMom =
vectorToGlobal(currentSensorID, localMom);
308 float globalMomXYZ[3];
309 globalMom.GetCoordinates(globalMomXYZ);
313 hit.getU(), hit.getV(), globalPosXYZ, globalMomXYZ, kineticEnergy,
314 stepLength, nielWeight,
315 stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime /
Unit::s),
316 nielWeight * stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime /
Unit::s)
324 B2DEBUG(100,
"Fired strips");
325 currentSensorID.
setID(0);
326 double currentSensorUCut = 0;
327 double currentSensorVCut = 0;
329 std::map<VxdID, std::multiset<unsigned short> > firedStrips;
333 VxdID sensorID = digit.getSensorID();
334 if (sensorID != currentSensorID) {
335 currentSensorID = sensorID;
337 currentSensorUCut = eToADU(3.0 * info.getElectronicNoiseU());
338 currentSensorVCut = eToADU(3.0 * info.getElectronicNoiseV());
340 B2DEBUG(30,
"MaxCharge: " << digit.getMaxADCCounts() <<
" threshold: " << (digit.isUStrip() ? currentSensorUCut :
342 if (digit.getMaxADCCounts() < (digit.isUStrip() ? currentSensorUCut : currentSensorVCut))
continue;
343 B2DEBUG(30,
"Passed.");
345 VxdID writeID(sensorID);
346 if (digit.isUStrip())
350 firedStrips[writeID].insert(digit.getCellID());
353 for (
auto idAndSet : firedStrips) {
354 bool isUStrip = (idAndSet.first.getSegmentNumber() == 0);
355 VxdID sensorID = idAndSet.first;
358 int nFired_APV = idAndSet.second.size();
360 for (
auto it = idAndSet.second.begin();
361 it != idAndSet.second.end();
362 it = idAndSet.second.upper_bound(*it)) nFired++;
363 double fired = nFired / (currentComponentTime /
Unit::s) / sensorArea;
389 B2DEBUG(100,
"Occupancy");
390 currentSensorID.
setID(0);
391 double currentNoiseU = 0;
392 double currentNoiseV = 0;
395 for (
auto cluster : storeClsuters) {
396 VxdID sensorID = cluster.getSensorID();
397 if (currentSensorID != sensorID) {
398 currentSensorID = sensorID;
400 currentNoiseU = eToADU(info.getElectronicNoiseU());
401 currentNoiseV = eToADU(info.getElectronicNoiseV());
402 nStripsU = info.getUCells();
403 nStripsV = info.getVCells();
405 bool isU = cluster.isUCluster();
406 double snr = (isU) ? cluster.getCharge() / currentNoiseU : cluster.getCharge() / currentNoiseV;
407 int nStrips = (isU) ? nStripsU : nStripsV;
408 double tau_error = 45 / snr *
Unit::ns;
411 double w_acceptance = tau_acceptance / currentComponentTime;
413 double occupancy = 1.0 / nStrips * cluster.getSize();
415 m_sensorData[sensorID].m_occupancyU += w_acceptance * occupancy;
416 m_sensorData[sensorID].m_occupancyU_APV += w_acceptance_APV * occupancy;
418 m_sensorData[sensorID].m_occupancyV += w_acceptance * occupancy;
419 m_sensorData[sensorID].m_occupancyV_APV += w_acceptance_APV * occupancy;
425 cluster.isUCluster(), cluster.getPosition(), cluster.getSize(),
426 cluster.getCharge(), snr, w_acceptance, w_acceptance * occupancy,
427 w_acceptance_APV * occupancy
444 outfile.open(outfileName.c_str(), ios::out | ios::trunc);
445 outfile <<
"component_name\t"
446 <<
"component_time\t"
459 <<
"occupancy_u_APV\t"
465 << componentTime <<
"\t"
466 << vxdSensor.first.getLayerNumber() <<
"\t"
467 << vxdSensor.first.getLadderNumber() <<
"\t"
468 << vxdSensor.first.getSensorNumber() <<
"\t"
469 << vxdSensor.second.m_dose <<
"\t"
470 << vxdSensor.second.m_expo <<
"\t"
471 << vxdSensor.second.m_neutronFlux <<
"\t"
472 << vxdSensor.second.m_firedU <<
"\t"
473 << vxdSensor.second.m_firedV <<
"\t"
474 << vxdSensor.second.m_firedU_t <<
"\t"
475 << vxdSensor.second.m_firedV_t <<
"\t"
476 << vxdSensor.second.m_occupancyU <<
"\t"
477 << vxdSensor.second.m_occupancyV <<
"\t"
478 << vxdSensor.second.m_occupancyU_APV <<
"\t"
479 << 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.