diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/GetAllEi.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/GetAllEi.h index 042371ba4e150994917722a0d77e52e9df69bd1d..d79bac83a162b8193dc033187ac6e2aca684f356 100644 --- a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/GetAllEi.h +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/GetAllEi.h @@ -87,7 +87,9 @@ protected: // for testing, private otherwise. /// if log, which identifies that instrument is running is available on workspace. /// The log should be positive when instrument is running and negative or 0 otherwise. - bool m_useFilterLog; + bool m_useFilterLog; + /// if true, take derivate of the filter log to identify interval when instrument is running. + bool m_FilterWithDerivative; /// maximal relative peak width to consider acceptable. Defined by minimal instrument resolution /// and does not exceed 0.08 double m_min_Eresolution; diff --git a/Code/Mantid/Framework/Algorithms/src/GetAllEi.cpp b/Code/Mantid/Framework/Algorithms/src/GetAllEi.cpp index c5783578fc0caecc79780b4d73e628ff74abadbc..d29e58432dbb793042221bf4ca4832e8861d667b 100644 --- a/Code/Mantid/Framework/Algorithms/src/GetAllEi.cpp +++ b/Code/Mantid/Framework/Algorithms/src/GetAllEi.cpp @@ -19,7 +19,9 @@ namespace Mantid { /// Empty default constructor GetAllEi::GetAllEi() : Algorithm(), - m_useFilterLog(true),m_min_Eresolution(0.08), + m_useFilterLog(true),m_FilterWithDerivative(true), + // minimal resolution for all instruments + m_min_Eresolution(0.08), // half maximal resolution for LET m_max_Eresolution(0.5e-3), m_peakEnergyRatio2reject(0.1){} @@ -52,6 +54,13 @@ namespace Mantid { " chopper speed and chopper delay which matter.\n" "If such log is not present, log values are calculated " "from experiment start&end times."); + declareProperty("FilterWithDerivative", true, "Use derivative of 'FilterBaseLog' " + "rather then log values itself to filter invalid time intervals.\n" + "Invalid values are then the " + "values where the derivative of the log turns zero.\n" + "E.g. would be 'proton_chage' log which grows for each frame " + "when instrument is counting and constant otherwise."); + auto maxInRange = boost::make_shared<Kernel::BoundedValidator<double>>(); maxInRange->setLower(1.e-6); @@ -121,11 +130,21 @@ namespace Mantid { } }; + struct peakKeeper2{ + double left_rng; + double right_rng; + peakKeeper2(){}; + peakKeeper2(double left,double right): + left_rng(left),right_rng(right) + {} + }; + + /** Executes the algorithm -- found all existing monitor peaks. */ void GetAllEi::exec() { // Get pointers to the workspace, parameter map and table API::MatrixWorkspace_sptr inputWS = getProperty("Workspace"); - + m_FilterWithDerivative = getProperty("FilterWithDerivative"); m_min_Eresolution = getProperty("MinInstrResolution"); m_max_Eresolution = getProperty("MaxInstrResolution"); m_peakEnergyRatio2reject = getProperty("PeaksRatioToReject"); @@ -333,7 +352,7 @@ namespace Mantid { double SmoothRange = 2*maxSigma; std::vector<double> SAvrg,binsAvrg; - Kernel::VectorHelper::smoothAtNPoints(S,SAvrg,SmoothRange,&X, + Kernel::VectorHelper::smoothInRange(S,SAvrg,SmoothRange,&X, ind_min,ind_max,&binsAvrg); double realPeakPos; // this position is less shifted due to the skew in averaging formula @@ -349,7 +368,7 @@ namespace Mantid { size_t ic(0); while((nPeaks>1 || nHills>2)&&(nPrevHills!=nHills) && ic<50){ - Kernel::VectorHelper::smoothAtNPoints(SAvrg,SAvrg1,SmoothRange,&binsAvrg, + Kernel::VectorHelper::smoothInRange(SAvrg,SAvrg1,SmoothRange,&binsAvrg, 0,ind_max-ind_min,&binsAvrg1); nPrevHills=nHills; @@ -497,11 +516,12 @@ namespace Mantid { std::vector<size_t> & irangeMax, std::vector<bool> &guessValid){ - size_t index_min,index_max; size_t nBins = eBins.size(); guessValid.resize(guess_energy.size()); - // get bin range corresponding to energy range - auto getBinRange=[&](double eMin,double eMax){ + // get bin range corresponding to the energy range + auto getBinRange=[&](double eMin,double eMax, + size_t &index_min,size_t &index_max) + { if(eMin<=eBins[0]){ index_min =0; }else{ @@ -509,18 +529,18 @@ namespace Mantid { } if(eMax>=eBins[nBins-1]){ - index_max =nBins+1; + index_max =nBins-1; }else{ index_max = Kernel::VectorHelper::getBinIndex(eBins,eMax)+1; - if(index_max>=nBins)index_max=nBins-1; + if(index_max>=nBins)index_max=nBins-1; // last bin range anyway. Should not happen } - }; // refine bin range. May need better procedure for this. - auto refineEGuess =[&](double &eGuess){ + auto refineEGuess =[&](double &eGuess,size_t index_min,size_t index_max) + { size_t ind_Emax=index_min; double SMax(0); - for(size_t i=index_min;i<index_max-1;i++){ + for(size_t i=index_min;i<index_max;i++){ double dX = eBins[i+1]-eBins[i]; double sig = signal[i]/dX; if(sig>SMax){ @@ -538,16 +558,38 @@ namespace Mantid { }; // Do the job + size_t ind_min,ind_max; + irangeMin.resize(0); + irangeMax.resize(0); + + // identify guess bin ranges + std::vector<peakKeeper2> guess_peak(guess_energy.size()); + for(size_t nGuess = 0;nGuess<guess_energy.size();nGuess++){ + double eGuess = guess_energy[nGuess]; + getBinRange(eGuess*(1-4*Eresolution),eGuess*(1+4*Eresolution),ind_min,ind_max); + guess_peak[nGuess] = peakKeeper2(eBins[ind_min],eBins[ind_max]); + } + // verify that the ranges not intercept and refine interceptions + for(size_t i = 1;i<guess_energy.size();i++){ + if(guess_peak[i-1].right_rng>guess_peak[i].left_rng){ + double mid_pnt = 0.5*(guess_peak[i-1].right_rng+guess_peak[i].left_rng); + guess_peak[i-1].right_rng = mid_pnt; + guess_peak[i].left_rng = mid_pnt; + } + } + // identify final bin ranges for(size_t nGuess = 0;nGuess<guess_energy.size();nGuess++){ double eGuess = guess_energy[nGuess]; - getBinRange(eGuess*(1-4*Eresolution),eGuess*(1+4*Eresolution)); + getBinRange(guess_peak[nGuess].left_rng,guess_peak[nGuess].right_rng,ind_min,ind_max); - if(refineEGuess(eGuess)){ + if(refineEGuess(eGuess,ind_min,ind_max)){ - getBinRange(eGuess*(1-3*Eresolution),eGuess*(1+3*Eresolution)); - irangeMin.push_back(index_min); - irangeMax.push_back(index_max); + getBinRange(std::max(guess_peak[nGuess].left_rng,eGuess*(1-3*Eresolution)), + std::max(guess_peak[nGuess].right_rng,eGuess*(1+3*Eresolution)), + ind_min,ind_max); + irangeMin.push_back(ind_min); + irangeMax.push_back(ind_max); guessValid[nGuess]=true; }else{ guessValid[nGuess]=false; diff --git a/Code/Mantid/Framework/Algorithms/test/GetAllEiTest.h b/Code/Mantid/Framework/Algorithms/test/GetAllEiTest.h index fbe0b79628937974d99737fa0304d6a27fc3b04d..264d2cc8197e9192a89834d50a1358ce8498ded7 100644 --- a/Code/Mantid/Framework/Algorithms/test/GetAllEiTest.h +++ b/Code/Mantid/Framework/Algorithms/test/GetAllEiTest.h @@ -33,17 +33,19 @@ public: API::MatrixWorkspace_sptr buildWorkspaceToFit(const API::MatrixWorkspace_sptr &inputWS, size_t &wsIndex0){ return GetAllEi::buildWorkspaceToFit(inputWS,wsIndex0); } - void findBinRanges(const MantidVec & eBins, - const std::vector<double> & guess_energy,double Eresolution,std::vector<size_t> & irangeMin, - std::vector<size_t> & irangeMax){ - GetAllEi::findBinRanges(eBins,guess_energy,Eresolution,irangeMin,irangeMax); + void findBinRanges(const MantidVec & eBins,const MantidVec & signal, + const std::vector<double> & guess_energies, + double Eresolution,std::vector<size_t> & irangeMin, + std::vector<size_t> & irangeMax, std::vector<bool> &guessValid){ + GetAllEi::findBinRanges(eBins,signal,guess_energies,Eresolution,irangeMin, + irangeMax,guessValid); } void setResolution(double newResolution){ this->m_max_Eresolution = newResolution; } size_t calcDerivativeAndCountZeros(const std::vector<double> &bins,const std::vector<double> &signal, - std::vector<double> &deriv){ - return GetAllEi::calcDerivativeAndCountZeros(bins,signal,deriv); + std::vector<double> &deriv,std::vector<double> &zeros){ + return GetAllEi::calcDerivativeAndCountZeros(bins,signal,deriv,zeros); } }; @@ -258,36 +260,15 @@ public: // TS_ASSERT_DELTA(Xsp1[i],Xsp2[i],1.e-6); //} } - void test_binRanges(){ - std::vector<size_t> bin_min,bin_max; - //Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 - double debin[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,15}; - std::vector<double> ebin(debin,debin+sizeof(debin)/sizeof(double)); - - double dguess[]= {1,2,10,15}; - std::vector<double> guess(dguess,dguess+sizeof(dguess)/sizeof(double)); - m_getAllEi.findBinRanges(ebin,guess,0.01,bin_min,bin_max); - - TS_ASSERT_EQUALS(bin_min.size(),4) - TS_ASSERT_EQUALS(bin_max.size(),4) - - TS_ASSERT_EQUALS(bin_min[0],0); - TS_ASSERT_EQUALS(bin_max[0],1); - TS_ASSERT_EQUALS(bin_min[1],0); - TS_ASSERT_EQUALS(bin_max[1],2); - TS_ASSERT_EQUALS(bin_min[2],8); - TS_ASSERT_EQUALS(bin_max[2],10); - TS_ASSERT_EQUALS(bin_min[3],12); - TS_ASSERT_EQUALS(bin_max[3],13); - } void test_calcDerivative(){ double sig[]={1,2,3,4,5,6}; std::vector<double> signal(sig,sig+sizeof(sig)/sizeof(double)); double bin[]={2,3,4,5,6,7,8}; std::vector<double> bins(bin,bin+sizeof(bin)/sizeof(double)); + std::vector<double> zeros; std::vector<double> deriv; - size_t nZer = m_getAllEi.calcDerivativeAndCountZeros(bins,signal,deriv); + size_t nZer = m_getAllEi.calcDerivativeAndCountZeros(bins,signal,deriv,zeros); TS_ASSERT_EQUALS(nZer,0); TS_ASSERT_DELTA(deriv[0],deriv[1],1.e-9); TS_ASSERT_DELTA(deriv[0],deriv[5],1.e-9); @@ -296,7 +277,7 @@ public: double bin1[]={0,1,3,6,10,15,21}; std::vector<double> bins1(bin1,bin1+sizeof(bin1)/sizeof(double)); - nZer = m_getAllEi.calcDerivativeAndCountZeros(bins1,signal,deriv); + nZer = m_getAllEi.calcDerivativeAndCountZeros(bins1,signal,deriv,zeros); TS_ASSERT_EQUALS(nZer,0); TS_ASSERT_DELTA(deriv[0],deriv[1],1.e-9); TS_ASSERT_DELTA(deriv[0],deriv[5],1.e-9); @@ -311,16 +292,70 @@ public: for(size_t i=0;i<100;i++){ signal[i]=std::sin(0.5*(bins[i]+bins[i+1])); } - nZer = m_getAllEi.calcDerivativeAndCountZeros(bins,signal,deriv); + nZer = m_getAllEi.calcDerivativeAndCountZeros(bins,signal,deriv,zeros); TS_ASSERT_EQUALS(nZer,3); for(size_t i=0;i<99;i++){ // intentionally left boundary point -- its accuracy is much lower TSM_ASSERT_DELTA("At i="+std::to_string(i),deriv[i],10.*std::cos(0.5*(bins[i]+bins[i+1])),1.e-1); } + TS_ASSERT_DELTA(zeros[0],1.65,1.e-3); + TS_ASSERT_DELTA(zeros[1],4.75,1.e-3); + TS_ASSERT_DELTA(zeros[2],7.95,1.e-3); + } + void test_binRanges(){ + std::vector<size_t> bin_min,bin_max,zeros; + //Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + double debin[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,15}; + std::vector<double> ebin(debin,debin+sizeof(debin)/sizeof(double)); + // Not yet supported in VC 2012 + //std::vector<double> ebin={1,2,3,4,5,6,7,8,9,10,11,12,13,15}; + //Ind 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + double sig[] = {0,0,0,3,0,0,4,0,0,0,11,0,0}; + std::vector<double> signal(sig,sig+sizeof(sig)/sizeof(double)); + + double dguess[]= {1,6,10,12}; + std::vector<double> guess(dguess,dguess+sizeof(dguess)/sizeof(double)); + std::vector<bool> guessValid; + + m_getAllEi.findBinRanges(ebin,signal,guess,0.1,bin_min,bin_max,guessValid); + + TS_ASSERT_EQUALS(bin_min.size(),2) + TS_ASSERT_EQUALS(bin_max.size(),2) + TS_ASSERT_EQUALS(guessValid.size(),4) + TS_ASSERT_EQUALS(bin_min[0],4) + TS_ASSERT_EQUALS(bin_max[0],9) + TS_ASSERT_EQUALS(bin_min[1],7) + TS_ASSERT_EQUALS(bin_max[1],13) + + + signal[10]=0; + signal[11]=11; + guess[1] = 3; + guess[2]=6; + guess[3]=11; + m_getAllEi.findBinRanges(ebin,signal,guess,0.01,bin_min,bin_max,guessValid); + TS_ASSERT_EQUALS(bin_min.size(),3) + TS_ASSERT_EQUALS(bin_max.size(),3) + TS_ASSERT_EQUALS(guessValid.size(),4) + + TS_ASSERT_EQUALS(bin_min[0],3); + TS_ASSERT_EQUALS(bin_max[0],4); + TS_ASSERT(guessValid[1]); + + TS_ASSERT_EQUALS(bin_min[1],6); + TS_ASSERT_EQUALS(bin_max[1],7); + TS_ASSERT(guessValid[2]); + + TS_ASSERT_EQUALS(bin_min[2],11); + TS_ASSERT_EQUALS(bin_max[2],12); + TS_ASSERT(guessValid[3]); + + TS_ASSERT(!guessValid[0]); } + private: GetAllEiTester m_getAllEi; diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/VectorHelper.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/VectorHelper.h index c791d5057ce2ff62f8e12d7fc40f3d8325f62927..e455cb5edeca1ae304641c0021d90edcb2cb3366 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/VectorHelper.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/VectorHelper.h @@ -82,13 +82,14 @@ MANTID_KERNEL_DLL int getBinIndex(const std::vector<double> &bins, MANTID_KERNEL_DLL void linearlyInterpolateY(const std::vector<double> &x, std::vector<double> &y, const double stepSize); -// Do n-point running average of input vector considering bin-boundaries if provided -MANTID_KERNEL_DLL void smoothAtNPoints(const std::vector<double> &input, +// Do running average of input vector within specified range, considering heterogeneous bin-boundaries +// if such boundaries are provided +MANTID_KERNEL_DLL void smoothInRange(const std::vector<double> &input, std::vector<double> &output, double avrgInterval, - std::vector<double> const * const binBoundaris =NULL, + std::vector<double> const * const binBoundaris =nullptr, size_t startIndex = 0,size_t endIndex = 0, - std::vector<double> * const outputBinBoundaries=NULL); + std::vector<double> * const outputBinBoundaries=nullptr); //------------------------------------------------------------------------------------- /** Return the length of the vector (in the physical sense), diff --git a/Code/Mantid/Framework/Kernel/src/VectorHelper.cpp b/Code/Mantid/Framework/Kernel/src/VectorHelper.cpp index 88b212d8dc83115af253c37175cfb8a8f3972dec..3be67dd244a68aa734905ec950fd5cfb30807f8f 100644 --- a/Code/Mantid/Framework/Kernel/src/VectorHelper.cpp +++ b/Code/Mantid/Framework/Kernel/src/VectorHelper.cpp @@ -534,8 +534,10 @@ void linearlyInterpolateY(const std::vector<double> &x, std::vector<double> &y, step++; } } -/**Basic running averaging procedure with possibility to account for - * variable bin ranges. +/** Basic running average of input vector within specified range, considering variable bin-boundaries + * if such boundaries are provided. + * The algorithm is trapezium integration, so some peak shift related to first derivative of the + * integrated function does happen. * * @param input:: input vector to smooth * @param output:: resulting vector (can not coincide with input) @@ -554,7 +556,7 @@ void linearlyInterpolateY(const std::vector<double> &x, std::vector<double> &y, * @param outBins :: if present, pointer to a vector to return * bin boundaries for output array. */ -void smoothAtNPoints(const std::vector<double> &input, +void smoothInRange(const std::vector<double> &input, std::vector<double> &output, double avrgInterval, std::vector<double> const * const binBndrs, diff --git a/Code/Mantid/Framework/Kernel/test/VectorHelperTest.h b/Code/Mantid/Framework/Kernel/test/VectorHelperTest.h index 498ebc5cd2ee0f6748febd495f8ce2c0f08aae47..f985d51d31e3ab1787d6564cd0a848a6e332eeb3 100644 --- a/Code/Mantid/Framework/Kernel/test/VectorHelperTest.h +++ b/Code/Mantid/Framework/Kernel/test/VectorHelperTest.h @@ -275,9 +275,9 @@ public: std::vector<double> inputBoundaries(ib,ib+sizeof(ib)/sizeof(double)); std::vector<double> output; - TS_ASSERT_THROWS(VectorHelper::smoothAtNPoints(inputData,output,6,&inputBoundaries),std::invalid_argument); + TS_ASSERT_THROWS(VectorHelper::smoothInRange(inputData,output,6,&inputBoundaries),std::invalid_argument); inputBoundaries.push_back(6); - VectorHelper::smoothAtNPoints(inputData,output,6,&inputBoundaries); + VectorHelper::smoothInRange(inputData,output,6,&inputBoundaries); TS_ASSERT_DELTA(output[1]-output[0],0.492,1.e-3); TS_ASSERT_DELTA(output[3]-output[2],0.4545,1.e-3); @@ -288,14 +288,14 @@ public: inputBoundaries[4]=10; inputBoundaries[5]=15; inputBoundaries[6]=21; - VectorHelper::smoothAtNPoints(inputData,output,6,&inputBoundaries); + VectorHelper::smoothInRange(inputData,output,6,&inputBoundaries); TS_ASSERT_DELTA(output[2],3.,1.e-8); TS_ASSERT_DELTA(output[0],1.,1.e-8); TS_ASSERT_DELTA(output[5],6.,1.e-8); std::vector<double> out_bins; - VectorHelper::smoothAtNPoints(inputData,output,3,&inputBoundaries,1,5,&out_bins); + VectorHelper::smoothInRange(inputData,output,3,&inputBoundaries,1,5,&out_bins); TS_ASSERT_EQUALS(output.size(),4); TS_ASSERT_DELTA(output[1],3.,1.e-8); } @@ -328,7 +328,7 @@ public: TS_ASSERT(iLeft<fMax); TS_ASSERT(iRight<fMax); - VectorHelper::smoothAtNPoints(inputData,output,10,&inputBoundaries); + VectorHelper::smoothInRange(inputData,output,10,&inputBoundaries); fMax = output[indOfMax]/(inputBoundaries[indOfMax+1]-inputBoundaries[indOfMax]); iLeft = inputData[indOfMax-1]/(inputBoundaries[indOfMax]-inputBoundaries[indOfMax-1]); iRight = inputData[indOfMax+1]/(inputBoundaries[indOfMax+2]-inputBoundaries[indOfMax+1]); @@ -337,7 +337,7 @@ public: //TS_ASSERT(iRight<fMax); output.swap(inputData); - VectorHelper::smoothAtNPoints(inputData,output,10,&inputBoundaries); + VectorHelper::smoothInRange(inputData,output,10,&inputBoundaries); fMax = output[indOfMax]/(inputBoundaries[indOfMax+1]-inputBoundaries[indOfMax]); iLeft = inputData[indOfMax-1]/(inputBoundaries[indOfMax]-inputBoundaries[indOfMax-1]); @@ -348,7 +348,7 @@ public: output.swap(inputData); - VectorHelper::smoothAtNPoints(inputData,output,10,&inputBoundaries); + VectorHelper::smoothInRange(inputData,output,10,&inputBoundaries); fMax = output[indOfMax]/(inputBoundaries[indOfMax+1]-inputBoundaries[indOfMax]); iLeft = inputData[indOfMax-1]/(inputBoundaries[indOfMax]-inputBoundaries[indOfMax-1]); @@ -358,7 +358,7 @@ public: //TS_ASSERT(iRight<fMax); output.swap(inputData); - VectorHelper::smoothAtNPoints(inputData,output,10,&inputBoundaries); + VectorHelper::smoothInRange(inputData,output,10,&inputBoundaries); fMax = output[indOfMax]/(inputBoundaries[indOfMax+1]-inputBoundaries[indOfMax]); iLeft = inputData[indOfMax-1]/(inputBoundaries[indOfMax]-inputBoundaries[indOfMax-1]);