Jpp 21.0.0-rc.1
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 <map>
6#include <memory>
7#include <limits>
8#include <cmath>
9
11
12#include "JLang/JException.hh"
13#include "JLang/JManip.hh"
14
15#include "Jeep/JMessage.hh"
16
17#include "JTools/JRange.hh"
18
19#include "JDetector/JModule.hh"
20
21#include "JMath/JVectorND.hh"
22#include "JMath/JMatrixNS.hh"
23#include "JMath/JMath.hh"
24#include "JMath/JBell.hh"
25#include "JMath/JMathToolkit.hh"
26
27#include "JFit/JMEstimator.hh"
28
30#include "JCalibrate/JTDC_t.hh"
31
32
33/**
34 * \author mdejong
35 */
36
37namespace JCALIBRATE {}
38namespace JPP { using namespace JCALIBRATE; }
39
40namespace JCALIBRATE {
41
42 using KM3NETDAQ::NUMBER_OF_PMTS;
45 using JMATH::JMath;
47
48
49 /**
50 * Fit options.
51 */
52 enum JOption_t {
53 FIT_PMTS_t = 1, //!< fit parameters of PMTs
54 FIT_PMTS_AND_ANGULAR_DEPENDENCE_t = 2, //!< fit parameters of PMTs and angular dependence of K40 rate
55 FIT_PMTS_AND_BACKGROUND_t = 3, //!< fit parameters of PMTs and background
56 FIT_PMTS_QE_FIXED_t = 4, //!< fit parameters of PMTs with QE fixed
57 FIT_MODEL_t = 5 //!< fit parameters of K40 rate and TTSs of PMTs
58 };
59
60 static const int INVALID_INDEX = -1; //!< invalid index
61
62 static double TEROSTAT_DZ = 0.40; //!< maximal PMT inclination
63 static double TEROSTAT_R1 = 1.00; //!< scaling factor
64 static double BELL_SHAPE = 1.55; //!< Bell shape
65
66
67 /**
68 * Data structure for measured coincidence rate of pair of PMTs.
69 */
70 struct rate_type {
71 /**
72 * Default constructor.
73 */
75 dt_ns(0.0),
76 value(0.0),
77 error(0.0)
78 {}
79
80
81 /**
82 * Constructor.
83 *
84 * \param dt_ns time difference [ns]
85 * \param value value of rate [Hz/ns]
86 * \param error error of rate [Hz/ns]
87 */
89 double value,
90 double error) :
91 dt_ns(dt_ns),
92 value(value),
94 {}
95
96 double dt_ns; //!< time difference [ns]
97 double value; //!< value of rate [Hz/ns]
98 double error; //!< error of rate [Hz/ns]
99 };
100
101
102 /**
103 * Data structure for measured coincidence rates of all pairs of PMTs in optical module.
104 */
105 struct data_type :
106 public std::map<pair_type, std::vector<rate_type> >
107 {};
108
109
110 /**
111 * Auxiliary class for fit parameter with optional limits.
112 */
114 public JMath<JParameter_t>
115 {
116 public:
117 /**
118 * Fit options.
119 */
120 enum FIT_t {
121 FREE_t = 0, //!< free
122 FIXED_t //!< fixed
123 };
124
125
126 /**
127 * Type definition for range of parameter values.
128 */
130
131
132 /**
133 * Default constructor.
134 */
136 {
137 set(0.0);
138 }
139
140
141 /**
142 * Constructor.
143 *
144 * \param value value
145 * \param range range
146 */
147 JParameter_t(const double value,
149 range(range)
150 {
151 set(value);
152 }
153
154
155 /**
156 * Negate parameter.
157 *
158 * \return this parameter
159 */
161 {
162 set(-get());
163
164 return *this;
165 }
166
167
168 /**
169 * Add parameter.
170 *
171 * \param parameter parameter
172 * \return this parameter
173 */
174 JParameter_t& add(const JParameter_t& parameter)
175 {
176 set(get() + parameter.get());
177
178 return *this;
179 }
180
181
182 /**
183 * Subtract parameter.
184 *
185 * \param parameter parameter
186 * \return this parameter
187 */
188 JParameter_t& sub(const JParameter_t& parameter)
189 {
190 set(get() - parameter.get());
191
192 return *this;
193 }
194
195
196 /**
197 * Scale parameter.
198 *
199 * \param factor multiplication factor
200 * \return this parameter
201 */
202 JParameter_t& mul(const double factor)
203 {
204 set(get() * factor);
205
206 return *this;
207 }
208
209
210 /**
211 * Scale parameter.
212 *
213 * \param factor division factor
214 * \return this parameter
215 */
216 JParameter_t& div(const double factor)
217 {
218 set(get() / factor);
219
220 return *this;
221 }
222
223
224 /**
225 * Scale parameter.
226 *
227 * \param first first parameter
228 * \param second second parameter
229 * \return this parameter
230 */
231 JParameter_t& mul(const JParameter_t& first, const JParameter_t& second)
232 {
233 set(first.get() * second.get());
234
235 return *this;
236 }
237
238
239 /**
240 * Check if parameter is free.
241 *
242 * \return true if free; else false
243 */
244 bool isFree() const
245 {
246 return option == FREE_t;
247 }
248
249
250 /**
251 * Check if parameter is fixed.
252 *
253 * \return true if fixed; else false
254 */
255 bool isFixed() const
256 {
257 return option == FIXED_t;
258 }
259
260
261 /**
262 * Check if parameter is bound.
263 *
264 * \return true if bound; else false
265 */
266 bool isBound() const
267 {
268 return range.is_valid();
269 }
270
271
272 /**
273 * Set current value.
274 */
275 void set()
276 {
277 option = FREE_t;
278 }
279
280
281 /**
282 * Fix current value.
283 */
284 void fix()
285 {
286 option = FIXED_t;
287 }
288
289
290 /**
291 * Get value.
292 *
293 * \return value
294 */
295 double get() const
296 {
297 if (isBound())
298 return range.getLowerLimit() + 0.5 * range.getLength() * (sin(value) + 1.0);
299 else
300 return value;
301 }
302
303
304 /**
305 * Set value.
306 *
307 * \param value value
308 */
309 void set(const double value)
310 {
311 if (isBound())
312 this->value = asin(2.0 * (range.constrain(value) - range.getLowerLimit()) / range.getLength() - 1.0);
313 else
314 this->value = value;
315
316 set();
317 }
318
319
320 /**
321 * Set limits.
322 *
323 * \param xmin minimal value
324 * \param xmax maximal value
325 */
326 void setLimits(const double xmin, const double xmax)
327 {
328 const double x = get();
329
330 range = range_type(xmin, xmax);
331
332 set(x);
333 }
334
335
336 /**
337 * Relax limits.
338 */
339 void relax()
340 {
341 const double x = get();
342
344
345 set(x);
346 }
347
348
349 /**
350 * Check if parameter is at limit.
351 *
352 * \param precision precision
353 * \return true if at limit; else false
354 */
355 bool atLimit(const double precision) const
356 {
357 if (isBound())
358 return (get() - range.getLowerLimit() <= precision ||
359 range.getUpperLimit() - get() <= precision);
360 else
361 return false;
362 }
363
364
365 /**
366 * Fix value.
367 *
368 * \param value value
369 */
370 void fix(const double value)
371 {
372 set(value);
373
374 fix();
375 }
376
377
378 /**
379 * Get derivative of value.
380 *
381 * \return derivative of value
382 */
383 double getDerivative() const
384 {
385 if (isBound())
386 return 1.0 / (0.5 * range.getLength() * cos(value));
387 else
388 return 1.0;
389 }
390
391
392 /**
393 * Type conversion operator.
394 *
395 * \return value
396 */
397 double operator()() const
398 {
399 return get();
400 }
401
402
403 /**
404 * Type conversion operator.
405 *
406 * \return value
407 */
408 operator double() const
409 {
410 return get();
411 }
412
413
414 /**
415 * Assignment operator.
416 *
417 * \param value value
418 * \return this parameter
419 */
421 {
422 set(value);
423
424 return *this;
425 }
426
427
428 /**
429 * Read parameter from input stream.
430 *
431 * \param in input stream
432 * \param object parameter
433 * \return input stream
434 */
435 friend inline std::istream& operator>>(std::istream& in, JParameter_t& object)
436 {
437 return in >> object.value;
438 }
439
440
441 /**
442 * Write parameter to output stream.
443 *
444 * \param out output stream
445 * \param object parameter
446 * \return output stream
447 */
448 friend inline std::ostream& operator<<(std::ostream& out, const JParameter_t& object)
449 {
450 using namespace std;
451
452 out << FIXED(12,6) << object.get() << ' '
453 << setw(5) << (object.isFixed() ? "fixed" : " ") << ' ';
454
455 if (object.isBound()) {
456 out << "[" << FIXED(12,6) << object.range.getLowerLimit() << "," << FIXED(12,6) << object.range.getUpperLimit() << "]";
457 }
458
459 return out;
460 }
461
462
463 double value = 0.0;
466 };
467
468
469 /**
470 * Fit parameters for single PMT.
471 */
473
474 static constexpr double QE_MIN = 0.0; //!< minimal QE
475 static constexpr double QE_MAX = 2.0; //!< maximal QE
476 static constexpr double TTS_NS = 2.0; //!< start value transition-time spread [ns]
477
478 /**
479 * Default constructor.
480 */
482 {
483 reset();
484 }
485
486
487 /**
488 * Get default values.
489 *
490 * \return parameters
491 */
493 {
494 static JPMTParameters_t parameters;
495
497
498 parameters.status = true;
499
500 parameters.QE .set(1.0);
501 parameters.TTS.set(TTS_NS);
502 parameters.t0 .set(0.0);
503 parameters.bg .set(0.0);
504
505 return parameters;
506 }
507
508
509 /**
510 * Reset.
511 */
512 void reset()
513 {
514 status = true;
515
516 QE .set(0.0);
517 TTS.set(0.0);
518 t0 .set(0.0);
519 bg .set(0.0);
520 }
521
522
523 /**
524 * Set parameters that are free to given values.
525 *
526 * \param parameters parameters
527 */
528 void set(const JPMTParameters_t& parameters)
529 {
530 if (QE .isFree()) { QE .set(parameters.QE); }
531 if (TTS.isFree()) { TTS.set(parameters.TTS); }
532 if (t0 .isFree()) { t0 .set(parameters.t0); }
533 if (bg .isFree()) { bg .set(parameters.bg); }
534 }
535
536
537 /**
538 * Get number of fit parameters.
539 *
540 * \return number of parameters
541 */
542 inline size_t getN() const
543 {
544 return ((QE. isFree() ? 1 : 0) +
545 (TTS.isFree() ? 1 : 0) +
546 (t0 .isFree() ? 1 : 0) +
547 (bg .isFree() ? 1 : 0));
548 }
549
550
551 /**
552 * Disable PMT.
553 */
554 void disable()
555 {
556 status = false;
557
558 QE .fix(0.0);
559 TTS.fix(TTS_NS);
560 t0 .fix(0.0);
561 bg .fix(0.0);
562 }
563
564
565 /**
566 * Enable PMT.
567 */
568 void enable()
569 {
570 status = true;
571
572 QE .set();
573 TTS.set();
574 t0 .set();
575 bg .set();
576 }
577
578
579 /**
580 * Write PMT parameters to output stream.
581 *
582 * \param out output stream
583 * \param object PMT parameters
584 * \return output stream
585 */
586 friend inline std::ostream& operator<<(std::ostream& out, const JPMTParameters_t& object)
587 {
588 using namespace std;
589
590 out << "QE " << FIXED(7,3) << object.QE << endl;
591 out << "TTS " << FIXED(7,3) << object.TTS << endl;
592 out << "t0 " << FIXED(7,3) << object.t0 << endl;
593 out << "bg " << FIXED(7,3) << object.bg << endl;
594
595 return out;
596 }
597
598
599 bool status; //!< status
600 JParameter_t QE; //!< relative quantum efficiency [unit]
601 JParameter_t TTS; //!< transition-time spread [ns]
602 JParameter_t t0; //!< time offset [ns]
603 JParameter_t bg; //!< background [Hz/ns]
604 };
605
606
607 /**
608 * Fit parameters for two-fold coincidence rate due to K40.
609 */
611 /**
612 * Default constructor.
613 */
615 {
616 reset();
617 }
618
619
620 /**
621 * Get K40 parameters.
622 *
623 * \return K40 parameters
624 */
626 {
627 return static_cast<const JK40Parameters_t&>(*this);
628 }
629
630
631 /**
632 * Set K40 parameters.
633 *
634 * \param parameters K40 parameters
635 */
636 void setK40Parameters(const JK40Parameters_t& parameters)
637 {
638 static_cast<JK40Parameters_t&>(*this) = parameters;
639 }
640
641
642 /**
643 * Reset.
644 */
645 void reset()
646 {
647 R .set(0.0);
648 p1.set(0.0);
649 p2.set(0.0);
650 p3.set(0.0);
651 p4.set(0.0);
652 cc.set(0.0);
653 bc.set(0.0);
654 }
655
656
657 /**
658 * Print model parameters to output stream conform include files.
659 *
660 * \param out output stream
661 */
662 void print(std::ostream& out) const
663 {
664 using namespace std;
665
666 out << "JFitK40.hh" << endl;
667 out << "parameters.R .set(" << FIXED(9,6) << this->R () << ");" << endl;
668 out << "parameters.p1.set(" << FIXED(9,6) << this->p1() << ");" << endl;
669 out << "parameters.p2.set(" << FIXED(9,6) << this->p2() << ");" << endl;
670 out << "parameters.p3.set(" << FIXED(9,6) << this->p3() << ");" << endl;
671 out << "parameters.p4.set(" << FIXED(9,6) << this->p4() << ");" << endl;
672 out << "cc " << FIXED(9,6) << this->cc() << endl;
673 out << "bc " << FIXED(9,6) << this->bc() << endl;
674 out << endl;
675
676 out << "JK40DefaultSimulator.hh" << endl;
677 out << "static constexpr double p1 = " << FIXED(9,6) << this->p1() << ";" << endl;
678 out << "static constexpr double p2 = " << FIXED(9,6) << this->p2() << ";" << endl;
679 out << "static constexpr double p3 = " << FIXED(9,6) << this->p3() << ";" << endl;
680 out << "static constexpr double p4 = " << FIXED(9,6) << this->p4() << ";" << endl;
681 out << endl;
682 }
683
684
685 /**
686 * Write model parameters to output stream.
687 *
688 * \param out output stream
689 * \param object model parameters
690 * \return output stream
691 */
692 friend inline std::ostream& operator<<(std::ostream& out, const JK40Parameters_t& object)
693 {
694 using namespace std;
695
696 out << "Rate [Hz] " << FIXED(12,6) << object.R << endl;
697 out << "p1 " << FIXED(12,6) << object.p1 << endl;
698 out << "p2 " << FIXED(12,6) << object.p2 << endl;
699 out << "p3 " << FIXED(12,6) << object.p3 << endl;
700 out << "p4 " << FIXED(12,6) << object.p4 << endl;
701 out << "cc " << FIXED(12,6) << object.cc << endl;
702 out << "bc " << FIXED(12,6) << object.bc << endl;
703 out << endl;
704
705 return out;
706 }
707
708 JParameter_t R; //!< maximal coincidence rate [Hz]
709 JParameter_t p1; //!< 1st order angle dependence coincidence rate
710 JParameter_t p2; //!< 2nd order angle dependence coincidence rate
711 JParameter_t p3; //!< 3rd order angle dependence coincidence rate
712 JParameter_t p4; //!< 4th order angle dependence coincidence rate
713 JParameter_t cc; //!< fraction of signal correlated background
714 JParameter_t bc; //!< constant background
715 };
716
717
718 /**
719 * Fit parameters for two-fold coincidence rate due to K40.
720 */
723 {
724 /**
725 * Default constructor.
726 */
729
730
731 /**
732 * Get default values.
733 *
734 * Values obtained with $JPP_DIR/examples/JCalibrate/JOMGsim.sh type B (see $JPP_DIR/examples/JCalibrate/README.md).
735 * If you change these values, you may also want to change the corresponding values in JK40DefaultSimulator.hh.
736 *
737 * \return parameters
738 */
740 {
741 static JK40Parameters parameters;
742
743 parameters.R .set(18.473257);
744 parameters.p1.set( 3.030307);
745 parameters.p2.set(-0.965429);
746 parameters.p3.set( 1.290367);
747 parameters.p4.set( 0.405618);
748 parameters.cc.set( 0.0);
749 parameters.bc.set( 0.0);
750
751 return parameters;
752 }
753
754
755 /**
756 * Get number of fit parameters.
757 *
758 * \return number of parameters
759 */
760 inline size_t getN() const
761 {
762 return ((R .isFree() ? 1 : 0) +
763 (p1.isFree() ? 1 : 0) +
764 (p2.isFree() ? 1 : 0) +
765 (p3.isFree() ? 1 : 0) +
766 (p4.isFree() ? 1 : 0) +
767 (cc.isFree() ? 1 : 0) +
768 (bc.isFree() ? 1 : 0));
769 }
770
771
772 /**
773 * Get index of parameter.
774 *
775 * \param p pointer to data member
776 * \return index
777 */
779 {
780 if (!(this->*p).isFree()) {
781 return INVALID_INDEX;
782 }
783
784 int N = 0;
785
786 if (p == &JK40Parameters::R) { return N; } if (R .isFree()) { ++N; }
787 if (p == &JK40Parameters::p1) { return N; } if (p1.isFree()) { ++N; }
788 if (p == &JK40Parameters::p2) { return N; } if (p2.isFree()) { ++N; }
789 if (p == &JK40Parameters::p3) { return N; } if (p3.isFree()) { ++N; }
790 if (p == &JK40Parameters::p4) { return N; } if (p4.isFree()) { ++N; }
791 if (p == &JK40Parameters::cc) { return N; } if (cc.isFree()) { ++N; }
792 if (p == &JK40Parameters::bc) { return N; } if (bc.isFree()) { ++N; }
793
794 return INVALID_INDEX;
795 }
796
797
798 /**
799 * Get K40 coincidence rate as a function of cosine angle between PMT axes.
800 *
801 * \param ct cosine angle between PMT axes
802 * \return rate [Hz]
803 */
804 double getValue(const double ct) const
805 {
806 return R * exp(ct*(p1+ct*(p2+ct*(p3+ct*p4))) - (p1+p2+p3+p4));
807 }
808
809
810 /**
811 * Get gradient.
812 *
813 * \param ct cosine angle between PMT axes
814 * \return gradient
815 */
816 const JK40Parameters_t& getGradient(const double ct) const
817 {
818 gradient.reset();
819
820 const double rate = getValue(ct);
821 const double ct2 = ct * ct;
822
823 if (R .isFree()) { gradient.R = rate / R; }
824 if (p1.isFree()) { gradient.p1 = rate * ct - rate; }
825 if (p2.isFree()) { gradient.p2 = rate * ct2 - rate; }
826 if (p3.isFree()) { gradient.p3 = rate * ct2 * ct - rate; }
827 if (p4.isFree()) { gradient.p4 = rate * ct2 * ct2 - rate; }
828 if (cc.isFree()) { gradient.cc = rate; }
829 if (bc.isFree()) { gradient.bc = 1.0; }
830
831 return gradient;
832 }
833
834 private:
836 };
837
838
839 /**
840 * Fit model.
841 */
842 struct JModel_t :
843 public JK40Parameters
844 {
846
847
848 /**
849 * Write model parameters to output stream.
850 *
851 * \param out output stream
852 * \param object model parameters
853 * \return output stream
854 */
855 friend inline std::ostream& operator<<(std::ostream& out, const JModel_t& object)
856 {
857 using namespace std;
858
859 out << static_cast<const JK40Parameters&>(object);
860
861 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
862 out << "PMT[" << FILL(2,'0') << i << FILL() << "]." << object.parameters[i].status << endl << object.parameters[i];
863 }
864
865 return out;
866 }
867 };
868
869
870 /**
871 * Fit model.
872 *
873 * In the absence of TDC constraints, the average time offset is fixed to zero.
874 */
875 struct JModel :
876 public JModel_t,
877 public JModule,
878 public JCombinatorics_t
879 {
883
884 /**
885 * Auxiliary data structure for derived quantities of a given PMT pair.
886 */
887 struct real_type {
888 double ct; //!< cosine angle between PMT axes
889 double t0; //!< time offset [ns]
890 double sigma; //!< total width [ns]
891 double signal; //!< combined signal
892 double background; //!< combined background
893 double cc; //!< correlated background
894 double bc; //!< uncorrelated background
895 };
896
897
898 /**
899 * Default constructor.
900 */
902 {}
903
904
905 /**
906 * Constructor.
907 *
908 * \param module detector module
909 * \param parameters K40 parameters
910 * \param TDC TDC constraints
911 * \param option option
912 */
913 JModel(const JModule& module,
915 const JTDC_t::range_type& TDC,
916 const int option) :
917 JModule (module),
918 JCombinatorics_t(module)
919 {
921
922 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
923 this->parameters[i] = JPMTParameters_t::getInstance();
924 }
925
926 for (JTDC_t::const_iterator i = TDC.first; i != TDC.second; ++i) {
927
928 if (i->second != JTDC_t::WILDCARD) {
929
930 this->parameters[i->second].t0.fix();
931
932 } else {
933
934 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
935 this->parameters[i].t0.fix();
936 }
937 }
938 }
939
940 this->index = (TDC.first == TDC.second ? 0 : INVALID_INDEX);
941
943 }
944
945
946 /**
947 * Constructor.
948 *
949 * \param module detector module
950 * \param parameters K40 parameters
951 */
952 JModel(const JModule& module,
953 const JK40Parameters& parameters) :
954 JModule (module),
955 JCombinatorics_t(module)
956 {
958
959 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
960 this->parameters[i] = JPMTParameters_t::getInstance();
961 }
962 }
963
964
965 /**
966 * Get fit option.
967 *
968 * \return option
969 */
971 {
972 return option;
973 }
974
975
976 /**
977 * Set fit option.
978 *
979 * \param option option
980 */
981 inline void setOption(const int option)
982 {
983 switch (option) {
984
985 case FIT_PMTS_t:
986
987 R .fix();
988 p1.fix();
989 p2.fix();
990 p3.fix();
991 p4.fix();
992
993 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
994 parameters[i].bg.fix();
995 }
996
997 break;
998
1000
1001 R .fix();
1002
1003 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1004 parameters[i].bg.fix();
1005 }
1006
1007 break;
1008
1010
1011 R .fix();
1012 p1.fix();
1013 p2.fix();
1014 p3.fix();
1015 p4.fix();
1016
1017 break;
1018
1020
1021 R .fix();
1022 p1.fix();
1023 p2.fix();
1024 p3.fix();
1025 p4.fix();
1026
1027 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1028 parameters[i].QE.fix();
1029 parameters[i].bg.fix();
1030 }
1031
1032 break;
1033
1034 case FIT_MODEL_t:
1035
1037
1038 //cc.fix();
1039 //bc.fix();
1040
1041 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1042 parameters[i].QE.fix();
1043 parameters[i].t0.fix();
1044 parameters[i].bg.fix();
1045 }
1046
1047 break;
1048
1049 default:
1050
1051 THROW(JValueOutOfRange, "Invalid option " << option);
1052 }
1053
1054 this->option = static_cast<JOption_t>(option);
1055 }
1056
1057
1058 /**
1059 * Check if time offset is fixed.
1060 *
1061 * \return true if time offset fixed; else false
1062 */
1064 {
1065 return index != INVALID_INDEX;
1066 }
1067
1068
1069 /**
1070 * Get time offset.
1071 *
1072 * \return time offset
1073 */
1074 double getFixedTimeOffset() const
1075 {
1076 double t0 = 0.0;
1077 size_t N = 0;
1078
1079 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1080 if (parameters[i].t0.isFree()) {
1081 t0 += parameters[i].t0;
1082 N += 1;
1083 }
1084 }
1085
1086 return t0 /= N;
1087 }
1088
1089
1090 /**
1091 * Get index of PMT used for fixed time offset.
1092 *
1093 * \return index
1094 */
1095 int getIndex() const
1096 {
1097 return index;
1098 }
1099
1100
1101 /**
1102 * Set index of PMT used for fixed time offset.
1103 */
1105 {
1106 if (index != INVALID_INDEX) {
1107
1108 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1109
1110 if (parameters[i].status) {
1111
1112 index = i;
1113
1115
1116 return;
1117 }
1118 }
1119
1120 THROW(JValueOutOfRange, "No valid index.");
1121 }
1122 }
1123
1124
1125 /**
1126 * Get number of fit parameters.
1127 *
1128 * \return number of parameters
1129 */
1130 inline size_t getN() const
1131 {
1132 size_t N = JK40Parameters::getN();
1133
1134 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1135 N += parameters[i].getN();
1136 }
1137
1138 return N;
1139 }
1140
1141
1142 /**
1143 * Get intrinsic K40 arrival time spread.
1144 *
1145 * \return sigma [ns]
1146 */
1147 double getSigmaK40() const
1148 {
1149 return this->sigmaK40_ns;
1150 }
1151
1152
1153 /**
1154 * Set intrinsic K40 arrival time spread.
1155 *
1156 * \param sigma sigma [ns]
1157 */
1158 void setSigmaK40(const double sigma)
1159 {
1160 this->sigmaK40_ns = sigma;
1161 }
1162
1163
1164 /**
1165 * Get derived quantities.
1166 *
1167 * \param pair PMT pair
1168 * \return quantities
1169 */
1170 const real_type& getReal(const pair_type& pair) const
1171 {
1172 real.ct = JPP::getDot((*this)[pair.first].getDirection(), (*this)[pair.second].getDirection());
1173
1174 real.t0 = (pair.first == this->index ? -this->parameters[pair.second].t0() :
1175 pair.second == this->index ? +this->parameters[pair.first ].t0() :
1176 this->parameters[pair.first].t0() - this->parameters[pair.second].t0());
1177
1178 real.sigma = sqrt(this->parameters[pair.first ].TTS() * this->parameters[pair.first ].TTS() +
1179 this->parameters[pair.second].TTS() * this->parameters[pair.second].TTS() +
1180 this->getSigmaK40() * this->getSigmaK40());
1181
1182 real.signal = this->parameters[pair.first].QE() * this->parameters[pair.second].QE();
1183
1184 real.background = this->parameters[pair.first].bg() + this->parameters[pair.second].bg();
1185
1186 real.cc = real.signal * this->cc();
1187 real.bc = this->bc();
1188
1189 const double z1 = (*this)[pair.first ].getDirection().getDZ();
1190 const double z2 = (*this)[pair.second].getDirection().getDZ();
1191
1192 if (fabs(z1) <= TEROSTAT_DZ &&
1193 fabs(z2) <= TEROSTAT_DZ &&
1194 signbit(z1) != signbit(z2)) {
1195
1197 }
1198
1199 return real;
1200 }
1201
1202
1203 /**
1204 * Get K40 coincidence rate.
1205 *
1206 * \param pair PMT pair
1207 * \param dt_ns time difference [ns]
1208 * \return rate [Hz/ns]
1209 */
1210 double getValue(const pair_type& pair, const double dt_ns) const
1211 {
1212 using namespace std;
1213 using namespace JPP;
1214
1215 const real_type& real = getReal(pair);
1216
1217 const JBell bell(real.t0, real.sigma, real.signal, 0.0, BELL_SHAPE);
1218
1219 const double R1 = this->getValue(real.ct);
1220 const double R2 = bell.getValue(dt_ns);
1221
1222 return real.bc + real.background + R1 * (real.cc + R2);
1223 }
1224
1225
1226 /**
1227 * Write model parameters to output stream.
1228 *
1229 * \param out output stream
1230 * \param object model parameters
1231 * \return output stream
1232 */
1233 friend inline std::ostream& operator<<(std::ostream& out, const JModel& object)
1234 {
1235 using namespace std;
1236
1237 out << "Module " << setw(10) << object.getID() << endl;
1238 out << "option " << object.option << endl;
1239 out << "index " << object.index << endl;
1240
1241 out << static_cast<const JModel_t&>(object);
1242
1243 return out;
1244 }
1245
1246 private:
1247 int index; //!< index of PMT used for fixed time offset
1248 double sigmaK40_ns = 0.54; //!< intrinsic K40 arrival time spread [ns]
1249 JOption_t option; //!< fit option (see JCALIBRATE::JOption_t)
1251 };
1252
1253
1254 /**
1255 * Fit.
1256 */
1257 class JFit
1258 {
1259 public:
1260 /**
1261 * Result type.
1262 */
1264 double chi2;
1265 int ndf;
1266 };
1267
1268 typedef std::shared_ptr<JMEstimator> estimator_type;
1269
1270
1271 /**
1272 * Constructor
1273 *
1274 * \param option M-estimator
1275 * \param debug debug
1276 */
1277 JFit(const int option, const int debug) :
1278 debug(debug)
1279 {
1280 using namespace JPP;
1281
1282 estimator.reset(getMEstimator(option));
1283 }
1284
1285
1286 /**
1287 * Fit.
1288 *
1289 * \param data data
1290 * \return chi2, NDF
1291 */
1293 {
1294 using namespace std;
1295 using namespace JPP;
1296
1297
1298 value.setIndex();
1299
1300 const size_t N = value.getN();
1301
1302 V.resize(N);
1303 Y.resize(N);
1304 h.resize(N);
1305
1306 double xmax = numeric_limits<double>::lowest();
1307 double xmin = numeric_limits<double>::max();
1308
1309 int ndf = 0;
1310
1311 for (data_type::const_iterator ix = data.begin(); ix != data.end(); ++ix) {
1312
1313 const pair_type& pair = ix->first;
1314
1315 if (value.parameters[pair.first ].status &&
1316 value.parameters[pair.second].status) {
1317
1318 ndf += ix->second.size();
1319
1320 for (const rate_type& iy : ix->second) {
1321 if (iy.dt_ns > xmax) { xmax = iy.dt_ns; }
1322 if (iy.dt_ns < xmin) { xmin = iy.dt_ns; }
1323 }
1324 }
1325 }
1326
1327 ndf -= value.getN();
1328
1329 if (ndf < 0) {
1330 return { 0.0, ndf };
1331 }
1332
1333 for (int pmt = 0; pmt != NUMBER_OF_PMTS; ++pmt) {
1334 if (value.parameters[pmt].t0.isFree()) {
1335 value.parameters[pmt].t0.setLimits(xmin, xmax);
1336 }
1337 }
1338
1340
1341 double precessor = numeric_limits<double>::max();
1342
1344
1345 DEBUG("step: " << numberOfIterations << endl);
1346
1347 evaluate(data);
1348
1349 DEBUG("lambda: " << FIXED(12,5) << lambda << endl);
1350 DEBUG("chi2: " << FIXED(12,3) << successor << endl);
1351
1352 if (successor < precessor) {
1353
1354 if (numberOfIterations != 0) {
1355
1356 if (fabs(precessor - successor) < EPSILON) {
1357
1358 seterr(data);
1359
1360 return { successor / estimator->getRho(1.0), ndf };
1361 }
1362
1363 if (lambda > LAMBDA_MIN) {
1365 }
1366 }
1367
1368 precessor = successor;
1369 previous = value;
1370
1371 } else {
1372
1373 value = previous;
1374 lambda *= LAMBDA_UP;
1375
1376 if (lambda > LAMBDA_MAX) {
1377 break;
1378 }
1379
1380 evaluate(data);
1381 }
1382
1383 if (debug >= debug_t) {
1384
1385 size_t row = 0;
1386
1387 if (value.R .isFree()) { cout << "R " << FIXED(12,5) << Y[row] << endl; ++row; }
1388 if (value.p1.isFree()) { cout << "p1 " << FIXED(12,5) << Y[row] << endl; ++row; }
1389 if (value.p2.isFree()) { cout << "p2 " << FIXED(12,5) << Y[row] << endl; ++row; }
1390 if (value.p3.isFree()) { cout << "p3 " << FIXED(12,5) << Y[row] << endl; ++row; }
1391 if (value.p4.isFree()) { cout << "p4 " << FIXED(12,5) << Y[row] << endl; ++row; }
1392 if (value.cc.isFree()) { cout << "cc " << FIXED(12,3) << Y[row] << endl; ++row; }
1393
1394 for (int pmt = 0; pmt != NUMBER_OF_PMTS; ++pmt) {
1395 if (value.parameters[pmt].QE .isFree()) { cout << "PMT[" << setw(2) << pmt << "].QE " << FIXED(12,5) << Y[row] << endl; ++row; }
1396 if (value.parameters[pmt].TTS.isFree()) { cout << "PMT[" << setw(2) << pmt << "].TTS " << FIXED(12,5) << Y[row] << endl; ++row; }
1397 if (value.parameters[pmt].t0 .isFree()) { cout << "PMT[" << setw(2) << pmt << "].t0 " << FIXED(12,5) << Y[row] << endl; ++row; }
1398 if (value.parameters[pmt].bg .isFree()) { cout << "PMT[" << setw(2) << pmt << "].bg " << FIXED(12,5) << Y[row] << endl; ++row; }
1399 }
1400 }
1401
1402 // force definite positiveness
1403
1404 for (size_t i = 0; i != N; ++i) {
1405
1406 if (V(i,i) < PIVOT) {
1407 V(i,i) = PIVOT;
1408 }
1409
1410 h[i] = 1.0 / sqrt(V(i,i));
1411 }
1412
1413 // normalisation
1414
1415 for (size_t i = 0; i != N; ++i) {
1416 for (size_t j = 0; j != i; ++j) {
1417 V(j,i) *= h[i] * h[j];
1418 V(i,j) = V(j,i);
1419 }
1420 }
1421
1422 for (size_t i = 0; i != N; ++i) {
1423 V(i,i) = 1.0 + lambda;
1424 }
1425
1426 // solve A x = b
1427
1428 for (size_t col = 0; col != N; ++col) {
1429 Y[col] *= h[col];
1430 }
1431
1432 try {
1433 V.solve(Y);
1434 }
1435 catch (const exception& error) {
1436
1437 ERROR("JGandalf: " << error.what() << endl << V << endl);
1438
1439 break;
1440 }
1441
1442 // update value
1443
1444 const double factor = 2.0;
1445
1446 size_t row = 0;
1447
1448 if (value.R .isFree()) { value.R -= factor * h[row] * Y[row]; ++row; }
1449 if (value.p1.isFree()) { value.p1 -= factor * h[row] * Y[row]; ++row; }
1450 if (value.p2.isFree()) { value.p2 -= factor * h[row] * Y[row]; ++row; }
1451 if (value.p3.isFree()) { value.p3 -= factor * h[row] * Y[row]; ++row; }
1452 if (value.p4.isFree()) { value.p4 -= factor * h[row] * Y[row]; ++row; }
1453 if (value.cc.isFree()) { value.cc -= factor * h[row] * Y[row]; ++row; }
1454 if (value.bc.isFree()) { value.bc -= factor * h[row] * Y[row]; ++row; }
1455
1456 for (int pmt = 0; pmt != NUMBER_OF_PMTS; ++pmt) {
1457 if (value.parameters[pmt].QE .isFree()) { value.parameters[pmt].QE -= factor * h[row] * Y[row]; ++row; }
1458 if (value.parameters[pmt].TTS.isFree()) { value.parameters[pmt].TTS -= factor * h[row] * Y[row]; ++row; }
1459 if (value.parameters[pmt].t0 .isFree()) { value.parameters[pmt].t0 -= factor * h[row] * Y[row]; ++row; }
1460 if (value.parameters[pmt].bg .isFree()) { value.parameters[pmt].bg -= factor * h[row] * Y[row]; ++row; }
1461 }
1462 }
1463
1464 seterr(data);
1465
1466 return { precessor / estimator->getRho(1.0), ndf };
1467 }
1468
1469
1470 static constexpr int MAXIMUM_ITERATIONS = 100000; //!< maximal number of iterations.
1471 static constexpr double EPSILON = 1.0e-3; //!< maximal distance to minimum.
1472 static constexpr double LAMBDA_MIN = 1.0e-2; //!< minimal value control parameter
1473 static constexpr double LAMBDA_MAX = 1.0e+4; //!< maximal value control parameter
1474 static constexpr double LAMBDA_UP = 10.0; //!< multiplication factor control parameter
1475 static constexpr double LAMBDA_DOWN = 10.0; //!< multiplication factor control parameter
1476 static constexpr double PIVOT = std::numeric_limits<double>::epsilon(); //!< minimal value diagonal element of matrix
1477
1479 estimator_type estimator; //!< M-Estimator function
1480
1481 double lambda;
1486
1487 bool TEST = false;
1488
1489 private:
1490 /**
1491 * Evaluation of fit.
1492 *
1493 * \param data data
1494 */
1495 void evaluate(const data_type& data)
1496 {
1497 using namespace std;
1498 using namespace JPP;
1499
1500 typedef JModel::real_type real_type;
1501
1502
1503 successor = 0.0;
1504
1505 V.reset();
1506 Y.reset();
1507
1508
1509 // model parameter indices
1510
1511 const struct M_t {
1512 M_t(const JModel& model)
1513 {
1514 R = model.getIndex(&JK40Parameters_t::R);
1515 p1 = model.getIndex(&JK40Parameters_t::p1);
1516 p2 = model.getIndex(&JK40Parameters_t::p2);
1517 p3 = model.getIndex(&JK40Parameters_t::p3);
1518 p4 = model.getIndex(&JK40Parameters_t::p4);
1519 cc = model.getIndex(&JK40Parameters_t::cc);
1520 bc = model.getIndex(&JK40Parameters_t::bc);
1521 }
1522
1523 int R;
1524 int p1;
1525 int p2;
1526 int p3;
1527 int p4;
1528 int cc;
1529 int bc;
1530
1531 } M(value);
1532
1533
1534 // PMT parameter indices
1535
1536 struct i_t {
1537 i_t() :
1538 QE (INVALID_INDEX),
1539 TTS(INVALID_INDEX),
1540 t0 (INVALID_INDEX),
1541 bg (INVALID_INDEX)
1542 {}
1543
1544 int QE;
1545 int TTS;
1546 int t0;
1547 int bg;
1548 };
1549
1550 const struct I_t : public std::array<i_t, NUMBER_OF_PMTS> {
1551 I_t(const JModel& value)
1552 {
1553 int N = value.JK40Parameters::getN();
1554
1555 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1556 if (value.parameters[i].QE .isFree()) { (*this)[i].QE = N; ++N; }
1557 if (value.parameters[i].TTS.isFree()) { (*this)[i].TTS = N; ++N; }
1558 if (value.parameters[i].t0 .isFree()) { (*this)[i].t0 = N; ++N; }
1559 if (value.parameters[i].bg .isFree()) { (*this)[i].bg = N; ++N; }
1560 }
1561 }
1562
1563 } I(value);
1564
1565
1566
1567 struct buffer_type : public vector< pair<int, double> > {
1568 double operator[](const int index) const
1569 {
1570 for (const_iterator i = this->begin(); i != this->end(); ++i) {
1571 if (i->first == index) {
1572 return i->second;
1573 }
1574 }
1575
1576 THROW(JValueOutOfRange, "Invalid index " << index);
1577 }
1578 };
1579
1580 buffer_type buffer;
1581
1582#define PUSH_BACK(i,v) if (i != INVALID_INDEX) { buffer.push_back({i, v}); }
1583
1584
1585 size_t number_of_errors = 0;
1586
1587 for (data_type::const_iterator ix = data.begin(); ix != data.end(); ++ix) {
1588
1589 const pair_type& pair = ix->first;
1590
1591 if (value.parameters[pair.first ].status &&
1592 value.parameters[pair.second].status) {
1593
1594 const real_type& real = value.getReal(pair);
1595
1596 const JBell bell(real.t0, real.sigma, real.signal, 0.0, BELL_SHAPE);
1597
1598 const double R1 = value.getValue (real.ct);
1599 const JK40Parameters_t& R1p = value.getGradient(real.ct);
1600
1601 for (const rate_type& iy : ix->second) {
1602
1603 const double R2 = bell.getValue (iy.dt_ns);
1604 const JBell_t& R2p = bell.getGradient(iy.dt_ns);
1605
1606 const double R = real.bc + real.background + R1 * (real.cc + R2);
1607 const double u = (iy.value - R) / iy.error;
1608 const double w = -estimator->getPsi(u) / iy.error;
1609
1610 successor += estimator->getRho(u);
1611
1612 buffer.clear();
1613
1614 PUSH_BACK(M.R, w * (real.cc + R2) * R1p.R () * value.R .getDerivative());
1615 PUSH_BACK(M.p1, w * (real.cc + R2) * R1p.p1() * value.p1.getDerivative());
1616 PUSH_BACK(M.p2, w * (real.cc + R2) * R1p.p2() * value.p2.getDerivative());
1617 PUSH_BACK(M.p3, w * (real.cc + R2) * R1p.p3() * value.p3.getDerivative());
1618 PUSH_BACK(M.p4, w * (real.cc + R2) * R1p.p4() * value.p4.getDerivative());
1619 PUSH_BACK(M.cc, w * real.signal * R1p.cc() * value.cc.getDerivative());
1620 PUSH_BACK(M.bc, w * R1p.bc() * value.bc.getDerivative());
1621
1622 PUSH_BACK(I[pair.first] .QE, w * R1 * R2p.signal * value.parameters[pair.second].QE () * value.parameters[pair.first ].QE .getDerivative());
1623 PUSH_BACK(I[pair.second].QE, w * R1 * R2p.signal * value.parameters[pair.first ].QE () * value.parameters[pair.second].QE .getDerivative());
1624 PUSH_BACK(I[pair.first] .TTS, w * R1 * R2p.sigma * value.parameters[pair.first ].TTS() * value.parameters[pair.first ].TTS.getDerivative() / real.sigma);
1625 PUSH_BACK(I[pair.second].TTS, w * R1 * R2p.sigma * value.parameters[pair.second].TTS() * value.parameters[pair.second].TTS.getDerivative() / real.sigma);
1626 PUSH_BACK(I[pair.first] .t0, w * R1 * R2p.mean * value.parameters[pair.first ].t0 .getDerivative() * +1.0);
1627 PUSH_BACK(I[pair.second].t0, w * R1 * R2p.mean * value.parameters[pair.second].t0 .getDerivative() * -1.0);
1628 PUSH_BACK(I[pair.first] .bg, w * value.parameters[pair.first ].bg .getDerivative());
1629 PUSH_BACK(I[pair.second].bg, w * value.parameters[pair.second].bg .getDerivative());
1630
1631 if (TEST) {
1632
1633 DEBUG("PMT pair(" << setw(2) << pair.first << "," << setw(2) << pair.second << ") " << FIXED(7,3) << iy.dt_ns << " [ns]" << endl);
1634
1635 const double PRECISION = 1.0e-5;
1636
1637#define MAKE_TEST(i,v) if (i != INVALID_INDEX) { \
1638 \
1639 const bool status = fabs(buffer[i] - v) <= PRECISION; \
1640 \
1641 DEBUG((status ? GREEN : RED) \
1642 << setw(20) << left << #i << right << ' ' \
1643 << setw(3) << i << ' ' \
1644 << FIXED(12,5) << buffer[i] << ' ' \
1645 << FIXED(12,5) << v << ' ' \
1646 << (!status ? "***" : "") \
1647 << RESET << endl); \
1648 \
1649 if (!status) { \
1650 number_of_errors += 1; \
1651 } \
1652 }
1653
1654 struct JTest_t : public JModel
1655 {
1656 JTest_t& operator=(const JModel& model)
1657 {
1658 static_cast<JModel&>(*this) = model;
1659
1660 R .relax();
1661 p1.relax();
1662 p2.relax();
1663 p3.relax();
1664 p4.relax();
1665 cc.relax();
1666 bc.relax();
1667
1668 for (int i = 0; i != NUMBER_OF_PMTS; ++i) {
1669 parameters[i].QE .relax();
1670 parameters[i].TTS.relax();
1671 parameters[i].t0 .relax();
1672 parameters[i].bg .relax();
1673 }
1674
1675 return *this;
1676 }
1677
1678 double operator()(const pair_type& pair, const rate_type& iy) const
1679 {
1680 return (iy.value - getValue(pair, iy.dt_ns)) / iy.error;
1681 }
1682 };
1683
1684 const double DX = 1.0e-8; // dx
1685 JTest_t m1, m2; // y1, y2
1686
1687 // derivative
1688
1689 auto fp = [&DX = DX, &m1 = m1, &m2 = m2, &estimator = estimator](const pair_type& pair, const rate_type& iy)
1690 {
1691 return (estimator->getRho(m2(pair, iy)) - estimator->getRho(m1(pair, iy))) / DX;
1692 };
1693
1694 { m1 = m2 = value; m2.R += 0.5*DX; m1.R -= 0.5*DX; MAKE_TEST(M.R, fp(pair, iy) * value.R .getDerivative()); }
1695 { m1 = m2 = value; m2.p1 += 0.5*DX; m1.p1 -= 0.5*DX; MAKE_TEST(M.p1, fp(pair, iy) * value.p1.getDerivative()); }
1696 { m1 = m2 = value; m2.p2 += 0.5*DX; m1.p2 -= 0.5*DX; MAKE_TEST(M.p2, fp(pair, iy) * value.p2.getDerivative()); }
1697 { m1 = m2 = value; m2.p3 += 0.5*DX; m1.p3 -= 0.5*DX; MAKE_TEST(M.p3, fp(pair, iy) * value.p3.getDerivative()); }
1698 { m1 = m2 = value; m2.p4 += 0.5*DX; m1.p4 -= 0.5*DX; MAKE_TEST(M.p4, fp(pair, iy) * value.p4.getDerivative()); }
1699 { m1 = m2 = value; m2.cc += 0.5*DX; m1.cc -= 0.5*DX; MAKE_TEST(M.cc, fp(pair, iy) * value.cc.getDerivative()); }
1700 { m1 = m2 = value; m2.bc += 0.5*DX; m1.bc -= 0.5*DX; MAKE_TEST(M.bc, fp(pair, iy) * value.bc.getDerivative()); }
1701
1702 { 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()); }
1703 { 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()); }
1704 { 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()); }
1705 { 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()); }
1706 if (pair.first != value.getIndex()) {
1707 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());
1708 }
1709 if (pair.second != value.getIndex()) {
1710 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());
1711 }
1712 { 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()); }
1713 { 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()); }
1714
1715 cout << endl;
1716 }
1717
1718 for (buffer_type::const_iterator row = buffer.begin(); row != buffer.end(); ++row) {
1719
1720 Y[row->first] += row->second;
1721
1722 V[row->first][row->first] += row->second * row->second;
1723
1724 for (buffer_type::const_iterator col = buffer.begin(); col != row; ++col) {
1725 V[row->first][col->first] += row->second * col->second;
1726 V[col->first][row->first] = V[row->first][col->first];
1727 }
1728 }
1729 }
1730 }
1731 }
1732
1733#undef PUSH_BACK
1734
1735 if (TEST) {
1736
1737 STATUS("Test finished with " << number_of_errors << " errors." << endl);
1738
1739 exit(number_of_errors == 0 ? 0 : 1);
1740 }
1741 }
1742
1743
1744 /**
1745 * Set errors.
1746 *
1747 * \param data data
1748 */
1749 void seterr(const data_type& data)
1750 {
1751 using namespace std;
1752
1753 error.reset();
1754
1755 evaluate(data);
1756
1757 try {
1758 V.invert();
1759 }
1760 catch (const exception& error) {}
1761
1762#define SQRT(X) (X >= 0.0 ? sqrt(X) : std::numeric_limits<double>::max())
1763
1764 size_t i = 0;
1765
1766 if (value.R .isFree()) { error.R = SQRT(V(i,i)); ++i; }
1767 if (value.p1.isFree()) { error.p1 = SQRT(V(i,i)); ++i; }
1768 if (value.p2.isFree()) { error.p2 = SQRT(V(i,i)); ++i; }
1769 if (value.p3.isFree()) { error.p3 = SQRT(V(i,i)); ++i; }
1770 if (value.p4.isFree()) { error.p4 = SQRT(V(i,i)); ++i; }
1771 if (value.cc.isFree()) { error.cc = SQRT(V(i,i)); ++i; }
1772 if (value.bc.isFree()) { error.bc = SQRT(V(i,i)); ++i; }
1773
1774 for (int pmt = 0; pmt != NUMBER_OF_PMTS; ++pmt) {
1775 if (value.parameters[pmt].QE .isFree()) { error.parameters[pmt].QE = SQRT(V(i,i)); ++i; }
1776 if (value.parameters[pmt].TTS.isFree()) { error.parameters[pmt].TTS = SQRT(V(i,i)); ++i; }
1777 if (value.parameters[pmt].t0 .isFree()) { error.parameters[pmt].t0 = SQRT(V(i,i)); ++i; }
1778 if (value.parameters[pmt].bg .isFree()) { error.parameters[pmt].bg = SQRT(V(i,i)); ++i; }
1779 }
1780
1781#undef SQRT
1782 }
1783
1784
1785 JMATH::JVectorND Y; // gradient
1788 std::vector<double> h; // normalisation vector
1789 };
1790}
1791
1792#endif
1793
1794
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:1268
std::vector< double > h
Definition JFitK40.hh:1788
static constexpr double LAMBDA_MIN
minimal value control parameter
Definition JFitK40.hh:1472
static constexpr double LAMBDA_DOWN
multiplication factor control parameter
Definition JFitK40.hh:1475
result_type operator()(const data_type &data)
Fit.
Definition JFitK40.hh:1292
void seterr(const data_type &data)
Set errors.
Definition JFitK40.hh:1749
static constexpr double LAMBDA_MAX
maximal value control parameter
Definition JFitK40.hh:1473
static constexpr double LAMBDA_UP
multiplication factor control parameter
Definition JFitK40.hh:1474
JMATH::JMatrixNS V
Definition JFitK40.hh:1485
static constexpr double EPSILON
maximal distance to minimum.
Definition JFitK40.hh:1471
JFit(const int option, const int debug)
Constructor.
Definition JFitK40.hh:1277
void evaluate(const data_type &data)
Evaluation of fit.
Definition JFitK40.hh:1495
static constexpr int MAXIMUM_ITERATIONS
maximal number of iterations.
Definition JFitK40.hh:1470
static constexpr double PIVOT
minimal value diagonal element of matrix
Definition JFitK40.hh:1476
estimator_type estimator
M-Estimator function.
Definition JFitK40.hh:1479
JMATH::JVectorND Y
Definition JFitK40.hh:1785
Auxiliary class for fit parameter with optional limits.
Definition JFitK40.hh:115
JParameter_t & mul(const double factor)
Scale parameter.
Definition JFitK40.hh:202
void set(const double value)
Set value.
Definition JFitK40.hh:309
void fix()
Fix current value.
Definition JFitK40.hh:284
JParameter_t & sub(const JParameter_t &parameter)
Subtract parameter.
Definition JFitK40.hh:188
JParameter_t & operator=(double value)
Assignment operator.
Definition JFitK40.hh:420
bool isFree() const
Check if parameter is free.
Definition JFitK40.hh:244
friend std::ostream & operator<<(std::ostream &out, const JParameter_t &object)
Write parameter to output stream.
Definition JFitK40.hh:448
friend std::istream & operator>>(std::istream &in, JParameter_t &object)
Read parameter from input stream.
Definition JFitK40.hh:435
JParameter_t & div(const double factor)
Scale parameter.
Definition JFitK40.hh:216
void relax()
Relax limits.
Definition JFitK40.hh:339
JParameter_t & mul(const JParameter_t &first, const JParameter_t &second)
Scale parameter.
Definition JFitK40.hh:231
double operator()() const
Type conversion operator.
Definition JFitK40.hh:397
void set()
Set current value.
Definition JFitK40.hh:275
JParameter_t(const double value, const range_type &range=range_type::DEFAULT_RANGE())
Constructor.
Definition JFitK40.hh:147
JParameter_t & negate()
Negate parameter.
Definition JFitK40.hh:160
JParameter_t()
Default constructor.
Definition JFitK40.hh:135
bool atLimit(const double precision) const
Check if parameter is at limit.
Definition JFitK40.hh:355
JTOOLS::JRange< double > range_type
Type definition for range of parameter values.
Definition JFitK40.hh:129
double getDerivative() const
Get derivative of value.
Definition JFitK40.hh:383
void setLimits(const double xmin, const double xmax)
Set limits.
Definition JFitK40.hh:326
JParameter_t & add(const JParameter_t &parameter)
Add parameter.
Definition JFitK40.hh:174
void fix(const double value)
Fix value.
Definition JFitK40.hh:370
double get() const
Get value.
Definition JFitK40.hh:295
bool isBound() const
Check if parameter is bound.
Definition JFitK40.hh:266
bool isFixed() const
Check if parameter is fixed.
Definition JFitK40.hh:255
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:63
static const int INVALID_INDEX
invalid index
Definition JFitK40.hh:60
JOption_t
Fit options.
Definition JFitK40.hh:52
@ FIT_PMTS_QE_FIXED_t
fit parameters of PMTs with QE fixed
Definition JFitK40.hh:56
@ FIT_PMTS_AND_ANGULAR_DEPENDENCE_t
fit parameters of PMTs and angular dependence of K40 rate
Definition JFitK40.hh:54
@ FIT_MODEL_t
fit parameters of K40 rate and TTSs of PMTs
Definition JFitK40.hh:57
@ FIT_PMTS_AND_BACKGROUND_t
fit parameters of PMTs and background
Definition JFitK40.hh:55
@ FIT_PMTS_t
fit parameters of PMTs
Definition JFitK40.hh:53
static double TEROSTAT_DZ
maximal PMT inclination
Definition JFitK40.hh:62
static double BELL_SHAPE
Bell shape.
Definition JFitK40.hh:64
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:610
JParameter_t bc
constant background
Definition JFitK40.hh:714
JParameter_t R
maximal coincidence rate [Hz]
Definition JFitK40.hh:708
JParameter_t p1
1st order angle dependence coincidence rate
Definition JFitK40.hh:709
JParameter_t p2
2nd order angle dependence coincidence rate
Definition JFitK40.hh:710
friend std::ostream & operator<<(std::ostream &out, const JK40Parameters_t &object)
Write model parameters to output stream.
Definition JFitK40.hh:692
JParameter_t p3
3rd order angle dependence coincidence rate
Definition JFitK40.hh:711
const JK40Parameters_t & getK40Parameters() const
Get K40 parameters.
Definition JFitK40.hh:625
JParameter_t p4
4th order angle dependence coincidence rate
Definition JFitK40.hh:712
JParameter_t cc
fraction of signal correlated background
Definition JFitK40.hh:713
JK40Parameters_t()
Default constructor.
Definition JFitK40.hh:614
void setK40Parameters(const JK40Parameters_t &parameters)
Set K40 parameters.
Definition JFitK40.hh:636
void print(std::ostream &out) const
Print model parameters to output stream conform include files.
Definition JFitK40.hh:662
Fit parameters for two-fold coincidence rate due to K40.
Definition JFitK40.hh:723
size_t getN() const
Get number of fit parameters.
Definition JFitK40.hh:760
const JK40Parameters_t & getGradient(const double ct) const
Get gradient.
Definition JFitK40.hh:816
JK40Parameters_t gradient
Definition JFitK40.hh:835
static const JK40Parameters & getInstance()
Get default values.
Definition JFitK40.hh:739
int getIndex(JParameter_t JK40Parameters::*p) const
Get index of parameter.
Definition JFitK40.hh:778
double getValue(const double ct) const
Get K40 coincidence rate as a function of cosine angle between PMT axes.
Definition JFitK40.hh:804
JK40Parameters()
Default constructor.
Definition JFitK40.hh:727
Auxiliary data structure for derived quantities of a given PMT pair.
Definition JFitK40.hh:887
double signal
combined signal
Definition JFitK40.hh:891
double sigma
total width [ns]
Definition JFitK40.hh:890
double cc
correlated background
Definition JFitK40.hh:893
double background
combined background
Definition JFitK40.hh:892
double t0
time offset [ns]
Definition JFitK40.hh:889
double bc
uncorrelated background
Definition JFitK40.hh:894
double ct
cosine angle between PMT axes
Definition JFitK40.hh:888
friend std::ostream & operator<<(std::ostream &out, const JModel_t &object)
Write model parameters to output stream.
Definition JFitK40.hh:855
JPMTParameters_t parameters[NUMBER_OF_PMTS]
Definition JFitK40.hh:845
JModel()
Default constructor.
Definition JFitK40.hh:901
friend std::ostream & operator<<(std::ostream &out, const JModel &object)
Write model parameters to output stream.
Definition JFitK40.hh:1233
size_t getN() const
Get number of fit parameters.
Definition JFitK40.hh:1130
double sigmaK40_ns
intrinsic K40 arrival time spread [ns]
Definition JFitK40.hh:1248
JOption_t getOption() const
Get fit option.
Definition JFitK40.hh:970
double getFixedTimeOffset() const
Get time offset.
Definition JFitK40.hh:1074
void setSigmaK40(const double sigma)
Set intrinsic K40 arrival time spread.
Definition JFitK40.hh:1158
int getIndex() const
Get index of PMT used for fixed time offset.
Definition JFitK40.hh:1095
double getSigmaK40() const
Get intrinsic K40 arrival time spread.
Definition JFitK40.hh:1147
void setOption(const int option)
Set fit option.
Definition JFitK40.hh:981
const real_type & getReal(const pair_type &pair) const
Get derived quantities.
Definition JFitK40.hh:1170
JModel(const JModule &module, const JK40Parameters &parameters)
Constructor.
Definition JFitK40.hh:952
double getValue(const pair_type &pair, const double dt_ns) const
Get K40 coincidence rate.
Definition JFitK40.hh:1210
void setIndex()
Set index of PMT used for fixed time offset.
Definition JFitK40.hh:1104
JOption_t option
fit option (see JCALIBRATE::JOption_t)
Definition JFitK40.hh:1249
JModel(const JModule &module, const JK40Parameters &parameters, const JTDC_t::range_type &TDC, const int option)
Constructor.
Definition JFitK40.hh:913
bool hasFixedTimeOffset() const
Check if time offset is fixed.
Definition JFitK40.hh:1063
int index
index of PMT used for fixed time offset
Definition JFitK40.hh:1247
Fit parameters for single PMT.
Definition JFitK40.hh:472
static constexpr double QE_MIN
minimal QE
Definition JFitK40.hh:474
friend std::ostream & operator<<(std::ostream &out, const JPMTParameters_t &object)
Write PMT parameters to output stream.
Definition JFitK40.hh:586
JParameter_t t0
time offset [ns]
Definition JFitK40.hh:602
static constexpr double TTS_NS
start value transition-time spread [ns]
Definition JFitK40.hh:476
JParameter_t TTS
transition-time spread [ns]
Definition JFitK40.hh:601
void disable()
Disable PMT.
Definition JFitK40.hh:554
size_t getN() const
Get number of fit parameters.
Definition JFitK40.hh:542
JPMTParameters_t()
Default constructor.
Definition JFitK40.hh:481
void set(const JPMTParameters_t &parameters)
Set parameters that are free to given values.
Definition JFitK40.hh:528
JParameter_t bg
background [Hz/ns]
Definition JFitK40.hh:603
static constexpr double QE_MAX
maximal QE
Definition JFitK40.hh:475
void enable()
Enable PMT.
Definition JFitK40.hh:568
static const JPMTParameters_t & getInstance()
Get default values.
Definition JFitK40.hh:492
JParameter_t QE
relative quantum efficiency [unit]
Definition JFitK40.hh:600
Data structure for measured coincidence rates of all pairs of PMTs in optical module.
Definition JFitK40.hh:107
Data structure for measured coincidence rate of pair of PMTs.
Definition JFitK40.hh:70
rate_type(double dt_ns, double value, double error)
Constructor.
Definition JFitK40.hh:88
double error
error of rate [Hz/ns]
Definition JFitK40.hh:98
double value
value of rate [Hz/ns]
Definition JFitK40.hh:97
rate_type()
Default constructor.
Definition JFitK40.hh:74
double dt_ns
time difference [ns]
Definition JFitK40.hh:96
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.