Skip to content
Snippets Groups Projects
Commit 441a4bb8 authored by Zhou, Wenduo's avatar Zhou, Wenduo
Browse files

Refactored FindPeakBackground. Refs #9020.

1. Refactored and thus fixed some issues;
2. Added  more unit tests;
3. Change input property. Algorithm can work with 1 spectrum only.
parent 12827dca
No related branches found
No related tags found
No related merge requests found
......@@ -76,9 +76,8 @@ namespace Algorithms
auto inwsprop = new WorkspaceProperty<MatrixWorkspace>("InputWorkspace", "Anonymous", Direction::Input);
declareProperty(inwsprop, "Name of input MatrixWorkspace that contains peaks.");
declareProperty(new ArrayProperty<int>("WorkspaceIndices"), "Optional: enter a comma-separated list of the "
"workspace indices to have peak and background separated. "
"Default is to calculate for all spectra.");
declareProperty("WorkspaceIndex", EMPTY_INT(), "workspace indices to have peak and background separated. "
"No default is taken. ");
declareProperty("SigmaConstant", 1.0, "Multiplier of standard deviations of the variance for convergence of "
"peak elimination. Default is 1.0. ");
......@@ -109,32 +108,27 @@ namespace Algorithms
{
// 1. Get input and validate
MatrixWorkspace_const_sptr inpWS = getProperty("InputWorkspace");
std::vector<int> inpwsindex = getProperty("WorkspaceIndices");
int inpwsindex = getProperty("WorkspaceIndex");
std::vector<double> m_vecFitWindows = getProperty("FitWindow");
m_backgroundType = getPropertyValue("BackgroundType");
double k = getProperty("SigmaConstant");
bool separateall = false;
if (inpwsindex.size() == 0)
if (inpwsindex < 0 || inpwsindex >= static_cast<int>(inpWS->getNumberHistograms()))
{
separateall = true;
stringstream errss;
errss << "Input workspace " << inpWS->name() << " has " << inpWS->getNumberHistograms()
<< " spectra. Input workspace index " << inpwsindex << " is out of boundary. ";
throw runtime_error(errss.str());
}
if (isEmpty(inpwsindex))
throw runtime_error("WorkspaceIndex must be given. ");
// 2. Generate output
size_t numspec;
if (separateall)
{
numspec = inpWS->getNumberHistograms();
}
else
{
numspec = inpwsindex.size();
}
size_t sizex = inpWS->readX(0).size();
size_t sizey = inpWS->readY(0).size();
const MantidVec& inpX = inpWS->readX(inpwsindex);
size_t sizex = inpWS->readX(inpwsindex).size();
size_t sizey = inpWS->readY(inpwsindex).size();
size_t n = sizey;
size_t l0 = 0;
const MantidVec& inpX = inpWS->readX(0);
if (m_vecFitWindows.size() > 1)
{
......@@ -152,145 +146,121 @@ namespace Algorithms
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();
m_outPeakTableWS->appendRow();
// 3. Get Y values
Progress prog(this, 0, 1.0, numspec);
PARALLEL_FOR2(inpWS, m_outPeakTableWS)
for (int i = 0; i < static_cast<int>(numspec); ++i)
Progress prog(this, 0, 1.0, 1);
// Find background
const MantidVec& inpY = inpWS->readY(inpwsindex);
double Ymean, Yvariance, Ysigma;
MantidVec maskedY;
MantidVec::const_iterator in = std::min_element(inpY.begin(), inpY.end());
double bkg0 = inpY[in - inpY.begin()];
for (size_t l = l0; l < n; ++l)
{
maskedY.push_back(inpY[l]-bkg0);
}
MantidVec mask(n-l0,0.0);
double xn = static_cast<double>(n-l0);
do
{
Statistics stats = getStatistics(maskedY);
Ymean = stats.mean;
Yvariance = stats.standard_deviation * stats.standard_deviation;
Ysigma = std::sqrt((moment4(maskedY,n-l0,Ymean)-(xn-3.0)/(xn-1.0) * Yvariance)/xn);
MantidVec::const_iterator it = std::max_element(maskedY.begin(), maskedY.end());
const size_t pos = it - maskedY.begin();
maskedY[pos] = 0;
mask[pos] = 1.0;
}
while (std::abs(Ymean-Yvariance) > k * Ysigma);
if(n-l0 > 5)
{
PARALLEL_START_INTERUPT_REGION
// a) figure out wsindex
size_t wsindex;
if (separateall)
// remove single outliers
if (mask[1] == mask[2] && mask[2] == mask[3])
mask[0] = mask[1];
if (mask[0] == mask[2] && mask[2] == mask[3])
mask[1] = mask[2];
for (size_t l = 2; l < n-l0-3; ++l)
{
// Update wsindex to index in input workspace
wsindex = static_cast<size_t>(i);
if (mask[l-1] == mask[l+1] && (mask[l-1] == mask[l-2] || mask[l+1] == mask[l+2]))
{
mask[l] = mask[l+1];
}
}
else
if (mask[n-l0-2] == mask[n-l0-3] && mask[n-l0-3] == mask[n-l0-4])
mask[n-l0-1] = mask[n-l0-2];
if (mask[n-l0-1] == mask[n-l0-3] && mask[n-l0-3] == mask[n-l0-4])
mask[n-l0-2] = mask[n-l0-1];
// mask regions not connected to largest region
// for loop can start > 1 for multiple peaks
vector<cont_peak> peaks;
if (mask[0] == 1)
{
// Use the wsindex as the input
wsindex = static_cast<size_t>(inpwsindex[i]);
if (wsindex >= inpWS->getNumberHistograms())
peaks.push_back(cont_peak());
peaks[peaks.size()-1].start = l0;
}
for (size_t l = 1; l < n-l0; ++l)
{
if (mask[l] != mask[l-1] && mask[l] == 1)
{
peaks.push_back(cont_peak());
peaks[peaks.size()-1].start = l+l0;
}
else if (peaks.size() > 0)
{
stringstream errmsg;
errmsg << "Input workspace index " << inpwsindex[i] << " is out of input workspace range = "
<< inpWS->getNumberHistograms() << endl;
size_t ipeak = peaks.size()-1;
if (mask[l] != mask[l-1] && mask[l] == 0)
{
peaks[ipeak].stop = l+l0;
}
if (inpY[l+l0] > peaks[ipeak].maxY) peaks[ipeak].maxY = inpY[l+l0];
}
}
// Find background
const MantidVec& inpX = inpWS->readX(wsindex);
const MantidVec& inpY = inpWS->readY(wsindex);
double Ymean, Yvariance, Ysigma;
MantidVec maskedY;
MantidVec::const_iterator in = std::min_element(inpY.begin(), inpY.end());
double bkg0 = inpY[in - inpY.begin()];
for (size_t l = l0; l < n; ++l)
size_t min_peak, max_peak;
double a0,a1,a2;
if(peaks.size()> 0)
{
maskedY.push_back(inpY[l]-bkg0);
if(peaks[peaks.size()-1].stop == 0) peaks[peaks.size()-1].stop = n-1;
std::sort(peaks.begin(), peaks.end(), by_len());
// save endpoints
min_peak = peaks[0].start;
// extra point for histogram input
max_peak = peaks[0].stop + sizex - sizey;
estimateBackground(inpX, inpY, l0, n,
peaks[0].start, peaks[0].stop, a0, a1, a2);
}
MantidVec mask(n-l0,0.0);
double xn = static_cast<double>(n-l0);
do
else
{
Statistics stats = getStatistics(maskedY);
Ymean = stats.mean;
Yvariance = stats.standard_deviation * stats.standard_deviation;
Ysigma = std::sqrt((moment4(maskedY,n-l0,Ymean)-(xn-3.0)/(xn-1.0) * Yvariance)/xn);
MantidVec::const_iterator it = std::max_element(maskedY.begin(), maskedY.end());
const size_t pos = it - maskedY.begin();
maskedY[pos] = 0;
mask[pos] = 1.0;
// assume background is 12 first and last points
min_peak = l0+12;
max_peak = n-13;
if (min_peak > sizey)min_peak = sizey-1;
a0 = 0.0;
a1 = 0.0;
a2 = 0.0;
}
while (std::abs(Ymean-Yvariance) > k * Ysigma);
if(n-l0 > 5)
{
// remove single outliers
if (mask[1] == mask[2] && mask[2] == mask[3])
mask[0] = mask[1];
if (mask[0] == mask[2] && mask[2] == mask[3])
mask[1] = mask[2];
for (size_t l = 2; l < n-l0-3; ++l)
{
if (mask[l-1] == mask[l+1] && (mask[l-1] == mask[l-2] || mask[l+1] == mask[l+2]))
{
mask[l] = mask[l+1];
}
}
if (mask[n-l0-2] == mask[n-l0-3] && mask[n-l0-3] == mask[n-l0-4])
mask[n-l0-1] = mask[n-l0-2];
if (mask[n-l0-1] == mask[n-l0-3] && mask[n-l0-3] == mask[n-l0-4])
mask[n-l0-2] = mask[n-l0-1];
// mask regions not connected to largest region
// for loop can start > 1 for multiple peaks
vector<cont_peak> peaks;
if (mask[0] == 1)
{
peaks.push_back(cont_peak());
peaks[peaks.size()-1].start = l0;
}
for (size_t l = 1; l < n-l0; ++l)
{
if (mask[l] != mask[l-1] && mask[l] == 1)
{
peaks.push_back(cont_peak());
peaks[peaks.size()-1].start = l+l0;
}
else if (peaks.size() > 0)
{
size_t ipeak = peaks.size()-1;
if (mask[l] != mask[l-1] && mask[l] == 0)
{
peaks[ipeak].stop = l+l0;
}
if (inpY[l+l0] > peaks[ipeak].maxY) peaks[ipeak].maxY = inpY[l+l0];
}
}
size_t min_peak, max_peak;
double a0,a1,a2;
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
min_peak = peaks[0].start;
// extra point for histogram input
max_peak = peaks[0].stop + sizex - sizey;
estimateBackground(inpX, inpY, l0, n,
peaks[0].start, peaks[0].stop, a0, a1, a2);
}
else
{
// assume background is 12 first and last points
min_peak = l0+12;
max_peak = n-13;
if (min_peak > sizey)min_peak = sizey-1;
a0 = 0.0;
a1 = 0.0;
a2 = 0.0;
}
// 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;
}
// Add a new row
API::TableRow t = m_outPeakTableWS->getRow(0);
t << static_cast<int>(inpwsindex) << static_cast<int>(min_peak) << static_cast<int>(max_peak) << a0 << a1 <<a2;
}
prog.report();
PARALLEL_END_INTERUPT_REGION
} // ENDFOR
PARALLEL_CHECK_INTERUPT_REGION
prog.report();
// 4. Set the output
setProperty("OutputWorkspace", m_outPeakTableWS);
return;
}
//----------------------------------------------------------------------------------------------
/** Estimate background
* @param X :: vec for X
......
......@@ -6,6 +6,7 @@
#include "MantidAlgorithms/FindPeakBackground.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidDataObjects/Workspace2D.h"
#include <cmath>
......@@ -30,78 +31,222 @@ public:
delete suite;
}
void test_Calculation() {
void test_Calculation()
{
// 1. Generate input workspace
MatrixWorkspace_sptr inWS = generateTestWorkspace();
// 1. Generate input workspace
MatrixWorkspace_sptr inWS = generateTestWorkspace();
// 2. Create
Algorithms::FindPeakBackground alg;
// 2. Create
Algorithms::FindPeakBackground alg;
alg.initialize();
TS_ASSERT(alg.isInitialized());
alg.initialize();
TS_ASSERT(alg.isInitialized());
alg.setProperty("InputWorkspace", inWS);
alg.setProperty("OutputWorkspace", "Signal");
alg.setProperty("WorkspaceIndex", 0);
alg.setProperty("InputWorkspace", inWS);
alg.setProperty("OutputWorkspace", "Signal");
alg.setProperty("WorkspaceIndices", "0");
alg.execute();
TS_ASSERT(alg.isExecuted());
alg.execute();
TS_ASSERT(alg.isExecuted());
Mantid::API::ITableWorkspace_sptr peaklist = boost::dynamic_pointer_cast<Mantid::API::ITableWorkspace>
(Mantid::API::AnalysisDataService::Instance().retrieve("Signal"));
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 );
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 );
AnalysisDataService::Instance().remove("Signal");
return;
return;
}
/** Generate a workspace for test
*/
MatrixWorkspace_sptr generateTestWorkspace() {
vector<double> data;
data.push_back(1);
data.push_back(2);
data.push_back(1);
data.push_back(1);
data.push_back(9);
data.push_back(11);
data.push_back(13);
data.push_back(20);
data.push_back(24);
data.push_back(32);
data.push_back(28);
data.push_back(48);
data.push_back(42);
data.push_back(77);
data.push_back(67);
data.push_back(33);
data.push_back(27);
data.push_back(20);
data.push_back(9);
data.push_back(2);
MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
WorkspaceFactory::Instance().create("Workspace2D", 1,
data.size(), data.size()));
MantidVec& vecX = ws->dataX(0);
MantidVec& vecY = ws->dataY(0);
MantidVec& vecE = ws->dataE(0);
for (size_t i = 0; i < data.size(); ++i) {
vecX[i] = static_cast<double> (i);
vecY[i] = data[i];
vecE[i] = sqrt(data[i]);
}
return ws;
MatrixWorkspace_sptr generateTestWorkspace()
{
vector<double> data;
data.push_back(1);
data.push_back(2);
data.push_back(1);
data.push_back(1);
data.push_back(9);
data.push_back(11);
data.push_back(13);
data.push_back(20);
data.push_back(24);
data.push_back(32);
data.push_back(28);
data.push_back(48);
data.push_back(42);
data.push_back(77);
data.push_back(67);
data.push_back(33);
data.push_back(27);
data.push_back(20);
data.push_back(9);
data.push_back(2);
MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
WorkspaceFactory::Instance().create("Workspace2D", 1,
data.size(), data.size()));
MantidVec& vecX = ws->dataX(0);
MantidVec& vecY = ws->dataY(0);
MantidVec& vecE = ws->dataE(0);
for (size_t i = 0; i < data.size(); ++i) {
vecX[i] = static_cast<double> (i);
vecY[i] = data[i];
vecE[i] = sqrt(data[i]);
}
return ws;
}
//--------------------------------------------------------------------------------------------
/** Test on a spectrum without peak
*/
void test_FindBackgroundOnFlat()
{
// Add workspace
MatrixWorkspace_sptr testws = generate2SpectraTestWorkspace();
AnalysisDataService::Instance().addOrReplace("Test2Workspace", testws);
// Set up algorithm
Algorithms::FindPeakBackground alg;
alg.initialize();
TS_ASSERT(alg.isInitialized());
alg.setProperty("InputWorkspace", "Test2Workspace");
alg.setProperty("OutputWorkspace", "Signal3");
alg.setProperty("WorkspaceIndex", 0);
// Execute
alg.execute();
TS_ASSERT(alg.isExecuted());
// Check result
ITableWorkspace_sptr outws = boost::dynamic_pointer_cast<ITableWorkspace>(
AnalysisDataService::Instance().retrieve("Signal3"));
TS_ASSERT(outws);
if (!outws)
return;
TS_ASSERT_EQUALS(outws->rowCount(), 1);
if (outws->rowCount() < 1)
return;
int ipeakmin = outws->Int(0, 1);
int ipeakmax = outws->Int(0, 2);
TS_ASSERT(ipeakmin >= ipeakmax);
return;
}
//--------------------------------------------------------------------------------------------
/** Test on a spectrum without peak
*/
void test_FindBackgroundOnSpec1()
{
// Add workspace
MatrixWorkspace_sptr testws = generate2SpectraTestWorkspace();
AnalysisDataService::Instance().addOrReplace("Test2Workspace", testws);
// Set up algorithm
Algorithms::FindPeakBackground alg;
alg.initialize();
TS_ASSERT(alg.isInitialized());
alg.setProperty("InputWorkspace", "Test2Workspace");
alg.setProperty("OutputWorkspace", "Signal2");
alg.setProperty("WorkspaceIndex", 1);
// Execute
alg.execute();
TS_ASSERT(alg.isExecuted());
// Check result
ITableWorkspace_sptr outws = boost::dynamic_pointer_cast<ITableWorkspace>(
AnalysisDataService::Instance().retrieve("Signal2"));
TS_ASSERT(outws);
if (!outws)
return;
TS_ASSERT_EQUALS(outws->rowCount(), 1);
if (outws->rowCount() < 1)
return;
TS_ASSERT_EQUALS( outws->rowCount() , 1 );
TS_ASSERT_DELTA( outws->Int(0,1), 4, 0.01 );
TS_ASSERT_DELTA( outws->Int(0,2), 19, 0.01 );
TS_ASSERT_DELTA( outws->Double(0,3), 1.2, 0.01 );
TS_ASSERT_DELTA( outws->Double(0,4), 0.04, 0.01 );
TS_ASSERT_DELTA( outws->Double(0,5), 0.0, 0.01 );
return;
}
//--------------------------------------------------------------------------------------------
/** Generate a workspace with 2 spectra for test
*/
MatrixWorkspace_sptr generate2SpectraTestWorkspace()
{
vector<double> data;
data.push_back(1);
data.push_back(2);
data.push_back(1);
data.push_back(1);
data.push_back(9);
data.push_back(11);
data.push_back(13);
data.push_back(20);
data.push_back(24);
data.push_back(32);
data.push_back(28);
data.push_back(48);
data.push_back(42);
data.push_back(77);
data.push_back(67);
data.push_back(33);
data.push_back(27);
data.push_back(20);
data.push_back(9);
data.push_back(2);
MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
WorkspaceFactory::Instance().create("Workspace2D", 2,
data.size(), data.size()));
// Workspace index = 0
MantidVec& vecX = ws->dataX(0);
MantidVec& vecY = ws->dataY(0);
MantidVec& vecE = ws->dataE(0);
for (size_t i = 0; i < data.size(); ++i)
{
vecX[i] = static_cast<double> (i);
vecY[i] = 0.0;
vecE[i] = 1.0;
}
// Workspace index = 1
MantidVec& vecX1 = ws->dataX(1);
MantidVec& vecY1 = ws->dataY(1);
MantidVec& vecE1 = ws->dataE(1);
for (size_t i = 0; i < data.size(); ++i)
{
vecX1[i] = static_cast<double> (i);
vecY1[i] = data[i];
vecE1[i] = sqrt(data[i]);
}
return ws;
}
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment