Jpp 21.0.0-rc.3
the software that should make you happy
Loading...
Searching...
No Matches
JPMTAnalogueSignalProcessor.hh
Go to the documentation of this file.
1#ifndef __JDETECTOR__JPMTANALOGUESIGNALPROCESSOR__
2#define __JDETECTOR__JPMTANALOGUESIGNALPROCESSOR__
3
4#include <istream>
5#include <cmath>
6#include <limits>
7
8#include "TRandom3.h"
9
10#include "JLang/JException.hh"
11#include "JMath/JGauss.hh"
17
18/**
19 * \file
20 *
21 * PMT analogue signal processor.
22 * \author mdejong & bjjung & evancampenhout
23 */
24namespace JDETECTOR {
25
27
28
29 /**
30 * PMT analogue signal processor.
31 *
32 * This class provides for an implementation of the JDETECTOR::JPMTSignalProcessorInterface
33 * using a specific model for the analogue pulse of the PMT.\n
34 * In this, the leading edge of the analogue pulse from the PMT is assumed to be a Gaussian and the tail an exponential.\n
35 * The width of the Gaussian is referred to as the rise time and
36 * the inverse slope of the exponential to the decay time.\n
37 * The two functions are matched at a point where the values and first derivatives are identical.\n
38 *
39 * Note that the decay time is related to the rise time via the specification JDETECTOR::TIME_OVER_THRESHOLD_NS.
40 *
41 * The charge distribution is assumed to be a Gaussian which is centered at the specified gain
42 * and truncated by the specified threshold.
43 *
44 * The transit times are generated according the specified spread as follows.
45 * - If the specified transit-time spread (TTS) is negative,
46 * the transit times are generated according to measurements (see method JDETECTOR::getTransitTime).\n
47 * In this, the negated integral value of the TTS corresponds to the option
48 * which in turn corresponds to the detector identifier of the measurements.
49 * - If the specified TTS is positive,
50 * the transit times are generated according a Gaussian with a sigma equals to the given TTS.
51 * - If the TTS is zero, the transit times are generated without any spread.
52 */
55 public JPMTParameters
56 {
57 /**
58 * Threshold domain specifiers.
59 */
61 BELOW_THRESHOLD = -1, //!< below threshold
62 THRESHOLDBAND = 0, //!< inside threshold band
63 ABOVE_THRESHOLD = 2 //!< above threshold
64 };
65
66
67 /**
68 * Amplification mode specifiers.
69 */
70 enum class JAmplificationMode {
71 Nominal, // no underamplification
72 Mixed, // underamplification
73 UnderAmplified // complete underamplification
74 };
75
76
77 /**
78 * Analogue pulse domain specifiers.
79 */
81 Gaussian, // Gaussian
82 Exponential, // Gaussian + exponential
83 Linear // Gaussian + exponential + linear
84 };
85
86
87 /**
88 * Constructor.
89 *
90 * \param parameters PMT parameters
91 */
94 JPMTParameters(parameters),
95 decayTime_ns(0.0),
96 t1(0.0),
97 y1(0.0),
98 x1(std::numeric_limits<double>::max())
99 {
100 configure();
101 }
102
103
104 /**
105 * Configure internal parameters.
106 *
107 * This method provides the implementations for
108 * - matching of the leading edge of the analogue pulse (Gaussian) and the tail (exponential); and
109 * - determination of number of photo-electrons above which the time-over-threshold
110 * linearly depends on the number of photo-electrons (apart from saturation).
111 *
112 * Note that this method will throw an error if the value of the rise time (i.e.\ width of the Gaussian)
113 * is too large with respect to the specification JDETECTOR::TIME_OVER_THRESHOLD_NS.
114 */
116 {
117 static const int N = 100;
118 static const double precision = 1.0e-4;
119
120 // check thresholdband
121
122 if (threshold - thresholdBand < getTH0()) {
123 THROW(JValueOutOfRange, "JPMTAnalogueSignalProcessor::configure(): Invalid thresholdband [npe] " << thresholdBand);
124 }
125
126 // check rise time
127
129 THROW(JValueOutOfRange, "JPMTAnalogueSignalProcessor::configure(): Invalid rise time [ns] " << riseTime_ns);
130 }
131
132 // check probability for under-amplified signal
133
134 if (PunderAmplified < 0.0) {
135 THROW(JValueOutOfRange, "JPMTAnalogueSignalProcessor::configure(): Invalid probability of under-amplification " << PunderAmplified);
136 }
137
138 // decay time
139
140 const double y = -log(threshold);
141
142 const double a = y;
143 const double b = riseTime_ns * sqrt(2.0*y) - TIME_OVER_THRESHOLD_NS;
144 const double c = 0.5*riseTime_ns*riseTime_ns;
145 const double Q = b*b - 4.0*a*c;
146
147 if (Q > 0.0)
148 decayTime_ns = (-b + sqrt(Q)) / (2.0*a);
149 else
150 decayTime_ns = -b / (2.0*a);
151
152 // fix matching of Gaussian and exponential
153
154 const double x = riseTime_ns / decayTime_ns;
155
156 t1 = riseTime_ns*x;
157 y1 = exp(-0.5*x*x);
158
159 // determine transition point to linear dependence of time-over-threshold as a function of number of photo-electrons
160
161 const double xs = saturation; // disable saturation
162
163 saturation = 1.0e50;
164
165 x1 = std::numeric_limits<double>::max(); // disable linearisation
166
167 double xmin = 1.0;
168 double xmax = 1.0 / (getDerivative(1.0) * slope);
169
170 for (int i = 0; i != N; ++i) {
171
172 const double x = 0.5 * (xmin + xmax);
173 const double u = getDerivative(x) * slope;
174
175 if (fabs(1.0 - u) < precision) {
176 break;
177 }
178
179 if (u < 1.0)
180 xmin = x;
181 else
182 xmax = x;
183 }
184
185 x1 = 0.5 * (xmin + xmax);
186
187 saturation = xs; // restore saturation
188 }
189
190
191 /**
192 * Get decay time.
193 *
194 * \return decay time [ns]
195 */
196 double getDecayTime() const
197 {
198 return decayTime_ns;
199 }
200
201
202 /**
203 * Get time at transition point from Gaussian to exponential.
204 *
205 * \return time [ns]
206 */
207 double getT1() const
208 {
209 return t1;
210 }
211
212
213 /**
214 * Get amplitude at transition point from Gaussian to exponential.
215 *
216 * \return amplitude [npe]
217 */
218 double getY1() const
219 {
220 return y1;
221 }
222
223
224 /**
225 * Get transition point from a model-dependent to linear relation between time-over-threshold and number of photo-electrons.
226 *
227 * \return number of photo-electrons [npe]
228 */
230 {
231 return x1;
232 }
233
234
235 /**
236 * Get amplitude at given time for a one photo-electron pulse.
237 *
238 * \param t1_ns time [ns]
239 * \return amplitude [npe]
240 */
241 double getAmplitude(const double t1_ns) const
242 {
243 if (t1_ns < t1) {
244
245 const double x = t1_ns / riseTime_ns;
246
247 return exp(-0.5*x*x); // Gaussian
248
249 } else {
250
251 const double x = t1_ns / decayTime_ns;
252
253 return exp(-x) / y1; // exponential
254 }
255 }
256
257
258 /**
259 * Get time to pass from threshold to top of analogue pulse.\n
260 * In this, the leading edge of the analogue pulse is assumed to be Gaussian.
261 *
262 * \param npe number of photo-electrons
263 * \param th threshold [npe]
264 * \return time [ns]
265 */
266 double getRiseTime(const double npe, const double th) const
267 {
268 return riseTime_ns * sqrt(2.0*log(npe/th)); // Gaussian
269 }
270
271
272 /**
273 * Get time to pass from top of analogue pulse to threshold.\n
274 * In this, the trailing edge of the analogue pulse is assumed to be exponential.
275 *
276 * \param npe number of photo-electrons
277 * \param th threshold [npe]
278 * \return time [ns]
279 */
280 double getDecayTime(const double npe, const double th) const
281 {
282 if (npe*y1 > th)
283 return decayTime_ns * (log(npe/th) - log(y1)); // exponential
284 else
285 return getRiseTime(npe, th); // Gaussian
286 }
287
288
289 /**
290 * Get maximal rise time for given threshold.
291 *
292 * Note that the rise time is entirely constrained by the specification JDETECTOR::TIME_OVER_THRESHOLD_NS.
293 *
294 * \param th threshold [npe]
295 * \return rise time [ns]
296 */
297 static double getMaximalRiseTime(const double th)
298 {
299 if (th > 0.0 && th < 1.0)
300 return 0.5 * TIME_OVER_THRESHOLD_NS / sqrt(-2.0*log(th));
301 else
302 THROW(JValueOutOfRange, "JPMTAnalogueSignalProcessor::getMaximalRiseTime(): Invalid threshold " << th);
303 }
304
305
306 /**
307 * Get time-over-threshold with saturation.
308 *
309 * \param tot_ns time-over-threshold without saturation
310 * \return time-over-threshold with saturation
311 */
312 double applySaturation(const double tot_ns) const
313 {
314 return saturation / sqrt(tot_ns*tot_ns + saturation*saturation) * tot_ns;
315 }
316
317
318 /**
319 * Get time-over-threshold without saturation.
320 *
321 * \param tot_ns time-over-threshold with saturation
322 * \return time-over-threshold without saturation
323 */
324 double removeSaturation(const double tot_ns) const
325 {
326 if (tot_ns < saturation)
327 return saturation / sqrt(saturation*saturation - tot_ns*tot_ns) * tot_ns;
328 else
329 return std::numeric_limits<double>::max();
330 }
331
332
333 /**
334 * Get derivative of saturation factor.
335 *
336 * \param tot_ns time-over-threshold without saturation
337 * \return derivative of saturation factor
338 */
339 double getDerivativeOfSaturation(const double tot_ns) const
340 {
341 return saturation * saturation * saturation / ((saturation*saturation + tot_ns*tot_ns) * sqrt(saturation*saturation + tot_ns*tot_ns));
342 }
343
344
345 /**
346 * Get gain.
347 *
348 * \param NPE number of photo-electrons
349 * \return gain
350 */
351 double getGain(int NPE) const
352 {
353 return ((double) NPE) * gain;
354 }
355
356
357 /**
358 * Get gain spread for given number of photo-electrons.
359 *
360 * \return gain spread
361 */
362 double getGainSpread() const
363 {
364 return sqrt(gain) * gainSpread;
365 }
366
367
368 /**
369 * Get gain spread for given number of photo-electrons.
370 *
371 * \param NPE number of photo-electrons
372 * \return gain spread
373 */
374 double getGainSpread(int NPE) const
375 {
376 return sqrt((double) NPE) * getGainSpread();
377 }
378
379
380 /**
381 * Get gain of underamplified pulses.
382 *
383 * \return gain of underamplified pulses
384 */
386 {
387 return gain * gainSpread * gainSpread;
388 }
389
390
391 /**
392 * Get gain of underamplified pulses.
393 *
394 * \param NPE number of photo-electrons
395 * \return gain of underamplified pulses
396 */
397 double getUnderamplifiedGain(int NPE) const
398 {
399 return ((double) NPE) * getUnderamplifiedGain();
400 }
401
402
403 /**
404 * Get gain spread of underamplified pulses.
405 *
406 * \return gain spread of underamplified pulses
407 */
409 {
410 return sqrt(gain) * gainSpread * gainSpread;
411 }
412
413
414 /**
415 * Get gain spread of underamplified pulses.
416 *
417 * \param NPE number of photo-electrons
418 * \return gain spread of underamplified pulses
419 */
420 double getUnderamplifiedGainSpread(int NPE) const
421 {
422 return sqrt((double) NPE) * getUnderamplifiedGainSpread();
423 }
424
425
426 /**
427 * Set PMT parameters.
428 *
429 * \param parameters PMT parameters
430 */
431 void setPMTParameters(const JPMTParameters& parameters)
432 {
433 static_cast<JPMTParameters&>(*this).setPMTParameters(parameters);
434
435 configure();
436 }
437
438
439 /**
440 * Read PMT signal from input.
441 *
442 * \param in input stream
443 * \param object PMT signal
444 * \return input stream
445 */
446 friend std::istream& operator>>(std::istream& in, JPMTAnalogueSignalProcessor& object)
447 {
448 in >> static_cast<JPMTParameters&>(object);
449
450 object.configure();
451
452 return in;
453 }
454
455
456 /**
457 * Get threshold domain.
458 *
459 * \param npe number of photo-electrons
460 * \return threshold domain
461 */
462 JThresholdDomain getThresholdDomain(const double npe) const
463 {
464 if (npe > threshold) {
465
466 return ABOVE_THRESHOLD;
467
468 } else if (npe > threshold - thresholdBand) {
469
470 return THRESHOLDBAND;
471
472 } else {
473
474 return BELOW_THRESHOLD;
475 }
476 }
477
478
479 /**
480 * Get amplification mode.
481 *
482 * \return amplification mode
483 */
485 {
486 if (PunderAmplified <= 0.0) {
487
489
490 } else if (PunderAmplified < 1.0) {
491
493
494 } else {
495
497 }
498 }
499
500
501 /**
502 * Get charge domain.
503 *
504 * \param npe observed number of photo-electrons
505 */
506 JAnaloguePulseDomain getChargeDomain(const double npe) const
507 {
508 if (npe*y1 <= threshold) {
509
511
512 } else if (npe <= getStartOfLinearisation()) {
513
515
516 } else {
517
519 }
520 }
521
522
523 /**
524 * Get time-over-threshold domain.
525 *
526 * \param tot_ns time-over-threshold (with saturation) [ns]
527 */
528 JAnaloguePulseDomain getToTDomain(const double tot_ns) const
529 {
530 const double tot = removeSaturation(tot_ns);
531 const double TOT = (getRiseTime (getStartOfLinearisation(), threshold) +
533
534 if (tot <= 2*getRiseTime(threshold/y1,threshold)) { // Gaussian + Gaussian
535
537
538 } else if (tot <= TOT) { // Gaussian + Exponential
539
541
542 } else { // linear
543
545 }
546 }
547
548
549 /**
550 * Apply relative QE.
551 *
552 * \return true if accepted; false if rejected
553 */
554 virtual bool applyQE() const override
555 {
556 if (QE <= 0.0)
557 return false;
558 else if (QE < 1.0)
559 return gRandom->Rndm() < QE;
560 else
561 return true;
562 }
563
564
565 /**
566 * Get randomised time according transit-time distribution.
567 *
568 * \param t_ns time [ns]
569 * \return time [ns]
570 */
571 virtual double getRandomTime(const double t_ns) const override
572 {
573 if (TTS_ns < 0.0)
574 return t_ns + getTransitTime(gRandom->Rndm(), getType());
575 else if (TTS_ns > 0.0)
576 return gRandom->Gaus(t_ns, TTS_ns);
577 else
578 return t_ns;
579 }
580
581
582 /**
583 * Compare arrival times of photo-electrons.
584 * This implementation uses the internal rise time as two photo-electron resolution.
585 *
586 * Two (or more) photo-electrons are merged if they are comparable.
587 *
588 * \param first first photo-electron
589 * \param second second photo-electron
590 * \return true if arrival times of photo-electrons are within two photo-electron resolution; else false
591 */
592 virtual bool compare(const JPhotoElectron& first, const JPhotoElectron& second) const override
593 {
594 return second.t_ns < first.t_ns + riseTime_ns;
595 }
596
597
598 /**
599 * Get randomised charge according to gain and gain spread.
600 *
601 * \param NPE number of photo-electrons
602 * \return number of photo-electrons
603 */
604 virtual double getRandomCharge(const int NPE) const override
605 {
606 if (NPE > 0) {
607
608 if (gainSpread > 0.0) {
609
610 switch (getAmplificationMode()) {
611
613 return getRandomChargeNominal(NPE);
614
616 return getRandomChargeMixed(NPE);
617
620
621 default:
622 return 0.0;
623 }
624
625 } else {
626
627 return getGain(NPE);
628 }
629
630 } else {
631
632 return 0.0;
633 }
634 }
635
636
637 /**
638 * Get randomised charge according to gain and gain spread with a nominal amplification mode.
639 *
640 * \param NPE number of photo-electrons
641 * \return number of photo-electrons
642 */
643 double getRandomChargeNominal(const int NPE) const
644 {
645 double q;
646
647 do {
648
649 const double mu = getGain(NPE);
650 const double sigma = getGainSpread(NPE);
651
652 q = gRandom->Gaus(mu, sigma);
653
654 } while (q < 0.0);
655
656 return q;
657 }
658
659
660 /**
661 * Get randomised charge according to gain and gain spread with a mixed amplification mode.
662 *
663 * \param NPE number of photo-electrons
664 * \return number of photo-electrons
665 */
666 double getRandomChargeMixed(const int NPE) const
667 {
668
669 double q;
670
671 do {
672 // Determine which contribution to sample from
673 // Method uses inverse transform sampling for a binomial distribution
674
675 const double X = gRandom->Uniform();
676 double sum_p = 0.0;
677 double weight = pow(1-PunderAmplified, NPE);
678 int k = 0; // k underamplified photo-electrons
679
680 for (; k <= NPE; ++k) {
681
682 sum_p += weight;
683 if (sum_p > X) { break; }
684
685 weight *= ((double) (NPE-k) / ((double) (k+1))) * PunderAmplified / (1.0 - PunderAmplified);
686 }
687
688 // Sample from chosen contribution
689 const double mu = (NPE-k) * gain + (k) * getUnderamplifiedGain();
690 const double sigma = gainSpread * sqrt(mu);
691
692 q = gRandom->Gaus(mu, sigma);
693
694 } while (q < 0.0);
695
696 return q;
697 }
698
699
700 /**
701 * Get randomised charge according to gain and gain spread with an underamplified amplification mode.
702 *
703 * \param NPE number of photo-electrons
704 * \return number of photo-electrons
705 */
706 double getRandomChargeUnderAmplified(const int NPE) const
707 {
708 double q;
709
710 do {
711
712 const double mu = getUnderamplifiedGain(NPE);
713 const double sigma = getUnderamplifiedGainSpread(NPE);
714
715 q = gRandom->Gaus(mu, sigma);
716
717 } while (q < 0.0);
718
719 return q;
720 }
721
722
723 /**
724 * Get probability density for given charge.
725 * The normalisation is from (threshold-thresholdband) to infinity.
726 *
727 * \param npe observed number of photo-electrons
728 * \param NPE true number of photo-electrons
729 * \return probability [npe^-1]
730 */
731 virtual double getChargeProbability(const double npe, const int NPE) const override
732 {
733 if ((NPE > 0) && (getThresholdDomain(npe) > BELOW_THRESHOLD)) {
734
735 switch (getAmplificationMode()) {
736
738 return getChargeProbabilityNominal(npe, NPE);
739
741 return getChargeProbabilityMixed(npe, NPE);
742
744 return getChargeProbabilityUnderAmplified(npe, NPE);
745
746 default:
747 return 0.0;
748 }
749
750 } else {
751
752 return 0.0;
753 }
754 }
755
756 /**
757 * Get probability density for given charge with a Nominal amplification mode.
758 * The normalisation is from (threshold-thresholdband) to infinity.
759 *
760 * \param npe observed number of photo-electrons
761 * \param NPE true number of photo-electrons
762 * \return probability [npe^-1]
763 */
764 double getChargeProbabilityNominal(const double npe, const int NPE) const
765 {
766 const double mu = getGain(NPE);
767 const double sigma = getGainSpread(NPE);
768
769 if (sigma > 0.0) {
770
771 JMATH::JGauss gauss = JMATH::JGauss(mu, sigma);
772
773 const double prob = gauss.getValue(npe);
774
775 const double normLowerLimit = threshold - thresholdBand;
776 const double normUpperLimit = std::numeric_limits<double>::infinity();
777 const double norm = gauss.getIntegral(normLowerLimit, normUpperLimit);
778
779 return prob / norm;
780
781 } else if (std::fabs(npe - mu) <= 0.0001 * mu) {
782
783 return 1.0;
784
785 } else {
786
787 return 0.0;
788 }
789 }
790
791
792 /**
793 * Get probability density for given charge with a mixed amplification mode.
794 * The normalisation is from (threshold-thresholdband) to infinity.
795 *
796 * \param npe observed number of photo-electrons
797 * \param NPE true number of photo-electrons
798 * \return probability [npe^-1]
799 */
800 double getChargeProbabilityMixed(const double npe, const double NPE) const
801 {
802 double norm = 0.0;
803 double prob = 0.0;
804 double weight = pow(1-PunderAmplified, NPE);
805
806 for (int k = 0; k <= NPE; ++k) { // k underamplified photo-electrons
807
808 const double mu = (NPE-k) * gain + (k) * getUnderamplifiedGain();
809 const double sigma = gainSpread * sqrt(mu);
810
811 if (sigma > 0.0) {
812
813 JMATH::JGauss gauss = JMATH::JGauss(mu, sigma);
814
815 prob += weight * gauss.getValue(npe);
816
817 const double normLowerLimit = threshold - thresholdBand;
818 const double normUpperLimit = std::numeric_limits<double>::infinity();
819
820 norm += weight * gauss.getIntegral(normLowerLimit, normUpperLimit);
821
822 } else if (std::fabs(npe - mu) <= 0.0001 * mu) {
823
824 prob += weight;
825 norm += weight;
826
827 } else {
828
829 return 0.0;
830 }
831
832 weight *= ((double) (NPE-k) / ((double) (k+1))) * PunderAmplified / (1.0 - PunderAmplified);
833 }
834
835 return prob / norm;
836 }
837
838
839 /**
840 * Get probability density for given charge with an underamplified amplification mode.
841 * The normalisation is from (threshold-thresholdband) to infinity.
842 *
843 * \param npe observed number of photo-electrons
844 * \param NPE true number of photo-electrons
845 * \return probability [npe^-1]
846 */
847 double getChargeProbabilityUnderAmplified(const double npe, const int NPE) const
848 {
849 if (gainSpread > 0.0) {
850
851 const double mu = getUnderamplifiedGain(NPE);
852 const double sigma = getUnderamplifiedGainSpread(NPE);
853
854 JMATH::JGauss gauss = JMATH::JGauss(mu, sigma);
855
856 const double prob = gauss.getValue(npe);
857
858 const double normLowerLimit = threshold - thresholdBand;
859 const double normUpperLimit = std::numeric_limits<double>::infinity();
860 const double norm = gauss.getIntegral(normLowerLimit, normUpperLimit);
861
862 return prob / norm;
863
864 } else {
865
866 return 0.0;
867 }
868 }
869
870
871 /**
872 * Get integral of probability.
873 * The normalisation is from (threshold-thresholdband) to infinity.
874 *
875 * \param xmin minimum number of photo-electrons
876 * \param xmax maximum number of photo-electrons
877 * \param NPE true number of photo-electrons
878 * \return probability
879 */
880 double getIntegralOfChargeProbability(const double xmin, const double xmax, const int NPE) const
881 {
882 if (NPE > 0) {
883
884 double zmin = xmin;
885 double zmax = xmax;
886
887 const double th = threshold - thresholdBand;
888
889 if (zmin < th) { zmin = th; }
890 if (zmax < th) { zmax = th; }
891
892 switch (getAmplificationMode()) {
893
895 return getIntegralOfChargeProbabilityNominal(zmin, zmax, NPE);
896
898 return getIntegralOfChargeProbabilityMixed(zmin, zmax, NPE);
899
901 return getIntegralOfChargeProbabilityUnderAmplified(zmin, zmax, NPE);
902
903 default:
904 return 0.0;
905 }
906
907 } else {
908
909 return 0.0;
910 }
911 }
912
913
914 /**
915 * Get integral of probability with a nominal amplification mode.
916 * The normalisation is from (threshold-thresholdband) to infinity.
917 *
918 * \param xmin minimum number of photo-electrons
919 * \param xmax maximum number of photo-electrons
920 * \param NPE true number of photo-electrons
921 * \return probability
922 */
923 double getIntegralOfChargeProbabilityNominal(const double xmin, const double xmax, const int NPE) const
924 {
925 const double mu = getGain(NPE);
926 const double sigma = getGainSpread(NPE);
927
928 if (sigma > 0.0) {
929
930 JMATH::JGauss gauss = JMATH::JGauss(mu, sigma);
931
932 const double cumulP = gauss.getIntegral(xmin, xmax);
933
934 const double normLowerLimit = threshold - thresholdBand;
935 const double normUpperLimit = std::numeric_limits<double>::infinity();
936 const double norm = gauss.getIntegral(normLowerLimit, normUpperLimit);
937
938 return cumulP / norm;
939
940 } else if ((mu >= xmin) && (mu <= xmax)) {
941
942 return 1.0;
943
944 } else {
945
946 return 0.0;
947 }
948 }
949
950
951 /**
952 * Get integral of probability with a mixed amplification mode.
953 * The normalisation is from (threshold-thresholdband) to infinity.
954 *
955 * \param xmin minimum number of photo-electrons
956 * \param xmax maximum number of photo-electrons
957 * \param NPE true number of photo-electrons
958 * \return probability
959 */
960 double getIntegralOfChargeProbabilityMixed(const double xmin, const double xmax, const int NPE) const
961 {
962 double cumulP = 0.0;
963 double norm = 0.0;
964 double weight = pow(1.0 - PunderAmplified, NPE);
965
966 for (int k = 0; k <= NPE; ++k) { // k underamplified photo-electrons
967
968 const double mu = (NPE-k) * gain + (k) * getUnderamplifiedGain();
969 const double sigma = gainSpread * sqrt(mu);
970
971 if (sigma > 0.0) {
972
973 JMATH::JGauss gauss = JMATH::JGauss(mu, sigma);
974
975 const double normLowerLimit = threshold - thresholdBand;
976 const double normUpperLimit = std::numeric_limits<double>::infinity();
977
978 cumulP += weight * gauss.getIntegral(xmin, xmax);
979 norm += weight * gauss.getIntegral(normLowerLimit, normUpperLimit);
980
981 } else if ((mu >= xmin) && (mu <= xmax)) {
982
983 cumulP += weight;
984 norm += weight;
985
986 } else {
987
988 return 0.0;
989 }
990
991 weight *= ((double) (NPE-k) / ((double) (k+1))) * PunderAmplified / (1.0 - PunderAmplified);
992 }
993
994 return cumulP / norm;
995 }
996
997
998 /**
999 * Get integral of probability with an underamplified amplification mode.
1000 * The normalisation is from (threshold-thresholdband) to infinity.
1001 *
1002 * \param xmin minimum number of photo-electrons
1003 * \param xmax maximum number of photo-electrons
1004 * \param NPE true number of photo-electrons
1005 * \return probability
1006 */
1007 double getIntegralOfChargeProbabilityUnderAmplified(const double xmin, const double xmax, const int NPE) const
1008 {
1009 if (gainSpread > 0.0) {
1010
1011 const double mu = getUnderamplifiedGain(NPE);
1012 const double sigma = getUnderamplifiedGainSpread(NPE);
1013
1014 JMATH::JGauss gauss = JMATH::JGauss(mu, sigma);
1015
1016 const double cumulP = gauss.getIntegral(xmin, xmax);
1017
1018 const double normLowerLimit = threshold - thresholdBand;
1019 const double normUpperLimit = std::numeric_limits<double>::infinity();
1020 const double norm = gauss.getIntegral(normLowerLimit, normUpperLimit);
1021
1022 return cumulP / norm;
1023
1024 } else {
1025
1026 return 0.0;
1027 }
1028 }
1029
1030
1031 /**
1032 * Get integral of probability in specific threshold domain.
1033 * The normalisation is from (threshold-thresholdband) to infinity.
1034 *
1035 * \param domain threshold domain
1036 * \param NPE true number of photo-electrons
1037 * \return probability
1038 */
1039 double getIntegralOfChargeProbability(const JThresholdDomain domain, const int NPE) const
1040 {
1041 switch (domain) {
1042
1043 case ABOVE_THRESHOLD:
1044 return getIntegralOfChargeProbability(threshold, std::numeric_limits<double>::infinity(), NPE);
1045
1046 case THRESHOLDBAND:
1048
1049 default:
1050 return 0.0;
1051 }
1052 }
1053
1054
1055 /**
1056 * Apply threshold.
1057 *
1058 * \param npe number of photo-electrons
1059 * \return true if pass; else false
1060 */
1061 virtual bool applyThreshold(const double npe) const override
1062 {
1063 return getThresholdDomain(npe) > BELOW_THRESHOLD;
1064 }
1065
1066
1067 /**
1068 * Get time to reach threshold.
1069 *
1070 * Note that the rise time is defined to be zero for a one photo-electron signal.
1071 *
1072 * \param npe number of photo-electrons
1073 * \return time [ns]
1074 */
1075 virtual double getRiseTime(const double npe) const override
1076 {
1077 if (slewing) {
1078
1079 switch (getThresholdDomain(npe)) {
1080
1081 case THRESHOLDBAND:
1082 return ((getRiseTime(npe, getTH0()) - getRiseTime(npe, threshold-thresholdBand)) -
1083 (getRiseTime(1.0, getTH0()) - getRiseTime(1.0, threshold-thresholdBand))) + this->mean_ns;
1084
1085 case ABOVE_THRESHOLD:
1086 return ((getRiseTime(npe, getTH0()) - getRiseTime(npe, threshold)) -
1087 (getRiseTime(1.0, getTH0()) - getRiseTime(1.0, threshold)));
1088
1089 default:
1090 THROW(JValueOutOfRange, "JPMTAnalogueSignalProcessor::getRiseTime: Invalid charge " << npe);
1091 }
1092
1093 } else {
1094
1095 return 0.0;
1096 }
1097 }
1098
1099
1100 /**
1101 * Get time-over-threshold.
1102 *
1103 * \param npe number of photo-electrons
1104 * \return time-over-threshold (with saturation) [ns]
1105 */
1106 virtual double getTimeOverThreshold(const double npe) const override
1107 {
1108 switch (getThresholdDomain(npe)) {
1109
1110 case THRESHOLDBAND:
1111 return gRandom->Gaus(mean_ns, sigma_ns);
1112
1113 case ABOVE_THRESHOLD: {
1114
1115 double tot = 0.0;
1116
1117 switch (getChargeDomain(npe)) {
1118
1120 tot += getRiseTime(npe, threshold); // Gaussian
1121 tot += getRiseTime(npe, threshold); // Gaussian
1122 break;
1123
1125 tot += getRiseTime (npe, threshold); // Gaussian
1126 tot += getDecayTime(npe, threshold); // exponential
1127 break;
1128
1130 tot += getRiseTime (getStartOfLinearisation(), threshold); // Gaussian
1131 tot += getDecayTime(getStartOfLinearisation(), threshold); // exponential
1132
1133 tot += slope * (npe - getStartOfLinearisation()); // linear
1134 break;
1135 }
1136
1137 return applySaturation(tot);
1138 }
1139
1140 default:
1141 THROW(JValueOutOfRange, "JPMTAnalogueSignalProcessor::getTimeOverThreshold: Invalid charge " << npe);
1142 }
1143 }
1144
1145
1146 /**
1147 * Get derivative of number of photo-electrons to time-over-threshold with saturation.
1148 *
1149 * \param npe number of photo-electrons
1150 * \return dnpe/dToT [ns^-1]
1151 */
1152 virtual double getDerivative(const double npe) const override
1153 {
1154 switch (getThresholdDomain(npe)) {
1155
1156 case ABOVE_THRESHOLD: {
1157
1158 const double tot_ns = getTimeOverThreshold(npe);
1159
1160 if (tot_ns < saturation) {
1161
1162 const double z = riseTime_ns / sqrt(2.0 * log(npe/threshold));
1163
1164 double y = 0.0;
1165
1166 switch (getChargeDomain(npe)) {
1167
1169 y += npe / (2.0 * z);
1170 break;
1171
1173 y += npe / (z + decayTime_ns);
1174 break;
1175
1177 y += 1.0 / slope;
1178 break;
1179 }
1180
1181 return y / getDerivativeOfSaturation(removeSaturation(tot_ns));
1182
1183 } else {
1184
1185 return 0.0;
1186 }
1187 }
1188
1189 default:
1190 return 0.0;
1191 }
1192 }
1193
1194
1195 /**
1196 * Probability that a hit survives the simulation of the PMT.
1197 * The survival probability takes into account the number of photo-electrons, the analogue signal of the PMT and the threshold of the discriminator.
1198 *
1199 * \param NPE number of photo-electrons
1200 * \return probability
1201 */
1202 virtual double getSurvivalProbability(const int NPE) const override
1203 {
1204 if (NPE > 0) {
1205
1206 if (QE <= 0.0) {
1207
1208 return 0.0;
1209
1210 } else if (QE < 1.0) {
1211
1212 double P = 0.0;
1213
1214 for (int i = 1; i <= NPE; ++i) { // i corresponds to number of photo-electrons passing relative QE
1215
1216 const double p = JMATH::binomial(NPE, i) * pow(QE, i) * pow(1.0 - QE, NPE - i);
1217
1218 P += p * getThresholdProbability(NPE);
1219 }
1220
1221 return P;
1222
1223 } else {
1224
1225 return getThresholdProbability(NPE);
1226 }
1227
1228 } else {
1229
1230 return 0.0;
1231 }
1232 }
1233
1234
1235 /**
1236 * Probability that a hit survives the threshold of the PMT.
1237 *
1238 * \param NPE number of photo-electrons
1239 * \return probability
1240 */
1241 virtual double getThresholdProbability(const int NPE) const override
1242 {
1243 if (NPE > 0) {
1244
1245 switch (getAmplificationMode()) {
1246
1249
1251 return getThresholdProbabilityMixed(NPE);
1252
1255
1256 default:
1257 return 0.0;
1258 }
1259
1260 } else {
1261
1262 return 0.0;
1263 }
1264 }
1265
1266
1267 /**
1268 * Probability that a hit survives the threshold of the PMT with a nominal amplification mode.
1269 *
1270 * \param NPE true number of photo-electrons
1271 * \return probability
1272 */
1273 double getThresholdProbabilityNominal(const int NPE) const
1274 {
1275 const double mu = getGain(NPE);
1276 const double sigma = getGainSpread(NPE);
1277
1278 if (sigma > 0.0) {
1279
1280 JMATH::JGauss gauss = JMATH::JGauss(mu, sigma);
1281
1282 const double probLowerLimit = threshold - thresholdBand;
1283 const double probUpperLimit = std::numeric_limits<double>::infinity();
1284 const double cumulP = gauss.getIntegral(probLowerLimit, probUpperLimit);
1285
1286 const double normLowerLimit = 0.0;
1287 const double normUpperLimit = std::numeric_limits<double>::infinity();
1288 const double norm = gauss.getIntegral(normLowerLimit, normUpperLimit);
1289
1290 return cumulP / norm;
1291
1292 } else if (mu >= threshold - thresholdBand) {
1293
1294 return 1.0;
1295
1296 } else {
1297
1298 return 0.0;
1299 }
1300 }
1301
1302
1303 /**
1304 * Probability that a hit survives the threshold of the PMT with a mixed amplification mode.
1305 *
1306 * \param NPE true number of photo-electrons
1307 * \return probability
1308 */
1309 double getThresholdProbabilityMixed(const int NPE) const
1310 {
1311 double cumulP = 0.0;
1312 double norm = 0.0;
1313 double weight = pow(1.0 - PunderAmplified, NPE);
1314
1315 for (int k = 0; k <= NPE; ++k) { // k underamplified photo-electrons
1316
1317 const double mu = (NPE-k) * gain + (k) * getUnderamplifiedGain();
1318 const double sigma = gainSpread * sqrt(mu);
1319
1320 if (sigma > 0.0) {
1321
1322 JMATH::JGauss gauss = JMATH::JGauss(mu, sigma);
1323
1324 const double probLowerLimit = threshold - thresholdBand;
1325 const double probUpperLimit = std::numeric_limits<double>::infinity();
1326
1327 cumulP += weight * gauss.getIntegral(probLowerLimit, probUpperLimit);
1328
1329 const double normLowerLimit = 0.0;
1330 const double normUpperLimit = std::numeric_limits<double>::infinity();
1331
1332 norm += weight * gauss.getIntegral(normLowerLimit, normUpperLimit);
1333
1334 } else if (mu >= threshold - thresholdBand) {
1335
1336 cumulP += weight;
1337 norm += weight;
1338
1339 } else {
1340
1341 return 0.0;
1342 }
1343
1344 weight *= ((double) (NPE-k) / ((double) (k+1))) * PunderAmplified / (1.0 - PunderAmplified);
1345 }
1346
1347 return cumulP / norm;
1348 }
1349
1350
1351 /**
1352 * Probability that a hit survives the threshold of the PMT with an underamplified amplification mode.
1353 *
1354 * \param NPE true number of photo-electrons
1355 * \return probability
1356 */
1357 double getThresholdProbabilityUnderAmplified(const int NPE) const
1358 {
1359 if (gainSpread > 0.0) {
1360
1361 const double mu = getUnderamplifiedGain(NPE);
1362 const double sigma = getUnderamplifiedGainSpread(NPE);
1363
1364 JMATH::JGauss gauss = JMATH::JGauss(mu, sigma);
1365
1366 const double probLowerLimit = threshold - thresholdBand;
1367 const double probUpperLimit = std::numeric_limits<double>::infinity();
1368 const double cumulP = gauss.getIntegral(probLowerLimit, probUpperLimit);
1369
1370 const double normLowerLimit = 0.0;
1371 const double normUpperLimit = std::numeric_limits<double>::infinity();
1372 const double norm = gauss.getIntegral(normLowerLimit, normUpperLimit);
1373
1374 return cumulP / norm;
1375
1376 } else {
1377
1378 return 0.0;
1379 }
1380 }
1381
1382
1383 /**
1384 * Get number of photo-electrons.
1385 *
1386 * \param tot_ns time-over-threshold (with saturation) [ns]
1387 * \return number of photo-electrons
1388 */
1389 virtual double getNPE(const double tot_ns) const override
1390 {
1391 if (tot_ns >= saturation) {
1392 return std::numeric_limits<double>::max();
1393 }
1394
1395 const double tot = removeSaturation(tot_ns);
1396 const double TOT = (getRiseTime (getStartOfLinearisation(), threshold) +
1398
1399 switch (getToTDomain(tot_ns)) {
1400
1402 return threshold * exp(tot*tot/riseTime_ns/riseTime_ns/8.0);
1403
1405
1406 const double a = decayTime_ns;
1407 const double b = sqrt(2.0) * riseTime_ns;
1408 const double c = -(decayTime_ns*log(y1) + tot);
1409 const double z = (-b + sqrt(b*b - 4*a*c)) / (2*a);
1410
1411 return threshold * exp(z*z);
1412 }
1413
1415 return getStartOfLinearisation() + (tot - TOT) / slope;
1416
1417 default:
1418 return 0.0;
1419 }
1420 }
1421
1422
1423 /**
1424 * Get probability of having a pulse with specific time-over-threshold.
1425 *
1426 * \param tot_ns time-over-threshold (with saturation) [ns]
1427 * \param NPE true number of photo-electrons
1428 * \return probability [ns^-1]
1429 */
1430 double getTimeOverThresholdProbability(const double tot_ns, const int NPE) const
1431 {
1432 if (tot_ns < saturation) {
1433
1434 const double npe = getNPE(tot_ns);
1435 const double y = getChargeProbability(npe, NPE);
1436 const double v = getDerivative(npe);
1437 const double RaboveTh = y * v;
1438
1439 const double w = getIntegralOfChargeProbability(ABOVE_THRESHOLD, NPE);
1441 const double gaussProb = gauss.getValue(tot_ns);
1442 const double gaussNorm = gauss.getIntegral(0, saturation);
1443 const double gaussDist = gaussProb / gaussNorm;
1444 const double RthBand = (1-w) * gaussDist;
1445
1446 return RaboveTh + RthBand;
1447
1448 } else {
1449
1450 return 0.0;
1451 }
1452 }
1453
1454
1455 /**
1456 * Get cumulative probability of time-over-threshold distribution.
1457 *
1458 * \param Tmin minimum time-over-threshold (with saturation) [ns]
1459 * \param Tmax maximum time-over-threshold (with saturation) [ns]
1460 * \param NPE true number of photo-electrons
1461 * \return probability [ns^-1]
1462 */
1463 double getIntegralOfTimeOverThresholdProbability(const double Tmin, const double Tmax, const int NPE) const
1464 {
1465 double Xmin = Tmin;
1466 double Xmax = Tmax;
1467
1468 if (Tmin > saturation) {Xmin = saturation;}
1469 if (Tmax > saturation) {Xmax = saturation;}
1470
1471 const double IaboveTh = getIntegralOfChargeProbability(getNPE(Xmin), getNPE(Xmax), NPE);
1472
1473 const double w = getIntegralOfChargeProbability(ABOVE_THRESHOLD, NPE);
1475 const double gaussCumulP = gauss.getIntegral(Xmin, Xmax);
1476 const double gaussNorm = gauss.getIntegral(0, saturation);
1477 const double gaussDist = gaussCumulP / gaussNorm;
1478 const double IthBand = (1-w) * gaussDist;
1479
1480 return IaboveTh + IthBand;
1481 }
1482
1483
1484 /**
1485 * Get lower threshold for rise time evaluation.
1486 *
1487 * \return threshold [npe]
1488 */
1489 static double getTH0()
1490 {
1491 return 0.1;
1492 }
1493
1494
1495 /**
1496 * Get upper threshold for rise time evaluation.
1497 *
1498 * \return threshold [npe]
1499 */
1500 static double getTH1()
1501 {
1502 return 0.9;
1503 }
1504
1505 protected:
1506
1507 double decayTime_ns; //!< decay time [ns]
1508 double t1; //!< time at match point [ns]
1509 double y1; //!< amplitude at match point [npe]
1510 /**
1511 * Transition point from a logarithmic to a linear relation
1512 * between time-over-threshold and number of photo-electrons.\n
1513 * Measurements by B. Schermer and R. Bruijn at Nikhef.
1514 */
1515 double x1;
1516 };
1517
1518
1519 /**
1520 * Get charge probability convoluted with a Poisson distribution.
1521 *
1522 * \param pmt PMT signal processor
1523 * \param npe measured number of photo-electrons
1524 * \param NPE expected number of photo-electrons
1525 * \param precision precision
1526 * \return probability
1527 */
1529 const double npe,
1530 const double NPE,
1531 const double precision = 1.0e-4)
1532 {
1533 int i = (int) (NPE - 5.0 * sqrt(NPE));
1534
1535 if (i < 1) {
1536 i = 1;
1537 }
1538
1539 double p = NPE * exp(-NPE) / (double) 1;
1540
1541 for (int __i = 1; __i != i; ++__i) {
1542 p *= NPE / __i;
1543 }
1544
1545 double P = 0.0;
1546
1547 for (double p0 = 0.0; (p >= p0 || p > precision); ++i, p0 = p, p *= NPE / (double) i) {
1548 P += pmt.getChargeProbability(npe, i) * p;
1549 }
1550
1551 return P;
1552 }
1553
1554
1555 /**
1556 * Get time-over-threshold probability convoluted with a Poisson distribution.
1557 *
1558 * \param pmt PMT signal processor
1559 * \param tot_ns time-over-threshold [ns]
1560 * \param NPE expected number of photo-electrons
1561 * \param precision precision
1562 * \return probability
1563 */
1565 const double tot_ns,
1566 const double NPE,
1567 const double precision = 1.0e-4)
1568 {
1569 int i = (int) (NPE - 5.0 * sqrt(NPE) - 0.5);
1570 int M = (int) (NPE + 5.0 * sqrt(NPE) + 0.5);
1571
1572 if (i < 1) { i = 1; }
1573 if (M < i) { M = i; }
1574
1575 double p = NPE * exp(-NPE) / (double) 1;
1576
1577 for (int __i = 1; __i != i; ++__i) {
1578 p *= NPE / __i;
1579 }
1580
1581 double P = 0.0;
1582
1583 for (double p0 = 0.0; (p >= p0 || p > precision) && i != M; ++i, p0 = p, p *= NPE / (double) i) {
1584 P += pmt.getTimeOverThresholdProbability(tot_ns, i) * p;
1585 }
1586
1587 return P;
1588 }
1589}
1590
1591#endif
Time calibration (including definition of sign of time offset).
Exceptions.
#define THROW(JException_t, A)
Marco for throwing exception with std::ostream compatible message.
Auxiliary methods for mathematics.
Data structure for PMT parameters.
double sigma_ns
time-over-threshold standard deviation of threshold-band hits [ns]
double QE
relative quantum efficiency
int getType() const
Get type for for time-slewing correction.
double thresholdBand
threshold-band [npe]
double gainSpread
gain spread [unit]
JPMTParameters()
Default constructor.
double riseTime_ns
rise time of analogue pulse [ns]
double TTS_ns
transition time spread [ns]
double threshold
threshold [npe]
double mean_ns
mean time-over-threshold of threshold-band hits [ns]
void setPMTParameters(const JPMTParameters &parameters)
Set PMT parameters.
double slope
slope [ns/npe]
double PunderAmplified
probability of underamplified hit
bool slewing
time slewing of analogue signal
double saturation
saturation [ns]
virtual double getChargeProbability(const double npe, const int NPE) const
Get probability density for given charge.
Exception for accessing a value in a collection that is outside of its range.
file Auxiliary data structures and methods for detector calibration.
Definition JAnchor.hh:12
JDETECTOR::JTransitTimeGenerator_t getTransitTime
Function object to generate transit time.
const double TIME_OVER_THRESHOLD_NS
Specification for time-over-threshold corresponding to a one photo-electron pulse.
double getChargeProbability(const JPMTSignalProcessorInterface &pmt, const double npe, const double NPE, const double precision=1.0e-4)
Get charge probability convoluted with a Poisson distribution.
double getTimeOverThresholdProbability(const JPMTAnalogueSignalProcessor &pmt, const double tot_ns, const double NPE, const double precision=1.0e-4)
Get time-over-threshold probability convoluted with a Poisson distribution.
double binomial(const size_t n, const size_t k)
Binomial function.
double getUnderamplifiedGain() const
Get gain of underamplified pulses.
friend std::istream & operator>>(std::istream &in, JPMTAnalogueSignalProcessor &object)
Read PMT signal from input.
virtual bool applyQE() const override
Apply relative QE.
virtual bool compare(const JPhotoElectron &first, const JPhotoElectron &second) const override
Compare arrival times of photo-electrons.
static double getMaximalRiseTime(const double th)
Get maximal rise time for given threshold.
double getT1() const
Get time at transition point from Gaussian to exponential.
double getUnderamplifiedGainSpread(int NPE) const
Get gain spread of underamplified pulses.
double getGainSpread(int NPE) const
Get gain spread for given number of photo-electrons.
double getIntegralOfChargeProbability(const JThresholdDomain domain, const int NPE) const
Get integral of probability in specific threshold domain.
virtual double getRandomTime(const double t_ns) const override
Get randomised time according transit-time distribution.
virtual bool applyThreshold(const double npe) const override
Apply threshold.
virtual double getChargeProbability(const double npe, const int NPE) const override
Get probability density for given charge.
JAnaloguePulseDomain getToTDomain(const double tot_ns) const
Get time-over-threshold domain.
double getUnderamplifiedGainSpread() const
Get gain spread of underamplified pulses.
static double getTH1()
Get upper threshold for rise time evaluation.
virtual double getRiseTime(const double npe) const override
Get time to reach threshold.
virtual double getNPE(const double tot_ns) const override
Get number of photo-electrons.
double x1
Transition point from a logarithmic to a linear relation between time-over-threshold and number of ph...
double getTimeOverThresholdProbability(const double tot_ns, const int NPE) const
Get probability of having a pulse with specific time-over-threshold.
double getIntegralOfChargeProbability(const double xmin, const double xmax, const int NPE) const
Get integral of probability.
double getIntegralOfTimeOverThresholdProbability(const double Tmin, const double Tmax, const int NPE) const
Get cumulative probability of time-over-threshold distribution.
JAnaloguePulseDomain getChargeDomain(const double npe) const
Get charge domain.
JAnaloguePulseDomain
Analogue pulse domain specifiers.
double getY1() const
Get amplitude at transition point from Gaussian to exponential.
JThresholdDomain getThresholdDomain(const double npe) const
Get threshold domain.
virtual double getThresholdProbability(const int NPE) const override
Probability that a hit survives the threshold of the PMT.
double getRandomChargeUnderAmplified(const int NPE) const
Get randomised charge according to gain and gain spread with an underamplified amplification mode.
double getRandomChargeMixed(const int NPE) const
Get randomised charge according to gain and gain spread with a mixed amplification mode.
virtual double getRandomCharge(const int NPE) const override
Get randomised charge according to gain and gain spread.
JPMTAnalogueSignalProcessor(const JPMTParameters &parameters=JPMTParameters())
Constructor.
double getChargeProbabilityMixed(const double npe, const double NPE) const
Get probability density for given charge with a mixed amplification mode.
double getDerivativeOfSaturation(const double tot_ns) const
Get derivative of saturation factor.
double getThresholdProbabilityUnderAmplified(const int NPE) const
Probability that a hit survives the threshold of the PMT with an underamplified amplification mode.
JAmplificationMode getAmplificationMode() const
Get amplification mode.
double getIntegralOfChargeProbabilityNominal(const double xmin, const double xmax, const int NPE) const
Get integral of probability with a nominal amplification mode.
double applySaturation(const double tot_ns) const
Get time-over-threshold with saturation.
double getDecayTime(const double npe, const double th) const
Get time to pass from top of analogue pulse to threshold.
double removeSaturation(const double tot_ns) const
Get time-over-threshold without saturation.
double getRiseTime(const double npe, const double th) const
Get time to pass from threshold to top of analogue pulse.
double getThresholdProbabilityNominal(const int NPE) const
Probability that a hit survives the threshold of the PMT with a nominal amplification mode.
double getChargeProbabilityNominal(const double npe, const int NPE) const
Get probability density for given charge with a Nominal amplification mode.
double getAmplitude(const double t1_ns) const
Get amplitude at given time for a one photo-electron pulse.
static double getTH0()
Get lower threshold for rise time evaluation.
double getStartOfLinearisation() const
Get transition point from a model-dependent to linear relation between time-over-threshold and number...
void setPMTParameters(const JPMTParameters &parameters)
Set PMT parameters.
void configure()
Configure internal parameters.
double getChargeProbabilityUnderAmplified(const double npe, const int NPE) const
Get probability density for given charge with an underamplified amplification mode.
virtual double getSurvivalProbability(const int NPE) const override
Probability that a hit survives the simulation of the PMT.
double getIntegralOfChargeProbabilityMixed(const double xmin, const double xmax, const int NPE) const
Get integral of probability with a mixed amplification mode.
virtual double getTimeOverThreshold(const double npe) const override
Get time-over-threshold.
double getIntegralOfChargeProbabilityUnderAmplified(const double xmin, const double xmax, const int NPE) const
Get integral of probability with an underamplified amplification mode.
double getGainSpread() const
Get gain spread for given number of photo-electrons.
virtual double getDerivative(const double npe) const override
Get derivative of number of photo-electrons to time-over-threshold with saturation.
double getUnderamplifiedGain(int NPE) const
Get gain of underamplified pulses.
double getThresholdProbabilityMixed(const int NPE) const
Probability that a hit survives the threshold of the PMT with a mixed amplification mode.
double getRandomChargeNominal(const int NPE) const
Get randomised charge according to gain and gain spread with a nominal amplification mode.
Data structure for single photo-electron.
Gauss function object.
Definition JMathlib.hh:2000