musrfit 1.12.1
PRunSingleHisto.cpp
Go to the documentation of this file.
1/***************************************************************************
2
3 PRunSingleHisto.cpp
4
5 Author: Andreas Suter
6 e-mail: andreas.suter@psi.ch
7
8***************************************************************************/
9
10/***************************************************************************
11 * Copyright (C) 2007-2026 by Andreas Suter *
12 * andreas.suter@psi.ch *
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program; if not, write to the *
26 * Free Software Foundation, Inc., *
27 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
28 ***************************************************************************/
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#ifdef HAVE_GOMP
35#include <omp.h>
36#endif
37
38#include <cmath>
39#include <iostream>
40#include <fstream>
41#include <string>
42#include <vector>
43
44#include <TString.h>
45
46#include "PMusr.h"
47#include "PStringUtils.h"
48#include "PRunSingleHisto.h"
49
50//--------------------------------------------------------------------------
51// Constructor
52//--------------------------------------------------------------------------
67{
68 fScaleN0AndBkg = true;
69 fNoOfFitBins = 0;
70 fBackground = 0;
71 fPacking = -1;
72 fTheoAsData = false;
73
74 // the 2 following variables are need in case fit range is given in bins, and since
75 // the fit range can be changed in the command block, these variables need to be accessible
76 fGoodBins[0] = -1;
77 fGoodBins[1] = -1;
78
79 fStartTimeBin = -1;
80 fEndTimeBin = -1;
81}
82
83//--------------------------------------------------------------------------
84// Constructor
85//--------------------------------------------------------------------------
109PRunSingleHisto::PRunSingleHisto(PMsrHandler *msrInfo, PRunDataHandler *rawData, UInt_t runNo, EPMusrHandleTag tag, Bool_t theoAsData) :
110 PRunBase(msrInfo, rawData, runNo, tag), fTheoAsData(theoAsData)
111{
113 fNoOfFitBins = 0;
114 fBackground = 0;
115
116 fPacking = fRunInfo->GetPacking();
117 if (fPacking == -1) { // i.e. packing is NOT given in the RUN-block, it must be given in the GLOBAL-block
118 fPacking = fMsrInfo->GetMsrGlobal()->GetPacking();
119 }
120 if (fPacking == -1) { // this should NOT happen, somethin is severely wrong
121 std::cerr << std::endl << ">> PRunSingleHisto::PRunSingleHisto: **SEVERE ERROR**: Couldn't find any packing information!";
122 std::cerr << std::endl << ">> This is very bad :-(, will quit ...";
123 std::cerr << std::endl;
124 fValid = false;
125 return;
126 }
127
128 // the 2 following variables are need in case fit range is given in bins, and since
129 // the fit range can be changed in the command block, these variables need to be accessible
130 fGoodBins[0] = -1;
131 fGoodBins[1] = -1;
132
133 fStartTimeBin = -1;
134 fEndTimeBin = -1;
135
136 if (!PrepareData()) {
137 std::cerr << std::endl << ">> PRunSingleHisto::PRunSingleHisto: **SEVERE ERROR**: Couldn't prepare data for fitting!";
138 std::cerr << std::endl << ">> This is very bad :-(, will quit ...";
139 std::cerr << std::endl;
140 fValid = false;
141 }
142}
143
144//--------------------------------------------------------------------------
145// Destructor
146//--------------------------------------------------------------------------
158
159//--------------------------------------------------------------------------
160// CalcChiSquare (public)
161//--------------------------------------------------------------------------
209Double_t PRunSingleHisto::CalcChiSquare(const std::vector<Double_t>& par)
210{
211 Double_t chisq = 0.0;
212 Double_t diff = 0.0;
213
214 Double_t N0 = 0.0;
215
216 // check if norm is a parameter or a function
217 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
218 N0 = par[fRunInfo->GetNormParamNo()-1];
219 } else { // norm is a function
220 // get function number
221 UInt_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
222 // evaluate function
223 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
224 }
225
226 // get tau
227 Double_t tau;
228 if (fRunInfo->GetLifetimeParamNo() != -1)
229 tau = par[fRunInfo->GetLifetimeParamNo()-1];
230 else
231 tau = PMUON_LIFETIME;
232
233 // get background
234 Double_t bkg;
235 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
236 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
237 bkg = fBackground;
238 } else { // fixed bkg given
239 bkg = fRunInfo->GetBkgFix(0);
240 }
241 } else { // bkg fitted
242 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
243 }
244
245 // calculate functions
246 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
247 UInt_t funcNo = fMsrInfo->GetFuncNo(i);
248 fFuncValues[i] = fMsrInfo->EvalFunc(funcNo, *fRunInfo->GetMap(), par, fMetaData);
249 }
250
251 // calculate chi square
252 Double_t time(1.0);
253 Int_t i;
254
255 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
256 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
257 // for a given set of parameters---which should be done outside of the parallelized loop.
258 // For all other functions it means a tiny and acceptable overhead.
259 time = fTheory->Func(time, par, fFuncValues);
260
261 #ifdef HAVE_GOMP
262 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
263 if (chunk < 10)
264 chunk = 10;
265 #pragma omp parallel for default(shared) private(i,time,diff) schedule(dynamic,chunk) reduction(+:chisq)
266 #endif
267 for (i=fStartTimeBin; i<fEndTimeBin; ++i) {
268 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
269 diff = fData.GetValue()->at(i) -
270 (N0*TMath::Exp(-time/tau)*(1.0+fTheory->Func(time, par, fFuncValues))+bkg);
271 chisq += diff*diff / (fData.GetError()->at(i)*fData.GetError()->at(i));
272 }
273
274 // the correction factor is need since the data scales like pack*t_res,
275 // whereas the error scales like sqrt(pack*t_res)
276 if (fScaleN0AndBkg)
277 chisq *= fPacking * (fTimeResolution * 1.0e3);
278
279 return chisq;
280}
281
282//--------------------------------------------------------------------------
283// CalcChiSquareExpected (public)
284//--------------------------------------------------------------------------
324Double_t PRunSingleHisto::CalcChiSquareExpected(const std::vector<Double_t>& par)
325{
326 Double_t chisq = 0.0;
327 Double_t diff = 0.0;
328 Double_t theo = 0.0;
329
330 Double_t N0 = 0.0;
331
332 // check if norm is a parameter or a function
333 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
334 N0 = par[fRunInfo->GetNormParamNo()-1];
335 } else { // norm is a function
336 // get function number
337 UInt_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
338 // evaluate function
339 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
340 }
341
342 // get tau
343 Double_t tau;
344 if (fRunInfo->GetLifetimeParamNo() != -1)
345 tau = par[fRunInfo->GetLifetimeParamNo()-1];
346 else
347 tau = PMUON_LIFETIME;
348
349 // get background
350 Double_t bkg;
351 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
352 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
353 bkg = fBackground;
354 } else { // fixed bkg given
355 bkg = fRunInfo->GetBkgFix(0);
356 }
357 } else { // bkg fitted
358 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
359 }
360
361 // calculate functions
362 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
363 Int_t funcNo = fMsrInfo->GetFuncNo(i);
364 fFuncValues[i] = fMsrInfo->EvalFunc(funcNo, *fRunInfo->GetMap(), par, fMetaData);
365 }
366
367 // calculate chi square
368 Double_t time(1.0);
369 Int_t i;
370
371 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
372 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
373 // for a given set of parameters---which should be done outside of the parallelized loop.
374 // For all other functions it means a tiny and acceptable overhead.
375 time = fTheory->Func(time, par, fFuncValues);
376
377 #ifdef HAVE_GOMP
378 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
379 if (chunk < 10)
380 chunk = 10;
381 #pragma omp parallel for default(shared) private(i,time,theo,diff) schedule(dynamic,chunk) reduction(+:chisq)
382 #endif
383 for (i=fStartTimeBin; i<fEndTimeBin; ++i) {
384 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
385 theo = N0*TMath::Exp(-time/tau)*(1.0+fTheory->Func(time, par, fFuncValues))+bkg;
386 diff = fData.GetValue()->at(i) - theo;
387 chisq += diff*diff / theo;
388 }
389
390 // the correction factor is need since the data scales like pack*t_res,
391 // whereas the error scales like sqrt(pack*t_res)
392 if (fScaleN0AndBkg)
393 chisq *= fPacking * (fTimeResolution * 1.0e3);
394
395 return chisq;
396}
397
398//--------------------------------------------------------------------------
399// CalcMaxLikelihood (public)
400//--------------------------------------------------------------------------
456Double_t PRunSingleHisto::CalcMaxLikelihood(const std::vector<Double_t>& par)
457{
458 Double_t mllh = 0.0; // maximum log likelihood assuming poisson distribution for the single bin
459
460 Double_t N0;
461
462 // check if norm is a parameter or a function
463 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
464 N0 = par[fRunInfo->GetNormParamNo()-1];
465 } else { // norm is a function
466 // get function number
467 Int_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
468 // evaluate function
469 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
470 }
471
472 // get tau
473 Double_t tau;
474 if (fRunInfo->GetLifetimeParamNo() != -1)
475 tau = par[fRunInfo->GetLifetimeParamNo()-1];
476 else
477 tau = PMUON_LIFETIME;
478
479 // get background
480 Double_t bkg;
481 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
482 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
483 bkg = fBackground;
484 } else { // fixed bkg given
485 bkg = fRunInfo->GetBkgFix(0);
486 }
487 } else { // bkg fitted
488 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
489 }
490
491 // calculate functions
492 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
493 UInt_t funcNo = fMsrInfo->GetFuncNo(i);
494 fFuncValues[i] = fMsrInfo->EvalFunc(funcNo, *fRunInfo->GetMap(), par, fMetaData);
495 }
496
497 // calculate maximum log likelihood
498 Double_t theo;
499 Double_t data;
500 Double_t time(1.0);
501 Bool_t post_msg(true);
502 Int_t i;
503
504 // norm is needed since there is no simple scaling like in chisq case to get the correct Max.Log.Likelihood value when normlizing N(t) to 1/ns
505 Double_t normalizer = 1.0;
506
507 if (fScaleN0AndBkg)
508 normalizer = fPacking * (fTimeResolution * 1.0e3);
509
510 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
511 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
512 // for a given set of parameters---which should be done outside of the parallelized loop.
513 // For all other functions it means a tiny and acceptable overhead.
514 time = fTheory->Func(time, par, fFuncValues);
515
516 #ifdef HAVE_GOMP
517 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
518 if (chunk < 10)
519 chunk = 10;
520 #pragma omp parallel for default(shared) private(i,time,theo,data,post_msg) schedule(dynamic,chunk) reduction(+:mllh)
521 #endif
522 for (i=fStartTimeBin; i<fEndTimeBin; ++i) {
523 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
524 // calculate theory for the given parameter set
525 theo = N0*TMath::Exp(-time/tau)*(1.0+fTheory->Func(time, par, fFuncValues))+bkg;
526
527 data = fData.GetValue()->at(i);
528
529 if (theo <= 0.0) {
530 if (post_msg) {
531 post_msg = false;
532 std::cerr << ">> PRunSingleHisto::CalcMaxLikelihood: **WARNING** NEGATIVE theory!!" << std::endl;
533 }
534 continue;
535 }
536
537 if (data > 1.0e-9) {
538 mllh += (theo-data) + data*log(data/theo);
539 } else {
540 mllh += (theo-data);
541 }
542 }
543
544 return normalizer*2.0*mllh;
545}
546
547//--------------------------------------------------------------------------
548// CalcMaxLikelihoodExpected (public)
549//--------------------------------------------------------------------------
595Double_t PRunSingleHisto::CalcMaxLikelihoodExpected(const std::vector<Double_t>& par)
596{
597 Double_t mllh = 0.0; // maximum log likelihood assuming poisson distribution for the single bin
598
599 Double_t N0;
600
601 // check if norm is a parameter or a function
602 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
603 N0 = par[fRunInfo->GetNormParamNo()-1];
604 } else { // norm is a function
605 // get function number
606 Int_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
607 // evaluate function
608 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
609 }
610
611 // get tau
612 Double_t tau;
613 if (fRunInfo->GetLifetimeParamNo() != -1)
614 tau = par[fRunInfo->GetLifetimeParamNo()-1];
615 else
616 tau = PMUON_LIFETIME;
617
618 // get background
619 Double_t bkg;
620 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
621 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
622 bkg = fBackground;
623 } else { // fixed bkg given
624 bkg = fRunInfo->GetBkgFix(0);
625 }
626 } else { // bkg fitted
627 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
628 }
629
630 // calculate functions
631 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
632 UInt_t funcNo = fMsrInfo->GetFuncNo(i);
633 fFuncValues[i] = fMsrInfo->EvalFunc(funcNo, *fRunInfo->GetMap(), par, fMetaData);
634 }
635
636 // calculate maximum log likelihood
637 Double_t theo;
638 Double_t data;
639 Double_t time(1.0);
640 Bool_t post_msg(true);
641 Int_t i;
642
643 // norm is needed since there is no simple scaling like in chisq case to get the correct Max.Log.Likelihood value when normlizing N(t) to 1/ns
644 Double_t normalizer = 1.0;
645
646 if (fScaleN0AndBkg)
647 normalizer = fPacking * (fTimeResolution * 1.0e3);
648
649 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
650 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
651 // for a given set of parameters---which should be done outside of the parallelized loop.
652 // For all other functions it means a tiny and acceptable overhead.
653 time = fTheory->Func(time, par, fFuncValues);
654
655 #ifdef HAVE_GOMP
656 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
657 if (chunk < 10)
658 chunk = 10;
659 #pragma omp parallel for default(shared) private(i,time,theo,data,post_msg) schedule(dynamic,chunk) reduction(+:mllh)
660 #endif
661 for (i=fStartTimeBin; i<fEndTimeBin; ++i) {
662 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
663 // calculate theory for the given parameter set
664 theo = N0*TMath::Exp(-time/tau)*(1.0+fTheory->Func(time, par, fFuncValues))+bkg;
665
666 data = fData.GetValue()->at(i);
667
668 if (theo <= 0.0) {
669 if (post_msg) {
670 post_msg = false;
671 std::cerr << ">> PRunSingleHisto::CalcMaxLikelihood: **WARNING** NEGATIVE theory!!" << std::endl;
672 }
673 continue;
674 }
675
676 if (data > 1.0e-9) { // is this correct?? needs to be checked. See G-test
677 mllh += data*log(data/theo);
678 }
679 }
680
681 return normalizer*2.0*mllh;
682}
683
684//--------------------------------------------------------------------------
685// CalcTheory (public)
686//--------------------------------------------------------------------------
724{
725 // feed the parameter vector
726 std::vector<Double_t> par;
727 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
728 for (UInt_t i=0; i<paramList->size(); i++)
729 par.push_back((*paramList)[i].fValue);
730
731 // calculate asymmetry
732 Double_t N0;
733 // check if norm is a parameter or a function
734 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
735 N0 = par[fRunInfo->GetNormParamNo()-1];
736 } else { // norm is a function
737 // get function number
738 Int_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
739 // evaluate function
740 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
741 }
742
743 // get tau
744 Double_t tau;
745 if (fRunInfo->GetLifetimeParamNo() != -1)
746 tau = par[fRunInfo->GetLifetimeParamNo()-1];
747 else
748 tau = PMUON_LIFETIME;
749
750 // get background
751 Double_t bkg;
752 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
753 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
754 bkg = fBackground;
755 } else { // fixed bkg given
756 bkg = fRunInfo->GetBkgFix(0);
757 }
758 } else { // bkg fitted
759 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
760 }
761
762 // calculate functions
763 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
764 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
765 }
766
767 // calculate theory
768 UInt_t size = fData.GetValue()->size();
769 Double_t start = fData.GetDataTimeStart();
770 Double_t resolution = fData.GetDataTimeStep();
771 Double_t time;
772 for (UInt_t i=0; i<size; i++) {
773 time = start + static_cast<Double_t>(i)*resolution;
774 fData.AppendTheoryValue(N0*TMath::Exp(-time/tau)*(1.0+fTheory->Func(time, par, fFuncValues))+bkg);
775 }
776
777 // clean up
778 par.clear();
779}
780
781//--------------------------------------------------------------------------
782// GetNoOfFitBins (public)
783//--------------------------------------------------------------------------
802{
804
805 return fNoOfFitBins;
806}
807
808//--------------------------------------------------------------------------
809// SetFitRangeBin (public)
810//--------------------------------------------------------------------------
854void PRunSingleHisto::SetFitRangeBin(const TString fitRange)
855{
856 TString str;
857 Ssiz_t idx = -1;
858 Int_t offset = 0;
859
860 std::vector<std::string> tok = PStringUtils::Split(fitRange.Data(), " \t");
861
862 if (tok.size() == 3) { // structure FIT_RANGE fgb+n0 lgb-n1
863 // handle fgb+n0 entry
864 str = tok[1];
865 // check if there is an offset present
866 idx = str.First("+");
867 if (idx != -1) { // offset present
868 str.Remove(0, idx+1);
869 if (str.IsFloat()) // if str is a valid number, convert is to an integer
870 offset = str.Atoi();
871 }
872 fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution;
873
874 // handle lgb-n1 entry
875 str = tok[2];
876 // check if there is an offset present
877 idx = str.First("-");
878 if (idx != -1) { // offset present
879 str.Remove(0, idx+1);
880 if (str.IsFloat()) // if str is a valid number, convert is to an integer
881 offset = str.Atoi();
882 }
883 fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution;
884 } else if ((tok.size() > 3) && (tok.size() % 2 == 1)) { // structure FIT_RANGE fgb[+n00] lgb[-n01] [fgb[+n10] lgb[-n11] ... fgb[+nN0] lgb[-nN1]]
885 UInt_t pos = 2*(fRunNo+1)-1;
886
887 if (pos + 1 >= tok.size()) {
888 std::cerr << std::endl << ">> PRunSingleHisto::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'";
889 std::cerr << std::endl << ">> will ignore it. Sorry ..." << std::endl;
890 } else {
891 // handle fgb+n0 entry
892 str = tok[pos];
893 // check if there is an offset present
894 idx = str.First("+");
895 if (idx != -1) { // offset present
896 str.Remove(0, idx+1);
897 if (str.IsFloat()) // if str is a valid number, convert is to an integer
898 offset = str.Atoi();
899 }
900 fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution;
901
902 // handle lgb-n1 entry
903 str = tok[pos+1];
904 // check if there is an offset present
905 idx = str.First("-");
906 if (idx != -1) { // offset present
907 str.Remove(0, idx+1);
908 if (str.IsFloat()) // if str is a valid number, convert is to an integer
909 offset = str.Atoi();
910 }
911 fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution;
912 }
913 } else { // error
914 std::cerr << std::endl << ">> PRunSingleHisto::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'";
915 std::cerr << std::endl << ">> will ignore it. Sorry ..." << std::endl;
916 }
917}
918
919//--------------------------------------------------------------------------
920// CalcNoOfFitBins (public)
921//--------------------------------------------------------------------------
950{
951 // In order not having to loop over all bins and to stay consistent with the chisq method, calculate the start and end bins explicitly
952 fStartTimeBin = static_cast<Int_t>(ceil((fFitStartTime - fData.GetDataTimeStart())/fData.GetDataTimeStep()));
953 if (fStartTimeBin < 0)
954 fStartTimeBin = 0;
955 fEndTimeBin = static_cast<Int_t>(floor((fFitEndTime - fData.GetDataTimeStart())/fData.GetDataTimeStep())) + 1;
956 if (fEndTimeBin > static_cast<Int_t>(fData.GetValue()->size()))
957 fEndTimeBin = fData.GetValue()->size();
958
961 else
962 fNoOfFitBins = 0;
963}
964
965//--------------------------------------------------------------------------
966// PrepareData (protected)
967//--------------------------------------------------------------------------
1010{
1011 Bool_t success = true;
1012
1013 if (!fValid)
1014 return false;
1015
1016 // keep the Global block info
1017 PMsrGlobalBlock *globalBlock = fMsrInfo->GetMsrGlobal();
1018
1019 // get the proper run
1020 PRawRunData* runData = fRawData->GetRunData(*fRunInfo->GetRunName());
1021 if (!runData) { // couldn't get run
1022 std::cerr << std::endl << ">> PRunSingleHisto::PrepareData(): **ERROR** Couldn't get run " << fRunInfo->GetRunName()->Data() << "!";
1023 std::cerr << std::endl;
1024 return false;
1025 }
1026
1027 // keep the field from the meta-data from the data-file
1028 fMetaData.fField = runData->GetField();
1029
1030 // keep the energy from the meta-data from the data-file
1031 fMetaData.fEnergy = runData->GetEnergy();
1032
1033 // keep the temperature(s) from the meta-data from the data-file
1034 for (unsigned int i=0; i<runData->GetNoOfTemperatures(); i++)
1035 fMetaData.fTemp.push_back(runData->GetTemperature(i));
1036
1037 // collect histogram numbers
1038 PUIntVector histoNo; // histoNo = msr-file forward + redGreen_offset - 1
1039 for (UInt_t i=0; i<fRunInfo->GetForwardHistoNoSize(); i++) {
1040 histoNo.push_back(fRunInfo->GetForwardHistoNo(i));
1041
1042 if (!runData->IsPresent(histoNo[i])) {
1043 std::cerr << std::endl << ">> PRunSingleHisto::PrepareData(): **PANIC ERROR**:";
1044 std::cerr << std::endl << ">> histoNo found = " << histoNo[i] << ", which is NOT present in the data file!?!?";
1045 std::cerr << std::endl << ">> Will quit :-(";
1046 std::cerr << std::endl;
1047 histoNo.clear();
1048 return false;
1049 }
1050 }
1051
1052 // keep the time resolution in (us)
1053 fTimeResolution = runData->GetTimeResolution()/1.0e3;
1054 std::cout.precision(10);
1055 std::cout << std::endl << ">> PRunSingleHisto::PrepareData(): time resolution=" << std::fixed << runData->GetTimeResolution() << "(ns)" << std::endl;
1056
1057 // get all the proper t0's and addt0's for the current RUN block
1058 if (!GetProperT0(runData, globalBlock, histoNo)) {
1059 return false;
1060 }
1061
1062 // keep the histo of each group at this point (addruns handled below)
1063 std::vector<PDoubleVector> forward;
1064 forward.resize(histoNo.size()); // resize to number of groups
1065 for (UInt_t i=0; i<histoNo.size(); i++) {
1066 forward[i].resize(runData->GetDataBin(histoNo[i])->size());
1067 forward[i] = *runData->GetDataBin(histoNo[i]);
1068 }
1069
1070 // check if a dead time correction has to be done
1071 // this will be done automatically in the function itself, which also
1072 // checks in the global and run section
1073 DeadTimeCorrection(forward, histoNo);
1074
1075 // check if there are runs to be added to the current one
1076 if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present
1077 PRawRunData *addRunData;
1078 std::vector<PDoubleVector> addForward;
1079 for (UInt_t i=1; i<fRunInfo->GetRunNameSize(); i++) { // loop over all ADDRUN's
1080
1081 // get run to be added to the main one
1082 addRunData = fRawData->GetRunData(*fRunInfo->GetRunName(i));
1083 if (addRunData == nullptr) { // couldn't get run
1084 std::cerr << std::endl << ">> PRunSingleHisto::PrepareData(): **ERROR** Couldn't get addrun " << fRunInfo->GetRunName(i)->Data() << "!";
1085 std::cerr << std::endl;
1086 return false;
1087 }
1088
1089 addForward.clear();
1090 addForward.resize(histoNo.size()); // resize to number of groups
1091 for (UInt_t j=0; j<histoNo.size(); j++) {
1092 addForward[j].resize(addRunData->GetDataBin(histoNo[j])->size());
1093 addForward[j] = *addRunData->GetDataBin(histoNo[j]);
1094 }
1095 DeadTimeCorrection(addForward, histoNo);
1096
1097 // add forward run
1098 UInt_t addRunSize;
1099 for (UInt_t k=0; k<histoNo.size(); k++) { // fill each group
1100 addRunSize = addForward[k].size();
1101 for (UInt_t j=0; j<addRunSize; j++) { // loop over the bin indices
1102 // make sure that the index stays in the proper range
1103 if ((static_cast<Int_t>(j)+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]) >= 0) &&
1104 (j+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]) < addRunSize)) {
1105 forward[k][j] += addForward[k][j+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k])];
1106 }
1107 }
1108 }
1109 }
1110 }
1111
1112 // set forward histo data of the first group
1113 fForward.resize(forward[0].size());
1114 for (UInt_t i=0; i<fForward.size(); i++) {
1115 fForward[i] = forward[0][i];
1116 }
1117
1118 // group histograms, add all the remaining forward histograms of the group
1119 for (UInt_t i=1; i<histoNo.size(); i++) { // loop over the groupings
1120 for (UInt_t j=0; j<runData->GetDataBin(histoNo[i])->size(); j++) { // loop over the bin indices
1121 // make sure that the index stays within proper range
1122 if ((static_cast<Int_t>(j)+fT0s[i]-fT0s[0] >= 0) && (j+fT0s[i]-fT0s[0] < runData->GetDataBin(histoNo[i])->size())) {
1123 fForward[j] += forward[i][j+static_cast<Int_t>(fT0s[i])-static_cast<Int_t>(fT0s[0])];
1124 }
1125 }
1126 }
1127
1128 // get the data range (fgb/lgb) for the current RUN block
1129 if (!GetProperDataRange()) {
1130 return false;
1131 }
1132
1133 // get the fit range for the current RUN block
1134 GetProperFitRange(globalBlock);
1135
1136 // get the lifetimecorrection flag
1137 Bool_t lifetimecorrection = false;
1138 PMsrPlotList *plot = fMsrInfo->GetMsrPlotList();
1139 lifetimecorrection = plot->at(0).fLifeTimeCorrection;
1140
1141 // do the more fit/view specific stuff
1142 if (fHandleTag == kFit)
1143 success = PrepareFitData(runData, histoNo[0]);
1144 else if ((fHandleTag == kView) && !lifetimecorrection)
1145 success = PrepareRawViewData(runData, histoNo[0]);
1146 else if ((fHandleTag == kView) && lifetimecorrection)
1147 success = PrepareViewData(runData, histoNo[0]);
1148 else
1149 success = false;
1150
1151 // cleanup
1152 histoNo.clear();
1153
1154 return success;
1155}
1156
1157//--------------------------------------------------------------------------
1158// PrepareFitData (protected)
1159//--------------------------------------------------------------------------
1211Bool_t PRunSingleHisto::PrepareFitData(PRawRunData* runData, const UInt_t histoNo)
1212{
1213 if (fMsrInfo->EstimateN0()) {
1214 EstimateN0();
1215 }
1216
1217 // transform raw histo data. This is done the following way (for details see the manual):
1218 // for the single histo fit, just the rebinned raw data are copied
1219
1220 // check how the background shall be handled
1221 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg shall **NOT** be fitted
1222 // subtract background from histogramms ------------------------------------------
1223 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given
1224 if (fRunInfo->GetBkgRange(0) >= 0) {
1225 if (!EstimateBkg(histoNo))
1226 return false;
1227 } else { // no background given to do the job, try estimate
1228 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.1), 0);
1229 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.6), 1);
1230 std::cerr << std::endl << ">> PRunSingleHisto::PrepareFitData(): **WARNING** Neither fix background nor background bins are given!";
1231 std::cerr << std::endl << ">> Will try the following: bkg start = " << fRunInfo->GetBkgRange(0) << ", bkg end = " << fRunInfo->GetBkgRange(1);
1232 std::cerr << std::endl << ">> NO WARRANTY THAT THIS MAKES ANY SENSE! Better check ...";
1233 std::cerr << std::endl;
1234 if (!EstimateBkg(histoNo))
1235 return false;
1236 }
1237 } else { // fixed background given
1238 for (UInt_t i=0; i<fForward.size(); i++) {
1239 fForward[i] -= fRunInfo->GetBkgFix(0);
1240 }
1241 }
1242 }
1243
1244 // everything looks fine, hence fill data set
1245 Int_t t0 = static_cast<Int_t>(fT0s[0]);
1246 Double_t value = 0.0;
1247 Double_t normalizer = 1.0;
1248 // in order that after rebinning the fit does not need to be redone (important for plots)
1249 // the value is normalize to per 1 nsec if scaling is whished
1250 if (fScaleN0AndBkg)
1251 normalizer = fPacking * (fTimeResolution * 1.0e3); // fTimeResolution us->ns
1252 // data start at data_start-t0
1253 // time shifted so that packing is included correctly, i.e. t0 == t0 after packing
1254 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(fGoodBins[0])-0.5) + static_cast<Double_t>(fPacking)/2.0 - static_cast<Double_t>(t0)));
1255 fData.SetDataTimeStep(fTimeResolution*fPacking);
1256 for (Int_t i=fGoodBins[0]; i<fGoodBins[1]; i++) {
1257 if (fPacking == 1) {
1258 value = fForward[i];
1259 value /= normalizer;
1260 fData.AppendValue(value);
1261 if (value == 0.0)
1262 fData.AppendErrorValue(1.0/normalizer);
1263 else
1264 fData.AppendErrorValue(TMath::Sqrt(value));
1265 } else { // packed data, i.e. fPacking > 1
1266 if (((i-fGoodBins[0]) % fPacking == 0) && (i != fGoodBins[0])) { // fill data
1267 value /= normalizer;
1268 fData.AppendValue(value);
1269 if (value == 0.0)
1270 fData.AppendErrorValue(1.0/normalizer);
1271 else
1272 fData.AppendErrorValue(TMath::Sqrt(value));
1273 // reset values
1274 value = 0.0;
1275 }
1276 value += fForward[i];
1277 }
1278 }
1279
1281
1282 return true;
1283}
1284
1285//--------------------------------------------------------------------------
1286// PrepareRawViewData (protected)
1287//--------------------------------------------------------------------------
1304Bool_t PRunSingleHisto::PrepareRawViewData(PRawRunData* runData, const UInt_t histoNo)
1305{
1306 // check if view_packing is wished
1307 Int_t packing = fPacking;
1308 if (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0) {
1309 packing = fMsrInfo->GetMsrPlotList()->at(0).fViewPacking;
1310 }
1311
1312 // calculate necessary norms
1313 Double_t dataNorm = 1.0, theoryNorm = 1.0;
1314 if (fScaleN0AndBkg) {
1315 dataNorm = 1.0/ (packing * (fTimeResolution * 1.0e3)); // fTimeResolution us->ns
1316 } else if (!fScaleN0AndBkg && (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0)) {
1317 theoryNorm = static_cast<Double_t>(fMsrInfo->GetMsrPlotList()->at(0).fViewPacking)/static_cast<Double_t>(fPacking);
1318 }
1319
1320 // raw data, since PMusrCanvas is doing ranging etc.
1321 // start = the first bin which is a multiple of packing backward from first good data bin
1322 Int_t start = fGoodBins[0] - (fGoodBins[0]/packing)*packing;
1323 // end = last bin starting from start which is a multiple of packing and still within the data
1324 Int_t end = start + ((fForward.size()-start)/packing)*packing;
1325 // check if data range has been provided, and if not try to estimate them
1326 if (start < 0) {
1327 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
1328 start = (static_cast<Int_t>(fT0s[0])+offset) - ((static_cast<Int_t>(fT0s[0])+offset)/packing)*packing;
1329 end = start + ((fForward.size()-start)/packing)*packing;
1330 std::cerr << std::endl << ">> PRunSingleHisto::PrepareRawViewData(): **WARNING** data range was not provided, will try data range start = " << start << ".";
1331 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1332 std::cerr << std::endl;
1333 }
1334 // check if start, end, and t0 make any sense
1335 // 1st check if start and end are in proper order
1336 if (end < start) { // need to swap them
1337 Int_t keep = end;
1338 end = start;
1339 start = keep;
1340 }
1341 // 2nd check if start is within proper bounds
1342 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
1343 std::cerr << std::endl << ">> PRunSingleHisto::PrepareRawViewData(): **ERROR** start data bin doesn't make any sense!";
1344 std::cerr << std::endl;
1345 return false;
1346 }
1347 // 3rd check if end is within proper bounds
1348 if ((end < 0) || (end > static_cast<Int_t>(fForward.size()))) {
1349 std::cerr << std::endl << ">> PRunSingleHisto::PrepareRawViewData(): **ERROR** end data bin doesn't make any sense!";
1350 std::cerr << std::endl;
1351 return false;
1352 }
1353
1354 // everything looks fine, hence fill data set
1355 Int_t t0 = static_cast<Int_t>(fT0s[0]);
1356 Double_t value = 0.0;
1357 // data start time = (binStart - 0.5) + pack/2 - t0, with pack and binStart used as double
1358 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(start)-0.5) + static_cast<Double_t>(packing)/2.0 - static_cast<Double_t>(t0)));
1359 fData.SetDataTimeStep(fTimeResolution*packing);
1360
1361 for (Int_t i=start; i<end; i++) {
1362 if (((i-start) % packing == 0) && (i != start)) { // fill data
1363 value *= dataNorm;
1364 fData.AppendValue(value);
1365 if (value == 0.0)
1366 fData.AppendErrorValue(1.0);
1367 else
1368 fData.AppendErrorValue(TMath::Sqrt(value*dataNorm));
1369 // reset values
1370 value = 0.0;
1371 }
1372 value += fForward[i];
1373 }
1374
1376
1377 // fill theory vector for kView
1378 // feed the parameter vector
1379 std::vector<Double_t> par;
1380 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
1381 for (UInt_t i=0; i<paramList->size(); i++)
1382 par.push_back((*paramList)[i].fValue);
1383
1384 // calculate asymmetry
1385 Double_t N0;
1386 // check if norm is a parameter or a function
1387 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
1388 N0 = par[fRunInfo->GetNormParamNo()-1];
1389 } else { // norm is a function
1390 // get function number
1391 UInt_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
1392 // evaluate function
1393 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
1394 }
1395 N0 *= theoryNorm;
1396
1397 // get tau
1398 Double_t tau;
1399 if (fRunInfo->GetLifetimeParamNo() != -1)
1400 tau = par[fRunInfo->GetLifetimeParamNo()-1];
1401 else
1402 tau = PMUON_LIFETIME;
1403
1404 // get background
1405 Double_t bkg;
1406 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
1407 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
1408 if (fRunInfo->GetBkgRange(0) >= 0) { // background range given
1409 if (!EstimateBkg(histoNo))
1410 return false;
1411 } else { // no background given to do the job, try estimate
1412 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.1), 0);
1413 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.6), 1);
1414 std::cerr << std::endl << ">> PRunSingleHisto::PrepareRawViewData(): **WARNING** Neither fix background nor background bins are given!";
1415 std::cerr << std::endl << ">> Will try the following: bkg start = " << fRunInfo->GetBkgRange(0) << ", bkg end = " << fRunInfo->GetBkgRange(1);
1416 std::cerr << std::endl << ">> NO WARRANTY THAT THIS MAKES ANY SENSE! Better check ...";
1417 std::cerr << std::endl;
1418 if (!EstimateBkg(histoNo))
1419 return false;
1420 }
1421 bkg = fBackground;
1422 } else { // fixed bkg given
1423 bkg = fRunInfo->GetBkgFix(0);
1424 }
1425 } else { // bkg fitted
1426 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
1427 }
1428 bkg *= theoryNorm;
1429
1430 // calculate functions
1431 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
1432 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
1433 }
1434
1435 // calculate theory
1436 UInt_t size = fForward.size();
1437 Int_t factor = 8; // 8 times more points for the theory (if fTheoAsData == false)
1438 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
1439 if (fTheoAsData) { // calculate theory only at the data points
1440 fData.SetTheoryTimeStep(fData.GetDataTimeStep());
1441 } else {
1442 // finer binning for the theory (8 times as many points = factor)
1443 size *= factor;
1444 fData.SetTheoryTimeStep(fData.GetDataTimeStep()/(Double_t)factor);
1445 }
1446
1447 Double_t time;
1448 Double_t theoryValue;
1449 for (UInt_t i=0; i<size; i++) {
1450 time = fData.GetTheoryTimeStart() + i*fData.GetTheoryTimeStep();
1451 theoryValue = fTheory->Func(time, par, fFuncValues);
1452 if (fabs(theoryValue) > 1.0e10) { // dirty hack needs to be fixed!!
1453 theoryValue = 0.0;
1454 }
1455 fData.AppendTheoryValue(N0*TMath::Exp(-time/tau)*(1.0+theoryValue)+bkg);
1456 }
1457
1458 // clean up
1459 par.clear();
1460
1461 return true;
1462}
1463
1464//--------------------------------------------------------------------------
1465// PrepareViewData (protected)
1466//--------------------------------------------------------------------------
1493Bool_t PRunSingleHisto::PrepareViewData(PRawRunData* runData, const UInt_t histoNo)
1494{
1495 // check if view_packing is wished. This is a global option for all PLOT blocks!
1496 Int_t packing = fPacking;
1497 if (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0) {
1498 packing = fMsrInfo->GetMsrPlotList()->at(0).fViewPacking;
1499 }
1500 // check if rrf_packing is present. This is a global option for all PLOT blocks, since operated on a single set of data.
1501 if (fMsrInfo->GetMsrPlotList()->at(0).fRRFPacking > 0) {
1502 packing = fMsrInfo->GetMsrPlotList()->at(0).fRRFPacking;
1503 }
1504
1505 // calculate necessary norms
1506 Double_t dataNorm = 1.0, theoryNorm = 1.0;
1507 if (fScaleN0AndBkg) {
1508 dataNorm = 1.0/ (packing * (fTimeResolution * 1.0e3)); // fTimeResolution us->ns
1509 } else if (!fScaleN0AndBkg && (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0)) {
1510 theoryNorm = static_cast<Double_t>(fMsrInfo->GetMsrPlotList()->at(0).fViewPacking)/static_cast<Double_t>(fPacking);
1511 }
1512
1513 // transform raw histo data. This is done the following way (for details see the manual):
1514 // for the single histo fit, just the rebinned raw data are copied
1515 // first get start data, end data, and t0
1516 Int_t t0 = static_cast<Int_t>(fT0s[0]);
1517
1518 // start = the first bin which is a multiple of packing backward from first good data bin
1519 Int_t start = fGoodBins[0] - (fGoodBins[0]/packing)*packing;
1520 // end = last bin starting from start which is a multiple of packing and still within the data
1521 Int_t end = start + ((fForward.size()-start)/packing)*packing;
1522
1523 // check if data range has been provided, and if not try to estimate them
1524 if (start < 0) {
1525 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
1526 start = (static_cast<Int_t>(fT0s[0])+offset) - ((static_cast<Int_t>(fT0s[0])+offset)/packing)*packing;
1527 end = start + ((fForward.size()-start)/packing)*packing;
1528 std::cerr << std::endl << ">> PRunSingleHisto::PrepareViewData(): **WARNING** data range was not provided, will try data range start = " << start << ".";
1529 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1530 std::cerr << std::endl;
1531 }
1532
1533 // check if start, end, and t0 make any sense
1534 // 1st check if start and end are in proper order
1535 if (end < start) { // need to swap them
1536 Int_t keep = end;
1537 end = start;
1538 start = keep;
1539 }
1540 // 2nd check if start is within proper bounds
1541 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
1542 std::cerr << std::endl << ">> PRunSingleHisto::PrepareViewData(): **ERROR** start data bin doesn't make any sense!";
1543 std::cerr << std::endl;
1544 return false;
1545 }
1546 // 3rd check if end is within proper bounds
1547 if ((end < 0) || (end > static_cast<Int_t>(fForward.size()))) {
1548 std::cerr << std::endl << ">> PRunSingleHisto::PrepareViewData(): **ERROR** end data bin doesn't make any sense!";
1549 std::cerr << std::endl;
1550 return false;
1551 }
1552
1553 // everything looks fine, hence fill data set
1554
1555 // feed the parameter vector
1556 std::vector<Double_t> par;
1557 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
1558 for (UInt_t i=0; i<paramList->size(); i++)
1559 par.push_back((*paramList)[i].fValue);
1560
1561 // calculate asymmetry
1562 Double_t N0;
1563 // check if norm is a parameter or a function
1564 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
1565 N0 = par[fRunInfo->GetNormParamNo()-1];
1566 } else { // norm is a function
1567 // get function number
1568 UInt_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
1569 // evaluate function
1570 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
1571 }
1572 N0 *= theoryNorm;
1573
1574 // get tau
1575 Double_t tau;
1576 if (fRunInfo->GetLifetimeParamNo() != -1)
1577 tau = par[fRunInfo->GetLifetimeParamNo()-1];
1578 else
1579 tau = PMUON_LIFETIME;
1580
1581 // get background
1582 Double_t bkg;
1583 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
1584 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
1585 if (fRunInfo->GetBkgRange(0) >= 0) { // background range given
1586 if (!EstimateBkg(histoNo))
1587 return false;
1588 } else { // no background given to do the job, try estimate
1589 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.1), 0);
1590 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.6), 1);
1591 std::cerr << std::endl << ">> PRunSingleHisto::PrepareViewData(): **WARNING** Neither fix background nor background bins are given!";
1592 std::cerr << std::endl << ">> Will try the following: bkg start = " << fRunInfo->GetBkgRange(0) << ", bkg end = " << fRunInfo->GetBkgRange(1);
1593 std::cerr << std::endl << ">> NO WARRANTY THAT THIS MAKES ANY SENSE! Better check ...";
1594 std::cerr << std::endl;
1595 if (!EstimateBkg(histoNo))
1596 return false;
1597 }
1598 bkg = fBackground;
1599 } else { // fixed bkg given
1600 bkg = fRunInfo->GetBkgFix(0);
1601 }
1602 } else { // bkg fitted
1603 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
1604 }
1605 bkg *= theoryNorm;
1606
1607 Double_t value = 0.0;
1608 Double_t expval = 0.0;
1609 Double_t rrf_val = 0.0;
1610 Double_t time = 0.0;
1611
1612 // data start time = (binStart - 0.5) + pack/2 - t0, with pack and binStart used as double
1613 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(start)-0.5) + static_cast<Double_t>(packing)/2.0 - static_cast<Double_t>(t0)));
1614 fData.SetDataTimeStep(fTimeResolution*packing);
1615
1616 // data is always normalized to (per nsec!!)
1617 Double_t gammaRRF = 0.0, wRRF = 0.0, phaseRRF = 0.0;
1618 if (fMsrInfo->GetMsrPlotList()->at(0).fRRFFreq == 0.0) { // normal Data representation
1619 for (Int_t i=start; i<end; i++) {
1620 if (((i-start) % packing == 0) && (i != start)) { // fill data
1621 value *= dataNorm;
1622 // since the packing counter is already at the end of the bin, the time needs be shifted back by pack*time_resolution
1623 time = (((static_cast<Double_t>(i)-0.5) + static_cast<Double_t>(packing)/2.0 - static_cast<Double_t>(t0)))*fTimeResolution - static_cast<Double_t>(packing)*fTimeResolution;
1624 expval = TMath::Exp(+time/tau)/N0;
1625 fData.AppendValue(-1.0+expval*(value-bkg));
1626 fData.AppendErrorValue(expval*TMath::Sqrt(value*dataNorm));
1627 value = 0.0;
1628 }
1629 value += fForward[i];
1630 }
1631 } else { // RRF representation
1632 // check which units shall be used
1633 switch (fMsrInfo->GetMsrPlotList()->at(0).fRRFUnit) {
1634 case RRF_UNIT_kHz:
1635 gammaRRF = TMath::TwoPi()*1.0e-3;
1636 break;
1637 case RRF_UNIT_MHz:
1638 gammaRRF = TMath::TwoPi();
1639 break;
1640 case RRF_UNIT_Mcs:
1641 gammaRRF = 1.0;
1642 break;
1643 case RRF_UNIT_G:
1644 gammaRRF = GAMMA_BAR_MUON*TMath::TwoPi();
1645 break;
1646 case RRF_UNIT_T:
1647 gammaRRF = GAMMA_BAR_MUON*TMath::TwoPi()*1.0e4;
1648 break;
1649 default:
1650 gammaRRF = TMath::TwoPi();
1651 break;
1652 }
1653 wRRF = gammaRRF * fMsrInfo->GetMsrPlotList()->at(0).fRRFFreq;
1654 phaseRRF = fMsrInfo->GetMsrPlotList()->at(0).fRRFPhase / 180.0 * TMath::Pi();
1655
1656 Double_t error = 0.0;
1657 for (Int_t i=start; i<end; i++) {
1658 if (((i-start) % packing == 0) && (i != start)) { // fill data
1659 fData.AppendValue(2.0*value/packing); // factor 2 needed because cos(a)cos(b) = 1/2(cos(a+b)+cos(a-b))
1660 fData.AppendErrorValue(expval*TMath::Sqrt(error/packing));
1661 value = 0.0;
1662 error = 0.0;
1663 }
1664 time = (static_cast<Double_t>(i)-t0)*fTimeResolution;
1665 expval = TMath::Exp(+time/tau)/N0;
1666 rrf_val = (-1.0+expval*(fForward[i]/(fTimeResolution*1.0e3)-bkg))*TMath::Cos(wRRF * time + phaseRRF);
1667 value += rrf_val;
1668 error += fForward[i]*dataNorm;
1669 }
1670 }
1671
1673
1674 // calculate functions
1675 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
1676 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
1677 }
1678
1679 // calculate theory
1680 Double_t theoryValue;
1681 UInt_t size = fForward.size()/packing;
1682 const Int_t factor = 8; // 8 times more points for the theory (if fTheoAsData == false)
1683 UInt_t rebinRRF = 0;
1684
1685 if (wRRF == 0) { // no RRF
1686 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
1687 if (fTheoAsData) { // calculate theory only at the data points
1688 fData.SetTheoryTimeStep(fData.GetDataTimeStep());
1689 } else {
1690 // finer binning for the theory (8 times as many points = factor)
1691 size *= factor;
1692 fData.SetTheoryTimeStep(fData.GetDataTimeStep()/(Double_t)factor);
1693 }
1694 } else { // RRF
1695 rebinRRF = static_cast<UInt_t>((TMath::Pi()/2.0/wRRF)/fTimeResolution); // RRF time resolution / data time resolution
1696 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
1697 fData.SetTheoryTimeStep(TMath::Pi()/2.0/wRRF/rebinRRF); // = theory time resolution as close as possible to the data time resolution compatible with wRRF
1698 }
1699
1700 for (UInt_t i=0; i<size; i++) {
1701 time = fData.GetTheoryTimeStart() + static_cast<Double_t>(i)*fData.GetTheoryTimeStep();
1702 theoryValue = fTheory->Func(time, par, fFuncValues);
1703 if (wRRF != 0.0) {
1704 theoryValue *= 2.0*TMath::Cos(wRRF * time + phaseRRF);
1705 }
1706 if (fabs(theoryValue) > 10.0) { // dirty hack needs to be fixed!!
1707 theoryValue = 0.0;
1708 }
1709 fData.AppendTheoryValue(theoryValue);
1710 }
1711
1712 // if RRF filter the theory with a FIR Kaiser low pass filter
1713 if (wRRF != 0.0) {
1714 // rebin theory to the RRF frequency
1715 if (rebinRRF != 0) {
1716 Double_t dval = 0.0;
1717 PDoubleVector theo;
1718 for (UInt_t i=0; i<fData.GetTheory()->size(); i++) {
1719 if ((i % rebinRRF == 0) && (i != 0)) {
1720 theo.push_back(dval/rebinRRF);
1721 dval = 0.0;
1722 }
1723 dval += fData.GetTheory()->at(i);
1724 }
1725 fData.SetTheoryTimeStart(fData.GetTheoryTimeStart()+static_cast<Double_t>(rebinRRF-1)*fData.GetTheoryTimeStep()/2.0);
1726 fData.SetTheoryTimeStep(rebinRRF*fData.GetTheoryTimeStep());
1727 fData.ReplaceTheory(theo);
1728 theo.clear();
1729 }
1730
1731 // filter theory
1732 CalculateKaiserFilterCoeff(wRRF, 60.0, 0.2); // w_c = wRRF, A = -20 log_10(delta), Delta w / w_c = (w_s - w_p) / (2 w_c)
1733 FilterTheo();
1734 }
1735
1736 // clean up
1737 par.clear();
1738
1739 return true;
1740}
1741
1742//--------------------------------------------------------------------------
1743// GetProperT0 (private)
1744//--------------------------------------------------------------------------
1796{
1797 // feed all T0's
1798 // first init T0's, T0's are stored as (forward T0, backward T0, etc.)
1799 fT0s.clear();
1800 fT0s.resize(histoNo.size());
1801 for (UInt_t i=0; i<fT0s.size(); i++) {
1802 fT0s[i] = -1.0;
1803 }
1804
1805 // fill in the T0's from the msr-file (if present)
1806 for (UInt_t i=0; i<fRunInfo->GetT0BinSize(); i++) {
1807 fT0s[i] = fRunInfo->GetT0Bin(i);
1808 }
1809
1810 // fill in the T0's from the GLOBAL block section (if present)
1811 for (UInt_t i=0; i<globalBlock->GetT0BinSize(); i++) {
1812 if (fT0s[i] == -1.0) { // i.e. not given in the RUN block section
1813 fT0s[i] = globalBlock->GetT0Bin(i);
1814 }
1815 }
1816
1817 // fill in the T0's from the data file, if not already present in the msr-file
1818 for (UInt_t i=0; i<histoNo.size(); i++) {
1819 if (fT0s[i] == -1.0) { // i.e. not present in the msr-file, try the data file
1820 if (runData->GetT0Bin(histoNo[i]) > 0.0) {
1821 fT0s[i] = runData->GetT0Bin(histoNo[i]);
1822 fRunInfo->SetT0Bin(fT0s[i], i); // keep value for the msr-file
1823 }
1824 }
1825 }
1826
1827 // fill in the T0's gaps, i.e. in case the T0's are NOT in the msr-file and NOT in the data file
1828 for (UInt_t i=0; i<histoNo.size(); i++) {
1829 if (fT0s[i] == -1.0) { // i.e. not present in the msr-file and data file, use the estimated T0
1830 fT0s[i] = runData->GetT0BinEstimated(histoNo[i]);
1831 fRunInfo->SetT0Bin(fT0s[i], i); // keep value for the msr-file
1832
1833 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!";
1834 std::cerr << std::endl << ">> run: " << fRunInfo->GetRunName()->Data();
1835 std::cerr << std::endl << ">> will try the estimated one: forward t0 = " << runData->GetT0BinEstimated(histoNo[i]);
1836 std::cerr << std::endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!";
1837 std::cerr << std::endl;
1838 }
1839 }
1840
1841 // check if t0 is within proper bounds
1842 for (UInt_t i=0; i<fRunInfo->GetForwardHistoNoSize(); i++) {
1843 if ((fT0s[i] < 0.0) || (fT0s[i] > static_cast<Int_t>(runData->GetDataBin(histoNo[i])->size()))) {
1844 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **ERROR** t0 data bin (" << fT0s[i] << ") doesn't make any sense!";
1845 std::cerr << std::endl;
1846 return false;
1847 }
1848 }
1849
1850 // check if there are runs to be added to the current one. If yes keep the needed t0's
1851 if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present
1852 PRawRunData *addRunData;
1853 fAddT0s.resize(fRunInfo->GetRunNameSize()-1); // resize to the number of addruns
1854 for (UInt_t i=1; i<fRunInfo->GetRunNameSize(); i++) {
1855
1856 // get run to be added to the main one
1857 addRunData = fRawData->GetRunData(*fRunInfo->GetRunName(i));
1858 if (addRunData == nullptr) { // couldn't get run
1859 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **ERROR** Couldn't get addrun " << fRunInfo->GetRunName(i)->Data() << "!";
1860 std::cerr << std::endl;
1861 return false;
1862 }
1863
1864 // feed all T0's
1865 // first init T0's, T0's are stored as (forward T0, backward T0, etc.)
1866 fAddT0s[i-1].resize(histoNo.size());
1867 for (UInt_t j=0; j<fAddT0s[i-1].size(); j++) {
1868 fAddT0s[i-1][j] = -1.0;
1869 }
1870
1871 // fill in the T0's from the msr-file (if present)
1872 for (UInt_t j=0; j<fRunInfo->GetT0BinSize(); j++) {
1873 fAddT0s[i-1][j] = fRunInfo->GetAddT0Bin(i-1,j); // addRunIdx starts at 0
1874 }
1875
1876 // fill in the T0's from the data file, if not already present in the msr-file
1877 for (UInt_t j=0; j<histoNo.size(); j++) {
1878 if (fAddT0s[i-1][j] == -1.0) // i.e. not present in the msr-file, try the data file
1879 if (addRunData->GetT0Bin(histoNo[j]) > 0.0) {
1880 fAddT0s[i-1][j] = addRunData->GetT0Bin(histoNo[j]);
1881 fRunInfo->SetAddT0Bin(fAddT0s[i-1][j], i-1, j); // keep value for the msr-file
1882 }
1883 }
1884
1885 // fill in the T0's gaps, i.e. in case the T0's are NOT in the msr-file and NOT in the data file
1886 for (UInt_t j=0; j<histoNo.size(); j++) {
1887 if (fAddT0s[i-1][j] == -1.0) { // i.e. not present in the msr-file and data file, use the estimated T0
1888 fAddT0s[i-1][j] = addRunData->GetT0BinEstimated(histoNo[j]);
1889 fRunInfo->SetAddT0Bin(fAddT0s[i-1][j], i-1, j); // keep value for the msr-file
1890
1891 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!";
1892 std::cerr << std::endl << ">> run: " << fRunInfo->GetRunName(i)->Data();
1893 std::cerr << std::endl << ">> will try the estimated one: forward t0 = " << addRunData->GetT0BinEstimated(histoNo[j]);
1894 std::cerr << std::endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!";
1895 std::cerr << std::endl;
1896 }
1897 }
1898
1899 // check if t0 is within proper bounds
1900 for (UInt_t j=0; j<fRunInfo->GetForwardHistoNoSize(); j++) {
1901 if ((fAddT0s[i-1][j] < 0.0) || (fAddT0s[i-1][j] > static_cast<Int_t>(addRunData->GetDataBin(histoNo[j])->size()))) {
1902 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **ERROR** addt0 data bin (" << fAddT0s[i-1][j] << ") doesn't make any sense!";
1903 std::cerr << std::endl;
1904 return false;
1905 }
1906 }
1907 }
1908 }
1909
1910 return true;
1911}
1912
1913//--------------------------------------------------------------------------
1914// GetProperDataRange (private)
1915//--------------------------------------------------------------------------
1961{
1962 // get start/end data
1963 Int_t start;
1964 Int_t end;
1965 start = fRunInfo->GetDataRange(0);
1966 end = fRunInfo->GetDataRange(1);
1967
1968 // check if data range has been given in the RUN block, if not try to get it from the GLOBAL block
1969 if (start < 0) {
1970 start = fMsrInfo->GetMsrGlobal()->GetDataRange(0);
1971 }
1972 if (end < 0) {
1973 end = fMsrInfo->GetMsrGlobal()->GetDataRange(1);
1974 }
1975
1976 // check if data range has been provided, and if not try to estimate them
1977 if (start < 0) {
1978 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
1979 start = static_cast<Int_t>(fT0s[0])+offset;
1980 fRunInfo->SetDataRange(start, 0);
1981 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **WARNING** data range was not provided, will try data range start = t0+" << offset << "(=10ns) = " << start << ".";
1982 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1983 std::cerr << std::endl;
1984 }
1985 if (end < 0) {
1986 end = fForward.size();
1987 fRunInfo->SetDataRange(end, 1);
1988 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **WARNING** data range was not provided, will try data range end = " << end << ".";
1989 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1990 std::cerr << std::endl;
1991 }
1992
1993 // check if start and end make any sense
1994 // 1st check if start and end are in proper order
1995 if (end < start) { // need to swap them
1996 Int_t keep = end;
1997 end = start;
1998 start = keep;
1999 }
2000 // 2nd check if start is within proper bounds
2001 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
2002 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **ERROR** start data bin (" << start << ") doesn't make any sense!";
2003 std::cerr << std::endl;
2004 return false;
2005 }
2006 // 3rd check if end is within proper bounds
2007 if (end < 0) {
2008 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **ERROR** end data bin (" << end << ") doesn't make any sense!";
2009 std::cerr << std::endl;
2010 return false;
2011 }
2012 if (end > static_cast<Int_t>(fForward.size())) {
2013 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **WARNING** end data bin (" << end << ") > histo length (" << fForward.size() << ").";
2014 std::cerr << std::endl << ">> Will set end = (histo length - 1). Consider to change it in the msr-file." << std::endl;
2015 std::cerr << std::endl;
2016 end = static_cast<Int_t>(fForward.size())-1;
2017 }
2018
2019 // keep good bins for potential later use
2020 fGoodBins[0] = start;
2021 fGoodBins[1] = end;
2022
2023 // make sure that fGoodBins are in proper range for fForward
2024 if (fGoodBins[0] < 0)
2025 fGoodBins[0]=0;
2026 if (fGoodBins[1] > fForward.size()) {
2027 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange **WARNING** needed to shift forward lgb,";
2028 std::cerr << std::endl << ">> from " << fGoodBins[1] << " to " << fForward.size()-1 << std::endl;
2029 fGoodBins[1]=fForward.size()-1;
2030 }
2031
2032 return true;
2033}
2034
2035//--------------------------------------------------------------------------
2036// GetProperFitRange (private)
2037//--------------------------------------------------------------------------
2095{
2096 // set fit start/end time; first check RUN Block
2097 fFitStartTime = fRunInfo->GetFitRange(0);
2098 fFitEndTime = fRunInfo->GetFitRange(1);
2099 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
2100 if (fRunInfo->IsFitRangeInBin()) {
2101 fFitStartTime = (fGoodBins[0] + fRunInfo->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
2102 fFitEndTime = (fGoodBins[1] - fRunInfo->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
2103 // write these times back into the data structure. This way it is available when writting the log-file
2104 fRunInfo->SetFitRange(fFitStartTime, 0);
2105 fRunInfo->SetFitRange(fFitEndTime, 1);
2106 }
2107 if (fFitStartTime == PMUSR_UNDEFINED) { // fit start/end NOT found in the RUN block, check GLOBAL block
2108 fFitStartTime = globalBlock->GetFitRange(0);
2109 fFitEndTime = globalBlock->GetFitRange(1);
2110 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
2111 if (globalBlock->IsFitRangeInBin()) {
2112 fFitStartTime = (fGoodBins[0] + globalBlock->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
2113 fFitEndTime = (fGoodBins[1] - globalBlock->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
2114 // write these times back into the data structure. This way it is available when writting the log-file
2115 globalBlock->SetFitRange(fFitStartTime, 0);
2116 globalBlock->SetFitRange(fFitEndTime, 1);
2117 }
2118 }
2120 fFitStartTime = (fGoodBins[0] - fT0s[0]) * fTimeResolution; // (fgb-t0)*dt
2121 fFitEndTime = (fGoodBins[1] - fT0s[0]) * fTimeResolution; // (lgb-t0)*dt
2122 std::cerr << ">> PRunSingleHisto::GetProperFitRange(): **WARNING** Couldn't get fit start/end time!" << std::endl;
2123 std::cerr << ">> Will set it to fgb/lgb which given in time is: " << fFitStartTime << "..." << fFitEndTime << " (usec)" << std::endl;
2124 }
2125}
2126
2127//--------------------------------------------------------------------------
2128// EstimateN0 (private)
2129//--------------------------------------------------------------------------
2173{
2174 // check that 'norm' in the msr-file run block is indeed a parameter number.
2175 // in case it is a function, nothing will be done.
2176 UInt_t paramNo = fRunInfo->GetNormParamNo();
2177 if (paramNo > 10000) // i.e. fun or map
2178 return;
2179
2180 // get the parameters
2181 PMsrParamList *param = fMsrInfo->GetMsrParamList();
2182 assert(param);
2183
2184 if (paramNo > param->size()) {
2185 std::cerr << std::endl << ">> PRunSingleHisto::EstimateN0: **ERROR** found parameter number " << paramNo << ", which is larger than the number of parameters = " << param->size() << std::endl;
2186 return;
2187 }
2188
2189 // check if N0 is fixed. If this is the case, do NOT estimate N0
2190 if (param->at(paramNo-1).fStep == 0.0) // N0 parameter fixed
2191 return;
2192
2193
2194 // check that 'backgr.fit' in the msr-file run block is indeed a parameter number.
2195 // in case it is a function, nothing will be done.
2196 Int_t paramNoBkg = fRunInfo->GetBkgFitParamNo();
2197 Bool_t scaleBkg = true;
2198 Double_t bkg=0.0, errBkg=1.0;
2199 if ((paramNoBkg > 10000) || (paramNoBkg == -1)) { // i.e. fun or map
2200 scaleBkg = false;
2201 } else {
2202 if (paramNoBkg-1 < static_cast<Int_t>(param->size())) {
2203 bkg = param->at(paramNoBkg-1).fValue;
2204 errBkg = param->at(paramNoBkg-1).fStep;
2205 }
2206 }
2207
2208 // estimate N0
2209 Double_t dt = fTimeResolution;
2210 Double_t tau = PMUON_LIFETIME;
2211
2212 UInt_t t0 = static_cast<UInt_t>(round(fT0s[0]));
2213 Double_t dval = 0.0;
2214 Double_t nom = 0.0;
2215 Double_t denom = 0.0;
2216 Double_t xx = 0.0;
2217
2218 // calc nominator
2219 for (UInt_t i=t0; i<fForward.size(); i++) {
2220 xx = exp(-dt*static_cast<Double_t>(i-t0)/tau);
2221 nom += xx;
2222 }
2223
2224 // calc denominator
2225 for (UInt_t i=t0; i<fForward.size(); i++) {
2226 xx = exp(-dt*static_cast<Double_t>(i-t0)/tau);
2227 dval = fForward[i];
2228 if (dval > 0)
2229 denom += xx*xx/dval;
2230 }
2231 Double_t N0 = nom/denom;
2232
2233 if (fScaleN0AndBkg) {
2234 N0 /= fTimeResolution*1.0e3;
2235 } else {
2236 N0 *= fPacking;
2237 }
2238
2239 Double_t rescale = 1;
2240 if ((param->at(paramNo-1).fValue != 0.0) && scaleBkg) {
2241 rescale = N0 / param->at(paramNo-1).fValue;
2242 bkg *= rescale;
2243 errBkg *= rescale;
2244 }
2245
2246 std::cout << ">> PRunSingleHisto::EstimateN0: found N0=" << param->at(paramNo-1).fValue << ", will set it to N0=" << N0 << std::endl;
2247 if (scaleBkg)
2248 std::cout << ">> PRunSingleHisto::EstimateN0: found Bkg=" << param->at(paramNoBkg-1).fValue << ", will set it to Bkg=" << bkg << std::endl;
2249 fMsrInfo->SetMsrParamValue(paramNo-1, N0);
2250 fMsrInfo->SetMsrParamStep(paramNo-1, sqrt(fabs(N0)));
2251 if (scaleBkg) {
2252 fMsrInfo->SetMsrParamValue(paramNoBkg-1, bkg);
2253 fMsrInfo->SetMsrParamStep(paramNoBkg-1, errBkg);
2254 }
2255}
2256
2257//--------------------------------------------------------------------------
2258// EstimateBkg (private)
2259//--------------------------------------------------------------------------
2308Bool_t PRunSingleHisto::EstimateBkg(UInt_t histoNo)
2309{
2310 Double_t beamPeriod = 0.0;
2311
2312 // check if data are from PSI, RAL, or TRIUMF
2313 if (fRunInfo->GetInstitute()->Contains("psi"))
2314 beamPeriod = ACCEL_PERIOD_PSI;
2315 else if (fRunInfo->GetInstitute()->Contains("ral"))
2316 beamPeriod = ACCEL_PERIOD_RAL;
2317 else if (fRunInfo->GetInstitute()->Contains("triumf"))
2318 beamPeriod = ACCEL_PERIOD_TRIUMF;
2319 else
2320 beamPeriod = 0.0;
2321
2322 // check if start and end are in proper order
2323 Int_t start = fRunInfo->GetBkgRange(0);
2324 Int_t end = fRunInfo->GetBkgRange(1);
2325 if (end < start) {
2326 std::cout << std::endl << "PRunSingleHisto::EstimatBkg(): end = " << end << " > start = " << start << "! Will swap them!";
2327 Int_t keep = end;
2328 end = start;
2329 start = keep;
2330 }
2331
2332 // calculate proper background range
2333 if (beamPeriod != 0.0) {
2334 Double_t timeBkg = static_cast<Double_t>(end-start)*(fTimeResolution*fPacking); // length of the background intervall in time
2335 UInt_t fullCycles = static_cast<UInt_t>(timeBkg/beamPeriod); // how many proton beam cylces can be placed within the proposed background intervall
2336 // correct the end of the background intervall such that the background is as close as possible to a multiple of the proton cylce
2337 end = start + static_cast<UInt_t>((fullCycles*beamPeriod)/(fTimeResolution*fPacking));
2338 std::cout << std::endl << "PRunSingleHisto::EstimatBkg(): Background " << start << ", " << end;
2339 if (end == start)
2340 end = fRunInfo->GetBkgRange(1);
2341 }
2342
2343 // check if start is within histogram bounds
2344 if (start >= fForward.size()) {
2345 std::cerr << std::endl << ">> PRunSingleHisto::EstimatBkg(): **ERROR** background bin values out of bound!";
2346 std::cerr << std::endl << ">> histo lengths = " << fForward.size();
2347 std::cerr << std::endl << ">> background start = " << start;
2348 std::cerr << std::endl;
2349 return false;
2350 }
2351
2352 // check if end is within histogram bounds
2353 if (end >= fForward.size()) {
2354 std::cerr << std::endl << ">> PRunSingleHisto::EstimatBkg(): **ERROR** background bin values out of bound!";
2355 std::cerr << std::endl << ">> histo lengths = " << fForward.size();
2356 std::cerr << std::endl << ">> background end = " << end;
2357 std::cerr << std::endl;
2358 return false;
2359 }
2360
2361 // calculate background
2362 Double_t bkg = 0.0;
2363
2364 // forward
2365 for (UInt_t i=start; i<end; i++)
2366 bkg += fForward[i];
2367 bkg /= static_cast<Double_t>(end - start + 1);
2368
2369 if (fScaleN0AndBkg)
2370 fBackground = bkg / (fTimeResolution * 1e3); // keep background (per 1 nsec) for chisq, max.log.likelihood, fTimeResolution us->ns
2371 else
2372 fBackground = bkg * fPacking; // keep background (per bin)
2373
2374 fRunInfo->SetBkgEstimated(fBackground, 0);
2375
2376 return true;
2377}
2378
2379//--------------------------------------------------------------------------
2380// IsScaleN0AndBkg (private)
2381//--------------------------------------------------------------------------
2425{
2426 Bool_t willScale = true;
2427
2428 PMsrLines *cmd = fMsrInfo->GetMsrCommands();
2429 for (UInt_t i=0; i<cmd->size(); i++) {
2430 if (cmd->at(i).fLine.Contains("SCALE_N0_BKG", TString::kIgnoreCase)) {
2431 std::vector<std::string> tokens = PStringUtils::Split(cmd->at(i).fLine.Data(), " \t");
2432 if (tokens.size() != 2) {
2433 std::cerr << std::endl << ">> PRunSingleHisto::IsScaleN0AndBkg(): **WARNING** Found uncorrect 'SCALE_N0_BKG' command, will ignore it.";
2434 std::cerr << std::endl << ">> Allowed commands: SCALE_N0_BKG TRUE | FALSE" << std::endl;
2435 return willScale;
2436 }
2437 if (PStringUtils::IsEqualNoCase(tokens[1], "FALSE")) {
2438 willScale = false;
2439 }
2440 }
2441 }
2442
2443 return willScale;
2444}
std::vector< UInt_t > PUIntVector
Definition PMusr.h:375
#define ACCEL_PERIOD_TRIUMF
TRIUMF accelerator cycle: 43.37 ns.
Definition PMusr.h:156
EPMusrHandleTag
Definition PMusr.h:427
@ kFit
Fitting mode - perform least-squares fit to data.
Definition PMusr.h:429
@ kView
Viewing mode - display data and theory without fitting.
Definition PMusr.h:430
#define RRF_UNIT_MHz
Frequency in MHz (megahertz).
Definition PMusr.h:349
#define PMUSR_UNDEFINED
Definition PMusr.h:177
#define GAMMA_BAR_MUON
Definition PMusr.h:143
#define PMUON_LIFETIME
Definition PMusr.h:124
#define MSR_PARAM_FUN_OFFSET
Offset added to function indices for parameter parsing.
Definition PMusr.h:265
std::vector< PMsrPlotStructure > PMsrPlotList
Definition PMusr.h:1330
std::vector< PMsrLineStructure > PMsrLines
Definition PMusr.h:1007
std::vector< PMsrParamStructure > PMsrParamList
Definition PMusr.h:1040
#define RRF_UNIT_Mcs
Angular frequency in Mc/s (Mega-cycles per second).
Definition PMusr.h:351
#define RRF_UNIT_G
Equivalent magnetic field in Gauss (G).
Definition PMusr.h:353
#define RRF_UNIT_kHz
Frequency in kHz (kilohertz).
Definition PMusr.h:347
#define ACCEL_PERIOD_PSI
PSI (Paul Scherrer Institute) accelerator cycle: 19.75 ns.
Definition PMusr.h:154
#define RRF_UNIT_T
Equivalent magnetic field in Tesla (T).
Definition PMusr.h:355
std::vector< Double_t > PDoubleVector
Definition PMusr.h:399
#define ACCEL_PERIOD_RAL
RAL (Rutherford Appleton Lab) - pulsed beam.
Definition PMusr.h:158
virtual void SetFitRange(Double_t dval, UInt_t idx)
Definition PMusr.cpp:1171
virtual Double_t GetFitRange(UInt_t idx)
Definition PMusr.cpp:1154
virtual UInt_t GetT0BinSize()
Definition PMusr.h:1068
virtual Bool_t IsFitRangeInBin()
Definition PMusr.h:1073
virtual Int_t GetFitRangeOffset(UInt_t idx)
Definition PMusr.cpp:1191
virtual Double_t GetT0Bin(UInt_t idx=0)
Definition PMusr.cpp:1038
MSR file parser and manager for the musrfit framework.
virtual const PDoubleVector * GetDataBin(const UInt_t histoNo)
Definition PMusr.h:896
virtual const Double_t GetT0Bin(const UInt_t histoNo)
Definition PMusr.h:884
virtual const Double_t GetTimeResolution()
Definition PMusr.h:882
virtual const Bool_t IsPresent(UInt_t histoNo)
Definition PMusr.h:883
virtual const UInt_t GetNoOfTemperatures()
Definition PMusr.h:874
virtual const Double_t GetField()
Definition PMusr.h:873
virtual const Double_t GetEnergy()
Definition PMusr.h:878
virtual const Double_t GetT0BinEstimated(const UInt_t histoNo)
Definition PMusr.h:885
virtual const PDoublePairVector * GetTemperature() const
Definition PMusr.h:875
Double_t fTimeResolution
Time resolution of raw histogram data in microseconds (μs), e.g., 0.01953125 μs for PSI GPS.
Definition PRunBase.h:276
Bool_t fValid
Flag indicating if run object initialized successfully; false if any error occurred.
Definition PRunBase.h:266
Double_t fFitEndTime
Fit range end time in microseconds (μs) relative to t0.
Definition PRunBase.h:282
PDoubleVector fFuncValues
Cached values of user-defined functions from FUNCTIONS block, evaluated at current parameters.
Definition PRunBase.h:284
PMsrHandler * fMsrInfo
Pointer to MSR file handler (owned externally, not deleted here).
Definition PRunBase.h:271
virtual void DeadTimeCorrection(std::vector< PDoubleVector > &histos, PUIntVector &histoNo)
carry out dead time correction
Definition PRunBase.cpp:169
PMetaData fMetaData
Experimental metadata extracted from data file header (magnetic field, temperature,...
Definition PRunBase.h:277
std::unique_ptr< PTheory > fTheory
Theory function evaluator (smart pointer, automatically deleted).
Definition PRunBase.h:285
std::vector< PDoubleVector > fAddT0s
Time-zero bin values for additional runs to be added to main run.
Definition PRunBase.h:279
EPMusrHandleTag fHandleTag
Operation mode: kFit (fitting), kView (display only), kEmpty (uninitialized).
Definition PRunBase.h:268
virtual void CalculateKaiserFilterCoeff(Double_t wc, Double_t A, Double_t dw)
Calculates Kaiser window FIR filter coefficients for RRF smoothing.
Definition PRunBase.cpp:337
PRunData fData
Processed data container: background-corrected, packed, with theory values.
Definition PRunBase.h:275
PRunDataHandler * fRawData
Pointer to raw data handler (owned externally, not deleted here).
Definition PRunBase.h:273
PDoubleVector fT0s
Time-zero bin values for all histograms in this run (forward, backward, etc.).
Definition PRunBase.h:278
PRunBase()
Default constructor.
Definition PRunBase.cpp:52
Int_t fRunNo
Run number (0-based index in MSR file RUN blocks).
Definition PRunBase.h:270
PMsrRunBlock * fRunInfo
Pointer to this run's RUN block settings within fMsrInfo.
Definition PRunBase.h:272
Double_t fFitStartTime
Fit range start time in microseconds (μs) relative to t0.
Definition PRunBase.h:281
virtual void FilterTheo()
Applies Kaiser FIR filter to theory values for RRF fits.
Definition PRunBase.cpp:403
Raw data file reader and format converter for μSR data.
virtual Double_t CalcChiSquare(const std::vector< Double_t > &par)
Calculates χ² between histogram data and theory.
virtual void CalcNoOfFitBins()
Calculates start/end bin indices from fit time range.
virtual Double_t CalcChiSquareExpected(const std::vector< Double_t > &par)
Calculates expected χ² based on theory predictions.
virtual Bool_t IsScaleN0AndBkg()
Determines if N₀ and background should be scaled to 1/ns.
Double_t fBackground
Background level in counts/bin (estimated from pre-t0 bins or fixed value from RUN block).
UInt_t fNoOfFitBins
Number of bins within fit range (fStartTimeBin to fEndTimeBin).
virtual ~PRunSingleHisto()
Virtual destructor cleaning up allocated resources.
virtual Bool_t PrepareViewData(PRawRunData *runData, const UInt_t histoNo)
Prepares processed histogram data for viewing/plotting.
virtual Double_t CalcMaxLikelihood(const std::vector< Double_t > &par)
Calculates maximum likelihood for Poisson-distributed histogram counts.
virtual Bool_t EstimateBkg(UInt_t histoNo)
Estimates background from pre-t0 bins.
virtual void CalcTheory()
Evaluates theory function at all data points or high-resolution grid.
virtual UInt_t GetNoOfFitBins()
Returns the number of bins included in the fit range.
virtual void EstimateN0()
Estimates initial normalization N₀ from histogram data.
Int_t fEndTimeBin
Last bin index in fit range (exclusive: loop as i < fEndTimeBin).
PRunSingleHisto()
Default constructor creating an empty, invalid single histogram run object.
virtual void GetProperFitRange(PMsrGlobalBlock *globalBlock)
Determines fit range from MSR file settings.
virtual void SetFitRangeBin(const TString fitRange)
Sets fit range using bin-offset specification (COMMANDS block syntax).
Bool_t fScaleN0AndBkg
Scaling mode: true = scale N₀ and B to 1/ns, false = leave as 1/bin (determined by IsScaleN0AndBkg())...
Int_t fStartTimeBin
First bin index in fit range (inclusive, 0-based after packing).
virtual Bool_t GetProperDataRange()
Determines data range (region of valid histogram data).
virtual Bool_t GetProperT0(PRawRunData *runData, PMsrGlobalBlock *globalBlock, PUIntVector &histoNo)
Determines and validates t0 values for histogram.
Bool_t fTheoAsData
Theory mode: true = at data points, false = high-resolution grid for smooth Fourier transforms.
Int_t fGoodBins[2]
Good bin markers for COMMANDS block: [0]=fgb (first good bin/t0), [1]=lgb (last good bin).
Int_t fPacking
Bin packing factor (REQUIRED: from RUN or GLOBAL block).
virtual Bool_t PrepareRawViewData(PRawRunData *runData, const UInt_t histoNo)
Prepares raw histogram data for viewing (minimal processing).
virtual Double_t CalcMaxLikelihoodExpected(const std::vector< Double_t > &par)
Calculates expected maximum likelihood.
virtual Bool_t PrepareData()
Main data preparation orchestrator.
virtual Bool_t PrepareFitData(PRawRunData *runData, const UInt_t histoNo)
Prepares histogram data for fitting.
PDoubleVector fForward
Forward detector histogram (background-corrected, packed).
static bool IsEqualNoCase(const std::string &a, const std::string &b)
static std::vector< std::string > Split(const std::string &str, const std::string &delimiters)