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>
42 double 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);
60 SVDBackgroundModule::SVDBackgroundModule() :
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 currentSensorMass(0);
190 double currentSensorArea(0);
194 B2DEBUG(100,
"Expo and dose");
195 currentSensorID.
setID(0);
196 for (
const SVDSimHit& hit : storeSimHits) {
198 VxdID sensorID = hit.getSensorID();
199 if (sensorID != currentSensorID) {
200 currentSensorID = sensorID;
208 (hitEnergy /
Unit::J) / (currentSensorMass / 1000) * (
c_smy / currentComponentTime);
210 m_sensorData[currentSensorID].m_expo += hitEnergy / currentSensorArea / (currentComponentTime /
Unit::s);
212 const ROOT::Math::XYZVector localPos = hit.getPosIn();
213 const ROOT::Math::XYZVector globalPos =
pointToGlobal(currentSensorID, localPos);
214 float globalPosXYZ[3];
215 globalPos.GetCoordinates(globalPosXYZ);
218 hit.getPDGcode(), hit.getGlobalTime(),
219 localPos.X(), localPos.Y(), globalPosXYZ, hitEnergy,
220 (hitEnergy /
Unit::J) / (currentSensorMass / 1000) / (currentComponentTime /
Unit::s),
221 (hitEnergy /
Unit::J) / currentSensorArea / (currentComponentTime /
Unit::s)
229 B2DEBUG(100,
"Neutron flux");
230 currentSensorID.
setID(0);
232 VxdID sensorID = hit.getSensorID();
234 if (sensorID != currentSensorID) {
235 currentSensorID = sensorID;
241 ROOT::Math::XYZVector entryPos(hit.getEntryU(), hit.getEntryV(), hit.getEntryW());
242 ROOT::Math::XYZVector exitPos(hit.getExitU(), hit.getExitV(), hit.getExitW());
243 double stepLength = (exitPos - entryPos).
R();
249 double minDistance = 1.0e10;
250 for (
const SVDSimHit& related : storeSimHits) {
251 double distance = (entryPos - related.getPosIn()).
R();
252 if (distance < minDistance) {
253 minDistance = distance;
262 ROOT::Math::XYZVector hitMomentum(hit.getMomentum());
263 hitMomentum.SetX(std::isfinite(hitMomentum.X()) ? hitMomentum.X() : 0.0);
264 hitMomentum.SetY(std::isfinite(hitMomentum.Y()) ? hitMomentum.Y() : 0.0);
265 hitMomentum.SetZ(std::isfinite(hitMomentum.Z()) ? hitMomentum.Z() : 0.0);
267 double kineticEnergy(0.0);
268 double nielWeight(0.0);
271 kineticEnergy =
sqrt(hitMomentum.Mag2() + m0 * m0) - m0;
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;
295 nielWeight = std::isfinite(nielWeight) ? nielWeight : 0.0;
296 m_sensorData[currentSensorID].m_neutronFlux += nielWeight * stepLength / currentSensorThickness / currentSensorArea /
297 currentComponentTime *
c_smy;
301 ROOT::Math::XYZVector localPos(hit.getU(), hit.getV(), hit.getW());
302 const ROOT::Math::XYZVector globalPos =
pointToGlobal(currentSensorID, localPos);
303 float globalPosXYZ[3];
304 globalPos.GetCoordinates(globalPosXYZ);
305 ROOT::Math::XYZVector localMom = hit.getMomentum();
306 const ROOT::Math::XYZVector globalMom =
vectorToGlobal(currentSensorID, localMom);
307 float globalMomXYZ[3];
308 globalMom.GetCoordinates(globalMomXYZ);
312 hit.getU(), hit.getV(), globalPosXYZ, globalMomXYZ, kineticEnergy,
313 stepLength, nielWeight,
314 stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime /
Unit::s),
315 nielWeight * stepLength / currentSensorThickness / currentSensorArea / (currentComponentTime /
Unit::s)
323 B2DEBUG(100,
"Fired strips");
324 currentSensorID.
setID(0);
325 double currentSensorUCut = 0;
326 double currentSensorVCut = 0;
328 std::map<VxdID, std::multiset<unsigned short> > firedStrips;
332 VxdID sensorID = digit.getSensorID();
333 if (sensorID != currentSensorID) {
334 currentSensorID = sensorID;
336 currentSensorUCut = eToADU(3.0 * info.getElectronicNoiseU());
337 currentSensorVCut = eToADU(3.0 * info.getElectronicNoiseV());
339 B2DEBUG(30,
"MaxCharge: " << digit.getMaxADCCounts() <<
" threshold: " << (digit.isUStrip() ? currentSensorUCut :
341 if (digit.getMaxADCCounts() < (digit.isUStrip() ? currentSensorUCut : currentSensorVCut))
continue;
342 B2DEBUG(30,
"Passed.");
344 VxdID writeID(sensorID);
345 if (digit.isUStrip())
349 firedStrips[writeID].insert(digit.getCellID());
352 for (
auto idAndSet : firedStrips) {
353 bool isUStrip = (idAndSet.first.getSegmentNumber() == 0);
354 VxdID sensorID = idAndSet.first;
357 int nFired_APV = idAndSet.second.size();
359 for (
auto it = idAndSet.second.begin();
360 it != idAndSet.second.end();
361 it = idAndSet.second.upper_bound(*it)) nFired++;
362 double fired = nFired / (currentComponentTime /
Unit::s) / sensorArea;
388 B2DEBUG(100,
"Occupancy");
389 currentSensorID.
setID(0);
390 double currentNoiseU = 0;
391 double currentNoiseV = 0;
394 for (
auto cluster : storeClsuters) {
395 VxdID sensorID = cluster.getSensorID();
396 if (currentSensorID != sensorID) {
397 currentSensorID = sensorID;
399 currentNoiseU = eToADU(info.getElectronicNoiseU());
400 currentNoiseV = eToADU(info.getElectronicNoiseV());
401 nStripsU = info.getUCells();
402 nStripsV = info.getVCells();
404 bool isU = cluster.isUCluster();
405 double snr = (isU) ? cluster.getCharge() / currentNoiseU : cluster.getCharge() / currentNoiseV;
406 int nStrips = (isU) ? nStripsU : nStripsV;
407 double tau_error = 45 / snr *
Unit::ns;
410 double w_acceptance = tau_acceptance / currentComponentTime;
412 double occupancy = 1.0 / nStrips * cluster.getSize();
414 m_sensorData[sensorID].m_occupancyU += w_acceptance * occupancy;
415 m_sensorData[sensorID].m_occupancyU_APV += w_acceptance_APV * occupancy;
417 m_sensorData[sensorID].m_occupancyV += w_acceptance * occupancy;
418 m_sensorData[sensorID].m_occupancyV_APV += w_acceptance_APV * occupancy;
424 cluster.isUCluster(), cluster.getPosition(), cluster.getSize(),
425 cluster.getCharge(), snr, w_acceptance, w_acceptance * occupancy,
426 w_acceptance_APV * occupancy
443 outfile.open(outfileName.c_str(), ios::out | ios::trunc);
444 outfile <<
"component_name\t"
445 <<
"component_time\t"
458 <<
"occupancy_u_APV\t"
464 << componentTime <<
"\t"
465 << vxdSensor.first.getLayerNumber() <<
"\t"
466 << vxdSensor.first.getLadderNumber() <<
"\t"
467 << vxdSensor.first.getSensorNumber() <<
"\t"
468 << vxdSensor.second.m_dose <<
"\t"
469 << vxdSensor.second.m_expo <<
"\t"
470 << vxdSensor.second.m_neutronFlux <<
"\t"
471 << vxdSensor.second.m_firedU <<
"\t"
472 << vxdSensor.second.m_firedV <<
"\t"
473 << vxdSensor.second.m_firedU_t <<
"\t"
474 << vxdSensor.second.m_firedV_t <<
"\t"
475 << vxdSensor.second.m_occupancyU <<
"\t"
476 << vxdSensor.second.m_occupancyV <<
"\t"
477 << vxdSensor.second.m_occupancyU_APV <<
"\t"
478 << 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.
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.
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.