/*************************************************************************** PRunAsymmetry.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch $Id$ ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2012 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_GOMP #include #endif #include #include using namespace std; #include #include #include #include "PMusr.h" #include "PRunAsymmetry.h" //-------------------------------------------------------------------------- // Constructor //-------------------------------------------------------------------------- /** *

Constructor */ PRunAsymmetry::PRunAsymmetry() : PRunBase() { fNoOfFitBins = 0; // the 2 following variables are need in case fit range is given in bins, and since // the fit range can be changed in the command block, these variables need to be accessible fGoodBins[0] = -1; fGoodBins[1] = -1; } //-------------------------------------------------------------------------- // Constructor //-------------------------------------------------------------------------- /** *

Constructor * * \param msrInfo pointer to the msr-file handler * \param rawData raw run data * \param runNo number of the run within the msr-file * \param tag tag showing what shall be done: kFit == fitting, kView == viewing */ PRunAsymmetry::PRunAsymmetry(PMsrHandler *msrInfo, PRunDataHandler *rawData, UInt_t runNo, EPMusrHandleTag tag) : PRunBase(msrInfo, rawData, runNo, tag) { // the 2 following variables are need in case fit range is given in bins, and since // the fit range can be changed in the command block, these variables need to be accessible fGoodBins[0] = -1; fGoodBins[1] = -1; // check if alpha and/or beta is fixed -------------------- PMsrParamList *param = msrInfo->GetMsrParamList(); // check if alpha is given if (fRunInfo->GetAlphaParamNo() == -1) { // no alpha given cerr << endl << ">> PRunAsymmetry::PRunAsymmetry(): **ERROR** no alpha parameter given! This is needed for an asymmetry fit!"; cerr << endl; fValid = false; return; } // check if alpha parameter is within proper bounds if ((fRunInfo->GetAlphaParamNo() < 0) || (fRunInfo->GetAlphaParamNo() > (Int_t)param->size())) { cerr << endl << ">> PRunAsymmetry::PRunAsymmetry(): **ERROR** alpha parameter no = " << fRunInfo->GetAlphaParamNo(); cerr << endl << ">> This is out of bound, since there are only " << param->size() << " parameters."; cerr << endl; fValid = false; return; } // check if alpha is fixed Bool_t alphaFixedToOne = false; if (((*param)[fRunInfo->GetAlphaParamNo()-1].fStep == 0.0) && ((*param)[fRunInfo->GetAlphaParamNo()-1].fValue == 1.0)) alphaFixedToOne = true; // check if beta is given Bool_t betaFixedToOne = false; if (fRunInfo->GetBetaParamNo() == -1) { // no beta given hence assuming beta == 1 betaFixedToOne = true; } else if ((fRunInfo->GetBetaParamNo() < 0) || (fRunInfo->GetBetaParamNo() > (Int_t)param->size())) { // check if beta parameter is within proper bounds cerr << endl << ">> PRunAsymmetry::PRunAsymmetry(): **ERROR** beta parameter no = " << fRunInfo->GetBetaParamNo(); cerr << endl << ">> This is out of bound, since there are only " << param->size() << " parameters."; cerr << endl; fValid = false; return; } else { // check if beta is fixed if (((*param)[fRunInfo->GetBetaParamNo()-1].fStep == 0.0) && ((*param)[fRunInfo->GetBetaParamNo()-1].fValue == 1.0)) betaFixedToOne = true; } // set fAlphaBetaTag if (alphaFixedToOne && betaFixedToOne) // alpha == 1, beta == 1 fAlphaBetaTag = 1; else if (!alphaFixedToOne && betaFixedToOne) // alpha != 1, beta == 1 fAlphaBetaTag = 2; else if (alphaFixedToOne && !betaFixedToOne) // alpha == 1, beta != 1 fAlphaBetaTag = 3; else fAlphaBetaTag = 4; // calculate fData if (!PrepareData()) fValid = false; } //-------------------------------------------------------------------------- // Destructor //-------------------------------------------------------------------------- /** *

Destructor. */ PRunAsymmetry::~PRunAsymmetry() { fForward.clear(); fForwardErr.clear(); fBackward.clear(); fBackwardErr.clear(); } //-------------------------------------------------------------------------- // CalcChiSquare (public) //-------------------------------------------------------------------------- /** *

Calculate chi-square. * * return: * - chisq value * * \param par parameter vector iterated by minuit2 */ Double_t PRunAsymmetry::CalcChiSquare(const std::vector& par) { Double_t chisq = 0.0; Double_t diff = 0.0; Double_t asymFcnValue = 0.0; Double_t a, b, f; // calculate functions for (Int_t i=0; iGetNoOfFuncs(); i++) { fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par); } // calculate chi square Double_t time(1.0); Int_t i, N(static_cast(fData.GetValue()->size())); // In order not to have an IF in the next loop, determine the start and end bins for the fit range now Int_t startTimeBin = static_cast(ceil((fFitStartTime - fData.GetDataTimeStart())/fData.GetDataTimeStep())); if (startTimeBin < 0) startTimeBin = 0; Int_t endTimeBin = static_cast(floor((fFitEndTime - fData.GetDataTimeStart())/fData.GetDataTimeStep())) + 1; if (endTimeBin > N) endTimeBin = N; // Calculate the theory function once to ensure one function evaluation for the current set of parameters. // This is needed for the LF and user functions where some non-thread-save calculations only need to be calculated once // for a given set of parameters---which should be done outside of the parallelized loop. // For all other functions it means a tiny and acceptable overhead. asymFcnValue = fTheory->Func(time, par, fFuncValues); #ifdef HAVE_GOMP Int_t chunk = (endTimeBin - startTimeBin)/omp_get_num_procs(); if (chunk < 10) chunk = 10; #pragma omp parallel for default(shared) private(i,time,diff,asymFcnValue,a,b,f) schedule(dynamic,chunk) reduction(+:chisq) #endif for (i=startTimeBin; i < endTimeBin; ++i) { time = fData.GetDataTimeStart() + (Double_t)i*fData.GetDataTimeStep(); switch (fAlphaBetaTag) { case 1: // alpha == 1, beta == 1 asymFcnValue = fTheory->Func(time, par, fFuncValues); break; case 2: // alpha != 1, beta == 1 a = par[fRunInfo->GetAlphaParamNo()-1]; f = fTheory->Func(time, par, fFuncValues); asymFcnValue = (f*(a+1.0)-(a-1.0))/((a+1.0)-f*(a-1.0)); break; case 3: // alpha == 1, beta != 1 b = par[fRunInfo->GetBetaParamNo()-1]; f = fTheory->Func(time, par, fFuncValues); asymFcnValue = f*(b+1.0)/(2.0-f*(b-1.0)); break; case 4: // alpha != 1, beta != 1 a = par[fRunInfo->GetAlphaParamNo()-1]; b = par[fRunInfo->GetBetaParamNo()-1]; f = fTheory->Func(time, par, fFuncValues); asymFcnValue = (f*(a*b+1.0)-(a-1.0))/((a+1.0)-f*(a*b-1.0)); break; default: asymFcnValue = 0.0; break; } diff = fData.GetValue()->at(i) - asymFcnValue; chisq += diff*diff / (fData.GetError()->at(i)*fData.GetError()->at(i)); } return chisq; } //-------------------------------------------------------------------------- // CalcChiSquareExpected (public) //-------------------------------------------------------------------------- /** *

Calculate expected chi-square. Currently not implemented since not clear what to be done. * * return: * - chisq value == 0.0 * * \param par parameter vector iterated by minuit2 */ Double_t PRunAsymmetry::CalcChiSquareExpected(const std::vector& par) { return 0.0; } //-------------------------------------------------------------------------- // CalcMaxLikelihood (public) //-------------------------------------------------------------------------- /** *

NOT IMPLEMENTED!! * * \param par parameter vector iterated by minuit2 */ Double_t PRunAsymmetry::CalcMaxLikelihood(const std::vector& par) { cout << endl << "PRunAsymmetry::CalcMaxLikelihood(): not implemented yet ..." << endl; return 1.0; } //-------------------------------------------------------------------------- // GetNoOfFitBins (public) //-------------------------------------------------------------------------- /** *

Calculate the number of fitted bins for the current fit range. * * return: number of fitted bins. */ UInt_t PRunAsymmetry::GetNoOfFitBins() { CalcNoOfFitBins(); return fNoOfFitBins; } //-------------------------------------------------------------------------- // SetFitRangeBin (public) //-------------------------------------------------------------------------- /** *

Allows to change the fit range on the fly. Used in the COMMAND block. * The syntax of the string is: FIT_RANGE fgb[+n00] lgb[-n01] [fgb[+n10] lgb[-n11] ... fgb[+nN0] lgb[-nN1]]. * If only one pair of fgb/lgb is given, it is used for all runs in the RUN block section. * If multiple fgb/lgb's are given, the number N has to be the number of RUN blocks in * the msr-file. * *

nXY are offsets which can be used to shift, limit the fit range. * * \param fitRange string containing the necessary information. */ void PRunAsymmetry::SetFitRangeBin(const TString fitRange) { TObjArray *tok = 0; TObjString *ostr = 0; TString str; Ssiz_t idx = -1; Int_t offset = 0; tok = fitRange.Tokenize(" \t"); if (tok->GetEntries() == 3) { // structure FIT_RANGE fgb+n0 lgb-n1 // handle fgb+n0 entry ostr = (TObjString*) tok->At(1); str = ostr->GetString(); // check if there is an offset present idx = str.First("+"); if (idx != -1) { // offset present str.Remove(0, idx+1); if (str.IsFloat()) // if str is a valid number, convert is to an integer offset = str.Atoi(); } fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution; // handle lgb-n1 entry ostr = (TObjString*) tok->At(2); str = ostr->GetString(); // check if there is an offset present idx = str.First("-"); if (idx != -1) { // offset present str.Remove(0, idx+1); if (str.IsFloat()) // if str is a valid number, convert is to an integer offset = str.Atoi(); } fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution; } else if ((tok->GetEntries() > 3) && (tok->GetEntries() % 2 == 1)) { // structure FIT_RANGE fgb[+n00] lgb[-n01] [fgb[+n10] lgb[-n11] ... fgb[+nN0] lgb[-nN1]] Int_t pos = 2*(fRunNo+1)-1; if (pos + 1 >= tok->GetEntries()) { cerr << endl << ">> PRunSingleHisto::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'"; cerr << endl << ">> will ignore it. Sorry ..." << endl; } else { // handle fgb+n0 entry ostr = (TObjString*) tok->At(pos); str = ostr->GetString(); // check if there is an offset present idx = str.First("+"); if (idx != -1) { // offset present str.Remove(0, idx+1); if (str.IsFloat()) // if str is a valid number, convert is to an integer offset = str.Atoi(); } fFitStartTime = (fGoodBins[0] + offset - fT0s[0]) * fTimeResolution; // handle lgb-n1 entry ostr = (TObjString*) tok->At(pos+1); str = ostr->GetString(); // check if there is an offset present idx = str.First("-"); if (idx != -1) { // offset present str.Remove(0, idx+1); if (str.IsFloat()) // if str is a valid number, convert is to an integer offset = str.Atoi(); } fFitEndTime = (fGoodBins[1] - offset - fT0s[0]) * fTimeResolution; } } else { // error cerr << endl << ">> PRunSingleHisto::SetFitRangeBin(): **ERROR** invalid FIT_RANGE command found: '" << fitRange << "'"; cerr << endl << ">> will ignore it. Sorry ..." << endl; } // clean up if (tok) { delete tok; } } //-------------------------------------------------------------------------- // CalcNoOfFitBins (protected) //-------------------------------------------------------------------------- /** *

Calculate the number of fitted bins for the current fit range. */ void PRunAsymmetry::CalcNoOfFitBins() { // In order not having to loop over all bins and to stay consistent with the chisq method, calculate the start and end bins explicitly Int_t startTimeBin = static_cast(ceil((fFitStartTime - fData.GetDataTimeStart())/fData.GetDataTimeStep())); if (startTimeBin < 0) startTimeBin = 0; Int_t endTimeBin = static_cast(floor((fFitEndTime - fData.GetDataTimeStart())/fData.GetDataTimeStep())) + 1; if (endTimeBin > static_cast(fData.GetValue()->size())) endTimeBin = fData.GetValue()->size(); if (endTimeBin > startTimeBin) fNoOfFitBins = endTimeBin - startTimeBin; else fNoOfFitBins = 0; } //-------------------------------------------------------------------------- // CalcTheory (protected) //-------------------------------------------------------------------------- /** *

Calculate theory for a given set of fit-parameters. */ void PRunAsymmetry::CalcTheory() { // feed the parameter vector std::vector par; PMsrParamList *paramList = fMsrInfo->GetMsrParamList(); for (UInt_t i=0; isize(); i++) par.push_back((*paramList)[i].fValue); // calculate functions for (Int_t i=0; iGetNoOfFuncs(); i++) { fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par); } // calculate asymmetry Double_t asymFcnValue = 0.0; Double_t a, b, f; Double_t time; for (UInt_t i=0; isize(); i++) { time = fData.GetDataTimeStart() + (Double_t)i*fData.GetDataTimeStep(); switch (fAlphaBetaTag) { case 1: // alpha == 1, beta == 1 asymFcnValue = fTheory->Func(time, par, fFuncValues); break; case 2: // alpha != 1, beta == 1 a = par[fRunInfo->GetAlphaParamNo()-1]; f = fTheory->Func(time, par, fFuncValues); asymFcnValue = (f*(a+1.0)-(a-1.0))/((a+1.0)-f*(a-1.0)); break; case 3: // alpha == 1, beta != 1 b = par[fRunInfo->GetBetaParamNo()-1]; f = fTheory->Func(time, par, fFuncValues); asymFcnValue = f*(b+1.0)/(2.0-f*(b-1.0)); break; case 4: // alpha != 1, beta != 1 a = par[fRunInfo->GetAlphaParamNo()-1]; b = par[fRunInfo->GetBetaParamNo()-1]; f = fTheory->Func(time, par, fFuncValues); asymFcnValue = (f*(a*b+1.0)-(a-1.0))/((a+1.0)-f*(a*b-1.0)); break; default: asymFcnValue = 0.0; break; } fData.AppendTheoryValue(asymFcnValue); } // clean up par.clear(); } //-------------------------------------------------------------------------- // PrepareData (protected) //-------------------------------------------------------------------------- /** *

Prepare data for fitting or viewing. What is already processed at this stage: * - get all needed forward/backward histograms * - get time resolution * - get start/stop fit time * - get t0's and perform necessary cross checks (e.g. if t0 of msr-file (if present) are consistent with t0 of the data files, etc.) * - add runs (if addruns are present) * - group histograms (if grouping is present) * - subtract background * * Error propagation for \f$ A_i = (f_i^{\rm c}-b_i^{\rm c})/(f_i^{\rm c}+b_i^{\rm c})\f$: * \f[ \Delta A_i = \pm\frac{2}{(f_i^{\rm c}+b_i^{\rm c})^2}\left[ * (b_i^{\rm c})^2 (\Delta f_i^{\rm c})^2 + * (\Delta b_i^{\rm c})^2 (f_i^{\rm c})^2\right]^{1/2}\f] * * return: * - true if everthing went smooth * - false, otherwise. */ Bool_t PRunAsymmetry::PrepareData() { // get forward/backward histo from PRunDataHandler object ------------------------ // get the correct run PRawRunData *runData = fRawData->GetRunData(*(fRunInfo->GetRunName())); if (!runData) { // run not found cerr << endl << ">> PRunAsymmetry::PrepareData(): **ERROR** Couldn't get run " << fRunInfo->GetRunName()->Data() << "!"; cerr << endl; return false; } // keep the time resolution in (us) fTimeResolution = runData->GetTimeResolution()/1.0e3; cout.precision(10); cout << endl << ">> PRunAsymmetry::PrepareData(): time resolution=" << fixed << runData->GetTimeResolution() << "(ns)" << endl; // collect histogram numbers PUIntVector forwardHistoNo; PUIntVector backwardHistoNo; for (UInt_t i=0; iGetForwardHistoNoSize(); i++) { forwardHistoNo.push_back(fRunInfo->GetForwardHistoNo(i)); if (!runData->IsPresent(forwardHistoNo[i])) { cerr << endl << ">> PRunAsymmetry::PrepareData(): **PANIC ERROR**:"; cerr << endl << ">> forwardHistoNo found = " << forwardHistoNo[i] << ", which is NOT present in the data file!?!?"; cerr << endl << ">> Will quit :-("; cerr << endl; // clean up forwardHistoNo.clear(); backwardHistoNo.clear(); return false; } } for (UInt_t i=0; iGetBackwardHistoNoSize(); i++) { backwardHistoNo.push_back(fRunInfo->GetBackwardHistoNo(i)); if (!runData->IsPresent(backwardHistoNo[i])) { cerr << endl << ">> PRunAsymmetry::PrepareData(): **PANIC ERROR**:"; cerr << endl << ">> backwardHistoNo found = " << backwardHistoNo[i] << ", which is NOT present in the data file!?!?"; cerr << endl << ">> Will quit :-("; cerr << endl; // clean up forwardHistoNo.clear(); backwardHistoNo.clear(); return false; } } if (forwardHistoNo.size() != backwardHistoNo.size()) { cerr << endl << ">> PRunAsymmetry::PrepareData(): **PANIC ERROR**:"; cerr << endl << ">> # of forward histograms different from # of backward histograms."; cerr << endl << ">> Will quit :-("; cerr << endl; // clean up forwardHistoNo.clear(); backwardHistoNo.clear(); return false; } // feed all T0's // first init T0's, T0's are stored as (forward T0, backward T0, etc.) fT0s.clear(); fT0s.resize(2*forwardHistoNo.size()); for (UInt_t i=0; iGetT0BinSize(); i++) { fT0s[i] = fRunInfo->GetT0Bin(i); } // fill in the T0's from the data file, if not already present in the msr-file for (UInt_t i=0; iGetT0Bin(forwardHistoNo[i]) > 0.0) { fT0s[2*i] = runData->GetT0Bin(forwardHistoNo[i]); fRunInfo->SetT0Bin(fT0s[2*i], 2*i); } } for (UInt_t i=0; iGetT0Bin(backwardHistoNo[i]) > 0.0) { fT0s[2*i+1] = runData->GetT0Bin(backwardHistoNo[i]); fRunInfo->SetT0Bin(fT0s[2*i+1], 2*i+1); } } // 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 for (UInt_t i=0; iGetT0BinEstimated(forwardHistoNo[i]); fRunInfo->SetT0Bin(fT0s[2*i], 2*i); cerr << endl << ">> PRunAsymmetry::PrepareData(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!"; cerr << endl << ">> run: " << fRunInfo->GetRunName(); cerr << endl << ">> will try the estimated one: forward t0 = " << runData->GetT0BinEstimated(forwardHistoNo[i]); cerr << endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!"; cerr << endl; } } for (UInt_t i=0; iGetT0BinEstimated(backwardHistoNo[i]); fRunInfo->SetT0Bin(fT0s[2*i+1], 2*i+1); cerr << endl << ">> PRunAsymmetry::PrepareData(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!"; cerr << endl << ">> run: " << fRunInfo->GetRunName(); cerr << endl << ">> will try the estimated one: backward t0 = " << runData->GetT0BinEstimated(backwardHistoNo[i]); cerr << endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!"; cerr << endl; } } // check if t0 is within proper bounds for (UInt_t i=0; i (Int_t)runData->GetDataBin(forwardHistoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareData(): **ERROR** t0 data bin (" << fT0s[2*i] << ") doesn't make any sense!"; cerr << endl << ">> forwardHistoNo " << forwardHistoNo[i]; cerr << endl; return false; } if ((fT0s[2*i+1] < 0) || (fT0s[2*i+1] > (Int_t)runData->GetDataBin(backwardHistoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareData(): **ERROR** t0 data bin (" << fT0s[2*i+1] << ") doesn't make any sense!"; cerr << endl << ">> backwardHistoNo " << backwardHistoNo[i]; cerr << endl; return false; } } // keep the histo of each group at this point (addruns handled below) vector forward, backward; forward.resize(forwardHistoNo.size()); // resize to number of groups backward.resize(backwardHistoNo.size()); // resize to numer of groups for (UInt_t i=0; iGetDataBin(forwardHistoNo[i])->size()); backward[i].resize(runData->GetDataBin(backwardHistoNo[i])->size()); forward[i] = *runData->GetDataBin(forwardHistoNo[i]); backward[i] = *runData->GetDataBin(backwardHistoNo[i]); } // check if addrun's are present, and if yes add data // check if there are runs to be added to the current one if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present PRawRunData *addRunData; for (UInt_t i=1; iGetRunNameSize(); i++) { // get run to be added to the main one addRunData = fRawData->GetRunData(*(fRunInfo->GetRunName(i))); if (addRunData == 0) { // couldn't get run cerr << endl << ">> PRunAsymmetry::PrepareData(): **ERROR** Couldn't get addrun " << fRunInfo->GetRunName(i)->Data() << "!"; cerr << endl; return false; } // get T0's of the to be added run PDoubleVector t0Add; // feed all T0's // first init T0's, T0's are stored as (forward T0, backward T0, etc.) t0Add.clear(); t0Add.resize(2*forwardHistoNo.size()); for (UInt_t j=0; jGetAddT0BinSize(i); j++) { t0Add[j] = fRunInfo->GetAddT0Bin(i, j); } // fill in the T0's from the data file, if not already present in the msr-file for (UInt_t j=0; jGetT0Bin(forwardHistoNo[j]) > 0.0) { t0Add[2*j] = addRunData->GetT0Bin(forwardHistoNo[j]); fRunInfo->SetAddT0Bin(t0Add[2*j], i-1, 2*j); } } for (UInt_t j=0; jGetT0Bin(backwardHistoNo[j]) > 0.0) { t0Add[2*j+1] = addRunData->GetT0Bin(backwardHistoNo[j]); fRunInfo->SetAddT0Bin(t0Add[2*j+1], i-1, 2*j+1); } } // 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 for (UInt_t j=0; jGetT0BinEstimated(forwardHistoNo[j]); fRunInfo->SetAddT0Bin(t0Add[2*j], i-1, 2*j); cerr << endl << ">> PRunAsymmetry::PrepareData(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!"; cerr << endl << ">> run: " << fRunInfo->GetRunName(i); cerr << endl << ">> will try the estimated one: forward t0 = " << addRunData->GetT0BinEstimated(forwardHistoNo[j]); cerr << endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!"; cerr << endl; } } for (UInt_t j=0; jGetT0BinEstimated(backwardHistoNo[j]); fRunInfo->SetAddT0Bin(t0Add[2*j+1], i-1, 2*j+1); cerr << endl << ">> PRunAsymmetry::PrepareData(): **WARRNING** NO t0's found, neither in the run data nor in the msr-file!"; cerr << endl << ">> run: " << fRunInfo->GetRunName(i); cerr << endl << ">> will try the estimated one: backward t0 = " << runData->GetT0BinEstimated(backwardHistoNo[j]); cerr << endl << ">> NO WARRANTY THAT THIS OK!! For instance for LEM this is almost for sure rubbish!"; cerr << endl; } } // add forward run UInt_t addRunSize; for (UInt_t k=0; kGetDataBin(forwardHistoNo[k])->size(); for (UInt_t j=0; jGetDataBin(forwardHistoNo[k])->size(); j++) { // loop over the bin indices // make sure that the index stays in the proper range if ((j+(Int_t)t0Add[2*k]-(Int_t)fT0s[2*k] >= 0) && (j+(Int_t)t0Add[2*k]-(Int_t)fT0s[2*k] < addRunSize)) { forward[k][j] += addRunData->GetDataBin(forwardHistoNo[k])->at(j+(Int_t)t0Add[2*k]-(Int_t)fT0s[2*k]); } } } // add backward run for (UInt_t k=0; kGetDataBin(backwardHistoNo[k])->size(); for (UInt_t j=0; jGetDataBin(backwardHistoNo[k])->size(); j++) { // loop over the bin indices // make sure that the index stays in the proper range if ((j+(Int_t)t0Add[2*k+1]-(Int_t)fT0s[2*k+1] >= 0) && (j+(Int_t)t0Add[2*k+1]-(Int_t)fT0s[2*k+1] < addRunSize)) { backward[k][j] += addRunData->GetDataBin(backwardHistoNo[k])->at(j+(Int_t)t0Add[2*k+1]-(Int_t)fT0s[2*k+1]); } } } // clean up t0Add.clear(); } } // set forward/backward histo data of the first group fForward.resize(forward[0].size()); fBackward.resize(backward[0].size()); for (UInt_t i=0; iGetDataBin(forwardHistoNo[i])->size(); j++) { // loop over the bin indices // make sure that the index stays within proper range if ((j+fT0s[2*i]-fT0s[0] >= 0) && (j+fT0s[2*i]-fT0s[0] < runData->GetDataBin(forwardHistoNo[i])->size())) { fForward[j] += forward[i][j+(Int_t)fT0s[2*i]-(Int_t)fT0s[0]]; } } } // group histograms, add all the remaining backward histograms of the group for (UInt_t i=1; iGetDataBin(backwardHistoNo[i])->size(); j++) { // loop over the bin indices // make sure that the index stays within proper range if ((j+fT0s[2*i+1]-fT0s[1] >= 0) && (j+fT0s[2*i+1]-fT0s[1] < runData->GetDataBin(backwardHistoNo[i])->size())) { fBackward[j] += backward[i][j+(Int_t)fT0s[2*i+1]-(Int_t)fT0s[1]]; } } } // subtract background from histogramms ------------------------------------------ if (fRunInfo->GetBkgFix(0) == PMUSR_UNDEFINED) { // no fixed background given if (fRunInfo->GetBkgRange(0) >= 0) { if (!SubtractEstimatedBkg()) return false; } else { // no background given to do the job, try to estimate it fRunInfo->SetBkgRange(static_cast(fT0s[0]*0.1), 0); fRunInfo->SetBkgRange(static_cast(fT0s[0]*0.6), 1); fRunInfo->SetBkgRange(static_cast(fT0s[1]*0.1), 2); fRunInfo->SetBkgRange(static_cast(fT0s[1]*0.6), 3); cerr << endl << ">> PRunAsymmetry::PrepareData(): **WARNING** Neither fix background nor background bins are given!"; cerr << endl << ">> Will try the following:"; cerr << endl << ">> forward: bkg start = " << fRunInfo->GetBkgRange(0) << ", bkg end = " << fRunInfo->GetBkgRange(1); cerr << endl << ">> backward: bkg start = " << fRunInfo->GetBkgRange(2) << ", bkg end = " << fRunInfo->GetBkgRange(3); cerr << endl << ">> NO WARRANTY THAT THIS MAKES ANY SENSE! Better check ..."; cerr << endl; if (!SubtractEstimatedBkg()) return false; } } else { // fixed background given if (!SubtractFixBkg()) return false; } // everything looks fine, hence fill data set UInt_t histoNo[2] = {forwardHistoNo[0], backwardHistoNo[0]}; Bool_t status; switch(fHandleTag) { case kFit: status = PrepareFitData(runData, histoNo); break; case kView: if (fMsrInfo->GetMsrPlotList()->at(0).fRRFPacking == 0) status = PrepareViewData(runData, histoNo); else status = PrepareRRFViewData(runData, histoNo); break; default: status = false; break; } // clean up forwardHistoNo.clear(); backwardHistoNo.clear(); return status; } //-------------------------------------------------------------------------- // SubtractFixBkg (private) //-------------------------------------------------------------------------- /** *

Subtracts a fixed background from the raw data. The background is given * in units of (1/ns). The error propagation * is done the following way: it is assumed that the error of the background * is Poisson like, i.e. \f$\Delta\mathrm{bkg} = \sqrt{\mathrm{bkg}}\f$. * * Error propagation: * \f[ \Delta f_i^{\rm c} = \pm\left[ (\Delta f_i)^2 + (\Delta \mathrm{bkg})^2 \right]^{1/2} = * \pm\left[ f_i + \mathrm{bkg} \right]^{1/2}, \f] * where \f$ f_i^{\rm c} \f$ is the background corrected histogram, \f$ f_i \f$ the raw histogram * and \f$ \mathrm{bkg} \f$ the fix given background. * * return: * - true * */ Bool_t PRunAsymmetry::SubtractFixBkg() { Double_t dval; for (UInt_t i=0; iGetBkgFix(0) * fTimeResolution * 1.0e3; // bkg per ns -> bkg per bin; 1.0e3: us -> ns if (fBackward[i] != 0.0) dval = TMath::Sqrt(fBackward[i]); else dval = 1.0; fBackwardErr.push_back(dval); fBackward[i] -= fRunInfo->GetBkgFix(1) * fTimeResolution * 1.0e3; // bkg per ns -> bkg per bin; 1.0e3: us -> ns } return true; } //-------------------------------------------------------------------------- // SubtractEstimatedBkg (private) //-------------------------------------------------------------------------- /** *

Subtracts the background which is estimated from a given interval (typically before t0). * * The background corrected histogramms are: * \f$ f_i^{\rm c} = f_i - \mathrm{bkg} \f$, where \f$ f_i \f$ is the raw data histogram, * \f$ \mathrm{bkg} \f$ the background estimate, and \f$ f_i^{\rm c} \f$ background corrected * histogram. The error on \f$ f_i^{\rm c} \f$ is * \f[ \Delta f_i^{\rm c} = \pm \sqrt{ (\Delta f_i)^2 + (\Delta \mathrm{bkg})^2 } = * \pm \sqrt{f_i + (\Delta \mathrm{bkg})^2} \f] * The background error \f$ \Delta \mathrm{bkg} \f$ is * \f[ \Delta \mathrm{bkg} = \pm\frac{1}{N}\left[\sum_{i=0}^N (\Delta f_i)^2\right]^{1/2} = * \pm\frac{1}{N}\left[\sum_{i=0}^N f_i \right]^{1/2},\f] * where \f$N\f$ is the number of bins over which the background is formed. * * return: * - true */ Bool_t PRunAsymmetry::SubtractEstimatedBkg() { Double_t beamPeriod = 0.0; // check if data are from PSI, RAL, or TRIUMF if (fRunInfo->GetInstitute()->Contains("psi")) beamPeriod = ACCEL_PERIOD_PSI; else if (fRunInfo->GetInstitute()->Contains("ral")) beamPeriod = ACCEL_PERIOD_RAL; else if (fRunInfo->GetInstitute()->Contains("triumf")) beamPeriod = ACCEL_PERIOD_TRIUMF; else beamPeriod = 0.0; // check if start and end are in proper order UInt_t start[2] = {fRunInfo->GetBkgRange(0), fRunInfo->GetBkgRange(2)}; UInt_t end[2] = {fRunInfo->GetBkgRange(1), fRunInfo->GetBkgRange(3)}; for (UInt_t i=0; i<2; i++) { if (end[i] < start[i]) { cout << endl << "PRunAsymmetry::SubtractEstimatedBkg(): end = " << end[i] << " > start = " << start[i] << "! Will swap them!"; UInt_t keep = end[i]; end[i] = start[i]; start[i] = keep; } } // calculate proper background range for (UInt_t i=0; i<2; i++) { if (beamPeriod != 0.0) { Double_t timeBkg = (Double_t)(end[i]-start[i])*(fTimeResolution*fRunInfo->GetPacking()); // length of the background intervall in time UInt_t fullCycles = (UInt_t)(timeBkg/beamPeriod); // how many proton beam cylces can be placed within the proposed background intervall // correct the end of the background intervall such that the background is as close as possible to a multiple of the proton cylce end[i] = start[i] + (UInt_t) ((fullCycles*beamPeriod)/(fTimeResolution*fRunInfo->GetPacking())); cout << "PRunAsymmetry::SubtractEstimatedBkg(): Background " << start[i] << ", " << end[i] << endl; if (end[i] == start[i]) end[i] = fRunInfo->GetBkgRange(2*i+1); } } // check if start is within histogram bounds if ((start[0] < 0) || (start[0] >= fForward.size()) || (start[1] < 0) || (start[1] >= fBackward.size())) { cerr << endl << ">> PRunAsymmetry::SubtractEstimatedBkg(): **ERROR** background bin values out of bound!"; cerr << endl << ">> histo lengths (f/b) = (" << fForward.size() << "/" << fBackward.size() << ")."; cerr << endl << ">> background start (f/b) = (" << start[0] << "/" << start[1] << ")."; return false; } // check if end is within histogram bounds if ((end[0] < 0) || (end[0] >= fForward.size()) || (end[1] < 0) || (end[1] >= fBackward.size())) { cerr << endl << ">> PRunAsymmetry::SubtractEstimatedBkg(): **ERROR** background bin values out of bound!"; cerr << endl << ">> histo lengths (f/b) = (" << fForward.size() << "/" << fBackward.size() << ")."; cerr << endl << ">> background end (f/b) = (" << end[0] << "/" << end[1] << ")."; return false; } // calculate background Double_t bkg[2] = {0.0, 0.0}; Double_t errBkg[2] = {0.0, 0.0}; // forward for (UInt_t i=start[0]; i(end[0] - start[0] + 1); cout << endl << ">> estimated forward histo background: " << bkg[0]; // backward for (UInt_t i=start[1]; i(end[1] - start[1] + 1); cout << endl << ">> estimated backward histo background: " << bkg[1] << endl; // correct error for forward, backward for (UInt_t i=0; iSetBkgEstimated(bkg[0], 0); fRunInfo->SetBkgEstimated(bkg[1], 1); return true; } //-------------------------------------------------------------------------- // PrepareFitData (protected) //-------------------------------------------------------------------------- /** *

Take the pre-processed data (i.e. grouping and addrun are preformed) and form the asymmetry for fitting. * Before forming the asymmetry, the following checks will be performed: * -# check if data range is given, if not try to estimate one. * -# check that if a data range is present, that it makes any sense. * -# check that 'first good bin'-'t0' is the same for forward and backward histogram. If not adjust it. * -# pack data (rebin). * -# if packed forward size != backward size, truncate the longer one such that an asymmetry can be formed. * -# calculate the asymmetry: \f$ A_i = (f_i^c-b_i^c)/(f_i^c+b_i^c) \f$ * -# calculate the asymmetry errors: \f$ \delta A_i = 2 \sqrt{(b_i^c)^2 (\delta f_i^c)^2 + (\delta b_i^c)^2 (f_i^c)^2}/(f_i^c+b_i^c)^2\f$ * * \param runData raw run data needed to perform some crosschecks * \param histoNo histogram number (within a run). histoNo[0]: forward histogram number, histNo[1]: backward histogram number */ Bool_t PRunAsymmetry::PrepareFitData(PRawRunData* runData, UInt_t histoNo[2]) { // transform raw histo data. This is done the following way (for details see the manual): // first rebin the data, than calculate the asymmetry // first get start data, end data, and t0 Int_t start[2] = {fRunInfo->GetDataRange(0), fRunInfo->GetDataRange(2)}; Int_t end[2] = {fRunInfo->GetDataRange(1), fRunInfo->GetDataRange(3)}; Double_t t0[2] = {fT0s[0], fT0s[1]}; Int_t offset = (Int_t)(10.0e-3/fTimeResolution); // needed in case first good bin is not given, default = 10ns // check if data range has been provided, and if not try to estimate them if (start[0] < 0) { start[0] = (Int_t)t0[0]+offset; fRunInfo->SetDataRange(start[0], 0); cerr << endl << ">> PRunAsymmetry::PrepareData(): **WARNING** data range (forward) was not provided, will try data range start = t0+" << offset << "(=10ns) = " << start[0] << "."; cerr << endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE."; cerr << endl; } if (start[1] < 0) { start[1] = (Int_t)t0[1]+offset; fRunInfo->SetDataRange(start[1], 2); cerr << endl << ">> PRunAsymmetry::PrepareData(): **WARNING** data range (backward) was not provided, will try data range start = t0+" << offset << "(=10ns) = " << start[1] << "."; cerr << endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE."; cerr << endl; } if (end[0] < 0) { end[0] = runData->GetDataBin(histoNo[0])->size(); fRunInfo->SetDataRange(end[0], 1); cerr << endl << ">> PRunAsymmetry::PrepareData(): **WARNING** data range (forward) was not provided, will try data range end = " << end[0] << "."; cerr << endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE."; cerr << endl; } if (end[1] < 0) { end[1] = runData->GetDataBin(histoNo[1])->size(); fRunInfo->SetDataRange(end[1], 3); cerr << endl << ">> PRunAsymmetry::PrepareData(): **WARNING** data range (backward) was not provided, will try data range end = " << end[1] << "."; cerr << endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE."; cerr << endl; } // check if start, end, and t0 make any sense // 1st check if start and end are in proper order for (UInt_t i=0; i<2; i++) { if (end[i] < start[i]) { // need to swap them Int_t keep = end[i]; end[i] = start[i]; start[i] = keep; } // 2nd check if start is within proper bounds if ((start[i] < 0) || (start[i] > (Int_t)runData->GetDataBin(histoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareFitData(): **ERROR** start data bin doesn't make any sense!"; cerr << endl; return false; } // 3rd check if end is within proper bounds if ((end[i] < 0) || (end[i] > (Int_t)runData->GetDataBin(histoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareFitData(): **ERROR** end data bin doesn't make any sense!"; cerr << endl; return false; } // 4th check if t0 is within proper bounds if ((t0[i] < 0) || (t0[i] > (Int_t)runData->GetDataBin(histoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareFitData(): **ERROR** t0 data bin doesn't make any sense!"; cerr << endl; return false; } } // check that start-t0 is the same for forward as for backward, otherwise take max(start[i]-t0[i]) if (fabs(static_cast(start[0])-t0[0]) > fabs(static_cast(start[1])-t0[1])){ start[1] = static_cast(t0[1] + static_cast(start[0]) - t0[0]); end[1] = static_cast(t0[1] + static_cast(end[0]) - t0[0]); cerr << endl << ">> PRunAsymmetry::PrepareFitData **WARNING** needed to shift backward data range."; cerr << endl << ">> given: " << fRunInfo->GetDataRange(2) << ", " << fRunInfo->GetDataRange(3); cerr << endl << ">> used : " << start[1] << ", " << end[1]; cerr << endl; } if (fabs(static_cast(start[0])-t0[0]) < fabs(static_cast(start[1])-t0[1])){ start[0] = static_cast(t0[0] + static_cast(start[1]) - t0[1]); end[0] = static_cast(t0[0] + static_cast(end[1]) - t0[1]); cerr << endl << ">> PRunAsymmetry::PrepareFitData **WARNING** needed to shift forward data range."; cerr << endl << ">> given: " << fRunInfo->GetDataRange(0) << ", " << fRunInfo->GetDataRange(1); cerr << endl << ">> used : " << start[0] << ", " << end[0]; cerr << endl; } // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now if (fRunInfo->IsFitRangeInBin()) { fFitStartTime = (fRunInfo->GetDataRange(0) + fRunInfo->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt fFitEndTime = (fRunInfo->GetDataRange(1) - fRunInfo->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt // write these times back into the data structure. This way it is available when writting the log-file fRunInfo->SetFitRange(fFitStartTime, 0); fRunInfo->SetFitRange(fFitEndTime, 1); } // keep good bins for potential latter use fGoodBins[0] = start[0]; fGoodBins[1] = end[0]; // everything looks fine, hence fill packed forward and backward histo PRunData forwardPacked; PRunData backwardPacked; Double_t value = 0.0; Double_t error = 0.0; // forward for (Int_t i=start[0]; iGetPacking() == 1) { forwardPacked.AppendValue(fForward[i]); forwardPacked.AppendErrorValue(fForwardErr[i]); } else { // packed data, i.e. fRunInfo->GetPacking() > 1 if (((i-start[0]) % fRunInfo->GetPacking() == 0) && (i != start[0])) { // fill data // in order that after rebinning the fit does not need to be redone (important for plots) // the value is normalize to per bin value /= fRunInfo->GetPacking(); forwardPacked.AppendValue(value); if (value == 0.0) forwardPacked.AppendErrorValue(1.0); else forwardPacked.AppendErrorValue(TMath::Sqrt(error)/fRunInfo->GetPacking()); value = 0.0; error = 0.0; } value += fForward[i]; error += fForwardErr[i]*fForwardErr[i]; } } // backward for (Int_t i=start[1]; iGetPacking() == 1) { backwardPacked.AppendValue(fBackward[i]); backwardPacked.AppendErrorValue(fBackwardErr[i]); } else { // packed data, i.e. fRunInfo->GetPacking() > 1 if (((i-start[1]) % fRunInfo->GetPacking() == 0) && (i != start[1])) { // fill data // in order that after rebinning the fit does not need to be redone (important for plots) // the value is normalize to per bin value /= fRunInfo->GetPacking(); backwardPacked.AppendValue(value); if (value == 0.0) backwardPacked.AppendErrorValue(1.0); else backwardPacked.AppendErrorValue(TMath::Sqrt(error)/fRunInfo->GetPacking()); value = 0.0; error = 0.0; } value += fBackward[i]; error += fBackwardErr[i]*fBackwardErr[i]; } } // check if packed forward and backward hist have the same size, otherwise take the minimum size UInt_t noOfBins = forwardPacked.GetValue()->size(); if (forwardPacked.GetValue()->size() != backwardPacked.GetValue()->size()) { if (forwardPacked.GetValue()->size() > backwardPacked.GetValue()->size()) noOfBins = backwardPacked.GetValue()->size(); } // form asymmetry including error propagation Double_t asym; Double_t f, b, ef, eb; // fill data time start, and step // data start at data_start-t0 shifted by (pack-1)/2 fData.SetDataTimeStart(fTimeResolution*((Double_t)start[0]-t0[0]+(Double_t)(fRunInfo->GetPacking()-1)/2.0)); fData.SetDataTimeStep(fTimeResolution*(Double_t)fRunInfo->GetPacking()); for (UInt_t i=0; iat(i); b = backwardPacked.GetValue()->at(i); ef = forwardPacked.GetError()->at(i); eb = backwardPacked.GetError()->at(i); // check that there are indeed bins if (f+b != 0.0) asym = (f-b) / (f+b); else asym = 0.0; fData.AppendValue(asym); // calculate the error if (f+b != 0.0) error = 2.0/((f+b)*(f+b))*TMath::Sqrt(b*b*ef*ef+eb*eb*f*f); else error = 1.0; fData.AppendErrorValue(error); } CalcNoOfFitBins(); // clean up fForward.clear(); fForwardErr.clear(); fBackward.clear(); fBackwardErr.clear(); return true; } //-------------------------------------------------------------------------- // PrepareViewData (protected) //-------------------------------------------------------------------------- /** *

Take the pre-processed data (i.e. grouping and addrun are preformed) and form the asymmetry for view representation. * Before forming the asymmetry, the following checks will be performed: * -# check if view packing is whished. * -# check if data range is given, if not try to estimate one. * -# check that data range is present, that it makes any sense. * -# check that 'first good bin'-'t0' is the same for forward and backward histogram. If not adjust it. * -# pack data (rebin). * -# if packed forward size != backward size, truncate the longer one such that an asymmetry can be formed. * -# calculate the asymmetry: \f$ A_i = (\alpha f_i^c-b_i^c)/(\alpha \beta f_i^c+b_i^c) \f$ * -# calculate the asymmetry errors: \f$ \delta A_i = 2 \sqrt{(b_i^c)^2 (\delta f_i^c)^2 + (\delta b_i^c)^2 (f_i^c)^2}/(f_i^c+b_i^c)^2\f$ * -# calculate the theory vector. * * \param runData raw run data needed to perform some crosschecks * \param histoNo histogram number (within a run). histoNo[0]: forward histogram number, histNo[1]: backward histogram number */ Bool_t PRunAsymmetry::PrepareViewData(PRawRunData* runData, UInt_t histoNo[2]) { // check if view_packing is wished Int_t packing = fRunInfo->GetPacking(); if (fMsrInfo->GetMsrPlotList()->at(0).fViewPacking > 0) { packing = fMsrInfo->GetMsrPlotList()->at(0).fViewPacking; } // feed the parameter vector std::vector par; PMsrParamList *paramList = fMsrInfo->GetMsrParamList(); for (UInt_t i=0; isize(); i++) par.push_back((*paramList)[i].fValue); // transform raw histo data. This is done the following way (for details see the manual): // first rebin the data, than calculate the asymmetry // first get start data, end data, and t0 Int_t start[2] = {0, 0}; Int_t end[2] = {0, 0}; Double_t t0[2] = {fT0s[0], fT0s[1]}; Int_t offset = (Int_t)(10.0e-3/fTimeResolution); // needed in case first good bin is not given, default = 10ns // check if data range has been provided, and if not try to estimate them if (fRunInfo->GetDataRange(0) < 0) { Int_t diff = offset; // calculate start position for plotting Int_t val = static_cast(t0[1])+diff-packing*((static_cast(t0[1])+diff)/packing); do { if (static_cast(val)+t0[1]-t0[0] < 0.0) val += packing; } while (static_cast(val) + t0[1] - t0[0] < 0.0); start[0] = val; start[1] = val + static_cast(t0[1] - t0[0]); cerr << endl << ">> PRunAsymmetry::PrepareViewData(): **WARNING** data range (forward/backward) not provided, will try data range start = t0_f/b+10ns."; cerr << endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE."; cerr << endl; } else { // calculate the max(data range start[i]-t0[i]) Int_t diff = fRunInfo->GetDataRange(0)-static_cast(t0[0]); if (abs(diff) < abs(fRunInfo->GetDataRange(2)-static_cast(t0[1]))) diff = fRunInfo->GetDataRange(0)-static_cast(t0[0]); // calculate start position for plotting Int_t val = static_cast(t0[1])+diff-packing*((static_cast(t0[1])+diff)/packing); do { if (static_cast(val)+t0[1]-t0[0] < 0.0) val += packing; } while (static_cast(val) + t0[1] - t0[0] < 0.0); start[0] = val; start[1] = val + static_cast(t0[1] - t0[0]); } // make sure that there are equal number of rebinned bins in forward and backward UInt_t noOfBins0 = (runData->GetDataBin(histoNo[0])->size()-start[0])/packing; UInt_t noOfBins1 = (runData->GetDataBin(histoNo[1])->size()-start[1])/packing; if (noOfBins0 > noOfBins1) noOfBins0 = noOfBins1; end[0] = start[0] + noOfBins0 * packing; end[1] = start[1] + noOfBins0 * packing; // check if start, end, and t0 make any sense // 1st check if start and end are in proper order for (UInt_t i=0; i<2; i++) { if (end[i] < start[i]) { // need to swap them Int_t keep = end[i]; end[i] = start[i]; start[i] = keep; } // 2nd check if start is within proper bounds if ((start[i] < 0) || (start[i] > (Int_t)runData->GetDataBin(histoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareViewData(): **ERROR** start data bin doesn't make any sense!"; cerr << endl; return false; } // 3rd check if end is within proper bounds if ((end[i] < 0) || (end[i] > (Int_t)runData->GetDataBin(histoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareViewData(): **ERROR** end data bin doesn't make any sense!"; cerr << endl; return false; } // 4th check if t0 is within proper bounds if ((t0[i] < 0) || (t0[i] > (Int_t)runData->GetDataBin(histoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareViewData(): **ERROR** t0 data bin doesn't make any sense!"; cerr << endl; return false; } } // if fit range is given in bins (and not time), the fit start/end time can be calculated at this point now if (fRunInfo->IsFitRangeInBin()) { fFitStartTime = (fRunInfo->GetDataRange(0) + fRunInfo->GetFitRangeOffset(0) - fT0s[0]) * fTimeResolution; // (fgb+n0-t0)*dt fFitEndTime = (fRunInfo->GetDataRange(1) - fRunInfo->GetFitRangeOffset(1) - fT0s[0]) * fTimeResolution; // (lgb-n1-t0)*dt } // everything looks fine, hence fill packed forward and backward histo PRunData forwardPacked; PRunData backwardPacked; Double_t value = 0.0; Double_t error = 0.0; // forward for (Int_t i=start[0]; i 1 if (((i-start[0]) % packing == 0) && (i != start[0])) { // fill data // in order that after rebinning the fit does not need to be redone (important for plots) // the value is normalize to per bin value /= packing; forwardPacked.AppendValue(value); if (value == 0.0) forwardPacked.AppendErrorValue(1.0); else forwardPacked.AppendErrorValue(TMath::Sqrt(error)/packing); value = 0.0; error = 0.0; } value += fForward[i]; error += fForwardErr[i]*fForwardErr[i]; } } // backward for (Int_t i=start[1]; i 1 if (((i-start[1]) % packing == 0) && (i != start[1])) { // fill data // in order that after rebinning the fit does not need to be redone (important for plots) // the value is normalize to per bin value /= packing; backwardPacked.AppendValue(value); if (value == 0.0) backwardPacked.AppendErrorValue(1.0); else backwardPacked.AppendErrorValue(TMath::Sqrt(error)/packing); value = 0.0; error = 0.0; } value += fBackward[i]; error += fBackwardErr[i]*fBackwardErr[i]; } } // check if packed forward and backward hist have the same size, otherwise take the minimum size UInt_t noOfBins = forwardPacked.GetValue()->size(); if (forwardPacked.GetValue()->size() != backwardPacked.GetValue()->size()) { if (forwardPacked.GetValue()->size() > backwardPacked.GetValue()->size()) noOfBins = backwardPacked.GetValue()->size(); } // form asymmetry including error propagation Double_t asym; Double_t f, b, ef, eb, alpha = 1.0, beta = 1.0; // set data time start, and step // data start at data_start-t0 fData.SetDataTimeStart(fTimeResolution*((Double_t)start[0]-t0[0]+(Double_t)(packing-1)/2.0)); fData.SetDataTimeStep(fTimeResolution*(Double_t)packing); // get the proper alpha and beta switch (fAlphaBetaTag) { case 1: // alpha == 1, beta == 1 alpha = 1.0; beta = 1.0; break; case 2: // alpha != 1, beta == 1 alpha = par[fRunInfo->GetAlphaParamNo()-1]; beta = 1.0; break; case 3: // alpha == 1, beta != 1 alpha = 1.0; beta = par[fRunInfo->GetBetaParamNo()-1]; break; case 4: // alpha != 1, beta != 1 alpha = par[fRunInfo->GetAlphaParamNo()-1]; beta = par[fRunInfo->GetBetaParamNo()-1]; break; default: break; } for (UInt_t i=0; isize(); i++) { // to make the formulae more readable f = forwardPacked.GetValue()->at(i); b = backwardPacked.GetValue()->at(i); ef = forwardPacked.GetError()->at(i); eb = backwardPacked.GetError()->at(i); // check that there are indeed bins if (f+b != 0.0) asym = (alpha*f-b) / (alpha*beta*f+b); else asym = 0.0; fData.AppendValue(asym); // calculate the error if (f+b != 0.0) error = 2.0/((f+b)*(f+b))*TMath::Sqrt(b*b*ef*ef+eb*eb*f*f); else error = 1.0; fData.AppendErrorValue(error); } CalcNoOfFitBins(); // clean up fForward.clear(); fForwardErr.clear(); fBackward.clear(); fBackwardErr.clear(); // fill theory vector for kView // calculate functions for (Int_t i=0; iGetNoOfFuncs(); i++) { fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par); } // calculate theory Double_t time; UInt_t size = runData->GetDataBin(histoNo[0])->size(); Double_t factor = 1.0; if (fData.GetValue()->size() * 10 > runData->GetDataBin(histoNo[0])->size()) { size = fData.GetValue()->size() * 10; factor = (Double_t)runData->GetDataBin(histoNo[0])->size() / (Double_t)size; } fData.SetTheoryTimeStart(fData.GetDataTimeStart()); fData.SetTheoryTimeStep(fTimeResolution*factor); for (UInt_t i=0; iFunc(time, par, fFuncValues); if (fabs(value) > 10.0) { // dirty hack needs to be fixed!! value = 0.0; } fData.AppendTheoryValue(value); } // clean up par.clear(); return true; } //-------------------------------------------------------------------------- // PrepareRRFViewData (protected) //-------------------------------------------------------------------------- /** *

Prepares the RRF data set for visual representation. This is done the following way: * -# make all necessary checks * -# build the asymmetry, \f$ A(t) \f$, WITHOUT packing. * -# \f$ A_R(t) = A(t) \cdot 2 \cos(\omega_R t + \phi_R) \f$ * -# do the packing of \f$ A_R(t) \f$ * -# calculate theory, \f$ T(t) \f$, as close as possible to the time resolution [compatible with the RRF frequency] * -# \f$ T_R(t) = T(t) \cdot 2 \cos(\omega_R t + \phi_R) \f$ * -# do the packing of \f$ T_R(t) \f$ * -# calculate the Kaiser FIR filter coefficients * -# filter \f$ T_R(t) \f$. * * \param runData raw run data needed to perform some crosschecks * \param histoNo array of the histo numbers form which to build the asymmetry */ Bool_t PRunAsymmetry::PrepareRRFViewData(PRawRunData* runData, UInt_t histoNo[2]) { // feed the parameter vector std::vector par; PMsrParamList *paramList = fMsrInfo->GetMsrParamList(); for (UInt_t i=0; isize(); i++) par.push_back((*paramList)[i].fValue); // ------------------------------------------------------------ // 1. make all necessary checks // ------------------------------------------------------------ // first get start data, end data, and t0 Int_t start[2] = {0, 0}; Int_t end[2] = {0, 0}; Double_t t0[2] = {fT0s[0], fT0s[1]}; UInt_t packing = fMsrInfo->GetMsrPlotList()->at(0).fRRFPacking; Int_t offset = (Int_t)(10.0e-3/fTimeResolution); // needed in case first good bin is not given, default = 10ns // check if data range has been provided, and if not try to estimate them if (fRunInfo->GetDataRange(0) < 0) { start[0] = static_cast(t0[0])+offset; cerr << endl << ">> PRunAsymmetry::PrepareRRFViewData(): **WARNING** data range (forward) was not provided, will try data range start = " << start[0] << "."; cerr << endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE."; cerr << endl; } else if (fRunInfo->GetDataRange(2) < 0) { start[1] = static_cast(t0[1])+offset; cerr << endl << ">> PRunAsymmetry::PrepareRRFViewData(): **WARNING** data range (backward) was not provided, will try data range start = " << start[1] << "."; cerr << endl << ">> NO WARRANTY THAT THIS DOES MAKE ANY SENSE."; cerr << endl; } else { Int_t val = fRunInfo->GetDataRange(0)-packing*(fRunInfo->GetDataRange(0)/packing); do { if (fRunInfo->GetDataRange(2) - fRunInfo->GetDataRange(0) < 0) val += packing; } while (val + fRunInfo->GetDataRange(2) - fRunInfo->GetDataRange(0) < 0); start[0] = val; start[1] = val + fRunInfo->GetDataRange(2) - fRunInfo->GetDataRange(0); } // make sure that there are equal number of rebinned bins in forward and backward UInt_t noOfBins0 = runData->GetDataBin(histoNo[0])->size()-start[0]; UInt_t noOfBins1 = runData->GetDataBin(histoNo[1])->size()-start[1]; if (noOfBins0 > noOfBins1) noOfBins0 = noOfBins1; end[0] = start[0] + noOfBins0; end[1] = start[1] + noOfBins0; // check if start, end, and t0 make any sense // 1st check if start and end are in proper order for (UInt_t i=0; i<2; i++) { if (end[i] < start[i]) { // need to swap them Int_t keep = end[i]; end[i] = start[i]; start[i] = keep; } // 2nd check if start is within proper bounds if ((start[i] < 0) || (start[i] > (Int_t)runData->GetDataBin(histoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareRRFViewData(): **ERROR** start data bin doesn't make any sense!"; cerr << endl; return false; } // 3rd check if end is within proper bounds if ((end[i] < 0) || (end[i] > (Int_t)runData->GetDataBin(histoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareRRFViewData(): **ERROR** end data bin doesn't make any sense!"; cerr << endl; return false; } // 4th check if t0 is within proper bounds if ((t0[i] < 0) || (t0[i] > (Int_t)runData->GetDataBin(histoNo[i])->size())) { cerr << endl << ">> PRunAsymmetry::PrepareRRFViewData(): **ERROR** t0 data bin doesn't make any sense!"; cerr << endl; return false; } } // ------------------------------------------------------------ // 2. build the asymmetry [A(t)] WITHOUT packing. // ------------------------------------------------------------ PDoubleVector forward, forwardErr; PDoubleVector backward, backwardErr; Double_t error = 0.0; // forward for (Int_t i=start[0]; i backward.size()) noOfBins = backward.size(); } // form asymmetry including error propagation PDoubleVector asymmetry, asymmetryErr; Double_t asym; Double_t f, b, ef, eb, alpha = 1.0, beta = 1.0; // get the proper alpha and beta switch (fAlphaBetaTag) { case 1: // alpha == 1, beta == 1 alpha = 1.0; beta = 1.0; break; case 2: // alpha != 1, beta == 1 alpha = par[fRunInfo->GetAlphaParamNo()-1]; beta = 1.0; break; case 3: // alpha == 1, beta != 1 alpha = 1.0; beta = par[fRunInfo->GetBetaParamNo()-1]; break; case 4: // alpha != 1, beta != 1 alpha = par[fRunInfo->GetAlphaParamNo()-1]; beta = par[fRunInfo->GetBetaParamNo()-1]; break; default: break; } //cout << endl << ">> alpha = " << alpha << ", beta = " << beta; for (UInt_t i=0; iGetMsrPlotList()->at(0).fRRFUnit) { case RRF_UNIT_kHz: gammaRRF = TMath::TwoPi()*1.0e-3; break; case RRF_UNIT_MHz: gammaRRF = TMath::TwoPi(); break; case RRF_UNIT_Mcs: gammaRRF = 1.0; break; case RRF_UNIT_G: gammaRRF = 0.0135538817*TMath::TwoPi(); break; case RRF_UNIT_T: gammaRRF = 0.0135538817*TMath::TwoPi()*1.0e4; break; default: gammaRRF = TMath::TwoPi(); break; } wRRF = gammaRRF * fMsrInfo->GetMsrPlotList()->at(0).fRRFFreq; phaseRRF = fMsrInfo->GetMsrPlotList()->at(0).fRRFPhase / 180.0 * TMath::Pi(); for (UInt_t i=0; i(start[0])-t0[0]+static_cast(i)); asymmetry[i] *= 2.0*TMath::Cos(wRRF*time+phaseRRF); } // ------------------------------------------------------------ // 4. do the packing of A_R(t) // ------------------------------------------------------------ Double_t value = 0.0; error = 0.0; for (UInt_t i=0; i(start[0])-t0[0]+static_cast(packing-1)/2.0)); fData.SetDataTimeStep(fTimeResolution*static_cast(packing)); // ------------------------------------------------------------ // 5. calculate theory [T(t)] as close as possible to the time resolution [compatible with the RRF frequency] // 6. T_R(t) = T(t) * 2 cos(w_R t + phi_R) // ------------------------------------------------------------ UInt_t rebinRRF = static_cast((TMath::Pi()/2.0/wRRF)/fTimeResolution); // RRF time resolution / data time resolution fData.SetTheoryTimeStart(fData.GetDataTimeStart()); fData.SetTheoryTimeStep(TMath::Pi()/2.0/wRRF/rebinRRF); // = theory time resolution as close as possible to the data time resolution compatible with wRRF /* cout << endl << ">> rebinRRF = " << rebinRRF; cout << endl << ">> theory time start = " << fData.GetTheoryTimeStart(); cout << endl << ">> theory time step = " << fData.GetTheoryTimeStep(); cout << endl; */ // calculate functions for (Int_t i=0; iGetNoOfFuncs(); i++) { fFuncValues[i] = fMsrInfo->EvalFunc(fMsrInfo->GetFuncNo(i), *fRunInfo->GetMap(), par); } Double_t theoryValue; for (UInt_t i=0; i(i)*fData.GetTheoryTimeStep(); theoryValue = fTheory->Func(time, par, fFuncValues); theoryValue *= 2.0*TMath::Cos(wRRF * time + phaseRRF); if (fabs(theoryValue) > 10.0) { // dirty hack needs to be fixed!! theoryValue = 0.0; } fData.AppendTheoryValue(theoryValue); } // ------------------------------------------------------------ // 7. do the packing of T_R(t) // ------------------------------------------------------------ PDoubleVector theo; Double_t dval = 0.0; for (UInt_t i=0; isize(); i++) { if ((i % rebinRRF == 0) && (i != 0)) { //cout << endl << "time = " << fData.GetTheoryTimeStart() + i * fData.GetTheoryTimeStep() << ", theory value = " << dval; theo.push_back(dval/rebinRRF); dval = 0.0; } dval += fData.GetTheory()->at(i); } fData.ReplaceTheory(theo); theo.clear(); // set the theory time start and step size fData.SetTheoryTimeStart(fData.GetTheoryTimeStart()+static_cast(rebinRRF-1)*fData.GetTheoryTimeStep()/2.0); fData.SetTheoryTimeStep(rebinRRF*fData.GetTheoryTimeStep()); // ------------------------------------------------------------ // 8. calculate the Kaiser FIR filter coefficients // ------------------------------------------------------------ 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) // ------------------------------------------------------------ // 9. filter T_R(t) // ------------------------------------------------------------ FilterTheo(); // clean up par.clear(); forward.clear(); forwardErr.clear(); backward.clear(); backwardErr.clear(); asymmetry.clear(); asymmetryErr.clear(); return true; }