From 370949ab7ab8e27d2f8e073433d91e2e743bf4fc Mon Sep 17 00:00:00 2001 From: Vickie Lynch <vlynch@ornl.gov> Date: Thu, 22 Aug 2013 07:30:54 -0400 Subject: [PATCH] Refs #7449 background estimation in table workspace --- .../inc/MantidAlgorithms/FindPeakBackground.h | 3 + .../Algorithms/src/FindPeakBackground.cpp | 152 ++++++++++++++---- .../Algorithms/test/FindPeakBackgroundTest.h | 20 +-- 3 files changed, 134 insertions(+), 41 deletions(-) diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FindPeakBackground.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FindPeakBackground.h index d92e232c0d7..5fdcca3134d 100644 --- a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FindPeakBackground.h +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FindPeakBackground.h @@ -47,6 +47,7 @@ namespace Algorithms virtual const std::string category() const { return "Utility";} private: + std::string m_backgroundType; //< The type of background to fit /// Sets documentation strings for this algorithm virtual void initDocs(); /// Implement abstract Algorithm methods @@ -54,6 +55,8 @@ namespace Algorithms /// Implement abstract Algorithm methods void exec(); double moment4(MantidVec& X, size_t n, double mean); + void estimateBackground(const MantidVec& X, const MantidVec& Y, const size_t i_min, const size_t i_max, + const size_t p_min, const size_t p_max,double& out_bg0, double& out_bg1, double& out_bg2); struct cont_peak { size_t start; diff --git a/Code/Mantid/Framework/Algorithms/src/FindPeakBackground.cpp b/Code/Mantid/Framework/Algorithms/src/FindPeakBackground.cpp index b82c612bc45..cd6a250e66c 100644 --- a/Code/Mantid/Framework/Algorithms/src/FindPeakBackground.cpp +++ b/Code/Mantid/Framework/Algorithms/src/FindPeakBackground.cpp @@ -1,6 +1,15 @@ /*WIKI* -Separates background from signal for spectra of a workspace. + + +J. Appl. Cryst. (2013). 46, 663-671 + +Objective algorithm to separate signal from noise in a Poisson-distributed pixel data set + +T. Straaso/, D. Mueter, H. O. So/rensen and J. Als-Nielsen + +Synopsis: A method is described for the estimation of background level and separation of background pixels from signal pixels in a Poisson-distributed data set by statistical analysis. + *WIKI*/ @@ -12,6 +21,9 @@ Separates background from signal for spectra of a workspace. #include "MantidKernel/ArrayProperty.h" #include "MantidKernel/Statistics.h" #include "MantidDataObjects/Workspace2D.h" +#include "MantidKernel/ListValidator.h" +#include "MantidDataObjects/TableWorkspace.h" +#include "MantidAPI/TableRow.h" #include <sstream> @@ -57,16 +69,26 @@ namespace Algorithms void FindPeakBackground::init() { auto inwsprop = new WorkspaceProperty<MatrixWorkspace>("InputWorkspace", "Anonymous", Direction::Input); - declareProperty(inwsprop, "Name of input MatrixWorkspace to have signal and background separated."); + declareProperty(inwsprop, "Name of input MatrixWorkspace that contains peaks."); declareProperty("WorkspaceIndex", EMPTY_INT(), "Index of the spectrum to have peak and background separated. " "Default is to calculate for all spectra."); + declareProperty("SigmaConstant", 1.0, "Multiplier of sigma for removing peak. Default is 1.0. "); + declareProperty(new ArrayProperty<double>("FitWindow"), "Optional: enter a comma-separated list of the expected X-position of window to fit. The number of values must be exactly two."); - auto outwsprop = new WorkspaceProperty<Workspace2D>("OutputWorkspace", "", Direction::Output); - declareProperty(outwsprop, "Name of the output Workspace2D containing the peak."); + std::vector<std::string> bkgdtypes; + bkgdtypes.push_back("Flat"); + bkgdtypes.push_back("Linear"); + //bkgdtypes.push_back("Quadratic"); + declareProperty("BackgroundType", "Linear", boost::make_shared<StringListValidator>(bkgdtypes), + "Type of Background."); + + // The found peak in a table + declareProperty(new WorkspaceProperty<API::ITableWorkspace>("OutputWorkspace", "", Direction::Output), + "The name of the TableWorkspace in which to store the list of peaks found"); } @@ -79,6 +101,8 @@ namespace Algorithms MatrixWorkspace_const_sptr inpWS = getProperty("InputWorkspace"); int inpwsindex = getProperty("WorkspaceIndex"); std::vector<double> m_vecFitWindows = getProperty("FitWindow"); + m_backgroundType = getPropertyValue("BackgroundType"); + double k = getProperty("SigmaConstant"); bool separateall = false; if (inpwsindex == EMPTY_INT()) @@ -110,15 +134,23 @@ namespace Algorithms if (n < sizey) n++; } - Workspace2D_sptr outWS = boost::dynamic_pointer_cast<Workspace2D>(WorkspaceFactory::Instance().create( - "Workspace2D", numspec, 2, 2)); + // Set up output table workspace + API::ITableWorkspace_sptr m_outPeakTableWS = WorkspaceFactory::Instance().createTable("TableWorkspace"); + m_outPeakTableWS->addColumn("int", "wkspindex"); + m_outPeakTableWS->addColumn("int", "peak_min"); + m_outPeakTableWS->addColumn("int", "peak_max"); + m_outPeakTableWS->addColumn("double", "bkg0"); + m_outPeakTableWS->addColumn("double", "bkg1"); + m_outPeakTableWS->addColumn("double", "bkg2"); + for( size_t i = 0; i < numspec; ++i ) + m_outPeakTableWS->appendRow(); // 3. Get Y values Progress prog(this, 0, 1.0, numspec); - //PARALLEL_FOR2(inpWS, outWS) + PARALLEL_FOR2(inpWS, m_outPeakTableWS) for (size_t i = 0; i < numspec; ++i) { - //PARALLEL_START_INTERUPT_REGION + PARALLEL_START_INTERUPT_REGION // a) figure out wsindex size_t wsindex; if (separateall) @@ -141,26 +173,12 @@ namespace Algorithms // Find background const MantidVec& inpX = inpWS->readX(wsindex); const MantidVec& inpY = inpWS->readY(wsindex); - const MantidVec& inpE = inpWS->readE(wsindex); - - MantidVec& vecX = outWS->dataX(i); - MantidVec& vecY = outWS->dataY(i); - MantidVec& vecE = outWS->dataE(i); - - // save output of mask * Y - vecX[0] = inpX[l0]; - vecX[1] = inpX[n-1]; - vecY[0] = inpY[l0]; - vecY[1] = inpY[n-1]; - vecE[0] = inpE[l0]; - vecE[1] = inpE[n-1]; double Ymean, Yvariance, Ysigma; MantidVec maskedY; for (size_t l = l0; l < n; ++l)maskedY.push_back(inpY[l]); MantidVec mask(n-l0,0.0); double xn = static_cast<double>(n-l0); - double k = 1.0; do { Statistics stats = getStatistics(maskedY); @@ -218,32 +236,104 @@ namespace Algorithms if (inpY[l+l0] > peaks[ipeak].maxY) peaks[ipeak].maxY = inpY[l+l0]; } } + size_t min_peak, max_peak; if(peaks.size()> 0) { if(peaks[peaks.size()-1].stop == 0) peaks[peaks.size()-1].stop = n-1; std::sort(peaks.begin(), peaks.end(), by_len()); // save endpoints - vecX[0] = inpX[peaks[0].start]; + min_peak = peaks[0].start; // extra point for histogram input - vecX[1] = inpX[peaks[0].stop + sizex - sizey]; - vecY[0] = inpY[peaks[0].start]; - vecY[1] = inpY[peaks[0].stop]; - vecE[0] = inpE[peaks[0].start]; - vecE[1] = inpE[peaks[0].stop]; + max_peak = peaks[0].stop + sizex - sizey; } + else + { + min_peak = l0; + max_peak = n-1; + } + double a0,a1,a2; + estimateBackground(inpX, inpY, l0, n, + peaks[0].start, peaks[0].stop, a0, a1, a2); + // Add a new row + API::TableRow t = m_outPeakTableWS->getRow(i); + t << static_cast<int>(wsindex) << static_cast<int>(min_peak) << static_cast<int>(max_peak) << a0 << a1 <<a2; } prog.report(); - //PARALLEL_END_INTERUPT_REGION + PARALLEL_END_INTERUPT_REGION } // ENDFOR - //PARALLEL_CHECK_INTERUPT_REGION + PARALLEL_CHECK_INTERUPT_REGION // 4. Set the output - setProperty("OutputWorkspace", outWS); + setProperty("OutputWorkspace", m_outPeakTableWS); return; } + //---------------------------------------------------------------------------------------------- + /** Estimate background +* @param X :: vec for X +* @param Y :: vec for Y +* @param i_min :: index of minimum in X to estimate background +* @param i_max :: index of maximum in X to estimate background +* @param p_min :: index of peak min in X to estimate background +* @param p_max :: index of peak max in X to estimate background +* @param out_bg0 :: interception +* @param out_bg1 :: slope +* @param out_bg2 :: a2 = 0 +*/ + void FindPeakBackground::estimateBackground(const MantidVec& X, const MantidVec& Y, const size_t i_min, const size_t i_max, + const size_t p_min, const size_t p_max,double& out_bg0, double& out_bg1, double& out_bg2) + { + // Validate input + if (i_min >= i_max) + throw std::runtime_error("i_min cannot larger or equal to i_max"); + if (p_min >= p_max) + throw std::runtime_error("p_min cannot larger or equal to p_max"); + double sum = 0.0; + double sumX = 0.0; + double sumY = 0.0; + double sumX2 = 0.0; + double sumXY = 0.0; + for (size_t i = i_min; i < i_max; ++i) + { + if(i >= p_min && i < p_max) continue; + sum += 1.0; + sumX += X[i]; + sumX2 += X[i]*X[i]; + sumY += Y[i]; + sumXY += X[i]*Y[i]; + } + + // Estimate + out_bg0 = 0.; + out_bg1 = 0.; + out_bg2 = 0.; + if (m_backgroundType.compare("Linear") == 0) // linear background + { + // Cramer's rule for 2 x 2 matrix + double devisor = sum*sumX2-sumX*sumX; + if (devisor != 0) + { + out_bg0 = (sumY*sumX2-sumX*sumXY)/devisor; + out_bg1 = (sum*sumXY-sumY*sumX)/devisor; + } + } + else // flat background + { if(sum != 0) out_bg0 = sumY/sum; + } + + g_log.debug() << "Estimated background: A0 = " << out_bg0 << ", A1 = " + << out_bg1 << ", A2 = " << out_bg2 << "\n"; + + return; + } + //---------------------------------------------------------------------------------------------- + /** Calculate 4th moment +* @param X :: vec for X +* @param n :: length of vector +* @param mean :: mean of X +*/ double FindPeakBackground::moment4(MantidVec& X, size_t n, double mean) { double sum=0.0; diff --git a/Code/Mantid/Framework/Algorithms/test/FindPeakBackgroundTest.h b/Code/Mantid/Framework/Algorithms/test/FindPeakBackgroundTest.h index d31202ec77e..6e84ce2b33a 100644 --- a/Code/Mantid/Framework/Algorithms/test/FindPeakBackgroundTest.h +++ b/Code/Mantid/Framework/Algorithms/test/FindPeakBackgroundTest.h @@ -48,16 +48,16 @@ public: alg.execute(); TS_ASSERT(alg.isExecuted()); - Workspace2D_sptr outWS = boost::dynamic_pointer_cast<Workspace2D>( - AnalysisDataService::Instance().retrieve("Signal")); - - const MantidVec& Signal = outWS->readY(0); - TS_ASSERT_DELTA(Signal[0], 9.0000, 0.0001); - TS_ASSERT_DELTA(Signal[1], 2.000, 0.0001); - - const MantidVec& vecX = outWS->readX(0); - TS_ASSERT_DELTA(vecX[0], 4.0, 0.000001); - TS_ASSERT_DELTA(vecX[1], 19.0, 0.000001); + Mantid::API::ITableWorkspace_sptr peaklist = boost::dynamic_pointer_cast<Mantid::API::ITableWorkspace> + (Mantid::API::AnalysisDataService::Instance().retrieve("Signal")); + + TS_ASSERT( peaklist ); + TS_ASSERT_EQUALS( peaklist->rowCount() , 1 ); + TS_ASSERT_DELTA( peaklist->Int(0,1), 4, 0.01 ); + TS_ASSERT_DELTA( peaklist->Int(0,2), 19, 0.01 ); + TS_ASSERT_DELTA( peaklist->Double(0,3), 1.2, 0.01 ); + TS_ASSERT_DELTA( peaklist->Double(0,4), 0.04, 0.01 ); + TS_ASSERT_DELTA( peaklist->Double(0,5), 0.0, 0.01 ); return; } -- GitLab