From 6d06ffad61056c1bffa19239b2f6301c97461ff5 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 13 Oct 2014 10:41:04 +0100 Subject: [PATCH 001/128] Fixed trivial issues, mainly uninitialised members Refs #10345 --- .../Mantid/MantidQt/API/src/GenericDialog.cpp | 3 +- .../API/src/MantidQwtIMDWorkspaceData.cpp | 3 +- .../MantidQt/API/src/QwtRasterDataMD.cpp | 3 + .../src/CreateSampleShapeDialog.cpp | 2 +- .../CustomDialogs/src/LoadAsciiDialog.cpp | 8 ++- .../CustomDialogs/src/LoadDAEDialog.cpp | 18 ++++-- .../CustomDialogs/src/LoadRawDialog.cpp | 3 +- .../src/SmoothNeighboursDialog.cpp | 3 +- .../CustomDialogs/src/StartLiveDataDialog.cpp | 4 +- .../SANSDiagnostics.h | 2 +- .../CustomInterfaces/src/ApplyCorr.cpp | 2 +- .../MantidQt/CustomInterfaces/src/Homer.cpp | 4 +- .../src/IndirectDataAnalysis.cpp | 4 +- .../MantidQt/CustomInterfaces/src/MSDFit.cpp | 4 +- .../CustomInterfaces/src/SANSPlotSpecial.cpp | 2 +- .../CustomInterfaces/src/SANSRunWindow.cpp | 2 + .../MantidWidgets/src/FitPropertyBrowser.cpp | 61 +++++++++++++------ .../MantidWidgets/src/PropertyHandler.cpp | 2 + .../RefRangeHandler.h | 2 +- .../src/RefMatrixWSImageView.cpp | 3 +- .../RefDetectorViewer/src/RefRangeHandler.cpp | 13 ++-- .../SliceViewer/src/PhysicalCrossPeak.cpp | 3 +- .../src/ProxyCompositePeaksPresenter.cpp | 3 +- .../SpectrumViewer/src/GraphDisplay.cpp | 4 +- .../SpectrumViewer/src/RangeHandler.cpp | 6 +- .../SpectrumViewer/src/SpectrumDisplay.cpp | 2 +- .../SpectrumViewer/src/SpectrumView.cpp | 9 ++- 27 files changed, 123 insertions(+), 52 deletions(-) diff --git a/Code/Mantid/MantidQt/API/src/GenericDialog.cpp b/Code/Mantid/MantidQt/API/src/GenericDialog.cpp index dae3a1ad2511..1ad125af5f91 100644 --- a/Code/Mantid/MantidQt/API/src/GenericDialog.cpp +++ b/Code/Mantid/MantidQt/API/src/GenericDialog.cpp @@ -43,7 +43,8 @@ using namespace Mantid::API; /** * Default Constructor */ -GenericDialog::GenericDialog(QWidget* parent) : AlgorithmDialog(parent) +GenericDialog::GenericDialog(QWidget* parent) : AlgorithmDialog(parent), + m_algoPropertiesWidget(NULL) { } diff --git a/Code/Mantid/MantidQt/API/src/MantidQwtIMDWorkspaceData.cpp b/Code/Mantid/MantidQt/API/src/MantidQwtIMDWorkspaceData.cpp index 9ab24cfaaadd..88a8f408b313 100644 --- a/Code/Mantid/MantidQt/API/src/MantidQwtIMDWorkspaceData.cpp +++ b/Code/Mantid/MantidQt/API/src/MantidQwtIMDWorkspaceData.cpp @@ -94,7 +94,8 @@ MantidQwtIMDWorkspaceData::MantidQwtIMDWorkspaceData(Mantid::API::IMDWorkspace_c //----------------------------------------------------------------------------- /// Copy constructor -MantidQwtIMDWorkspaceData::MantidQwtIMDWorkspaceData(const MantidQwtIMDWorkspaceData& data) +MantidQwtIMDWorkspaceData::MantidQwtIMDWorkspaceData(const MantidQwtIMDWorkspaceData& data) : + m_minPositive(0.0) { this->operator =(data); } diff --git a/Code/Mantid/MantidQt/API/src/QwtRasterDataMD.cpp b/Code/Mantid/MantidQt/API/src/QwtRasterDataMD.cpp index 24ab0cdd4beb..ee059b16603b 100644 --- a/Code/Mantid/MantidQt/API/src/QwtRasterDataMD.cpp +++ b/Code/Mantid/MantidQt/API/src/QwtRasterDataMD.cpp @@ -19,6 +19,9 @@ using Mantid::Geometry::IMDDimension_const_sptr; QwtRasterDataMD::QwtRasterDataMD() : m_ws(), m_overlayWS(), m_slicePoint(NULL), m_fast(true), m_zerosAsNan(true), + m_overlayXMin(0.0), m_overlayXMax(0.0), + m_overlayYMin(0.0), m_overlayYMax(0.0), + m_overlayInSlice(false), m_normalization(Mantid::API::VolumeNormalization) { m_range = QwtDoubleInterval(0.0, 1.0); diff --git a/Code/Mantid/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp b/Code/Mantid/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp index 54c9353030ea..238dab402252 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp +++ b/Code/Mantid/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp @@ -38,7 +38,7 @@ using namespace MantidQt::CustomDialogs; * Constructor */ CreateSampleShapeDialog::CreateSampleShapeDialog(QWidget *parent) : - AlgorithmDialog(parent), m_setup_map(), m_details_map(), m_ops_map() + AlgorithmDialog(parent), m_shapeTree(NULL), m_setup_map(), m_details_map(), m_ops_map() { m_object_viewer = new MantidGLWidget; } diff --git a/Code/Mantid/MantidQt/CustomDialogs/src/LoadAsciiDialog.cpp b/Code/Mantid/MantidQt/CustomDialogs/src/LoadAsciiDialog.cpp index b3bfe99fc058..97e65a3689a1 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/src/LoadAsciiDialog.cpp +++ b/Code/Mantid/MantidQt/CustomDialogs/src/LoadAsciiDialog.cpp @@ -15,13 +15,17 @@ namespace MantidQt DECLARE_DIALOG(LoadAsciiDialog) LoadAsciiDialog::LoadAsciiDialog(QWidget *parent) - : MantidQt::API::AlgorithmDialog(parent) + : MantidQt::API::AlgorithmDialog(parent), + m_lineFilename(NULL), + m_lineOutputWorkspace(NULL), + m_lineCommentIndicator(NULL), + m_lineCustomSeparator(NULL), + m_separatorBox(NULL) { } LoadAsciiDialog::~LoadAsciiDialog() { - } void LoadAsciiDialog::initLayout() diff --git a/Code/Mantid/MantidQt/CustomDialogs/src/LoadDAEDialog.cpp b/Code/Mantid/MantidQt/CustomDialogs/src/LoadDAEDialog.cpp index ec1a11a1278f..a378f5bc1b41 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/src/LoadDAEDialog.cpp +++ b/Code/Mantid/MantidQt/CustomDialogs/src/LoadDAEDialog.cpp @@ -20,13 +20,19 @@ class NoDeleting { public: /// Does nothing - void operator()(void*){} - /// Does nothing - void operator()(const void*){} - }; + void operator()(void*){} + /// Does nothing + void operator()(const void*){} +}; - LoadDAEDialog::LoadDAEDialog(QWidget *parent) -: MantidQt::API::AlgorithmDialog(parent) +LoadDAEDialog::LoadDAEDialog(QWidget *parent) + : MantidQt::API::AlgorithmDialog(parent), + lineHost(NULL), + lineName(NULL), + minSpLineEdit(NULL), + maxSpLineEdit(NULL), + listSpLineEdit(NULL), + updateLineEdit(NULL) { } diff --git a/Code/Mantid/MantidQt/CustomDialogs/src/LoadRawDialog.cpp b/Code/Mantid/MantidQt/CustomDialogs/src/LoadRawDialog.cpp index 4976b559a89a..685a349fbdce 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/src/LoadRawDialog.cpp +++ b/Code/Mantid/MantidQt/CustomDialogs/src/LoadRawDialog.cpp @@ -35,7 +35,8 @@ using namespace MantidQt::CustomDialogs; /** * Constructor */ -LoadRawDialog::LoadRawDialog(QWidget *parent) : AlgorithmDialog(parent) +LoadRawDialog::LoadRawDialog(QWidget *parent) : AlgorithmDialog(parent), + m_pathBox(NULL), m_wsBox(NULL) { } diff --git a/Code/Mantid/MantidQt/CustomDialogs/src/SmoothNeighboursDialog.cpp b/Code/Mantid/MantidQt/CustomDialogs/src/SmoothNeighboursDialog.cpp index 74c3e4cea556..57379d6ab99f 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/src/SmoothNeighboursDialog.cpp +++ b/Code/Mantid/MantidQt/CustomDialogs/src/SmoothNeighboursDialog.cpp @@ -13,7 +13,8 @@ const QString SmoothNeighboursDialog::RECTANGULAR_GROUP = "Rectangular Detectors const QString SmoothNeighboursDialog::INPUT_WORKSPACE = "InputWorkspace"; SmoothNeighboursDialog::SmoothNeighboursDialog(QWidget* parent) - : AlgorithmDialog(parent) + : AlgorithmDialog(parent), + m_propertiesWidget(NULL), m_dialogLayout(NULL) { } diff --git a/Code/Mantid/MantidQt/CustomDialogs/src/StartLiveDataDialog.cpp b/Code/Mantid/MantidQt/CustomDialogs/src/StartLiveDataDialog.cpp index 64babaf5bab8..773926463535 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/src/StartLiveDataDialog.cpp +++ b/Code/Mantid/MantidQt/CustomDialogs/src/StartLiveDataDialog.cpp @@ -71,7 +71,9 @@ namespace CustomDialogs //---------------------- ///Constructor StartLiveDataDialog::StartLiveDataDialog(QWidget *parent) : - AlgorithmDialog(parent) + AlgorithmDialog(parent), + m_useProcessAlgo(false), m_useProcessScript(NULL), + m_usePostProcessAlgo(false), m_usePostProcessScript(false) { // Create the input history. This loads it too. LiveDataAlgInputHistory::Instance(); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSDiagnostics.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSDiagnostics.h index d48972cd4978..4e6189901cbe 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSDiagnostics.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSDiagnostics.h @@ -43,7 +43,7 @@ namespace CustomInterfaces { public: /// constructor - RectDetectorDetails(){} + RectDetectorDetails(): m_minDetId(0), m_maxDetId(0) {} ///destructor ~RectDetectorDetails(){} /// set minimum detector id diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/ApplyCorr.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/ApplyCorr.cpp index b3ea0d159d27..d0d88bf1adac 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/ApplyCorr.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/ApplyCorr.cpp @@ -17,7 +17,7 @@ namespace CustomInterfaces namespace IDA { ApplyCorr::ApplyCorr(QWidget * parent) : - IDATab(parent) + IDATab(parent), m_valPosDbl(NULL) { } diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Homer.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Homer.cpp index 7c1155de353d..0dbe328ed5a5 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Homer.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Homer.cpp @@ -38,7 +38,9 @@ using namespace MantidQt::CustomInterfaces; Homer::Homer(QWidget *parent, Ui::DirectConvertToEnergy & uiForm) : UserSubWindow(parent), m_uiForm(uiForm), m_backgroundDialog(NULL), m_diagPage(NULL),m_saveChanged(false), - m_backgroundWasVisible(false), m_absEiDirty(false), m_topSettingsGroup("CustomInterfaces/Homer") + m_backgroundWasVisible(false), m_absEiDirty(false), + m_saveChecksGroup(NULL), + m_topSettingsGroup("CustomInterfaces/Homer") {} /// Set up the dialog layout diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDataAnalysis.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDataAnalysis.cpp index d880aa990450..85798a0d78de 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDataAnalysis.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDataAnalysis.cpp @@ -34,7 +34,9 @@ namespace IDA * @param parent :: the parent QWidget. */ IndirectDataAnalysis::IndirectDataAnalysis(QWidget *parent) : - UserSubWindow(parent), m_dblEdFac(NULL), m_blnEdFac(NULL), + UserSubWindow(parent), + m_valInt(NULL), m_valDbl(NULL), + m_dblEdFac(NULL), m_blnEdFac(NULL), m_changeObserver(*this, &IndirectDataAnalysis::handleDirectoryChange) { // Allows us to get a handle on a tab using an enum, for example "m_tabs[ELWIN]". diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/MSDFit.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/MSDFit.cpp index 226cd5965c33..2655b41c5877 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/MSDFit.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/MSDFit.cpp @@ -16,7 +16,9 @@ namespace CustomInterfaces { namespace IDA { - MSDFit::MSDFit(QWidget * parent) : IDATab(parent), m_msdPlot(NULL), m_msdRange(NULL), m_msdDataCurve(NULL), m_msdFitCurve(NULL), + MSDFit::MSDFit(QWidget * parent) : IDATab(parent), + m_intVal(NULL), + m_msdPlot(NULL), m_msdRange(NULL), m_msdDataCurve(NULL), m_msdFitCurve(NULL), m_msdTree(NULL), m_msdProp(), m_msdDblMng(NULL) {} diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/SANSPlotSpecial.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/SANSPlotSpecial.cpp index 8cfc0d5adfec..bf2ae347a6ec 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/SANSPlotSpecial.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/SANSPlotSpecial.cpp @@ -844,7 +844,7 @@ QPair > SANSPlotSpecial::getProperties(const //------- Utility "Transform" Class ---------------------------------- //-------------------------------------------------------------------- SANSPlotSpecial::Transform::Transform(Transform::TransformType type) : m_type(type), - m_xWidgets(QList()), m_yWidgets(QList()), m_gDeriv(""), m_iDeriv("") + m_xWidgets(QList()), m_yWidgets(QList()), m_parent(NULL), m_gDeriv(""), m_iDeriv("") { init(); } diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp index dc2fff810eb0..1767acd57efd 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp @@ -156,11 +156,13 @@ SANSRunWindow::SANSRunWindow(QWidget *parent) : UserSubWindow(parent), m_addFilesTab(NULL), m_displayTab(NULL), m_diagnosticsTab(NULL), m_saveWorkspaces(NULL), m_ins_defdir(""), m_last_dir(""), m_cfg_loaded(true), m_userFname(false), m_sample_file(), + m_reducemapper(NULL), m_warnings_issued(false), m_force_reload(false), m_newInDir(*this, &SANSRunWindow::handleInputDirChange), m_delete_observer(*this, &SANSRunWindow::handleMantidDeleteWorkspace), m_s2d_detlabels(), m_loq_detlabels(), m_allowed_batchtags(), m_have_reducemodule(false), m_dirty_batch_grid(false), m_tmp_batchfile(""), + m_batch_paste(NULL), m_batch_clear(NULL), slicingWindow(NULL) { ConfigService::Instance().addObserver(m_newInDir); diff --git a/Code/Mantid/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp b/Code/Mantid/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp index 7569e77f952b..5661757ccf5b 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp +++ b/Code/Mantid/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp @@ -85,23 +85,49 @@ namespace MantidWidgets * @param parent :: The parent widget - must be an ApplicationWindow * @param mantidui :: The UI form for MantidPlot */ -FitPropertyBrowser::FitPropertyBrowser(QWidget *parent, QObject* mantidui) -:QDockWidget("Fit Function",parent), -m_logValue(NULL), -m_compositeFunction(), -m_changeSlotsEnabled(false), -m_guessOutputName(true), -m_updateObserver(*this,&FitPropertyBrowser::handleFactoryUpdate), -m_currentHandler(0), -m_defaultFunction("Gaussian"), -m_defaultPeak("Gaussian"), -m_defaultBackground("LinearBackground"), -m_peakToolOn(false), -m_auto_back(false), -m_autoBgName(QString::fromStdString(Mantid::Kernel::ConfigService::Instance().getString("curvefitting.autoBackground"))), -m_autoBackground(NULL), -m_decimals(-1), -m_mantidui(mantidui) +FitPropertyBrowser::FitPropertyBrowser(QWidget *parent, QObject* mantidui): + QDockWidget("Fit Function",parent), + m_logValue(NULL), + m_plotCompositeMembers(NULL), + m_convolveMembers(NULL), + m_rawData(NULL), + m_xColumn(NULL), + m_yColumn(NULL), + m_errColumn(NULL), + m_showParamErrors(NULL), + m_compositeFunction(), + m_browser(NULL), + m_fitActionUndoFit(NULL), + m_fitActionSeqFit(NULL), + m_fitActionFit(NULL), + m_fitActionEvaluate(NULL), + m_functionsGroup(NULL), + m_settingsGroup(NULL), + m_customSettingsGroup(NULL), + m_changeSlotsEnabled(false), + m_guessOutputName(true), + m_updateObserver(*this,&FitPropertyBrowser::handleFactoryUpdate), + m_fitMapper(NULL), + m_fitMenu(NULL), + m_displayActionPlotGuess(NULL), + m_displayActionQuality(NULL), + m_displayActionClearAll(NULL), + m_setupActionCustomSetup(NULL), + m_setupActionRemove(NULL), + m_tip(NULL), + m_fitSelector(NULL), + m_fitTree(NULL), + m_currentHandler(0), + m_defaultFunction("Gaussian"), + m_defaultPeak("Gaussian"), + m_defaultBackground("LinearBackground"), + m_index_(0), + m_peakToolOn(false), + m_auto_back(false), + m_autoBgName(QString::fromStdString(Mantid::Kernel::ConfigService::Instance().getString("curvefitting.autoBackground"))), + m_autoBackground(NULL), + m_decimals(-1), + m_mantidui(mantidui) { // Make sure plugins are loaded std::string libpath = Mantid::Kernel::ConfigService::Instance().getString("plugins.directory"); @@ -2074,6 +2100,7 @@ void FitPropertyBrowser::deleteTie() QtBrowserItem * ci = m_browser->currentItem(); QtProperty* paramProp = ci->property(); PropertyHandler* h = getHandler()->findHandler(paramProp); + if (!h) return; if (ci->property()->propertyName() != "Tie") { diff --git a/Code/Mantid/MantidQt/MantidWidgets/src/PropertyHandler.cpp b/Code/Mantid/MantidQt/MantidWidgets/src/PropertyHandler.cpp index 72bd55b076a1..26f2aa3bd9b8 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/src/PropertyHandler.cpp +++ b/Code/Mantid/MantidQt/MantidWidgets/src/PropertyHandler.cpp @@ -41,6 +41,8 @@ PropertyHandler::PropertyHandler(Mantid::API::IFunction_sptr fun, m_parent(parent), m_type(NULL), m_item(item), + m_workspace(NULL), + m_workspaceIndex(NULL), m_isMultispectral(false), m_base(0), m_ci(0), diff --git a/Code/Mantid/MantidQt/RefDetectorViewer/inc/MantidQtRefDetectorViewer/RefRangeHandler.h b/Code/Mantid/MantidQt/RefDetectorViewer/inc/MantidQtRefDetectorViewer/RefRangeHandler.h index c251cc3990c3..0facba9a1b93 100644 --- a/Code/Mantid/MantidQt/RefDetectorViewer/inc/MantidQtRefDetectorViewer/RefRangeHandler.h +++ b/Code/Mantid/MantidQt/RefDetectorViewer/inc/MantidQtRefDetectorViewer/RefRangeHandler.h @@ -62,8 +62,8 @@ class EXPORT_OPT_MANTIDQT_REFDETECTORVIEWER RefRangeHandler : public SpectrumVie Ui_RefImageViewer* iv_ui; double total_min_x; double total_max_x; - double total_max_y; double total_min_y; + double total_max_y; size_t total_n_steps; }; diff --git a/Code/Mantid/MantidQt/RefDetectorViewer/src/RefMatrixWSImageView.cpp b/Code/Mantid/MantidQt/RefDetectorViewer/src/RefMatrixWSImageView.cpp index 558a8d6fab87..01458b2fc9a0 100644 --- a/Code/Mantid/MantidQt/RefDetectorViewer/src/RefMatrixWSImageView.cpp +++ b/Code/Mantid/MantidQt/RefDetectorViewer/src/RefMatrixWSImageView.cpp @@ -18,7 +18,8 @@ using namespace Mantid::API; /** * Construct an ImageView for the specified matrix workspace */ -RefMatrixWSImageView::RefMatrixWSImageView( MatrixWorkspace_sptr /*mat_ws*/ ) +RefMatrixWSImageView::RefMatrixWSImageView( MatrixWorkspace_sptr /*mat_ws*/ ) : + image_view(NULL) { return; // RefMatrixWSDataSource* source = new RefMatrixWSDataSource( mat_ws ); diff --git a/Code/Mantid/MantidQt/RefDetectorViewer/src/RefRangeHandler.cpp b/Code/Mantid/MantidQt/RefDetectorViewer/src/RefRangeHandler.cpp index b0aaee783531..c15eb69b56e9 100644 --- a/Code/Mantid/MantidQt/RefDetectorViewer/src/RefRangeHandler.cpp +++ b/Code/Mantid/MantidQt/RefDetectorViewer/src/RefRangeHandler.cpp @@ -17,9 +17,13 @@ namespace RefDetectorViewer * Construct a RefRangeHandler object to manage min, max and step controls * in the specified UI */ -RefRangeHandler::RefRangeHandler( Ui_RefImageViewer* iv_ui ) +RefRangeHandler::RefRangeHandler( Ui_RefImageViewer* iv_ui ) : + iv_ui(iv_ui), + total_min_x(0.0), total_max_x(0.0), + total_min_y(0.0), total_max_y(0.0), + total_n_steps(0) { - this->iv_ui = iv_ui; + /* this->iv_ui = iv_ui; */ } @@ -30,8 +34,7 @@ RefRangeHandler::RefRangeHandler( Ui_RefImageViewer* iv_ui ) */ void RefRangeHandler::ConfigureRangeControls( SpectrumDataSource* data_source ) { - - //x axis + //x axis total_min_x = data_source->GetXMin(); total_max_x = data_source->GetXMax(); total_n_steps = data_source->GetNCols(); @@ -58,8 +61,6 @@ void RefRangeHandler::ConfigureRangeControls( SpectrumDataSource* data_source ) } SetRange( total_min_y, total_max_y, defaulty_step, 'y' ); - - } diff --git a/Code/Mantid/MantidQt/SliceViewer/src/PhysicalCrossPeak.cpp b/Code/Mantid/MantidQt/SliceViewer/src/PhysicalCrossPeak.cpp index 331860e12796..000827b5f2bc 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/PhysicalCrossPeak.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/PhysicalCrossPeak.cpp @@ -21,7 +21,8 @@ namespace MantidQt m_opacityMin(0.0), m_opacityGradient((m_opacityMin - m_opacityMax)/m_effectiveRadius), m_crossViewFraction(0.015), - m_opacityAtDistance(0.0) + m_opacityAtDistance(0.0), + m_slicePoint(0.0) { } diff --git a/Code/Mantid/MantidQt/SliceViewer/src/ProxyCompositePeaksPresenter.cpp b/Code/Mantid/MantidQt/SliceViewer/src/ProxyCompositePeaksPresenter.cpp index 3249ce6374ab..a734d112be06 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/ProxyCompositePeaksPresenter.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/ProxyCompositePeaksPresenter.cpp @@ -13,7 +13,8 @@ namespace MantidQt m_compositePresenter->registerOwningPresenter(this); } - ProxyCompositePeaksPresenter::ProxyCompositePeaksPresenter() + ProxyCompositePeaksPresenter::ProxyCompositePeaksPresenter() : + m_updateableView(NULL) { } diff --git a/Code/Mantid/MantidQt/SpectrumViewer/src/GraphDisplay.cpp b/Code/Mantid/MantidQt/SpectrumViewer/src/GraphDisplay.cpp index f7afa51747f0..65cf9d734d1a 100644 --- a/Code/Mantid/MantidQt/SpectrumViewer/src/GraphDisplay.cpp +++ b/Code/Mantid/MantidQt/SpectrumViewer/src/GraphDisplay.cpp @@ -27,7 +27,9 @@ namespace SpectrumView */ GraphDisplay::GraphDisplay( QwtPlot* graph_plot, QTableWidget* graph_table, - bool is_vertical ) + bool is_vertical ) : + min_x(0.0), max_x(0.0), + min_y(0.0), max_y(0.0) { this->graph_plot = graph_plot; this->graph_table = graph_table; diff --git a/Code/Mantid/MantidQt/SpectrumViewer/src/RangeHandler.cpp b/Code/Mantid/MantidQt/SpectrumViewer/src/RangeHandler.cpp index 73238c78f253..20cda648141b 100644 --- a/Code/Mantid/MantidQt/SpectrumViewer/src/RangeHandler.cpp +++ b/Code/Mantid/MantidQt/SpectrumViewer/src/RangeHandler.cpp @@ -16,7 +16,10 @@ namespace SpectrumView * Construct a RangeHandler object to manage min, max and step controls * in the specified UI */ -RangeHandler::RangeHandler( Ui_SpectrumViewer* sv_ui ) : IRangeHandler() +RangeHandler::RangeHandler( Ui_SpectrumViewer* sv_ui ) : IRangeHandler(), + total_min_x(0.0), + total_max_x(0.0), + total_n_steps(0) { this->sv_ui = sv_ui; } @@ -29,7 +32,6 @@ RangeHandler::RangeHandler( Ui_SpectrumViewer* sv_ui ) : IRangeHandler() */ void RangeHandler::ConfigureRangeControls( SpectrumDataSource* data_source ) { - total_min_x = data_source->GetXMin(); total_max_x = data_source->GetXMax(); total_n_steps = data_source->GetNCols(); diff --git a/Code/Mantid/MantidQt/SpectrumViewer/src/SpectrumDisplay.cpp b/Code/Mantid/MantidQt/SpectrumViewer/src/SpectrumDisplay.cpp index 0b5caea9fdbf..45aa7066025b 100644 --- a/Code/Mantid/MantidQt/SpectrumViewer/src/SpectrumDisplay.cpp +++ b/Code/Mantid/MantidQt/SpectrumViewer/src/SpectrumDisplay.cpp @@ -40,7 +40,7 @@ SpectrumDisplay::SpectrumDisplay( QwtPlot* spectrum_plot, GraphDisplay* h_graph, GraphDisplay* v_graph, QTableWidget* table_widget ) - : data_source(0), spectrum_plot(spectrum_plot), slider_handler(slider_handler), + : data_source(NULL), data_array(NULL), spectrum_plot(spectrum_plot), slider_handler(slider_handler), range_handler(range_handler), h_graph_display(h_graph), v_graph_display(v_graph), image_table(table_widget) { diff --git a/Code/Mantid/MantidQt/SpectrumViewer/src/SpectrumView.cpp b/Code/Mantid/MantidQt/SpectrumViewer/src/SpectrumView.cpp index 12297305815a..60415867526f 100644 --- a/Code/Mantid/MantidQt/SpectrumViewer/src/SpectrumView.cpp +++ b/Code/Mantid/MantidQt/SpectrumViewer/src/SpectrumView.cpp @@ -30,7 +30,14 @@ namespace SpectrumView SpectrumView::SpectrumView(QWidget *parent) : QMainWindow(parent, 0), WorkspaceObserver(), - m_ui(new Ui::SpectrumViewer()) + h_graph(NULL), + v_graph(NULL), + m_ui(new Ui::SpectrumViewer()), + m_slider_handler(NULL), + m_range_handler(NULL), + m_spectrum_display(NULL), + m_sv_connections(NULL), + m_emode_handler(NULL) { m_ui->setupUi(this); } From 44645e152ee487f9364f98c6253bc2c0e7719a19 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 13 Oct 2014 11:09:45 +0100 Subject: [PATCH 002/128] Fixed unchecked casts Refs #10345 --- .../src/CreateSampleShapeDialog.cpp | 4 +- .../MantidQt/CustomInterfaces/src/ConvFit.cpp | 10 +-- .../src/IndirectDataReduction.cpp | 5 +- .../MantidQt/CustomInterfaces/src/JumpFit.cpp | 68 ++++++++++--------- .../SpectrumViewer/src/SVConnections.cpp | 1 + 5 files changed, 45 insertions(+), 43 deletions(-) diff --git a/Code/Mantid/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp b/Code/Mantid/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp index 238dab402252..c0345f3727b1 100644 --- a/Code/Mantid/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp +++ b/Code/Mantid/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp @@ -334,6 +334,7 @@ void CreateSampleShapeDialog::addShape(QAction *shape) { // Get the selected item BinaryTreeWidgetItem *parent = getSelectedItem(); + if(!parent) return; if( parent && parent->childCount() == 2 ) return; BinaryTreeWidgetItem *child = new BinaryTreeWidgetItem(QStringList(shape->text())); @@ -360,6 +361,7 @@ void CreateSampleShapeDialog::addOperation(QAction *opt) { //Get the selected item BinaryTreeWidgetItem *selected = getSelectedItem(); + if(!selected) return; if( selected && selected->childCount() == 2 ) return; BinaryTreeWidgetItem *operation = new BinaryTreeWidgetItem; @@ -468,6 +470,7 @@ void CreateSampleShapeDialog::setupDetailsBox() if( m_uiForm.details_scroll->widget() ) m_uiForm.details_scroll->takeWidget(); BinaryTreeWidgetItem *item = dynamic_cast(selection[0]); + if(!item) return; QString shapename = item->text(0); if( m_setup_map.contains(shapename) ) { @@ -484,7 +487,6 @@ void CreateSampleShapeDialog::setupDetailsBox() //Set it as the currently displayed widget m_uiForm.details_scroll->setWidget(obj); } - } /** diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/ConvFit.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/ConvFit.cpp index 85ccbff755a1..a3e0f0c4e97d 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/ConvFit.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/ConvFit.cpp @@ -894,15 +894,7 @@ namespace IDA { // Two Lorentz QString pref = prefBase; - - if ( usingCompositeFunc ) - { - pref += "f" + QString::number(funcIndex) + ".f" + QString::number(subIndex) + "."; - } - else - { - pref += "f" + QString::number(subIndex) + "."; - } + pref += "f" + QString::number(funcIndex) + ".f" + QString::number(subIndex) + "."; m_cfDblMng->setValue(m_cfProp["Lorentzian 2.Amplitude"], parameters[pref+"Amplitude"]); m_cfDblMng->setValue(m_cfProp["Lorentzian 2.PeakCentre"], parameters[pref+"PeakCentre"]); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDataReduction.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDataReduction.cpp index ed47aa0f798b..5661335623c1 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDataReduction.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDataReduction.cpp @@ -314,7 +314,10 @@ void IndirectDataReduction::openDirectoryDialog() */ void IndirectDataReduction::setIDFValues(const QString & prefix) { - dynamic_cast(m_tab_convert_to_energy)->setIDFValues(prefix); + IndirectConvertToEnergy *etTab = dynamic_cast(m_tab_convert_to_energy); + + if(etTab) + etTab->setIDFValues(prefix); } /** diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/JumpFit.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/JumpFit.cpp index d6492b4c0293..08ec80644cf4 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/JumpFit.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/JumpFit.cpp @@ -181,39 +181,43 @@ namespace MantidQt for (size_t i = 0; i < ws->getNumberHistograms(); ++i) { auto axis = dynamic_cast(ws->getAxis(1)); - std::string title = axis->label(i); - //check if the axis labels indicate this spectrum is width data - size_t qLinesWidthIndex = title.find(".Width"); - size_t convFitWidthIndex = title.find(".FWHM"); - - bool qLinesWidth = qLinesWidthIndex != std::string::npos; - bool convFitWidth = convFitWidthIndex != std::string::npos; - - //if we get a match, add this spectrum to the combobox - if(convFitWidth || qLinesWidth) - { - std::string cbItemName = ""; - size_t substrIndex = 0; - - if (qLinesWidth) - { - substrIndex = qLinesWidthIndex; - } - else if (convFitWidth) - { - substrIndex = convFitWidthIndex; - } - - cbItemName = title.substr(0, substrIndex); - spectraList[cbItemName] = static_cast(i); - m_uiForm.cbWidth->addItem(QString(cbItemName.c_str())); - - //display widths f1.f1, f2.f1 and f2.f2 - if (m_uiForm.cbWidth->count() == 3) - { - return; - } + if(axis) + { + std::string title = axis->label(i); + + //check if the axis labels indicate this spectrum is width data + size_t qLinesWidthIndex = title.find(".Width"); + size_t convFitWidthIndex = title.find(".FWHM"); + + bool qLinesWidth = qLinesWidthIndex != std::string::npos; + bool convFitWidth = convFitWidthIndex != std::string::npos; + + //if we get a match, add this spectrum to the combobox + if(convFitWidth || qLinesWidth) + { + std::string cbItemName = ""; + size_t substrIndex = 0; + + if (qLinesWidth) + { + substrIndex = qLinesWidthIndex; + } + else if (convFitWidth) + { + substrIndex = convFitWidthIndex; + } + + cbItemName = title.substr(0, substrIndex); + spectraList[cbItemName] = static_cast(i); + m_uiForm.cbWidth->addItem(QString(cbItemName.c_str())); + + //display widths f1.f1, f2.f1 and f2.f2 + if (m_uiForm.cbWidth->count() == 3) + { + return; + } + } } } } diff --git a/Code/Mantid/MantidQt/SpectrumViewer/src/SVConnections.cpp b/Code/Mantid/MantidQt/SpectrumViewer/src/SVConnections.cpp index daa4f1203634..ac8c9f256cee 100644 --- a/Code/Mantid/MantidQt/SpectrumViewer/src/SVConnections.cpp +++ b/Code/Mantid/MantidQt/SpectrumViewer/src/SVConnections.cpp @@ -313,6 +313,7 @@ bool SVConnections::eventFilter(QObject *object, QEvent *event) int newY = m_picker_y; QKeyEvent *keyEvent = dynamic_cast(event); + if(!keyEvent) return false; int key = keyEvent->key(); switch (key) { From 44662859f69cac0f08c3e07538a0eb79d3a14613 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 13 Oct 2014 11:50:57 +0100 Subject: [PATCH 003/128] Correct initialisation order warnings Refs #10345 --- Code/Mantid/MantidQt/API/src/QwtRasterDataMD.cpp | 3 ++- Code/Mantid/MantidQt/MantidWidgets/src/PropertyHandler.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/MantidQt/API/src/QwtRasterDataMD.cpp b/Code/Mantid/MantidQt/API/src/QwtRasterDataMD.cpp index ee059b16603b..897926b8bc07 100644 --- a/Code/Mantid/MantidQt/API/src/QwtRasterDataMD.cpp +++ b/Code/Mantid/MantidQt/API/src/QwtRasterDataMD.cpp @@ -18,10 +18,11 @@ using Mantid::Geometry::IMDDimension_const_sptr; /// Constructor QwtRasterDataMD::QwtRasterDataMD() : m_ws(), m_overlayWS(), - m_slicePoint(NULL), m_fast(true), m_zerosAsNan(true), + m_slicePoint(NULL), m_overlayXMin(0.0), m_overlayXMax(0.0), m_overlayYMin(0.0), m_overlayYMax(0.0), m_overlayInSlice(false), + m_fast(true), m_zerosAsNan(true), m_normalization(Mantid::API::VolumeNormalization) { m_range = QwtDoubleInterval(0.0, 1.0); diff --git a/Code/Mantid/MantidQt/MantidWidgets/src/PropertyHandler.cpp b/Code/Mantid/MantidQt/MantidWidgets/src/PropertyHandler.cpp index 26f2aa3bd9b8..e44adcf5c55f 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/src/PropertyHandler.cpp +++ b/Code/Mantid/MantidQt/MantidWidgets/src/PropertyHandler.cpp @@ -41,9 +41,9 @@ PropertyHandler::PropertyHandler(Mantid::API::IFunction_sptr fun, m_parent(parent), m_type(NULL), m_item(item), + m_isMultispectral(false), m_workspace(NULL), m_workspaceIndex(NULL), - m_isMultispectral(false), m_base(0), m_ci(0), m_hasPlot(false) From eb87f8875767b0d93fa71592486fd219933831bf Mon Sep 17 00:00:00 2001 From: Mathieu Doucet Date: Mon, 13 Oct 2014 13:24:59 -0400 Subject: [PATCH 004/128] Re #10355 added four models --- .../plugins/functions/Guinier.py | 65 ++++++++ .../plugins/functions/GuinierPorod.py | 149 ++++++++++++++++++ .../plugins/functions/Lorentz.py | 69 ++++++++ .../plugins/functions/Porod.py | 64 ++++++++ 4 files changed, 347 insertions(+) create mode 100644 Code/Mantid/Framework/PythonInterface/plugins/functions/Guinier.py create mode 100644 Code/Mantid/Framework/PythonInterface/plugins/functions/GuinierPorod.py create mode 100644 Code/Mantid/Framework/PythonInterface/plugins/functions/Lorentz.py create mode 100644 Code/Mantid/Framework/PythonInterface/plugins/functions/Porod.py diff --git a/Code/Mantid/Framework/PythonInterface/plugins/functions/Guinier.py b/Code/Mantid/Framework/PythonInterface/plugins/functions/Guinier.py new file mode 100644 index 000000000000..00bffff5abee --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/functions/Guinier.py @@ -0,0 +1,65 @@ +''' +@author Mathieu Doucet, ORNL +@date Oct 10, 2014 + +Copyright © 2007-8 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +File change history is stored at: +Code Documentation is available at: +''' + +from mantid.api import IFunction1D, FunctionFactory +import math +import numpy as np + +class Guinier(IFunction1D): + """ + Provide a Guinier fit function for SANS + + I(q) = I(0) exp(-R^2 q^2 / 3) + """ + def category(self): + return "SANS" + + def init(self): + # Active fitting parameters + self.declareParameter("Scale", 1.0, 'Scale') + self.declareParameter("Rg", 60.0, 'Radius of gyration') + + def function1D(self, xvals): + """ + Evaluate the model + @param xvals: numpy array of q-values + """ + return self.getParameterValue("Scale") * np.exp(-(self.getParameterValue('Rg')*xvals)**2/3.0 ) + + def functionDeriv1D(self, xvals, jacobian): + """ + Evaluate the first derivatives + @param xvals: numpy array of q-values + @param jacobian: Jacobian object + """ + i = 0 + rg = self.getParameterValue('Rg') + for x in xvals: + jacobian.set(i,0, math.exp(-(rg*x)**2/3.0 ) ) + jacobian.set(i,1, -self.getParameterValue("Scale") * math.exp(-(rg*x)**2/3.0 )*2.0/3.0*rg*x*x ); + i += 1 + +# Required to have Mantid recognise the new function +FunctionFactory.subscribe(Guinier) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/functions/GuinierPorod.py b/Code/Mantid/Framework/PythonInterface/plugins/functions/GuinierPorod.py new file mode 100644 index 000000000000..6c9f2db97bfc --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/functions/GuinierPorod.py @@ -0,0 +1,149 @@ +''' +@author Mathieu Doucet, ORNL +@date Oct 13, 2014 + +Copyright © 2007-8 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +File change history is stored at: +Code Documentation is available at: +''' + +from mantid.api import IFunction1D, FunctionFactory +import math +import numpy as np + +class GuinierPorod(IFunction1D): + """ + Provide a Guinier-Porod model for SANS. + + See Hammouda, J. Appl. Cryst. (2010) 43, 716-719 + """ + def category(self): + return "SANS" + + def init(self): + # Active fitting parameters + self.declareParameter("Scale", 1.0, 'Scale') + self.declareParameter("Dimension", 1.0, 'Dimension') + self.declareParameter("Rg", 50.0, 'Radius of gyration') + self.declareParameter("M", 3.0, 'M') + self.declareParameter("Background", 0.0, 'Background') + + def _guinier_porod_core(self, qval): + """ + Compute the main function for the model + @param qval: q-value to evaluate at + """ + s = self.getParameterValue('Dimension') + Rg = self.getParameterValue('Rg') + m = self.getParameterValue('M') + n = 3.0 - s + q1 = math.sqrt((m-s)*n/2.0)/Rg + if qval < q1: + return math.pow(qval,-s)*math.exp((-qval*qval*Rg*Rg)/n) + else: + return math.pow(qval,-m)*math.pow(Rg,s-m)*math.exp((s-m)/2.0)*math.pow((m-s)*n/2.0,(m-s)/2.0) + + def _first_derivative_dim(self, qval): + """ + Compute the first derivative dI/d(Dimension) + @param qval: q-value to evaluate at + """ + s = self.getParameterValue('Dimension') + Rg = self.getParameterValue('Rg') + m = self.getParameterValue('M') + n = 3.0 - s + q1 = math.sqrt((m-s)*n/2.0)/Rg + qrg = qval*qval*Rg*Rg + if qval < q1: + return -math.exp(-qrg/n)*math.pow(qval,-s)*math.log(qval) \ + - math.exp(-qrg/n)*math.pow(qval, -s)*qrg/n/n + else: + result = (2.0*s-m-3.0)/(2.0*(3.0-s)) - 0.5*(math.log(m-s)+math.log(3-s)) + result += math.log(Rg) + math.log(2.0) + 1.0 + return result * math.pow(qval,-m) * math.pow(Rg,s-m) * math.exp((s-m)/2.0) * math.pow((m-s)*n/2.0,(m-s)/2.0) + + + def _first_derivative_m(self, qval): + """ + Compute the first derivative dI/dM + @param qval: q-value to evaluate at + + Derivatives can be obtained here: + http://www.derivative-calculator.net/#expr=%28%28m-s%29%283-s%29%2F2%29%5E%28%28m%20-%20s%29%2F2%29q%5E-mr%5E%28s-m%29exp%28%28s-m%29%2F2%29&diffvar=m + """ + s = self.getParameterValue('Dimension') + Rg = self.getParameterValue('Rg') + m = self.getParameterValue('M') + n = 3.0 - s + q1 = math.sqrt((m-s)*n/2.0)/Rg + if qval < q1: + return 0.0 + else: + result = -math.log(qval) - math.log(Rg) - math.log(2.0) - 1.0 + result += ( (math.log(m-s)+math.log(3-s))/2.0 + 0.5 ) + return result * math.pow(qval,-m) * math.pow(Rg,s-m) * math.exp((s-m)/2.0) * math.pow((m-s)*n/2.0,(m-s)/2.0) + + def _first_derivative_rg(self, qval): + """ + Compute the first derivative dI/d(Rg) + @param qval: q-value to evaluate at + """ + s = self.getParameterValue('Dimension') + Rg = self.getParameterValue('Rg') + m = self.getParameterValue('M') + n = 3.0 - s + q1 = math.sqrt((m-s)*n/2.0)/Rg + qrg = qval*qval*Rg*Rg + if qval < q1: + return -2.0*Rg*math.pow(qval,-s)*math.exp(-qrg/n)*qval*qval/n + else: + return math.pow(qval,-m)*math.exp((s-m)/2.0)*math.pow(((m-s)*n/2.0), + ((m-s)/2.0))*(s-m)*math.pow(Rg,(s-m-1)) + + def function1D(self, xvals): + """ + Evaluate the model + @param xvals: numpy array of q-values + """ + # parameters + scale = self.getParameterValue('Scale') + bgd = self.getParameterValue('Background') + + output = np.zeros(len(xvals), dtype=float) + for i in range(len(xvals)): + output[i] = scale * self._guinier_porod_core(xvals[i]) + bgd + return output + + def functionDeriv1D(self, xvals, jacobian): + """ + Evaluate the first derivatives + @param xvals: numpy array of q-values + @param jacobian: Jacobian object + """ + i = 0 + for x in xvals: + jacobian.set(i,0, self._guinier_porod_core(x)) + jacobian.set(i,1, self._first_derivative_dim(x)) + jacobian.set(i,2, self._first_derivative_rg(x)) + jacobian.set(i,3, self._first_derivative_m(x)) + jacobian.set(i,4, 1.0) + i += 1 + +# Required to have Mantid recognise the new function +FunctionFactory.subscribe(GuinierPorod) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/functions/Lorentz.py b/Code/Mantid/Framework/PythonInterface/plugins/functions/Lorentz.py new file mode 100644 index 000000000000..d6283b6cd5cc --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/functions/Lorentz.py @@ -0,0 +1,69 @@ +''' +@author Mathieu Doucet, ORNL +@date Oct 13, 2014 + +Copyright © 2007-8 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +File change history is stored at: +Code Documentation is available at: +''' + +from mantid.api import IFunction1D, FunctionFactory +import math +import numpy as np + +class Lorentz(IFunction1D): + """ + Provide a Lorentz model for SANS + + I(q) = scale / ( 1 + q^2 L^2 ) + background + """ + + def category(self): + return "SANS" + + def init(self): + # Active fitting parameters + self.declareParameter("Scale", 1.0, 'Scale') + self.declareParameter("Length", 50.0, 'Length') + self.declareParameter("Background", 0.0, 'Background') + + def function1D(self, xvals): + """ + Evaluate the model + @param xvals: numpy array of q-values + """ + return self.getParameterValue("Scale") / (1.0 + np.power(xvals*self.getParameterValue('Length'), 2)) + self.getParameterValue('Background') + + def functionDeriv1D(self, xvals, jacobian): + """ + Evaluate the first derivatives + @param xvals: numpy array of q-values + @param jacobian: Jacobian object + """ + i = 0 + for x in xvals: + jacobian.set(i,0, 1.0 / (1.0 + np.power(x*self.getParameterValue('Length'), 2))) + denom = math.pow(1.0 + math.pow(x*self.getParameterValue('Length'), 2), -2) + jacobian.set(i,1, -2.0 * self.getParameterValue("Scale") * x * x * self.getParameterValue('Length') * denom) + jacobian.set(i,2, 1.0) + i += 1 + +# Required to have Mantid recognise the new function +FunctionFactory.subscribe(Lorentz) + diff --git a/Code/Mantid/Framework/PythonInterface/plugins/functions/Porod.py b/Code/Mantid/Framework/PythonInterface/plugins/functions/Porod.py new file mode 100644 index 000000000000..dc39aa80f85b --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/functions/Porod.py @@ -0,0 +1,64 @@ +''' +@author Mathieu Doucet, ORNL +@date Oct 13, 2014 + +Copyright © 2007-8 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + +This file is part of Mantid. + +Mantid is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +Mantid is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +File change history is stored at: +Code Documentation is available at: +''' + +from mantid.api import IFunction1D, FunctionFactory +import math +import numpy as np + +class Porod(IFunction1D): + """ + Provide a Porod model for SANS + + I(q) = C/q^4 + background + """ + def category(self): + return "SANS" + + def init(self): + # Active fitting parameters + self.declareParameter("Scale", 1.0, 'Scale') + self.declareParameter("Background", 0.0, 'Background') + + def function1D(self, xvals): + """ + Evaluate the model + @param xvals: numpy array of q-values + """ + return self.getParameterValue("Scale") * np.power(xvals, -4) + self.getParameterValue('Background') + + def functionDeriv1D(self, xvals, jacobian): + """ + Evaluate the first derivatives + @param xvals: numpy array of q-values + @param jacobian: Jacobian object + """ + i = 0 + for x in xvals: + jacobian.set(i,0, math.pow(x, -4)) + jacobian.set(i,1, 1.0) + i += 1 + +# Required to have Mantid recognise the new function +FunctionFactory.subscribe(Porod) From 6bb9f1de27b2d9f8569a88854579e765af64df21 Mon Sep 17 00:00:00 2001 From: Mathieu Doucet Date: Mon, 13 Oct 2014 14:27:07 -0400 Subject: [PATCH 005/128] Re #10356 added patch sensitivity to HFIR SANS --- .../instruments/eqsans_interface_dev.py | 2 +- .../instruments/hfir_interface_dev.py | 3 ++- .../reduction_gui/reduction/hfir_reduction.py | 25 +++++++++++++++++++ .../widgets/sans/hfir_detector.py | 4 +-- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Code/Mantid/scripts/Interface/reduction_gui/instruments/eqsans_interface_dev.py b/Code/Mantid/scripts/Interface/reduction_gui/instruments/eqsans_interface_dev.py index a5d33bf3be29..0c57da6dafbd 100644 --- a/Code/Mantid/scripts/Interface/reduction_gui/instruments/eqsans_interface_dev.py +++ b/Code/Mantid/scripts/Interface/reduction_gui/instruments/eqsans_interface_dev.py @@ -44,7 +44,7 @@ def __init__(self, name, settings): self.attach(SANSInstrumentWidget(settings = self._settings, data_proxy=DataProxy, data_type = self.data_type)) # Detector - self.attach(DetectorWidget(settings = self._settings, data_proxy=None, + self.attach(DetectorWidget(settings = self._settings, data_proxy=DataProxy, data_type = self.data_type, use_sample_dc=True, options_callback = self.scripter.set_options)) diff --git a/Code/Mantid/scripts/Interface/reduction_gui/instruments/hfir_interface_dev.py b/Code/Mantid/scripts/Interface/reduction_gui/instruments/hfir_interface_dev.py index 564ff961a970..f617bc9f6f1b 100644 --- a/Code/Mantid/scripts/Interface/reduction_gui/instruments/hfir_interface_dev.py +++ b/Code/Mantid/scripts/Interface/reduction_gui/instruments/hfir_interface_dev.py @@ -43,7 +43,8 @@ def __init__(self, name, settings): self.attach(SANSInstrumentWidget(settings = self._settings, name=name, data_proxy=DataProxy)) # Detector - self.attach(DetectorWidget(settings = self._settings, data_proxy=DataProxy)) + self.attach(DetectorWidget(settings = self._settings, data_proxy=DataProxy, + options_callback = self.scripter.set_options)) # Sample self.attach(SampleDataWidget(settings = self._settings, data_proxy=DataProxy)) diff --git a/Code/Mantid/scripts/Interface/reduction_gui/reduction/hfir_reduction.py b/Code/Mantid/scripts/Interface/reduction_gui/reduction/hfir_reduction.py index 0903283b04b4..f787756416c7 100644 --- a/Code/Mantid/scripts/Interface/reduction_gui/reduction/hfir_reduction.py +++ b/Code/Mantid/scripts/Interface/reduction_gui/reduction/hfir_reduction.py @@ -6,6 +6,13 @@ import os from scripter import BaseReductionScripter +HAS_MANTID = False +try: + import mantidplot + HAS_MANTID = True +except: + pass + class HFIRReductionScripter(BaseReductionScripter): """ Organizes the set of reduction parameters that will be used to @@ -49,4 +56,22 @@ def to_script(self, file_name=None): return script + def set_options(self): + """ + Set up the reduction options, without executing + """ + if HAS_MANTID: + self.update() + table_ws = "__patch_options" + script = "SetupHFIRReduction(\n" + for item in self._observers: + if item.state() is not None: + if hasattr(item.state(), "options"): + script += item.state().options() + + script += "ReductionProperties='%s')" % table_ws + mantidplot.runPythonScript(script, True) + return table_ws + else: + raise RuntimeError, "Reduction could not be executed: Mantid could not be imported" diff --git a/Code/Mantid/scripts/Interface/reduction_gui/widgets/sans/hfir_detector.py b/Code/Mantid/scripts/Interface/reduction_gui/widgets/sans/hfir_detector.py index dafc5c1920b8..b1151785c73a 100644 --- a/Code/Mantid/scripts/Interface/reduction_gui/widgets/sans/hfir_detector.py +++ b/Code/Mantid/scripts/Interface/reduction_gui/widgets/sans/hfir_detector.py @@ -134,10 +134,8 @@ def _patch_checked(self): def _draw_patch(self): if IS_IN_MANTIDPLOT: - from reduction_gui.reduction.sans.eqsans_data_proxy import DataProxy self.show_instrument(self._content.sensitivity_file_edit.text, - workspace=self.patch_ws, tab=2, reload=True, - data_proxy=DataProxy) + workspace=self.patch_ws, tab=2, reload=True, data_proxy=None) def _create_sensitivity(self): if IS_IN_MANTIDPLOT and self.options_callback is not None: From b3b7b98529cee29a5293381ac68d13ef46ed9b6c Mon Sep 17 00:00:00 2001 From: Mathieu Doucet Date: Tue, 14 Oct 2014 09:23:29 -0400 Subject: [PATCH 006/128] Re #10355 check boundary constraints --- .../plugins/functions/GuinierPorod.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/functions/GuinierPorod.py b/Code/Mantid/Framework/PythonInterface/plugins/functions/GuinierPorod.py index 6c9f2db97bfc..a9303ecde0a9 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/functions/GuinierPorod.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/functions/GuinierPorod.py @@ -44,6 +44,20 @@ def init(self): self.declareParameter("M", 3.0, 'M') self.declareParameter("Background", 0.0, 'Background') + def _boundary_conditions(self, qval): + """ + Check boundary constraints and return True if we + are out of bounds. + @param qval: q-value to evaluate at + """ + s = self.getParameterValue('Dimension') + Rg = self.getParameterValue('Rg') + m = self.getParameterValue('M') + if Rg<=0: return True + if m3.0: return True + return False + def _guinier_porod_core(self, qval): """ Compute the main function for the model @@ -53,6 +67,7 @@ def _guinier_porod_core(self, qval): Rg = self.getParameterValue('Rg') m = self.getParameterValue('M') n = 3.0 - s + if self._boundary_conditions(qval): return 0.0 q1 = math.sqrt((m-s)*n/2.0)/Rg if qval < q1: return math.pow(qval,-s)*math.exp((-qval*qval*Rg*Rg)/n) @@ -68,6 +83,7 @@ def _first_derivative_dim(self, qval): Rg = self.getParameterValue('Rg') m = self.getParameterValue('M') n = 3.0 - s + if self._boundary_conditions(qval): return 1.0 q1 = math.sqrt((m-s)*n/2.0)/Rg qrg = qval*qval*Rg*Rg if qval < q1: @@ -91,6 +107,7 @@ def _first_derivative_m(self, qval): Rg = self.getParameterValue('Rg') m = self.getParameterValue('M') n = 3.0 - s + if self._boundary_conditions(qval): return 1.0 q1 = math.sqrt((m-s)*n/2.0)/Rg if qval < q1: return 0.0 @@ -108,6 +125,7 @@ def _first_derivative_rg(self, qval): Rg = self.getParameterValue('Rg') m = self.getParameterValue('M') n = 3.0 - s + if self._boundary_conditions(qval): return 1.0 q1 = math.sqrt((m-s)*n/2.0)/Rg qrg = qval*qval*Rg*Rg if qval < q1: @@ -146,4 +164,4 @@ def functionDeriv1D(self, xvals, jacobian): i += 1 # Required to have Mantid recognise the new function -FunctionFactory.subscribe(GuinierPorod) +FunctionFactory.subscribe(GuinierPorod) \ No newline at end of file From 4a4e9565b1a3a6bdd755a9bc750b523e996334c8 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Fri, 17 Oct 2014 13:55:17 +0100 Subject: [PATCH 007/128] Fix copy paste error in FitPropertyBrowser This seemed to be a genuine error which affects the automatic population of the X and Y columns in workspace settings group of fit properties. Refs #10345 --- Code/Mantid/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Mantid/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp b/Code/Mantid/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp index 5661757ccf5b..8c90ff90a87a 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp +++ b/Code/Mantid/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp @@ -3046,7 +3046,7 @@ void FitPropertyBrowser::setWorkspaceProperties() { if ( name != xName ) { - m_columnManager->setValue(m_xColumn, columns.indexOf( name )); + m_columnManager->setValue(m_yColumn, columns.indexOf( name )); break; } } From 1978e1484b60c48538484ca46450103e829bbb7c Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Thu, 23 Oct 2014 11:28:16 +0100 Subject: [PATCH 008/128] refs #10385. Extract spectrum info to object. This is the first step towards reusing the same spectrum information rather than fetching it renewed each time. One caveat with this is that you will HAVE to be sure that all workspaces in the group are equivalent in terms of instrument detector mappings etc. What i intend to do next is: 1) For workspaces that look to relate to multiperiod group workspaces, default to reuse the spectrum-detectector mappings, once obtained on a lazy basis. 2) Put a boolean property with value in place (which defaults to true) called "PredictiveInstrumentLoading". If false, we would go back to old behaviour. --- .../DataHandling/src/LoadNexusProcessed.cpp | 162 ++++++++++++------ 1 file changed, 106 insertions(+), 56 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 55a620bd91e7..8348e1355417 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -1176,6 +1176,98 @@ API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot & root, const std::stri return boost::static_pointer_cast(local_workspace); } +typedef boost::shared_array IntArray_shared; +struct SpectraInfo +{ + // Number of spectra + const int nSpectra; + // Do we have any spectra + const bool hasSpectra; + // Contains spectrum numbers for each workspace index + const IntArray_shared spectraNumbers; + // Index of the detector in the workspace. + const IntArray_shared detectorIndex; + // Number of detectors associated with each spectra + const IntArray_shared detectorCount; + // Detector list contains a list of all of the detector numbers + const IntArray_shared detectorList; + + SpectraInfo() : + nSpectra(0), hasSpectra(false) + { + } + + SpectraInfo(int _nSpectra, bool _hasSpectra, IntArray_shared _spectraNumbers + , IntArray_shared _detectorIndex + , IntArray_shared _detectorCount + , IntArray_shared _detectorList) + : + nSpectra(_nSpectra), hasSpectra(_hasSpectra), + spectraNumbers(_spectraNumbers), detectorIndex(_detectorIndex), + detectorCount(_detectorCount), detectorList(_detectorList) + { + } +}; + + +SpectraInfo doReadInstrumentGroup(NXEntry & mtd_entry, Logger& logger) +{ + //Instrument information + NXInstrument inst = mtd_entry.openNXInstrument("instrument"); + if ( ! inst.containsGroup("detector") ) + { + logger.information() << "Detector block not found. The workspace will not contain any detector information.\n"; + return SpectraInfo(); + } + + //Populate the spectra-detector map + NXDetector detgroup = inst.openNXDetector("detector"); + + //Read necessary arrays from the file + // Detector list contains a list of all of the detector numbers. If it not present then we can't update the spectra + // map + boost::shared_array detectorList; + try + { + NXInt detlist_group = detgroup.openNXInt("detector_list"); + detlist_group.load(); + detectorList = detlist_group.sharedBuffer(); + } + catch(std::runtime_error &) + { + logger.information() << "detector_list block not found. The workspace will not contain any detector information." + << std::endl; + return SpectraInfo(); + } + + //Detector count contains the number of detectors associated with each spectra + NXInt det_count = detgroup.openNXInt("detector_count"); + det_count.load(); + boost::shared_array detectorCount = det_count.sharedBuffer(); + //Detector index - contains the index of the detector in the workspace + NXInt det_index = detgroup.openNXInt("detector_index"); + det_index.load(); + int nspectra = det_index.dim0(); + boost::shared_array detectorIndex = det_index.sharedBuffer(); + + //Spectra block - Contains spectrum numbers for each workspace index + // This might not exist so wrap and check. If it doesn't exist create a default mapping + bool have_spectra(true); + boost::shared_array spectra; + try + { + NXInt spectra_block = detgroup.openNXInt("spectra"); + spectra_block.load(); + spectra = spectra_block.sharedBuffer(); + } + catch(std::runtime_error &) + { + have_spectra = false; + } + return SpectraInfo(nspectra, have_spectra, spectra, detectorIndex, detectorCount, detectorList); + +}; + //------------------------------------------------------------------------------------------------- @@ -1186,65 +1278,23 @@ API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot & root, const std::stri */ void LoadNexusProcessed::readInstrumentGroup(NXEntry & mtd_entry, API::MatrixWorkspace_sptr local_workspace) { - //Instrument information - NXInstrument inst = mtd_entry.openNXInstrument("instrument"); - if ( ! inst.containsGroup("detector") ) - { - g_log.information() << "Detector block not found. The workspace will not contain any detector information.\n"; - return; - } - - //Populate the spectra-detector map - NXDetector detgroup = inst.openNXDetector("detector"); - - //Read necessary arrays from the file - // Detector list contains a list of all of the detector numbers. If it not present then we can't update the spectra - // map - boost::shared_array det_list; - try - { - NXInt detlist_group = detgroup.openNXInt("detector_list"); - detlist_group.load(); - det_list = detlist_group.sharedBuffer(); - } - catch(std::runtime_error &) - { - g_log.information() << "detector_list block not found. The workspace will not contain any detector information." - << std::endl; - return; - } - - //Detector count contains the number of detectors associated with each spectra - NXInt det_count = detgroup.openNXInt("detector_count"); - det_count.load(); - //Detector index - contains the index of the detector in the workspace - NXInt det_index = detgroup.openNXInt("detector_index"); - det_index.load(); - int nspectra = det_index.dim0(); - - //Spectra block - Contains spectrum numbers for each workspace index - // This might not exist so wrap and check. If it doesn't exist create a default mapping - bool have_spectra(true); - boost::shared_array spectra; - try - { - NXInt spectra_block = detgroup.openNXInt("spectra"); - spectra_block.load(); - spectra = spectra_block.sharedBuffer(); - } - catch(std::runtime_error &) - { - have_spectra = false; - } + // Get spectrum information for the current entry. + SpectraInfo spectraInfo = doReadInstrumentGroup(mtd_entry, this->g_log); //Now build the spectra list int index=0; - for(int i = 1; i <= nspectra; ++i) + for(int i = 1; i <= spectraInfo.nSpectra; ++i) { int spectrum(-1); - if( have_spectra ) spectrum = spectra[i-1]; - else spectrum = i+1 ; + if( spectraInfo.hasSpectra ) + { + spectrum = spectraInfo.spectraNumbers[i-1]; + } + else + { + spectrum = i+1; + } if ((i >= m_spec_min && i < m_spec_max )||(m_list && find(m_spec_list.begin(), m_spec_list.end(), i) != m_spec_list.end())) @@ -1260,9 +1310,9 @@ void LoadNexusProcessed::readInstrumentGroup(NXEntry & mtd_entry, API::MatrixWor } ++index; - int start = det_index[i-1]; - int end = start + det_count[i-1]; - spec->setDetectorIDs(std::set(det_list.get()+start,det_list.get()+end)); + int start = spectraInfo.detectorIndex[i-1]; + int end = start + spectraInfo.detectorCount[i-1]; + spec->setDetectorIDs(std::set(spectraInfo.detectorList.get()+start,spectraInfo.detectorList.get()+end)); } } } From fdf6281af77bfb069315c3fae6937bad26e09bab Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Thu, 23 Oct 2014 12:07:32 +0100 Subject: [PATCH 009/128] refs #10385. Naming issue root problem. There is a naming issue here, which is actually the root cause of the problem! The query that was being performed retrieved the number of workspace entries, NOT the number of periods. Going forward. If the number of periods exactly matches the number of workspace entries, we have a multiperiod group workspace, and can happily apply the optimisations we want. Next step will be to actually extract the nperiods. To do that we need to try to fetch it out of the logs for The first entry. --- .../DataHandling/src/LoadNexusProcessed.cpp | 2876 +++++++++-------- 1 file changed, 1448 insertions(+), 1428 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 8348e1355417..4a989069f719 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -31,1737 +32,1756 @@ namespace Mantid { -namespace DataHandling -{ + namespace DataHandling + { // Register the algorithm into the algorithm factory -DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadNexusProcessed); - -using namespace Mantid::NeXus; -using namespace DataObjects; -using namespace Kernel; -using namespace API; -using Geometry::Instrument_const_sptr; - -/// Default constructor -LoadNexusProcessed::LoadNexusProcessed() : m_shared_bins(false), m_xbins(), - m_axis1vals(), m_list(false), m_interval(false), - m_spec_list(), m_spec_min(0), m_spec_max(Mantid::EMPTY_INT()),m_cppFile(NULL) -{ -} - -/// Delete NexusFileIO in destructor -LoadNexusProcessed::~LoadNexusProcessed() -{ - delete m_cppFile; -} - -/** - * Return the confidence with with this algorithm can load the file - * @param descriptor A descriptor for the file - * @returns An integer specifying the confidence level. 0 indicates it will not be used - */ -int LoadNexusProcessed::confidence(Kernel::NexusDescriptor & descriptor) const -{ - if(descriptor.pathExists("/mantid_workspace_1")) return 80; - else return 0; -} - -/** Initialisation method. - * - */ -void LoadNexusProcessed::init() -{ - // Declare required input parameters for algorithm - std::vector exts; - exts.push_back(".nxs"); - exts.push_back(".nx5"); - exts.push_back(".xml"); - declareProperty(new FileProperty("Filename", "", FileProperty::Load, exts), - "The name of the Nexus file to read, as a full or relative path." ); - declareProperty(new WorkspaceProperty ("OutputWorkspace", "", - Direction::Output), - "The name of the workspace to be created as the output of the algorithm. A workspace of this name will be created and stored in the Analysis Data Service. For multiperiod files, one workspace may be generated for each period. Currently only one workspace can be saved at a time so multiperiod Mantid files are not generated."); - - - - // optional - auto mustBePositive = boost::make_shared >(); - mustBePositive->setLower(0); - - declareProperty("SpectrumMin", (int64_t)1, mustBePositive, - "Number of first spectrum to read."); - declareProperty("SpectrumMax", (int64_t)Mantid::EMPTY_INT(), mustBePositive, - "Number of last spectrum to read."); - declareProperty(new ArrayProperty ("SpectrumList"), - "List of spectrum numbers to read."); - declareProperty("EntryNumber", (int64_t)0, mustBePositive, - "The particular entry number to read. Default load all workspaces and creates a workspacegroup (default: read all entries)." ); - declareProperty("LoadHistory", true, "If true, the workspace history will be loaded"); -} + DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadNexusProcessed); + using namespace Mantid::NeXus; + using namespace DataObjects; + using namespace Kernel; + using namespace API; + using Geometry::Instrument_const_sptr; -//------------------------------------------------------------------------------------------------- -/** Executes the algorithm. Reading in the file and creating and populating - * the output workspace - * - * @throw runtime_error Thrown if algorithm cannot execute - */ -void LoadNexusProcessed::exec() -{ - progress(0,"Opening file..."); + namespace + { + // Helper typedef + typedef boost::shared_array IntArray_shared; - //Throws an approriate exception if there is a problem with file access - NXRoot root(getPropertyValue("Filename")); + // Struct to contain spectrum information. + struct SpectraInfo + { + // Number of spectra + const int nSpectra; + // Do we have any spectra + const bool hasSpectra; + // Contains spectrum numbers for each workspace index + const IntArray_shared spectraNumbers; + // Index of the detector in the workspace. + const IntArray_shared detectorIndex; + // Number of detectors associated with each spectra + const IntArray_shared detectorCount; + // Detector list contains a list of all of the detector numbers + const IntArray_shared detectorList; + + SpectraInfo() : + nSpectra(0), hasSpectra(false) + { + } - // "Open" the same file but with the C++ interface - m_cppFile = new ::NeXus::File(root.m_fileID); + SpectraInfo(int _nSpectra, bool _hasSpectra, IntArray_shared _spectraNumbers, + IntArray_shared _detectorIndex, IntArray_shared _detectorCount, IntArray_shared _detectorList) : + nSpectra(_nSpectra), hasSpectra(_hasSpectra), spectraNumbers(_spectraNumbers), detectorIndex( + _detectorIndex), detectorCount(_detectorCount), detectorList(_detectorList) + { + } + }; + // Helper typdef. + typedef boost::optional SpectraInfo_optional; + + /** + * Extract ALL the detector, spectrum number and workspace index mapping information. + * @param mtd_entry + * @param logger + * @return + */ + SpectraInfo extractMappingInfo(NXEntry & mtd_entry, Logger& logger) + { + //Instrument information + NXInstrument inst = mtd_entry.openNXInstrument("instrument"); + if (!inst.containsGroup("detector")) + { + logger.information() + << "Detector block not found. The workspace will not contain any detector information.\n"; + return SpectraInfo(); + } - //Find out how many first level entries there are - int64_t nperiods = static_cast(root.groups().size()); + //Populate the spectra-detector map + NXDetector detgroup = inst.openNXDetector("detector"); - // Check for an entry number property - int64_t entrynumber = static_cast(getProperty("EntryNumber")); + //Read necessary arrays from the file + // Detector list contains a list of all of the detector numbers. If it not present then we can't update the spectra + // map + boost::shared_array detectorList; + try + { + NXInt detlist_group = detgroup.openNXInt("detector_list"); + detlist_group.load(); + detectorList = detlist_group.sharedBuffer(); + } catch (std::runtime_error &) + { + logger.information() + << "detector_list block not found. The workspace will not contain any detector information." + << std::endl; + return SpectraInfo(); + } - if( entrynumber > 0 && entrynumber > nperiods ) - { - g_log.error() << "Invalid entry number specified. File only contains " << nperiods << " entries.\n"; - throw std::invalid_argument("Invalid entry number specified."); - } + //Detector count contains the number of detectors associated with each spectra + NXInt det_count = detgroup.openNXInt("detector_count"); + det_count.load(); + boost::shared_array detectorCount = det_count.sharedBuffer(); + //Detector index - contains the index of the detector in the workspace + NXInt det_index = detgroup.openNXInt("detector_index"); + det_index.load(); + int nspectra = det_index.dim0(); + boost::shared_array detectorIndex = det_index.sharedBuffer(); + + //Spectra block - Contains spectrum numbers for each workspace index + // This might not exist so wrap and check. If it doesn't exist create a default mapping + bool have_spectra(true); + boost::shared_array spectra; + try + { + NXInt spectra_block = detgroup.openNXInt("spectra"); + spectra_block.load(); + spectra = spectra_block.sharedBuffer(); + } catch (std::runtime_error &) + { + have_spectra = false; + } + return SpectraInfo(nspectra, have_spectra, spectra, detectorIndex, detectorCount, detectorList); - const std::string basename = "mantid_workspace_"; - if( nperiods == 1 || entrynumber > 0 ) - { // Load one first level entry, specified if there are several - if( entrynumber == 0 ) ++entrynumber; - std::ostringstream os; - os << entrynumber; - API::Workspace_sptr workspace = loadEntry(root, basename + os.str(), 0, 1); - //API::Workspace_sptr workspace = boost::static_pointer_cast(local_workspace); - setProperty("OutputWorkspace", workspace); - } - else - { // Load all first level entries - WorkspaceGroup_sptr wksp_group(new WorkspaceGroup); - //This forms the name of the group - std::string base_name = getPropertyValue("OutputWorkspace"); - // First member of group should be the group itself, for some reason! - - //load names of each of the workspaces and check for a common stem - std::vector names(nperiods+1); - bool commonStem = checkForCommonNameStem(root, names); - - //remove existing workspace and replace with the one being loaded - bool wsExists = AnalysisDataService::Instance().doesExist(base_name); - if(wsExists) - { - Algorithm_sptr alg = AlgorithmManager::Instance().createUnmanaged("DeleteWorkspace"); - alg->initialize(); - alg->setChild(true); - alg->setProperty("Workspace", base_name); - alg->execute(); + } } - base_name += "_"; - const std::string prop_name = "OutputWorkspace_"; - double nperiods_d = static_cast(nperiods); - for( int64_t p = 1; p <= nperiods; ++p ) +/// Default constructor + LoadNexusProcessed::LoadNexusProcessed() : + m_shared_bins(false), m_xbins(), m_axis1vals(), m_list(false), m_interval(false), m_spec_list(), m_spec_min( + 0), m_spec_max(Mantid::EMPTY_INT()), m_cppFile(NULL) { - std::ostringstream os; - os << p; - - //decide what the workspace should be called - std::string wsName = buildWorkspaceName(names[p], base_name, p, commonStem); - - Workspace_sptr local_workspace = loadEntry(root, basename + os.str(), static_cast(p-1)/nperiods_d, 1./nperiods_d); - declareProperty(new WorkspaceProperty(prop_name + os.str(), wsName, - Direction::Output)); - //wksp_group->add(base_name + os.str()); - wksp_group->addWorkspace(local_workspace); - setProperty(prop_name + os.str(), local_workspace); } - // The group is the root property value - setProperty("OutputWorkspace", boost::static_pointer_cast(wksp_group)); - - } - - m_axis1vals.clear(); -} - - -/** - * Decides what to call a child of a group workspace. - * - * This function uses information about if the child workspace has a common stem - * and checks if the file contained a workspace name to decide what it should be called - * - * @param name :: The name loaded from the file (possibly the empty string if none was loaded) - * @param baseName :: The name group workspace - * @param wsIndex :: The current index of this workspace - * @param commonStem :: Whether the workspaces share a common name stem - * - * @return The name of the workspace - */ -std::string LoadNexusProcessed::buildWorkspaceName(const std::string& name, const std::string& baseName, int64_t wsIndex, bool commonStem) -{ - std::string wsName; - std::string index = boost::lexical_cast(wsIndex); - - //if we don't have a common stem then use name tag - if(!commonStem) - { - if(!name.empty()) +/// Delete NexusFileIO in destructor + LoadNexusProcessed::~LoadNexusProcessed() { - //use name loaded from file there's no common stem - wsName = name; + delete m_cppFile; } - else + + /** + * Return the confidence with with this algorithm can load the file + * @param descriptor A descriptor for the file + * @returns An integer specifying the confidence level. 0 indicates it will not be used + */ + int LoadNexusProcessed::confidence(Kernel::NexusDescriptor & descriptor) const { - //if the name property wasn't defined just use _n - wsName = baseName + index; + if (descriptor.pathExists("/mantid_workspace_1")) + return 80; + else + return 0; } - } - else - { - //we have a common stem so rename accordingly - boost::smatch results; - const boost::regex exp(".*_(\\d+$)"); - //if we have a common name stem then name is _n - if(boost::regex_search(name, results, exp)) + + /** Initialisation method. + * + */ + void LoadNexusProcessed::init() { - wsName = baseName + std::string(results[1].first, results[1].second); + // Declare required input parameters for algorithm + std::vector exts; + exts.push_back(".nxs"); + exts.push_back(".nx5"); + exts.push_back(".xml"); + declareProperty(new FileProperty("Filename", "", FileProperty::Load, exts), + "The name of the Nexus file to read, as a full or relative path."); + declareProperty(new WorkspaceProperty("OutputWorkspace", "", Direction::Output), + "The name of the workspace to be created as the output of the algorithm. A workspace of this name will be created and stored in the Analysis Data Service. For multiperiod files, one workspace may be generated for each period. Currently only one workspace can be saved at a time so multiperiod Mantid files are not generated."); + + // optional + auto mustBePositive = boost::make_shared >(); + mustBePositive->setLower(0); + + declareProperty("SpectrumMin", (int64_t) 1, mustBePositive, "Number of first spectrum to read."); + declareProperty("SpectrumMax", (int64_t) Mantid::EMPTY_INT(), mustBePositive, + "Number of last spectrum to read."); + declareProperty(new ArrayProperty("SpectrumList"), "List of spectrum numbers to read."); + declareProperty("EntryNumber", (int64_t) 0, mustBePositive, + "The particular entry number to read. Default load all workspaces and creates a workspacegroup (default: read all entries)."); + declareProperty("LoadHistory", true, "If true, the workspace history will be loaded"); } - else + +//------------------------------------------------------------------------------------------------- + /** Executes the algorithm. Reading in the file and creating and populating + * the output workspace + * + * @throw runtime_error Thrown if algorithm cannot execute + */ + void LoadNexusProcessed::exec() { - //use default name if we couldn't match for some reason - wsName = baseName + index; - } - } + progress(0, "Opening file..."); - correctForWorkspaceNameClash(wsName); + //Throws an approriate exception if there is a problem with file access + NXRoot root(getPropertyValue("Filename")); - return wsName; -} + // "Open" the same file but with the C++ interface + m_cppFile = new ::NeXus::File(root.m_fileID); -/** - * Append an index to the name if it already exists in the AnalysisDataService - * - * @param wsName :: Name to call the workspace - */ -void LoadNexusProcessed::correctForWorkspaceNameClash(std::string& wsName) -{ - bool noClash(false); + //Find out how many first level entries there are + int64_t nWorkspaceEntries = static_cast(root.groups().size()); - for (int i =0; !noClash; ++i ) - { - std::string wsIndex = ""; //dont use an index if there is no other workspace - if(i > 0) - { - wsIndex = "_" + boost::lexical_cast(i); + // Check for an entry number property + int64_t entrynumber = static_cast(getProperty("EntryNumber")); + + if (entrynumber > 0 && entrynumber > nWorkspaceEntries) + { + g_log.error() << "Invalid entry number specified. File only contains " << nWorkspaceEntries + << " entries.\n"; + throw std::invalid_argument("Invalid entry number specified."); + } + + const std::string basename = "mantid_workspace_"; + if (nWorkspaceEntries == 1 || entrynumber > 0) + { // Load one first level entry, specified if there are several + if (entrynumber == 0) + ++entrynumber; + std::ostringstream os; + os << entrynumber; + API::Workspace_sptr workspace = loadEntry(root, basename + os.str(), 0, 1); + //API::Workspace_sptr workspace = boost::static_pointer_cast(local_workspace); + setProperty("OutputWorkspace", workspace); + } + else + { // Load all first level entries + WorkspaceGroup_sptr wksp_group(new WorkspaceGroup); + //This forms the name of the group + std::string base_name = getPropertyValue("OutputWorkspace"); + // First member of group should be the group itself, for some reason! + + //load names of each of the workspaces and check for a common stem + std::vector names(nWorkspaceEntries + 1); + bool commonStem = checkForCommonNameStem(root, names); + + //remove existing workspace and replace with the one being loaded + bool wsExists = AnalysisDataService::Instance().doesExist(base_name); + if (wsExists) + { + Algorithm_sptr alg = AlgorithmManager::Instance().createUnmanaged("DeleteWorkspace"); + alg->initialize(); + alg->setChild(true); + alg->setProperty("Workspace", base_name); + alg->execute(); + } + + base_name += "_"; + const std::string prop_name = "OutputWorkspace_"; + double nWorkspaceEntries_d = static_cast(nWorkspaceEntries); + for (int64_t p = 1; p <= nWorkspaceEntries; ++p) + { + std::ostringstream os; + os << p; + + //decide what the workspace should be called + std::string wsName = buildWorkspaceName(names[p], base_name, p, commonStem); + + Workspace_sptr local_workspace = loadEntry(root, basename + os.str(), + static_cast(p - 1) / nWorkspaceEntries_d, 1. / nWorkspaceEntries_d); + declareProperty( + new WorkspaceProperty(prop_name + os.str(), wsName, Direction::Output)); + //wksp_group->add(base_name + os.str()); + wksp_group->addWorkspace(local_workspace); + setProperty(prop_name + os.str(), local_workspace); + } + + // The group is the root property value + setProperty("OutputWorkspace", boost::static_pointer_cast(wksp_group)); + + } + + m_axis1vals.clear(); } - bool wsExists = AnalysisDataService::Instance().doesExist(wsName+wsIndex); - if(!wsExists) + /** + * Decides what to call a child of a group workspace. + * + * This function uses information about if the child workspace has a common stem + * and checks if the file contained a workspace name to decide what it should be called + * + * @param name :: The name loaded from the file (possibly the empty string if none was loaded) + * @param baseName :: The name group workspace + * @param wsIndex :: The current index of this workspace + * @param commonStem :: Whether the workspaces share a common name stem + * + * @return The name of the workspace + */ + std::string LoadNexusProcessed::buildWorkspaceName(const std::string& name, + const std::string& baseName, int64_t wsIndex, bool commonStem) { - wsName += wsIndex; - noClash = true; - } - } -} - -/** - * Check if the workspace name contains a common stem and load the workspace names - * - * @param root :: the root for the NeXus document - * @param names :: vector to store the names to be loaded. - * @return Whether there was a common stem. - */ -bool LoadNexusProcessed::checkForCommonNameStem(NXRoot & root, std::vector& names) -{ - bool success(true); - int64_t nperiods = static_cast(root.groups().size()); - for( int64_t p = 1; p <= nperiods; ++p ) - { - std::ostringstream os; - os << p; + std::string wsName; + std::string index = boost::lexical_cast(wsIndex); - names[p] = loadWorkspaceName(root, "mantid_workspace_" + os.str()); + //if we don't have a common stem then use name tag + if (!commonStem) + { + if (!name.empty()) + { + //use name loaded from file there's no common stem + wsName = name; + } + else + { + //if the name property wasn't defined just use _n + wsName = baseName + index; + } + } + else + { + //we have a common stem so rename accordingly + boost::smatch results; + const boost::regex exp(".*_(\\d+$)"); + //if we have a common name stem then name is _n + if (boost::regex_search(name, results, exp)) + { + wsName = baseName + std::string(results[1].first, results[1].second); + } + else + { + //use default name if we couldn't match for some reason + wsName = baseName + index; + } + } - boost::smatch results; - const boost::regex exp(".*_\\d+$"); + correctForWorkspaceNameClash(wsName); - //check if the workspace name has an index on the end - if (!boost::regex_match(names[p], results, exp)) + return wsName; + } + + /** + * Append an index to the name if it already exists in the AnalysisDataService + * + * @param wsName :: Name to call the workspace + */ + void LoadNexusProcessed::correctForWorkspaceNameClash(std::string& wsName) { - success = false; + bool noClash(false); + + for (int i = 0; !noClash; ++i) + { + std::string wsIndex = ""; //dont use an index if there is no other workspace + if (i > 0) + { + wsIndex = "_" + boost::lexical_cast(i); + } + + bool wsExists = AnalysisDataService::Instance().doesExist(wsName + wsIndex); + if (!wsExists) + { + wsName += wsIndex; + noClash = true; + } + } } - } - return success; -} - -/** - * Load the workspace name, if the attribute exists - * - * @param root :: Root of NeXus file - * @param entry_name :: Entry in NeXus file to look at - * @return The workspace name. If none found an empty string is returned. - */ -std::string LoadNexusProcessed::loadWorkspaceName(NXRoot & root, const std::string& entry_name) -{ - NXEntry mtd_entry = root.openEntry(entry_name); - try - { - return mtd_entry.getString("workspace_name"); - } - catch (std::runtime_error&) - { - return std::string(); - } -} + /** + * Check if the workspace name contains a common stem and load the workspace names + * + * @param root :: the root for the NeXus document + * @param names :: vector to store the names to be loaded. + * @return Whether there was a common stem. + */ + bool LoadNexusProcessed::checkForCommonNameStem(NXRoot & root, std::vector& names) + { + bool success(true); + int64_t nWorkspaceEntries = static_cast(root.groups().size()); + for (int64_t p = 1; p <= nWorkspaceEntries; ++p) + { + std::ostringstream os; + os << p; + names[p] = loadWorkspaceName(root, "mantid_workspace_" + os.str()); -//------------------------------------------------------------------------------------------------- -/** Load the event_workspace field - * - * @param wksp_cls - * @param xbins - * @param progressStart - * @param progressRange - * @return - */ -API::MatrixWorkspace_sptr LoadNexusProcessed::loadEventEntry(NXData & wksp_cls, NXDouble & xbins, - const double& progressStart, const double& progressRange) -{ - NXDataSetTyped indices_data = wksp_cls.openNXDataSet("indices"); - indices_data.load(); - boost::shared_array indices = indices_data.sharedBuffer(); - int numspec = indices_data.dim0()-1; - - int num_xbins = xbins.dim0(); - if (num_xbins < 2) num_xbins = 2; - EventWorkspace_sptr ws = boost::dynamic_pointer_cast - (WorkspaceFactory::Instance().create("EventWorkspace", numspec, num_xbins, num_xbins-1)); - - // Set the YUnit label - ws->setYUnit(indices_data.attributes("units")); - std::string unitLabel = indices_data.attributes("unit_label"); - if (unitLabel.empty()) unitLabel = indices_data.attributes("units"); - ws->setYUnitLabel(unitLabel); - - //Handle optional fields. - // TODO: Handle inconsistent sizes - boost::shared_array pulsetimes; - if (wksp_cls.isValid("pulsetime")) - { - NXDataSetTyped pulsetime = wksp_cls.openNXDataSet("pulsetime"); - pulsetime.load(); - pulsetimes = pulsetime.sharedBuffer(); - } + boost::smatch results; + const boost::regex exp(".*_\\d+$"); - boost::shared_array tofs; - if (wksp_cls.isValid("tof")) - { - NXDouble tof = wksp_cls.openNXDouble("tof"); - tof.load(); - tofs = tof.sharedBuffer(); - } + //check if the workspace name has an index on the end + if (!boost::regex_match(names[p], results, exp)) + { + success = false; + } + } - boost::shared_array error_squareds; - if (wksp_cls.isValid("error_squared")) - { - NXFloat error_squared = wksp_cls.openNXFloat("error_squared"); - error_squared.load(); - error_squareds = error_squared.sharedBuffer(); - } + return success; + } - boost::shared_array weights; - if (wksp_cls.isValid("weight")) - { - NXFloat weight = wksp_cls.openNXFloat("weight"); - weight.load(); - weights = weight.sharedBuffer(); - } + /** + * Load the workspace name, if the attribute exists + * + * @param root :: Root of NeXus file + * @param entry_name :: Entry in NeXus file to look at + * @return The workspace name. If none found an empty string is returned. + */ + std::string LoadNexusProcessed::loadWorkspaceName(NXRoot & root, const std::string& entry_name) + { + NXEntry mtd_entry = root.openEntry(entry_name); + try + { + return mtd_entry.getString("workspace_name"); + } catch (std::runtime_error&) + { + return std::string(); + } + } - // What type of event lists? - EventType type = TOF; - if (tofs && pulsetimes && weights && error_squareds) - type = WEIGHTED; - else if ((tofs && weights && error_squareds)) - type = WEIGHTED_NOTIME; - else if (pulsetimes && tofs) - type = TOF; - else - throw std::runtime_error("Could not figure out the type of event list!"); - - // Create all the event lists - PARALLEL_FOR_NO_WSP_CHECK() - for (int wi=0; wi < numspec; wi++) - { - PARALLEL_START_INTERUPT_REGION - int64_t index_start = indices[wi]; - int64_t index_end = indices[wi+1]; - if (index_end >= index_start) +//------------------------------------------------------------------------------------------------- + /** Load the event_workspace field + * + * @param wksp_cls + * @param xbins + * @param progressStart + * @param progressRange + * @return + */ + API::MatrixWorkspace_sptr LoadNexusProcessed::loadEventEntry(NXData & wksp_cls, NXDouble & xbins, + const double& progressStart, const double& progressRange) { - EventList & el = ws->getEventList(wi); - el.switchTo(type); + NXDataSetTyped indices_data = wksp_cls.openNXDataSet("indices"); + indices_data.load(); + boost::shared_array indices = indices_data.sharedBuffer(); + int numspec = indices_data.dim0() - 1; + + int num_xbins = xbins.dim0(); + if (num_xbins < 2) + num_xbins = 2; + EventWorkspace_sptr ws = boost::dynamic_pointer_cast( + WorkspaceFactory::Instance().create("EventWorkspace", numspec, num_xbins, num_xbins - 1)); + + // Set the YUnit label + ws->setYUnit(indices_data.attributes("units")); + std::string unitLabel = indices_data.attributes("unit_label"); + if (unitLabel.empty()) + unitLabel = indices_data.attributes("units"); + ws->setYUnitLabel(unitLabel); + + //Handle optional fields. + // TODO: Handle inconsistent sizes + boost::shared_array pulsetimes; + if (wksp_cls.isValid("pulsetime")) + { + NXDataSetTyped pulsetime = wksp_cls.openNXDataSet("pulsetime"); + pulsetime.load(); + pulsetimes = pulsetime.sharedBuffer(); + } - // Allocate all the required memory - el.reserve(index_end - index_start); - el.clearDetectorIDs(); + boost::shared_array tofs; + if (wksp_cls.isValid("tof")) + { + NXDouble tof = wksp_cls.openNXDouble("tof"); + tof.load(); + tofs = tof.sharedBuffer(); + } - for (int64_t i=index_start; i error_squareds; + if (wksp_cls.isValid("error_squared")) { - case TOF: - el.addEventQuickly( TofEvent( tofs[i], DateAndTime(pulsetimes[i])) ); - break; - case WEIGHTED: - el.addEventQuickly( WeightedEvent( tofs[i], DateAndTime(pulsetimes[i]), weights[i], error_squareds[i]) ); - break; - case WEIGHTED_NOTIME: - el.addEventQuickly( WeightedEventNoTime( tofs[i], weights[i], error_squareds[i]) ); - break; + NXFloat error_squared = wksp_cls.openNXFloat("error_squared"); + error_squared.load(); + error_squareds = error_squared.sharedBuffer(); } - // Set the X axis - if (this->m_shared_bins) - el.setX(this->m_xbins); - else + boost::shared_array weights; + if (wksp_cls.isValid("weight")) { - MantidVec x; - x.resize(xbins.dim0()); - for (int i=0; i < xbins.dim0(); i++) - x[i] = xbins(wi, i); - el.setX(x); + NXFloat weight = wksp_cls.openNXFloat("weight"); + weight.load(); + weights = weight.sharedBuffer(); } - } - progress(progressStart + progressRange*(1.0/numspec)); - PARALLEL_END_INTERUPT_REGION - } - PARALLEL_CHECK_INTERUPT_REGION + // What type of event lists? + EventType type = TOF; + if (tofs && pulsetimes && weights && error_squareds) + type = WEIGHTED; + else if ((tofs && weights && error_squareds)) + type = WEIGHTED_NOTIME; + else if (pulsetimes && tofs) + type = TOF; + else + throw std::runtime_error("Could not figure out the type of event list!"); + // Create all the event lists + PARALLEL_FOR_NO_WSP_CHECK() + for (int wi = 0; wi < numspec; wi++) + { + PARALLEL_START_INTERUPT_REGION + int64_t index_start = indices[wi]; + int64_t index_end = indices[wi + 1]; + if (index_end >= index_start) + { + EventList & el = ws->getEventList(wi); + el.switchTo(type); + + // Allocate all the required memory + el.reserve(index_end - index_start); + el.clearDetectorIDs(); + + for (int64_t i = index_start; i < index_end; i++) + switch (type) + { + case TOF: + el.addEventQuickly(TofEvent(tofs[i], DateAndTime(pulsetimes[i]))); + break; + case WEIGHTED: + el.addEventQuickly( + WeightedEvent(tofs[i], DateAndTime(pulsetimes[i]), weights[i], error_squareds[i])); + break; + case WEIGHTED_NOTIME: + el.addEventQuickly(WeightedEventNoTime(tofs[i], weights[i], error_squareds[i])); + break; + } + + // Set the X axis + if (this->m_shared_bins) + el.setX(this->m_xbins); + else + { + MantidVec x; + x.resize(xbins.dim0()); + for (int i = 0; i < xbins.dim0(); i++) + x[i] = xbins(wi, i); + el.setX(x); + } + } - return ws; -} + progress(progressStart + progressRange * (1.0 / numspec)); + PARALLEL_END_INTERUPT_REGION + } + PARALLEL_CHECK_INTERUPT_REGION + return ws; + } //------------------------------------------------------------------------------------------------- -/** - * Load a table - */ -API::Workspace_sptr LoadNexusProcessed::loadTableEntry(NXEntry & entry) -{ - API::ITableWorkspace_sptr workspace; - workspace = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace"); + /** + * Load a table + */ + API::Workspace_sptr LoadNexusProcessed::loadTableEntry(NXEntry & entry) + { + API::ITableWorkspace_sptr workspace; + workspace = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace"); - NXData nx_tw = entry.openNXData("table_workspace"); + NXData nx_tw = entry.openNXData("table_workspace"); - bool hasNumberOfRowBeenSet = false; - //int numberOfRows = 0; + bool hasNumberOfRowBeenSet = false; + //int numberOfRows = 0; - int columnNumber = 1; - do - { - std::string str = "column_" + boost::lexical_cast(columnNumber); - - NXInfo info = nx_tw.getDataSetInfo(str.c_str()); - if (info.stat == NX_ERROR) + int columnNumber = 1; + do { - // Assume we done last column of table - break; - } + std::string str = "column_" + boost::lexical_cast(columnNumber); - if ( info.rank == 1 ) - { - if ( info.type == NX_FLOAT64 ) + NXInfo info = nx_tw.getDataSetInfo(str.c_str()); + if (info.stat == NX_ERROR) { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - std::string columnTitle = nxDouble.attributes("name"); - if (!columnTitle.empty()) + // Assume we done last column of table + break; + } + + if (info.rank == 1) + { + if (info.type == NX_FLOAT64) { - workspace->addColumn("double", columnTitle); - nxDouble.load(); - int length = nxDouble.dim0(); - if ( !hasNumberOfRowBeenSet ) + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + std::string columnTitle = nxDouble.attributes("name"); + if (!columnTitle.empty()) { - workspace->setRowCount(length); - hasNumberOfRowBeenSet = true; + workspace->addColumn("double", columnTitle); + nxDouble.load(); + int length = nxDouble.dim0(); + if (!hasNumberOfRowBeenSet) + { + workspace->setRowCount(length); + hasNumberOfRowBeenSet = true; + } + for (int i = 0; i < length; i++) + workspace->cell(i, columnNumber - 1) = *(nxDouble() + i); } - for (int i = 0; i < length; i++) - workspace->cell(i,columnNumber-1) = *(nxDouble() + i); } - } - else if ( info.type == NX_INT32 ) - { - NXInt nxInt = nx_tw.openNXInt(str.c_str()); - std::string columnTitle = nxInt.attributes("name"); - if (!columnTitle.empty()) + else if (info.type == NX_INT32) { - workspace->addColumn("int", columnTitle); - nxInt.load(); - int length = nxInt.dim0(); - if ( !hasNumberOfRowBeenSet ) + NXInt nxInt = nx_tw.openNXInt(str.c_str()); + std::string columnTitle = nxInt.attributes("name"); + if (!columnTitle.empty()) { - workspace->setRowCount(length); - hasNumberOfRowBeenSet = true; + workspace->addColumn("int", columnTitle); + nxInt.load(); + int length = nxInt.dim0(); + if (!hasNumberOfRowBeenSet) + { + workspace->setRowCount(length); + hasNumberOfRowBeenSet = true; + } + for (int i = 0; i < length; i++) + workspace->cell(i, columnNumber - 1) = *(nxInt() + i); } - for (int i = 0; i < length; i++) - workspace->cell(i,columnNumber-1) = *(nxInt() + i); } } - } - else if ( info.rank == 2 ) - { - if ( info.type == NX_CHAR ) + else if (info.rank == 2) { - NXChar data = nx_tw.openNXChar(str.c_str()); - std::string columnTitle = data.attributes("name"); - if (!columnTitle.empty()) + if (info.type == NX_CHAR) { - workspace->addColumn("str", columnTitle); - int nRows = info.dims[0]; - if ( !hasNumberOfRowBeenSet ) + NXChar data = nx_tw.openNXChar(str.c_str()); + std::string columnTitle = data.attributes("name"); + if (!columnTitle.empty()) { - workspace->setRowCount(nRows); - hasNumberOfRowBeenSet = true; - } - - const int maxStr = info.dims[1]; - data.load(); - for (int iR = 0; iR < nRows; ++iR) - { - auto& cellContents = workspace->cell(iR,columnNumber-1); - auto startPoint = data() + maxStr*iR; - cellContents.assign(startPoint,startPoint+maxStr); - boost::trim_right(cellContents); + workspace->addColumn("str", columnTitle); + int nRows = info.dims[0]; + if (!hasNumberOfRowBeenSet) + { + workspace->setRowCount(nRows); + hasNumberOfRowBeenSet = true; + } + + const int maxStr = info.dims[1]; + data.load(); + for (int iR = 0; iR < nRows; ++iR) + { + auto& cellContents = workspace->cell(iR, columnNumber - 1); + auto startPoint = data() + maxStr * iR; + cellContents.assign(startPoint, startPoint + maxStr); + boost::trim_right(cellContents); + } } } - } - #define IF_VECTOR_COLUMN(Type, ColumnTypeName, NexusType) \ +#define IF_VECTOR_COLUMN(Type, ColumnTypeName, NexusType) \ else if ( info.type == NexusType ) \ { \ loadVectorColumn(nx_tw, str, workspace, #ColumnTypeName); \ } - IF_VECTOR_COLUMN(int, vector_int, NX_INT32) - IF_VECTOR_COLUMN(double, vector_double, NX_FLOAT64) - - } + IF_VECTOR_COLUMN(int, vector_int, NX_INT32) + IF_VECTOR_COLUMN(double, vector_double, NX_FLOAT64) - columnNumber++; - - } while ( 1 ); - - return boost::static_pointer_cast(workspace); -} - -/** - * Loads a vector column to the TableWorkspace. - * @param tableData :: Table data to load from - * @param dataSetName :: Name of the data set to use to get column data - * @param tableWs :: Workspace to add column to - * @param columnType :: Name of the column type to create - */ -template -void LoadNexusProcessed::loadVectorColumn(const NXData& tableData, - const std::string& dataSetName, - const ITableWorkspace_sptr& tableWs, - const std::string& columnType) -{ - NXDataSetTyped data = tableData.openNXDataSet(dataSetName.c_str()); - std::string columnTitle = data.attributes("name"); - if ( ! columnTitle.empty() ) - { - tableWs->addColumn(columnType, columnTitle); + } - NXInfo info = tableData.getDataSetInfo(dataSetName.c_str()); - const size_t rowCount = info.dims[0]; - const size_t blockSize = info.dims[1]; + columnNumber++; - // This might've been done already, but doing it twice should't do any harm - tableWs->setRowCount(rowCount); + } while (1); - data.load(); + return boost::static_pointer_cast(workspace); + } - for ( size_t i = 0; i < rowCount; ++i ) + /** + * Loads a vector column to the TableWorkspace. + * @param tableData :: Table data to load from + * @param dataSetName :: Name of the data set to use to get column data + * @param tableWs :: Workspace to add column to + * @param columnType :: Name of the column type to create + */ + template + void LoadNexusProcessed::loadVectorColumn(const NXData& tableData, const std::string& dataSetName, + const ITableWorkspace_sptr& tableWs, const std::string& columnType) + { + NXDataSetTyped data = tableData.openNXDataSet(dataSetName.c_str()); + std::string columnTitle = data.attributes("name"); + if (!columnTitle.empty()) { - auto& cell = tableWs->cell< std::vector >(i, tableWs->columnCount() - 1); + tableWs->addColumn(columnType, columnTitle); - Type* from = data() + blockSize * i; + NXInfo info = tableData.getDataSetInfo(dataSetName.c_str()); + const size_t rowCount = info.dims[0]; + const size_t blockSize = info.dims[1]; - cell.assign(from, from + blockSize); + // This might've been done already, but doing it twice should't do any harm + tableWs->setRowCount(rowCount); - std::ostringstream rowSizeAttrName; rowSizeAttrName << "row_size_" << i; + data.load(); - // This is ugly, but I can only get attribute as a string using the API - std::istringstream rowSizeStr( data.attributes(rowSizeAttrName.str()) ); + for (size_t i = 0; i < rowCount; ++i) + { + auto& cell = tableWs->cell >(i, tableWs->columnCount() - 1); - int rowSize; rowSizeStr >> rowSize; + Type* from = data() + blockSize * i; - cell.resize(rowSize); - } - } -} + cell.assign(from, from + blockSize); -//------------------------------------------------------------------------------------------------- -/** - * Load peaks - */ -API::Workspace_sptr LoadNexusProcessed::loadPeaksEntry(NXEntry & entry) -{ - //API::IPeaksWorkspace_sptr workspace; - API::ITableWorkspace_sptr tWorkspace; - //PeaksWorkspace_sptr workspace; - tWorkspace = Mantid::API::WorkspaceFactory::Instance().createTable("PeaksWorkspace"); + std::ostringstream rowSizeAttrName; + rowSizeAttrName << "row_size_" << i; - PeaksWorkspace_sptr peakWS = boost::dynamic_pointer_cast(tWorkspace); + // This is ugly, but I can only get attribute as a string using the API + std::istringstream rowSizeStr(data.attributes(rowSizeAttrName.str())); - NXData nx_tw = entry.openNXData("peaks_workspace"); + int rowSize; + rowSizeStr >> rowSize; + cell.resize(rowSize); + } + } + } - int columnNumber = 1; - int numberPeaks = 0; - std::vector columnNames; - do +//------------------------------------------------------------------------------------------------- + /** + * Load peaks + */ + API::Workspace_sptr LoadNexusProcessed::loadPeaksEntry(NXEntry & entry) { - std::string str = "column_" + boost::lexical_cast(columnNumber); - - NXInfo info = nx_tw.getDataSetInfo(str.c_str()); - if (info.stat == NX_ERROR) - { - // Assume we done last column of table - break; - } + //API::IPeaksWorkspace_sptr workspace; + API::ITableWorkspace_sptr tWorkspace; + //PeaksWorkspace_sptr workspace; + tWorkspace = Mantid::API::WorkspaceFactory::Instance().createTable("PeaksWorkspace"); - // store column names - columnNames.push_back(str); + PeaksWorkspace_sptr peakWS = boost::dynamic_pointer_cast(tWorkspace); + NXData nx_tw = entry.openNXData("peaks_workspace"); - // determine number of peaks - // here we assume that a peaks_table has always one column of doubles - - if ( info.type == NX_FLOAT64 ) + int columnNumber = 1; + int numberPeaks = 0; + std::vector columnNames; + do { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - std::string columnTitle = nxDouble.attributes("name"); - if (!columnTitle.empty() && numberPeaks==0) + std::string str = "column_" + boost::lexical_cast(columnNumber); + + NXInfo info = nx_tw.getDataSetInfo(str.c_str()); + if (info.stat == NX_ERROR) { - numberPeaks = nxDouble.dim0(); + // Assume we done last column of table + break; } - } - - columnNumber++; - } while ( 1 ); + // store column names + columnNames.push_back(str); + // determine number of peaks + // here we assume that a peaks_table has always one column of doubles - //Get information from all but data group - std::string parameterStr; - // Hop to the right point - m_cppFile->openPath(entry.path()); - try - { - // This loads logs, sample, and instrument. - peakWS->loadExperimentInfoNexus(m_cppFile, parameterStr); - } - catch (std::exception & e) - { - g_log.information("Error loading Instrument section of nxs file"); - g_log.information(e.what()); - } - - - // std::vector p; - for (int r = 0; r < numberPeaks; r++) - { - Kernel::V3D v3d; - v3d[2] = 1.0; - API::IPeak* p; - p = peakWS->createPeak(v3d); - peakWS->addPeak(*p); - } + if (info.type == NX_FLOAT64) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + std::string columnTitle = nxDouble.attributes("name"); + if (!columnTitle.empty() && numberPeaks == 0) + { + numberPeaks = nxDouble.dim0(); + } + } + columnNumber++; + } while (1); - for (size_t i = 0; i < columnNames.size(); i++) - { - const std::string str = columnNames[i]; - if ( !str.compare("column_1") ) + //Get information from all but data group + std::string parameterStr; + // Hop to the right point + m_cppFile->openPath(entry.path()); + try { - NXInt nxInt = nx_tw.openNXInt(str.c_str()); - nxInt.load(); - - for (int r = 0; r < numberPeaks; r++) { - int ival = nxInt[r]; - if( ival != -1) peakWS->getPeak(r).setDetectorID( ival ); - } - } - - if ( !str.compare("column_2") ) + // This loads logs, sample, and instrument. + peakWS->loadExperimentInfoNexus(m_cppFile, parameterStr); + } catch (std::exception & e) { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); - - for (int r = 0; r < numberPeaks; r++) { - double val = nxDouble[r]; - peakWS->getPeak(r).setH( val ); - } + g_log.information("Error loading Instrument section of nxs file"); + g_log.information(e.what()); } - if ( !str.compare("column_3") ) + // std::vector p; + for (int r = 0; r < numberPeaks; r++) { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); - - for (int r = 0; r < numberPeaks; r++) { - double val = nxDouble[r]; - peakWS->getPeak(r).setK( val ); - } + Kernel::V3D v3d; + v3d[2] = 1.0; + API::IPeak* p; + p = peakWS->createPeak(v3d); + peakWS->addPeak(*p); } - if ( !str.compare("column_4") ) + for (size_t i = 0; i < columnNames.size(); i++) { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); + const std::string str = columnNames[i]; + if (!str.compare("column_1")) + { + NXInt nxInt = nx_tw.openNXInt(str.c_str()); + nxInt.load(); - for (int r = 0; r < numberPeaks; r++) { - double val = nxDouble[r]; - peakWS->getPeak(r).setL( val ); + for (int r = 0; r < numberPeaks; r++) + { + int ival = nxInt[r]; + if (ival != -1) + peakWS->getPeak(r).setDetectorID(ival); + } } - } - if ( !str.compare("column_5") ) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); + if (!str.compare("column_2")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); - for (int r = 0; r < numberPeaks; r++) { - double val = nxDouble[r]; - peakWS->getPeak(r).setIntensity( val ); + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setH(val); + } } - } - if ( !str.compare("column_6") ) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); + if (!str.compare("column_3")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); - for (int r = 0; r < numberPeaks; r++) { - double val = nxDouble[r]; - peakWS->getPeak(r).setSigmaIntensity( val ); + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setK(val); + } } - } + if (!str.compare("column_4")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setL(val); + } + } - if ( !str.compare("column_7") ) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); + if (!str.compare("column_5")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); - for (int r = 0; r < numberPeaks; r++) { - double val = nxDouble[r]; - peakWS->getPeak(r).setBinCount( val ); + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setIntensity(val); + } } - } + if (!str.compare("column_6")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); - if ( !str.compare("column_10") ) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); - - for (int r = 0; r < numberPeaks; r++) { - double val = nxDouble[r]; - peakWS->getPeak(r).setWavelength( val ); + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setSigmaIntensity(val); + } } - } - if ( !str.compare("column_14") ) - { - NXInt nxInt = nx_tw.openNXInt(str.c_str()); - nxInt.load(); + if (!str.compare("column_7")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); - for (int r = 0; r < numberPeaks; r++) { - int ival = nxInt[r]; - if( ival != -1) peakWS->getPeak(r).setRunNumber( ival ); + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setBinCount(val); + } } - } - if ( !str.compare("column_15") ) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); - Kernel::Matrix gm(3, 3, false); - int k = 0; - for (int r = 0; r < numberPeaks; r++) { - for (int j = 0; j < 9; j++) - { - double val = nxDouble[k]; - k++; - gm[j%3][j/3] = val; - } - peakWS->getPeak(r).setGoniometerMatrix( gm ); + if (!str.compare("column_10")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); + + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setWavelength(val); + } } - } - } + if (!str.compare("column_14")) + { + NXInt nxInt = nx_tw.openNXInt(str.c_str()); + nxInt.load(); - return boost::static_pointer_cast(peakWS); -} + for (int r = 0; r < numberPeaks; r++) + { + int ival = nxInt[r]; + if (ival != -1) + peakWS->getPeak(r).setRunNumber(ival); + } + } -//------------------------------------------------------------------------------------------------- -/** - * Load a single entry into a workspace - * @param root :: The opened root node - * @param entry_name :: The entry name - * @param progressStart :: The percentage value to start the progress reporting for this entry - * @param progressRange :: The percentage range that the progress reporting should cover - * @returns A 2D workspace containing the loaded data - */ -API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot & root, const std::string & entry_name, - const double& progressStart, const double& progressRange) -{ - progress(progressStart,"Opening entry " + entry_name + "..."); + if (!str.compare("column_15")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); + Kernel::Matrix gm(3, 3, false); + int k = 0; + for (int r = 0; r < numberPeaks; r++) + { + for (int j = 0; j < 9; j++) + { + double val = nxDouble[k]; + k++; + gm[j % 3][j / 3] = val; + } + peakWS->getPeak(r).setGoniometerMatrix(gm); + } + } - NXEntry mtd_entry = root.openEntry(entry_name); + } - if (mtd_entry.containsGroup("table_workspace")) - { - return loadTableEntry(mtd_entry); - } + return boost::static_pointer_cast(peakWS); + } - if (mtd_entry.containsGroup("peaks_workspace")) +//------------------------------------------------------------------------------------------------- + /** + * Load a single entry into a workspace + * @param root :: The opened root node + * @param entry_name :: The entry name + * @param progressStart :: The percentage value to start the progress reporting for this entry + * @param progressRange :: The percentage range that the progress reporting should cover + * @returns A 2D workspace containing the loaded data + */ + API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot & root, const std::string & entry_name, + const double& progressStart, const double& progressRange) { - return loadPeaksEntry(mtd_entry); - } + progress(progressStart, "Opening entry " + entry_name + "..."); + NXEntry mtd_entry = root.openEntry(entry_name); - // Determine workspace type and name of group containing workspace characteristics - bool isEvent = false; - std::string workspaceType = "Workspace2D"; - std::string group_name = "workspace"; - if (mtd_entry.containsGroup("event_workspace")) - { - isEvent = true; - group_name = "event_workspace"; - } - else if (mtd_entry.containsGroup("offsets_workspace")) - { - workspaceType = "OffsetsWorkspace"; - group_name = "offsets_workspace"; - } + if (mtd_entry.containsGroup("table_workspace")) + { + return loadTableEntry(mtd_entry); + } - // Get workspace characteristics - NXData wksp_cls = mtd_entry.openNXData(group_name); - - // Axis information - // "X" axis - NXDouble xbins = wksp_cls.openNXDouble("axis1"); - xbins.load(); - std::string unit1 = xbins.attributes("units"); - // Non-uniform x bins get saved as a 2D 'axis1' dataset - int xlength(-1); - if( xbins.rank() == 2 ) - { - xlength = xbins.dim1(); - m_shared_bins = false; - } - else if( xbins.rank() == 1 ) - { - xlength = xbins.dim0(); - m_shared_bins = true; - xbins.load(); - m_xbins.access().assign(xbins(), xbins() + xlength); - } - else - { - throw std::runtime_error("Unknown axis1 dimension encountered."); - } + if (mtd_entry.containsGroup("peaks_workspace")) + { + return loadPeaksEntry(mtd_entry); + } - // MatrixWorkspace axis 1 - NXDouble axis2 = wksp_cls.openNXDouble("axis2"); - std::string unit2 = axis2.attributes("units"); + // Determine workspace type and name of group containing workspace characteristics + bool isEvent = false; + std::string workspaceType = "Workspace2D"; + std::string group_name = "workspace"; + if (mtd_entry.containsGroup("event_workspace")) + { + isEvent = true; + group_name = "event_workspace"; + } + else if (mtd_entry.containsGroup("offsets_workspace")) + { + workspaceType = "OffsetsWorkspace"; + group_name = "offsets_workspace"; + } - // The workspace being worked on - API::MatrixWorkspace_sptr local_workspace; - size_t nspectra; - int64_t nchannels; + // Get workspace characteristics + NXData wksp_cls = mtd_entry.openNXData(group_name); - // -------- Process as event ? -------------------- - if (isEvent) - { - local_workspace = loadEventEntry(wksp_cls, xbins, progressStart, progressRange); - nspectra = local_workspace->getNumberHistograms(); - nchannels = local_workspace->blocksize(); - } - else - { - NXDataSetTyped data = wksp_cls.openDoubleData(); - nspectra = data.dim0(); - nchannels = data.dim1(); - //// validate the optional spectrum parameters, if set - checkOptionalProperties(nspectra); - // Actual number of spectra in output workspace (if only a range was going to be loaded) - size_t total_specs=calculateWorkspacesize(nspectra); - - //// Create the 2D workspace for the output - bool hasFracArea = false; - if (wksp_cls.isValid("frac_area")) + // Axis information + // "X" axis + NXDouble xbins = wksp_cls.openNXDouble("axis1"); + xbins.load(); + std::string unit1 = xbins.attributes("units"); + // Non-uniform x bins get saved as a 2D 'axis1' dataset + int xlength(-1); + if (xbins.rank() == 2) { - // frac_area entry is the signal for a RebinnedOutput workspace - hasFracArea = true; - workspaceType.clear(); - workspaceType = "RebinnedOutput"; + xlength = xbins.dim1(); + m_shared_bins = false; } - local_workspace = boost::dynamic_pointer_cast - (WorkspaceFactory::Instance().create(workspaceType, total_specs, xlength, nchannels)); - try + else if (xbins.rank() == 1) { - local_workspace->setTitle(mtd_entry.getString("title")); + xlength = xbins.dim0(); + m_shared_bins = true; + xbins.load(); + m_xbins.access().assign(xbins(), xbins() + xlength); } - catch (std::runtime_error&) + else { - g_log.debug() << "No title was found in the input file, " << getPropertyValue("Filename") << std::endl; + throw std::runtime_error("Unknown axis1 dimension encountered."); } - // Set the YUnit label - local_workspace->setYUnit(data.attributes("units")); - std::string unitLabel = data.attributes("unit_label"); - if (unitLabel.empty()) unitLabel = data.attributes("units"); - local_workspace->setYUnitLabel(unitLabel); - - readBinMasking(wksp_cls, local_workspace); - NXDataSetTyped errors = wksp_cls.openNXDouble("errors"); - NXDataSetTyped fracarea = wksp_cls.openNXDouble("errors"); - if (hasFracArea) + // MatrixWorkspace axis 1 + NXDouble axis2 = wksp_cls.openNXDouble("axis2"); + std::string unit2 = axis2.attributes("units"); + + // The workspace being worked on + API::MatrixWorkspace_sptr local_workspace; + size_t nspectra; + int64_t nchannels; + + // -------- Process as event ? -------------------- + if (isEvent) { - fracarea = wksp_cls.openNXDouble("frac_area"); + local_workspace = loadEventEntry(wksp_cls, xbins, progressStart, progressRange); + nspectra = local_workspace->getNumberHistograms(); + nchannels = local_workspace->blocksize(); } - - int64_t blocksize(8); - //const int fullblocks = nspectra / blocksize; - //size of the workspace - int64_t fullblocks = total_specs / blocksize; - int64_t read_stop = (fullblocks * blocksize); - const double progressBegin = progressStart+0.25*progressRange; - const double progressScaler = 0.75*progressRange; - int64_t hist_index = 0; - int64_t wsIndex=0; - if( m_shared_bins ) + else { - //if spectrum min,max,list properties are set - if(m_interval||m_list) + NXDataSetTyped data = wksp_cls.openDoubleData(); + nspectra = data.dim0(); + nchannels = data.dim1(); + //// validate the optional spectrum parameters, if set + checkOptionalProperties(nspectra); + // Actual number of spectra in output workspace (if only a range was going to be loaded) + size_t total_specs = calculateWorkspacesize(nspectra); + + //// Create the 2D workspace for the output + bool hasFracArea = false; + if (wksp_cls.isValid("frac_area")) { - //if spectrum max,min properties are set read the data as a block(multiple of 8) and - //then read the remaining data as finalblock - if(m_interval) - { - //specs at the min-max interval - int interval_specs=static_cast(m_spec_max-m_spec_min); - fullblocks=(interval_specs)/blocksize; - read_stop = (fullblocks * blocksize)+m_spec_min-1; + // frac_area entry is the signal for a RebinnedOutput workspace + hasFracArea = true; + workspaceType.clear(); + workspaceType = "RebinnedOutput"; + } + local_workspace = boost::dynamic_pointer_cast( + WorkspaceFactory::Instance().create(workspaceType, total_specs, xlength, nchannels)); + try + { + local_workspace->setTitle(mtd_entry.getString("title")); + } catch (std::runtime_error&) + { + g_log.debug() << "No title was found in the input file, " << getPropertyValue("Filename") + << std::endl; + } - if(interval_specssetYUnit(data.attributes("units")); + std::string unitLabel = data.attributes("unit_label"); + if (unitLabel.empty()) + unitLabel = data.attributes("units"); + local_workspace->setYUnitLabel(unitLabel); + + readBinMasking(wksp_cls, local_workspace); + NXDataSetTyped errors = wksp_cls.openNXDouble("errors"); + NXDataSetTyped fracarea = wksp_cls.openNXDouble("errors"); + if (hasFracArea) + { + fracarea = wksp_cls.openNXDouble("frac_area"); + } - for( ; hist_index < read_stop; ) + int64_t blocksize(8); + //const int fullblocks = nspectra / blocksize; + //size of the workspace + int64_t fullblocks = total_specs / blocksize; + int64_t read_stop = (fullblocks * blocksize); + const double progressBegin = progressStart + 0.25 * progressRange; + const double progressScaler = 0.75 * progressRange; + int64_t hist_index = 0; + int64_t wsIndex = 0; + if (m_shared_bins) + { + //if spectrum min,max,list properties are set + if (m_interval || m_list) + { + //if spectrum max,min properties are set read the data as a block(multiple of 8) and + //then read the remaining data as finalblock + if (m_interval) { - progress(progressBegin+progressScaler*static_cast(hist_index)/static_cast(read_stop),"Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, blocksize, nchannels, hist_index,wsIndex, local_workspace); + //specs at the min-max interval + int interval_specs = static_cast(m_spec_max - m_spec_min); + fullblocks = (interval_specs) / blocksize; + read_stop = (fullblocks * blocksize) + m_spec_min - 1; + + if (interval_specs < blocksize) + { + blocksize = total_specs; + read_stop = m_spec_max - 1; + } + hist_index = m_spec_min - 1; + + for (; hist_index < read_stop;) + { + progress( + progressBegin + + progressScaler * static_cast(hist_index) + / static_cast(read_stop), "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, blocksize, nchannels, hist_index, wsIndex, + local_workspace); + } + int64_t finalblock = m_spec_max - 1 - read_stop; + if (finalblock > 0) + { + loadBlock(data, errors, fracarea, hasFracArea, finalblock, nchannels, hist_index, wsIndex, + local_workspace); + } } - int64_t finalblock = m_spec_max-1 - read_stop; - if( finalblock > 0 ) + // if spectrum list property is set read each spectrum separately by setting blocksize=1 + if (m_list) { - loadBlock(data, errors, fracarea, hasFracArea, finalblock, nchannels, hist_index,wsIndex,local_workspace); + std::vector::iterator itr = m_spec_list.begin(); + for (; itr != m_spec_list.end(); ++itr) + { + int64_t specIndex = (*itr) - 1; + progress( + progressBegin + + progressScaler * static_cast(specIndex) + / static_cast(m_spec_list.size()), "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, static_cast(1), nchannels, + specIndex, wsIndex, local_workspace); + } + } } - // if spectrum list property is set read each spectrum separately by setting blocksize=1 - if(m_list) + else { - std::vector::iterator itr=m_spec_list.begin(); - for(;itr!=m_spec_list.end();++itr) + for (; hist_index < read_stop;) { - int64_t specIndex=(*itr)-1; - progress(progressBegin+progressScaler*static_cast(specIndex)/static_cast(m_spec_list.size()),"Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, static_cast(1), nchannels, specIndex,wsIndex, local_workspace); + progress( + progressBegin + + progressScaler * static_cast(hist_index) / static_cast(read_stop), + "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, blocksize, nchannels, hist_index, wsIndex, + local_workspace); + } + int64_t finalblock = total_specs - read_stop; + if (finalblock > 0) + { + loadBlock(data, errors, fracarea, hasFracArea, finalblock, nchannels, hist_index, wsIndex, + local_workspace); } - } + } else { - for( ; hist_index < read_stop; ) - { - progress(progressBegin+progressScaler*static_cast(hist_index)/static_cast(read_stop),"Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, blocksize, nchannels, hist_index,wsIndex, local_workspace); - } - int64_t finalblock = total_specs - read_stop; - if( finalblock > 0 ) - { - loadBlock(data, errors, fracarea, hasFracArea, finalblock, nchannels, hist_index,wsIndex,local_workspace); - } - } - - } - else - { - if(m_interval||m_list) - { - if(m_interval) + if (m_interval || m_list) { - int64_t interval_specs=m_spec_max-m_spec_min; - fullblocks=(interval_specs)/blocksize; - read_stop = (fullblocks * blocksize)+m_spec_min-1; - - if(interval_specs(hist_index)/static_cast(read_stop),"Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, xbins, blocksize, nchannels, hist_index,wsIndex,local_workspace); + int64_t interval_specs = m_spec_max - m_spec_min; + fullblocks = (interval_specs) / blocksize; + read_stop = (fullblocks * blocksize) + m_spec_min - 1; + + if (interval_specs < blocksize) + { + blocksize = interval_specs; + read_stop = m_spec_max - 1; + } + hist_index = m_spec_min - 1; + + for (; hist_index < read_stop;) + { + progress( + progressBegin + + progressScaler * static_cast(hist_index) + / static_cast(read_stop), "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, xbins, blocksize, nchannels, hist_index, + wsIndex, local_workspace); + } + int64_t finalblock = m_spec_max - 1 - read_stop; + if (finalblock > 0) + { + loadBlock(data, errors, fracarea, hasFracArea, xbins, finalblock, nchannels, hist_index, + wsIndex, local_workspace); + } } - int64_t finalblock = m_spec_max-1 - read_stop; - if( finalblock > 0 ) + // + if (m_list) { - loadBlock(data, errors, fracarea, hasFracArea, xbins, finalblock, nchannels, hist_index,wsIndex, local_workspace); + std::vector::iterator itr = m_spec_list.begin(); + for (; itr != m_spec_list.end(); ++itr) + { + int64_t specIndex = (*itr) - 1; + progress( + progressBegin + + progressScaler * static_cast(specIndex) / static_cast(read_stop), + "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, xbins, 1, nchannels, specIndex, wsIndex, + local_workspace); + } + } } - // - if(m_list) + else { - std::vector::iterator itr=m_spec_list.begin(); - for(;itr!=m_spec_list.end();++itr) + for (; hist_index < read_stop;) { - int64_t specIndex=(*itr)-1; - progress(progressBegin+progressScaler*static_cast(specIndex)/static_cast(read_stop),"Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, xbins, 1, nchannels, specIndex,wsIndex,local_workspace); + progress( + progressBegin + + progressScaler * static_cast(hist_index) / static_cast(read_stop), + "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, xbins, blocksize, nchannels, hist_index, + wsIndex, local_workspace); + } + int64_t finalblock = total_specs - read_stop; + if (finalblock > 0) + { + loadBlock(data, errors, fracarea, hasFracArea, xbins, finalblock, nchannels, hist_index, + wsIndex, local_workspace); } - } } - else + } //end of NOT an event ------------------------------- + + //Units + bool verticalHistogram(false); + try + { + local_workspace->getAxis(0)->unit() = UnitFactory::Instance().create(unit1); + if (unit1 == "Label") { - for( ; hist_index < read_stop; ) - { - progress(progressBegin+progressScaler*static_cast(hist_index)/static_cast(read_stop),"Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, xbins, blocksize, nchannels, hist_index,wsIndex,local_workspace); - } - int64_t finalblock = total_specs - read_stop; - if( finalblock > 0 ) - { - loadBlock(data, errors, fracarea, hasFracArea, xbins, finalblock, nchannels, hist_index,wsIndex, local_workspace); - } + auto label = boost::dynamic_pointer_cast( + local_workspace->getAxis(0)->unit()); + auto ax = wksp_cls.openNXDouble("axis1"); + label->setLabel(ax.attributes("caption"), ax.attributes("label")); } - } - } //end of NOT an event ------------------------------- - - - //Units - bool verticalHistogram(false); - try - { - local_workspace->getAxis(0)->unit() = UnitFactory::Instance().create(unit1); - if(unit1 == "Label") + //If this doesn't throw then it is a numeric access so grab the data so we can set it later + axis2.load(); + if (static_cast(axis2.size()) == nspectra + 1) + verticalHistogram = true; + m_axis1vals = MantidVec(axis2(), axis2() + axis2.dim0()); + } catch (std::runtime_error &) { - auto label = boost::dynamic_pointer_cast(local_workspace->getAxis(0)->unit()); - auto ax = wksp_cls.openNXDouble("axis1"); - label->setLabel(ax.attributes("caption"), ax.attributes("label")); + g_log.information() << "Axis 0 set to unitless quantity \"" << unit1 << "\"\n"; } - //If this doesn't throw then it is a numeric access so grab the data so we can set it later - axis2.load(); - if(static_cast(axis2.size()) == nspectra + 1) verticalHistogram = true; - m_axis1vals = MantidVec(axis2(), axis2() + axis2.dim0()); - } - catch( std::runtime_error & ) - { - g_log.information() << "Axis 0 set to unitless quantity \"" << unit1 << "\"\n"; - } - - // Setting a unit onto a TextAxis makes no sense. - if ( unit2 == "TextAxis" ) - { - Mantid::API::TextAxis* newAxis = new Mantid::API::TextAxis(nspectra); - local_workspace->replaceAxis(1, newAxis); - } - else if ( unit2 != "spectraNumber" ) - { - try + // Setting a unit onto a TextAxis makes no sense. + if (unit2 == "TextAxis") { - auto* newAxis = (verticalHistogram) ? new API::BinEdgeAxis(nspectra+1) : new API::NumericAxis(nspectra); + Mantid::API::TextAxis* newAxis = new Mantid::API::TextAxis(nspectra); local_workspace->replaceAxis(1, newAxis); - newAxis->unit() = UnitFactory::Instance().create(unit2); - if(unit2 == "Label") + } + else if (unit2 != "spectraNumber") + { + try { - auto label = boost::dynamic_pointer_cast(newAxis->unit()); - auto ax = wksp_cls.openNXDouble("axis2"); - label->setLabel(ax.attributes("caption"), ax.attributes("label")); + auto* newAxis = + (verticalHistogram) ? new API::BinEdgeAxis(nspectra + 1) : new API::NumericAxis(nspectra); + local_workspace->replaceAxis(1, newAxis); + newAxis->unit() = UnitFactory::Instance().create(unit2); + if (unit2 == "Label") + { + auto label = boost::dynamic_pointer_cast(newAxis->unit()); + auto ax = wksp_cls.openNXDouble("axis2"); + label->setLabel(ax.attributes("caption"), ax.attributes("label")); + } + } catch (std::runtime_error &) + { + g_log.information() << "Axis 1 set to unitless quantity \"" << unit2 << "\"\n"; } } - catch( std::runtime_error & ) + + //Are we a distribution + std::string dist = xbins.attributes("distribution"); + if (dist == "1") { - g_log.information() << "Axis 1 set to unitless quantity \"" << unit2 << "\"\n"; + local_workspace->isDistribution(true); } - } - - - //Are we a distribution - std::string dist = xbins.attributes("distribution"); - if( dist == "1" ) - { - local_workspace->isDistribution(true); - } - else - { - local_workspace->isDistribution(false); - } - - //Get information from all but data group - std::string parameterStr; - - progress(progressStart+0.05*progressRange,"Reading the sample details..."); - - // Hop to the right point - m_cppFile->openPath(mtd_entry.path()); - try - { - // This loads logs, sample, and instrument. - local_workspace->loadExperimentInfoNexus(m_cppFile, parameterStr); - } - catch (std::exception & e) - { - g_log.information("Error loading Instrument section of nxs file"); - g_log.information(e.what()); - } - - // Now assign the spectra-detector map - readInstrumentGroup(mtd_entry, local_workspace); - - // Parameter map parsing - progress(progressStart+0.11*progressRange,"Reading the parameter maps..."); - local_workspace->readParameterMap(parameterStr); - - - if ( ! local_workspace->getAxis(1)->isSpectra() ) - { // If not a spectra axis, load the axis data into the workspace. (MW 25/11/10) - loadNonSpectraAxis(local_workspace, wksp_cls); - } - - progress(progressStart+0.15*progressRange,"Reading the workspace history..."); - m_cppFile->openPath(mtd_entry.path()); - try - { - bool load_history = getProperty("LoadHistory"); - if (load_history) local_workspace->history().loadNexus(m_cppFile); - } - catch (std::out_of_range&) - { - g_log.warning() << "Error in the workspaces algorithm list, its processing history is incomplete\n"; - } - - progress(progressStart+0.2*progressRange,"Reading the workspace history..."); - - return boost::static_pointer_cast(local_workspace); -} - -typedef boost::shared_array IntArray_shared; -struct SpectraInfo -{ - // Number of spectra - const int nSpectra; - // Do we have any spectra - const bool hasSpectra; - // Contains spectrum numbers for each workspace index - const IntArray_shared spectraNumbers; - // Index of the detector in the workspace. - const IntArray_shared detectorIndex; - // Number of detectors associated with each spectra - const IntArray_shared detectorCount; - // Detector list contains a list of all of the detector numbers - const IntArray_shared detectorList; - - SpectraInfo() : - nSpectra(0), hasSpectra(false) - { - } - - SpectraInfo(int _nSpectra, bool _hasSpectra, IntArray_shared _spectraNumbers - , IntArray_shared _detectorIndex - , IntArray_shared _detectorCount - , IntArray_shared _detectorList) - : - nSpectra(_nSpectra), hasSpectra(_hasSpectra), - spectraNumbers(_spectraNumbers), detectorIndex(_detectorIndex), - detectorCount(_detectorCount), detectorList(_detectorList) - { - } -}; - - -SpectraInfo doReadInstrumentGroup(NXEntry & mtd_entry, Logger& logger) -{ - //Instrument information - NXInstrument inst = mtd_entry.openNXInstrument("instrument"); - if ( ! inst.containsGroup("detector") ) + else { - logger.information() << "Detector block not found. The workspace will not contain any detector information.\n"; - return SpectraInfo(); + local_workspace->isDistribution(false); } - //Populate the spectra-detector map - NXDetector detgroup = inst.openNXDetector("detector"); + //Get information from all but data group + std::string parameterStr; + + progress(progressStart + 0.05 * progressRange, "Reading the sample details..."); - //Read necessary arrays from the file - // Detector list contains a list of all of the detector numbers. If it not present then we can't update the spectra - // map - boost::shared_array detectorList; + // Hop to the right point + m_cppFile->openPath(mtd_entry.path()); try { - NXInt detlist_group = detgroup.openNXInt("detector_list"); - detlist_group.load(); - detectorList = detlist_group.sharedBuffer(); - } - catch(std::runtime_error &) + // This loads logs, sample, and instrument. + local_workspace->loadExperimentInfoNexus(m_cppFile, parameterStr); + } catch (std::exception & e) { - logger.information() << "detector_list block not found. The workspace will not contain any detector information." - << std::endl; - return SpectraInfo(); + g_log.information("Error loading Instrument section of nxs file"); + g_log.information(e.what()); + } + + // Now assign the spectra-detector map + readInstrumentGroup(mtd_entry, local_workspace); + + // Parameter map parsing + progress(progressStart + 0.11 * progressRange, "Reading the parameter maps..."); + local_workspace->readParameterMap(parameterStr); + + if (!local_workspace->getAxis(1)->isSpectra()) + { // If not a spectra axis, load the axis data into the workspace. (MW 25/11/10) + loadNonSpectraAxis(local_workspace, wksp_cls); } - //Detector count contains the number of detectors associated with each spectra - NXInt det_count = detgroup.openNXInt("detector_count"); - det_count.load(); - boost::shared_array detectorCount = det_count.sharedBuffer(); - //Detector index - contains the index of the detector in the workspace - NXInt det_index = detgroup.openNXInt("detector_index"); - det_index.load(); - int nspectra = det_index.dim0(); - boost::shared_array detectorIndex = det_index.sharedBuffer(); - - //Spectra block - Contains spectrum numbers for each workspace index - // This might not exist so wrap and check. If it doesn't exist create a default mapping - bool have_spectra(true); - boost::shared_array spectra; + progress(progressStart + 0.15 * progressRange, "Reading the workspace history..."); + m_cppFile->openPath(mtd_entry.path()); try { - NXInt spectra_block = detgroup.openNXInt("spectra"); - spectra_block.load(); - spectra = spectra_block.sharedBuffer(); - } - catch(std::runtime_error &) + bool load_history = getProperty("LoadHistory"); + if (load_history) + local_workspace->history().loadNexus(m_cppFile); + } catch (std::out_of_range&) { - have_spectra = false; + g_log.warning() + << "Error in the workspaces algorithm list, its processing history is incomplete\n"; } - return SpectraInfo(nspectra, have_spectra, spectra, detectorIndex, detectorCount, detectorList); - -}; + progress(progressStart + 0.2 * progressRange, "Reading the workspace history..."); + return boost::static_pointer_cast(local_workspace); + } //------------------------------------------------------------------------------------------------- -/** - * Read the instrument group - * @param mtd_entry :: The node for the current workspace - * @param local_workspace :: The workspace to attach the instrument - */ -void LoadNexusProcessed::readInstrumentGroup(NXEntry & mtd_entry, API::MatrixWorkspace_sptr local_workspace) -{ - // Get spectrum information for the current entry. - SpectraInfo spectraInfo = doReadInstrumentGroup(mtd_entry, this->g_log); + /** + * Read the instrument group + * @param mtd_entry :: The node for the current workspace + * @param local_workspace :: The workspace to attach the instrument + */ + void LoadNexusProcessed::readInstrumentGroup(NXEntry & mtd_entry, + API::MatrixWorkspace_sptr local_workspace) + { + // Get spectrum information for the current entry. + SpectraInfo spectraInfo = extractMappingInfo(mtd_entry, this->g_log); - //Now build the spectra list - int index=0; + //Now build the spectra list + int index = 0; - for(int i = 1; i <= spectraInfo.nSpectra; ++i) - { + for (int i = 1; i <= spectraInfo.nSpectra; ++i) + { int spectrum(-1); - if( spectraInfo.hasSpectra ) + if (spectraInfo.hasSpectra) { - spectrum = spectraInfo.spectraNumbers[i-1]; + spectrum = spectraInfo.spectraNumbers[i - 1]; } else { - spectrum = i+1; + spectrum = i + 1; } - if ((i >= m_spec_min && i < m_spec_max )||(m_list && find(m_spec_list.begin(), m_spec_list.end(), - i) != m_spec_list.end())) + if ((i >= m_spec_min && i < m_spec_max) + || (m_list && find(m_spec_list.begin(), m_spec_list.end(), i) != m_spec_list.end())) { ISpectrum * spec = local_workspace->getSpectrum(index); - if( m_axis1vals.empty() ) + if (m_axis1vals.empty()) { spec->setSpectrumNo(spectrum); } else { - spec->setSpectrumNo(static_cast(m_axis1vals[i-1])); + spec->setSpectrumNo(static_cast(m_axis1vals[i - 1])); } ++index; - int start = spectraInfo.detectorIndex[i-1]; - int end = start + spectraInfo.detectorCount[i-1]; - spec->setDetectorIDs(std::set(spectraInfo.detectorList.get()+start,spectraInfo.detectorList.get()+end)); + int start = spectraInfo.detectorIndex[i - 1]; + int end = start + spectraInfo.detectorCount[i - 1]; + spec->setDetectorIDs( + std::set(spectraInfo.detectorList.get() + start, + spectraInfo.detectorList.get() + end)); } + } } -} - - //------------------------------------------------------------------------------------------------- -/** -* Loads the information contained in non-Spectra (ie, Text or Numeric) axis in the Nexus -* file into the workspace. -* @param local_workspace :: pointer to workspace object -* @param data :: reference to the NeXuS data for the axis -*/ -void LoadNexusProcessed::loadNonSpectraAxis(API::MatrixWorkspace_sptr local_workspace, NXData & data) -{ - Axis* axis = local_workspace->getAxis(1); - - if ( axis->isNumeric() ) + /** + * Loads the information contained in non-Spectra (ie, Text or Numeric) axis in the Nexus + * file into the workspace. + * @param local_workspace :: pointer to workspace object + * @param data :: reference to the NeXuS data for the axis + */ + void LoadNexusProcessed::loadNonSpectraAxis(API::MatrixWorkspace_sptr local_workspace, NXData & data) { - NXDouble axisData = data.openNXDouble("axis2"); - axisData.load(); - for ( int i = 0; i < static_cast(axis->length()); i++ ) + Axis* axis = local_workspace->getAxis(1); + + if (axis->isNumeric()) { - axis->setValue(i, axisData[i]); + NXDouble axisData = data.openNXDouble("axis2"); + axisData.load(); + for (int i = 0; i < static_cast(axis->length()); i++) + { + axis->setValue(i, axisData[i]); + } } - } - else if ( axis->isText() ) - { - NXChar axisData = data.openNXChar("axis2"); - axisData.load(); - std::string axisLabels = axisData(); - // Use boost::tokenizer to split up the input - boost::char_separator sep("\n"); - boost::tokenizer > tokenizer(axisLabels, sep); - // We must cast the axis object to TextAxis so we may use ->setLabel - TextAxis* textAxis = static_cast(axis); - int i = 0; - for ( auto tokIter = tokenizer.begin(); tokIter != tokenizer.end(); ++tokIter, ++i ) + else if (axis->isText()) { - textAxis->setLabel(i, *tokIter); + NXChar axisData = data.openNXChar("axis2"); + axisData.load(); + std::string axisLabels = axisData(); + // Use boost::tokenizer to split up the input + boost::char_separator sep("\n"); + boost::tokenizer > tokenizer(axisLabels, sep); + // We must cast the axis object to TextAxis so we may use ->setLabel + TextAxis* textAxis = static_cast(axis); + int i = 0; + for (auto tokIter = tokenizer.begin(); tokIter != tokenizer.end(); ++tokIter, ++i) + { + textAxis->setLabel(i, *tokIter); + } } } -} - - - -/** - * Binary predicate function object to sort the AlgorithmHistory vector by execution order - * @param elem1 :: first element in the vector - * @param elem2 :: second element in the vecor - */ -bool UDlesserExecCount(NXClassInfo elem1,NXClassInfo elem2) -{ - std::string::size_type index1, index2; - std::string num1,num2; - //find the number after "_" in algorithm name ( eg:MantidAlogorthm_1) - index1=elem1.nxname.find("_"); - if ( index1 != std::string::npos ) - { - num1=elem1.nxname.substr(index1+1,elem1.nxname.length()-index1); - } - index2=elem2.nxname.find("_"); - if ( index2 != std::string::npos ) + /** + * Binary predicate function object to sort the AlgorithmHistory vector by execution order + * @param elem1 :: first element in the vector + * @param elem2 :: second element in the vecor + */ + bool UDlesserExecCount(NXClassInfo elem1, NXClassInfo elem2) { - num2=elem2.nxname.substr(index2+1,elem2.nxname.length()-index2); - } - std::stringstream is1,is2; - is1<>execNum1; - is2>>execNum2; + int execNum1 = -1; + int execNum2 = -1; + is1 >> execNum1; + is2 >> execNum2; - if(execNum1flagMasked(si,bins[j],weights[j]); + int si = spec(i, 0); + int j0 = spec(i, 1); + int j1 = i < n1 ? spec(i + 1, 1) : bins.dim0(); + for (int j = j0; j < j1; ++j) + { + local_workspace->flagMasked(si, bins[j], weights[j]); + } } } -} - - - - - -/** - * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. This assumes that the - * xbins have alread been cached - * @param data :: The NXDataSet object of y values - * @param errors :: The NXDataSet object of error values - * @param farea :: The NXDataSet object of fraction area values - * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use - * @param blocksize :: The blocksize to use - * @param nchannels :: The number of channels for the block - * @param hist :: The workspace index to start reading into - * @param local_workspace :: A pointer to the workspace - */ -void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, - NXDataSetTyped & errors, - NXDataSetTyped & farea, - bool hasFArea, - int64_t blocksize, - int64_t nchannels, int64_t &hist, - API::MatrixWorkspace_sptr local_workspace) -{ - data.load(static_cast(blocksize),static_cast(hist)); - errors.load(static_cast(blocksize),static_cast(hist)); - double *data_start = data(); - double *data_end = data_start + nchannels; - double *err_start = errors(); - double *err_end = err_start + nchannels; - double *farea_start = NULL; - double *farea_end = NULL; - RebinnedOutput_sptr rb_workspace; - if (hasFArea) - { - farea.load(static_cast(blocksize),static_cast(hist)); - farea_start = farea(); - farea_end = farea_start + nchannels; - rb_workspace = boost::dynamic_pointer_cast(local_workspace); - } - int64_t final(hist + blocksize); - while( hist < final ) + /** + * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. This assumes that the + * xbins have alread been cached + * @param data :: The NXDataSet object of y values + * @param errors :: The NXDataSet object of error values + * @param farea :: The NXDataSet object of fraction area values + * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use + * @param blocksize :: The blocksize to use + * @param nchannels :: The number of channels for the block + * @param hist :: The workspace index to start reading into + * @param local_workspace :: A pointer to the workspace + */ + void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, NXDataSetTyped & errors, + NXDataSetTyped & farea, bool hasFArea, int64_t blocksize, int64_t nchannels, int64_t &hist, + API::MatrixWorkspace_sptr local_workspace) { - MantidVec& Y = local_workspace->dataY(hist); - Y.assign(data_start, data_end); - data_start += nchannels; data_end += nchannels; - MantidVec& E = local_workspace->dataE(hist); - E.assign(err_start, err_end); - err_start += nchannels; err_end += nchannels; + data.load(static_cast(blocksize), static_cast(hist)); + errors.load(static_cast(blocksize), static_cast(hist)); + double *data_start = data(); + double *data_end = data_start + nchannels; + double *err_start = errors(); + double *err_end = err_start + nchannels; + double *farea_start = NULL; + double *farea_end = NULL; + RebinnedOutput_sptr rb_workspace; if (hasFArea) { - MantidVec& F = rb_workspace->dataF(hist); - F.assign(farea_start, farea_end); - farea_start += nchannels; - farea_end += nchannels; + farea.load(static_cast(blocksize), static_cast(hist)); + farea_start = farea(); + farea_end = farea_start + nchannels; + rb_workspace = boost::dynamic_pointer_cast(local_workspace); + } + int64_t final(hist + blocksize); + while (hist < final) + { + MantidVec& Y = local_workspace->dataY(hist); + Y.assign(data_start, data_end); + data_start += nchannels; + data_end += nchannels; + MantidVec& E = local_workspace->dataE(hist); + E.assign(err_start, err_end); + err_start += nchannels; + err_end += nchannels; + if (hasFArea) + { + MantidVec& F = rb_workspace->dataF(hist); + F.assign(farea_start, farea_end); + farea_start += nchannels; + farea_end += nchannels; + } + local_workspace->setX(hist, m_xbins); + ++hist; } - local_workspace->setX(hist, m_xbins); - ++hist; - } -} - -/** - * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. This assumes that the - * xbins have alread been cached - * @param data :: The NXDataSet object of y values - * @param errors :: The NXDataSet object of error values - * @param farea :: The NXDataSet object of fraction area values - * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use - * @param blocksize :: The blocksize to use - * @param nchannels :: The number of channels for the block - * @param hist :: The workspace index to start reading into - * @param wsIndex :: The workspace index to save data into - * @param local_workspace :: A pointer to the workspace - */ - -void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, - NXDataSetTyped & errors, - NXDataSetTyped & farea, - bool hasFArea, - int64_t blocksize, int64_t nchannels, - int64_t &hist,int64_t& wsIndex, - API::MatrixWorkspace_sptr local_workspace) -{ - data.load(static_cast(blocksize),static_cast(hist)); - errors.load(static_cast(blocksize),static_cast(hist)); - double *data_start = data(); - double *data_end = data_start + nchannels; - double *err_start = errors(); - double *err_end = err_start + nchannels; - double *farea_start = NULL; - double *farea_end = NULL; - RebinnedOutput_sptr rb_workspace; - if (hasFArea) - { - farea.load(static_cast(blocksize),static_cast(hist)); - farea_start = farea(); - farea_end = farea_start + nchannels; - rb_workspace = boost::dynamic_pointer_cast(local_workspace); } - int64_t final(hist + blocksize); - while( hist < final ) + + /** + * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. This assumes that the + * xbins have alread been cached + * @param data :: The NXDataSet object of y values + * @param errors :: The NXDataSet object of error values + * @param farea :: The NXDataSet object of fraction area values + * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use + * @param blocksize :: The blocksize to use + * @param nchannels :: The number of channels for the block + * @param hist :: The workspace index to start reading into + * @param wsIndex :: The workspace index to save data into + * @param local_workspace :: A pointer to the workspace + */ + + void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, NXDataSetTyped & errors, + NXDataSetTyped & farea, bool hasFArea, int64_t blocksize, int64_t nchannels, int64_t &hist, + int64_t& wsIndex, API::MatrixWorkspace_sptr local_workspace) { - MantidVec& Y = local_workspace->dataY(wsIndex); - Y.assign(data_start, data_end); - data_start += nchannels; data_end += nchannels; - MantidVec& E = local_workspace->dataE(wsIndex); - E.assign(err_start, err_end); - err_start += nchannels; err_end += nchannels; + data.load(static_cast(blocksize), static_cast(hist)); + errors.load(static_cast(blocksize), static_cast(hist)); + double *data_start = data(); + double *data_end = data_start + nchannels; + double *err_start = errors(); + double *err_end = err_start + nchannels; + double *farea_start = NULL; + double *farea_end = NULL; + RebinnedOutput_sptr rb_workspace; if (hasFArea) { - MantidVec& F = rb_workspace->dataF(wsIndex); - F.assign(farea_start, farea_end); - farea_start += nchannels; - farea_end += nchannels; + farea.load(static_cast(blocksize), static_cast(hist)); + farea_start = farea(); + farea_end = farea_start + nchannels; + rb_workspace = boost::dynamic_pointer_cast(local_workspace); } - local_workspace->setX(wsIndex, m_xbins); - ++hist; - ++wsIndex; + int64_t final(hist + blocksize); + while (hist < final) + { + MantidVec& Y = local_workspace->dataY(wsIndex); + Y.assign(data_start, data_end); + data_start += nchannels; + data_end += nchannels; + MantidVec& E = local_workspace->dataE(wsIndex); + E.assign(err_start, err_end); + err_start += nchannels; + err_end += nchannels; + if (hasFArea) + { + MantidVec& F = rb_workspace->dataF(wsIndex); + F.assign(farea_start, farea_end); + farea_start += nchannels; + farea_end += nchannels; + } + local_workspace->setX(wsIndex, m_xbins); + ++hist; + ++wsIndex; + } } -} - -/** - * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. The xbins are read along with - * each call to the data/error loading - * @param data :: The NXDataSet object of y values - * @param errors :: The NXDataSet object of error values - * @param farea :: The NXDataSet object of fraction area values - * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use - * @param xbins :: The xbin NXDataSet - * @param blocksize :: The blocksize to use - * @param nchannels :: The number of channels for the block - * @param hist :: The workspace index to start reading into - * @param wsIndex :: The workspace index to save data into - * @param local_workspace :: A pointer to the workspace - */ -void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, - NXDataSetTyped & errors, - NXDataSetTyped & farea, - bool hasFArea, - NXDouble & xbins, - int64_t blocksize, int64_t nchannels, - int64_t &hist, int64_t& wsIndex, - API::MatrixWorkspace_sptr local_workspace) -{ - data.load(static_cast(blocksize),static_cast(hist)); - double *data_start = data(); - double *data_end = data_start + nchannels; - errors.load(static_cast(blocksize),static_cast(hist)); - double *err_start = errors(); - double *err_end = err_start + nchannels; - double *farea_start = NULL; - double *farea_end = NULL; - RebinnedOutput_sptr rb_workspace; - if (hasFArea) - { - farea.load(static_cast(blocksize),static_cast(hist)); - farea_start = farea(); - farea_end = farea_start + nchannels; - rb_workspace = boost::dynamic_pointer_cast(local_workspace); - } - xbins.load(static_cast(blocksize),static_cast(hist)); - const int64_t nxbins(nchannels + 1); - double *xbin_start = xbins(); - double *xbin_end = xbin_start + nxbins; - int64_t final(hist + blocksize); - while( hist < final ) + + /** + * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. The xbins are read along with + * each call to the data/error loading + * @param data :: The NXDataSet object of y values + * @param errors :: The NXDataSet object of error values + * @param farea :: The NXDataSet object of fraction area values + * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use + * @param xbins :: The xbin NXDataSet + * @param blocksize :: The blocksize to use + * @param nchannels :: The number of channels for the block + * @param hist :: The workspace index to start reading into + * @param wsIndex :: The workspace index to save data into + * @param local_workspace :: A pointer to the workspace + */ + void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, NXDataSetTyped & errors, + NXDataSetTyped & farea, bool hasFArea, NXDouble & xbins, int64_t blocksize, + int64_t nchannels, int64_t &hist, int64_t& wsIndex, API::MatrixWorkspace_sptr local_workspace) { - MantidVec& Y = local_workspace->dataY(wsIndex); - Y.assign(data_start, data_end); - data_start += nchannels; data_end += nchannels; - MantidVec& E = local_workspace->dataE(wsIndex); - E.assign(err_start, err_end); - err_start += nchannels; err_end += nchannels; + data.load(static_cast(blocksize), static_cast(hist)); + double *data_start = data(); + double *data_end = data_start + nchannels; + errors.load(static_cast(blocksize), static_cast(hist)); + double *err_start = errors(); + double *err_end = err_start + nchannels; + double *farea_start = NULL; + double *farea_end = NULL; + RebinnedOutput_sptr rb_workspace; if (hasFArea) { - MantidVec& F = rb_workspace->dataF(wsIndex); - F.assign(farea_start, farea_end); - farea_start += nchannels; - farea_end += nchannels; + farea.load(static_cast(blocksize), static_cast(hist)); + farea_start = farea(); + farea_end = farea_start + nchannels; + rb_workspace = boost::dynamic_pointer_cast(local_workspace); } - MantidVec& X = local_workspace->dataX(wsIndex); - X.assign(xbin_start, xbin_end); - xbin_start += nxbins; xbin_end += nxbins; - ++hist; - ++wsIndex; - } -} - - -/** - *Validates the optional 'spectra to read' properties, if they have been set - * @param numberofspectra :: number of spectrum - */ -void LoadNexusProcessed::checkOptionalProperties(const std::size_t numberofspectra ) -{ - //read in the settings passed to the algorithm - m_spec_list = getProperty("SpectrumList"); - m_spec_max = getProperty("SpectrumMax"); - m_spec_min = getProperty("SpectrumMin"); - //Are we using a list of spectra or all the spectra in a range? - m_list = !m_spec_list.empty(); - m_interval = (m_spec_max != Mantid::EMPTY_INT()) || (m_spec_min != 1); - if ( m_spec_max == Mantid::EMPTY_INT() ) m_spec_max = 1; - - // Check validity of spectra list property, if set - if (m_list) - { - m_list = true; - const int64_t minlist = *min_element(m_spec_list.begin(), m_spec_list.end()); - const int64_t maxlist = *max_element(m_spec_list.begin(), m_spec_list.end()); - if (maxlist > static_cast(numberofspectra) || minlist == 0) + xbins.load(static_cast(blocksize), static_cast(hist)); + const int64_t nxbins(nchannels + 1); + double *xbin_start = xbins(); + double *xbin_end = xbin_start + nxbins; + int64_t final(hist + blocksize); + while (hist < final) { - g_log.error("Invalid list of spectra"); - throw std::invalid_argument("Inconsistent properties defined"); + MantidVec& Y = local_workspace->dataY(wsIndex); + Y.assign(data_start, data_end); + data_start += nchannels; + data_end += nchannels; + MantidVec& E = local_workspace->dataE(wsIndex); + E.assign(err_start, err_end); + err_start += nchannels; + err_end += nchannels; + if (hasFArea) + { + MantidVec& F = rb_workspace->dataF(wsIndex); + F.assign(farea_start, farea_end); + farea_start += nchannels; + farea_end += nchannels; + } + MantidVec& X = local_workspace->dataX(wsIndex); + X.assign(xbin_start, xbin_end); + xbin_start += nxbins; + xbin_end += nxbins; + ++hist; + ++wsIndex; } } - // Check validity of spectra range, if set - if (m_interval) + /** + *Validates the optional 'spectra to read' properties, if they have been set + * @param numberofspectra :: number of spectrum + */ + void LoadNexusProcessed::checkOptionalProperties(const std::size_t numberofspectra) { - m_interval = true; + //read in the settings passed to the algorithm + m_spec_list = getProperty("SpectrumList"); + m_spec_max = getProperty("SpectrumMax"); m_spec_min = getProperty("SpectrumMin"); - if (m_spec_min != 1 && m_spec_max == 1) - { - m_spec_max = numberofspectra; - } - if (m_spec_max < m_spec_min || m_spec_max > static_cast(numberofspectra)) + //Are we using a list of spectra or all the spectra in a range? + m_list = !m_spec_list.empty(); + m_interval = (m_spec_max != Mantid::EMPTY_INT()) || (m_spec_min != 1); + if (m_spec_max == Mantid::EMPTY_INT()) + m_spec_max = 1; + + // Check validity of spectra list property, if set + if (m_list) { - g_log.error("Invalid Spectrum min/max properties"); - throw std::invalid_argument("Inconsistent properties defined"); + m_list = true; + const int64_t minlist = *min_element(m_spec_list.begin(), m_spec_list.end()); + const int64_t maxlist = *max_element(m_spec_list.begin(), m_spec_list.end()); + if (maxlist > static_cast(numberofspectra) || minlist == 0) + { + g_log.error("Invalid list of spectra"); + throw std::invalid_argument("Inconsistent properties defined"); + } } - } -} - -/** - * Calculate the size of a workspace - * @param numberofspectra :: number of spectrums - * @return the size of a workspace - */ -size_t LoadNexusProcessed::calculateWorkspacesize(const std::size_t numberofspectra) -{ - // Calculate the size of a workspace, given its number of spectra to read - int total_specs; - if( m_interval || m_list) - { + + // Check validity of spectra range, if set if (m_interval) { + m_interval = true; + m_spec_min = getProperty("SpectrumMin"); if (m_spec_min != 1 && m_spec_max == 1) { m_spec_max = numberofspectra; } - total_specs = static_cast(m_spec_max-m_spec_min+1); - m_spec_max += 1; + if (m_spec_max < m_spec_min || m_spec_max > static_cast(numberofspectra)) + { + g_log.error("Invalid Spectrum min/max properties"); + throw std::invalid_argument("Inconsistent properties defined"); + } } - else - total_specs = 0; + } - if (m_list) + /** + * Calculate the size of a workspace + * @param numberofspectra :: number of spectrums + * @return the size of a workspace + */ + size_t LoadNexusProcessed::calculateWorkspacesize(const std::size_t numberofspectra) + { + // Calculate the size of a workspace, given its number of spectra to read + int total_specs; + if (m_interval || m_list) { if (m_interval) { - for(std::vector::iterator it=m_spec_list.begin();it!=m_spec_list.end();) - if (*it >= m_spec_min && *it (m_spec_max - m_spec_min + 1); + m_spec_max += 1; + } + else + total_specs = 0; + + if (m_list) + { + if (m_interval) + { + for (std::vector::iterator it = m_spec_list.begin(); it != m_spec_list.end();) + if (*it >= m_spec_min && *it < m_spec_max) + { + it = m_spec_list.erase(it); + } + else + ++it; + } + if (m_spec_list.size() == 0) + m_list = false; + total_specs += static_cast(m_spec_list.size()); } - if (m_spec_list.size() == 0) m_list = false; - total_specs += static_cast(m_spec_list.size()); } + else + { + total_specs = static_cast(numberofspectra); + m_spec_min = 1; + m_spec_max = static_cast(numberofspectra) + 1; + } + return total_specs; } - else - { - total_specs = static_cast(numberofspectra); - m_spec_min = 1; - m_spec_max = static_cast(numberofspectra) +1; - } - return total_specs; -} } // namespace DataHandling } // namespace Mantid From d0ba5d5f93dfb7b1c20474eece8952f88099963b Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Thu, 23 Oct 2014 13:06:42 +0100 Subject: [PATCH 010/128] refs #10385. Query default property. --- .../DataHandling/src/LoadNexusProcessed.cpp | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 4a989069f719..4045473802c6 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -71,7 +71,8 @@ namespace Mantid } SpectraInfo(int _nSpectra, bool _hasSpectra, IntArray_shared _spectraNumbers, - IntArray_shared _detectorIndex, IntArray_shared _detectorCount, IntArray_shared _detectorList) : + IntArray_shared _detectorIndex, IntArray_shared _detectorCount, + IntArray_shared _detectorList) : nSpectra(_nSpectra), hasSpectra(_hasSpectra), spectraNumbers(_spectraNumbers), detectorIndex( _detectorIndex), detectorCount(_detectorCount), detectorList(_detectorList) { @@ -220,8 +221,10 @@ namespace Mantid // Check for an entry number property int64_t entrynumber = static_cast(getProperty("EntryNumber")); + Property const * const entryNumberProperty = this->getProperty("EntryNumber"); + bool bDefaultEntryNumber = entryNumberProperty->isDefault(); - if (entrynumber > 0 && entrynumber > nWorkspaceEntries) + if (!bDefaultEntryNumber && entrynumber > nWorkspaceEntries) { g_log.error() << "Invalid entry number specified. File only contains " << nWorkspaceEntries << " entries.\n"; @@ -229,13 +232,18 @@ namespace Mantid } const std::string basename = "mantid_workspace_"; - if (nWorkspaceEntries == 1 || entrynumber > 0) + + std::ostringstream os; + if (bDefaultEntryNumber) + { + ++entrynumber; + } + os << basename << entrynumber; + const std::string targetEntryName = os.str(); + if (nWorkspaceEntries == 1 || !bDefaultEntryNumber) { // Load one first level entry, specified if there are several - if (entrynumber == 0) - ++entrynumber; - std::ostringstream os; - os << entrynumber; - API::Workspace_sptr workspace = loadEntry(root, basename + os.str(), 0, 1); + + API::Workspace_sptr workspace = loadEntry(root, targetEntryName, 0, 1); //API::Workspace_sptr workspace = boost::static_pointer_cast(local_workspace); setProperty("OutputWorkspace", workspace); } From 8a0c59958fdc0b0f05ecfb616f273b34c6764aa9 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Thu, 23 Oct 2014 13:35:25 +0100 Subject: [PATCH 011/128] refs #10385. Multiperiod query. --- .../DataHandling/src/LoadNexusProcessed.cpp | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 4045473802c6..b9e133092f57 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -144,6 +144,33 @@ namespace Mantid return SpectraInfo(nspectra, have_spectra, spectra, detectorIndex, detectorCount, detectorList); } + + /** + * Is this file from a well-formed multiperiod group workspace. + * @param nWorkspaceEntries : Number of entries in the group workspace + * @param sampleWS : Sample workspace to inspect the logs of + * @param log : Information logger object + * @return True only if multiperiod. + */ + bool isMultiPeriodFile(int nWorkspaceEntries, Workspace_sptr sampleWS, Logger& log) + { + bool isMultiPeriod = false; + if (ExperimentInfo_sptr expInfo = boost::dynamic_pointer_cast(sampleWS)) + { + const std::string nPeriodsLogEntryName = "nperiods"; + const Run& run = expInfo->run(); + if (run.hasProperty(nPeriodsLogEntryName)) + { + const int nPeriods = run.getPropertyValueAsType(nPeriodsLogEntryName); + if (nPeriods == nWorkspaceEntries) + { + isMultiPeriod = true; + log.information("Loading as MultiPeriod group workspace."); + } + } + } + return isMultiPeriod; + } } /// Default constructor @@ -236,19 +263,26 @@ namespace Mantid std::ostringstream os; if (bDefaultEntryNumber) { - ++entrynumber; + // Set the entry number to 1 if not provided. + entrynumber = 1; } os << basename << entrynumber; const std::string targetEntryName = os.str(); - if (nWorkspaceEntries == 1 || !bDefaultEntryNumber) - { // Load one first level entry, specified if there are several - API::Workspace_sptr workspace = loadEntry(root, targetEntryName, 0, 1); - //API::Workspace_sptr workspace = boost::static_pointer_cast(local_workspace); - setProperty("OutputWorkspace", workspace); + // Take the first real workspace obtainable. We need it even if loading groups. + API::Workspace_sptr tempWS = loadEntry(root, targetEntryName, 0, 1); + + if (nWorkspaceEntries == 1 || !bDefaultEntryNumber) + { + // We have what we need. + setProperty("OutputWorkspace", tempWS); } else - { // Load all first level entries + { + // We already know that this is a group workspace. Is it a true multiperiod workspace. + const bool bIsMultiPeriod = isMultiPeriodFile(nWorkspaceEntries, tempWS, g_log); + + // Load all first level entries WorkspaceGroup_sptr wksp_group(new WorkspaceGroup); //This forms the name of the group std::string base_name = getPropertyValue("OutputWorkspace"); From 61959e5705be8423f54eb8a77034d8e739880dfb Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Thu, 23 Oct 2014 15:39:16 +0100 Subject: [PATCH 012/128] refs #10385. Reuse the SpecInfo on multiperiod groups. --- .../MantidDataHandling/LoadNexusProcessed.h | 63 +++++++++++++++++- .../DataHandling/src/LoadNexusProcessed.cpp | 65 +++++++------------ 2 files changed, 85 insertions(+), 43 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h index bf994856b7ba..b5c5e5ebd9fa 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h @@ -9,12 +9,70 @@ #include "MantidNexus/NexusClasses.h" #include +#include +#include namespace Mantid { namespace DataHandling { + + // Helper typedef + typedef boost::shared_array IntArray_shared; + + // Struct to contain spectrum information. + struct SpectraInfo + { + // Number of spectra + int nSpectra; + // Do we have any spectra + bool hasSpectra; + // Contains spectrum numbers for each workspace index + IntArray_shared spectraNumbers; + // Index of the detector in the workspace. + IntArray_shared detectorIndex; + // Number of detectors associated with each spectra + IntArray_shared detectorCount; + // Detector list contains a list of all of the detector numbers + IntArray_shared detectorList; + + SpectraInfo() : + nSpectra(0), hasSpectra(false) + { + } + + SpectraInfo(int _nSpectra, bool _hasSpectra, IntArray_shared _spectraNumbers, + IntArray_shared _detectorIndex, IntArray_shared _detectorCount, + IntArray_shared _detectorList) : + nSpectra(_nSpectra), hasSpectra(_hasSpectra), spectraNumbers(_spectraNumbers), detectorIndex( + _detectorIndex), detectorCount(_detectorCount), detectorList(_detectorList) + { + } + + SpectraInfo(const SpectraInfo& other) : nSpectra(other.nSpectra), hasSpectra(other.hasSpectra), spectraNumbers(other.spectraNumbers), detectorIndex( + other.detectorIndex), detectorCount(other.detectorCount), detectorList(other.detectorList) + { + } + + SpectraInfo& operator=(const SpectraInfo& other) + { + if (&other != this) + { + nSpectra = other.nSpectra; + hasSpectra = other.hasSpectra; + spectraNumbers = other.spectraNumbers; + detectorIndex = other.detectorIndex; + detectorCount = other.detectorCount; + detectorList = other.detectorList; + } + return *this; + } + }; + + // Helper typdef. + typedef boost::optional SpectraInfo_optional; + /** Loads a workspace from a NeXus Processed entry in a NeXus file. @@ -91,7 +149,8 @@ namespace Mantid /// Load a single entry API::Workspace_sptr loadEntry(Mantid::NeXus::NXRoot & root, const std::string & entry_name, - const double& progressStart, const double& progressRange); + const double& progressStart, const double& progressRange + , SpectraInfo_optional& specInfo, bool ignoreSpecInfo); API::Workspace_sptr loadTableEntry(Mantid::NeXus::NXEntry& entry); @@ -112,7 +171,7 @@ namespace Mantid /// Add a property to the sample object bool addSampleProperty(Mantid::NeXus::NXMainClass & sample_entry, const std::string & entryName, API::Sample& sampleDetails); /// Read the spectra - void readInstrumentGroup(Mantid::NeXus::NXEntry & mtd_entry, API::MatrixWorkspace_sptr local_workspace); + void readInstrumentGroup(Mantid::NeXus::NXEntry & mtd_entry, API::MatrixWorkspace_sptr local_workspace, SpectraInfo_optional& specInfo, bool ignoreSpecInfo); /// Splits a string of exactly three words into the separate words void getWordsInString(const std::string & words3, std::string & w1, std::string & w2, std::string & w3); /// Splits a string of exactly four words into the separate words diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index b9e133092f57..039ae19c9c9c 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -46,40 +45,6 @@ namespace Mantid namespace { - // Helper typedef - typedef boost::shared_array IntArray_shared; - - // Struct to contain spectrum information. - struct SpectraInfo - { - // Number of spectra - const int nSpectra; - // Do we have any spectra - const bool hasSpectra; - // Contains spectrum numbers for each workspace index - const IntArray_shared spectraNumbers; - // Index of the detector in the workspace. - const IntArray_shared detectorIndex; - // Number of detectors associated with each spectra - const IntArray_shared detectorCount; - // Detector list contains a list of all of the detector numbers - const IntArray_shared detectorList; - - SpectraInfo() : - nSpectra(0), hasSpectra(false) - { - } - - SpectraInfo(int _nSpectra, bool _hasSpectra, IntArray_shared _spectraNumbers, - IntArray_shared _detectorIndex, IntArray_shared _detectorCount, - IntArray_shared _detectorList) : - nSpectra(_nSpectra), hasSpectra(_hasSpectra), spectraNumbers(_spectraNumbers), detectorIndex( - _detectorIndex), detectorCount(_detectorCount), detectorList(_detectorList) - { - } - }; - // Helper typdef. - typedef boost::optional SpectraInfo_optional; /** * Extract ALL the detector, spectrum number and workspace index mapping information. @@ -270,7 +235,9 @@ namespace Mantid const std::string targetEntryName = os.str(); // Take the first real workspace obtainable. We need it even if loading groups. - API::Workspace_sptr tempWS = loadEntry(root, targetEntryName, 0, 1); + SpectraInfo_optional spectraInfo; + API::Workspace_sptr tempWS = loadEntry(root, targetEntryName, 0, 1, spectraInfo /*Ignore to begin with*/ + , false /*Do not Ignore spectrum/instrument information inputs, write them*/); if (nWorkspaceEntries == 1 || !bDefaultEntryNumber) { @@ -281,6 +248,7 @@ namespace Mantid { // We already know that this is a group workspace. Is it a true multiperiod workspace. const bool bIsMultiPeriod = isMultiPeriodFile(nWorkspaceEntries, tempWS, g_log); + const bool ignoreSpecInfo = !bIsMultiPeriod; // Multiperiod groups can reuse it. // Load all first level entries WorkspaceGroup_sptr wksp_group(new WorkspaceGroup); @@ -315,7 +283,8 @@ namespace Mantid std::string wsName = buildWorkspaceName(names[p], base_name, p, commonStem); Workspace_sptr local_workspace = loadEntry(root, basename + os.str(), - static_cast(p - 1) / nWorkspaceEntries_d, 1. / nWorkspaceEntries_d); + static_cast(p - 1) / nWorkspaceEntries_d, 1. / nWorkspaceEntries_d, spectraInfo, ignoreSpecInfo); + declareProperty( new WorkspaceProperty(prop_name + os.str(), wsName, Direction::Output)); //wksp_group->add(base_name + os.str()); @@ -962,10 +931,12 @@ namespace Mantid * @param entry_name :: The entry name * @param progressStart :: The percentage value to start the progress reporting for this entry * @param progressRange :: The percentage range that the progress reporting should cover + * @param specInfo :: Spectrum information object + * @param ignoreSpecInfo :: true to skip reading and wrting to optional specInfo * @returns A 2D workspace containing the loaded data */ API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot & root, const std::string & entry_name, - const double& progressStart, const double& progressRange) + const double& progressStart, const double& progressRange, SpectraInfo_optional& specInfo, bool ignoreSpecInfo) { progress(progressStart, "Opening entry " + entry_name + "..."); @@ -1316,7 +1287,7 @@ namespace Mantid } // Now assign the spectra-detector map - readInstrumentGroup(mtd_entry, local_workspace); + readInstrumentGroup(mtd_entry, local_workspace, specInfo, ignoreSpecInfo); // Parameter map parsing progress(progressStart + 0.11 * progressRange, "Reading the parameter maps..."); @@ -1350,12 +1321,18 @@ namespace Mantid * Read the instrument group * @param mtd_entry :: The node for the current workspace * @param local_workspace :: The workspace to attach the instrument + * @param inOutSpecInfo :: Spectrum information + * @param ignoreSpecInfo :: If True ignore input spectrum info and obtain it yourself. */ void LoadNexusProcessed::readInstrumentGroup(NXEntry & mtd_entry, - API::MatrixWorkspace_sptr local_workspace) + API::MatrixWorkspace_sptr local_workspace, SpectraInfo_optional& inOutSpecInfo, bool ignoreSpecInfo) { // Get spectrum information for the current entry. - SpectraInfo spectraInfo = extractMappingInfo(mtd_entry, this->g_log); + + + const bool bUseExistingInfo = inOutSpecInfo.is_initialized() && !ignoreSpecInfo; + + SpectraInfo spectraInfo = bUseExistingInfo ? inOutSpecInfo.get() : extractMappingInfo(mtd_entry, this->g_log); //Now build the spectra list int index = 0; @@ -1393,6 +1370,12 @@ namespace Mantid spectraInfo.detectorList.get() + end)); } } + + // We can write the spec info under the following conditions. + if(!inOutSpecInfo.is_initialized() && !ignoreSpecInfo) + { + inOutSpecInfo = spectraInfo; + } } //------------------------------------------------------------------------------------------------- From 9a677316ce4294e96ec8a2c793c9d9090dd13be8 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Wed, 29 Oct 2014 11:20:01 +0000 Subject: [PATCH 013/128] refs #10385. Try to use clone and write technique. --- .../DataHandling/src/LoadNexusProcessed.cpp | 2136 +++++++++-------- 1 file changed, 1115 insertions(+), 1021 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 039ae19c9c9c..000e1beb26bb 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -237,7 +237,7 @@ namespace Mantid // Take the first real workspace obtainable. We need it even if loading groups. SpectraInfo_optional spectraInfo; API::Workspace_sptr tempWS = loadEntry(root, targetEntryName, 0, 1, spectraInfo /*Ignore to begin with*/ - , false /*Do not Ignore spectrum/instrument information inputs, write them*/); + , false /*Do not Ignore spectrum/instrument information inputs, write them*/); if (nWorkspaceEntries == 1 || !bDefaultEntryNumber) { @@ -282,8 +282,95 @@ namespace Mantid //decide what the workspace should be called std::string wsName = buildWorkspaceName(names[p], base_name, p, commonStem); - Workspace_sptr local_workspace = loadEntry(root, basename + os.str(), - static_cast(p - 1) / nWorkspaceEntries_d, 1. / nWorkspaceEntries_d, spectraInfo, ignoreSpecInfo); + Workspace_sptr local_workspace; + if (!bIsMultiPeriod) + { + local_workspace = loadEntry(root, basename + os.str(), + static_cast(p - 1) / nWorkspaceEntries_d, 1. / nWorkspaceEntries_d, spectraInfo, + ignoreSpecInfo); + } + else + { + g_log.warning("Reading AS MULTIPERIOD"); + // Clone the original workspace + auto cloneAlg = this->createChildAlgorithm("CloneWorkspace"); + cloneAlg->setProperty("InputWorkspace", tempWS); + cloneAlg->execute(); + local_workspace = cloneAlg->getProperty("OutputWorkspace"); + MatrixWorkspace_sptr local_workspace_2d = boost::dynamic_pointer_cast( + local_workspace); + // Now overwrite the y, e and log values. + + NXEntry mtdEntry = root.openEntry(basename + os.str()); + NXData wsEntry = mtdEntry.openNXData("workspace"); // TODO. hardcoded group_name is HACK + + NXDataSetTyped data = wsEntry.openDoubleData(); + NXDataSetTyped errors = wsEntry.openNXDouble("errors"); + + const int nSpectra = data.dim0(); + const int nChannels = data.dim1(); + + //// validate the optional spectrum parameters, if set + checkOptionalProperties(nSpectra); + // Actual number of spectra in output workspace (if only a range was going to be loaded) + const size_t nHistograms = calculateWorkspacesize(nSpectra); + + int64_t blockSize = 8; // Read block size. Set to 8 for efficiency. i.e. read 8 histograms at a time. + const int64_t nFullBlocks = nHistograms / blockSize; // Truncated number of full blocks to read. Remainder removed + const int64_t nRemainder = nHistograms % blockSize; // Remainder + const int64_t readOptimumStop = (nFullBlocks * blockSize); + const int64_t readStop = m_spec_max - 1; // HACK + const int64_t finalBlockSize = readStop - readOptimumStop; + + int64_t wsIndex = 0; + int64_t histIndex = 0; // HACK. This needs to be calculated. + + for (; histIndex < readStop;) + { + if(histIndex >= readOptimumStop) + { + blockSize = finalBlockSize; + } + + data.load(static_cast(blockSize), static_cast(histIndex)); + errors.load(static_cast(blockSize), static_cast(histIndex)); + + double *dataStart = data(); + double *dataEnd = dataStart + nChannels; + + double *errorStart = errors(); + double *errorEnd = errorStart + nChannels; + + int64_t final(histIndex + blockSize); + while (histIndex < final) + { + MantidVec& Y = local_workspace_2d->dataY(wsIndex); + Y.assign(dataStart, dataEnd); + dataStart += nChannels; + dataEnd += nChannels; + MantidVec& E = local_workspace_2d->dataE(wsIndex); + E.assign(errorStart, errorEnd); + errorStart += nChannels; + errorEnd += nChannels; + + ++wsIndex; + ++histIndex; + } + } + + // TODO deal with this not being a workspace2D + + // TODO deal with fractional area. + + // TODO need to do the same as above, but to handle the remainder, so do same as above, but with blockSize = finalBlocSize; + + // TODO need to copy log values + + // TODO need to guarantee m_shared_bins, or do we just assume this? + + // TODO need to handle spectrum intervals correctly. + + } declareProperty( new WorkspaceProperty(prop_name + os.str(), wsName, Direction::Output)); @@ -511,580 +598,621 @@ namespace Mantid for (int wi = 0; wi < numspec; wi++) { PARALLEL_START_INTERUPT_REGION - int64_t index_start = indices[wi]; - int64_t index_end = indices[wi + 1]; - if (index_end >= index_start) - { - EventList & el = ws->getEventList(wi); - el.switchTo(type); +int64_t index_start = indices[wi]; + int64_t index_end = indices[wi + 1]; + if (index_end >= index_start) + { + EventList & el = ws->getEventList(wi); + el.switchTo(type); - // Allocate all the required memory - el.reserve(index_end - index_start); - el.clearDetectorIDs(); + // Allocate all the required memory + el.reserve(index_end - index_start); + el.clearDetectorIDs(); - for (int64_t i = index_start; i < index_end; i++) + for (int64_t i = index_start; i < index_end; i++) switch (type) { - case TOF: + case TOF: el.addEventQuickly(TofEvent(tofs[i], DateAndTime(pulsetimes[i]))); break; - case WEIGHTED: + case WEIGHTED: el.addEventQuickly( WeightedEvent(tofs[i], DateAndTime(pulsetimes[i]), weights[i], error_squareds[i])); break; - case WEIGHTED_NOTIME: + case WEIGHTED_NOTIME: el.addEventQuickly(WeightedEventNoTime(tofs[i], weights[i], error_squareds[i])); break; } - // Set the X axis - if (this->m_shared_bins) + // Set the X axis + if (this->m_shared_bins) el.setX(this->m_xbins); - else - { - MantidVec x; - x.resize(xbins.dim0()); - for (int i = 0; i < xbins.dim0(); i++) + else + { + MantidVec x; + x.resize(xbins.dim0()); + for (int i = 0; i < xbins.dim0(); i++) x[i] = xbins(wi, i); - el.setX(x); + el.setX(x); + } } + + progress(progressStart + progressRange * (1.0 / numspec)); + PARALLEL_END_INTERUPT_REGION } + PARALLEL_CHECK_INTERUPT_REGION - progress(progressStart + progressRange * (1.0 / numspec)); - PARALLEL_END_INTERUPT_REGION + return ws; } - PARALLEL_CHECK_INTERUPT_REGION - - return ws; - } //------------------------------------------------------------------------------------------------- - /** - * Load a table - */ - API::Workspace_sptr LoadNexusProcessed::loadTableEntry(NXEntry & entry) - { - API::ITableWorkspace_sptr workspace; - workspace = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace"); - - NXData nx_tw = entry.openNXData("table_workspace"); + /** + * Load a table + */ + API::Workspace_sptr LoadNexusProcessed::loadTableEntry(NXEntry & entry) + { + API::ITableWorkspace_sptr workspace; + workspace = Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace"); - bool hasNumberOfRowBeenSet = false; - //int numberOfRows = 0; + NXData nx_tw = entry.openNXData("table_workspace"); - int columnNumber = 1; - do - { - std::string str = "column_" + boost::lexical_cast(columnNumber); + bool hasNumberOfRowBeenSet = false; + //int numberOfRows = 0; - NXInfo info = nx_tw.getDataSetInfo(str.c_str()); - if (info.stat == NX_ERROR) + int columnNumber = 1; + do { - // Assume we done last column of table - break; - } + std::string str = "column_" + boost::lexical_cast(columnNumber); - if (info.rank == 1) - { - if (info.type == NX_FLOAT64) + NXInfo info = nx_tw.getDataSetInfo(str.c_str()); + if (info.stat == NX_ERROR) { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - std::string columnTitle = nxDouble.attributes("name"); - if (!columnTitle.empty()) + // Assume we done last column of table + break; + } + + if (info.rank == 1) + { + if (info.type == NX_FLOAT64) { - workspace->addColumn("double", columnTitle); - nxDouble.load(); - int length = nxDouble.dim0(); - if (!hasNumberOfRowBeenSet) + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + std::string columnTitle = nxDouble.attributes("name"); + if (!columnTitle.empty()) { - workspace->setRowCount(length); - hasNumberOfRowBeenSet = true; + workspace->addColumn("double", columnTitle); + nxDouble.load(); + int length = nxDouble.dim0(); + if (!hasNumberOfRowBeenSet) + { + workspace->setRowCount(length); + hasNumberOfRowBeenSet = true; + } + for (int i = 0; i < length; i++) + workspace->cell(i, columnNumber - 1) = *(nxDouble() + i); } - for (int i = 0; i < length; i++) - workspace->cell(i, columnNumber - 1) = *(nxDouble() + i); } - } - else if (info.type == NX_INT32) - { - NXInt nxInt = nx_tw.openNXInt(str.c_str()); - std::string columnTitle = nxInt.attributes("name"); - if (!columnTitle.empty()) + else if (info.type == NX_INT32) { - workspace->addColumn("int", columnTitle); - nxInt.load(); - int length = nxInt.dim0(); - if (!hasNumberOfRowBeenSet) + NXInt nxInt = nx_tw.openNXInt(str.c_str()); + std::string columnTitle = nxInt.attributes("name"); + if (!columnTitle.empty()) { - workspace->setRowCount(length); - hasNumberOfRowBeenSet = true; + workspace->addColumn("int", columnTitle); + nxInt.load(); + int length = nxInt.dim0(); + if (!hasNumberOfRowBeenSet) + { + workspace->setRowCount(length); + hasNumberOfRowBeenSet = true; + } + for (int i = 0; i < length; i++) + workspace->cell(i, columnNumber - 1) = *(nxInt() + i); } - for (int i = 0; i < length; i++) - workspace->cell(i, columnNumber - 1) = *(nxInt() + i); } } - } - else if (info.rank == 2) - { - if (info.type == NX_CHAR) + else if (info.rank == 2) { - NXChar data = nx_tw.openNXChar(str.c_str()); - std::string columnTitle = data.attributes("name"); - if (!columnTitle.empty()) + if (info.type == NX_CHAR) { - workspace->addColumn("str", columnTitle); - int nRows = info.dims[0]; - if (!hasNumberOfRowBeenSet) - { - workspace->setRowCount(nRows); - hasNumberOfRowBeenSet = true; - } - - const int maxStr = info.dims[1]; - data.load(); - for (int iR = 0; iR < nRows; ++iR) + NXChar data = nx_tw.openNXChar(str.c_str()); + std::string columnTitle = data.attributes("name"); + if (!columnTitle.empty()) { - auto& cellContents = workspace->cell(iR, columnNumber - 1); - auto startPoint = data() + maxStr * iR; - cellContents.assign(startPoint, startPoint + maxStr); - boost::trim_right(cellContents); + workspace->addColumn("str", columnTitle); + int nRows = info.dims[0]; + if (!hasNumberOfRowBeenSet) + { + workspace->setRowCount(nRows); + hasNumberOfRowBeenSet = true; + } + + const int maxStr = info.dims[1]; + data.load(); + for (int iR = 0; iR < nRows; ++iR) + { + auto& cellContents = workspace->cell(iR, columnNumber - 1); + auto startPoint = data() + maxStr * iR; + cellContents.assign(startPoint, startPoint + maxStr); + boost::trim_right(cellContents); + } } } - } #define IF_VECTOR_COLUMN(Type, ColumnTypeName, NexusType) \ else if ( info.type == NexusType ) \ { \ loadVectorColumn(nx_tw, str, workspace, #ColumnTypeName); \ } - IF_VECTOR_COLUMN(int, vector_int, NX_INT32) - IF_VECTOR_COLUMN(double, vector_double, NX_FLOAT64) + IF_VECTOR_COLUMN(int, vector_int, NX_INT32) + IF_VECTOR_COLUMN(double, vector_double, NX_FLOAT64) - } + } - columnNumber++; + columnNumber++; - } while (1); + } while (1); - return boost::static_pointer_cast(workspace); - } + return boost::static_pointer_cast(workspace); + } - /** - * Loads a vector column to the TableWorkspace. - * @param tableData :: Table data to load from - * @param dataSetName :: Name of the data set to use to get column data - * @param tableWs :: Workspace to add column to - * @param columnType :: Name of the column type to create - */ - template - void LoadNexusProcessed::loadVectorColumn(const NXData& tableData, const std::string& dataSetName, - const ITableWorkspace_sptr& tableWs, const std::string& columnType) - { - NXDataSetTyped data = tableData.openNXDataSet(dataSetName.c_str()); - std::string columnTitle = data.attributes("name"); - if (!columnTitle.empty()) + /** + * Loads a vector column to the TableWorkspace. + * @param tableData :: Table data to load from + * @param dataSetName :: Name of the data set to use to get column data + * @param tableWs :: Workspace to add column to + * @param columnType :: Name of the column type to create + */ + template + void LoadNexusProcessed::loadVectorColumn(const NXData& tableData, const std::string& dataSetName, + const ITableWorkspace_sptr& tableWs, const std::string& columnType) { - tableWs->addColumn(columnType, columnTitle); + NXDataSetTyped data = tableData.openNXDataSet(dataSetName.c_str()); + std::string columnTitle = data.attributes("name"); + if (!columnTitle.empty()) + { + tableWs->addColumn(columnType, columnTitle); - NXInfo info = tableData.getDataSetInfo(dataSetName.c_str()); - const size_t rowCount = info.dims[0]; - const size_t blockSize = info.dims[1]; + NXInfo info = tableData.getDataSetInfo(dataSetName.c_str()); + const size_t rowCount = info.dims[0]; + const size_t blockSize = info.dims[1]; - // This might've been done already, but doing it twice should't do any harm - tableWs->setRowCount(rowCount); + // This might've been done already, but doing it twice should't do any harm + tableWs->setRowCount(rowCount); - data.load(); + data.load(); - for (size_t i = 0; i < rowCount; ++i) - { - auto& cell = tableWs->cell >(i, tableWs->columnCount() - 1); + for (size_t i = 0; i < rowCount; ++i) + { + auto& cell = tableWs->cell >(i, tableWs->columnCount() - 1); - Type* from = data() + blockSize * i; + Type* from = data() + blockSize * i; - cell.assign(from, from + blockSize); + cell.assign(from, from + blockSize); - std::ostringstream rowSizeAttrName; - rowSizeAttrName << "row_size_" << i; + std::ostringstream rowSizeAttrName; + rowSizeAttrName << "row_size_" << i; - // This is ugly, but I can only get attribute as a string using the API - std::istringstream rowSizeStr(data.attributes(rowSizeAttrName.str())); + // This is ugly, but I can only get attribute as a string using the API + std::istringstream rowSizeStr(data.attributes(rowSizeAttrName.str())); - int rowSize; - rowSizeStr >> rowSize; + int rowSize; + rowSizeStr >> rowSize; - cell.resize(rowSize); + cell.resize(rowSize); + } } } - } //------------------------------------------------------------------------------------------------- - /** - * Load peaks - */ - API::Workspace_sptr LoadNexusProcessed::loadPeaksEntry(NXEntry & entry) - { - //API::IPeaksWorkspace_sptr workspace; - API::ITableWorkspace_sptr tWorkspace; - //PeaksWorkspace_sptr workspace; - tWorkspace = Mantid::API::WorkspaceFactory::Instance().createTable("PeaksWorkspace"); - - PeaksWorkspace_sptr peakWS = boost::dynamic_pointer_cast(tWorkspace); - - NXData nx_tw = entry.openNXData("peaks_workspace"); - - int columnNumber = 1; - int numberPeaks = 0; - std::vector columnNames; - do + /** + * Load peaks + */ + API::Workspace_sptr LoadNexusProcessed::loadPeaksEntry(NXEntry & entry) { - std::string str = "column_" + boost::lexical_cast(columnNumber); + //API::IPeaksWorkspace_sptr workspace; + API::ITableWorkspace_sptr tWorkspace; + //PeaksWorkspace_sptr workspace; + tWorkspace = Mantid::API::WorkspaceFactory::Instance().createTable("PeaksWorkspace"); - NXInfo info = nx_tw.getDataSetInfo(str.c_str()); - if (info.stat == NX_ERROR) - { - // Assume we done last column of table - break; - } + PeaksWorkspace_sptr peakWS = boost::dynamic_pointer_cast(tWorkspace); - // store column names - columnNames.push_back(str); + NXData nx_tw = entry.openNXData("peaks_workspace"); - // determine number of peaks - // here we assume that a peaks_table has always one column of doubles - - if (info.type == NX_FLOAT64) + int columnNumber = 1; + int numberPeaks = 0; + std::vector columnNames; + do { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - std::string columnTitle = nxDouble.attributes("name"); - if (!columnTitle.empty() && numberPeaks == 0) + std::string str = "column_" + boost::lexical_cast(columnNumber); + + NXInfo info = nx_tw.getDataSetInfo(str.c_str()); + if (info.stat == NX_ERROR) { - numberPeaks = nxDouble.dim0(); + // Assume we done last column of table + break; } - } - columnNumber++; + // store column names + columnNames.push_back(str); - } while (1); + // determine number of peaks + // here we assume that a peaks_table has always one column of doubles - //Get information from all but data group - std::string parameterStr; - // Hop to the right point - m_cppFile->openPath(entry.path()); - try - { - // This loads logs, sample, and instrument. - peakWS->loadExperimentInfoNexus(m_cppFile, parameterStr); - } catch (std::exception & e) - { - g_log.information("Error loading Instrument section of nxs file"); - g_log.information(e.what()); - } + if (info.type == NX_FLOAT64) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + std::string columnTitle = nxDouble.attributes("name"); + if (!columnTitle.empty() && numberPeaks == 0) + { + numberPeaks = nxDouble.dim0(); + } + } - // std::vector p; - for (int r = 0; r < numberPeaks; r++) - { - Kernel::V3D v3d; - v3d[2] = 1.0; - API::IPeak* p; - p = peakWS->createPeak(v3d); - peakWS->addPeak(*p); - } + columnNumber++; - for (size_t i = 0; i < columnNames.size(); i++) - { - const std::string str = columnNames[i]; - if (!str.compare("column_1")) - { - NXInt nxInt = nx_tw.openNXInt(str.c_str()); - nxInt.load(); + } while (1); - for (int r = 0; r < numberPeaks; r++) - { - int ival = nxInt[r]; - if (ival != -1) - peakWS->getPeak(r).setDetectorID(ival); - } + //Get information from all but data group + std::string parameterStr; + // Hop to the right point + m_cppFile->openPath(entry.path()); + try + { + // This loads logs, sample, and instrument. + peakWS->loadExperimentInfoNexus(m_cppFile, parameterStr); + } catch (std::exception & e) + { + g_log.information("Error loading Instrument section of nxs file"); + g_log.information(e.what()); } - if (!str.compare("column_2")) + // std::vector p; + for (int r = 0; r < numberPeaks; r++) { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); - - for (int r = 0; r < numberPeaks; r++) - { - double val = nxDouble[r]; - peakWS->getPeak(r).setH(val); - } + Kernel::V3D v3d; + v3d[2] = 1.0; + API::IPeak* p; + p = peakWS->createPeak(v3d); + peakWS->addPeak(*p); } - if (!str.compare("column_3")) + for (size_t i = 0; i < columnNames.size(); i++) { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); - - for (int r = 0; r < numberPeaks; r++) + const std::string str = columnNames[i]; + if (!str.compare("column_1")) { - double val = nxDouble[r]; - peakWS->getPeak(r).setK(val); - } - } + NXInt nxInt = nx_tw.openNXInt(str.c_str()); + nxInt.load(); - if (!str.compare("column_4")) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); + for (int r = 0; r < numberPeaks; r++) + { + int ival = nxInt[r]; + if (ival != -1) + peakWS->getPeak(r).setDetectorID(ival); + } + } - for (int r = 0; r < numberPeaks; r++) + if (!str.compare("column_2")) { - double val = nxDouble[r]; - peakWS->getPeak(r).setL(val); - } - } + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); - if (!str.compare("column_5")) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setH(val); + } + } - for (int r = 0; r < numberPeaks; r++) + if (!str.compare("column_3")) { - double val = nxDouble[r]; - peakWS->getPeak(r).setIntensity(val); - } - } + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); - if (!str.compare("column_6")) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setK(val); + } + } - for (int r = 0; r < numberPeaks; r++) + if (!str.compare("column_4")) { - double val = nxDouble[r]; - peakWS->getPeak(r).setSigmaIntensity(val); - } - } + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); - if (!str.compare("column_7")) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setL(val); + } + } - for (int r = 0; r < numberPeaks; r++) + if (!str.compare("column_5")) { - double val = nxDouble[r]; - peakWS->getPeak(r).setBinCount(val); + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); + + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setIntensity(val); + } } - } - if (!str.compare("column_10")) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); + if (!str.compare("column_6")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); - for (int r = 0; r < numberPeaks; r++) + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setSigmaIntensity(val); + } + } + + if (!str.compare("column_7")) { - double val = nxDouble[r]; - peakWS->getPeak(r).setWavelength(val); + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); + + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setBinCount(val); + } } - } - if (!str.compare("column_14")) - { - NXInt nxInt = nx_tw.openNXInt(str.c_str()); - nxInt.load(); + if (!str.compare("column_10")) + { + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); + + for (int r = 0; r < numberPeaks; r++) + { + double val = nxDouble[r]; + peakWS->getPeak(r).setWavelength(val); + } + } - for (int r = 0; r < numberPeaks; r++) + if (!str.compare("column_14")) { - int ival = nxInt[r]; - if (ival != -1) - peakWS->getPeak(r).setRunNumber(ival); + NXInt nxInt = nx_tw.openNXInt(str.c_str()); + nxInt.load(); + + for (int r = 0; r < numberPeaks; r++) + { + int ival = nxInt[r]; + if (ival != -1) + peakWS->getPeak(r).setRunNumber(ival); + } } - } - if (!str.compare("column_15")) - { - NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); - nxDouble.load(); - Kernel::Matrix gm(3, 3, false); - int k = 0; - for (int r = 0; r < numberPeaks; r++) + if (!str.compare("column_15")) { - for (int j = 0; j < 9; j++) + NXDouble nxDouble = nx_tw.openNXDouble(str.c_str()); + nxDouble.load(); + Kernel::Matrix gm(3, 3, false); + int k = 0; + for (int r = 0; r < numberPeaks; r++) { - double val = nxDouble[k]; - k++; - gm[j % 3][j / 3] = val; + for (int j = 0; j < 9; j++) + { + double val = nxDouble[k]; + k++; + gm[j % 3][j / 3] = val; + } + peakWS->getPeak(r).setGoniometerMatrix(gm); } - peakWS->getPeak(r).setGoniometerMatrix(gm); } + } + return boost::static_pointer_cast(peakWS); } - return boost::static_pointer_cast(peakWS); - } - //------------------------------------------------------------------------------------------------- - /** - * Load a single entry into a workspace - * @param root :: The opened root node - * @param entry_name :: The entry name - * @param progressStart :: The percentage value to start the progress reporting for this entry - * @param progressRange :: The percentage range that the progress reporting should cover - * @param specInfo :: Spectrum information object - * @param ignoreSpecInfo :: true to skip reading and wrting to optional specInfo - * @returns A 2D workspace containing the loaded data - */ - API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot & root, const std::string & entry_name, - const double& progressStart, const double& progressRange, SpectraInfo_optional& specInfo, bool ignoreSpecInfo) - { - progress(progressStart, "Opening entry " + entry_name + "..."); - - NXEntry mtd_entry = root.openEntry(entry_name); - - if (mtd_entry.containsGroup("table_workspace")) + /** + * Load a single entry into a workspace + * @param root :: The opened root node + * @param entry_name :: The entry name + * @param progressStart :: The percentage value to start the progress reporting for this entry + * @param progressRange :: The percentage range that the progress reporting should cover + * @param specInfo :: Spectrum information object + * @param ignoreSpecInfo :: true to skip reading and wrting to optional specInfo + * @returns A 2D workspace containing the loaded data + */ + API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot & root, const std::string & entry_name, + const double& progressStart, const double& progressRange, SpectraInfo_optional& specInfo, + bool ignoreSpecInfo) { - return loadTableEntry(mtd_entry); - } + progress(progressStart, "Opening entry " + entry_name + "..."); - if (mtd_entry.containsGroup("peaks_workspace")) - { - return loadPeaksEntry(mtd_entry); - } + NXEntry mtd_entry = root.openEntry(entry_name); - // Determine workspace type and name of group containing workspace characteristics - bool isEvent = false; - std::string workspaceType = "Workspace2D"; - std::string group_name = "workspace"; - if (mtd_entry.containsGroup("event_workspace")) - { - isEvent = true; - group_name = "event_workspace"; - } - else if (mtd_entry.containsGroup("offsets_workspace")) - { - workspaceType = "OffsetsWorkspace"; - group_name = "offsets_workspace"; - } + if (mtd_entry.containsGroup("table_workspace")) + { + return loadTableEntry(mtd_entry); + } - // Get workspace characteristics - NXData wksp_cls = mtd_entry.openNXData(group_name); - - // Axis information - // "X" axis - NXDouble xbins = wksp_cls.openNXDouble("axis1"); - xbins.load(); - std::string unit1 = xbins.attributes("units"); - // Non-uniform x bins get saved as a 2D 'axis1' dataset - int xlength(-1); - if (xbins.rank() == 2) - { - xlength = xbins.dim1(); - m_shared_bins = false; - } - else if (xbins.rank() == 1) - { - xlength = xbins.dim0(); - m_shared_bins = true; - xbins.load(); - m_xbins.access().assign(xbins(), xbins() + xlength); - } - else - { - throw std::runtime_error("Unknown axis1 dimension encountered."); - } + if (mtd_entry.containsGroup("peaks_workspace")) + { + return loadPeaksEntry(mtd_entry); + } + + // Determine workspace type and name of group containing workspace characteristics + bool isEvent = false; + std::string workspaceType = "Workspace2D"; + std::string group_name = "workspace"; + if (mtd_entry.containsGroup("event_workspace")) + { + isEvent = true; + group_name = "event_workspace"; + } + else if (mtd_entry.containsGroup("offsets_workspace")) + { + workspaceType = "OffsetsWorkspace"; + group_name = "offsets_workspace"; + } - // MatrixWorkspace axis 1 - NXDouble axis2 = wksp_cls.openNXDouble("axis2"); - std::string unit2 = axis2.attributes("units"); + // Get workspace characteristics + NXData wksp_cls = mtd_entry.openNXData(group_name); - // The workspace being worked on - API::MatrixWorkspace_sptr local_workspace; - size_t nspectra; - int64_t nchannels; + // Axis information + // "X" axis - // -------- Process as event ? -------------------- - if (isEvent) - { - local_workspace = loadEventEntry(wksp_cls, xbins, progressStart, progressRange); - nspectra = local_workspace->getNumberHistograms(); - nchannels = local_workspace->blocksize(); - } - else - { - NXDataSetTyped data = wksp_cls.openDoubleData(); - nspectra = data.dim0(); - nchannels = data.dim1(); - //// validate the optional spectrum parameters, if set - checkOptionalProperties(nspectra); - // Actual number of spectra in output workspace (if only a range was going to be loaded) - size_t total_specs = calculateWorkspacesize(nspectra); - - //// Create the 2D workspace for the output - bool hasFracArea = false; - if (wksp_cls.isValid("frac_area")) + // ---- START NOT REQUIRED PER PERIOD --- + NXDouble xbins = wksp_cls.openNXDouble("axis1"); + xbins.load(); + std::string unit1 = xbins.attributes("units"); + // Non-uniform x bins get saved as a 2D 'axis1' dataset + int xlength(-1); + if (xbins.rank() == 2) { - // frac_area entry is the signal for a RebinnedOutput workspace - hasFracArea = true; - workspaceType.clear(); - workspaceType = "RebinnedOutput"; + xlength = xbins.dim1(); + m_shared_bins = false; } - local_workspace = boost::dynamic_pointer_cast( - WorkspaceFactory::Instance().create(workspaceType, total_specs, xlength, nchannels)); - try + else if (xbins.rank() == 1) { - local_workspace->setTitle(mtd_entry.getString("title")); - } catch (std::runtime_error&) + xlength = xbins.dim0(); + m_shared_bins = true; //SHOULD BE THE CASE FOR MULTIPERIOD DATA!!!!! + xbins.load(); + m_xbins.access().assign(xbins(), xbins() + xlength); + } + else { - g_log.debug() << "No title was found in the input file, " << getPropertyValue("Filename") - << std::endl; + throw std::runtime_error("Unknown axis1 dimension encountered."); } + // ---- END NOT REQUIRED PER PERIOD --- - // Set the YUnit label - local_workspace->setYUnit(data.attributes("units")); - std::string unitLabel = data.attributes("unit_label"); - if (unitLabel.empty()) - unitLabel = data.attributes("units"); - local_workspace->setYUnitLabel(unitLabel); + // ---- START NOT REQUIRED PER PERIOD --- + // MatrixWorkspace axis 1 + NXDouble axis2 = wksp_cls.openNXDouble("axis2"); + std::string unit2 = axis2.attributes("units"); + // ---- END NOT REQUIRED PER PERIOD --- - readBinMasking(wksp_cls, local_workspace); - NXDataSetTyped errors = wksp_cls.openNXDouble("errors"); - NXDataSetTyped fracarea = wksp_cls.openNXDouble("errors"); - if (hasFracArea) + // The workspace being worked on + API::MatrixWorkspace_sptr local_workspace; + size_t nspectra; + int64_t nchannels; + + // -------- Process as event ? -------------------- + if (isEvent) { - fracarea = wksp_cls.openNXDouble("frac_area"); + local_workspace = loadEventEntry(wksp_cls, xbins, progressStart, progressRange); + nspectra = local_workspace->getNumberHistograms(); + nchannels = local_workspace->blocksize(); } - - int64_t blocksize(8); - //const int fullblocks = nspectra / blocksize; - //size of the workspace - int64_t fullblocks = total_specs / blocksize; - int64_t read_stop = (fullblocks * blocksize); - const double progressBegin = progressStart + 0.25 * progressRange; - const double progressScaler = 0.75 * progressRange; - int64_t hist_index = 0; - int64_t wsIndex = 0; - if (m_shared_bins) + else { - //if spectrum min,max,list properties are set - if (m_interval || m_list) + NXDataSetTyped data = wksp_cls.openDoubleData(); + nspectra = data.dim0(); + nchannels = data.dim1(); + //// validate the optional spectrum parameters, if set + checkOptionalProperties(nspectra); + // Actual number of spectra in output workspace (if only a range was going to be loaded) + size_t total_specs = calculateWorkspacesize(nspectra); + + //// Create the 2D workspace for the output + bool hasFracArea = false; + if (wksp_cls.isValid("frac_area")) { - //if spectrum max,min properties are set read the data as a block(multiple of 8) and - //then read the remaining data as finalblock - if (m_interval) - { - //specs at the min-max interval - int interval_specs = static_cast(m_spec_max - m_spec_min); - fullblocks = (interval_specs) / blocksize; - read_stop = (fullblocks * blocksize) + m_spec_min - 1; + // frac_area entry is the signal for a RebinnedOutput workspace + hasFracArea = true; + workspaceType.clear(); + workspaceType = "RebinnedOutput"; + } + local_workspace = boost::dynamic_pointer_cast( + WorkspaceFactory::Instance().create(workspaceType, total_specs, xlength, nchannels)); + try + { + local_workspace->setTitle(mtd_entry.getString("title")); + } catch (std::runtime_error&) + { + g_log.debug() << "No title was found in the input file, " << getPropertyValue("Filename") + << std::endl; + } + + // Set the YUnit label + local_workspace->setYUnit(data.attributes("units")); + std::string unitLabel = data.attributes("unit_label"); + if (unitLabel.empty()) + unitLabel = data.attributes("units"); + local_workspace->setYUnitLabel(unitLabel); + + readBinMasking(wksp_cls, local_workspace); + NXDataSetTyped errors = wksp_cls.openNXDouble("errors"); + NXDataSetTyped fracarea = wksp_cls.openNXDouble("errors"); + if (hasFracArea) + { + fracarea = wksp_cls.openNXDouble("frac_area"); + } - if (interval_specs < blocksize) + int64_t blocksize(8); + //const int fullblocks = nspectra / blocksize; + //size of the workspace + int64_t fullblocks = total_specs / blocksize; + int64_t read_stop = (fullblocks * blocksize); + const double progressBegin = progressStart + 0.25 * progressRange; + const double progressScaler = 0.75 * progressRange; + int64_t hist_index = 0; + int64_t wsIndex = 0; + if (m_shared_bins) + { + //if spectrum min,max,list properties are set + if (m_interval || m_list) + { + //if spectrum max,min properties are set read the data as a block(multiple of 8) and + //then read the remaining data as finalblock + if (m_interval) { - blocksize = total_specs; - read_stop = m_spec_max - 1; + //specs at the min-max interval + int interval_specs = static_cast(m_spec_max - m_spec_min); + fullblocks = (interval_specs) / blocksize; + read_stop = (fullblocks * blocksize) + m_spec_min - 1; + + if (interval_specs < blocksize) + { + blocksize = total_specs; + read_stop = m_spec_max - 1; + } + hist_index = m_spec_min - 1; + + for (; hist_index < read_stop;) + { + progress( + progressBegin + + progressScaler * static_cast(hist_index) + / static_cast(read_stop), "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, blocksize, nchannels, hist_index, wsIndex, + local_workspace); + } + int64_t finalblock = m_spec_max - 1 - read_stop; + if (finalblock > 0) + { + loadBlock(data, errors, fracarea, hasFracArea, finalblock, nchannels, hist_index, + wsIndex, local_workspace); + } } - hist_index = m_spec_min - 1; + // if spectrum list property is set read each spectrum separately by setting blocksize=1 + if (m_list) + { + std::vector::iterator itr = m_spec_list.begin(); + for (; itr != m_spec_list.end(); ++itr) + { + int64_t specIndex = (*itr) - 1; + progress( + progressBegin + + progressScaler * static_cast(specIndex) + / static_cast(m_spec_list.size()), "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, static_cast(1), nchannels, + specIndex, wsIndex, local_workspace); + } + } + } + else + { for (; hist_index < read_stop;) { progress( @@ -1094,67 +1222,67 @@ namespace Mantid loadBlock(data, errors, fracarea, hasFracArea, blocksize, nchannels, hist_index, wsIndex, local_workspace); } - int64_t finalblock = m_spec_max - 1 - read_stop; + int64_t finalblock = total_specs - read_stop; if (finalblock > 0) { loadBlock(data, errors, fracarea, hasFracArea, finalblock, nchannels, hist_index, wsIndex, local_workspace); } } - // if spectrum list property is set read each spectrum separately by setting blocksize=1 - if (m_list) - { - std::vector::iterator itr = m_spec_list.begin(); - for (; itr != m_spec_list.end(); ++itr) - { - int64_t specIndex = (*itr) - 1; - progress( - progressBegin - + progressScaler * static_cast(specIndex) - / static_cast(m_spec_list.size()), "Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, static_cast(1), nchannels, - specIndex, wsIndex, local_workspace); - } - } } else { - for (; hist_index < read_stop;) - { - progress( - progressBegin - + progressScaler * static_cast(hist_index) / static_cast(read_stop), - "Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, blocksize, nchannels, hist_index, wsIndex, - local_workspace); - } - int64_t finalblock = total_specs - read_stop; - if (finalblock > 0) - { - loadBlock(data, errors, fracarea, hasFracArea, finalblock, nchannels, hist_index, wsIndex, - local_workspace); - } - } - - } - else - { - if (m_interval || m_list) - { - if (m_interval) + if (m_interval || m_list) { - int64_t interval_specs = m_spec_max - m_spec_min; - fullblocks = (interval_specs) / blocksize; - read_stop = (fullblocks * blocksize) + m_spec_min - 1; - - if (interval_specs < blocksize) + if (m_interval) { - blocksize = interval_specs; - read_stop = m_spec_max - 1; + int64_t interval_specs = m_spec_max - m_spec_min; + fullblocks = (interval_specs) / blocksize; + read_stop = (fullblocks * blocksize) + m_spec_min - 1; + + if (interval_specs < blocksize) + { + blocksize = interval_specs; + read_stop = m_spec_max - 1; + } + hist_index = m_spec_min - 1; + + for (; hist_index < read_stop;) + { + progress( + progressBegin + + progressScaler * static_cast(hist_index) + / static_cast(read_stop), "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, xbins, blocksize, nchannels, hist_index, + wsIndex, local_workspace); + } + int64_t finalblock = m_spec_max - 1 - read_stop; + if (finalblock > 0) + { + loadBlock(data, errors, fracarea, hasFracArea, xbins, finalblock, nchannels, hist_index, + wsIndex, local_workspace); + } } - hist_index = m_spec_min - 1; + // + if (m_list) + { + std::vector::iterator itr = m_spec_list.begin(); + for (; itr != m_spec_list.end(); ++itr) + { + int64_t specIndex = (*itr) - 1; + progress( + progressBegin + + progressScaler * static_cast(specIndex) + / static_cast(read_stop), "Reading workspace data..."); + loadBlock(data, errors, fracarea, hasFracArea, xbins, 1, nchannels, specIndex, wsIndex, + local_workspace); + } + } + } + else + { for (; hist_index < read_stop;) { progress( @@ -1164,649 +1292,615 @@ namespace Mantid loadBlock(data, errors, fracarea, hasFracArea, xbins, blocksize, nchannels, hist_index, wsIndex, local_workspace); } - int64_t finalblock = m_spec_max - 1 - read_stop; + int64_t finalblock = total_specs - read_stop; if (finalblock > 0) { loadBlock(data, errors, fracarea, hasFracArea, xbins, finalblock, nchannels, hist_index, wsIndex, local_workspace); } } - // - if (m_list) - { - std::vector::iterator itr = m_spec_list.begin(); - for (; itr != m_spec_list.end(); ++itr) - { - int64_t specIndex = (*itr) - 1; - progress( - progressBegin - + progressScaler * static_cast(specIndex) / static_cast(read_stop), - "Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, xbins, 1, nchannels, specIndex, wsIndex, - local_workspace); - } + } + } //end of NOT an event ------------------------------- - } + //Units + bool verticalHistogram(false); + try + { + local_workspace->getAxis(0)->unit() = UnitFactory::Instance().create(unit1); + if (unit1 == "Label") + { + auto label = boost::dynamic_pointer_cast( + local_workspace->getAxis(0)->unit()); + auto ax = wksp_cls.openNXDouble("axis1"); + label->setLabel(ax.attributes("caption"), ax.attributes("label")); } - else + + //If this doesn't throw then it is a numeric access so grab the data so we can set it later + axis2.load(); + if (static_cast(axis2.size()) == nspectra + 1) + verticalHistogram = true; + m_axis1vals = MantidVec(axis2(), axis2() + axis2.dim0()); + } catch (std::runtime_error &) + { + g_log.information() << "Axis 0 set to unitless quantity \"" << unit1 << "\"\n"; + } + + // Setting a unit onto a TextAxis makes no sense. + if (unit2 == "TextAxis") + { + Mantid::API::TextAxis* newAxis = new Mantid::API::TextAxis(nspectra); + local_workspace->replaceAxis(1, newAxis); + } + else if (unit2 != "spectraNumber") + { + try { - for (; hist_index < read_stop;) + auto* newAxis = + (verticalHistogram) ? new API::BinEdgeAxis(nspectra + 1) : new API::NumericAxis(nspectra); + local_workspace->replaceAxis(1, newAxis); + newAxis->unit() = UnitFactory::Instance().create(unit2); + if (unit2 == "Label") { - progress( - progressBegin - + progressScaler * static_cast(hist_index) / static_cast(read_stop), - "Reading workspace data..."); - loadBlock(data, errors, fracarea, hasFracArea, xbins, blocksize, nchannels, hist_index, - wsIndex, local_workspace); - } - int64_t finalblock = total_specs - read_stop; - if (finalblock > 0) - { - loadBlock(data, errors, fracarea, hasFracArea, xbins, finalblock, nchannels, hist_index, - wsIndex, local_workspace); + auto label = boost::dynamic_pointer_cast(newAxis->unit()); + auto ax = wksp_cls.openNXDouble("axis2"); + label->setLabel(ax.attributes("caption"), ax.attributes("label")); } + } catch (std::runtime_error &) + { + g_log.information() << "Axis 1 set to unitless quantity \"" << unit2 << "\"\n"; } } - } //end of NOT an event ------------------------------- - //Units - bool verticalHistogram(false); - try - { - local_workspace->getAxis(0)->unit() = UnitFactory::Instance().create(unit1); - if (unit1 == "Label") + //Are we a distribution + std::string dist = xbins.attributes("distribution"); + if (dist == "1") + { + local_workspace->isDistribution(true); + } + else { - auto label = boost::dynamic_pointer_cast( - local_workspace->getAxis(0)->unit()); - auto ax = wksp_cls.openNXDouble("axis1"); - label->setLabel(ax.attributes("caption"), ax.attributes("label")); + local_workspace->isDistribution(false); } - //If this doesn't throw then it is a numeric access so grab the data so we can set it later - axis2.load(); - if (static_cast(axis2.size()) == nspectra + 1) - verticalHistogram = true; - m_axis1vals = MantidVec(axis2(), axis2() + axis2.dim0()); - } catch (std::runtime_error &) - { - g_log.information() << "Axis 0 set to unitless quantity \"" << unit1 << "\"\n"; - } + //Get information from all but data group + std::string parameterStr; - // Setting a unit onto a TextAxis makes no sense. - if (unit2 == "TextAxis") - { - Mantid::API::TextAxis* newAxis = new Mantid::API::TextAxis(nspectra); - local_workspace->replaceAxis(1, newAxis); - } - else if (unit2 != "spectraNumber") - { + progress(progressStart + 0.05 * progressRange, "Reading the sample details..."); + + // Hop to the right point + m_cppFile->openPath(mtd_entry.path()); try { - auto* newAxis = - (verticalHistogram) ? new API::BinEdgeAxis(nspectra + 1) : new API::NumericAxis(nspectra); - local_workspace->replaceAxis(1, newAxis); - newAxis->unit() = UnitFactory::Instance().create(unit2); - if (unit2 == "Label") - { - auto label = boost::dynamic_pointer_cast(newAxis->unit()); - auto ax = wksp_cls.openNXDouble("axis2"); - label->setLabel(ax.attributes("caption"), ax.attributes("label")); - } - } catch (std::runtime_error &) + // This loads logs, sample, and instrument. + local_workspace->loadExperimentInfoNexus(m_cppFile, parameterStr); // REQUIRED PER PERIOD + } catch (std::exception & e) { - g_log.information() << "Axis 1 set to unitless quantity \"" << unit2 << "\"\n"; + g_log.information("Error loading Instrument section of nxs file"); + g_log.information(e.what()); } - } - - //Are we a distribution - std::string dist = xbins.attributes("distribution"); - if (dist == "1") - { - local_workspace->isDistribution(true); - } - else - { - local_workspace->isDistribution(false); - } - //Get information from all but data group - std::string parameterStr; + // Now assign the spectra-detector map + readInstrumentGroup(mtd_entry, local_workspace, specInfo, ignoreSpecInfo); - progress(progressStart + 0.05 * progressRange, "Reading the sample details..."); + // Parameter map parsing + progress(progressStart + 0.11 * progressRange, "Reading the parameter maps..."); + local_workspace->readParameterMap(parameterStr); - // Hop to the right point - m_cppFile->openPath(mtd_entry.path()); - try - { - // This loads logs, sample, and instrument. - local_workspace->loadExperimentInfoNexus(m_cppFile, parameterStr); - } catch (std::exception & e) - { - g_log.information("Error loading Instrument section of nxs file"); - g_log.information(e.what()); - } - - // Now assign the spectra-detector map - readInstrumentGroup(mtd_entry, local_workspace, specInfo, ignoreSpecInfo); + if (!local_workspace->getAxis(1)->isSpectra()) + { // If not a spectra axis, load the axis data into the workspace. (MW 25/11/10) + loadNonSpectraAxis(local_workspace, wksp_cls); + } - // Parameter map parsing - progress(progressStart + 0.11 * progressRange, "Reading the parameter maps..."); - local_workspace->readParameterMap(parameterStr); + progress(progressStart + 0.15 * progressRange, "Reading the workspace history..."); + m_cppFile->openPath(mtd_entry.path()); + try + { + bool load_history = getProperty("LoadHistory"); + if (load_history) + local_workspace->history().loadNexus(m_cppFile); + } catch (std::out_of_range&) + { + g_log.warning() + << "Error in the workspaces algorithm list, its processing history is incomplete\n"; + } - if (!local_workspace->getAxis(1)->isSpectra()) - { // If not a spectra axis, load the axis data into the workspace. (MW 25/11/10) - loadNonSpectraAxis(local_workspace, wksp_cls); - } + progress(progressStart + 0.2 * progressRange, "Reading the workspace history..."); - progress(progressStart + 0.15 * progressRange, "Reading the workspace history..."); - m_cppFile->openPath(mtd_entry.path()); - try - { - bool load_history = getProperty("LoadHistory"); - if (load_history) - local_workspace->history().loadNexus(m_cppFile); - } catch (std::out_of_range&) - { - g_log.warning() - << "Error in the workspaces algorithm list, its processing history is incomplete\n"; + return boost::static_pointer_cast(local_workspace); } - progress(progressStart + 0.2 * progressRange, "Reading the workspace history..."); - - return boost::static_pointer_cast(local_workspace); - } - //------------------------------------------------------------------------------------------------- - /** - * Read the instrument group - * @param mtd_entry :: The node for the current workspace - * @param local_workspace :: The workspace to attach the instrument - * @param inOutSpecInfo :: Spectrum information - * @param ignoreSpecInfo :: If True ignore input spectrum info and obtain it yourself. - */ - void LoadNexusProcessed::readInstrumentGroup(NXEntry & mtd_entry, - API::MatrixWorkspace_sptr local_workspace, SpectraInfo_optional& inOutSpecInfo, bool ignoreSpecInfo) - { - // Get spectrum information for the current entry. - - - const bool bUseExistingInfo = inOutSpecInfo.is_initialized() && !ignoreSpecInfo; + /** + * Read the instrument group + * @param mtd_entry :: The node for the current workspace + * @param local_workspace :: The workspace to attach the instrument + * @param inOutSpecInfo :: Spectrum information + * @param ignoreSpecInfo :: If True ignore input spectrum info and obtain it yourself. + */ + void LoadNexusProcessed::readInstrumentGroup(NXEntry & mtd_entry, + API::MatrixWorkspace_sptr local_workspace, SpectraInfo_optional& inOutSpecInfo, + bool ignoreSpecInfo) + { + // Get spectrum information for the current entry. - SpectraInfo spectraInfo = bUseExistingInfo ? inOutSpecInfo.get() : extractMappingInfo(mtd_entry, this->g_log); + const bool bUseExistingInfo = inOutSpecInfo.is_initialized() && !ignoreSpecInfo; - //Now build the spectra list - int index = 0; + SpectraInfo spectraInfo = + bUseExistingInfo ? inOutSpecInfo.get() : extractMappingInfo(mtd_entry, this->g_log); - for (int i = 1; i <= spectraInfo.nSpectra; ++i) - { - int spectrum(-1); - if (spectraInfo.hasSpectra) - { - spectrum = spectraInfo.spectraNumbers[i - 1]; - } - else - { - spectrum = i + 1; - } + //Now build the spectra list + int index = 0; - if ((i >= m_spec_min && i < m_spec_max) - || (m_list && find(m_spec_list.begin(), m_spec_list.end(), i) != m_spec_list.end())) + for (int i = 1; i <= spectraInfo.nSpectra; ++i) { - ISpectrum * spec = local_workspace->getSpectrum(index); - if (m_axis1vals.empty()) + int spectrum(-1); + if (spectraInfo.hasSpectra) { - spec->setSpectrumNo(spectrum); + spectrum = spectraInfo.spectraNumbers[i - 1]; } else { - spec->setSpectrumNo(static_cast(m_axis1vals[i - 1])); + spectrum = i + 1; } - ++index; - int start = spectraInfo.detectorIndex[i - 1]; - int end = start + spectraInfo.detectorCount[i - 1]; - spec->setDetectorIDs( - std::set(spectraInfo.detectorList.get() + start, - spectraInfo.detectorList.get() + end)); + if ((i >= m_spec_min && i < m_spec_max) + || (m_list && find(m_spec_list.begin(), m_spec_list.end(), i) != m_spec_list.end())) + { + ISpectrum * spec = local_workspace->getSpectrum(index); + if (m_axis1vals.empty()) + { + spec->setSpectrumNo(spectrum); + } + else + { + spec->setSpectrumNo(static_cast(m_axis1vals[i - 1])); + } + ++index; + + int start = spectraInfo.detectorIndex[i - 1]; + int end = start + spectraInfo.detectorCount[i - 1]; + spec->setDetectorIDs( + std::set(spectraInfo.detectorList.get() + start, + spectraInfo.detectorList.get() + end)); + } } - } - // We can write the spec info under the following conditions. - if(!inOutSpecInfo.is_initialized() && !ignoreSpecInfo) - { - inOutSpecInfo = spectraInfo; + // We can write the spec info under the following conditions. + if (!inOutSpecInfo.is_initialized() && !ignoreSpecInfo) + { + inOutSpecInfo = spectraInfo; + } } - } //------------------------------------------------------------------------------------------------- - /** - * Loads the information contained in non-Spectra (ie, Text or Numeric) axis in the Nexus - * file into the workspace. - * @param local_workspace :: pointer to workspace object - * @param data :: reference to the NeXuS data for the axis - */ - void LoadNexusProcessed::loadNonSpectraAxis(API::MatrixWorkspace_sptr local_workspace, NXData & data) - { - Axis* axis = local_workspace->getAxis(1); - - if (axis->isNumeric()) + /** + * Loads the information contained in non-Spectra (ie, Text or Numeric) axis in the Nexus + * file into the workspace. + * @param local_workspace :: pointer to workspace object + * @param data :: reference to the NeXuS data for the axis + */ + void LoadNexusProcessed::loadNonSpectraAxis(API::MatrixWorkspace_sptr local_workspace, NXData & data) { - NXDouble axisData = data.openNXDouble("axis2"); - axisData.load(); - for (int i = 0; i < static_cast(axis->length()); i++) + Axis* axis = local_workspace->getAxis(1); + + if (axis->isNumeric()) { - axis->setValue(i, axisData[i]); + NXDouble axisData = data.openNXDouble("axis2"); + axisData.load(); + for (int i = 0; i < static_cast(axis->length()); i++) + { + axis->setValue(i, axisData[i]); + } } - } - else if (axis->isText()) - { - NXChar axisData = data.openNXChar("axis2"); - axisData.load(); - std::string axisLabels = axisData(); - // Use boost::tokenizer to split up the input - boost::char_separator sep("\n"); - boost::tokenizer > tokenizer(axisLabels, sep); - // We must cast the axis object to TextAxis so we may use ->setLabel - TextAxis* textAxis = static_cast(axis); - int i = 0; - for (auto tokIter = tokenizer.begin(); tokIter != tokenizer.end(); ++tokIter, ++i) + else if (axis->isText()) { - textAxis->setLabel(i, *tokIter); + NXChar axisData = data.openNXChar("axis2"); + axisData.load(); + std::string axisLabels = axisData(); + // Use boost::tokenizer to split up the input + boost::char_separator sep("\n"); + boost::tokenizer > tokenizer(axisLabels, sep); + // We must cast the axis object to TextAxis so we may use ->setLabel + TextAxis* textAxis = static_cast(axis); + int i = 0; + for (auto tokIter = tokenizer.begin(); tokIter != tokenizer.end(); ++tokIter, ++i) + { + textAxis->setLabel(i, *tokIter); + } } } - } - - /** - * Binary predicate function object to sort the AlgorithmHistory vector by execution order - * @param elem1 :: first element in the vector - * @param elem2 :: second element in the vecor - */ - bool UDlesserExecCount(NXClassInfo elem1, NXClassInfo elem2) - { - std::string::size_type index1, index2; - std::string num1, num2; - //find the number after "_" in algorithm name ( eg:MantidAlogorthm_1) - index1 = elem1.nxname.find("_"); - if (index1 != std::string::npos) - { - num1 = elem1.nxname.substr(index1 + 1, elem1.nxname.length() - index1); - } - index2 = elem2.nxname.find("_"); - if (index2 != std::string::npos) + + /** + * Binary predicate function object to sort the AlgorithmHistory vector by execution order + * @param elem1 :: first element in the vector + * @param elem2 :: second element in the vecor + */ + bool UDlesserExecCount(NXClassInfo elem1, NXClassInfo elem2) { - num2 = elem2.nxname.substr(index2 + 1, elem2.nxname.length() - index2); - } - std::stringstream is1, is2; - is1 << num1; - is2 << num2; + std::string::size_type index1, index2; + std::string num1, num2; + //find the number after "_" in algorithm name ( eg:MantidAlogorthm_1) + index1 = elem1.nxname.find("_"); + if (index1 != std::string::npos) + { + num1 = elem1.nxname.substr(index1 + 1, elem1.nxname.length() - index1); + } + index2 = elem2.nxname.find("_"); + if (index2 != std::string::npos) + { + num2 = elem2.nxname.substr(index2 + 1, elem2.nxname.length() - index2); + } + std::stringstream is1, is2; + is1 << num1; + is2 << num2; - int execNum1 = -1; - int execNum2 = -1; - is1 >> execNum1; - is2 >> execNum2; + int execNum1 = -1; + int execNum2 = -1; + is1 >> execNum1; + is2 >> execNum2; - if (execNum1 < execNum2) - return true; - else - return false; - } + if (execNum1 < execNum2) + return true; + else + return false; + } //------------------------------------------------------------------------------------------------- - /** If the first string contains exactly three words separated by spaces - * these words will be copied into each of the following strings that were passed - * @param[in] words3 a string with 3 words separated by spaces - * @param[out] w1 the first word in the input string - * @param[out] w2 the second word in the input string - * @param[out] w3 the third word in the input string - * @throw out_of_range if there aren't exaltly three strings in the word - */ - void LoadNexusProcessed::getWordsInString(const std::string & words3, std::string & w1, - std::string & w2, std::string & w3) - { - Poco::StringTokenizer data(words3, " ", Poco::StringTokenizer::TOK_TRIM); - if (data.count() != 3) + /** If the first string contains exactly three words separated by spaces + * these words will be copied into each of the following strings that were passed + * @param[in] words3 a string with 3 words separated by spaces + * @param[out] w1 the first word in the input string + * @param[out] w2 the second word in the input string + * @param[out] w3 the third word in the input string + * @throw out_of_range if there aren't exaltly three strings in the word + */ + void LoadNexusProcessed::getWordsInString(const std::string & words3, std::string & w1, + std::string & w2, std::string & w3) { - g_log.warning() << "Algorithm list line " + words3 + " is not of the correct format\n"; - throw std::out_of_range(words3); - } + Poco::StringTokenizer data(words3, " ", Poco::StringTokenizer::TOK_TRIM); + if (data.count() != 3) + { + g_log.warning() << "Algorithm list line " + words3 + " is not of the correct format\n"; + throw std::out_of_range(words3); + } - w1 = data[0]; - w2 = data[1]; - w3 = data[2]; - } + w1 = data[0]; + w2 = data[1]; + w3 = data[2]; + } //------------------------------------------------------------------------------------------------- - /** If the first string contains exactly four words separated by spaces - * these words will be copied into each of the following strings that were passed - * @param[in] words4 a string with 4 words separated by spaces - * @param[out] w1 the first word in the input string - * @param[out] w2 the second word in the input string - * @param[out] w3 the third word in the input string - * @param[out] w4 the fourth word in the input string - * @throw out_of_range if there aren't exaltly four strings in the word - */ - void LoadNexusProcessed::getWordsInString(const std::string & words4, std::string & w1, - std::string & w2, std::string & w3, std::string & w4) - { - Poco::StringTokenizer data(words4, " ", Poco::StringTokenizer::TOK_TRIM); - if (data.count() != 4) + /** If the first string contains exactly four words separated by spaces + * these words will be copied into each of the following strings that were passed + * @param[in] words4 a string with 4 words separated by spaces + * @param[out] w1 the first word in the input string + * @param[out] w2 the second word in the input string + * @param[out] w3 the third word in the input string + * @param[out] w4 the fourth word in the input string + * @throw out_of_range if there aren't exaltly four strings in the word + */ + void LoadNexusProcessed::getWordsInString(const std::string & words4, std::string & w1, + std::string & w2, std::string & w3, std::string & w4) { - g_log.warning() << "Algorithm list line " + words4 + " is not of the correct format\n"; - throw std::out_of_range(words4); - } + Poco::StringTokenizer data(words4, " ", Poco::StringTokenizer::TOK_TRIM); + if (data.count() != 4) + { + g_log.warning() << "Algorithm list line " + words4 + " is not of the correct format\n"; + throw std::out_of_range(words4); + } - w1 = data[0]; - w2 = data[1]; - w3 = data[2]; - w4 = data[3]; - } + w1 = data[0]; + w2 = data[1]; + w3 = data[2]; + w4 = data[3]; + } //------------------------------------------------------------------------------------------------- - /** - * Read the bin masking information from the mantid_workspace_i/workspace group. - * @param wksp_cls :: The data group - * @param local_workspace :: The workspace to read into - */ - void LoadNexusProcessed::readBinMasking(NXData & wksp_cls, API::MatrixWorkspace_sptr local_workspace) - { - if (wksp_cls.getDataSetInfo("masked_spectra").stat == NX_ERROR) - { - return; - } - NXInt spec = wksp_cls.openNXInt("masked_spectra"); - spec.load(); - NXInt bins = wksp_cls.openNXInt("masked_bins"); - bins.load(); - NXDouble weights = wksp_cls.openNXDouble("mask_weights"); - weights.load(); - const int n = spec.dim0(); - const int n1 = n - 1; - for (int i = 0; i < n; ++i) + /** + * Read the bin masking information from the mantid_workspace_i/workspace group. + * @param wksp_cls :: The data group + * @param local_workspace :: The workspace to read into + */ + void LoadNexusProcessed::readBinMasking(NXData & wksp_cls, API::MatrixWorkspace_sptr local_workspace) { - int si = spec(i, 0); - int j0 = spec(i, 1); - int j1 = i < n1 ? spec(i + 1, 1) : bins.dim0(); - for (int j = j0; j < j1; ++j) + if (wksp_cls.getDataSetInfo("masked_spectra").stat == NX_ERROR) { - local_workspace->flagMasked(si, bins[j], weights[j]); + return; + } + NXInt spec = wksp_cls.openNXInt("masked_spectra"); + spec.load(); + NXInt bins = wksp_cls.openNXInt("masked_bins"); + bins.load(); + NXDouble weights = wksp_cls.openNXDouble("mask_weights"); + weights.load(); + const int n = spec.dim0(); + const int n1 = n - 1; + for (int i = 0; i < n; ++i) + { + int si = spec(i, 0); + int j0 = spec(i, 1); + int j1 = i < n1 ? spec(i + 1, 1) : bins.dim0(); + for (int j = j0; j < j1; ++j) + { + local_workspace->flagMasked(si, bins[j], weights[j]); + } } } - } - - /** - * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. This assumes that the - * xbins have alread been cached - * @param data :: The NXDataSet object of y values - * @param errors :: The NXDataSet object of error values - * @param farea :: The NXDataSet object of fraction area values - * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use - * @param blocksize :: The blocksize to use - * @param nchannels :: The number of channels for the block - * @param hist :: The workspace index to start reading into - * @param local_workspace :: A pointer to the workspace - */ - void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, NXDataSetTyped & errors, - NXDataSetTyped & farea, bool hasFArea, int64_t blocksize, int64_t nchannels, int64_t &hist, - API::MatrixWorkspace_sptr local_workspace) - { - data.load(static_cast(blocksize), static_cast(hist)); - errors.load(static_cast(blocksize), static_cast(hist)); - double *data_start = data(); - double *data_end = data_start + nchannels; - double *err_start = errors(); - double *err_end = err_start + nchannels; - double *farea_start = NULL; - double *farea_end = NULL; - RebinnedOutput_sptr rb_workspace; - if (hasFArea) - { - farea.load(static_cast(blocksize), static_cast(hist)); - farea_start = farea(); - farea_end = farea_start + nchannels; - rb_workspace = boost::dynamic_pointer_cast(local_workspace); - } - int64_t final(hist + blocksize); - while (hist < final) + + /** + * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. This assumes that the + * xbins have alread been cached + * @param data :: The NXDataSet object of y values + * @param errors :: The NXDataSet object of error values + * @param farea :: The NXDataSet object of fraction area values + * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use + * @param blocksize :: The blocksize to use + * @param nchannels :: The number of channels for the block + * @param hist :: The workspace index to start reading into + * @param local_workspace :: A pointer to the workspace + */ + void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, NXDataSetTyped & errors, + NXDataSetTyped & farea, bool hasFArea, int64_t blocksize, int64_t nchannels, + int64_t &hist, API::MatrixWorkspace_sptr local_workspace) { - MantidVec& Y = local_workspace->dataY(hist); - Y.assign(data_start, data_end); - data_start += nchannels; - data_end += nchannels; - MantidVec& E = local_workspace->dataE(hist); - E.assign(err_start, err_end); - err_start += nchannels; - err_end += nchannels; + data.load(static_cast(blocksize), static_cast(hist)); + errors.load(static_cast(blocksize), static_cast(hist)); + double *data_start = data(); + double *data_end = data_start + nchannels; + double *err_start = errors(); + double *err_end = err_start + nchannels; + double *farea_start = NULL; + double *farea_end = NULL; + RebinnedOutput_sptr rb_workspace; if (hasFArea) { - MantidVec& F = rb_workspace->dataF(hist); - F.assign(farea_start, farea_end); - farea_start += nchannels; - farea_end += nchannels; + farea.load(static_cast(blocksize), static_cast(hist)); + farea_start = farea(); + farea_end = farea_start + nchannels; + rb_workspace = boost::dynamic_pointer_cast(local_workspace); + } + int64_t final(hist + blocksize); + while (hist < final) + { + MantidVec& Y = local_workspace->dataY(hist); + Y.assign(data_start, data_end); + data_start += nchannels; + data_end += nchannels; + MantidVec& E = local_workspace->dataE(hist); + E.assign(err_start, err_end); + err_start += nchannels; + err_end += nchannels; + if (hasFArea) + { + MantidVec& F = rb_workspace->dataF(hist); + F.assign(farea_start, farea_end); + farea_start += nchannels; + farea_end += nchannels; + } + local_workspace->setX(hist, m_xbins); + ++hist; } - local_workspace->setX(hist, m_xbins); - ++hist; - } - } - - /** - * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. This assumes that the - * xbins have alread been cached - * @param data :: The NXDataSet object of y values - * @param errors :: The NXDataSet object of error values - * @param farea :: The NXDataSet object of fraction area values - * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use - * @param blocksize :: The blocksize to use - * @param nchannels :: The number of channels for the block - * @param hist :: The workspace index to start reading into - * @param wsIndex :: The workspace index to save data into - * @param local_workspace :: A pointer to the workspace - */ - - void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, NXDataSetTyped & errors, - NXDataSetTyped & farea, bool hasFArea, int64_t blocksize, int64_t nchannels, int64_t &hist, - int64_t& wsIndex, API::MatrixWorkspace_sptr local_workspace) - { - data.load(static_cast(blocksize), static_cast(hist)); - errors.load(static_cast(blocksize), static_cast(hist)); - double *data_start = data(); - double *data_end = data_start + nchannels; - double *err_start = errors(); - double *err_end = err_start + nchannels; - double *farea_start = NULL; - double *farea_end = NULL; - RebinnedOutput_sptr rb_workspace; - if (hasFArea) - { - farea.load(static_cast(blocksize), static_cast(hist)); - farea_start = farea(); - farea_end = farea_start + nchannels; - rb_workspace = boost::dynamic_pointer_cast(local_workspace); } - int64_t final(hist + blocksize); - while (hist < final) + + /** + * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. This assumes that the + * xbins have alread been cached + * @param data :: The NXDataSet object of y values + * @param errors :: The NXDataSet object of error values + * @param farea :: The NXDataSet object of fraction area values + * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use + * @param blocksize :: The blocksize to use + * @param nchannels :: The number of channels for the block + * @param hist :: The workspace index to start reading into + * @param wsIndex :: The workspace index to save data into + * @param local_workspace :: A pointer to the workspace + */ + + void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, NXDataSetTyped & errors, + NXDataSetTyped & farea, bool hasFArea, int64_t blocksize, int64_t nchannels, + int64_t &hist, int64_t& wsIndex, API::MatrixWorkspace_sptr local_workspace) { - MantidVec& Y = local_workspace->dataY(wsIndex); - Y.assign(data_start, data_end); - data_start += nchannels; - data_end += nchannels; - MantidVec& E = local_workspace->dataE(wsIndex); - E.assign(err_start, err_end); - err_start += nchannels; - err_end += nchannels; + data.load(static_cast(blocksize), static_cast(hist)); + errors.load(static_cast(blocksize), static_cast(hist)); + double *data_start = data(); + double *data_end = data_start + nchannels; + double *err_start = errors(); + double *err_end = err_start + nchannels; + double *farea_start = NULL; + double *farea_end = NULL; + RebinnedOutput_sptr rb_workspace; if (hasFArea) { - MantidVec& F = rb_workspace->dataF(wsIndex); - F.assign(farea_start, farea_end); - farea_start += nchannels; - farea_end += nchannels; + farea.load(static_cast(blocksize), static_cast(hist)); + farea_start = farea(); + farea_end = farea_start + nchannels; + rb_workspace = boost::dynamic_pointer_cast(local_workspace); } - local_workspace->setX(wsIndex, m_xbins); - ++hist; - ++wsIndex; + int64_t final(hist + blocksize); + while (hist < final) + { + MantidVec& Y = local_workspace->dataY(wsIndex); + Y.assign(data_start, data_end); + data_start += nchannels; + data_end += nchannels; + MantidVec& E = local_workspace->dataE(wsIndex); + E.assign(err_start, err_end); + err_start += nchannels; + err_end += nchannels; + if (hasFArea) + { + MantidVec& F = rb_workspace->dataF(wsIndex); + F.assign(farea_start, farea_end); + farea_start += nchannels; + farea_end += nchannels; + } + local_workspace->setX(wsIndex, m_xbins); + ++hist; + ++wsIndex; + } } - } - - /** - * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. The xbins are read along with - * each call to the data/error loading - * @param data :: The NXDataSet object of y values - * @param errors :: The NXDataSet object of error values - * @param farea :: The NXDataSet object of fraction area values - * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use - * @param xbins :: The xbin NXDataSet - * @param blocksize :: The blocksize to use - * @param nchannels :: The number of channels for the block - * @param hist :: The workspace index to start reading into - * @param wsIndex :: The workspace index to save data into - * @param local_workspace :: A pointer to the workspace - */ - void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, NXDataSetTyped & errors, - NXDataSetTyped & farea, bool hasFArea, NXDouble & xbins, int64_t blocksize, - int64_t nchannels, int64_t &hist, int64_t& wsIndex, API::MatrixWorkspace_sptr local_workspace) - { - data.load(static_cast(blocksize), static_cast(hist)); - double *data_start = data(); - double *data_end = data_start + nchannels; - errors.load(static_cast(blocksize), static_cast(hist)); - double *err_start = errors(); - double *err_end = err_start + nchannels; - double *farea_start = NULL; - double *farea_end = NULL; - RebinnedOutput_sptr rb_workspace; - if (hasFArea) - { - farea.load(static_cast(blocksize), static_cast(hist)); - farea_start = farea(); - farea_end = farea_start + nchannels; - rb_workspace = boost::dynamic_pointer_cast(local_workspace); - } - xbins.load(static_cast(blocksize), static_cast(hist)); - const int64_t nxbins(nchannels + 1); - double *xbin_start = xbins(); - double *xbin_end = xbin_start + nxbins; - int64_t final(hist + blocksize); - while (hist < final) + + /** + * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given blocksize. The xbins are read along with + * each call to the data/error loading + * @param data :: The NXDataSet object of y values + * @param errors :: The NXDataSet object of error values + * @param farea :: The NXDataSet object of fraction area values + * @param hasFArea :: Flag to signal a RebinnedOutput workspace is in use + * @param xbins :: The xbin NXDataSet + * @param blocksize :: The blocksize to use + * @param nchannels :: The number of channels for the block + * @param hist :: The workspace index to start reading into + * @param wsIndex :: The workspace index to save data into + * @param local_workspace :: A pointer to the workspace + */ + void LoadNexusProcessed::loadBlock(NXDataSetTyped & data, NXDataSetTyped & errors, + NXDataSetTyped & farea, bool hasFArea, NXDouble & xbins, int64_t blocksize, + int64_t nchannels, int64_t &hist, int64_t& wsIndex, API::MatrixWorkspace_sptr local_workspace) { - MantidVec& Y = local_workspace->dataY(wsIndex); - Y.assign(data_start, data_end); - data_start += nchannels; - data_end += nchannels; - MantidVec& E = local_workspace->dataE(wsIndex); - E.assign(err_start, err_end); - err_start += nchannels; - err_end += nchannels; + data.load(static_cast(blocksize), static_cast(hist)); + double *data_start = data(); + double *data_end = data_start + nchannels; + errors.load(static_cast(blocksize), static_cast(hist)); + double *err_start = errors(); + double *err_end = err_start + nchannels; + double *farea_start = NULL; + double *farea_end = NULL; + RebinnedOutput_sptr rb_workspace; if (hasFArea) { - MantidVec& F = rb_workspace->dataF(wsIndex); - F.assign(farea_start, farea_end); - farea_start += nchannels; - farea_end += nchannels; + farea.load(static_cast(blocksize), static_cast(hist)); + farea_start = farea(); + farea_end = farea_start + nchannels; + rb_workspace = boost::dynamic_pointer_cast(local_workspace); } - MantidVec& X = local_workspace->dataX(wsIndex); - X.assign(xbin_start, xbin_end); - xbin_start += nxbins; - xbin_end += nxbins; - ++hist; - ++wsIndex; - } - } - - /** - *Validates the optional 'spectra to read' properties, if they have been set - * @param numberofspectra :: number of spectrum - */ - void LoadNexusProcessed::checkOptionalProperties(const std::size_t numberofspectra) - { - //read in the settings passed to the algorithm - m_spec_list = getProperty("SpectrumList"); - m_spec_max = getProperty("SpectrumMax"); - m_spec_min = getProperty("SpectrumMin"); - //Are we using a list of spectra or all the spectra in a range? - m_list = !m_spec_list.empty(); - m_interval = (m_spec_max != Mantid::EMPTY_INT()) || (m_spec_min != 1); - if (m_spec_max == Mantid::EMPTY_INT()) - m_spec_max = 1; - - // Check validity of spectra list property, if set - if (m_list) - { - m_list = true; - const int64_t minlist = *min_element(m_spec_list.begin(), m_spec_list.end()); - const int64_t maxlist = *max_element(m_spec_list.begin(), m_spec_list.end()); - if (maxlist > static_cast(numberofspectra) || minlist == 0) + xbins.load(static_cast(blocksize), static_cast(hist)); + const int64_t nxbins(nchannels + 1); + double *xbin_start = xbins(); + double *xbin_end = xbin_start + nxbins; + int64_t final(hist + blocksize); + while (hist < final) { - g_log.error("Invalid list of spectra"); - throw std::invalid_argument("Inconsistent properties defined"); + MantidVec& Y = local_workspace->dataY(wsIndex); + Y.assign(data_start, data_end); + data_start += nchannels; + data_end += nchannels; + MantidVec& E = local_workspace->dataE(wsIndex); + E.assign(err_start, err_end); + err_start += nchannels; + err_end += nchannels; + if (hasFArea) + { + MantidVec& F = rb_workspace->dataF(wsIndex); + F.assign(farea_start, farea_end); + farea_start += nchannels; + farea_end += nchannels; + } + MantidVec& X = local_workspace->dataX(wsIndex); + X.assign(xbin_start, xbin_end); + xbin_start += nxbins; + xbin_end += nxbins; + ++hist; + ++wsIndex; } } - // Check validity of spectra range, if set - if (m_interval) + /** + *Validates the optional 'spectra to read' properties, if they have been set + * @param numberofspectra :: number of spectrum + */ + void LoadNexusProcessed::checkOptionalProperties(const std::size_t numberofspectra) { - m_interval = true; + //read in the settings passed to the algorithm + m_spec_list = getProperty("SpectrumList"); + m_spec_max = getProperty("SpectrumMax"); m_spec_min = getProperty("SpectrumMin"); - if (m_spec_min != 1 && m_spec_max == 1) - { - m_spec_max = numberofspectra; - } - if (m_spec_max < m_spec_min || m_spec_max > static_cast(numberofspectra)) + //Are we using a list of spectra or all the spectra in a range? + m_list = !m_spec_list.empty(); + m_interval = (m_spec_max != Mantid::EMPTY_INT()) || (m_spec_min != 1); + if (m_spec_max == Mantid::EMPTY_INT()) + m_spec_max = 1; + + // Check validity of spectra list property, if set + if (m_list) { - g_log.error("Invalid Spectrum min/max properties"); - throw std::invalid_argument("Inconsistent properties defined"); + m_list = true; + const int64_t minlist = *min_element(m_spec_list.begin(), m_spec_list.end()); + const int64_t maxlist = *max_element(m_spec_list.begin(), m_spec_list.end()); + if (maxlist > static_cast(numberofspectra) || minlist == 0) + { + g_log.error("Invalid list of spectra"); + throw std::invalid_argument("Inconsistent properties defined"); + } } - } - } - - /** - * Calculate the size of a workspace - * @param numberofspectra :: number of spectrums - * @return the size of a workspace - */ - size_t LoadNexusProcessed::calculateWorkspacesize(const std::size_t numberofspectra) - { - // Calculate the size of a workspace, given its number of spectra to read - int total_specs; - if (m_interval || m_list) - { + + // Check validity of spectra range, if set if (m_interval) { + m_interval = true; + m_spec_min = getProperty("SpectrumMin"); if (m_spec_min != 1 && m_spec_max == 1) { m_spec_max = numberofspectra; } - total_specs = static_cast(m_spec_max - m_spec_min + 1); - m_spec_max += 1; + if (m_spec_max < m_spec_min || m_spec_max > static_cast(numberofspectra)) + { + g_log.error("Invalid Spectrum min/max properties"); + throw std::invalid_argument("Inconsistent properties defined"); + } } - else - total_specs = 0; + } - if (m_list) + /** + * Calculate the size of a workspace + * @param numberofspectra :: number of spectrums + * @return the size of a workspace + */ + size_t LoadNexusProcessed::calculateWorkspacesize(const std::size_t numberofspectra) + { + // Calculate the size of a workspace, given its number of spectra to read + int total_specs; + if (m_interval || m_list) { if (m_interval) { - for (std::vector::iterator it = m_spec_list.begin(); it != m_spec_list.end();) - if (*it >= m_spec_min && *it < m_spec_max) - { - it = m_spec_list.erase(it); - } - else - ++it; + if (m_spec_min != 1 && m_spec_max == 1) + { + m_spec_max = numberofspectra; + } + total_specs = static_cast(m_spec_max - m_spec_min + 1); + m_spec_max += 1; + } + else + total_specs = 0; + + if (m_list) + { + if (m_interval) + { + for (std::vector::iterator it = m_spec_list.begin(); it != m_spec_list.end();) + if (*it >= m_spec_min && *it < m_spec_max) + { + it = m_spec_list.erase(it); + } + else + ++it; + } + if (m_spec_list.size() == 0) + m_list = false; + total_specs += static_cast(m_spec_list.size()); } - if (m_spec_list.size() == 0) - m_list = false; - total_specs += static_cast(m_spec_list.size()); } + else + { + total_specs = static_cast(numberofspectra); + m_spec_min = 1; + m_spec_max = static_cast(numberofspectra) + 1; + } + return total_specs; } - else - { - total_specs = static_cast(numberofspectra); - m_spec_min = 1; - m_spec_max = static_cast(numberofspectra) + 1; - } - return total_specs; - } -} // namespace DataHandling + } // namespace DataHandling } // namespace Mantid From ccc1c235df1cb2d613326730fd9c0421f0751754 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Wed, 29 Oct 2014 16:25:34 +0000 Subject: [PATCH 014/128] refs #10385. Test file is twice as fast now. There are lots of TODOs still to resolve. We also need to add tests for this sort of multiperiod loading. --- .../DataHandling/src/LoadNexusProcessed.cpp | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 000e1beb26bb..5b3f7368dbe5 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -28,6 +28,7 @@ #include #include #include "MantidDataObjects/PeaksWorkspace.h" +#include "MantidKernel/MultiThreaded.h" namespace Mantid { @@ -239,6 +240,8 @@ namespace Mantid API::Workspace_sptr tempWS = loadEntry(root, targetEntryName, 0, 1, spectraInfo /*Ignore to begin with*/ , false /*Do not Ignore spectrum/instrument information inputs, write them*/); + g_log.warning("loaded tempws"); + if (nWorkspaceEntries == 1 || !bDefaultEntryNumber) { // We have what we need. @@ -258,7 +261,9 @@ namespace Mantid //load names of each of the workspaces and check for a common stem std::vector names(nWorkspaceEntries + 1); - bool commonStem = checkForCommonNameStem(root, names); + bool commonStem = bIsMultiPeriod || checkForCommonNameStem(root, names); + + g_log.warning("got names"); //remove existing workspace and replace with the one being loaded bool wsExists = AnalysisDataService::Instance().doesExist(base_name); @@ -274,7 +279,11 @@ namespace Mantid base_name += "_"; const std::string prop_name = "OutputWorkspace_"; double nWorkspaceEntries_d = static_cast(nWorkspaceEntries); - for (int64_t p = 1; p <= nWorkspaceEntries; ++p) + + MatrixWorkspace_sptr tempWS2D = boost::dynamic_pointer_cast(tempWS); + + //PARALLEL_FOR_NO_WSP_CHECK() + for (int p = 1; p <= nWorkspaceEntries; ++p) { std::ostringstream os; os << p; @@ -291,7 +300,12 @@ namespace Mantid } else { + + + g_log.warning("Reading AS MULTIPERIOD"); + + /* // Clone the original workspace auto cloneAlg = this->createChildAlgorithm("CloneWorkspace"); cloneAlg->setProperty("InputWorkspace", tempWS); @@ -300,6 +314,27 @@ namespace Mantid MatrixWorkspace_sptr local_workspace_2d = boost::dynamic_pointer_cast( local_workspace); // Now overwrite the y, e and log values. + * + */ + + + + MatrixWorkspace_sptr local_workspace_2d = WorkspaceFactory::Instance().create(tempWS2D); + //PARALLEL_FOR_NO_WSP_CHECK() + for (int64_t i = 0; i < int64_t(local_workspace_2d->getNumberHistograms()); ++i) + { + //PARALLEL_START_INTERUPT_REGION + + local_workspace_2d->setX(i,tempWS2D->refX(i)); + + + // PARALLEL_END_INTERUPT_REGION + } + // PARALLEL_CHECK_INTERUPT_REGION + + + + local_workspace = local_workspace_2d; NXEntry mtdEntry = root.openEntry(basename + os.str()); NXData wsEntry = mtdEntry.openNXData("workspace"); // TODO. hardcoded group_name is HACK @@ -370,13 +405,18 @@ namespace Mantid // TODO need to handle spectrum intervals correctly. + // TODO reporting + } + //(LoadNexusProcessed_multiperiodadd) + //{ declareProperty( new WorkspaceProperty(prop_name + os.str(), wsName, Direction::Output)); //wksp_group->add(base_name + os.str()); wksp_group->addWorkspace(local_workspace); setProperty(prop_name + os.str(), local_workspace); + //} } // The group is the root property value From 757b0046c62a550e10f005d04fa2284fa4f18286 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Wed, 29 Oct 2014 17:32:04 +0000 Subject: [PATCH 015/128] refs #10385. Add failing test. We are not currently handling log extraction properly, which is why the test is failing. File size is just over the threshold, but shouldn't be a problem. I've tried to trim it down as much as possible. --- .../test/LoadNexusProcessedTest.h | 33 ++++++++++++++++++ .../UsageData/POLREF00004699_nexus.nxs | Bin 0 -> 1059354 bytes 2 files changed, 33 insertions(+) create mode 100644 Test/AutoTestData/UsageData/POLREF00004699_nexus.nxs diff --git a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h index 949347f4bc6a..792ea5ee6805 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h @@ -635,6 +635,39 @@ class LoadNexusProcessedTest : public CxxTest::TestSuite } } + void test_load_multiperiod_workspace() + { + LoadNexusProcessed loader; + loader.setChild(true); + loader.initialize(); + loader.setPropertyValue("Filename", "POLREF00004699_nexus.nxs"); + loader.setPropertyValue("OutputWorkspace", "ws"); + + TS_ASSERT( loader.execute() ); + + Workspace_sptr outWS = loader.getProperty("OutputWorkspace"); + WorkspaceGroup_sptr asGroupWS = boost::dynamic_pointer_cast(outWS); + TSM_ASSERT("We expect a group workspace back", asGroupWS); + TSM_ASSERT_EQUALS("We expect the size to be 2", 2, asGroupWS->size()); + MatrixWorkspace_sptr period1 = boost::dynamic_pointer_cast(asGroupWS->getItem(0)); + MatrixWorkspace_sptr period2 = boost::dynamic_pointer_cast(asGroupWS->getItem(1)); + TSM_ASSERT("We expect the group workspace is multiperiod", asGroupWS->isMultiperiod()); + TSM_ASSERT_EQUALS("X-data should be identical", period1->readX(0), period2->readX(0)); + TSM_ASSERT_DIFFERS("Y-data should be different", period1->readY(0), period2->readY(0)); + TSM_ASSERT_DIFFERS("E-data should be different", period1->readE(0), period2->readE(0)); + + TS_ASSERT(period1->getInstrument()); + TS_ASSERT(period2->getInstrument()); + + auto period1Logs = period1->run().getLogData(); + auto period2Logs = period2->run().getLogData(); + + TSM_ASSERT_EQUALS("We expect to have the same number of log entries", period1Logs.size(), period2Logs.size()); + + TSM_ASSERT_THROWS("Should only have a period 1 entry", period1->run().getLogData("period 2"), Exception::NotFoundError& ); + TSM_ASSERT_THROWS("Should only have a period 2 entry", period2->run().getLogData("period 1"), Exception::NotFoundError& ); + } + private: void doHistoryTest(MatrixWorkspace_sptr matrix_ws) { diff --git a/Test/AutoTestData/UsageData/POLREF00004699_nexus.nxs b/Test/AutoTestData/UsageData/POLREF00004699_nexus.nxs new file mode 100644 index 0000000000000000000000000000000000000000..abef271cfa79ddc710525ae0032c5a843977982b GIT binary patch literal 1059354 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 z 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

ORH!25);cW-w$*%t<3I_{10 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 G9{&gNw>g~v literal 0 HcmV?d00001 From ab1da07fcd610910084b5c5e6ee641efddba9322 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Thu, 30 Oct 2014 17:58:36 +0000 Subject: [PATCH 016/128] refs #10385. Remove log values This fixes the regression test. We clear the logs off the temporary workspace, that way we don't have to do a similar thing in the loop, and we avoid copying them over each time. This is not a fully formed solution, but it's a start. --- .../Framework/API/inc/MantidAPI/LogManager.h | 2 + Code/Mantid/Framework/API/src/LogManager.cpp | 11 ++++- .../DataHandling/src/LoadNexusProcessed.cpp | 49 +++++++------------ 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/LogManager.h b/Code/Mantid/Framework/API/inc/MantidAPI/LogManager.h index f717d6334a6c..0ad6ab635880 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/LogManager.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/LogManager.h @@ -150,6 +150,8 @@ namespace Mantid virtual void saveNexus(::NeXus::File * file, const std::string & group,bool keepOpen=false) const; /// Load the run from a NeXus file with a given group name virtual void loadNexus(::NeXus::File * file, const std::string & group,bool keepOpen=false); + /// Clear the logs + void clearLogs(); protected: /// A pointer to a property manager diff --git a/Code/Mantid/Framework/API/src/LogManager.cpp b/Code/Mantid/Framework/API/src/LogManager.cpp index 8f9f9c99af88..b85e60740697 100644 --- a/Code/Mantid/Framework/API/src/LogManager.cpp +++ b/Code/Mantid/Framework/API/src/LogManager.cpp @@ -434,13 +434,22 @@ using namespace Kernel; if (prop) { if (m_manager.existsProperty(prop->name() )) + { m_manager.removeProperty(prop->name() ); + } m_manager.declareProperty(prop); } } } if (!(group.empty()||keepOpen))file->closeGroup(); - + } + + /** + * Clear the logs. + */ + void LogManager::clearLogs() + { + m_manager.clear(); } //----------------------------------------------------------------------------------------------------------------------- diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 5b3f7368dbe5..ef412a0ac4c5 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -281,6 +281,7 @@ namespace Mantid double nWorkspaceEntries_d = static_cast(nWorkspaceEntries); MatrixWorkspace_sptr tempWS2D = boost::dynamic_pointer_cast(tempWS); + tempWS2D->mutableRun().clearLogs(); // Strip out any loaded logs. //PARALLEL_FOR_NO_WSP_CHECK() for (int p = 1; p <= nWorkspaceEntries; ++p) @@ -300,38 +301,12 @@ namespace Mantid } else { - - - - g_log.warning("Reading AS MULTIPERIOD"); - - /* - // Clone the original workspace - auto cloneAlg = this->createChildAlgorithm("CloneWorkspace"); - cloneAlg->setProperty("InputWorkspace", tempWS); - cloneAlg->execute(); - local_workspace = cloneAlg->getProperty("OutputWorkspace"); - MatrixWorkspace_sptr local_workspace_2d = boost::dynamic_pointer_cast( - local_workspace); - // Now overwrite the y, e and log values. - * - */ - - - MatrixWorkspace_sptr local_workspace_2d = WorkspaceFactory::Instance().create(tempWS2D); - //PARALLEL_FOR_NO_WSP_CHECK() - for (int64_t i = 0; i < int64_t(local_workspace_2d->getNumberHistograms()); ++i) - { - //PARALLEL_START_INTERUPT_REGION - - local_workspace_2d->setX(i,tempWS2D->refX(i)); - - - // PARALLEL_END_INTERUPT_REGION - } - // PARALLEL_CHECK_INTERUPT_REGION + for (int64_t i = 0; i < int64_t(local_workspace_2d->getNumberHistograms()); ++i) + { + local_workspace_2d->setX(i, tempWS2D->refX(i)); + } local_workspace = local_workspace_2d; @@ -362,7 +337,7 @@ namespace Mantid for (; histIndex < readStop;) { - if(histIndex >= readOptimumStop) + if (histIndex >= readOptimumStop) { blockSize = finalBlockSize; } @@ -393,6 +368,18 @@ namespace Mantid } } + std::string parameterStr; + m_cppFile->openPath(mtdEntry.path()); + try + { + // This loads logs, sample, and instrument. + local_workspace_2d->loadSampleAndLogInfoNexus(m_cppFile); + } catch (std::exception & e) + { + g_log.information("Error loading Instrument section of nxs file"); + g_log.information(e.what()); + } + // TODO deal with this not being a workspace2D // TODO deal with fractional area. From 8e03062228667837665c57b4ef45c5f95f82ef35 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Fri, 31 Oct 2014 09:31:53 +0000 Subject: [PATCH 017/128] refs #10385. Reporting added and extra property. Also better robustness around workspace type. --- .../DataHandling/src/LoadNexusProcessed.cpp | 60 ++++++++++++------- .../test/LoadNexusProcessedTest.h | 9 +++ 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index ef412a0ac4c5..7b7cd934e7b2 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -191,6 +191,7 @@ namespace Mantid declareProperty("EntryNumber", (int64_t) 0, mustBePositive, "The particular entry number to read. Default load all workspaces and creates a workspacegroup (default: read all entries)."); declareProperty("LoadHistory", true, "If true, the workspace history will be loaded"); + declareProperty(new PropertyWithValue("FastMultiPeriod", true, Direction::Input), "For multiperiod workspaces. Copy instrument, parameter and x-data rather than loading it directly for each workspace. Y, E and log information is always loaded." ); } //------------------------------------------------------------------------------------------------- @@ -250,6 +251,7 @@ namespace Mantid else { // We already know that this is a group workspace. Is it a true multiperiod workspace. + const bool bFastMultiPeriod = this->getProperty("FastMultiPeriod"); const bool bIsMultiPeriod = isMultiPeriodFile(nWorkspaceEntries, tempWS, g_log); const bool ignoreSpecInfo = !bIsMultiPeriod; // Multiperiod groups can reuse it. @@ -281,10 +283,23 @@ namespace Mantid double nWorkspaceEntries_d = static_cast(nWorkspaceEntries); MatrixWorkspace_sptr tempWS2D = boost::dynamic_pointer_cast(tempWS); - tempWS2D->mutableRun().clearLogs(); // Strip out any loaded logs. + bool bAccelleratedMultiPeriodLoading = false; + if (tempWS2D) + { + bAccelleratedMultiPeriodLoading = bIsMultiPeriod && bFastMultiPeriod; + tempWS2D->mutableRun().clearLogs(); // Strip out any loaded logs. That way we don't pay for copying that information around. + } + + if(bAccelleratedMultiPeriodLoading) + { + g_log.information("Accelerated multiperiod loading"); + } + else + { + g_log.information("Individual group loading"); + } - //PARALLEL_FOR_NO_WSP_CHECK() - for (int p = 1; p <= nWorkspaceEntries; ++p) + for (int64_t p = 1; p <= nWorkspaceEntries; ++p) { std::ostringstream os; os << p; @@ -293,13 +308,12 @@ namespace Mantid std::string wsName = buildWorkspaceName(names[p], base_name, p, commonStem); Workspace_sptr local_workspace; - if (!bIsMultiPeriod) - { - local_workspace = loadEntry(root, basename + os.str(), - static_cast(p - 1) / nWorkspaceEntries_d, 1. / nWorkspaceEntries_d, spectraInfo, - ignoreSpecInfo); - } - else + + /* + For multiperiod workspaces we can accelerate the loading by making resonable assumptions about the differences between the workspaces + Only Y, E and log data entries should vary. Therefore we can clone our temp workspace, and overwrite those things we are interested in. + */ + if (bAccelleratedMultiPeriodLoading) { MatrixWorkspace_sptr local_workspace_2d = WorkspaceFactory::Instance().create(tempWS2D); @@ -308,7 +322,6 @@ namespace Mantid local_workspace_2d->setX(i, tempWS2D->refX(i)); } - local_workspace = local_workspace_2d; NXEntry mtdEntry = root.openEntry(basename + os.str()); @@ -380,30 +393,31 @@ namespace Mantid g_log.information(e.what()); } - // TODO deal with this not being a workspace2D - // TODO deal with fractional area. - // TODO need to do the same as above, but to handle the remainder, so do same as above, but with blockSize = finalBlocSize; - - // TODO need to copy log values + // TODO need to handle spectrum intervals correctly. - // TODO need to guarantee m_shared_bins, or do we just assume this? + // TODO remove spectraInfo. - // TODO need to handle spectrum intervals correctly. + // TODO LoadNexus needs to forward "FastMultiPeriod". - // TODO reporting + const double fractionComplete = double(p-1)/double(nWorkspaceEntries); + progress(fractionComplete, "Loading multiperiod entry"); } + else // Fall-back for generic loading + { + local_workspace = loadEntry(root, basename + os.str(), + static_cast(p - 1) / nWorkspaceEntries_d, 1. / nWorkspaceEntries_d, spectraInfo, + ignoreSpecInfo); + } - //(LoadNexusProcessed_multiperiodadd) - //{ declareProperty( new WorkspaceProperty(prop_name + os.str(), wsName, Direction::Output)); - //wksp_group->add(base_name + os.str()); + wksp_group->addWorkspace(local_workspace); setProperty(prop_name + os.str(), local_workspace); - //} + } // The group is the root property value diff --git a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h index 792ea5ee6805..cf8a202e13f4 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h @@ -48,6 +48,15 @@ class LoadNexusProcessedTest : public CxxTest::TestSuite AnalysisDataService::Instance().clear(); } + void testFastMultiPeriodDefault() + { + LoadNexusProcessed alg; + alg.initialize(); + TS_ASSERT(alg.isInitialized()); + const bool bFastMultiPeriod = alg.getProperty("FastMultiPeriod"); + TSM_ASSERT("Should defalt to offering fast multiperiod loading", bFastMultiPeriod); + } + void testProcessedFile() { From aba603d5e0bef0c6a3c3babfef7edc0f46e955d8 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Fri, 31 Oct 2014 10:00:07 +0000 Subject: [PATCH 018/128] refs #10385 Refactor new functionality to method. Should read better now, although the entire algorithm is still a mess. --- .../MantidDataHandling/LoadNexusProcessed.h | 4 + .../DataHandling/src/LoadNexusProcessed.cpp | 197 +++++++++--------- 2 files changed, 105 insertions(+), 96 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h index b5c5e5ebd9fa..c5c952b79d0f 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h @@ -6,6 +6,7 @@ //---------------------------------------------------------------------- #include "MantidAPI/IFileLoader.h" #include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/MatrixWorkspace.h" #include "MantidNexus/NexusClasses.h" #include @@ -214,6 +215,9 @@ namespace Mantid /// calculates the workspace size std::size_t calculateWorkspacesize(const std::size_t numberofspectra); + + /// Accellerated multiperiod loading + Mantid::API::Workspace_sptr doAccelleratedMultiPeriodLoading(Mantid::NeXus::NXRoot & root, const std::string & entryName, Mantid::API::MatrixWorkspace_sptr& tempMatrixWorkspace, const int64_t nWorkspaceEntries, const int64_t i); /// Does the current workspace have uniform binning bool m_shared_bins; diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 7b7cd934e7b2..ae8d9f362959 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -194,6 +194,103 @@ namespace Mantid declareProperty(new PropertyWithValue("FastMultiPeriod", true, Direction::Input), "For multiperiod workspaces. Copy instrument, parameter and x-data rather than loading it directly for each workspace. Y, E and log information is always loaded." ); } + /** + * Loading specifically for mulitperiod group workspaces + * @param root : NXRoot ref + * @param entryName : Entry name to load. + * @param tempMatrixWorkspace : Template workspace to base the next multiperiod entry off. + * @param nWorkspaceEntries : N entries in the file + * @param i : index + 1 being processed. + * @return Next multiperiod group workspace + */ + Workspace_sptr LoadNexusProcessed::doAccelleratedMultiPeriodLoading(NXRoot & root, const std::string & entryName, MatrixWorkspace_sptr& tempMatrixWorkspace, const int64_t nWorkspaceEntries, const int64_t i) + { + + MatrixWorkspace_sptr periodWorkspace = WorkspaceFactory::Instance().create(tempMatrixWorkspace); + + const size_t nHistograms = periodWorkspace->getNumberHistograms(); + for (size_t i = 0; i < nHistograms; ++i) + { + periodWorkspace->setX(i, tempMatrixWorkspace->refX(i)); + } + + NXEntry mtdEntry = root.openEntry(entryName); + NXData wsEntry = mtdEntry.openNXData("workspace"); // TODO. hardcoded group_name is HACK + + NXDataSetTyped data = wsEntry.openDoubleData(); + NXDataSetTyped errors = wsEntry.openNXDouble("errors"); + + const int nSpectra = data.dim0(); + const int nChannels = data.dim1(); + + int64_t blockSize = 8; // Read block size. Set to 8 for efficiency. i.e. read 8 histograms at a time. + const int64_t nFullBlocks = nHistograms / blockSize; // Truncated number of full blocks to read. Remainder removed + const int64_t nRemainder = nHistograms % blockSize; // Remainder + const int64_t readOptimumStop = (nFullBlocks * blockSize); + const int64_t readStop = m_spec_max - 1; // HACK + const int64_t finalBlockSize = readStop - readOptimumStop; + + int64_t wsIndex = 0; + int64_t histIndex = 0; // HACK. This needs to be calculated. + + for (; histIndex < readStop;) + { + if (histIndex >= readOptimumStop) + { + blockSize = finalBlockSize; + } + + data.load(static_cast(blockSize), static_cast(histIndex)); + errors.load(static_cast(blockSize), static_cast(histIndex)); + + double *dataStart = data(); + double *dataEnd = dataStart + nChannels; + + double *errorStart = errors(); + double *errorEnd = errorStart + nChannels; + + int64_t final(histIndex + blockSize); + while (histIndex < final) + { + MantidVec& Y = periodWorkspace->dataY(wsIndex); + Y.assign(dataStart, dataEnd); + dataStart += nChannels; + dataEnd += nChannels; + MantidVec& E = periodWorkspace->dataE(wsIndex); + E.assign(errorStart, errorEnd); + errorStart += nChannels; + errorEnd += nChannels; + + ++wsIndex; + ++histIndex; + } + } + + std::string parameterStr; + m_cppFile->openPath(mtdEntry.path()); + try + { + // This loads logs, sample, and instrument. + periodWorkspace->loadSampleAndLogInfoNexus(m_cppFile); + } + catch (std::exception & e) + { + g_log.information("Error loading Instrument section of nxs file"); + g_log.information(e.what()); + } + + // TODO deal with fractional area. + + // TODO need to handle spectrum intervals correctly. + + // TODO remove spectraInfo. + + const double fractionComplete = double(i-1)/double(nWorkspaceEntries); + progress(fractionComplete, "Loading multiperiod entry"); + return periodWorkspace; + + } + //------------------------------------------------------------------------------------------------- /** Executes the algorithm. Reading in the file and creating and populating * the output workspace @@ -241,8 +338,6 @@ namespace Mantid API::Workspace_sptr tempWS = loadEntry(root, targetEntryName, 0, 1, spectraInfo /*Ignore to begin with*/ , false /*Do not Ignore spectrum/instrument information inputs, write them*/); - g_log.warning("loaded tempws"); - if (nWorkspaceEntries == 1 || !bDefaultEntryNumber) { // We have what we need. @@ -265,8 +360,6 @@ namespace Mantid std::vector names(nWorkspaceEntries + 1); bool commonStem = bIsMultiPeriod || checkForCommonNameStem(root, names); - g_log.warning("got names"); - //remove existing workspace and replace with the one being loaded bool wsExists = AnalysisDataService::Instance().doesExist(base_name); if (wsExists) @@ -282,12 +375,12 @@ namespace Mantid const std::string prop_name = "OutputWorkspace_"; double nWorkspaceEntries_d = static_cast(nWorkspaceEntries); - MatrixWorkspace_sptr tempWS2D = boost::dynamic_pointer_cast(tempWS); + MatrixWorkspace_sptr tempMatrixWorkspace = boost::dynamic_pointer_cast(tempWS); bool bAccelleratedMultiPeriodLoading = false; - if (tempWS2D) + if (tempMatrixWorkspace) { bAccelleratedMultiPeriodLoading = bIsMultiPeriod && bFastMultiPeriod; - tempWS2D->mutableRun().clearLogs(); // Strip out any loaded logs. That way we don't pay for copying that information around. + tempMatrixWorkspace->mutableRun().clearLogs(); // Strip out any loaded logs. That way we don't pay for copying that information around. } if(bAccelleratedMultiPeriodLoading) @@ -315,95 +408,7 @@ namespace Mantid */ if (bAccelleratedMultiPeriodLoading) { - MatrixWorkspace_sptr local_workspace_2d = WorkspaceFactory::Instance().create(tempWS2D); - - for (int64_t i = 0; i < int64_t(local_workspace_2d->getNumberHistograms()); ++i) - { - local_workspace_2d->setX(i, tempWS2D->refX(i)); - } - - local_workspace = local_workspace_2d; - - NXEntry mtdEntry = root.openEntry(basename + os.str()); - NXData wsEntry = mtdEntry.openNXData("workspace"); // TODO. hardcoded group_name is HACK - - NXDataSetTyped data = wsEntry.openDoubleData(); - NXDataSetTyped errors = wsEntry.openNXDouble("errors"); - - const int nSpectra = data.dim0(); - const int nChannels = data.dim1(); - - //// validate the optional spectrum parameters, if set - checkOptionalProperties(nSpectra); - // Actual number of spectra in output workspace (if only a range was going to be loaded) - const size_t nHistograms = calculateWorkspacesize(nSpectra); - - int64_t blockSize = 8; // Read block size. Set to 8 for efficiency. i.e. read 8 histograms at a time. - const int64_t nFullBlocks = nHistograms / blockSize; // Truncated number of full blocks to read. Remainder removed - const int64_t nRemainder = nHistograms % blockSize; // Remainder - const int64_t readOptimumStop = (nFullBlocks * blockSize); - const int64_t readStop = m_spec_max - 1; // HACK - const int64_t finalBlockSize = readStop - readOptimumStop; - - int64_t wsIndex = 0; - int64_t histIndex = 0; // HACK. This needs to be calculated. - - for (; histIndex < readStop;) - { - if (histIndex >= readOptimumStop) - { - blockSize = finalBlockSize; - } - - data.load(static_cast(blockSize), static_cast(histIndex)); - errors.load(static_cast(blockSize), static_cast(histIndex)); - - double *dataStart = data(); - double *dataEnd = dataStart + nChannels; - - double *errorStart = errors(); - double *errorEnd = errorStart + nChannels; - - int64_t final(histIndex + blockSize); - while (histIndex < final) - { - MantidVec& Y = local_workspace_2d->dataY(wsIndex); - Y.assign(dataStart, dataEnd); - dataStart += nChannels; - dataEnd += nChannels; - MantidVec& E = local_workspace_2d->dataE(wsIndex); - E.assign(errorStart, errorEnd); - errorStart += nChannels; - errorEnd += nChannels; - - ++wsIndex; - ++histIndex; - } - } - - std::string parameterStr; - m_cppFile->openPath(mtdEntry.path()); - try - { - // This loads logs, sample, and instrument. - local_workspace_2d->loadSampleAndLogInfoNexus(m_cppFile); - } catch (std::exception & e) - { - g_log.information("Error loading Instrument section of nxs file"); - g_log.information(e.what()); - } - - // TODO deal with fractional area. - - // TODO need to handle spectrum intervals correctly. - - // TODO remove spectraInfo. - - // TODO LoadNexus needs to forward "FastMultiPeriod". - - const double fractionComplete = double(p-1)/double(nWorkspaceEntries); - progress(fractionComplete, "Loading multiperiod entry"); - + local_workspace = doAccelleratedMultiPeriodLoading(root, basename + os.str(), tempMatrixWorkspace, nWorkspaceEntries, p); } else // Fall-back for generic loading { From d88bbe4abf5cdb342d58b79897e75486c14d9ce7 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Fri, 31 Oct 2014 10:13:49 +0000 Subject: [PATCH 019/128] refs #10385. Remove instrument info caching This does result in a speed up, but the caching is being bypassed at the moment since our strategy is to clone and overwrite. I've removed the caching code as part of the clean up, but I've kept the SpecInfo type around as it makes the usage clearer, and does not result in a performance penalty. --- .../MantidDataHandling/LoadNexusProcessed.h | 62 +------------ .../DataHandling/src/LoadNexusProcessed.cpp | 89 ++++++++++++++----- 2 files changed, 67 insertions(+), 84 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h index c5c952b79d0f..7d26c4f04352 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadNexusProcessed.h @@ -10,8 +10,6 @@ #include "MantidNexus/NexusClasses.h" #include -#include -#include namespace Mantid { @@ -19,61 +17,6 @@ namespace Mantid namespace DataHandling { - // Helper typedef - typedef boost::shared_array IntArray_shared; - - // Struct to contain spectrum information. - struct SpectraInfo - { - // Number of spectra - int nSpectra; - // Do we have any spectra - bool hasSpectra; - // Contains spectrum numbers for each workspace index - IntArray_shared spectraNumbers; - // Index of the detector in the workspace. - IntArray_shared detectorIndex; - // Number of detectors associated with each spectra - IntArray_shared detectorCount; - // Detector list contains a list of all of the detector numbers - IntArray_shared detectorList; - - SpectraInfo() : - nSpectra(0), hasSpectra(false) - { - } - - SpectraInfo(int _nSpectra, bool _hasSpectra, IntArray_shared _spectraNumbers, - IntArray_shared _detectorIndex, IntArray_shared _detectorCount, - IntArray_shared _detectorList) : - nSpectra(_nSpectra), hasSpectra(_hasSpectra), spectraNumbers(_spectraNumbers), detectorIndex( - _detectorIndex), detectorCount(_detectorCount), detectorList(_detectorList) - { - } - - SpectraInfo(const SpectraInfo& other) : nSpectra(other.nSpectra), hasSpectra(other.hasSpectra), spectraNumbers(other.spectraNumbers), detectorIndex( - other.detectorIndex), detectorCount(other.detectorCount), detectorList(other.detectorList) - { - } - - SpectraInfo& operator=(const SpectraInfo& other) - { - if (&other != this) - { - nSpectra = other.nSpectra; - hasSpectra = other.hasSpectra; - spectraNumbers = other.spectraNumbers; - detectorIndex = other.detectorIndex; - detectorCount = other.detectorCount; - detectorList = other.detectorList; - } - return *this; - } - }; - - // Helper typdef. - typedef boost::optional SpectraInfo_optional; - /** Loads a workspace from a NeXus Processed entry in a NeXus file. @@ -150,8 +93,7 @@ namespace Mantid /// Load a single entry API::Workspace_sptr loadEntry(Mantid::NeXus::NXRoot & root, const std::string & entry_name, - const double& progressStart, const double& progressRange - , SpectraInfo_optional& specInfo, bool ignoreSpecInfo); + const double& progressStart, const double& progressRange); API::Workspace_sptr loadTableEntry(Mantid::NeXus::NXEntry& entry); @@ -172,7 +114,7 @@ namespace Mantid /// Add a property to the sample object bool addSampleProperty(Mantid::NeXus::NXMainClass & sample_entry, const std::string & entryName, API::Sample& sampleDetails); /// Read the spectra - void readInstrumentGroup(Mantid::NeXus::NXEntry & mtd_entry, API::MatrixWorkspace_sptr local_workspace, SpectraInfo_optional& specInfo, bool ignoreSpecInfo); + void readInstrumentGroup(Mantid::NeXus::NXEntry & mtd_entry, API::MatrixWorkspace_sptr local_workspace); /// Splits a string of exactly three words into the separate words void getWordsInString(const std::string & words3, std::string & w1, std::string & w2, std::string & w3); /// Splits a string of exactly four words into the separate words diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index ae8d9f362959..f7c8f994d456 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,64 @@ namespace Mantid namespace { + // Helper typedef + typedef boost::shared_array IntArray_shared; + + // Struct to contain spectrum information. + struct SpectraInfo + { + // Number of spectra + int nSpectra; + // Do we have any spectra + bool hasSpectra; + // Contains spectrum numbers for each workspace index + IntArray_shared spectraNumbers; + // Index of the detector in the workspace. + IntArray_shared detectorIndex; + // Number of detectors associated with each spectra + IntArray_shared detectorCount; + // Detector list contains a list of all of the detector numbers + IntArray_shared detectorList; + + SpectraInfo() : + nSpectra(0), hasSpectra(false) + { + } + + SpectraInfo(int _nSpectra, bool _hasSpectra, IntArray_shared _spectraNumbers, + IntArray_shared _detectorIndex, IntArray_shared _detectorCount, + IntArray_shared _detectorList) : + nSpectra(_nSpectra), hasSpectra(_hasSpectra), spectraNumbers(_spectraNumbers), detectorIndex( + _detectorIndex), detectorCount(_detectorCount), detectorList(_detectorList) + { + } + + SpectraInfo(const SpectraInfo& other) : nSpectra(other.nSpectra), hasSpectra(other.hasSpectra), spectraNumbers(other.spectraNumbers), detectorIndex( + other.detectorIndex), detectorCount(other.detectorCount), detectorList(other.detectorList) + { + } + + /* + SpectraInfo& operator=(const SpectraInfo& other) + { + if (&other != this) + { + nSpectra = other.nSpectra; + hasSpectra = other.hasSpectra; + spectraNumbers = other.spectraNumbers; + detectorIndex = other.detectorIndex; + detectorCount = other.detectorCount; + detectorList = other.detectorList; + } + return *this; + } + */ + }; + + // Helper typdef. + typedef boost::optional SpectraInfo_optional; + + /** * Extract ALL the detector, spectrum number and workspace index mapping information. * @param mtd_entry @@ -334,9 +393,7 @@ namespace Mantid const std::string targetEntryName = os.str(); // Take the first real workspace obtainable. We need it even if loading groups. - SpectraInfo_optional spectraInfo; - API::Workspace_sptr tempWS = loadEntry(root, targetEntryName, 0, 1, spectraInfo /*Ignore to begin with*/ - , false /*Do not Ignore spectrum/instrument information inputs, write them*/); + API::Workspace_sptr tempWS = loadEntry(root, targetEntryName, 0, 1); if (nWorkspaceEntries == 1 || !bDefaultEntryNumber) { @@ -413,8 +470,7 @@ namespace Mantid else // Fall-back for generic loading { local_workspace = loadEntry(root, basename + os.str(), - static_cast(p - 1) / nWorkspaceEntries_d, 1. / nWorkspaceEntries_d, spectraInfo, - ignoreSpecInfo); + static_cast(p - 1) / nWorkspaceEntries_d, 1. / nWorkspaceEntries_d); } declareProperty( @@ -1064,13 +1120,10 @@ int64_t index_start = indices[wi]; * @param entry_name :: The entry name * @param progressStart :: The percentage value to start the progress reporting for this entry * @param progressRange :: The percentage range that the progress reporting should cover - * @param specInfo :: Spectrum information object - * @param ignoreSpecInfo :: true to skip reading and wrting to optional specInfo * @returns A 2D workspace containing the loaded data */ API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot & root, const std::string & entry_name, - const double& progressStart, const double& progressRange, SpectraInfo_optional& specInfo, - bool ignoreSpecInfo) + const double& progressStart, const double& progressRange) { progress(progressStart, "Opening entry " + entry_name + "..."); @@ -1426,7 +1479,7 @@ int64_t index_start = indices[wi]; } // Now assign the spectra-detector map - readInstrumentGroup(mtd_entry, local_workspace, specInfo, ignoreSpecInfo); + readInstrumentGroup(mtd_entry, local_workspace); // Parameter map parsing progress(progressStart + 0.11 * progressRange, "Reading the parameter maps..."); @@ -1460,19 +1513,13 @@ int64_t index_start = indices[wi]; * Read the instrument group * @param mtd_entry :: The node for the current workspace * @param local_workspace :: The workspace to attach the instrument - * @param inOutSpecInfo :: Spectrum information - * @param ignoreSpecInfo :: If True ignore input spectrum info and obtain it yourself. */ void LoadNexusProcessed::readInstrumentGroup(NXEntry & mtd_entry, - API::MatrixWorkspace_sptr local_workspace, SpectraInfo_optional& inOutSpecInfo, - bool ignoreSpecInfo) + API::MatrixWorkspace_sptr local_workspace) { // Get spectrum information for the current entry. - const bool bUseExistingInfo = inOutSpecInfo.is_initialized() && !ignoreSpecInfo; - - SpectraInfo spectraInfo = - bUseExistingInfo ? inOutSpecInfo.get() : extractMappingInfo(mtd_entry, this->g_log); + SpectraInfo spectraInfo = extractMappingInfo(mtd_entry, this->g_log); //Now build the spectra list int index = 0; @@ -1510,12 +1557,6 @@ int64_t index_start = indices[wi]; spectraInfo.detectorList.get() + end)); } } - - // We can write the spec info under the following conditions. - if (!inOutSpecInfo.is_initialized() && !ignoreSpecInfo) - { - inOutSpecInfo = spectraInfo; - } } //------------------------------------------------------------------------------------------------- From 5b18d28967654bbbfa5f76fd32b1a2245977b7b1 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Fri, 31 Oct 2014 12:20:27 +0000 Subject: [PATCH 020/128] refs #10385. Minor changes. --- .../DataHandling/src/LoadNexusProcessed.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index f7c8f994d456..813d1f012196 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -290,7 +290,7 @@ namespace Mantid const int64_t finalBlockSize = readStop - readOptimumStop; int64_t wsIndex = 0; - int64_t histIndex = 0; // HACK. This needs to be calculated. + int64_t histIndex = m_spec_min - 1; for (; histIndex < readStop;) { @@ -432,7 +432,7 @@ namespace Mantid const std::string prop_name = "OutputWorkspace_"; double nWorkspaceEntries_d = static_cast(nWorkspaceEntries); - MatrixWorkspace_sptr tempMatrixWorkspace = boost::dynamic_pointer_cast(tempWS); + MatrixWorkspace_sptr tempMatrixWorkspace = boost::dynamic_pointer_cast(tempWS); bool bAccelleratedMultiPeriodLoading = false; if (tempMatrixWorkspace) { @@ -1160,7 +1160,6 @@ int64_t index_start = indices[wi]; // Axis information // "X" axis - // ---- START NOT REQUIRED PER PERIOD --- NXDouble xbins = wksp_cls.openNXDouble("axis1"); xbins.load(); std::string unit1 = xbins.attributes("units"); @@ -1174,7 +1173,7 @@ int64_t index_start = indices[wi]; else if (xbins.rank() == 1) { xlength = xbins.dim0(); - m_shared_bins = true; //SHOULD BE THE CASE FOR MULTIPERIOD DATA!!!!! + m_shared_bins = true; xbins.load(); m_xbins.access().assign(xbins(), xbins() + xlength); } @@ -1182,13 +1181,11 @@ int64_t index_start = indices[wi]; { throw std::runtime_error("Unknown axis1 dimension encountered."); } - // ---- END NOT REQUIRED PER PERIOD --- - // ---- START NOT REQUIRED PER PERIOD --- // MatrixWorkspace axis 1 NXDouble axis2 = wksp_cls.openNXDouble("axis2"); std::string unit2 = axis2.attributes("units"); - // ---- END NOT REQUIRED PER PERIOD --- + // The workspace being worked on API::MatrixWorkspace_sptr local_workspace; @@ -1241,7 +1238,7 @@ int64_t index_start = indices[wi]; readBinMasking(wksp_cls, local_workspace); NXDataSetTyped errors = wksp_cls.openNXDouble("errors"); - NXDataSetTyped fracarea = wksp_cls.openNXDouble("errors"); + NXDataSetTyped fracarea = errors; if (hasFracArea) { fracarea = wksp_cls.openNXDouble("frac_area"); From fb70f730ed01cb46d4a4e064fb989b95ce7e6aed Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Fri, 31 Oct 2014 12:37:19 +0000 Subject: [PATCH 021/128] refs #10385. Put error identifer code in place. --- .../DataHandling/src/LoadNexusProcessed.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 813d1f012196..de2183161e4c 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -274,7 +274,21 @@ namespace Mantid } NXEntry mtdEntry = root.openEntry(entryName); - NXData wsEntry = mtdEntry.openNXData("workspace"); // TODO. hardcoded group_name is HACK + const std::string groupName = "workspace"; + if (!mtdEntry.containsGroup(groupName)) + { + std::stringstream buffer; + buffer << "Group entry " << i - 1 << " is not a workspace 2D. Retry with FastMultiPeriod option set off." << std::endl; + throw std::runtime_error(buffer.str()); + } + + NXData wsEntry = mtdEntry.openNXData(groupName); + if (wsEntry.isValid("frac_area")) + { + std::stringstream buffer; + buffer << "Group entry " << i - 1 << " has fractional area present. Try reloading with FastMultiPeriod set off." << std::endl; + throw std::runtime_error(buffer.str()); + } NXDataSetTyped data = wsEntry.openDoubleData(); NXDataSetTyped errors = wsEntry.openNXDouble("errors"); From ce10e438130d7a0d0aa3684f6ed5c90b9d9b5d0f Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Fri, 31 Oct 2014 12:56:50 +0000 Subject: [PATCH 022/128] refs #10385 Extend tests. Extend tests. Do not process spectrum lists. --- .../DataHandling/src/LoadNexusProcessed.cpp | 11 +- .../test/LoadNexusProcessedTest.h | 1006 +++++++++-------- 2 files changed, 521 insertions(+), 496 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index de2183161e4c..88c2e08fb0fd 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -352,12 +352,6 @@ namespace Mantid g_log.information(e.what()); } - // TODO deal with fractional area. - - // TODO need to handle spectrum intervals correctly. - - // TODO remove spectraInfo. - const double fractionComplete = double(i-1)/double(nWorkspaceEntries); progress(fractionComplete, "Loading multiperiod entry"); return periodWorkspace; @@ -420,6 +414,8 @@ namespace Mantid const bool bFastMultiPeriod = this->getProperty("FastMultiPeriod"); const bool bIsMultiPeriod = isMultiPeriodFile(nWorkspaceEntries, tempWS, g_log); const bool ignoreSpecInfo = !bIsMultiPeriod; // Multiperiod groups can reuse it. + Property * specListProp = this->getProperty("SpectrumList"); + m_list = !specListProp->isDefault(); // Load all first level entries WorkspaceGroup_sptr wksp_group(new WorkspaceGroup); @@ -450,7 +446,8 @@ namespace Mantid bool bAccelleratedMultiPeriodLoading = false; if (tempMatrixWorkspace) { - bAccelleratedMultiPeriodLoading = bIsMultiPeriod && bFastMultiPeriod; + // We only accelerate for simple scenarios for now. Spectrum lists are too complicated to bother with. + bAccelleratedMultiPeriodLoading = bIsMultiPeriod && bFastMultiPeriod && !m_list; tempMatrixWorkspace->mutableRun().clearLogs(); // Strip out any loaded logs. That way we don't pay for copying that information around. } diff --git a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h index cf8a202e13f4..19978f69babe 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h @@ -30,15 +30,20 @@ using Mantid::detid_t; // LoadRawSaveNxsLoadNxs should be run when making any changes to LoadNexusProcessed // in addition to this test. -class LoadNexusProcessedTest : public CxxTest::TestSuite +class LoadNexusProcessedTest: public CxxTest::TestSuite { public: - static LoadNexusProcessedTest *createSuite() { return new LoadNexusProcessedTest(); } - static void destroySuite(LoadNexusProcessedTest *suite) { delete suite; } + static LoadNexusProcessedTest *createSuite() + { + return new LoadNexusProcessedTest(); + } + static void destroySuite(LoadNexusProcessedTest *suite) + { + delete suite; + } LoadNexusProcessedTest() : - testFile("GEM38370_Focussed_Legacy.nxs"), - output_ws("nxstest") + testFile("GEM38370_Focussed_Legacy.nxs"), output_ws("nxstest") { } @@ -63,21 +68,20 @@ class LoadNexusProcessedTest : public CxxTest::TestSuite LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); + TS_ASSERT( alg.isInitialized()); alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); TS_ASSERT_THROWS_NOTHING(alg.execute()); - + //Test some aspects of the file Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws) ); - TS_ASSERT( workspace.get() ); + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); + TS_ASSERT( workspace.get()); MatrixWorkspace_sptr matrix_ws = boost::dynamic_pointer_cast(workspace); - TS_ASSERT( matrix_ws.get() ); - + TS_ASSERT( matrix_ws.get()); // Test proton charge from the sample block TS_ASSERT_DELTA(matrix_ws->run().getProtonCharge(), 30.14816, 1e-5); @@ -87,7 +91,7 @@ class LoadNexusProcessedTest : public CxxTest::TestSuite boost::shared_ptr inst = matrix_ws->getInstrument(); TS_ASSERT_EQUALS(inst->getName(), "GEM"); TS_ASSERT_EQUALS(inst->getSource()->getPos().Z(), -17); - } + } void testNexusProcessed_Min_Max() { @@ -95,587 +99,611 @@ class LoadNexusProcessedTest : public CxxTest::TestSuite LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - testFile="focussed.nxs"; + TS_ASSERT( alg.isInitialized()); + testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); - alg.setPropertyValue("SpectrumMin","2"); - alg.setPropertyValue("SpectrumMax","4"); + alg.setPropertyValue("SpectrumMin", "2"); + alg.setPropertyValue("SpectrumMax", "4"); TS_ASSERT_THROWS_NOTHING(alg.execute()); - TS_ASSERT( alg.isExecuted() ); - + TS_ASSERT( alg.isExecuted()); + //Test some aspects of the file Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws) ); - TS_ASSERT( workspace.get() ); + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); + TS_ASSERT( workspace.get()); MatrixWorkspace_sptr matrix_ws = boost::dynamic_pointer_cast(workspace); - TS_ASSERT( matrix_ws.get() ); + TS_ASSERT( matrix_ws.get()); - //Testing the number of histograms - TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(),3); + //Testing the number of histograms + TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(), 3); doHistoryTest(matrix_ws); - + boost::shared_ptr inst = matrix_ws->getInstrument(); TS_ASSERT_EQUALS(inst->getName(), "GEM"); TS_ASSERT_EQUALS(inst->getSource()->getPos().Z(), -17); - } + } void testNexusProcessed_List() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - testFile="focussed.nxs"; + TS_ASSERT( alg.isInitialized()); + testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); - alg.setPropertyValue("SpectrumList","1,2,3,4"); + alg.setPropertyValue("SpectrumList", "1,2,3,4"); TS_ASSERT_THROWS_NOTHING(alg.execute()); - TS_ASSERT( alg.isExecuted() ); - + TS_ASSERT( alg.isExecuted()); + //Test some aspects of the file Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws) ); - TS_ASSERT( workspace.get() ); + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); + TS_ASSERT( workspace.get()); MatrixWorkspace_sptr matrix_ws = boost::dynamic_pointer_cast(workspace); - TS_ASSERT( matrix_ws.get() ); + TS_ASSERT( matrix_ws.get()); - //Testing the number of histograms - TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(),4); + //Testing the number of histograms + TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(), 4); //Test history doHistoryTest(matrix_ws); - + boost::shared_ptr inst = matrix_ws->getInstrument(); TS_ASSERT_EQUALS(inst->getName(), "GEM"); TS_ASSERT_EQUALS(inst->getSource()->getPos().Z(), -17); - } + } void testNexusProcessed_Min_Max_List() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - testFile="focussed.nxs"; + TS_ASSERT( alg.isInitialized()); + testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); - alg.setPropertyValue("SpectrumMin","1"); - alg.setPropertyValue("SpectrumMax","3"); - alg.setPropertyValue("SpectrumList","4,5"); + alg.setPropertyValue("SpectrumMin", "1"); + alg.setPropertyValue("SpectrumMax", "3"); + alg.setPropertyValue("SpectrumList", "4,5"); TS_ASSERT_THROWS_NOTHING(alg.execute()); - + //Test some aspects of the file Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws) ); - TS_ASSERT( workspace.get() ); + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); + TS_ASSERT( workspace.get()); MatrixWorkspace_sptr matrix_ws = boost::dynamic_pointer_cast(workspace); - TS_ASSERT( matrix_ws.get() ); + TS_ASSERT( matrix_ws.get()); - //Testing the number of histograms - TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(),5); + //Testing the number of histograms + TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(), 5); //Test history doHistoryTest(matrix_ws); - + boost::shared_ptr inst = matrix_ws->getInstrument(); TS_ASSERT_EQUALS(inst->getName(), "GEM"); TS_ASSERT_EQUALS(inst->getSource()->getPos().Z(), -17); - } + } void testNexusProcessed_Min() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - testFile="focussed.nxs"; + TS_ASSERT( alg.isInitialized()); + testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); - alg.setPropertyValue("SpectrumMin","4"); - + alg.setPropertyValue("SpectrumMin", "4"); + TS_ASSERT_THROWS_NOTHING(alg.execute()); - + //Test some aspects of the file Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws) ); - TS_ASSERT( workspace.get() ); + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); + TS_ASSERT( workspace.get()); MatrixWorkspace_sptr matrix_ws = boost::dynamic_pointer_cast(workspace); - TS_ASSERT( matrix_ws.get() ); + TS_ASSERT( matrix_ws.get()); - //Testing the number of histograms - TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(),3); + //Testing the number of histograms + TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(), 3); //Test history doHistoryTest(matrix_ws); - + boost::shared_ptr inst = matrix_ws->getInstrument(); TS_ASSERT_EQUALS(inst->getName(), "GEM"); TS_ASSERT_EQUALS(inst->getSource()->getPos().Z(), -17); - } + } - void testNexusProcessed_Max() + void testNexusProcessed_Max() { LoadNexusProcessed alg; TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - testFile="focussed.nxs"; + TS_ASSERT( alg.isInitialized()); + testFile = "focussed.nxs"; alg.setPropertyValue("Filename", testFile); alg.setPropertyValue("OutputWorkspace", output_ws); - alg.setPropertyValue("SpectrumMax","3"); - + alg.setPropertyValue("SpectrumMax", "3"); + TS_ASSERT_THROWS_NOTHING(alg.execute()); - + //Test some aspects of the file Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws) ); - TS_ASSERT( workspace.get() ); + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); + TS_ASSERT( workspace.get()); MatrixWorkspace_sptr matrix_ws = boost::dynamic_pointer_cast(workspace); - TS_ASSERT( matrix_ws.get() ); + TS_ASSERT( matrix_ws.get()); - //Testing the number of histograms - TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(),3); + //Testing the number of histograms + TS_ASSERT_EQUALS(matrix_ws->getNumberHistograms(), 3); //Test history doHistoryTest(matrix_ws); - + boost::shared_ptr inst = matrix_ws->getInstrument(); TS_ASSERT_EQUALS(inst->getName(), "GEM"); TS_ASSERT_EQUALS(inst->getSource()->getPos().Z(), -17); - } - - - // Saving and reading masking correctly - void testMasked() - { - LoadNexusProcessed alg; - - TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - testFile="focussed.nxs"; - alg.setPropertyValue("Filename", testFile); - testFile = alg.getPropertyValue("Filename"); - - alg.setPropertyValue("OutputWorkspace", output_ws); - - TS_ASSERT_THROWS_NOTHING(alg.execute()); - - //Test some aspects of the file - MatrixWorkspace_sptr workspace; - workspace = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve(output_ws) ); - TS_ASSERT( workspace.get() ); - - for(size_t si = 0; si < workspace->getNumberHistograms(); ++si) - { - workspace->maskBin(si,0,1.0); - workspace->maskBin(si,1,1.0); - workspace->maskBin(si,2,1.0); - } - - SaveNexusProcessed save; - save.initialize(); - save.setPropertyValue("InputWorkspace",output_ws); - std::string filename = "LoadNexusProcessed_tmp.nxs"; - save.setPropertyValue("Filename",filename); - filename = save.getPropertyValue("Filename"); - save.execute(); - LoadNexusProcessed load; - load.initialize(); - load.setPropertyValue("Filename",filename); - load.setPropertyValue("OutputWorkspace",output_ws); - load.execute(); - - workspace = boost::dynamic_pointer_cast(AnalysisDataService::Instance().retrieve(output_ws) ); - TS_ASSERT( workspace.get() ); - - TS_ASSERT_EQUALS(workspace->getNumberHistograms(),6); - - TS_ASSERT(workspace->hasMaskedBins(0)); - TS_ASSERT(workspace->hasMaskedBins(1)); - TS_ASSERT(workspace->hasMaskedBins(2)); - TS_ASSERT(workspace->hasMaskedBins(3)); - TS_ASSERT(workspace->hasMaskedBins(4)); - TS_ASSERT(workspace->hasMaskedBins(5)); - - if( Poco::File(filename).exists() ) - Poco::File(filename).remove(); - } - - void dotest_LoadAnEventFile(EventType type) - { - std::string filename_root = "LoadNexusProcessed_ExecEvent_"; - - // Call a function that writes out the file - std::string outputFile; - EventWorkspace_sptr origWS = SaveNexusProcessedTest::do_testExec_EventWorkspaces(filename_root, type, outputFile, false, false); - - LoadNexusProcessed alg; - TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - alg.setPropertyValue("Filename", outputFile); - alg.setPropertyValue("OutputWorkspace", output_ws); - - TS_ASSERT_THROWS_NOTHING(alg.execute()); - - //Test some aspects of the file - Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws) ); - TS_ASSERT( workspace.get() ); - - EventWorkspace_sptr ws = boost::dynamic_pointer_cast(workspace); - TS_ASSERT( ws ); - if (!ws) return; - - //Testing the number of histograms - TS_ASSERT_EQUALS(ws->getNumberHistograms(),5); - - for (size_t wi=0; wi < 5; wi++) - { - const EventList & el = ws->getEventList(wi); - TS_ASSERT_EQUALS( el.getEventType(), type ); - TS_ASSERT( el.hasDetectorID(detid_t(wi+1)*10) ); - } - TS_ASSERT_EQUALS( ws->getEventList(0).getNumberEvents(), 300 ); - TS_ASSERT_EQUALS( ws->getEventList(1).getNumberEvents(), 100 ); - TS_ASSERT_EQUALS( ws->getEventList(2).getNumberEvents(), 200 ); - TS_ASSERT_EQUALS( ws->getEventList(3).getNumberEvents(), 0 ); - TS_ASSERT_EQUALS( ws->getEventList(4).getNumberEvents(), 100 ); - - // Do the comparison algo to check that they really are the same - origWS->sortAll(TOF_SORT, NULL); - ws->sortAll(TOF_SORT, NULL); - - IAlgorithm_sptr alg2 = AlgorithmManager::Instance().createUnmanaged("CheckWorkspacesMatch"); - alg2->initialize(); - alg2->setProperty("Workspace1",origWS); - alg2->setProperty("Workspace2",ws); - alg2->setProperty("Tolerance", 1e-5); - alg2->setProperty("CheckAxes", false); - alg2->execute(); - if (alg2->isExecuted()) - { - TS_ASSERT (alg2->getPropertyValue("Result") == "Success!"); - } - else - { - TS_ASSERT ( false ); - } - - //Clear old file - if( Poco::File(outputFile).exists() ) Poco::File(outputFile).remove(); - - } - - void test_LoadEventNexus_TOF() - { - dotest_LoadAnEventFile(TOF); - } - - void test_LoadEventNexus_WEIGHTED() - { - dotest_LoadAnEventFile(WEIGHTED); - } - - void test_LoadEventNexus_WEIGHTED_NOTIME() - { - dotest_LoadAnEventFile(WEIGHTED_NOTIME); - } - - void test_load_saved_workspace_group() - { - LoadNexusProcessed alg; - TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - alg.setPropertyValue("Filename", "WorkspaceGroup.nxs"); - alg.setPropertyValue("OutputWorkspace", "group"); - - TS_ASSERT_THROWS_NOTHING(alg.execute()); - - Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group") ); - WorkspaceGroup_sptr group = boost::dynamic_pointer_cast( workspace ); - TS_ASSERT( group ); - int groupSize = group->getNumberOfEntries(); - TS_ASSERT_EQUALS( groupSize, 12 ); - for(int i = 0; i < groupSize; ++i) - { - MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast( group->getItem(i) ); - TS_ASSERT( ws ); - TS_ASSERT_EQUALS( ws->getNumberHistograms(), 1 ); - TS_ASSERT_EQUALS( ws->blocksize(), 10 ); - TS_ASSERT_EQUALS( ws->name(), "group_" + boost::lexical_cast( i + 1 ) ); - } - - } - - void test_load_workspace_group_unique_names() - { - LoadNexusProcessed alg; - TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - - //Group two uses unique names for each workspace - alg.setPropertyValue("Filename", "WorkspaceGroup2.nxs"); - alg.setPropertyValue("OutputWorkspace", "group"); - - const char* suffix[] = {"eq2", "eq1", "elf"}; - TS_ASSERT_THROWS_NOTHING(alg.execute()); - - Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group") ); - WorkspaceGroup_sptr group = boost::dynamic_pointer_cast( workspace ); - TS_ASSERT( group ); - int groupSize = group->getNumberOfEntries(); - TS_ASSERT_EQUALS( groupSize, 3); - for(int i = 0; i < groupSize; ++i) - { - MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast( group->getItem(i) ); - TS_ASSERT( ws ); - TS_ASSERT_EQUALS( ws->getNumberHistograms(), 1 ); - TS_ASSERT_EQUALS( ws->blocksize(), 2 ); - TS_ASSERT_EQUALS( ws->name(), "irs55125_graphite002_to_55131_" + std::string(suffix[i])); - } - } - - void test_load_workspace_group_unique_names_two_workspaces() - { - LoadNexusProcessed alg; - TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - - //Group two uses unique names for each workspace - alg.setPropertyValue("Filename", "WorkspaceGroup2.nxs"); - alg.setPropertyValue("OutputWorkspace", "group"); - - const char* suffix[] = {"eq2", "eq1", "elf"}; - TS_ASSERT_THROWS_NOTHING(alg.execute()); - - Workspace_sptr workspace; - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group") ); - WorkspaceGroup_sptr group = boost::dynamic_pointer_cast( workspace ); - TS_ASSERT( group ); - int groupSize = group->getNumberOfEntries(); - TS_ASSERT_EQUALS( groupSize, 3); - for(int i = 0; i < groupSize; ++i) - { - MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast( group->getItem(i) ); - TS_ASSERT( ws ); - TS_ASSERT_EQUALS( ws->getNumberHistograms(), 1 ); - TS_ASSERT_EQUALS( ws->blocksize(), 2 ); - TS_ASSERT_EQUALS( ws->name(), "irs55125_graphite002_to_55131_" + std::string(suffix[i])); - } - - //load same file again, but to a different group - //this checks that the names will be unique - - LoadNexusProcessed alg2; - TS_ASSERT_THROWS_NOTHING(alg2.initialize()); - TS_ASSERT( alg2.isInitialized() ); - - //Group two uses unique names for each workspace - alg2.setPropertyValue("Filename", "WorkspaceGroup2.nxs"); - alg2.setPropertyValue("OutputWorkspace", "group2"); - - TS_ASSERT_THROWS_NOTHING(alg2.execute()); - TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group2") ); - group = boost::dynamic_pointer_cast( workspace ); - TS_ASSERT( group ); - groupSize = group->getNumberOfEntries(); - TS_ASSERT_EQUALS( groupSize, 3); - - for(int i = 0; i < groupSize; ++i) - { - MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast( group->getItem(i) ); - TS_ASSERT( ws ); - TS_ASSERT_EQUALS( ws->getNumberHistograms(), 1 ); - TS_ASSERT_EQUALS( ws->blocksize(), 2 ); - TS_ASSERT_EQUALS( ws->name(), "irs55125_graphite002_to_55131_" + std::string(suffix[i]) + "_1"); - } - } - - - void test_load_fit_parameters() - { - LoadNexusProcessed alg; - TS_ASSERT_THROWS_NOTHING(alg.initialize()); - TS_ASSERT( alg.isInitialized() ); - alg.setPropertyValue("Filename", "HRP38692a.nxs"); - alg.setPropertyValue("OutputWorkspace", "HRPDparameters"); - - TS_ASSERT_THROWS_NOTHING(alg.execute()); + } + + // Saving and reading masking correctly + void testMasked() + { + LoadNexusProcessed alg; + + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + TS_ASSERT( alg.isInitialized()); + testFile = "focussed.nxs"; + alg.setPropertyValue("Filename", testFile); + testFile = alg.getPropertyValue("Filename"); + + alg.setPropertyValue("OutputWorkspace", output_ws); + + TS_ASSERT_THROWS_NOTHING(alg.execute()); + + //Test some aspects of the file + MatrixWorkspace_sptr workspace; + workspace = boost::dynamic_pointer_cast( + AnalysisDataService::Instance().retrieve(output_ws)); + TS_ASSERT( workspace.get()); + + for (size_t si = 0; si < workspace->getNumberHistograms(); ++si) + { + workspace->maskBin(si, 0, 1.0); + workspace->maskBin(si, 1, 1.0); + workspace->maskBin(si, 2, 1.0); + } + + SaveNexusProcessed save; + save.initialize(); + save.setPropertyValue("InputWorkspace", output_ws); + std::string filename = "LoadNexusProcessed_tmp.nxs"; + save.setPropertyValue("Filename", filename); + filename = save.getPropertyValue("Filename"); + save.execute(); + LoadNexusProcessed load; + load.initialize(); + load.setPropertyValue("Filename", filename); + load.setPropertyValue("OutputWorkspace", output_ws); + load.execute(); + + workspace = boost::dynamic_pointer_cast( + AnalysisDataService::Instance().retrieve(output_ws)); + TS_ASSERT( workspace.get()); + + TS_ASSERT_EQUALS(workspace->getNumberHistograms(), 6); + + TS_ASSERT(workspace->hasMaskedBins(0)); + TS_ASSERT(workspace->hasMaskedBins(1)); + TS_ASSERT(workspace->hasMaskedBins(2)); + TS_ASSERT(workspace->hasMaskedBins(3)); + TS_ASSERT(workspace->hasMaskedBins(4)); + TS_ASSERT(workspace->hasMaskedBins(5)); + + if (Poco::File(filename).exists()) + Poco::File(filename).remove(); + } + + void dotest_LoadAnEventFile(EventType type) + { + std::string filename_root = "LoadNexusProcessed_ExecEvent_"; + + // Call a function that writes out the file + std::string outputFile; + EventWorkspace_sptr origWS = SaveNexusProcessedTest::do_testExec_EventWorkspaces(filename_root, type, + outputFile, false, false); + + LoadNexusProcessed alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + TS_ASSERT( alg.isInitialized()); + alg.setPropertyValue("Filename", outputFile); + alg.setPropertyValue("OutputWorkspace", output_ws); + + TS_ASSERT_THROWS_NOTHING(alg.execute()); + + //Test some aspects of the file + Workspace_sptr workspace; + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve(output_ws)); + TS_ASSERT( workspace.get()); + + EventWorkspace_sptr ws = boost::dynamic_pointer_cast(workspace); + TS_ASSERT( ws); + if (!ws) + return; + + //Testing the number of histograms + TS_ASSERT_EQUALS(ws->getNumberHistograms(), 5); + + for (size_t wi = 0; wi < 5; wi++) + { + const EventList & el = ws->getEventList(wi); + TS_ASSERT_EQUALS( el.getEventType(), type); + TS_ASSERT( el.hasDetectorID(detid_t(wi+1)*10)); + } + TS_ASSERT_EQUALS( ws->getEventList(0).getNumberEvents(), 300); + TS_ASSERT_EQUALS( ws->getEventList(1).getNumberEvents(), 100); + TS_ASSERT_EQUALS( ws->getEventList(2).getNumberEvents(), 200); + TS_ASSERT_EQUALS( ws->getEventList(3).getNumberEvents(), 0); + TS_ASSERT_EQUALS( ws->getEventList(4).getNumberEvents(), 100); + + // Do the comparison algo to check that they really are the same + origWS->sortAll(TOF_SORT, NULL); + ws->sortAll(TOF_SORT, NULL); + + IAlgorithm_sptr alg2 = AlgorithmManager::Instance().createUnmanaged("CheckWorkspacesMatch"); + alg2->initialize(); + alg2->setProperty("Workspace1", origWS); + alg2->setProperty("Workspace2", ws); + alg2->setProperty("Tolerance", 1e-5); + alg2->setProperty("CheckAxes", false); + alg2->execute(); + if (alg2->isExecuted()) + { + TS_ASSERT(alg2->getPropertyValue("Result") == "Success!"); + } + else + { + TS_ASSERT( false); + } + + //Clear old file + if (Poco::File(outputFile).exists()) + Poco::File(outputFile).remove(); + + } + + void test_LoadEventNexus_TOF() + { + dotest_LoadAnEventFile(TOF); + } + + void test_LoadEventNexus_WEIGHTED() + { + dotest_LoadAnEventFile(WEIGHTED); + } + + void test_LoadEventNexus_WEIGHTED_NOTIME() + { + dotest_LoadAnEventFile(WEIGHTED_NOTIME); + } + + void test_load_saved_workspace_group() + { + LoadNexusProcessed alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + TS_ASSERT( alg.isInitialized()); + alg.setPropertyValue("Filename", "WorkspaceGroup.nxs"); + alg.setPropertyValue("OutputWorkspace", "group"); + + TS_ASSERT_THROWS_NOTHING(alg.execute()); + + Workspace_sptr workspace; + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group")); + WorkspaceGroup_sptr group = boost::dynamic_pointer_cast(workspace); + TS_ASSERT( group); + int groupSize = group->getNumberOfEntries(); + TS_ASSERT_EQUALS( groupSize, 12); + for (int i = 0; i < groupSize; ++i) + { + MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast(group->getItem(i)); + TS_ASSERT( ws); + TS_ASSERT_EQUALS( ws->getNumberHistograms(), 1); + TS_ASSERT_EQUALS( ws->blocksize(), 10); + TS_ASSERT_EQUALS( ws->name(), "group_" + boost::lexical_cast( i + 1 )); + } + + } + + void test_load_workspace_group_unique_names() + { + LoadNexusProcessed alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + TS_ASSERT( alg.isInitialized()); + + //Group two uses unique names for each workspace + alg.setPropertyValue("Filename", "WorkspaceGroup2.nxs"); + alg.setPropertyValue("OutputWorkspace", "group"); + + const char* suffix[] = + { "eq2", "eq1", "elf" }; + TS_ASSERT_THROWS_NOTHING(alg.execute()); + + Workspace_sptr workspace; + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group")); + WorkspaceGroup_sptr group = boost::dynamic_pointer_cast(workspace); + TS_ASSERT( group); + int groupSize = group->getNumberOfEntries(); + TS_ASSERT_EQUALS( groupSize, 3); + for (int i = 0; i < groupSize; ++i) + { + MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast(group->getItem(i)); + TS_ASSERT( ws); + TS_ASSERT_EQUALS( ws->getNumberHistograms(), 1); + TS_ASSERT_EQUALS( ws->blocksize(), 2); + TS_ASSERT_EQUALS( ws->name(), "irs55125_graphite002_to_55131_" + std::string(suffix[i])); + } + } + + void test_load_workspace_group_unique_names_two_workspaces() + { + LoadNexusProcessed alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + TS_ASSERT( alg.isInitialized()); + + //Group two uses unique names for each workspace + alg.setPropertyValue("Filename", "WorkspaceGroup2.nxs"); + alg.setPropertyValue("OutputWorkspace", "group"); + + const char* suffix[] = + { "eq2", "eq1", "elf" }; + TS_ASSERT_THROWS_NOTHING(alg.execute()); + + Workspace_sptr workspace; + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group")); + WorkspaceGroup_sptr group = boost::dynamic_pointer_cast(workspace); + TS_ASSERT( group); + int groupSize = group->getNumberOfEntries(); + TS_ASSERT_EQUALS( groupSize, 3); + for (int i = 0; i < groupSize; ++i) + { + MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast(group->getItem(i)); + TS_ASSERT( ws); + TS_ASSERT_EQUALS( ws->getNumberHistograms(), 1); + TS_ASSERT_EQUALS( ws->blocksize(), 2); + TS_ASSERT_EQUALS( ws->name(), "irs55125_graphite002_to_55131_" + std::string(suffix[i])); + } + + //load same file again, but to a different group + //this checks that the names will be unique + + LoadNexusProcessed alg2; + TS_ASSERT_THROWS_NOTHING(alg2.initialize()); + TS_ASSERT( alg2.isInitialized()); + + //Group two uses unique names for each workspace + alg2.setPropertyValue("Filename", "WorkspaceGroup2.nxs"); + alg2.setPropertyValue("OutputWorkspace", "group2"); + + TS_ASSERT_THROWS_NOTHING(alg2.execute()); + TS_ASSERT_THROWS_NOTHING( workspace = AnalysisDataService::Instance().retrieve("group2")); + group = boost::dynamic_pointer_cast(workspace); + TS_ASSERT( group); + groupSize = group->getNumberOfEntries(); + TS_ASSERT_EQUALS( groupSize, 3); + + for (int i = 0; i < groupSize; ++i) + { + MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast(group->getItem(i)); + TS_ASSERT( ws); + TS_ASSERT_EQUALS( ws->getNumberHistograms(), 1); + TS_ASSERT_EQUALS( ws->blocksize(), 2); + TS_ASSERT_EQUALS( ws->name(), "irs55125_graphite002_to_55131_" + std::string(suffix[i]) + "_1"); + } + } + + void test_load_fit_parameters() + { + LoadNexusProcessed alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + TS_ASSERT( alg.isInitialized()); + alg.setPropertyValue("Filename", "HRP38692a.nxs"); + alg.setPropertyValue("OutputWorkspace", "HRPDparameters"); + + TS_ASSERT_THROWS_NOTHING(alg.execute()); MatrixWorkspace_sptr ws; ws = AnalysisDataService::Instance().retrieveWS("HRPDparameters"); // test to see if parameters are loaded - std::vector > bankComp = ws->getInstrument()->getAllComponentsWithName("bank_bsk"); - - TS_ASSERT( bankComp[0]->getParameterNames().size() == 3 ); - } - - void testTableWorkspace() - { - Load alg; - alg.initialize(); - alg.setPropertyValue("Filename","SavedTableWorkspace.nxs"); - const std::string wsName("SavedTableWorkspace"); - alg.setPropertyValue("OutputWorkspace",wsName); - TS_ASSERT( alg.execute() ); - - TableWorkspace_const_sptr ws = AnalysisDataService::Instance().retrieveWS(wsName); - TS_ASSERT_EQUALS( ws->columnCount(), 3 ); - TS_ASSERT_EQUALS( ws->rowCount(), 4 ); - Column_const_sptr column; - TS_ASSERT_THROWS_NOTHING( column = ws->getColumn("Name") ); - TS_ASSERT_EQUALS( column->cell(0), "Height" ); - TS_ASSERT_EQUALS( column->cell(1), "PeakCentre" ); - TS_ASSERT_EQUALS( column->cell(2), "Sigma" ); - TS_ASSERT_EQUALS( column->cell(3), "Cost function value" ); - TS_ASSERT_THROWS_NOTHING( column = ws->getColumn("Value") ); - TS_ASSERT_DELTA( column->cell(0), 79.2315, 0.0001 ); - TS_ASSERT_DELTA( column->cell(1), 2.3979, 0.0001 ); - TS_ASSERT_DELTA( column->cell(2), 0.3495, 0.0001 ); - TS_ASSERT_DELTA( column->cell(3), 35.6841, 0.0001 ); - TS_ASSERT_THROWS_NOTHING( column = ws->getColumn("Error") ); - TS_ASSERT_DELTA( column->cell(0), 0.814478, 0.0001); - TS_ASSERT_DELTA( column->cell(1), 0.00348291, 0.000001 ); - TS_ASSERT_DELTA( column->cell(2), 0.00342847, 0.000001 ); - TS_ASSERT_EQUALS( column->cell(3), 0 ); - - AnalysisDataService::Instance().remove(wsName); - } - - void testTableWorkspace_vectorColumn() - { - // Create a table we will save - ITableWorkspace_sptr table = WorkspaceFactory::Instance().createTable(); - table->addColumn("vector_int", "IntVectorColumn"); - table->addColumn("vector_double", "DoubleVectorColumn"); - - std::vector d1, d2, d3; - d1.push_back(0.5); - d2.push_back(1.0); d2.push_back(2.5); - d3.push_back(4.0); - - std::vector i1( Strings::parseRange("1") ); - std::vector i2( Strings::parseRange("2,3,") ); - std::vector i3( Strings::parseRange("4,5,6,7") ); - - // Add some rows of different sizes - TableRow row1 = table->appendRow(); row1 << i1 << d1; - TableRow row2 = table->appendRow(); row2 << i2 << d2; - TableRow row3 = table->appendRow(); row3 << i3 << d3; - - ScopedWorkspace inTableEntry(table); - std::string savedFileName("LoadNexusProcessedTest_testTableWorkspace_vectorColumn.nxs"); - - SaveNexusProcessed saveAlg; - saveAlg.initialize(); - saveAlg.setPropertyValue("InputWorkspace", inTableEntry.name()); - saveAlg.setPropertyValue("Filename", savedFileName); - TS_ASSERT_THROWS_NOTHING( saveAlg.execute() ); - TS_ASSERT( saveAlg.isExecuted() ); - - if ( ! saveAlg.isExecuted() ) - return; // Nothing to check - - // Get absolute path to the saved file - savedFileName = saveAlg.getPropertyValue("Filename"); - - ScopedWorkspace outTableEntry; - - LoadNexusProcessed loadAlg; - loadAlg.initialize(); - loadAlg.setPropertyValue("Filename", savedFileName); - loadAlg.setPropertyValue("OutputWorkspace", outTableEntry.name()); - - TS_ASSERT_THROWS_NOTHING( loadAlg.execute() ); - TS_ASSERT( loadAlg.isExecuted() ); - - // The file is not needed anymore - Poco::File(savedFileName).remove(); - - if ( ! loadAlg.isExecuted() ) - return; // Nothing to check - - auto outTable = boost::dynamic_pointer_cast(outTableEntry.retrieve()); - TS_ASSERT( outTable ); - - if ( ! outTable ) - return; // Nothing to check - - TS_ASSERT_EQUALS( outTable->columnCount(), 2 ); - TS_ASSERT_EQUALS( outTable->rowCount(), 3 ); - - Column_const_sptr column; // Column we are currently checking - - TS_ASSERT_THROWS_NOTHING( column = outTable->getColumn("IntVectorColumn") ); - TS_ASSERT( column->isType< std::vector >() ); - - if ( column->isType< std::vector >() ) - { - TS_ASSERT_EQUALS( column->cell< std::vector >(0), i1 ); - TS_ASSERT_EQUALS( column->cell< std::vector >(1), i2 ); - TS_ASSERT_EQUALS( column->cell< std::vector >(2), i3 ); - } - - TS_ASSERT_THROWS_NOTHING( column = outTable->getColumn("DoubleVectorColumn") ); - TS_ASSERT( column->isType< std::vector >() ); - - if ( column->isType< std::vector >() ) - { - TS_ASSERT_EQUALS( column->cell< std::vector >(0), d1 ); - TS_ASSERT_EQUALS( column->cell< std::vector >(1), d2 ); - TS_ASSERT_EQUALS( column->cell< std::vector >(2), d3 ); - } - } - - void test_load_multiperiod_workspace() - { - LoadNexusProcessed loader; - loader.setChild(true); - loader.initialize(); - loader.setPropertyValue("Filename", "POLREF00004699_nexus.nxs"); - loader.setPropertyValue("OutputWorkspace", "ws"); - - TS_ASSERT( loader.execute() ); - - Workspace_sptr outWS = loader.getProperty("OutputWorkspace"); - WorkspaceGroup_sptr asGroupWS = boost::dynamic_pointer_cast(outWS); - TSM_ASSERT("We expect a group workspace back", asGroupWS); - TSM_ASSERT_EQUALS("We expect the size to be 2", 2, asGroupWS->size()); - MatrixWorkspace_sptr period1 = boost::dynamic_pointer_cast(asGroupWS->getItem(0)); - MatrixWorkspace_sptr period2 = boost::dynamic_pointer_cast(asGroupWS->getItem(1)); - TSM_ASSERT("We expect the group workspace is multiperiod", asGroupWS->isMultiperiod()); - TSM_ASSERT_EQUALS("X-data should be identical", period1->readX(0), period2->readX(0)); - TSM_ASSERT_DIFFERS("Y-data should be different", period1->readY(0), period2->readY(0)); - TSM_ASSERT_DIFFERS("E-data should be different", period1->readE(0), period2->readE(0)); + std::vector > bankComp = + ws->getInstrument()->getAllComponentsWithName("bank_bsk"); + + TS_ASSERT( bankComp[0]->getParameterNames().size() == 3); + } + + void testTableWorkspace() + { + Load alg; + alg.initialize(); + alg.setPropertyValue("Filename", "SavedTableWorkspace.nxs"); + const std::string wsName("SavedTableWorkspace"); + alg.setPropertyValue("OutputWorkspace", wsName); + TS_ASSERT( alg.execute()); + + TableWorkspace_const_sptr ws = AnalysisDataService::Instance().retrieveWS(wsName); + TS_ASSERT_EQUALS( ws->columnCount(), 3); + TS_ASSERT_EQUALS( ws->rowCount(), 4); + Column_const_sptr column; + TS_ASSERT_THROWS_NOTHING( column = ws->getColumn("Name")); + TS_ASSERT_EQUALS( column->cell(0), "Height"); + TS_ASSERT_EQUALS( column->cell(1), "PeakCentre"); + TS_ASSERT_EQUALS( column->cell(2), "Sigma"); + TS_ASSERT_EQUALS( column->cell(3), "Cost function value"); + TS_ASSERT_THROWS_NOTHING( column = ws->getColumn("Value")); + TS_ASSERT_DELTA( column->cell(0), 79.2315, 0.0001); + TS_ASSERT_DELTA( column->cell(1), 2.3979, 0.0001); + TS_ASSERT_DELTA( column->cell(2), 0.3495, 0.0001); + TS_ASSERT_DELTA( column->cell(3), 35.6841, 0.0001); + TS_ASSERT_THROWS_NOTHING( column = ws->getColumn("Error")); + TS_ASSERT_DELTA( column->cell(0), 0.814478, 0.0001); + TS_ASSERT_DELTA( column->cell(1), 0.00348291, 0.000001); + TS_ASSERT_DELTA( column->cell(2), 0.00342847, 0.000001); + TS_ASSERT_EQUALS( column->cell(3), 0); + + AnalysisDataService::Instance().remove(wsName); + } + + void testTableWorkspace_vectorColumn() + { + // Create a table we will save + ITableWorkspace_sptr table = WorkspaceFactory::Instance().createTable(); + table->addColumn("vector_int", "IntVectorColumn"); + table->addColumn("vector_double", "DoubleVectorColumn"); + + std::vector d1, d2, d3; + d1.push_back(0.5); + d2.push_back(1.0); + d2.push_back(2.5); + d3.push_back(4.0); + + std::vector i1(Strings::parseRange("1")); + std::vector i2(Strings::parseRange("2,3,")); + std::vector i3(Strings::parseRange("4,5,6,7")); + + // Add some rows of different sizes + TableRow row1 = table->appendRow(); + row1 << i1 << d1; + TableRow row2 = table->appendRow(); + row2 << i2 << d2; + TableRow row3 = table->appendRow(); + row3 << i3 << d3; + + ScopedWorkspace inTableEntry(table); + std::string savedFileName("LoadNexusProcessedTest_testTableWorkspace_vectorColumn.nxs"); - TS_ASSERT(period1->getInstrument()); - TS_ASSERT(period2->getInstrument()); + SaveNexusProcessed saveAlg; + saveAlg.initialize(); + saveAlg.setPropertyValue("InputWorkspace", inTableEntry.name()); + saveAlg.setPropertyValue("Filename", savedFileName); + TS_ASSERT_THROWS_NOTHING( saveAlg.execute()); + TS_ASSERT( saveAlg.isExecuted()); - auto period1Logs = period1->run().getLogData(); - auto period2Logs = period2->run().getLogData(); + if (!saveAlg.isExecuted()) + return; // Nothing to check - TSM_ASSERT_EQUALS("We expect to have the same number of log entries", period1Logs.size(), period2Logs.size()); + // Get absolute path to the saved file + savedFileName = saveAlg.getPropertyValue("Filename"); - TSM_ASSERT_THROWS("Should only have a period 1 entry", period1->run().getLogData("period 2"), Exception::NotFoundError& ); - TSM_ASSERT_THROWS("Should only have a period 2 entry", period2->run().getLogData("period 1"), Exception::NotFoundError& ); - } + ScopedWorkspace outTableEntry; + + LoadNexusProcessed loadAlg; + loadAlg.initialize(); + loadAlg.setPropertyValue("Filename", savedFileName); + loadAlg.setPropertyValue("OutputWorkspace", outTableEntry.name()); + + TS_ASSERT_THROWS_NOTHING( loadAlg.execute()); + TS_ASSERT( loadAlg.isExecuted()); + + // The file is not needed anymore + Poco::File(savedFileName).remove(); + + if (!loadAlg.isExecuted()) + return; // Nothing to check + + auto outTable = boost::dynamic_pointer_cast(outTableEntry.retrieve()); + TS_ASSERT( outTable); + + if (!outTable) + return; // Nothing to check + + TS_ASSERT_EQUALS( outTable->columnCount(), 2); + TS_ASSERT_EQUALS( outTable->rowCount(), 3); + + Column_const_sptr column; // Column we are currently checking + + TS_ASSERT_THROWS_NOTHING( column = outTable->getColumn("IntVectorColumn")); + TS_ASSERT( column->isType< std::vector >()); + + if (column->isType >()) + { + TS_ASSERT_EQUALS( column->cell< std::vector >(0), i1); + TS_ASSERT_EQUALS( column->cell< std::vector >(1), i2); + TS_ASSERT_EQUALS( column->cell< std::vector >(2), i3); + } + + TS_ASSERT_THROWS_NOTHING( column = outTable->getColumn("DoubleVectorColumn")); + TS_ASSERT( column->isType< std::vector >()); + + if (column->isType >()) + { + TS_ASSERT_EQUALS( column->cell< std::vector >(0), d1); + TS_ASSERT_EQUALS( column->cell< std::vector >(1), d2); + TS_ASSERT_EQUALS( column->cell< std::vector >(2), d3); + } + } + + void do_load_multiperiod_workspace(bool fast) + { + LoadNexusProcessed loader; + loader.setChild(true); + loader.initialize(); + loader.setPropertyValue("Filename", "POLREF00004699_nexus.nxs"); + loader.setPropertyValue("OutputWorkspace", "ws"); + loader.setProperty("FastMultiPeriod", fast); + + TS_ASSERT( loader.execute()); + + Workspace_sptr outWS = loader.getProperty("OutputWorkspace"); + WorkspaceGroup_sptr asGroupWS = boost::dynamic_pointer_cast(outWS); + TSM_ASSERT("We expect a group workspace back", asGroupWS); + TSM_ASSERT_EQUALS("We expect the size to be 2", 2, asGroupWS->size()); + MatrixWorkspace_sptr period1 = boost::dynamic_pointer_cast(asGroupWS->getItem(0)); + MatrixWorkspace_sptr period2 = boost::dynamic_pointer_cast(asGroupWS->getItem(1)); + TSM_ASSERT("We expect the group workspace is multiperiod", asGroupWS->isMultiperiod()); + TSM_ASSERT_EQUALS("X-data should be identical", period1->readX(0), period2->readX(0)); + TSM_ASSERT_DIFFERS("Y-data should be different", period1->readY(0), period2->readY(0)); + TSM_ASSERT_DIFFERS("E-data should be different", period1->readE(0), period2->readE(0)); + + TS_ASSERT(period1->getInstrument()); + TS_ASSERT(period2->getInstrument()); + + auto period1Logs = period1->run().getLogData(); + auto period2Logs = period2->run().getLogData(); + + TSM_ASSERT_EQUALS("We expect to have the same number of log entries", period1Logs.size(), + period2Logs.size()); + + TSM_ASSERT_THROWS("Should only have a period 1 entry", period1->run().getLogData("period 2"), + Exception::NotFoundError&); + TSM_ASSERT_THROWS("Should only have a period 2 entry", period2->run().getLogData("period 1"), + Exception::NotFoundError&); + } + + void test_load_multiperiod_workspace_fast() + { + do_load_multiperiod_workspace(true /*Use optimised route*/); + } + + void test_load_multiperiod_workspace_old() + { + do_load_multiperiod_workspace(false /*Use old route*/); + } private: void doHistoryTest(MatrixWorkspace_sptr matrix_ws) @@ -683,8 +711,8 @@ class LoadNexusProcessedTest : public CxxTest::TestSuite const WorkspaceHistory history = matrix_ws->getHistory(); int nalgs = static_cast(history.size()); TS_ASSERT_EQUALS(nalgs, 4); - - if( nalgs == 4 ) + + if (nalgs == 4) { TS_ASSERT_EQUALS(history[0]->name(), "LoadRaw"); TS_ASSERT_EQUALS(history[1]->name(), "AlignDetectors"); @@ -701,7 +729,7 @@ class LoadNexusProcessedTest : public CxxTest::TestSuite // Performance test //------------------------------------------------------------------------------ -class LoadNexusProcessedTestPerformance : public CxxTest::TestSuite +class LoadNexusProcessedTestPerformance: public CxxTest::TestSuite { public: void testHistogramWorkspace() @@ -710,7 +738,7 @@ class LoadNexusProcessedTestPerformance : public CxxTest::TestSuite loader.initialize(); loader.setPropertyValue("Filename", "PG3_733_focussed.nxs"); loader.setPropertyValue("OutputWorkspace", "ws"); - TS_ASSERT( loader.execute() ); + TS_ASSERT( loader.execute()); } }; From e084e3b8da4a930d627b8561edfde75d0a401df6 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Fri, 31 Oct 2014 16:23:20 +0000 Subject: [PATCH 023/128] refs #10385. Fix warnings. --- .../DataHandling/src/LoadNexusProcessed.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 88c2e08fb0fd..dbe17c4eaa0b 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -259,10 +259,10 @@ namespace Mantid * @param entryName : Entry name to load. * @param tempMatrixWorkspace : Template workspace to base the next multiperiod entry off. * @param nWorkspaceEntries : N entries in the file - * @param i : index + 1 being processed. + * @param p : index + 1 being processed. * @return Next multiperiod group workspace */ - Workspace_sptr LoadNexusProcessed::doAccelleratedMultiPeriodLoading(NXRoot & root, const std::string & entryName, MatrixWorkspace_sptr& tempMatrixWorkspace, const int64_t nWorkspaceEntries, const int64_t i) + Workspace_sptr LoadNexusProcessed::doAccelleratedMultiPeriodLoading(NXRoot & root, const std::string & entryName, MatrixWorkspace_sptr& tempMatrixWorkspace, const int64_t nWorkspaceEntries, const int64_t p) { MatrixWorkspace_sptr periodWorkspace = WorkspaceFactory::Instance().create(tempMatrixWorkspace); @@ -278,7 +278,7 @@ namespace Mantid if (!mtdEntry.containsGroup(groupName)) { std::stringstream buffer; - buffer << "Group entry " << i - 1 << " is not a workspace 2D. Retry with FastMultiPeriod option set off." << std::endl; + buffer << "Group entry " << p - 1 << " is not a workspace 2D. Retry with FastMultiPeriod option set off." << std::endl; throw std::runtime_error(buffer.str()); } @@ -286,21 +286,19 @@ namespace Mantid if (wsEntry.isValid("frac_area")) { std::stringstream buffer; - buffer << "Group entry " << i - 1 << " has fractional area present. Try reloading with FastMultiPeriod set off." << std::endl; + buffer << "Group entry " << p - 1 << " has fractional area present. Try reloading with FastMultiPeriod set off." << std::endl; throw std::runtime_error(buffer.str()); } NXDataSetTyped data = wsEntry.openDoubleData(); NXDataSetTyped errors = wsEntry.openNXDouble("errors"); - const int nSpectra = data.dim0(); const int nChannels = data.dim1(); int64_t blockSize = 8; // Read block size. Set to 8 for efficiency. i.e. read 8 histograms at a time. const int64_t nFullBlocks = nHistograms / blockSize; // Truncated number of full blocks to read. Remainder removed - const int64_t nRemainder = nHistograms % blockSize; // Remainder const int64_t readOptimumStop = (nFullBlocks * blockSize); - const int64_t readStop = m_spec_max - 1; // HACK + const int64_t readStop = m_spec_max - 1; const int64_t finalBlockSize = readStop - readOptimumStop; int64_t wsIndex = 0; @@ -352,7 +350,7 @@ namespace Mantid g_log.information(e.what()); } - const double fractionComplete = double(i-1)/double(nWorkspaceEntries); + const double fractionComplete = double(p-1)/double(nWorkspaceEntries); progress(fractionComplete, "Loading multiperiod entry"); return periodWorkspace; @@ -412,8 +410,7 @@ namespace Mantid { // We already know that this is a group workspace. Is it a true multiperiod workspace. const bool bFastMultiPeriod = this->getProperty("FastMultiPeriod"); - const bool bIsMultiPeriod = isMultiPeriodFile(nWorkspaceEntries, tempWS, g_log); - const bool ignoreSpecInfo = !bIsMultiPeriod; // Multiperiod groups can reuse it. + const bool bIsMultiPeriod = isMultiPeriodFile(static_cast(nWorkspaceEntries), tempWS, g_log); Property * specListProp = this->getProperty("SpectrumList"); m_list = !specListProp->isDefault(); From ddd2263bc781f690a8aa0e8f458c18f0a78b50bd Mon Sep 17 00:00:00 2001 From: Jean Bilheux Date: Fri, 31 Oct 2014 11:03:41 -0700 Subject: [PATCH 024/128] Fixed issue. This refs #10465 --- .../plugins/algorithms/sfCalculator.py | 90 ++++++++++--------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/sfCalculator.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/sfCalculator.py index e36963c10314..c833e155c826 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/sfCalculator.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/sfCalculator.py @@ -3,13 +3,14 @@ from mantid.simpleapi import * from numpy import zeros, unique, arange, sqrt, size import os.path -import sys import math PRECISION = 0.020 class sfCalculator(): + ref_date = '2014-10-01' # when the detector has been rotated + INDEX = 0 tof_min = None #microS @@ -63,6 +64,8 @@ class sfCalculator(): y_axis_error_ratio = None x_axis_ratio = None + is_nexus_detector_rotated_flag = True + def __init__(self, numerator=None, denominator=None, tof_range=None): @@ -201,6 +204,18 @@ def run(self): new_y_axis_error_ratio[i] = self.y_axis_ratio[i]* tmp_value self.y_axis_error_ratio = new_y_axis_error_ratio + def isNexusTakeAfterRefDate(self, nexus_date): + ''' + This function parses the output.date and returns true if this date is after the ref date + ''' + nexus_date_acquisition = nexus_date.split('T')[0] + + if nexus_date_acquisition > self.ref_date: + return True + else: + return False + + def _calculateFinalYAxis(self, bNumerator=True): """ run full calculation for numerator or denominator @@ -223,8 +238,8 @@ def _calculateFinalYAxis(self, bNumerator=True): nexus_file_numerator = file print '----> loading nexus file: ' + nexus_file_numerator EventDataWks = LoadEventNexus(Filename=nexus_file_numerator) -# OutputWorkspace='EventDataWks') -# mt1 = mtd['EventDataWks'] + + self.is_nexus_detector_rotated_flag = self.isNexusTakeAfterRefDate(EventDataWks.getRun().getProperty('run_start').value) proton_charge = self._getProtonCharge(EventDataWks) print '----> rebinning ' @@ -374,8 +389,6 @@ def _calculateFinalAxis(self, Workspace=None, bNumerator=None): print 'done with _calculateFinalAxis' - - def _createIntegratedWorkspace(self, InputWorkspace=None, OutputWorkspace=None, @@ -403,33 +416,23 @@ def _createIntegratedWorkspace(self, # y_error_axis[y, :] += ((InputWorkspace.readE(index)[:]) * # (InputWorkspace.readE(index)[:])) - #case 1 - print 'using case 1' - for x in range(304): - for y in y_range: - index = int(y+x*256) -# y_axis[y, :] += InputWorkspace.readY(index)[:] - y_axis[y, :] += InputWorkspace.readY(index)[:] - y_error_axis[y, :] += ((InputWorkspace.readE(index)[:]) * - (InputWorkspace.readE(index)[:])) - -## case 2 -# for x in range(304): -# for y in range(256): -# index = int(x+y*304) -## y_axis[y, :] += InputWorkspace.readY(index)[:] -# y_axis[y, :] += InputWorkspace.readY(index)[:] -# y_error_axis[y, :] += ((InputWorkspace.readE(index)[:]) * -# (InputWorkspace.readE(index)[:])) - - -# for x in range(self.alpha_pixel_nbr): -# for y in range(256): -# index = int(self.beta_pixel_nbr * x + y) -## y_axis[y, :] += InputWorkspace.readY(index)[:] -# y_axis[y, :] += InputWorkspace.readY(index)[:] -# y_error_axis[y, :] += ((InputWorkspace.readE(index)[:]) * -# (InputWorkspace.readE(index)[:])) + if self.is_nexus_detector_rotated_flag: + for x in range(256): + for y in y_range: + index = int(y+x*304) + # y_axis[y, :] += InputWorkspace.readY(index)[:] + y_axis[y, :] += InputWorkspace.readY(index)[:] + y_error_axis[y, :] += ((InputWorkspace.readE(index)[:]) * + (InputWorkspace.readE(index)[:])) + + else: + for x in range(304): + for y in y_range: + index = int(y+x*256) + # y_axis[y, :] += InputWorkspace.readY(index)[:] + y_axis[y, :] += InputWorkspace.readY(index)[:] + y_error_axis[y, :] += ((InputWorkspace.readE(index)[:]) * + (InputWorkspace.readE(index)[:])) # #DEBUG # f=open('/home/j35/myASCIIfromCode.txt','w') @@ -539,11 +542,19 @@ def _removeBackground(self, nbr_tof = len(tof_axis)-1 # make big array of data - data = zeros((256,nbr_tof)) - error = zeros((256,nbr_tof)) - for x in range(256): - data[x,:] = InputWorkspace.readY(x)[:] - error[x,:] = InputWorkspace.readE(x)[:] + if self.is_nexus_detector_rotated_flag: + data = zeros((304,nbr_tof)) + error = zeros((304,nbr_tof)) + for x in range(304): + data[x,:] = InputWorkspace.readY(x)[:] + error[x,:] = InputWorkspace.readE(x)[:] + + else: + data = zeros((256,nbr_tof)) + error = zeros((256,nbr_tof)) + for x in range(256): + data[x,:] = InputWorkspace.readY(x)[:] + error[x,:] = InputWorkspace.readE(x)[:] peak_array = zeros(nbr_tof) peak_array_error = zeros(nbr_tof) @@ -1184,10 +1195,6 @@ def help(): print ' > sfCalculator.calculate(string_runs="55889:0, 55890:1, 55891:1, 55892:2",' print ' list_' - - - - #if __name__ == '__main__': def calculate(string_runs=None, # list_attenuator=None, @@ -1389,3 +1396,4 @@ def calculate(string_runs=None, """ pass + From 679c839829669c9252c7d0ea73caef984f968287 Mon Sep 17 00:00:00 2001 From: Owen Arnold Date: Mon, 3 Nov 2014 11:25:12 +0000 Subject: [PATCH 025/128] refs #10385. Fix cpp check issue. --- Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index dbe17c4eaa0b..4bb714a6e686 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -337,7 +337,6 @@ namespace Mantid } } - std::string parameterStr; m_cppFile->openPath(mtdEntry.path()); try { From 502dc11510f65f66e3d32414fcbb81338eb9fe80 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Fri, 7 Nov 2014 10:08:19 +0000 Subject: [PATCH 026/128] Commit 01 Refs #8959 checkpointing --- .../MantidDataHandling/SaveReflCustomAscii.h | 68 +++++++++++++++++++ .../DataHandling/src/SaveReflCustomAscii.cpp | 53 +++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h create mode 100644 Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h new file mode 100644 index 000000000000..a11a37c541e3 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h @@ -0,0 +1,68 @@ +#ifndef MANTID_DATAHANDLING_SaveReflCustomAscii_H_ +#define MANTID_DATAHANDLING_SaveReflCustomAscii_H_ + +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidDataHandling/AsciiPointBase.h" + +namespace Mantid +{ + namespace DataHandling + { + /** + Saves a file in ILL Cosmos format from a 2D workspace + (Workspace2D class). SaveILLCosmosAscii is an algorithm but inherits frrm the + AsciiPointBase class which provides the main implementation for the init() & exec() methods. + Output is tab delimited Ascii point data with dq/q and extra header information. + + Copyright © 2007-14 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + File change history is stored at: . + Code Documentation is available at: + */ + class DLLExport SaveReflCustomAscii : public DataHandling::AsciiPointBase + { + public: + /// Default constructor + SaveReflCustomAscii() {} + /// Destructor + ~SaveReflCustomAscii() {} + /// Algorithm's name for identification overriding a virtual method + virtual const std::string name() const { return "SaveReflCustomAscii"; } + ///Summary of algorithms purpose + virtual const std::string summary() const {return "Saves a 2D workspace to a ascii file.";} + + /// Algorithm's version for identification overriding a virtual method + virtual int version() const { return 1; } + + private: + + /// Return the file extension this algorthm should output. + virtual std::string ext() {return ".dat";} + ///extra properties specifically for this + virtual void extraProps(); + /// write any extra information required + virtual void extraHeaders(std::ofstream & file); + }; + } // namespace DataHandling +} // namespace Mantid + +#endif /* MANTID_DATAHANDLING_SaveReflCustomAscii_H_ */ diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp new file mode 100644 index 000000000000..037741937791 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp @@ -0,0 +1,53 @@ +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidDataHandling/SaveReflCustomAscii.h" +#include "MantidDataHandling/AsciiPointBase.h" +#include "MantidKernel/ArrayProperty.h" +#include + +namespace Mantid +{ + namespace DataHandling + { + // Register the algorithm into the algorithm factory + DECLARE_ALGORITHM(SaveReflCustomAscii) + using namespace Kernel; + using namespace API; + + /// virtual method to set the extra properties required for this algorithm + void SaveReflCustomAscii::extraProps() + { + declareProperty(new ArrayProperty("LogList"),"List of logs to write to file."); + declareProperty("UserContact", "", "Text to be written to the User-local contact field"); + declareProperty("Title", "", "Text to be written to the Title field"); + } + + /** virtual method to add information to the file before the data + * @param file :: pointer to output file stream + */ + void SaveReflCustomAscii::extraHeaders(std::ofstream & file) + { + auto samp = m_ws->run(); + std::string title = getProperty("Title"); + + if (title) //if is toggled + { + file << "#" << title << std::endl; + } + + const std::vector logList = getProperty("LogList"); + ///logs + for (auto log = logList.begin(); log != logList.end(); ++log) + { + file << boost::lexical_cast(*log) << ": " << boost::lexical_cast(samp.getLogData(*log)->value()) << std::endl; + } + + file << "Number of file format: 2" << std::endl; + file << "Number of data points:" << sep() << m_xlength << std::endl; + file << std::endl; + + file << sep() << "q" << sep() << "refl" << sep() << "refl_err" << sep() << "q_res" << std::endl; + } + } // namespace DataHandling +} // namespace Mantid From 826443f68fe774a3b84c082f17c3161b60f49dfc Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Fri, 7 Nov 2014 13:28:03 +0000 Subject: [PATCH 027/128] Commit 2 Refs #8959 checkpoint --- .../Framework/DataHandling/src/SaveReflCustomAscii.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp index 037741937791..bae77f27269a 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp @@ -31,10 +31,10 @@ namespace Mantid auto samp = m_ws->run(); std::string title = getProperty("Title"); - if (title) //if is toggled - { - file << "#" << title << std::endl; - } + //if (title) //if is toggled + //{ + // file << "#" << title << std::endl; + //} const std::vector logList = getProperty("LogList"); ///logs From 1696e98190943c095a90a61cc9b535cc1a184910 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Mon, 10 Nov 2014 16:50:08 +0000 Subject: [PATCH 028/128] Commit 3 Refs #8959 added new saveAlgorithm with custom header detail --- .../MantidDataHandling/SaveReflCustomAscii.h | 2 + .../DataHandling/src/SaveReflCustomAscii.cpp | 47 +++++++++++++++---- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h index a11a37c541e3..16e0a03c930e 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h @@ -53,6 +53,8 @@ namespace Mantid /// Algorithm's version for identification overriding a virtual method virtual int version() const { return 1; } + void SaveReflCustomAscii::data(std::ofstream & file, const std::vector & XData){} + private: /// Return the file extension this algorthm should output. diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp index bae77f27269a..157c582a11d1 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp @@ -21,6 +21,7 @@ namespace Mantid declareProperty(new ArrayProperty("LogList"),"List of logs to write to file."); declareProperty("UserContact", "", "Text to be written to the User-local contact field"); declareProperty("Title", "", "Text to be written to the Title field"); + declareProperty("WriteXError", false, "If true, the error on X will be written as the fourth column."); } /** virtual method to add information to the file before the data @@ -29,12 +30,21 @@ namespace Mantid void SaveReflCustomAscii::extraHeaders(std::ofstream & file) { auto samp = m_ws->run(); + std::string subtitle; std::string title = getProperty("Title"); + try + { + subtitle = samp.getLogData("run_title")->value(); + } + catch (Kernel::Exception::NotFoundError &) + { + subtitle = ""; + } - //if (title) //if is toggled - //{ - // file << "#" << title << std::endl; - //} + if (title != "") //if is toggled + { + file << "#" << title << std::endl; + } const std::vector logList = getProperty("LogList"); ///logs @@ -43,11 +53,30 @@ namespace Mantid file << boost::lexical_cast(*log) << ": " << boost::lexical_cast(samp.getLogData(*log)->value()) << std::endl; } - file << "Number of file format: 2" << std::endl; - file << "Number of data points:" << sep() << m_xlength << std::endl; - file << std::endl; - - file << sep() << "q" << sep() << "refl" << sep() << "refl_err" << sep() << "q_res" << std::endl; } + /*void SaveReflCustomAscii::data(std::ofstream & file, const std::vector & XData) + { + const std::vector & yData = m_ws->readY(0); + const std::vector & eData = m_ws->readE(0); + {if (1){ + for (size_t i = 0; i < m_xlength; ++i) + { + double dq = XData[i]*m_qres; + outputval(XData[i], file, leadingSep()); + outputval(yData[i], file); + outputval(eData[i], file); + outputval(dq, file); + file << std::endl; + }} + else + { + for (size_t i = 0; i < m_xlength; ++i) + { + outputval(XData[i], file, leadingSep()); + outputval(yData[i], file); + outputval(eData[i], file); + file << std::endl; + } + }};*/ } // namespace DataHandling } // namespace Mantid From 7f2ad13cd973f36a8e1ad9afb0492cedcc138845 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Tue, 11 Nov 2014 09:44:52 +0000 Subject: [PATCH 029/128] Commit 4 Refs #8959 adjusted AsciiPointBase class data method --- .../inc/MantidDataHandling/AsciiPointBase.h | 2 +- .../MantidDataHandling/SaveReflCustomAscii.h | 1 - .../DataHandling/src/AsciiPointBase.cpp | 18 +++++++++++- .../DataHandling/src/SaveReflCustomAscii.cpp | 28 ++----------------- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h index 6f938b48bf91..afc1a6f96510 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h @@ -61,7 +61,7 @@ namespace Mantid /// write any extra information required virtual void extraHeaders(std::ofstream & file) = 0; /// write the main content of the data - virtual void data(std::ofstream & file, const std::vector & XData); + virtual void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ = true); /// Overwrites Algorithm method. void init(); /// Overwrites Algorithm method diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h index 16e0a03c930e..df1e7c334403 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h @@ -53,7 +53,6 @@ namespace Mantid /// Algorithm's version for identification overriding a virtual method virtual int version() const { return 1; } - void SaveReflCustomAscii::data(std::ofstream & file, const std::vector & XData){} private: diff --git a/Code/Mantid/Framework/DataHandling/src/AsciiPointBase.cpp b/Code/Mantid/Framework/DataHandling/src/AsciiPointBase.cpp index a4c7b89926e1..e86c91879c34 100644 --- a/Code/Mantid/Framework/DataHandling/src/AsciiPointBase.cpp +++ b/Code/Mantid/Framework/DataHandling/src/AsciiPointBase.cpp @@ -75,11 +75,15 @@ namespace Mantid /** virtual method to add information to the file before the data * @param file :: pointer to output file stream * @param XData :: pointer to a std::vector containing the point data to be printed + * @param exportDeltaQ :: bool on whether deltaQ column to be printed */ - void AsciiPointBase::data(std::ofstream & file, const std::vector & XData) + void AsciiPointBase::data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ) { + const std::vector & yData = m_ws->readY(0); const std::vector & eData = m_ws->readE(0); + if (exportDeltaQ) + { for (size_t i = 0; i < m_xlength; ++i) { double dq = XData[i]*m_qres; @@ -89,8 +93,20 @@ namespace Mantid outputval(dq, file); file << std::endl; } + } + else + { + for (size_t i = 0; i < m_xlength; ++i) + { + outputval(XData[i], file, leadingSep()); + outputval(yData[i], file); + outputval(eData[i], file); + file << std::endl; + } + } } + /** writes a properly formatted line of data * @param val :: the double value to be written * @param file :: pointer to output file stream diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp index 157c582a11d1..a7abdec84108 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp @@ -21,7 +21,7 @@ namespace Mantid declareProperty(new ArrayProperty("LogList"),"List of logs to write to file."); declareProperty("UserContact", "", "Text to be written to the User-local contact field"); declareProperty("Title", "", "Text to be written to the Title field"); - declareProperty("WriteXError", false, "If true, the error on X will be written as the fourth column."); + declareProperty("WriteXError", false, "If true, the error on X will be written as the fourth column."); //deltaQ } /** virtual method to add information to the file before the data @@ -54,29 +54,7 @@ namespace Mantid } } - /*void SaveReflCustomAscii::data(std::ofstream & file, const std::vector & XData) - { - const std::vector & yData = m_ws->readY(0); - const std::vector & eData = m_ws->readE(0); - {if (1){ - for (size_t i = 0; i < m_xlength; ++i) - { - double dq = XData[i]*m_qres; - outputval(XData[i], file, leadingSep()); - outputval(yData[i], file); - outputval(eData[i], file); - outputval(dq, file); - file << std::endl; - }} - else - { - for (size_t i = 0; i < m_xlength; ++i) - { - outputval(XData[i], file, leadingSep()); - outputval(yData[i], file); - outputval(eData[i], file); - file << std::endl; - } - }};*/ + + } // namespace DataHandling } // namespace Mantid From 0a7898383917263d2479cf9509c5a1eae6ff7618 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Tue, 11 Nov 2014 11:34:05 +0000 Subject: [PATCH 030/128] Commit 5 Refs #8959 finished working ReflCustomAscii class --- .../inc/MantidDataHandling/AsciiPointBase.h | 5 ++-- .../MantidDataHandling/SaveReflCustomAscii.h | 4 ++- .../DataHandling/src/AsciiPointBase.cpp | 30 +++++++++---------- .../DataHandling/src/SaveReflCustomAscii.cpp | 12 +++++--- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h index afc1a6f96510..d0816d967522 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h @@ -60,8 +60,7 @@ namespace Mantid virtual void extraProps() = 0; /// write any extra information required virtual void extraHeaders(std::ofstream & file) = 0; - /// write the main content of the data - virtual void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ = true); + /// Overwrites Algorithm method. void init(); /// Overwrites Algorithm method @@ -77,6 +76,8 @@ namespace Mantid protected: /// Return the separator character virtual char sep() {return '\t';} + /// write the main content of the data + virtual void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ = true); double m_qres; size_t m_xlength; API::MatrixWorkspace_const_sptr m_ws; diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h index df1e7c334403..69a53f953f46 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflCustomAscii.h @@ -49,10 +49,12 @@ namespace Mantid virtual const std::string name() const { return "SaveReflCustomAscii"; } ///Summary of algorithms purpose virtual const std::string summary() const {return "Saves a 2D workspace to a ascii file.";} - /// Algorithm's version for identification overriding a virtual method virtual int version() const { return 1; } + + /// + void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ); private: diff --git a/Code/Mantid/Framework/DataHandling/src/AsciiPointBase.cpp b/Code/Mantid/Framework/DataHandling/src/AsciiPointBase.cpp index e86c91879c34..fdc3539fecb6 100644 --- a/Code/Mantid/Framework/DataHandling/src/AsciiPointBase.cpp +++ b/Code/Mantid/Framework/DataHandling/src/AsciiPointBase.cpp @@ -84,25 +84,25 @@ namespace Mantid const std::vector & eData = m_ws->readE(0); if (exportDeltaQ) { - for (size_t i = 0; i < m_xlength; ++i) - { - double dq = XData[i]*m_qres; - outputval(XData[i], file, leadingSep()); - outputval(yData[i], file); - outputval(eData[i], file); - outputval(dq, file); - file << std::endl; - } + for (size_t i = 0; i < m_xlength; ++i) + { + double dq = XData[i]*m_qres; + outputval(XData[i], file, leadingSep()); + outputval(yData[i], file); + outputval(eData[i], file); + outputval(dq, file); + file << std::endl; + } } else { for (size_t i = 0; i < m_xlength; ++i) - { - outputval(XData[i], file, leadingSep()); - outputval(yData[i], file); - outputval(eData[i], file); - file << std::endl; - } + { + outputval(XData[i], file, leadingSep()); + outputval(yData[i], file); + outputval(eData[i], file); + file << std::endl; + } } } diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp index a7abdec84108..624b80110c77 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp @@ -19,9 +19,8 @@ namespace Mantid void SaveReflCustomAscii::extraProps() { declareProperty(new ArrayProperty("LogList"),"List of logs to write to file."); - declareProperty("UserContact", "", "Text to be written to the User-local contact field"); declareProperty("Title", "", "Text to be written to the Title field"); - declareProperty("WriteXError", false, "If true, the error on X will be written as the fourth column."); //deltaQ + declareProperty("WriteDeltaQ", false, "If true, the error on DeltaQ will be written as the fourth column."); } /** virtual method to add information to the file before the data @@ -52,9 +51,14 @@ namespace Mantid { file << boost::lexical_cast(*log) << ": " << boost::lexical_cast(samp.getLogData(*log)->value()) << std::endl; } - } + + void SaveReflCustomAscii::data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ) + { + + AsciiPointBase::data(file, XData, getProperty("WriteDeltaQ")); + } + - } // namespace DataHandling } // namespace Mantid From af7418b798bd01b685e94b1102f4ea7a210c72a0 Mon Sep 17 00:00:00 2001 From: Anton Piccardo-Selg Date: Tue, 11 Nov 2014 14:18:25 +0000 Subject: [PATCH 031/128] Provide absolute path for PV to find QuadView.dll Refs #10533 When switching from standard view to three slice view in Vates on a Windows 7 machine, the application crashes. ParaView is not able to find the required DLLs. Providing the absolute path to the DLLs to ParaView solves the issue. --- .../Kernel/inc/MantidKernel/ConfigService.h | 3 +++ .../Framework/Kernel/src/ConfigService.cpp | 9 ++++++++ .../ViewWidgets/src/MdViewerWidget.cpp | 23 +++++++++++++++++-- .../ViewWidgets/src/ThreesliceView.cpp | 22 ++++++++++++++++-- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h index 62f8ebbc6412..67c2c1e71dcc 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h @@ -225,6 +225,9 @@ namespace Mantid /// Quick check to determine if vates has been installed. bool quickVatesCheck() const; + /// Get the ParaViewPath + const std::string getParaViewPath() const; + private: friend struct Mantid::Kernel::CreateUsingNew; /// Handles distribution of Poco signals. diff --git a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp index 1cc770bb01f5..f997ef081420 100644 --- a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp @@ -1991,6 +1991,15 @@ bool ConfigServiceImpl::quickVatesCheck() const return found; } +/** + * Gets the path to ParaView. + * @returns The ParaView path. + */ +const std::string ConfigServiceImpl::getParaViewPath() const +{ + return getString("paraview.path"); +} + /// \cond TEMPLATE template DLLExport int ConfigServiceImpl::getValue(const std::string&, double&); template DLLExport int ConfigServiceImpl::getValue(const std::string&, std::string&); diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp index 57d4f56a7f57..e94ec3ad2040 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp @@ -12,6 +12,8 @@ #include "MantidQtAPI/InterfaceManager.h" #include "MantidKernel/DynamicFactory.h" +#include "MantidKernel/Logger.h" +#include "MantidKernel/ConfigService.h" // Have to deal with ParaView warnings and Intel compiler the hard way. #if defined(__INTEL_COMPILER) @@ -84,6 +86,8 @@ #include #include +#include +#include namespace Mantid { @@ -94,6 +98,12 @@ namespace SimpleGui using namespace Mantid::API; using namespace MantidQt::API; +namespace +{ + /// Static logger + Kernel::Logger g_log("MdViewerWidget"); +} + REGISTER_VATESGUI(MdViewerWidget) /** @@ -241,8 +251,17 @@ void MdViewerWidget::createAppCoreForPlugin() { if (!pqApplicationCore::instance()) { - int argc = 1; - char *argv[] = {"/tmp/MantidPlot"}; + // Provide ParaView's application core with a path to ParaView + int argc = 1; + + std::string paraviewPath = Mantid::Kernel::ConfigService::Instance().getParaViewPath(); + std::vector argvConversion(paraviewPath.begin(), paraviewPath.end()); + argvConversion.push_back('\0'); + + char *argv[] = {&argvConversion[0]}; + + g_log.debug() << "Intialize pqApplicationCore with " << argv << "\n"; + new pqPVApplicationCore(argc, argv); } else diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp index 8c92d979c42d..73f2b563bfd2 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp @@ -1,5 +1,8 @@ #include "MantidVatesSimpleGuiViewWidgets/ThreesliceView.h" #include "MantidVatesSimpleGuiViewWidgets/LibHelper.h" +#include "MantidKernel/ConfigService.h" +#include "MantidKernel/Logger.h" +#include #if defined(__INTEL_COMPILER) #pragma warning disable 1170 @@ -23,6 +26,7 @@ #include #include +#include namespace Mantid { @@ -30,16 +34,30 @@ namespace Vates { namespace SimpleGui { - +namespace +{ + /// Static logger + Kernel::Logger g_log("ThreeSliceView"); +} ThreeSliceView::ThreeSliceView(QWidget *parent) : ViewBase(parent) { this->ui.setupUi(this); + // We need to load the QuadView.dll plugin. The Windows system requires the full + // path information. The DLL is located in the apropriate executeable path of paraview. + const Poco::Path paraviewPath(Mantid::Kernel::ConfigService::Instance().getParaViewPath()); + + Poco::Path quadViewFullPath(paraviewPath, QUADVIEW_LIBRARY.toStdString()); + + QString quadViewLibrary(quadViewFullPath.toString().c_str()); + // Need to load plugin pqPluginManager* pm = pqApplicationCore::instance()->getPluginManager(); QString error; pm->loadExtension(pqActiveObjects::instance().activeServer(), - QUADVIEW_LIBRARY, &error, false); + quadViewLibrary, &error, false); + + g_log.debug() << "Loading QuadView.dll from " << quadViewLibrary.toStdString() << "\n"; this->mainView = this->createRenderView(this->ui.mainRenderFrame, QString("pqQuadView")); From c2e020679f78fc26f7a5135abd275c77d4796acd Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Tue, 11 Nov 2014 15:57:42 +0000 Subject: [PATCH 032/128] Commit 6 Refs #8959 wrote unittest --- .../test/SaveReflCustomAsciiTest.h | 289 ++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 Code/Mantid/Framework/DataHandling/test/SaveReflCustomAsciiTest.h diff --git a/Code/Mantid/Framework/DataHandling/test/SaveReflCustomAsciiTest.h b/Code/Mantid/Framework/DataHandling/test/SaveReflCustomAsciiTest.h new file mode 100644 index 000000000000..48d8ea8c8e39 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/test/SaveReflCustomAsciiTest.h @@ -0,0 +1,289 @@ +#ifndef SAVEREFLCUSTOMASCIITEST_H_ +#define SAVEREFLCUSTOMASCIITEST_H_ + +#include +#include "MantidDataHandling/SaveReflCustomAscii.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include +#include +#include + +using namespace Mantid::API; +using namespace Mantid::DataHandling; +using namespace Mantid::DataObjects; + +class SaveReflCustomAsciiTest : public CxxTest::TestSuite +{ + +public: + + static SaveReflCustomAsciiTest *createSuite() { return new SaveReflCustomAsciiTest(); } + static void destroySuite(SaveReflCustomAsciiTest *suite) { delete suite; } + + SaveReflCustomAsciiTest() + { + m_filename = "SaveReflCustomAsciiTestFile.txt"; + m_name = "SaveReflCustomAsciiWS"; + for (int i = 1; i < 11; ++i) + { + //X, Y and E get [1,2,3,4,5,6,7,8,9,10] + //0 gets [0,0,0,0,0,0,0,0,0,0] and is used to make sure there is no problem with divide by zero + m_dataX.push_back(i); + m_dataY.push_back(i); + m_dataE.push_back(i); + m_data0.push_back(0); + } + } + ~SaveReflCustomAsciiTest() + { + } + + void testExec() + { + //create a new workspace and then delete it later on + createWS(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflCustomAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflCustomAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline); + getline(in,fullline); + + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),5); /////// + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); + in.close(); + + cleanupafterwards(); + } + void testNoX() + { + //create a new workspace and then delete it later on + createWS(true); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflCustomAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflCustomAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline); + getline(in,fullline); + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),5); + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 0, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); + TS_ASSERT((columns.at(4) == "nan") || (columns.at(4) == "inf")); + in.close(); + + cleanupafterwards(); + } + void testNoY() + { + //create a new workspace and then delete it later on + createWS(false,true); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflCustomAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflCustomAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline); + getline(in,fullline); + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),5); + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 0, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); + in.close(); + + cleanupafterwards(); + } + void testNoE() + { + //create a new workspace and then delete it later on + createWS(false,false,true); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflCustomAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflCustomAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline); + getline(in,fullline); + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),5); + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 0, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); + in.close(); + + cleanupafterwards(); + } + void testParameters() + { + //create a new workspace and then delete it later on + createWS(false,false,false,true); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflCustomAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + alg->setPropertyValue("Title", "Testing this algorithm"); + alg->setPropertyValue("WriteDeltaQ", false); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflCustomAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline,true); + getline(in,fullline); + + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),5); + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); + in.close(); + + cleanupafterwards(); + } + void test_fail_invalid_workspace() + { + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflCustomAscii"); + alg->setRethrows(true); + TS_ASSERT(alg->isInitialized()); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); + m_long_filename= alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_ANYTHING(alg->setPropertyValue("InputWorkspace", "NotARealWS")); + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + + // the algorithm shouldn't have written a file to disk + TS_ASSERT( !Poco::File(m_long_filename).exists() ); + } +private: + void headingsTests(std::ifstream & in,std::string & fullline, bool propertiesLogs = false) + { + if (propertiesLogs) + { + getline(in,fullline); + TS_ASSERT(fullline == "Title: Testing this algorithm"); + getline(in,fullline); + TS_ASSERT(fullline == "Subtitle: ILL COSMOS save test"); + } + else + { + } + } + void createWS(bool zeroX = false, bool zeroY = false, bool zeroE = false, bool createLogs = false) + { + MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(1,10); + + if (createLogs) + { + } + + AnalysisDataService::Instance().addOrReplace(m_name, ws); + //Check if any of X, Y or E should be zeroed to check for divide by zero or similiar + if (zeroX) + { + ws->dataX(0) = m_data0; + } + else + { + ws->dataX(0) = m_dataX; + } + + if (zeroY) + { + ws->dataY(0) = m_data0; + } + else + { + ws->dataY(0) = m_dataY; + } + + if (zeroE) + { + ws->dataE(0) = m_data0; + } + else + { + ws->dataE(0) = m_dataE; + } + } + void cleanupafterwards() + { + Poco::File(m_long_filename).remove(); + AnalysisDataService::Instance().remove(m_name); + } + std::string m_filename, m_name, m_long_filename; + std::vector m_dataX, m_dataY, m_dataE, m_data0; +}; +#endif /*SAVEREFLCUSTOMASCIITEST_H_*/ From 044b776ddfae148947b8c33f54bb4a1cc0d88686 Mon Sep 17 00:00:00 2001 From: Vickie Lynch Date: Tue, 11 Nov 2014 11:14:17 -0500 Subject: [PATCH 033/128] Refs #10535 zero edge intensity --- .../MDAlgorithms/src/IntegratePeaksMD2.cpp | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp index 8337881274a2..54cbc16551cf 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp @@ -260,7 +260,15 @@ namespace MDAlgorithms if (!detectorQ(p.getQLabFrame(), BackgroundOuterRadius)) { g_log.warning() << "Warning: sphere/cylinder for integration is off edge of detector for peak " << i << std::endl; - if (!integrateEdge)continue; + if (!integrateEdge) + { + if (replaceIntensity) + { + p.setIntensity(0.0); + p.setSigmaIntensity( 0.0 ); + } + continue; + } } } else @@ -268,7 +276,15 @@ namespace MDAlgorithms if (!detectorQ(p.getQLabFrame(), PeakRadius)) { g_log.warning() << "Warning: sphere/cylinder for integration is off edge of detector for peak " << i << std::endl; - if (!integrateEdge)continue; + if (!integrateEdge) + { + if (replaceIntensity) + { + p.setIntensity(0.0); + p.setSigmaIntensity( 0.0 ); + } + continue; + } } } From aea62e9b3957824ac4df6b9c67b82a74cd5fe466 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Wed, 12 Nov 2014 09:08:01 +0000 Subject: [PATCH 034/128] Refs #8961 wrote threecolumn class --- .../SaveReflThreeColumnAscii.h | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h new file mode 100644 index 000000000000..38e6ffcbe8b9 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h @@ -0,0 +1,71 @@ +#ifndef MANTID_DATAHANDLING_SAVEREFLTHREECOLUMNASCII_H_ +#define MANTID_DATAHANDLING_SAVEREFLTHREECOLUMNASCII_H_ + +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidDataHandling/AsciiPointBase.h" + +namespace Mantid +{ + namespace DataHandling + { + /** + Saves a file in ILL Cosmos format from a 2D workspace + (Workspace2D class). SaveILLCosmosAscii is an algorithm but inherits frrm the + AsciiPointBase class which provides the main implementation for the init() & exec() methods. + Output is tab delimited Ascii point data with dq/q and extra header information. + + Copyright © 2007-14 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + File change history is stored at: . + Code Documentation is available at: + */ + class DLLExport SaveReflThreeColumnAscii : public DataHandling::AsciiPointBase + { + public: + /// Default constructor + SaveReflThreeColumnAscii() {} + /// Destructor + ~SaveReflThreeColumnAscii() {} + /// Algorithm's name for identification overriding a virtual method + virtual const std::string name() const { return "SaveReflThreeColumnAscii"; } + ///Summary of algorithms purpose + virtual const std::string summary() const {return "Saves a 2D workspace to a ascii file.";} + /// Algorithm's version for identification overriding a virtual method + virtual int version() const { return 1; } + + + /// + void data(std::ofstream & file, const std::vector & XData); + + private: + + /// Return the file extension this algorthm should output. + virtual std::string ext() {return ".dat";} + ///extra properties specifically for this + virtual void extraProps(); + /// write any extra information required + virtual void extraHeaders(std::ofstream & file); + }; + } // namespace DataHandling +} // namespace Mantid + +#endif /* MANTID_DATAHANDLING_SAVEREFLTHREECOLUMNASCII_H_ */ From 29cb9023cec0290a1f3bb683f80a2e0108f450e7 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Wed, 12 Nov 2014 10:24:10 +0000 Subject: [PATCH 035/128] Refs #8961 inc src file --- .../src/SaveReflThreeColumnAscii.cpp | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp new file mode 100644 index 000000000000..18ce9da72112 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp @@ -0,0 +1,62 @@ +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidDataHandling/SaveReflThreeColumnAscii.h" +#include "MantidDataHandling/AsciiPointBase.h" +#include "MantidKernel/ArrayProperty.h" +#include + +namespace Mantid +{ + namespace DataHandling + { + // Register the algorithm into the algorithm factory + DECLARE_ALGORITHM(SaveReflThreeColumnAscii) + using namespace Kernel; + using namespace API; + + /// virtual method to set the extra properties required for this algorithm + void SaveReflThreeColumnAscii::extraProps() + { + declareProperty(new ArrayProperty("LogList"),"List of logs to write to file."); + declareProperty("Title", "", "Text to be written to the Title field"); + } + + /** virtual method to add information to the file before the data + * @param file :: pointer to output file stream + */ + void SaveReflThreeColumnAscii::extraHeaders(std::ofstream & file) + { + auto samp = m_ws->run(); + std::string subtitle; + std::string title = getProperty("Title"); + try + { + subtitle = samp.getLogData("run_title")->value(); + } + catch (Kernel::Exception::NotFoundError &) + { + subtitle = ""; + } + ////git change!!!!!!!! + if (title != "") //if is toggled + { + file << "#" << title << std::endl; + } + + const std::vector logList = getProperty("LogList"); + ///logs + for (auto log = logList.begin(); log != logList.end(); ++log) + { + file << boost::lexical_cast(*log) << ": " << boost::lexical_cast(samp.getLogData(*log)->value()) << std::endl; + } + } + + void SaveReflThreeColumnAscii::data(std::ofstream & file, const std::vector & XData) + { + AsciiPointBase::data(file, XData, false); + } + + + } // namespace DataHandling +} // namespace Mantid From 4c2683c7246afce437afe6d87145aaac6c744c86 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Wed, 12 Nov 2014 14:08:12 +0000 Subject: [PATCH 036/128] Refs #8961 inc testing file --- .../test/SaveReflThreeColumnAsciiTest.h | 288 ++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 Code/Mantid/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h diff --git a/Code/Mantid/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h b/Code/Mantid/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h new file mode 100644 index 000000000000..523af3c0b2b9 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h @@ -0,0 +1,288 @@ +#ifndef SAVEREFLTHREECOLUMNASCIITEST_H_ +#define SAVEREFLTHREECOLUMNASCIITEST_H_ + +#include +#include "MantidDataHandling/SaveReflThreeColumnAscii.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include +#include +#include + +using namespace Mantid::API; +using namespace Mantid::DataHandling; +using namespace Mantid::DataObjects; + +class SaveReflThreeColumnAsciiTest : public CxxTest::TestSuite +{ + +public: + + static SaveReflThreeColumnAsciiTest *createSuite() { return new SaveReflThreeColumnAsciiTest(); } + static void destroySuite(SaveReflThreeColumnAsciiTest *suite) { delete suite; } + + SaveReflThreeColumnAsciiTest() + { + m_filename = "SaveReflThreeColumnAsciiTestFile.txt"; + m_name = "SaveReflThreeColumnAsciiWS"; + for (int i = 1; i < 11; ++i) + { + //X, Y and E get [1,2,3,4,5,6,7,8,9,10] + //0 gets [0,0,0,0,0,0,0,0,0,0] and is used to make sure there is no problem with divide by zero + m_dataX.push_back(i); + m_dataY.push_back(i); + m_dataE.push_back(i); + m_data0.push_back(0); + } + } + ~SaveReflThreeColumnAsciiTest() + { + } + + void testExec() + { + //create a new workspace and then delete it later on + createWS(); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflThreeColumnAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflThreeColumnAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline); + getline(in,fullline); + + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),3); /////// + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); + in.close(); + + cleanupafterwards(); + } + void testNoX() + { + //create a new workspace and then delete it later on + createWS(true); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflThreeColumnAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflThreeColumnAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline); + getline(in,fullline); + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),5); + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 0, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); + TS_ASSERT((columns.at(4) == "nan") || (columns.at(4) == "inf")); + in.close(); + + cleanupafterwards(); + } + void testNoY() + { + //create a new workspace and then delete it later on + createWS(false,true); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflThreeColumnAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflThreeColumnAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline); + getline(in,fullline); + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),5); + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 0, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); + in.close(); + + cleanupafterwards(); + } + void testNoE() + { + //create a new workspace and then delete it later on + createWS(false,false,true); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflThreeColumnAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflThreeColumnAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline); + getline(in,fullline); + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),5); + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 0, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); + in.close(); + + cleanupafterwards(); + } + void testParameters() + { + //create a new workspace and then delete it later on + createWS(false,false,false,true); + + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflThreeColumnAscii"); + alg->setPropertyValue("InputWorkspace", m_name); + alg->setPropertyValue("Filename", m_filename); + alg->setPropertyValue("Title", "Testing this algorithm"); + TS_ASSERT_THROWS_NOTHING(alg->execute()); + + if ( ! alg->isExecuted() ) + { + TS_FAIL("Could not run SaveReflThreeColumnAscii"); + } + m_long_filename= alg->getPropertyValue("Filename"); + // has the algorithm written a file to disk? + TS_ASSERT( Poco::File(m_long_filename).exists() ); + std::ifstream in(m_long_filename.c_str()); + std::string fullline; + headingsTests(in, fullline,true); + getline(in,fullline); + + std::vector columns; + boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); + TS_ASSERT_EQUALS(columns.size(),5); + //the first is black due to the leading tab + TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); + in.close(); + + cleanupafterwards(); + } + void test_fail_invalid_workspace() + { + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflCustomAscii"); + alg->setRethrows(true); + TS_ASSERT(alg->isInitialized()); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); + m_long_filename= alg->getPropertyValue("Filename"); //Get absolute path + TS_ASSERT_THROWS_ANYTHING(alg->setPropertyValue("InputWorkspace", "NotARealWS")); + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + + // the algorithm shouldn't have written a file to disk + TS_ASSERT( !Poco::File(m_long_filename).exists() ); + } +private: + void headingsTests(std::ifstream & in,std::string & fullline, bool propertiesLogs = false) + { + if (propertiesLogs) + { + getline(in,fullline); + TS_ASSERT(fullline == "Title: Testing this algorithm"); + getline(in,fullline); + TS_ASSERT(fullline == "Subtitle: SaveReflThreeColumnAscii save test"); + } + else + { + } + } + void createWS(bool zeroX = false, bool zeroY = false, bool zeroE = false, bool createLogs = false) + { + MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(1,10); + + if (createLogs) + { + } + + AnalysisDataService::Instance().addOrReplace(m_name, ws); + //Check if any of X, Y or E should be zeroed to check for divide by zero or similiar + if (zeroX) + { + ws->dataX(0) = m_data0; + } + else + { + ws->dataX(0) = m_dataX; + } + + if (zeroY) + { + ws->dataY(0) = m_data0; + } + else + { + ws->dataY(0) = m_dataY; + } + + if (zeroE) + { + ws->dataE(0) = m_data0; + } + else + { + ws->dataE(0) = m_dataE; + } + } + void cleanupafterwards() + { + Poco::File(m_long_filename).remove(); + AnalysisDataService::Instance().remove(m_name); + } + std::string m_filename, m_name, m_long_filename; + std::vector m_dataX, m_dataY, m_dataE, m_data0; +}; +#endif /*SAVEREFLTHREECOLUMNASCIITEST_H_*/ From 4caeae0ce8546b8e24d3ee4c4c59fe0ca7c8168e Mon Sep 17 00:00:00 2001 From: Vickie Lynch Date: Wed, 12 Nov 2014 16:27:33 -0500 Subject: [PATCH 037/128] Refs #10541 sum background for NoFit and add MANDI to MaskBTP --- .../MDAlgorithms/src/IntegratePeaksMD2.cpp | 13 +++++++++++-- .../plugins/algorithms/MaskBTP.py | 18 +++++++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp index 8337881274a2..d1444b20cf21 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp @@ -432,7 +432,15 @@ namespace MDAlgorithms } } - if (profileFunction.compare("NoFit") != 0) + if (profileFunction.compare("NoFit") == 0) + { + for (size_t j = 0; j < numSteps; j++) + { + if (j < peakMin || j > peakMax) + background_total = background_total + wsProfile2D->dataY(i)[j]; + } + } + else { API::IAlgorithm_sptr findpeaks = createChildAlgorithm("FindPeaks", -1, -1, false); findpeaks->setProperty("InputWorkspace", wsProfile2D); @@ -554,7 +562,8 @@ namespace MDAlgorithms g_log.information() << "Peak " << i << " at " << pos << ": signal " << signal << " (sig^2 " << errorSquared << "), with background " - << bgSignal << " (sig^2 " << bgErrorSquared << ") subtracted." + << bgSignal + ratio * background_total << " (sig^2 " + << bgErrorSquared+ ratio * ratio * std::fabs(background_total) << ") subtracted." << std::endl; } diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/MaskBTP.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/MaskBTP.py index 3c4466cf2705..3e2326027143 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/MaskBTP.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/MaskBTP.py @@ -24,8 +24,8 @@ def summary(self): def PyInit(self): self.declareProperty(mantid.api.WorkspaceProperty("Workspace", "",direction=mantid.kernel.Direction.InOut, optional = mantid.api.PropertyMode.Optional), "Input workspace (optional)") - allowedInstrumentList=mantid.kernel.StringListValidator(["","ARCS","CNCS","CORELLI","HYSPEC","NOMAD","POWGEN","SEQUOIA","SNAP","SXD","TOPAZ","WISH"]) - self.declareProperty("Instrument","",validator=allowedInstrumentList,doc="One of the following instruments: ARCS, CNCS, CORELLI, HYSPEC, NOMAD, POWGEN, SNAP, SEQUOIA, SXD, TOPAZ, WISH") + allowedInstrumentList=mantid.kernel.StringListValidator(["","ARCS","CNCS","CORELLI","HYSPEC","MANDI","NOMAD","POWGEN","SEQUOIA","SNAP","SXD","TOPAZ","WISH"]) + self.declareProperty("Instrument","",validator=allowedInstrumentList,doc="One of the following instruments: ARCS, CNCS, CORELLI, HYSPEC, MANDI, NOMAD, POWGEN, SNAP, SEQUOIA, SXD, TOPAZ, WISH") self.declareProperty("Bank","",doc="Bank(s) to be masked. If empty, will apply to all banks") self.declareProperty("Tube","",doc="Tube(s) to be masked. If empty, will apply to all tubes") self.declareProperty("Pixel","",doc="Pixel(s) to be masked. If empty, will apply to all pixels") @@ -47,13 +47,13 @@ def PyExec(self): self.instrument = ws.getInstrument() self.instname = self.instrument.getName() - instrumentList=["ARCS","CNCS","CORELLI","HYSPEC","NOMAD","POWGEN","SEQUOIA","SNAP","SXD","TOPAZ","WISH"] - self.bankmin={"ARCS":1,"CNCS":1,"CORELLI":1,"HYSPEC":1,"NOMAD":1,"POWGEN":1,"SEQUOIA":38,"SNAP":1,"SXD":1,"TOPAZ":10,"WISH":1} - self.bankmax={"ARCS":115,"CNCS":50,"CORELLI":91,"HYSPEC":20,"NOMAD":99,"POWGEN":300,"SEQUOIA":150,"SNAP":18,"SXD":11,"TOPAZ":59,"WISH":10} - tubemin={"ARCS":1,"CNCS":1,"CORELLI":1,"HYSPEC":1,"NOMAD":1,"POWGEN":0,"SEQUOIA":1,"SNAP":0,"SXD":0,"TOPAZ":0,"WISH":1} - tubemax={"ARCS":8,"CNCS":8,"CORELLI":16,"HYSPEC":8,"NOMAD":8,"POWGEN":153,"SEQUOIA":8,"SNAP":255,"SXD":63,"TOPAZ":255,"WISH":152} - pixmin={"ARCS":1,"CNCS":1,"CORELLI":1,"HYSPEC":1,"NOMAD":1,"POWGEN":0,"SEQUOIA":1,"SNAP":0,"SXD":0,"TOPAZ":0,"WISH":1} - pixmax={"ARCS":128,"CNCS":128,"CORELLI":256,"HYSPEC":128,"NOMAD":128,"POWGEN":6,"SEQUOIA":128,"SNAP":255,"SXD":63,"TOPAZ":255,"WISH":512} + instrumentList=["ARCS","CNCS","CORELLI","HYSPEC","MANDI","NOMAD","POWGEN","SEQUOIA","SNAP","SXD","TOPAZ","WISH"] + self.bankmin={"ARCS":1,"CNCS":1,"CORELLI":1,"HYSPEC":1,"MANDI":10,"NOMAD":1,"POWGEN":1,"SEQUOIA":38,"SNAP":1,"SXD":1,"TOPAZ":10,"WISH":1} + self.bankmax={"ARCS":115,"CNCS":50,"CORELLI":91,"HYSPEC":20,"MANDI":59,"NOMAD":99,"POWGEN":300,"SEQUOIA":150,"SNAP":18,"SXD":11,"TOPAZ":59,"WISH":10} + tubemin={"ARCS":1,"CNCS":1,"CORELLI":1,"HYSPEC":1,"MANDI":0,"NOMAD":1,"POWGEN":0,"SEQUOIA":1,"SNAP":0,"SXD":0,"TOPAZ":0,"WISH":1} + tubemax={"ARCS":8,"CNCS":8,"CORELLI":16,"HYSPEC":8,"MANDI":255,"NOMAD":8,"POWGEN":153,"SEQUOIA":8,"SNAP":255,"SXD":63,"TOPAZ":255,"WISH":152} + pixmin={"ARCS":1,"CNCS":1,"CORELLI":1,"HYSPEC":1,"MANDI":0,"NOMAD":1,"POWGEN":0,"SEQUOIA":1,"SNAP":0,"SXD":0,"TOPAZ":0,"WISH":1} + pixmax={"ARCS":128,"CNCS":128,"CORELLI":256,"HYSPEC":128,"MANDI":255,"NOMAD":128,"POWGEN":6,"SEQUOIA":128,"SNAP":255,"SXD":63,"TOPAZ":255,"WISH":512} try: instrumentList.index(self.instname) From fd5d717e058b5294a90dfe290c2dd95ab52113cc Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Thu, 13 Nov 2014 09:29:50 +0000 Subject: [PATCH 038/128] Refs #8961 fully working save algorithm --- .../inc/MantidDataHandling/SaveReflThreeColumnAscii.h | 6 ++---- .../Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h index 38e6ffcbe8b9..7f145fd6eb42 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h @@ -51,10 +51,8 @@ namespace Mantid virtual const std::string summary() const {return "Saves a 2D workspace to a ascii file.";} /// Algorithm's version for identification overriding a virtual method virtual int version() const { return 1; } - - - /// - void data(std::ofstream & file, const std::vector & XData); + ///Algorithm's version for data output overriding a virtual method + void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ); private: diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp index 18ce9da72112..84ddb8e8ca26 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp @@ -38,7 +38,6 @@ namespace Mantid { subtitle = ""; } - ////git change!!!!!!!! if (title != "") //if is toggled { file << "#" << title << std::endl; @@ -52,9 +51,9 @@ namespace Mantid } } - void SaveReflThreeColumnAscii::data(std::ofstream & file, const std::vector & XData) + void SaveReflThreeColumnAscii::data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ) { - AsciiPointBase::data(file, XData, false); + AsciiPointBase::data(file, XData, false); //toggled false permantly because only to show 3 columns } From 51f0fa177cca51c3fec1b68cc9f4935529d00cc7 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Thu, 13 Nov 2014 11:32:21 +0000 Subject: [PATCH 039/128] Refs #8961 delete whitespace --- .../DataHandling/src/SaveReflThreeColumnAscii.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp index 84ddb8e8ca26..ad0eea402041 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp @@ -51,9 +51,14 @@ namespace Mantid } } + /** virtual method to add information to the file before the data + * @param file :: pointer to output file stream + * @param XData :: pointer to a std::vector containing the point data to be printed + * @param exportDeltaQ :: bool on whether deltaQ column to be printed (permanantly false in this case) + */ void SaveReflThreeColumnAscii::data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ) { - AsciiPointBase::data(file, XData, false); //toggled false permantly because only to show 3 columns + AsciiPointBase::data(file, XData, false); } From d6ce9111d8dca4ec4f20f6186a0c8417052fed3b Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Thu, 13 Nov 2014 14:22:08 +0000 Subject: [PATCH 040/128] Refs #10552 Prompt user to login to catalog when needed --- .../MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp index 800fec7e18d2..ed194f1ab8d8 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp @@ -1,5 +1,6 @@ #include "MantidQtCustomInterfaces/ReflMainViewPresenter.h" #include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/CatalogManager.h" #include "MantidAPI/ITableWorkspace.h" #include "MantidAPI/TableRow.h" #include "MantidGeometry/Instrument/ParameterMap.h" @@ -1169,6 +1170,11 @@ namespace MantidQt if(searchString.empty()) return; + //This is breaking the abstraction provided by IReflSearcher, but provides a nice usability win + //If we're not logged into a catalog, prompt the user to do so + if(CatalogManager::Instance().getActiveSessions().empty()) + m_view->showAlgorithmDialog("CatalogLogin"); + try { auto results = m_searcher->search(searchString, searchInstr); From 25018a3e9588db3e5d0e5b1909e66b161b2a23f5 Mon Sep 17 00:00:00 2001 From: Vickie Lynch Date: Thu, 13 Nov 2014 16:44:40 -0500 Subject: [PATCH 041/128] Refs #10541 fix intensity sum and zero at profile edge --- .../Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp | 8 ++++++-- Code/Mantid/Framework/MDEvents/src/MDBox.cpp | 5 ++--- Code/Mantid/Framework/MDEvents/src/MDGridBox.cpp | 7 ++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp index d1444b20cf21..638c28ba54bf 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp @@ -434,11 +434,15 @@ namespace MDAlgorithms if (profileFunction.compare("NoFit") == 0) { + signal = 0.; for (size_t j = 0; j < numSteps; j++) { if (j < peakMin || j > peakMax) background_total = background_total + wsProfile2D->dataY(i)[j]; + else + signal = signal + wsProfile2D->dataY(i)[j]; } + errorSquared = std::fabs(signal); } else { @@ -522,7 +526,7 @@ namespace MDAlgorithms signal = 0.0; if (integrationOption.compare("Sum") == 0) { - for (size_t j = 0; j < numSteps; j++) if ( !boost::math::isnan(yy[j]) && !boost::math::isinf(yy[j]))signal+= yy[j]; + for (size_t j = peakMin; j <= peakMax; j++) if ( !boost::math::isnan(yy[j]) && !boost::math::isinf(yy[j]))signal+= yy[j]; } else { @@ -535,7 +539,7 @@ namespace MDAlgorithms F.function = &Mantid::MDAlgorithms::f_eval2; F.params = &fun; - gsl_integration_qags (&F, x[0], x[numSteps-1], 0, 1e-7, 1000, + gsl_integration_qags (&F, x[peakMin], x[peakMax], 0, 1e-7, 1000, w, &signal, &error); gsl_integration_workspace_free (w); diff --git a/Code/Mantid/Framework/MDEvents/src/MDBox.cpp b/Code/Mantid/Framework/MDEvents/src/MDBox.cpp index ece7dfc1309f..d167f484ee39 100644 --- a/Code/Mantid/Framework/MDEvents/src/MDBox.cpp +++ b/Code/Mantid/Framework/MDEvents/src/MDBox.cpp @@ -4,6 +4,7 @@ #include "MantidMDEvents/MDLeanEvent.h" #include "MantidKernel/DiskBuffer.h" #include "MantidMDEvents/MDGridBox.h" +#include #include using namespace Mantid::API; @@ -644,9 +645,7 @@ namespace MDEvents if (out[0] < radius && std::fabs(out[1]) < 0.5*length) { // add event to appropriate y channel - size_t xchannel; - if (out[1] < 0) xchannel = static_cast(out[1] / deltaQ - 0.5) + static_cast(numSteps / 2)-1; - else xchannel = static_cast(out[1] / deltaQ + 0.5) + static_cast(numSteps / 2)-1; + size_t xchannel = static_cast(std::floor(out[1] / deltaQ)) + numSteps / 2; if (xchannel < numSteps ) signal_fit[xchannel] += static_cast(it->getSignal()); signal += static_cast(it->getSignal()); diff --git a/Code/Mantid/Framework/MDEvents/src/MDGridBox.cpp b/Code/Mantid/Framework/MDEvents/src/MDGridBox.cpp index 92b4191455bf..ba39552ea74f 100644 --- a/Code/Mantid/Framework/MDEvents/src/MDGridBox.cpp +++ b/Code/Mantid/Framework/MDEvents/src/MDGridBox.cpp @@ -9,6 +9,7 @@ #include "MantidMDEvents/MDBox.h" #include "MantidMDEvents/MDEvent.h" #include "MantidMDEvents/MDGridBox.h" +#include #include #include "MantidKernel/Strings.h" @@ -1436,11 +1437,7 @@ GCC_DIAG_OFF(array-bounds) coord_t out[nd]; radiusTransform.apply(eventCenter, out); // add event to appropriate y channel - size_t xchannel; - if (out[1] < 0) - xchannel = static_cast(out[1] / deltaQ - 0.5) + static_cast(numSteps / 2)-1; - else - xchannel = static_cast(out[1] / deltaQ + 0.5) + static_cast(numSteps / 2)-1; + size_t xchannel = static_cast(std::floor(out[1] / deltaQ)) + numSteps / 2; if (xchannel < numSteps ) signal_fit[xchannel] += coordTable[k*nColumns]; From 8f9facd7ca8fff3c3879e971fc78fd6cb7dd7d68 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Fri, 14 Nov 2014 12:29:04 +0000 Subject: [PATCH 042/128] Refactoring in SofQWMoments Refs #10340 --- .../Algorithms/src/GeneratePythonScript.cpp | 6 ++++++ .../algorithms/WorkflowAlgorithms/SofQWMoments.py | 12 ++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Code/Mantid/Framework/Algorithms/src/GeneratePythonScript.cpp b/Code/Mantid/Framework/Algorithms/src/GeneratePythonScript.cpp index a66d07d86845..88ca0531b4be 100644 --- a/Code/Mantid/Framework/Algorithms/src/GeneratePythonScript.cpp +++ b/Code/Mantid/Framework/Algorithms/src/GeneratePythonScript.cpp @@ -11,6 +11,11 @@ using namespace Mantid::Kernel; using namespace Mantid::API; +namespace +{ + Mantid::Kernel::Logger g_log("GeneratePythonScript"); +} + namespace Mantid { namespace Algorithms @@ -61,6 +66,7 @@ void GeneratePythonScript::exec() // Get the algorithm histories of the workspace. const WorkspaceHistory wsHistory = ws->getHistory(); + g_log.information() << "Number of history items: " << wsHistory.size() << std::endl; auto view = wsHistory.createView(); diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMoments.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMoments.py index 88cc2e3dbcaf..5818186cb4ed 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMoments.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMoments.py @@ -1,13 +1,13 @@ # Algorithm to start Bayes programs from mantid.simpleapi import * -from mantid.api import PythonAlgorithm, AlgorithmFactory, MatrixWorkspaceProperty, WorkspaceGroupProperty +from mantid.api import DataProcessorAlgorithm, AlgorithmFactory, MatrixWorkspaceProperty, WorkspaceGroupProperty from mantid.kernel import Direction from mantid import logger import os.path import numpy as np -class SofQWMoments(PythonAlgorithm): +class SofQWMoments(DataProcessorAlgorithm): def category(self): return "Workflow\\MIDAS;PythonAlgorithms" @@ -104,9 +104,9 @@ def PyExec(self): AddSampleLog(Workspace=ws_name, LogName="energy_max", LogType="Number", LogText=str(emax)) AddSampleLog(Workspace=ws_name, LogName="scale_factor", LogType="Number", LogText=str(factor)) - #group ouput workspace + # Group output workspace group_workspaces = ','.join([output_workspace+ext for ext in extensions]) - GroupWorkspaces(InputWorkspaces=group_workspaces,OutputWorkspace=output_workspace) + GroupWorkspaces(InputWorkspaces=group_workspaces, OutputWorkspace=output_workspace) if Save: workdir = getDefaultWorkingDirectory() @@ -126,8 +126,8 @@ def _plot_moments(self, inputWS): from IndirectImport import import_mantidplot mp = import_mantidplot() - mp.plotSpectrum(inputWS+'_M0',0) - mp.plotSpectrum([inputWS+'_M2',inputWS+'_M4'],0) + mp.plotSpectrum(inputWS+'_M0', 0) + mp.plotSpectrum([inputWS+'_M2', inputWS+'_M4'], 0) # Register algorithm with Mantid AlgorithmFactory.subscribe(SofQWMoments) From 79c0ad72f61a4231f5b1bd8d66aedcbe9f9a42ca Mon Sep 17 00:00:00 2001 From: Vickie Lynch Date: Fri, 14 Nov 2014 09:23:05 -0500 Subject: [PATCH 043/128] Refs #10535 coding change suggested by Andrei --- .../MDAlgorithms/src/IntegratePeaksMD2.cpp | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp index 54cbc16551cf..790bdad9da6a 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp @@ -257,23 +257,7 @@ namespace MDAlgorithms // Do not integrate if sphere is off edge of detector if (BackgroundOuterRadius > PeakRadius) { - if (!detectorQ(p.getQLabFrame(), BackgroundOuterRadius)) - { - g_log.warning() << "Warning: sphere/cylinder for integration is off edge of detector for peak " << i << std::endl; - if (!integrateEdge) - { - if (replaceIntensity) - { - p.setIntensity(0.0); - p.setSigmaIntensity( 0.0 ); - } - continue; - } - } - } - else - { - if (!detectorQ(p.getQLabFrame(), PeakRadius)) + if (!detectorQ(p.getQLabFrame(), std::max(BackgroundOuterRadius, PeakRadius))) { g_log.warning() << "Warning: sphere/cylinder for integration is off edge of detector for peak " << i << std::endl; if (!integrateEdge) From 34b872205c8eeed92405fc20560e14691b02af67 Mon Sep 17 00:00:00 2001 From: Vickie Lynch Date: Fri, 14 Nov 2014 09:29:42 -0500 Subject: [PATCH 044/128] Refs #10535 remove outer loop --- .../MDAlgorithms/src/IntegratePeaksMD2.cpp | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp index 790bdad9da6a..3b57416b1a2d 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp @@ -255,22 +255,20 @@ namespace MDAlgorithms pos = p.getHKL(); // Do not integrate if sphere is off edge of detector - if (BackgroundOuterRadius > PeakRadius) - { - if (!detectorQ(p.getQLabFrame(), std::max(BackgroundOuterRadius, PeakRadius))) - { - g_log.warning() << "Warning: sphere/cylinder for integration is off edge of detector for peak " << i << std::endl; - if (!integrateEdge) + + if (!detectorQ(p.getQLabFrame(), std::max(BackgroundOuterRadius, PeakRadius))) + { + g_log.warning() << "Warning: sphere/cylinder for integration is off edge of detector for peak " << i << std::endl; + if (!integrateEdge) + { + if (replaceIntensity) { - if (replaceIntensity) - { - p.setIntensity(0.0); - p.setSigmaIntensity( 0.0 ); - } - continue; + p.setIntensity(0.0); + p.setSigmaIntensity( 0.0 ); } - } - } + continue; + } + } // Build the sphere transformation bool dimensionsUsed[nd]; From af0d63574830d691417571b90da8cbcd29f11048 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 17 Nov 2014 10:19:56 +0000 Subject: [PATCH 045/128] Better logging in IIR algo Refs #10562 --- .../WorkflowAlgorithms/InelasticIndirectReduction.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py index 059a46744d5c..638b66a88e85 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py @@ -76,10 +76,10 @@ def PyExec(self): reducer.set_detector_range(int(self._detector_range[0]) - 1, int(self._detector_range[1]) - 1) - self._use_calib_ws = self._calib_ws.value is not None + self._use_calib_ws = self._calib_ws_name != '' if self._use_calib_ws: - logger.debug('Using calibration workspace') - reducer.set_calibration_workspace(self._calib_ws.valueAsStr) + logger.information('Using calibration workspace: %s' % self._calib_ws_name) + reducer.set_calibration_workspace(self._calib_ws_name) if len(self._background_range) == 2: logger.debug('Using background range: ' + str(self._background_range)) @@ -169,7 +169,6 @@ def _setup(self): self._detector_range = self.getProperty('DetectorRange').value self._background_range = self.getProperty('BackgroundRange').value - self._calib_ws = self.getProperty('CalibrationWorkspace') self._calib_ws_name = self.getPropertyValue('CalibrationWorkspace') self._detailed_balance = self.getProperty('DetailedBalance').value From 3f14d3900e30c8215b7e4d160222d2e555148861 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 17 Nov 2014 10:21:23 +0000 Subject: [PATCH 046/128] Add runtime props to IIR algo Refs #10562 --- .../MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp index 9718efca4d08..779bd4102886 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp @@ -177,7 +177,7 @@ namespace CustomInterfaces break; } - m_batchAlgoRunner->addAlgorithm(reductionAlg); + m_batchAlgoRunner->addAlgorithm(reductionAlg, reductionRuntimeProps); m_batchAlgoRunner->executeBatchAsync(); } From 2112c7d2d3885efc05b33e1239679d5f8d37e475 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 17 Nov 2014 10:37:06 +0000 Subject: [PATCH 047/128] Populate calib filename with saved file from Calib tab Refs #10562 --- .../MantidQt/CustomInterfaces/src/IndirectCalibration.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectCalibration.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectCalibration.cpp index 51b186d669fd..19b5be13d198 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectCalibration.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectCalibration.cpp @@ -238,7 +238,11 @@ namespace CustomInterfaces createRESfile(filenames); } - /* m_uiForm.ind_calibFile->setFileTextWithSearch(pyOutput + ".nxs"); */ + QString firstFile = m_uiForm.cal_leRunNo->getFirstFilename(); + QFileInfo firstFileInfo(firstFile); + QString calFileName = firstFileInfo.baseName() + "_" + m_uiForm.cbAnalyser->currentText() + m_uiForm.cbReflection->currentText() + "_calib.nxs"; + + m_uiForm.ind_calibFile->setFileTextWithSearch(calFileName); m_uiForm.ckUseCalib->setChecked(true); disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(algorithmsComplete(bool))); From 1c1d2dd2d81a475b22b88780c3eeb0f2240181d1 Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Mon, 17 Nov 2014 12:08:21 +0000 Subject: [PATCH 048/128] Updated links in deb readme nd script, and in tests and doc, re #10490 --- .../Build/paraview-deb-packaging/README | 17 +++-- .../build_and_package.sh | 4 +- .../ICat/test/CatalogDownloadDataFilesTest.h | 76 ++++++++++--------- .../Properties/Mantid.properties.template | 2 +- .../CreateEmptyTableWorkspace-v1.rst | 2 +- 5 files changed, 54 insertions(+), 47 deletions(-) diff --git a/Code/Mantid/Build/paraview-deb-packaging/README b/Code/Mantid/Build/paraview-deb-packaging/README index c0ad9aace0ab..2a81ae958d90 100644 --- a/Code/Mantid/Build/paraview-deb-packaging/README +++ b/Code/Mantid/Build/paraview-deb-packaging/README @@ -1,14 +1,19 @@ --Author: Owen Arnold ---Date: 06/March/2012 +--Date: 06/March/2012, updated 14/Nov/2014 Info: The bash script in this directory is used to build and package ParaView to Debian packages for Ubuntu platforms. -At the time of writing custom deployment is necessary for these reasons: +At the time of writing custom deployment is necessary for two reasons: -1) Current versions of Ubuntu distribute much older versions of ParaView from their repositories -2) The distributed source version of ParaView 3.10.1 contains bugs which we have fixed in our modified source code. This script can be used with our patched source. Currently available at http://download.mantidproject.org/VatesDownload.psp -3) The default ParaView packaging puts libraries in subdirectories of lib and they therefore cannot be found by Mantid without manually modifying the LD_LIBRARY_PATH. This packaging script will fix that issue. +1) We distribute a slightly modified source version of ParaView 3.98.1. This script can be used with our patched source. + Currently available at http://download.mantidproject.org +2) The default ParaView packaging puts libraries in subdirectories of lib and they therefore cannot be found by Mantid + without manually modifying the LD_LIBRARY_PATH. This packaging script will fix that issue. Usage: -In order to build the binary packages. Place the *.tar.gz paraview source compressed file from http://download.mantidproject.org/VatesDownload.psp into an empty directory. Copy the accompanying *.sh script associated with this README into the same directory. Run the bash script. The packaged .*Deb binaries will appear in the /paraview/install directory at the end of the process. +- In order to build the binary packages. Place the *.tar.gz paraview source compressed file from + http://download.mantidproject.org into an empty directory. + +- Copy the accompanying *.sh script associated with this README into the same directory. Run the bash script. + The packaged .*Deb binaries will appear in the /paraview/install directory at the end of the process. diff --git a/Code/Mantid/Build/paraview-deb-packaging/build_and_package.sh b/Code/Mantid/Build/paraview-deb-packaging/build_and_package.sh index 823b1369fd5a..bd24d6a3b7a4 100755 --- a/Code/Mantid/Build/paraview-deb-packaging/build_and_package.sh +++ b/Code/Mantid/Build/paraview-deb-packaging/build_and_package.sh @@ -9,9 +9,9 @@ PV_LOC=paraview PV_PKG=ParaView -PV_VER=3.10.1 +PV_VER=3.98.1 -PV_NAME=${PV_PKG}-${PV_VER}-patched +PV_NAME=${PV_PKG}-${PV_VER}-source PV_SRC=${PV_NAME}.tar.gz diff --git a/Code/Mantid/Framework/ICat/test/CatalogDownloadDataFilesTest.h b/Code/Mantid/Framework/ICat/test/CatalogDownloadDataFilesTest.h index 2710f389091c..0fbebf343a8f 100644 --- a/Code/Mantid/Framework/ICat/test/CatalogDownloadDataFilesTest.h +++ b/Code/Mantid/Framework/ICat/test/CatalogDownloadDataFilesTest.h @@ -232,44 +232,46 @@ class CatalogDownloadDataFilesTest: public CxxTest::TestSuite if (Poco::File(filepath).exists()) Poco::File(filepath).remove(); } - void xtestDownloaddataFile1() - { - std::string filepath=Kernel::ConfigService::Instance().getString("defaultsave.directory"); - filepath += "download_time.txt"; - std::ofstream ofs(filepath.c_str(), std::ios_base::out | std::ios_base::app); - if ( ofs.rdstate() & std::ios::failbit ) - { - throw Mantid::Kernel::Exception::FileError("Error on creating File","download_time.txt"); - } - - CatalogDownloadDataFiles downloadobj1; - - // As the algorithm now uses setProperty to allow us to save it to a directory we must pass in the default for testing. - std::string fName = Kernel::ConfigService::Instance().getString("defaultsave.directory"); - // Need to initialize the algorithm in order to set the "downloadPath" property. - if ( !downloadobj1.isInitialized() ) downloadobj1.initialize(); - downloadobj1.setPropertyValue("DownloadPath",fName); - - clock_t start=clock(); - std::string fullPathDownloadedFile = downloadobj1.testDownload("http://download.mantidproject.org/videos/Installation.htm","test.htm"); - clock_t end=clock(); - float diff = float(end -start)/CLOCKS_PER_SEC; - - ofs<<"Time taken for http download from mantidwebserver over internet for a small file of size 1KB is "< Date: Mon, 17 Nov 2014 12:09:31 +0000 Subject: [PATCH 049/128] update link to where the repo currently lives, re #10490 --- Code/Mantid/docs/source/concepts/Properties_File.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/docs/source/concepts/Properties_File.rst b/Code/Mantid/docs/source/concepts/Properties_File.rst index 7a780e0c0dd2..a86c236c2af4 100644 --- a/Code/Mantid/docs/source/concepts/Properties_File.rst +++ b/Code/Mantid/docs/source/concepts/Properties_File.rst @@ -143,7 +143,7 @@ ScriptRepository Properties +=======================+===============================================+================================================================+ |ScriptLocalRepository |Directory where ScriptRepository is Installed. |c:\MantidInstall\MyScriptRepository | +-----------------------+-----------------------------------------------+----------------------------------------------------------------+ -|ScriptRepository |URL for the remote script repository. |http://download.mantidproject.org/scriptrepository/ | +|ScriptRepository |URL for the remote script repository. |https://github.com/mantidproject/scriptrepository | +-----------------------+-----------------------------------------------+----------------------------------------------------------------+ |UploaderWebServer |URL for uploading scripts. |http://upload.mantidproject.org/scriptrepository/payload/publish| +-----------------------+-----------------------------------------------+----------------------------------------------------------------+ @@ -162,4 +162,4 @@ To get access to, e.g. data saving path property from a C++ program one has to i path = ConfigService.getString("defaultsave.directory") -.. categories:: Concepts \ No newline at end of file +.. categories:: Concepts From bd8c3dc2e69817f185e84abb23e4607febe3bcc5 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 17 Nov 2014 13:40:31 +0000 Subject: [PATCH 050/128] Add history of a WS group to children on algo Refs #10340 --- Code/Mantid/Framework/API/src/Algorithm.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Code/Mantid/Framework/API/src/Algorithm.cpp b/Code/Mantid/Framework/API/src/Algorithm.cpp index f7cec91dc0fe..7e12dfaf7c3c 100644 --- a/Code/Mantid/Framework/API/src/Algorithm.cpp +++ b/Code/Mantid/Framework/API/src/Algorithm.cpp @@ -1055,15 +1055,33 @@ namespace Mantid // Loop over the output workspaces for (outWS = outputWorkspaces.begin(); outWS != outputWorkspaces.end(); ++outWS) { + WorkspaceGroup_sptr wsGroup = boost::dynamic_pointer_cast(*outWS); + // Loop over the input workspaces, making the call that copies their history to the output ones // (Protection against copy to self is in WorkspaceHistory::copyAlgorithmHistory) for (inWS = inputWorkspaces.begin(); inWS != inputWorkspaces.end(); ++inWS) { (*outWS)->history().addHistory( (*inWS)->getHistory() ); + + if(wsGroup) + { + for(size_t i = 0; i < wsGroup->size(); i++) + { + wsGroup->getItem(i)->history().addHistory( (*inWS)->getHistory() ); + } + } } // Add the history for the current algorithm to all the output workspaces (*outWS)->history().addHistory(m_history); + + if(wsGroup) + { + for(size_t i = 0; i < wsGroup->size(); i++) + { + wsGroup->getItem(i)->history().addHistory(m_history); + } + } } } //this is a child algorithm, but we still want to keep the history. From a5659b188ef8436a465f1d7991f4846f7a9b7ff0 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 17 Nov 2014 13:43:42 +0000 Subject: [PATCH 051/128] Remove old variable from ApplyCorr constructor Refs #10345 --- Code/Mantid/MantidQt/CustomInterfaces/src/ApplyCorr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/ApplyCorr.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/ApplyCorr.cpp index 53a895237ea4..3586c5c5acfe 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/ApplyCorr.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/ApplyCorr.cpp @@ -18,7 +18,7 @@ namespace CustomInterfaces namespace IDA { ApplyCorr::ApplyCorr(QWidget * parent) : - IDATab(parent), m_valPosDbl(NULL) + IDATab(parent) { } From 5318ec9fe9bebad609959e5aaf25c067b9dc8240 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 17 Nov 2014 15:16:23 +0000 Subject: [PATCH 052/128] Added new ElasticWindowMultiple algorithm Refs #10409 --- .../ElasticWindowMultiple.py | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py new file mode 100644 index 000000000000..1bc5dfd49382 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py @@ -0,0 +1,165 @@ +from mantid.simpleapi import * +from mantid.kernel import * +from mantid.api import * + + +class ElasticWindowMultiple(DataProcessorAlgorithm): + + def category(self): + return 'Workflow\\Inelastic;PythonAlgorithms;Inelastic' + + + def summary(self): + return 'Performs the ElasticWindow algorithm over multiple input workspaces' + + + def PyInit(self): + self.declareProperty(WorkspaceGroupProperty('InputWorkspaces', '', Direction.Input), + doc='Resolution workspace') + + self.declareProperty(name='Range1Start', defaultValue=0.0, doc='Range 1 start') + self.declareProperty(name='Range1End', defaultValue=0.0, doc='Range 1 end') + + self.declareProperty(name='Range2Start', defaultValue='', doc='Range 2 start') + self.declareProperty(name='Range2End', defaultValue='', doc='Range 2 end') + + self.declareProperty(WorkspaceProperty('OutputInQ', '', Direction.Output), + doc='Output workspace in Q') + + self.declareProperty(WorkspaceProperty('OutputInQSquared', '', Direction.Output), + doc='Output workspace in Q Squared') + + self.declareProperty(name='Plot', defaultValue=False, doc='Plot result spectra') + + + def validateInputs(self): + issues = dict() + + input_workspaces = self.getProperty('InputWorkspaces').value + if len(input_workspaces.getNames()) < 2: + issues['InputWorkspaces'] = 'Input workspace group must contain at least 2 workspaces' + + range_2_start = self.getPropertyValue('Range2Start') + range_2_end = self.getPropertyValue('Range2End') + + if range_2_start != '' and range_2_end == '': + issues['Range2End'] = 'If range 2 start was given and range 2 end must also be provided.' + + if range_2_start == '' and range_2_end != '': + issues['Range2Start'] = 'If range 2 end was given and range 2 start must also be provided.' + + if range_2_start != '': + try: + val = float(range_2_start) + except ValueError: + issues['Range2Start'] = 'Range 2 start is not a double number' + + if range_2_end != '': + try: + val = float(range_2_end) + except ValueError: + issues['Range2End'] = 'Range 2 end is not a double number' + + return issues + + + def PyExec(self): + from IndirectImport import import_mantidplot + + # Do setup + self._setup() + + # Lists of input and output workspaces + input_workspace_names = self._input_workspaces.getNames() + q_workspaces = list() + q2_workspaces = list() + + # Perform the ElasticWindow algorithms + for input_ws in input_workspace_names: + q_ws = input_ws + '_q' + q2_ws = input_ws + '_q2' + + if self._range_2_start != '' and self._range_2_end != '': + ElasticWindow(InputWorkspace=input_ws, OutputInQ=q_ws, OutputInQSquared=q2_ws, + Range1Start=self._range_1_start, Range1End=self._range_1_end, + Range2Start=float(self._range_2_start), Range2End=float(self._range_2_end)) + else: + ElasticWindow(InputWorkspace=input_ws, OutputInQ=q_ws, OutputInQSquared=q2_ws, + Range1Start=self._range_1_start, Range1End=self._range_1_end) + + q_workspaces.append(q_ws) + q2_workspaces.append(q2_ws) + + # Must have two of each type of workspace to continue + if len(q_workspaces) < 2: + raise RuntimeError('Have less than 2 result workspaces in Q') + if len(q2_workspaces) < 2: + raise RuntimeError('Hvae less than 2 result workspaces in Q^2') + + # Append the spectra of the first two workspaces + AppendSpectra(InputWorkspace1=q_workspaces[0], InputWorkspace2=q_workspaces[1], OutputWorkspace=self._q_workspace) + AppendSpectra(InputWorkspace1=q2_workspaces[0], InputWorkspace2=q2_workspaces[1], OutputWorkspace=self._q2_workspace) + + # Append to the spectra of each remaining workspace + for idx in xrange(2, len(input_workspace_names)): + AppendSpectra(InputWorkspace1=self._q_workspace, InputWorkspace2=q_workspaces[idx], OutputWorkspace=self._q_workspace) + AppendSpectra(InputWorkspace1=self._q2_workspace, InputWorkspace2=q2_workspaces[idx], OutputWorkspace=self._q2_workspace) + + # Delete the output workspaces from the ElasticWindow algorithms + for q_ws in q_workspaces: + DeleteWorkspace(q_ws) + for q2_ws in q2_workspaces: + DeleteWorkspace(q2_ws) + + # Set the output workspace + self.setProperty('OutputInQ', self._q_workspace) + self.setProperty('OutputInQSquared', self._q2_workspace) + + # Plot spectra plots + if self._plot: + self._mtd_plot = import_mantidplot() + self._plot_spectra(self._q_workspace) + self._plot_spectra(self._q2_workspace) + + + def _setup(self): + """ + Gets algorithm properties. + """ + + self._plot = self.getProperty('Plot').value + + self._input_workspaces = self.getProperty('InputWorkspaces').value + self._q_workspace = self.getPropertyValue('OutputInQ') + self._q2_workspace = self.getPropertyValue('OutputInQSquared') + + self._range_1_start = self.getProperty('Range1Start').value + self._range_1_end = self.getProperty('Range1End').value + + self._range_2_start = self.getPropertyValue('Range2Start') + self._range_2_end = self.getPropertyValue('Range2End') + + + def _plot_spectra(self, ws_name): + """ + Plots up to the first 10 spectra from a workspace. + + @param ws_name Name of workspace to plot + """ + + num_hist = mtd[ws_name].getNumberHistograms() + + # Limit number of plotted histograms to 10 + if num_hist > 10: + num_hist = 10 + + # Build plot list + plot_list = [] + for i in range(0, num_hist): + plot_list.append(i) + + self._mtd_plot.plotSpectrum(ws_name, plot_list) + + +# Register algorithm with Mantid +AlgorithmFactory.subscribe(ElasticWindowMultiple) From 962ac2ddf5f322e68be5b22fb19a56a0cae640ef Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Mon, 17 Nov 2014 15:27:38 +0000 Subject: [PATCH 053/128] fix base repo url so that urls can be properly constructed, re #10490 --- Code/Mantid/Framework/Properties/Mantid.properties.template | 4 ++-- Code/Mantid/docs/source/concepts/Properties_File.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Mantid/Framework/Properties/Mantid.properties.template b/Code/Mantid/Framework/Properties/Mantid.properties.template index 5c49f4ebd98f..2245b3e08cd8 100644 --- a/Code/Mantid/Framework/Properties/Mantid.properties.template +++ b/Code/Mantid/Framework/Properties/Mantid.properties.template @@ -182,8 +182,8 @@ interfaces.categories.hidden = UploaderWebServer = @MANTIDPUBLISHER@ # Local system path for the script repository. ScriptLocalRepository = -# Url for the remote script repository. -ScriptRepository = https://github.com/mantidproject/scriptrepository +# Base Url for the remote script repository. Not necessarily accessible, it is used to construct longer URLs +ScriptRepository = http://download.mantidproject.org/scriptrepository/ # Pattern given to ScriptRepository that is used to hide entries from repository to the users. It is a csv string separated with ';' ScriptRepositoryIgnore = *pyc; diff --git a/Code/Mantid/docs/source/concepts/Properties_File.rst b/Code/Mantid/docs/source/concepts/Properties_File.rst index a86c236c2af4..69c73b53d206 100644 --- a/Code/Mantid/docs/source/concepts/Properties_File.rst +++ b/Code/Mantid/docs/source/concepts/Properties_File.rst @@ -143,7 +143,7 @@ ScriptRepository Properties +=======================+===============================================+================================================================+ |ScriptLocalRepository |Directory where ScriptRepository is Installed. |c:\MantidInstall\MyScriptRepository | +-----------------------+-----------------------------------------------+----------------------------------------------------------------+ -|ScriptRepository |URL for the remote script repository. |https://github.com/mantidproject/scriptrepository | +|ScriptRepository |Base URL for the remote script repository. |http://download.mantidproject.org/scriptrepository/ | +-----------------------+-----------------------------------------------+----------------------------------------------------------------+ |UploaderWebServer |URL for uploading scripts. |http://upload.mantidproject.org/scriptrepository/payload/publish| +-----------------------+-----------------------------------------------+----------------------------------------------------------------+ From 0e7283be98fbef9a1af0a89e093461732d2d882c Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Mon, 17 Nov 2014 15:15:23 +0000 Subject: [PATCH 054/128] Refs #8961 fixed for cppcheckbuilds --- .../MantidDataHandling/SaveReflThreeColumn.h | 69 +++++++++++++++++++ .../DataHandling/src/SaveReflThreeColumn.cpp | 61 ++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumn.h create mode 100644 Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumn.cpp diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumn.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumn.h new file mode 100644 index 000000000000..54d76c6de494 --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumn.h @@ -0,0 +1,69 @@ +#ifndef MANTID_DATAHANDLING_SAVEREFLTHREECOLUMNASCII_H_ +#define MANTID_DATAHANDLING_SAVEREFLTHREECOLUMNASCII_H_ + +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidDataHandling/AsciiPointBase.h" + +namespace Mantid +{ + namespace DataHandling + { + /** + Saves a file in ILL Cosmos format from a 2D workspace + (Workspace2D class). SaveILLCosmosAscii is an algorithm but inherits frrm the + AsciiPointBase class which provides the main implementation for the init() & exec() methods. + Output is tab delimited Ascii point data with dq/q and extra header information. + + Copyright © 2007-14 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + File change history is stored at: . + Code Documentation is available at: + */ + class DLLExport SaveReflThreeColumnAscii : public DataHandling::AsciiPointBase + { + public: + /// Default constructor + SaveReflThreeColumnAscii() {} + /// Destructor + ~SaveReflThreeColumnAscii() {} + /// Algorithm's name for identification overriding a virtual method + virtual const std::string name() const { return "SaveReflThreeColumnAscii"; } + ///Summary of algorithms purpose + virtual const std::string summary() const {return "Saves a 2D workspace to a ascii file.";} + /// Algorithm's version for identification overriding a virtual method + virtual int version() const { return 1; } + ///Algorithm's version for data output overriding a virtual method + void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ); + + private: + + /// Return the file extension this algorthm should output. + virtual std::string ext() {return ".dat";} + ///extra properties specifically for this + virtual void extraProps(); + /// write any extra information required + virtual void extraHeaders(std::ofstream & file); + }; + } // namespace DataHandling +} // namespace Mantid + +#endif /* MANTID_DATAHANDLING_SAVEREFLTHREECOLUMNASCII_H_ */ \ No newline at end of file diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumn.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumn.cpp new file mode 100644 index 000000000000..4f9ba406226a --- /dev/null +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumn.cpp @@ -0,0 +1,61 @@ +//---------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------- +#include "MantidDataHandling/SaveReflThreeColumnAscii.h" +#include "MantidDataHandling/AsciiPointBase.h" +#include "MantidKernel/ArrayProperty.h" +#include + +namespace Mantid +{ + namespace DataHandling + { + // Register the algorithm into the algorithm factory + DECLARE_ALGORITHM(SaveReflThreeColumnAscii) + using namespace Kernel; + using namespace API; + + /// virtual method to set the extra properties required for this algorithm + void SaveReflThreeColumnAscii::extraProps() + { + declareProperty(new ArrayProperty("LogList"),"List of logs to write to file."); + declareProperty("Title", "", "Text to be written to the Title field"); + } + + /** virtual method to add information to the file before the data + * @param file :: pointer to output file stream + */ + void SaveReflThreeColumnAscii::extraHeaders(std::ofstream & file) + { + auto samp = m_ws->run(); + //std::string subtitle; + std::string title = getProperty("Title"); + /*try + { + subtitle = samp.getLogData("run_title")->value(); + } + catch (Kernel::Exception::NotFoundError &) + { + subtitle = ""; + }*/ + if (title != "") //if is toggled + { + file << "#" << title << std::endl; + } + + const std::vector logList = getProperty("LogList"); + ///logs + for (auto log = logList.begin(); log != logList.end(); ++log) + { + file << boost::lexical_cast(*log) << ": " << boost::lexical_cast(samp.getLogData(*log)->value()) << std::endl; + } + } + + void SaveReflThreeColumnAscii::data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ) + { + AsciiPointBase::data(file, XData, false); //toggled false permantly because only to show 3 columns + } + + + } // namespace DataHandling +} // namespace Mantid \ No newline at end of file From 2dd14f45163c4526dece79d4e70afdf3654e6094 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Mon, 17 Nov 2014 16:14:19 +0000 Subject: [PATCH 055/128] Refs #8961 Fixed for cppCheck --- .../Framework/DataHandling/CMakeLists.txt | 2 + .../MantidDataHandling/SaveReflThreeColumn.h | 69 ------------------- .../DataHandling/src/SaveReflThreeColumn.cpp | 61 ---------------- 3 files changed, 2 insertions(+), 130 deletions(-) delete mode 100644 Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumn.h delete mode 100644 Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumn.cpp diff --git a/Code/Mantid/Framework/DataHandling/CMakeLists.txt b/Code/Mantid/Framework/DataHandling/CMakeLists.txt index 5df27be94a93..a2c98d7bb815 100644 --- a/Code/Mantid/Framework/DataHandling/CMakeLists.txt +++ b/Code/Mantid/Framework/DataHandling/CMakeLists.txt @@ -136,6 +136,7 @@ set ( SRC_FILES src/SaveParameterFile.cpp src/SaveRKH.cpp src/SaveReflTBL.cpp + src/SaveReflThreeColumnAscii.cpp src/SaveSPE.cpp src/SaveToSNSHistogramNexus.cpp src/SaveVTK.cpp @@ -277,6 +278,7 @@ set ( INC_FILES inc/MantidDataHandling/SaveParameterFile.h inc/MantidDataHandling/SaveRKH.h inc/MantidDataHandling/SaveReflTBL.h + inc/MantidDataHandling/SaveReflThreeColumnAscii.h inc/MantidDataHandling/SaveSPE.h inc/MantidDataHandling/SaveToSNSHistogramNexus.h inc/MantidDataHandling/SaveVTK.h diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumn.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumn.h deleted file mode 100644 index 54d76c6de494..000000000000 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumn.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef MANTID_DATAHANDLING_SAVEREFLTHREECOLUMNASCII_H_ -#define MANTID_DATAHANDLING_SAVEREFLTHREECOLUMNASCII_H_ - -//---------------------------------------------------------------------- -// Includes -//---------------------------------------------------------------------- -#include "MantidAPI/Algorithm.h" -#include "MantidAPI/MatrixWorkspace.h" -#include "MantidDataHandling/AsciiPointBase.h" - -namespace Mantid -{ - namespace DataHandling - { - /** - Saves a file in ILL Cosmos format from a 2D workspace - (Workspace2D class). SaveILLCosmosAscii is an algorithm but inherits frrm the - AsciiPointBase class which provides the main implementation for the init() & exec() methods. - Output is tab delimited Ascii point data with dq/q and extra header information. - - Copyright © 2007-14 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory - - This file is part of Mantid. - - Mantid is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Mantid is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - File change history is stored at: . - Code Documentation is available at: - */ - class DLLExport SaveReflThreeColumnAscii : public DataHandling::AsciiPointBase - { - public: - /// Default constructor - SaveReflThreeColumnAscii() {} - /// Destructor - ~SaveReflThreeColumnAscii() {} - /// Algorithm's name for identification overriding a virtual method - virtual const std::string name() const { return "SaveReflThreeColumnAscii"; } - ///Summary of algorithms purpose - virtual const std::string summary() const {return "Saves a 2D workspace to a ascii file.";} - /// Algorithm's version for identification overriding a virtual method - virtual int version() const { return 1; } - ///Algorithm's version for data output overriding a virtual method - void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ); - - private: - - /// Return the file extension this algorthm should output. - virtual std::string ext() {return ".dat";} - ///extra properties specifically for this - virtual void extraProps(); - /// write any extra information required - virtual void extraHeaders(std::ofstream & file); - }; - } // namespace DataHandling -} // namespace Mantid - -#endif /* MANTID_DATAHANDLING_SAVEREFLTHREECOLUMNASCII_H_ */ \ No newline at end of file diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumn.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumn.cpp deleted file mode 100644 index 4f9ba406226a..000000000000 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumn.cpp +++ /dev/null @@ -1,61 +0,0 @@ -//---------------------------------------------------------------------- -// Includes -//---------------------------------------------------------------------- -#include "MantidDataHandling/SaveReflThreeColumnAscii.h" -#include "MantidDataHandling/AsciiPointBase.h" -#include "MantidKernel/ArrayProperty.h" -#include - -namespace Mantid -{ - namespace DataHandling - { - // Register the algorithm into the algorithm factory - DECLARE_ALGORITHM(SaveReflThreeColumnAscii) - using namespace Kernel; - using namespace API; - - /// virtual method to set the extra properties required for this algorithm - void SaveReflThreeColumnAscii::extraProps() - { - declareProperty(new ArrayProperty("LogList"),"List of logs to write to file."); - declareProperty("Title", "", "Text to be written to the Title field"); - } - - /** virtual method to add information to the file before the data - * @param file :: pointer to output file stream - */ - void SaveReflThreeColumnAscii::extraHeaders(std::ofstream & file) - { - auto samp = m_ws->run(); - //std::string subtitle; - std::string title = getProperty("Title"); - /*try - { - subtitle = samp.getLogData("run_title")->value(); - } - catch (Kernel::Exception::NotFoundError &) - { - subtitle = ""; - }*/ - if (title != "") //if is toggled - { - file << "#" << title << std::endl; - } - - const std::vector logList = getProperty("LogList"); - ///logs - for (auto log = logList.begin(); log != logList.end(); ++log) - { - file << boost::lexical_cast(*log) << ": " << boost::lexical_cast(samp.getLogData(*log)->value()) << std::endl; - } - } - - void SaveReflThreeColumnAscii::data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ) - { - AsciiPointBase::data(file, XData, false); //toggled false permantly because only to show 3 columns - } - - - } // namespace DataHandling -} // namespace Mantid \ No newline at end of file From d4e9e1657d0f958b044b880aaeb8c0f77c1bf8e3 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Mon, 17 Nov 2014 16:15:37 +0000 Subject: [PATCH 056/128] Refs #8961 Fixed for cppCheck1 --- .../Framework/DataHandling/src/SaveReflCustomAscii.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp index 624b80110c77..d0d873d6a42c 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflCustomAscii.cpp @@ -29,16 +29,16 @@ namespace Mantid void SaveReflCustomAscii::extraHeaders(std::ofstream & file) { auto samp = m_ws->run(); - std::string subtitle; + //std::string subtitle; std::string title = getProperty("Title"); - try + /*try { subtitle = samp.getLogData("run_title")->value(); } catch (Kernel::Exception::NotFoundError &) { subtitle = ""; - } + }*/ if (title != "") //if is toggled { From 5b04b60ebf8dd4a6d338a2277dc23079bdf28482 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Mon, 17 Nov 2014 11:36:24 +0000 Subject: [PATCH 057/128] Refs #10563 Add interfaces category to offline documentation --- Code/Mantid/docs/source/index.rst | 2 ++ Code/Mantid/docs/source/interfaces/index.rst | 20 +++++++++++++++++++ .../mantiddoc/directives/categories.py | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Code/Mantid/docs/source/interfaces/index.rst diff --git a/Code/Mantid/docs/source/index.rst b/Code/Mantid/docs/source/index.rst index 1c4433a05226..65ef864bf2be 100644 --- a/Code/Mantid/docs/source/index.rst +++ b/Code/Mantid/docs/source/index.rst @@ -18,6 +18,7 @@ algorithms/* concepts/index + interfaces/index fitfunctions/* api/index @@ -27,6 +28,7 @@ This is the documentation for Mantid |release|. * `Algorithms `_ * `Concepts `_ +* `Interfaces `_ * `Fit Functions `_ * `API `_ - `Python `_ diff --git a/Code/Mantid/docs/source/interfaces/index.rst b/Code/Mantid/docs/source/interfaces/index.rst new file mode 100644 index 000000000000..8996c5b5eefa --- /dev/null +++ b/Code/Mantid/docs/source/interfaces/index.rst @@ -0,0 +1,20 @@ +.. Interfaces master file + It contains a hidden root toctree directive so that Sphinx + has an internal index of all of the pages and doesn't + produce a plethora of warnings about most documents not being in + a toctree. + See http://sphinx-doc.org/tutorial.html#defining-document-structure + +.. _interfaces contents: + +============ + Interfaces +============ + +.. toctree:: + :hidden: + :glob: + :maxdepth: 1 + + * + diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py index dfb7b9f204a4..178c05b63372 100644 --- a/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/categories.py @@ -17,7 +17,7 @@ # List of category names that are considered the index for everything in that type # When this category is encountered an additional index.html is written to both the # directory of the document and the category directory -INDEX_CATEGORIES = ["Algorithms", "FitFunctions","Concepts"] +INDEX_CATEGORIES = ["Algorithms", "FitFunctions", "Concepts", "Interfaces"] class LinkItem(object): """ From 8a137c9b62464531e1877108942f5df914dd7d82 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Mon, 17 Nov 2014 14:51:33 +0000 Subject: [PATCH 058/128] Refs #10563 Add initial ISIS Reflectometry interface documentation --- .../source/interfaces/ISIS_Reflectometry.rst | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst diff --git a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst new file mode 100644 index 000000000000..0c47464cc1a7 --- /dev/null +++ b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst @@ -0,0 +1,213 @@ +.. _ISIS Reflectometry: + +ISIS Reflectometry Interface +============================ + +Menu bar +-------- + +At the top of the interface is a menu bar. Through this menu bar you can +start a new table, open an existing table from a :ref:`workspace `, +or save your current table to a :ref:`workspace `. + +You are also able to import or export .TBL files from disk using the +*Import .TBL* and *Export .TBL* options. These options will run the +:ref:`LoadReflTBL ` and :ref:`SaveReflTBL ` +algorithms as appropriate. + +The menu bar also provides access to the options menu, and many actions +pertaining to the processing table. + +Search Interface +---------------- + +To search for runs, select the instrument the runs are from, enter the id of +the investigation the runs are part of, and hit *Search*. + +In the table below, valid runs and their descriptions will be listed. You +can then transfer runs to the processing table by selecting the runs you +wish to transfer, and hit the *Transfer* button. You can also right-click +on one of the selected runs and select *Transfer* in the context menu that +appears. + +If a run's description contains the text ``in 0.7 theta``, or ``th=0.7``, or +``th:0.7``, then the interface will deduce that the run's angle (also known +as theta), was ``0.7``, and enter this value into the angle column for you. +This holds true for any numeric value. + +When multiple runs are selected and transferred simultaneously, the interface +will attempt to organise them appropriately in the processing table. The exact +behaviour of this is as follows: + +- Any runs with the same description, excluding their theta value, will be + placed into the same group. +- Any runs with the same description, including their theta value, will be + merged into a single row, with all the runs listed in the *Run(s)* column + in the format, ``123+124+125``. + +Processing Table +---------------- + +The processing table is where the bulk of the work takes place. It is used to +specify which runs to process, the parameters that should be used to process +them, and how the different runs should be joined together. + +Above the processing table is a tool bar providing a number of useful actions. +Below the table is a progress bar, showing the current progress of any +processing that is taking place, and a processing instrument selector. +The processing instrument is used by the interface to help load the correct +files from disk when processing. + +Actions +~~~~~~~ + +.. WARNING If you're updating this documentation, you probably also want to update the "What's This" tips in ReflMainWidget.ui + ++------------------+----------------------------------------------------------+ +| Action | Effect | ++==================+==========================================================+ +| Process | Processes the selected runs, or, if no runs are selected,| +| | all of the runs in the table. | ++------------------+----------------------------------------------------------+ +| Expand Selection | Expands your selection such that any rows in the same | +| | group as a row you have selected are added to your | +| | selection. | ++------------------+----------------------------------------------------------+ +| Insert Row | Adds a new row after the first selected row, or at the | +| | end of the table if no rows are selected. | ++------------------+----------------------------------------------------------+ +| Delete Row | Deletes any selected rows. If no rows are selected, | +| | nothing happens. | ++------------------+----------------------------------------------------------+ +| Group Rows | Takes all the selected rows and places them in a group | +| | together, separate from any other group. | ++------------------+----------------------------------------------------------+ +| Copy Rows | Copies the selected rows to the clipboard. In the | +| | clipboard, each column's value is separated by a tab, and| +| | each row is placed on a new line. | ++------------------+----------------------------------------------------------+ +| Cut Rows | Copies the selected rows, and then deletes them. | ++------------------+----------------------------------------------------------+ +| Paste Rows | Pastes the contents of the clipboard into the selected | +| | rows. If no rows are selected, new rows are inserted. | ++------------------+----------------------------------------------------------+ +| Clear Rows | Resets the cells in any selected rows to their initial | +| | value, in other words, blank. | ++------------------+----------------------------------------------------------+ +| Whats This | Provides guidance on what various parts of the interface | +| | are for. | ++------------------+----------------------------------------------------------+ +| Help | Opens this documentation for viewing. | ++------------------+----------------------------------------------------------+ + +Columns +~~~~~~~ + +.. WARNING If you're updating this documentation, you probably also want to update the "What's This" tips for the columns in QReflTableModel.cpp + ++---------------------+-----------+-----------------------------------------------+ +| Column Title | Required? | Description | ++=====================+===========+===============================================+ +| Run(s) | Yes | Contains the sample runs to be processed. | +| | | Runs may be given as run numbers or workspace | +| | | names. Multiple runs may be added together by | +| | | separating them with a '+'. | +| | | | +| | | Example: ``1234+1235+1236`` | ++---------------------+-----------+-----------------------------------------------+ +| Angle | No | Contains the angle used during the run, in | +| | | degrees. If left blank, this is set to the | +| | | last value for 'THETA' in the run's sample | +| | | log. If multiple runs were given in the Run(s)| +| | | column, the first listed run's sample log will| +| | | be used. | +| | | | +| | | Example: ``0.7`` | ++---------------------+-----------+-----------------------------------------------+ +| Transmission Run(s) | No | Contains the transmission run(s) used to | +| | | normalise the sample runs. To specify two | +| | | transmission runs, separate them with a comma.| +| | | If left blank, the sample runs will be | +| | | normalised by monitor only. | +| | | | +| | | Example: ``1234,1235`` | ++---------------------+-----------+-----------------------------------------------+ +| Q min | No | Contains the minimum value of Q to be used in | +| | | Ã…\ :sup:`−1`\ . Data with a value of Q lower | +| | | than this will be discarded. If left blank, | +| | | this is set to the lowest Q value found. This | +| | | is useful for discarding noisy data. | +| | | | +| | | Example: ``0.1`` | ++---------------------+-----------+-----------------------------------------------+ +| Q max | No | Contains the maximum value of Q to be used in | +| | | Ã…\ :sup:`−1`\ . Data with a value of Q higher | +| | | than this will be discarded. If left blank, | +| | | this is set to the highest Q value found. This| +| | | is useful for discarding noisy data. | +| | | | +| | | Example: ``0.9`` | ++---------------------+-----------+-----------------------------------------------+ +| dQ/Q | No | Contains the resolution used when rebinning | +| | | output workspaces. If left blank, this is | +| | | calculated for you using the | +| | | CalculateResolution algorithm. | +| | | | +| | | Example: ``0.9`` | ++---------------------+-----------+-----------------------------------------------+ +| Scale | Yes | Contains the factor used to scale output | +| | | IvsQ workspaces. The IvsQ workspaces are | +| | | scaled by ``1/i`` where i is the value of | +| | | this column. | +| | | | +| | | Example: ``1.0`` | ++---------------------+-----------+-----------------------------------------------+ +| Group | Yes | Contains the group number used for stitching | +| | | output workspaces. The value of this column | +| | | determines which other rows this row's output | +| | | will be stitched with. All rows with the same | +| | | group number are stitched together. | ++---------------------+-----------+-----------------------------------------------+ +| Options | No | Contains options that allow you to override | +| | | ReflectometryReductionOneAuto's properties. | +| | | Options are given as ``key=value`` pairs, | +| | | separated by commas. Values containing commas | +| | | must be quoted. | +| | | | +| | | Example: ``StrictSpectrumChecking=0,`` | +| | | ``RegionOfDirectBeam="0,2", Params="1,2,3"`` | ++---------------------+-----------+-----------------------------------------------+ + +Options +------- + +Through the options menu, a small number of options may be configured to adjust +the behaviour of the interface. + + ++-------------------------------+------------------------------------------------------+ +| Name | Description | ++===============================+======================================================+ +| Warn when processing all rows | When the *Process* button is pressed with no rows | +| | selected, all rows will be processed. | +| | If this is enabled, you will be asked if you're sure | +| | you want to process all rows first. | ++-------------------------------+------------------------------------------------------+ +| Warn when processing only | If this is enabled and you press *Process* with only | +| part of a group | a subset of a group's rows selected, you will be | +| | asked if you're sure you that's what you intended to | +| | do. | ++-------------------------------+------------------------------------------------------+ +| Warn when discarding unsaved | If this is neabled and you try to open an existing | +| changes | table, or start a new table, with unsaved changes to | +| | the current table, you will be asked if you're sure | +| | you want to discard the current table. | ++-------------------------------+------------------------------------------------------+ +| Rounding | When a column is left blank, the Reflectometry | +| | interface will try to fill it with a sensible value | +| | for you. This option allows you to configure whether | +| | the value should be rounded, and if so, to how many | +| | decimal places. | ++-------------------------------+------------------------------------------------------+ + +.. categories:: Interfaces Reflectometry From d4319281e99d8cf593fcec120a5de3ee035f3886 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Mon, 17 Nov 2014 15:17:17 +0000 Subject: [PATCH 059/128] Refs #10563 Add "help" action to Reflectometry UI --- .../MantidQtCustomInterfaces/QtReflMainView.h | 1 + .../ReflMainWidget.ui | 19 +++++++++++++++++++ .../CustomInterfaces/src/QtReflMainView.cpp | 9 +++++++++ 3 files changed, 29 insertions(+) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h index c77727b0878c..e13b25b0b271 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h @@ -117,6 +117,7 @@ namespace MantidQt void on_actionTransfer_triggered(); void on_actionImportTable_triggered(); void on_actionExportTable_triggered(); + void on_actionHelp_triggered(); void setModel(QString name); void tableUpdated(const QModelIndex& topLeft, const QModelIndex& bottomRight); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui index 6a9ca25866ee..e712337f6a78 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui @@ -249,6 +249,7 @@ + @@ -648,6 +649,24 @@ Exports a table workspace to a .TBL file that can be used by the ISIS Reflectometry UI in older versions of Mantid. + + + + :/help.png:/help.png + + + Help + + + Opens the documentation. + + + Opens the interface's documentation in the Qt Help Browser. + + + F1 + + comboSearchInstrument diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp index ffb8bd3b27bc..4e3bb4ec5cb0 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp @@ -3,6 +3,7 @@ #include "MantidQtCustomInterfaces/ReflMainViewPresenter.h" #include "MantidQtMantidWidgets/HintingLineEditFactory.h" #include "MantidAPI/ITableWorkspace.h" +#include "MantidQtAPI/HelpWindow.h" #include "MantidKernel/ConfigService.h" #include #include @@ -257,6 +258,14 @@ namespace MantidQt m_presenter->notify(IReflPresenter::ImportTableFlag); } + /** + This slot opens the documentation when the "help" button has been pressed + */ + void QtReflMainView::on_actionHelp_triggered() + { + MantidQt::API::HelpWindow::showPage(this, QString("qthelp://org.mantidproject/doc/interfaces/ISIS_Reflectometry.html")); + } + /** This slot notifies the presenter that the table has been updated/changed by the user */ From 2f74e975cb11fc9fa2184b7365d0cfe2a5509fb5 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 17 Nov 2014 16:37:26 +0000 Subject: [PATCH 060/128] Add ELF workspace and correct vertical units Refs #10409 --- .../ElasticWindowMultiple.py | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py index 1bc5dfd49382..dfca8ccb7a82 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py @@ -29,6 +29,9 @@ def PyInit(self): self.declareProperty(WorkspaceProperty('OutputInQSquared', '', Direction.Output), doc='Output workspace in Q Squared') + self.declareProperty(WorkspaceProperty('OutputELF', '', Direction.Output, PropertyMode.Optional), + doc='Output workspace') + self.declareProperty(name='Plot', defaultValue=False, doc='Plot result spectra') @@ -64,6 +67,7 @@ def validateInputs(self): def PyExec(self): + from IndirectCommon import getInstrRun from IndirectImport import import_mantidplot # Do setup @@ -73,6 +77,7 @@ def PyExec(self): input_workspace_names = self._input_workspaces.getNames() q_workspaces = list() q2_workspaces = list() + run_numbers = list() # Perform the ElasticWindow algorithms for input_ws in input_workspace_names: @@ -90,6 +95,10 @@ def PyExec(self): q_workspaces.append(q_ws) q2_workspaces.append(q2_ws) + # Get the run number + run_no = getInstrRun(input_ws)[1] + run_numbers.append(run_no) + # Must have two of each type of workspace to continue if len(q_workspaces) < 2: raise RuntimeError('Have less than 2 result workspaces in Q') @@ -101,7 +110,7 @@ def PyExec(self): AppendSpectra(InputWorkspace1=q2_workspaces[0], InputWorkspace2=q2_workspaces[1], OutputWorkspace=self._q2_workspace) # Append to the spectra of each remaining workspace - for idx in xrange(2, len(input_workspace_names)): + for idx in range(2, len(input_workspace_names)): AppendSpectra(InputWorkspace1=self._q_workspace, InputWorkspace2=q_workspaces[idx], OutputWorkspace=self._q_workspace) AppendSpectra(InputWorkspace1=self._q2_workspace, InputWorkspace2=q2_workspaces[idx], OutputWorkspace=self._q2_workspace) @@ -111,6 +120,25 @@ def PyExec(self): for q2_ws in q2_workspaces: DeleteWorkspace(q2_ws) + # Set the verical axis axis + unit = ('Run No', 'last 3 digits') + + q_ws_axis = mtd[self._q_workspace].getAxis(1) + q_ws_axis.setUnit("Label").setLabel(unit[0], unit[1]) + + q2_ws_axis = mtd[self._q2_workspace].getAxis(1) + q2_ws_axis.setUnit("Label").setLabel(unit[0], unit[1]) + + for idx in range(0, len(run_numbers)): + q_ws_axis.setValue(idx, float(run_numbers[idx][-3:])) + q2_ws_axis.setValue(idx, float(run_numbers[idx][-3:])) + + # Process the ELF workspace + if self._elf_workspace != '': + Transpose(InputWorkspace=self._q_workspace, OutputWorkspace=self._elf_workspace) + SortXAxis(InputWorkspace=self._elf_workspace, OutputWorkspace=self._elf_workspace) + self.setProperty('OutputELF', self._elf_workspace) + # Set the output workspace self.setProperty('OutputInQ', self._q_workspace) self.setProperty('OutputInQSquared', self._q2_workspace) @@ -118,9 +146,13 @@ def PyExec(self): # Plot spectra plots if self._plot: self._mtd_plot = import_mantidplot() + self._plot_spectra(self._q_workspace) self._plot_spectra(self._q2_workspace) + if self._elf_workspace != '': + self._plot_spectra(self._elf_workspace) + def _setup(self): """ @@ -132,6 +164,7 @@ def _setup(self): self._input_workspaces = self.getProperty('InputWorkspaces').value self._q_workspace = self.getPropertyValue('OutputInQ') self._q2_workspace = self.getPropertyValue('OutputInQSquared') + self._elf_workspace = self.getPropertyValue('OutputELF') self._range_1_start = self.getProperty('Range1Start').value self._range_1_end = self.getProperty('Range1End').value From 751931e42ad7b7c40b0abbc12b77033c7d6cf5eb Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Mon, 17 Nov 2014 16:51:19 +0000 Subject: [PATCH 061/128] Refs #10563 Add python bindings for createSubWindow We need this to generate documentation screenshots of c++ custom interfaces --- Code/Mantid/MantidQt/Python/mantidqt.sip | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Code/Mantid/MantidQt/Python/mantidqt.sip b/Code/Mantid/MantidQt/Python/mantidqt.sip index 653474fd0f1e..cb4fe1b5674b 100644 --- a/Code/Mantid/MantidQt/Python/mantidqt.sip +++ b/Code/Mantid/MantidQt/Python/mantidqt.sip @@ -95,6 +95,15 @@ private: AlgorithmDialog(); }; +class UserSubWindow : QMainWindow +{ +%TypeHeaderCode +#include "MantidQtAPI/UserSubWindow.h" +%End +private: + UserSubWindow(); +}; + class InterfaceManager { %TypeHeaderCode @@ -103,6 +112,7 @@ class InterfaceManager public: MantidQt::API::AlgorithmDialog* createDialogFromName(const QString&, const int = -1, QWidget* = 0, bool = false); + MantidQt::API::UserSubWindow* createSubWindow(const QString& interface_name, QWidget* parent = 0); }; From f103d7a6325903902e3f8c9383bd416c7224fc08 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Mon, 17 Nov 2014 17:03:48 +0000 Subject: [PATCH 062/128] Support temperatures from log files Refs #10409 --- .../ElasticWindowMultiple.py | 94 +++++++++++++++++-- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py index dfca8ccb7a82..32f09bbb247c 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py @@ -2,6 +2,55 @@ from mantid.kernel import * from mantid.api import * +from IndirectCommon import getInstrRun + + +def _get_temperature(ws_name, log_name): + """ + Gets the sample temperature for a given workspace. + + @param ws_name Name of workspace + @param log_name Name of the sample environment log entry + @returns Temperature in Kelvin or None if not found + """ + + instr, run_number = getInstrRun(ws_name) + + facility = config.getFacility() + pad_num = facility.instrument(instr).zeroPadding(int(run_number)) + zero_padding = '0' * (pad_num - len(run_number)) + + run_name = instr + zero_padding + run_number + log_name = run_name.upper() + '.log' + + run = mtd[ws_name].getRun() + + if log_name in run: + # Look for temperature in logs in workspace + tmp = run[log_name].value + temp = tmp[len(tmp) - 1] + logger.debug('Temperature %d K found for run :%s' % (temp, run_name)) + return temp + + else: + # Logs not in workspace, try loading from file + logger.information('Log parameter not found in workspace. Searching for log file.') + log_path = FileFinder.getFullPath(log_name) + + if log_path != '': + # Get temperature from log file + LoadLog(Workspace=ws_name, Filename=log_path) + run_logs = mtd[ws_name].getRun() + tmp = run_logs[log_name].value + temp = tmp[len(tmp) - 1] + logger.debug('Temperature %d K found for run :%s' % (temp, run_name)) + return temp + + else: + # Can't find log file + logger.warning('No temperature fround for run :%s' % run_name) + return None + class ElasticWindowMultiple(DataProcessorAlgorithm): @@ -23,6 +72,8 @@ def PyInit(self): self.declareProperty(name='Range2Start', defaultValue='', doc='Range 2 start') self.declareProperty(name='Range2End', defaultValue='', doc='Range 2 end') + self.declareProperty(name='SampleEnvironmentLogName', defaultValue='sample', doc='Name of the sample environment log entry') + self.declareProperty(WorkspaceProperty('OutputInQ', '', Direction.Output), doc='Output workspace in Q') @@ -30,7 +81,10 @@ def PyInit(self): doc='Output workspace in Q Squared') self.declareProperty(WorkspaceProperty('OutputELF', '', Direction.Output, PropertyMode.Optional), - doc='Output workspace') + doc='Output workspace ELF') + + self.declareProperty(WorkspaceProperty('OutputELT', '', Direction.Output, PropertyMode.Optional), + doc='Output workspace ELT') self.declareProperty(name='Plot', defaultValue=False, doc='Plot result spectra') @@ -67,7 +121,6 @@ def validateInputs(self): def PyExec(self): - from IndirectCommon import getInstrRun from IndirectImport import import_mantidplot # Do setup @@ -78,9 +131,12 @@ def PyExec(self): q_workspaces = list() q2_workspaces = list() run_numbers = list() + temperatures = list() # Perform the ElasticWindow algorithms for input_ws in input_workspace_names: + logger.information('Running ElasticWindow for workspace: %s' % input_ws) + q_ws = input_ws + '_q' q2_ws = input_ws + '_q2' @@ -99,12 +155,19 @@ def PyExec(self): run_no = getInstrRun(input_ws)[1] run_numbers.append(run_no) + # Get the sample temperature + temp = _get_temperature(input_ws, self._sample_log_name) + if temp is not None: + temperatures.append(temp) + # Must have two of each type of workspace to continue if len(q_workspaces) < 2: raise RuntimeError('Have less than 2 result workspaces in Q') if len(q2_workspaces) < 2: raise RuntimeError('Hvae less than 2 result workspaces in Q^2') + logger.information('Creating Q and Q^2 workspaces') + # Append the spectra of the first two workspaces AppendSpectra(InputWorkspace1=q_workspaces[0], InputWorkspace2=q_workspaces[1], OutputWorkspace=self._q_workspace) AppendSpectra(InputWorkspace1=q2_workspaces[0], InputWorkspace2=q2_workspaces[1], OutputWorkspace=self._q2_workspace) @@ -120,8 +183,17 @@ def PyExec(self): for q2_ws in q2_workspaces: DeleteWorkspace(q2_ws) - # Set the verical axis axis - unit = ('Run No', 'last 3 digits') + logger.information('Setting vertical axis units and values') + + # Set the verical axis units + v_axis_is_temp = len(input_workspace_names) == len(temperatures) + + if v_axis_is_temp: + logger.notice('Vertical axis is in temperature') + unit = ('Temperature', 'K') + else: + logger.notice('Vertical axis is in run number') + unit = ('Run No', 'last 3 digits') q_ws_axis = mtd[self._q_workspace].getAxis(1) q_ws_axis.setUnit("Label").setLabel(unit[0], unit[1]) @@ -129,12 +201,18 @@ def PyExec(self): q2_ws_axis = mtd[self._q2_workspace].getAxis(1) q2_ws_axis.setUnit("Label").setLabel(unit[0], unit[1]) - for idx in range(0, len(run_numbers)): - q_ws_axis.setValue(idx, float(run_numbers[idx][-3:])) - q2_ws_axis.setValue(idx, float(run_numbers[idx][-3:])) + # Set the vertical axis values + for idx in range(0, len(input_workspace_names)): + if v_axis_is_temp: + q_ws_axis.setValue(idx, float(temperatures[idx])) + q2_ws_axis.setValue(idx, float(temperatures[idx])) + else: + q_ws_axis.setValue(idx, float(run_numbers[idx][-3:])) + q2_ws_axis.setValue(idx, float(run_numbers[idx][-3:])) # Process the ELF workspace if self._elf_workspace != '': + logger.information('Creating ELF workspace') Transpose(InputWorkspace=self._q_workspace, OutputWorkspace=self._elf_workspace) SortXAxis(InputWorkspace=self._elf_workspace, OutputWorkspace=self._elf_workspace) self.setProperty('OutputELF', self._elf_workspace) @@ -160,11 +238,13 @@ def _setup(self): """ self._plot = self.getProperty('Plot').value + self._sample_log_name = self.getPropertyValue('SampleEnvironmentLogName') self._input_workspaces = self.getProperty('InputWorkspaces').value self._q_workspace = self.getPropertyValue('OutputInQ') self._q2_workspace = self.getPropertyValue('OutputInQSquared') self._elf_workspace = self.getPropertyValue('OutputELF') + self._elt_workspace = self.getPropertyValue('OutputELT') self._range_1_start = self.getProperty('Range1Start').value self._range_1_end = self.getProperty('Range1End').value From b1cc3b07a0711883d5fe39a41bc262d8bafad6d8 Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Mon, 17 Nov 2014 16:49:42 -0500 Subject: [PATCH 063/128] Refs #10566. Adding linux version of getOSVersionReadable. --- .../Kernel/inc/MantidKernel/ConfigService.h | 2 + .../Framework/Kernel/src/ConfigService.cpp | 75 +++++++++++++++++++ .../Framework/Kernel/test/ConfigServiceTest.h | 2 + 3 files changed, 79 insertions(+) diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h index 498154a9719c..3e184f71fd21 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h @@ -152,6 +152,8 @@ namespace Mantid std::string getOSArchitecture(); /// Returns the OS version std::string getOSVersion(); + /// Returns a human readable version of the OS version + std::string getOSVersionReadable(); /// Returns the username std::string getUsername(); /// Returns the current directory diff --git a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp index f81d562cb7a1..ed79563c5d87 100644 --- a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #ifdef _WIN32 @@ -1241,6 +1242,80 @@ std::string ConfigServiceImpl::getOSVersion() return m_pSysConfig->getString("system.osVersion"); } +/// @returns true if the file exists and can be read +bool canRead(const std::string &filename) { + // check for existence of the file + Poco::File pocoFile(filename); + if (!pocoFile.exists()) { + return false; + } + + // just return if it is readable + return pocoFile.canRead(); +} + +/** + * Gets the name of the operating system version in a human readable form. + * + * @returns The operating system desciption + */ +std::string ConfigServiceImpl::getOSVersionReadable() { + std::string description; + +#ifdef __linux__ + // read os-release + static const std::string OS_RELEASE("/etc/os-release"); + if (canRead(OS_RELEASE)) { + static const std::string PRETTY_NAME("PRETTY_NAME="); + + // open it to see if it has the magic line + std::ifstream handle(OS_RELEASE.c_str(), std::ios::in); + + // go through the file + std::string line; + while (std::getline(handle, line)) { + if (line.find(PRETTY_NAME) != std::string::npos) { + if (line.length() > PRETTY_NAME.length() + 1) { + size_t length = line.length() - PRETTY_NAME.length() - 2; + description = line.substr(PRETTY_NAME.length() + 1, length); + } + break; + } + } + + // cleanup + handle.close(); + if (!description.empty()) { + return description; + } + } + + // read redhat-release + static const std::string REDHAT_RELEASE("/etc/redhat-release"); + if (canRead(REDHAT_RELEASE)) { + // open it to see if it has the magic line + std::ifstream handle(REDHAT_RELEASE.c_str(), std::ios::in); + + // go through the file + std::string line; + while (std::getline(handle, line)) { + if (!line.empty()) { + description = line; + break; + } + } + + // cleanup + handle.close(); + if (!description.empty()) { + return description; + } + } +#endif + + return description; +} + /// @returns The name of the current user as reported by the environment. std::string ConfigServiceImpl::getUsername() { std::string username; diff --git a/Code/Mantid/Framework/Kernel/test/ConfigServiceTest.h b/Code/Mantid/Framework/Kernel/test/ConfigServiceTest.h index c52d513e0fe1..5f57df4a5f39 100644 --- a/Code/Mantid/Framework/Kernel/test/ConfigServiceTest.h +++ b/Code/Mantid/Framework/Kernel/test/ConfigServiceTest.h @@ -186,6 +186,8 @@ class ConfigServiceTest : public CxxTest::TestSuite std::string username = ConfigService::Instance().getUsername(); TS_ASSERT_LESS_THAN(0, username.length()); TS_ASSERT_LESS_THAN(0, ConfigService::Instance().getOSVersion().length()); //check that the string is not empty + TS_ASSERT_LESS_THAN( + 0, ConfigService::Instance().getOSVersionReadable().length()); TS_ASSERT_LESS_THAN(0, ConfigService::Instance().getCurrentDir().length()); //check that the string is not empty // TS_ASSERT_LESS_THAN(0, ConfigService::Instance().getHomeDir().length()); //check that the string is not empty TS_ASSERT_LESS_THAN(0, ConfigService::Instance().getTempDir().length()); //check that the string is not empty From 1aa1b3c5e68b3b8a7d01d80328dc88abd5137c3f Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 10:07:34 +0000 Subject: [PATCH 064/128] Add commenting to changes Refs #10340 --- Code/Mantid/Framework/API/src/Algorithm.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Mantid/Framework/API/src/Algorithm.cpp b/Code/Mantid/Framework/API/src/Algorithm.cpp index 7e12dfaf7c3c..591e7aee085a 100644 --- a/Code/Mantid/Framework/API/src/Algorithm.cpp +++ b/Code/Mantid/Framework/API/src/Algorithm.cpp @@ -1063,6 +1063,7 @@ namespace Mantid { (*outWS)->history().addHistory( (*inWS)->getHistory() ); + // Add history to each child of output workspace group if(wsGroup) { for(size_t i = 0; i < wsGroup->size(); i++) @@ -1075,6 +1076,7 @@ namespace Mantid // Add the history for the current algorithm to all the output workspaces (*outWS)->history().addHistory(m_history); + // Add history to each child of output workspace group if(wsGroup) { for(size_t i = 0; i < wsGroup->size(); i++) From fbe175b957bdb96f66c5748effb56e63be238b32 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Tue, 18 Nov 2014 10:17:21 +0000 Subject: [PATCH 065/128] Refs #8961 Fixed for cppcheckBuild --- .../Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp index ad0eea402041..da032bbd7cdd 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp @@ -28,9 +28,9 @@ namespace Mantid void SaveReflThreeColumnAscii::extraHeaders(std::ofstream & file) { auto samp = m_ws->run(); - std::string subtitle; + //std::string subtitle; std::string title = getProperty("Title"); - try + /*try { subtitle = samp.getLogData("run_title")->value(); } @@ -41,7 +41,7 @@ namespace Mantid if (title != "") //if is toggled { file << "#" << title << std::endl; - } + }*/ const std::vector logList = getProperty("LogList"); ///logs From 75e00f78b38d04b932a7f3f26e047dc4c73e5b2e Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 10:47:46 +0000 Subject: [PATCH 066/128] Correct get temperature function Refs #10409 --- .../ElasticWindowMultiple.py | 121 ++++++++++++------ 1 file changed, 80 insertions(+), 41 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py index 32f09bbb247c..7022fa988968 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py @@ -5,51 +5,21 @@ from IndirectCommon import getInstrRun -def _get_temperature(ws_name, log_name): +def _normalize_to_lowest_temp(elt_ws_name): """ - Gets the sample temperature for a given workspace. + Normalise a workspace to the lowest temperature run. - @param ws_name Name of workspace - @param log_name Name of the sample environment log entry - @returns Temperature in Kelvin or None if not found + @param elt_ws_name Name of the ELT workspace """ - instr, run_number = getInstrRun(ws_name) + num_hist = mtd[elt_ws_name].getNumberHistograms() - facility = config.getFacility() - pad_num = facility.instrument(instr).zeroPadding(int(run_number)) - zero_padding = '0' * (pad_num - len(run_number)) - - run_name = instr + zero_padding + run_number - log_name = run_name.upper() + '.log' - - run = mtd[ws_name].getRun() - - if log_name in run: - # Look for temperature in logs in workspace - tmp = run[log_name].value - temp = tmp[len(tmp) - 1] - logger.debug('Temperature %d K found for run :%s' % (temp, run_name)) - return temp - - else: - # Logs not in workspace, try loading from file - logger.information('Log parameter not found in workspace. Searching for log file.') - log_path = FileFinder.getFullPath(log_name) - - if log_path != '': - # Get temperature from log file - LoadLog(Workspace=ws_name, Filename=log_path) - run_logs = mtd[ws_name].getRun() - tmp = run_logs[log_name].value - temp = tmp[len(tmp) - 1] - logger.debug('Temperature %d K found for run :%s' % (temp, run_name)) - return temp - - else: - # Can't find log file - logger.warning('No temperature fround for run :%s' % run_name) - return None + # Normalize each spectrum in the workspace + for idx in range(0, num_hist): + y_vals = mtd[elt_ws_name].readY(idx) + scale = 1.0 / y_vals[0] + y_vals_scaled = scale * y_vals + mtd[elt_ws_name].setY(idx, y_vals_scaled) class ElasticWindowMultiple(DataProcessorAlgorithm): @@ -148,6 +118,8 @@ def PyExec(self): ElasticWindow(InputWorkspace=input_ws, OutputInQ=q_ws, OutputInQSquared=q2_ws, Range1Start=self._range_1_start, Range1End=self._range_1_end) + Logarithm(InputWorkspace=q2_ws, OutputWorkspace=q2_ws) + q_workspaces.append(q_ws) q2_workspaces.append(q2_ws) @@ -156,7 +128,7 @@ def PyExec(self): run_numbers.append(run_no) # Get the sample temperature - temp = _get_temperature(input_ws, self._sample_log_name) + temp = self._get_temperature(input_ws) if temp is not None: temperatures.append(temp) @@ -213,10 +185,27 @@ def PyExec(self): # Process the ELF workspace if self._elf_workspace != '': logger.information('Creating ELF workspace') + Transpose(InputWorkspace=self._q_workspace, OutputWorkspace=self._elf_workspace) SortXAxis(InputWorkspace=self._elf_workspace, OutputWorkspace=self._elf_workspace) + self.setProperty('OutputELF', self._elf_workspace) + # Do temperature normalisation + if self._elt_workspace != '': + logger.information('Creating ELT workspace') + + # If the ELT workspace wqas not already created then crate it here, otherwise just clone it + if self._elf_workspace == '': + Transpose(InputWorkspace=self._q_workspace, OutputWorkspace=self._elt_workspace) + SortXAxis(InputWorkspace=self._elt_workspace, OutputWorkspace=self._elt_workspace) + else: + CloneWorkspace(InputWorkspace=self._elf_workspace, OutputWorkspace=self._elt_workspace) + + _normalize_to_lowest_temp(self._elt_workspace) + + self.setProperty('OutputELT', self._elt_workspace) + # Set the output workspace self.setProperty('OutputInQ', self._q_workspace) self.setProperty('OutputInQSquared', self._q2_workspace) @@ -231,6 +220,9 @@ def PyExec(self): if self._elf_workspace != '': self._plot_spectra(self._elf_workspace) + if self._elt_workspace != '': + self._plot_spectra(self._elt_workspace) + def _setup(self): """ @@ -274,5 +266,52 @@ def _plot_spectra(self, ws_name): self._mtd_plot.plotSpectrum(ws_name, plot_list) + def _get_temperature(self, ws_name): + """ + Gets the sample temperature for a given workspace. + + @param ws_name Name of workspace + @returns Temperature in Kelvin or None if not found + """ + + instr, run_number = getInstrRun(ws_name) + + facility = config.getFacility() + pad_num = facility.instrument(instr).zeroPadding(int(run_number)) + zero_padding = '0' * (pad_num - len(run_number)) + + run_name = instr + zero_padding + run_number + log_filename = run_name.upper() + '.log' + + run = mtd[ws_name].getRun() + + if self._sample_log_name in run: + # Look for temperature in logs in workspace + tmp = run[self._sample_log_name].value + temp = tmp[len(tmp) - 1] + logger.debug('Temperature %d K found for run: %s' % (temp, run_name)) + return temp + + else: + # Logs not in workspace, try loading from file + logger.information('Log parameter not found in workspace. Searching for log file.') + log_path = FileFinder.getFullPath(log_filename) + + if log_path != '': + # Get temperature from log file + LoadLog(Workspace=ws_name, Filename=log_path) + run_logs = mtd[ws_name].getRun() + tmp = run_logs[self._sample_log_name].value + temp = tmp[len(tmp) - 1] + logger.debug('Temperature %d K found for run: %s' % (temp, run_name)) + return temp + + else: + # Can't find log file + logger.warning('Log file for run %s not found' % run_name) + logger.warning('No temperature found for run: %s' % run_name) + return None + + # Register algorithm with Mantid AlgorithmFactory.subscribe(ElasticWindowMultiple) From 5b34f4cb10698ca7c105ecb8cf4ac306714bc440 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 11:37:26 +0000 Subject: [PATCH 067/128] Work in progress adding new algo to existing UI Refs #10409 --- .../inc/MantidQtCustomInterfaces/Elwin.h | 1 + .../MantidQt/CustomInterfaces/src/Elwin.cpp | 114 +++++++++++++++--- 2 files changed, 95 insertions(+), 20 deletions(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Elwin.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Elwin.h index f7478f49aaf1..88512f2e27fb 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Elwin.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Elwin.h @@ -34,6 +34,7 @@ namespace IDA void updateRS(QtProperty * prop, double val); private: + void addSaveAlgorithm(QString workspaceName, QString filename=""); QtTreePropertyBrowser* m_elwTree; }; diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp index 8d7ce675d019..c262a1bf31e5 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp @@ -7,6 +7,9 @@ #include +using namespace Mantid::API; +using namespace MantidQt::API; + namespace MantidQt { namespace CustomInterfaces @@ -89,38 +92,109 @@ namespace IDA void Elwin::run() { - QString pyInput = - "from IndirectDataAnalysis import elwin\n" - "input = [r'" + uiForm().elwin_inputFile->getFilenames().join("', r'") + "']\n" - "eRange = [ " + QString::number(m_dblManager->value(m_properties["R1S"])) +","+ QString::number(m_dblManager->value(m_properties["R1E"])); + // Get workspace names + + //TODO + QString qWorkspace = "q"; + QString qSquaredWorkspace = "q2"; + QString elfWorkspace = "elf"; + QString eltWorkspace = "elt"; + + std::string inputGroupWsName = "IDA_Elwin_Input"; - if ( m_blnManager->value(m_properties["UseTwoRanges"]) ) + // Load input files + QStringList inputFilenames = uiForm().elwin_inputFile->getFilenames(); + std::vector inputWorkspaceNames; + + for(auto it = inputFilenames.begin(); it != inputFilenames.end(); ++it) { - pyInput += ", " + QString::number(m_dblManager->value(m_properties["R2S"])) + ", " + QString::number(m_dblManager->value(m_properties["R2E"])); + QFileInfo inputFileInfo(*it); + std::string workspaceName = inputFileInfo.baseName().toStdString(); + + IAlgorithm_sptr loadAlg = AlgorithmManager::Instance().create("LoadNexus"); + loadAlg->initialize(); + loadAlg->setProperty("Filename", (*it).toStdString()); + loadAlg->setProperty("OutputWorkspace", workspaceName); + + m_batchAlgoRunner->addAlgorithm(loadAlg); + inputWorkspaceNames.push_back(workspaceName); } - pyInput+= "]\n"; + // Group input workspaces + IAlgorithm_sptr groupWsAlg = AlgorithmManager::Instance().create("GroupWorkspaces"); + groupWsAlg->initialize(); + groupWsAlg->setProperty("InputWorkspaces", inputWorkspaceNames); + groupWsAlg->setProperty("OutputWorkspace", inputGroupWsName); + + m_batchAlgoRunner->addAlgorithm(groupWsAlg); + + // Configure ElasticWindowMultiple algorithm + IAlgorithm_sptr elwinMultAlg = AlgorithmManager::Instance().create("ElasticWindowMultiple"); + elwinMultAlg->initialize(); + + elwinMultAlg->setProperty("Plot", uiForm().elwin_ckPlot->isChecked()); + + elwinMultAlg->setProperty("OutputInQ", qWorkspace.toStdString()); + elwinMultAlg->setProperty("OutputInQSquared", qSquaredWorkspace.toStdString()); + elwinMultAlg->setProperty("OutputELF", elfWorkspace.toStdString()); + + elwinMultAlg->setProperty("SampleEnvironmentLogName", uiForm().leLogName->text().toStdString()); + + elwinMultAlg->setProperty("Range1Start", m_dblManager->value(m_properties["R1S"])); + elwinMultAlg->setProperty("Range1End", m_dblManager->value(m_properties["R1E"])); - pyInput+= "logType = '"+ uiForm().leLogName->text() +"'\n"; + if(m_blnManager->value(m_properties["UseTwoRanges"])) + { + elwinMultAlg->setProperty("Range2Start", boost::lexical_cast(m_dblManager->value(m_properties["R1S"]))); + elwinMultAlg->setProperty("Range2End", boost::lexical_cast(m_dblManager->value(m_properties["R1E"]))); + } - if ( uiForm().elwin_ckNormalise->isChecked() ) pyInput += "normalise = True\n"; - else pyInput += "normalise = False\n"; + if(uiForm().elwin_ckNormalise->isChecked()) + { + elwinMultAlg->setProperty("OutputELT", eltWorkspace.toStdString()); + } + + BatchAlgorithmRunner::AlgorithmRuntimeProps elwinInputProps; + elwinInputProps["InputWorkspaces"] = inputGroupWsName; - if ( uiForm().elwin_ckSave->isChecked() ) pyInput += "save = True\n"; - else pyInput += "save = False\n"; + m_batchAlgoRunner->addAlgorithm(elwinMultAlg, elwinInputProps); - if ( uiForm().elwin_ckVerbose->isChecked() ) pyInput += "verbose = True\n"; - else pyInput += "verbose = False\n"; + // Configure Save algorithms + if(uiForm().elwin_ckSave->isChecked()) + { + addSaveAlgorithm(qWorkspace); + addSaveAlgorithm(qSquaredWorkspace); + addSaveAlgorithm(elfWorkspace); - if ( uiForm().elwin_ckPlot->isChecked() ) pyInput += "plot = True\n"; - else pyInput += "plot = False\n"; + if(uiForm().elwin_ckNormalise->isChecked()) + addSaveAlgorithm(eltWorkspace); + } + + m_batchAlgoRunner->executeBatchAsync(); + } + + /** + * Configures and adds a SaveNexus algorithm to the batch runner. + * + * @param workspaceName Name of the workspace to save + * @param filename Name of the file to save it as + */ + void Elwin::addSaveAlgorithm(QString workspaceName, QString filename) + { + // Set a default filename if none provided + if(filename.isEmpty()) + filename = workspaceName + ".nxs"; + // Configure the algorithm + IAlgorithm_sptr loadAlg = AlgorithmManager::Instance().create("SaveNexus"); + loadAlg->initialize(); + loadAlg->setProperty("Filename", filename.toStdString()); - pyInput += - "eq1_ws, eq2_ws = elwin(input, eRange, log_type=logType, Normalise=normalise, Save=save, Verbose=verbose, Plot=plot)\n"; + BatchAlgorithmRunner::AlgorithmRuntimeProps saveAlgProps; + saveAlgProps["InputWorkspace"] = workspaceName.toStdString(); - QString pyOutput = runPythonCode(pyInput); - UNUSED_ARG(pyOutput); + // Add it to the batch runner + m_batchAlgoRunner->addAlgorithm(loadAlg, saveAlgProps); } bool Elwin::validate() From 66e728f68a4ec5bebfe5bb0a928d4205b222eab9 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Nov 2014 10:18:04 +0000 Subject: [PATCH 068/128] Refs #10563 Generate screenshots for custom interface documentation --- .../source/interfaces/ISIS_Reflectometry.rst | 4 +- .../mantiddoc/directives/__init__.py | 3 +- .../mantiddoc/directives/interface.py | 146 ++++++++++++++++++ .../sphinxext/mantiddoc/tools/screenshot.py | 30 ++++ 4 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py diff --git a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst index 0c47464cc1a7..bbd446f16087 100644 --- a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst +++ b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst @@ -1,8 +1,8 @@ -.. _ISIS Reflectometry: - ISIS Reflectometry Interface ============================ +.. interface:: New ISIS Reflectometry (Prototype) + Menu bar -------- diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py index 2215cdd4afaa..58dda55dc5ff 100644 --- a/Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/__init__.py @@ -7,7 +7,7 @@ 'mantiddoc.directives' to be added to the Sphinx extensions configuration. """ -import algorithm, alias, attributes, categories, properties, summary +import algorithm, alias, attributes, categories, interface, properties, summary def setup(app): """ @@ -20,5 +20,6 @@ def setup(app): alias.setup(app) attributes.setup(app) categories.setup(app) + interface.setup(app) properties.setup(app) summary.setup(app) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py new file mode 100644 index 000000000000..745037ffa554 --- /dev/null +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py @@ -0,0 +1,146 @@ +from base import BaseDirective +from sphinx.locale import _ +import os + +class InterfaceDirective(BaseDirective): + + """ + Inserts details of a custom interface + + Adds: + - A screenshot of the interface + - Table of contents + + It requires a SCREENSHOTS_DIR environment variable to be set to the + directory where a screenshot should be generated. If it is not set then + a RuntimeError occurs + """ + + required_arguments, optional_arguments = 1, 0 + + def run(self): + """ + The main entry point that docutils calls. + It calls self.execute to do the main work. + Derived classes should override execute() and insert + whatever rst they require with self.add_rst() + """ + nodes = self.execute() + if self.rst_lines is not None: + self.commit_rst() + return nodes + + def execute(self): + """ + Called by Sphinx when the ..interface:: directive is encountered + """ + picture = self._create_screenshot() + self._insert_screenshot_link(picture) + self._insert_toc() + return [] + + def interface_name(self): + return self.arguments[0] + + def _insert_toc(self): + """ + Outputs a title for the page + """ + self.add_rst(".. contents:: Table of Contents\n :local:\n") + + def _create_screenshot(self): + """ + Creates a screenshot for the named interface in the "images/screenshots" + subdirectory. + + The file will be named "interfacename_interface.png", e.g. "ISIS_Reflectometry_interface.png" + + Returns: + screenshot: A mantiddoc.tools.Screenshot object + """ + try: + screenshots_dir = self._screenshot_directory() + except RuntimeError: + return None + + # Generate image + from mantiddoc.tools.screenshot import custominterface_screenshot + if not os.path.exists(screenshots_dir): + os.makedirs(screenshots_dir) + + try: + picture = custominterface_screenshot(self.interface_name(), screenshots_dir) + except RuntimeError, exc: + env = self.state.document.settings.env + env.warn(env.docname, "Unable to generate screenshot for '%s' - %s" % (self.interface_name(), str(exc))) + picture = None + + return picture + + def _insert_screenshot_link(self, picture): + """ + Outputs an image link with a custom :class: style. The filename is + extracted from the path given and then a relative link to the + directory specified by the SCREENSHOTS_DIR environment variable from + the root source directory is formed. + + Args: + picture (Screenshot): A Screenshot object + """ + env = self.state.document.settings.env + format_str = ".. figure:: %s\n"\ + " :class: screenshot\n"\ + " :width: %dpx\n"\ + " :align: left\n\n"\ + " %s\n\n" + + # Sphinx assumes that an absolute path is actually relative to the directory containing the + # conf.py file and a relative path is relative to the directory where the current rst file + # is located. + if picture: + screenshots_dir, filename = os.path.split(picture.imgpath) + # Find the width of the image + width, height = picture.width, picture.height + + # relative path to image + rel_path = os.path.relpath(screenshots_dir, env.srcdir) + # This is a href link so is expected to be in unix style + rel_path = rel_path.replace("\\","/") + # stick a "/" as the first character so Sphinx computes relative location from source directory + path = "/" + rel_path + "/" + filename + else: + # use stock not found image + path = "/images/ImageNotFound.png" + width = 200 + + caption = "**" + self.interface_name() + "** interface." + self.add_rst(format_str % (path, width, caption)) + + def _screenshot_directory(self): + """ + Returns a full path where the screenshots should be generated. They are + put in a screenshots subdirectory of the main images directory in the source + tree. Sphinx then handles copying them to the final location + + Arguments: + env (BuildEnvironment): Allows access to find the source directory + + Returns: + str: A string containing a path to where the screenshots should be created. This will + be a filesystem path + """ + try: + return os.environ["SCREENSHOTS_DIR"] + except: + raise RuntimeError("The '.. interface::' directive requires a SCREENSHOTS_DIR environment variable to be set.") + +#------------------------------------------------------------------------------------------------------------ + +def setup(app): + """ + Setup the directives when the extension is activated + + Args: + app: The main Sphinx application object + """ + app.add_directive('interface', InterfaceDirective) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py b/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py index 0d5da7a28bed..7d5a2801e1b3 100644 --- a/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py +++ b/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py @@ -57,3 +57,33 @@ def algorithm_screenshot(name, directory, version = -1, ext = ".png"): picture = Screenshot(dlg, filename, directory) threadsafe_call(dlg.close) return picture + +#-------------------------------------------------------------------------- + +def custominterface_screenshot(name, directory, ext = ".png"): + """ + Takes a snapshot of a custom interface and saves it as an image + named "name.png" + + Args: + name (str): The name of the custom interface + directory (str): An directory path where the image should be saved + ext (str): An optional extension (including the period). Default=.png + + Returns: + str: A full path to the image file + """ + import mantid + if not mantid.__gui__: + raise RuntimeError("MantidPlot not available. Cannot take screenshot") + + import mantidqtpython as mantidqt + from mantidplot import threadsafe_call + + iface_mgr = mantidqt.MantidQt.API.InterfaceManager() + # threadsafe_call required for MantidPlot + dlg = threadsafe_call(iface_mgr.createSubWindow, name, None) + + picture = Screenshot(dlg, name.replace(' ','_') + "_interface" + ext, directory) + threadsafe_call(dlg.close) + return picture From 9d3b4d08db2f11a2dee0418a8aa10105dee6cc53 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Nov 2014 11:41:30 +0000 Subject: [PATCH 069/128] Refs #10563 Add troubleshooting instructions to Refl UI documentation --- .../source/interfaces/ISIS_Reflectometry.rst | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst index bbd446f16087..e0a2f47665d9 100644 --- a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst +++ b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst @@ -210,4 +210,49 @@ the behaviour of the interface. | | decimal places. | +-------------------------------+------------------------------------------------------+ + +Troubleshooting +--------------- + +When I try to process I get an error: "Invalid value for property Filename (list of str lists) ..." +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This occurs when Mantid is unable to load a run. If the run was given as a +workspace name, check the spelling. If the run was given as a number, check +that the run number is correct. If the run number is incorrect, check the +number given in the *Run(s)* or *Transmission Run(s)* columns. If the run +number is correct, check the instrument named in the error message is correct. +If the instrument is incorrect, check that the processing instrument selector +(at the bottom right of the interface) is correct. + +If the run still isn't loading check Mantid's user directories are set +correctly, and that the desired run is in one of the given directories. To +manage the user directories, open *File -> Manage User Directories*. + +When I try to process I get an error: "Invalid key value pair, '...'" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This occurs when the contents of the options column are invalid. +Key value pairs must be given in the form ``key = value``, and if the value +contains commas it **must** be quoted, like so: ``key = "v,a,l,u,e"``. + +The *Open Table* menu doesn't do anything +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *Open Table* menu contains a list of valid table workspaces to open in the +processing table. If a workspace is not compatible, it will not be listed. So, +if there are no compatible workspaces the *Open Table* menu will be empty. + +My IvsQ workspaces are not being stitched correctly +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Stitching is controlled by the group a row is in. For stitching to occur, the +rows must be in the same group, and be processed simultaneously. + +An easy way to check the runs are in the same group is to select one of the +rows you want stitched, and then in the menu bar select *Edit -> Expand Selection*. +All the rows in that group will be selected. If you have another row that you +would like to add to the group, you can do this easily by adding it to the +selection, and then in the menu bar selecting *Edit -> Group Selected*. + .. categories:: Interfaces Reflectometry From 185888ef3f4ecd53f6717a991c5f4b927237d001 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 11:47:18 +0000 Subject: [PATCH 070/128] Get workspace names from file names Refs #10409 --- .../MantidQt/CustomInterfaces/src/Elwin.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp index c262a1bf31e5..5614aa7e7b82 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp @@ -92,18 +92,22 @@ namespace IDA void Elwin::run() { + QStringList inputFilenames = uiForm().elwin_inputFile->getFilenames(); + inputFilenames.sort(); + // Get workspace names + std::string inputGroupWsName = "IDA_Elwin_Input"; - //TODO - QString qWorkspace = "q"; - QString qSquaredWorkspace = "q2"; - QString elfWorkspace = "elf"; - QString eltWorkspace = "elt"; + QFileInfo firstFileInfo(inputFilenames[0]); + QString filename = firstFileInfo.baseName(); + QString workspaceBaseName = filename.left(filename.lastIndexOf("_")) + "_elwin_"; - std::string inputGroupWsName = "IDA_Elwin_Input"; + QString qWorkspace = workspaceBaseName + "q"; + QString qSquaredWorkspace = workspaceBaseName + "q2"; + QString elfWorkspace = workspaceBaseName + "elf"; + QString eltWorkspace = workspaceBaseName + "elt"; // Load input files - QStringList inputFilenames = uiForm().elwin_inputFile->getFilenames(); std::vector inputWorkspaceNames; for(auto it = inputFilenames.begin(); it != inputFilenames.end(); ++it) From 52c8665a7a63aa7c900fb0f8188297ab46ba95cc Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 11:51:32 +0000 Subject: [PATCH 071/128] Tidy up SortXAxis, remove additional workspace left in ADS Refs #10568 --- .../plugins/algorithms/SortXAxis.py | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/SortXAxis.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/SortXAxis.py index c2de7daabfa7..39c81a9f31a3 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/SortXAxis.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/SortXAxis.py @@ -21,25 +21,32 @@ def PyInit(self): self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", defaultValue="", direction=Direction.Output), doc="Sorted Output Workspace") def PyExec(self): - inputws = self.getProperty("InputWorkspace").value - specs = inputws.getNumberHistograms() - outws = api.CloneWorkspace(InputWorkspace=inputws) - for i in range(0, specs): - x = inputws.readX(i) - y = inputws.readY(i) - e = inputws.readE(i) + input_ws = self.getProperty('InputWorkspace').value + output_ws = self.getPropertyValue('OutputWorkspace') + + num_specs = input_ws.getNumberHistograms() + api.CloneWorkspace(InputWorkspace=input_ws, OutputWorkspace=output_ws) + + for i in range(0, num_specs): + x = input_ws.readX(i) + y = input_ws.readY(i) + e = input_ws.readE(i) + indexes = x.argsort() - xordered = x[indexes] - if inputws.isHistogramData(): + + x_ordered = x[indexes] + if input_ws.isHistogramData(): max_index = np.argmax(indexes) indexes = np.delete(indexes, max_index) - yordered = y[indexes] - eordered = e[indexes] - outws.setX(i, xordered) - outws.setY(i, yordered) - outws.setE(i, eordered) - self.setProperty('OutputWorkspace', outws) + y_ordered = y[indexes] + e_ordered = e[indexes] + + mtd[output_ws].setX(i, x_ordered) + mtd[output_ws].setY(i, y_ordered) + mtd[output_ws].setE(i, e_ordered) + + self.setProperty('OutputWorkspace', output_ws) ############################################################################################# From 24fdf2c8a5bd90b6ce3a08a6f5b41ac902d2c467 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 12:12:58 +0000 Subject: [PATCH 072/128] Tidy UI, use naming required for MSD fit Refs #10409 --- .../inc/MantidQtCustomInterfaces/Elwin.h | 6 ++--- .../IndirectDataAnalysis.ui | 24 +------------------ .../MantidQt/CustomInterfaces/src/Elwin.cpp | 19 ++++++++------- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Elwin.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Elwin.h index 88512f2e27fb..ffb221210f97 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Elwin.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Elwin.h @@ -15,7 +15,7 @@ namespace IDA Q_OBJECT public: - Elwin(QWidget * parent = 0); + Elwin(QWidget* parent = 0); private: virtual void setup(); @@ -28,10 +28,10 @@ namespace IDA private slots: void plotInput(); - void twoRanges(QtProperty *, bool); + void twoRanges(QtProperty* prop, bool); void minChanged(double val); void maxChanged(double val); - void updateRS(QtProperty * prop, double val); + void updateRS(QtProperty* prop, double val); private: void addSaveAlgorithm(QString workspaceName, QString filename=""); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataAnalysis.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataAnalysis.ui index 4f695252715d..c0b46181aeed 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataAnalysis.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataAnalysis.ui @@ -84,13 +84,6 @@ - - - - Normalise to Lowest Temperature - - - @@ -139,19 +132,6 @@ Output - - - - true - - - Verbose - - - true - - - @@ -2854,8 +2834,8 @@ tabWidget + elwin_inputFile elwin_pbPlotInput - elwin_ckVerbose elwin_ckPlot elwin_ckSave msd_ckVerbose @@ -2876,8 +2856,6 @@ pbHelp pbRun pbManageDirs - elwin_inputFile - elwin_ckNormalise leLogName furyfit_inputFile furyfit_pbPlotInput diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp index 5614aa7e7b82..4adc265c2df8 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp @@ -42,6 +42,7 @@ namespace IDA m_dblManager->setDecimals(m_properties["R2E"], NUM_DECIMALS); m_properties["UseTwoRanges"] = m_blnManager->addProperty("Use Two Ranges"); + m_properties["Normalise"] = m_blnManager->addProperty("Normalise to Lowest Temp"); m_properties["Range1"] = m_grpManager->addProperty("Range One"); m_properties["Range1"]->addSubProperty(m_properties["R1S"]); @@ -53,6 +54,7 @@ namespace IDA m_elwTree->addProperty(m_properties["Range1"]); m_elwTree->addProperty(m_properties["UseTwoRanges"]); m_elwTree->addProperty(m_properties["Range2"]); + m_elwTree->addProperty(m_properties["Normalise"]); // Create Slice Plot Widget for Range Selection m_plots["ElwinPlot"] = new QwtPlot(m_parentWidget); @@ -77,7 +79,7 @@ namespace IDA connect(m_dblManager, SIGNAL(valueChanged(QtProperty*, double)), this, SLOT(updateRS(QtProperty*, double))); connect(m_blnManager, SIGNAL(valueChanged(QtProperty*, bool)), this, SLOT(twoRanges(QtProperty*, bool))); - twoRanges(0, false); + twoRanges(m_properties["UseTwoRanges"], false); connect(uiForm().elwin_pbPlotInput, SIGNAL(clicked()), this, SLOT(plotInput())); connect(uiForm().elwin_inputFile, SIGNAL(filesFound()), this, SLOT(plotInput())); @@ -100,10 +102,10 @@ namespace IDA QFileInfo firstFileInfo(inputFilenames[0]); QString filename = firstFileInfo.baseName(); - QString workspaceBaseName = filename.left(filename.lastIndexOf("_")) + "_elwin_"; + QString workspaceBaseName = filename.left(filename.lastIndexOf("_")) + "_elwin-mult_"; - QString qWorkspace = workspaceBaseName + "q"; - QString qSquaredWorkspace = workspaceBaseName + "q2"; + QString qWorkspace = workspaceBaseName + "eq"; + QString qSquaredWorkspace = workspaceBaseName + "eq2"; QString elfWorkspace = workspaceBaseName + "elf"; QString eltWorkspace = workspaceBaseName + "elt"; @@ -153,7 +155,7 @@ namespace IDA elwinMultAlg->setProperty("Range2End", boost::lexical_cast(m_dblManager->value(m_properties["R1E"]))); } - if(uiForm().elwin_ckNormalise->isChecked()) + if(m_blnManager->value(m_properties["Normalise"])) { elwinMultAlg->setProperty("OutputELT", eltWorkspace.toStdString()); } @@ -170,7 +172,7 @@ namespace IDA addSaveAlgorithm(qSquaredWorkspace); addSaveAlgorithm(elfWorkspace); - if(uiForm().elwin_ckNormalise->isChecked()) + if(m_blnManager->value(m_properties["Normalise"])) addSaveAlgorithm(eltWorkspace); } @@ -309,9 +311,10 @@ namespace IDA } } - void Elwin::twoRanges(QtProperty*, bool val) + void Elwin::twoRanges(QtProperty* prop, bool val) { - m_rangeSelectors["ElwinRange2"]->setVisible(val); + if(prop == m_properties["UseTwoRanges"]) + m_rangeSelectors["ElwinRange2"]->setVisible(val); } void Elwin::minChanged(double val) From 49ca1c4e9db01e24382b2fd023845fdaa18a0bcb Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 12:16:08 +0000 Subject: [PATCH 073/128] Fix failing unit tests Refs #10409 --- .../algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py index 7022fa988968..c4d5422dc533 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py @@ -2,8 +2,6 @@ from mantid.kernel import * from mantid.api import * -from IndirectCommon import getInstrRun - def _normalize_to_lowest_temp(elt_ws_name): """ @@ -92,6 +90,7 @@ def validateInputs(self): def PyExec(self): from IndirectImport import import_mantidplot + from IndirectCommon import getInstrRun # Do setup self._setup() From 74cadc59789fdd4f0d6587f9dbe74f453b73a9bd Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 14:11:09 +0000 Subject: [PATCH 074/128] Fixed issues in reduction, resolution and diff. reduction Refs #10571 --- .../WorkflowAlgorithms/IndirectResolution.py | 2 +- .../IndirectTransmissionMonitor.py | 7 +------ .../InelasticIndirectReduction.py | 21 +++++++++++-------- .../MSGDiffractionReduction.py | 21 ++++++++++++------- .../WorkflowAlgorithms/TimeSlice.py | 14 ++++++------- .../src/IndirectCalibration.cpp | 1 + .../src/IndirectConvertToEnergy.cpp | 2 ++ .../src/IndirectDiagnostics.cpp | 1 + .../src/IndirectDiffractionReduction.cpp | 2 +- 9 files changed, 38 insertions(+), 33 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py index d521ad91d69e..38fb54891c2e 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py @@ -59,7 +59,7 @@ def PyExec(self): SumFiles=True, InputFiles=self._input_files, DetectorRange=self._detector_range, - OutputWorkspaceGroup='__icon_ws_group') + OutputWorkspace='__icon_ws_group') icon_ws = mtd['__icon_ws_group'].getItem(0).getName() diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectTransmissionMonitor.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectTransmissionMonitor.py index beb5308debe6..19705a7937d0 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectTransmissionMonitor.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectTransmissionMonitor.py @@ -22,8 +22,7 @@ def PyInit(self): self.declareProperty(WorkspaceProperty('CanWorkspace', '', direction=Direction.Input), doc='Background/can workspace') - self.declareProperty(WorkspaceProperty('OutputWorkspace', '', direction=Direction.Output, - optional=PropertyMode.Optional), + self.declareProperty(WorkspaceProperty('OutputWorkspace', '', direction=Direction.Output), doc='Output workspace group') self.declareProperty(name='Verbose', defaultValue=False, doc='Output more verbose message to log') @@ -52,10 +51,6 @@ def PyExec(self): AddSampleLog(Workspace=trans_ws, LogName='can_workspace', LogType='String', LogText=self._can_ws_in) - # Generate an output workspace name if none provided - if self._out_ws == '': - self._out_ws = ws_basename + '_Transmission' - # Group workspaces group = sam_ws + ',' + can_ws + ',' + trans_ws GroupWorkspaces(InputWorkspaces=group, OutputWorkspace=self._out_ws) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py index 059a46744d5c..7fefbeb7fbad 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py @@ -2,6 +2,7 @@ from mantid.api import * from mantid.simpleapi import * + class InelasticIndirectReduction(DataProcessorAlgorithm): def category(self): @@ -16,9 +17,9 @@ def PyInit(self): self.declareProperty(StringArrayProperty(name='InputFiles'), doc='Comma separated list of input files') - self.declareProperty(WorkspaceGroupProperty('OutputWorkspaceGroup', '', - direction=Direction.Output, optional=PropertyMode.Optional), - doc='Optionally group the resulting workspaces') + self.declareProperty(WorkspaceGroupProperty('OutputWorkspace', '', + direction=Direction.Output), + doc='Workspace group for the resulting workspaces') self.declareProperty(name='SumFiles', defaultValue=False, doc='Toggle input file summing or sequential processing') self.declareProperty(name='LoadLogs', defaultValue=False, doc='Load sample logs from input files') @@ -43,7 +44,7 @@ def PyInit(self): self.declareProperty(name='DetailedBalance', defaultValue=-1.0, doc='') self.declareProperty(name='ScaleFactor', defaultValue=1.0, doc='') self.declareProperty(name='Grouping', defaultValue='', - doc='Method used to group spectra, can be either: Individual, All, a .map fielname or a group workspace name') + doc='Method used to group spectra, can be either: Individual, All, a .map filename or a group workspace name') self.declareProperty(name='Fold', defaultValue=False, doc='') self.declareProperty(name='SaveCM1', defaultValue=False, doc='') self.declareProperty(StringArrayProperty(name='SaveFormats'), doc='Comma separated list of save formats') @@ -123,9 +124,8 @@ def PyExec(self): self._add_ws_logs(workspace) # Group output workspaces - if self._out_ws_group != '': - GroupWorkspaces(InputWorkspaces=ws_list, OutputWorkspace=self._out_ws_group) - self.setProperty('OutputWorkspaceGroup', self._out_ws_group) + GroupWorkspaces(InputWorkspaces=ws_list, OutputWorkspace=self._out_ws_group) + self.setProperty('OutputWorkspace', self._out_ws_group) # Do plotting if self._plot_type != 'none': @@ -133,6 +133,7 @@ def PyExec(self): EndTime('InelasticIndirectReduction') + def validateInputs(self): """ Validates algorithm properties. @@ -147,17 +148,18 @@ def validateInputs(self): if save_format not in valid_formats: invalid_formats.append(save_format) if len(invalid_formats) > 0: - issues['SaveFormats'] = 'The following save formats are not valid' + ','.join(invalid_formats) + issues['SaveFormats'] = 'The following save formats are not valid: ' + ','.join(invalid_formats) return issues + def _setup(self): """ Gets and algorithm properties. """ # Get parameter values - self._out_ws_group = self.getPropertyValue('OutputWorkspaceGroup') + self._out_ws_group = self.getPropertyValue('OutputWorkspace') self._data_files = self.getProperty('InputFiles').value self._instrument = self.getPropertyValue('Instrument') @@ -182,6 +184,7 @@ def _setup(self): self._save_formats = self.getProperty('SaveFormats').value self._plot_type = self.getPropertyValue('Plot') + def _add_ws_logs(self, workspace_name): """ Adds sample logs to a given output workspace. diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSGDiffractionReduction.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSGDiffractionReduction.py index ed75174e90ee..15438f256618 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSGDiffractionReduction.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSGDiffractionReduction.py @@ -2,16 +2,20 @@ from mantid.api import * from mantid.kernel import * from mantid import config + import os.path, math + class MSGDiffractionReduction(PythonAlgorithm): def category(self): return 'Diffraction;PythonAlgorithms' + def summary(self): return 'Calculates the scattering & transmission for Indirect Geometry spectrometers.' + def PyInit(self): self.declareProperty(StringArrayProperty(name='InputFiles'), doc='Comma separated list of input files.') @@ -36,13 +40,14 @@ def PyInit(self): self.declareProperty(name='RebinParam', defaultValue='', doc='Rebin parameters.') - self.declareProperty(WorkspaceGroupProperty('OutputWorkspaceGroup', '', - direction=Direction.Output, optional=PropertyMode.Optional), - doc='Optionally group the result workspaces.') + self.declareProperty(WorkspaceGroupProperty('OutputWorkspace', '', + direction=Direction.Output), + doc='Group name for the result workspaces.') self.declareProperty(StringArrayProperty(name='SaveFormats'), doc='Save formats to save output in.') + def validateInputs(self): """ Checks for issues with user input. @@ -72,6 +77,7 @@ def validateInputs(self): return issues + def PyExec(self): from IndirectCommon import StartTime, EndTime from IndirectDiffractionReduction import MSGDiffractionReducer @@ -85,7 +91,7 @@ def PyExec(self): mode = self.getPropertyValue('Mode') detector_range = self.getProperty('DetectorRange').value rebin_string = self.getPropertyValue('RebinParam') - output_ws_group = self.getPropertyValue('OutputWorkspaceGroup') + output_ws_group = self.getPropertyValue('OutputWorkspace') save_formats = self.getProperty('SaveFormats').value ipf_filename = instrument_name + '_diffraction_' + mode + '_Parameters.xml' @@ -111,10 +117,9 @@ def PyExec(self): reducer.reduce() - if output_ws_group != '': - result_ws_list = reducer.get_result_workspaces() - GroupWorkspaces(InputWorkspaces=result_ws_list, OutputWorkspace=output_ws_group) - self.setProperty('OutputWorkspaceGroup', output_ws_group) + result_ws_list = reducer.get_result_workspaces() + GroupWorkspaces(InputWorkspaces=result_ws_list, OutputWorkspace=output_ws_group) + self.setProperty('OutputWorkspace', output_ws_group) EndTime('MSGDiffractionReduction') diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TimeSlice.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TimeSlice.py index 6a6a12ea599b..7872645e422d 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TimeSlice.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TimeSlice.py @@ -84,8 +84,8 @@ def PyInit(self): self.declareProperty(name='OutputNameSuffix', defaultValue='_slice', doc='Suffix to append to raw file name for name of output workspace') - self.declareProperty(WorkspaceGroupProperty(name='OutputWorkspaceGroup', defaultValue='', - optional=PropertyMode.Optional, direction=Direction.Output), + self.declareProperty(WorkspaceGroupProperty(name='OutputWorkspace', defaultValue='', + direction=Direction.Output), doc='Name of workspace group to group result workspaces into') @@ -150,9 +150,9 @@ def PyExec(self): if self._verbose: logger.notice('Output file :' + save_path) - if self._out_ws_group is not None: - all_workspaces = ','.join(out_ws_list) - GroupWorkspaces(InputWorkspaces=all_workspaces, OutputWorkspace=self._out_ws_group) + all_workspaces = ','.join(out_ws_list) + GroupWorkspaces(InputWorkspaces=all_workspaces, OutputWorkspace=self._out_ws_group) + self.setProperty('OutputWorkspace', self._out_ws_group) if self._plot: try: @@ -182,9 +182,7 @@ def _setup(self): if self._calib_ws == '': self._calib_ws = None - self._out_ws_group = self.getPropertyValue('OutputWorkspaceGroup') - if self._out_ws_group == '': - self._out_ws_group = None + self._out_ws_group = self.getPropertyValue('OutputWorkspace') self._verbose = self.getProperty('Verbose').value self._plot = self.getProperty('Plot').value diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectCalibration.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectCalibration.cpp index 51b186d669fd..6e9388383e37 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectCalibration.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectCalibration.cpp @@ -388,6 +388,7 @@ namespace CustomInterfaces reductionAlg->setProperty("Analyser", m_uiForm.cbAnalyser->currentText().toStdString()); reductionAlg->setProperty("Reflection", m_uiForm.cbReflection->currentText().toStdString()); reductionAlg->setProperty("InputFiles", files.toStdString()); + reductionAlg->setProperty("OutputWorkspace", "__IndirectCalibration_reduction"); reductionAlg->setProperty("DetectorRange", detRange.toStdString()); reductionAlg->execute(); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp index 9718efca4d08..a9c0eefe999d 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp @@ -164,6 +164,8 @@ namespace CustomInterfaces reductionAlg->setProperty("SaveCM1", m_uiForm.ckCm1Units->isChecked()); reductionAlg->setProperty("SaveFormats", getSaveFormats()); + reductionAlg->setProperty("OutputWorkspace", "IndirectInelasticReduction"); + // Plot Output options switch(m_uiForm.ind_cbPlotOutput->currentIndex()) { diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiagnostics.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiagnostics.cpp index e1ac3785e73f..4a589ebcdffc 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiagnostics.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiagnostics.cpp @@ -156,6 +156,7 @@ namespace CustomInterfaces sliceAlg->setProperty("Plot", m_uiForm.slice_ckPlot->isChecked()); sliceAlg->setProperty("Save", m_uiForm.slice_ckSave->isChecked()); sliceAlg->setProperty("OutputNameSuffix", suffix.toStdString()); + sliceAlg->setProperty("OutputWorkspace", "IndirectDiagnostics_Workspaces"); if(m_uiForm.slice_ckUseCalib->isChecked()) { diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiffractionReduction.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiffractionReduction.cpp index e3c9a1c5a406..153ec3ba6e33 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiffractionReduction.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiffractionReduction.cpp @@ -167,7 +167,7 @@ void IndirectDiffractionReduction::runGenericReduction(QString instName, QString msgDiffReduction->setProperty("RebinParam", rebin.toStdString()); msgDiffReduction->setProperty("IndividualGrouping", individualGrouping); msgDiffReduction->setProperty("SaveFormats", saveFormats); - msgDiffReduction->setProperty("OutputWorkspaceGroup", "IndirectDiffraction_Workspaces"); + msgDiffReduction->setProperty("OutputWorkspace", "IndirectDiffraction_Workspaces"); m_batchAlgoRunner->addAlgorithm(msgDiffReduction); From 36524d506889a09d5813cc836852d0dc550ee65a Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 14:30:10 +0000 Subject: [PATCH 075/128] Fix failing system test Refs #10409 --- .../algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py index c4d5422dc533..1e89c72c286b 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py @@ -272,6 +272,7 @@ def _get_temperature(self, ws_name): @param ws_name Name of workspace @returns Temperature in Kelvin or None if not found """ + from IndirectCommon import getInstrRun instr, run_number = getInstrRun(ws_name) From 6d81c8e700765864646aaa5192ade52e53817151 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 14:32:02 +0000 Subject: [PATCH 076/128] Changed unit tests for algorithm changes Refs #10571 --- .../InelasticIndirectReductionTest.py | 2 +- .../python/plugins/algorithms/TimeSliceTest.py | 17 +++-------------- .../src/IndirectConvertToEnergy.cpp | 2 +- .../src/IndirectDiagnostics.cpp | 1 + 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/InelasticIndirectReductionTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/InelasticIndirectReductionTest.py index 860dde95c5a1..576a0bbf5e5c 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/InelasticIndirectReductionTest.py +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/InelasticIndirectReductionTest.py @@ -7,7 +7,7 @@ class InelasticIndirectReductionTest(unittest.TestCase): def test_basic(self): InelasticIndirectReduction(InputFiles='IRS26176.RAW', - OutputWorkspaceGroup='IndirectReductions', + OutputWorkspace='IndirectReductions', Instrument='IRIS', Analyser='graphite', Reflection='002', diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TimeSliceTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TimeSliceTest.py index 093118b8effe..9a30f00dc6ba 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TimeSliceTest.py +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TimeSliceTest.py @@ -9,23 +9,11 @@ def test_basic(self): Test to ensure that algorithm completes succesfully. """ - TimeSlice(InputFiles=['IRS26173.raw'], - SpectraRange=[3, 53], - PeakRange=[62500, 65000], - BackgroundRange=[59000, 61500]) - - self.assertTrue(mtd.doesExist('irs26173_slice')) - - def test_group(self): - """ - Tests to ensure that result workspaces are goruped correctly. - """ - TimeSlice(InputFiles=['IRS26173.raw'], SpectraRange=[3, 53], PeakRange=[62500, 65000], BackgroundRange=[59000, 61500], - OutputWorkspaceGroup='SliceTestOut') + OutputWorkspace='SliceTestOut') self.assertTrue(mtd.doesExist('SliceTestOut')) self.assertTrue(mtd.doesExist('irs26173_slice')) @@ -39,7 +27,8 @@ def test_suffix(self): SpectraRange=[3, 53], PeakRange=[62500, 65000], BackgroundRange=[59000, 61500], - OutputNameSuffix='_graphite002_slice') + OutputNameSuffix='_graphite002_slice', + OutputWorkspace='SliceTestOut') self.assertTrue(mtd.doesExist('irs26173_graphite002_slice')) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp index a9c0eefe999d..c7da7b5e6227 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectConvertToEnergy.cpp @@ -164,7 +164,7 @@ namespace CustomInterfaces reductionAlg->setProperty("SaveCM1", m_uiForm.ckCm1Units->isChecked()); reductionAlg->setProperty("SaveFormats", getSaveFormats()); - reductionAlg->setProperty("OutputWorkspace", "IndirectInelasticReduction"); + reductionAlg->setProperty("OutputWorkspace", "IndirectInergyTransfer_Workspaces"); // Plot Output options switch(m_uiForm.ind_cbPlotOutput->currentIndex()) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiagnostics.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiagnostics.cpp index 4a589ebcdffc..33df411d9887 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiagnostics.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectDiagnostics.cpp @@ -366,6 +366,7 @@ namespace CustomInterfaces sliceAlg->setProperty("Plot", false); sliceAlg->setProperty("Save", false); sliceAlg->setProperty("OutputNameSuffix", suffix.toStdString()); + sliceAlg->setProperty("OutputWorkspace", "IndirectDiagnostics_Workspaces"); if(m_uiForm.slice_ckUseCalib->isChecked()) { From 7dfef06baaf998e5ee20e70a663169ccd83aad79 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Nov 2014 14:26:46 +0000 Subject: [PATCH 077/128] Refs #10570 Add segfaulting test to ReflectometryReductionOneAutoTest --- .../test/ReflectometryReductionOneAutoTest.h | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h b/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h index 756b342c4549..bcbef47502ae 100644 --- a/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h +++ b/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h @@ -6,6 +6,7 @@ #include "MantidAlgorithms/ReflectometryReductionOneAuto.h" #include "MantidAPI/FrameworkManager.h" #include "MantidAPI/AlgorithmManager.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" #include using Mantid::Algorithms::ReflectometryReductionOneAuto; @@ -370,7 +371,28 @@ class ReflectometryReductionOneAutoTest: public CxxTest::TestSuite } + void test_missing_instrument_parameters_throws() + { + auto tinyWS = WorkspaceCreationHelper::create2DWorkspaceWithReflectometryInstrument(); + auto inst = tinyWS->getInstrument(); + + inst->getParameterMap()->addDouble(inst.get(), "I0MonitorIndex", 1.0); + + tinyWS->mutableRun().addLogData(new PropertyWithValue("Theta", 0.12345)); + tinyWS->mutableRun().addLogData(new PropertyWithValue("run_number", "12345")); + + IAlgorithm_sptr alg = AlgorithmManager::Instance().create("ReflectometryReductionOneAuto"); + alg->setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg->initialize()); + TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", tinyWS)); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("OutputWorkspace", outWSQName)); + TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("OutputWorkspaceWavelength", outWSLamName)); + TS_ASSERT_THROWS_ANYTHING(alg->execute()); + // Remove workspace from the data service. + AnalysisDataService::Instance().remove(outWSQName); + AnalysisDataService::Instance().remove(outWSLamName); + } }; From 44012231081a2ac501a7b9cdd86c21bb86b70443 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Tue, 18 Nov 2014 14:55:16 +0000 Subject: [PATCH 078/128] Refs #8961 Fixed unit test working --- .../Framework/DataHandling/CMakeLists.txt | 1 + .../SaveReflThreeColumnAscii.h | 6 +- .../src/SaveReflThreeColumnAscii.cpp | 14 +-- .../test/SaveReflThreeColumnAsciiTest.h | 90 +++---------------- 4 files changed, 18 insertions(+), 93 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/CMakeLists.txt b/Code/Mantid/Framework/DataHandling/CMakeLists.txt index a2c98d7bb815..d9efbca2083d 100644 --- a/Code/Mantid/Framework/DataHandling/CMakeLists.txt +++ b/Code/Mantid/Framework/DataHandling/CMakeLists.txt @@ -413,6 +413,7 @@ set ( TEST_FILES SaveParameterFileTest.h SaveRKHTest.h SaveReflTBLTest.h + SaveReflThreeColumnAsciiTest.h SaveSPETest.h SaveToSNSHistogramNexusTest.h SetSampleMaterialTest.h diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h index 7f145fd6eb42..19ba41f9cb17 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h @@ -13,10 +13,10 @@ namespace Mantid namespace DataHandling { /** - Saves a file in ILL Cosmos format from a 2D workspace - (Workspace2D class). SaveILLCosmosAscii is an algorithm but inherits frrm the + Saves a file in three column format from a 2D workspace + (Workspace2D class). SaveReflThreeColumnAscii is an algorithm but inherits from the AsciiPointBase class which provides the main implementation for the init() & exec() methods. - Output is tab delimited Ascii point data with dq/q and extra header information. + Output is tab delimited Ascii point data without dq/q and with extra header information. Copyright © 2007-14 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp index da032bbd7cdd..07e57575f2a6 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp @@ -18,8 +18,8 @@ namespace Mantid /// virtual method to set the extra properties required for this algorithm void SaveReflThreeColumnAscii::extraProps() { - declareProperty(new ArrayProperty("LogList"),"List of logs to write to file."); declareProperty("Title", "", "Text to be written to the Title field"); + declareProperty(new ArrayProperty("LogList"),"List of logs to write to file."); } /** virtual method to add information to the file before the data @@ -28,20 +28,12 @@ namespace Mantid void SaveReflThreeColumnAscii::extraHeaders(std::ofstream & file) { auto samp = m_ws->run(); - //std::string subtitle; std::string title = getProperty("Title"); - /*try - { - subtitle = samp.getLogData("run_title")->value(); - } - catch (Kernel::Exception::NotFoundError &) - { - subtitle = ""; - } + if (title != "") //if is toggled { file << "#" << title << std::endl; - }*/ + } const std::vector logList = getProperty("LogList"); ///logs diff --git a/Code/Mantid/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h b/Code/Mantid/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h index 523af3c0b2b9..5582560081c6 100644 --- a/Code/Mantid/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h +++ b/Code/Mantid/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h @@ -59,18 +59,13 @@ class SaveReflThreeColumnAsciiTest : public CxxTest::TestSuite TS_ASSERT( Poco::File(m_long_filename).exists() ); std::ifstream in(m_long_filename.c_str()); std::string fullline; - headingsTests(in, fullline); getline(in,fullline); - std::vector columns; boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); - TS_ASSERT_EQUALS(columns.size(),3); /////// - //the first is black due to the leading tab - TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_EQUALS(columns.size(),4); //first blank TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); in.close(); cleanupafterwards(); @@ -94,17 +89,13 @@ class SaveReflThreeColumnAsciiTest : public CxxTest::TestSuite TS_ASSERT( Poco::File(m_long_filename).exists() ); std::ifstream in(m_long_filename.c_str()); std::string fullline; - headingsTests(in, fullline); getline(in,fullline); std::vector columns; boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); - TS_ASSERT_EQUALS(columns.size(),5); - //the first is black due to the leading tab - TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_EQUALS(columns.size(),4); //first blank TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 0, 0.01); TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); - TS_ASSERT((columns.at(4) == "nan") || (columns.at(4) == "inf")); + //TS_ASSERT((columns.at(3) == "nan") || (columns.at(3) == "inf")); in.close(); cleanupafterwards(); @@ -128,17 +119,13 @@ class SaveReflThreeColumnAsciiTest : public CxxTest::TestSuite TS_ASSERT( Poco::File(m_long_filename).exists() ); std::ifstream in(m_long_filename.c_str()); std::string fullline; - headingsTests(in, fullline); getline(in,fullline); std::vector columns; boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); - TS_ASSERT_EQUALS(columns.size(),5); - //the first is black due to the leading tab - TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_EQUALS(columns.size(),4); //first blank TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 0, 0.01); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 0, 0.01); + TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); in.close(); cleanupafterwards(); @@ -162,60 +149,21 @@ class SaveReflThreeColumnAsciiTest : public CxxTest::TestSuite TS_ASSERT( Poco::File(m_long_filename).exists() ); std::ifstream in(m_long_filename.c_str()); std::string fullline; - headingsTests(in, fullline); getline(in,fullline); std::vector columns; boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); - TS_ASSERT_EQUALS(columns.size(),5); - //the first is black due to the leading tab - TS_ASSERT(columns.at(0) == ""); + TS_ASSERT_EQUALS(columns.size(),4); //first blank TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 0, 0.01); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); in.close(); cleanupafterwards(); } - void testParameters() - { - //create a new workspace and then delete it later on - createWS(false,false,false,true); - - Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflThreeColumnAscii"); - alg->setPropertyValue("InputWorkspace", m_name); - alg->setPropertyValue("Filename", m_filename); - alg->setPropertyValue("Title", "Testing this algorithm"); - TS_ASSERT_THROWS_NOTHING(alg->execute()); - - if ( ! alg->isExecuted() ) - { - TS_FAIL("Could not run SaveReflThreeColumnAscii"); - } - m_long_filename= alg->getPropertyValue("Filename"); - // has the algorithm written a file to disk? - TS_ASSERT( Poco::File(m_long_filename).exists() ); - std::ifstream in(m_long_filename.c_str()); - std::string fullline; - headingsTests(in, fullline,true); - getline(in,fullline); - - std::vector columns; - boost::split(columns, fullline, boost::is_any_of("\t"), boost::token_compress_on); - TS_ASSERT_EQUALS(columns.size(),5); - //the first is black due to the leading tab - TS_ASSERT(columns.at(0) == ""); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(1)), 1.5, 0.01); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(2)), 1, 0.01); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(3)), 1, 0.01); - TS_ASSERT_DELTA(boost::lexical_cast(columns.at(4)), 0.6, 0.01); - in.close(); - cleanupafterwards(); - } void test_fail_invalid_workspace() { - Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflCustomAscii"); + Mantid::API::IAlgorithm_sptr alg = Mantid::API::AlgorithmManager::Instance().create("SaveReflThreeColumnAscii"); alg->setRethrows(true); TS_ASSERT(alg->isInitialized()); TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Filename", m_filename)); @@ -227,27 +175,9 @@ class SaveReflThreeColumnAsciiTest : public CxxTest::TestSuite TS_ASSERT( !Poco::File(m_long_filename).exists() ); } private: - void headingsTests(std::ifstream & in,std::string & fullline, bool propertiesLogs = false) - { - if (propertiesLogs) - { - getline(in,fullline); - TS_ASSERT(fullline == "Title: Testing this algorithm"); - getline(in,fullline); - TS_ASSERT(fullline == "Subtitle: SaveReflThreeColumnAscii save test"); - } - else - { - } - } - void createWS(bool zeroX = false, bool zeroY = false, bool zeroE = false, bool createLogs = false) + void createWS(bool zeroX = false, bool zeroY = false, bool zeroE = false) { MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(1,10); - - if (createLogs) - { - } - AnalysisDataService::Instance().addOrReplace(m_name, ws); //Check if any of X, Y or E should be zeroed to check for divide by zero or similiar if (zeroX) @@ -285,4 +215,6 @@ class SaveReflThreeColumnAsciiTest : public CxxTest::TestSuite std::string m_filename, m_name, m_long_filename; std::vector m_dataX, m_dataY, m_dataE, m_data0; }; + + #endif /*SAVEREFLTHREECOLUMNASCIITEST_H_*/ From ad9f36db421be98863d437e230d889bc1da009f0 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Nov 2014 14:38:29 +0000 Subject: [PATCH 079/128] Refs #10570 Sum range of point detectors --- .../Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp | 2 +- .../Algorithms/test/ReflectometryReductionOneAutoTest.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp b/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp index 560f9ac6a5b1..abfd829d2cd3 100644 --- a/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp +++ b/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp @@ -138,7 +138,7 @@ namespace Mantid else { //Otherwise, we create a range. - processing_commands = boost::lexical_cast(detStart) + ":" + boost::lexical_cast(detStop); + processing_commands = boost::lexical_cast(detStart) + "-" + boost::lexical_cast(detStop); } } else diff --git a/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h b/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h index bcbef47502ae..fd16133be9c5 100644 --- a/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h +++ b/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h @@ -349,7 +349,7 @@ class ReflectometryReductionOneAutoTest: public CxxTest::TestSuite std::string processingInstructions = findPropertyValue(vecPropertyHistories, "ProcessingInstructions"); std::vector pointDetectorStartStop; - boost::split(pointDetectorStartStop, processingInstructions, boost::is_any_of(":")); + boost::split(pointDetectorStartStop, processingInstructions, boost::is_any_of("-")); TS_ASSERT_EQUALS(inst->getNumberParameter("LambdaMin")[0], wavelengthMin); TS_ASSERT_EQUALS(inst->getNumberParameter("LambdaMax")[0], wavelengthMax); From 4c7bb8687503d8f0042f13dc0924b9009aa0434a Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Nov 2014 14:58:49 +0000 Subject: [PATCH 080/128] Refs #10570 Fetch point detector parameters more carefully --- .../src/ReflectometryReductionOneAuto.cpp | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp b/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp index abfd829d2cd3..79d97e63e758 100644 --- a/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp +++ b/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp @@ -127,8 +127,19 @@ namespace Mantid { if (analysis_mode == "PointDetectorAnalysis") { - const int detStart = static_cast(instrument->getNumberParameter("PointDetectorStart")[0]); - const int detStop = static_cast(instrument->getNumberParameter("PointDetectorStop")[0]); + std::vector pointStart = instrument->getNumberParameter("PointDetectorStart"); + std::vector pointStop = instrument->getNumberParameter("PointDetectorStop"); + + if(pointStart.empty() || pointStop.empty()) + throw std::runtime_error( + "If ProcessingInstructions is not specified, BOTH PointDetectorStart " + "and PointDetectorStop must exist as instrument parameters.\n" + "Please check if you meant to enter ProcessingInstructions or " + "if your instrument parameter file is correct." + ); + + const int detStart = static_cast(pointStart[0]); + const int detStop = static_cast(pointStop[0]); if(detStart == detStop) { @@ -143,7 +154,15 @@ namespace Mantid } else { - processing_commands = boost::lexical_cast(static_cast(instrument->getNumberParameter("MultiDetectorStart")[0])) + std::vector multiStart = instrument->getNumberParameter("MultiDetectorStart"); + if(multiStart.empty()) + throw std::runtime_error( + "If ProcessingInstructions is not specified, MultiDetectorStart" + "must exist as an instrument parameter.\n" + "Please check if you meant to enter ProcessingInstructions or " + "if your instrument parameter file is correct." + ); + processing_commands = boost::lexical_cast(static_cast(multiStart[0])) + ":" + boost::lexical_cast(in_ws->getNumberHistograms() - 1); } } From a62f3aba544d9210672cf19c02103e23bb794650 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 15:05:19 +0000 Subject: [PATCH 081/128] Fix failing doc tests Refs #10571 --- .../algorithms/InelasticIndirectReduction-v1.rst | 2 +- .../algorithms/MSGDiffractionReduction-v1.rst | 4 ++-- .../Mantid/docs/source/algorithms/TimeSlice-v1.rst | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Code/Mantid/docs/source/algorithms/InelasticIndirectReduction-v1.rst b/Code/Mantid/docs/source/algorithms/InelasticIndirectReduction-v1.rst index f21cb07071a9..f5290faa11a9 100644 --- a/Code/Mantid/docs/source/algorithms/InelasticIndirectReduction-v1.rst +++ b/Code/Mantid/docs/source/algorithms/InelasticIndirectReduction-v1.rst @@ -21,7 +21,7 @@ Usage .. testcode:: ExIRISReduction InelasticIndirectReduction(InputFiles='IRS21360.raw', - OutputWorkspaceGroup='IndirectReductions', + OutputWorkspace='IndirectReductions', Instrument='IRIS', Analyser='graphite', Reflection='002', diff --git a/Code/Mantid/docs/source/algorithms/MSGDiffractionReduction-v1.rst b/Code/Mantid/docs/source/algorithms/MSGDiffractionReduction-v1.rst index 9f0c82741e1a..de9bb0b693f6 100644 --- a/Code/Mantid/docs/source/algorithms/MSGDiffractionReduction-v1.rst +++ b/Code/Mantid/docs/source/algorithms/MSGDiffractionReduction-v1.rst @@ -19,12 +19,12 @@ Usage .. testcode:: ExMSGDiffractionReductionSimple MSGDiffractionReduction(InputFiles='IRS21360.raw', - OutputWorkspaceGroup='DiffOut', + OutputWorkspace='DiffractionReductions', Instrument='IRIS', Mode='diffspec', DetectorRange=[105,112]) - ws = mtd['DiffOut'].getItem(0) + ws = mtd['DiffractionReductions'].getItem(0) print 'Workspace name: %s' % ws.getName() print 'Number of spectra: %d' % ws.getNumberHistograms() diff --git a/Code/Mantid/docs/source/algorithms/TimeSlice-v1.rst b/Code/Mantid/docs/source/algorithms/TimeSlice-v1.rst index fa9cad85fb99..c5ae72713eb6 100644 --- a/Code/Mantid/docs/source/algorithms/TimeSlice-v1.rst +++ b/Code/Mantid/docs/source/algorithms/TimeSlice-v1.rst @@ -30,18 +30,18 @@ Usage **Example - Running TimeSlice** -.. testcode:: ExIndirectTransmissionSimple +.. testcode:: ExTimeSliceSimple - TimeSlice(InputFiles=['IRS26173.raw'], - SpectraRange=[3, 53], - PeakRange=[62500, 65000]) + time_slice_results = TimeSlice(InputFiles=['IRS26173.raw'], + SpectraRange=[3, 53], + PeakRange=[62500, 65000]) - print mtd.doesExist('irs26173_slice') + print time_slice_results.getNames() Output: -.. testoutput:: ExIndirectTransmissionSimple +.. testoutput:: ExTimeSliceSimple - True + ['irs26173_slice'] .. categories:: From 1954a3b2f26fe990126f91c6936fab13950bc627 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 15:09:31 +0000 Subject: [PATCH 082/128] Use invisible workspaces in ElasticWindowMultiple Refs #10409 --- .../algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py index 1e89c72c286b..991151668fc1 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py @@ -106,8 +106,8 @@ def PyExec(self): for input_ws in input_workspace_names: logger.information('Running ElasticWindow for workspace: %s' % input_ws) - q_ws = input_ws + '_q' - q2_ws = input_ws + '_q2' + q_ws = '__' + input_ws + '_q' + q2_ws = '__' + input_ws + '_q2' if self._range_2_start != '' and self._range_2_end != '': ElasticWindow(InputWorkspace=input_ws, OutputInQ=q_ws, OutputInQSquared=q2_ws, From 7dcdc9e861f5bb4a5dbefeadf34eb2ceb9cc01f5 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Tue, 18 Nov 2014 15:52:18 +0000 Subject: [PATCH 083/128] Added ElasticWindowMultiple docs Refs #10409 --- .../algorithms/ElasticWindowMultiple-v1.rst | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Code/Mantid/docs/source/algorithms/ElasticWindowMultiple-v1.rst diff --git a/Code/Mantid/docs/source/algorithms/ElasticWindowMultiple-v1.rst b/Code/Mantid/docs/source/algorithms/ElasticWindowMultiple-v1.rst new file mode 100644 index 000000000000..1c3bd36354fe --- /dev/null +++ b/Code/Mantid/docs/source/algorithms/ElasticWindowMultiple-v1.rst @@ -0,0 +1,22 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +This algorithm performs the ElasticWindow algorithm over a set of workspaces +provided as a workspace group, the binning of each workspace must match. + +The Q and Q Suared output workspaces show the output of ElasticWindow for each +input workspace, the ELF workspace shows the data transposed with the X axis in +either sample temperature or run number of temperature is not available. + +The ELT workspace shows the normalisation of the ELF workspace to run with the +lowest sample temperature. + +.. categories:: From 45bf269464f86075d1b1c4f333f1eb89b7de5384 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Nov 2014 16:46:07 +0000 Subject: [PATCH 084/128] Refs #10563 Christen the new Refl UI --- .../MantidQtCustomInterfaces/QtReflMainView.h | 2 +- .../ReflMainWidget.ui | 20 +------------------ .../source/interfaces/ISIS_Reflectometry.rst | 6 +++--- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h index e13b25b0b271..3b0cd9337c0b 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h @@ -46,7 +46,7 @@ namespace MantidQt virtual ~QtReflMainView(); /// Name of the interface - static std::string name() { return "New ISIS Reflectometry (Prototype)"; } + static std::string name() { return "ISIS Reflectometry (Polref)"; } // This interface's categories. static QString categoryInfo() { return "Reflectometry"; } diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui index e712337f6a78..b7f3b8cc187f 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainWidget.ui @@ -11,31 +11,13 @@ - ISIS Reflectometry + ISIS Reflectometry (Polref) 1 - - - - - 12 - 75 - true - false - - - - PROTOTYPE - - - Qt::AlignCenter - - - diff --git a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst index e0a2f47665d9..dce062b2e9f4 100644 --- a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst +++ b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst @@ -1,7 +1,7 @@ -ISIS Reflectometry Interface -============================ +ISIS Reflectometry (Polref) Interface +===================================== -.. interface:: New ISIS Reflectometry (Prototype) +.. interface:: ISIS Reflectometry (Polref) Menu bar -------- From c9b534090547f826d802647dc656e2f08643477f Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Tue, 18 Nov 2014 16:59:07 +0000 Subject: [PATCH 085/128] Refs #10563 Insert TOC manually --- .../docs/source/interfaces/ISIS_Reflectometry.rst | 3 +++ .../sphinxext/mantiddoc/directives/interface.py | 13 +------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst index dce062b2e9f4..9341f517a51a 100644 --- a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst +++ b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst @@ -3,6 +3,9 @@ ISIS Reflectometry (Polref) Interface .. interface:: ISIS Reflectometry (Polref) +.. contents:: Table of Contents + :local: + Menu bar -------- diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py index 745037ffa554..25a1a8d6559c 100644 --- a/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py @@ -5,11 +5,7 @@ class InterfaceDirective(BaseDirective): """ - Inserts details of a custom interface - - Adds: - - A screenshot of the interface - - Table of contents + Adds a screenshot of the custom interface It requires a SCREENSHOTS_DIR environment variable to be set to the directory where a screenshot should be generated. If it is not set then @@ -36,18 +32,11 @@ def execute(self): """ picture = self._create_screenshot() self._insert_screenshot_link(picture) - self._insert_toc() return [] def interface_name(self): return self.arguments[0] - def _insert_toc(self): - """ - Outputs a title for the page - """ - self.add_rst(".. contents:: Table of Contents\n :local:\n") - def _create_screenshot(self): """ Creates a screenshot for the named interface in the "images/screenshots" From 74561d71994931663b066d387486aa215ffc77ae Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Wed, 19 Nov 2014 09:09:51 +0000 Subject: [PATCH 086/128] Refs #10563 Add "widget" option to interface directive This option allows you to specify a widget's name to screenshot just that widget. --- .../docs/sphinxext/mantiddoc/directives/interface.py | 7 ++++--- Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py | 9 +++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py index 25a1a8d6559c..91f983e68757 100644 --- a/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py @@ -13,6 +13,7 @@ class InterfaceDirective(BaseDirective): """ required_arguments, optional_arguments = 1, 0 + option_spec = {"widget" : str} def run(self): """ @@ -30,14 +31,14 @@ def execute(self): """ Called by Sphinx when the ..interface:: directive is encountered """ - picture = self._create_screenshot() + picture = self._create_screenshot(widget_name = self.options.get("widget", None)) self._insert_screenshot_link(picture) return [] def interface_name(self): return self.arguments[0] - def _create_screenshot(self): + def _create_screenshot(self, widget_name = None): """ Creates a screenshot for the named interface in the "images/screenshots" subdirectory. @@ -58,7 +59,7 @@ def _create_screenshot(self): os.makedirs(screenshots_dir) try: - picture = custominterface_screenshot(self.interface_name(), screenshots_dir) + picture = custominterface_screenshot(self.interface_name(), screenshots_dir, widget_name = widget_name) except RuntimeError, exc: env = self.state.document.settings.env env.warn(env.docname, "Unable to generate screenshot for '%s' - %s" % (self.interface_name(), str(exc))) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py b/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py index 7d5a2801e1b3..e034b434ce0e 100644 --- a/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py +++ b/Code/Mantid/docs/sphinxext/mantiddoc/tools/screenshot.py @@ -60,7 +60,7 @@ def algorithm_screenshot(name, directory, version = -1, ext = ".png"): #-------------------------------------------------------------------------- -def custominterface_screenshot(name, directory, ext = ".png"): +def custominterface_screenshot(name, directory, ext = ".png", widget_name = None): """ Takes a snapshot of a custom interface and saves it as an image named "name.png" @@ -79,11 +79,16 @@ def custominterface_screenshot(name, directory, ext = ".png"): import mantidqtpython as mantidqt from mantidplot import threadsafe_call + from PyQt4.QtGui import QWidget iface_mgr = mantidqt.MantidQt.API.InterfaceManager() # threadsafe_call required for MantidPlot dlg = threadsafe_call(iface_mgr.createSubWindow, name, None) - picture = Screenshot(dlg, name.replace(' ','_') + "_interface" + ext, directory) + if widget_name: + widget = dlg.findChild(QWidget, widget_name) + picture = Screenshot(widget, name.replace(' ','_') + "_" + widget_name + "_widget" + ext, directory) + else: + picture = Screenshot(dlg, name.replace(' ','_') + "_interface" + ext, directory) threadsafe_call(dlg.close) return picture From 457ef303bbabd0679c4257b6690932c20123ea7a Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Wed, 19 Nov 2014 09:41:20 +0000 Subject: [PATCH 087/128] Refs #10563 Support custom alignment --- .../mantiddoc/directives/interface.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py index 91f983e68757..139ac69bf973 100644 --- a/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/interface.py @@ -13,7 +13,7 @@ class InterfaceDirective(BaseDirective): """ required_arguments, optional_arguments = 1, 0 - option_spec = {"widget" : str} + option_spec = {"widget" : str, "align" : str} def run(self): """ @@ -32,7 +32,7 @@ def execute(self): Called by Sphinx when the ..interface:: directive is encountered """ picture = self._create_screenshot(widget_name = self.options.get("widget", None)) - self._insert_screenshot_link(picture) + self._insert_screenshot_link(picture, align = self.options.get("align", None)) return [] def interface_name(self): @@ -67,7 +67,7 @@ def _create_screenshot(self, widget_name = None): return picture - def _insert_screenshot_link(self, picture): + def _insert_screenshot_link(self, picture, align = None): """ Outputs an image link with a custom :class: style. The filename is extracted from the path given and then a relative link to the @@ -76,13 +76,16 @@ def _insert_screenshot_link(self, picture): Args: picture (Screenshot): A Screenshot object + align: The alignment to use, None for block, "left" or "right" for flowing """ env = self.state.document.settings.env format_str = ".. figure:: %s\n"\ " :class: screenshot\n"\ - " :width: %dpx\n"\ - " :align: left\n\n"\ - " %s\n\n" + " :width: %dpx" + if align != None: + format_str += "\n :align: " + align + + format_str += "\n\n" # Sphinx assumes that an absolute path is actually relative to the directory containing the # conf.py file and a relative path is relative to the directory where the current rst file @@ -103,8 +106,7 @@ def _insert_screenshot_link(self, picture): path = "/images/ImageNotFound.png" width = 200 - caption = "**" + self.interface_name() + "** interface." - self.add_rst(format_str % (path, width, caption)) + self.add_rst(format_str % (path, width)) def _screenshot_directory(self): """ From b082d34f649a8a6ae70753619536166498758bc6 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Wed, 19 Nov 2014 09:41:47 +0000 Subject: [PATCH 088/128] Refs #10563 Use widget screenshots in Refl UI docs --- .../source/interfaces/ISIS_Reflectometry.rst | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst index 9341f517a51a..d2b6fdf95de9 100644 --- a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst +++ b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst @@ -2,6 +2,7 @@ ISIS Reflectometry (Polref) Interface ===================================== .. interface:: ISIS Reflectometry (Polref) + :align: left .. contents:: Table of Contents :local: @@ -24,6 +25,10 @@ pertaining to the processing table. Search Interface ---------------- +.. interface:: ISIS Reflectometry (Polref) + :widget: groupSearchPane + :align: right + To search for runs, select the instrument the runs are from, enter the id of the investigation the runs are part of, and hit *Search*. @@ -51,11 +56,15 @@ behaviour of this is as follows: Processing Table ---------------- +.. interface:: ISIS Reflectometry (Polref) + :widget: groupProcessPane + The processing table is where the bulk of the work takes place. It is used to specify which runs to process, the parameters that should be used to process them, and how the different runs should be joined together. Above the processing table is a tool bar providing a number of useful actions. + Below the table is a progress bar, showing the current progress of any processing that is taking place, and a processing instrument selector. The processing instrument is used by the interface to help load the correct @@ -64,6 +73,11 @@ files from disk when processing. Actions ~~~~~~~ +This table details the behaviour of the actions in the tool bar, from left to right. + +.. interface:: ISIS Reflectometry (Polref) + :widget: rowToolBar + .. WARNING If you're updating this documentation, you probably also want to update the "What's This" tips in ReflMainWidget.ui +------------------+----------------------------------------------------------+ @@ -97,11 +111,11 @@ Actions | Clear Rows | Resets the cells in any selected rows to their initial | | | value, in other words, blank. | +------------------+----------------------------------------------------------+ +| Help | Opens this documentation for viewing. | ++------------------+----------------------------------------------------------+ | Whats This | Provides guidance on what various parts of the interface | | | are for. | +------------------+----------------------------------------------------------+ -| Help | Opens this documentation for viewing. | -+------------------+----------------------------------------------------------+ Columns ~~~~~~~ From db6bc62a4b87370add42653f06363f7839d9a9bd Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Wed, 19 Nov 2014 10:14:32 +0000 Subject: [PATCH 089/128] A few typo corrections Refs #10409 --- .../algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py index 991151668fc1..15b4176c1d33 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py @@ -135,7 +135,7 @@ def PyExec(self): if len(q_workspaces) < 2: raise RuntimeError('Have less than 2 result workspaces in Q') if len(q2_workspaces) < 2: - raise RuntimeError('Hvae less than 2 result workspaces in Q^2') + raise RuntimeError('Have less than 2 result workspaces in Q^2') logger.information('Creating Q and Q^2 workspaces') @@ -194,7 +194,7 @@ def PyExec(self): if self._elt_workspace != '': logger.information('Creating ELT workspace') - # If the ELT workspace wqas not already created then crate it here, otherwise just clone it + # If the ELT workspace was not already created then create it here, otherwise just clone it if self._elf_workspace == '': Transpose(InputWorkspace=self._q_workspace, OutputWorkspace=self._elt_workspace) SortXAxis(InputWorkspace=self._elt_workspace, OutputWorkspace=self._elt_workspace) From 8f38811a9c7c6d697a9299d7d2e6850c21115ef4 Mon Sep 17 00:00:00 2001 From: Roman Tolchenov Date: Wed, 19 Nov 2014 10:19:18 +0000 Subject: [PATCH 090/128] Re #10545. Integrate other types of matrix workspaces. --- .../inc/MantidMDAlgorithms/IntegrateFlux.h | 17 +- .../MDAlgorithms/src/IntegrateFlux.cpp | 365 +++++++++++++++++- .../MDAlgorithms/test/IntegrateFluxTest.h | 364 +++++++++++++---- 3 files changed, 654 insertions(+), 92 deletions(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegrateFlux.h b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegrateFlux.h index 0b652515c80f..1403cc64a210 100644 --- a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegrateFlux.h +++ b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegrateFlux.h @@ -7,6 +7,11 @@ namespace Mantid { +namespace API +{ + class MatrixWorkspace; +} + namespace DataObjects { class EventWorkspace; @@ -18,7 +23,6 @@ namespace MDAlgorithms /** Algorithm IntegrateFlux. Calculates indefinite integral of the spectra in the input workspace sampled at a regular grid. - The input workspace is expected to be an event workspace with weighted-no-time events. Copyright © 2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory @@ -53,8 +57,15 @@ namespace MDAlgorithms void init(); void exec(); - boost::shared_ptr createOutputWorkspace( const DataObjects::EventWorkspace& eventWS, size_t nX ) const; - void integrateSpectra( const DataObjects::EventWorkspace& eventWS, API::MatrixWorkspace &integrWS ); + boost::shared_ptr createOutputWorkspace( const API::MatrixWorkspace& inputWS, size_t nX ) const; + void integrateSpectra( const API::MatrixWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const; + template + void integrateSpectraEvents( const DataObjects::EventWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const; + void integrateSpectraMatrix( const API::MatrixWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const; + void integrateSpectraHistograms( const API::MatrixWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const; + void integrateSpectraPointData( const API::MatrixWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const; + + size_t getMaxNumberOfPoints( const API::MatrixWorkspace& inputWS ) const; }; diff --git a/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp b/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp index 65f7469307f3..1ef4802b4f1e 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp @@ -5,6 +5,7 @@ #include "MantidKernel/BoundedValidator.h" #include +#include namespace Mantid { @@ -24,7 +25,7 @@ class NoEventWorkspaceDeleting { public: /// deleting operator. Does nothing - void operator()(const DataObjects::EventWorkspace*){} + void operator()(const API::MatrixWorkspace*){} }; } @@ -48,7 +49,7 @@ class NoEventWorkspaceDeleting */ void IntegrateFlux::init() { - declareProperty(new WorkspaceProperty("InputWorkspace","",Direction::Input), "An input workspace."); + declareProperty(new WorkspaceProperty("InputWorkspace","",Direction::Input), "An input workspace."); auto validator = boost::make_shared>(); validator->setLower(2); declareProperty("NPoints", 1000, validator, "Number of points per output spectrum."); @@ -60,7 +61,7 @@ class NoEventWorkspaceDeleting */ void IntegrateFlux::exec() { - DataObjects::EventWorkspace_sptr inputWS = getProperty("InputWorkspace"); + API::MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); size_t nX = static_cast( (int)getProperty("NPoints") ); auto outputWS = createOutputWorkspace( *inputWS, nX ); @@ -72,12 +73,12 @@ class NoEventWorkspaceDeleting /** * Create an empty output workspace with required dimensions and defined x-values - * @param eventWS :: The input event workspace. + * @param inputWS :: The input event workspace. * @param nX :: Suggested size of the output spectra. It can change in the actual output. */ - boost::shared_ptr IntegrateFlux::createOutputWorkspace( const DataObjects::EventWorkspace& eventWS, size_t nX ) const + boost::shared_ptr IntegrateFlux::createOutputWorkspace( const API::MatrixWorkspace& inputWS, size_t nX ) const { - size_t nSpec = eventWS.getNumberHistograms(); + size_t nSpec = inputWS.getNumberHistograms(); if ( nSpec == 0 ) { @@ -85,10 +86,10 @@ class NoEventWorkspaceDeleting } // make sure the output spectrum size isn't too large - auto nEvents = eventWS.getEventList(0).getNumberEvents(); - if ( nX > nEvents ) + auto maxPoints = getMaxNumberOfPoints(inputWS); + if ( nX > maxPoints ) { - nX = nEvents; + nX = maxPoints; } // and not 0 or 1 as they are to be used for interpolation @@ -100,12 +101,12 @@ class NoEventWorkspaceDeleting // crate empty output workspace API::MatrixWorkspace_sptr ws = API::WorkspaceFactory::Instance().create( - boost::shared_ptr(&eventWS,NoEventWorkspaceDeleting()), + boost::shared_ptr(&inputWS,NoEventWorkspaceDeleting()), nSpec, nX, nX ); // claculate the integration points and save them in the x-vactors of integrFlux - double xMin = eventWS.getEventXMin(); - double xMax = eventWS.getEventXMax(); + double xMin = inputWS.getXMin(); + double xMax = inputWS.getXMax(); double dx = ( xMax - xMin ) / static_cast( nX - 1 ); auto &X = ws->dataX(0); auto ix = X.begin(); @@ -125,27 +126,60 @@ class NoEventWorkspaceDeleting return ws; } + /** + * Integrate spectra in inputWS at x-values in integrWS and save the results in y-vectors of integrWS. + * @param inputWS :: A workspace to integrate. The events have to be weighted-no-time. + * @param integrWS :: A workspace to store the results. + */ + void IntegrateFlux::integrateSpectra( const API::MatrixWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const + { + auto eventWS = dynamic_cast( &inputWS ); + + if ( eventWS ) + { + auto eventType = eventWS->getEventType(); + switch( eventType ) + { + case(API::WEIGHTED_NOTIME): + integrateSpectraEvents( *eventWS, integrWS ); + return; + case(API::WEIGHTED): + integrateSpectraEvents( *eventWS, integrWS ); + return; + case(API::TOF): + integrateSpectraEvents( *eventWS, integrWS ); + return; + } + } + else + { + integrateSpectraMatrix( inputWS, integrWS ); + } + } + /** * Integrate spectra in eventWS at x-values in integrWS and save the results in y-vectors of integrWS. - * @param eventWS :: A workspace to integrate. The events have to be weighted-no-time. + * @param inputWS :: An event workspace to integrate. * @param integrWS :: A workspace to store the results. */ - void IntegrateFlux::integrateSpectra( const DataObjects::EventWorkspace& eventWS, API::MatrixWorkspace &integrWS ) + template + void IntegrateFlux::integrateSpectraEvents( const DataObjects::EventWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const { - size_t nSpec = eventWS.getNumberHistograms(); + size_t nSpec = inputWS.getNumberHistograms(); assert( nSpec == integrWS.getNumberHistograms() ); auto &X = integrWS.readX(0); // loop overr the spectra and integrate for(size_t sp = 0; sp < nSpec; ++sp) { - std::vector el = eventWS.getEventList(sp).getWeightedEventsNoTime(); + const std::vector* el; + DataObjects::getEventsFrom( inputWS.getEventList(sp), el ); auto &outY = integrWS.dataY(sp); double sum = 0; auto x = X.begin() + 1; size_t i = 1; // the integral is a running sum of the event weights in the spectrum - for(auto evnt = el.begin(); evnt != el.end(); ++evnt) + for(auto evnt = el->begin(); evnt != el->end(); ++evnt) { double tof = evnt->tof(); while( x != X.end() && *x < tof ) @@ -160,5 +194,302 @@ class NoEventWorkspaceDeleting } } + /** + * Integrate spectra in eventWS at x-values in integrWS and save the results in y-vectors of integrWS. + * @param inputWS :: A 2d workspace to integrate. + * @param integrWS :: A workspace to store the results. + */ + void IntegrateFlux::integrateSpectraMatrix( const API::MatrixWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const + { + bool isHistogram = inputWS.isHistogramData(); + + if ( isHistogram ) + { + integrateSpectraHistograms( inputWS, integrWS ); + } + else + { + integrateSpectraPointData( inputWS, integrWS ); + } + } + + /** + * Integrate spectra in eventWS at x-values in integrWS and save the results in y-vectors of integrWS. + * @param inputWS :: A 2d workspace to integrate. + * @param integrWS :: A workspace to store the results. + */ + void IntegrateFlux::integrateSpectraHistograms( const API::MatrixWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const + { + size_t nSpec = inputWS.getNumberHistograms(); + assert( nSpec == integrWS.getNumberHistograms() ); + + bool isDistribution = inputWS.isDistribution(); + + auto &X = integrWS.readX(0); + + // loop overr the spectra and integrate + for(size_t sp = 0; sp < nSpec; ++sp) + { + auto &inX = inputWS.dataX(sp); + auto inY = inputWS.dataY(sp); // make a copy + + // if it's a distribution y's must be multiplied by the bin widths + if ( isDistribution ) + { + std::vector xDiff( inX.size() ); + std::adjacent_difference( inX.begin(), inX.end(), xDiff.begin() ); + std::transform( xDiff.begin() + 1, xDiff.end(), inY.begin(), inY.begin(), std::multiplies() ); + } + + // integral at the first point is always 0 + auto outY = integrWS.dataY(sp).begin(); + *outY = 0.0; + ++outY; + // initialize summation + double sum = 0; + // cache some iterators + auto inXbegin = inX.begin(); + auto inXend = inX.end(); + auto inYbegin = inY.begin(); + auto x0 = inXbegin; // iterator over x in input workspace + // loop over the iteration points starting from the second one + for(auto outX = X.begin()+1; outX != X.end(); ++outX,++outY) + { + // there are no data to integrate + if ( x0 == inXend ) + { + *outY = sum; + continue; + } + + // in each iteration we find the integral of the input spectrum + // between bounds [lowerBound,upperBound] + const double& lowerBound = *(outX - 1); + double upperBound = *outX; + + // interval [*x0, *x1] is the smalest interval in inX that contains + // the integration interval [lowerBound,upperBound] + auto x1 = std::lower_bound( x0, inXend, upperBound ); + + // reached end of input data + if ( x1 == inXend ) + { + --x1; + if ( x1 == x0 ) + { + *outY = sum; + x0 = inXend; + continue; + } + upperBound = *x1; + } + + // if starting point in input x is smaller (not equal) than the lower integration bound + // then there is a partial bin at the beginning of the interval + if ( *x0 < lowerBound ) + { + // first find the part of bin [*x0,*(x0+1)] which hasn't been integrated yet + // the left boundary == lowerBound + // the right boundary == min( upperBound, *(x0+1) ) + const double leftX = lowerBound; + const double rightX = std::min( upperBound, *(x0 + 1) ); + + auto i = static_cast( std::distance( inXbegin, x0 ) ); + // add bin's fraction between leftX and rightX + sum += inY[i] * (rightX - leftX) / (*(x0+1) - *x0); + + // if rightX == upperBound there is nothing left to integrate, move to the next integration point + if ( rightX == upperBound ) + { + *outY = sum; + continue; + } + + ++x0; + } + + // accumulate values in bins that fit entirely into the integration interval [lowerBound,upperBound] + auto i0 = static_cast( std::distance( inXbegin, x0 ) ); + auto i1 = static_cast( std::distance( inXbegin, x1 ) ); + if ( *x1 > upperBound ) --i1; + for(auto i = i0; i < i1; ++i) + { + sum += inY[i]; + } + + // if x1 is greater than upperBound there is a partial "bin" that has to be added + if ( *x1 > upperBound ) + { + // find the part of "bin" [*(x1-1),*x1] which needs to be integrated + // the left boundary == *(x1-1) + // the right boundary == upperBound + const double leftX = *(x1-1); + const double rightX = upperBound; + + auto i = static_cast( std::distance( inXbegin, x1 ) ); + // add the area under the line between leftX and rightX + sum += inY[i-1] * (rightX - leftX) / (*x1 - *(x1-1)); + + // advance in the input workspace + x0 = x1 - 1; + } + else + { + // advance in the input workspace + x0 = x1; + } + + // store the current sum + *outY = sum; + } + } + } + + /** + * Integrate spectra in eventWS at x-values in integrWS and save the results in y-vectors of integrWS. + * @param inputWS :: A 2d workspace to integrate. + * @param integrWS :: A workspace to store the results. + */ + void IntegrateFlux::integrateSpectraPointData( const API::MatrixWorkspace& inputWS, API::MatrixWorkspace &integrWS ) const + { + size_t nSpec = inputWS.getNumberHistograms(); + assert( nSpec == integrWS.getNumberHistograms() ); + + auto &X = integrWS.dataX(0); + + // loop overr the spectra and integrate + for(size_t sp = 0; sp < nSpec; ++sp) + { + auto &inX = inputWS.readX(sp); + auto &inY = inputWS.readY(sp); + + // integral at the first point is always 0 + auto outY = integrWS.dataY(sp).begin(); + *outY = 0.0; + ++outY; + // initialize summation + double sum = 0; + // cache some iterators + auto inXbegin = inX.begin(); + auto inXend = inX.end(); + auto inYbegin = inY.begin(); + auto x0 = inXbegin; // iterator over x in input workspace + + // loop over the iteration points starting from the second one + for(auto outX = X.begin()+1; outX != X.end(); ++outX,++outY) + { + // there are no data to integrate + if ( x0 == inXend ) + { + *outY = sum; + continue; + } + + // in each iteration we find the integral of the input spectrum + // between bounds [lowerBound,upperBound] + const double& lowerBound = *(outX - 1); + double upperBound = *outX; + + // interval [*x0, *x1] is the smalest interval in inX that contains + // the integration interval [lowerBound,upperBound] + auto x1 = std::lower_bound( x0, inXend, upperBound ); + + // reached end of input data + if ( x1 == inXend ) + { + --x1; + if ( x1 == x0 ) + { + *outY = sum; + x0 = inXend; + continue; + } + upperBound = *x1; + } + + // if starting point in input x is smaller (not equal) than the lower integration bound + // then there is a partial "bin" at the beginning of the interval + if ( *x0 < lowerBound ) + { + // first find the part of "bin" [*x0,*(x0+1)] which hasn't been integrated yet + // the left boundary == lowerBound + // the right boundary == min( upperBound, *(x0+1) ) + const double leftX = lowerBound; + const double rightX = std::min( upperBound, *(x0 + 1) ); + + auto i = static_cast( std::distance( inXbegin, x0 ) ); + // gradient of "bin" [*x0,*(x0+1)] + double dy_dx = (inY[i + 1] - inY[i]) / (*(x0+1) - *x0); + + // add the area under the line between leftX and rightX + sum += ( inY[i] + 0.5 * dy_dx *(leftX + rightX - 2 * (*(x0))) ) * (rightX - leftX); + + // if rightX == upperBound there is nothing left to integrate, move to the next integration point + if ( rightX == upperBound ) + { + *outY = sum; + continue; + } + + ++x0; + } + + // accumulate values in bins that fit entirely into the integration interval [lowerBound,upperBound] + auto i0 = static_cast( std::distance( inXbegin, x0 ) ); + auto i1 = static_cast( std::distance( inXbegin, x1 ) ); + if ( *x1 > upperBound ) --i1; + + for(auto i = i0; i < i1; ++i) + { + sum += (inY[i] + inY[i+1])/2 * (inX[i+1] - inX[i]); + } + + // if x1 is greater than upperBound there is a partial "bin" that has to be added + if ( *x1 > upperBound ) + { + // find the part of "bin" [*(x1-1),*x1] which needs to be integrated + // the left boundary == *(x1-1) + // the right boundary == upperBound + const double leftX = *(x1-1); + const double rightX = upperBound; + + auto i = static_cast( std::distance( inXbegin, x1 ) ); + // gradient of "bin" [*(x1-1),*x1] + double dy_dx = (inY[i] - inY[i - 1]) / (*x1 - *(x1-1)); + + // add the area under the line between leftX and rightX + sum += ( inY[i-1] + 0.5 * dy_dx *(rightX - *(x1-1)) ) * (rightX - leftX); + + // advance in the input workspace + x0 = x1 - 1; + } + else + { + // advance in the input workspace + x0 = x1; + } + + // store the current sum + *outY = sum; + } + } + } + + /** + * Calculate the maximun number of points in the integration grid. + * @param inputWS :: An input workspace. + */ + size_t IntegrateFlux::getMaxNumberOfPoints( const API::MatrixWorkspace& inputWS ) const + { + // if it's events we shouldn't care about binning + auto eventWS = dynamic_cast( &inputWS ); + if ( eventWS ) + { + return eventWS->getEventList(0).getNumberEvents(); + } + + return inputWS.blocksize(); + } + } // namespace MDAlgorithms } // namespace Mantid \ No newline at end of file diff --git a/Code/Mantid/Framework/MDAlgorithms/test/IntegrateFluxTest.h b/Code/Mantid/Framework/MDAlgorithms/test/IntegrateFluxTest.h index ec5e88feb910..110e4946c35e 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/IntegrateFluxTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/IntegrateFluxTest.h @@ -5,10 +5,68 @@ #include "MantidMDAlgorithms/IntegrateFlux.h" #include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/WorkspaceFactory.h" + +#include using Mantid::MDAlgorithms::IntegrateFlux; using namespace Mantid::API; +namespace +{ + enum WorkspaceType { Tof, Weighted, WeightedNoTime, Histogram, HistogramNonUniform, Distribution, PointData, PointDataNonUniform }; + + struct TestingFunction + { + const MatrixWorkspace& workspace; + WorkspaceType type; + const double dx; + TestingFunction(const MatrixWorkspace& ws, WorkspaceType t): + workspace(ws), + type(t), + dx((ws.getXMax()-ws.getXMin())/ws.blocksize()) + {} + double operator()(double x) const + { + switch(type) + { + case PointData: + case PointDataNonUniform: + return x * x + x; + case Distribution: + return x * x / dx; + case HistogramNonUniform: + { + double res = 0.0; + auto& X = workspace.readX(0); + auto& Y = workspace.readY(0); + auto ix = std::lower_bound( X.begin(), X.end(), x ); + if ( ix != X.end() ) + { + if ( x < *ix ) + { + --ix; + auto i = static_cast(std::distance( X.begin(), ix )); + res = Y[i] * (x - *ix) / (*(ix+1) - *ix); + } + } + else + { + --ix; + } + auto i = static_cast(std::distance( X.begin(), ix )); + res += std::accumulate( Y.begin(), Y.begin() + i, 0.0 ); + return res; + } + default: + x /= dx; + return x * x; + } + throw std::logic_error("Cannot test this workspace type."); + } + }; +} + class IntegrateFluxTest : public CxxTest::TestSuite { public: @@ -20,7 +78,6 @@ class IntegrateFluxTest : public CxxTest::TestSuite delete suite; } - void test_Init() { IntegrateFlux alg; @@ -28,7 +85,79 @@ class IntegrateFluxTest : public CxxTest::TestSuite TS_ASSERT( alg.isInitialized() ) } - void test_exec() + void test_weighted_no_time() + { + const size_t expectedNormalInterpolationSize = 98; + do_test_all(WeightedNoTime,expectedNormalInterpolationSize); + } + + void test_tof() + { + const size_t expectedNormalInterpolationSize = 1000; + do_test_all(Tof,expectedNormalInterpolationSize); + } + + void test_histogram() + { + size_t expectedNormalInterpolationSize = 100; + const double tolerance = 1e-3; + do_test_all(Histogram,expectedNormalInterpolationSize,tolerance); + expectedNormalInterpolationSize = do_test_normal_case(Histogram,tolerance,99); + TS_ASSERT_EQUALS( expectedNormalInterpolationSize, 99 ); + expectedNormalInterpolationSize = do_test_normal_case(Histogram,tolerance,30); + TS_ASSERT_EQUALS( expectedNormalInterpolationSize, 30 ); + } + + void test_histogram_non_uniform() + { + size_t expectedNormalInterpolationSize = 100; + const double tolerance = 1e-3; + do_test_all(HistogramNonUniform,expectedNormalInterpolationSize,tolerance); + expectedNormalInterpolationSize = do_test_normal_case(HistogramNonUniform,tolerance,99); + TS_ASSERT_EQUALS( expectedNormalInterpolationSize, 99 ); + expectedNormalInterpolationSize = do_test_normal_case(HistogramNonUniform,tolerance,30); + TS_ASSERT_EQUALS( expectedNormalInterpolationSize, 30 ); + } + + void test_distribution() + { + const size_t expectedNormalInterpolationSize = 100; + const double tolerance = 1e-3; + do_test_all(Distribution,expectedNormalInterpolationSize,tolerance); + } + + void test_point_data() + { + size_t expectedNormalInterpolationSize = 100; + const double tolerance = 1e-5; + do_test_all(PointData,expectedNormalInterpolationSize,tolerance); + expectedNormalInterpolationSize = do_test_normal_case(PointData,tolerance,99); + TS_ASSERT_EQUALS( expectedNormalInterpolationSize, 99 ); + } + + void test_point_data_non_uniform() + { + size_t expectedNormalInterpolationSize = 100; + const double tolerance = 1e-5; + do_test_all(PointDataNonUniform,expectedNormalInterpolationSize,tolerance); + expectedNormalInterpolationSize = do_test_normal_case(PointData,tolerance,99); + TS_ASSERT_EQUALS( expectedNormalInterpolationSize, 99 ); + expectedNormalInterpolationSize = do_test_normal_case(PointData,tolerance,30); + TS_ASSERT_EQUALS( expectedNormalInterpolationSize, 30 ); + } + +private: + + void do_test_all(WorkspaceType type, size_t normalInterpolationSize, double tolerance = 0.1) + { + do_test_one_interpolation_point(type); + auto n = do_test_normal_case(type,tolerance); + TS_ASSERT_EQUALS( n, normalInterpolationSize ); + n = do_test_normal_case(type,tolerance,2); + TS_ASSERT_EQUALS( n, 2 ); + } + + size_t do_test_normal_case(WorkspaceType wsType, double tolerance, int nPoints = 1000) { // Name of the input workspace. std::string inWSName("IntegrateFluxTest_InputWS"); @@ -36,13 +165,14 @@ class IntegrateFluxTest : public CxxTest::TestSuite std::string outWSName("IntegrateFluxTest_OutputWS"); // Create an input workspace - createInputWorkspace(inWSName); + createInputWorkspace(inWSName,wsType); IntegrateFlux alg; TS_ASSERT_THROWS_NOTHING( alg.initialize() ) TS_ASSERT( alg.isInitialized() ) TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InputWorkspace", inWSName) ); TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace", outWSName) ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("NPoints", nPoints) ); TS_ASSERT_THROWS_NOTHING( alg.execute(); ); TS_ASSERT( alg.isExecuted() ); @@ -50,7 +180,7 @@ class IntegrateFluxTest : public CxxTest::TestSuite MatrixWorkspace_sptr ws; TS_ASSERT_THROWS_NOTHING( ws = AnalysisDataService::Instance().retrieveWS(outWSName) ); TS_ASSERT(ws); - if (!ws) return; + if (!ws) return -1; auto inWS = AnalysisDataService::Instance().retrieveWS( inWSName ); @@ -60,59 +190,27 @@ class IntegrateFluxTest : public CxxTest::TestSuite auto &x = ws->readX(0); auto &y = ws->readY(0); - TS_ASSERT_EQUALS( x.size(), 98 ); - TS_ASSERT_EQUALS( x.size(), y.size() ); - - for(size_t i = 10; i < x.size(); ++i) + size_t n = x.size(); + TS_ASSERT_EQUALS( n, y.size() ); + TS_ASSERT_EQUALS( y.front(), 0.0 ); + + TestingFunction fun(*inWS,wsType); + size_t i0 = n * 20 / 100; + if ( i0 == 0 ) i0 = 1; + for(size_t i = i0; i < n; ++i) { - double t = x[i]; - TS_ASSERT_DELTA( t*(t+1.0) / y[i], 1.0, 0.1 ); + TS_ASSERT_DELTA( y[i] / fun(x[i]), 1.0, tolerance ); + //std::cerr << x[i] << ' ' << fun(x[i]) << ' ' << y[i] << ' ' << std::endl; } - // Remove workspace from the data service. - AnalysisDataService::Instance().clear(); - } - - void test_two_interpolation_point() - { - // Name of the input workspace. - std::string inWSName("IntegrateFluxTest_InputWS"); - // Name of the output workspace. - std::string outWSName("IntegrateFluxTest_OutputWS"); - - // Create an input workspace - createInputWorkspace(inWSName); - - IntegrateFlux alg; - alg.initialize(); - alg.setPropertyValue("InputWorkspace", inWSName); - alg.setPropertyValue("OutputWorkspace", outWSName); - alg.setProperty("NPoints", 2); - alg.execute(); - TS_ASSERT( alg.isExecuted() ); - - // Retrieve the workspace from data service. TODO: Change to your desired type - MatrixWorkspace_sptr ws; - TS_ASSERT_THROWS_NOTHING( ws = AnalysisDataService::Instance().retrieveWS(outWSName) ); - TS_ASSERT(ws); - if (!ws) return; - - TS_ASSERT_EQUALS( ws->getNumberHistograms(), 4 ); - - auto &x = ws->readX(0); - auto &y = ws->readY(0); - - TS_ASSERT_EQUALS( x.size(), y.size() ); - TS_ASSERT_EQUALS( x.size(), 2 ); - - double t = x[1]; - TS_ASSERT_DELTA( t*(t+1.0) / y[1], 1.0, 0.1 ); // Remove workspace from the data service. AnalysisDataService::Instance().clear(); + + return n; } - void test_one_interpolation_point() + void do_test_one_interpolation_point(WorkspaceType type) { // Name of the input workspace. std::string inWSName("IntegrateFluxTest_InputWS"); @@ -120,7 +218,7 @@ class IntegrateFluxTest : public CxxTest::TestSuite std::string outWSName("IntegrateFluxTest_OutputWS"); // Create an input workspace - createInputWorkspace(inWSName); + createInputWorkspace(inWSName,type); IntegrateFlux alg; alg.initialize(); @@ -132,30 +230,37 @@ class IntegrateFluxTest : public CxxTest::TestSuite AnalysisDataService::Instance().clear(); } - void test_bad_input_workspace() - { - // Name of the input workspace. - std::string inWSName("IntegrateFluxTest_InputWS"); - // Name of the output workspace. - std::string outWSName("IntegrateFluxTest_OutputWS"); - - // Create an input workspace - createBadInputWorkspace(inWSName); - - IntegrateFlux alg; - alg.initialize(); - alg.setRethrows(true); - alg.setPropertyValue("InputWorkspace", inWSName); - alg.setPropertyValue("OutputWorkspace", outWSName); - TS_ASSERT_THROWS( alg.execute(), std::runtime_error ); +private: - // Remove workspace from the data service. - AnalysisDataService::Instance().clear(); + void createInputWorkspace(const std::string& wsName, WorkspaceType type) + { + switch(type) + { + case WeightedNoTime: + createInputWorkspaceWeightedNoTime(wsName); + return; + case Tof: + createInputWorkspaceTOF(wsName); + return; + case Histogram: + createInputWorkspaceHistogram(wsName); + return; + case HistogramNonUniform: + createInputWorkspaceHistogramNonUniform(wsName); + return; + case Distribution: + createInputWorkspaceDistribution(wsName); + return; + case PointData: + createInputWorkspacePointData(wsName); + return; + case PointDataNonUniform: + createInputWorkspacePointDataNonUniform(wsName); + return; + }; } - -private: - void createInputWorkspace(const std::string& wsName) + void createInputWorkspaceWeightedNoTime(const std::string& wsName) { auto alg = Mantid::API::AlgorithmManager::Instance().create("CreateSampleWorkspace"); alg->initialize(); @@ -180,7 +285,7 @@ class IntegrateFluxTest : public CxxTest::TestSuite alg->execute(); } - void createBadInputWorkspace(const std::string& wsName) + void createInputWorkspaceTOF(const std::string& wsName) { auto alg = Mantid::API::AlgorithmManager::Instance().create("CreateSampleWorkspace"); alg->initialize(); @@ -198,6 +303,121 @@ class IntegrateFluxTest : public CxxTest::TestSuite alg->execute(); } + + void createInputWorkspaceHistogram(const std::string& wsName) + { + auto ws = Mantid::API::WorkspaceFactory::Instance().create( "Workspace2D", 4, 101, 100 ); + auto& x = ws->dataX(0); + x[0] = 0.0; + for(auto i = x.begin()+1; i != x.end(); ++i) + { + *i = *(i-1) + 0.3; + } + for(size_t spec = 0; spec != ws->getNumberHistograms(); ++spec) + { + ws->setX(spec,x); + auto& y = ws->dataY(spec); + for(auto j = y.begin(); j != y.end(); ++j) + { + auto i = std::distance( y.begin(), j ); + *j = double(2 * i) + 1.0; + } + } + Mantid::API::AnalysisDataService::Instance().addOrReplace(wsName,ws); + } + + void createInputWorkspaceHistogramNonUniform(const std::string& wsName) + { + auto ws = Mantid::API::WorkspaceFactory::Instance().create( "Workspace2D", 4, 101, 100 ); + auto& x = ws->dataX(0); + x[0] = 0.0; + for(auto i = x.begin()+1; i != x.end(); ++i) + { + double tmp = *(i-1); + *i = tmp * (1.0 + 0.0001 * tmp) + 0.3; + } + for(size_t spec = 0; spec != ws->getNumberHistograms(); ++spec) + { + ws->setX(spec,x); + auto& y = ws->dataY(spec); + for(auto j = y.begin(); j != y.end(); ++j) + { + auto i = std::distance( y.begin(), j ); + *j = double(2 * i) + 1.0; + } + } + Mantid::API::AnalysisDataService::Instance().addOrReplace(wsName,ws); + } + + void createInputWorkspaceDistribution(const std::string& wsName) + { + auto ws = Mantid::API::WorkspaceFactory::Instance().create( "Workspace2D", 4, 101, 100 ); + auto& x = ws->dataX(0); + x[0] = 0.0; + for(auto i = x.begin()+1; i != x.end(); ++i) + { + *i = *(i-1) + 0.3; + } + for(size_t spec = 0; spec != ws->getNumberHistograms(); ++spec) + { + ws->setX(spec,x); + auto& y = ws->dataY(spec); + for(auto j = y.begin(); j != y.end(); ++j) + { + auto i = std::distance( y.begin(), j ); + *j = double(2 * i) + 1.0; + } + //std::cerr << std::accumulate( y.begin(), y.end(), 0.0 ) << std::endl; + } + ws->isDistribution(true); + Mantid::API::AnalysisDataService::Instance().addOrReplace(wsName,ws); + } + + void createInputWorkspacePointData(const std::string& wsName) + { + auto ws = Mantid::API::WorkspaceFactory::Instance().create( "Workspace2D", 4, 100, 100 ); + auto& x = ws->dataX(0); + x[0] = 0.0; + for(auto i = x.begin()+1; i != x.end(); ++i) + { + *i = *(i-1) + 0.3; + } + for(size_t spec = 0; spec != ws->getNumberHistograms(); ++spec) + { + ws->setX(spec,x); + auto& y = ws->dataY(spec); + for(auto j = y.begin(); j != y.end(); ++j) + { + auto i = std::distance( y.begin(), j ); + *j = 2 * x[i] + 1.0; + } + } + Mantid::API::AnalysisDataService::Instance().addOrReplace(wsName,ws); + } + + void createInputWorkspacePointDataNonUniform(const std::string& wsName) + { + auto ws = Mantid::API::WorkspaceFactory::Instance().create( "Workspace2D", 4, 100, 100 ); + auto& x = ws->dataX(0); + x[0] = 0.0; + for(auto i = x.begin()+1; i != x.end(); ++i) + { + double tmp = *(i-1); + *i = tmp * (1.0 + 0.0001 * tmp) + 0.3; + } + for(size_t spec = 0; spec != ws->getNumberHistograms(); ++spec) + { + ws->setX(spec,x); + auto& y = ws->dataY(spec); + for(auto j = y.begin(); j != y.end(); ++j) + { + auto i = std::distance( y.begin(), j ); + *j = 2 * x[i] + 1.0; + } + } + Mantid::API::AnalysisDataService::Instance().addOrReplace(wsName,ws); + } + }; From 7662852e82970b8eed29510c21728d1c0ce1efc3 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Wed, 19 Nov 2014 10:20:23 +0000 Subject: [PATCH 091/128] Do not add mult marker to output WS Refs #10409 --- Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp index 4adc265c2df8..2a902b4225f8 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Elwin.cpp @@ -102,7 +102,7 @@ namespace IDA QFileInfo firstFileInfo(inputFilenames[0]); QString filename = firstFileInfo.baseName(); - QString workspaceBaseName = filename.left(filename.lastIndexOf("_")) + "_elwin-mult_"; + QString workspaceBaseName = filename.left(filename.lastIndexOf("_")) + "_elwin_"; QString qWorkspace = workspaceBaseName + "eq"; QString qSquaredWorkspace = workspaceBaseName + "eq2"; From d9fd7624af65b2d4f7037a1570ef96991febed08 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Wed, 19 Nov 2014 10:56:44 +0000 Subject: [PATCH 092/128] Refs #10563 Add example workflow to refl ui docs --- .../source/interfaces/ISIS_Reflectometry.rst | 76 +++++++++++++++++-- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst index d2b6fdf95de9..0a0bad429fbe 100644 --- a/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst +++ b/Code/Mantid/docs/source/interfaces/ISIS_Reflectometry.rst @@ -1,14 +1,16 @@ ISIS Reflectometry (Polref) Interface ===================================== -.. interface:: ISIS Reflectometry (Polref) - :align: left - .. contents:: Table of Contents :local: +Layout +------ + +.. interface:: ISIS Reflectometry (Polref) + Menu bar --------- +~~~~~~~~ At the top of the interface is a menu bar. Through this menu bar you can start a new table, open an existing table from a :ref:`workspace `, @@ -23,7 +25,7 @@ The menu bar also provides access to the options menu, and many actions pertaining to the processing table. Search Interface ----------------- +~~~~~~~~~~~~~~~~ .. interface:: ISIS Reflectometry (Polref) :widget: groupSearchPane @@ -54,7 +56,7 @@ behaviour of this is as follows: in the format, ``123+124+125``. Processing Table ----------------- +~~~~~~~~~~~~~~~~ .. interface:: ISIS Reflectometry (Polref) :widget: groupProcessPane @@ -196,7 +198,7 @@ Columns +---------------------+-----------+-----------------------------------------------+ Options -------- +~~~~~~~ Through the options menu, a small number of options may be configured to adjust the behaviour of the interface. @@ -215,7 +217,7 @@ the behaviour of the interface. | | asked if you're sure you that's what you intended to | | | do. | +-------------------------------+------------------------------------------------------+ -| Warn when discarding unsaved | If this is neabled and you try to open an existing | +| Warn when discarding unsaved | If this is enabled and you try to open an existing | | changes | table, or start a new table, with unsaved changes to | | | the current table, you will be asked if you're sure | | | you want to discard the current table. | @@ -227,6 +229,64 @@ the behaviour of the interface. | | decimal places. | +-------------------------------+------------------------------------------------------+ +Example Workflow +---------------- + +To follow this example you will need to ISIS reflectometry example materials: + +* ``INTER_NR_test2.tbl`` +* ``INTER00013460.nxs`` +* ``INTER00013462.nxs`` +* ``INTER00013463.nxs`` +* ``INTER00013464.nxs`` +* ``INTER00013469.nxs`` +* ``INTER00013470.nxs`` + +These can be downloaded as part of the `ISIS example data `. + +Once they are downloaded, place the nxs files in one of Mantid's user directories. +(To see a list of directories, click on *File -> Manager User Directories*) +The tbl file can be left anywhere you like, as long as you know where it is. + +You can then open MantidPlot, and open the ISIS Reflectometry (Polref) interface. +(*Interfaces -> Reflectometry -> ISIS Reflectometry (Polref)*) + +Within the interface, we first want to import the tbl file as a TableWorkspace. +To do this, go to *Reflectometry -> Import .TBL*. A :ref:`LoadReflTBL ` +dialog will open. Select ``INTER_NR_test2.tbl`` as the file, and enter ``MyTable`` +as the output workspace. + +A table workspace called ``MyTable`` should now exist in the :ref:`ADS `. +To open the table workspace go to *Reflectometry -> Open Table -> MyTable*. +The processing table (shown below) should now contain four rows (13460, 13462, 13469, 13470). + +.. interface:: ISIS Reflectometry (Polref) + :widget: viewTable + +We want to process the first two rows, which are in group 1. The simplest way to do this is +simply to select the two rows we want to process, and then press *Process*. If you receive +an error, consult the `_Troubleshooting` section of this document for guidance on fixing it. + +If the processing was successful, you should now have ten more workspaces in the ADS. + +Among them shall be: + +TOF_13460 + This is the data before processing. + +TRANS_13463_13464 + This is a transmission run, created by running :ref:`CreateTransmissionWorkspace ` + on ``TOF_13463`` and ``TOF_13464``. + +IvsQ_13460 + This is the output workspace of :ref:`ReflectometryReductionOneAuto `. + +IvsLam_13460 + This is the wavelength output workspace of :ref:`ReflectometryReductionOneAuto `. + +IvsQ_13460_13462 + This is the result of stitching ``IvsQ_13460`` and ``IvsQ_13462`` together using + :ref:`Stitch1D `. Troubleshooting --------------- From edd88dcf3eefb73d906aeee85e586fdb0ea69fe5 Mon Sep 17 00:00:00 2001 From: Roman Tolchenov Date: Wed, 19 Nov 2014 11:06:01 +0000 Subject: [PATCH 093/128] Re #10545. Removed IncreasingDataValidator. --- .../API/inc/MantidAPI/WorkspaceValidators.h | 38 ------------------- .../MDAlgorithms/src/IntegrateFlux.cpp | 8 ++-- .../Framework/MDAlgorithms/src/MDNormSXD.cpp | 1 - .../source/algorithms/IntegrateFlux-v1.rst | 4 -- 4 files changed, 4 insertions(+), 47 deletions(-) diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/WorkspaceValidators.h b/Code/Mantid/Framework/API/inc/MantidAPI/WorkspaceValidators.h index fbc3c24c4aec..ee9485b4d878 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/WorkspaceValidators.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/WorkspaceValidators.h @@ -369,44 +369,6 @@ class DLLExport IncreasingAxisValidator : public MatrixWorkspaceValidator } }; -//=============================================================================================== -/** - * A validator which checks whether data in each spectrum of the input workspace are monotonically increasing. - */ -class DLLExport IncreasingDataValidator : public MatrixWorkspaceValidator -{ -public: - ///Gets the type of the validator - std::string getType() const { return "increasingdata"; } - /// Clone the current state - Kernel::IValidator_sptr clone() const { return boost::make_shared(*this); } - -private: - /** Validate a workspace. - * @param value :: The workspace to test - * @return A message for users with negative results, otherwise "" - */ - std::string checkValidity( const MatrixWorkspace_sptr& value ) const - { - if ( value->blocksize() < 2 ) - { - return "Spectra must have two or more data points (bins)."; - } - for(size_t spec = 0; spec < value->getNumberHistograms(); ++spec) - { - auto &Y = value->readY( spec ); - double y = Y.front(); - for(auto it = Y.begin() + 1; it != Y.end(); ++it) - { - if ( y > *it ) return "Data in the workspace must monotonically increase."; - y = *it; - } - } - return ""; - } - -}; - } // namespace API } // namespace Mantid diff --git a/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp b/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp index 1ef4802b4f1e..b818998ee1ce 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp @@ -158,7 +158,7 @@ class NoEventWorkspaceDeleting } /** - * Integrate spectra in eventWS at x-values in integrWS and save the results in y-vectors of integrWS. + * Integrate spectra in inputWS at x-values in integrWS and save the results in y-vectors of integrWS. * @param inputWS :: An event workspace to integrate. * @param integrWS :: A workspace to store the results. */ @@ -195,7 +195,7 @@ class NoEventWorkspaceDeleting } /** - * Integrate spectra in eventWS at x-values in integrWS and save the results in y-vectors of integrWS. + * Integrate spectra in inputWS at x-values in integrWS and save the results in y-vectors of integrWS. * @param inputWS :: A 2d workspace to integrate. * @param integrWS :: A workspace to store the results. */ @@ -214,7 +214,7 @@ class NoEventWorkspaceDeleting } /** - * Integrate spectra in eventWS at x-values in integrWS and save the results in y-vectors of integrWS. + * Integrate spectra in inputWS at x-values in integrWS and save the results in y-vectors of integrWS. * @param inputWS :: A 2d workspace to integrate. * @param integrWS :: A workspace to store the results. */ @@ -346,7 +346,7 @@ class NoEventWorkspaceDeleting } /** - * Integrate spectra in eventWS at x-values in integrWS and save the results in y-vectors of integrWS. + * Integrate spectra in inputWS at x-values in integrWS and save the results in y-vectors of integrWS. * @param inputWS :: A 2d workspace to integrate. * @param integrWS :: A workspace to store the results. */ diff --git a/Code/Mantid/Framework/MDAlgorithms/src/MDNormSXD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/MDNormSXD.cpp index 49fa22981141..e45fd24c8665 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/MDNormSXD.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/MDNormSXD.cpp @@ -97,7 +97,6 @@ namespace MDAlgorithms fluxValidator->add(); fluxValidator->add(); auto solidAngleValidator = fluxValidator->clone(); - fluxValidator->add(); declareProperty(new WorkspaceProperty<>("FluxWorkspace","",Direction::Input,fluxValidator), "An input workspace containing integrated momentum dependent flux."); declareProperty(new WorkspaceProperty<>("SolidAngleWorkspace","",Direction::Input,solidAngleValidator), "An input workspace containing momentum integrated vanadium (a measure of the solid angle)."); diff --git a/Code/Mantid/docs/source/algorithms/IntegrateFlux-v1.rst b/Code/Mantid/docs/source/algorithms/IntegrateFlux-v1.rst index 82124878d83e..8fab83650ea9 100644 --- a/Code/Mantid/docs/source/algorithms/IntegrateFlux-v1.rst +++ b/Code/Mantid/docs/source/algorithms/IntegrateFlux-v1.rst @@ -15,8 +15,6 @@ the output workspace has its indefinite integral: :math:`\int_{x_0}^x f(\xi)d\xi`. -The input workspace is expected to be an event workspace with weighted-no-time events. - Usage ----- @@ -27,8 +25,6 @@ Usage # Create an event workspace ws = CreateSampleWorkspace("Event") - # Make evet type weighted-no-time. - ws = CompressEvents( ws ) # Integrate all spectra. wsOut = IntegrateFlux( ws ) From 53de00c25ba2f81de37e92db6684d1fa23d47d31 Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Wed, 19 Nov 2014 11:09:00 +0000 Subject: [PATCH 094/128] Revert "Refs #10570 Sum range of point detectors" This reverts commit ad9f36db421be98863d437e230d889bc1da009f0. --- .../Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp | 2 +- .../Algorithms/test/ReflectometryReductionOneAutoTest.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp b/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp index 79d97e63e758..b860eb3f7250 100644 --- a/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp +++ b/Code/Mantid/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp @@ -149,7 +149,7 @@ namespace Mantid else { //Otherwise, we create a range. - processing_commands = boost::lexical_cast(detStart) + "-" + boost::lexical_cast(detStop); + processing_commands = boost::lexical_cast(detStart) + ":" + boost::lexical_cast(detStop); } } else diff --git a/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h b/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h index fd16133be9c5..bcbef47502ae 100644 --- a/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h +++ b/Code/Mantid/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h @@ -349,7 +349,7 @@ class ReflectometryReductionOneAutoTest: public CxxTest::TestSuite std::string processingInstructions = findPropertyValue(vecPropertyHistories, "ProcessingInstructions"); std::vector pointDetectorStartStop; - boost::split(pointDetectorStartStop, processingInstructions, boost::is_any_of("-")); + boost::split(pointDetectorStartStop, processingInstructions, boost::is_any_of(":")); TS_ASSERT_EQUALS(inst->getNumberParameter("LambdaMin")[0], wavelengthMin); TS_ASSERT_EQUALS(inst->getNumberParameter("LambdaMax")[0], wavelengthMax); From ad32335d8faf6fcd88d6a31682e27e61aef2b580 Mon Sep 17 00:00:00 2001 From: Roman Tolchenov Date: Wed, 19 Nov 2014 11:12:57 +0000 Subject: [PATCH 095/128] Re #10545. Fixed a unit test. --- Code/Mantid/Framework/MDAlgorithms/test/MDNormSXDTest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/test/MDNormSXDTest.h b/Code/Mantid/Framework/MDAlgorithms/test/MDNormSXDTest.h index 3e4082bb571b..2f4539a45926 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/MDNormSXDTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/MDNormSXDTest.h @@ -44,7 +44,7 @@ class MDNormSXDTest : public CxxTest::TestSuite TS_ASSERT( alg.isInitialized() ) TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InputWorkspace", mdWsName) ); TS_ASSERT_THROWS_NOTHING( alg.setProperty("FluxWorkspace", fluxGoodWsName) ); - TS_ASSERT_THROWS( alg.setProperty("FluxWorkspace", fluxBadWsName), std::invalid_argument ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("FluxWorkspace", fluxBadWsName) ); // it isn't bad any more TS_ASSERT_THROWS_NOTHING( alg.setProperty("SolidAngleWorkspace", saWsName) ); TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace", "OutWSName") ); TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputNormalizationWorkspace", "OutNormWSName") ); From 5c366d21c9ce1599f12382dd2cb7d248b30bc4b9 Mon Sep 17 00:00:00 2001 From: Roman Tolchenov Date: Wed, 19 Nov 2014 11:47:28 +0000 Subject: [PATCH 096/128] Re #10545. Fix compiler warnings. --- Code/Mantid/Framework/MDAlgorithms/test/IntegrateFluxTest.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/test/IntegrateFluxTest.h b/Code/Mantid/Framework/MDAlgorithms/test/IntegrateFluxTest.h index 110e4946c35e..428f948b62a3 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/IntegrateFluxTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/IntegrateFluxTest.h @@ -14,7 +14,7 @@ using namespace Mantid::API; namespace { - enum WorkspaceType { Tof, Weighted, WeightedNoTime, Histogram, HistogramNonUniform, Distribution, PointData, PointDataNonUniform }; + enum WorkspaceType { Tof, /*Weighted,*/ WeightedNoTime, Histogram, HistogramNonUniform, Distribution, PointData, PointDataNonUniform }; struct TestingFunction { @@ -24,7 +24,7 @@ namespace TestingFunction(const MatrixWorkspace& ws, WorkspaceType t): workspace(ws), type(t), - dx((ws.getXMax()-ws.getXMin())/ws.blocksize()) + dx((ws.getXMax()-ws.getXMin())/ static_cast(ws.blocksize())) {} double operator()(double x) const { From 3f2dfd0ba74d0da51b1887527086271ef91d71f4 Mon Sep 17 00:00:00 2001 From: Roman Tolchenov Date: Wed, 19 Nov 2014 12:07:52 +0000 Subject: [PATCH 097/128] Re #10545. Remove unused variables. --- Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp b/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp index b818998ee1ce..f0cd107ea71d 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/IntegrateFlux.cpp @@ -250,7 +250,6 @@ class NoEventWorkspaceDeleting // cache some iterators auto inXbegin = inX.begin(); auto inXend = inX.end(); - auto inYbegin = inY.begin(); auto x0 = inXbegin; // iterator over x in input workspace // loop over the iteration points starting from the second one for(auto outX = X.begin()+1; outX != X.end(); ++outX,++outY) @@ -372,7 +371,6 @@ class NoEventWorkspaceDeleting // cache some iterators auto inXbegin = inX.begin(); auto inXend = inX.end(); - auto inYbegin = inY.begin(); auto x0 = inXbegin; // iterator over x in input workspace // loop over the iteration points starting from the second one From 3e47d17662b9955a9260bfd931e9fdeb8fe266ef Mon Sep 17 00:00:00 2001 From: Harry Jeffery Date: Wed, 19 Nov 2014 12:15:56 +0000 Subject: [PATCH 098/128] Refs #10565 Synchronise the instrument selection widgets --- .../inc/MantidQtCustomInterfaces/QtReflMainView.h | 3 +++ .../MantidQt/CustomInterfaces/src/QtReflMainView.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h index c77727b0878c..0d2e84c227b8 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h @@ -118,6 +118,9 @@ namespace MantidQt void on_actionImportTable_triggered(); void on_actionExportTable_triggered(); + void on_comboSearchInstrument_currentIndexChanged(int index); + void on_comboProcessInstrument_currentIndexChanged(int index); + void setModel(QString name); void tableUpdated(const QModelIndex& topLeft, const QModelIndex& bottomRight); void showContextMenu(const QPoint& pos); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp index ffb8bd3b27bc..4b1ee56e8913 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/QtReflMainView.cpp @@ -257,6 +257,18 @@ namespace MantidQt m_presenter->notify(IReflPresenter::ImportTableFlag); } + /** This slot is used to syncrhonise the two instrument selection widgets */ + void QtReflMainView::on_comboProcessInstrument_currentIndexChanged(int index) + { + ui.comboSearchInstrument->setCurrentIndex(index); + } + + /** This slot is used to syncrhonise the two instrument selection widgets */ + void QtReflMainView::on_comboSearchInstrument_currentIndexChanged(int index) + { + ui.comboProcessInstrument->setCurrentIndex(index); + } + /** This slot notifies the presenter that the table has been updated/changed by the user */ From dceb3ea7d973c745c6007016fc3722d09b3f0ce3 Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Wed, 19 Nov 2014 10:08:45 -0500 Subject: [PATCH 099/128] Refs #10566. Adding code that should work for mac and windoze --- .../Framework/Kernel/src/ConfigService.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp index ed79563c5d87..b478b4179623 100644 --- a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp @@ -1311,8 +1311,48 @@ std::string ConfigServiceImpl::getOSVersionReadable() { return description; } } + +#endif + + // try system calls + std::string cmd; + std::vector args; +#ifdef __APPLE__ + cmd = "sw_vers"; // mac +#elif _WIN32 + cmd = "wmic"; // windows + args.push_back("os"); // windows + args.push_back("get"); // windows + args.push_back("Caption"); // windows + args.push_back("/value"); // windows #endif + if (!cmd.empty()) { + try { + Poco::Pipe outPipe, errorPipe; + Poco::ProcessHandle ph = + Poco::Process::launch(cmd, args, 0, &outPipe, &errorPipe); + const int rc = ph.wait(); + // Only if the command returned successfully. + if (rc == 1) { + Poco::PipeInputStream pipeStream(outPipe); + std::stringstream stringStream; + Poco::StreamCopier::copyStream(pipeStream, stringStream); + // TODO process the result + // std::cout << "***" << stringStream.str() << "***" << + // std::endl; + } else { + std::stringstream messageStream; + messageStream << "command \"" << cmd << "\" failed with code: " << rc; + g_log.debug(messageStream.str()); + } + } + catch (Poco::SystemException &e) { + g_log.debug("command \"" + cmd + "\" failed"); + g_log.debug(e.what()); + } + } + return description; } From 283859b3a9404fdc1a6aca2bebd3f5fcc5301142 Mon Sep 17 00:00:00 2001 From: Lottie Greenwood Date: Wed, 19 Nov 2014 16:28:52 +0000 Subject: [PATCH 100/128] Refs #8961 Fixes unused variable --- .../DataHandling/inc/MantidDataHandling/AsciiPointBase.h | 1 + .../inc/MantidDataHandling/SaveReflThreeColumnAscii.h | 2 +- .../Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h index d0816d967522..fbe0641b75fd 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h @@ -80,6 +80,7 @@ namespace Mantid virtual void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ = true); double m_qres; size_t m_xlength; + API::MatrixWorkspace_const_sptr m_ws; }; diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h index 19ba41f9cb17..eccd47b857bf 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/SaveReflThreeColumnAscii.h @@ -52,7 +52,7 @@ namespace Mantid /// Algorithm's version for identification overriding a virtual method virtual int version() const { return 1; } ///Algorithm's version for data output overriding a virtual method - void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ); + void data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ = false); private: diff --git a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp index 07e57575f2a6..6d16b8a89fe6 100644 --- a/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp +++ b/Code/Mantid/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp @@ -49,10 +49,10 @@ namespace Mantid * @param exportDeltaQ :: bool on whether deltaQ column to be printed (permanantly false in this case) */ void SaveReflThreeColumnAscii::data(std::ofstream & file, const std::vector & XData, bool exportDeltaQ) - { - AsciiPointBase::data(file, XData, false); + { + exportDeltaQ = false; + AsciiPointBase::data(file, XData, exportDeltaQ); } - } // namespace DataHandling } // namespace Mantid From e5511c4bb5861c561e1696633c97c5368e7d5c9b Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Wed, 19 Nov 2014 16:48:46 +0000 Subject: [PATCH 101/128] Remove SofQW3 option from IDR tab Refs #10596 --- .../inc/MantidQtCustomInterfaces/IndirectDataReduction.ui | 5 ----- Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSqw.cpp | 2 -- 2 files changed, 7 deletions(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataReduction.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataReduction.ui index a5ba958a33cc..68b86d9a7132 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataReduction.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataReduction.ui @@ -2296,11 +2296,6 @@ Later steps in the process (saving, renaming) will not be done. Parallelepiped (SofQW2) - - - Parallelepiped/Fractional Area (SofQW3) - - diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSqw.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSqw.cpp index b35252c05c50..4d7de60347a5 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSqw.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSqw.cpp @@ -184,8 +184,6 @@ namespace CustomInterfaces sqwAlg = AlgorithmManager::Instance().create("SofQW"); else if(rebinType == "Parallelepiped (SofQW2)") sqwAlg = AlgorithmManager::Instance().create("SofQW2"); - else if(rebinType == "Parallelepiped/Fractional Area (SofQW3)") - sqwAlg = AlgorithmManager::Instance().create("SofQW3"); // S(Q, w) algorithm sqwAlg->initialize(); From 6cdb998d3a00f7dfffedba60482ec46c1bf04263 Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Wed, 19 Nov 2014 11:55:34 -0500 Subject: [PATCH 102/128] Re #10566. Adding implementation for windows and mac. --- .../Framework/Kernel/src/ConfigService.cpp | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp index b478b4179623..c32799234884 100644 --- a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp @@ -1254,6 +1254,22 @@ bool canRead(const std::string &filename) { return pocoFile.canRead(); } +/// @returns the value associated with the key. +std::string getValueFromStdOut(const std::string &orig, const std::string &key) { + size_t start = orig.find(key); + if (start == std::string::npos) { + return std::string(); + } + start += key.size(); + + size_t stop = orig.find("\n", start); + if (stop == std::string::npos) { + return std::string(); + } + + return Mantid::Kernel::Strings::strip(orig.substr(start, stop-start-1)); +} + /** * Gets the name of the operating system version in a human readable form. * @@ -1334,13 +1350,20 @@ std::string ConfigServiceImpl::getOSVersionReadable() { Poco::Process::launch(cmd, args, 0, &outPipe, &errorPipe); const int rc = ph.wait(); // Only if the command returned successfully. - if (rc == 1) { + if (rc == 0) { Poco::PipeInputStream pipeStream(outPipe); std::stringstream stringStream; Poco::StreamCopier::copyStream(pipeStream, stringStream); - // TODO process the result - // std::cout << "***" << stringStream.str() << "***" << - // std::endl; + const std::string result = stringStream.str(); +#ifdef __APPLE__ + const std::string product_name = getValueFromStdOut(result, "ProductName:"); + const std::string product_vers = getValueFromStdOut(result, "ProductVersion:"); + + description = product_name + " " + product_vers; +#elif _WIN32 + description = getValueFromStdOut(result, "Caption="); + // std::cout << "***" << stringStream.str() << "***" << std::endl; +#endif } else { std::stringstream messageStream; messageStream << "command \"" << cmd << "\" failed with code: " << rc; From 603750f078e0f26cef6d901a6dc3cac253144ffc Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Wed, 19 Nov 2014 12:12:07 -0500 Subject: [PATCH 103/128] Refs #10593. Adding jsoncpp-devel to required packages. --- .../dev-packages/rpm/mantid-developer/mantid-developer.spec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Mantid/Build/dev-packages/rpm/mantid-developer/mantid-developer.spec b/Code/Mantid/Build/dev-packages/rpm/mantid-developer/mantid-developer.spec index d5970a46aa71..e2796a7c881b 100644 --- a/Code/Mantid/Build/dev-packages/rpm/mantid-developer/mantid-developer.spec +++ b/Code/Mantid/Build/dev-packages/rpm/mantid-developer/mantid-developer.spec @@ -1,5 +1,5 @@ Name: mantid-developer -Version: 1.4 +Version: 1.5 Release: 1%{?dist} Summary: Meta Package to install dependencies for Mantid Development @@ -19,6 +19,7 @@ Requires: git-all Requires: gsl-devel Requires: hdf-devel Requires: hdf5-devel +Requires: jsoncpp-devel Requires: muParser-devel Requires: mxml-devel Requires: nexus >= 4.2 From e540d5ef83187433237072097009dece16f84d66 Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Wed, 19 Nov 2014 13:16:55 -0500 Subject: [PATCH 104/128] Refs #10566. Check for the files on every os. --- Code/Mantid/Framework/Kernel/src/ConfigService.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp index c32799234884..19c665dfdad3 100644 --- a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp @@ -1278,7 +1278,6 @@ std::string getValueFromStdOut(const std::string &orig, const std::string &key) std::string ConfigServiceImpl::getOSVersionReadable() { std::string description; -#ifdef __linux__ // read os-release static const std::string OS_RELEASE("/etc/os-release"); if (canRead(OS_RELEASE)) { @@ -1328,8 +1327,6 @@ std::string ConfigServiceImpl::getOSVersionReadable() { } } -#endif - // try system calls std::string cmd; std::vector args; From daf532b689a1ab81071818439f7d5decb56f3ae3 Mon Sep 17 00:00:00 2001 From: Martyn Gigg Date: Wed, 19 Nov 2014 20:50:19 +0000 Subject: [PATCH 105/128] Require Poco version 1.4.2 runtime libraries Only required for Trusty as we have dropped support for previous versions. Refs #10574 --- Code/Mantid/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Code/Mantid/CMakeLists.txt b/Code/Mantid/CMakeLists.txt index 2a19d9eb65ee..5924106a34c6 100644 --- a/Code/Mantid/CMakeLists.txt +++ b/Code/Mantid/CMakeLists.txt @@ -224,7 +224,6 @@ if ( ENABLE_CPACK ) set ( DEPENDS_LIST "libboost-date-time${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}," "libboost-regex${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}," "libboost-python${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}," - "libpocofoundation9,libpocoutil9,libpoconet9,libpoconetssl9,libpococrypto9,libpocoxml9," "libnexus0 (>= 4.3),libgsl0ldbl,libqtcore4 (>= 4.2),libqtgui4 (>= 4.2),libqt4-opengl (>= 4.2)," "libqt4-xml (>= 4.2),libqt4-svg (>= 4.2),libqt4-qt3support (>= 4.2),qt4-dev-tools," "libqwt5-qt4,libqwtplot3d-qt4-0,python-numpy,python-sip,python-qt4" ) @@ -232,17 +231,19 @@ if ( ENABLE_CPACK ) if( "${UNIX_CODENAME}" MATCHES "lucid" ) list ( APPEND DEPENDS_LIST ",libqscintilla2-5," "libopencascade-foundation-6.3.0 (>= 6.3.0),libopencascade-modeling-6.3.0 (>= 6.3.0)," - "libmuparser0" ) + "libmuparser0,libpocofoundation9,libpocoutil9,libpoconet9,libpoconetssl9,libpococrypto9,libpocoxml9" ) elseif( "${UNIX_CODENAME}" MATCHES "precise" ) list ( APPEND DEPENDS_LIST ",libqscintilla2-8," "libopencascade-foundation-6.5.0 (>= 6.5.0),libopencascade-modeling-6.5.0 (>= 6.5.0)," "libmuparser0debian1," - "ipython-qtconsole (>= 1.1),python-matplotlib,python-scipy" ) + "ipython-qtconsole (>= 1.1),python-matplotlib,python-scipy," + "libpocofoundation9,libpocoutil9,libpoconet9,libpoconetssl9,libpococrypto9,libpocoxml9") elseif( "${UNIX_CODENAME}" STREQUAL "trusty" ) list ( APPEND DEPENDS_LIST ",libqscintilla2-11," "liboce-foundation8,liboce-modeling8," "libmuparser2," - "ipython-qtconsole (>= 1.1),python-matplotlib,python-scipy" ) + "ipython-qtconsole (>= 1.1),python-matplotlib,python-scipy," + "libpocofoundation11,libpocoutil11,libpoconet11,libpoconetssl11,libpococrypto11,libpocoxml11") set ( PERFTOOLS_DEB_PACKAGE "libgoogle-perftools4 (>= 1.7)" ) else() message( WARNING "Mantid does not support packaging of this Ubuntu version: ${UNIX_CODENAME}") From 06f628446391951abd9f4303b99d0a9080886f8f Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Thu, 20 Nov 2014 08:56:53 +0000 Subject: [PATCH 106/128] add Distribution: True/False to MatrixWorkspace info, re #10072 --- Code/Mantid/Framework/API/src/MatrixWorkspace.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Code/Mantid/Framework/API/src/MatrixWorkspace.cpp b/Code/Mantid/Framework/API/src/MatrixWorkspace.cpp index 374c0949573a..36baf62d4e0a 100644 --- a/Code/Mantid/Framework/API/src/MatrixWorkspace.cpp +++ b/Code/Mantid/Framework/API/src/MatrixWorkspace.cpp @@ -84,6 +84,10 @@ namespace Mantid os << "\n" << "Y axis: " << YUnitLabel() << "\n"; + os << "Distribution: " + << (isDistribution()? "True" : "False") + << "\n"; + os << ExperimentInfo::toString(); return os.str(); } From 69e719cbc1cd3475effcf009a0126acc3523bb27 Mon Sep 17 00:00:00 2001 From: Martyn Gigg Date: Wed, 19 Nov 2014 13:37:27 +0000 Subject: [PATCH 107/128] Add jsconcpp as a required dependency for Kernel. Refs #10573 --- Code/Mantid/Build/CMake/CommonSetup.cmake | 2 ++ Code/Mantid/Build/CMake/FindJsonCPP.cmake | 33 +++++++++++++++++++++ Code/Mantid/Build/CMake/WindowsSetup.cmake | 2 +- Code/Mantid/Framework/Kernel/CMakeLists.txt | 3 +- 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 Code/Mantid/Build/CMake/FindJsonCPP.cmake diff --git a/Code/Mantid/Build/CMake/CommonSetup.cmake b/Code/Mantid/Build/CMake/CommonSetup.cmake index 1693e45d1966..b6f7badbd2fb 100644 --- a/Code/Mantid/Build/CMake/CommonSetup.cmake +++ b/Code/Mantid/Build/CMake/CommonSetup.cmake @@ -55,6 +55,8 @@ include_directories ( SYSTEM ${NEXUS_INCLUDE_DIR} ) find_package ( MuParser REQUIRED ) +find_package ( JsonCPP REQUIRED ) + find_package ( Doxygen ) # optional # Need to change search path to find zlib include on Windows. diff --git a/Code/Mantid/Build/CMake/FindJsonCPP.cmake b/Code/Mantid/Build/CMake/FindJsonCPP.cmake new file mode 100644 index 000000000000..947dda4c29f6 --- /dev/null +++ b/Code/Mantid/Build/CMake/FindJsonCPP.cmake @@ -0,0 +1,33 @@ +# - Find jsoncpp include dirs and libraries +# Use this module by invoking find_package with the form: +# find_package(JsonCPP [required] [quiet] ) +# +# The module sets the following variables +# JSONCPP_FOUND - True if headers and libraries were found +# JSONCPP_INCLUDE_DIR - jsoncpp include directories +# JSONCPP_LIBRARY - library files for linking (optimised version) +# JSONCPP_LIBRARY_DEBUG - library files for linking (debug version) +# JSONCPP_LIBRARIES - All required libraries, including the configuration type + +# Headers +find_path ( JSONCPP_INCLUDE_DIR jsoncpp/json/json.h ) + +# Libraries +find_library ( JSONCPP_LIBRARY NAMES jsoncpp ) # optimized +find_library ( JSONCPP_LIBRARY_DEBUG NAMES jsoncpp_d ) # debug + +if ( JSONCPP_LIBRARY AND JSONCPP_LIBRARY_DEBUG ) + set ( JSONCPP_LIBRARIES optimized ${JSONCPP_LIBRARY} debug ${JSONCPP_LIBRARY_DEBUG} ) +else() + set ( JSONCPP_LIBRARIES ${JSONCPP_LIBRARY} ) +endif() + +# Handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE if +# all listed variables are TRUE +include ( FindPackageHandleStandardArgs ) +find_package_handle_standard_args( JsonCPP DEFAULT_MSG JSONCPP_INCLUDE_DIR JSONCPP_LIBRARIES ) + +# Advanced variables +mark_as_advanced ( JSONCPP_INCLUDE_DIR JSONCPP_LIBRARIES ) + + diff --git a/Code/Mantid/Build/CMake/WindowsSetup.cmake b/Code/Mantid/Build/CMake/WindowsSetup.cmake index f7a0ce3ea49f..e8a98b9cfb42 100644 --- a/Code/Mantid/Build/CMake/WindowsSetup.cmake +++ b/Code/Mantid/Build/CMake/WindowsSetup.cmake @@ -82,7 +82,7 @@ set ( PYTHONW_EXECUTABLE "${CMAKE_LIBRARY_PATH}/Python27/pythonw.exe" CACHE FILE ########################################################################### add_definitions ( -DWIN32 -D_WINDOWS -DMS_VISUAL_STUDIO ) add_definitions ( -D_USE_MATH_DEFINES -DNOMINMAX ) -add_definitions ( -DGSL_DLL ) +add_definitions ( -DGSL_DLL -DJSON_DLL ) add_definitions ( -DPOCO_NO_UNWINDOWS ) add_definitions ( -D_SCL_SECURE_NO_WARNINGS ) add_definitions ( -D_CRT_SECURE_NO_WARNINGS ) diff --git a/Code/Mantid/Framework/Kernel/CMakeLists.txt b/Code/Mantid/Framework/Kernel/CMakeLists.txt index c76df1829da6..d1230b53b18b 100644 --- a/Code/Mantid/Framework/Kernel/CMakeLists.txt +++ b/Code/Mantid/Framework/Kernel/CMakeLists.txt @@ -376,7 +376,8 @@ set_target_properties ( Kernel PROPERTIES OUTPUT_NAME MantidKernel # Add to the 'Framework' group in VS set_property ( TARGET Kernel PROPERTY FOLDER "MantidFramework" ) -target_link_libraries ( Kernel ${MANTIDLIBS} ${GSL_LIBRARIES} ${NEXUS_LIBRARIES} ${NETWORK_LIBRARIES} ) +target_link_libraries ( Kernel ${MANTIDLIBS} ${GSL_LIBRARIES} ${NEXUS_LIBRARIES} + ${NETWORK_LIBRARIES} ${JSONCPP_LIBRARIES} ) if ( WIN32 ) target_link_libraries ( Kernel Psapi.lib ) # For memory usage queries endif() From 2fe0660f19b779c67315d975904ff4c8b06f3825 Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Thu, 20 Nov 2014 09:31:43 +0000 Subject: [PATCH 108/128] update APITest_MatrixWorkspaceTest - 'Distribution: False, re #10072' --- .../Framework/API/test/MatrixWorkspaceTest.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Code/Mantid/Framework/API/test/MatrixWorkspaceTest.h b/Code/Mantid/Framework/API/test/MatrixWorkspaceTest.h index d7d490e1c59c..774f3b9cd6b2 100644 --- a/Code/Mantid/Framework/API/test/MatrixWorkspaceTest.h +++ b/Code/Mantid/Framework/API/test/MatrixWorkspaceTest.h @@ -76,14 +76,15 @@ class MatrixWorkspaceTest : public CxxTest::TestSuite testWS->setYUnitLabel("Counts"); std::string expected = \ - "WorkspaceTester\n" - "Title: A test run\n" - "Histograms: 1\n" - "Bins: 1\n" - "Histogram\n" - "X axis: Time-of-flight / microsecond\n" - "Y axis: Counts\n" - "Instrument: (1990-Jan-01 to 1990-Jan-01)\n"; + "WorkspaceTester\n" + "Title: A test run\n" + "Histograms: 1\n" + "Bins: 1\n" + "Histogram\n" + "X axis: Time-of-flight / microsecond\n" + "Y axis: Counts\n" + "Distribution: False\n" + "Instrument: (1990-Jan-01 to 1990-Jan-01)\n"; TS_ASSERT_EQUALS(expected, testWS->toString()); } From 5f273094b4a702fb06c951d75dc9061f2f2d019e Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Thu, 20 Nov 2014 09:48:08 +0000 Subject: [PATCH 109/128] show (non-empty) more informative layer names, re #10244 --- Code/Mantid/MantidPlot/src/PlotDialog.cpp | 38 ++++++++++++++--------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/Code/Mantid/MantidPlot/src/PlotDialog.cpp b/Code/Mantid/MantidPlot/src/PlotDialog.cpp index b8e0ec90dd27..cd9232ec5f2c 100644 --- a/Code/Mantid/MantidPlot/src/PlotDialog.cpp +++ b/Code/Mantid/MantidPlot/src/PlotDialog.cpp @@ -1378,6 +1378,7 @@ void PlotDialog::setMultiLayer(MultiLayer *ml) boxScaleLayers->setChecked(d_ml->scaleLayersOnPrint()); boxPrintCrops->setChecked(d_ml->printCropmarksEnabled()); + // the plot (dataset) name will be displayed in the tree entry (leftmost/topmost tree level) QTreeWidgetItem *item = new QTreeWidgetItem(listBox, QStringList(ml->name())); item->setIcon(0, QIcon(getQPixmap("folder_open"))); listBox->addTopLevelItem(item); @@ -1385,22 +1386,24 @@ void PlotDialog::setMultiLayer(MultiLayer *ml) QList layers = ml->layersList(); int i = 0; - foreach(Graph *g, layers){ - LayerItem *layer = new LayerItem(g, item, tr("Layer") + QString::number(++i)); - item->addChild(layer); - - if (g == ml->activeGraph()) + foreach(Graph *g, layers) { - layer->setExpanded(true); - layer->setActive(true); - listBox->setCurrentItem(layer); + // builds the names/labels of layers (Layer1, Layer2, etc.) visible in the tree + LayerItem *layer = new LayerItem(g, item, tr("Layer ") + QString::number(++i)); + item->addChild(layer); + + if (g == ml->activeGraph()) + { + layer->setExpanded(true); + layer->setActive(true); + listBox->setCurrentItem(layer); - keepRatioOnResizeBox->setChecked(g->isFixedAspectRatioEnabled()); - if (g->isSpectrogram()) keepRatioOnResizeBox->show(); - else keepRatioOnResizeBox->hide(); + keepRatioOnResizeBox->setChecked(g->isFixedAspectRatioEnabled()); + if (g->isSpectrogram()) keepRatioOnResizeBox->show(); + else keepRatioOnResizeBox->hide(); + } } } -} void PlotDialog::selectCurve(int index) { @@ -3078,11 +3081,18 @@ void LayerItem::insertCurvesList() QString table = dc->table()->name(); plotAssociation = table + ": " + s.remove(table + "_"); } + else + { + plotAssociation = it->title().text(); + } + } + else // builds the names/labels of special (non-) curves within layers displayed in tree entries + { + if (d_graph->isSpectrogram() || it->title().isEmpty()) + plotAssociation = it->title().text() + " Layer details (editable)"; else plotAssociation = it->title().text(); } - else - plotAssociation = it->title().text(); addChild(new CurveTreeItem(it, this, plotAssociation)); } From 08d2a25cdc86b2f5e328261da7af8290f6c04114 Mon Sep 17 00:00:00 2001 From: Martyn Gigg Date: Thu, 20 Nov 2014 10:50:35 +0000 Subject: [PATCH 110/128] Replace Poco::RegularExpression with boost::regex Refs #10603 --- .../WorkflowAlgorithms/src/EQSANSLoad.cpp | 111 ++++++++---------- 1 file changed, 49 insertions(+), 62 deletions(-) diff --git a/Code/Mantid/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp b/Code/Mantid/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp index fdfc3ed55708..9100f5351be5 100644 --- a/Code/Mantid/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp +++ b/Code/Mantid/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp @@ -8,7 +8,6 @@ #include #include "MantidKernel/TimeSeriesProperty.h" #include "Poco/DirectoryIterator.h" -#include "Poco/RegularExpression.h" #include "Poco/NumberParser.h" #include "Poco/NumberFormatter.h" #include "Poco/String.h" @@ -17,6 +16,7 @@ #include #include #include +#include #include "MantidWorkflowAlgorithms/EQSANSInstrument.h" #include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/AlgorithmProperty.h" @@ -94,26 +94,23 @@ std::string EQSANSLoad::findConfigFile(const int& run) int max_run_number = 0; std::string config_file = ""; - Poco::RegularExpression re1("eqsans_configuration.[0-9]+"); - Poco::RegularExpression re2("[0-9]+"); + static boost::regex re1("eqsans_configuration\\.([0-9]+)"); + boost::smatch matches; for (; it != searchPaths.end(); ++it) { Poco::DirectoryIterator file_it(*it); Poco::DirectoryIterator end; for (; file_it != end; ++file_it) { - if (re1.match(file_it.name())) + if (boost::regex_match(file_it.name(), matches, re1)) { - std::string s; - if (re2.extract(file_it.name(), s)==1) + std::string s = matches[1]; + int run_number = 0; + Poco::NumberParser::tryParse(s, run_number); + if (run_number > max_run_number && run_number <= run) { - int run_number = 0; - Poco::NumberParser::tryParse(s, run_number); - if (run_number > max_run_number && run_number <= run) - { - max_run_number = run_number; - config_file = file_it.path().toString(); - } + max_run_number = run_number; + config_file = file_it.path().toString(); } } } @@ -127,21 +124,19 @@ void EQSANSLoad::readRectangularMasks(const std::string& line) { // Looking for rectangular mask // Rectangular mask = 7, 0; 7, 255 - Poco::RegularExpression re_key("rectangular mask", Poco::RegularExpression::RE_CASELESS); - Poco::RegularExpression re_key_alt("elliptical mask", Poco::RegularExpression::RE_CASELESS); - Poco::RegularExpression::Match match; - if (re_key.match(line, 0, match) || re_key_alt.match(line, 0, match)) + boost::regex re_key("rectangular mask", boost::regex::icase); + boost::regex re_key_alt("elliptical mask", boost::regex::icase); + if (boost::regex_match(line, re_key) || boost::regex_match(line, re_key_alt)) { - Poco::RegularExpression re_sig("=[ ]*([0-9]+)[ ]*[ ,][ ]*([0-9]+)[ ]*[ ;,][ ]*([0-9]+)[ ]*[ ,][ ]*([0-9]+)"); - if (re_sig.match(line, 0, match)) + boost::regex re_sig("=[ ]*([0-9]+)[ ]*[ ,][ ]*([0-9]+)[ ]*[ ;,][ ]*([0-9]+)[ ]*[ ,][ ]*([0-9]+)"); + boost::smatch posVec; + if (boost::regex_match(line, posVec, re_sig)) { - Poco::RegularExpression::MatchVec posVec; - re_sig.match(line, 0, posVec); if (posVec.size()==5) { for (int i=0; i<4; i++) { - std::string num_str = line.substr(posVec[i+1].offset, posVec[i+1].length); + std::string num_str = posVec[i+1]; m_mask_as_string = m_mask_as_string + " " + num_str; } m_mask_as_string += ","; @@ -155,20 +150,18 @@ void EQSANSLoad::readRectangularMasks(const std::string& line) /// @param line :: line (string) from the config file void EQSANSLoad::readTOFcuts(const std::string& line) { - Poco::RegularExpression re_key("tof edge discard", Poco::RegularExpression::RE_CASELESS); - Poco::RegularExpression::Match match; - if (re_key.match(line, 0, match)) + boost::regex re_key("tof edge discard", boost::regex::icase); + if (boost::regex_match(line, re_key)) { - Poco::RegularExpression re_sig("=[ ]*([0-9]+)[ ]*[ ,][ ]*([0-9]+)"); - if (re_sig.match(line, 0, match)) + boost::regex re_sig("=[ ]*([0-9]+)[ ]*[ ,][ ]*([0-9]+)"); + boost::smatch posVec; + if (boost::regex_match(line, posVec, re_sig)) { - Poco::RegularExpression::MatchVec posVec; - re_sig.match(line, 0, posVec); if (posVec.size()==3) { - std::string num_str = line.substr(posVec[1].offset, posVec[1].length); + std::string num_str = posVec[1]; Poco::NumberParser::tryParseFloat(num_str, m_low_TOF_cut); - num_str = line.substr(posVec[2].offset, posVec[2].length); + num_str = posVec[2]; Poco::NumberParser::tryParseFloat(num_str, m_high_TOF_cut); } } @@ -179,20 +172,18 @@ void EQSANSLoad::readTOFcuts(const std::string& line) /// @param line :: line (string) from the config file void EQSANSLoad::readBeamCenter(const std::string& line) { - Poco::RegularExpression re_key("spectrum center", Poco::RegularExpression::RE_CASELESS); - Poco::RegularExpression::Match match; - if (re_key.match(line, 0, match)) + boost::regex re_key("spectrum center", boost::regex::icase); + if (boost::regex_match(line, re_key)) { - Poco::RegularExpression re_sig("=[ ]*([0-9]+.[0-9]*)[ ]*[ ,][ ]*([0-9]+.[0-9]+)"); - if (re_sig.match(line, 0, match)) + boost::regex re_sig("=[ ]*([0-9]+.[0-9]*)[ ]*[ ,][ ]*([0-9]+.[0-9]+)"); + boost::smatch posVec; + if (boost::regex_match(line, posVec, re_sig)) { - Poco::RegularExpression::MatchVec posVec; - re_sig.match(line, 0, posVec); if (posVec.size()==3) { - std::string num_str = line.substr(posVec[1].offset, posVec[1].length); + std::string num_str = posVec[1]; Poco::NumberParser::tryParseFloat(num_str, m_center_x); - num_str = line.substr(posVec[2].offset, posVec[2].length); + num_str = posVec[2]; Poco::NumberParser::tryParseFloat(num_str, m_center_y); } } @@ -203,18 +194,16 @@ void EQSANSLoad::readBeamCenter(const std::string& line) /// @param line :: line (string) from the config file void EQSANSLoad::readModeratorPosition(const std::string& line) { - Poco::RegularExpression re_key("sample location", Poco::RegularExpression::RE_CASELESS); - Poco::RegularExpression::Match match; - if (re_key.match(line, 0, match)) + boost::regex re_key("sample location", boost::regex::icase); + if (boost::regex_match(line, re_key)) { - Poco::RegularExpression re_sig("=[ ]*([0-9]+)"); - if (re_sig.match(line, 0, match)) + boost::regex re_sig("=[ ]*([0-9]+)"); + boost::smatch posVec; + if (boost::regex_match(line, posVec, re_sig)) { - Poco::RegularExpression::MatchVec posVec; - re_sig.match(line, 0, posVec); if (posVec.size()==2) { - std::string num_str = line.substr(posVec[1].offset, posVec[1].length); + std::string num_str = posVec[1]; Poco::NumberParser::tryParseFloat(num_str, m_moderator_position); m_moderator_position = -m_moderator_position/1000.0; } @@ -226,34 +215,32 @@ void EQSANSLoad::readModeratorPosition(const std::string& line) /// @param line :: line (string) from the config file void EQSANSLoad::readSourceSlitSize(const std::string& line) { - Poco::RegularExpression re_key("wheel", Poco::RegularExpression::RE_CASELESS); - Poco::RegularExpression::Match match; - if (re_key.match(line, 0, match)) + boost::regex re_key("wheel", boost::regex::icase); + if (boost::regex_match(line, re_key)) { - Poco::RegularExpression re_sig("([1-8]) wheel[ ]*([1-3])[ \\t]*=[ \\t]*(\\w+)"); - if (re_sig.match(line, 0, match)) + boost::regex re_sig("([1-8]) wheel[ ]*([1-3])[ \\t]*=[ \\t]*(\\w+)"); + boost::smatch posVec; + if (boost::regex_match(line, posVec, re_sig)) { - Poco::RegularExpression::MatchVec posVec; - re_sig.match(line, 0, posVec); - if (posVec.size()==2) + if (posVec.size()==4) { - std::string num_str = line.substr(posVec[1].offset, posVec[1].length); + std::string num_str = posVec[1]; int slit_number = 0; Poco::NumberParser::tryParse(num_str, slit_number); slit_number--; - num_str = line.substr(posVec[2].offset, posVec[2].length); + num_str = posVec[2]; int wheel_number = 0; Poco::NumberParser::tryParse(num_str, wheel_number); wheel_number--; - num_str = line.substr(posVec[3].offset, posVec[3].length); - Poco::RegularExpression re_size("\\w*?([0-9]+)mm"); + num_str = posVec[3]; + boost::regex re_size("\\w*?([0-9]+)mm"); int slit_size = 0; - re_size.match(num_str, 0, posVec); + boost::regex_match(num_str, posVec, re_size); if (posVec.size()==2) { - num_str = line.substr(posVec[1].offset, posVec[1].length); + num_str = posVec[1]; Poco::NumberParser::tryParse(num_str, slit_size); } m_slit_positions[wheel_number][slit_number] = slit_size; From f16cd217ad819a92d085dc18a6773ff4b60837e7 Mon Sep 17 00:00:00 2001 From: Dan Nixon Date: Thu, 20 Nov 2014 11:22:22 +0000 Subject: [PATCH 111/128] Only have SofQW2 on Sqw tab Refs #10596 --- .../IndirectDataReduction.ui | 49 ------------------- .../CustomInterfaces/src/IndirectSqw.cpp | 23 +-------- 2 files changed, 1 insertion(+), 71 deletions(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataReduction.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataReduction.ui index 68b86d9a7132..1d94f0269d63 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataReduction.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/IndirectDataReduction.ui @@ -2122,19 +2122,6 @@ Later steps in the process (saving, renaming) will not be done. - - - - - 43 - 0 - - - - Rebin Type: - - - @@ -2263,41 +2250,6 @@ Later steps in the process (saving, renaming) will not be done. - - - - - 0 - 0 - - - - - 200 - 0 - - - - - 200 - 16777215 - - - - 0 - - - - Centre (SofQW) - - - - - Parallelepiped (SofQW2) - - - - @@ -2794,7 +2746,6 @@ Later steps in the process (saving, renaming) will not be done. trans_ckVerbose trans_ckPlot trans_ckSave - sqw_cbRebinType sqw_leQLow sqw_leQWidth sqw_leQHigh diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSqw.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSqw.cpp index 4d7de60347a5..0ad571a8b157 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSqw.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/IndirectSqw.cpp @@ -174,18 +174,10 @@ namespace CustomInterfaces m_batchAlgoRunner->addAlgorithm(energyRebinAlg); } - // Get correct S(Q, w) algorithm QString eFixed = getInstrumentDetails()["efixed-val"]; - IAlgorithm_sptr sqwAlg; - QString rebinType = m_uiForm.sqw_cbRebinType->currentText(); - - if(rebinType == "Centre (SofQW)") - sqwAlg = AlgorithmManager::Instance().create("SofQW"); - else if(rebinType == "Parallelepiped (SofQW2)") - sqwAlg = AlgorithmManager::Instance().create("SofQW2"); - // S(Q, w) algorithm + IAlgorithm_sptr sqwAlg = AlgorithmManager::Instance().create("SofQW2"); sqwAlg->initialize(); BatchAlgorithmRunner::AlgorithmRuntimeProps sqwInputProps; @@ -201,19 +193,6 @@ namespace CustomInterfaces m_batchAlgoRunner->addAlgorithm(sqwAlg, sqwInputProps); - // Add sample log for S(Q, w) algorithm used - IAlgorithm_sptr sampleLogAlg = AlgorithmManager::Instance().create("AddSampleLog"); - sampleLogAlg->initialize(); - - sampleLogAlg->setProperty("LogName", "rebin_type"); - sampleLogAlg->setProperty("LogType", "String"); - sampleLogAlg->setProperty("LogText", rebinType.toStdString()); - - BatchAlgorithmRunner::AlgorithmRuntimeProps inputToAddSampleLogProps; - inputToAddSampleLogProps["Workspace"] = sqwWsName.toStdString(); - - m_batchAlgoRunner->addAlgorithm(sampleLogAlg, inputToAddSampleLogProps); - // Save S(Q, w) workspace if(m_uiForm.sqw_ckSave->isChecked()) { From 8982f702e6d15c51db4f5d5f4b60a386ee34bc16 Mon Sep 17 00:00:00 2001 From: Martyn Gigg Date: Thu, 20 Nov 2014 14:12:24 +0000 Subject: [PATCH 112/128] Use boost::regex_search and not boost::regex_match The latter requires everything to match, but we just want to search within a string. This is more like what Poco did. Refs #10603 --- .../WorkflowAlgorithms/src/EQSANSLoad.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Code/Mantid/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp b/Code/Mantid/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp index 9100f5351be5..30fe6f32b90b 100644 --- a/Code/Mantid/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp +++ b/Code/Mantid/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp @@ -102,7 +102,7 @@ std::string EQSANSLoad::findConfigFile(const int& run) Poco::DirectoryIterator end; for (; file_it != end; ++file_it) { - if (boost::regex_match(file_it.name(), matches, re1)) + if (boost::regex_search(file_it.name(), matches, re1)) { std::string s = matches[1]; int run_number = 0; @@ -126,11 +126,11 @@ void EQSANSLoad::readRectangularMasks(const std::string& line) // Rectangular mask = 7, 0; 7, 255 boost::regex re_key("rectangular mask", boost::regex::icase); boost::regex re_key_alt("elliptical mask", boost::regex::icase); - if (boost::regex_match(line, re_key) || boost::regex_match(line, re_key_alt)) + if (boost::regex_search(line, re_key) || boost::regex_search(line, re_key_alt)) { boost::regex re_sig("=[ ]*([0-9]+)[ ]*[ ,][ ]*([0-9]+)[ ]*[ ;,][ ]*([0-9]+)[ ]*[ ,][ ]*([0-9]+)"); boost::smatch posVec; - if (boost::regex_match(line, posVec, re_sig)) + if (boost::regex_search(line, posVec, re_sig)) { if (posVec.size()==5) { @@ -151,11 +151,11 @@ void EQSANSLoad::readRectangularMasks(const std::string& line) void EQSANSLoad::readTOFcuts(const std::string& line) { boost::regex re_key("tof edge discard", boost::regex::icase); - if (boost::regex_match(line, re_key)) + if (boost::regex_search(line, re_key)) { boost::regex re_sig("=[ ]*([0-9]+)[ ]*[ ,][ ]*([0-9]+)"); boost::smatch posVec; - if (boost::regex_match(line, posVec, re_sig)) + if (boost::regex_search(line, posVec, re_sig)) { if (posVec.size()==3) { @@ -173,11 +173,11 @@ void EQSANSLoad::readTOFcuts(const std::string& line) void EQSANSLoad::readBeamCenter(const std::string& line) { boost::regex re_key("spectrum center", boost::regex::icase); - if (boost::regex_match(line, re_key)) + if (boost::regex_search(line, re_key)) { boost::regex re_sig("=[ ]*([0-9]+.[0-9]*)[ ]*[ ,][ ]*([0-9]+.[0-9]+)"); boost::smatch posVec; - if (boost::regex_match(line, posVec, re_sig)) + if (boost::regex_search(line, posVec, re_sig)) { if (posVec.size()==3) { @@ -195,11 +195,11 @@ void EQSANSLoad::readBeamCenter(const std::string& line) void EQSANSLoad::readModeratorPosition(const std::string& line) { boost::regex re_key("sample location", boost::regex::icase); - if (boost::regex_match(line, re_key)) + if (boost::regex_search(line, re_key)) { boost::regex re_sig("=[ ]*([0-9]+)"); boost::smatch posVec; - if (boost::regex_match(line, posVec, re_sig)) + if (boost::regex_search(line, posVec, re_sig)) { if (posVec.size()==2) { @@ -216,11 +216,11 @@ void EQSANSLoad::readModeratorPosition(const std::string& line) void EQSANSLoad::readSourceSlitSize(const std::string& line) { boost::regex re_key("wheel", boost::regex::icase); - if (boost::regex_match(line, re_key)) + if (boost::regex_search(line, re_key)) { boost::regex re_sig("([1-8]) wheel[ ]*([1-3])[ \\t]*=[ \\t]*(\\w+)"); boost::smatch posVec; - if (boost::regex_match(line, posVec, re_sig)) + if (boost::regex_search(line, posVec, re_sig)) { if (posVec.size()==4) { @@ -237,7 +237,7 @@ void EQSANSLoad::readSourceSlitSize(const std::string& line) num_str = posVec[3]; boost::regex re_size("\\w*?([0-9]+)mm"); int slit_size = 0; - boost::regex_match(num_str, posVec, re_size); + boost::regex_search(num_str, posVec, re_size); if (posVec.size()==2) { num_str = posVec[1]; From 47dcadbf4da5cce0a467c7cd776c2977e80d0606 Mon Sep 17 00:00:00 2001 From: Martyn Gigg Date: Thu, 20 Nov 2014 15:06:05 +0000 Subject: [PATCH 113/128] Add version requirement for Poco package. Refs #10574 --- Code/Mantid/Build/CMake/CommonSetup.cmake | 2 +- Code/Mantid/Build/CMake/FindPoco.cmake | 36 +++++++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/Code/Mantid/Build/CMake/CommonSetup.cmake b/Code/Mantid/Build/CMake/CommonSetup.cmake index 1693e45d1966..971d836d58c1 100644 --- a/Code/Mantid/Build/CMake/CommonSetup.cmake +++ b/Code/Mantid/Build/CMake/CommonSetup.cmake @@ -47,7 +47,7 @@ add_definitions ( -DBOOST_ALL_DYN_LINK ) # Need this defined globally for our log time values add_definitions ( -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG ) -find_package ( Poco REQUIRED ) +find_package ( Poco 1.4.2 REQUIRED ) include_directories( SYSTEM ${POCO_INCLUDE_DIRS} ) find_package ( Nexus 4.3.0 REQUIRED ) diff --git a/Code/Mantid/Build/CMake/FindPoco.cmake b/Code/Mantid/Build/CMake/FindPoco.cmake index ce00daa04ca5..63c811ccf494 100644 --- a/Code/Mantid/Build/CMake/FindPoco.cmake +++ b/Code/Mantid/Build/CMake/FindPoco.cmake @@ -47,10 +47,42 @@ set ( POCO_LIBRARIES ${POCO_LIB_FOUNDATION} endif() +# Set a version string by examining either the Poco/Version.h header or +# the Poco/Foundation.h header if Version.h does not exist +if( POCO_INCLUDE_DIR ) + if ( EXISTS ${POCO_INCLUDE_DIR}/Poco/Version.h ) + set ( VERSION_FILE ${POCO_INCLUDE_DIR}/Poco/Version.h ) + else () + set ( VERSION_FILE ${POCO_INCLUDE_DIR}/Poco/Foundation.h ) + endif () + # regex quantifiers like {8} don't seem to work so we'll stick with + even though + # it's not strictly true + set ( VERS_REGEX "^#define[ \t]+POCO_VERSION[ \t]+0x([0-9]+)$" ) + file ( STRINGS ${VERSION_FILE} POCO_VERSION REGEX ${VERS_REGEX} ) + # pull out just the part after the 0x + string( REGEX REPLACE ${VERS_REGEX} "\\1" POCO_VERSION ${POCO_VERSION} ) + # Pretty format + string( SUBSTRING ${POCO_VERSION} 0 2 POCO_VERSION_MAJOR ) + string( REGEX REPLACE "^0" "" POCO_VERSION_MAJOR ${POCO_VERSION_MAJOR} ) + string( SUBSTRING ${POCO_VERSION} 2 2 POCO_VERSION_MINOR ) + string( REGEX REPLACE "^0" "" POCO_VERSION_MINOR ${POCO_VERSION_MINOR} ) + string( SUBSTRING ${POCO_VERSION} 4 2 POCO_VERSION_PATCH ) + string( REGEX REPLACE "^0" "" POCO_VERSION_PATCH ${POCO_VERSION_PATCH} ) + + set ( POCO_VERSION "${POCO_VERSION_MAJOR}.${POCO_VERSION_MINOR}.${POCO_VERSION_PATCH}" ) +endif() + + # handle the QUIETLY and REQUIRED arguments and set POCO_FOUND to TRUE if # all listed variables are TRUE include ( FindPackageHandleStandardArgs ) -find_package_handle_standard_args( Poco DEFAULT_MSG POCO_LIBRARIES POCO_INCLUDE_DIR ) +if (POCO_VERSION) + find_package_handle_standard_args( Poco REQUIRED_VARS POCO_LIBRARIES POCO_INCLUDE_DIR + VERSION_VAR POCO_VERSION ) +else () + message (status "Failed to determine Poco version: Ignoring requirement") + find_package_handle_standard_args( Poco DEFAULT_MSG POCO_LIBRARIES POCO_INCLUDE_DIR ) +endif () mark_as_advanced ( POCO_INCLUDE_DIR POCO_LIB_FOUNDATION POCO_LIB_FOUNDATION_DEBUG @@ -59,4 +91,4 @@ mark_as_advanced ( POCO_INCLUDE_DIR POCO_LIB_NET POCO_LIB_NET_DEBUG POCO_LIB_CRYPTO POCO_LIB_CRYPTO_DEBUG POCO_LIB_NETSSL POCO_LIB_NETSSL_DEBUG -) \ No newline at end of file +) From 852108c50932aa2e012984b4bec2a393c5b6ef6b Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Thu, 20 Nov 2014 16:41:42 +0000 Subject: [PATCH 114/128] added disableSaveNexus to keep File->Save in sync, re #1109 --- Code/Mantid/MantidPlot/src/ApplicationWindow.cpp | 12 ++++++++++-- Code/Mantid/MantidPlot/src/ApplicationWindow.h | 5 ++++- Code/Mantid/MantidPlot/src/Mantid/MantidDock.cpp | 10 ++++++++++ Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp | 14 ++++++++++++-- Code/Mantid/MantidPlot/src/Mantid/MantidUI.h | 1 + 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/Code/Mantid/MantidPlot/src/ApplicationWindow.cpp b/Code/Mantid/MantidPlot/src/ApplicationWindow.cpp index 1948d3a8a4dd..9c6457324e83 100644 --- a/Code/Mantid/MantidPlot/src/ApplicationWindow.cpp +++ b/Code/Mantid/MantidPlot/src/ApplicationWindow.cpp @@ -17592,11 +17592,19 @@ void ApplicationWindow::savedatainNexusFormat(const std::string& wsName,const st { } } -void ApplicationWindow::enablesaveNexus(const QString &wsName) + +void ApplicationWindow::enableSaveNexus(const QString &wsName) { - if(actionSaveFile) actionSaveFile->setEnabled(true); + if (actionSaveFile) actionSaveFile->setEnabled(true); m_nexusInputWSName=wsName; } + +void ApplicationWindow::disableSaveNexus() +{ + if (actionSaveFile) + actionSaveFile->setEnabled(false); +} + /* For zooming the selected graph using the drag canvas tool and mouse drag. */ void ApplicationWindow::panOnPlot() diff --git a/Code/Mantid/MantidPlot/src/ApplicationWindow.h b/Code/Mantid/MantidPlot/src/ApplicationWindow.h index 11aa20883421..c262317bdc0c 100644 --- a/Code/Mantid/MantidPlot/src/ApplicationWindow.h +++ b/Code/Mantid/MantidPlot/src/ApplicationWindow.h @@ -206,7 +206,10 @@ class ApplicationWindow: public QMainWindow, public Scripted QString endOfLine(); bool autoUpdateTableValues(){return d_auto_update_table_values;}; void setAutoUpdateTableValues(bool on = true); - void enablesaveNexus(const QString& wsName); + // enables File->Save->Nexus action in the main menu and sets the parameter wsName as input workspace for save alg. + void enableSaveNexus(const QString& wsName); + // disables File->Save-Nexus action in the main menu. Useful when de-selecting workspaces + void disableSaveNexus(); public slots: //! \name Projects and Project Files diff --git a/Code/Mantid/MantidPlot/src/Mantid/MantidDock.cpp b/Code/Mantid/MantidPlot/src/Mantid/MantidDock.cpp index 4cda13373850..318c5c760200 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/MantidDock.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/MantidDock.cpp @@ -1371,6 +1371,16 @@ void MantidDockWidget::treeSelectionChanged() if(m_saveButton) m_saveButton->setEnabled(Items.size() > 0); + + if (Items.size() > 0) + { + auto item = *(Items.begin()); + m_mantidUI->enableSaveNexus(item->text(0)); + } + else + { + m_mantidUI->disableSaveNexus(); + } } /** diff --git a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp index 26a889f1c537..96f82832c946 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp @@ -1412,7 +1412,10 @@ void MantidUI::executeSaveNexus() { QString wsName = getSelectedWorkspaceName(); QHash presets; - presets["InputWorkspace"] = wsName; + if (!wsName.isEmpty()) + { + presets["InputWorkspace"] = wsName; + } showAlgorithmDialog("SaveNexus", presets); } @@ -2118,11 +2121,18 @@ void MantidUI::saveProject(bool saved) } Mantid::API::FrameworkManager::Instance().clear(); } + void MantidUI::enableSaveNexus(const QString& wsName) { - appWindow()->enablesaveNexus(wsName); + appWindow()->enableSaveNexus(wsName); } +void MantidUI::disableSaveNexus() +{ + appWindow()->disableSaveNexus(); +} + + /** This method is sueful for saving the currently loaded workspaces to project file on save. * saves the names of all the workspaces loaded into mantid workspace tree * into a string and calls save nexus on each workspace to save the data to a nexus file. diff --git a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h index 04fdc0a92cde..290247f2e296 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h +++ b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h @@ -299,6 +299,7 @@ class MantidUI:public QObject void saveProject(bool save); void enableSaveNexus(const QString & wsName); + void disableSaveNexus(); signals: //A signal to indicate that we want a script to produce a dialog From 80da92915b8b7c3727c48cf4c37008b9631bd60e Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Thu, 20 Nov 2014 18:32:16 +0000 Subject: [PATCH 115/128] ensure .png extension so QPixmap save works, re #8482 --- .../MantidQt/SliceViewer/src/SliceViewer.cpp | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp b/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp index 192ae892f15e..608bbb0213ce 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp @@ -1125,6 +1125,28 @@ void SliceViewer::copyImageToClipboard() QApplication::clipboard()->setImage(pix, QClipboard::Clipboard); } +/** + * Adds .png extension if not already included + * + * @param filename :: a file name to save an (png) image + * @return input file name with '.png' appended if needed + **/ +QString SliceViewer::ensurePngExtension(const QString& fname) const +{ + const QString goodExt = "png"; + + QString res = fname; + qDebug() << "fname: " << fname; + qDebug() << "res before: " << res; + qDebug() << "suffix: " << QFileInfo(fname).suffix(); + if (QFileInfo(fname).suffix() != goodExt) + { + res = res + "." + goodExt; + } + qDebug() << "returning: " << res; + return res; +} + //------------------------------------------------------------------------------------ /** Save the rendered 2D slice to an image file. * @@ -1147,10 +1169,13 @@ void SliceViewer::saveImage(const QString & filename) else fileselection = filename; + // append '.png' if needed + QString finalName = ensurePngExtension(fileselection); + // Create the image QPixmap pix = this->getImage(); // And save to the file - pix.save(fileselection); + pix.save(finalName); } From 51ee3a2df09a9685a9235a476654cbf1b6aaca98 Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Thu, 20 Nov 2014 18:36:14 +0000 Subject: [PATCH 116/128] new helper function for .png extension, re #8482 --- .../MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h index 82015c76e0be..5746de5872d5 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h @@ -192,6 +192,8 @@ public slots: bool isAutoRebinSet() const; void autoRebinIfRequired(); + // helper for saveImage + QString ensurePngExtension(const QString& fname) const; private: From 34581caada4aed77cb534405a41b16f031723ecc Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Thu, 20 Nov 2014 18:42:42 +0000 Subject: [PATCH 117/128] fix doxygen param name, re #8482 --- Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp b/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp index 608bbb0213ce..5c7c00195d85 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp @@ -1128,7 +1128,7 @@ void SliceViewer::copyImageToClipboard() /** * Adds .png extension if not already included * - * @param filename :: a file name to save an (png) image + * @param fname :: a file name to save an (png) image * @return input file name with '.png' appended if needed **/ QString SliceViewer::ensurePngExtension(const QString& fname) const From 3496f7a84120ea03d513475671d4809c9a28e198 Mon Sep 17 00:00:00 2001 From: Wenduo Zhou Date: Thu, 20 Nov 2014 16:29:51 -0500 Subject: [PATCH 118/128] Refs #10602. Fixed the bug. --- .../Mantid/docs/source/algorithms/GetDetOffsetsMultiPeaks-v1.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Mantid/docs/source/algorithms/GetDetOffsetsMultiPeaks-v1.rst b/Code/Mantid/docs/source/algorithms/GetDetOffsetsMultiPeaks-v1.rst index ad5625bc89eb..a8c8ca50d49c 100644 --- a/Code/Mantid/docs/source/algorithms/GetDetOffsetsMultiPeaks-v1.rst +++ b/Code/Mantid/docs/source/algorithms/GetDetOffsetsMultiPeaks-v1.rst @@ -182,6 +182,7 @@ Here are the cases that a spectra (i.e., a detector) will be masked in the outpu - A dead detector, i.e., the corresponding spectrum has counts less than :math:`10^{-3}` in defined d-range. It isnoted as "dead det"; - A spectrum that does not have peak within specified d-range. It is noted as "no peaks". Here is the criteria for this case. + * Algorithm FindPeaks fails to find any peak; * No peak found has height larger than specified 'MinimumPeakHeight'; * No peak found has observed height larger than specified 'MinimumPeakHeightObs'; From caa49a83c8259f350541d4353a3d94619d4743aa Mon Sep 17 00:00:00 2001 From: Jean Bilheux Date: Thu, 20 Nov 2014 16:53:02 -0500 Subject: [PATCH 119/128] Here are the changes. This refs #10609 --- .../PythonInterface/plugins/algorithms/sfCalculator.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/sfCalculator.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/sfCalculator.py index c833e155c826..c56e679f913b 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/sfCalculator.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/sfCalculator.py @@ -241,6 +241,13 @@ def _calculateFinalYAxis(self, bNumerator=True): self.is_nexus_detector_rotated_flag = self.isNexusTakeAfterRefDate(EventDataWks.getRun().getProperty('run_start').value) + if self.is_nexus_detector_rotated_flag: + self.alpha_pixel_nbr = 304 + self.beta_pixel_nbr = 256 + else: + alpha_pixel_nbr = 256 + beta_pixel_nbr = 304 #will be integrated over this dimension + proton_charge = self._getProtonCharge(EventDataWks) print '----> rebinning ' HistoDataWks = Rebin(InputWorkspace=EventDataWks, From 759cd1c63c050359a203421d3a74b90832b1b0cc Mon Sep 17 00:00:00 2001 From: Federico Montesino Pouzols Date: Fri, 21 Nov 2014 09:33:30 +0000 Subject: [PATCH 120/128] all fine in windoze, remove qdebugs, re #8482 --- Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp b/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp index 5c7c00195d85..5402fe131ecf 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp @@ -1136,14 +1136,10 @@ QString SliceViewer::ensurePngExtension(const QString& fname) const const QString goodExt = "png"; QString res = fname; - qDebug() << "fname: " << fname; - qDebug() << "res before: " << res; - qDebug() << "suffix: " << QFileInfo(fname).suffix(); if (QFileInfo(fname).suffix() != goodExt) { res = res + "." + goodExt; } - qDebug() << "returning: " << res; return res; } From 8f7ffe0e7b42acc335ed14e17d95e02e8f7c5a49 Mon Sep 17 00:00:00 2001 From: Martyn Gigg Date: Fri, 21 Nov 2014 14:20:19 +0000 Subject: [PATCH 121/128] Use OCE libraries rather than OpenCascade because of licensing. Refs #10616 --- Code/Mantid/CMakeLists.txt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Code/Mantid/CMakeLists.txt b/Code/Mantid/CMakeLists.txt index 2a19d9eb65ee..20eaa689aff2 100644 --- a/Code/Mantid/CMakeLists.txt +++ b/Code/Mantid/CMakeLists.txt @@ -186,12 +186,8 @@ if ( ENABLE_CPACK ) # rhel requirements set ( CPACK_RPM_PACKAGE_REQUIRES "boost >= 1.34.1,qt4 >= 4.2,nexus,nexus-python,gsl,glibc,qwtplot3d-qt4,muParser,numpy" ) - # OpenCASCADE changed names when packaged for Fedora 20 and RHEL7 - if( "${UNIX_CODENAME}" MATCHES "Heisenbug" OR "${UNIX_CODENAME}" MATCHES "Maipo" ) - set( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},OCE-devel" ) - else() - set( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},OpenCASCADE-libs-modelling >= 6.3.0,OpenCASCADE-libs-foundation >= 6.3.0,OpenCASCADE-libs-visualization >= 6.3.0,OpenCASCADE-libs-ocaf >= 6.3.0,OpenCASCADE-libs-ocaf-lite >= 6.3.0" ) - endif() + # OCE + set( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},OCE-draw,OCE-foundation,OCE-modeling,OCE_ocaf,OCE-visualization") # Qwt is qwt5-qt4 in RHEL7 if( "${UNIX_CODENAME}" MATCHES "Maipo" ) set( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},qwt5-qt4" ) From 2af0f21e63aeb66b1bc2534d2c25abbfaba7f626 Mon Sep 17 00:00:00 2001 From: Martyn Gigg Date: Fri, 21 Nov 2014 14:43:34 +0000 Subject: [PATCH 122/128] Fix typo in OCE requirements Refs #10616 --- Code/Mantid/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Mantid/CMakeLists.txt b/Code/Mantid/CMakeLists.txt index 20eaa689aff2..b06747503b0c 100644 --- a/Code/Mantid/CMakeLists.txt +++ b/Code/Mantid/CMakeLists.txt @@ -187,7 +187,7 @@ if ( ENABLE_CPACK ) # rhel requirements set ( CPACK_RPM_PACKAGE_REQUIRES "boost >= 1.34.1,qt4 >= 4.2,nexus,nexus-python,gsl,glibc,qwtplot3d-qt4,muParser,numpy" ) # OCE - set( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},OCE-draw,OCE-foundation,OCE-modeling,OCE_ocaf,OCE-visualization") + set( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},OCE-draw,OCE-foundation,OCE-modeling,OCE-ocaf,OCE-visualization") # Qwt is qwt5-qt4 in RHEL7 if( "${UNIX_CODENAME}" MATCHES "Maipo" ) set( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},qwt5-qt4" ) From 79f7d8d142e8402365e2f939e8480f33a2e6a516 Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Fri, 21 Nov 2014 09:54:57 -0500 Subject: [PATCH 123/128] Refs #10618. Fixing cppcheck warning. --- Code/Mantid/Framework/Kernel/src/ConfigService.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp index 19c665dfdad3..66fd93187c1f 100644 --- a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp @@ -1359,7 +1359,8 @@ std::string ConfigServiceImpl::getOSVersionReadable() { description = product_name + " " + product_vers; #elif _WIN32 description = getValueFromStdOut(result, "Caption="); - // std::cout << "***" << stringStream.str() << "***" << std::endl; +#else + UNUSED_ARG(result); // only used on mac and windows #endif } else { std::stringstream messageStream; From 12689f3a9bd1ec0c77c79d31104a3185ceae1626 Mon Sep 17 00:00:00 2001 From: Mathieu Doucet Date: Fri, 21 Nov 2014 12:32:47 -0500 Subject: [PATCH 124/128] Re #10355 Add documentation --- .../docs/source/fitfunctions/Guinier.rst | 24 ++++++++++++++++++ .../docs/source/fitfunctions/GuinierPorod.rst | 19 ++++++++++++++ .../docs/source/fitfunctions/Lorentz.rst | 25 +++++++++++++++++++ .../Mantid/docs/source/fitfunctions/Porod.rst | 24 ++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 Code/Mantid/docs/source/fitfunctions/Guinier.rst create mode 100644 Code/Mantid/docs/source/fitfunctions/GuinierPorod.rst create mode 100644 Code/Mantid/docs/source/fitfunctions/Lorentz.rst create mode 100644 Code/Mantid/docs/source/fitfunctions/Porod.rst diff --git a/Code/Mantid/docs/source/fitfunctions/Guinier.rst b/Code/Mantid/docs/source/fitfunctions/Guinier.rst new file mode 100644 index 000000000000..0f1a717fdefa --- /dev/null +++ b/Code/Mantid/docs/source/fitfunctions/Guinier.rst @@ -0,0 +1,24 @@ +.. _func-Guinier: + +======= +Guinier +======= + +.. index:: Guinier + +Description +----------- + +The Guinier model is defined by: + +.. math:: I(q) = I_0 \exp{-R_g^2 q^2 / 3} + +where: +- :math:`I_0` is the amplitude +- :math:`R_g` is the radius of gyration + +.. attributes:: + +.. properties:: + +.. categories:: diff --git a/Code/Mantid/docs/source/fitfunctions/GuinierPorod.rst b/Code/Mantid/docs/source/fitfunctions/GuinierPorod.rst new file mode 100644 index 000000000000..7f69961ba873 --- /dev/null +++ b/Code/Mantid/docs/source/fitfunctions/GuinierPorod.rst @@ -0,0 +1,19 @@ +.. _func-GuinierPorod: + +============ +GuinierPorod +============ + +.. index:: GuinierPorod + +Description +----------- + +Calculates the scattering for a generalized Guinier/power law object. +The Guinier-Porod model is defined in Hammouda, J. Appl. Cryst. (2010) 43, 716-719. + +.. attributes:: + +.. properties:: + +.. categories:: diff --git a/Code/Mantid/docs/source/fitfunctions/Lorentz.rst b/Code/Mantid/docs/source/fitfunctions/Lorentz.rst new file mode 100644 index 000000000000..9fa0774d6d16 --- /dev/null +++ b/Code/Mantid/docs/source/fitfunctions/Lorentz.rst @@ -0,0 +1,25 @@ +.. _func-Lorentz: + +======= +Lorentz +======= + +.. index:: Lorentz + +Description +----------- + +The Ornstein-Zernicke model is defined as: + +.. math:: I(q) = I_0 / (1 + q^2L^2) + background + +where: +- :math:`I_0` is a scale factor +- :math:`L` is the screening length +- :math:`background` is the background level + +.. attributes:: + +.. properties:: + +.. categories:: diff --git a/Code/Mantid/docs/source/fitfunctions/Porod.rst b/Code/Mantid/docs/source/fitfunctions/Porod.rst new file mode 100644 index 000000000000..dba28edc8291 --- /dev/null +++ b/Code/Mantid/docs/source/fitfunctions/Porod.rst @@ -0,0 +1,24 @@ +.. _func-Porod: + +===== +Porod +===== + +.. index:: Porod + +Description +----------- + +The Porod model is defined by: + +.. math:: I(q) = I_0 / q^4 + background + +where: +- :math:`I_0` is a scale factor +- :math:`background` is the background level + +.. attributes:: + +.. properties:: + +.. categories:: From 5166a3cfafb5c0657182870b305938d8d381aa47 Mon Sep 17 00:00:00 2001 From: Mathieu Doucet Date: Fri, 21 Nov 2014 14:59:27 -0500 Subject: [PATCH 125/128] Re #10355 Tweak docs --- Code/Mantid/docs/source/fitfunctions/Guinier.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Mantid/docs/source/fitfunctions/Guinier.rst b/Code/Mantid/docs/source/fitfunctions/Guinier.rst index 0f1a717fdefa..5fe32bc5652e 100644 --- a/Code/Mantid/docs/source/fitfunctions/Guinier.rst +++ b/Code/Mantid/docs/source/fitfunctions/Guinier.rst @@ -11,7 +11,7 @@ Description The Guinier model is defined by: -.. math:: I(q) = I_0 \exp{-R_g^2 q^2 / 3} +.. math:: I(q) = I_0 \exp{(-R_g^2 q^2 / 3)} where: - :math:`I_0` is the amplitude From 5e08ad9efb0686ec278e3c8e9e694859b398ff9b Mon Sep 17 00:00:00 2001 From: Jean Bilheux Date: Fri, 21 Nov 2014 15:14:04 -0500 Subject: [PATCH 126/128] Fixed missing import. This refs #10609 --- .../reduction_gui/reduction/reflectometer/refl_sf_calculator.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Mantid/scripts/Interface/reduction_gui/reduction/reflectometer/refl_sf_calculator.py b/Code/Mantid/scripts/Interface/reduction_gui/reduction/reflectometer/refl_sf_calculator.py index 1066023e1e93..fa68ff9c5923 100644 --- a/Code/Mantid/scripts/Interface/reduction_gui/reduction/reflectometer/refl_sf_calculator.py +++ b/Code/Mantid/scripts/Interface/reduction_gui/reduction/reflectometer/refl_sf_calculator.py @@ -4,6 +4,8 @@ """ import time from reduction_gui.reduction.scripter import BaseReductionScripter +import sys + # Check whether Mantid is available try: import mantidplot From fa4f08efa6a8fb36f38df64aa8931c3f8ed6eed1 Mon Sep 17 00:00:00 2001 From: Wenduo Zhou Date: Sat, 22 Nov 2014 10:11:56 -0500 Subject: [PATCH 127/128] Refs #10602. Modified sub bullet sign from * to -. As Martyn's suggestion. Though it does not seems to change any format in the generated html file. On the other hand, the previously reported warning was fixed by last commit (http://builds.mantidproject.org/job/develop_clean/505/) --- .../source/algorithms/GetDetOffsetsMultiPeaks-v1.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Code/Mantid/docs/source/algorithms/GetDetOffsetsMultiPeaks-v1.rst b/Code/Mantid/docs/source/algorithms/GetDetOffsetsMultiPeaks-v1.rst index a8c8ca50d49c..a17d40595ec3 100644 --- a/Code/Mantid/docs/source/algorithms/GetDetOffsetsMultiPeaks-v1.rst +++ b/Code/Mantid/docs/source/algorithms/GetDetOffsetsMultiPeaks-v1.rst @@ -183,11 +183,11 @@ Here are the cases that a spectra (i.e., a detector) will be masked in the outpu - A spectrum that does not have peak within specified d-range. It is noted as "no peaks". Here is the criteria for this case. - * Algorithm FindPeaks fails to find any peak; - * No peak found has height larger than specified 'MinimumPeakHeight'; - * No peak found has observed height larger than specified 'MinimumPeakHeightObs'; - * No peak found has resolution within specified range; - * No peak found whose calculated offset is smaller than the user-defined maximum offset. + - Algorithm FindPeaks fails to find any peak; + - No peak found has height larger than specified 'MinimumPeakHeight'; + - No peak found has observed height larger than specified 'MinimumPeakHeightObs'; + - No peak found has resolution within specified range; + - No peak found whose calculated offset is smaller than the user-defined maximum offset. Usage ----- From a2f7d8d713727a74b7b571c1c7baf47d378d02d6 Mon Sep 17 00:00:00 2001 From: Anton Piccardo-Selg Date: Mon, 24 Nov 2014 08:22:44 +0000 Subject: [PATCH 128/128] Refs #10533 Replace tabs with spaces --- .../Kernel/inc/MantidKernel/ConfigService.h | 4 ++-- .../Framework/Kernel/src/ConfigService.cpp | 2 +- .../ViewWidgets/src/MdViewerWidget.cpp | 18 +++++++++--------- .../ViewWidgets/src/ThreesliceView.cpp | 10 +++++----- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h index 67c2c1e71dcc..74ad45743570 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ConfigService.h @@ -225,8 +225,8 @@ namespace Mantid /// Quick check to determine if vates has been installed. bool quickVatesCheck() const; - /// Get the ParaViewPath - const std::string getParaViewPath() const; + /// Get the ParaViewPath + const std::string getParaViewPath() const; private: friend struct Mantid::Kernel::CreateUsingNew; diff --git a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp index f997ef081420..25b14134f7e3 100644 --- a/Code/Mantid/Framework/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Framework/Kernel/src/ConfigService.cpp @@ -1997,7 +1997,7 @@ bool ConfigServiceImpl::quickVatesCheck() const */ const std::string ConfigServiceImpl::getParaViewPath() const { - return getString("paraview.path"); + return getString("paraview.path"); } /// \cond TEMPLATE diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp index e94ec3ad2040..6ffd05e4eba3 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp @@ -100,8 +100,8 @@ using namespace MantidQt::API; namespace { - /// Static logger - Kernel::Logger g_log("MdViewerWidget"); + /// Static logger + Kernel::Logger g_log("MdViewerWidget"); } REGISTER_VATESGUI(MdViewerWidget) @@ -251,16 +251,16 @@ void MdViewerWidget::createAppCoreForPlugin() { if (!pqApplicationCore::instance()) { - // Provide ParaView's application core with a path to ParaView - int argc = 1; + // Provide ParaView's application core with a path to ParaView + int argc = 1; - std::string paraviewPath = Mantid::Kernel::ConfigService::Instance().getParaViewPath(); - std::vector argvConversion(paraviewPath.begin(), paraviewPath.end()); - argvConversion.push_back('\0'); + std::string paraviewPath = Mantid::Kernel::ConfigService::Instance().getParaViewPath(); + std::vector argvConversion(paraviewPath.begin(), paraviewPath.end()); + argvConversion.push_back('\0'); - char *argv[] = {&argvConversion[0]}; + char *argv[] = {&argvConversion[0]}; - g_log.debug() << "Intialize pqApplicationCore with " << argv << "\n"; + g_log.debug() << "Intialize pqApplicationCore with " << argv << "\n"; new pqPVApplicationCore(argc, argv); } diff --git a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp index 73f2b563bfd2..bc67d528228d 100644 --- a/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp +++ b/Code/Mantid/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp @@ -36,16 +36,16 @@ namespace SimpleGui { namespace { - /// Static logger - Kernel::Logger g_log("ThreeSliceView"); + /// Static logger + Kernel::Logger g_log("ThreeSliceView"); } ThreeSliceView::ThreeSliceView(QWidget *parent) : ViewBase(parent) { this->ui.setupUi(this); - // We need to load the QuadView.dll plugin. The Windows system requires the full + // We need to load the QuadView.dll plugin. The Windows system requires the full // path information. The DLL is located in the apropriate executeable path of paraview. - const Poco::Path paraviewPath(Mantid::Kernel::ConfigService::Instance().getParaViewPath()); + const Poco::Path paraviewPath(Mantid::Kernel::ConfigService::Instance().getParaViewPath()); Poco::Path quadViewFullPath(paraviewPath, QUADVIEW_LIBRARY.toStdString()); @@ -57,7 +57,7 @@ ThreeSliceView::ThreeSliceView(QWidget *parent) : ViewBase(parent) pm->loadExtension(pqActiveObjects::instance().activeServer(), quadViewLibrary, &error, false); - g_log.debug() << "Loading QuadView.dll from " << quadViewLibrary.toStdString() << "\n"; + g_log.debug() << "Loading QuadView.dll from " << quadViewLibrary.toStdString() << "\n"; this->mainView = this->createRenderView(this->ui.mainRenderFrame, QString("pqQuadView"));