Jpp 20.0.0-72-g597b30bc9
the software that should make you happy
Loading...
Searching...
No Matches
JK40DefaultSimulatorInterface.hh
Go to the documentation of this file.
1#ifndef __JDETECTOR__JK40DEFAULTSIMULATORINTERFACE__
2#define __JDETECTOR__JK40DEFAULTSIMULATORINTERFACE__
3
4#include <utility>
5#include <vector>
6#include <set>
7
8#include "TRandom3.h"
9
11
16
17#include "JMath/JMathToolkit.hh"
18#include "JLang/JComparator.hh"
19#include "JLang/JException.hh"
20#include "JLang/JCC.hh"
21
22
23/**
24 * \author mdejong
25 */
26
27namespace JDETECTOR {}
28namespace JPP { using namespace JDETECTOR; }
29
30namespace JDETECTOR {
31
33
34
35 /**
36 * Default K40 simulator interface.
37 *
38 * This class provides for a default implementation of the JK40Simulator interface
39 * which is based on a set of virtual methods.
40 * These methods constitute a user interface to the K40 background simulation.
41 */
43 public JK40Simulator
44 {
45 /**
46 * Auxiliary data structure for value with associated probability.
47 */
48 template<class T>
50 T v; //!< value
51 double P; //!< probability
52 };
53
54
55 public:
56 /**
57 * Auxiliary data structure for selecting values according associated probabilities.
58 */
59 template<class T>
60 struct cdf_type :
61 public std::vector< probability_type<T> >
62 {
63 /**
64 * Get random value according associated probabilities.
65 *
66 * \param rv random vavlue [0,1>
67 * \return value
68 */
69 const T& operator()(const double rv) const
70 {
71 const double P = this->rbegin()->P * rv;
72
73 size_t first = 0;
74 size_t count = this->size();
75
76 for (size_t i, step; count != 0; ) {
77
78 step = count / 2;
79 i = first + step;
80
81 if ((*this)[i].P < P) {
82 first = ++i;
83 count -= step + 1;
84 } else {
85 count = step;
86 }
87 }
88
89 return (*this)[first].v;
90 }
91
92
93 /**
94 * Put value with given probability.
95 *
96 * \param v value
97 * \param P probability
98 */
99 void put(const T& v, const double P)
100 {
101 if (this->empty())
102 this->push_back({v, P});
103 else
104 this->push_back({v, this->rbegin()->P + P});
105 }
106 };
107
108
109 protected:
110 /**
111 * Default constructor.
112 */
115
116
117 public:
118 /**
119 * Get singles rate as a function of PMT.
120 *
121 * \param pmt PMT identifier
122 * \return rate [Hz]
123 */
124 virtual double getSinglesRate(const JPMTIdentifier& pmt) const = 0;
125
126
127 /**
128 * Get multiples rate as a function of optical module.
129 *
130 * \param module optical module identifier
131 * \param M multiplicity (M >= 2)
132 * \return rate [Hz]
133 */
134 virtual double getMultiplesRate(const JModuleIdentifier& module, const int M) const = 0;
135
136
137 /**
138 * Get probability of coincidence.
139 *
140 * \param ct cosine space angle between PMT axes
141 * \return probability
142 */
143 virtual double getProbability(const double ct) const = 0;
144
145
146 /**
147 * Get mixed L0 (lower module) and L1 (upper module) rate [Hz]
148 *
149 * \return rate [Hz]
150 */
151 virtual double getL01Rate() const = 0;
152
153
154 /**
155 * Get mixed L1 (lower module) and L0 (upper module) rate [Hz]
156 *
157 * \return rate [Hz]
158 */
159 virtual double getL10Rate() const = 0;
160
161
162 /**
163 * Generate hits.
164 *
165 * \param module module
166 * \param period time window [ns]
167 * \param output background data
168 */
169 virtual void generateHits(const JModule& module,
170 const JTimeRange& period,
171 JModuleData& output) const override
172 {
173 using namespace std;
174 using namespace JPP;
175
176 const size_t N = module.size();
177
178
179 // generate singles
180
181 for (size_t pmt = 0; pmt != N; ++pmt) {
182
183 const double rateL0_Hz = getSinglesRate(JPMTIdentifier(module.getID(), pmt));
184
185 if (rateL0_Hz > 0.0) {
186
187 const bool asap = (output[pmt].size() != 0); // sort as soon as possible
188
189 const double t_ns = 1.0e9 / rateL0_Hz; // interval period [ns]
190
191 for (double t1 = period.getLowerLimit() + gRandom->Exp(t_ns); t1 < period.getUpperLimit(); t1 += gRandom->Exp(t_ns)) {
192 output[pmt].push_back(JPMTSignal(t1, -1)); // see JPMTSignalProcessorInterface::operator()
193 }
194
195 if (asap) {
196 output[pmt].sort();
197 }
198 }
199 }
200
201
202 // generate coincidences
203
204 double totalRateL1_Hz = 0.0;
205
206 // multiples rate as a function of the multiplicity - index i corresponds to multiplicity M = i + 2
207
208 vector<double> rateL1_Hz(N, 0.0);
209
210 for (size_t i = 0; i != N; ++i) {
211 totalRateL1_Hz += rateL1_Hz[i] = getMultiplesRate(module.getID(), i + 2);
212 }
213
214 if (totalRateL1_Hz > 0.0) {
215
217
218 cdf_type<pair_type> probablityL1;
219
220 const double t_ns = 1.0e9 / totalRateL1_Hz; // interval period [ns]
221
222 double t1 = period.getLowerLimit() + gRandom->Exp(t_ns);
223
224 if (t1 < period.getUpperLimit()) {
225
226 // configure pair-wise propabilities
227
228 for (size_t pmt1 = 0; pmt1 != N; ++pmt1) {
229 for (size_t pmt2 = 0; pmt2 != pmt1; ++pmt2) {
230
231 const double ct = getDot(module[pmt1].getDirection(), module[pmt2].getDirection());
232 const double p = getProbability(ct);
233
234 probablityL1.put({pmt1, pmt2}, p);
235 }
236 }
237
238 for ( ; t1 < period.getUpperLimit(); t1 += gRandom->Exp(t_ns)) {
239
240 try {
241
242 // generate two-fold coincidence
243
244 const pair_type& pair = probablityL1(gRandom->Rndm());
245
246 output[pair.first ].insert(JPMTSignal(gRandom->Gaus(t1, getSigma()), 1));
247 output[pair.second].insert(JPMTSignal(gRandom->Gaus(t1, getSigma()), 1));
248
249 // generate larger than two-fold coincidences, if any
250
251 size_t M = 0;
252
253 for (double R = totalRateL1_Hz * gRandom->Rndm(); M != N && (R -= rateL1_Hz[M]) > 0.0; ++M) {}
254
255 if (M != 0) {
256
257 set<size_t> buffer = { pair.first , pair.second }; // hit PMTs
258
259 for ( ; M != 0; --M) {
260
261 vector<double> probability1D(N, 1.0);
262
263 double P = 0.0;
264
265 for (size_t i = 0; i != N; ++i) {
266
267 if (buffer.count(i) == 0) {
268
269 for (set<size_t>::const_iterator pmt = buffer.begin(); pmt != buffer.end(); ++pmt) {
270
271 const double ct = getDot(module[i].getDirection(), module[*pmt].getDirection());
272
273 probability1D[i] *= getProbability(ct);
274 }
275
276 P += probability1D[i];
277
278 } else {
279
280 probability1D[i] = 0.0;
281 }
282 }
283
284 if (P > 0.0) {
285
286 size_t pmt = 0;
287
288 for (P *= gRandom->Rndm(); pmt != N && (P -= probability1D[pmt]) > 0.0; ++pmt) {}
289
290 if (pmt != N) {
291
292 output[pmt].insert(JPMTSignal(gRandom->Gaus(t1, getSigma()), 1));
293
294 buffer.insert(pmt);
295 }
296
297 } else {
298
299 break;
300 }
301 }
302 }
303 }
304 catch (const JNumericalPrecision&) {}
305 }
306 }
307 }
308 }
309
310
311 /**
312 * Generate mixed-L1/L0 hits.
313 *
314 * \param input module pair
315 * \param period time window [ns]
316 * \param output background data
317 */
318 virtual void generateHits(const module_pair& input,
319 const JTimeRange& period,
320 const module_data& output) const override
321 {
322 using namespace JPP;
323
324 const double rate_Hz = getL01Rate() + getL10Rate();
325
326 if (rate_Hz > 0.0) {
327
328 if (!input.first.empty() && !input.second.empty()) {
329
330 if (neighbours(input.first, input.second)) {
331
332 // locate decay in between modules
333
334 const double ts = 0.8 * fabs(input.first.getZ() - input.second.getZ()) * getInverseSpeedOfLight() * getIndexOfRefraction();
335
336 const JModule& input_lower = (input.first.getFloor() == input.second.getFloor() - 1 ? input.first : input.second);
337 const JModule& input_upper = (input.first.getFloor() == input.second.getFloor() + 1 ? input.first : input.second);
338
339 JModuleData& output_lower = (input.first.getFloor() == input.second.getFloor() - 1 ? output.first : output.second);
340 JModuleData& output_upper = (input.first.getFloor() == input.second.getFloor() + 1 ? output.first : output.second);
341
342 cdf_type<size_t> probability_lower;
343 cdf_type<size_t> probability_upper;
344
345 // use angular dependence of coincidence rate with respect to z-axis
346
347 for (size_t i = 0; i != input_lower.size(); ++i) { probability_lower.put(i, this->getProbability(+1.0 * input_lower[i].getDZ())); }
348 for (size_t i = 0; i != input_upper.size(); ++i) { probability_upper.put(i, this->getProbability(-1.0 * input_upper[i].getDZ())); }
349
350 const double t_ns = 1.0e9 / rate_Hz; // interval period [ns]
351
352 for (double t1 = period.getLowerLimit() + gRandom->Exp(t_ns); t1 < period.getUpperLimit(); t1 += gRandom->Exp(t_ns)) {
353
354 const bool L01 = gRandom->Uniform(0.0, rate_Hz) < getL01Rate();
355
356 JModuleData& output_L1 = (L01 ? output_upper : output_lower);
357 JModuleData& output_L0 = (L01 ? output_lower : output_upper);
358
359 cdf_type<size_t>& probability_L1 = (L01 ? probability_upper : probability_lower);
360 cdf_type<size_t>& probability_L0 = (L01 ? probability_lower : probability_upper);
361
362 output_L1[probability_L1(gRandom->Rndm())].insert(JPMTSignal(gRandom->Gaus(t1, getSigma()), 1));
363 output_L1[probability_L1(gRandom->Rndm())].insert(JPMTSignal(gRandom->Gaus(t1, getSigma()), 1));
364
365 output_L0[probability_L0(gRandom->Rndm())].insert(JPMTSignal(gRandom->Gaus(t1 + ts, getSigma()), 1));
366 }
367 }
368 }
369 }
370 }
371
372
373 /**
374 * Get intrinsic time smearing of K40 coincidences.
375 *
376 * \return sigma [ns]
377 */
378 static double getSigma()
379 {
380 return get_sigma();
381 }
382
383
384 /**
385 * Set intrinsic time smearing of K40 coincidences.
386 *
387 * \param sigma sigma [ns]
388 */
389 static void setSigma(const double sigma)
390 {
391 get_sigma() = sigma;
392 }
393
394 private:
395 /**
396 * Get intrinsic time smearing of K40 coincidences.
397 *
398 * \return sigma [ns]
399 */
400 static double& get_sigma()
401 {
402 static double sigma = 0.5;
403
404 return sigma;
405 }
406 };
407}
408
409#endif
Compiler version dependent expressions, macros, etc.
Exceptions.
Binary methods for member methods.
Physics constants.
static double & get_sigma()
Get intrinsic time smearing of K40 coincidences.
virtual void generateHits(const JModule &module, const JTimeRange &period, JModuleData &output) const override
Generate hits.
static double getSigma()
Get intrinsic time smearing of K40 coincidences.
virtual void generateHits(const module_pair &input, const JTimeRange &period, const module_data &output) const override
Generate mixed-L1/L0 hits.
static void setSigma(const double sigma)
Set intrinsic time smearing of K40 coincidences.
virtual double getSinglesRate(const JPMTIdentifier &pmt) const =0
Get singles rate as a function of PMT.
virtual double getMultiplesRate(const JModuleIdentifier &module, const int M) const =0
Get multiples rate as a function of optical module.
virtual double getL01Rate() const =0
Get mixed L0 (lower module) and L1 (upper module) rate [Hz].
virtual double getL10Rate() const =0
Get mixed L1 (lower module) and L0 (upper module) rate [Hz].
virtual double getProbability(const double ct) const =0
Get probability of coincidence.
Interface for simulation of K40 background.
int getFloor() const
Get floor number.
Definition JLocation.hh:146
Data structure for a composite optical module.
Definition JModule.hh:76
double getZ() const
Get z position.
Definition JVector3D.hh:115
Exception for numerical precision error.
Auxiliary class for object identification.
Definition JObjectID.hh:25
int getID() const
Get identifier.
Definition JObjectID.hh:50
T getLowerLimit() const
Get lower limit.
Definition JRange.hh:202
T getUpperLimit() const
Get upper limit.
Definition JRange.hh:213
file Auxiliary data structures and methods for detector calibration.
Definition JAnchor.hh:12
bool neighbours(const JLocation &first, const JLocation &second)
Check if two locations are neighbours.
Definition JLocation.hh:263
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
Auxiliary data structure for selecting values according associated probabilities.
const T & operator()(const double rv) const
Get random value according associated probabilities.
void put(const T &v, const double P)
Put value with given probability.
Auxiliary data structure for value with associated probability.
Auxiliary data structure for argument parsing of module data.
Auxiliary data structure for argument parsing of module pair.
Data structure for PMT analogue signal.
Data structure for a pair of indices.