Newer
Older
#include "MantidQtCustomInterfaces/ReflMainViewPresenter.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidQtCustomInterfaces/ReflMainView.h"
#include "MantidAPI/AlgorithmManager.h"
using namespace Mantid::API;
namespace MantidQt
{
namespace CustomInterfaces
{
ReflMainViewPresenter::ReflMainViewPresenter(ReflMainView* view): m_view(view)
ReflMainViewPresenter::ReflMainViewPresenter(ITableWorkspace_sptr model, ReflMainView* view): m_model(model), m_view(view)
ReflMainViewPresenter::~ReflMainViewPresenter()
{
/**
Process selected rows
*/
void ReflMainViewPresenter::process()
{
if(m_model->rowCount() == 0)
{
m_view->giveUserWarning("Cannot process an empty Table","Warning");
return;
}
std::vector<size_t> rows = m_view->getSelectedRowIndexes();
//Does the user want to abort?
if(!m_view->askUserYesNo("This will process all rows in the table. Continue?","Process all rows?"))
return;
//They want to process all rows, so populate rows with every index in the model
for(size_t idx = 0; idx < m_model->rowCount(); ++idx)
rows.push_back(idx);
//Maps group numbers to the list of rows in that group we want to process
std::map<int,std::vector<size_t> > groups;
for(auto it = rows.begin(); it != rows.end(); ++it)
const int group = m_model->Int(*it, COL_GROUP);
groups[group].push_back(*it);
}
catch(std::exception& ex)
{
const std::string rowNo = Mantid::Kernel::Strings::toString<size_t>(*it + 1);
m_view->giveUserCritical("Error found in row " + rowNo + ":\n" + ex.what(), "Error");
return;
}
//Each group and each row within count as a progress step.
const int maxProgress = (int)(rows.size() + groups.size());
m_view->setProgressRange(progress, maxProgress);
m_view->setProgress(progress);
for(auto gIt = groups.begin(); gIt != groups.end(); ++gIt)
const std::vector<size_t> groupRows = gIt->second;
//Process each row individually
for(auto rIt = groupRows.begin(); rIt != groupRows.end(); ++rIt)
{
try
{
processRow(*rIt);
m_view->setProgress(++progress);
}
catch(std::exception& ex)
{
const std::string rowNo = Mantid::Kernel::Strings::toString<size_t>(*rIt + 1);
const std::string message = "Error encountered while processing row " + rowNo + ":\n";
m_view->giveUserCritical(message + ex.what(), "Error");
m_view->setProgress(0);
return;
}
}
stitchRows(groupRows);
m_view->setProgress(++progress);
}
catch(std::exception& ex)
{
const std::string groupNo = Mantid::Kernel::Strings::toString<int>(gIt->first);
const std::string message = "Error encountered while stitching group " + groupNo + ":\n";
m_view->giveUserCritical(message + ex.what(), "Error");
@param rowNo : The row in the model to validate
@throws std::invalid_argument if the row fails validation
void ReflMainViewPresenter::validateRow(size_t rowNo) const
const std::string runStr = m_model->String(rowNo, COL_RUNS);
const std::string dqqStr = m_model->String(rowNo, COL_DQQ);
const std::string thetaStr = m_model->String(rowNo, COL_ANGLE);
const std::string qMinStr = m_model->String(rowNo, COL_QMIN);
const std::string qMaxStr = m_model->String(rowNo, COL_QMAX);
if(runStr.empty())
throw std::invalid_argument("Run column may not be empty.");
if(dqqStr.empty() && thetaStr.empty())
throw std::invalid_argument("Theta and dQ/Q columns may not BOTH be empty.");
if(qMinStr.empty())
throw std::invalid_argument("Qmin column may not be empty.");
if(qMaxStr.empty())
throw std::invalid_argument("Qmax column may not be empty.");
}
/**
Fetches a run from disk or the AnalysisDataService
@param run : The name of the run
@param instrument : The instrument the run belongs to
@throws std::runtime_error if the run cannot be found
@returns a shared pointer to the workspace
*/
Workspace_sptr ReflMainViewPresenter::fetchRun(const std::string& run, const std::string& instrument = "")
{
const std::string wsName = run + "_TOF";
//First, let's see if the run given is the name of a workspace in the ADS
if(AnalysisDataService::Instance().doesExist(wsName))
return AnalysisDataService::Instance().retrieveWS<Workspace>(wsName);
const std::string filename = instrument + run;
//We'll just have to load it ourselves
IAlgorithm_sptr algLoadRun = AlgorithmManager::Instance().create("Load");
algLoadRun->initialize();
algLoadRun->setProperty("Filename", filename);
algLoadRun->setProperty("OutputWorkspace", wsName);
algLoadRun->execute();
throw std::runtime_error("Could not open " + filename);
return algLoadRun->getProperty("OutputWorkspace");
}
@param rowNo : The row in the model to process
@throws std::runtime_error if processing fails
void ReflMainViewPresenter::processRow(size_t rowNo)
const std::string run = m_model->String(rowNo, COL_RUNS);
const std::string transStr = m_model->String(rowNo, COL_TRANSMISSION);
const std::string transWSName = makeTransWSName(transStr);
const std::string options = m_model->String(rowNo, COL_OPTIONS);
double theta = 0;
const bool thetaGiven = !m_model->String(rowNo, COL_ANGLE).empty();
if(thetaGiven)
Mantid::Kernel::Strings::convert<double>(m_model->String(rowNo, COL_ANGLE), theta);
Workspace_sptr runWS = fetchRun(run, m_view->getProcessInstrument());
//If the transmission workspace already exists, re-use it.
MatrixWorkspace_sptr transWS;
if(AnalysisDataService::Instance().doesExist(transWSName))
transWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(transWSName);
else
transWS = makeTransWS(transStr);
IAlgorithm_sptr algReflOne = AlgorithmManager::Instance().create("ReflectometryReductionOneAuto");
algReflOne->initialize();
algReflOne->setChild(true);
algReflOne->setProperty("InputWorkspace", runWS);
algReflOne->setProperty("FirstTransmissionRun", transWS);
algReflOne->setProperty("OutputWorkspace", run + "_IvsQ");
algReflOne->setProperty("OutputWorkspaceWaveLength", run + "_IvsLam");
algReflOne->setProperty("ThetaIn", theta);
//Parse and set any user-specified options
auto optionsMap = Mantid::Kernel::Strings::splitToKeyValues(options);
for(auto kvp = optionsMap.begin(); kvp != optionsMap.end(); ++kvp)
{
try
{
algReflOne->setProperty(kvp->first, kvp->second);
}
catch(Mantid::Kernel::Exception::NotFoundError& e)
{
throw std::runtime_error("Invalid property in options column: " + kvp->first);
}
}
algReflOne->execute();
if(!algReflOne->isExecuted())
throw std::runtime_error("Failed to run ReflectometryReductionOneAuto.");
MatrixWorkspace_sptr runWSQ = algReflOne->getProperty("OutputWorkspace");
MatrixWorkspace_sptr runWSLam = algReflOne->getProperty("OutputWorkspaceWaveLength");
//Finally, place the resulting workspaces into the ADS.
AnalysisDataService::Instance().addOrReplace(run + "_TOF", runWS);
AnalysisDataService::Instance().addOrReplace(run + "_IvsQ", runWSQ);
AnalysisDataService::Instance().addOrReplace(run + "_IvsLam", runWSLam);
AnalysisDataService::Instance().addOrReplace(transWSName, transWS);
}
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/**
Stitches the workspaces created by the given rows together.
@param rows : the list of rows
*/
void ReflMainViewPresenter::stitchRows(std::vector<size_t> rows)
{
//If we can get away with doing nothing, do.
if(rows.size() < 2)
return;
//Ensure the rows are in order.
std::sort(rows.begin(), rows.end());
//Properties for Stitch1DMany
std::vector<std::string> wsNames;
std::vector<std::string> runs;
std::vector<double> params;
std::vector<double> startOverlaps;
std::vector<double> endOverlaps;
//Go through each row and prepare the properties
for(auto rowIt = rows.begin(); rowIt != rows.end(); ++rowIt)
{
const std::string runStr = m_model->String(*rowIt, COL_RUNS);
const std::string qMinStr = m_model->String(*rowIt, COL_QMIN);
const std::string qMaxStr = m_model->String(*rowIt, COL_QMAX);
double qmin, qmax;
Mantid::Kernel::Strings::convert<double>(qMinStr, qmin);
Mantid::Kernel::Strings::convert<double>(qMaxStr, qmax);
runs.push_back(runStr);
wsNames.push_back(runStr + "_IvsQ");
startOverlaps.push_back(qmin);
endOverlaps.push_back(qmax);
}
double dqq;
std::string dqqStr = m_model->String(rows.front(), COL_DQQ);
Mantid::Kernel::Strings::convert<double>(dqqStr, dqq);
//params are qmin, -dqq, qmax for the final output
params.push_back(*std::min_element(startOverlaps.begin(), startOverlaps.end()));
params.push_back(-dqq);
params.push_back(*std::max_element(endOverlaps.begin(), endOverlaps.end()));
//startOverlaps and endOverlaps need to be slightly offset from each other
//See usage examples of Stitch1DMany to see why we discard first qmin and last qmax
startOverlaps.erase(startOverlaps.begin());
endOverlaps.pop_back();
std::string outputWSName = boost::algorithm::join(runs, "_") + "_IvsQ";
IAlgorithm_sptr algStitch = AlgorithmManager::Instance().create("Stitch1DMany");
algStitch->initialize();
algStitch->setChild(true);
algStitch->setProperty("InputWorkspaces", boost::algorithm::join(wsNames, ","));
algStitch->setProperty("OutputWorkspace", outputWSName);
algStitch->setProperty("Params", params);
algStitch->setProperty("StartOverlaps", startOverlaps);
algStitch->setProperty("EndOverlaps", endOverlaps);
algStitch->execute();
if(!algStitch->isExecuted())
throw std::runtime_error("Failed to run Stitch1DMany on IvsQ workspaces.");
Workspace_sptr stitchedWS = algStitch->getProperty("OutputWorkspace");
//Insert the final stitched row into the ADS
AnalysisDataService::Instance().addOrReplace(outputWSName, stitchedWS);
}
/**
Converts a transmission workspace input string into its ADS name
@param transString : the comma separated transmission run numbers to use
@returns the ADS name the transmission run should be stored as
*/
std::string ReflMainViewPresenter::makeTransWSName(const std::string& transString) const
{
std::vector<std::string> transVec;
boost::split(transVec, transString, boost::is_any_of(","));
return "TRANS_" + transVec[0] + (transVec.size() > 1 ? "_" + transVec[1] : "");
@param transString : the numbers of the transmission runs to use
*/
MatrixWorkspace_sptr ReflMainViewPresenter::makeTransWS(const std::string& transString)
const size_t maxTransWS = 2;
std::vector<std::string> transVec;
//Take the first two run numbers
boost::split(transVec, transString, boost::is_any_of(","));
if(transVec.size() > maxTransWS)
transVec.resize(maxTransWS);
if(transVec.size() == 0)
throw std::runtime_error("Failed to parse the transmission run list.");
for(auto it = transVec.begin(); it != transVec.end(); ++it)
transWSVec.push_back(fetchRun(*it, m_view->getProcessInstrument()));
//We have the runs, so we can create a TransWS
IAlgorithm_sptr algCreateTrans = AlgorithmManager::Instance().create("CreateTransmissionWorkspaceAuto");
algCreateTrans->initialize();
algCreateTrans->setChild(true);
algCreateTrans->setProperty("FirstTransmissionRun", boost::dynamic_pointer_cast<MatrixWorkspace>(transWSVec[0]));
if(transWSVec.size() > 1)
algCreateTrans->setProperty("SecondTransmissionRun", boost::dynamic_pointer_cast<MatrixWorkspace>(transWSVec[1]));
algCreateTrans->setProperty("OutputWorkspace", makeTransWSName(transString));
if(!algCreateTrans->isInitialized())
throw std::runtime_error("Could not initialize CreateTransmissionWorkspaceAuto");
algCreateTrans->execute();
if(!algCreateTrans->isExecuted())
throw std::runtime_error("CreateTransmissionWorkspaceAuto failed to execute");
return algCreateTrans->getProperty("OutputWorkspace");
}
/**
Add row(s) to the model
*/
void ReflMainViewPresenter::addRow()
{
std::vector<size_t> rows = m_view->getSelectedRowIndexes();
if (rows.size() == 0)
{
m_model->appendRow();
}
else
{
//as selections have to be contigous, then all that needs to be done is add
//a number of rows at the highest index equal to the size of the returned vector
std::sort (rows.begin(), rows.end());
for (size_t idx = rows.size(); 0 < idx; --idx)
{
m_model->insertRow(rows.at(0));
}
}
m_view->showTable(m_model);
}
/**
Delete row(s) from the model
*/
void ReflMainViewPresenter::deleteRow()
{
std::vector<size_t> rows = m_view->getSelectedRowIndexes();
std::sort(rows.begin(), rows.end());
for(size_t idx = rows.size(); 0 < idx; --idx)
m_model->removeRow(rows.at(0));
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
/**
Group rows together
*/
void ReflMainViewPresenter::groupRows()
{
std::vector<size_t> rows = m_view->getSelectedRowIndexes();
std::vector<int> usedGroups;
//First we need find the first unused group id
//Scan through all the rows, working out which group ids are used
for(size_t idx = 0; idx < m_model->rowCount(); ++idx)
{
//If this row is one of the selected rows we don't need to include it
if(std::find(rows.begin(), rows.end(), idx) != rows.end())
continue;
//This is an unselected row. At it to the list of used group ids
usedGroups.push_back(m_model->Int(idx, COL_GROUP));
}
int groupId = 0;
//While the group id is one of the used ones, increment it by 1
while(std::find(usedGroups.begin(), usedGroups.end(), groupId) != usedGroups.end())
groupId++;
//Now we just have to set the group id on the selected rows
for(auto it = rows.begin(); it != rows.end(); ++it)
m_model->Int(*it, COL_GROUP) = groupId;
m_view->showTable(m_model);
}
/**
Used by the view to tell the presenter something has changed
*/
void ReflMainViewPresenter::notify(int flag)
case ReflMainView::SaveAsFlag: saveAs(); break;
case ReflMainView::SaveFlag: save(); break;
case ReflMainView::AddRowFlag: addRow(); break;
case ReflMainView::DeleteRowFlag: deleteRow(); break;
case ReflMainView::ProcessFlag: process(); break;
case ReflMainView::GroupRowsFlag: groupRows(); break;
case ReflMainView::NoFlags: return;
//Not having a 'default' case is deliberate. gcc issues a warning if there's a flag we aren't handling.
/**
Load the model into the table
*/
void ReflMainViewPresenter::load()
{
m_view->showTable(m_model);