Newer
Older
Federico Montesino Pouzols
committed
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidQtAPI/AlgorithmInputHistory.h"
#include "MantidQtAPI/AlgorithmRunner.h"
#include "MantidQtAPI/PythonRunner.h"
// #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionModel.h"
#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h"
Federico Montesino Pouzols
committed
#include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h"
#include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h"
#include <boost/lexical_cast.hpp>
#include <Poco/File.h>
#include <Poco/Path.h>
Federico Montesino Pouzols
committed
#include <QThread>
using namespace Mantid::API;
using namespace MantidQt::CustomInterfaces;
namespace MantidQt {
namespace CustomInterfaces {
namespace {
Mantid::Kernel::Logger g_log("EngineeringDiffractionGUI");
}
const std::string EnggDiffractionPresenter::g_enginxStr = "ENGINX";
// discouraged at the moment
const bool EnggDiffractionPresenter::g_askUserCalibFilename = false;
EnggDiffractionPresenter::EnggDiffractionPresenter(IEnggDiffractionView *view)
: m_workerThread(NULL), m_calibFinishedOK(false), m_focusFinishedOK(false),
Federico Montesino Pouzols
committed
m_view(view) /*, m_model(new EnggDiffractionModel()), */ {
if (!m_view) {
throw std::runtime_error(
"Severe inconsistency found. Presenter created "
"with an empty/null view (engineeering diffraction interface). "
"Cannot continue.");
}
}
EnggDiffractionPresenter::~EnggDiffractionPresenter() { cleanup(); }
/**
* Close open sessions, kill threads etc., save settings, etc. for a
* graceful window close/destruction
*/
void EnggDiffractionPresenter::cleanup() {
// m_model->cleanup();
Federico Montesino Pouzols
committed
// this may still be running
if (m_workerThread) {
if (m_workerThread->isRunning()) {
g_log.notice() << "A calibration process is currently running, shutting "
"it down immediately..." << std::endl;
m_workerThread->wait(10);
}
delete m_workerThread;
m_workerThread = NULL;
}
}
void EnggDiffractionPresenter::notify(
IEnggDiffractionPresenter::Notification notif) {
switch (notif) {
case IEnggDiffractionPresenter::Start:
processStart();
break;
case IEnggDiffractionPresenter::LoadExistingCalib:
processLoadExistingCalib();
break;
case IEnggDiffractionPresenter::CalcCalib:
processCalcCalib();
break;
case IEnggDiffractionPresenter::FocusRun:
processFocusRun();
break;
case IEnggDiffractionPresenter::LogMsg:
processLogMsg();
break;
case IEnggDiffractionPresenter::InstrumentChange:
processInstChange();
case IEnggDiffractionPresenter::ShutDown:
processShutDown();
break;
}
}
void EnggDiffractionPresenter::processStart() {
EnggDiffCalibSettings cs = m_view->currentCalibSettings();
}
void EnggDiffractionPresenter::processLoadExistingCalib() {
EnggDiffCalibSettings cs = m_view->currentCalibSettings();
std::string fname = m_view->askExistingCalibFilename();
Federico Montesino Pouzols
committed
if (fname.empty()) {
return;
}
std::string instName, vanNo, ceriaNo;
try {
parseCalibrateFilename(fname, instName, vanNo, ceriaNo);
} catch (std::invalid_argument &ia) {
m_view->userWarning("Invalid calibration filename : " + fname, ia.what());
return;
}
m_view->newCalibLoaded(vanNo, ceriaNo, fname);
}
void EnggDiffractionPresenter::processCalcCalib() {
std::string vanNo = m_view->newVanadiumNo();
std::string ceriaNo = m_view->newCeriaNo();
try {
inputChecksBeforeCalibrate(vanNo, ceriaNo);
} catch (std::invalid_argument &ia) {
m_view->userWarning("Error in the inputs required for calibrate",
ia.what());
g_log.notice() << "EnggDiffraction GUI: starting new calibration. This may "
"take a few seconds... " << std::endl;
const std::string outFilename = outputCalibFilename(vanNo, ceriaNo);
m_view->enableCalibrateAndFocusActions(false);
// alternatively, this would be GUI-blocking:
// doNewCalibration(outFilename, vanNo, ceriaNo);
// calibrationFinished()
startAsyncCalibWorker(outFilename, vanNo, ceriaNo);
}
void EnggDiffractionPresenter::processFocusRun() {
std::string runNo = m_view->focusingRunNo();
int bank = m_view->focusingBank();
try {
inputChecksBeforeFocus(runNo, bank);
} catch (std::invalid_argument &ia) {
m_view->userWarning("Error in the inputs required to focus a run",
ia.what());
return;
}
g_log.notice() << "EnggDiffraction GUI: starting new focusing. This may take "
"some seconds... " << std::endl;
const std::string focusDir = m_view->focusingDir();
const std::string outFilename = outputFocusFilename(runNo, bank);
m_view->enableCalibrateAndFocusActions(false);
// GUI-blocking alternative:
// doFocusRun(outFielname, runNo, bank)
// focusingFinished()
startAsyncFocusWorker(focusDir, outFilename, runNo, bank);
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
}
void EnggDiffractionPresenter::processLogMsg() {
std::vector<std::string> msgs = m_view->logMsgs();
for (size_t i = 0; i < msgs.size(); i++) {
g_log.information() << msgs[i] << std::endl;
}
}
void EnggDiffractionPresenter::processInstChange() {
const std::string err = "Changing instrument is not supported!";
g_log.error() << err << std::endl;
m_view->userError("Fatal error", err);
}
void EnggDiffractionPresenter::processShutDown() {
m_view->saveSettings();
cleanup();
}
/**
* Does several checks on the current inputs and settings. This should
* be done before starting any calibration work. The message return
* should in principle be shown to the user as a visible message
* (pop-up, error log, etc.)
*
* @param newVanNo number of the Vanadium run for the new calibration
* @param newCeriaNo number of the Ceria run for the new calibration
*
* @throws std::invalid_argument with an informative message.
*/
void EnggDiffractionPresenter::inputChecksBeforeCalibrate(
const std::string &newVanNo, const std::string &newCeriaNo) {
if (newVanNo.empty()) {
throw std::invalid_argument(
"The Vanadium number cannot be empty and must be an integer number.");
}
if (newCeriaNo.empty()) {
throw std::invalid_argument(
Federico Montesino Pouzols
committed
"The Ceria number cannot be empty and must be an integer number.");
Federico Montesino Pouzols
committed
EnggDiffCalibSettings cs = m_view->currentCalibSettings();
const std::string pixelCalib = cs.m_pixelCalibFilename;
if (pixelCalib.empty()) {
throw std::invalid_argument(
Federico Montesino Pouzols
committed
"You need to set a pixel (full) calibration in settings.");
}
const std::string templGSAS = cs.m_templateGSAS_PRM;
if (templGSAS.empty()) {
throw std::invalid_argument(
Federico Montesino Pouzols
committed
"You need to set a template calibration file for GSAS in settings.");
}
Federico Montesino Pouzols
committed
/**
* What should be the name of the output GSAS calibration file, given
* the Vanadium and Ceria runs
*
* @param vanNo number of the Vanadium run, which is normally part of the name
* @param ceriaNo number of the Ceria run, which is normally part of the name
*
* @return filename (without the full path)
*/
std::string
EnggDiffractionPresenter::outputCalibFilename(const std::string &vanNo,
const std::string &ceriaNo) {
std::string outFilename = "";
const std::string sugg = buildCalibrateSuggestedFilename(vanNo, ceriaNo);
if (!g_askUserCalibFilename) {
outFilename = sugg;
} else {
outFilename = m_view->askNewCalibrationFilename(sugg);
if (!outFilename.empty()) {
// make sure it follows the rules
try {
std::string inst, van, ceria;
parseCalibrateFilename(outFilename, inst, van, ceria);
} catch (std::invalid_argument &ia) {
m_view->userWarning(
"Invalid output calibration filename: " + outFilename, ia.what());
outFilename = "";
}
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
return outFilename;
}
/**
* Parses the name of a calibration file and guesses the instrument,
* vanadium and ceria run numbers, assuming that the name has been
* build with buildCalibrateSuggestedFilename().
*
* @todo this is currently based on the filename. This method should
* do a basic sanity check that the file is actually a calibration
* file (IPARM file for GSAS), and get the numbers from the file not
* from the name of the file. Leaving this as a TODO for now, as the
* file template and contents are still subject to change.
*
* @param path full path to a calibration file
* @param instName instrument used in the file
* @param vanNo number of the Vanadium run used for this calibration file
* @param ceriaNo number of the Ceria run
*
* @throws invalid_argument with an informative message if tha name does
* not look correct (does not follow the conventions).
*/
void EnggDiffractionPresenter::parseCalibrateFilename(const std::string &path,
std::string &instName,
std::string &vanNo,
std::string &ceriaNo) {
instName = "";
vanNo = "";
ceriaNo = "";
Poco::Path fullPath(path);
const std::string filename = fullPath.getFileName();
if (filename.empty()) {
return;
Federico Montesino Pouzols
committed
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
const std::string explMsg =
"Expected a file name like 'INSTR_vanNo_ceriaNo_....par', "
"where INSTR is the instrument name and vanNo and ceriaNo are the "
"numbers of the Vanadium and calibration sample (Ceria, CeO2) runs.";
std::vector<std::string> parts;
boost::split(parts, filename, boost::is_any_of("_"));
if (parts.size() < 4) {
throw std::invalid_argument(
"Failed to find at least the 4 required parts of the file name.\n\n" +
explMsg);
}
// check the rules on the file name
if (g_enginxStr != parts[0]) {
throw std::invalid_argument("The first component of the file name is not "
"the expected instrument name: " +
g_enginxStr + ".\n\n" + explMsg);
}
const std::string castMsg =
"It is not possible to interpret as an integer number ";
try {
boost::lexical_cast<int>(parts[1]);
} catch (std::runtime_error &) {
throw std::invalid_argument(
castMsg + "the Vanadium number part of the file name.\n\n" + explMsg);
}
try {
boost::lexical_cast<int>(parts[2]);
} catch (std::runtime_error &) {
throw std::invalid_argument(
castMsg + "the Ceria number part of the file name.\n\n" + explMsg);
}
instName = parts[0];
vanNo = parts[1];
ceriaNo = parts[2];
Federico Montesino Pouzols
committed
}
/**
* Start the calibration work without blocking the GUI. This uses
* connect for Qt signals/slots so that it runs well with the Qt event
* loop. Because of that this class needs to be a Q_OBJECT.
Federico Montesino Pouzols
committed
*
* @param outFilename name for the output GSAS calibration file
* @param vanNo vanadium run number
* @param ceriaNo ceria run number
*/
void
EnggDiffractionPresenter::startAsyncCalibWorker(const std::string &outFilename,
const std::string &vanNo,
const std::string &ceriaNo) {
Federico Montesino Pouzols
committed
delete m_workerThread;
m_workerThread = new QThread(this);
EnggDiffWorker *worker =
new EnggDiffWorker(this, outFilename, vanNo, ceriaNo);
worker->moveToThread(m_workerThread);
connect(m_workerThread, SIGNAL(started()), worker, SLOT(calibrate()));
connect(worker, SIGNAL(finished()), this, SLOT(calibrationFinished()));
// early delete of thread and worker
connect(m_workerThread, SIGNAL(finished()), m_workerThread,
SLOT(deleteLater()), Qt::DirectConnection);
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
m_workerThread->start();
}
/**
* Calculate a new calibration. This is what threads/workers should
* use to run the calculations in response to the user clicking
* 'calibrate' or similar.
*
* @param outFilename name for the output GSAS calibration file
* @param vanNo vanadium run number
* @param ceriaNo ceria run number
*/
Federico Montesino Pouzols
committed
void EnggDiffractionPresenter::doNewCalibration(const std::string &outFilename,
const std::string &vanNo,
const std::string &ceriaNo) {
Federico Montesino Pouzols
committed
g_log.notice() << "Generating new calibration file: " << outFilename
<< std::endl;
Federico Montesino Pouzols
committed
EnggDiffCalibSettings cs = m_view->currentCalibSettings();
Federico Montesino Pouzols
committed
Mantid::Kernel::ConfigServiceImpl &conf =
Mantid::Kernel::ConfigService::Instance();
const std::vector<std::string> tmpDirs = conf.getDataSearchDirs();
// in principle, the run files will be found from 'DirRaw', and the
// pre-calculated Vanadium corrections from 'DirCalib'
Federico Montesino Pouzols
committed
if (!cs.m_inputDirCalib.empty() && Poco::File(cs.m_inputDirCalib).exists()) {
Federico Montesino Pouzols
committed
conf.appendDataSearchDir(cs.m_inputDirCalib);
Federico Montesino Pouzols
committed
}
if (!cs.m_inputDirRaw.empty() && Poco::File(cs.m_inputDirRaw).exists())
conf.appendDataSearchDir(cs.m_inputDirRaw);
try {
doCalib(cs, vanNo, ceriaNo, outFilename);
Federico Montesino Pouzols
committed
m_calibFinishedOK = true;
} catch (std::runtime_error &) {
Federico Montesino Pouzols
committed
g_log.error() << "The calibration calculations failed. One of the "
"algorithms did not execute correctly. See log messages "
"for details. " << std::endl;
} catch (std::invalid_argument &) {
g_log.error()
Federico Montesino Pouzols
committed
<< "The calibration calculations failed. Some input properties "
"were not valid. See log messages for details. " << std::endl;
}
Federico Montesino Pouzols
committed
// restore normal data search paths
conf.setDataSearchDirs(tmpDirs);
/**
* Method to call when the calibration work has finished, either from
* a separate thread or not (as in this presenter's' test).
*/
void EnggDiffractionPresenter::calibrationFinished() {
if (!m_view)
return;
m_view->enableCalibrateAndFocusActions(true);
if (!m_calibFinishedOK) {
g_log.warning() << "The cablibration did not finished correctly."
<< std::endl;
} else {
const std::string vanNo = m_view->newVanadiumNo();
const std::string ceriaNo = m_view->newCeriaNo();
const std::string outFilename =
buildCalibrateSuggestedFilename(vanNo, ceriaNo);
m_view->newCalibLoaded(vanNo, ceriaNo, outFilename);
g_log.notice()
<< "Cablibration finished and ready as 'current calibration'."
<< std::endl;
}
if (m_workerThread) {
delete m_workerThread;
m_workerThread = NULL;
}
}
/**
* Build a suggested name for a new calibration, by appending instrument name,
* relevant run numbers, etc., like: ENGINX_241391_236516_both_banks.par
*
* @param vanNo number of the Vanadium run
* @param ceriaNo number of the Ceria run
*
* @return Suggested name for a new calibration file, following
* ENGIN-X practices
*/
std::string EnggDiffractionPresenter::buildCalibrateSuggestedFilename(
const std::string &vanNo, const std::string &ceriaNo) const {
// default and only one supported
std::string instStr = g_enginxStr;
std::string nameAppendix = "_both_banks";
if ("ENGIN-X" != m_view->currentInstrument()) {
instStr = "UNKNOWNINST";
nameAppendix = "_calibration";
}
// default extension for calibration files
const std::string calibExt = ".prm";
std::string sugg =
instStr + "_" + vanNo + "_" + ceriaNo + nameAppendix + calibExt;
return sugg;
}
/**
* Calculate a calibration, responding the the "new calibration"
* action/button.
*
* @param cs user settings
* @param vanNo Vanadium run number
* @param ceriaNo Ceria run number
* @param outFilename output filename chosen by the user
*/
void EnggDiffractionPresenter::doCalib(const EnggDiffCalibSettings &cs,
const std::string &vanNo,
const std::string &ceriaNo,
const std::string &outFilename) {
Federico Montesino Pouzols
committed
ITableWorkspace_sptr vanIntegWS;
MatrixWorkspace_sptr vanCurvesWS;
MatrixWorkspace_sptr ceriaWS;
Federico Montesino Pouzols
committed
loadOrCalcVanadiumWorkspaces(vanNo, cs.m_inputDirCalib, vanIntegWS,
vanCurvesWS, cs.m_forceRecalcOverwrite);
Federico Montesino Pouzols
committed
const std::string instStr = m_view->currentInstrument();
try {
auto load = Algorithm::fromString("Load");
load->initialize();
load->setPropertyValue("Filename", instStr + ceriaNo);
std::string ceriaWSName = "engggui_calibration_sample_ws";
load->setPropertyValue("OutputWorkspace", ceriaWSName);
load->execute();
AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance();
ceriaWS = ADS.retrieveWS<MatrixWorkspace>(ceriaWSName);
} catch (std::runtime_error &re) {
Federico Montesino Pouzols
committed
g_log.error()
<< "Error while loading calibration sample data. "
"Could not run the algorithm Load succesfully for the calibration "
"sample (run number: " +
ceriaNo + "). Error description: " + re.what() +
" Please check also the previous log messages for details.";
Federico Montesino Pouzols
committed
throw;
}
// Bank 1 and 2 - ENGIN-X
const size_t numBanks = 2;
std::vector<double> difc, tzero;
Federico Montesino Pouzols
committed
difc.resize(numBanks);
tzero.resize(numBanks);
for (size_t i = 0; i < difc.size(); i++) {
auto alg = Algorithm::fromString("EnggCalibrate");
try {
alg->initialize();
alg->setProperty("InputWorkspace", ceriaWS);
Federico Montesino Pouzols
committed
alg->setProperty("VanIntegrationWorkspace", vanIntegWS);
alg->setProperty("VanCurvesWorkspace", vanCurvesWS);
alg->setPropertyValue("Bank", boost::lexical_cast<std::string>(i + 1));
// TODO: figure out what should be done about the list of expected peaks
Federico Montesino Pouzols
committed
// to EnggCalibrate => it should be a default, as in EnggFitPeaks, that
// should be fixed in a nother ticket/issue
alg->setPropertyValue(
"ExpectedPeaks",
"3.1243, 2.7057, 1.9132, 1.6316, 1.5621, "
"1.3529, 1.2415, 1.2100, 1.1046, 1.0414, 0.9566, 0.9147, 0.9019, "
"0.8556, 0.8252, 0.8158, 0.7811");
alg->setPropertyValue("OutputParametersTableName",
"engggui_calibration_bank_" +
boost::lexical_cast<std::string>(i + 1));
alg->execute();
} catch (std::runtime_error &re) {
Federico Montesino Pouzols
committed
g_log.error() << "Error in calibration. ",
"Could not run the algorithm EnggCalibrate succesfully for bank " +
boost::lexical_cast<std::string>(i) + ". Error description: " +
re.what() + " Please check also the log messages for details.";
}
difc[i] = alg->getProperty("Difc");
tzero[i] = alg->getProperty("Zero");
g_log.notice() << " * Bank " << i + 1 << " calibrated, "
Federico Montesino Pouzols
committed
<< "difc: " << difc[i] << ", zero: " << tzero[i]
<< std::endl;
Federico Montesino Pouzols
committed
// Double horror: 1st use a python script
// 2nd: because runPythonCode does this by emitting a signal that goes to
// MantidPlot,
// it has to be done in the view (which is a UserSubWindow).
Poco::Path outFullPath(cs.m_inputDirCalib);
outFullPath.append(outFilename);
m_view->writeOutCalibFile(outFullPath.toString(), difc, tzero);
g_log.notice() << "Calibration file written as " << outFullPath.toString()
<< std::endl;
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
/**
* @TODO
*
*/
void EnggDiffractionPresenter::inputChecksBeforeFocus(const std::string &runNo,
int bank) {}
/**
* @TODO
*
*/
std::string
EnggDiffractionPresenter::outputFocusFilename(const std::string &runNo,
int bank) {
const std::string instStr = m_view->currentInstrument();
return instStr + runNo + "_focused";
}
/**
* Start the focusing algorithm(s) without blocking the GUI. This is
* based on Qt connect / signals-slots so that it goes in sync with
* the Qt event loop. For that reason this class needs to be a
* Q_OBJECT.
*
* @param dir directory (full path) for the focused output files
* @param outFilename full name for the output focused run
* @param runNo input run number
* @param bank instrument bank to focus
*/
void EnggDiffractionPresenter::startAsyncFocusWorker(
const std::string &dir, const std::string &outFilename,
const std::string &runNo, int bank) {
delete m_workerThread;
m_workerThread = new QThread(this);
EnggDiffWorker *worker =
new EnggDiffWorker(this, dir, outFilename, runNo, bank);
worker->moveToThread(m_workerThread);
connect(m_workerThread, SIGNAL(started()), worker, SLOT(focus()));
connect(worker, SIGNAL(finished()), this, SLOT(focusingFinished()));
// early delete of thread and worker
connect(m_workerThread, SIGNAL(finished()), m_workerThread,
SLOT(deleteLater()), Qt::DirectConnection);
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
m_workerThread->start();
}
/**
* Produce a new focused output file. This is what threads/workers
* should use to run the calculations required to process a 'focus'
* push or similar from the user.
*
* @param dir directory (full path) for the output focused files
* @param outFilename name for the output focused file
* @param runNo input run number
* @param bank bank number for the focusing
*/
void EnggDiffractionPresenter::doFocusRun(const std::string &dir,
const std::string &outFilename,
const std::string &runNo, int bank) {
g_log.notice() << "Generating new focused file (bank " +
boost::lexical_cast<std::string>(bank) + ") for run " +
runNo + " into: " << outFilename << std::endl;
Poco::Path fpath(dir);
Federico Montesino Pouzols
committed
const std::string fullFilename = fpath.append(outFilename).toString();
// TODO: this is almost 100% common with doNewCalibrate() - refactor
EnggDiffCalibSettings cs = m_view->currentCalibSettings();
Mantid::Kernel::ConfigServiceImpl &conf =
Mantid::Kernel::ConfigService::Instance();
const std::vector<std::string> tmpDirs = conf.getDataSearchDirs();
// in principle, the run files will be found from 'DirRaw', and the
// pre-calculated Vanadium corrections from 'DirCalib'
if (!cs.m_inputDirCalib.empty() && Poco::File(cs.m_inputDirCalib).exists()) {
conf.appendDataSearchDir(cs.m_inputDirCalib);
}
if (!cs.m_inputDirRaw.empty() && Poco::File(cs.m_inputDirRaw).exists()) {
conf.appendDataSearchDir(cs.m_inputDirRaw);
}
try {
doFocusing(cs, fullFilename, runNo, bank);
m_focusFinishedOK = true;
} catch (std::runtime_error &) {
g_log.error() << "The focusing calculations failed. One of the algorithms"
"did not execute correctly. See log messages for details."
<< std::endl;
Federico Montesino Pouzols
committed
} catch (std::invalid_argument &ia) {
g_log.error()
<< "The focusing failed. Some input properties were not valid. "
Federico Montesino Pouzols
committed
"See log messages for details. Error: " << ia.what() << std::endl;
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
}
// restore initial data search paths
conf.setDataSearchDirs(tmpDirs);
}
/**
* Method (Qt slot) to call when the focusing work has finished,
* possibly from a separate thread but sometimes not (as in this
* presenter class' test).
*/
void EnggDiffractionPresenter::focusingFinished() {
if (!m_view)
return;
m_view->enableCalibrateAndFocusActions(true);
if (!m_focusFinishedOK) {
g_log.warning() << "The cablibration did not finished correctly."
<< std::endl;
} else {
g_log.notice() << "Focusing finished - focused run ready." << std::endl;
}
if (m_workerThread) {
delete m_workerThread;
m_workerThread = NULL;
}
}
/**
* Focuses a run, produces a focused workspace, and saves it into a
* file.
*
* @param cs user settings for calibration (this does not calibrate but
* uses calibration input files such as vanadium runs
*
* @param fullFilename full paht for the output (focused) filename
* @param runNo input run to focus
* @param bank instrument bank to focus
*/
void EnggDiffractionPresenter::doFocusing(const EnggDiffCalibSettings &cs,
const std::string &fullFilename,
const std::string &runNo, int bank) {
ITableWorkspace_sptr vanIntegWS;
MatrixWorkspace_sptr vanCurvesWS;
MatrixWorkspace_sptr inWS;
const std::string vanNo = m_view->currentVanadiumNo();
loadOrCalcVanadiumWorkspaces(vanNo, cs.m_inputDirCalib, vanIntegWS,
vanCurvesWS, cs.m_forceRecalcOverwrite);
const std::string inWSName = "engggui_focusing_input_ws";
const std::string instStr = m_view->currentInstrument();
try {
auto load = Algorithm::fromString("Load");
load->initialize();
load->setPropertyValue("Filename", instStr + runNo);
load->setPropertyValue("OutputWorkspace", inWSName);
load->execute();
AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance();
inWS = ADS.retrieveWS<MatrixWorkspace>(inWSName);
} catch (std::runtime_error &re) {
g_log.error()
<< "Error while loading sample data for focusing. "
"Could not run the algorithm Load succesfully for the focusing "
"sample (run number: " +
runNo + "). Error description: " + re.what() +
" Please check also the previous log messages for details.";
throw;
}
Federico Montesino Pouzols
committed
const std::string outWSName = "engggui_focusing_output_ws";
try {
auto alg = Algorithm::fromString("EnggFocus");
alg->initialize();
alg->setProperty("InputWorkspace", inWSName);
alg->setProperty("OutputWorkspace", outWSName);
alg->setProperty("VanIntegrationWorkspace", vanIntegWS);
alg->setProperty("VanCurvesWorkspace", vanCurvesWS);
alg->setPropertyValue("Bank", boost::lexical_cast<std::string>(bank));
// TODO: use detector positions (from calibrate full) when available
// alg->setProperty(DetectorPositions, TableWorkspace)
alg->execute();
} catch (std::runtime_error &re) {
g_log.error() << "Error in calibration. ",
"Could not run the algorithm EnggCalibrate succesfully for bank " +
boost::lexical_cast<std::string>(bank) + ". Error description: " +
re.what() + " Please check also the log messages for details.";
throw;
}
g_log.notice() << "Produced focused workspace: " << outWSName << std::endl;
try {
Federico Montesino Pouzols
committed
g_log.debug() << "Going to save focused output into nexus file: "
<< fullFilename << std::endl;
auto alg = Algorithm::fromString("SaveNexus");
alg->initialize();
alg->setPropertyValue("InputWorkspace", outWSName);
alg->setPropertyValue("Filename", fullFilename);
alg->execute();
} catch (std::runtime_error &re) {
g_log.error() << "Error in calibration. ",
"Could not run the algorithm EnggCalibrate succesfully for bank " +
boost::lexical_cast<std::string>(bank) + ". Error description: " +
re.what() + " Please check also the log messages for details.";
throw;
}
g_log.notice() << "Saved focused workspace as file: " << fullFilename
<< std::endl;
}
* Produce the two workspaces that are required to apply Vanadium
* corrections. Try to load them if precalculated results are
* available from files, otherwise load the source Vanadium run
* workspace and do the calculations.
* @param vanNo Vanadium run number
* @param inputDirCalib The 'calibration files' input directory given
* in settings
* @param vanIntegWS workspace where to create/load the Vanadium
* spectra integration
*
* @param vanCurvesWS workspace where to create/load the Vanadium
* aggregated per-bank curve
*
* @param forceRecalc whether to calculate Vanadium corrections even
* if the files of pre-calculated results are found
void EnggDiffractionPresenter::loadOrCalcVanadiumWorkspaces(
const std::string &vanNo, const std::string &inputDirCalib,
ITableWorkspace_sptr &vanIntegWS, MatrixWorkspace_sptr &vanCurvesWS,
bool forceRecalc) {
bool foundPrecalc = false;
std::string preIntegFilename, preCurvesFilename;
findPrecalcVanadiumCorrFilenames(vanNo, inputDirCalib, preIntegFilename,
preCurvesFilename, foundPrecalc);
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
if (forceRecalc || !foundPrecalc) {
g_log.notice()
<< "Calculating Vanadium corrections. This may take a few seconds..."
<< std::endl;
try {
calcVanadiumWorkspaces(vanNo, vanIntegWS, vanCurvesWS);
} catch (std::invalid_argument &ia) {
g_log.error() << "Failed to calculate Vanadium corrections. "
"There was an error in the execution of the algorithms "
"required to calculate Vanadium corrections. Some "
"properties passed to the algorithms were invalid. "
"This is possibly because some of the settings are not "
"consistent. Please check the log messages for "
"details. Details: " +
std::string(ia.what()) << std::endl;
throw;
} catch (std::runtime_error &re) {
g_log.error() << "Failed to calculate Vanadium corrections. "
"There was an error while executing one of the "
"algorithms used to perform Vanadium corrections. "
"There was no obvious error in the input properties "
"but the algorithm failed. Please check the log "
"messages for details." +
std::string(re.what()) << std::endl;
throw;
}
} else {
g_log.notice()
<< "Found precalculated Vanadium correction features for Vanadium run "
<< vanNo << ". Re-using these files: " << preIntegFilename << ", and "
<< preCurvesFilename << std::endl;
try {
loadVanadiumPrecalcWorkspaces(preIntegFilename, preCurvesFilename,
vanIntegWS, vanCurvesWS);
} catch (std::invalid_argument &ia) {
g_log.error() << "Error while loading precalculated Vanadium corrections",
"The files with precalculated Vanadium corection features (spectra "
"integration and per-bank curves) were found (with names '" +
preIntegFilename + "' and '" + preCurvesFilename +
"', respectively, but there was a problem with the inputs to the "
"load algorithms to load them: " +
std::string(ia.what());
throw;
} catch (std::runtime_error &re) {
g_log.error() << "Error while loading precalculated Vanadium corrections",
"The files with precalculated Vanadium corection features (spectra "
"integration and per-bank curves) were found (with names '" +
preIntegFilename + "' and '" + preCurvesFilename +
"', respectively, but there was a problem while loading them. "
"Please check the log messages for details. You might want to "
"delete those files or force recalculations (in settings). Error "
"details: " +
std::string(re.what());
throw;
}
* builds the expected names of the precalculated Vanadium correction
* files and tells if both files are found, similar to:
* ENGINX_precalculated_vanadium_run000236516_integration.nxs
* ENGINX_precalculated_vanadium_run00236516_bank_curves.nxs
* @param vanNo Vanadium run number
* @param inputDirCalib calibration directory in settings
* @param preIntegFilename if not found on disk, the string is set as empty
* @param preCurvesFilename if not found on disk, the string is set as empty
* @param found true if both files are found and (re-)usable
void EnggDiffractionPresenter::findPrecalcVanadiumCorrFilenames(
const std::string &vanNo, const std::string &inputDirCalib,
std::string &preIntegFilename, std::string &preCurvesFilename,
bool &found) {
found = false;
const std::string runNo = std::string(2, '0').append(vanNo);
preIntegFilename =
g_enginxStr + "_precalculated_vanadium_run" + runNo + "_integration.nxs";
preCurvesFilename =
g_enginxStr + "_precalculated_vanadium_run" + runNo + "_bank_curves.nxs";
Poco::Path pathInteg(inputDirCalib);
pathInteg.append(preIntegFilename);
Poco::Path pathCurves(inputDirCalib);
pathCurves.append(preCurvesFilename);
if (Poco::File(pathInteg).exists() && Poco::File(pathCurves).exists()) {
preIntegFilename = pathInteg.toString();
preCurvesFilename = pathCurves.toString();
found = true;
}
* Load precalculated results from Vanadium corrections previously
* calculated.
Federico Montesino Pouzols
committed
* @param preIntegFilename filename (can be full path) where the
* vanadium spectra integration table should be loaded from
*
* @param preCurvesFilename filename (can be full path) where the
* vanadium per-bank curves should be loaded from
*
* @param vanIntegWS output (matrix) workspace loaded from the
* precalculated Vanadium correction file, with the integration
* resutls
*
* @param vanCurvesWS output (matrix) workspace loaded from the
* precalculated Vanadium correction file, with the per-bank curves
*/
void EnggDiffractionPresenter::loadVanadiumPrecalcWorkspaces(
Federico Montesino Pouzols
committed
const std::string &preIntegFilename, const std::string &preCurvesFilename,
ITableWorkspace_sptr &vanIntegWS, MatrixWorkspace_sptr &vanCurvesWS) {
AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance();
auto alg = Algorithm::fromString("LoadNexus");
alg->initialize();
Federico Montesino Pouzols
committed
alg->setPropertyValue("Filename", preIntegFilename);
std::string integWSName = "engggui_vanadium_integration_ws";
alg->setPropertyValue("OutputWorkspace", integWSName);
Federico Montesino Pouzols
committed
// alg->getProperty("OutputWorkspace");
vanIntegWS = ADS.retrieveWS<ITableWorkspace>(integWSName);
auto algCurves = Algorithm::fromString("LoadNexus");
algCurves->initialize();
Federico Montesino Pouzols
committed
algCurves->setPropertyValue("Filename", preCurvesFilename);
std::string curvesWSName = "engggui_vanadium_curves_ws";
algCurves->setPropertyValue("OutputWorkspace", curvesWSName);
algCurves->execute();
Federico Montesino Pouzols
committed
// algCurves->getProperty("OutputWorkspace");
vanCurvesWS = ADS.retrieveWS<MatrixWorkspace>(curvesWSName);
/**
* Calculate vanadium corrections (in principle only for when
* pre-calculated results are not available). This is expensive.
*
* @param vanNo Vanadium run number
*
* @param vanIntegWS where to keep the Vanadium run spectra
* integration values
*
* @param vanCurvesWS workspace where to keep the per-bank vanadium
* curves
*/
void EnggDiffractionPresenter::calcVanadiumWorkspaces(
Federico Montesino Pouzols
committed
const std::string &vanNo, ITableWorkspace_sptr &vanIntegWS,
MatrixWorkspace_sptr &vanCurvesWS) {
auto load = Algorithm::fromString("Load");
Federico Montesino Pouzols
committed
load->setPropertyValue("Filename",
vanNo); // TODO more specific build Vanadium filename
std::string vanWSName = "engggui_vanadium_ws";
load->setPropertyValue("OutputWorkspace", vanWSName);
load->execute();
Federico Montesino Pouzols
committed
AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance();
MatrixWorkspace_sptr vanWS = ADS.retrieveWS<MatrixWorkspace>(vanWSName);
// TODO: maybe use setChild() and then load->getProperty("OutputWorkspace");
auto alg = Algorithm::fromString("EnggVanadiumCorrections");
alg->initialize();
alg->setProperty("VanadiumWorkspace", vanWS);
Federico Montesino Pouzols
committed
std::string integName = "engggui_van_integration_ws";
alg->setPropertyValue("IntegrationWorkspace", integName);
std::string curvesName = "engggui_van_curves_ws";
alg->setPropertyValue("CurvesWorkspace", curvesName);
Federico Montesino Pouzols
committed
ADS.remove(vanWSName);
vanIntegWS = ADS.retrieveWS<ITableWorkspace>(integName);
vanCurvesWS = ADS.retrieveWS<MatrixWorkspace>(curvesName);
} // namespace CustomInterfaces
} // namespace MantidQt