musrfit 1.10.0
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 Int_t i;
502
503 // 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
504 Double_t normalizer = 1.0;
505
506 if (fScaleN0AndBkg)
507 normalizer = fPacking * (fTimeResolution * 1.0e3);
508
509 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
510 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
511 // for a given set of parameters---which should be done outside of the parallelized loop.
512 // For all other functions it means a tiny and acceptable overhead.
513 time = fTheory->Func(time, par, fFuncValues);
514
515 #ifdef HAVE_GOMP
516 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
517 if (chunk < 10)
518 chunk = 10;
519 #pragma omp parallel for default(shared) private(i,time,theo,data) schedule(dynamic,chunk) reduction(+:mllh)
520 #endif
521 for (i=fStartTimeBin; i<fEndTimeBin; ++i) {
522 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
523 // calculate theory for the given parameter set
524 theo = N0*TMath::Exp(-time/tau)*(1.0+fTheory->Func(time, par, fFuncValues))+bkg;
525
526 data = fData.GetValue()->at(i);
527
528 if (theo <= 0.0) {
529 std::cerr << ">> PRunSingleHisto::CalcMaxLikelihood: **WARNING** NEGATIVE theory!!" << std::endl;
530 continue;
531 }
532
533 if (data > 1.0e-9) {
534 mllh += (theo-data) + data*log(data/theo);
535 } else {
536 mllh += (theo-data);
537 }
538 }
539
540 return normalizer*2.0*mllh;
541}
542
543//--------------------------------------------------------------------------
544// CalcMaxLikelihoodExpected (public)
545//--------------------------------------------------------------------------
591Double_t PRunSingleHisto::CalcMaxLikelihoodExpected(const std::vector<Double_t>& par)
592{
593 Double_t mllh = 0.0; // maximum log likelihood assuming poisson distribution for the single bin
594
595 Double_t N0;
596
597 // check if norm is a parameter or a function
598 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
599 N0 = par[fRunInfo->GetNormParamNo()-1];
600 } else { // norm is a function
601 // get function number
602 Int_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
603 // evaluate function
604 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
605 }
606
607 // get tau
608 Double_t tau;
609 if (fRunInfo->GetLifetimeParamNo() != -1)
610 tau = par[fRunInfo->GetLifetimeParamNo()-1];
611 else
612 tau = PMUON_LIFETIME;
613
614 // get background
615 Double_t bkg;
616 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
617 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
618 bkg = fBackground;
619 } else { // fixed bkg given
620 bkg = fRunInfo->GetBkgFix(0);
621 }
622 } else { // bkg fitted
623 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
624 }
625
626 // calculate functions
627 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
628 UInt_t funcNo = fMsrInfo->GetFuncNo(i);
629 fFuncValues[i] = fMsrInfo->EvalFunc(funcNo, *fRunInfo->GetMap(), par, fMetaData);
630 }
631
632 // calculate maximum log likelihood
633 Double_t theo;
634 Double_t data;
635 Double_t time(1.0);
636 Int_t i;
637
638 // 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
639 Double_t normalizer = 1.0;
640
641 if (fScaleN0AndBkg)
642 normalizer = fPacking * (fTimeResolution * 1.0e3);
643
644 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
645 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
646 // for a given set of parameters---which should be done outside of the parallelized loop.
647 // For all other functions it means a tiny and acceptable overhead.
648 time = fTheory->Func(time, par, fFuncValues);
649
650 #ifdef HAVE_GOMP
651 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
652 if (chunk < 10)
653 chunk = 10;
654 #pragma omp parallel for default(shared) private(i,time,theo,data) schedule(dynamic,chunk) reduction(+:mllh)
655 #endif
656 for (i=fStartTimeBin; i<fEndTimeBin; ++i) {
657 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
658 // calculate theory for the given parameter set
659 theo = N0*TMath::Exp(-time/tau)*(1.0+fTheory->Func(time, par, fFuncValues))+bkg;
660
661 data = fData.GetValue()->at(i);
662
663 if (theo <= 0.0) {
664 std::cerr << ">> PRunSingleHisto::CalcMaxLikelihood: **WARNING** NEGATIVE theory!!" << std::endl;
665 continue;
666 }
667
668 if (data > 1.0e-9) { // is this correct?? needs to be checked. See G-test
669 mllh += data*log(data/theo);
670 }
671 }
672
673 return normalizer*2.0*mllh;
674}
675
676//--------------------------------------------------------------------------
677// CalcTheory (public)
678//--------------------------------------------------------------------------
716{
717 // feed the parameter vector
718 std::vector<Double_t> par;
719 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
720 for (UInt_t i=0; i<paramList->size(); i++)
721 par.push_back((*paramList)[i].fValue);
722
723 // calculate asymmetry
724 Double_t N0;
725 // check if norm is a parameter or a function
726 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
727 N0 = par[fRunInfo->GetNormParamNo()-1];
728 } else { // norm is a function
729 // get function number
730 Int_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
731 // evaluate function
732 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
733 }
734
735 // get tau
736 Double_t tau;
737 if (fRunInfo->GetLifetimeParamNo() != -1)
738 tau = par[fRunInfo->GetLifetimeParamNo()-1];
739 else
740 tau = PMUON_LIFETIME;
741
742 // get background
743 Double_t bkg;
744 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
745 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
746 bkg = fBackground;
747 } else { // fixed bkg given
748 bkg = fRunInfo->GetBkgFix(0);
749 }
750 } else { // bkg fitted
751 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
752 }
753
754 // calculate functions
755 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
756 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
757 }
758
759 // calculate theory
760 UInt_t size = fData.GetValue()->size();
761 Double_t start = fData.GetDataTimeStart();
762 Double_t resolution = fData.GetDataTimeStep();
763 Double_t time;
764 for (UInt_t i=0; i<size; i++) {
765 time = start + static_cast<Double_t>(i)*resolution;
766 fData.AppendTheoryValue(N0*TMath::Exp(-time/tau)*(1.0+fTheory->Func(time, par, fFuncValues))+bkg);
767 }
768
769 // clean up
770 par.clear();
771}
772
773//--------------------------------------------------------------------------
774// GetNoOfFitBins (public)
775//--------------------------------------------------------------------------
794{
796
797 return fNoOfFitBins;
798}
799
800//--------------------------------------------------------------------------
801// SetFitRangeBin (public)
802//--------------------------------------------------------------------------
846void PRunSingleHisto::SetFitRangeBin(const TString fitRange)
847{
848 TString str;
849 Ssiz_t idx = -1;
850 Int_t offset = 0;
851
852 std::vector<std::string> tok = PStringUtils::Split(fitRange.Data(), " \t");
853
854 if (tok.size() == 3) { // structure FIT_RANGE fgb+n0 lgb-n1
855 // handle fgb+n0 entry
856 str = tok[1];
857 // check if there is an offset present
858 idx = str.First("+");
859 if (idx != -1) { // offset present
860 str.Remove(0, idx+1);
861 if (str.IsFloat()) // if str is a valid number, convert is to an integer
862 offset = str.Atoi();
863 }
864 fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution;
865
866 // handle lgb-n1 entry
867 str = tok[2];
868 // check if there is an offset present
869 idx = str.First("-");
870 if (idx != -1) { // offset present
871 str.Remove(0, idx+1);
872 if (str.IsFloat()) // if str is a valid number, convert is to an integer
873 offset = str.Atoi();
874 }
875 fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution;
876 } else if ((tok.size() > 3) && (tok.size() % 2 == 1)) { // structure FIT_RANGE fgb[+n00] lgb[-n01] [fgb[+n10] lgb[-n11] ... fgb[+nN0] lgb[-nN1]]
877 UInt_t pos = 2*(fRunNo+1)-1;
878
879 if (pos + 1 >= tok.size()) {
880 std::cerr << std::endl << ">> PRunSingleHisto::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'";
881 std::cerr << std::endl << ">> will ignore it. Sorry ..." << std::endl;
882 } else {
883 // handle fgb+n0 entry
884 str = tok[pos];
885 // check if there is an offset present
886 idx = str.First("+");
887 if (idx != -1) { // offset present
888 str.Remove(0, idx+1);
889 if (str.IsFloat()) // if str is a valid number, convert is to an integer
890 offset = str.Atoi();
891 }
892 fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution;
893
894 // handle lgb-n1 entry
895 str = tok[pos+1];
896 // check if there is an offset present
897 idx = str.First("-");
898 if (idx != -1) { // offset present
899 str.Remove(0, idx+1);
900 if (str.IsFloat()) // if str is a valid number, convert is to an integer
901 offset = str.Atoi();
902 }
903 fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution;
904 }
905 } else { // error
906 std::cerr << std::endl << ">> PRunSingleHisto::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'";
907 std::cerr << std::endl << ">> will ignore it. Sorry ..." << std::endl;
908 }
909}
910
911//--------------------------------------------------------------------------
912// CalcNoOfFitBins (public)
913//--------------------------------------------------------------------------
942{
943 // In order not having to loop over all bins and to stay consistent with the chisq method, calculate the start and end bins explicitly
944 fStartTimeBin = static_cast<Int_t>(ceil((fFitStartTime - fData.GetDataTimeStart())/fData.GetDataTimeStep()));
945 if (fStartTimeBin < 0)
946 fStartTimeBin = 0;
947 fEndTimeBin = static_cast<Int_t>(floor((fFitEndTime - fData.GetDataTimeStart())/fData.GetDataTimeStep())) + 1;
948 if (fEndTimeBin > static_cast<Int_t>(fData.GetValue()->size()))
949 fEndTimeBin = fData.GetValue()->size();
950
953 else
954 fNoOfFitBins = 0;
955}
956
957//--------------------------------------------------------------------------
958// PrepareData (protected)
959//--------------------------------------------------------------------------
1002{
1003 Bool_t success = true;
1004
1005 if (!fValid)
1006 return false;
1007
1008 // keep the Global block info
1009 PMsrGlobalBlock *globalBlock = fMsrInfo->GetMsrGlobal();
1010
1011 // get the proper run
1012 PRawRunData* runData = fRawData->GetRunData(*fRunInfo->GetRunName());
1013 if (!runData) { // couldn't get run
1014 std::cerr << std::endl << ">> PRunSingleHisto::PrepareData(): **ERROR** Couldn't get run " << fRunInfo->GetRunName()->Data() << "!";
1015 std::cerr << std::endl;
1016 return false;
1017 }
1018
1019 // keep the field from the meta-data from the data-file
1020 fMetaData.fField = runData->GetField();
1021
1022 // keep the energy from the meta-data from the data-file
1023 fMetaData.fEnergy = runData->GetEnergy();
1024
1025 // keep the temperature(s) from the meta-data from the data-file
1026 for (unsigned int i=0; i<runData->GetNoOfTemperatures(); i++)
1027 fMetaData.fTemp.push_back(runData->GetTemperature(i));
1028
1029 // collect histogram numbers
1030 PUIntVector histoNo; // histoNo = msr-file forward + redGreen_offset - 1
1031 for (UInt_t i=0; i<fRunInfo->GetForwardHistoNoSize(); i++) {
1032 histoNo.push_back(fRunInfo->GetForwardHistoNo(i));
1033
1034 if (!runData->IsPresent(histoNo[i])) {
1035 std::cerr << std::endl << ">> PRunSingleHisto::PrepareData(): **PANIC ERROR**:";
1036 std::cerr << std::endl << ">> histoNo found = " << histoNo[i] << ", which is NOT present in the data file!?!?";
1037 std::cerr << std::endl << ">> Will quit :-(";
1038 std::cerr << std::endl;
1039 histoNo.clear();
1040 return false;
1041 }
1042 }
1043
1044 // keep the time resolution in (us)
1045 fTimeResolution = runData->GetTimeResolution()/1.0e3;
1046 std::cout.precision(10);
1047 std::cout << std::endl << ">> PRunSingleHisto::PrepareData(): time resolution=" << std::fixed << runData->GetTimeResolution() << "(ns)" << std::endl;
1048
1049 // get all the proper t0's and addt0's for the current RUN block
1050 if (!GetProperT0(runData, globalBlock, histoNo)) {
1051 return false;
1052 }
1053
1054 // keep the histo of each group at this point (addruns handled below)
1055 std::vector<PDoubleVector> forward;
1056 forward.resize(histoNo.size()); // resize to number of groups
1057 for (UInt_t i=0; i<histoNo.size(); i++) {
1058 forward[i].resize(runData->GetDataBin(histoNo[i])->size());
1059 forward[i] = *runData->GetDataBin(histoNo[i]);
1060 }
1061
1062 // check if a dead time correction has to be done
1063 // this will be done automatically in the function itself, which also
1064 // checks in the global and run section
1065 DeadTimeCorrection(forward, histoNo);
1066
1067 // check if there are runs to be added to the current one
1068 if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present
1069 PRawRunData *addRunData;
1070 std::vector<PDoubleVector> addForward;
1071 for (UInt_t i=1; i<fRunInfo->GetRunNameSize(); i++) { // loop over all ADDRUN's
1072
1073 // get run to be added to the main one
1074 addRunData = fRawData->GetRunData(*fRunInfo->GetRunName(i));
1075 if (addRunData == nullptr) { // couldn't get run
1076 std::cerr << std::endl << ">> PRunSingleHisto::PrepareData(): **ERROR** Couldn't get addrun " << fRunInfo->GetRunName(i)->Data() << "!";
1077 std::cerr << std::endl;
1078 return false;
1079 }
1080
1081 addForward.clear();
1082 addForward.resize(histoNo.size()); // resize to number of groups
1083 for (UInt_t j=0; j<histoNo.size(); j++) {
1084 addForward[j].resize(addRunData->GetDataBin(histoNo[j])->size());
1085 addForward[j] = *addRunData->GetDataBin(histoNo[j]);
1086 }
1087 DeadTimeCorrection(addForward, histoNo);
1088
1089 // add forward run
1090 UInt_t addRunSize;
1091 for (UInt_t k=0; k<histoNo.size(); k++) { // fill each group
1092 addRunSize = addForward[k].size();
1093 for (UInt_t j=0; j<addRunSize; j++) { // loop over the bin indices
1094 // make sure that the index stays in the proper range
1095 if ((static_cast<Int_t>(j)+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]) >= 0) &&
1096 (j+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]) < addRunSize)) {
1097 forward[k][j] += addForward[k][j+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k])];
1098 }
1099 }
1100 }
1101 }
1102 }
1103
1104 // set forward histo data of the first group
1105 fForward.resize(forward[0].size());
1106 for (UInt_t i=0; i<fForward.size(); i++) {
1107 fForward[i] = forward[0][i];
1108 }
1109
1110 // group histograms, add all the remaining forward histograms of the group
1111 for (UInt_t i=1; i<histoNo.size(); i++) { // loop over the groupings
1112 for (UInt_t j=0; j<runData->GetDataBin(histoNo[i])->size(); j++) { // loop over the bin indices
1113 // make sure that the index stays within proper range
1114 if ((static_cast<Int_t>(j)+fT0s[i]-fT0s[0] >= 0) && (j+fT0s[i]-fT0s[0] < runData->GetDataBin(histoNo[i])->size())) {
1115 fForward[j] += forward[i][j+static_cast<Int_t>(fT0s[i])-static_cast<Int_t>(fT0s[0])];
1116 }
1117 }
1118 }
1119
1120 // get the data range (fgb/lgb) for the current RUN block
1121 if (!GetProperDataRange()) {
1122 return false;
1123 }
1124
1125 // get the fit range for the current RUN block
1126 GetProperFitRange(globalBlock);
1127
1128 // get the lifetimecorrection flag
1129 Bool_t lifetimecorrection = false;
1130 PMsrPlotList *plot = fMsrInfo->GetMsrPlotList();
1131 lifetimecorrection = plot->at(0).fLifeTimeCorrection;
1132
1133 // do the more fit/view specific stuff
1134 if (fHandleTag == kFit)
1135 success = PrepareFitData(runData, histoNo[0]);
1136 else if ((fHandleTag == kView) && !lifetimecorrection)
1137 success = PrepareRawViewData(runData, histoNo[0]);
1138 else if ((fHandleTag == kView) && lifetimecorrection)
1139 success = PrepareViewData(runData, histoNo[0]);
1140 else
1141 success = false;
1142
1143 // cleanup
1144 histoNo.clear();
1145
1146 return success;
1147}
1148
1149//--------------------------------------------------------------------------
1150// PrepareFitData (protected)
1151//--------------------------------------------------------------------------
1203Bool_t PRunSingleHisto::PrepareFitData(PRawRunData* runData, const UInt_t histoNo)
1204{
1205 if (fMsrInfo->EstimateN0()) {
1206 EstimateN0();
1207 }
1208
1209 // transform raw histo data. This is done the following way (for details see the manual):
1210 // for the single histo fit, just the rebinned raw data are copied
1211
1212 // check how the background shall be handled
1213 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg shall **NOT** be fitted
1214 // subtract background from histogramms ------------------------------------------
1215 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given
1216 if (fRunInfo->GetBkgRange(0) >= 0) {
1217 if (!EstimateBkg(histoNo))
1218 return false;
1219 } else { // no background given to do the job, try estimate
1220 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.1), 0);
1221 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.6), 1);
1222 std::cerr << std::endl << ">> PRunSingleHisto::PrepareFitData(): **WARNING** Neither fix background nor background bins are given!";
1223 std::cerr << std::endl << ">> Will try the following: bkg start = " << fRunInfo->GetBkgRange(0) << ", bkg end = " << fRunInfo->GetBkgRange(1);
1224 std::cerr << std::endl << ">> NO WARRANTY THAT THIS MAKES ANY SENSE! Better check ...";
1225 std::cerr << std::endl;
1226 if (!EstimateBkg(histoNo))
1227 return false;
1228 }
1229 } else { // fixed background given
1230 for (UInt_t i=0; i<fForward.size(); i++) {
1231 fForward[i] -= fRunInfo->GetBkgFix(0);
1232 }
1233 }
1234 }
1235
1236 // everything looks fine, hence fill data set
1237 Int_t t0 = static_cast<Int_t>(fT0s[0]);
1238 Double_t value = 0.0;
1239 Double_t normalizer = 1.0;
1240 // in order that after rebinning the fit does not need to be redone (important for plots)
1241 // the value is normalize to per 1 nsec if scaling is whished
1242 if (fScaleN0AndBkg)
1243 normalizer = fPacking * (fTimeResolution * 1.0e3); // fTimeResolution us->ns
1244 // data start at data_start-t0
1245 // time shifted so that packing is included correctly, i.e. t0 == t0 after packing
1246 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(fGoodBins[0])-0.5) + static_cast<Double_t>(fPacking)/2.0 - static_cast<Double_t>(t0)));
1247 fData.SetDataTimeStep(fTimeResolution*fPacking);
1248 for (Int_t i=fGoodBins[0]; i<fGoodBins[1]; i++) {
1249 if (fPacking == 1) {
1250 value = fForward[i];
1251 value /= normalizer;
1252 fData.AppendValue(value);
1253 if (value == 0.0)
1254 fData.AppendErrorValue(1.0/normalizer);
1255 else
1256 fData.AppendErrorValue(TMath::Sqrt(value));
1257 } else { // packed data, i.e. fPacking > 1
1258 if (((i-fGoodBins[0]) % fPacking == 0) && (i != fGoodBins[0])) { // fill data
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 // reset values
1266 value = 0.0;
1267 }
1268 value += fForward[i];
1269 }
1270 }
1271
1273
1274 return true;
1275}
1276
1277//--------------------------------------------------------------------------
1278// PrepareRawViewData (protected)
1279//--------------------------------------------------------------------------
1296Bool_t PRunSingleHisto::PrepareRawViewData(PRawRunData* runData, const UInt_t histoNo)
1297{
1298 // check if view_packing is wished
1299 Int_t packing = fPacking;
1300 if (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0) {
1301 packing = fMsrInfo->GetMsrPlotList()->at(0).fViewPacking;
1302 }
1303
1304 // calculate necessary norms
1305 Double_t dataNorm = 1.0, theoryNorm = 1.0;
1306 if (fScaleN0AndBkg) {
1307 dataNorm = 1.0/ (packing * (fTimeResolution * 1.0e3)); // fTimeResolution us->ns
1308 } else if (!fScaleN0AndBkg && (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0)) {
1309 theoryNorm = static_cast<Double_t>(fMsrInfo->GetMsrPlotList()->at(0).fViewPacking)/static_cast<Double_t>(fPacking);
1310 }
1311
1312 // raw data, since PMusrCanvas is doing ranging etc.
1313 // start = the first bin which is a multiple of packing backward from first good data bin
1314 Int_t start = fGoodBins[0] - (fGoodBins[0]/packing)*packing;
1315 // end = last bin starting from start which is a multiple of packing and still within the data
1316 Int_t end = start + ((fForward.size()-start)/packing)*packing;
1317 // check if data range has been provided, and if not try to estimate them
1318 if (start < 0) {
1319 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
1320 start = (static_cast<Int_t>(fT0s[0])+offset) - ((static_cast<Int_t>(fT0s[0])+offset)/packing)*packing;
1321 end = start + ((fForward.size()-start)/packing)*packing;
1322 std::cerr << std::endl << ">> PRunSingleHisto::PrepareRawViewData(): **WARNING** data range was not provided, will try data range start = " << start << ".";
1323 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1324 std::cerr << std::endl;
1325 }
1326 // check if start, end, and t0 make any sense
1327 // 1st check if start and end are in proper order
1328 if (end < start) { // need to swap them
1329 Int_t keep = end;
1330 end = start;
1331 start = keep;
1332 }
1333 // 2nd check if start is within proper bounds
1334 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
1335 std::cerr << std::endl << ">> PRunSingleHisto::PrepareRawViewData(): **ERROR** start data bin doesn't make any sense!";
1336 std::cerr << std::endl;
1337 return false;
1338 }
1339 // 3rd check if end is within proper bounds
1340 if ((end < 0) || (end > static_cast<Int_t>(fForward.size()))) {
1341 std::cerr << std::endl << ">> PRunSingleHisto::PrepareRawViewData(): **ERROR** end data bin doesn't make any sense!";
1342 std::cerr << std::endl;
1343 return false;
1344 }
1345
1346 // everything looks fine, hence fill data set
1347 Int_t t0 = static_cast<Int_t>(fT0s[0]);
1348 Double_t value = 0.0;
1349 // data start time = (binStart - 0.5) + pack/2 - t0, with pack and binStart used as double
1350 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(start)-0.5) + static_cast<Double_t>(packing)/2.0 - static_cast<Double_t>(t0)));
1351 fData.SetDataTimeStep(fTimeResolution*packing);
1352
1353 for (Int_t i=start; i<end; i++) {
1354 if (((i-start) % packing == 0) && (i != start)) { // fill data
1355 value *= dataNorm;
1356 fData.AppendValue(value);
1357 if (value == 0.0)
1358 fData.AppendErrorValue(1.0);
1359 else
1360 fData.AppendErrorValue(TMath::Sqrt(value*dataNorm));
1361 // reset values
1362 value = 0.0;
1363 }
1364 value += fForward[i];
1365 }
1366
1368
1369 // fill theory vector for kView
1370 // feed the parameter vector
1371 std::vector<Double_t> par;
1372 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
1373 for (UInt_t i=0; i<paramList->size(); i++)
1374 par.push_back((*paramList)[i].fValue);
1375
1376 // calculate asymmetry
1377 Double_t N0;
1378 // check if norm is a parameter or a function
1379 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
1380 N0 = par[fRunInfo->GetNormParamNo()-1];
1381 } else { // norm is a function
1382 // get function number
1383 UInt_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
1384 // evaluate function
1385 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
1386 }
1387 N0 *= theoryNorm;
1388
1389 // get tau
1390 Double_t tau;
1391 if (fRunInfo->GetLifetimeParamNo() != -1)
1392 tau = par[fRunInfo->GetLifetimeParamNo()-1];
1393 else
1394 tau = PMUON_LIFETIME;
1395
1396 // get background
1397 Double_t bkg;
1398 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
1399 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
1400 if (fRunInfo->GetBkgRange(0) >= 0) { // background range given
1401 if (!EstimateBkg(histoNo))
1402 return false;
1403 } else { // no background given to do the job, try estimate
1404 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.1), 0);
1405 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.6), 1);
1406 std::cerr << std::endl << ">> PRunSingleHisto::PrepareRawViewData(): **WARNING** Neither fix background nor background bins are given!";
1407 std::cerr << std::endl << ">> Will try the following: bkg start = " << fRunInfo->GetBkgRange(0) << ", bkg end = " << fRunInfo->GetBkgRange(1);
1408 std::cerr << std::endl << ">> NO WARRANTY THAT THIS MAKES ANY SENSE! Better check ...";
1409 std::cerr << std::endl;
1410 if (!EstimateBkg(histoNo))
1411 return false;
1412 }
1413 bkg = fBackground;
1414 } else { // fixed bkg given
1415 bkg = fRunInfo->GetBkgFix(0);
1416 }
1417 } else { // bkg fitted
1418 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
1419 }
1420 bkg *= theoryNorm;
1421
1422 // calculate functions
1423 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
1424 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
1425 }
1426
1427 // calculate theory
1428 UInt_t size = fForward.size();
1429 Int_t factor = 8; // 8 times more points for the theory (if fTheoAsData == false)
1430 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
1431 if (fTheoAsData) { // calculate theory only at the data points
1432 fData.SetTheoryTimeStep(fData.GetDataTimeStep());
1433 } else {
1434 // finer binning for the theory (8 times as many points = factor)
1435 size *= factor;
1436 fData.SetTheoryTimeStep(fData.GetDataTimeStep()/(Double_t)factor);
1437 }
1438
1439 Double_t time;
1440 Double_t theoryValue;
1441 for (UInt_t i=0; i<size; i++) {
1442 time = fData.GetTheoryTimeStart() + i*fData.GetTheoryTimeStep();
1443 theoryValue = fTheory->Func(time, par, fFuncValues);
1444 if (fabs(theoryValue) > 1.0e10) { // dirty hack needs to be fixed!!
1445 theoryValue = 0.0;
1446 }
1447 fData.AppendTheoryValue(N0*TMath::Exp(-time/tau)*(1.0+theoryValue)+bkg);
1448 }
1449
1450 // clean up
1451 par.clear();
1452
1453 return true;
1454}
1455
1456//--------------------------------------------------------------------------
1457// PrepareViewData (protected)
1458//--------------------------------------------------------------------------
1485Bool_t PRunSingleHisto::PrepareViewData(PRawRunData* runData, const UInt_t histoNo)
1486{
1487 // check if view_packing is wished. This is a global option for all PLOT blocks!
1488 Int_t packing = fPacking;
1489 if (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0) {
1490 packing = fMsrInfo->GetMsrPlotList()->at(0).fViewPacking;
1491 }
1492 // check if rrf_packing is present. This is a global option for all PLOT blocks, since operated on a single set of data.
1493 if (fMsrInfo->GetMsrPlotList()->at(0).fRRFPacking > 0) {
1494 packing = fMsrInfo->GetMsrPlotList()->at(0).fRRFPacking;
1495 }
1496
1497 // calculate necessary norms
1498 Double_t dataNorm = 1.0, theoryNorm = 1.0;
1499 if (fScaleN0AndBkg) {
1500 dataNorm = 1.0/ (packing * (fTimeResolution * 1.0e3)); // fTimeResolution us->ns
1501 } else if (!fScaleN0AndBkg && (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0)) {
1502 theoryNorm = static_cast<Double_t>(fMsrInfo->GetMsrPlotList()->at(0).fViewPacking)/static_cast<Double_t>(fPacking);
1503 }
1504
1505 // transform raw histo data. This is done the following way (for details see the manual):
1506 // for the single histo fit, just the rebinned raw data are copied
1507 // first get start data, end data, and t0
1508 Int_t t0 = static_cast<Int_t>(fT0s[0]);
1509
1510 // start = the first bin which is a multiple of packing backward from first good data bin
1511 Int_t start = fGoodBins[0] - (fGoodBins[0]/packing)*packing;
1512 // end = last bin starting from start which is a multiple of packing and still within the data
1513 Int_t end = start + ((fForward.size()-start)/packing)*packing;
1514
1515 // check if data range has been provided, and if not try to estimate them
1516 if (start < 0) {
1517 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
1518 start = (static_cast<Int_t>(fT0s[0])+offset) - ((static_cast<Int_t>(fT0s[0])+offset)/packing)*packing;
1519 end = start + ((fForward.size()-start)/packing)*packing;
1520 std::cerr << std::endl << ">> PRunSingleHisto::PrepareViewData(): **WARNING** data range was not provided, will try data range start = " << start << ".";
1521 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1522 std::cerr << std::endl;
1523 }
1524
1525 // check if start, end, and t0 make any sense
1526 // 1st check if start and end are in proper order
1527 if (end < start) { // need to swap them
1528 Int_t keep = end;
1529 end = start;
1530 start = keep;
1531 }
1532 // 2nd check if start is within proper bounds
1533 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
1534 std::cerr << std::endl << ">> PRunSingleHisto::PrepareViewData(): **ERROR** start data bin doesn't make any sense!";
1535 std::cerr << std::endl;
1536 return false;
1537 }
1538 // 3rd check if end is within proper bounds
1539 if ((end < 0) || (end > static_cast<Int_t>(fForward.size()))) {
1540 std::cerr << std::endl << ">> PRunSingleHisto::PrepareViewData(): **ERROR** end data bin doesn't make any sense!";
1541 std::cerr << std::endl;
1542 return false;
1543 }
1544
1545 // everything looks fine, hence fill data set
1546
1547 // feed the parameter vector
1548 std::vector<Double_t> par;
1549 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
1550 for (UInt_t i=0; i<paramList->size(); i++)
1551 par.push_back((*paramList)[i].fValue);
1552
1553 // calculate asymmetry
1554 Double_t N0;
1555 // check if norm is a parameter or a function
1556 if (fRunInfo->GetNormParamNo() < MSR_PARAM_FUN_OFFSET) { // norm is a parameter
1557 N0 = par[fRunInfo->GetNormParamNo()-1];
1558 } else { // norm is a function
1559 // get function number
1560 UInt_t funNo = fRunInfo->GetNormParamNo()-MSR_PARAM_FUN_OFFSET;
1561 // evaluate function
1562 N0 = fMsrInfo->EvalFunc(funNo, *fRunInfo->GetMap(), par, fMetaData);
1563 }
1564 N0 *= theoryNorm;
1565
1566 // get tau
1567 Double_t tau;
1568 if (fRunInfo->GetLifetimeParamNo() != -1)
1569 tau = par[fRunInfo->GetLifetimeParamNo()-1];
1570 else
1571 tau = PMUON_LIFETIME;
1572
1573 // get background
1574 Double_t bkg;
1575 if (fRunInfo->GetBkgFitParamNo() == -1) { // bkg not fitted
1576 if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given (background interval)
1577 if (fRunInfo->GetBkgRange(0) >= 0) { // background range given
1578 if (!EstimateBkg(histoNo))
1579 return false;
1580 } else { // no background given to do the job, try estimate
1581 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.1), 0);
1582 fRunInfo->SetBkgRange(static_cast<Int_t>(fT0s[0]*0.6), 1);
1583 std::cerr << std::endl << ">> PRunSingleHisto::PrepareViewData(): **WARNING** Neither fix background nor background bins are given!";
1584 std::cerr << std::endl << ">> Will try the following: bkg start = " << fRunInfo->GetBkgRange(0) << ", bkg end = " << fRunInfo->GetBkgRange(1);
1585 std::cerr << std::endl << ">> NO WARRANTY THAT THIS MAKES ANY SENSE! Better check ...";
1586 std::cerr << std::endl;
1587 if (!EstimateBkg(histoNo))
1588 return false;
1589 }
1590 bkg = fBackground;
1591 } else { // fixed bkg given
1592 bkg = fRunInfo->GetBkgFix(0);
1593 }
1594 } else { // bkg fitted
1595 bkg = par[fRunInfo->GetBkgFitParamNo()-1];
1596 }
1597 bkg *= theoryNorm;
1598
1599 Double_t value = 0.0;
1600 Double_t expval = 0.0;
1601 Double_t rrf_val = 0.0;
1602 Double_t time = 0.0;
1603
1604 // data start time = (binStart - 0.5) + pack/2 - t0, with pack and binStart used as double
1605 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(start)-0.5) + static_cast<Double_t>(packing)/2.0 - static_cast<Double_t>(t0)));
1606 fData.SetDataTimeStep(fTimeResolution*packing);
1607
1608 // data is always normalized to (per nsec!!)
1609 Double_t gammaRRF = 0.0, wRRF = 0.0, phaseRRF = 0.0;
1610 if (fMsrInfo->GetMsrPlotList()->at(0).fRRFFreq == 0.0) { // normal Data representation
1611 for (Int_t i=start; i<end; i++) {
1612 if (((i-start) % packing == 0) && (i != start)) { // fill data
1613 value *= dataNorm;
1614 // since the packing counter is already at the end of the bin, the time needs be shifted back by pack*time_resolution
1615 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;
1616 expval = TMath::Exp(+time/tau)/N0;
1617 fData.AppendValue(-1.0+expval*(value-bkg));
1618 fData.AppendErrorValue(expval*TMath::Sqrt(value*dataNorm));
1619 value = 0.0;
1620 }
1621 value += fForward[i];
1622 }
1623 } else { // RRF representation
1624 // check which units shall be used
1625 switch (fMsrInfo->GetMsrPlotList()->at(0).fRRFUnit) {
1626 case RRF_UNIT_kHz:
1627 gammaRRF = TMath::TwoPi()*1.0e-3;
1628 break;
1629 case RRF_UNIT_MHz:
1630 gammaRRF = TMath::TwoPi();
1631 break;
1632 case RRF_UNIT_Mcs:
1633 gammaRRF = 1.0;
1634 break;
1635 case RRF_UNIT_G:
1636 gammaRRF = GAMMA_BAR_MUON*TMath::TwoPi();
1637 break;
1638 case RRF_UNIT_T:
1639 gammaRRF = GAMMA_BAR_MUON*TMath::TwoPi()*1.0e4;
1640 break;
1641 default:
1642 gammaRRF = TMath::TwoPi();
1643 break;
1644 }
1645 wRRF = gammaRRF * fMsrInfo->GetMsrPlotList()->at(0).fRRFFreq;
1646 phaseRRF = fMsrInfo->GetMsrPlotList()->at(0).fRRFPhase / 180.0 * TMath::Pi();
1647
1648 Double_t error = 0.0;
1649 for (Int_t i=start; i<end; i++) {
1650 if (((i-start) % packing == 0) && (i != start)) { // fill data
1651 fData.AppendValue(2.0*value/packing); // factor 2 needed because cos(a)cos(b) = 1/2(cos(a+b)+cos(a-b))
1652 fData.AppendErrorValue(expval*TMath::Sqrt(error/packing));
1653 value = 0.0;
1654 error = 0.0;
1655 }
1656 time = (static_cast<Double_t>(i)-t0)*fTimeResolution;
1657 expval = TMath::Exp(+time/tau)/N0;
1658 rrf_val = (-1.0+expval*(fForward[i]/(fTimeResolution*1.0e3)-bkg))*TMath::Cos(wRRF * time + phaseRRF);
1659 value += rrf_val;
1660 error += fForward[i]*dataNorm;
1661 }
1662 }
1663
1665
1666 // calculate functions
1667 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
1668 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
1669 }
1670
1671 // calculate theory
1672 Double_t theoryValue;
1673 UInt_t size = fForward.size()/packing;
1674 const Int_t factor = 8; // 8 times more points for the theory (if fTheoAsData == false)
1675 UInt_t rebinRRF = 0;
1676
1677 if (wRRF == 0) { // no RRF
1678 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
1679 if (fTheoAsData) { // calculate theory only at the data points
1680 fData.SetTheoryTimeStep(fData.GetDataTimeStep());
1681 } else {
1682 // finer binning for the theory (8 times as many points = factor)
1683 size *= factor;
1684 fData.SetTheoryTimeStep(fData.GetDataTimeStep()/(Double_t)factor);
1685 }
1686 } else { // RRF
1687 rebinRRF = static_cast<UInt_t>((TMath::Pi()/2.0/wRRF)/fTimeResolution); // RRF time resolution / data time resolution
1688 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
1689 fData.SetTheoryTimeStep(TMath::Pi()/2.0/wRRF/rebinRRF); // = theory time resolution as close as possible to the data time resolution compatible with wRRF
1690 }
1691
1692 for (UInt_t i=0; i<size; i++) {
1693 time = fData.GetTheoryTimeStart() + static_cast<Double_t>(i)*fData.GetTheoryTimeStep();
1694 theoryValue = fTheory->Func(time, par, fFuncValues);
1695 if (wRRF != 0.0) {
1696 theoryValue *= 2.0*TMath::Cos(wRRF * time + phaseRRF);
1697 }
1698 if (fabs(theoryValue) > 10.0) { // dirty hack needs to be fixed!!
1699 theoryValue = 0.0;
1700 }
1701 fData.AppendTheoryValue(theoryValue);
1702 }
1703
1704 // if RRF filter the theory with a FIR Kaiser low pass filter
1705 if (wRRF != 0.0) {
1706 // rebin theory to the RRF frequency
1707 if (rebinRRF != 0) {
1708 Double_t dval = 0.0;
1709 PDoubleVector theo;
1710 for (UInt_t i=0; i<fData.GetTheory()->size(); i++) {
1711 if ((i % rebinRRF == 0) && (i != 0)) {
1712 theo.push_back(dval/rebinRRF);
1713 dval = 0.0;
1714 }
1715 dval += fData.GetTheory()->at(i);
1716 }
1717 fData.SetTheoryTimeStart(fData.GetTheoryTimeStart()+static_cast<Double_t>(rebinRRF-1)*fData.GetTheoryTimeStep()/2.0);
1718 fData.SetTheoryTimeStep(rebinRRF*fData.GetTheoryTimeStep());
1719 fData.ReplaceTheory(theo);
1720 theo.clear();
1721 }
1722
1723 // filter theory
1724 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)
1725 FilterTheo();
1726 }
1727
1728 // clean up
1729 par.clear();
1730
1731 return true;
1732}
1733
1734//--------------------------------------------------------------------------
1735// GetProperT0 (private)
1736//--------------------------------------------------------------------------
1788{
1789 // feed all T0's
1790 // first init T0's, T0's are stored as (forward T0, backward T0, etc.)
1791 fT0s.clear();
1792 fT0s.resize(histoNo.size());
1793 for (UInt_t i=0; i<fT0s.size(); i++) {
1794 fT0s[i] = -1.0;
1795 }
1796
1797 // fill in the T0's from the msr-file (if present)
1798 for (UInt_t i=0; i<fRunInfo->GetT0BinSize(); i++) {
1799 fT0s[i] = fRunInfo->GetT0Bin(i);
1800 }
1801
1802 // fill in the T0's from the GLOBAL block section (if present)
1803 for (UInt_t i=0; i<globalBlock->GetT0BinSize(); i++) {
1804 if (fT0s[i] == -1.0) { // i.e. not given in the RUN block section
1805 fT0s[i] = globalBlock->GetT0Bin(i);
1806 }
1807 }
1808
1809 // fill in the T0's from the data file, if not already present in the msr-file
1810 for (UInt_t i=0; i<histoNo.size(); i++) {
1811 if (fT0s[i] == -1.0) { // i.e. not present in the msr-file, try the data file
1812 if (runData->GetT0Bin(histoNo[i]) > 0.0) {
1813 fT0s[i] = runData->GetT0Bin(histoNo[i]);
1814 fRunInfo->SetT0Bin(fT0s[i], i); // keep value for the msr-file
1815 }
1816 }
1817 }
1818
1819 // 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
1820 for (UInt_t i=0; i<histoNo.size(); i++) {
1821 if (fT0s[i] == -1.0) { // i.e. not present in the msr-file and data file, use the estimated T0
1822 fT0s[i] = runData->GetT0BinEstimated(histoNo[i]);
1823 fRunInfo->SetT0Bin(fT0s[i], i); // keep value for the msr-file
1824
1825 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!";
1826 std::cerr << std::endl << ">> run: " << fRunInfo->GetRunName()->Data();
1827 std::cerr << std::endl << ">> will try the estimated one: forward t0 = " << runData->GetT0BinEstimated(histoNo[i]);
1828 std::cerr << std::endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!";
1829 std::cerr << std::endl;
1830 }
1831 }
1832
1833 // check if t0 is within proper bounds
1834 for (UInt_t i=0; i<fRunInfo->GetForwardHistoNoSize(); i++) {
1835 if ((fT0s[i] < 0.0) || (fT0s[i] > static_cast<Int_t>(runData->GetDataBin(histoNo[i])->size()))) {
1836 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **ERROR** t0 data bin (" << fT0s[i] << ") doesn't make any sense!";
1837 std::cerr << std::endl;
1838 return false;
1839 }
1840 }
1841
1842 // check if there are runs to be added to the current one. If yes keep the needed t0's
1843 if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present
1844 PRawRunData *addRunData;
1845 fAddT0s.resize(fRunInfo->GetRunNameSize()-1); // resize to the number of addruns
1846 for (UInt_t i=1; i<fRunInfo->GetRunNameSize(); i++) {
1847
1848 // get run to be added to the main one
1849 addRunData = fRawData->GetRunData(*fRunInfo->GetRunName(i));
1850 if (addRunData == nullptr) { // couldn't get run
1851 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **ERROR** Couldn't get addrun " << fRunInfo->GetRunName(i)->Data() << "!";
1852 std::cerr << std::endl;
1853 return false;
1854 }
1855
1856 // feed all T0's
1857 // first init T0's, T0's are stored as (forward T0, backward T0, etc.)
1858 fAddT0s[i-1].resize(histoNo.size());
1859 for (UInt_t j=0; j<fAddT0s[i-1].size(); j++) {
1860 fAddT0s[i-1][j] = -1.0;
1861 }
1862
1863 // fill in the T0's from the msr-file (if present)
1864 for (UInt_t j=0; j<fRunInfo->GetT0BinSize(); j++) {
1865 fAddT0s[i-1][j] = fRunInfo->GetAddT0Bin(i-1,j); // addRunIdx starts at 0
1866 }
1867
1868 // fill in the T0's from the data file, if not already present in the msr-file
1869 for (UInt_t j=0; j<histoNo.size(); j++) {
1870 if (fAddT0s[i-1][j] == -1.0) // i.e. not present in the msr-file, try the data file
1871 if (addRunData->GetT0Bin(histoNo[j]) > 0.0) {
1872 fAddT0s[i-1][j] = addRunData->GetT0Bin(histoNo[j]);
1873 fRunInfo->SetAddT0Bin(fAddT0s[i-1][j], i-1, j); // keep value for the msr-file
1874 }
1875 }
1876
1877 // 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
1878 for (UInt_t j=0; j<histoNo.size(); j++) {
1879 if (fAddT0s[i-1][j] == -1.0) { // i.e. not present in the msr-file and data file, use the estimated T0
1880 fAddT0s[i-1][j] = addRunData->GetT0BinEstimated(histoNo[j]);
1881 fRunInfo->SetAddT0Bin(fAddT0s[i-1][j], i-1, j); // keep value for the msr-file
1882
1883 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!";
1884 std::cerr << std::endl << ">> run: " << fRunInfo->GetRunName(i)->Data();
1885 std::cerr << std::endl << ">> will try the estimated one: forward t0 = " << addRunData->GetT0BinEstimated(histoNo[j]);
1886 std::cerr << std::endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!";
1887 std::cerr << std::endl;
1888 }
1889 }
1890
1891 // check if t0 is within proper bounds
1892 for (UInt_t j=0; j<fRunInfo->GetForwardHistoNoSize(); j++) {
1893 if ((fAddT0s[i-1][j] < 0.0) || (fAddT0s[i-1][j] > static_cast<Int_t>(addRunData->GetDataBin(histoNo[j])->size()))) {
1894 std::cerr << std::endl << ">> PRunSingleHisto::GetProperT0(): **ERROR** addt0 data bin (" << fAddT0s[i-1][j] << ") doesn't make any sense!";
1895 std::cerr << std::endl;
1896 return false;
1897 }
1898 }
1899 }
1900 }
1901
1902 return true;
1903}
1904
1905//--------------------------------------------------------------------------
1906// GetProperDataRange (private)
1907//--------------------------------------------------------------------------
1953{
1954 // get start/end data
1955 Int_t start;
1956 Int_t end;
1957 start = fRunInfo->GetDataRange(0);
1958 end = fRunInfo->GetDataRange(1);
1959
1960 // check if data range has been given in the RUN block, if not try to get it from the GLOBAL block
1961 if (start < 0) {
1962 start = fMsrInfo->GetMsrGlobal()->GetDataRange(0);
1963 }
1964 if (end < 0) {
1965 end = fMsrInfo->GetMsrGlobal()->GetDataRange(1);
1966 }
1967
1968 // check if data range has been provided, and if not try to estimate them
1969 if (start < 0) {
1970 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
1971 start = static_cast<Int_t>(fT0s[0])+offset;
1972 fRunInfo->SetDataRange(start, 0);
1973 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **WARNING** data range was not provided, will try data range start = t0+" << offset << "(=10ns) = " << start << ".";
1974 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1975 std::cerr << std::endl;
1976 }
1977 if (end < 0) {
1978 end = fForward.size();
1979 fRunInfo->SetDataRange(end, 1);
1980 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **WARNING** data range was not provided, will try data range end = " << end << ".";
1981 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1982 std::cerr << std::endl;
1983 }
1984
1985 // check if start and end make any sense
1986 // 1st check if start and end are in proper order
1987 if (end < start) { // need to swap them
1988 Int_t keep = end;
1989 end = start;
1990 start = keep;
1991 }
1992 // 2nd check if start is within proper bounds
1993 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
1994 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **ERROR** start data bin (" << start << ") doesn't make any sense!";
1995 std::cerr << std::endl;
1996 return false;
1997 }
1998 // 3rd check if end is within proper bounds
1999 if (end < 0) {
2000 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **ERROR** end data bin (" << end << ") doesn't make any sense!";
2001 std::cerr << std::endl;
2002 return false;
2003 }
2004 if (end > static_cast<Int_t>(fForward.size())) {
2005 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange(): **WARNING** end data bin (" << end << ") > histo length (" << fForward.size() << ").";
2006 std::cerr << std::endl << ">> Will set end = (histo length - 1). Consider to change it in the msr-file." << std::endl;
2007 std::cerr << std::endl;
2008 end = static_cast<Int_t>(fForward.size())-1;
2009 }
2010
2011 // keep good bins for potential later use
2012 fGoodBins[0] = start;
2013 fGoodBins[1] = end;
2014
2015 // make sure that fGoodBins are in proper range for fForward
2016 if (fGoodBins[0] < 0)
2017 fGoodBins[0]=0;
2018 if (fGoodBins[1] > fForward.size()) {
2019 std::cerr << std::endl << ">> PRunSingleHisto::GetProperDataRange **WARNING** needed to shift forward lgb,";
2020 std::cerr << std::endl << ">> from " << fGoodBins[1] << " to " << fForward.size()-1 << std::endl;
2021 fGoodBins[1]=fForward.size()-1;
2022 }
2023
2024 return true;
2025}
2026
2027//--------------------------------------------------------------------------
2028// GetProperFitRange (private)
2029//--------------------------------------------------------------------------
2087{
2088 // set fit start/end time; first check RUN Block
2089 fFitStartTime = fRunInfo->GetFitRange(0);
2090 fFitEndTime = fRunInfo->GetFitRange(1);
2091 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
2092 if (fRunInfo->IsFitRangeInBin()) {
2093 fFitStartTime = (fGoodBins[0] + fRunInfo->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
2094 fFitEndTime = (fGoodBins[1] - fRunInfo->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
2095 // write these times back into the data structure. This way it is available when writting the log-file
2096 fRunInfo->SetFitRange(fFitStartTime, 0);
2097 fRunInfo->SetFitRange(fFitEndTime, 1);
2098 }
2099 if (fFitStartTime == PMUSR_UNDEFINED) { // fit start/end NOT found in the RUN block, check GLOBAL block
2100 fFitStartTime = globalBlock->GetFitRange(0);
2101 fFitEndTime = globalBlock->GetFitRange(1);
2102 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
2103 if (globalBlock->IsFitRangeInBin()) {
2104 fFitStartTime = (fGoodBins[0] + globalBlock->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
2105 fFitEndTime = (fGoodBins[1] - globalBlock->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
2106 // write these times back into the data structure. This way it is available when writting the log-file
2107 globalBlock->SetFitRange(fFitStartTime, 0);
2108 globalBlock->SetFitRange(fFitEndTime, 1);
2109 }
2110 }
2112 fFitStartTime = (fGoodBins[0] - fT0s[0]) * fTimeResolution; // (fgb-t0)*dt
2113 fFitEndTime = (fGoodBins[1] - fT0s[0]) * fTimeResolution; // (lgb-t0)*dt
2114 std::cerr << ">> PRunSingleHisto::GetProperFitRange(): **WARNING** Couldn't get fit start/end time!" << std::endl;
2115 std::cerr << ">> Will set it to fgb/lgb which given in time is: " << fFitStartTime << "..." << fFitEndTime << " (usec)" << std::endl;
2116 }
2117}
2118
2119//--------------------------------------------------------------------------
2120// EstimateN0 (private)
2121//--------------------------------------------------------------------------
2165{
2166 // check that 'norm' in the msr-file run block is indeed a parameter number.
2167 // in case it is a function, nothing will be done.
2168 UInt_t paramNo = fRunInfo->GetNormParamNo();
2169 if (paramNo > 10000) // i.e. fun or map
2170 return;
2171
2172 // get the parameters
2173 PMsrParamList *param = fMsrInfo->GetMsrParamList();
2174 assert(param);
2175
2176 if (paramNo > param->size()) {
2177 std::cerr << std::endl << ">> PRunSingleHisto::EstimateN0: **ERROR** found parameter number " << paramNo << ", which is larger than the number of parameters = " << param->size() << std::endl;
2178 return;
2179 }
2180
2181 // check if N0 is fixed. If this is the case, do NOT estimate N0
2182 if (param->at(paramNo-1).fStep == 0.0) // N0 parameter fixed
2183 return;
2184
2185
2186 // check that 'backgr.fit' in the msr-file run block is indeed a parameter number.
2187 // in case it is a function, nothing will be done.
2188 Int_t paramNoBkg = fRunInfo->GetBkgFitParamNo();
2189 Bool_t scaleBkg = true;
2190 Double_t bkg=0.0, errBkg=1.0;
2191 if ((paramNoBkg > 10000) || (paramNoBkg == -1)) { // i.e. fun or map
2192 scaleBkg = false;
2193 } else {
2194 if (paramNoBkg-1 < static_cast<Int_t>(param->size())) {
2195 bkg = param->at(paramNoBkg-1).fValue;
2196 errBkg = param->at(paramNoBkg-1).fStep;
2197 }
2198 }
2199
2200 // estimate N0
2201 Double_t dt = fTimeResolution;
2202 Double_t tau = PMUON_LIFETIME;
2203
2204 UInt_t t0 = static_cast<UInt_t>(round(fT0s[0]));
2205 Double_t dval = 0.0;
2206 Double_t nom = 0.0;
2207 Double_t denom = 0.0;
2208 Double_t xx = 0.0;
2209
2210 // calc nominator
2211 for (UInt_t i=t0; i<fForward.size(); i++) {
2212 xx = exp(-dt*static_cast<Double_t>(i-t0)/tau);
2213 nom += xx;
2214 }
2215
2216 // calc denominator
2217 for (UInt_t i=t0; i<fForward.size(); i++) {
2218 xx = exp(-dt*static_cast<Double_t>(i-t0)/tau);
2219 dval = fForward[i];
2220 if (dval > 0)
2221 denom += xx*xx/dval;
2222 }
2223 Double_t N0 = nom/denom;
2224
2225 if (fScaleN0AndBkg) {
2226 N0 /= fTimeResolution*1.0e3;
2227 } else {
2228 N0 *= fPacking;
2229 }
2230
2231 Double_t rescale = 1;
2232 if ((param->at(paramNo-1).fValue != 0.0) && scaleBkg) {
2233 rescale = N0 / param->at(paramNo-1).fValue;
2234 bkg *= rescale;
2235 errBkg *= rescale;
2236 }
2237
2238 std::cout << ">> PRunSingleHisto::EstimateN0: found N0=" << param->at(paramNo-1).fValue << ", will set it to N0=" << N0 << std::endl;
2239 if (scaleBkg)
2240 std::cout << ">> PRunSingleHisto::EstimateN0: found Bkg=" << param->at(paramNoBkg-1).fValue << ", will set it to Bkg=" << bkg << std::endl;
2241 fMsrInfo->SetMsrParamValue(paramNo-1, N0);
2242 fMsrInfo->SetMsrParamStep(paramNo-1, sqrt(fabs(N0)));
2243 if (scaleBkg) {
2244 fMsrInfo->SetMsrParamValue(paramNoBkg-1, bkg);
2245 fMsrInfo->SetMsrParamStep(paramNoBkg-1, errBkg);
2246 }
2247}
2248
2249//--------------------------------------------------------------------------
2250// EstimateBkg (private)
2251//--------------------------------------------------------------------------
2300Bool_t PRunSingleHisto::EstimateBkg(UInt_t histoNo)
2301{
2302 Double_t beamPeriod = 0.0;
2303
2304 // check if data are from PSI, RAL, or TRIUMF
2305 if (fRunInfo->GetInstitute()->Contains("psi"))
2306 beamPeriod = ACCEL_PERIOD_PSI;
2307 else if (fRunInfo->GetInstitute()->Contains("ral"))
2308 beamPeriod = ACCEL_PERIOD_RAL;
2309 else if (fRunInfo->GetInstitute()->Contains("triumf"))
2310 beamPeriod = ACCEL_PERIOD_TRIUMF;
2311 else
2312 beamPeriod = 0.0;
2313
2314 // check if start and end are in proper order
2315 Int_t start = fRunInfo->GetBkgRange(0);
2316 Int_t end = fRunInfo->GetBkgRange(1);
2317 if (end < start) {
2318 std::cout << std::endl << "PRunSingleHisto::EstimatBkg(): end = " << end << " > start = " << start << "! Will swap them!";
2319 Int_t keep = end;
2320 end = start;
2321 start = keep;
2322 }
2323
2324 // calculate proper background range
2325 if (beamPeriod != 0.0) {
2326 Double_t timeBkg = static_cast<Double_t>(end-start)*(fTimeResolution*fPacking); // length of the background intervall in time
2327 UInt_t fullCycles = static_cast<UInt_t>(timeBkg/beamPeriod); // how many proton beam cylces can be placed within the proposed background intervall
2328 // correct the end of the background intervall such that the background is as close as possible to a multiple of the proton cylce
2329 end = start + static_cast<UInt_t>((fullCycles*beamPeriod)/(fTimeResolution*fPacking));
2330 std::cout << std::endl << "PRunSingleHisto::EstimatBkg(): Background " << start << ", " << end;
2331 if (end == start)
2332 end = fRunInfo->GetBkgRange(1);
2333 }
2334
2335 // check if start is within histogram bounds
2336 if (start >= fForward.size()) {
2337 std::cerr << std::endl << ">> PRunSingleHisto::EstimatBkg(): **ERROR** background bin values out of bound!";
2338 std::cerr << std::endl << ">> histo lengths = " << fForward.size();
2339 std::cerr << std::endl << ">> background start = " << start;
2340 std::cerr << std::endl;
2341 return false;
2342 }
2343
2344 // check if end is within histogram bounds
2345 if (end >= fForward.size()) {
2346 std::cerr << std::endl << ">> PRunSingleHisto::EstimatBkg(): **ERROR** background bin values out of bound!";
2347 std::cerr << std::endl << ">> histo lengths = " << fForward.size();
2348 std::cerr << std::endl << ">> background end = " << end;
2349 std::cerr << std::endl;
2350 return false;
2351 }
2352
2353 // calculate background
2354 Double_t bkg = 0.0;
2355
2356 // forward
2357 for (UInt_t i=start; i<end; i++)
2358 bkg += fForward[i];
2359 bkg /= static_cast<Double_t>(end - start + 1);
2360
2361 if (fScaleN0AndBkg)
2362 fBackground = bkg / (fTimeResolution * 1e3); // keep background (per 1 nsec) for chisq, max.log.likelihood, fTimeResolution us->ns
2363 else
2364 fBackground = bkg * fPacking; // keep background (per bin)
2365
2366 fRunInfo->SetBkgEstimated(fBackground, 0);
2367
2368 return true;
2369}
2370
2371//--------------------------------------------------------------------------
2372// IsScaleN0AndBkg (private)
2373//--------------------------------------------------------------------------
2417{
2418 Bool_t willScale = true;
2419
2420 PMsrLines *cmd = fMsrInfo->GetMsrCommands();
2421 for (UInt_t i=0; i<cmd->size(); i++) {
2422 if (cmd->at(i).fLine.Contains("SCALE_N0_BKG", TString::kIgnoreCase)) {
2423 std::vector<std::string> tokens = PStringUtils::Split(cmd->at(i).fLine.Data(), " \t");
2424 if (tokens.size() != 2) {
2425 std::cerr << std::endl << ">> PRunSingleHisto::IsScaleN0AndBkg(): **WARNING** Found uncorrect 'SCALE_N0_BKG' command, will ignore it.";
2426 std::cerr << std::endl << ">> Allowed commands: SCALE_N0_BKG TRUE | FALSE" << std::endl;
2427 return willScale;
2428 }
2429 if (PStringUtils::IsEqualNoCase(tokens[1], "FALSE")) {
2430 willScale = false;
2431 }
2432 }
2433 }
2434
2435 return willScale;
2436}
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)