Jpp 21.0.0-rc.1-88-g0130508c4
the software that should make you happy
Loading...
Searching...
No Matches
JFitK40.hh
Go to the documentation of this file.
1#ifndef __JCALIBRATE_JFITK40__
2#define __JCALIBRATE_JFITK40__
3
4#include <vector>
5#include <array>
6#include <map>
7#include <memory>
8#include <limits>
9#include <cmath>
10
12
13#include "JLang/JException.hh"
14#include "JLang/JManip.hh"
15
16#include "Jeep/JMessage.hh"
17
18#include "JTools/JRange.hh"
19
20#include "JDetector/JModule.hh"
21
22#include "JMath/JVectorND.hh"
23#include "JMath/JMatrixNS.hh"
24#include "JMath/JMath.hh"
25#include "JMath/JBell.hh"
26#include "JMath/JMathToolkit.hh"
27
28#include "JFit/JMEstimator.hh"
29
31#include "JCalibrate/JTDC_t.hh"
32
33
34/**
35 * \author mdejong
36 */
37
38namespace JCALIBRATE {}
39namespace JPP { using namespace JCALIBRATE; }
40
41namespace JCALIBRATE {
42
43 using KM3NETDAQ::NUMBER_OF_PMTS;
46 using JMATH::JMath;
48
49
50 /**
51 * Fit options.
52 */
53 enum JOption_t {
54 FIT_PMTS_t = 1, //!< fit parameters of PMTs
55 FIT_PMTS_AND_ANGULAR_DEPENDENCE_t = 2, //!< fit parameters of PMTs and angular dependence of K40 rate
56 FIT_PMTS_AND_BACKGROUND_t = 3, //!< fit parameters of PMTs and background
57 FIT_PMTS_QE_FIXED_t = 4, //!< fit parameters of PMTs with QE fixed
58 FIT_MODEL_t = 5 //!< fit parameters of K40 rate and TTSs of PMTs
59 };
60
61 static const int INVALID_INDEX = -1; //!< invalid index
62
63 static const int NUMBER_OF_RINGS = 6; //!< number of rings in optical module.
64
65 static double TEROSTAT_DZ = 0.40; //!< maximal PMT inclination
66 static double TEROSTAT_R1 = 1.00; //!< scaling factor
67 static double BELL_SHAPE = 1.55; //!< Bell shape
68
69
70 /**
71 * Data structure for measured coincidence rate of pair of PMTs.
72 */
73 struct rate_type {
74 /**
75 * Default constructor.
76 */
78 dt_ns(0.0),
79 value(0.0),
80 error(0.0)
81 {}
82
83
84 /**
85 * Constructor.
86 *
87 * \param dt_ns time difference [ns]
88 * \param value value of rate [Hz/ns]
89 * \param error error of rate [Hz/ns]
90 */
92 double value,
93 double error) :
94 dt_ns(dt_ns),
95 value(value),
97 {}
98
99 double dt_ns; //!< time difference [ns]
100 double value; //!< value of rate [Hz/ns]
101 double error; //!< error of rate [Hz/ns]
102 };
103
104
105 /**
106 * Data structure for measured coincidence rates of all pairs of PMTs in optical module.
107 */
108 struct data_type :
109 public std::map<pair_type, std::vector<rate_type> >
110 {};
111
112
113 /**
114 * Auxiliary class for fit parameter with optional limits.
115 */
117 public JMath<JParameter_t>
118 {
119 public:
120 /**
121 * Fit options.
122 */
123 enum FIT_t {
124 FREE_t = 0, //!< free
125 FIXED_t //!< fixed
126 };
127
128
129 /**
130 * Type definition for range of parameter values.
131 */
133
134
135 /**
136 * Default constructor.
137 */
139 {
140 set(0.0);
141 }
142
143
144 /**
145 * Constructor.
146 *
147 * \param value value
148 * \param range range
149 */
150 JParameter_t(const double value,
152 range(range)
153 {
154 set(value);
155 }
156
157
158 /**
159 * Negate parameter.
160 *
161 * \return this parameter
162 */
164 {
165 set(-get());
166
167 return *this;
168 }
169
170
171 /**
172 * Add parameter.
173 *
174 * \param parameter parameter
175 * \return this parameter
176 */
177 JParameter_t& add(const JParameter_t& parameter)
178 {
179 set(get() + parameter.get());
180
181 return *this;
182 }
183
184
185 /**
186 * Subtract parameter.
187 *
188 * \param parameter parameter
189 * \return this parameter
190 */
191 JParameter_t& sub(const JParameter_t& parameter)
192 {
193 set(get() - parameter.get());
194
195 return *this;
196 }
197
198
199 /**
200 * Scale parameter.
201 *
202 * \param factor multiplication factor
203 * \return this parameter
204 */
205 JParameter_t& mul(const double factor)
206 {
207 set(get() * factor);
208
209 return *this;
210 }
211
212
213 /**
214 * Scale parameter.
215 *
216 * \param factor division factor
217 * \return this parameter
218 */
219 JParameter_t& div(const double factor)
220 {
221 set(get() / factor);
222
223 return *this;
224 }
225
226
227 /**
228 * Scale parameter.
229 *
230 * \param first first parameter
231 * \param second second parameter
232 * \return this parameter
233 */
234 JParameter_t& mul(const JParameter_t& first, const JParameter_t& second)
235 {
236 set(first.get() * second.get());
237
238 return *this;
239 }
240
241
242 /**
243 * Check if parameter is free.
244 *
245 * \return true if free; else false
246 */
247 bool isFree() const
248 {
249 return option == FREE_t;
250 }
251
252
253 /**
254 * Check if parameter is fixed.
255 *
256 * \return true if fixed; else false
257 */
258 bool isFixed() const
259 {
260 return option == FIXED_t;
261 }
262
263
264 /**
265 * Check if parameter is bound.
266 *
267 * \return true if bound; else false
268 */
269 bool isBound() const
270 {
271 return range.is_valid();
272 }
273
274
275 /**
276 * Set current value.
277 */
278 void set()
279 {
280 option = FREE_t;
281 }
282
283
284 /**
285 * Fix current value.
286 */
287 void fix()
288 {
289 option = FIXED_t;
290 }
291
292
293 /**
294 * Get value.
295 *
296 * \return value
297 */
298 double get() const
299 {
300 if (isBound())
301 return range.getLowerLimit() + 0.5 * range.getLength() * (sin(value) + 1.0);
302 else
303 return value;
304 }
305
306
307 /**
308 * Set value.
309 *
310 * \param value value
311 */
312 void set(const double value)
313 {
314 if (isBound())
315 this->value = asin(2.0 * (range.constrain(value) - range.getLowerLimit()) / range.getLength() - 1.0);
316 else
317 this->value = value;
318
319 set();
320 }
321
322
323 /**
324 * Set limits.
325 *
326 * \param xmin minimal value
327 * \param xmax maximal value
328 */
329 void setLimits(const double xmin, const double xmax)
330 {
331 const double x = get();
332
333 range = range_type(xmin, xmax);
334
335 set(x);
336 }
337
338
339 /**
340 * Relax limits.
341 */
342 void relax()
343 {
344 const double x = get();
345
347
348 set(x);
349 }
350
351
352 /**
353 * Check if parameter is at limit.
354 *
355 * \param precision precision
356 * \return true if at limit; else false
357 */
358 bool atLimit(const double precision) const
359 {
360 if (isBound())
361 return (get() - range.getLowerLimit() <= precision ||
362 range.getUpperLimit() - get() <= precision);
363 else
364 return false;
365 }
366
367
368 /**
369 * Fix value.
370 *
371 * \param value value
372 */
373 void fix(const double value)
374 {
375 set(value);
376
377 fix();
378 }
379
380
381 /**
382 * Get derivative of value.
383 *
384 * \return derivative of value
385 */
386 double getDerivative() const
387 {
388 if (isBound())
389 return 1.0 / (0.5 * range.getLength() * cos(value));
390 else
391 return 1.0;
392 }
393
394
395 /**
396 * Type conversion operator.
397 *
398 * \return value
399 */
400 double operator()() const
401 {
402 return get();
403 }
404
405
406 /**
407 * Type conversion operator.
408 *
409 * \return value
410 */
411 operator double() const
412 {
413 return get();
414 }
415
416
417 /**
418 * Assignment operator.
419 *
420 * \param value value
421 * \return this parameter
422 */
424 {
425 set(value);
426
427 return *this;
428 }
429
430
431 /**
432 * Read parameter from input stream.
433 *
434 * \param in input stream
435 * \param object parameter
436 * \return input stream
437 */
438 friend inline std::istream& operator>>(std::istream& in, JParameter_t& object)
439 {
440 return in >> object.value;
441 }
442
443
444 /**
445 * Write parameter to output stream.
446 *
447 * \param out output stream
448 * \param object parameter
449 * \return output stream
450 */
451 friend inline std::ostream& operator<<(std::ostream& out, const JParameter_t& object)
452 {
453 using namespace std;
454
455 out << FIXED(12,6) << object.get() << ' '
456 << setw(5) << (object.isFixed() ? "fixed" : " ") << ' ';
457
458 if (object.isBound()) {
459 out << "[" << FIXED(12,6) << object.range.getLowerLimit() << "," << FIXED(12,6) << object.range.getUpperLimit() << "]";
460 }
461
462 return out;
463 }
464
465
466 double value = 0.0;
469 };
470
471
472 /**
473 * Fit parameters for single PMT.
474 */
476
477 static constexpr double QE_MIN = 0.0; //!< minimal QE
478 static constexpr double QE_MAX = 2.0; //!< maximal QE
479 static constexpr double TTS_NS = 2.0; //!< start value transition-time spread [ns]
480
481 /**
482 * Default constructor.
483 */
485 {
486 reset();
487 }
488
489
490 /**
491 * Get default values.
492 *
493 * \return parameters
494 */
496 {
497 static JPMTParameters_t parameters;
498
500
501 parameters.status = true;
502
503 parameters.QE .set(1.0);
504 parameters.TTS.set(TTS_NS);
505 parameters.t0 .set(0.0);
506 parameters.bg .set(0.0);
507
508 return parameters;
509 }
510
511
512 /**
513 * Reset.
514 */
515 void reset()
516 {
517 status = true;
518
519 QE .set(0.0);
520 TTS.set(0.0);
521 t0 .set(0.0);
522 bg .set(0.0);
523 }
524
525
526 /**
527 * Set parameters that are free to given values.
528 *
529 * \param parameters parameters
530 */
531 void set(const JPMTParameters_t& parameters)
532 {
533 if (QE .isFree()) { QE .set(parameters.QE); }
534 if (TTS.isFree()) { TTS.set(parameters.TTS); }
535 if (t0 .isFree()) { t0 .set(parameters.t0); }
536 if (bg .isFree()) { bg .set(parameters.bg); }
537 }
538
539
540 /**
541 * Get number of fit parameters.
542 *
543 * \return number of parameters
544 */
545 inline size_t getN() const
546 {
547 return ((QE. isFree() ? 1 : 0) +
548 (TTS.isFree() ? 1 : 0) +
549 (t0 .isFree() ? 1 : 0) +
550 (bg .isFree() ? 1 : 0));
551 }
552
553
554 /**
555 * Disable PMT.
556 */
557 void disable()
558 {
559 status = false;
560
561 QE .fix(0.0);
562 TTS.fix(TTS_NS);
563 t0 .fix(0.0);
564 bg .fix(0.0);
565 }
566
567
568 /**
569 * Enable PMT.
570 */
571 void enable()
572 {
573 status = true;
574
575 QE .set();
576 TTS.set();
577 t0 .set();
578 bg .set();
579 }
580
581
582 /**
583 * Write PMT parameters to output stream.
584 *
585 * \param out output stream
586 * \param object PMT parameters
587 * \return output stream
588 */
589 friend inline std::ostream& operator<<(std::ostream& out, const JPMTParameters_t& object)
590 {
591 using namespace std;
592
593 out << "QE " << FIXED(7,3) << object.QE << endl;
594 out << "TTS " << FIXED(7,3) << object.TTS << endl;
595 out << "t0 " << FIXED(7,3) << object.t0 << endl;
596 out << "bg " << FIXED(7,3) << object.bg << endl;
597
598 return out;
599 }
600
601
602 bool status; //!< status
603 JParameter_t QE; //!< relative quantum efficiency [unit]
604 JParameter_t TTS; //!< transition-time spread [ns]
605 JParameter_t t0; //!< time offset [ns]
606 JParameter_t bg; //!< background [Hz/ns]
607 };
608
609
610 /**
611 * Fit parameters for two-fold coincidence rate due to K40.
612 */
614 /**
615 * Default constructor.
616 */
618 {
619 reset();
620 }
621
622
623 /**
624 * Get K40 parameters.
625 *
626 * \return K40 parameters
627 */
629 {
630 return static_cast<const JK40Parameters_t&>(*this);
631 }
632
633
634 /**
635 * Set K40 parameters.
636 *
637 * \param parameters K40 parameters
638 */
639 void setK40Parameters(const JK40Parameters_t& parameters)
640 {
641 static_cast<JK40Parameters_t&>(*this) = parameters;
642 }
643
644
645 /**
646 * Reset.
647 */
648 void reset()
649 {
650 R .set(0.0);
651 p1.set(0.0);
652 p2.set(0.0);
653 p3.set(0.0);
654 p4.set(0.0);
655 cc.set(0.0);
656 bc.set(0.0);
657 }
658
659
660 /**
661 * Print model parameters to output stream conform include files.
662 *
663 * \param out output stream
664 */
665 void print(std::ostream& out) const
666 {
667 using namespace std;
668
669 out << "JFitK40.hh" << endl;
670 out << "parameters.R .set(" << FIXED(9,6) << this->R () << ");" << endl;
671 out << "parameters.p1.set(" << FIXED(9,6) << this->p1() << ");" << endl;
672 out << "parameters.p2.set(" << FIXED(9,6) << this->p2() << ");" << endl;
673 out << "parameters.p3.set(" << FIXED(9,6) << this->p3() << ");" << endl;
674 out << "parameters.p4.set(" << FIXED(9,6) << this->p4() << ");" << endl;
675 out << "cc " << FIXED(9,6) << this->cc() << endl;
676 out << "bc " << FIXED(9,6) << this->bc() << endl;
677 out << endl;
678
679 out << "JK40DefaultSimulator.hh" << endl;
680 out << "static constexpr double p1 = " << FIXED(9,6) << this->p1() << ";" << endl;
681 out << "static constexpr double p2 = " << FIXED(9,6) << this->p2() << ";" << endl;
682 out << "static constexpr double p3 = " << FIXED(9,6) << this->p3() << ";" << endl;
683 out << "static constexpr double p4 = " << FIXED(9,6) << this->p4() << ";" << endl;
684 out << endl;
685 }
686
687
688 /**
689 * Write model parameters to output stream.
690 *
691 * \param out output stream
692 * \param object model parameters
693 * \return output stream
694 */
695 friend inline std::ostream& operator<<(std::ostream& out, const JK40Parameters_t& object)
696 {
697 using namespace std;
698
699 out << "Rate [Hz] " << FIXED(12,6) << object.R << endl;
700 out << "p1 " << FIXED(12,6) << object.p1 << endl;
701 out << "p2 " << FIXED(12,6) << object.p2 << endl;
702 out << "p3 " << FIXED(12,6) << object.p3 << endl;
703 out << "p4 " << FIXED(12,6) << object.p4 << endl;
704 out << "cc " << FIXED(12,6) << object.cc << endl;
705 out << "bc " << FIXED(12,6) << object.bc << endl;
706 out << endl;
707
708 return out;
709 }
710
711 JParameter_t R; //!< maximal coincidence rate [Hz]
712 JParameter_t p1; //!< 1st order angle dependence coincidence rate
713 JParameter_t p2; //!< 2nd order angle dependence coincidence rate
714 JParameter_t p3; //!< 3rd order angle dependence coincidence rate
715 JParameter_t p4; //!< 4th order angle dependence coincidence rate
716 JParameter_t cc; //!< fraction of signal correlated background
717 JParameter_t bc; //!< constant background
718 };
719
720
721 /**
722 * Fit parameters for two-fold coincidence rate due to K40.
723 */
726 {
727 /**
728 * Default constructor.
729 */
732
733
734 /**
735 * Get default values.
736 *
737 * Values obtained with $JPP_DIR/examples/JCalibrate/JOMGsim.sh type B (see $JPP_DIR/examples/JCalibrate/README.md).
738 * If you change these values, you may also want to change the corresponding values in JK40DefaultSimulator.hh.
739 *
740 * \return parameters
741 */
743 {
744 static JK40Parameters parameters;
745 parameters.R .set(18.430675);
746 parameters.p1.set( 2.919895);
747 parameters.p2.set(-0.831970);
748 parameters.p3.set( 1.407887);
749 parameters.p4.set( 0.170510);
750 parameters.cc.set( 0.0);
751 parameters.bc.set( 0.0);
752
753 return parameters;
754 }
755
756
757 /**
758 * Get number of fit parameters.
759 *
760 * \return number of parameters
761 */
762 inline size_t getN() const
763 {
764 return ((R .isFree() ? 1 : 0) +
765 (p1.isFree() ? 1 : 0) +
766 (p2.isFree() ? 1 : 0) +
767 (p3.isFree() ? 1 : 0) +
768 (p4.isFree() ? 1 : 0) +
769 (cc.isFree() ? 1 : 0) +
770 (bc.isFree() ? 1 : 0));
771 }
772
773
774 /**
775 * Get index of parameter.
776 *
777 * \param p pointer to data member
778 * \return index
779 */
781 {
782 if (!(this->*p).isFree()) {
783 return INVALID_INDEX;
784 }
785
786 int N = 0;
787
788 if (p == &JK40Parameters::R) { return N; } if (R .isFree()) { ++N; }
789 if (p == &JK40Parameters::p1) { return N; } if (p1.isFree()) { ++N; }
790 if (p == &JK40Parameters::p2) { return N; } if (p2.isFree()) { ++N; }
791 if (p == &JK40Parameters::p3) { return N; } if (p3.isFree()) { ++N; }
792 if (p == &JK40Parameters::p4) { return N; } if (p4.isFree()) { ++N; }
793 if (p == &JK40Parameters::cc) { return N; } if (cc.isFree()) { ++N; }
794 if (p == &JK40Parameters::bc) { return N; } if (bc.isFree()) { ++N; }
795
796 return INVALID_INDEX;
797 }
798
799
800 /**
801 * Get K40 coincidence rate as a function of cosine angle between PMT axes.
802 *
803 * \param ct cosine angle between PMT axes
804 * \return rate [Hz]
805 */
806 double getValue(const double ct) const
807 {
808 return R * exp(ct*(p1+ct*(p2+ct*(p3+ct*p4))) - (p1+p2+p3+p4));
809 }
810
811
812 /**
813 * Get gradient.
814 *
815 * \param ct cosine angle between PMT axes
816 * \return gradient
817 */
818 const JK40Parameters_t& getGradient(const double ct) const
819 {
820 gradient.reset();
821
822 const double rate = getValue(ct);
823 const double ct2 = ct * ct;
824
825 if (R .isFree()) { gradient.R = rate / R; }
826 if (p1.isFree()) { gradient.p1 = rate * ct - rate; }
827 if (p2.isFree()) { gradient.p2 = rate * ct2 - rate; }
828 if (p3.isFree()) { gradient.p3 = rate * ct2 * ct - rate; }
829 if (p4.isFree()) { gradient.p4 = rate * ct2 * ct2 - rate; }
830 if (cc.isFree()) { gradient.cc = rate; }
831 if (bc.isFree()) { gradient.bc = 1.0; }
832
833 return gradient;
834 }
835
836 private:
838 };
839
840
841 /**
842 * Auxiliary data structure for fraction of water to total.
843 */
844 struct JWater :
845 public JK40Parameters_t
846 {
847 /**
848 * Default constructor.
849 */
851 {
852 //simple for Water
853 this->R .set( 0.595927);
854 this->p1.set(-0.032784);
855 this->p2.set( 0.075297);
856 this->p3.set(-0.076032);
857 this->p4.set(-0.453102);
858
859 /*
860 //simple DOM low stat for Water
861 this->R .set( 0.589235);
862 this->p1.set(-0.018508);
863 this->p2.set( 0.105162);
864 this->p3.set(-0.107452);
865 this->p4.set(-0.475067);
866 */
867
868 /*
869 //full DOM for Water
870 this->R .set( 0.649367);
871 this->p1.set(-0.011764);
872 this->p2.set(-0.282949);
873 this->p3.set(-0.119943);
874 this->p4.set(-0.019789);
875 */
876 }
877
878
879 /**
880 * Get fraction of water as a function of cosine angle between PMT axes.
881 *
882 * \param ct cosine angle between PMT axes
883 * \return fraction
884 */
885 double operator()(const double ct) const
886 {
887 return R * exp(ct*(p1+ct*(p2+ct*(p3+ct*p4))) - (p1+p2+p3+p4));
888 }
889 };
890
891
892 /**
893 * Function object for fraction of water to total.
894 */
896
897
898 /**
899 * Auxiliary data structure to define ring.
900 * The ring values run from 'A' (down) to 'F' (up).
901 */
902 struct ring_type {
903 /**
904 * Constructor.
905 *
906 * \param c ring
907 */
908 ring_type(const char c) :
909 c(c)
910 {}
911
912
913 /**
914 * Get index.
915 *
916 * \return index
917 */
918 int getIndex() const
919 {
920 return (c - 'A');
921 }
922
923
924 /**
925 * Type conversion operator.
926 *
927 * \return index
928 */
929 operator int() const
930 {
931 return getIndex();
932 }
933
934
935 /**
936 * Get ring.
937 *
938 * \param index index
939 * \return ring
940 */
941 static inline ring_type getRing(const int index)
942 {
943 return { (char) ('A' + index) };
944 }
945
946
947 /**
948 * Read ring from input stream.
949 *
950 * \param in input stream
951 * \param ring ring
952 * \return input stream
953 */
954 friend inline std::istream& operator>>(std::istream& in, ring_type& ring)
955 {
956 return in >> ring.c;
957 }
958
959
960 /**
961 * Write ring to output stream.
962 *
963 * \param out output stream
964 * \param ring ring
965 * \return output stream
966 */
967 friend inline std::ostream& operator<<(std::ostream& out, const ring_type& ring)
968 {
969 return out << ring.c;
970 }
971
972 char c; // ring
973 };
974
975
976 /**
977 * Type definition of indices of pair of rings.
978 */
980
981
982 /**
983 * Get ring.
984 *
985 * \param dz cosine zenith angle of PMT axis
986 * \return ring
987 */
988 inline ring_type getRing(const double dz)
989 {
990 const double rz[] = { // cosine zenith angle of PMT axes
991 -1.000,
992 -0.850,
993 -0.555,
994 -0.295,
995 +0.295,
996 +0.555
997 };
998
999 const int N = sizeof(rz) / sizeof(rz[0]);
1000
1001 for (int i = 1; i != N; ++i) {
1002 if (dz <= 0.5 * (rz[i-1] + rz[i])) {
1003 return ring_type::getRing(i-1);
1004 }
1005 }
1006
1007 return ring_type::getRing(N-1);
1008 }
1009
1010
1011 /**
1012 * Auxiliary data structure to handle transmittance of glass sphere due to sedimentation.
1013 */
1015 std::array<JParameter_t, NUMBER_OF_RINGS>
1016 {
1017 /**
1018 * Default constructor.
1019 */
1021 {
1022 reset();
1023 }
1024
1025
1026 /**
1027 * Reset.
1028 */
1029 void reset()
1030 {
1031 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1032 (*this)[i].set(0.0);
1033 }
1034 }
1035
1036
1037 /**
1038 * Set parameters that are free to given values.
1039 *
1040 * \param parameters parameters
1041 */
1042 void set(const JTransmittance_t& parameters)
1043 {
1044 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1045 if ((*this)[i].isFree()) { (*this)[i].set(parameters[i].get()); }
1046 }
1047 }
1048 };
1049
1050
1051 /**
1052 * Auxiliary data structure to handle transmittance of glass sphere due to sedimentation.
1053 */
1055 public JTransmittance_t
1056 {
1057 /**
1058 * Default constructor.
1059 */
1062
1063
1064 /**
1065 * Get default values.
1066 *
1067 * \return transmittance
1068 */
1070 {
1071 static JTransmittance transmittance;
1072
1073 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1074 transmittance[i].set(1.0);
1075 }
1076
1077 return transmittance;
1078 }
1079
1080
1081 /**
1082 * Get number of fit parameters.
1083 *
1084 * \return number of parameters
1085 */
1086 inline size_t getN() const
1087 {
1088 int N = 0;
1089
1090 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1091 if ((*this)[i].isFree()) {
1092 N += 1;
1093 }
1094 }
1095
1096 return N;
1097 }
1098
1099
1100 /**
1101 * Get weighed contribution of water and glass.
1102 *
1103 * \param ct cosine angle between PMT axes
1104 * \param pair PMT ring pair
1105 * \return fraction
1106 */
1107 double getValue(const double ct, const ring_pair pair) const
1108 {
1109 const double w = getWater(ct);
1110
1111 return w * (*this)[pair.first].get() * (*this)[pair.second].get() + (1.0 - w);
1112 }
1113
1114
1115 /**
1116 * Get gradient.
1117 *
1118 * \param ct cosine angle between PMT axes
1119 * \param pair PMT ring pair
1120 * \return gradient
1121 */
1122 const JTransmittance_t& getGradient(const double ct, const ring_pair pair) const
1123 {
1124 gradient.reset();
1125
1126 const double w = getWater(ct);
1127
1128 gradient[pair.first] += w * (*this)[pair.second].get();
1129 gradient[pair.second] += w * (*this)[pair.first] .get();
1130
1131 return gradient;
1132 }
1133
1134
1135 /**
1136 * Write transmittances to output stream.
1137 *
1138 * \param out output stream
1139 * \param object transmittances
1140 * \return output stream
1141 */
1142 friend inline std::ostream& operator<<(std::ostream& out, const JTransmittance& object)
1143 {
1144 using namespace std;
1145
1146 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1147 out << "transmittance[" << ring_type::getRing(i) << "] " << object[i].get() << endl;
1148 }
1149
1150 return out;
1151 }
1152
1153 private:
1155 };
1156
1157
1158 /**
1159 * Fit model.
1160 */
1161 struct JModel_t {
1162
1166
1167
1168 /**
1169 * Reset.
1170 */
1171 void reset()
1172 {
1173 model .reset();
1175
1176 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1177 parameters[i].reset();
1178 }
1179 }
1180
1181
1182 /**
1183 * Write model parameters to output stream.
1184 *
1185 * \param out output stream
1186 * \param object model parameters
1187 * \return output stream
1188 */
1189 friend inline std::ostream& operator<<(std::ostream& out, const JModel_t& object)
1190 {
1191 using namespace std;
1192
1193 out << object.model;
1194 out << object.transmittance;
1195
1196 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1197 out << "PMT[" << FILL(2,'0') << i << FILL() << "]." << object.parameters[i].status << endl << object.parameters[i];
1198 }
1199
1200 return out;
1201 }
1202 };
1203
1204
1205 /**
1206 * Fit model.
1207 *
1208 * In the absence of TDC constraints, the average time offset is fixed to zero.
1209 */
1210 struct JModel :
1211 public JModel_t,
1212 public JModule,
1213 public JCombinatorics_t
1214 {
1216
1217 /**
1218 * Auxiliary data structure for derived quantities of a given PMT pair.
1219 */
1220 struct real_type {
1221 ring_pair pair; //!< PMT ring pair
1222 double ct; //!< cosine angle between PMT axes
1223 double t0; //!< time offset [ns]
1224 double sigma; //!< total width [ns]
1225 double signal; //!< combined signal
1226 double background; //!< combined background
1227 double cc; //!< correlated background
1228 double bc; //!< uncorrelated background
1229 };
1230
1231
1232 /**
1233 * Default constructor.
1234 */
1236 {}
1237
1238
1239 /**
1240 * Constructor.
1241 *
1242 * \param module detector module
1243 * \param parameters K40 parameters
1244 * \param TDC TDC constraints
1245 * \param option option
1246 */
1247 JModel(const JModule& module,
1249 const JTDC_t::range_type& TDC,
1250 const int option) :
1251 JModule (module),
1252 JCombinatorics_t(module)
1253 {
1254 model = parameters;
1256
1257 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1258 this->parameters[i] = JPMTParameters_t::getInstance();
1259 }
1260
1261 for (JTDC_t::const_iterator i = TDC.first; i != TDC.second; ++i) {
1262
1263 if (i->second != JTDC_t::WILDCARD) {
1264
1265 this->parameters[i->second].t0.fix();
1266
1267 } else {
1268
1269 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1270 this->parameters[i].t0.fix();
1271 }
1272 }
1273 }
1274
1275 this->index = (TDC.first == TDC.second ? 0 : INVALID_INDEX);
1276
1278 }
1279
1280
1281 /**
1282 * Constructor.
1283 *
1284 * \param module detector module
1285 * \param parameters K40 parameters
1286 */
1287 JModel(const JModule& module,
1288 const JK40Parameters& parameters) :
1289 JModule (module),
1290 JCombinatorics_t(module)
1291 {
1292 model = parameters;
1294
1295 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1296 this->parameters[i] = JPMTParameters_t::getInstance();
1297 }
1298 }
1299
1300
1301 /**
1302 * Get fit option.
1303 *
1304 * \return option
1305 */
1307 {
1308 return option;
1309 }
1310
1311
1312 /**
1313 * Set fit option.
1314 *
1315 * \param option option
1316 */
1317 inline void setOption(const int option)
1318 {
1319 switch (option) {
1320
1321 case FIT_PMTS_t:
1322
1323 model.R .fix();
1324 model.p1.fix();
1325 model.p2.fix();
1326 model.p3.fix();
1327 model.p4.fix();
1328
1329 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1330 transmittance[i].fix();
1331 }
1332
1333 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1334 parameters[i].bg.fix();
1335 }
1336
1337 break;
1338
1340
1341 model.R .fix();
1342
1343 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1344 transmittance[i].fix();
1345 }
1346
1347 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1348 parameters[i].bg.fix();
1349 }
1350
1351 break;
1352
1354
1355 model.R .fix();
1356 model.p1.fix();
1357 model.p2.fix();
1358 model.p3.fix();
1359 model.p4.fix();
1360
1361 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1362 transmittance[i].fix();
1363 }
1364
1365 break;
1366
1368
1369 model.R .fix();
1370 model.p1.fix();
1371 model.p2.fix();
1372 model.p3.fix();
1373 model.p4.fix();
1374
1375 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1376 transmittance[i].fix();
1377 }
1378
1379 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1380 parameters[i].QE.fix();
1381 parameters[i].bg.fix();
1382 }
1383
1384 break;
1385
1386 case FIT_MODEL_t:
1387
1389
1390 //cc.fix();
1391 //bc.fix();
1392
1393 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1394 transmittance[i].fix();
1395 }
1396
1397 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1398 parameters[i].QE.fix();
1399 parameters[i].t0.fix();
1400 parameters[i].bg.fix();
1401 }
1402
1403 break;
1404
1405 default:
1406
1407 THROW(JValueOutOfRange, "Invalid option " << option);
1408 }
1409
1410 this->option = static_cast<JOption_t>(option);
1411 }
1412
1413
1414 /**
1415 * Check if time offset is fixed.
1416 *
1417 * \return true if time offset fixed; else false
1418 */
1420 {
1421 return index != INVALID_INDEX;
1422 }
1423
1424
1425 /**
1426 * Get time offset.
1427 *
1428 * \return time offset
1429 */
1430 double getFixedTimeOffset() const
1431 {
1432 double t0 = 0.0;
1433 size_t N = 0;
1434
1435 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1436 if (parameters[i].t0.isFree()) {
1437 t0 += parameters[i].t0;
1438 N += 1;
1439 }
1440 }
1441
1442 return t0 /= N;
1443 }
1444
1445
1446 /**
1447 * Get index of PMT used for fixed time offset.
1448 *
1449 * \return index
1450 */
1451 int getIndex() const
1452 {
1453 return index;
1454 }
1455
1456
1457 /**
1458 * Set index of PMT used for fixed time offset.
1459 */
1461 {
1462 if (index != INVALID_INDEX) {
1463
1464 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1465
1466 if (parameters[i].status) {
1467
1468 index = i;
1469
1471
1472 return;
1473 }
1474 }
1475
1476 THROW(JValueOutOfRange, "No valid index.");
1477 }
1478 }
1479
1480
1481 /**
1482 * Get number of fit parameters.
1483 *
1484 * \return number of parameters
1485 */
1486 inline size_t getN() const
1487 {
1488 size_t N = 0;
1489
1490 N += model .getN();
1491 N += transmittance.getN();
1492
1493 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1494 N += parameters[i].getN();
1495 }
1496
1497 return N;
1498 }
1499
1500
1501 /**
1502 * Get intrinsic K40 arrival time spread.
1503 *
1504 * \return sigma [ns]
1505 */
1506 double getSigmaK40() const
1507 {
1508 return this->sigmaK40_ns;
1509 }
1510
1511
1512 /**
1513 * Set intrinsic K40 arrival time spread.
1514 *
1515 * \param sigma sigma [ns]
1516 */
1517 void setSigmaK40(const double sigma)
1518 {
1519 this->sigmaK40_ns = sigma;
1520 }
1521
1522
1523 /**
1524 * Get derived quantities.
1525 *
1526 * \param pair PMT pair
1527 * \return quantities
1528 */
1529 const real_type& getReal(const pair_type& pair) const
1530 {
1531 real.pair.first = getRing((*this)[pair.first] .getDZ()).getIndex();
1532 real.pair.second = getRing((*this)[pair.second].getDZ()).getIndex();
1533
1534 real.ct = JPP::getDot((*this)[pair.first].getDirection(), (*this)[pair.second].getDirection());
1535
1536 real.t0 = (pair.first == this->index ? -this->parameters[pair.second].t0() :
1537 pair.second == this->index ? +this->parameters[pair.first ].t0() :
1538 this->parameters[pair.first].t0() - this->parameters[pair.second].t0());
1539
1540 real.sigma = sqrt(this->parameters[pair.first ].TTS() * this->parameters[pair.first ].TTS() +
1541 this->parameters[pair.second].TTS() * this->parameters[pair.second].TTS() +
1542 this->getSigmaK40() * this->getSigmaK40());
1543
1544 real.signal = this->parameters[pair.first].QE() * this->parameters[pair.second].QE();
1545
1546 real.background = this->parameters[pair.first].bg() + this->parameters[pair.second].bg();
1547
1548 real.cc = real.signal * model.cc();
1549 real.bc = model.bc();
1550
1551 const double z1 = (*this)[pair.first ].getDirection().getDZ();
1552 const double z2 = (*this)[pair.second].getDirection().getDZ();
1553
1554 if (fabs(z1) <= TEROSTAT_DZ &&
1555 fabs(z2) <= TEROSTAT_DZ &&
1556 signbit(z1) != signbit(z2)) {
1557
1559 }
1560
1561 return real;
1562 }
1563
1564
1565 /**
1566 * Get K40 coincidence rate as a function of cosine angle between PMT axes.
1567 *
1568 * \param ct cosine angle between PMT axes
1569 * \return rate [Hz]
1570 */
1571 double getValue(const double ct) const
1572 {
1573 return model.getValue(ct);
1574 }
1575
1576
1577 /**
1578 * Get K40 coincidence rate.
1579 *
1580 * \param pair PMT pair
1581 * \param dt_ns time difference [ns]
1582 * \return rate [Hz/ns]
1583 */
1584 double getValue(const pair_type& pair, const double dt_ns) const
1585 {
1586 using namespace std;
1587 using namespace JPP;
1588
1589 const real_type& real = getReal(pair);
1590
1591 const JBell bell(real.t0, real.sigma, real.signal, 0.0, BELL_SHAPE);
1592
1593 const double R1 = model.getValue(real.ct);
1594 const double R2 = bell .getValue(dt_ns);
1595
1596 return real.bc + real.background + R1 * (real.cc + R2);
1597 }
1598
1599
1600 /**
1601 * Write model parameters to output stream.
1602 *
1603 * \param out output stream
1604 * \param object model parameters
1605 * \return output stream
1606 */
1607 friend inline std::ostream& operator<<(std::ostream& out, const JModel& object)
1608 {
1609 using namespace std;
1610
1611 out << "Module " << setw(10) << object.getID() << endl;
1612 out << "option " << object.option << endl;
1613 out << "index " << object.index << endl;
1614
1615 out << static_cast<const JModel_t&>(object);
1616
1617 return out;
1618 }
1619
1620 private:
1621 int index; //!< index of PMT used for fixed time offset
1622 double sigmaK40_ns = 0.54; //!< intrinsic K40 arrival time spread [ns]
1623 JOption_t option; //!< fit option (see JCALIBRATE::JOption_t)
1625 };
1626
1627
1628 /**
1629 * Fit.
1630 */
1631 class JFit
1632 {
1633 public:
1634 /**
1635 * Result type.
1636 */
1638 double chi2;
1639 int ndf;
1640 };
1641
1642 typedef std::shared_ptr<JMEstimator> estimator_type;
1643
1644
1645 /**
1646 * Constructor
1647 *
1648 * \param option M-estimator
1649 * \param debug debug
1650 */
1651 JFit(const int option, const int debug) :
1652 debug(debug)
1653 {
1654 using namespace JPP;
1655
1656 estimator.reset(getMEstimator(option));
1657 }
1658
1659
1660 /**
1661 * Fit.
1662 *
1663 * \param data data
1664 * \return chi2, NDF
1665 */
1667 {
1668 using namespace std;
1669 using namespace JPP;
1670
1671
1672 value.setIndex();
1673
1674 const size_t N = value.getN();
1675
1676 V.resize(N);
1677 Y.resize(N);
1678 h.resize(N);
1679
1680 double xmax = numeric_limits<double>::lowest();
1681 double xmin = numeric_limits<double>::max();
1682
1683 int ndf = 0;
1684
1685 for (data_type::const_iterator ix = data.begin(); ix != data.end(); ++ix) {
1686
1687 const pair_type& pair = ix->first;
1688
1689 if (value.parameters[pair.first ].status &&
1690 value.parameters[pair.second].status) {
1691
1692 ndf += ix->second.size();
1693
1694 for (const rate_type& iy : ix->second) {
1695 if (iy.dt_ns > xmax) { xmax = iy.dt_ns; }
1696 if (iy.dt_ns < xmin) { xmin = iy.dt_ns; }
1697 }
1698 }
1699 }
1700
1701 ndf -= value.getN();
1702
1703 if (ndf < 0) {
1704 return { 0.0, ndf };
1705 }
1706
1707 for (int pmt = 0; pmt != NUMBER_OF_PMTS; ++pmt) {
1708 if (value.parameters[pmt].t0.isFree()) {
1709 value.parameters[pmt].t0.setLimits(xmin, xmax);
1710 }
1711 }
1712
1713
1715
1716 double precessor = numeric_limits<double>::max();
1717
1719
1720 DEBUG("step: " << numberOfIterations << endl);
1721
1722 evaluate(data);
1723
1724 DEBUG("lambda: " << FIXED(12,5) << lambda << endl);
1725 DEBUG("chi2: " << FIXED(12,3) << successor << endl);
1726
1727 if (successor < precessor) {
1728
1729 if (numberOfIterations != 0) {
1730
1731 if (fabs(precessor - successor) < EPSILON) {
1732
1733 seterr(data);
1734
1735 return { successor / estimator->getRho(1.0), ndf };
1736 }
1737
1738 if (lambda > LAMBDA_MIN) {
1740 }
1741 }
1742
1743 precessor = successor;
1744 previous = value;
1745
1746 } else {
1747
1748 value = previous;
1749 lambda *= LAMBDA_UP;
1750
1751 if (lambda > LAMBDA_MAX) {
1752 break;
1753 }
1754
1755 evaluate(data);
1756 }
1757
1758 if (debug >= debug_t) {
1759
1760 size_t row = 0;
1761
1762 if (value.model.R .isFree()) { cout << "R " << FIXED(12,5) << Y[row] << endl; ++row; }
1763 if (value.model.p1.isFree()) { cout << "p1 " << FIXED(12,5) << Y[row] << endl; ++row; }
1764 if (value.model.p2.isFree()) { cout << "p2 " << FIXED(12,5) << Y[row] << endl; ++row; }
1765 if (value.model.p3.isFree()) { cout << "p3 " << FIXED(12,5) << Y[row] << endl; ++row; }
1766 if (value.model.p4.isFree()) { cout << "p4 " << FIXED(12,5) << Y[row] << endl; ++row; }
1767 if (value.model.cc.isFree()) { cout << "cc " << FIXED(12,3) << Y[row] << endl; ++row; }
1768
1769 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1770 if (value.transmittance[i].isFree()) { cout << "transmittance[" << ring_type::getRing(i) << "] " << FIXED(9,6) << Y[row] << endl; ++row; }
1771 }
1772
1773 for (int pmt = 0; pmt != NUMBER_OF_PMTS; ++pmt) {
1774 if (value.parameters[pmt].QE .isFree()) { cout << "PMT[" << setw(2) << pmt << "].QE " << FIXED(12,5) << Y[row] << endl; ++row; }
1775 if (value.parameters[pmt].TTS.isFree()) { cout << "PMT[" << setw(2) << pmt << "].TTS " << FIXED(12,5) << Y[row] << endl; ++row; }
1776 if (value.parameters[pmt].t0 .isFree()) { cout << "PMT[" << setw(2) << pmt << "].t0 " << FIXED(12,5) << Y[row] << endl; ++row; }
1777 if (value.parameters[pmt].bg .isFree()) { cout << "PMT[" << setw(2) << pmt << "].bg " << FIXED(12,5) << Y[row] << endl; ++row; }
1778 }
1779 }
1780
1781 // force definite positiveness
1782
1783 for (size_t i = 0; i != N; ++i) {
1784
1785 if (V(i,i) < PIVOT) {
1786 V(i,i) = PIVOT;
1787 }
1788
1789 h[i] = 1.0 / sqrt(V(i,i));
1790 }
1791
1792 // normalisation
1793
1794 for (size_t i = 0; i != N; ++i) {
1795 for (size_t j = 0; j != i; ++j) {
1796 V(j,i) *= h[i] * h[j];
1797 V(i,j) = V(j,i);
1798 }
1799 }
1800
1801 for (size_t i = 0; i != N; ++i) {
1802 V(i,i) = 1.0 + lambda;
1803 }
1804
1805 // solve A x = b
1806
1807 for (size_t col = 0; col != N; ++col) {
1808 Y[col] *= h[col];
1809 }
1810
1811 try {
1812 V.solve(Y);
1813 }
1814 catch (const exception& error) {
1815
1816 ERROR("JGandalf: " << error.what() << endl << V << endl);
1817
1818 break;
1819 }
1820
1821 // update value
1822
1823 const double factor = 2.0;
1824
1825 size_t row = 0;
1826
1827 if (value.model.R .isFree()) { value.model.R -= factor * h[row] * Y[row]; ++row; }
1828 if (value.model.p1.isFree()) { value.model.p1 -= factor * h[row] * Y[row]; ++row; }
1829 if (value.model.p2.isFree()) { value.model.p2 -= factor * h[row] * Y[row]; ++row; }
1830 if (value.model.p3.isFree()) { value.model.p3 -= factor * h[row] * Y[row]; ++row; }
1831 if (value.model.p4.isFree()) { value.model.p4 -= factor * h[row] * Y[row]; ++row; }
1832 if (value.model.cc.isFree()) { value.model.cc -= factor * h[row] * Y[row]; ++row; }
1833 if (value.model.bc.isFree()) { value.model.bc -= factor * h[row] * Y[row]; ++row; }
1834
1835 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1836 if (value.transmittance[i].isFree()) { value.transmittance[i] -= factor * h[row] * Y[row]; ++row; }
1837 }
1838
1839 for (int pmt = 0; pmt != NUMBER_OF_PMTS; ++pmt) {
1840 if (value.parameters[pmt].QE .isFree()) { value.parameters[pmt].QE -= factor * h[row] * Y[row]; ++row; }
1841 if (value.parameters[pmt].TTS.isFree()) { value.parameters[pmt].TTS -= factor * h[row] * Y[row]; ++row; }
1842 if (value.parameters[pmt].t0 .isFree()) { value.parameters[pmt].t0 -= factor * h[row] * Y[row]; ++row; }
1843 if (value.parameters[pmt].bg .isFree()) { value.parameters[pmt].bg -= factor * h[row] * Y[row]; ++row; }
1844 }
1845 }
1846
1847 seterr(data);
1848
1849 return { precessor / estimator->getRho(1.0), ndf };
1850 }
1851
1852
1853 static constexpr int MAXIMUM_ITERATIONS = 100000; //!< maximal number of iterations.
1854 static constexpr double EPSILON = 1.0e-3; //!< maximal distance to minimum.
1855 static constexpr double LAMBDA_MIN = 1.0e-2; //!< minimal value control parameter
1856 static constexpr double LAMBDA_MAX = 1.0e+4; //!< maximal value control parameter
1857 static constexpr double LAMBDA_UP = 10.0; //!< multiplication factor control parameter
1858 static constexpr double LAMBDA_DOWN = 10.0; //!< multiplication factor control parameter
1859 static constexpr double PIVOT = std::numeric_limits<double>::epsilon(); //!< minimal value diagonal element of matrix
1860
1862 estimator_type estimator; //!< M-Estimator function
1863
1864 double lambda;
1869
1870 bool TEST = false;
1871
1872 private:
1873 /**
1874 * Evaluation of fit.
1875 *
1876 * \param data data
1877 */
1878 void evaluate(const data_type& data)
1879 {
1880 using namespace std;
1881 using namespace JPP;
1882
1883 typedef JModel::real_type real_type;
1884
1885
1886 successor = 0.0;
1887
1888 V.reset();
1889 Y.reset();
1890
1891
1892 // model parameter indices
1893
1894 const struct M_t {
1895 M_t(const JModel& value)
1896 {
1897 R = value.model.getIndex(&JK40Parameters_t::R);
1898 p1 = value.model.getIndex(&JK40Parameters_t::p1);
1899 p2 = value.model.getIndex(&JK40Parameters_t::p2);
1900 p3 = value.model.getIndex(&JK40Parameters_t::p3);
1901 p4 = value.model.getIndex(&JK40Parameters_t::p4);
1902 cc = value.model.getIndex(&JK40Parameters_t::cc);
1903 bc = value.model.getIndex(&JK40Parameters_t::bc);
1904 }
1905
1906 int R;
1907 int p1;
1908 int p2;
1909 int p3;
1910 int p4;
1911 int cc;
1912 int bc;
1913
1914 } M(value);
1915
1916
1917 // transmittance indices
1918
1919 const struct T_t : public std::array<int, NUMBER_OF_RINGS> {
1920 T_t(const JModel& value)
1921 {
1922 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1923 (*this)[i] = INVALID_INDEX;
1924 }
1925
1926 int N = value.model.getN();
1927
1928 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
1929 if (value.transmittance[i].isFree()) { (*this)[i] = N; ++N; }
1930 }
1931 }
1932 } T(value);
1933
1934
1935 // PMT parameter indices
1936
1937 struct i_t {
1938 i_t() :
1939 QE (INVALID_INDEX),
1940 TTS(INVALID_INDEX),
1941 t0 (INVALID_INDEX),
1942 bg (INVALID_INDEX)
1943 {}
1944
1945 int QE;
1946 int TTS;
1947 int t0;
1948 int bg;
1949 };
1950
1951 const struct I_t : public std::array<i_t, NUMBER_OF_PMTS> {
1952 I_t(const JModel& value)
1953 {
1954 int N = value.model.getN() + value.transmittance.getN();
1955
1956 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1957 if (value.parameters[i].QE .isFree()) { (*this)[i].QE = N; ++N; }
1958 if (value.parameters[i].TTS.isFree()) { (*this)[i].TTS = N; ++N; }
1959 if (value.parameters[i].t0 .isFree()) { (*this)[i].t0 = N; ++N; }
1960 if (value.parameters[i].bg .isFree()) { (*this)[i].bg = N; ++N; }
1961 }
1962 }
1963
1964 } I(value);
1965
1966
1967 struct buffer_type : public vector< pair<int, double> > {
1968 double operator[](const int index) const
1969 {
1970 for (const_iterator i = this->begin(); i != this->end(); ++i) {
1971 if (i->first == index) {
1972 return i->second;
1973 }
1974 }
1975
1976 THROW(JValueOutOfRange, "Invalid index " << index);
1977 }
1978 };
1979
1980 buffer_type buffer;
1981
1982#define PUSH_BACK(i,v) if (i != INVALID_INDEX) { buffer.push_back({i, v}); }
1983
1984
1985 size_t number_of_errors = 0;
1986
1987 for (data_type::const_iterator ix = data.begin(); ix != data.end(); ++ix) {
1988
1989 const pair_type& pair = ix->first;
1990
1991 if (value.parameters[pair.first ].status &&
1992 value.parameters[pair.second].status) {
1993
1994 const real_type& real = value.getReal(pair);
1995
1996 const JBell bell(real.t0, real.sigma, real.signal, 0.0, BELL_SHAPE);
1997
1998 const double R1 = value.model .getValue (real.ct);
1999 const double T1 = value.transmittance.getValue (real.ct, real.pair);
2000 const JK40Parameters_t& R1p = value.model .getGradient(real.ct);
2001 const JTransmittance_t& T1p = value.transmittance.getGradient(real.ct, real.pair);
2002
2003 for (const rate_type& iy : ix->second) {
2004
2005 const double R2 = bell.getValue (iy.dt_ns);
2006 const JBell_t& R2p = bell.getGradient(iy.dt_ns);
2007
2008 const double R = real.bc + real.background + T1 * R1 * (real.cc + R2);
2009 const double u = (iy.value - R) / iy.error;
2010 const double w = -estimator->getPsi(u) / iy.error;
2011
2012 successor += estimator->getRho(u);
2013
2014 buffer.clear();
2015
2016 PUSH_BACK(M.R, w * T1 * (real.cc + R2) * R1p.R () * value.model.R .getDerivative());
2017 PUSH_BACK(M.p1, w * T1 * (real.cc + R2) * R1p.p1() * value.model.p1.getDerivative());
2018 PUSH_BACK(M.p2, w * T1 * (real.cc + R2) * R1p.p2() * value.model.p2.getDerivative());
2019 PUSH_BACK(M.p3, w * T1 * (real.cc + R2) * R1p.p3() * value.model.p3.getDerivative());
2020 PUSH_BACK(M.p4, w * T1 * (real.cc + R2) * R1p.p4() * value.model.p4.getDerivative());
2021 PUSH_BACK(M.cc, w * T1 * real.signal * R1p.cc() * value.model.cc.getDerivative());
2022 PUSH_BACK(M.bc, w * R1p.bc() * value.model.bc.getDerivative());
2023
2024 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
2025 PUSH_BACK(T[i], w * R1 * (real.cc + R2) * T1p[i] * value.transmittance[i].getDerivative());
2026 }
2027
2028 PUSH_BACK(I[pair.first] .QE, w * T1 * R1 * R2p.signal * value.parameters[pair.second].QE () * value.parameters[pair.first ].QE .getDerivative());
2029 PUSH_BACK(I[pair.second].QE, w * T1 * R1 * R2p.signal * value.parameters[pair.first ].QE () * value.parameters[pair.second].QE .getDerivative());
2030 PUSH_BACK(I[pair.first] .TTS, w * T1 * R1 * R2p.sigma * value.parameters[pair.first ].TTS() * value.parameters[pair.first ].TTS.getDerivative() / real.sigma);
2031 PUSH_BACK(I[pair.second].TTS, w * T1 * R1 * R2p.sigma * value.parameters[pair.second].TTS() * value.parameters[pair.second].TTS.getDerivative() / real.sigma);
2032 PUSH_BACK(I[pair.first] .t0, w * T1 * R1 * R2p.mean * value.parameters[pair.first ].t0 .getDerivative() * +1.0);
2033 PUSH_BACK(I[pair.second].t0, w * T1 * R1 * R2p.mean * value.parameters[pair.second].t0 .getDerivative() * -1.0);
2034 PUSH_BACK(I[pair.first] .bg, w * value.parameters[pair.first ].bg .getDerivative());
2035 PUSH_BACK(I[pair.second].bg, w * value.parameters[pair.second].bg .getDerivative());
2036
2037 if (TEST) {
2038
2039 DEBUG("PMT pair(" << setw(2) << pair.first << "," << setw(2) << pair.second << ") " << FIXED(7,3) << iy.dt_ns << " [ns]" << endl);
2040
2041 const double PRECISION = 1.0e-5;
2042
2043#define MAKE_TEST(i,v) if (i != INVALID_INDEX) { \
2044 \
2045 const bool status = fabs(buffer[i] - v) <= PRECISION; \
2046 \
2047 DEBUG((status ? GREEN : RED) \
2048 << setw(20) << left << #i << right << ' ' \
2049 << setw(3) << i << ' ' \
2050 << FIXED(12,5) << buffer[i] << ' ' \
2051 << FIXED(12,5) << v << ' ' \
2052 << (!status ? "***" : "") \
2053 << RESET << endl); \
2054 \
2055 if (!status) { \
2056 number_of_errors += 1; \
2057 } \
2058 }
2059
2060 struct JTest_t : public JModel
2061 {
2062 JTest_t& operator=(const JModel& model)
2063 {
2064 static_cast<JModel&>(*this) = model;
2065
2066 this->model.R .relax();
2067 this->model.p1.relax();
2068 this->model.p2.relax();
2069 this->model.p3.relax();
2070 this->model.p4.relax();
2071 this->model.cc.relax();
2072 this->model.bc.relax();
2073
2074 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
2075 parameters[i].QE .relax();
2076 parameters[i].TTS.relax();
2077 parameters[i].t0 .relax();
2078 parameters[i].bg .relax();
2079 }
2080
2081 return *this;
2082 }
2083
2084 double operator()(const pair_type& pair, const rate_type& iy) const
2085 {
2086 return (iy.value - getValue(pair, iy.dt_ns)) / iy.error;
2087 }
2088 };
2089
2090 const double DX = 1.0e-8; // dx
2091 JTest_t m1, m2; // y1, y2
2092
2093 // derivative
2094
2095 auto fp = [&DX = DX, &m1 = m1, &m2 = m2, &estimator = estimator](const pair_type& pair, const rate_type& iy)
2096 {
2097 return (estimator->getRho(m2(pair, iy)) - estimator->getRho(m1(pair, iy))) / DX;
2098 };
2099
2100 { m1 = m2 = value; m2.model.R += 0.5*DX; m1.model.R -= 0.5*DX; MAKE_TEST(M.R, fp(pair, iy) * value.model.R .getDerivative()); }
2101 { m1 = m2 = value; m2.model.p1 += 0.5*DX; m1.model.p1 -= 0.5*DX; MAKE_TEST(M.p1, fp(pair, iy) * value.model.p1.getDerivative()); }
2102 { m1 = m2 = value; m2.model.p2 += 0.5*DX; m1.model.p2 -= 0.5*DX; MAKE_TEST(M.p2, fp(pair, iy) * value.model.p2.getDerivative()); }
2103 { m1 = m2 = value; m2.model.p3 += 0.5*DX; m1.model.p3 -= 0.5*DX; MAKE_TEST(M.p3, fp(pair, iy) * value.model.p3.getDerivative()); }
2104 { m1 = m2 = value; m2.model.p4 += 0.5*DX; m1.model.p4 -= 0.5*DX; MAKE_TEST(M.p4, fp(pair, iy) * value.model.p4.getDerivative()); }
2105 { m1 = m2 = value; m2.model.cc += 0.5*DX; m1.model.cc -= 0.5*DX; MAKE_TEST(M.cc, fp(pair, iy) * value.model.cc.getDerivative()); }
2106 { m1 = m2 = value; m2.model.bc += 0.5*DX; m1.model.bc -= 0.5*DX; MAKE_TEST(M.bc, fp(pair, iy) * value.model.bc.getDerivative()); }
2107
2108 { m1 = m2 = value; m2.parameters[pair.first] .QE += 0.5*DX; m1.parameters[pair.first] .QE -= 0.5*DX; MAKE_TEST(I[pair.first] .QE, fp(pair, iy) * value.parameters[pair.first] .QE .getDerivative()); }
2109 { m1 = m2 = value; m2.parameters[pair.second].QE += 0.5*DX; m1.parameters[pair.second].QE -= 0.5*DX; MAKE_TEST(I[pair.second].QE, fp(pair, iy) * value.parameters[pair.second].QE .getDerivative()); }
2110 { m1 = m2 = value; m2.parameters[pair.first] .TTS += 0.5*DX; m1.parameters[pair.first] .TTS -= 0.5*DX; MAKE_TEST(I[pair.first] .TTS, fp(pair, iy) * value.parameters[pair.first] .TTS.getDerivative()); }
2111 { m1 = m2 = value; m2.parameters[pair.second].TTS += 0.5*DX; m1.parameters[pair.second].TTS -= 0.5*DX; MAKE_TEST(I[pair.second].TTS, fp(pair, iy) * value.parameters[pair.second].TTS.getDerivative()); }
2112 if (pair.first != value.getIndex()) {
2113 m1 = m2 = value; m2.parameters[pair.first] .t0 += 0.5*DX; m1.parameters[pair.first] .t0 -= 0.5*DX; MAKE_TEST(I[pair.first] .t0, fp(pair, iy) * value.parameters[pair.first] .t0 .getDerivative());
2114 }
2115 if (pair.second != value.getIndex()) {
2116 m1 = m2 = value; m2.parameters[pair.second].t0 += 0.5*DX; m1.parameters[pair.second].t0 -= 0.5*DX; MAKE_TEST(I[pair.second].t0, fp(pair, iy) * value.parameters[pair.second].t0 .getDerivative());
2117 }
2118 { m1 = m2 = value; m2.parameters[pair.first] .bg += 0.5*DX; m1.parameters[pair.first] .bg -= 0.5*DX; MAKE_TEST(I[pair.first] .bg, fp(pair, iy) * value.parameters[pair.first] .bg .getDerivative()); }
2119 { m1 = m2 = value; m2.parameters[pair.second].bg += 0.5*DX; m1.parameters[pair.second].bg -= 0.5*DX; MAKE_TEST(I[pair.second].bg, fp(pair, iy) * value.parameters[pair.second].bg .getDerivative()); }
2120
2121 cout << endl;
2122 }
2123
2124 for (buffer_type::const_iterator row = buffer.begin(); row != buffer.end(); ++row) {
2125
2126 Y[row->first] += row->second;
2127
2128 V[row->first][row->first] += row->second * row->second;
2129
2130 for (buffer_type::const_iterator col = buffer.begin(); col != row; ++col) {
2131 V[row->first][col->first] += row->second * col->second;
2132 V[col->first][row->first] = V[row->first][col->first];
2133 }
2134 }
2135 }
2136 }
2137 }
2138
2139#undef PUSH_BACK
2140
2141 if (TEST) {
2142
2143 STATUS("Test finished with " << number_of_errors << " errors." << endl);
2144
2145 exit(number_of_errors == 0 ? 0 : 1);
2146 }
2147 }
2148
2149
2150 /**
2151 * Set errors.
2152 *
2153 * \param data data
2154 */
2155 void seterr(const data_type& data)
2156 {
2157 using namespace std;
2158
2159 error.reset();
2160
2161 evaluate(data);
2162
2163 try {
2164 V.invert();
2165 }
2166 catch (const exception& error) {}
2167
2168#define SQRT(X) (X >= 0.0 ? sqrt(X) : std::numeric_limits<double>::max())
2169
2170 size_t row = 0;
2171
2172 if (value.model.R .isFree()) { error.model.R = SQRT(V(row,row)); ++row; }
2173 if (value.model.p1.isFree()) { error.model.p1 = SQRT(V(row,row)); ++row; }
2174 if (value.model.p2.isFree()) { error.model.p2 = SQRT(V(row,row)); ++row; }
2175 if (value.model.p3.isFree()) { error.model.p3 = SQRT(V(row,row)); ++row; }
2176 if (value.model.p4.isFree()) { error.model.p4 = SQRT(V(row,row)); ++row; }
2177 if (value.model.cc.isFree()) { error.model.cc = SQRT(V(row,row)); ++row; }
2178 if (value.model.bc.isFree()) { error.model.bc = SQRT(V(row,row)); ++row; }
2179
2180 for (int i = 0; i != NUMBER_OF_RINGS; ++i) {
2181 if (value.transmittance[i].isFree()) { error.transmittance[i] = SQRT(V(row,row)); ++row; }
2182 }
2183
2184 for (int pmt = 0; pmt != NUMBER_OF_PMTS; ++pmt) {
2185 if (value.parameters[pmt].QE .isFree()) { error.parameters[pmt].QE = SQRT(V(row,row)); ++row; }
2186 if (value.parameters[pmt].TTS.isFree()) { error.parameters[pmt].TTS = SQRT(V(row,row)); ++row; }
2187 if (value.parameters[pmt].t0 .isFree()) { error.parameters[pmt].t0 = SQRT(V(row,row)); ++row; }
2188 if (value.parameters[pmt].bg .isFree()) { error.parameters[pmt].bg = SQRT(V(row,row)); ++row; }
2189 }
2190
2191#undef SQRT
2192 }
2193
2194
2195 JMATH::JVectorND Y; // gradient
2198 std::vector<double> h; // normalisation vector
2199 };
2200}
2201
2202#endif
2203
2204
KM3NeT DAQ constants, bit handling, etc.
TPaveText * p1
Exceptions.
#define THROW(JException_t, A)
Marco for throwing exception with std::ostream compatible message.
#define PUSH_BACK(i, v)
#define SQRT(X)
#define MAKE_TEST(i, v)
Maximum likelihood estimator (M-estimators).
I/O manipulators.
Binary methods for member methods.
Base class for data structures with artithmetic capabilities.
General purpose messaging.
#define DEBUG(A)
Message macros.
Definition JMessage.hh:62
#define STATUS(A)
Definition JMessage.hh:63
#define ERROR(A)
Definition JMessage.hh:66
Data structure for optical module.
Auxiliary class to define a range between two values.
std::shared_ptr< JMEstimator > estimator_type
Definition JFitK40.hh:1642
std::vector< double > h
Definition JFitK40.hh:2198
static constexpr double LAMBDA_MIN
minimal value control parameter
Definition JFitK40.hh:1855
static constexpr double LAMBDA_DOWN
multiplication factor control parameter
Definition JFitK40.hh:1858
result_type operator()(const data_type &data)
Fit.
Definition JFitK40.hh:1666
void seterr(const data_type &data)
Set errors.
Definition JFitK40.hh:2155
static constexpr double LAMBDA_MAX
maximal value control parameter
Definition JFitK40.hh:1856
static constexpr double LAMBDA_UP
multiplication factor control parameter
Definition JFitK40.hh:1857
JMATH::JMatrixNS V
Definition JFitK40.hh:1868
static constexpr double EPSILON
maximal distance to minimum.
Definition JFitK40.hh:1854
JFit(const int option, const int debug)
Constructor.
Definition JFitK40.hh:1651
void evaluate(const data_type &data)
Evaluation of fit.
Definition JFitK40.hh:1878
static constexpr int MAXIMUM_ITERATIONS
maximal number of iterations.
Definition JFitK40.hh:1853
static constexpr double PIVOT
minimal value diagonal element of matrix
Definition JFitK40.hh:1859
estimator_type estimator
M-Estimator function.
Definition JFitK40.hh:1862
JMATH::JVectorND Y
Definition JFitK40.hh:2195
Auxiliary class for fit parameter with optional limits.
Definition JFitK40.hh:118
JParameter_t & mul(const double factor)
Scale parameter.
Definition JFitK40.hh:205
void set(const double value)
Set value.
Definition JFitK40.hh:312
void fix()
Fix current value.
Definition JFitK40.hh:287
JParameter_t & sub(const JParameter_t &parameter)
Subtract parameter.
Definition JFitK40.hh:191
JParameter_t & operator=(double value)
Assignment operator.
Definition JFitK40.hh:423
bool isFree() const
Check if parameter is free.
Definition JFitK40.hh:247
friend std::ostream & operator<<(std::ostream &out, const JParameter_t &object)
Write parameter to output stream.
Definition JFitK40.hh:451
friend std::istream & operator>>(std::istream &in, JParameter_t &object)
Read parameter from input stream.
Definition JFitK40.hh:438
JParameter_t & div(const double factor)
Scale parameter.
Definition JFitK40.hh:219
void relax()
Relax limits.
Definition JFitK40.hh:342
JParameter_t & mul(const JParameter_t &first, const JParameter_t &second)
Scale parameter.
Definition JFitK40.hh:234
double operator()() const
Type conversion operator.
Definition JFitK40.hh:400
void set()
Set current value.
Definition JFitK40.hh:278
JParameter_t(const double value, const range_type &range=range_type::DEFAULT_RANGE())
Constructor.
Definition JFitK40.hh:150
JParameter_t & negate()
Negate parameter.
Definition JFitK40.hh:163
JParameter_t()
Default constructor.
Definition JFitK40.hh:138
bool atLimit(const double precision) const
Check if parameter is at limit.
Definition JFitK40.hh:358
JTOOLS::JRange< double > range_type
Type definition for range of parameter values.
Definition JFitK40.hh:132
double getDerivative() const
Get derivative of value.
Definition JFitK40.hh:386
void setLimits(const double xmin, const double xmax)
Set limits.
Definition JFitK40.hh:329
JParameter_t & add(const JParameter_t &parameter)
Add parameter.
Definition JFitK40.hh:177
void fix(const double value)
Fix value.
Definition JFitK40.hh:373
double get() const
Get value.
Definition JFitK40.hh:298
bool isBound() const
Check if parameter is bound.
Definition JFitK40.hh:269
bool isFixed() const
Check if parameter is fixed.
Definition JFitK40.hh:258
Interface to read input and write output for TObject tests.
Definition JTest_t.hh:42
Data structure for a composite optical module.
Definition JModule.hh:76
Exception for accessing a value in a collection that is outside of its range.
int getIndex(const int first, const int second) const
Get index of pair of indices.
Range of values.
Definition JRange.hh:42
bool is_valid() const
Check validity of range.
Definition JRange.hh:311
T getLength() const
Get length (difference between upper and lower limit).
Definition JRange.hh:289
T constrain(argument_type x) const
Constrain value to range.
Definition JRange.hh:350
static JRange< double, std::less< double > > DEFAULT_RANGE()
Definition JRange.hh:555
T getLowerLimit() const
Get lower limit.
Definition JRange.hh:202
T getUpperLimit() const
Get upper limit.
Definition JRange.hh:213
#define R1(x)
Auxiliary classes and methods for PMT calibration.
static double TEROSTAT_R1
scaling factor
Definition JFitK40.hh:66
const JWater getWater
Function object for fraction of water to total.
Definition JFitK40.hh:895
static const int INVALID_INDEX
invalid index
Definition JFitK40.hh:61
JOption_t
Fit options.
Definition JFitK40.hh:53
@ FIT_PMTS_QE_FIXED_t
fit parameters of PMTs with QE fixed
Definition JFitK40.hh:57
@ FIT_PMTS_AND_ANGULAR_DEPENDENCE_t
fit parameters of PMTs and angular dependence of K40 rate
Definition JFitK40.hh:55
@ FIT_MODEL_t
fit parameters of K40 rate and TTSs of PMTs
Definition JFitK40.hh:58
@ FIT_PMTS_AND_BACKGROUND_t
fit parameters of PMTs and background
Definition JFitK40.hh:56
@ FIT_PMTS_t
fit parameters of PMTs
Definition JFitK40.hh:54
static const int NUMBER_OF_RINGS
number of rings in optical module.
Definition JFitK40.hh:63
static double TEROSTAT_DZ
maximal PMT inclination
Definition JFitK40.hh:65
std::pair< int, int > ring_pair
Type definition of indices of pair of rings.
Definition JFitK40.hh:979
ring_type getRing(const double dz)
Get ring.
Definition JFitK40.hh:988
static double BELL_SHAPE
Bell shape.
Definition JFitK40.hh:67
double getDot(const JFirst_t &first, const JSecond_t &second)
Get dot product of objects.
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
Auxiliary data structure for sequence of same character.
Definition JManip.hh:330
Auxiliary data structure for floating point format specification.
Definition JManip.hh:448
PMT combinatorics for optical module.
Fit parameters for two-fold coincidence rate due to K40.
Definition JFitK40.hh:613
JParameter_t bc
constant background
Definition JFitK40.hh:717
JParameter_t R
maximal coincidence rate [Hz]
Definition JFitK40.hh:711
JParameter_t p1
1st order angle dependence coincidence rate
Definition JFitK40.hh:712
JParameter_t p2
2nd order angle dependence coincidence rate
Definition JFitK40.hh:713
friend std::ostream & operator<<(std::ostream &out, const JK40Parameters_t &object)
Write model parameters to output stream.
Definition JFitK40.hh:695
JParameter_t p3
3rd order angle dependence coincidence rate
Definition JFitK40.hh:714
const JK40Parameters_t & getK40Parameters() const
Get K40 parameters.
Definition JFitK40.hh:628
JParameter_t p4
4th order angle dependence coincidence rate
Definition JFitK40.hh:715
JParameter_t cc
fraction of signal correlated background
Definition JFitK40.hh:716
JK40Parameters_t()
Default constructor.
Definition JFitK40.hh:617
void setK40Parameters(const JK40Parameters_t &parameters)
Set K40 parameters.
Definition JFitK40.hh:639
void print(std::ostream &out) const
Print model parameters to output stream conform include files.
Definition JFitK40.hh:665
Fit parameters for two-fold coincidence rate due to K40.
Definition JFitK40.hh:726
size_t getN() const
Get number of fit parameters.
Definition JFitK40.hh:762
const JK40Parameters_t & getGradient(const double ct) const
Get gradient.
Definition JFitK40.hh:818
JK40Parameters_t gradient
Definition JFitK40.hh:837
static const JK40Parameters & getInstance()
Get default values.
Definition JFitK40.hh:742
int getIndex(JParameter_t JK40Parameters::*p) const
Get index of parameter.
Definition JFitK40.hh:780
double getValue(const double ct) const
Get K40 coincidence rate as a function of cosine angle between PMT axes.
Definition JFitK40.hh:806
JK40Parameters()
Default constructor.
Definition JFitK40.hh:730
Auxiliary data structure for derived quantities of a given PMT pair.
Definition JFitK40.hh:1220
double signal
combined signal
Definition JFitK40.hh:1225
double sigma
total width [ns]
Definition JFitK40.hh:1224
double cc
correlated background
Definition JFitK40.hh:1227
double background
combined background
Definition JFitK40.hh:1226
double t0
time offset [ns]
Definition JFitK40.hh:1223
ring_pair pair
PMT ring pair.
Definition JFitK40.hh:1221
double bc
uncorrelated background
Definition JFitK40.hh:1228
double ct
cosine angle between PMT axes
Definition JFitK40.hh:1222
JTransmittance transmittance
Definition JFitK40.hh:1164
void reset()
Reset.
Definition JFitK40.hh:1171
friend std::ostream & operator<<(std::ostream &out, const JModel_t &object)
Write model parameters to output stream.
Definition JFitK40.hh:1189
JK40Parameters model
Definition JFitK40.hh:1163
JPMTParameters_t parameters[NUMBER_OF_PMTS]
Definition JFitK40.hh:1165
JModel()
Default constructor.
Definition JFitK40.hh:1235
friend std::ostream & operator<<(std::ostream &out, const JModel &object)
Write model parameters to output stream.
Definition JFitK40.hh:1607
size_t getN() const
Get number of fit parameters.
Definition JFitK40.hh:1486
double getValue(const double ct) const
Get K40 coincidence rate as a function of cosine angle between PMT axes.
Definition JFitK40.hh:1571
double sigmaK40_ns
intrinsic K40 arrival time spread [ns]
Definition JFitK40.hh:1622
JOption_t getOption() const
Get fit option.
Definition JFitK40.hh:1306
double getFixedTimeOffset() const
Get time offset.
Definition JFitK40.hh:1430
void setSigmaK40(const double sigma)
Set intrinsic K40 arrival time spread.
Definition JFitK40.hh:1517
int getIndex() const
Get index of PMT used for fixed time offset.
Definition JFitK40.hh:1451
double getSigmaK40() const
Get intrinsic K40 arrival time spread.
Definition JFitK40.hh:1506
void setOption(const int option)
Set fit option.
Definition JFitK40.hh:1317
const real_type & getReal(const pair_type &pair) const
Get derived quantities.
Definition JFitK40.hh:1529
JModel(const JModule &module, const JK40Parameters &parameters)
Constructor.
Definition JFitK40.hh:1287
double getValue(const pair_type &pair, const double dt_ns) const
Get K40 coincidence rate.
Definition JFitK40.hh:1584
void setIndex()
Set index of PMT used for fixed time offset.
Definition JFitK40.hh:1460
JOption_t option
fit option (see JCALIBRATE::JOption_t)
Definition JFitK40.hh:1623
JModel(const JModule &module, const JK40Parameters &parameters, const JTDC_t::range_type &TDC, const int option)
Constructor.
Definition JFitK40.hh:1247
bool hasFixedTimeOffset() const
Check if time offset is fixed.
Definition JFitK40.hh:1419
int index
index of PMT used for fixed time offset
Definition JFitK40.hh:1621
Fit parameters for single PMT.
Definition JFitK40.hh:475
static constexpr double QE_MIN
minimal QE
Definition JFitK40.hh:477
friend std::ostream & operator<<(std::ostream &out, const JPMTParameters_t &object)
Write PMT parameters to output stream.
Definition JFitK40.hh:589
JParameter_t t0
time offset [ns]
Definition JFitK40.hh:605
static constexpr double TTS_NS
start value transition-time spread [ns]
Definition JFitK40.hh:479
JParameter_t TTS
transition-time spread [ns]
Definition JFitK40.hh:604
void disable()
Disable PMT.
Definition JFitK40.hh:557
size_t getN() const
Get number of fit parameters.
Definition JFitK40.hh:545
JPMTParameters_t()
Default constructor.
Definition JFitK40.hh:484
void set(const JPMTParameters_t &parameters)
Set parameters that are free to given values.
Definition JFitK40.hh:531
JParameter_t bg
background [Hz/ns]
Definition JFitK40.hh:606
static constexpr double QE_MAX
maximal QE
Definition JFitK40.hh:478
void enable()
Enable PMT.
Definition JFitK40.hh:571
static const JPMTParameters_t & getInstance()
Get default values.
Definition JFitK40.hh:495
JParameter_t QE
relative quantum efficiency [unit]
Definition JFitK40.hh:603
Auxiliary data structure to handle transmittance of glass sphere due to sedimentation.
Definition JFitK40.hh:1016
void set(const JTransmittance_t &parameters)
Set parameters that are free to given values.
Definition JFitK40.hh:1042
JTransmittance_t()
Default constructor.
Definition JFitK40.hh:1020
Auxiliary data structure to handle transmittance of glass sphere due to sedimentation.
Definition JFitK40.hh:1056
JTransmittance()
Default constructor.
Definition JFitK40.hh:1060
JTransmittance_t gradient
Definition JFitK40.hh:1154
size_t getN() const
Get number of fit parameters.
Definition JFitK40.hh:1086
double getValue(const double ct, const ring_pair pair) const
Get weighed contribution of water and glass.
Definition JFitK40.hh:1107
friend std::ostream & operator<<(std::ostream &out, const JTransmittance &object)
Write transmittances to output stream.
Definition JFitK40.hh:1142
const JTransmittance_t & getGradient(const double ct, const ring_pair pair) const
Get gradient.
Definition JFitK40.hh:1122
static const JTransmittance & getInstance()
Get default values.
Definition JFitK40.hh:1069
Auxiliary data structure for fraction of water to total.
Definition JFitK40.hh:846
double operator()(const double ct) const
Get fraction of water as a function of cosine angle between PMT axes.
Definition JFitK40.hh:885
JWater()
Default constructor.
Definition JFitK40.hh:850
Data structure for measured coincidence rates of all pairs of PMTs in optical module.
Definition JFitK40.hh:110
Data structure for measured coincidence rate of pair of PMTs.
Definition JFitK40.hh:73
rate_type(double dt_ns, double value, double error)
Constructor.
Definition JFitK40.hh:91
double error
error of rate [Hz/ns]
Definition JFitK40.hh:101
double value
value of rate [Hz/ns]
Definition JFitK40.hh:100
rate_type()
Default constructor.
Definition JFitK40.hh:77
double dt_ns
time difference [ns]
Definition JFitK40.hh:99
Auxiliary data structure to define ring.
Definition JFitK40.hh:902
int getIndex() const
Get index.
Definition JFitK40.hh:918
friend std::ostream & operator<<(std::ostream &out, const ring_type &ring)
Write ring to output stream.
Definition JFitK40.hh:967
friend std::istream & operator>>(std::istream &in, ring_type &ring)
Read ring from input stream.
Definition JFitK40.hh:954
ring_type(const char c)
Constructor.
Definition JFitK40.hh:908
static ring_type getRing(const int index)
Get ring.
Definition JFitK40.hh:941
Interface for maximum likelihood estimator (M-estimator).
status_type status
Definition JStatus.hh:252
Bell function object.
Definition JBell.hh:32
const JBell_t & getGradient(const double x) const
Get gradient.
Definition JBell.hh:125
double getValue(const double x) const
Function value.
Definition JBell.hh:85
Gauss model.
Definition JGauss.hh:32
double background
Definition JGauss.hh:164
double signal
Definition JGauss.hh:163
Auxiliary base class for aritmetic operations of derived class types.
Definition JMath.hh:347
void resize(const size_t size)
Resize matrix.
Definition JMatrixND.hh:446
JMatrixND & reset()
Set matrix to the null matrix.
Definition JMatrixND.hh:459
N x N symmetric matrix.
Definition JMatrixNS.hh:30
void solve(JVectorND_t &u)
Get solution of equation A x = b.
Definition JMatrixNS.hh:308
void invert()
Invert matrix according LDU decomposition.
Definition JMatrixNS.hh:75
Nx1 matrix.
Definition JVectorND.hh:23
void reset()
Reset.
Definition JVectorND.hh:45
Data structure for a pair of indices.