musrfit 1.10.0
PRunMuMinus.cpp
Go to the documentation of this file.
1/***************************************************************************
2
3 PRunMuMinus.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 <iostream>
39#include <string>
40#include <vector>
41
42#include <TString.h>
43
44#include "PStringUtils.h"
45#include "PRunMuMinus.h"
46
47//--------------------------------------------------------------------------
48// Constructor
49//--------------------------------------------------------------------------
66{
67 fNoOfFitBins = 0;
68 fPacking = -1;
69 fTheoAsData = false;
70
71 // the 2 following variables are need in case fit range is given in bins, and since
72 // the fit range can be changed in the command block, these variables need to be accessible
73 fGoodBins[0] = -1;
74 fGoodBins[1] = -1;
75
76 fStartTimeBin = -1;
77 fEndTimeBin = -1;
78
80}
81
82//--------------------------------------------------------------------------
83// Constructor
84//--------------------------------------------------------------------------
124PRunMuMinus::PRunMuMinus(PMsrHandler *msrInfo, PRunDataHandler *rawData, UInt_t runNo, EPMusrHandleTag tag, Bool_t theoAsData) :
125 PRunBase(msrInfo, rawData, runNo, tag), fTheoAsData(theoAsData)
126{
127 fNoOfFitBins = 0;
128
129 fPacking = fRunInfo->GetPacking();
130 if (fPacking == -1) { // i.e. packing is NOT given in the RUN-block, it must be given in the GLOBAL-block
131 fPacking = fMsrInfo->GetMsrGlobal()->GetPacking();
132 }
133 if (fPacking == -1) { // this should NOT happen, somethin is severely wrong
134 std::cerr << std::endl << ">> PRunMuMinus::PRunMuMinus: **SEVERE ERROR**: Couldn't find any packing information!";
135 std::cerr << std::endl << ">> This is very bad :-(, will quit ...";
136 std::cerr << std::endl;
137 fValid = false;
138 return;
139 }
140
141 // the 2 following variables are need in case fit range is given in bins, and since
142 // the fit range can be changed in the command block, these variables need to be accessible
143 fGoodBins[0] = -1;
144 fGoodBins[1] = -1;
145
146 fStartTimeBin = -1;
147 fEndTimeBin = -1;
148
149 if (!PrepareData()) {
150 std::cerr << std::endl << ">> PRunMuMinus::PRunMuMinus: **SEVERE ERROR**: Couldn't prepare data for fitting!";
151 std::cerr << std::endl << ">> This is very bad :-(, will quit ...";
152 std::cerr << std::endl;
153 fValid = false;
154 }
155}
156
157//--------------------------------------------------------------------------
158// Destructor
159//--------------------------------------------------------------------------
167{
168 fForward.clear();
169}
170
171//--------------------------------------------------------------------------
172// CalcChiSquare
173//--------------------------------------------------------------------------
208Double_t PRunMuMinus::CalcChiSquare(const std::vector<Double_t>& par)
209{
210 Double_t chisq = 0.0;
211 Double_t diff = 0.0;
212
213 // calculate functions
214 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
215 Int_t funcNo = fMsrInfo->GetFuncNo(i);
216 fFuncValues[i] = fMsrInfo->EvalFunc(funcNo, *fRunInfo->GetMap(), par, fMetaData);
217 }
218
219 // calculate chi square
220 Double_t time(1.0);
221 Int_t i;
222
223 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
224 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
225 // for a given set of parameters---which should be done outside of the parallelized loop.
226 // For all other functions it means a tiny and acceptable overhead.
227 time = fTheory->Func(time, par, fFuncValues);
228
229 #ifdef HAVE_GOMP
230 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
231 if (chunk < 10)
232 chunk = 10;
233 #pragma omp parallel for default(shared) private(i,time,diff) schedule(dynamic,chunk) reduction(+:chisq)
234 #endif
235 for (i=fStartTimeBin; i < fEndTimeBin; ++i) {
236 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
237 diff = fData.GetValue()->at(i) - fTheory->Func(time, par, fFuncValues);
238 chisq += diff*diff / (fData.GetError()->at(i)*fData.GetError()->at(i));
239 }
240
241 return chisq;
242}
243
244//--------------------------------------------------------------------------
245// CalcChiSquareExpected (public)
246//--------------------------------------------------------------------------
276Double_t PRunMuMinus::CalcChiSquareExpected(const std::vector<Double_t>& par)
277{
278 Double_t chisq = 0.0;
279 Double_t diff = 0.0;
280 Double_t theo = 0.0;
281
282 // calculate functions
283 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
284 Int_t funcNo = fMsrInfo->GetFuncNo(i);
285 fFuncValues[i] = fMsrInfo->EvalFunc(funcNo, *fRunInfo->GetMap(), par, fMetaData);
286 }
287
288 // calculate chi square
289 Double_t time(1.0);
290 Int_t i;
291
292 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
293 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
294 // for a given set of parameters---which should be done outside of the parallelized loop.
295 // For all other functions it means a tiny and acceptable overhead.
296 time = fTheory->Func(time, par, fFuncValues);
297
298 #ifdef HAVE_GOMP
299 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
300 if (chunk < 10)
301 chunk = 10;
302 #pragma omp parallel for default(shared) private(i,time,diff) schedule(dynamic,chunk) reduction(+:chisq)
303 #endif
304 for (i=fStartTimeBin; i < fEndTimeBin; ++i) {
305 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
306 theo = fTheory->Func(time, par, fFuncValues);
307 diff = fData.GetValue()->at(i) - theo;
308 chisq += diff*diff / theo;
309 }
310
311 return 0.0;
312}
313
314//--------------------------------------------------------------------------
315// CalcMaxLikelihood
316//--------------------------------------------------------------------------
361Double_t PRunMuMinus::CalcMaxLikelihood(const std::vector<Double_t>& par)
362{
363 Double_t mllh = 0.0; // maximum log likelihood assuming poisson distribution for the single bin
364
365 // calculate functions
366 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
367 Int_t funcNo = fMsrInfo->GetFuncNo(i);
368 fFuncValues[i] = fMsrInfo->EvalFunc(funcNo, *fRunInfo->GetMap(), par, fMetaData);
369 }
370
371 // calculate maximum log likelihood
372 Double_t theo;
373 Double_t data;
374 Double_t time(1.0);
375 Int_t i;
376
377 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
378 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
379 // for a given set of parameters---which should be done outside of the parallelized loop.
380 // For all other functions it means a tiny and acceptable overhead.
381 time = fTheory->Func(time, par, fFuncValues);
382
383 #ifdef HAVE_GOMP
384 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
385 if (chunk < 10)
386 chunk = 10;
387 #pragma omp parallel for default(shared) private(i,time,theo,data) schedule(dynamic,chunk) reduction(+:mllh)
388 #endif
389 for (i=fStartTimeBin; i < fEndTimeBin; ++i) {
390 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
391 // calculate theory for the given parameter set
392 theo = fTheory->Func(time, par, fFuncValues);
393
394 data = fData.GetValue()->at(i);
395
396 if (theo <= 0.0) {
397 std::cerr << ">> PRunMuMinus::CalcMaxLikelihood: **WARNING** NEGATIVE theory!!" << std::endl;
398 continue;
399 }
400
401 if (data > 1.0e-9) {
402 mllh += (theo-data) + data*log(data/theo);
403 } else {
404 mllh += (theo-data);
405 }
406 }
407
408 return 2.0*mllh;
409}
410
411//--------------------------------------------------------------------------
412// GetNoOfFitBins (public)
413//--------------------------------------------------------------------------
430{
432
433 return fNoOfFitBins;
434}
435
436//--------------------------------------------------------------------------
437// SetFitRangeBin (public)
438//--------------------------------------------------------------------------
450void PRunMuMinus::SetFitRangeBin(const TString fitRange)
451{
452 TString str;
453 Ssiz_t idx = -1;
454 Int_t offset = 0;
455
456 std::vector<std::string> tok = PStringUtils::Split(fitRange.Data(), " \t");
457
458 if (tok.size() == 3) { // structure FIT_RANGE fgb+n0 lgb-n1
459 // handle fgb+n0 entry
460 str = tok[1];
461 // check if there is an offset present
462 idx = str.First("+");
463 if (idx != -1) { // offset present
464 str.Remove(0, idx+1);
465 if (str.IsFloat()) // if str is a valid number, convert is to an integer
466 offset = str.Atoi();
467 }
468 fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution;
469
470 // handle lgb-n1 entry
471 str = tok[2];
472 // check if there is an offset present
473 idx = str.First("-");
474 if (idx != -1) { // offset present
475 str.Remove(0, idx+1);
476 if (str.IsFloat()) // if str is a valid number, convert is to an integer
477 offset = str.Atoi();
478 }
479 fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution;
480 } else if ((tok.size() > 3) && (tok.size() % 2 == 1)) { // structure FIT_RANGE fgb[+n00] lgb[-n01] [fgb[+n10] lgb[-n11] ... fgb[+nN0] lgb[-nN1]]
481 UInt_t pos = 2*(fRunNo+1)-1;
482
483 if (pos + 1 >= tok.size()) {
484 std::cerr << std::endl << ">> PRunMuMinus::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'";
485 std::cerr << std::endl << ">> will ignore it. Sorry ..." << std::endl;
486 } else {
487 // handle fgb+n0 entry
488 str = tok[pos];
489 // check if there is an offset present
490 idx = str.First("+");
491 if (idx != -1) { // offset present
492 str.Remove(0, idx+1);
493 if (str.IsFloat()) // if str is a valid number, convert is to an integer
494 offset = str.Atoi();
495 }
496 fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution;
497
498 // handle lgb-n1 entry
499 str = tok[pos+1];
500 // check if there is an offset present
501 idx = str.First("-");
502 if (idx != -1) { // offset present
503 str.Remove(0, idx+1);
504 if (str.IsFloat()) // if str is a valid number, convert is to an integer
505 offset = str.Atoi();
506 }
507 fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution;
508 }
509 } else { // error
510 std::cerr << std::endl << ">> PRunMuMinus::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'";
511 std::cerr << std::endl << ">> will ignore it. Sorry ..." << std::endl;
512 }
513}
514
515//--------------------------------------------------------------------------
516// CalcNoOfFitBins (public)
517//--------------------------------------------------------------------------
522{
523 // In order not having to loop over all bins and to stay consistent with the chisq method, calculate the start and end bins explicitly
524 fStartTimeBin = static_cast<Int_t>(ceil((fFitStartTime - fData.GetDataTimeStart())/fData.GetDataTimeStep()));
525 if (fStartTimeBin < 0)
526 fStartTimeBin = 0;
527 fEndTimeBin = static_cast<Int_t>(floor((fFitEndTime - fData.GetDataTimeStart())/fData.GetDataTimeStep())) + 1;
528 if (fEndTimeBin > static_cast<Int_t>(fData.GetValue()->size()))
529 fEndTimeBin = fData.GetValue()->size();
530
533 else
534 fNoOfFitBins = 0;
535}
536
537//--------------------------------------------------------------------------
538// CalcTheory
539//--------------------------------------------------------------------------
544{
545 // feed the parameter vector
546 std::vector<Double_t> par;
547 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
548 for (UInt_t i=0; i<paramList->size(); i++)
549 par.push_back((*paramList)[i].fValue);
550
551 // calculate functions
552 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
553 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
554 }
555
556 // calculate theory
557 UInt_t size = fData.GetValue()->size();
558 Double_t start = fData.GetDataTimeStart();
559 Double_t resolution = fData.GetDataTimeStep();
560 Double_t time;
561 for (UInt_t i=0; i<size; i++) {
562 time = start + static_cast<Double_t>(i)*resolution;
563 fData.AppendTheoryValue(fTheory->Func(time, par, fFuncValues));
564 }
565
566 // clean up
567 par.clear();
568}
569
570//--------------------------------------------------------------------------
571// PrepareData
572//--------------------------------------------------------------------------
587{
588 Bool_t success = true;
589
590 if (!fValid)
591 return false;
592
593 // keep the Global block info
594 PMsrGlobalBlock *globalBlock = fMsrInfo->GetMsrGlobal();
595
596 // get the proper run
597 PRawRunData* runData = fRawData->GetRunData(*fRunInfo->GetRunName());
598 if (!runData) { // couldn't get run
599 std::cerr << std::endl << ">> PRunMuMinus::PrepareData(): **ERROR** Couldn't get run " << fRunInfo->GetRunName()->Data() << "!";
600 std::cerr << std::endl;
601 return false;
602 }
603
604 // keep the field from the meta-data from the data-file
605 fMetaData.fField = runData->GetField();
606
607 // keep the energy from the meta-data from the data-file
608 fMetaData.fEnergy = runData->GetEnergy();
609
610 // keep the temperature(s) from the meta-data from the data-file
611 for (unsigned int i=0; i<runData->GetNoOfTemperatures(); i++)
612 fMetaData.fTemp.push_back(runData->GetTemperature(i));
613
614 // collect histogram numbers
615 PUIntVector histoNo; // histoNo = msr-file forward + redGreen_offset - 1
616 for (UInt_t i=0; i<fRunInfo->GetForwardHistoNoSize(); i++) {
617 histoNo.push_back(fRunInfo->GetForwardHistoNo(i));
618
619 if (!runData->IsPresent(histoNo[i])) {
620 std::cerr << std::endl << ">> PRunMuMinus::PrepareData(): **PANIC ERROR**:";
621 std::cerr << std::endl << ">> histoNo found = " << histoNo[i] << ", which is NOT present in the data file!?!?";
622 std::cerr << std::endl << ">> Will quit :-(";
623 std::cerr << std::endl;
624 histoNo.clear();
625 return false;
626 }
627 }
628
629 // keep the time resolution in (us)
630 fTimeResolution = runData->GetTimeResolution()/1.0e3;
631 std::cout.precision(10);
632 std::cout << std::endl << ">> PRunMuMinus::PrepareData(): time resolution=" << std::fixed << runData->GetTimeResolution() << "(ns)" << std::endl;
633
634 // get all the proper t0's and addt0's for the current RUN block
635 if (!GetProperT0(runData, globalBlock, histoNo)) {
636 return false;
637 }
638
639 // keep the histo of each group at this point (addruns handled below)
640 std::vector<PDoubleVector> forward;
641 forward.resize(histoNo.size()); // resize to number of groups
642 for (UInt_t i=0; i<histoNo.size(); i++) {
643 forward[i].resize(runData->GetDataBin(histoNo[i])->size());
644 forward[i] = *runData->GetDataBin(histoNo[i]);
645 }
646
647 // check if there are runs to be added to the current one
648 if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present
649 PRawRunData *addRunData;
650 for (UInt_t i=1; i<fRunInfo->GetRunNameSize(); i++) {
651
652 // get run to be added to the main one
653 addRunData = fRawData->GetRunData(*fRunInfo->GetRunName(i));
654 if (addRunData == nullptr) { // couldn't get run
655 std::cerr << std::endl << ">> PRunMuMinus::PrepareData(): **ERROR** Couldn't get addrun " << fRunInfo->GetRunName(i)->Data() << "!";
656 std::cerr << std::endl;
657 return false;
658 }
659
660 // add forward run
661 UInt_t addRunSize;
662 for (UInt_t k=0; k<histoNo.size(); k++) { // fill each group
663 addRunSize = addRunData->GetDataBin(histoNo[k])->size();
664 for (UInt_t j=0; j<addRunData->GetDataBin(histoNo[k])->size(); j++) { // loop over the bin indices
665 // make sure that the index stays in the proper range
666 if ((static_cast<Int_t>(j)+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]) >= 0) &&
667 (j+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]) < addRunSize)) {
668 forward[k][j] += addRunData->GetDataBin(histoNo[k])->at(j+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]));
669 }
670 }
671 }
672 }
673 }
674
675 // set forward/backward histo data of the first group
676 fForward.resize(forward[0].size());
677 for (UInt_t i=0; i<fForward.size(); i++) {
678 fForward[i] = forward[0][i];
679 }
680
681 // group histograms, add all the remaining forward histograms of the group
682 for (UInt_t i=1; i<histoNo.size(); i++) { // loop over the groupings
683 for (UInt_t j=0; j<runData->GetDataBin(histoNo[i])->size(); j++) { // loop over the bin indices
684 // make sure that the index stays within proper range
685 if ((static_cast<Int_t>(j)+fT0s[i]-fT0s[0] >= 0) && (j+fT0s[i]-fT0s[0] < runData->GetDataBin(histoNo[i])->size())) {
686 fForward[j] += forward[i][j+static_cast<Int_t>(fT0s[i])-static_cast<Int_t>(fT0s[0])];
687 }
688 }
689 }
690
691 // get the data range (fgb/lgb) for the current RUN block
692 if (!GetProperDataRange()) {
693 return false;
694 }
695
696 // get the fit range for the current RUN block
697 GetProperFitRange(globalBlock);
698
699 // do the more fit/view specific stuff
700 if (fHandleTag == kFit)
701 success = PrepareFitData(runData, histoNo[0]);
702 else if (fHandleTag == kView)
703 success = PrepareRawViewData(runData, histoNo[0]);
704 else
705 success = false;
706
707 // cleanup
708 histoNo.clear();
709
710 return success;
711}
712
713//--------------------------------------------------------------------------
714// PrepareFitData (private)
715//--------------------------------------------------------------------------
730Bool_t PRunMuMinus::PrepareFitData(PRawRunData* runData, const UInt_t histoNo)
731{
732 // transform raw histo data. This is done the following way (for details see the manual):
733 // for the single histo fit, just the rebinned raw data are copied
734
735 // fill data set
736 Int_t t0 = static_cast<Int_t>(fT0s[0]);
737 Double_t value = 0.0;
738 // data start at data_start-t0
739 // data start time = (binStart - 0.5) + pack/2 - t0, with pack and binStart used as double
740 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(fGoodBins[0])-0.5) + static_cast<Double_t>(fPacking)/2.0 - static_cast<Double_t>(t0)));
741 fData.SetDataTimeStep(fTimeResolution*fPacking);
742 for (Int_t i=fGoodBins[0]; i<fGoodBins[1]; i++) {
743 if (fPacking == 1) {
744 value = fForward[i];
745 fData.AppendValue(value);
746 if (value == 0.0)
747 fData.AppendErrorValue(1.0);
748 else
749 fData.AppendErrorValue(TMath::Sqrt(value));
750 } else { // packed data, i.e. fPacking > 1
751 if (((i-fGoodBins[0]) % fPacking == 0) && (i != fGoodBins[0])) { // fill data
752 fData.AppendValue(value);
753 if (value == 0.0)
754 fData.AppendErrorValue(1.0);
755 else
756 fData.AppendErrorValue(TMath::Sqrt(value));
757 // reset values
758 value = 0.0;
759 }
760 value += fForward[i];
761 }
762 }
763
765
766 return true;
767}
768
769//--------------------------------------------------------------------------
770// PrepareRawViewData (private)
771//--------------------------------------------------------------------------
788Bool_t PRunMuMinus::PrepareRawViewData(PRawRunData* runData, const UInt_t histoNo)
789{
790 // check if view_packing is wished
791 Int_t packing = fPacking;
792 if (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0) {
793 packing = fMsrInfo->GetMsrPlotList()->at(0).fViewPacking;
794 }
795
796 // calculate necessary norms
797 Double_t theoryNorm = 1.0;
798 if (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0) {
799 theoryNorm = static_cast<Double_t>(fMsrInfo->GetMsrPlotList()->at(0).fViewPacking)/static_cast<Double_t>(fPacking);
800 }
801
802 // raw data, since PMusrCanvas is doing ranging etc.
803 // start = the first bin which is a multiple of packing backward from first good data bin
804 Int_t start = fGoodBins[0] - (fGoodBins[0]/packing)*packing;
805 // end = last bin starting from start which is a multipl of packing and still within the data
806 Int_t end = start + ((fForward.size()-start)/packing)*packing;
807 // check if data range has been provided, and if not try to estimate them
808 if (start < 0) {
809 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
810 start = (static_cast<Int_t>(fT0s[0])+offset) - ((static_cast<Int_t>(fT0s[0])+offset)/packing)*packing;
811 end = start + ((fForward.size()-start)/packing)*packing;
812 std::cerr << std::endl << ">> PRunMuMinus::PrepareData(): **WARNING** data range was not provided, will try data range start = " << start << ".";
813 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
814 std::cerr << std::endl;
815 }
816 // check if start, end, and t0 make any sense
817 // 1st check if start and end are in proper order
818 if (end < start) { // need to swap them
819 Int_t keep = end;
820 end = start;
821 start = keep;
822 }
823 // 2nd check if start is within proper bounds
824 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
825 std::cerr << std::endl << ">> PRunMuMinus::PrepareRawViewData(): **ERROR** start data bin doesn't make any sense!";
826 std::cerr << std::endl;
827 return false;
828 }
829 // 3rd check if end is within proper bounds
830 if ((end < 0) || (end > static_cast<Int_t>(fForward.size()))) {
831 std::cerr << std::endl << ">> PRunMuMinus::PrepareRawViewData(): **ERROR** end data bin doesn't make any sense!";
832 std::cerr << std::endl;
833 return false;
834 }
835
836 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
837 if (fRunInfo->IsFitRangeInBin()) {
838 fFitStartTime = (fRunInfo->GetDataRange(0) + fRunInfo->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
839 fFitEndTime = (fRunInfo->GetDataRange(1) - fRunInfo->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
840 }
841
842 // everything looks fine, hence fill data set
843 Int_t t0 = static_cast<Int_t>(fT0s[0]);
844 Double_t value = 0.0;
845 // data start time = (binStart - 0.5) + pack/2 - t0, with pack and binStart used as double
846 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(start)-0.5) + static_cast<Double_t>(packing)/2.0 - static_cast<Double_t>(t0)));
847 fData.SetDataTimeStep(fTimeResolution*packing);
848
849 for (Int_t i=start; i<end; i++) {
850 if (((i-start) % packing == 0) && (i != start)) { // fill data
851 fData.AppendValue(value);
852 if (value == 0.0)
853 fData.AppendErrorValue(1.0);
854 else
855 fData.AppendErrorValue(TMath::Sqrt(value));
856 // reset values
857 value = 0.0;
858 }
859 value += fForward[i];
860 }
861
863
864 // fill theory vector for kView
865 // feed the parameter vector
866 std::vector<Double_t> par;
867 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
868 for (UInt_t i=0; i<paramList->size(); i++)
869 par.push_back((*paramList)[i].fValue);
870
871 // calculate functions
872 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
873 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
874 }
875
876 // calculate theory
877 UInt_t size = fForward.size();
878/* //as35
879 Double_t factor = 1.0;
880 if (fData.GetValue()->size() * 10 > fForward.size()) {
881 size = fData.GetValue()->size() * 10;
882 factor = static_cast<Double_t>(fForward.size()) / static_cast<Double_t>(size);
883 }
884 Double_t time;
885 Double_t theoryValue;
886 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
887 fData.SetTheoryTimeStep(fTimeResolution*factor);
888*/ //as35
889
890 Int_t factor = 8; // 8 times more points for the theory (if fTheoAsData == false)
891 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
892 if (fTheoAsData) { // calculate theory only at the data points
893 fData.SetTheoryTimeStep(fData.GetDataTimeStep());
894 } else {
895 // finer binning for the theory (8 times as many points = factor)
896 size *= factor;
897 fData.SetTheoryTimeStep(fData.GetDataTimeStep()/(Double_t)factor);
898 }
899
900 Double_t time;
901 Double_t theoryValue;
902 for (UInt_t i=0; i<size; i++) {
903 time = fData.GetTheoryTimeStart() + i*fData.GetTheoryTimeStep();
904 theoryValue = fTheory->Func(time, par, fFuncValues);
905 if (fabs(theoryValue) > 1.0e10) { // dirty hack needs to be fixed!!
906 theoryValue = 0.0;
907 }
908 fData.AppendTheoryValue(theoryNorm*theoryValue);
909 }
910
911 // clean up
912 par.clear();
913
914 return true;
915}
916
917//--------------------------------------------------------------------------
918// GetProperT0 (private)
919//--------------------------------------------------------------------------
935Bool_t PRunMuMinus::GetProperT0(PRawRunData* runData, PMsrGlobalBlock *globalBlock, PUIntVector &histoNo)
936{
937 // feed all T0's
938 // first init T0's, T0's are stored as (forward T0, backward T0, etc.)
939 fT0s.clear();
940 fT0s.resize(histoNo.size());
941 for (UInt_t i=0; i<fT0s.size(); i++) {
942 fT0s[i] = -1.0;
943 }
944
945 // fill in the T0's from the msr-file (if present)
946 for (UInt_t i=0; i<fRunInfo->GetT0BinSize(); i++) {
947 fT0s[i] = fRunInfo->GetT0Bin(i);
948 }
949
950 // fill in the T0's from the GLOBAL block section (if present)
951 for (UInt_t i=0; i<globalBlock->GetT0BinSize(); i++) {
952 if (fT0s[i] == -1.0) { // i.e. not given in the RUN block section
953 fT0s[i] = globalBlock->GetT0Bin(i);
954 }
955 }
956
957 // fill in the T0's from the data file, if not already present in the msr-file
958 for (UInt_t i=0; i<histoNo.size(); i++) {
959 if (fT0s[i] == -1.0) { // i.e. not present in the msr-file, try the data file
960 if (runData->GetT0Bin(histoNo[i]) > 0.0) {
961 fT0s[i] = runData->GetT0Bin(histoNo[i]);
962 fRunInfo->SetT0Bin(fT0s[i], i); // keep value for the msr-file
963 }
964 }
965 }
966
967 // 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
968 for (UInt_t i=0; i<histoNo.size(); i++) {
969 if (fT0s[i] == -1.0) { // i.e. not present in the msr-file and data file, use the estimated T0
970 fT0s[i] = runData->GetT0BinEstimated(histoNo[i]);
971 fRunInfo->SetT0Bin(fT0s[i], i); // keep value for the msr-file
972
973 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!";
974 std::cerr << std::endl << ">> run: " << fRunInfo->GetRunName()->Data();
975 std::cerr << std::endl << ">> will try the estimated one: forward t0 = " << runData->GetT0BinEstimated(histoNo[i]);
976 std::cerr << std::endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!";
977 std::cerr << std::endl;
978 }
979 }
980
981 // check if t0 is within proper bounds
982 for (UInt_t i=0; i<fRunInfo->GetForwardHistoNoSize(); i++) {
983 if ((fT0s[i] < 0) || (fT0s[i] > static_cast<Int_t>(runData->GetDataBin(histoNo[i])->size()))) {
984 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **ERROR** t0 data bin (" << fT0s[i] << ") doesn't make any sense!";
985 std::cerr << std::endl;
986 return false;
987 }
988 }
989
990 // check if there are runs to be added to the current one
991 if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present
992 PRawRunData *addRunData;
993 fAddT0s.resize(fRunInfo->GetRunNameSize()-1); // resize to the number of addruns
994 for (UInt_t i=1; i<fRunInfo->GetRunNameSize(); i++) {
995
996 // get run to be added to the main one
997 addRunData = fRawData->GetRunData(*fRunInfo->GetRunName(i));
998 if (addRunData == nullptr) { // couldn't get run
999 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **ERROR** Couldn't get addrun " << fRunInfo->GetRunName(i)->Data() << "!";
1000 std::cerr << std::endl;
1001 return false;
1002 }
1003
1004 // feed all T0's
1005 // first init T0's, T0's are stored as (forward T0, backward T0, etc.)
1006 fAddT0s[i-1].resize(histoNo.size());
1007 for (UInt_t j=0; j<fAddT0s[i-1].size(); j++) {
1008 fAddT0s[i-1][j] = -1.0;
1009 }
1010
1011 // fill in the T0's from the msr-file (if present)
1012 for (UInt_t j=0; j<fRunInfo->GetT0BinSize(); j++) {
1013 fAddT0s[i-1][j] = fRunInfo->GetAddT0Bin(i-1,j); // addRunIdx starts at 0
1014 }
1015
1016 // fill in the T0's from the data file, if not already present in the msr-file
1017 for (UInt_t j=0; j<histoNo.size(); j++) {
1018 if (fAddT0s[i-1][j] == -1.0) // i.e. not present in the msr-file, try the data file
1019 if (addRunData->GetT0Bin(histoNo[j]) > 0.0) {
1020 fAddT0s[i-1][j] = addRunData->GetT0Bin(histoNo[j]);
1021 fRunInfo->SetAddT0Bin(fAddT0s[i-1][j], i-1, j); // keep value for the msr-file
1022 }
1023 }
1024
1025 // 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
1026 for (UInt_t j=0; j<histoNo.size(); j++) {
1027 if (fAddT0s[i-1][j] == -1.0) { // i.e. not present in the msr-file and data file, use the estimated T0
1028 fAddT0s[i-1][j] = addRunData->GetT0BinEstimated(histoNo[j]);
1029 fRunInfo->SetAddT0Bin(fAddT0s[i-1][j], i-1, j); // keep value for the msr-file
1030
1031 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!";
1032 std::cerr << std::endl << ">> run: " << fRunInfo->GetRunName(i)->Data();
1033 std::cerr << std::endl << ">> will try the estimated one: forward t0 = " << addRunData->GetT0BinEstimated(histoNo[j]);
1034 std::cerr << std::endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!";
1035 std::cerr << std::endl;
1036 }
1037 }
1038
1039 // check if t0 is within proper bounds
1040 for (UInt_t j=0; j<fRunInfo->GetForwardHistoNoSize(); j++) {
1041 if ((fAddT0s[i-1][j] < 0) || (fAddT0s[i-1][j] > static_cast<Int_t>(addRunData->GetDataBin(histoNo[j])->size()))) {
1042 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **ERROR** addt0 data bin (" << fAddT0s[i-1][j] << ") doesn't make any sense!";
1043 std::cerr << std::endl;
1044 return false;
1045 }
1046 }
1047 }
1048 }
1049
1050 return true;
1051}
1052
1053//--------------------------------------------------------------------------
1054// GetProperDataRange (private)
1055//--------------------------------------------------------------------------
1067{
1068 // get start/end data
1069 Int_t start;
1070 Int_t end;
1071 start = fRunInfo->GetDataRange(0);
1072 end = fRunInfo->GetDataRange(1);
1073
1074 // check if data range has been given in the RUN block, if not try to get it from the GLOBAL block
1075 if (start < 0) {
1076 start = fMsrInfo->GetMsrGlobal()->GetDataRange(0);
1077 }
1078 if (end < 0) {
1079 end = fMsrInfo->GetMsrGlobal()->GetDataRange(1);
1080 }
1081
1082 // check if data range has been provided, and if not try to estimate them
1083 if (start < 0) {
1084 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
1085 start = static_cast<Int_t>(fT0s[0])+offset;
1086 fRunInfo->SetDataRange(start, 0);
1087 std::cerr << std::endl << ">> PRunMuMinus::GetProperDataRange(): **WARNING** data range was not provided, will try data range start = t0+" << offset << "(=10ns) = " << start << ".";
1088 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1089 std::cerr << std::endl;
1090 }
1091 if (end < 0) {
1092 end = fForward.size();
1093 fRunInfo->SetDataRange(end, 1);
1094 std::cerr << std::endl << ">> PRunMuMinus::GetProperDataRange(): **WARNING** data range was not provided, will try data range end = " << end << ".";
1095 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1096 std::cerr << std::endl;
1097 }
1098
1099 // check if start and end make any sense
1100 // 1st check if start and end are in proper order
1101 if (end < start) { // need to swap them
1102 Int_t keep = end;
1103 end = start;
1104 start = keep;
1105 }
1106 // 2nd check if start is within proper bounds
1107 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
1108 std::cerr << std::endl << ">> PRunMuMinus::GetProperDataRange(): **ERROR** start data bin (" << start << ") doesn't make any sense!";
1109 std::cerr << std::endl;
1110 return false;
1111 }
1112 // 3rd check if end is within proper bounds
1113 if ((end < 0) || (end > static_cast<Int_t>(fForward.size()))) {
1114 std::cerr << std::endl << ">> PRunMuMinus::GetProperDataRange(): **ERROR** end data bin (" << end << ") doesn't make any sense!";
1115 std::cerr << std::endl;
1116 return false;
1117 }
1118
1119 // keep good bins for potential later use
1120 fGoodBins[0] = start;
1121 fGoodBins[1] = end;
1122
1123 return true;
1124}
1125
1126//--------------------------------------------------------------------------
1127// GetProperFitRange (private)
1128//--------------------------------------------------------------------------
1142{
1143 // set fit start/end time; first check RUN Block
1144 fFitStartTime = fRunInfo->GetFitRange(0);
1145 fFitEndTime = fRunInfo->GetFitRange(1);
1146 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
1147 if (fRunInfo->IsFitRangeInBin()) {
1148 fFitStartTime = (fGoodBins[0] + fRunInfo->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
1149 fFitEndTime = (fGoodBins[1] - fRunInfo->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
1150 // write these times back into the data structure. This way it is available when writting the log-file
1151 fRunInfo->SetFitRange(fFitStartTime, 0);
1152 fRunInfo->SetFitRange(fFitEndTime, 1);
1153 }
1154 if (fFitStartTime == PMUSR_UNDEFINED) { // fit start/end NOT found in the RUN block, check GLOBAL block
1155 fFitStartTime = globalBlock->GetFitRange(0);
1156 fFitEndTime = globalBlock->GetFitRange(1);
1157 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
1158 if (globalBlock->IsFitRangeInBin()) {
1159 fFitStartTime = (fGoodBins[0] + globalBlock->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
1160 fFitEndTime = (fGoodBins[1] - globalBlock->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
1161 // write these times back into the data structure. This way it is available when writting the log-file
1162 globalBlock->SetFitRange(fFitStartTime, 0);
1163 globalBlock->SetFitRange(fFitEndTime, 1);
1164 }
1165 }
1167 fFitStartTime = (fGoodBins[0] - fT0s[0]) * fTimeResolution; // (fgb-t0)*dt
1168 fFitEndTime = (fGoodBins[1] - fT0s[0]) * fTimeResolution; // (lgb-t0)*dt
1169 std::cerr << ">> PRunMuMinus::GetProperFitRange(): **WARNING** Couldn't get fit start/end time!" << std::endl;
1170 std::cerr << ">> Will set it to fgb/lgb which given in time is: " << fFitStartTime << "..." << fFitEndTime << " (usec)" << std::endl;
1171 }
1172}
std::vector< UInt_t > PUIntVector
Definition PMusr.h:375
EPMusrHandleTag
Definition PMusr.h:427
@ kEmpty
No operation active.
Definition PMusr.h:428
@ 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 PMUSR_UNDEFINED
Definition PMusr.h:177
std::vector< PMsrParamStructure > PMsrParamList
Definition PMusr.h:1040
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
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
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
Raw data file reader and format converter for μSR data.
virtual ~PRunMuMinus()
Virtual destructor cleaning up allocated resources.
Bool_t fTheoAsData
Theory calculation mode flag.
PRunMuMinus()
Default constructor creating an empty, invalid μ⁻ run object.
Int_t fPacking
Bin packing factor (REQUIRED for μ⁻).
Int_t fGoodBins[2]
Good bin markers for bin-based fit range specification.
virtual Bool_t PrepareData()
Main data preparation routine for μ⁻ fitting and viewing.
virtual Double_t CalcChiSquareExpected(const std::vector< Double_t > &par)
Calculates expected χ² based on theory predictions (statistical diagnostic).
virtual Bool_t GetProperDataRange()
Determines data range (region of valid histogram data).
virtual void SetFitRangeBin(const TString fitRange)
Sets fit range using bin-offset specification (COMMANDS block syntax).
virtual void GetProperFitRange(PMsrGlobalBlock *globalBlock)
Determines fit range from MSR file settings.
virtual UInt_t GetNoOfFitBins()
Returns the number of bins included in the fit range.
virtual void CalcTheory()
Evaluates theory function at all data points (or high-resolution grid).
PDoubleVector fForward
Forward detector histogram data (background-corrected, packed).
virtual Bool_t GetProperT0(PRawRunData *runData, PMsrGlobalBlock *globalBlock, PUIntVector &histoNo)
Determines and validates t0 values for μ⁻ histogram.
Int_t fEndTimeBin
Last bin index in fit range (exclusive: loop as i < fEndTimeBin)
Int_t fStartTimeBin
First bin index in fit range (inclusive, 0-based after packing)
virtual Bool_t PrepareFitData(PRawRunData *runData, const UInt_t histoNo)
Prepares μ⁻ histogram data for fitting.
virtual Double_t CalcChiSquare(const std::vector< Double_t > &par)
Calculates χ² between μ⁻ data and theory (least-squares fit metric).
virtual void CalcNoOfFitBins()
Calculates start/end bin indices from fit time range.
virtual Double_t CalcMaxLikelihood(const std::vector< Double_t > &par)
Calculates negative log-likelihood for Poisson statistics (low-count fit metric).
virtual Bool_t PrepareRawViewData(PRawRunData *runData, const UInt_t histoNo)
Prepares μ⁻ histogram data for viewing/plotting (minimal processing).
UInt_t fNoOfFitBins
Number of bins within fit range (between fStartTimeBin and fEndTimeBin)