musrfit 1.12.1
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 Bool_t post_msg(true);
376 Int_t i;
377
378 // Calculate the theory function once to ensure one function evaluation for the current set of parameters.
379 // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once
380 // for a given set of parameters---which should be done outside of the parallelized loop.
381 // For all other functions it means a tiny and acceptable overhead.
382 time = fTheory->Func(time, par, fFuncValues);
383
384 #ifdef HAVE_GOMP
385 Int_t chunk = (fEndTimeBin - fStartTimeBin)/omp_get_num_procs();
386 if (chunk < 10)
387 chunk = 10;
388 #pragma omp parallel for default(shared) private(i,time,theo,data,post_msg) schedule(dynamic,chunk) reduction(+:mllh)
389 #endif
390 for (i=fStartTimeBin; i < fEndTimeBin; ++i) {
391 time = fData.GetDataTimeStart() + static_cast<Double_t>(i)*fData.GetDataTimeStep();
392 // calculate theory for the given parameter set
393 theo = fTheory->Func(time, par, fFuncValues);
394
395 data = fData.GetValue()->at(i);
396
397 if (theo <= 0.0) {
398 if (post_msg) {
399 post_msg = false;
400 std::cerr << ">> PRunMuMinus::CalcMaxLikelihood: **WARNING** NEGATIVE theory!!" << std::endl;
401 }
402 continue;
403 }
404
405 if (data > 1.0e-9) {
406 mllh += (theo-data) + data*log(data/theo);
407 } else {
408 mllh += (theo-data);
409 }
410 }
411
412 return 2.0*mllh;
413}
414
415//--------------------------------------------------------------------------
416// GetNoOfFitBins (public)
417//--------------------------------------------------------------------------
434{
436
437 return fNoOfFitBins;
438}
439
440//--------------------------------------------------------------------------
441// SetFitRangeBin (public)
442//--------------------------------------------------------------------------
454void PRunMuMinus::SetFitRangeBin(const TString fitRange)
455{
456 TString str;
457 Ssiz_t idx = -1;
458 Int_t offset = 0;
459
460 std::vector<std::string> tok = PStringUtils::Split(fitRange.Data(), " \t");
461
462 if (tok.size() == 3) { // structure FIT_RANGE fgb+n0 lgb-n1
463 // handle fgb+n0 entry
464 str = tok[1];
465 // check if there is an offset present
466 idx = str.First("+");
467 if (idx != -1) { // offset present
468 str.Remove(0, idx+1);
469 if (str.IsFloat()) // if str is a valid number, convert is to an integer
470 offset = str.Atoi();
471 }
472 fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution;
473
474 // handle lgb-n1 entry
475 str = tok[2];
476 // check if there is an offset present
477 idx = str.First("-");
478 if (idx != -1) { // offset present
479 str.Remove(0, idx+1);
480 if (str.IsFloat()) // if str is a valid number, convert is to an integer
481 offset = str.Atoi();
482 }
483 fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution;
484 } else if ((tok.size() > 3) && (tok.size() % 2 == 1)) { // structure FIT_RANGE fgb[+n00] lgb[-n01] [fgb[+n10] lgb[-n11] ... fgb[+nN0] lgb[-nN1]]
485 UInt_t pos = 2*(fRunNo+1)-1;
486
487 if (pos + 1 >= tok.size()) {
488 std::cerr << std::endl << ">> PRunMuMinus::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'";
489 std::cerr << std::endl << ">> will ignore it. Sorry ..." << std::endl;
490 } else {
491 // handle fgb+n0 entry
492 str = tok[pos];
493 // check if there is an offset present
494 idx = str.First("+");
495 if (idx != -1) { // offset present
496 str.Remove(0, idx+1);
497 if (str.IsFloat()) // if str is a valid number, convert is to an integer
498 offset = str.Atoi();
499 }
500 fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution;
501
502 // handle lgb-n1 entry
503 str = tok[pos+1];
504 // check if there is an offset present
505 idx = str.First("-");
506 if (idx != -1) { // offset present
507 str.Remove(0, idx+1);
508 if (str.IsFloat()) // if str is a valid number, convert is to an integer
509 offset = str.Atoi();
510 }
511 fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution;
512 }
513 } else { // error
514 std::cerr << std::endl << ">> PRunMuMinus::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'";
515 std::cerr << std::endl << ">> will ignore it. Sorry ..." << std::endl;
516 }
517}
518
519//--------------------------------------------------------------------------
520// CalcNoOfFitBins (public)
521//--------------------------------------------------------------------------
526{
527 // In order not having to loop over all bins and to stay consistent with the chisq method, calculate the start and end bins explicitly
528 fStartTimeBin = static_cast<Int_t>(ceil((fFitStartTime - fData.GetDataTimeStart())/fData.GetDataTimeStep()));
529 if (fStartTimeBin < 0)
530 fStartTimeBin = 0;
531 fEndTimeBin = static_cast<Int_t>(floor((fFitEndTime - fData.GetDataTimeStart())/fData.GetDataTimeStep())) + 1;
532 if (fEndTimeBin > static_cast<Int_t>(fData.GetValue()->size()))
533 fEndTimeBin = fData.GetValue()->size();
534
537 else
538 fNoOfFitBins = 0;
539}
540
541//--------------------------------------------------------------------------
542// CalcTheory
543//--------------------------------------------------------------------------
548{
549 // feed the parameter vector
550 std::vector<Double_t> par;
551 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
552 for (UInt_t i=0; i<paramList->size(); i++)
553 par.push_back((*paramList)[i].fValue);
554
555 // calculate functions
556 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
557 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
558 }
559
560 // calculate theory
561 UInt_t size = fData.GetValue()->size();
562 Double_t start = fData.GetDataTimeStart();
563 Double_t resolution = fData.GetDataTimeStep();
564 Double_t time;
565 for (UInt_t i=0; i<size; i++) {
566 time = start + static_cast<Double_t>(i)*resolution;
567 fData.AppendTheoryValue(fTheory->Func(time, par, fFuncValues));
568 }
569
570 // clean up
571 par.clear();
572}
573
574//--------------------------------------------------------------------------
575// PrepareData
576//--------------------------------------------------------------------------
591{
592 Bool_t success = true;
593
594 if (!fValid)
595 return false;
596
597 // keep the Global block info
598 PMsrGlobalBlock *globalBlock = fMsrInfo->GetMsrGlobal();
599
600 // get the proper run
601 PRawRunData* runData = fRawData->GetRunData(*fRunInfo->GetRunName());
602 if (!runData) { // couldn't get run
603 std::cerr << std::endl << ">> PRunMuMinus::PrepareData(): **ERROR** Couldn't get run " << fRunInfo->GetRunName()->Data() << "!";
604 std::cerr << std::endl;
605 return false;
606 }
607
608 // keep the field from the meta-data from the data-file
609 fMetaData.fField = runData->GetField();
610
611 // keep the energy from the meta-data from the data-file
612 fMetaData.fEnergy = runData->GetEnergy();
613
614 // keep the temperature(s) from the meta-data from the data-file
615 for (unsigned int i=0; i<runData->GetNoOfTemperatures(); i++)
616 fMetaData.fTemp.push_back(runData->GetTemperature(i));
617
618 // collect histogram numbers
619 PUIntVector histoNo; // histoNo = msr-file forward + redGreen_offset - 1
620 for (UInt_t i=0; i<fRunInfo->GetForwardHistoNoSize(); i++) {
621 histoNo.push_back(fRunInfo->GetForwardHistoNo(i));
622
623 if (!runData->IsPresent(histoNo[i])) {
624 std::cerr << std::endl << ">> PRunMuMinus::PrepareData(): **PANIC ERROR**:";
625 std::cerr << std::endl << ">> histoNo found = " << histoNo[i] << ", which is NOT present in the data file!?!?";
626 std::cerr << std::endl << ">> Will quit :-(";
627 std::cerr << std::endl;
628 histoNo.clear();
629 return false;
630 }
631 }
632
633 // keep the time resolution in (us)
634 fTimeResolution = runData->GetTimeResolution()/1.0e3;
635 std::cout.precision(10);
636 std::cout << std::endl << ">> PRunMuMinus::PrepareData(): time resolution=" << std::fixed << runData->GetTimeResolution() << "(ns)" << std::endl;
637
638 // get all the proper t0's and addt0's for the current RUN block
639 if (!GetProperT0(runData, globalBlock, histoNo)) {
640 return false;
641 }
642
643 // keep the histo of each group at this point (addruns handled below)
644 std::vector<PDoubleVector> forward;
645 forward.resize(histoNo.size()); // resize to number of groups
646 for (UInt_t i=0; i<histoNo.size(); i++) {
647 forward[i].resize(runData->GetDataBin(histoNo[i])->size());
648 forward[i] = *runData->GetDataBin(histoNo[i]);
649 }
650
651 // check if there are runs to be added to the current one
652 if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present
653 PRawRunData *addRunData;
654 for (UInt_t i=1; i<fRunInfo->GetRunNameSize(); i++) {
655
656 // get run to be added to the main one
657 addRunData = fRawData->GetRunData(*fRunInfo->GetRunName(i));
658 if (addRunData == nullptr) { // couldn't get run
659 std::cerr << std::endl << ">> PRunMuMinus::PrepareData(): **ERROR** Couldn't get addrun " << fRunInfo->GetRunName(i)->Data() << "!";
660 std::cerr << std::endl;
661 return false;
662 }
663
664 // add forward run
665 UInt_t addRunSize;
666 for (UInt_t k=0; k<histoNo.size(); k++) { // fill each group
667 addRunSize = addRunData->GetDataBin(histoNo[k])->size();
668 for (UInt_t j=0; j<addRunData->GetDataBin(histoNo[k])->size(); j++) { // loop over the bin indices
669 // make sure that the index stays in the proper range
670 if ((static_cast<Int_t>(j)+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]) >= 0) &&
671 (j+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]) < addRunSize)) {
672 forward[k][j] += addRunData->GetDataBin(histoNo[k])->at(j+static_cast<Int_t>(fAddT0s[i-1][k])-static_cast<Int_t>(fT0s[k]));
673 }
674 }
675 }
676 }
677 }
678
679 // set forward/backward histo data of the first group
680 fForward.resize(forward[0].size());
681 for (UInt_t i=0; i<fForward.size(); i++) {
682 fForward[i] = forward[0][i];
683 }
684
685 // group histograms, add all the remaining forward histograms of the group
686 for (UInt_t i=1; i<histoNo.size(); i++) { // loop over the groupings
687 for (UInt_t j=0; j<runData->GetDataBin(histoNo[i])->size(); j++) { // loop over the bin indices
688 // make sure that the index stays within proper range
689 if ((static_cast<Int_t>(j)+fT0s[i]-fT0s[0] >= 0) && (j+fT0s[i]-fT0s[0] < runData->GetDataBin(histoNo[i])->size())) {
690 fForward[j] += forward[i][j+static_cast<Int_t>(fT0s[i])-static_cast<Int_t>(fT0s[0])];
691 }
692 }
693 }
694
695 // get the data range (fgb/lgb) for the current RUN block
696 if (!GetProperDataRange()) {
697 return false;
698 }
699
700 // get the fit range for the current RUN block
701 GetProperFitRange(globalBlock);
702
703 // do the more fit/view specific stuff
704 if (fHandleTag == kFit)
705 success = PrepareFitData(runData, histoNo[0]);
706 else if (fHandleTag == kView)
707 success = PrepareRawViewData(runData, histoNo[0]);
708 else
709 success = false;
710
711 // cleanup
712 histoNo.clear();
713
714 return success;
715}
716
717//--------------------------------------------------------------------------
718// PrepareFitData (private)
719//--------------------------------------------------------------------------
734Bool_t PRunMuMinus::PrepareFitData(PRawRunData* runData, const UInt_t histoNo)
735{
736 // transform raw histo data. This is done the following way (for details see the manual):
737 // for the single histo fit, just the rebinned raw data are copied
738
739 // fill data set
740 Int_t t0 = static_cast<Int_t>(fT0s[0]);
741 Double_t value = 0.0;
742 // data start at data_start-t0
743 // data start time = (binStart - 0.5) + pack/2 - t0, with pack and binStart used as double
744 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(fGoodBins[0])-0.5) + static_cast<Double_t>(fPacking)/2.0 - static_cast<Double_t>(t0)));
745 fData.SetDataTimeStep(fTimeResolution*fPacking);
746 for (Int_t i=fGoodBins[0]; i<fGoodBins[1]; i++) {
747 if (fPacking == 1) {
748 value = fForward[i];
749 fData.AppendValue(value);
750 if (value == 0.0)
751 fData.AppendErrorValue(1.0);
752 else
753 fData.AppendErrorValue(TMath::Sqrt(value));
754 } else { // packed data, i.e. fPacking > 1
755 if (((i-fGoodBins[0]) % fPacking == 0) && (i != fGoodBins[0])) { // fill data
756 fData.AppendValue(value);
757 if (value == 0.0)
758 fData.AppendErrorValue(1.0);
759 else
760 fData.AppendErrorValue(TMath::Sqrt(value));
761 // reset values
762 value = 0.0;
763 }
764 value += fForward[i];
765 }
766 }
767
769
770 return true;
771}
772
773//--------------------------------------------------------------------------
774// PrepareRawViewData (private)
775//--------------------------------------------------------------------------
792Bool_t PRunMuMinus::PrepareRawViewData(PRawRunData* runData, const UInt_t histoNo)
793{
794 // check if view_packing is wished
795 Int_t packing = fPacking;
796 if (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0) {
797 packing = fMsrInfo->GetMsrPlotList()->at(0).fViewPacking;
798 }
799
800 // calculate necessary norms
801 Double_t theoryNorm = 1.0;
802 if (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0) {
803 theoryNorm = static_cast<Double_t>(fMsrInfo->GetMsrPlotList()->at(0).fViewPacking)/static_cast<Double_t>(fPacking);
804 }
805
806 // raw data, since PMusrCanvas is doing ranging etc.
807 // start = the first bin which is a multiple of packing backward from first good data bin
808 Int_t start = fGoodBins[0] - (fGoodBins[0]/packing)*packing;
809 // end = last bin starting from start which is a multipl of packing and still within the data
810 Int_t end = start + ((fForward.size()-start)/packing)*packing;
811 // check if data range has been provided, and if not try to estimate them
812 if (start < 0) {
813 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
814 start = (static_cast<Int_t>(fT0s[0])+offset) - ((static_cast<Int_t>(fT0s[0])+offset)/packing)*packing;
815 end = start + ((fForward.size()-start)/packing)*packing;
816 std::cerr << std::endl << ">> PRunMuMinus::PrepareData(): **WARNING** data range was not provided, will try data range start = " << start << ".";
817 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
818 std::cerr << std::endl;
819 }
820 // check if start, end, and t0 make any sense
821 // 1st check if start and end are in proper order
822 if (end < start) { // need to swap them
823 Int_t keep = end;
824 end = start;
825 start = keep;
826 }
827 // 2nd check if start is within proper bounds
828 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
829 std::cerr << std::endl << ">> PRunMuMinus::PrepareRawViewData(): **ERROR** start data bin doesn't make any sense!";
830 std::cerr << std::endl;
831 return false;
832 }
833 // 3rd check if end is within proper bounds
834 if ((end < 0) || (end > static_cast<Int_t>(fForward.size()))) {
835 std::cerr << std::endl << ">> PRunMuMinus::PrepareRawViewData(): **ERROR** end data bin doesn't make any sense!";
836 std::cerr << std::endl;
837 return false;
838 }
839
840 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
841 if (fRunInfo->IsFitRangeInBin()) {
842 fFitStartTime = (fRunInfo->GetDataRange(0) + fRunInfo->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
843 fFitEndTime = (fRunInfo->GetDataRange(1) - fRunInfo->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
844 }
845
846 // everything looks fine, hence fill data set
847 Int_t t0 = static_cast<Int_t>(fT0s[0]);
848 Double_t value = 0.0;
849 // data start time = (binStart - 0.5) + pack/2 - t0, with pack and binStart used as double
850 fData.SetDataTimeStart(fTimeResolution*((static_cast<Double_t>(start)-0.5) + static_cast<Double_t>(packing)/2.0 - static_cast<Double_t>(t0)));
851 fData.SetDataTimeStep(fTimeResolution*packing);
852
853 for (Int_t i=start; i<end; i++) {
854 if (((i-start) % packing == 0) && (i != start)) { // fill data
855 fData.AppendValue(value);
856 if (value == 0.0)
857 fData.AppendErrorValue(1.0);
858 else
859 fData.AppendErrorValue(TMath::Sqrt(value));
860 // reset values
861 value = 0.0;
862 }
863 value += fForward[i];
864 }
865
867
868 // fill theory vector for kView
869 // feed the parameter vector
870 std::vector<Double_t> par;
871 PMsrParamList *paramList = fMsrInfo->GetMsrParamList();
872 for (UInt_t i=0; i<paramList->size(); i++)
873 par.push_back((*paramList)[i].fValue);
874
875 // calculate functions
876 for (Int_t i=0; i<fMsrInfo->GetNoOfFuncs(); i++) {
877 fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par, fMetaData);
878 }
879
880 // calculate theory
881 UInt_t size = fForward.size();
882/* //as35
883 Double_t factor = 1.0;
884 if (fData.GetValue()->size() * 10 > fForward.size()) {
885 size = fData.GetValue()->size() * 10;
886 factor = static_cast<Double_t>(fForward.size()) / static_cast<Double_t>(size);
887 }
888 Double_t time;
889 Double_t theoryValue;
890 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
891 fData.SetTheoryTimeStep(fTimeResolution*factor);
892*/ //as35
893
894 Int_t factor = 8; // 8 times more points for the theory (if fTheoAsData == false)
895 fData.SetTheoryTimeStart(fData.GetDataTimeStart());
896 if (fTheoAsData) { // calculate theory only at the data points
897 fData.SetTheoryTimeStep(fData.GetDataTimeStep());
898 } else {
899 // finer binning for the theory (8 times as many points = factor)
900 size *= factor;
901 fData.SetTheoryTimeStep(fData.GetDataTimeStep()/(Double_t)factor);
902 }
903
904 Double_t time;
905 Double_t theoryValue;
906 for (UInt_t i=0; i<size; i++) {
907 time = fData.GetTheoryTimeStart() + i*fData.GetTheoryTimeStep();
908 theoryValue = fTheory->Func(time, par, fFuncValues);
909 if (fabs(theoryValue) > 1.0e10) { // dirty hack needs to be fixed!!
910 theoryValue = 0.0;
911 }
912 fData.AppendTheoryValue(theoryNorm*theoryValue);
913 }
914
915 // clean up
916 par.clear();
917
918 return true;
919}
920
921//--------------------------------------------------------------------------
922// GetProperT0 (private)
923//--------------------------------------------------------------------------
939Bool_t PRunMuMinus::GetProperT0(PRawRunData* runData, PMsrGlobalBlock *globalBlock, PUIntVector &histoNo)
940{
941 // feed all T0's
942 // first init T0's, T0's are stored as (forward T0, backward T0, etc.)
943 fT0s.clear();
944 fT0s.resize(histoNo.size());
945 for (UInt_t i=0; i<fT0s.size(); i++) {
946 fT0s[i] = -1.0;
947 }
948
949 // fill in the T0's from the msr-file (if present)
950 for (UInt_t i=0; i<fRunInfo->GetT0BinSize(); i++) {
951 fT0s[i] = fRunInfo->GetT0Bin(i);
952 }
953
954 // fill in the T0's from the GLOBAL block section (if present)
955 for (UInt_t i=0; i<globalBlock->GetT0BinSize(); i++) {
956 if (fT0s[i] == -1.0) { // i.e. not given in the RUN block section
957 fT0s[i] = globalBlock->GetT0Bin(i);
958 }
959 }
960
961 // fill in the T0's from the data file, if not already present in the msr-file
962 for (UInt_t i=0; i<histoNo.size(); i++) {
963 if (fT0s[i] == -1.0) { // i.e. not present in the msr-file, try the data file
964 if (runData->GetT0Bin(histoNo[i]) > 0.0) {
965 fT0s[i] = runData->GetT0Bin(histoNo[i]);
966 fRunInfo->SetT0Bin(fT0s[i], i); // keep value for the msr-file
967 }
968 }
969 }
970
971 // 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
972 for (UInt_t i=0; i<histoNo.size(); i++) {
973 if (fT0s[i] == -1.0) { // i.e. not present in the msr-file and data file, use the estimated T0
974 fT0s[i] = runData->GetT0BinEstimated(histoNo[i]);
975 fRunInfo->SetT0Bin(fT0s[i], i); // keep value for the msr-file
976
977 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!";
978 std::cerr << std::endl << ">> run: " << fRunInfo->GetRunName()->Data();
979 std::cerr << std::endl << ">> will try the estimated one: forward t0 = " << runData->GetT0BinEstimated(histoNo[i]);
980 std::cerr << std::endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!";
981 std::cerr << std::endl;
982 }
983 }
984
985 // check if t0 is within proper bounds
986 for (UInt_t i=0; i<fRunInfo->GetForwardHistoNoSize(); i++) {
987 if ((fT0s[i] < 0) || (fT0s[i] > static_cast<Int_t>(runData->GetDataBin(histoNo[i])->size()))) {
988 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **ERROR** t0 data bin (" << fT0s[i] << ") doesn't make any sense!";
989 std::cerr << std::endl;
990 return false;
991 }
992 }
993
994 // check if there are runs to be added to the current one
995 if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present
996 PRawRunData *addRunData;
997 fAddT0s.resize(fRunInfo->GetRunNameSize()-1); // resize to the number of addruns
998 for (UInt_t i=1; i<fRunInfo->GetRunNameSize(); i++) {
999
1000 // get run to be added to the main one
1001 addRunData = fRawData->GetRunData(*fRunInfo->GetRunName(i));
1002 if (addRunData == nullptr) { // couldn't get run
1003 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **ERROR** Couldn't get addrun " << fRunInfo->GetRunName(i)->Data() << "!";
1004 std::cerr << std::endl;
1005 return false;
1006 }
1007
1008 // feed all T0's
1009 // first init T0's, T0's are stored as (forward T0, backward T0, etc.)
1010 fAddT0s[i-1].resize(histoNo.size());
1011 for (UInt_t j=0; j<fAddT0s[i-1].size(); j++) {
1012 fAddT0s[i-1][j] = -1.0;
1013 }
1014
1015 // fill in the T0's from the msr-file (if present)
1016 for (UInt_t j=0; j<fRunInfo->GetT0BinSize(); j++) {
1017 fAddT0s[i-1][j] = fRunInfo->GetAddT0Bin(i-1,j); // addRunIdx starts at 0
1018 }
1019
1020 // fill in the T0's from the data file, if not already present in the msr-file
1021 for (UInt_t j=0; j<histoNo.size(); j++) {
1022 if (fAddT0s[i-1][j] == -1.0) // i.e. not present in the msr-file, try the data file
1023 if (addRunData->GetT0Bin(histoNo[j]) > 0.0) {
1024 fAddT0s[i-1][j] = addRunData->GetT0Bin(histoNo[j]);
1025 fRunInfo->SetAddT0Bin(fAddT0s[i-1][j], i-1, j); // keep value for the msr-file
1026 }
1027 }
1028
1029 // 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
1030 for (UInt_t j=0; j<histoNo.size(); j++) {
1031 if (fAddT0s[i-1][j] == -1.0) { // i.e. not present in the msr-file and data file, use the estimated T0
1032 fAddT0s[i-1][j] = addRunData->GetT0BinEstimated(histoNo[j]);
1033 fRunInfo->SetAddT0Bin(fAddT0s[i-1][j], i-1, j); // keep value for the msr-file
1034
1035 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!";
1036 std::cerr << std::endl << ">> run: " << fRunInfo->GetRunName(i)->Data();
1037 std::cerr << std::endl << ">> will try the estimated one: forward t0 = " << addRunData->GetT0BinEstimated(histoNo[j]);
1038 std::cerr << std::endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!";
1039 std::cerr << std::endl;
1040 }
1041 }
1042
1043 // check if t0 is within proper bounds
1044 for (UInt_t j=0; j<fRunInfo->GetForwardHistoNoSize(); j++) {
1045 if ((fAddT0s[i-1][j] < 0) || (fAddT0s[i-1][j] > static_cast<Int_t>(addRunData->GetDataBin(histoNo[j])->size()))) {
1046 std::cerr << std::endl << ">> PRunMuMinus::GetProperT0(): **ERROR** addt0 data bin (" << fAddT0s[i-1][j] << ") doesn't make any sense!";
1047 std::cerr << std::endl;
1048 return false;
1049 }
1050 }
1051 }
1052 }
1053
1054 return true;
1055}
1056
1057//--------------------------------------------------------------------------
1058// GetProperDataRange (private)
1059//--------------------------------------------------------------------------
1071{
1072 // get start/end data
1073 Int_t start;
1074 Int_t end;
1075 start = fRunInfo->GetDataRange(0);
1076 end = fRunInfo->GetDataRange(1);
1077
1078 // check if data range has been given in the RUN block, if not try to get it from the GLOBAL block
1079 if (start < 0) {
1080 start = fMsrInfo->GetMsrGlobal()->GetDataRange(0);
1081 }
1082 if (end < 0) {
1083 end = fMsrInfo->GetMsrGlobal()->GetDataRange(1);
1084 }
1085
1086 // check if data range has been provided, and if not try to estimate them
1087 if (start < 0) {
1088 Int_t offset = static_cast<Int_t>(10.0e-3/fTimeResolution);
1089 start = static_cast<Int_t>(fT0s[0])+offset;
1090 fRunInfo->SetDataRange(start, 0);
1091 std::cerr << std::endl << ">> PRunMuMinus::GetProperDataRange(): **WARNING** data range was not provided, will try data range start = t0+" << offset << "(=10ns) = " << start << ".";
1092 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1093 std::cerr << std::endl;
1094 }
1095 if (end < 0) {
1096 end = fForward.size();
1097 fRunInfo->SetDataRange(end, 1);
1098 std::cerr << std::endl << ">> PRunMuMinus::GetProperDataRange(): **WARNING** data range was not provided, will try data range end = " << end << ".";
1099 std::cerr << std::endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE.";
1100 std::cerr << std::endl;
1101 }
1102
1103 // check if start and end make any sense
1104 // 1st check if start and end are in proper order
1105 if (end < start) { // need to swap them
1106 Int_t keep = end;
1107 end = start;
1108 start = keep;
1109 }
1110 // 2nd check if start is within proper bounds
1111 if ((start < 0) || (start > static_cast<Int_t>(fForward.size()))) {
1112 std::cerr << std::endl << ">> PRunMuMinus::GetProperDataRange(): **ERROR** start data bin (" << start << ") doesn't make any sense!";
1113 std::cerr << std::endl;
1114 return false;
1115 }
1116 // 3rd check if end is within proper bounds
1117 if ((end < 0) || (end > static_cast<Int_t>(fForward.size()))) {
1118 std::cerr << std::endl << ">> PRunMuMinus::GetProperDataRange(): **ERROR** end data bin (" << end << ") doesn't make any sense!";
1119 std::cerr << std::endl;
1120 return false;
1121 }
1122
1123 // keep good bins for potential later use
1124 fGoodBins[0] = start;
1125 fGoodBins[1] = end;
1126
1127 return true;
1128}
1129
1130//--------------------------------------------------------------------------
1131// GetProperFitRange (private)
1132//--------------------------------------------------------------------------
1146{
1147 // set fit start/end time; first check RUN Block
1148 fFitStartTime = fRunInfo->GetFitRange(0);
1149 fFitEndTime = fRunInfo->GetFitRange(1);
1150 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
1151 if (fRunInfo->IsFitRangeInBin()) {
1152 fFitStartTime = (fGoodBins[0] + fRunInfo->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
1153 fFitEndTime = (fGoodBins[1] - fRunInfo->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
1154 // write these times back into the data structure. This way it is available when writting the log-file
1155 fRunInfo->SetFitRange(fFitStartTime, 0);
1156 fRunInfo->SetFitRange(fFitEndTime, 1);
1157 }
1158 if (fFitStartTime == PMUSR_UNDEFINED) { // fit start/end NOT found in the RUN block, check GLOBAL block
1159 fFitStartTime = globalBlock->GetFitRange(0);
1160 fFitEndTime = globalBlock->GetFitRange(1);
1161 // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now
1162 if (globalBlock->IsFitRangeInBin()) {
1163 fFitStartTime = (fGoodBins[0] + globalBlock->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt
1164 fFitEndTime = (fGoodBins[1] - globalBlock->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt
1165 // write these times back into the data structure. This way it is available when writting the log-file
1166 globalBlock->SetFitRange(fFitStartTime, 0);
1167 globalBlock->SetFitRange(fFitEndTime, 1);
1168 }
1169 }
1171 fFitStartTime = (fGoodBins[0] - fT0s[0]) * fTimeResolution; // (fgb-t0)*dt
1172 fFitEndTime = (fGoodBins[1] - fT0s[0]) * fTimeResolution; // (lgb-t0)*dt
1173 std::cerr << ">> PRunMuMinus::GetProperFitRange(): **WARNING** Couldn't get fit start/end time!" << std::endl;
1174 std::cerr << ">> Will set it to fgb/lgb which given in time is: " << fFitStartTime << "..." << fFitEndTime << " (usec)" << std::endl;
1175 }
1176}
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).
static std::vector< std::string > Split(const std::string &str, const std::string &delimiters)