Skip to content

Commit

Permalink
Added spectra range option, updated UI
Browse files Browse the repository at this point in the history
Refs #7860
  • Loading branch information
DanNixon committed Sep 4, 2014
1 parent 97cb4ba commit 829ff5b
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 31 deletions.
@@ -1,6 +1,6 @@
from mantid import logger, mtd
from mantid.api import PythonAlgorithm, AlgorithmFactory, WorkspaceProperty, PropertyMode
from mantid.kernel import Direction
from mantid.kernel import Direction, IntArrayProperty, IntArrayMandatoryValidator
from mantid.simpleapi import CreateWorkspace, CopyLogs, CopySample, CopyInstrumentParameters, SaveNexusProcessed, CreateEmptyTableWorkspace

import math
Expand Down Expand Up @@ -28,42 +28,44 @@ def PyInit(self):
self.declareProperty('Save', defaultValue=False,
doc='Switch saving result to nxs file Off/On')

self.declareProperty(IntArrayProperty(name='SpectraRange'),
doc='Range of spectra to symmetrise (defaults to entire range if not set)')

self.declareProperty(WorkspaceProperty('OutputWorkspace', '',
Direction.Output), doc='Name to call the output workspace.')

self.declareProperty(WorkspaceProperty('OutputPropertiesTable', '',
Direction.Output, PropertyMode.Optional), doc='Name to call the properties output table workspace.')

def PyExec(self):
from IndirectCommon import CheckHistZero, StartTime, EndTime
from IndirectCommon import StartTime, EndTime

StartTime('Symmetrise')
self._setup()
num_spectra, _ = CheckHistZero(self._sample)
sample_x = mtd[self._sample].readX(0)

if math.fabs(self._x_cut) < 1e-5:
raise ValueError('XCut point is Zero')
# The number of spectra that will actually be changed
num_symm_spectra = self._spectra_range[1] - self._spectra_range[0] + 1

# Find the smallest data array in the first spectra
len_x = len(mtd[self._sample].readX(0))
len_y = len(mtd[self._sample].readY(0))
len_e = len(mtd[self._sample].readE(0))
sample_array_len = min(len_x, len_y, len_e) - 1

sample_x = mtd[self._sample].readX(0)
delta_x = sample_x[1] - sample_x[0]

# Find array index of negative XCut
negative_diff = np.absolute(sample_x + self._x_cut)
self._negative_index = np.where(negative_diff < delta_x)[0][-1]
self._check_bounds(self._negative_index, sample_array_len, label='Negative')

# FInd array index of positive XCut
# Find array index of positive XCut
positive_diff = np.absolute(sample_x + sample_x[self._negative_index])
self._positive_index = np.where(positive_diff < delta_x)[0][-1]
self._check_bounds(self._positive_index, sample_array_len, label='Positive')

# Calculate number of elements neede dfor new array (per spectra)
# Calculate number of elements needed for new array (per spectra)
new_array_len = 2 * sample_array_len - (self._positive_index + self._negative_index) + 1

if self._verbose:
Expand All @@ -74,23 +76,30 @@ def PyExec(self):
% (self._positive_index, sample_x[self._positive_index]))
logger.notice('New array size = %d' % new_array_len)

x_unit = mtd[self._sample].getXDimension().getUnits()

# Create an empty workspace with enough storage for the new data
zeros = np.zeros(new_array_len * num_spectra)
zeros = np.zeros(new_array_len * num_symm_spectra)
CreateWorkspace(OutputWorkspace=self._output_workspace,
DataX=zeros, DataY=zeros, DataE=zeros,
NSpec=num_spectra)
NSpec=num_symm_spectra,
UnitX=x_unit)

# Copy logs and properties from sample workspace
CopyLogs(InputWorkspace=self._sample, OutputWorkspace=self._output_workspace)
CopyInstrumentParameters(InputWorkspace=self._sample, OutputWorkspace=self._output_workspace)
# CopySample(InputWorkspace=self._sample, OutputWorkspace=self._output_workspace)

# For each spectrum copy positive values to the negative
for index in xrange(num_spectra):
output_spectrum_index = 0
for spectrum_no in range(self._spectra_range[0], self._spectra_range[1] + 1):
# Get index of original spectra
spectrum_index = mtd[self._sample].getIndexFromSpectrumNumber(spectrum_no)

# Strip any additional array cells
x_in = mtd[self._sample].readX(index)[:sample_array_len + 1]
y_in = mtd[self._sample].readY(index)[:sample_array_len + 1]
e_in = mtd[self._sample].readE(index)[:sample_array_len + 1]
x_in = mtd[self._sample].readX(spectrum_index)[:sample_array_len + 1]
y_in = mtd[self._sample].readY(spectrum_index)[:sample_array_len + 1]
e_in = mtd[self._sample].readE(spectrum_index)[:sample_array_len + 1]

# Get some zeroed data to overwrite with copies from sample
x_out = np.zeros(new_array_len)
Expand All @@ -107,12 +116,17 @@ def PyExec(self):
y_out[sample_array_len - self._positive_index:] = y_in[self._negative_index:]
e_out[sample_array_len - self._positive_index:] = e_in[self._negative_index:]

mtd[self._output_workspace].setX(index, x_out)
mtd[self._output_workspace].setY(index, y_out)
mtd[self._output_workspace].setE(index, e_out)
# Set output spectrum data
mtd[self._output_workspace].setX(output_spectrum_index, x_out)
mtd[self._output_workspace].setY(output_spectrum_index, y_out)
mtd[self._output_workspace].setE(output_spectrum_index, e_out)

# Set output spectrum number
mtd[self._output_workspace].getSpectrum(output_spectrum_index).setSpectrumNo(spectrum_no)

logger.information('Spectra %d out of %d done'
% (index + 1, num_spectra))
output_spectrum_index += 1

logger.information('Symmetrise spectra %d' % spectrum_no)

if self._save:
self._save_output()
Expand All @@ -129,15 +143,36 @@ def PyExec(self):

def _setup(self):
"""
Get the algorithm properties.
Get the algorithm properties and validate them.
"""
from IndirectCommon import CheckHistZero

self._sample = self.getPropertyValue('Sample')

num_sample_spectra, _ = CheckHistZero(self._sample)
min_spectra_number = mtd[self._sample].getSpectrum(0).getSpectrumNo()
max_spectra_number = mtd[self._sample].getSpectrum(num_sample_spectra - 1).getSpectrumNo()

self._x_cut = self.getProperty('XCut').value

if math.fabs(self._x_cut) < 1e-5:
raise ValueError('XCut point is Zero')

self._verbose = self.getProperty('Verbose').value
self._plot = self.getProperty('Plot').value
self._save = self.getProperty('Save').value

self._spectra_range = self.getProperty('SpectraRange').value

if len(self._spectra_range) < 2:
self._spectra_range = [min_spectra_number, max_spectra_number]
else:
if self._spectra_range[0] > self._spectra_range[1]:
raise ValueError('Invalid spectra range')

if self._spectra_range[1] > max_spectra_number:
raise ValueError('Max spectrum number out of range')

self._output_workspace = self.getPropertyValue('OutputWorkspace')
self._props_output_workspace = self.getPropertyValue('OutputPropertiesTable')

Expand Down Expand Up @@ -187,6 +222,7 @@ def _plot_output(self):
"""
from IndirectImport import import_mantidplot
mtd_plot = import_mantidplot()

mtd_plot.plotSpectrum([self._sample, self._output_workspace], 0)

# Register algorithm with Mantid
Expand Down
Expand Up @@ -67,7 +67,7 @@ namespace CustomInterfaces

private slots:
void plotRawInput(const QString &workspaceName);
void updateRawPlot();
void updateMiniPlots();
void replotNewSpectrum(QtProperty *prop, double value);
void updateRangeSelectors(QtProperty *prop, double value);
void preview();
Expand Down
76 changes: 66 additions & 10 deletions Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSymmetrise.cpp
Expand Up @@ -64,21 +64,27 @@ namespace CustomInterfaces
m_plots["SymmRawPlot"] = new QwtPlot(m_parentWidget);
m_curves["SymmRawPlot"] = new QwtPlotCurve();

// Indicators for negative and positive XCut values on X axis
m_rangeSelectors["NegativeXCut_Raw"] = new MantidWidgets::RangeSelector(m_plots["SymmRawPlot"],
MantidWidgets::RangeSelector::XSINGLE, true, false);
m_rangeSelectors["PositiveXCut_Raw"] = new MantidWidgets::RangeSelector(m_plots["SymmRawPlot"],
MantidWidgets::RangeSelector::XSINGLE, true, false);

m_rangeSelectors["NegativeXCut_Raw"]->setColour(Qt::darkGreen);
m_rangeSelectors["PositiveXCut_Raw"]->setColour(Qt::darkGreen);

// Indicators for Y value at each XCut position
m_rangeSelectors["NegativeXCutYPos"] = new MantidWidgets::RangeSelector(m_plots["SymmRawPlot"],
MantidWidgets::RangeSelector::YSINGLE, true, false);
m_rangeSelectors["PositiveXCutYPos"] = new MantidWidgets::RangeSelector(m_plots["SymmRawPlot"],
MantidWidgets::RangeSelector::YSINGLE, true, false);

m_rangeSelectors["NegativeXCutYPos"]->setColour(Qt::red);
m_rangeSelectors["PositiveXCutYPos"]->setColour(Qt::red);
m_rangeSelectors["PositiveXCutYPos"]->setColour(Qt::blue);
m_rangeSelectors["NegativeXCutYPos"]->setMinimum(0);
m_rangeSelectors["PositiveXCutYPos"]->setMinimum(0);

// Indicator for centre of symmetry (x=0)
m_rangeSelectors["CentreMark_Raw"] = new MantidWidgets::RangeSelector(m_plots["SymmRawPlot"],
MantidWidgets::RangeSelector::XSINGLE, true, true);
m_rangeSelectors["CentreMark_Raw"]->setColour(Qt::cyan);
Expand All @@ -93,11 +99,16 @@ namespace CustomInterfaces
m_plots["SymmPreviewPlot"] = new QwtPlot(m_parentWidget);
m_curves["SymmPreviewPlot"] = new QwtPlotCurve();

// Indicators for negative and positive XCut values on X axis
m_rangeSelectors["NegativeXCut_PV"] = new MantidWidgets::RangeSelector(m_plots["SymmPreviewPlot"],
MantidWidgets::RangeSelector::XSINGLE, true, true);
m_rangeSelectors["PositiveXCut_PV"] = new MantidWidgets::RangeSelector(m_plots["SymmPreviewPlot"],
MantidWidgets::RangeSelector::XSINGLE, true, true);

m_rangeSelectors["NegativeXCut_PV"]->setColour(Qt::darkGreen);
m_rangeSelectors["PositiveXCut_PV"]->setColour(Qt::darkGreen);

// Indicator for centre of symmetry (x=0)
m_rangeSelectors["CentreMark_PV"] = new MantidWidgets::RangeSelector(m_plots["SymmPreviewPlot"],
MantidWidgets::RangeSelector::XSINGLE, true, true);
m_rangeSelectors["CentreMark_PV"]->setColour(Qt::cyan);
Expand Down Expand Up @@ -179,21 +190,33 @@ namespace CustomInterfaces
runAlgorithm(symmetriseAlg);
}

/**
* Plots a new workspace in the mini plot when it is loaded form the data selector.
*
* @param workspaceName Name of the workspace that has been laoded
*/
void IndirectSymmetrise::plotRawInput(const QString &workspaceName)
{
UNUSED_ARG(workspaceName);
// Set the preview spectrum number to the first spectrum in the workspace
MatrixWorkspace_sptr sampleWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(workspaceName.toStdString());
int minSpectrumRange = sampleWS->getSpectrum(0)->getSpectrumNo();
m_dblManager->setValue(m_properties["PreviewSpec"], static_cast<double>(minSpectrumRange));

updateRawPlot();
updateMiniPlots();

// Set the preview range to the maximum absolute X value
auto axisRange = getCurveRange("SymmRawPlot");
double symmRange = std::max(fabs(axisRange.first), fabs(axisRange.second));
g_log.information() << "Symmetrise x axis range +/- " << symmRange << std::endl;
m_dblManager->setValue(m_properties["PreviewRange"], symmRange);

updateRawPlot();
updateMiniPlots();
}

void IndirectSymmetrise::updateRawPlot()
/**
* Updates the mini plots.
*/
void IndirectSymmetrise::updateMiniPlots()
{
if(!m_uiForm.symm_dsInput->isValid())
return;
Expand All @@ -204,26 +227,35 @@ namespace CustomInterfaces
Mantid::API::MatrixWorkspace_sptr input = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
Mantid::API::AnalysisDataService::Instance().retrieve(workspaceName.toStdString()));

// Set the X axis range based on the range specified by the user
std::pair<double, double>range;
range.first = -m_dblManager->value(m_properties["PreviewRange"]);
range.second = m_dblManager->value(m_properties["PreviewRange"]);
setAxisRange("SymmRawPlot", QwtPlot::xBottom, range);

plotMiniPlot(input, spectrumNumber, "SymmRawPlot");
// Plot the spectrum chosen by the user
size_t spectrumIndex = input->getIndexFromSpectrumNumber(spectrumNumber);
plotMiniPlot(input, spectrumIndex, "SymmRawPlot");

// Match X axis range on preview plot
setAxisRange("SymmPreviewPlot", QwtPlot::xBottom, range);
m_plots["SymmPreviewPlot"]->replot();
}

/**
* Redraws mini plots when user changes previw range or spectrum.
*/
void IndirectSymmetrise::replotNewSpectrum(QtProperty *prop, double value)
{
UNUSED_ARG(value);

if((prop == m_properties["PreviewSpec"]) || (prop == m_properties["PreviewRange"]))
updateRawPlot();
updateMiniPlots();
}

/**
* Updates position of XCut range selectors when used changed value of XCut.
*/
void IndirectSymmetrise::updateRangeSelectors(QtProperty *prop, double value)
{
if(prop == m_properties["XCut"])
Expand All @@ -236,30 +268,46 @@ namespace CustomInterfaces
}
}

/**
* Handles a request to preview the symmetrise.
*
* Runs Symmetrise on the current spectrum and plots in preview mini plot.
*
* @see IndirectSymmetrise::previewAlgDone()
*/
void IndirectSymmetrise::preview()
{
// Handle algorithm completion signal
connect(m_algRunner, SIGNAL(algorithmComplete(bool)), this, SLOT(previewAlgDone(bool)));

// Do nothing if no data has been laoded
QString workspaceName = m_uiForm.symm_dsInput->getCurrentDataName();

if(workspaceName.isEmpty())
return;

bool verbose = m_uiForm.symm_ckVerbose->isChecked();
double x_cut = m_dblManager->value(m_properties["XCut"]);
long spectrumNumber = static_cast<long>(m_dblManager->value(m_properties["PreviewSpec"]));
std::vector<long> spectraRange(2, spectrumNumber);

// Run the algorithm on the preview spectrum only
IAlgorithm_sptr symmetriseAlg = AlgorithmManager::Instance().create("Symmetrise", -1);
symmetriseAlg->initialize();
symmetriseAlg->setProperty("Sample", workspaceName.toStdString());
symmetriseAlg->setProperty("XCut", x_cut);
symmetriseAlg->setProperty("Plot", false);
symmetriseAlg->setProperty("Verbose", false);
symmetriseAlg->setProperty("Verbose", verbose);
symmetriseAlg->setProperty("Save", false);
symmetriseAlg->setProperty("SpectraRange", spectraRange);
symmetriseAlg->setProperty("OutputWorkspace", "__Symmetrise_temp");
symmetriseAlg->setProperty("OutputPropertiesTable", "__SymmetriseProps_temp");

runAlgorithm(symmetriseAlg);
}

/**
* Handles completion of the preview algorithm.
*/
void IndirectSymmetrise::previewAlgDone(bool error)
{
if(error)
Expand All @@ -270,23 +318,31 @@ namespace CustomInterfaces

MatrixWorkspace_sptr sampleWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(workspaceName.toStdString());
ITableWorkspace_sptr propsTable = AnalysisDataService::Instance().retrieveWS<ITableWorkspace>("__SymmetriseProps_temp");
MatrixWorkspace_sptr symmWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("__Symmetrise_temp");

// Get the index of XCut on each side of zero
int negativeIndex = propsTable->getColumn("NegativeCutIndex")->cell<int>(0);
int positiveIndex = propsTable->getColumn("PositiveCutIndex")->cell<int>(0);

// Get the Y values for each XCut and the difference between them
double negativeY = sampleWS->dataY(0)[negativeIndex];
double positiveY = sampleWS->dataY(0)[positiveIndex];
double deltaY = fabs(negativeY - positiveY);

// Show values in property tree
m_dblManager->setValue(m_properties["NegativeYValue"], negativeY);
m_dblManager->setValue(m_properties["PositiveYValue"], positiveY);
m_dblManager->setValue(m_properties["DeltaY"], deltaY);

// Set indicator positions
m_rangeSelectors["NegativeXCutYPos"]->setMinimum(negativeY);
m_rangeSelectors["PositiveXCutYPos"]->setMinimum(positiveY);

plotMiniPlot("__Symmetrise_temp", spectrumNumber, "SymmPreviewPlot");
// Plot preview plot
size_t spectrumIndex = symmWS->getIndexFromSpectrumNumber(spectrumNumber);
plotMiniPlot("__Symmetrise_temp", spectrumIndex, "SymmPreviewPlot");

// Don't want this to trigger when the algorithm is run for all spectra
disconnect(m_algRunner, SIGNAL(algorithmComplete(bool)), this, SLOT(previewAlgDone(bool)));
}

Expand Down

0 comments on commit 829ff5b

Please sign in to comment.