Skip to content

Commit

Permalink
Refactored FindPeakBackground. Refs #9020.
Browse files Browse the repository at this point in the history
1. Refactored and thus fixed some issues;
2. Added  more unit tests;
3. Change input property. Algorithm can work with 1 spectrum only.
  • Loading branch information
wdzhou committed Feb 17, 2014
1 parent 12827dc commit 441a4bb
Show file tree
Hide file tree
Showing 2 changed files with 312 additions and 197 deletions.
244 changes: 107 additions & 137 deletions Code/Mantid/Framework/Algorithms/src/FindPeakBackground.cpp
Expand Up @@ -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. ");
Expand Down Expand Up @@ -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)
{
Expand All @@ -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);

This comment has been minimized.

Copy link
@mdoucet

mdoucet Feb 19, 2014

Member

This line is what is causing the error on the autoreduction. There is a check in Algorithm.cpp (around line 817) that checks if (startProgress >= 0 && endProgress > startProgress && endProgress <= 1.). When that check is true, an error is written out to the log, which in turn makes the autoreduction report an error. That is also why the reduction completed, since that check doesn't actually raise any exception.

This comment has been minimized.

Copy link
@RussellTaylor

RussellTaylor via email Feb 19, 2014

Contributor

// 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
Expand Down

0 comments on commit 441a4bb

Please sign in to comment.