gdynamicDigitization
Loading...
Searching...
No Matches
gDosimeterDigitization.cc
Go to the documentation of this file.
1
12#include <fstream>
13
14// See header for API docs.
16 // Time window is the width of one electronics time cell (unit follows the convention
17 // used by the rest of the digitization chain; typically ns).
18 double timeWindow = 10; // electronic readout time-window of the detector
19 double gridStartTime = 0; // defines the windows grid
20 auto hitBitSet = HitBitSet("000001"); // defines what information to be stored in the hit
21
22 // Readout specs are immutable after initialization and shared by all processed hits.
23 readoutSpecs = std::make_shared<GReadoutSpecs>(timeWindow, gridStartTime, hitBitSet, log);
24
25 return true;
26}
27
28// See header for API docs.
29std::unique_ptr<GDigitizedData> GDosimeterDigitization::digitizeHitImpl(GHit* ghit, [[maybe_unused]] size_t hitn) {
31
32 // Expected to be a single-identity detector: take the first identity entry.
33 GIdentifier identity = ghit->getGID().front();
34
35 auto gdata = std::make_unique<GDigitizedData>(gopts, ghit);
36
37 // Store the detector identity and the total deposited energy.
38 gdata->includeVariable(identity.getName(), identity.getValue());
39 gdata->includeVariable("eTot", ghit->getTotalEnergyDeposited());
40
41 // Per-step information used to build the NIEL-weight.
42 auto pids = ghit->getPids();
43 auto pEnergies = ghit->getEs();
44
45 double nielWeight = 0;
46
47 // Accumulate NIEL factor step-by-step. This treats each step independently and sums
48 // the interpolated factors for supported particle species.
49 for (size_t stepIndex = 0; stepIndex < pids.size(); stepIndex++) {
50 // Use absolute PID so negative particle IDs (e.g. -11) are handled.
51 int pid = std::abs(pids[stepIndex]);
52
53 // Only a few particle types are supported by the calibration data files.
54 if (pid == 11 || pid == 211 || pid == 2212 || pid == 2112) {
55 // Convert from total energy to kinetic-like quantity used by the NIEL tables
56 // by subtracting the particle rest mass (in MeV).
57 double E = pEnergies[stepIndex] - pMassMeV[pid];
58 nielWeight += getNielFactorForParticleAtEnergy(pid, E);
59 }
60 }
61
62 gdata->includeVariable("nielWeight", nielWeight);
63
64 return gdata;
65}
66
67// See header for API docs.
68bool GDosimeterDigitization::loadConstantsImpl([[maybe_unused]] int runno,
69 [[maybe_unused]] std::string const& variation) {
70 // Map from particle id to the calibration filename (text, 2 columns).
71 std::map<int, std::string> nielDataFiles;
72 nielDataFiles[11] = "niel_electron.txt";
73 nielDataFiles[211] = "niel_pion.txt";
74 nielDataFiles[2112] = "niel_neutron.txt";
75 nielDataFiles[2212] = "niel_proton.txt";
76
77 // GEMC installation root used to locate plugin data.
78 std::filesystem::path gemcRoot = gutilities::gemc_root();
79
80 for (const auto& [pid, filename] : nielDataFiles) {
81 std::string dataFileWithPath = gemcRoot.string() + "/dosimeterData" + "/Niel/" + filename;
82
83 std::ifstream inputfile(dataFileWithPath);
84 if (!inputfile) {
85 // On Linux, tests may run from the build directory, where plugin data lives under
86 // gdynamicDigitization/...
87 dataFileWithPath = gemcRoot.string() + "/gdynamicDigitization/dosimeterData" + "/Niel/" + filename;
88 inputfile.open(dataFileWithPath);
89 if (!inputfile) {
90 log->error(EC__FILENOTFOUND, "Error loading dosimeter data for pid <", pid, "> from file ",
91 dataFileWithPath);
92 }
93 }
94
95 log->info(0, " Loading dosimeter data for pid <", pid, "> from file ", dataFileWithPath);
96
97 // Expected file format: repeated pairs (factor, energyMeV).
98 double p0, p1;
99 while (inputfile >> p0 >> p1) {
100 nielfactorMap[pid].push_back(p0);
101 E_nielfactorMap[pid].push_back(p1);
102 }
103 inputfile.close();
104 }
105
106 // Particle rest masses used by the interpolation routine (MeV).
107 pMassMeV[11] = 0.510;
108 pMassMeV[211] = 139.570;
109 pMassMeV[2112] = 939.565;
110 pMassMeV[2212] = 938.272;
111
112 return true;
113}
114
115// See header for API docs.
116double GDosimeterDigitization::getNielFactorForParticleAtEnergy(int pid, double energyMeV) {
117 const auto niel_N = nielfactorMap[pid].size();
118
119 // Guard against missing/empty calibration data.
120 // (If this happens, it indicates loadConstantsImpl did not populate the maps as expected.)
121 if (niel_N == 0) {
122 log->error(EC__FILENOTFOUND, "NIEL tables are empty for pid <", pid, ">. Did loadConstantsImpl fail?");
123 return 0.0;
124 }
125
126 // j is the first index for which energyMeV < E_table[j]. Initialize to "past the end".
127 size_t j = niel_N;
128
129 for (size_t i = 0; i < niel_N; i++) {
130 if (energyMeV < E_nielfactorMap[pid][i]) {
131 j = i;
132 break;
133 }
134 }
135
136 double value = 0.0;
137
138 if (j > 0 && j < niel_N) {
139 // Linear interpolation between (j-1) and j.
140 const auto nielfactor_low = nielfactorMap[pid][j - 1];
141 const auto nielfactor_high = nielfactorMap[pid][j];
142 const auto energy_low = E_nielfactorMap[pid][j - 1];
143 const auto energy_high = E_nielfactorMap[pid][j];
144
145 value = nielfactor_low +
146 (nielfactor_high - nielfactor_low) / (energy_high - energy_low) * (energyMeV - energy_low);
147 }
148 else if (j == 0) {
149 // energy below the first threshold: clamp to first value.
150 value = nielfactorMap[pid].front();
151 }
152 else {
153 // energy beyond the last threshold: clamp to last value.
154 value = nielfactorMap[pid].back();
155 }
156
157 log->debug(NORMAL, " pid: ", pid, ", j: ", j, ", value: ", value, ", energy: ", energyMeV);
158
159 return value;
160}
std::shared_ptr< GLogger > log
bool defineReadoutSpecsImpl() override
Defines readout specifications for dosimeter digitization.
std::unique_ptr< GDigitizedData > digitizeHitImpl(GHit *ghit, size_t hitn) override
Digitizes a hit for dosimeter detectors.
bool loadConstantsImpl(int runno, std::string const &variation) override
Loads digitization constants for dosimeter digitization.
std::shared_ptr< GOptions > gopts
Options used by the digitization plugin instance.
void check_if_log_defined() const
Ensures options/logging are configured before plugin methods run.
std::shared_ptr< const GReadoutSpecs > readoutSpecs
Readout specs are created during initialization and treated as immutable.
std::vector< int > getPids() const
std::vector< double > getEs() const
std::vector< GIdentifier > getGID() const
double getTotalEnergyDeposited()
void debug(debug_type type, Args &&... args) const
void info(int level, Args &&... args) const
void error(int exit_code, Args &&... args) const
std::bitset< NHITBITS > HitBitSet
Internal digitization plugins shipped with the gdynamic digitization library.
#define EC__FILENOTFOUND
std::filesystem::path gemc_root()
std::string getName() const
int getValue() const